Subversion Repositories Kolibri OS

Compare Revisions

No changes between revisions

Regard whitespace Rev 1891 → Rev 1892

/programs/develop/libraries/cairo/AUTHORS
0,0 → 1,110
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
Olivier Andrieu <oliv__a@users.sourceforge.net> PNG backend
Peter Dennis Bartok <peter@novonyx.com> Bug fix for clipping
Dave Beckett <dajobe@debian.org> Build fixes, Debian packaging
Kai-Uwe Behrmann <ku.b@gmx.de> SVG bug fixes
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
Carlos Garcia Campos <carlosgc@gnome.org> libspectre integration into the test-suite
Andrea Canciani <ranma42@gmail.com> Bugs, quartz backend improvements and type 6/7 patterns.
Damien Carbery <damien.carbery@sun.com> Build fixes
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)
Julien Danjou <julien@danjou.info> XCB fixes
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
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
Larry Ewing <lewing@novell.com> Test case for group-clip
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
Damian Frank <damian.frank@gmail.com> Build system improvements for win32
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
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
Thomas Hunger <info@teh-web.de> Initial version of cairo_in_stroke/fill
Thomas Jaeger <ThJaeger@gmail.com> Extended repeat modes for X
Björn Lindqvist <bjourne@gmail.com> Performance test cases
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> OpenVG backend, 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.
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
Nis Martensen <nis.martensen@web.de> Bug fix for sub paths
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
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
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
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
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
Zhe Su <james.su@gmail.com> Add support for fontconfig's embeddedbitmap option
Owen Taylor <otaylor@redhat.com> Font rewrite, documentation, win32 backend
Pierre Tardy <tardyp@gmail.com> EGL support and testing, OpenVG backend
Karl Tomlinson <karlt+@karlt.net> Optimisation and obscure bug fixes (mozilla)
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
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
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)
/programs/develop/libraries/cairo/BIBLIOGRAPHY
0,0 → 1,109
Here's an effort to document some of the academic work that was
referenced during the implementation of cairo. It is presented in the
context of operations as they would be performed by either
cairo_stroke() or cairo_fill():
 
Given a Bézier path, approximate it with line segments:
 
The deCasteljau algorithm
"Outillages methodes calcul", P de Casteljau, technical
report, - Andre Citroen Automobiles SA, Paris, 1959
 
That technical report might be "hard" to find, but fortunately
this algorithm will be described in any reasonable textbook on
computational geometry. Two that have been recommended by
cairo contributors are:
 
"Computational Geometry, Algorithms and Applications", M. de
Berg, M. van Kreveld, M. Overmars, M. Schwarzkopf;
Springer-Verlag, ISBN: 3-540-65620-0.
 
"Computational Geometry in C (Second Edition)", Joseph
O'Rourke, Cambridge University Press, ISBN 0521640105.
 
Then, if stroking, construct a polygonal representation of the pen
approximating a circle (if filling skip three steps):
 
"Good approximation of circles by curvature-continuous Bezier
curves", Tor Dokken and Morten Daehlen, Computer Aided
Geometric Design 8 (1990) 22-41.
 
Add points to that pen based on the initial/final path faces and take
the convex hull:
 
Convex hull algorithm
 
[Again, see your favorite computational geometry
textbook. Should cite the name of the algorithm cairo uses
here, if it has a name.]
 
Now, "convolve" the "tracing" of the pen with the tracing of the path:
 
"A Kinetic Framework for Computational Geometry", Leonidas
J. Guibas, Lyle Ramshaw, and Jorge Stolfi, Proceedings of the
24th IEEE Annual Symposium on Foundations of Computer Science
(FOCS), November 1983, 100-111.
 
The result of the convolution is a polygon that must be filled. A fill
operations begins here. We use a very conventional Bentley-Ottmann
pass for computing the intersections, informed by some hints on robust
implementation courtesy of John Hobby:
 
John D. Hobby, Practical Segment Intersection with Finite
Precision Output, Computation Geometry Theory and
Applications, 13(4), 1999.
 
http://cm.bell-labs.com/who/hobby/93_2-27.pdf
 
Hobby's primary contribution in that paper is his "tolerance square"
algorithm for robustness against edges being "bent" due to restricting
intersection coordinates to the grid available by finite-precision
arithmetic. This is one algorithm we have not implemented yet.
 
We use a data-structure called Skiplists in the our implementation
of Bentley-Ottmann:
 
W. Pugh, Skip Lists: a Probabilistic Alternative to Balanced Trees,
Communications of the ACM, vol. 33, no. 6, pp.668-676, 1990.
 
http://citeseer.ist.psu.edu/pugh90skip.html
 
The random number generator used in our skip list implementation is a
very small generator by Hars and Petruska. The generator is based on
an invertable function on Z_{2^32} with full period and is described
in
 
Hars L. and Petruska G.,
``Pseudorandom Recursions: Small and Fast Pseurodandom
Number Generators for Embedded Applications'',
Hindawi Publishing Corporation
EURASIP Journal on Embedded Systems
Volume 2007, Article ID 98417, 13 pages
doi:10.1155/2007/98417
 
http://www.hindawi.com/getarticle.aspx?doi=10.1155/2007/98417&e=cta
 
From the result of the intersection-finding pass, we are currently
computing a tessellation of trapezoids, (the exact manner is
undergoing some work right now with some important speedup), but we
may want to rasterize directly from those edges at some point.
 
Given the set of tessellated trapezoids, we currently execute a
straightforward, (and slow), point-sampled rasterization, (and
currently with a near-pessimal regular 15x17 grid).
 
We've now computed a mask which gets fed along with the source and
destination into cairo's fundamental rendering equation. The most
basic form of this equation is:
 
destination = (source IN mask) OP destination
 
with the restriction that no part of the destination outside the
current clip region is affected. In this equation, IN refers to the
Porter-Duff "in" operation, while OP refers to a any user-selected
Porter-Duff operator:
 
T. Porter & T. Duff, Compositing Digital Images Computer
Graphics Volume 18, Number 3 July 1984 pp 253-259
 
http://keithp.com/~keithp/porterduff/p253-porter.pdf
/programs/develop/libraries/cairo/BUGS
0,0 → 1,85
If you find a bug in cairo we would love to hear about it. We're also
trying to make cairo better, and learning about the bugs that users
encounter is an essential part of that. So we really appreciate the
extra effort users put in to providing high-quality bug reports.
 
There are two acceptable ways to report cairo bugs, and you can choose
which you prefer:
 
1) Bugzilla bug tracking database:
 
You can use the following web interface to report new bugs, follow
up on previous bug reports, and search for existing, known
bugs. Just use the "cairo" product:
 
http://bugs.freedesktop.org
 
It is necessary to go through a quick account creation process,
(with email address verification), in order to be able to report
new bugs in bugzilla. We apologize for any inconvenience that might
cause, and hope it won't prevent you from reporting bugs.
 
2) Cairo mailing list:
 
For people who cannot stand the bugzilla interface, you can just
send an email to cairo mailing list (cairo@cairographics.org). The
mailing list only allows posting from subscribers, so use the
following page for subscription instructions:
 
http://cairographics.org/lists
 
Again, we apologize for any inconvenience this subscription step
might cause, but we've found it necessary to require this in order
to enjoy spam-free discussions on the list.
 
If you don't actually _want_ to be a subscriber to the mailing
list, but just want to be able to send a message, the easiest thing
to do is to go through the subscription process, and then use the
preferences page to disable message delivery to your address.
 
Which of the above you use to report bugs depends on your own
preferences. Some people find just typing an email message much easier
than using the web-based forms on bugzilla. Others greatly prefer the
ability to check back on a specific bug entry in bugzilla without
having to ask on the mailing list if an issue has been resolved.
 
Regardless of which method you use, here are some general tips that
will help you improve the quality of your bug report, (which will help
in getting the bug fixed sooner):
 
1) Check to see if the bug has been reported already. It's pretty easy
to run a search or two against the cairo product in the
http://bugs.freedesktop.org bugzilla database. Another place to
look for known bugs is the cairo ROADMAP:
 
http://cairographics.org/ROADMAP
 
which shows a planned schedule of releases and which bug fixes are
being planned for each release.
 
2) Provide an accurate description of the bug with detailed steps for
how we can reproduce the problem.
 
3) If possible provide a minimal test case demonstrating the bug. A
great test case would be a minimal self-contained function in C or
python or whatever language you are using for cairo. The function
might accept nothing more than a cairo context, (cairo_t* in C).
 
4) If you feel like being particularly helpful, you could craft this
minimal test case in the form necessary for cairo's test
suite. This isn't much more work than writing a minimal
function. Just look at the cairo/test/README file and imitate the
style of existing test cases.
 
If you do submit a test case, be sure to include Copyright
information, (with the standard MIT licensing blurb if you want us
to include your test in the test case). Also, including a reference
image showing the expected result will be extremely useful.
 
5) Finally, the best bug report also comes attached with a patch to
cairo to fix the bug. So send this too if you have it! Otherwise,
don't worry about it and we'll try to fix cairo when we can.
 
Thanks, and have fun with cairo!
 
-Carl
/programs/develop/libraries/cairo/Makefile
0,0 → 1,112
 
LIBRARY = cairo
 
CC = gcc
 
CFLAGS = -c -O2
 
DEFINES = -DHAVE_CONFIG_H -U_WIN32 -DCAIRO_NO_MUTEX
 
INCLUDES = -I../pixman -I../newlib/include -I../newlib/include/sys
 
SOURCES = \
cairo-analysis-surface.c \
cairo-arc.c \
cairo-array.c \
cairo-atomic.c \
cairo-base64-stream.c \
cairo-base85-stream.c \
cairo-bentley-ottmann.c \
cairo-bentley-ottmann-rectangular.c \
cairo-bentley-ottmann-rectilinear.c \
cairo-botor-scan-converter.c \
cairo-boxes.c \
cairo.c \
cairo-cache.c \
cairo-clip.c \
cairo-color.c \
cairo-composite-rectangles.c \
cairo-debug.c \
cairo-device.c \
cairo-fixed.c \
cairo-font-face.c \
cairo-font-face-twin.c \
cairo-font-face-twin-data.c \
cairo-font-options.c \
cairo-freelist.c \
cairo-freed-pool.c \
cairo-gstate.c \
cairo-hash.c \
cairo-hull.c \
cairo-image-info.c \
cairo-image-surface.c \
cairo-lzw.c \
cairo-matrix.c \
cairo-recording-surface.c \
cairo-misc.c \
cairo-mutex.c \
cairo-observer.c \
cairo-output-stream.c \
cairo-paginated-surface.c \
cairo-path-bounds.c \
cairo-path.c \
cairo-path-fill.c \
cairo-path-fixed.c \
cairo-path-in-fill.c \
cairo-path-stroke.c \
cairo-pattern.c \
cairo-pen.c \
cairo-polygon.c \
cairo-rectangle.c \
cairo-rectangular-scan-converter.c \
cairo-region.c \
cairo-rtree.c \
cairo-scaled-font.c \
cairo-slope.c \
cairo-spans.c \
cairo-spline.c \
cairo-stroke-style.c \
cairo-surface.c \
cairo-surface-fallback.c \
cairo-surface-clipper.c \
cairo-surface-offset.c \
cairo-surface-snapshot.c \
cairo-surface-subsurface.c \
cairo-surface-wrapper.c \
cairo-tor-scan-converter.c \
cairo-toy-font-face.c \
cairo-traps.c \
cairo-unicode.c \
cairo-user-font.c \
cairo-version.c \
cairo-wideint.c \
$(NULL)
 
 
 
OBJECTS = $(patsubst %.c, src/%.o, $(SOURCES))
 
 
# targets
 
 
all:$(LIBRARY).a
 
 
$(LIBRARY).a: $(OBJECTS) Makefile
ar cvrs $(LIBRARY).a $(OBJECTS)
 
 
%.o : %.c Makefile
$(CC) $(CFLAGS) $(DEFINES) $(INCLUDES) -o $@ $<
 
 
 
 
 
 
 
 
 
/programs/develop/libraries/cairo/README
0,0 → 1,194
Cairo - Multi-platform 2D graphics library
http://cairographics.org
 
What is cairo
=============
Cairo is a 2D graphics library with support for multiple output
devices. Currently supported output targets include the X Window
System, quartz, win32, and image buffers, as well as PDF, PostScript,
and SVG file output. Experimental backends include OpenGL, XCB, BeOS,
OS/2, and DirectFB.
 
Cairo is designed to produce consistent output on all output media
while taking advantage of display hardware acceleration when available
(for example, through the X Render Extension).
 
The cairo API provides operations similar to the drawing operators of
PostScript and PDF. Operations in cairo include stroking and filling
cubic Bézier splines, transforming and compositing translucent images,
and antialiased text rendering. All drawing operations can be
transformed by any affine transformation (scale, rotation, shear,
etc.).
 
Cairo has been designed to let you draw anything you want in a modern
2D graphical user interface. At the same time, the cairo API has been
designed to be as fun and easy to learn as possible. If you're not
having fun while programming with cairo, then we have failed
somewhere---let us know and we'll try to fix it next time around.
 
Cairo is free software and is available to be redistributed and/or
modified under the terms of either the GNU Lesser General Public
License (LGPL) version 2.1 or the Mozilla Public License (MPL) version
1.1.
 
Where to get more information about cairo
=========================================
The primary source of information about cairo is:
 
http://cairographics.org/
 
The latest versions of cairo can always be found at:
 
http://cairographics.org/download
 
Documentation on using cairo and frequently-asked questions:
 
http://cairographics.org/documentation
http://cairographics.org/FAQ
 
Mailing lists for contacting cairo users and developers:
 
http://cairographics.org/lists
 
Roadmap and unscheduled things to do, (please feel free to help out):
 
http://cairographics.org/roadmap
http://cairographics.org/todo
 
Dependencies
============
The set of libraries needed to compile cairo depends on which backends
are enabled when cairo is configured. So look at the list below to
determine which dependencies are needed for the backends of interest.
 
For the surface backends, we have both "supported" and "experimental"
backends. Further, the supported backends can be divided into the
"standard" backends which can be easily built on any platform, and the
"platform" backends which depend on some underlying platform-specific
system, (such as the X Window System or some other window system).
 
As an example, for a standard Linux build, (with image, png, pdf,
PostScript, svg, and xlib surface backends, and the freetype font
backend), the following sample commands will install necessary
dependencies:
 
Debian (and similar):
 
apt-get install libpng12-dev libz-dev libxrender-dev libfontconfig1-dev
 
Fedora (and similar):
 
yum install libpng-devel zlib-devel libXrender-devel fontconfig-devel
 
(Those commands intentionally don't install pixman from a distribution
package since if you're manually compiling cairo, then you likely want
to grab pixman from the same place at the same time and compile it as
well.)
 
Supported, "standard" surface backends
------------------------------------
image backend (required)
------------------------
pixman >= 0.18.4 http://cairographics.org/releases
 
png support (can be left out if desired, but many
----------- applications expect it to be present)
libpng http://www.libpng.org/pub/png/libpng.html
 
pdf backend
-----------
zlib http://www.gzip.org/zlib
 
postscript backend
------------------
zlib http://www.gzip.org/zlib
 
svg backend
-----------
[none]
 
Supported, "platform" surface backends
-----------------------------------
xlib backend
------------
X11 http://freedesktop.org/Software/xlibs
 
xlib-xrender backend
--------------------
Xrender >= 0.6 http://freedesktop.org/Software/xlibs
 
quartz backend
--------------
MacOS X >= 10.4 with Xcode >= 2.4
 
win32 backend
-------------
Microsoft Windows 2000 or newer[*].
 
Font backends (required to have at least one)
---------------------------------------------
freetype font backend
---------------------
freetype >= 2.1.9 http://freetype.org
fontconfig http://fontconfig.org
 
quartz-font backend
-------------------
MacOS X >= 10.4 with Xcode >= 2.4
 
win32 font backend
------------------
Microsoft Windows 2000 or newer[*].
 
[*] The Win32 backend should work on Windows 2000 and newer
(excluding Windows Me.) Most testing has been done on
Windows XP. While some portions of the code have been
adapted to work on older versions of Windows, considerable
work still needs to be done to get cairo running in those
environments.
 
Cairo can be compiled on Windows with either the gcc
toolchain (see http://www.mingw.org) or with Microsoft
Visual C++. If the gcc toolchain is used, the standard
build instructions using configure apply, (see INSTALL).
If Visual C++ is desired, GNU make is required and
Makefile.win32 can be used via 'make -f Makefile.win32'.
The compiler, include paths, and library paths must be set
up correctly in the environment.
 
MSVC versions earlier than 7.1 are known to miscompile
parts of cairo and pixman, and so should be avoided. MSVC
7.1 or later, including the free Microsoft Visual Studio
Express editions, produce correct code.
 
Experimental surface backends
-----------------------------
xcb backend
-----------
XCB http://xcb.freedesktop.org
 
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
 
Compiling
=========
See the INSTALL document for build instructions.
 
History
=======
Cairo was originally developed by Carl Worth <cworth@cworth.org> and
Keith Packard <keithp@keithp.com>. Many thanks are due to Lyle Ramshaw
without whose patient help our ignorance would be much more apparent.
 
Since the original development, many more people have contributed to
cairo. See the AUTHORS files for as complete a list as we've been able
to compile so far.
/programs/develop/libraries/cairo/cairo-version.h
0,0 → 1,8
#ifndef CAIRO_VERSION_H
#define CAIRO_VERSION_H
 
#define CAIRO_VERSION_MAJOR 1
#define CAIRO_VERSION_MINOR 10
#define CAIRO_VERSION_MICRO 2
 
#endif
/programs/develop/libraries/cairo/config.h
0,0 → 1,366
/* config.h. Generated from config.h.in by configure. */
/* config.h.in. Generated from configure.ac by autoheader. */
 
/* Define if building universal (internal helper macro) */
/* #undef AC_APPLE_UNIVERSAL_BUILD */
 
/* whether memory barriers are needed around atomic operations */
/* #undef ATOMIC_OP_NEEDS_MEMORY_BARRIER */
 
/* Define to 1 if the PDF backend can be tested (need poppler and other
dependencies for pdf2png) */
/* #undef CAIRO_CAN_TEST_PDF_SURFACE */
 
/* Define to 1 if the PS backend can be tested (needs ghostscript) */
/* #undef CAIRO_CAN_TEST_PS_SURFACE */
 
/* Define to 1 if the SVG backend can be tested */
/* #undef CAIRO_CAN_TEST_SVG_SURFACE */
 
/* Define to 1 if the Win32 Printing backend can be tested (needs ghostscript)
*/
/* #undef CAIRO_CAN_TEST_WIN32_PRINTING_SURFACE */
 
/* Define to 1 to enable cairo's cairo-script-interpreter feature */
//#define CAIRO_HAS_INTERPRETER 1
 
/* Define to 1 to enable cairo's pthread feature */
//#define CAIRO_HAS_PTHREAD 1
 
/* Define to 1 if we have full pthread support */
//#define CAIRO_HAS_REAL_PTHREAD 1
 
/* Define to 1 if libspectre is available */
/* #undef CAIRO_HAS_SPECTRE */
 
/* Define to 1 to enable cairo's symbol-lookup feature */
/* #undef CAIRO_HAS_SYMBOL_LOOKUP */
 
/* Define to 1 to enable cairo's test surfaces feature */
/* #undef CAIRO_HAS_TEST_SURFACES */
 
/* Define to 1 to enable cairo's cairo-trace feature */
//#define CAIRO_HAS_TRACE 1
 
/* Define to 1 to disable certain code paths that rely heavily on double
precision floating-point calculation */
/* #undef DISABLE_SOME_FLOATING_POINT */
 
/* Define to 1 if your system stores words within floats with the most
significant word first */
/* #undef FLOAT_WORDS_BIGENDIAN */
 
/* Define to 1 if you have the `alarm' function. */
//#define HAVE_ALARM 1
 
/* Define to 1 if you have the binutils development files installed */
/* #undef HAVE_BFD */
 
/* Define to 1 if your compiler supports the __builtin_return_address()
intrinsic. */
#define HAVE_BUILTIN_RETURN_ADDRESS 1
 
/* Define to 1 if you have the <byteswap.h> header file. */
#define HAVE_BYTESWAP_H 1
 
/* Define to 1 if you have the `clock_gettime' function. */
//#define HAVE_CLOCK_GETTIME 1
 
/* Define to 1 if you have the `ctime_r' function. */
//#define HAVE_CTIME_R 1
 
/* Define to 1 if you have the <dlfcn.h> header file. */
#define HAVE_DLFCN_H 1
 
/* Define to 1 if you have the `drand48' function. */
//#define HAVE_DRAND48 1
 
/* Define to 1 if you have the `FcFini' function. */
/* #undef HAVE_FCFINI */
 
/* Define to 1 if you have the `FcInit' function. */
/* #undef HAVE_FCINIT */
 
/* Define to 1 if you have the <fcntl.h> header file. */
#define HAVE_FCNTL_H 1
 
/* Define to 1 if you have the `feclearexcept' function. */
#define HAVE_FECLEAREXCEPT 1
 
/* Define to 1 if you have the `fedisableexcept' function. */
#define HAVE_FEDISABLEEXCEPT 1
 
/* Define to 1 if you have the `feenableexcept' function. */
#define HAVE_FEENABLEEXCEPT 1
 
/* Define to 1 if you have the <fenv.h> header file. */
#define HAVE_FENV_H 1
 
/* Define to 1 if you have the `ffs' function. */
#define HAVE_FFS 1
 
/* Define to 1 if you have the `flockfile' function. */
#define HAVE_FLOCKFILE 1
 
/* Define to 1 if you have the `fork' function. */
//#define HAVE_FORK 1
 
/* FT_Bitmap_Size structure includes y_ppem field */
/* #undef HAVE_FT_BITMAP_SIZE_Y_PPEM */
 
/* Define to 1 if you have the `FT_GlyphSlot_Embolden' function. */
/* #undef HAVE_FT_GLYPHSLOT_EMBOLDEN */
 
/* Define to 1 if you have the `FT_Library_SetLcdFilter' function. */
/* #undef HAVE_FT_LIBRARY_SETLCDFILTER */
 
/* Define to 1 if you have the `FT_Load_Sfnt_Table' function. */
/* #undef HAVE_FT_LOAD_SFNT_TABLE */
 
/* Whether you have gcov */
/* #undef HAVE_GCOV */
 
/* Enable if your compiler supports the Intel __sync_* atomic primitives */
#define HAVE_INTEL_ATOMIC_PRIMITIVES 1
 
/* Define to 1 if you have the <inttypes.h> header file. */
#define HAVE_INTTYPES_H 1
 
/* Define to 1 if you have the <io.h> header file. */
/* #undef HAVE_IO_H */
 
/* Define to 1 if you have the <libgen.h> header file. */
#define HAVE_LIBGEN_H 1
 
/* Enable if you have libatomic-ops-dev installed */
/* #undef HAVE_LIB_ATOMIC_OPS */
 
/* Define to 1 if you have the `link' function. */
//#define HAVE_LINK 1
 
/* Define to 1 if you have the Valgrind lockdep tool */
/* #undef HAVE_LOCKDEP */
 
/* Define to 1 if you have the Valgrind memfault tool */
/* #undef HAVE_MEMFAULT */
 
/* Define to 1 if you have the <memory.h> header file. */
#define HAVE_MEMORY_H 1
 
/* Define to non-zero if your system has mkdir, and to 2 if your version of
mkdir requires a mode parameter */
//#define HAVE_MKDIR 2
 
/* Define to 1 if you have the `mmap' function. */
//#define HAVE_MMAP 1
 
/* Enable if you have MacOS X atomic operations */
/* #undef HAVE_OS_ATOMIC_OPS */
 
/* Define to 1 if you have the `poppler_page_render' function. */
/* #undef HAVE_POPPLER_PAGE_RENDER */
 
/* Define to 1 if you have the `raise' function. */
//#define HAVE_RAISE 1
 
/* Define to 1 if you have the `rsvg_pixbuf_from_file' function. */
/* #undef HAVE_RSVG_PIXBUF_FROM_FILE */
 
/* Define to 1 if you have the `sched_getaffinity' function. */
//#define HAVE_SCHED_GETAFFINITY 1
 
/* Define to 1 if you have the <sched.h> header file. */
//#define HAVE_SCHED_H 1
 
/* Define to 1 if you have the <setjmp.h> header file. */
//#define HAVE_SETJMP_H 1
 
/* Define to 1 if you have the <signal.h> header file. */
//#define HAVE_SIGNAL_H 1
 
/* Define to 1 if you have the <stdint.h> header file. */
#define HAVE_STDINT_H 1
 
/* Define to 1 if you have the <stdlib.h> header file. */
#define HAVE_STDLIB_H 1
 
/* Define to 1 if you have the <strings.h> header file. */
#define HAVE_STRINGS_H 1
 
/* Define to 1 if you have the <string.h> header file. */
#define HAVE_STRING_H 1
 
/* Define to 1 if you have the <sys/int_types.h> header file. */
/* #undef HAVE_SYS_INT_TYPES_H */
 
/* Define to 1 if you have the <sys/mman.h> header file. */
//#define HAVE_SYS_MMAN_H 1
 
/* Define to 1 if you have the <sys/poll.h> header file. */
//#define HAVE_SYS_POLL_H 1
 
/* Define to 1 if you have the <sys/socket.h> header file. */
//#define HAVE_SYS_SOCKET_H 1
 
/* Define to 1 if you have the <sys/stat.h> header file. */
#define HAVE_SYS_STAT_H 1
 
/* Define to 1 if you have the <sys/types.h> header file. */
#define HAVE_SYS_TYPES_H 1
 
/* Define to 1 if you have the <sys/un.h> header file. */
#define HAVE_SYS_UN_H 1
 
/* Define to 1 if you have the <time.h> header file. */
#define HAVE_TIME_H 1
 
/* Define to 1 if the system has the type `uint128_t'. */
/* #undef HAVE_UINT128_T */
 
/* Define to 1 if the system has the type `uint64_t'. */
#define HAVE_UINT64_T 1
 
/* Define to 1 if you have the <unistd.h> header file. */
#define HAVE_UNISTD_H 1
 
/* Define to 1 if you have Valgrind */
/* #undef HAVE_VALGRIND */
 
/* Define to 1 if you have the `vasnprintf' function. */
/* #undef HAVE_VASNPRINTF */
 
/* Define to 1 if you have the `waitpid' function. */
//#define HAVE_WAITPID 1
 
/* Define to 1 if you have the <windows.h> header file. */
/* #undef HAVE_WINDOWS_H */
 
/* Define to 1 if you have zlib available */
#define HAVE_ZLIB 1
 
/* Define to 1 if the system has the type `__uint128_t'. */
/* #undef HAVE___UINT128_T */
 
/* Define to the sub-directory in which libtool stores uninstalled libraries.
*/
#define LT_OBJDIR ".libs/"
 
/* Define to 1 if your C compiler doesn't accept -c and -o together. */
/* #undef NO_MINUS_C_MINUS_O */
 
/* Define to the address where bug reports for this package should be sent. */
#define PACKAGE_BUGREPORT "http://bugs.freedesktop.org/enter_bug.cgi?product=cairo"
 
/* Define to the full name of this package. */
#define PACKAGE_NAME USE_cairo_INSTEAD
 
/* Define to the full name and version of this package. */
#define PACKAGE_STRING USE_cairo_version_OR_cairo_version_string_INSTEAD
 
/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME USE_cairo_INSTEAD
 
/* Define to the home page for this package. */
#define PACKAGE_URL ""
 
/* Define to the version of this package. */
#define PACKAGE_VERSION USE_cairo_version_OR_cairo_version_string_INSTEAD
 
/* Shared library file extension */
#define SHARED_LIB_EXT "so"
 
/* The size of `int', as computed by sizeof. */
#define SIZEOF_INT 4
 
/* The size of `long', as computed by sizeof. */
#define SIZEOF_LONG 4
 
/* The size of `long long', as computed by sizeof. */
#define SIZEOF_LONG_LONG 8
 
/* The size of `size_t', as computed by sizeof. */
#define SIZEOF_SIZE_T 4
 
/* The size of `void *', as computed by sizeof. */
#define SIZEOF_VOID_P 4
 
/* Define to 1 if you have the ANSI C header files. */
#define STDC_HEADERS 1
 
/* Enable extensions on AIX 3, Interix. */
#ifndef _ALL_SOURCE
# define _ALL_SOURCE 1
#endif
/* Enable GNU extensions on systems that have them. */
#ifndef _GNU_SOURCE
# define _GNU_SOURCE 1
#endif
/* Enable threading extensions on Solaris. */
#ifndef _POSIX_PTHREAD_SEMANTICS
# define _POSIX_PTHREAD_SEMANTICS 1
#endif
/* Enable extensions on HP NonStop. */
#ifndef _TANDEM_SOURCE
# define _TANDEM_SOURCE 1
#endif
/* Enable general extensions on Solaris. */
#ifndef __EXTENSIONS__
# define __EXTENSIONS__ 1
#endif
 
 
/* Define to the value your compiler uses to support the warn-unused-result
attribute */
#define WARN_UNUSED_RESULT __attribute__((__warn_unused_result__))
 
/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
significant byte first (like Motorola and SPARC, unlike Intel). */
#if defined AC_APPLE_UNIVERSAL_BUILD
# if defined __BIG_ENDIAN__
# define WORDS_BIGENDIAN 1
# endif
#else
# ifndef WORDS_BIGENDIAN
/* # undef WORDS_BIGENDIAN */
# endif
#endif
 
 
/* Deal with multiple architecture compiles on Mac OS X */
#ifdef __APPLE_CC__
#ifdef __BIG_ENDIAN__
#define WORDS_BIGENDIAN 1
#define FLOAT_WORDS_BIGENDIAN 1
#else
/* #undef WORDS_BIGENDIAN */
/* #undef FLOAT_WORDS_BIGENDIAN */
#endif
#endif
 
 
/* Define to 1 if the X Window System is missing or not being used. */
#define X_DISPLAY_MISSING 1
 
/* Number of bits in a file offset, on hosts where this is settable. */
#define _FILE_OFFSET_BITS 64
 
/* Define for large files, on AIX-style hosts. */
/* #undef _LARGE_FILES */
 
/* Define to 1 if on MINIX. */
/* #undef _MINIX */
 
/* Define to 2 if the system does not provide POSIX.1 features except with
this defined. */
/* #undef _POSIX_1_SOURCE */
 
/* Define to 1 if you need to in order for `stat' and other things to work. */
/* #undef _POSIX_SOURCE */
 
/* Define to `__inline__' or `__inline' if that's what the C compiler
calls it, or to nothing if 'inline' is not supported under any name. */
#ifndef __cplusplus
/* #undef inline */
#endif
 
 
/programs/develop/libraries/cairo/src/README
0,0 → 1,69
Cairo Library Source Code
=========================
 
This directory contains the source code of the cairo library.
 
 
Source Code Listing
-------------------
 
The canonical list of source files is the file Makefile.sources. See that
file for how it works.
 
 
New Backends
------------
 
The rule of the thumb for adding new backends is to see how other
backends are integrated. Pick one of the simpler, unsupported, backends
and search the entire tree for it, and go from there.
 
To add new backends you need to basically:
 
* Modify $(top_srcdir)/configure.in to add checks for your backend.
 
* Modify Makefile.sources to add source files for your backend,
 
* Modify $(top_srcdir)/boilerplate/ to add boilerplate code for
testing your new backend.
 
 
New API
-------
 
After adding new API, run "make check" in this directory and fix any
reported issues. Also add new API to the right location in
$(top_srcdir)/doc/public/cairo-sections.txt and run "make check"
in $(top_builddir)/doc/public to make sure that any newly added
documentation is correctly hooked up.
 
Do not forget to add tests for the new API. See next section.
 
 
Tests
-----
 
There are some tests in this directory that check the source code and
the build for various issues. The tests are very quick to run, and
particularly should be run after any documentation or API changes. It
does not hurt to run them after any source modification either. Run
them simply by calling:
 
make check
 
There are also extensive regression tests in $(top_srcdir)/test. It is
a good idea to run that test suite for any changes made to the source
code. Moreover, for any new feature, API, or bug fix, new tests should
be added to the regression test suite to test the new code.
 
 
Bibliography
------------
 
A detailed list of academic publications used in cairo code is available
in the file $(top_srcdir)/BIBLIOGRAPHY. Feel free to update as you
implement more papers.
 
For more technical publications (eg. Adobe technical reports) just
point them out in a comment in the header of the file implementing them.
 
/programs/develop/libraries/cairo/src/cairo-analysis-surface-private.h
0,0 → 1,74
/*
* Copyright © 2005 Keith Packard
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Keith Packard
*
* Contributor(s):
* Keith Packard <keithp@keithp.com>
*/
 
#ifndef CAIRO_ANALYSIS_SURFACE_H
#define CAIRO_ANALYSIS_SURFACE_H
 
#include "cairoint.h"
 
cairo_private cairo_surface_t *
_cairo_analysis_surface_create (cairo_surface_t *target);
 
cairo_private void
_cairo_analysis_surface_set_ctm (cairo_surface_t *surface,
const cairo_matrix_t *ctm);
 
cairo_private void
_cairo_analysis_surface_get_ctm (cairo_surface_t *surface,
cairo_matrix_t *ctm);
 
cairo_private cairo_region_t *
_cairo_analysis_surface_get_supported (cairo_surface_t *surface);
 
cairo_private cairo_region_t *
_cairo_analysis_surface_get_unsupported (cairo_surface_t *surface);
 
cairo_private cairo_bool_t
_cairo_analysis_surface_has_supported (cairo_surface_t *surface);
 
cairo_private cairo_bool_t
_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);
 
cairo_private cairo_int_status_t
_cairo_analysis_surface_merge_status (cairo_int_status_t status_a,
cairo_int_status_t status_b);
 
cairo_private cairo_surface_t *
_cairo_null_surface_create (cairo_content_t content);
 
#endif /* CAIRO_ANALYSIS_SURFACE_H */
/programs/develop/libraries/cairo/src/cairo-analysis-surface.c
0,0 → 1,905
/*
* Copyright © 2006 Keith Packard
* Copyright © 2007 Adrian Johnson
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Keith Packard
*
* Contributor(s):
* Keith Packard <keithp@keithp.com>
* Adrian Johnson <ajohnson@redneon.com>
*/
 
#include "cairoint.h"
 
#include "cairo-analysis-surface-private.h"
#include "cairo-error-private.h"
#include "cairo-paginated-private.h"
#include "cairo-recording-surface-private.h"
#include "cairo-surface-subsurface-private.h"
#include "cairo-region-private.h"
 
typedef struct {
cairo_surface_t base;
 
cairo_surface_t *target;
 
cairo_bool_t first_op;
cairo_bool_t has_supported;
cairo_bool_t has_unsupported;
 
cairo_region_t supported_region;
cairo_region_t fallback_region;
cairo_box_t page_bbox;
 
cairo_bool_t has_ctm;
cairo_matrix_t ctm;
 
} cairo_analysis_surface_t;
 
cairo_int_status_t
_cairo_analysis_surface_merge_status (cairo_int_status_t status_a,
cairo_int_status_t status_b)
{
/* fatal errors should be checked and propagated at source */
assert (! _cairo_status_is_error (status_a));
assert (! _cairo_status_is_error (status_b));
 
/* return the most important status */
if (status_a == CAIRO_INT_STATUS_UNSUPPORTED ||
status_b == CAIRO_INT_STATUS_UNSUPPORTED)
return CAIRO_INT_STATUS_UNSUPPORTED;
 
if (status_a == CAIRO_INT_STATUS_IMAGE_FALLBACK ||
status_b == CAIRO_INT_STATUS_IMAGE_FALLBACK)
return CAIRO_INT_STATUS_IMAGE_FALLBACK;
 
if (status_a == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN ||
status_b == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN)
return CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN;
 
if (status_a == CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY ||
status_b == CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY)
return CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY;
 
/* at this point we have checked all the valid internal codes, so... */
assert (status_a == CAIRO_STATUS_SUCCESS &&
status_b == CAIRO_STATUS_SUCCESS);
 
return CAIRO_STATUS_SUCCESS;
}
 
static cairo_int_status_t
_analyze_recording_surface_pattern (cairo_analysis_surface_t *surface,
const cairo_pattern_t *pattern)
{
const cairo_surface_pattern_t *surface_pattern;
cairo_bool_t old_has_ctm;
cairo_matrix_t old_ctm, p2d;
cairo_status_t status;
cairo_surface_t *source;
 
assert (pattern->type == CAIRO_PATTERN_TYPE_SURFACE);
surface_pattern = (const cairo_surface_pattern_t *) pattern;
assert (surface_pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING);
 
old_ctm = surface->ctm;
old_has_ctm = surface->has_ctm;
 
p2d = pattern->matrix;
status = cairo_matrix_invert (&p2d);
assert (status == CAIRO_STATUS_SUCCESS);
 
cairo_matrix_multiply (&surface->ctm, &p2d, &surface->ctm);
surface->has_ctm = ! _cairo_matrix_is_identity (&surface->ctm);
 
source = surface_pattern->surface;
if (source->backend->type == CAIRO_SURFACE_TYPE_SUBSURFACE) {
cairo_surface_subsurface_t *sub = (cairo_surface_subsurface_t *) source;
source = sub->target;
}
 
status = _cairo_recording_surface_replay_and_create_regions (source, &surface->base);
 
surface->ctm = old_ctm;
surface->has_ctm = old_has_ctm;
 
return status;
}
 
static cairo_int_status_t
_add_operation (cairo_analysis_surface_t *surface,
cairo_rectangle_int_t *rect,
cairo_int_status_t backend_status)
{
cairo_int_status_t status;
cairo_box_t bbox;
 
if (rect->width == 0 || rect->height == 0) {
/* Even though the operation is not visible we must be careful
* to not allow unsupported operations to be replayed to the
* backend during CAIRO_PAGINATED_MODE_RENDER */
if (backend_status == CAIRO_STATUS_SUCCESS ||
backend_status == CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY)
{
return CAIRO_STATUS_SUCCESS;
}
else
{
return CAIRO_INT_STATUS_IMAGE_FALLBACK;
}
}
 
_cairo_box_from_rectangle (&bbox, rect);
 
if (surface->has_ctm) {
int tx, ty;
 
if (_cairo_matrix_is_integer_translation (&surface->ctm, &tx, &ty)) {
rect->x += tx;
rect->y += ty;
} else {
_cairo_matrix_transform_bounding_box_fixed (&surface->ctm,
&bbox, NULL);
 
if (bbox.p1.x == bbox.p2.x || bbox.p1.y == bbox.p2.y) {
/* Even though the operation is not visible we must be
* careful to not allow unsupported operations to be
* replayed to the backend during
* CAIRO_PAGINATED_MODE_RENDER */
if (backend_status == CAIRO_STATUS_SUCCESS ||
backend_status == CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY)
{
return CAIRO_STATUS_SUCCESS;
}
else
{
return CAIRO_INT_STATUS_IMAGE_FALLBACK;
}
}
 
_cairo_box_round_to_rectangle (&bbox, rect);
}
}
 
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
* region there is no benefit in emitting a native operation as
* the fallback image will be painted on top.
*/
if (cairo_region_contains_rectangle (&surface->fallback_region, rect) == CAIRO_REGION_OVERLAP_IN)
return CAIRO_INT_STATUS_IMAGE_FALLBACK;
 
if (backend_status == CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY) {
/* A status of CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY indicates
* that the backend only supports this operation if the
* transparency removed. If the extents of this operation does
* not intersect any other native operation, the operation is
* natively supported and the backend will blend the
* transparency into the white background.
*/
if (cairo_region_contains_rectangle (&surface->supported_region, rect) == CAIRO_REGION_OVERLAP_OUT)
backend_status = CAIRO_STATUS_SUCCESS;
}
 
if (backend_status == CAIRO_STATUS_SUCCESS) {
/* Add the operation to the supported region. Operations in
* this region will be emitted as native operations.
*/
surface->has_supported = TRUE;
return cairo_region_union_rectangle (&surface->supported_region, rect);
}
 
/* Add the operation to the unsupported region. This region will
* be painted as an image after all native operations have been
* emitted.
*/
surface->has_unsupported = TRUE;
status = cairo_region_union_rectangle (&surface->fallback_region, rect);
 
/* The status CAIRO_INT_STATUS_IMAGE_FALLBACK is used to indicate
* unsupported operations to the recording surface as using
* CAIRO_INT_STATUS_UNSUPPORTED would cause cairo-surface to
* invoke the cairo-surface-fallback path then return
* CAIRO_STATUS_SUCCESS.
*/
if (status == CAIRO_STATUS_SUCCESS)
return CAIRO_INT_STATUS_IMAGE_FALLBACK;
else
return status;
}
 
static cairo_status_t
_cairo_analysis_surface_finish (void *abstract_surface)
{
cairo_analysis_surface_t *surface = (cairo_analysis_surface_t *) abstract_surface;
 
_cairo_region_fini (&surface->supported_region);
_cairo_region_fini (&surface->fallback_region);
 
cairo_surface_destroy (surface->target);
 
return CAIRO_STATUS_SUCCESS;
}
 
static cairo_bool_t
_cairo_analysis_surface_get_extents (void *abstract_surface,
cairo_rectangle_int_t *rectangle)
{
cairo_analysis_surface_t *surface = abstract_surface;
 
return _cairo_surface_get_extents (surface->target, rectangle);
}
 
static void
_rectangle_intersect_clip (cairo_rectangle_int_t *extents, cairo_clip_t *clip)
{
const cairo_rectangle_int_t *clip_extents;
cairo_bool_t is_empty;
 
clip_extents = NULL;
if (clip != NULL)
clip_extents = _cairo_clip_get_extents (clip);
 
if (clip_extents != NULL)
is_empty = _cairo_rectangle_intersect (extents, clip_extents);
}
 
static void
_cairo_analysis_surface_operation_extents (cairo_analysis_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_clip_t *clip,
cairo_rectangle_int_t *extents)
{
cairo_bool_t is_empty;
 
is_empty = _cairo_surface_get_extents (&surface->base, extents);
 
if (_cairo_operator_bounded_by_source (op)) {
cairo_rectangle_int_t source_extents;
 
_cairo_pattern_get_extents (source, &source_extents);
is_empty = _cairo_rectangle_intersect (extents, &source_extents);
}
 
_rectangle_intersect_clip (extents, clip);
}
 
static cairo_int_status_t
_cairo_analysis_surface_paint (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_clip_t *clip)
{
cairo_analysis_surface_t *surface = abstract_surface;
cairo_status_t backend_status;
cairo_rectangle_int_t extents;
 
if (surface->target->backend->paint == NULL) {
backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
} else {
backend_status =
surface->target->backend->paint (surface->target,
op, source, clip);
if (_cairo_status_is_error (backend_status))
return backend_status;
}
 
if (backend_status == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN)
backend_status = _analyze_recording_surface_pattern (surface, source);
 
_cairo_analysis_surface_operation_extents (surface,
op, source, clip,
&extents);
 
return _add_operation (surface, &extents, backend_status);
}
 
static cairo_int_status_t
_cairo_analysis_surface_mask (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_pattern_t *mask,
cairo_clip_t *clip)
{
cairo_analysis_surface_t *surface = abstract_surface;
cairo_int_status_t backend_status;
cairo_rectangle_int_t extents;
cairo_bool_t is_empty;
 
if (surface->target->backend->mask == NULL) {
backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
} else {
backend_status =
surface->target->backend->mask (surface->target,
op, source, mask, clip);
if (_cairo_status_is_error (backend_status))
return backend_status;
}
 
if (backend_status == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN) {
cairo_int_status_t backend_source_status = CAIRO_STATUS_SUCCESS;
cairo_int_status_t backend_mask_status = CAIRO_STATUS_SUCCESS;
 
if (source->type == CAIRO_PATTERN_TYPE_SURFACE) {
const cairo_surface_pattern_t *surface_pattern = (const cairo_surface_pattern_t *) source;
if (_cairo_surface_is_recording (surface_pattern->surface)) {
backend_source_status =
_analyze_recording_surface_pattern (surface, source);
if (_cairo_status_is_error (backend_source_status))
return backend_source_status;
}
}
 
if (mask->type == CAIRO_PATTERN_TYPE_SURFACE) {
cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) mask;
if (_cairo_surface_is_recording (surface_pattern->surface)) {
backend_mask_status =
_analyze_recording_surface_pattern (surface, mask);
if (_cairo_status_is_error (backend_mask_status))
return backend_mask_status;
}
}
 
backend_status =
_cairo_analysis_surface_merge_status (backend_source_status,
backend_mask_status);
}
 
_cairo_analysis_surface_operation_extents (surface,
op, source, clip,
&extents);
 
if (_cairo_operator_bounded_by_mask (op)) {
cairo_rectangle_int_t mask_extents;
 
_cairo_pattern_get_extents (mask, &mask_extents);
is_empty = _cairo_rectangle_intersect (&extents, &mask_extents);
 
}
 
return _add_operation (surface, &extents, backend_status);
}
 
static cairo_int_status_t
_cairo_analysis_surface_stroke (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_path_fixed_t *path,
const cairo_stroke_style_t *style,
const cairo_matrix_t *ctm,
const cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
cairo_clip_t *clip)
{
cairo_analysis_surface_t *surface = abstract_surface;
cairo_status_t backend_status;
cairo_rectangle_int_t extents;
cairo_bool_t is_empty;
 
if (surface->target->backend->stroke == NULL) {
backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
} else {
backend_status =
surface->target->backend->stroke (surface->target, op,
source, path, style,
ctm, ctm_inverse,
tolerance, antialias,
clip);
if (_cairo_status_is_error (backend_status))
return backend_status;
}
 
if (backend_status == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN)
backend_status = _analyze_recording_surface_pattern (surface, source);
 
_cairo_analysis_surface_operation_extents (surface,
op, source, clip,
&extents);
 
if (_cairo_operator_bounded_by_mask (op)) {
cairo_rectangle_int_t mask_extents;
cairo_status_t status;
 
status = _cairo_path_fixed_stroke_extents (path, style,
ctm, ctm_inverse,
tolerance,
&mask_extents);
if (unlikely (status))
return status;
 
is_empty = _cairo_rectangle_intersect (&extents, &mask_extents);
}
 
return _add_operation (surface, &extents, backend_status);
}
 
static cairo_int_status_t
_cairo_analysis_surface_fill (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias,
cairo_clip_t *clip)
{
cairo_analysis_surface_t *surface = abstract_surface;
cairo_status_t backend_status;
cairo_rectangle_int_t extents;
cairo_bool_t is_empty;
 
if (surface->target->backend->fill == NULL) {
backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
} else {
backend_status =
surface->target->backend->fill (surface->target, op,
source, path, fill_rule,
tolerance, antialias,
clip);
if (_cairo_status_is_error (backend_status))
return backend_status;
}
 
if (backend_status == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN)
backend_status = _analyze_recording_surface_pattern (surface, source);
 
_cairo_analysis_surface_operation_extents (surface,
op, source, clip,
&extents);
 
if (_cairo_operator_bounded_by_mask (op)) {
cairo_rectangle_int_t mask_extents;
 
_cairo_path_fixed_fill_extents (path, fill_rule, tolerance,
&mask_extents);
 
is_empty = _cairo_rectangle_intersect (&extents, &mask_extents);
}
 
return _add_operation (surface, &extents, backend_status);
}
 
static cairo_int_status_t
_cairo_analysis_surface_show_glyphs (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font,
cairo_clip_t *clip,
int *remaining_glyphs)
{
cairo_analysis_surface_t *surface = abstract_surface;
cairo_status_t status, backend_status;
cairo_rectangle_int_t extents, glyph_extents;
cairo_bool_t is_empty;
 
/* Adapted from _cairo_surface_show_glyphs */
if (surface->target->backend->show_glyphs != NULL) {
backend_status =
surface->target->backend->show_glyphs (surface->target, op,
source,
glyphs, num_glyphs,
scaled_font,
clip,
remaining_glyphs);
if (_cairo_status_is_error (backend_status))
return backend_status;
}
else if (surface->target->backend->show_text_glyphs != NULL)
{
backend_status =
surface->target->backend->show_text_glyphs (surface->target, op,
source,
NULL, 0,
glyphs, num_glyphs,
NULL, 0,
FALSE,
scaled_font,
clip);
if (_cairo_status_is_error (backend_status))
return backend_status;
}
else
{
backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
}
 
if (backend_status == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN)
backend_status = _analyze_recording_surface_pattern (surface, source);
 
_cairo_analysis_surface_operation_extents (surface,
op, source, clip,
&extents);
 
if (_cairo_operator_bounded_by_mask (op)) {
status = _cairo_scaled_font_glyph_device_extents (scaled_font,
glyphs,
num_glyphs,
&glyph_extents,
NULL);
if (unlikely (status))
return status;
 
is_empty = _cairo_rectangle_intersect (&extents, &glyph_extents);
}
 
return _add_operation (surface, &extents, backend_status);
}
 
static cairo_bool_t
_cairo_analysis_surface_has_show_text_glyphs (void *abstract_surface)
{
cairo_analysis_surface_t *surface = abstract_surface;
 
return cairo_surface_has_show_text_glyphs (surface->target);
}
 
static cairo_int_status_t
_cairo_analysis_surface_show_text_glyphs (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const char *utf8,
int utf8_len,
cairo_glyph_t *glyphs,
int num_glyphs,
const cairo_text_cluster_t *clusters,
int num_clusters,
cairo_text_cluster_flags_t cluster_flags,
cairo_scaled_font_t *scaled_font,
cairo_clip_t *clip)
{
cairo_analysis_surface_t *surface = abstract_surface;
cairo_status_t status, backend_status;
cairo_rectangle_int_t extents, glyph_extents;
cairo_bool_t is_empty;
 
/* Adapted from _cairo_surface_show_glyphs */
backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
if (surface->target->backend->show_text_glyphs != NULL) {
backend_status =
surface->target->backend->show_text_glyphs (surface->target, op,
source,
utf8, utf8_len,
glyphs, num_glyphs,
clusters, num_clusters,
cluster_flags,
scaled_font,
clip);
if (_cairo_status_is_error (backend_status))
return backend_status;
}
if (backend_status == CAIRO_INT_STATUS_UNSUPPORTED &&
surface->target->backend->show_glyphs != NULL)
{
int remaining_glyphs = num_glyphs;
backend_status =
surface->target->backend->show_glyphs (surface->target, op,
source,
glyphs, num_glyphs,
scaled_font,
clip,
&remaining_glyphs);
if (_cairo_status_is_error (backend_status))
return backend_status;
 
glyphs += num_glyphs - remaining_glyphs;
num_glyphs = remaining_glyphs;
if (remaining_glyphs == 0)
backend_status = CAIRO_STATUS_SUCCESS;
}
 
if (backend_status == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN)
backend_status = _analyze_recording_surface_pattern (surface, source);
 
_cairo_analysis_surface_operation_extents (surface,
op, source, clip,
&extents);
 
if (_cairo_operator_bounded_by_mask (op)) {
status = _cairo_scaled_font_glyph_device_extents (scaled_font,
glyphs,
num_glyphs,
&glyph_extents,
NULL);
if (unlikely (status))
return status;
 
is_empty = _cairo_rectangle_intersect (&extents, &glyph_extents);
}
 
return _add_operation (surface, &extents, backend_status);
}
 
static const cairo_surface_backend_t cairo_analysis_surface_backend = {
CAIRO_INTERNAL_SURFACE_TYPE_ANALYSIS,
NULL, /* create_similar */
_cairo_analysis_surface_finish,
NULL, /* acquire_source_image */
NULL, /* release_source_image */
NULL, /* acquire_dest_image */
NULL, /* release_dest_image */
NULL, /* clone_similar */
NULL, /* composite */
NULL, /* fill_rectangles */
NULL, /* composite_trapezoids */
NULL, /* create_span_renderer */
NULL, /* check_span_renderer */
NULL, /* copy_page */
NULL, /* show_page */
_cairo_analysis_surface_get_extents,
NULL, /* old_show_glyphs */
NULL, /* get_font_options */
NULL, /* flush */
NULL, /* mark_dirty_rectangle */
NULL, /* scaled_font_fini */
NULL, /* scaled_glyph_fini */
_cairo_analysis_surface_paint,
_cairo_analysis_surface_mask,
_cairo_analysis_surface_stroke,
_cairo_analysis_surface_fill,
_cairo_analysis_surface_show_glyphs,
NULL, /* snapshot */
NULL, /* is_similar */
NULL, /* fill_stroke */
NULL, /* create_solid_pattern_surface */
NULL, /* can_repaint_solid_pattern_surface */
_cairo_analysis_surface_has_show_text_glyphs,
_cairo_analysis_surface_show_text_glyphs
};
 
cairo_surface_t *
_cairo_analysis_surface_create (cairo_surface_t *target)
{
cairo_analysis_surface_t *surface;
cairo_status_t status;
 
status = target->status;
if (unlikely (status))
return _cairo_surface_create_in_error (status);
 
surface = malloc (sizeof (cairo_analysis_surface_t));
if (unlikely (surface == NULL))
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
 
/* I believe the content type here is truly arbitrary. I'm quite
* sure nothing will ever use this value. */
_cairo_surface_init (&surface->base,
&cairo_analysis_surface_backend,
NULL, /* device */
CAIRO_CONTENT_COLOR_ALPHA);
 
cairo_matrix_init_identity (&surface->ctm);
surface->has_ctm = FALSE;
 
surface->target = cairo_surface_reference (target);
surface->first_op = TRUE;
surface->has_supported = FALSE;
surface->has_unsupported = FALSE;
 
_cairo_region_init (&surface->supported_region);
_cairo_region_init (&surface->fallback_region);
 
surface->page_bbox.p1.x = 0;
surface->page_bbox.p1.y = 0;
surface->page_bbox.p2.x = 0;
surface->page_bbox.p2.y = 0;
 
return &surface->base;
}
 
void
_cairo_analysis_surface_set_ctm (cairo_surface_t *abstract_surface,
const cairo_matrix_t *ctm)
{
cairo_analysis_surface_t *surface;
 
if (abstract_surface->status)
return;
 
surface = (cairo_analysis_surface_t *) abstract_surface;
 
surface->ctm = *ctm;
surface->has_ctm = ! _cairo_matrix_is_identity (&surface->ctm);
}
 
void
_cairo_analysis_surface_get_ctm (cairo_surface_t *abstract_surface,
cairo_matrix_t *ctm)
{
cairo_analysis_surface_t *surface = (cairo_analysis_surface_t *) abstract_surface;
 
*ctm = surface->ctm;
}
 
 
cairo_region_t *
_cairo_analysis_surface_get_supported (cairo_surface_t *abstract_surface)
{
cairo_analysis_surface_t *surface = (cairo_analysis_surface_t *) abstract_surface;
 
return &surface->supported_region;
}
 
cairo_region_t *
_cairo_analysis_surface_get_unsupported (cairo_surface_t *abstract_surface)
{
cairo_analysis_surface_t *surface = (cairo_analysis_surface_t *) abstract_surface;
 
return &surface->fallback_region;
}
 
cairo_bool_t
_cairo_analysis_surface_has_supported (cairo_surface_t *abstract_surface)
{
cairo_analysis_surface_t *surface = (cairo_analysis_surface_t *) abstract_surface;
 
return surface->has_supported;
}
 
cairo_bool_t
_cairo_analysis_surface_has_unsupported (cairo_surface_t *abstract_surface)
{
cairo_analysis_surface_t *surface = (cairo_analysis_surface_t *) abstract_surface;
 
return surface->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;
}
 
/* null surface type: a surface that does nothing (has no side effects, yay!) */
 
static cairo_int_status_t
_return_success (void)
{
return CAIRO_STATUS_SUCCESS;
}
 
/* These typedefs are just to silence the compiler... */
typedef cairo_int_status_t
(*_paint_func) (void *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_clip_t *clip);
 
typedef cairo_int_status_t
(*_mask_func) (void *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_pattern_t *mask,
cairo_clip_t *clip);
 
typedef cairo_int_status_t
(*_stroke_func) (void *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_path_fixed_t *path,
const cairo_stroke_style_t *style,
const cairo_matrix_t *ctm,
const cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
cairo_clip_t *clip);
 
typedef cairo_int_status_t
(*_fill_func) (void *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias,
cairo_clip_t *clip);
 
typedef cairo_int_status_t
(*_show_glyphs_func) (void *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font,
cairo_clip_t *clip,
int *remaining_glyphs);
 
static const cairo_surface_backend_t cairo_null_surface_backend = {
CAIRO_INTERNAL_SURFACE_TYPE_NULL,
 
NULL, /* create_similar */
NULL, /* finish */
NULL, /* acquire_source_image */
NULL, /* release_source_image */
NULL, /* acquire_dest_image */
NULL, /* release_dest_image */
NULL, /* clone_similar */
NULL, /* composite */
NULL, /* fill_rectangles */
NULL, /* composite_trapezoids */
NULL, /* create_span_renderer */
NULL, /* check_span_renderer */
NULL, /* copy_page */
NULL, /* show_page */
NULL, /* get_extents */
NULL, /* old_show_glyphs */
NULL, /* get_font_options */
NULL, /* flush */
NULL, /* mark_dirty_rectangle */
NULL, /* scaled_font_fini */
NULL, /* scaled_glyph_fini */
(_paint_func) _return_success, /* paint */
(_mask_func) _return_success, /* mask */
(_stroke_func) _return_success, /* stroke */
(_fill_func) _return_success, /* fill */
(_show_glyphs_func) _return_success, /* show_glyphs */
NULL, /* snapshot */
NULL, /* is_similar */
NULL, /* fill_stroke */
NULL, /* create_solid_pattern_surface */
NULL, /* can_repaint_solid_pattern_surface */
NULL, /* has_show_text_glyphs */
NULL /* show_text_glyphs */
};
 
cairo_surface_t *
_cairo_null_surface_create (cairo_content_t content)
{
cairo_surface_t *surface;
 
surface = malloc (sizeof (cairo_surface_t));
if (unlikely (surface == NULL)) {
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
}
 
_cairo_surface_init (surface,
&cairo_null_surface_backend,
NULL, /* device */
content);
 
return surface;
}
/programs/develop/libraries/cairo/src/cairo-arc-private.h
0,0 → 1,57
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2005 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
* Carl D. Worth <cworth@redhat.com>
*/
 
#ifndef CAIRO_ARC_PRIVATE_H
#define CAIRO_ARC_PRIVATE_H
 
#include "cairoint.h"
 
cairo_private void
_cairo_arc_path (cairo_t *cr,
double xc,
double yc,
double radius,
double angle1,
double angle2);
 
cairo_private void
_cairo_arc_path_negative (cairo_t *cr,
double xc,
double yc,
double radius,
double angle1,
double angle2);
 
#endif /* CAIRO_ARC_PRIVATE_H */
/programs/develop/libraries/cairo/src/cairo-arc.c
0,0 → 1,296
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2002 University of Southern California
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
*/
 
#include "cairoint.h"
 
#include "cairo-arc-private.h"
 
/* Spline deviation from the circle in radius would be given by:
 
error = sqrt (x**2 + y**2) - 1
 
A simpler error function to work with is:
 
e = x**2 + y**2 - 1
 
From "Good approximation of circles by curvature-continuous Bezier
curves", Tor Dokken and Morten Daehlen, Computer Aided Geometric
Design 8 (1990) 22-41, we learn:
 
abs (max(e)) = 4/27 * sin**6(angle/4) / cos**2(angle/4)
 
and
abs (error) =~ 1/2 * e
 
Of course, this error value applies only for the particular spline
approximation that is used in _cairo_gstate_arc_segment.
*/
static double
_arc_error_normalized (double angle)
{
return 2.0/27.0 * pow (sin (angle / 4), 6) / pow (cos (angle / 4), 2);
}
 
static double
_arc_max_angle_for_tolerance_normalized (double tolerance)
{
double angle, error;
int i;
 
/* Use table lookup to reduce search time in most cases. */
struct {
double angle;
double error;
} table[] = {
{ M_PI / 1.0, 0.0185185185185185036127 },
{ M_PI / 2.0, 0.000272567143730179811158 },
{ M_PI / 3.0, 2.38647043651461047433e-05 },
{ M_PI / 4.0, 4.2455377443222443279e-06 },
{ M_PI / 5.0, 1.11281001494389081528e-06 },
{ M_PI / 6.0, 3.72662000942734705475e-07 },
{ M_PI / 7.0, 1.47783685574284411325e-07 },
{ M_PI / 8.0, 6.63240432022601149057e-08 },
{ M_PI / 9.0, 3.2715520137536980553e-08 },
{ M_PI / 10.0, 1.73863223499021216974e-08 },
{ M_PI / 11.0, 9.81410988043554039085e-09 },
};
int table_size = ARRAY_LENGTH (table);
 
for (i = 0; i < table_size; i++)
if (table[i].error < tolerance)
return table[i].angle;
 
++i;
do {
angle = M_PI / i++;
error = _arc_error_normalized (angle);
} while (error > tolerance);
 
return angle;
}
 
static int
_arc_segments_needed (double angle,
double radius,
cairo_matrix_t *ctm,
double tolerance)
{
double major_axis, max_angle;
 
/* the error is amplified by at most the length of the
* major axis of the circle; see cairo-pen.c for a more detailed analysis
* of this. */
major_axis = _cairo_matrix_transformed_circle_major_axis (ctm, radius);
max_angle = _arc_max_angle_for_tolerance_normalized (tolerance / major_axis);
 
return ceil (fabs (angle) / max_angle);
}
 
/* We want to draw a single spline approximating a circular arc radius
R from angle A to angle B. Since we want a symmetric spline that
matches the endpoints of the arc in position and slope, we know
that the spline control points must be:
 
(R * cos(A), R * sin(A))
(R * cos(A) - h * sin(A), R * sin(A) + h * cos (A))
(R * cos(B) + h * sin(B), R * sin(B) - h * cos (B))
(R * cos(B), R * sin(B))
 
for some value of h.
 
"Approximation of circular arcs by cubic poynomials", Michael
Goldapp, Computer Aided Geometric Design 8 (1991) 227-238, provides
various values of h along with error analysis for each.
 
From that paper, a very practical value of h is:
 
h = 4/3 * tan(angle/4)
 
This value does not give the spline with minimal error, but it does
provide a very good approximation, (6th-order convergence), and the
error expression is quite simple, (see the comment for
_arc_error_normalized).
*/
static void
_cairo_arc_segment (cairo_t *cr,
double xc,
double yc,
double radius,
double angle_A,
double angle_B)
{
double r_sin_A, r_cos_A;
double r_sin_B, r_cos_B;
double h;
 
r_sin_A = radius * sin (angle_A);
r_cos_A = radius * cos (angle_A);
r_sin_B = radius * sin (angle_B);
r_cos_B = radius * cos (angle_B);
 
h = 4.0/3.0 * tan ((angle_B - angle_A) / 4.0);
 
cairo_curve_to (cr,
xc + r_cos_A - h * r_sin_A,
yc + r_sin_A + h * r_cos_A,
xc + r_cos_B + h * r_sin_B,
yc + r_sin_B - h * r_cos_B,
xc + r_cos_B,
yc + r_sin_B);
}
 
static void
_cairo_arc_in_direction (cairo_t *cr,
double xc,
double yc,
double radius,
double angle_min,
double angle_max,
cairo_direction_t dir)
{
if (cairo_status (cr))
return;
 
while (angle_max - angle_min > 4 * M_PI)
angle_max -= 2 * M_PI;
 
/* Recurse if drawing arc larger than pi */
if (angle_max - angle_min > M_PI) {
double angle_mid = angle_min + (angle_max - angle_min) / 2.0;
if (dir == CAIRO_DIRECTION_FORWARD) {
_cairo_arc_in_direction (cr, xc, yc, radius,
angle_min, angle_mid,
dir);
 
_cairo_arc_in_direction (cr, xc, yc, radius,
angle_mid, angle_max,
dir);
} else {
_cairo_arc_in_direction (cr, xc, yc, radius,
angle_mid, angle_max,
dir);
 
_cairo_arc_in_direction (cr, xc, yc, radius,
angle_min, angle_mid,
dir);
}
} else if (angle_max != angle_min) {
cairo_matrix_t ctm;
int i, segments;
double angle, angle_step;
 
cairo_get_matrix (cr, &ctm);
segments = _arc_segments_needed (angle_max - angle_min,
radius, &ctm,
cairo_get_tolerance (cr));
angle_step = (angle_max - angle_min) / (double) segments;
 
if (dir == CAIRO_DIRECTION_FORWARD) {
angle = angle_min;
} else {
angle = angle_max;
angle_step = - angle_step;
}
 
for (i = 0; i < segments; i++, angle += angle_step) {
_cairo_arc_segment (cr, xc, yc,
radius,
angle,
angle + angle_step);
}
} else {
cairo_line_to (cr,
xc + radius * cos (angle_min),
yc + radius * sin (angle_min));
}
}
 
/**
* _cairo_arc_path
* @cr: a cairo context
* @xc: X position of the center of the arc
* @yc: Y position of the center of the arc
* @radius: the radius of the arc
* @angle1: the start angle, in radians
* @angle2: the end angle, in radians
*
* Compute a path for the given arc and append it onto the current
* path within @cr. The arc will be accurate within the current
* tolerance and given the current transformation.
**/
void
_cairo_arc_path (cairo_t *cr,
double xc,
double yc,
double radius,
double angle1,
double angle2)
{
_cairo_arc_in_direction (cr, xc, yc,
radius,
angle1, angle2,
CAIRO_DIRECTION_FORWARD);
}
 
/**
* _cairo_arc_path_negative:
* @xc: X position of the center of the arc
* @yc: Y position of the center of the arc
* @radius: the radius of the arc
* @angle1: the start angle, in radians
* @angle2: the end angle, in radians
* @ctm: the current transformation matrix
* @tolerance: the current tolerance value
* @path: the path onto which the arc will be appended
*
* Compute a path for the given arc (defined in the negative
* direction) and append it onto the current path within @cr. The arc
* will be accurate within the current tolerance and given the current
* transformation.
**/
void
_cairo_arc_path_negative (cairo_t *cr,
double xc,
double yc,
double radius,
double angle1,
double angle2)
{
_cairo_arc_in_direction (cr, xc, yc,
radius,
angle2, angle1,
CAIRO_DIRECTION_REVERSE);
}
/programs/develop/libraries/cairo/src/cairo-array.c
0,0 → 1,528
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2004 Red Hat, Inc
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Kristian Høgsberg <krh@redhat.com>
* Carl Worth <cworth@cworth.org>
*/
 
#include "cairoint.h"
#include "cairo-error-private.h"
 
/**
* _cairo_array_init:
*
* Initialize a new #cairo_array_t object to store objects each of size
* @element_size.
*
* The #cairo_array_t object provides grow-by-doubling storage. It
* never interprets the data passed to it, nor does it provide any
* sort of callback mechanism for freeing resources held onto by
* stored objects.
*
* When finished using the array, _cairo_array_fini() should be
* called to free resources allocated during use of the array.
**/
void
_cairo_array_init (cairo_array_t *array, int element_size)
{
array->size = 0;
array->num_elements = 0;
array->element_size = element_size;
array->elements = NULL;
 
array->is_snapshot = FALSE;
}
 
/**
* _cairo_array_init_snapshot:
* @array: A #cairo_array_t to be initialized as a snapshot
* @other: The #cairo_array_t from which to create the snapshot
*
* Initialize @array as an immutable copy of @other. It is an error to
* call an array-modifying function (other than _cairo_array_fini) on
* @array after calling this function.
**/
void
_cairo_array_init_snapshot (cairo_array_t *array,
const cairo_array_t *other)
{
array->size = other->size;
array->num_elements = other->num_elements;
array->element_size = other->element_size;
array->elements = other->elements;
 
array->is_snapshot = TRUE;
}
 
/**
* _cairo_array_fini:
* @array: A #cairo_array_t
*
* Free all resources associated with @array. After this call, @array
* should not be used again without a subsequent call to
* _cairo_array_init() again first.
**/
void
_cairo_array_fini (cairo_array_t *array)
{
if (array->is_snapshot)
return;
 
if (array->elements) {
free (* array->elements);
free (array->elements);
}
}
 
/**
* _cairo_array_grow_by:
* @array: a #cairo_array_t
*
* Increase the size of @array (if needed) so that there are at least
* @additional free spaces in the array. The actual size of the array
* is always increased by doubling as many times as necessary.
**/
cairo_status_t
_cairo_array_grow_by (cairo_array_t *array, unsigned int additional)
{
char *new_elements;
unsigned int old_size = array->size;
unsigned int required_size = array->num_elements + additional;
unsigned int new_size;
 
assert (! array->is_snapshot);
 
/* check for integer overflow */
if (required_size > INT_MAX || required_size < array->num_elements)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
if (CAIRO_INJECT_FAULT ())
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
if (required_size <= old_size)
return CAIRO_STATUS_SUCCESS;
 
if (old_size == 0)
new_size = 1;
else
new_size = old_size * 2;
 
while (new_size < required_size)
new_size = new_size * 2;
 
if (array->elements == NULL) {
array->elements = malloc (sizeof (char *));
if (unlikely (array->elements == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
*array->elements = NULL;
}
 
array->size = new_size;
new_elements = _cairo_realloc_ab (*array->elements,
array->size, array->element_size);
 
if (unlikely (new_elements == NULL)) {
array->size = old_size;
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
 
*array->elements = new_elements;
 
return CAIRO_STATUS_SUCCESS;
}
 
/**
* _cairo_array_truncate:
* @array: a #cairo_array_t
*
* Truncate size of the array to @num_elements if less than the
* current size. No memory is actually freed. The stored objects
* beyond @num_elements are simply "forgotten".
**/
void
_cairo_array_truncate (cairo_array_t *array, unsigned int num_elements)
{
assert (! array->is_snapshot);
 
if (num_elements < array->num_elements)
array->num_elements = num_elements;
}
 
/**
* _cairo_array_index:
* @array: a #cairo_array_t
* Returns: A pointer to the object stored at @index.
*
* If the resulting value is assigned to a pointer to an object of the same
* element_size as initially passed to _cairo_array_init() then that
* pointer may be used for further direct indexing with []. For
* example:
*
* <informalexample><programlisting>
* cairo_array_t array;
* double *values;
*
* _cairo_array_init (&array, sizeof(double));
* ... calls to _cairo_array_append() here ...
*
* values = _cairo_array_index (&array, 0);
* for (i = 0; i < _cairo_array_num_elements (&array); i++)
* ... use values[i] here ...
* </programlisting></informalexample>
**/
void *
_cairo_array_index (cairo_array_t *array, unsigned int index)
{
/* We allow an index of 0 for the no-elements case.
* This makes for cleaner calling code which will often look like:
*
* elements = _cairo_array_index (array, num_elements);
* for (i=0; i < num_elements; i++) {
* ... use elements[i] here ...
* }
*
* which in the num_elements==0 case gets the NULL pointer here,
* but never dereferences it.
*/
if (index == 0 && array->num_elements == 0)
return NULL;
 
assert (index < array->num_elements);
 
return (void *) &(*array->elements)[index * array->element_size];
}
 
/**
* _cairo_array_copy_element:
* @array: a #cairo_array_t
*
* Copy a single element out of the array from index @index into the
* location pointed to by @dst.
**/
void
_cairo_array_copy_element (cairo_array_t *array, int index, void *dst)
{
memcpy (dst, _cairo_array_index (array, index), array->element_size);
}
 
/**
* _cairo_array_append:
* @array: a #cairo_array_t
*
* Append a single item onto the array by growing the array by at
* least one element, then copying element_size bytes from @element
* into the array. The address of the resulting object within the
* array can be determined with:
*
* _cairo_array_index (array, _cairo_array_num_elements (array) - 1);
*
* Return value: %CAIRO_STATUS_SUCCESS if successful or
* %CAIRO_STATUS_NO_MEMORY if insufficient memory is available for the
* operation.
**/
cairo_status_t
_cairo_array_append (cairo_array_t *array,
const void *element)
{
assert (! array->is_snapshot);
 
return _cairo_array_append_multiple (array, element, 1);
}
 
/**
* _cairo_array_append_multiple:
* @array: a #cairo_array_t
*
* Append one or more items onto the array by growing the array by
* @num_elements, then copying @num_elements * element_size bytes from
* @elements into the array.
*
* Return value: %CAIRO_STATUS_SUCCESS if successful or
* %CAIRO_STATUS_NO_MEMORY if insufficient memory is available for the
* operation.
**/
cairo_status_t
_cairo_array_append_multiple (cairo_array_t *array,
const void *elements,
int num_elements)
{
cairo_status_t status;
void *dest;
 
assert (! array->is_snapshot);
 
status = _cairo_array_allocate (array, num_elements, &dest);
if (unlikely (status))
return status;
 
memcpy (dest, elements, num_elements * array->element_size);
 
return CAIRO_STATUS_SUCCESS;
}
 
/**
* _cairo_array_allocate:
* @array: a #cairo_array_t
*
* Allocate space at the end of the array for @num_elements additional
* elements, providing the address of the new memory chunk in
* @elements. This memory will be unitialized, but will be accounted
* for in the return value of _cairo_array_num_elements().
*
* Return value: %CAIRO_STATUS_SUCCESS if successful or
* %CAIRO_STATUS_NO_MEMORY if insufficient memory is available for the
* operation.
**/
cairo_status_t
_cairo_array_allocate (cairo_array_t *array,
unsigned int num_elements,
void **elements)
{
cairo_status_t status;
 
assert (! array->is_snapshot);
 
status = _cairo_array_grow_by (array, num_elements);
if (unlikely (status))
return status;
 
assert (array->num_elements + num_elements <= array->size);
 
*elements = &(*array->elements)[array->num_elements * array->element_size];
 
array->num_elements += num_elements;
 
return CAIRO_STATUS_SUCCESS;
}
 
/**
* _cairo_array_num_elements:
* @array: a #cairo_array_t
* Returns: The number of elements stored in @array.
*
* This space was left intentionally blank, but gtk-doc filled it.
**/
int
_cairo_array_num_elements (cairo_array_t *array)
{
return array->num_elements;
}
 
/**
* _cairo_array_size:
* @array: a #cairo_array_t
* Returns: The number of elements for which there is currently space
* allocated in @array.
*
* This space was left intentionally blank, but gtk-doc filled it.
**/
int
_cairo_array_size (cairo_array_t *array)
{
return array->size;
}
 
/**
* _cairo_user_data_array_init:
* @array: a #cairo_user_data_array_t
*
* Initializes a #cairo_user_data_array_t structure for future
* use. After initialization, the array has no keys. Call
* _cairo_user_data_array_fini() to free any allocated memory
* when done using the array.
**/
void
_cairo_user_data_array_init (cairo_user_data_array_t *array)
{
_cairo_array_init (array, sizeof (cairo_user_data_slot_t));
}
 
/**
* _cairo_user_data_array_fini:
* @array: a #cairo_user_data_array_t
*
* Destroys all current keys in the user data array and deallocates
* any memory allocated for the array itself.
**/
void
_cairo_user_data_array_fini (cairo_user_data_array_t *array)
{
unsigned int num_slots;
 
num_slots = array->num_elements;
if (num_slots) {
cairo_user_data_slot_t *slots;
 
slots = _cairo_array_index (array, 0);
do {
if (slots->user_data != NULL && slots->destroy != NULL)
slots->destroy (slots->user_data);
slots++;
} while (--num_slots);
}
 
_cairo_array_fini (array);
}
 
/**
* _cairo_user_data_array_get_data:
* @array: a #cairo_user_data_array_t
* @key: the address of the #cairo_user_data_key_t the user data was
* attached to
*
* Returns user data previously attached using the specified
* key. If no user data has been attached with the given key this
* function returns %NULL.
*
* Return value: the user data previously attached or %NULL.
**/
void *
_cairo_user_data_array_get_data (cairo_user_data_array_t *array,
const cairo_user_data_key_t *key)
{
int i, num_slots;
cairo_user_data_slot_t *slots;
 
/* We allow this to support degenerate objects such as cairo_surface_nil. */
if (array == NULL)
return NULL;
 
num_slots = array->num_elements;
slots = _cairo_array_index (array, 0);
for (i = 0; i < num_slots; i++) {
if (slots[i].key == key)
return slots[i].user_data;
}
 
return NULL;
}
 
/**
* _cairo_user_data_array_set_data:
* @array: a #cairo_user_data_array_t
* @key: the address of a #cairo_user_data_key_t to attach the user data to
* @user_data: the user data to attach
* @destroy: a #cairo_destroy_func_t which will be called when the
* user data array is destroyed or when new user data is attached using the
* same key.
*
* Attaches user data to a user data array. To remove user data,
* call this function with the key that was used to set it and %NULL
* for @data.
*
* Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY if a
* slot could not be allocated for the user data.
**/
cairo_status_t
_cairo_user_data_array_set_data (cairo_user_data_array_t *array,
const cairo_user_data_key_t *key,
void *user_data,
cairo_destroy_func_t destroy)
{
cairo_status_t status;
int i, num_slots;
cairo_user_data_slot_t *slots, *slot, new_slot;
 
if (user_data) {
new_slot.key = key;
new_slot.user_data = user_data;
new_slot.destroy = destroy;
} else {
new_slot.key = NULL;
new_slot.user_data = NULL;
new_slot.destroy = NULL;
}
 
slot = NULL;
num_slots = array->num_elements;
slots = _cairo_array_index (array, 0);
for (i = 0; i < num_slots; i++) {
if (slots[i].key == key) {
slot = &slots[i];
if (slot->destroy && slot->user_data)
slot->destroy (slot->user_data);
break;
}
if (user_data && slots[i].user_data == NULL) {
slot = &slots[i]; /* Have to keep searching for an exact match */
}
}
 
if (slot) {
*slot = new_slot;
return CAIRO_STATUS_SUCCESS;
}
 
status = _cairo_array_append (array, &new_slot);
if (unlikely (status))
return status;
 
return CAIRO_STATUS_SUCCESS;
}
 
cairo_status_t
_cairo_user_data_array_copy (cairo_user_data_array_t *dst,
cairo_user_data_array_t *src)
{
/* discard any existing user-data */
if (dst->num_elements != 0) {
_cairo_user_data_array_fini (dst);
_cairo_user_data_array_init (dst);
}
 
if (src->num_elements == 0)
return CAIRO_STATUS_SUCCESS;
 
return _cairo_array_append_multiple (dst,
_cairo_array_index (src, 0),
src->num_elements);
}
 
void
_cairo_user_data_array_foreach (cairo_user_data_array_t *array,
void (*func) (const void *key,
void *elt,
void *closure),
void *closure)
{
cairo_user_data_slot_t *slots;
int i, num_slots;
 
num_slots = array->num_elements;
slots = _cairo_array_index (array, 0);
for (i = 0; i < num_slots; i++) {
if (slots[i].user_data != NULL)
func (slots[i].key, slots[i].user_data, closure);
}
}
/programs/develop/libraries/cairo/src/cairo-atomic-private.h
0,0 → 1,265
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2007 Chris Wilson
* Copyright © 2010 Andrea Canciani
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Chris Wilson <chris@chris-wilson.co.uk>
* Andrea Canciani <ranma42@gmail.com>
*/
 
#ifndef CAIRO_ATOMIC_PRIVATE_H
#define CAIRO_ATOMIC_PRIVATE_H
 
# include "cairo-compiler-private.h"
 
#if HAVE_CONFIG_H
#include "config.h"
#endif
 
/* The autoconf on OpenBSD 4.5 produces the malformed constant name
* SIZEOF_VOID__ rather than SIZEOF_VOID_P. Work around that here. */
#if !defined(SIZEOF_VOID_P) && defined(SIZEOF_VOID__)
# define SIZEOF_VOID_P SIZEOF_VOID__
#endif
 
CAIRO_BEGIN_DECLS
 
#if HAVE_INTEL_ATOMIC_PRIMITIVES
 
#define HAS_ATOMIC_OPS 1
 
typedef int cairo_atomic_int_t;
 
#ifdef ATOMIC_OP_NEEDS_MEMORY_BARRIER
static cairo_always_inline cairo_atomic_int_t
_cairo_atomic_int_get (cairo_atomic_int_t *x)
{
__sync_synchronize ();
return *x;
}
 
static cairo_always_inline void *
_cairo_atomic_ptr_get (void **x)
{
__sync_synchronize ();
return *x;
}
#else
# define _cairo_atomic_int_get(x) (*x)
# define _cairo_atomic_ptr_get(x) (*x)
#endif
 
# 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_bool_compare_and_swap (x, oldv, newv)
# define _cairo_atomic_int_cmpxchg_return_old(x, oldv, newv) __sync_val_compare_and_swap (x, oldv, newv)
 
#if SIZEOF_VOID_P==SIZEOF_INT
typedef int cairo_atomic_intptr_t;
#elif SIZEOF_VOID_P==SIZEOF_LONG
typedef long cairo_atomic_intptr_t;
#elif SIZEOF_VOID_P==SIZEOF_LONG_LONG
typedef long long cairo_atomic_intptr_t;
#else
#error No matching integer pointer type
#endif
 
# define _cairo_atomic_ptr_cmpxchg(x, oldv, newv) \
__sync_bool_compare_and_swap ((cairo_atomic_intptr_t*)x, (cairo_atomic_intptr_t)oldv, (cairo_atomic_intptr_t)newv)
 
# define _cairo_atomic_ptr_cmpxchg_return_old(x, oldv, newv) \
_cairo_atomic_intptr_to_voidptr (__sync_val_compare_and_swap ((cairo_atomic_intptr_t*)x, (cairo_atomic_intptr_t)oldv, (cairo_atomic_intptr_t)newv))
 
#endif
 
#if HAVE_LIB_ATOMIC_OPS
#include <atomic_ops.h>
 
#define HAS_ATOMIC_OPS 1
 
typedef AO_t cairo_atomic_int_t;
 
# define _cairo_atomic_int_get(x) (AO_load_full (x))
 
# define _cairo_atomic_int_inc(x) ((void) AO_fetch_and_add1_full(x))
# define _cairo_atomic_int_dec_and_test(x) (AO_fetch_and_sub1_full(x) == 1)
# define _cairo_atomic_int_cmpxchg(x, oldv, newv) AO_compare_and_swap_full(x, oldv, newv)
 
#if SIZEOF_VOID_P==SIZEOF_INT
typedef unsigned int cairo_atomic_intptr_t;
#elif SIZEOF_VOID_P==SIZEOF_LONG
typedef unsigned long cairo_atomic_intptr_t;
#elif SIZEOF_VOID_P==SIZEOF_LONG_LONG
typedef unsigned long long cairo_atomic_intptr_t;
#else
#error No matching integer pointer type
#endif
 
# define _cairo_atomic_ptr_get(x) _cairo_atomic_intptr_to_voidptr (AO_load_full (x))
# define _cairo_atomic_ptr_cmpxchg(x, oldv, newv) \
_cairo_atomic_int_cmpxchg ((cairo_atomic_intptr_t*)(x), (cairo_atomic_intptr_t)oldv, (cairo_atomic_intptr_t)newv)
 
#endif
 
#if HAVE_OS_ATOMIC_OPS
#include <libkern/OSAtomic.h>
 
#define HAS_ATOMIC_OPS 1
 
typedef int32_t cairo_atomic_int_t;
 
# define _cairo_atomic_int_get(x) (OSMemoryBarrier(), *(x))
 
# define _cairo_atomic_int_inc(x) ((void) OSAtomicIncrement32Barrier (x))
# define _cairo_atomic_int_dec_and_test(x) (OSAtomicDecrement32Barrier (x) == 0)
# define _cairo_atomic_int_cmpxchg(x, oldv, newv) OSAtomicCompareAndSwap32Barrier(oldv, newv, x)
 
#if SIZEOF_VOID_P==4
typedef int32_t cairo_atomic_intptr_t;
# define _cairo_atomic_ptr_cmpxchg(x, oldv, newv) \
OSAtomicCompareAndSwap32Barrier((cairo_atomic_intptr_t)oldv, (cairo_atomic_intptr_t)newv, (cairo_atomic_intptr_t *)x)
 
#elif SIZEOF_VOID_P==8
typedef int64_t cairo_atomic_intptr_t;
# define _cairo_atomic_ptr_cmpxchg(x, oldv, newv) \
OSAtomicCompareAndSwap64Barrier((cairo_atomic_intptr_t)oldv, (cairo_atomic_intptr_t)newv, (cairo_atomic_intptr_t *)x)
 
#else
#error No matching integer pointer type
#endif
 
# define _cairo_atomic_ptr_get(x) (OSMemoryBarrier(), *(x))
 
#endif
 
#ifndef HAS_ATOMIC_OPS
 
#if SIZEOF_VOID_P==SIZEOF_INT
typedef unsigned int cairo_atomic_intptr_t;
#elif SIZEOF_VOID_P==SIZEOF_LONG
typedef unsigned long cairo_atomic_intptr_t;
#elif SIZEOF_VOID_P==SIZEOF_LONG_LONG
typedef unsigned long long cairo_atomic_intptr_t;
#else
#error No matching integer pointer type
#endif
 
typedef cairo_atomic_intptr_t cairo_atomic_int_t;
 
cairo_private void
_cairo_atomic_int_inc (cairo_atomic_int_t *x);
 
cairo_private cairo_bool_t
_cairo_atomic_int_dec_and_test (cairo_atomic_int_t *x);
 
cairo_private cairo_atomic_int_t
_cairo_atomic_int_cmpxchg_return_old_impl (cairo_atomic_int_t *x, cairo_atomic_int_t oldv, cairo_atomic_int_t newv);
 
cairo_private void *
_cairo_atomic_ptr_cmpxchg_return_old_impl (void **x, void *oldv, void *newv);
 
#define _cairo_atomic_int_cmpxchg_return_old(x, oldv, newv) _cairo_atomic_int_cmpxchg_return_old_impl (x, oldv, newv)
#define _cairo_atomic_ptr_cmpxchg_return_old(x, oldv, newv) _cairo_atomic_ptr_cmpxchg_return_old_impl (x, oldv, newv)
 
#ifdef ATOMIC_OP_NEEDS_MEMORY_BARRIER
cairo_private cairo_atomic_int_t
_cairo_atomic_int_get (cairo_atomic_int_t *x);
# define _cairo_atomic_ptr_get(x) (void *) _cairo_atomic_int_get((cairo_atomic_int_t *) x)
#else
# define _cairo_atomic_int_get(x) (*x)
# define _cairo_atomic_ptr_get(x) (*x)
#endif
 
#else
 
/* Workaround GCC complaining about casts */
static cairo_always_inline void *
_cairo_atomic_intptr_to_voidptr (cairo_atomic_intptr_t x)
{
return (void *) x;
}
 
static cairo_always_inline cairo_atomic_int_t
_cairo_atomic_int_cmpxchg_return_old_fallback(cairo_atomic_int_t *x, cairo_atomic_int_t oldv, cairo_atomic_int_t newv)
{
cairo_atomic_int_t curr;
 
do {
curr = _cairo_atomic_int_get (x);
} while (curr == oldv && !_cairo_atomic_int_cmpxchg (x, oldv, newv));
 
return curr;
}
 
static cairo_always_inline void *
_cairo_atomic_ptr_cmpxchg_return_old_fallback(void **x, void *oldv, void *newv)
{
void *curr;
 
do {
curr = _cairo_atomic_ptr_get (x);
} while (curr == oldv && !_cairo_atomic_ptr_cmpxchg (x, oldv, newv));
 
return curr;
}
#endif
 
#ifndef _cairo_atomic_int_cmpxchg_return_old
#define _cairo_atomic_int_cmpxchg_return_old(x, oldv, newv) _cairo_atomic_int_cmpxchg_return_old_fallback (x, oldv, newv)
#endif
 
#ifndef _cairo_atomic_ptr_cmpxchg_return_old
#define _cairo_atomic_ptr_cmpxchg_return_old(x, oldv, newv) _cairo_atomic_ptr_cmpxchg_return_old_fallback (x, oldv, newv)
#endif
 
#ifndef _cairo_atomic_int_cmpxchg
#define _cairo_atomic_int_cmpxchg(x, oldv, newv) (_cairo_atomic_int_cmpxchg_return_old (x, oldv, newv) == oldv)
#endif
 
#ifndef _cairo_atomic_ptr_cmpxchg
#define _cairo_atomic_ptr_cmpxchg(x, oldv, newv) (_cairo_atomic_ptr_cmpxchg_return_old (x, oldv, newv) == oldv)
#endif
 
#define _cairo_atomic_uint_get(x) _cairo_atomic_int_get(x)
#define _cairo_atomic_uint_cmpxchg(x, oldv, newv) \
_cairo_atomic_int_cmpxchg((cairo_atomic_int_t *)x, oldv, newv)
 
#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 ((cairo_atomic_int_t *) status, CAIRO_STATUS_SUCCESS, err); \
(void) ret__; \
} while (0)
 
CAIRO_END_DECLS
 
#endif
/programs/develop/libraries/cairo/src/cairo-atomic.c
0,0 → 1,106
/* 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., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* Contributor(s):
* Chris Wilson <chris@chris-wilson.co.uk>
*/
 
#include "cairoint.h"
 
#include "cairo-atomic-private.h"
#include "cairo-mutex-private.h"
 
#ifdef HAS_ATOMIC_OPS
COMPILE_TIME_ASSERT(sizeof(void*) == sizeof(int) ||
sizeof(void*) == sizeof(long) ||
sizeof(void*) == sizeof(long long));
#else
void
_cairo_atomic_int_inc (cairo_atomic_intptr_t *x)
{
CAIRO_MUTEX_LOCK (_cairo_atomic_mutex);
*x += 1;
CAIRO_MUTEX_UNLOCK (_cairo_atomic_mutex);
}
 
cairo_bool_t
_cairo_atomic_int_dec_and_test (cairo_atomic_intptr_t *x)
{
cairo_bool_t ret;
 
CAIRO_MUTEX_LOCK (_cairo_atomic_mutex);
ret = --*x == 0;
CAIRO_MUTEX_UNLOCK (_cairo_atomic_mutex);
 
return ret;
}
 
cairo_atomic_intptr_t
_cairo_atomic_int_cmpxchg_return_old_impl (cairo_atomic_intptr_t *x, cairo_atomic_intptr_t oldv, cairo_atomic_intptr_t newv)
{
cairo_atomic_intptr_t ret;
 
CAIRO_MUTEX_LOCK (_cairo_atomic_mutex);
ret = *x;
if (ret == oldv)
*x = newv;
CAIRO_MUTEX_UNLOCK (_cairo_atomic_mutex);
 
return ret;
}
 
void *
_cairo_atomic_ptr_cmpxchg_return_old_impl (void **x, void *oldv, void *newv)
{
void *ret;
 
CAIRO_MUTEX_LOCK (_cairo_atomic_mutex);
ret = *x;
if (ret == oldv)
*x = newv;
CAIRO_MUTEX_UNLOCK (_cairo_atomic_mutex);
 
return ret;
}
 
#ifdef ATOMIC_OP_NEEDS_MEMORY_BARRIER
cairo_atomic_intptr_t
_cairo_atomic_int_get (cairo_atomic_intptr_t *x)
{
cairo_atomic_intptr_t ret;
 
CAIRO_MUTEX_LOCK (_cairo_atomic_mutex);
ret = *x;
CAIRO_MUTEX_UNLOCK (_cairo_atomic_mutex);
 
return ret;
}
#endif
 
#endif
/programs/develop/libraries/cairo/src/cairo-base64-stream.c
0,0 → 1,144
/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2005-2007 Emmanuel Pacaud <emmanuel.pacaud@free.fr>
* Copyright © 2009 Chris Wilson
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Author(s):
* Kristian Høgsberg <krh@redhat.com>
* Chris Wilson <chris@chris-wilson.co.uk>
*/
 
#include "cairoint.h"
#include "cairo-error-private.h"
#include "cairo-output-stream-private.h"
 
typedef struct _cairo_base64_stream {
cairo_output_stream_t base;
cairo_output_stream_t *output;
unsigned int in_mem;
unsigned int trailing;
unsigned char src[3];
} cairo_base64_stream_t;
 
static char const base64_table[64] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
 
static cairo_status_t
_cairo_base64_stream_write (cairo_output_stream_t *base,
const unsigned char *data,
unsigned int length)
{
cairo_base64_stream_t * stream = (cairo_base64_stream_t *) base;
unsigned char *src = stream->src;
unsigned int i;
 
if (stream->in_mem + length < 3) {
for (i = 0; i < length; i++) {
src[i + stream->in_mem] = *data++;
}
stream->in_mem += length;
return CAIRO_STATUS_SUCCESS;
}
 
do {
unsigned char dst[4];
 
for (i = stream->in_mem; i < 3; i++) {
src[i] = *data++;
length--;
}
stream->in_mem = 0;
 
dst[0] = base64_table[src[0] >> 2];
dst[1] = base64_table[(src[0] & 0x03) << 4 | src[1] >> 4];
dst[2] = base64_table[(src[1] & 0x0f) << 2 | src[2] >> 6];
dst[3] = base64_table[src[2] & 0xfc >> 2];
/* Special case for the last missing bits */
switch (stream->trailing) {
case 2:
dst[2] = '=';
case 1:
dst[3] = '=';
default:
break;
}
_cairo_output_stream_write (stream->output, dst, 4);
} while (length >= 3);
 
for (i = 0; i < length; i++) {
src[i] = *data++;
}
stream->in_mem = length;
 
return _cairo_output_stream_get_status (stream->output);
}
 
static cairo_status_t
_cairo_base64_stream_close (cairo_output_stream_t *base)
{
cairo_base64_stream_t *stream = (cairo_base64_stream_t *) base;
cairo_status_t status = CAIRO_STATUS_SUCCESS;
 
if (stream->in_mem > 0) {
memset (stream->src + stream->in_mem, 0, 3 - stream->in_mem);
stream->trailing = 3 - stream->in_mem;
stream->in_mem = 3;
status = _cairo_base64_stream_write (base, NULL, 0);
}
 
return status;
}
 
cairo_output_stream_t *
_cairo_base64_stream_create (cairo_output_stream_t *output)
{
cairo_base64_stream_t *stream;
 
if (output->status)
return _cairo_output_stream_create_in_error (output->status);
 
stream = malloc (sizeof (cairo_base64_stream_t));
if (unlikely (stream == NULL)) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_output_stream_t *) &_cairo_output_stream_nil;
}
 
_cairo_output_stream_init (&stream->base,
_cairo_base64_stream_write,
NULL,
_cairo_base64_stream_close);
 
stream->output = output;
stream->in_mem = 0;
stream->trailing = 0;
 
return &stream->base;
}
/programs/develop/libraries/cairo/src/cairo-base85-stream.c
0,0 → 1,131
/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2005 Red Hat, Inc
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Author(s):
* Kristian Høgsberg <krh@redhat.com>
*/
 
#include "cairoint.h"
#include "cairo-error-private.h"
#include "cairo-output-stream-private.h"
 
typedef struct _cairo_base85_stream {
cairo_output_stream_t base;
cairo_output_stream_t *output;
unsigned char four_tuple[4];
int pending;
} cairo_base85_stream_t;
 
static void
_expand_four_tuple_to_five (unsigned char four_tuple[4],
unsigned char five_tuple[5],
cairo_bool_t *all_zero)
{
uint32_t value;
int digit, i;
 
value = four_tuple[0] << 24 | four_tuple[1] << 16 | four_tuple[2] << 8 | four_tuple[3];
if (all_zero)
*all_zero = TRUE;
for (i = 0; i < 5; i++) {
digit = value % 85;
if (digit != 0 && all_zero)
*all_zero = FALSE;
five_tuple[4-i] = digit + 33;
value = value / 85;
}
}
 
static cairo_status_t
_cairo_base85_stream_write (cairo_output_stream_t *base,
const unsigned char *data,
unsigned int length)
{
cairo_base85_stream_t *stream = (cairo_base85_stream_t *) base;
const unsigned char *ptr = data;
unsigned char five_tuple[5];
cairo_bool_t is_zero;
 
while (length) {
stream->four_tuple[stream->pending++] = *ptr++;
length--;
if (stream->pending == 4) {
_expand_four_tuple_to_five (stream->four_tuple, five_tuple, &is_zero);
if (is_zero)
_cairo_output_stream_write (stream->output, "z", 1);
else
_cairo_output_stream_write (stream->output, five_tuple, 5);
stream->pending = 0;
}
}
 
return _cairo_output_stream_get_status (stream->output);
}
 
static cairo_status_t
_cairo_base85_stream_close (cairo_output_stream_t *base)
{
cairo_base85_stream_t *stream = (cairo_base85_stream_t *) base;
unsigned char five_tuple[5];
 
if (stream->pending) {
memset (stream->four_tuple + stream->pending, 0, 4 - stream->pending);
_expand_four_tuple_to_five (stream->four_tuple, five_tuple, NULL);
_cairo_output_stream_write (stream->output, five_tuple, stream->pending + 1);
}
 
return _cairo_output_stream_get_status (stream->output);
}
 
cairo_output_stream_t *
_cairo_base85_stream_create (cairo_output_stream_t *output)
{
cairo_base85_stream_t *stream;
 
if (output->status)
return _cairo_output_stream_create_in_error (output->status);
 
stream = malloc (sizeof (cairo_base85_stream_t));
if (unlikely (stream == NULL)) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_output_stream_t *) &_cairo_output_stream_nil;
}
 
_cairo_output_stream_init (&stream->base,
_cairo_base85_stream_write,
NULL,
_cairo_base85_stream_close);
stream->output = output;
stream->pending = 0;
 
return &stream->base;
}
/programs/develop/libraries/cairo/src/cairo-bentley-ottmann-rectangular.c
0,0 → 1,787
/*
* Copyright © 2004 Carl Worth
* Copyright © 2006 Red Hat, Inc.
* Copyright © 2009 Chris Wilson
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Carl Worth
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
* Chris Wilson <chris@chris-wilson.co.uk>
*/
 
/* Provide definitions for standalone compilation */
#include "cairoint.h"
 
#include "cairo-boxes-private.h"
#include "cairo-error-private.h"
#include "cairo-combsort-private.h"
#include "cairo-list-private.h"
 
#include <setjmp.h>
 
typedef struct _rectangle rectangle_t;
typedef struct _edge edge_t;
 
struct _edge {
edge_t *next, *prev;
edge_t *right;
cairo_fixed_t x, top;
int dir;
};
 
struct _rectangle {
edge_t left, right;
int32_t top, bottom;
};
 
#define UNROLL3(x) x x x
 
/* the parent is always given by index/2 */
#define PQ_PARENT_INDEX(i) ((i) >> 1)
#define PQ_FIRST_ENTRY 1
 
/* left and right children are index * 2 and (index * 2) +1 respectively */
#define PQ_LEFT_CHILD_INDEX(i) ((i) << 1)
 
typedef struct _pqueue {
int size, max_size;
 
rectangle_t **elements;
rectangle_t *elements_embedded[1024];
} pqueue_t;
 
typedef struct _sweep_line {
rectangle_t **rectangles;
pqueue_t pq;
edge_t head, tail;
edge_t *insert_left, *insert_right;
int32_t current_y;
int32_t last_y;
 
cairo_fill_rule_t fill_rule;
 
jmp_buf unwind;
} sweep_line_t;
 
#define DEBUG_TRAPS 0
 
#if DEBUG_TRAPS
static void
dump_traps (cairo_traps_t *traps, const char *filename)
{
FILE *file;
int n;
 
if (getenv ("CAIRO_DEBUG_TRAPS") == NULL)
return;
 
file = fopen (filename, "a");
if (file != NULL) {
for (n = 0; n < traps->num_traps; n++) {
fprintf (file, "%d %d L:(%d, %d), (%d, %d) R:(%d, %d), (%d, %d)\n",
traps->traps[n].top,
traps->traps[n].bottom,
traps->traps[n].left.p1.x,
traps->traps[n].left.p1.y,
traps->traps[n].left.p2.x,
traps->traps[n].left.p2.y,
traps->traps[n].right.p1.x,
traps->traps[n].right.p1.y,
traps->traps[n].right.p2.x,
traps->traps[n].right.p2.y);
}
fprintf (file, "\n");
fclose (file);
}
}
#else
#define dump_traps(traps, filename)
#endif
 
static inline int
rectangle_compare_start (const rectangle_t *a,
const rectangle_t *b)
{
return a->top - b->top;
}
 
static inline int
rectangle_compare_stop (const rectangle_t *a,
const rectangle_t *b)
{
return a->bottom - b->bottom;
}
 
static inline void
pqueue_init (pqueue_t *pq)
{
pq->max_size = ARRAY_LENGTH (pq->elements_embedded);
pq->size = 0;
 
pq->elements = pq->elements_embedded;
pq->elements[PQ_FIRST_ENTRY] = NULL;
}
 
static inline void
pqueue_fini (pqueue_t *pq)
{
if (pq->elements != pq->elements_embedded)
free (pq->elements);
}
 
static cairo_bool_t
pqueue_grow (pqueue_t *pq)
{
rectangle_t **new_elements;
pq->max_size *= 2;
 
if (pq->elements == pq->elements_embedded) {
new_elements = _cairo_malloc_ab (pq->max_size,
sizeof (rectangle_t *));
if (unlikely (new_elements == NULL))
return FALSE;
 
memcpy (new_elements, pq->elements_embedded,
sizeof (pq->elements_embedded));
} else {
new_elements = _cairo_realloc_ab (pq->elements,
pq->max_size,
sizeof (rectangle_t *));
if (unlikely (new_elements == NULL))
return FALSE;
}
 
pq->elements = new_elements;
return TRUE;
}
 
static inline void
pqueue_push (sweep_line_t *sweep, rectangle_t *rectangle)
{
rectangle_t **elements;
int i, parent;
 
if (unlikely (sweep->pq.size + 1 == sweep->pq.max_size)) {
if (unlikely (! pqueue_grow (&sweep->pq))) {
longjmp (sweep->unwind,
_cairo_error (CAIRO_STATUS_NO_MEMORY));
}
}
 
elements = sweep->pq.elements;
for (i = ++sweep->pq.size;
i != PQ_FIRST_ENTRY &&
rectangle_compare_stop (rectangle,
elements[parent = PQ_PARENT_INDEX (i)]) < 0;
i = parent)
{
elements[i] = elements[parent];
}
 
elements[i] = rectangle;
}
 
static inline void
pqueue_pop (pqueue_t *pq)
{
rectangle_t **elements = pq->elements;
rectangle_t *tail;
int child, i;
 
tail = elements[pq->size--];
if (pq->size == 0) {
elements[PQ_FIRST_ENTRY] = NULL;
return;
}
 
for (i = PQ_FIRST_ENTRY;
(child = PQ_LEFT_CHILD_INDEX (i)) <= pq->size;
i = child)
{
if (child != pq->size &&
rectangle_compare_stop (elements[child+1],
elements[child]) < 0)
{
child++;
}
 
if (rectangle_compare_stop (elements[child], tail) >= 0)
break;
 
elements[i] = elements[child];
}
elements[i] = tail;
}
 
static inline rectangle_t *
rectangle_pop_start (sweep_line_t *sweep_line)
{
return *sweep_line->rectangles++;
}
 
static inline rectangle_t *
rectangle_peek_stop (sweep_line_t *sweep_line)
{
return sweep_line->pq.elements[PQ_FIRST_ENTRY];
}
 
CAIRO_COMBSORT_DECLARE (_rectangle_sort,
rectangle_t *,
rectangle_compare_start)
 
static void
sweep_line_init (sweep_line_t *sweep_line,
rectangle_t **rectangles,
int num_rectangles,
cairo_fill_rule_t fill_rule)
{
_rectangle_sort (rectangles, num_rectangles);
rectangles[num_rectangles] = NULL;
sweep_line->rectangles = rectangles;
 
sweep_line->head.x = INT32_MIN;
sweep_line->head.right = NULL;
sweep_line->head.dir = 0;
sweep_line->head.next = &sweep_line->tail;
sweep_line->tail.x = INT32_MAX;
sweep_line->tail.right = NULL;
sweep_line->tail.dir = 0;
sweep_line->tail.prev = &sweep_line->head;
 
sweep_line->insert_left = &sweep_line->tail;
sweep_line->insert_right = &sweep_line->tail;
 
sweep_line->current_y = INT32_MIN;
sweep_line->last_y = INT32_MIN;
 
sweep_line->fill_rule = fill_rule;
 
pqueue_init (&sweep_line->pq);
}
 
static void
sweep_line_fini (sweep_line_t *sweep_line)
{
pqueue_fini (&sweep_line->pq);
}
 
static void
edge_end_box (sweep_line_t *sweep_line,
edge_t *left,
int32_t bot,
cairo_bool_t do_traps,
void *container)
{
cairo_status_t status = CAIRO_STATUS_SUCCESS;
 
/* Only emit (trivial) non-degenerate trapezoids with positive height. */
if (likely (left->top < bot)) {
if (do_traps) {
cairo_line_t _left = {
{ left->x, left->top },
{ left->x, bot },
}, _right = {
{ left->right->x, left->top },
{ left->right->x, bot },
};
_cairo_traps_add_trap (container, left->top, bot, &_left, &_right);
status = _cairo_traps_status ((cairo_traps_t *) container);
} else {
cairo_box_t box;
 
box.p1.x = left->x;
box.p1.y = left->top;
box.p2.x = left->right->x;
box.p2.y = bot;
 
status = _cairo_boxes_add (container, &box);
}
}
if (unlikely (status))
longjmp (sweep_line->unwind, status);
 
left->right = NULL;
}
 
/* Start a new trapezoid at the given top y coordinate, whose edges
* are `edge' and `edge->next'. If `edge' already has a trapezoid,
* then either add it to the traps in `traps', if the trapezoid's
* right edge differs from `edge->next', or do nothing if the new
* trapezoid would be a continuation of the existing one. */
static inline void
edge_start_or_continue_box (sweep_line_t *sweep_line,
edge_t *left,
edge_t *right,
int top,
cairo_bool_t do_traps,
void *container)
{
if (left->right == right)
return;
 
if (left->right != NULL) {
if (right != NULL && left->right->x == right->x) {
/* continuation on right, so just swap edges */
left->right = right;
return;
}
 
edge_end_box (sweep_line,
left, top, do_traps, container);
}
 
if (right != NULL && left->x != right->x) {
left->top = top;
left->right = right;
}
}
 
static inline void
active_edges_to_traps (sweep_line_t *sweep,
cairo_bool_t do_traps,
void *container)
{
int top = sweep->current_y;
edge_t *pos;
 
if (sweep->last_y == sweep->current_y)
return;
 
pos = sweep->head.next;
if (pos == &sweep->tail)
return;
 
if (sweep->fill_rule == CAIRO_FILL_RULE_WINDING) {
do {
edge_t *left, *right;
int winding;
 
left = pos;
winding = left->dir;
 
right = left->next;
 
/* Check if there is a co-linear edge with an existing trap */
if (left->right == NULL) {
while (unlikely (right->x == left->x)) {
winding += right->dir;
if (right->right != NULL) {
/* continuation on left */
left->top = right->top;
left->right = right->right;
right->right = NULL;
winding -= right->dir;
break;
}
 
right = right->next;
}
 
if (winding == 0) {
pos = right;
continue;
}
}
 
/* Greedily search for the closing edge, so that we generate the
* maximal span width with the minimal number of trapezoids.
*/
 
do {
/* End all subsumed traps */
if (unlikely (right->right != NULL)) {
edge_end_box (sweep,
right, top, do_traps, container);
}
 
winding += right->dir;
if (winding == 0) {
/* skip co-linear edges */
if (likely (right->x != right->next->x))
break;
}
 
right = right->next;
} while (TRUE);
 
edge_start_or_continue_box (sweep,
left, right, top,
do_traps, container);
 
pos = right->next;
} while (pos != &sweep->tail);
} else {
do {
edge_t *right = pos->next;
int count = 0;
 
do {
/* End all subsumed traps */
if (unlikely (right->right != NULL)) {
edge_end_box (sweep,
right, top, do_traps, container);
}
 
if (++count & 1) {
/* skip co-linear edges */
if (likely (right->x != right->next->x))
break;
}
 
right = right->next;
} while (TRUE);
 
edge_start_or_continue_box (sweep,
pos, right, top,
do_traps, container);
 
pos = right->next;
} while (pos != &sweep->tail);
}
 
sweep->last_y = sweep->current_y;
}
 
static inline void
sweep_line_delete_edge (sweep_line_t *sweep_line,
edge_t *edge,
cairo_bool_t do_traps,
void *container)
{
if (edge->right != NULL) {
edge_t *next = edge->next;
if (next->x == edge->x) {
next->top = edge->top;
next->right = edge->right;
} else {
edge_end_box (sweep_line,
edge,
sweep_line->current_y,
do_traps, container);
}
}
 
if (sweep_line->insert_left == edge)
sweep_line->insert_left = edge->next;
if (sweep_line->insert_right == edge)
sweep_line->insert_right = edge->next;
 
edge->prev->next = edge->next;
edge->next->prev = edge->prev;
}
 
static inline cairo_bool_t
sweep_line_delete (sweep_line_t *sweep,
rectangle_t *rectangle,
cairo_bool_t do_traps,
void *container)
{
cairo_bool_t update;
 
update = TRUE;
if (sweep->fill_rule == CAIRO_FILL_RULE_WINDING &&
rectangle->left.prev->dir == rectangle->left.dir)
{
update = rectangle->left.next != &rectangle->right;
}
 
sweep_line_delete_edge (sweep,
&rectangle->left,
do_traps, container);
 
sweep_line_delete_edge (sweep,
&rectangle->right,
do_traps, container);
 
pqueue_pop (&sweep->pq);
return update;
}
 
static inline void
insert_edge (edge_t *edge, edge_t *pos)
{
if (pos->x != edge->x) {
if (pos->x > edge->x) {
do {
UNROLL3({
if (pos->prev->x <= edge->x)
break;
pos = pos->prev;
})
} while (TRUE);
} else {
do {
UNROLL3({
pos = pos->next;
if (pos->x >= edge->x)
break;
})
} while (TRUE);
}
}
 
pos->prev->next = edge;
edge->prev = pos->prev;
edge->next = pos;
pos->prev = edge;
}
 
static inline cairo_bool_t
sweep_line_insert (sweep_line_t *sweep,
rectangle_t *rectangle)
{
edge_t *pos;
 
/* right edge */
pos = sweep->insert_right;
insert_edge (&rectangle->right, pos);
sweep->insert_right = &rectangle->right;
 
/* left edge */
pos = sweep->insert_left;
if (pos->x > sweep->insert_right->x)
pos = sweep->insert_right->prev;
insert_edge (&rectangle->left, pos);
sweep->insert_left = &rectangle->left;
 
pqueue_push (sweep, rectangle);
 
if (sweep->fill_rule == CAIRO_FILL_RULE_WINDING &&
rectangle->left.prev->dir == rectangle->left.dir)
{
return rectangle->left.next != &rectangle->right;
}
 
return TRUE;
}
 
static cairo_status_t
_cairo_bentley_ottmann_tessellate_rectangular (rectangle_t **rectangles,
int num_rectangles,
cairo_fill_rule_t fill_rule,
cairo_bool_t do_traps,
void *container)
{
sweep_line_t sweep_line;
rectangle_t *rectangle;
cairo_status_t status;
cairo_bool_t update = FALSE;
 
sweep_line_init (&sweep_line, rectangles, num_rectangles, fill_rule);
if ((status = setjmp (sweep_line.unwind)))
goto unwind;
 
rectangle = rectangle_pop_start (&sweep_line);
do {
if (rectangle->top != sweep_line.current_y) {
rectangle_t *stop;
 
stop = rectangle_peek_stop (&sweep_line);
while (stop != NULL && stop->bottom < rectangle->top) {
if (stop->bottom != sweep_line.current_y) {
if (update) {
active_edges_to_traps (&sweep_line,
do_traps, container);
update = FALSE;
}
 
sweep_line.current_y = stop->bottom;
}
 
update |= sweep_line_delete (&sweep_line, stop, do_traps, container);
 
stop = rectangle_peek_stop (&sweep_line);
}
 
if (update) {
active_edges_to_traps (&sweep_line, do_traps, container);
update = FALSE;
}
 
sweep_line.current_y = rectangle->top;
}
 
update |= sweep_line_insert (&sweep_line, rectangle);
} while ((rectangle = rectangle_pop_start (&sweep_line)) != NULL);
 
while ((rectangle = rectangle_peek_stop (&sweep_line)) != NULL) {
if (rectangle->bottom != sweep_line.current_y) {
if (update) {
active_edges_to_traps (&sweep_line, do_traps, container);
update = FALSE;
}
 
sweep_line.current_y = rectangle->bottom;
}
 
update |= sweep_line_delete (&sweep_line, rectangle, do_traps, container);
}
 
unwind:
sweep_line_fini (&sweep_line);
return status;
}
 
cairo_status_t
_cairo_bentley_ottmann_tessellate_rectangular_traps (cairo_traps_t *traps,
cairo_fill_rule_t fill_rule)
{
rectangle_t stack_rectangles[CAIRO_STACK_ARRAY_LENGTH (rectangle_t)];
rectangle_t *rectangles;
rectangle_t *stack_rectangles_ptrs[ARRAY_LENGTH (stack_rectangles) + 1];
rectangle_t **rectangles_ptrs;
cairo_status_t status;
int i;
 
if (unlikely (traps->num_traps <= 1))
return CAIRO_STATUS_SUCCESS;
 
assert (traps->is_rectangular);
 
dump_traps (traps, "bo-rects-traps-in.txt");
 
rectangles = stack_rectangles;
rectangles_ptrs = stack_rectangles_ptrs;
if (traps->num_traps > ARRAY_LENGTH (stack_rectangles)) {
rectangles = _cairo_malloc_ab_plus_c (traps->num_traps,
sizeof (rectangle_t) +
sizeof (rectangle_t *),
sizeof (rectangle_t *));
if (unlikely (rectangles == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
rectangles_ptrs = (rectangle_t **) (rectangles + traps->num_traps);
}
 
for (i = 0; i < traps->num_traps; i++) {
if (traps->traps[i].left.p1.x < traps->traps[i].right.p1.x) {
rectangles[i].left.x = traps->traps[i].left.p1.x;
rectangles[i].left.dir = 1;
 
rectangles[i].right.x = traps->traps[i].right.p1.x;
rectangles[i].right.dir = -1;
} else {
rectangles[i].right.x = traps->traps[i].left.p1.x;
rectangles[i].right.dir = 1;
 
rectangles[i].left.x = traps->traps[i].right.p1.x;
rectangles[i].left.dir = -1;
}
 
rectangles[i].left.right = NULL;
rectangles[i].right.right = NULL;
 
rectangles[i].top = traps->traps[i].top;
rectangles[i].bottom = traps->traps[i].bottom;
 
rectangles_ptrs[i] = &rectangles[i];
}
 
_cairo_traps_clear (traps);
status = _cairo_bentley_ottmann_tessellate_rectangular (rectangles_ptrs, i,
fill_rule,
TRUE, traps);
traps->is_rectilinear = TRUE;
traps->is_rectangular = TRUE;
 
if (rectangles != stack_rectangles)
free (rectangles);
 
dump_traps (traps, "bo-rects-traps-out.txt");
 
return status;
}
 
cairo_status_t
_cairo_bentley_ottmann_tessellate_boxes (const cairo_boxes_t *in,
cairo_fill_rule_t fill_rule,
cairo_boxes_t *out)
{
rectangle_t stack_rectangles[CAIRO_STACK_ARRAY_LENGTH (rectangle_t)];
rectangle_t *rectangles;
rectangle_t *stack_rectangles_ptrs[ARRAY_LENGTH (stack_rectangles) + 1];
rectangle_t **rectangles_ptrs;
const struct _cairo_boxes_chunk *chunk;
cairo_status_t status;
int i, j;
 
if (unlikely (in->num_boxes <= 1))
return CAIRO_STATUS_SUCCESS;
 
rectangles = stack_rectangles;
rectangles_ptrs = stack_rectangles_ptrs;
if (in->num_boxes > ARRAY_LENGTH (stack_rectangles)) {
rectangles = _cairo_malloc_ab_plus_c (in->num_boxes,
sizeof (rectangle_t) +
sizeof (rectangle_t *),
sizeof (rectangle_t *));
if (unlikely (rectangles == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
rectangles_ptrs = (rectangle_t **) (rectangles + in->num_boxes);
}
 
j = 0;
for (chunk = &in->chunks; chunk != NULL; chunk = chunk->next) {
const cairo_box_t *box = chunk->base;
for (i = 0; i < chunk->count; i++) {
if (box[i].p1.x < box[i].p2.x) {
rectangles[j].left.x = box[i].p1.x;
rectangles[j].left.dir = 1;
 
rectangles[j].right.x = box[i].p2.x;
rectangles[j].right.dir = -1;
} else {
rectangles[j].right.x = box[i].p1.x;
rectangles[j].right.dir = 1;
 
rectangles[j].left.x = box[i].p2.x;
rectangles[j].left.dir = -1;
}
 
rectangles[j].left.right = NULL;
rectangles[j].right.right = NULL;
 
rectangles[j].top = box[i].p1.y;
rectangles[j].bottom = box[i].p2.y;
 
rectangles_ptrs[j] = &rectangles[j];
j++;
}
}
 
_cairo_boxes_clear (out);
status = _cairo_bentley_ottmann_tessellate_rectangular (rectangles_ptrs, j,
fill_rule,
FALSE, out);
if (rectangles != stack_rectangles)
free (rectangles);
 
return status;
}
/programs/develop/libraries/cairo/src/cairo-bentley-ottmann-rectilinear.c
0,0 → 1,667
/*
* Copyright © 2004 Carl Worth
* Copyright © 2006 Red Hat, Inc.
* Copyright © 2008 Chris Wilson
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Carl Worth
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
* Chris Wilson <chris@chris-wilson.co.uk>
*/
 
/* Provide definitions for standalone compilation */
#include "cairoint.h"
 
#include "cairo-boxes-private.h"
#include "cairo-combsort-private.h"
#include "cairo-error-private.h"
 
typedef struct _cairo_bo_edge cairo_bo_edge_t;
typedef struct _cairo_bo_trap cairo_bo_trap_t;
 
/* A deferred trapezoid of an edge */
struct _cairo_bo_trap {
cairo_bo_edge_t *right;
int32_t top;
};
 
struct _cairo_bo_edge {
cairo_edge_t edge;
cairo_bo_edge_t *prev;
cairo_bo_edge_t *next;
cairo_bo_trap_t deferred_trap;
};
 
typedef enum {
CAIRO_BO_EVENT_TYPE_START,
CAIRO_BO_EVENT_TYPE_STOP
} cairo_bo_event_type_t;
 
typedef struct _cairo_bo_event {
cairo_bo_event_type_t type;
cairo_point_t point;
cairo_bo_edge_t *edge;
} cairo_bo_event_t;
 
typedef struct _cairo_bo_sweep_line {
cairo_bo_event_t **events;
cairo_bo_edge_t *head;
cairo_bo_edge_t *stopped;
int32_t current_y;
cairo_bo_edge_t *current_edge;
} cairo_bo_sweep_line_t;
 
static inline int
_cairo_point_compare (const cairo_point_t *a,
const cairo_point_t *b)
{
int cmp;
 
cmp = a->y - b->y;
if (likely (cmp))
return cmp;
 
return a->x - b->x;
}
 
static inline int
_cairo_bo_edge_compare (const cairo_bo_edge_t *a,
const cairo_bo_edge_t *b)
{
int cmp;
 
cmp = a->edge.line.p1.x - b->edge.line.p1.x;
if (likely (cmp))
return cmp;
 
return b->edge.bottom - a->edge.bottom;
}
 
static inline int
cairo_bo_event_compare (const cairo_bo_event_t *a,
const cairo_bo_event_t *b)
{
int cmp;
 
cmp = _cairo_point_compare (&a->point, &b->point);
if (likely (cmp))
return cmp;
 
cmp = a->type - b->type;
if (cmp)
return cmp;
 
return a - b;
}
 
static inline cairo_bo_event_t *
_cairo_bo_event_dequeue (cairo_bo_sweep_line_t *sweep_line)
{
return *sweep_line->events++;
}
 
CAIRO_COMBSORT_DECLARE (_cairo_bo_event_queue_sort,
cairo_bo_event_t *,
cairo_bo_event_compare)
 
static void
_cairo_bo_sweep_line_init (cairo_bo_sweep_line_t *sweep_line,
cairo_bo_event_t **events,
int num_events)
{
_cairo_bo_event_queue_sort (events, num_events);
events[num_events] = NULL;
sweep_line->events = events;
 
sweep_line->head = NULL;
sweep_line->current_y = INT32_MIN;
sweep_line->current_edge = NULL;
}
 
static void
_cairo_bo_sweep_line_insert (cairo_bo_sweep_line_t *sweep_line,
cairo_bo_edge_t *edge)
{
if (sweep_line->current_edge != NULL) {
cairo_bo_edge_t *prev, *next;
int cmp;
 
cmp = _cairo_bo_edge_compare (sweep_line->current_edge, edge);
if (cmp < 0) {
prev = sweep_line->current_edge;
next = prev->next;
while (next != NULL && _cairo_bo_edge_compare (next, edge) < 0)
prev = next, next = prev->next;
 
prev->next = edge;
edge->prev = prev;
edge->next = next;
if (next != NULL)
next->prev = edge;
} else if (cmp > 0) {
next = sweep_line->current_edge;
prev = next->prev;
while (prev != NULL && _cairo_bo_edge_compare (prev, edge) > 0)
next = prev, prev = next->prev;
 
next->prev = edge;
edge->next = next;
edge->prev = prev;
if (prev != NULL)
prev->next = edge;
else
sweep_line->head = edge;
} else {
prev = sweep_line->current_edge;
edge->prev = prev;
edge->next = prev->next;
if (prev->next != NULL)
prev->next->prev = edge;
prev->next = edge;
}
} else {
sweep_line->head = edge;
}
 
sweep_line->current_edge = edge;
}
 
static void
_cairo_bo_sweep_line_delete (cairo_bo_sweep_line_t *sweep_line,
cairo_bo_edge_t *edge)
{
if (edge->prev != NULL)
edge->prev->next = edge->next;
else
sweep_line->head = edge->next;
 
if (edge->next != NULL)
edge->next->prev = edge->prev;
 
if (sweep_line->current_edge == edge)
sweep_line->current_edge = edge->prev ? edge->prev : edge->next;
}
 
static inline cairo_bool_t
edges_collinear (const cairo_bo_edge_t *a, const cairo_bo_edge_t *b)
{
return a->edge.line.p1.x == b->edge.line.p1.x;
}
 
static cairo_status_t
_cairo_bo_edge_end_trap (cairo_bo_edge_t *left,
int32_t bot,
cairo_bool_t do_traps,
void *container)
{
cairo_bo_trap_t *trap = &left->deferred_trap;
cairo_status_t status = CAIRO_STATUS_SUCCESS;
 
/* Only emit (trivial) non-degenerate trapezoids with positive height. */
if (likely (trap->top < bot)) {
if (do_traps) {
_cairo_traps_add_trap (container,
trap->top, bot,
&left->edge.line, &trap->right->edge.line);
status = _cairo_traps_status ((cairo_traps_t *) container);
} else {
cairo_box_t box;
 
box.p1.x = left->edge.line.p1.x;
box.p1.y = trap->top;
box.p2.x = trap->right->edge.line.p1.x;
box.p2.y = bot;
status = _cairo_boxes_add (container, &box);
}
}
 
trap->right = NULL;
 
return status;
}
 
/* Start a new trapezoid at the given top y coordinate, whose edges
* are `edge' and `edge->next'. If `edge' already has a trapezoid,
* then either add it to the traps in `traps', if the trapezoid's
* right edge differs from `edge->next', or do nothing if the new
* trapezoid would be a continuation of the existing one. */
static inline cairo_status_t
_cairo_bo_edge_start_or_continue_trap (cairo_bo_edge_t *left,
cairo_bo_edge_t *right,
int top,
cairo_bool_t do_traps,
void *container)
{
cairo_status_t status;
 
if (left->deferred_trap.right == right)
return CAIRO_STATUS_SUCCESS;
 
if (left->deferred_trap.right != NULL) {
if (right != NULL && edges_collinear (left->deferred_trap.right, right))
{
/* continuation on right, so just swap edges */
left->deferred_trap.right = right;
return CAIRO_STATUS_SUCCESS;
}
 
status = _cairo_bo_edge_end_trap (left, top, do_traps, container);
if (unlikely (status))
return status;
}
 
if (right != NULL && ! edges_collinear (left, right)) {
left->deferred_trap.top = top;
left->deferred_trap.right = right;
}
 
return CAIRO_STATUS_SUCCESS;
}
 
static inline cairo_status_t
_active_edges_to_traps (cairo_bo_edge_t *left,
int32_t top,
cairo_fill_rule_t fill_rule,
cairo_bool_t do_traps,
void *container)
{
cairo_bo_edge_t *right;
cairo_status_t status;
 
if (fill_rule == CAIRO_FILL_RULE_WINDING) {
while (left != NULL) {
int in_out;
 
/* Greedily search for the closing edge, so that we generate the
* maximal span width with the minimal number of trapezoids.
*/
in_out = left->edge.dir;
 
/* Check if there is a co-linear edge with an existing trap */
right = left->next;
if (left->deferred_trap.right == NULL) {
while (right != NULL && right->deferred_trap.right == NULL)
right = right->next;
 
if (right != NULL && edges_collinear (left, right)) {
/* continuation on left */
left->deferred_trap = right->deferred_trap;
right->deferred_trap.right = NULL;
}
}
 
/* End all subsumed traps */
right = left->next;
while (right != NULL) {
if (right->deferred_trap.right != NULL) {
status = _cairo_bo_edge_end_trap (right, top, do_traps, container);
if (unlikely (status))
return status;
}
 
in_out += right->edge.dir;
if (in_out == 0) {
/* skip co-linear edges */
if (right->next == NULL ||
! edges_collinear (right, right->next))
{
break;
}
}
 
right = right->next;
}
 
status = _cairo_bo_edge_start_or_continue_trap (left, right, top,
do_traps, container);
if (unlikely (status))
return status;
 
left = right;
if (left != NULL)
left = left->next;
}
} else {
while (left != NULL) {
int in_out = 0;
 
right = left->next;
while (right != NULL) {
if (right->deferred_trap.right != NULL) {
status = _cairo_bo_edge_end_trap (right, top, do_traps, container);
if (unlikely (status))
return status;
}
 
if ((in_out++ & 1) == 0) {
cairo_bo_edge_t *next;
cairo_bool_t skip = FALSE;
 
/* skip co-linear edges */
next = right->next;
if (next != NULL)
skip = edges_collinear (right, next);
 
if (! skip)
break;
}
 
right = right->next;
}
 
status = _cairo_bo_edge_start_or_continue_trap (left, right, top,
do_traps, container);
if (unlikely (status))
return status;
 
left = right;
if (left != NULL)
left = left->next;
}
}
 
return CAIRO_STATUS_SUCCESS;
}
 
static cairo_status_t
_cairo_bentley_ottmann_tessellate_rectilinear (cairo_bo_event_t **start_events,
int num_events,
cairo_fill_rule_t fill_rule,
cairo_bool_t do_traps,
void *container)
{
cairo_bo_sweep_line_t sweep_line;
cairo_bo_event_t *event;
cairo_status_t status;
 
_cairo_bo_sweep_line_init (&sweep_line, start_events, num_events);
 
while ((event = _cairo_bo_event_dequeue (&sweep_line))) {
if (event->point.y != sweep_line.current_y) {
status = _active_edges_to_traps (sweep_line.head,
sweep_line.current_y,
fill_rule, do_traps, container);
if (unlikely (status))
return status;
 
sweep_line.current_y = event->point.y;
}
 
switch (event->type) {
case CAIRO_BO_EVENT_TYPE_START:
_cairo_bo_sweep_line_insert (&sweep_line, event->edge);
break;
 
case CAIRO_BO_EVENT_TYPE_STOP:
_cairo_bo_sweep_line_delete (&sweep_line, event->edge);
 
if (event->edge->deferred_trap.right != NULL) {
status = _cairo_bo_edge_end_trap (event->edge,
sweep_line.current_y,
do_traps, container);
if (unlikely (status))
return status;
}
 
break;
}
}
 
return CAIRO_STATUS_SUCCESS;
}
 
cairo_status_t
_cairo_bentley_ottmann_tessellate_rectilinear_polygon (cairo_traps_t *traps,
const cairo_polygon_t *polygon,
cairo_fill_rule_t fill_rule)
{
cairo_status_t status;
cairo_bo_event_t stack_events[CAIRO_STACK_ARRAY_LENGTH (cairo_bo_event_t)];
cairo_bo_event_t *events;
cairo_bo_event_t *stack_event_ptrs[ARRAY_LENGTH (stack_events) + 1];
cairo_bo_event_t **event_ptrs;
cairo_bo_edge_t stack_edges[ARRAY_LENGTH (stack_events)];
cairo_bo_edge_t *edges;
int num_events;
int i, j;
 
if (unlikely (polygon->num_edges == 0))
return CAIRO_STATUS_SUCCESS;
 
num_events = 2 * polygon->num_edges;
 
events = stack_events;
event_ptrs = stack_event_ptrs;
edges = stack_edges;
if (num_events > ARRAY_LENGTH (stack_events)) {
events = _cairo_malloc_ab_plus_c (num_events,
sizeof (cairo_bo_event_t) +
sizeof (cairo_bo_edge_t) +
sizeof (cairo_bo_event_t *),
sizeof (cairo_bo_event_t *));
if (unlikely (events == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
event_ptrs = (cairo_bo_event_t **) (events + num_events);
edges = (cairo_bo_edge_t *) (event_ptrs + num_events + 1);
}
 
for (i = j = 0; i < polygon->num_edges; i++) {
edges[i].edge = polygon->edges[i];
edges[i].deferred_trap.right = NULL;
edges[i].prev = NULL;
edges[i].next = NULL;
 
event_ptrs[j] = &events[j];
events[j].type = CAIRO_BO_EVENT_TYPE_START;
events[j].point.y = polygon->edges[i].top;
events[j].point.x = polygon->edges[i].line.p1.x;
events[j].edge = &edges[i];
j++;
 
event_ptrs[j] = &events[j];
events[j].type = CAIRO_BO_EVENT_TYPE_STOP;
events[j].point.y = polygon->edges[i].bottom;
events[j].point.x = polygon->edges[i].line.p1.x;
events[j].edge = &edges[i];
j++;
}
 
status = _cairo_bentley_ottmann_tessellate_rectilinear (event_ptrs, j,
fill_rule,
TRUE, traps);
if (events != stack_events)
free (events);
 
traps->is_rectilinear = TRUE;
 
return status;
}
 
cairo_status_t
_cairo_bentley_ottmann_tessellate_rectilinear_polygon_to_boxes (const cairo_polygon_t *polygon,
cairo_fill_rule_t fill_rule,
cairo_boxes_t *boxes)
{
cairo_status_t status;
cairo_bo_event_t stack_events[CAIRO_STACK_ARRAY_LENGTH (cairo_bo_event_t)];
cairo_bo_event_t *events;
cairo_bo_event_t *stack_event_ptrs[ARRAY_LENGTH (stack_events) + 1];
cairo_bo_event_t **event_ptrs;
cairo_bo_edge_t stack_edges[ARRAY_LENGTH (stack_events)];
cairo_bo_edge_t *edges;
int num_events;
int i, j;
 
if (unlikely (polygon->num_edges == 0))
return CAIRO_STATUS_SUCCESS;
 
num_events = 2 * polygon->num_edges;
 
events = stack_events;
event_ptrs = stack_event_ptrs;
edges = stack_edges;
if (num_events > ARRAY_LENGTH (stack_events)) {
events = _cairo_malloc_ab_plus_c (num_events,
sizeof (cairo_bo_event_t) +
sizeof (cairo_bo_edge_t) +
sizeof (cairo_bo_event_t *),
sizeof (cairo_bo_event_t *));
if (unlikely (events == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
event_ptrs = (cairo_bo_event_t **) (events + num_events);
edges = (cairo_bo_edge_t *) (event_ptrs + num_events + 1);
}
 
for (i = j = 0; i < polygon->num_edges; i++) {
edges[i].edge = polygon->edges[i];
edges[i].deferred_trap.right = NULL;
edges[i].prev = NULL;
edges[i].next = NULL;
 
event_ptrs[j] = &events[j];
events[j].type = CAIRO_BO_EVENT_TYPE_START;
events[j].point.y = polygon->edges[i].top;
events[j].point.x = polygon->edges[i].line.p1.x;
events[j].edge = &edges[i];
j++;
 
event_ptrs[j] = &events[j];
events[j].type = CAIRO_BO_EVENT_TYPE_STOP;
events[j].point.y = polygon->edges[i].bottom;
events[j].point.x = polygon->edges[i].line.p1.x;
events[j].edge = &edges[i];
j++;
}
 
status = _cairo_bentley_ottmann_tessellate_rectilinear (event_ptrs, j,
fill_rule,
FALSE, boxes);
if (events != stack_events)
free (events);
 
return status;
}
 
cairo_status_t
_cairo_bentley_ottmann_tessellate_rectilinear_traps (cairo_traps_t *traps,
cairo_fill_rule_t fill_rule)
{
cairo_bo_event_t stack_events[CAIRO_STACK_ARRAY_LENGTH (cairo_bo_event_t)];
cairo_bo_event_t *events;
cairo_bo_event_t *stack_event_ptrs[ARRAY_LENGTH (stack_events) + 1];
cairo_bo_event_t **event_ptrs;
cairo_bo_edge_t stack_edges[ARRAY_LENGTH (stack_events)];
cairo_bo_edge_t *edges;
cairo_status_t status;
int i, j, k;
 
if (unlikely (traps->num_traps == 0))
return CAIRO_STATUS_SUCCESS;
 
assert (traps->is_rectilinear);
 
i = 4 * traps->num_traps;
 
events = stack_events;
event_ptrs = stack_event_ptrs;
edges = stack_edges;
if (i > ARRAY_LENGTH (stack_events)) {
events = _cairo_malloc_ab_plus_c (i,
sizeof (cairo_bo_event_t) +
sizeof (cairo_bo_edge_t) +
sizeof (cairo_bo_event_t *),
sizeof (cairo_bo_event_t *));
if (unlikely (events == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
event_ptrs = (cairo_bo_event_t **) (events + i);
edges = (cairo_bo_edge_t *) (event_ptrs + i + 1);
}
 
for (i = j = k = 0; i < traps->num_traps; i++) {
edges[k].edge.top = traps->traps[i].top;
edges[k].edge.bottom = traps->traps[i].bottom;
edges[k].edge.line = traps->traps[i].left;
edges[k].edge.dir = 1;
edges[k].deferred_trap.right = NULL;
edges[k].prev = NULL;
edges[k].next = NULL;
 
event_ptrs[j] = &events[j];
events[j].type = CAIRO_BO_EVENT_TYPE_START;
events[j].point.y = traps->traps[i].top;
events[j].point.x = traps->traps[i].left.p1.x;
events[j].edge = &edges[k];
j++;
 
event_ptrs[j] = &events[j];
events[j].type = CAIRO_BO_EVENT_TYPE_STOP;
events[j].point.y = traps->traps[i].bottom;
events[j].point.x = traps->traps[i].left.p1.x;
events[j].edge = &edges[k];
j++;
k++;
 
edges[k].edge.top = traps->traps[i].top;
edges[k].edge.bottom = traps->traps[i].bottom;
edges[k].edge.line = traps->traps[i].right;
edges[k].edge.dir = -1;
edges[k].deferred_trap.right = NULL;
edges[k].prev = NULL;
edges[k].next = NULL;
 
event_ptrs[j] = &events[j];
events[j].type = CAIRO_BO_EVENT_TYPE_START;
events[j].point.y = traps->traps[i].top;
events[j].point.x = traps->traps[i].right.p1.x;
events[j].edge = &edges[k];
j++;
 
event_ptrs[j] = &events[j];
events[j].type = CAIRO_BO_EVENT_TYPE_STOP;
events[j].point.y = traps->traps[i].bottom;
events[j].point.x = traps->traps[i].right.p1.x;
events[j].edge = &edges[k];
j++;
k++;
}
 
_cairo_traps_clear (traps);
status = _cairo_bentley_ottmann_tessellate_rectilinear (event_ptrs, j,
fill_rule,
TRUE, traps);
traps->is_rectilinear = TRUE;
 
if (events != stack_events)
free (events);
 
return status;
}
/programs/develop/libraries/cairo/src/cairo-bentley-ottmann.c
0,0 → 1,2133
/*
* Copyright © 2004 Carl Worth
* Copyright © 2006 Red Hat, Inc.
* Copyright © 2008 Chris Wilson
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Carl Worth
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
* Chris Wilson <chris@chris-wilson.co.uk>
*/
 
/* Provide definitions for standalone compilation */
#include "cairoint.h"
 
#include "cairo-error-private.h"
#include "cairo-freelist-private.h"
#include "cairo-combsort-private.h"
 
#define DEBUG_PRINT_STATE 0
#define DEBUG_EVENTS 0
#define DEBUG_TRAPS 0
 
typedef cairo_point_t cairo_bo_point32_t;
 
typedef struct _cairo_bo_intersect_ordinate {
int32_t ordinate;
enum { EXACT, INEXACT } exactness;
} cairo_bo_intersect_ordinate_t;
 
typedef struct _cairo_bo_intersect_point {
cairo_bo_intersect_ordinate_t x;
cairo_bo_intersect_ordinate_t y;
} cairo_bo_intersect_point_t;
 
typedef struct _cairo_bo_edge cairo_bo_edge_t;
typedef struct _cairo_bo_trap cairo_bo_trap_t;
 
/* A deferred trapezoid of an edge */
struct _cairo_bo_trap {
cairo_bo_edge_t *right;
int32_t top;
};
 
struct _cairo_bo_edge {
cairo_edge_t edge;
cairo_bo_edge_t *prev;
cairo_bo_edge_t *next;
cairo_bo_trap_t deferred_trap;
};
 
/* the parent is always given by index/2 */
#define PQ_PARENT_INDEX(i) ((i) >> 1)
#define PQ_FIRST_ENTRY 1
 
/* left and right children are index * 2 and (index * 2) +1 respectively */
#define PQ_LEFT_CHILD_INDEX(i) ((i) << 1)
 
typedef enum {
CAIRO_BO_EVENT_TYPE_STOP,
CAIRO_BO_EVENT_TYPE_INTERSECTION,
CAIRO_BO_EVENT_TYPE_START
} cairo_bo_event_type_t;
 
typedef struct _cairo_bo_event {
cairo_bo_event_type_t type;
cairo_point_t point;
} cairo_bo_event_t;
 
typedef struct _cairo_bo_start_event {
cairo_bo_event_type_t type;
cairo_point_t point;
cairo_bo_edge_t edge;
} cairo_bo_start_event_t;
 
typedef struct _cairo_bo_queue_event {
cairo_bo_event_type_t type;
cairo_point_t point;
cairo_bo_edge_t *e1;
cairo_bo_edge_t *e2;
} cairo_bo_queue_event_t;
 
typedef struct _pqueue {
int size, max_size;
 
cairo_bo_event_t **elements;
cairo_bo_event_t *elements_embedded[1024];
} pqueue_t;
 
typedef struct _cairo_bo_event_queue {
cairo_freepool_t pool;
pqueue_t pqueue;
cairo_bo_event_t **start_events;
} cairo_bo_event_queue_t;
 
typedef struct _cairo_bo_sweep_line {
cairo_bo_edge_t *head;
cairo_bo_edge_t *stopped;
int32_t current_y;
cairo_bo_edge_t *current_edge;
} cairo_bo_sweep_line_t;
 
#if DEBUG_TRAPS
static void
dump_traps (cairo_traps_t *traps, const char *filename)
{
FILE *file;
cairo_box_t extents;
int n;
 
if (getenv ("CAIRO_DEBUG_TRAPS") == NULL)
return;
 
#if 0
if (traps->has_limits) {
printf ("%s: limits=(%d, %d, %d, %d)\n",
filename,
traps->limits.p1.x, traps->limits.p1.y,
traps->limits.p2.x, traps->limits.p2.y);
}
#endif
_cairo_traps_extents (traps, &extents);
printf ("%s: extents=(%d, %d, %d, %d)\n",
filename,
extents.p1.x, extents.p1.y,
extents.p2.x, extents.p2.y);
 
file = fopen (filename, "a");
if (file != NULL) {
for (n = 0; n < traps->num_traps; n++) {
fprintf (file, "%d %d L:(%d, %d), (%d, %d) R:(%d, %d), (%d, %d)\n",
traps->traps[n].top,
traps->traps[n].bottom,
traps->traps[n].left.p1.x,
traps->traps[n].left.p1.y,
traps->traps[n].left.p2.x,
traps->traps[n].left.p2.y,
traps->traps[n].right.p1.x,
traps->traps[n].right.p1.y,
traps->traps[n].right.p2.x,
traps->traps[n].right.p2.y);
}
fprintf (file, "\n");
fclose (file);
}
}
 
static void
dump_edges (cairo_bo_start_event_t *events,
int num_edges,
const char *filename)
{
FILE *file;
int n;
 
if (getenv ("CAIRO_DEBUG_TRAPS") == NULL)
return;
 
file = fopen (filename, "a");
if (file != NULL) {
for (n = 0; n < num_edges; n++) {
fprintf (file, "(%d, %d), (%d, %d) %d %d %d\n",
events[n].edge.edge.line.p1.x,
events[n].edge.edge.line.p1.y,
events[n].edge.edge.line.p2.x,
events[n].edge.edge.line.p2.y,
events[n].edge.edge.top,
events[n].edge.edge.bottom,
events[n].edge.edge.dir);
}
fprintf (file, "\n");
fclose (file);
}
}
#endif
 
static cairo_fixed_t
_line_compute_intersection_x_for_y (const cairo_line_t *line,
cairo_fixed_t y)
{
cairo_fixed_t x, dy;
 
if (y == line->p1.y)
return line->p1.x;
if (y == line->p2.y)
return line->p2.x;
 
x = line->p1.x;
dy = line->p2.y - line->p1.y;
if (dy != 0) {
x += _cairo_fixed_mul_div_floor (y - line->p1.y,
line->p2.x - line->p1.x,
dy);
}
 
return x;
}
 
static inline int
_cairo_bo_point32_compare (cairo_bo_point32_t const *a,
cairo_bo_point32_t const *b)
{
int cmp;
 
cmp = a->y - b->y;
if (cmp)
return cmp;
 
return a->x - b->x;
}
 
/* Compare the slope of a to the slope of b, returning 1, 0, -1 if the
* slope a is respectively greater than, equal to, or less than the
* slope of b.
*
* For each edge, consider the direction vector formed from:
*
* top -> bottom
*
* which is:
*
* (dx, dy) = (line.p2.x - line.p1.x, line.p2.y - line.p1.y)
*
* We then define the slope of each edge as dx/dy, (which is the
* inverse of the slope typically used in math instruction). We never
* compute a slope directly as the value approaches infinity, but we
* can derive a slope comparison without division as follows, (where
* the ? represents our compare operator).
*
* 1. slope(a) ? slope(b)
* 2. adx/ady ? bdx/bdy
* 3. (adx * bdy) ? (bdx * ady)
*
* Note that from step 2 to step 3 there is no change needed in the
* sign of the result since both ady and bdy are guaranteed to be
* greater than or equal to 0.
*
* When using this slope comparison to sort edges, some care is needed
* when interpreting the results. Since the slope compare operates on
* distance vectors from top to bottom it gives a correct left to
* right sort for edges that have a common top point, (such as two
* edges with start events at the same location). On the other hand,
* the sense of the result will be exactly reversed for two edges that
* have a common stop point.
*/
static inline int
_slope_compare (const cairo_bo_edge_t *a,
const cairo_bo_edge_t *b)
{
/* XXX: We're assuming here that dx and dy will still fit in 32
* bits. That's not true in general as there could be overflow. We
* should prevent that before the tessellation algorithm
* begins.
*/
int32_t adx = a->edge.line.p2.x - a->edge.line.p1.x;
int32_t bdx = b->edge.line.p2.x - b->edge.line.p1.x;
 
/* Since the dy's are all positive by construction we can fast
* path several common cases.
*/
 
/* First check for vertical lines. */
if (adx == 0)
return -bdx;
if (bdx == 0)
return adx;
 
/* Then where the two edges point in different directions wrt x. */
if ((adx ^ bdx) < 0)
return adx;
 
/* Finally we actually need to do the general comparison. */
{
int32_t ady = a->edge.line.p2.y - a->edge.line.p1.y;
int32_t bdy = b->edge.line.p2.y - b->edge.line.p1.y;
cairo_int64_t adx_bdy = _cairo_int32x32_64_mul (adx, bdy);
cairo_int64_t bdx_ady = _cairo_int32x32_64_mul (bdx, ady);
 
return _cairo_int64_cmp (adx_bdy, bdx_ady);
}
}
 
/*
* We need to compare the x-coordinates of a pair of lines for a particular y,
* without loss of precision.
*
* The x-coordinate along an edge for a given y is:
* X = A_x + (Y - A_y) * A_dx / A_dy
*
* So the inequality we wish to test is:
* A_x + (Y - A_y) * A_dx / A_dy ∘ B_x + (Y - B_y) * B_dx / B_dy,
* where ∘ is our inequality operator.
*
* By construction, we know that A_dy and B_dy (and (Y - A_y), (Y - B_y)) are
* all positive, so we can rearrange it thus without causing a sign change:
* A_dy * B_dy * (A_x - B_x) ∘ (Y - B_y) * B_dx * A_dy
* - (Y - A_y) * A_dx * B_dy
*
* Given the assumption that all the deltas fit within 32 bits, we can compute
* this comparison directly using 128 bit arithmetic. For certain, but common,
* input we can reduce this down to a single 32 bit compare by inspecting the
* deltas.
*
* (And put the burden of the work on developing fast 128 bit ops, which are
* required throughout the tessellator.)
*
* See the similar discussion for _slope_compare().
*/
static int
edges_compare_x_for_y_general (const cairo_bo_edge_t *a,
const cairo_bo_edge_t *b,
int32_t y)
{
/* XXX: We're assuming here that dx and dy will still fit in 32
* bits. That's not true in general as there could be overflow. We
* should prevent that before the tessellation algorithm
* begins.
*/
int32_t dx;
int32_t adx, ady;
int32_t bdx, bdy;
enum {
HAVE_NONE = 0x0,
HAVE_DX = 0x1,
HAVE_ADX = 0x2,
HAVE_DX_ADX = HAVE_DX | HAVE_ADX,
HAVE_BDX = 0x4,
HAVE_DX_BDX = HAVE_DX | HAVE_BDX,
HAVE_ADX_BDX = HAVE_ADX | HAVE_BDX,
HAVE_ALL = HAVE_DX | HAVE_ADX | HAVE_BDX
} have_dx_adx_bdx = HAVE_ALL;
 
/* don't bother solving for abscissa if the edges' bounding boxes
* can be used to order them. */
{
int32_t amin, amax;
int32_t bmin, bmax;
if (a->edge.line.p1.x < a->edge.line.p2.x) {
amin = a->edge.line.p1.x;
amax = a->edge.line.p2.x;
} else {
amin = a->edge.line.p2.x;
amax = a->edge.line.p1.x;
}
if (b->edge.line.p1.x < b->edge.line.p2.x) {
bmin = b->edge.line.p1.x;
bmax = b->edge.line.p2.x;
} else {
bmin = b->edge.line.p2.x;
bmax = b->edge.line.p1.x;
}
if (amax < bmin) return -1;
if (amin > bmax) return +1;
}
 
ady = a->edge.line.p2.y - a->edge.line.p1.y;
adx = a->edge.line.p2.x - a->edge.line.p1.x;
if (adx == 0)
have_dx_adx_bdx &= ~HAVE_ADX;
 
bdy = b->edge.line.p2.y - b->edge.line.p1.y;
bdx = b->edge.line.p2.x - b->edge.line.p1.x;
if (bdx == 0)
have_dx_adx_bdx &= ~HAVE_BDX;
 
dx = a->edge.line.p1.x - b->edge.line.p1.x;
if (dx == 0)
have_dx_adx_bdx &= ~HAVE_DX;
 
#define L _cairo_int64x32_128_mul (_cairo_int32x32_64_mul (ady, bdy), dx)
#define A _cairo_int64x32_128_mul (_cairo_int32x32_64_mul (adx, bdy), y - a->edge.line.p1.y)
#define B _cairo_int64x32_128_mul (_cairo_int32x32_64_mul (bdx, ady), y - b->edge.line.p1.y)
switch (have_dx_adx_bdx) {
default:
case HAVE_NONE:
return 0;
case HAVE_DX:
/* A_dy * B_dy * (A_x - B_x) ∘ 0 */
return dx; /* ady * bdy is positive definite */
case HAVE_ADX:
/* 0 ∘ - (Y - A_y) * A_dx * B_dy */
return adx; /* bdy * (y - a->top.y) is positive definite */
case HAVE_BDX:
/* 0 ∘ (Y - B_y) * B_dx * A_dy */
return -bdx; /* ady * (y - b->top.y) is positive definite */
case HAVE_ADX_BDX:
/* 0 ∘ (Y - B_y) * B_dx * A_dy - (Y - A_y) * A_dx * B_dy */
if ((adx ^ bdx) < 0) {
return adx;
} else if (a->edge.line.p1.y == b->edge.line.p1.y) { /* common origin */
cairo_int64_t adx_bdy, bdx_ady;
 
/* ∴ A_dx * B_dy ∘ B_dx * A_dy */
 
adx_bdy = _cairo_int32x32_64_mul (adx, bdy);
bdx_ady = _cairo_int32x32_64_mul (bdx, ady);
 
return _cairo_int64_cmp (adx_bdy, bdx_ady);
} else
return _cairo_int128_cmp (A, B);
case HAVE_DX_ADX:
/* A_dy * (A_x - B_x) ∘ - (Y - A_y) * A_dx */
if ((-adx ^ dx) < 0) {
return dx;
} else {
cairo_int64_t ady_dx, dy_adx;
 
ady_dx = _cairo_int32x32_64_mul (ady, dx);
dy_adx = _cairo_int32x32_64_mul (a->edge.line.p1.y - y, adx);
 
return _cairo_int64_cmp (ady_dx, dy_adx);
}
case HAVE_DX_BDX:
/* B_dy * (A_x - B_x) ∘ (Y - B_y) * B_dx */
if ((bdx ^ dx) < 0) {
return dx;
} else {
cairo_int64_t bdy_dx, dy_bdx;
 
bdy_dx = _cairo_int32x32_64_mul (bdy, dx);
dy_bdx = _cairo_int32x32_64_mul (y - b->edge.line.p1.y, bdx);
 
return _cairo_int64_cmp (bdy_dx, dy_bdx);
}
case HAVE_ALL:
/* XXX try comparing (a->edge.line.p2.x - b->edge.line.p2.x) et al */
return _cairo_int128_cmp (L, _cairo_int128_sub (B, A));
}
#undef B
#undef A
#undef L
}
 
/*
* We need to compare the x-coordinate of a line for a particular y wrt to a
* given x, without loss of precision.
*
* The x-coordinate along an edge for a given y is:
* X = A_x + (Y - A_y) * A_dx / A_dy
*
* So the inequality we wish to test is:
* A_x + (Y - A_y) * A_dx / A_dy ∘ X
* where ∘ is our inequality operator.
*
* By construction, we know that A_dy (and (Y - A_y)) are
* all positive, so we can rearrange it thus without causing a sign change:
* (Y - A_y) * A_dx ∘ (X - A_x) * A_dy
*
* Given the assumption that all the deltas fit within 32 bits, we can compute
* this comparison directly using 64 bit arithmetic.
*
* See the similar discussion for _slope_compare() and
* edges_compare_x_for_y_general().
*/
static int
edge_compare_for_y_against_x (const cairo_bo_edge_t *a,
int32_t y,
int32_t x)
{
int32_t adx, ady;
int32_t dx, dy;
cairo_int64_t L, R;
 
if (x < a->edge.line.p1.x && x < a->edge.line.p2.x)
return 1;
if (x > a->edge.line.p1.x && x > a->edge.line.p2.x)
return -1;
 
adx = a->edge.line.p2.x - a->edge.line.p1.x;
dx = x - a->edge.line.p1.x;
 
if (adx == 0)
return -dx;
if (dx == 0 || (adx ^ dx) < 0)
return adx;
 
dy = y - a->edge.line.p1.y;
ady = a->edge.line.p2.y - a->edge.line.p1.y;
 
L = _cairo_int32x32_64_mul (dy, adx);
R = _cairo_int32x32_64_mul (dx, ady);
 
return _cairo_int64_cmp (L, R);
}
 
static int
edges_compare_x_for_y (const cairo_bo_edge_t *a,
const cairo_bo_edge_t *b,
int32_t y)
{
/* If the sweep-line is currently on an end-point of a line,
* then we know its precise x value (and considering that we often need to
* compare events at end-points, this happens frequently enough to warrant
* special casing).
*/
enum {
HAVE_NEITHER = 0x0,
HAVE_AX = 0x1,
HAVE_BX = 0x2,
HAVE_BOTH = HAVE_AX | HAVE_BX
} have_ax_bx = HAVE_BOTH;
int32_t ax, bx;
 
if (y == a->edge.line.p1.y)
ax = a->edge.line.p1.x;
else if (y == a->edge.line.p2.y)
ax = a->edge.line.p2.x;
else
have_ax_bx &= ~HAVE_AX;
 
if (y == b->edge.line.p1.y)
bx = b->edge.line.p1.x;
else if (y == b->edge.line.p2.y)
bx = b->edge.line.p2.x;
else
have_ax_bx &= ~HAVE_BX;
 
switch (have_ax_bx) {
default:
case HAVE_NEITHER:
return edges_compare_x_for_y_general (a, b, y);
case HAVE_AX:
return -edge_compare_for_y_against_x (b, y, ax);
case HAVE_BX:
return edge_compare_for_y_against_x (a, y, bx);
case HAVE_BOTH:
return ax - bx;
}
}
 
static inline int
_line_equal (const cairo_line_t *a, const cairo_line_t *b)
{
return a->p1.x == b->p1.x && a->p1.y == b->p1.y &&
a->p2.x == b->p2.x && a->p2.y == b->p2.y;
}
 
static int
_cairo_bo_sweep_line_compare_edges (cairo_bo_sweep_line_t *sweep_line,
const cairo_bo_edge_t *a,
const cairo_bo_edge_t *b)
{
int cmp;
 
/* compare the edges if not identical */
if (! _line_equal (&a->edge.line, &b->edge.line)) {
cmp = edges_compare_x_for_y (a, b, sweep_line->current_y);
if (cmp)
return cmp;
 
/* The two edges intersect exactly at y, so fall back on slope
* comparison. We know that this compare_edges function will be
* called only when starting a new edge, (not when stopping an
* edge), so we don't have to worry about conditionally inverting
* the sense of _slope_compare. */
cmp = _slope_compare (a, b);
if (cmp)
return cmp;
}
 
/* We've got two collinear edges now. */
return b->edge.bottom - a->edge.bottom;
}
 
static inline cairo_int64_t
det32_64 (int32_t a, int32_t b,
int32_t c, int32_t d)
{
/* det = a * d - b * c */
return _cairo_int64_sub (_cairo_int32x32_64_mul (a, d),
_cairo_int32x32_64_mul (b, c));
}
 
static inline cairo_int128_t
det64x32_128 (cairo_int64_t a, int32_t b,
cairo_int64_t c, int32_t d)
{
/* det = a * d - b * c */
return _cairo_int128_sub (_cairo_int64x32_128_mul (a, d),
_cairo_int64x32_128_mul (c, b));
}
 
/* Compute the intersection of two lines as defined by two edges. The
* result is provided as a coordinate pair of 128-bit integers.
*
* Returns %CAIRO_BO_STATUS_INTERSECTION if there is an intersection or
* %CAIRO_BO_STATUS_PARALLEL if the two lines are exactly parallel.
*/
static cairo_bool_t
intersect_lines (cairo_bo_edge_t *a,
cairo_bo_edge_t *b,
cairo_bo_intersect_point_t *intersection)
{
cairo_int64_t a_det, b_det;
 
/* XXX: We're assuming here that dx and dy will still fit in 32
* bits. That's not true in general as there could be overflow. We
* should prevent that before the tessellation algorithm begins.
* What we're doing to mitigate this is to perform clamping in
* cairo_bo_tessellate_polygon().
*/
int32_t dx1 = a->edge.line.p1.x - a->edge.line.p2.x;
int32_t dy1 = a->edge.line.p1.y - a->edge.line.p2.y;
 
int32_t dx2 = b->edge.line.p1.x - b->edge.line.p2.x;
int32_t dy2 = b->edge.line.p1.y - b->edge.line.p2.y;
 
cairo_int64_t den_det;
cairo_int64_t R;
cairo_quorem64_t qr;
 
den_det = det32_64 (dx1, dy1, dx2, dy2);
 
/* Q: Can we determine that the lines do not intersect (within range)
* much more cheaply than computing the intersection point i.e. by
* avoiding the division?
*
* X = ax + t * adx = bx + s * bdx;
* Y = ay + t * ady = by + s * bdy;
* ∴ t * (ady*bdx - bdy*adx) = bdx * (by - ay) + bdy * (ax - bx)
* => t * L = R
*
* Therefore we can reject any intersection (under the criteria for
* valid intersection events) if:
* L^R < 0 => t < 0, or
* L<R => t > 1
*
* (where top/bottom must at least extend to the line endpoints).
*
* A similar substitution can be performed for s, yielding:
* s * (ady*bdx - bdy*adx) = ady * (ax - bx) - adx * (ay - by)
*/
R = det32_64 (dx2, dy2,
b->edge.line.p1.x - a->edge.line.p1.x,
b->edge.line.p1.y - a->edge.line.p1.y);
if (_cairo_int64_negative (den_det)) {
if (_cairo_int64_ge (den_det, R))
return FALSE;
} else {
if (_cairo_int64_le (den_det, R))
return FALSE;
}
 
R = det32_64 (dy1, dx1,
a->edge.line.p1.y - b->edge.line.p1.y,
a->edge.line.p1.x - b->edge.line.p1.x);
if (_cairo_int64_negative (den_det)) {
if (_cairo_int64_ge (den_det, R))
return FALSE;
} else {
if (_cairo_int64_le (den_det, R))
return FALSE;
}
 
/* We now know that the two lines should intersect within range. */
 
a_det = det32_64 (a->edge.line.p1.x, a->edge.line.p1.y,
a->edge.line.p2.x, a->edge.line.p2.y);
b_det = det32_64 (b->edge.line.p1.x, b->edge.line.p1.y,
b->edge.line.p2.x, b->edge.line.p2.y);
 
/* x = det (a_det, dx1, b_det, dx2) / den_det */
qr = _cairo_int_96by64_32x64_divrem (det64x32_128 (a_det, dx1,
b_det, dx2),
den_det);
if (_cairo_int64_eq (qr.rem, den_det))
return FALSE;
#if 0
intersection->x.exactness = _cairo_int64_is_zero (qr.rem) ? EXACT : INEXACT;
#else
intersection->x.exactness = EXACT;
if (! _cairo_int64_is_zero (qr.rem)) {
if (_cairo_int64_negative (den_det) ^ _cairo_int64_negative (qr.rem))
qr.rem = _cairo_int64_negate (qr.rem);
qr.rem = _cairo_int64_mul (qr.rem, _cairo_int32_to_int64 (2));
if (_cairo_int64_ge (qr.rem, den_det)) {
qr.quo = _cairo_int64_add (qr.quo,
_cairo_int32_to_int64 (_cairo_int64_negative (qr.quo) ? -1 : 1));
} else
intersection->x.exactness = INEXACT;
}
#endif
intersection->x.ordinate = _cairo_int64_to_int32 (qr.quo);
 
/* y = det (a_det, dy1, b_det, dy2) / den_det */
qr = _cairo_int_96by64_32x64_divrem (det64x32_128 (a_det, dy1,
b_det, dy2),
den_det);
if (_cairo_int64_eq (qr.rem, den_det))
return FALSE;
#if 0
intersection->y.exactness = _cairo_int64_is_zero (qr.rem) ? EXACT : INEXACT;
#else
intersection->y.exactness = EXACT;
if (! _cairo_int64_is_zero (qr.rem)) {
if (_cairo_int64_negative (den_det) ^ _cairo_int64_negative (qr.rem))
qr.rem = _cairo_int64_negate (qr.rem);
qr.rem = _cairo_int64_mul (qr.rem, _cairo_int32_to_int64 (2));
if (_cairo_int64_ge (qr.rem, den_det)) {
qr.quo = _cairo_int64_add (qr.quo,
_cairo_int32_to_int64 (_cairo_int64_negative (qr.quo) ? -1 : 1));
} else
intersection->y.exactness = INEXACT;
}
#endif
intersection->y.ordinate = _cairo_int64_to_int32 (qr.quo);
 
return TRUE;
}
 
static int
_cairo_bo_intersect_ordinate_32_compare (cairo_bo_intersect_ordinate_t a,
int32_t b)
{
/* First compare the quotient */
if (a.ordinate > b)
return +1;
if (a.ordinate < b)
return -1;
/* With quotient identical, if remainder is 0 then compare equal */
/* Otherwise, the non-zero remainder makes a > b */
return INEXACT == a.exactness;
}
 
/* Does the given edge contain the given point. The point must already
* be known to be contained within the line determined by the edge,
* (most likely the point results from an intersection of this edge
* with another).
*
* If we had exact arithmetic, then this function would simply be a
* matter of examining whether the y value of the point lies within
* the range of y values of the edge. But since intersection points
* are not exact due to being rounded to the nearest integer within
* the available precision, we must also examine the x value of the
* point.
*
* The definition of "contains" here is that the given intersection
* point will be seen by the sweep line after the start event for the
* given edge and before the stop event for the edge. See the comments
* in the implementation for more details.
*/
static cairo_bool_t
_cairo_bo_edge_contains_intersect_point (cairo_bo_edge_t *edge,
cairo_bo_intersect_point_t *point)
{
int cmp_top, cmp_bottom;
 
/* XXX: When running the actual algorithm, we don't actually need to
* compare against edge->top at all here, since any intersection above
* top is eliminated early via a slope comparison. We're leaving these
* here for now only for the sake of the quadratic-time intersection
* finder which needs them.
*/
 
cmp_top = _cairo_bo_intersect_ordinate_32_compare (point->y,
edge->edge.top);
cmp_bottom = _cairo_bo_intersect_ordinate_32_compare (point->y,
edge->edge.bottom);
 
if (cmp_top < 0 || cmp_bottom > 0)
{
return FALSE;
}
 
if (cmp_top > 0 && cmp_bottom < 0)
{
return TRUE;
}
 
/* At this stage, the point lies on the same y value as either
* edge->top or edge->bottom, so we have to examine the x value in
* order to properly determine containment. */
 
/* If the y value of the point is the same as the y value of the
* top of the edge, then the x value of the point must be greater
* to be considered as inside the edge. Similarly, if the y value
* of the point is the same as the y value of the bottom of the
* edge, then the x value of the point must be less to be
* considered as inside. */
 
if (cmp_top == 0) {
cairo_fixed_t top_x;
 
top_x = _line_compute_intersection_x_for_y (&edge->edge.line,
edge->edge.top);
return _cairo_bo_intersect_ordinate_32_compare (point->x, top_x) > 0;
} else { /* cmp_bottom == 0 */
cairo_fixed_t bot_x;
 
bot_x = _line_compute_intersection_x_for_y (&edge->edge.line,
edge->edge.bottom);
return _cairo_bo_intersect_ordinate_32_compare (point->x, bot_x) < 0;
}
}
 
/* Compute the intersection of two edges. The result is provided as a
* coordinate pair of 128-bit integers.
*
* Returns %CAIRO_BO_STATUS_INTERSECTION if there is an intersection
* that is within both edges, %CAIRO_BO_STATUS_NO_INTERSECTION if the
* intersection of the lines defined by the edges occurs outside of
* one or both edges, and %CAIRO_BO_STATUS_PARALLEL if the two edges
* are exactly parallel.
*
* Note that when determining if a candidate intersection is "inside"
* an edge, we consider both the infinitesimal shortening and the
* infinitesimal tilt rules described by John Hobby. Specifically, if
* the intersection is exactly the same as an edge point, it is
* effectively outside (no intersection is returned). Also, if the
* intersection point has the same
*/
static cairo_bool_t
_cairo_bo_edge_intersect (cairo_bo_edge_t *a,
cairo_bo_edge_t *b,
cairo_bo_point32_t *intersection)
{
cairo_bo_intersect_point_t quorem;
 
if (! intersect_lines (a, b, &quorem))
return FALSE;
 
if (! _cairo_bo_edge_contains_intersect_point (a, &quorem))
return FALSE;
 
if (! _cairo_bo_edge_contains_intersect_point (b, &quorem))
return FALSE;
 
/* Now that we've correctly compared the intersection point and
* determined that it lies within the edge, then we know that we
* no longer need any more bits of storage for the intersection
* than we do for our edge coordinates. We also no longer need the
* remainder from the division. */
intersection->x = quorem.x.ordinate;
intersection->y = quorem.y.ordinate;
 
return TRUE;
}
 
static inline int
cairo_bo_event_compare (const cairo_bo_event_t *a,
const cairo_bo_event_t *b)
{
int cmp;
 
cmp = _cairo_bo_point32_compare (&a->point, &b->point);
if (cmp)
return cmp;
 
cmp = a->type - b->type;
if (cmp)
return cmp;
 
return a - b;
}
 
static inline void
_pqueue_init (pqueue_t *pq)
{
pq->max_size = ARRAY_LENGTH (pq->elements_embedded);
pq->size = 0;
 
pq->elements = pq->elements_embedded;
}
 
static inline void
_pqueue_fini (pqueue_t *pq)
{
if (pq->elements != pq->elements_embedded)
free (pq->elements);
}
 
static cairo_status_t
_pqueue_grow (pqueue_t *pq)
{
cairo_bo_event_t **new_elements;
pq->max_size *= 2;
 
if (pq->elements == pq->elements_embedded) {
new_elements = _cairo_malloc_ab (pq->max_size,
sizeof (cairo_bo_event_t *));
if (unlikely (new_elements == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
memcpy (new_elements, pq->elements_embedded,
sizeof (pq->elements_embedded));
} else {
new_elements = _cairo_realloc_ab (pq->elements,
pq->max_size,
sizeof (cairo_bo_event_t *));
if (unlikely (new_elements == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
 
pq->elements = new_elements;
return CAIRO_STATUS_SUCCESS;
}
 
static inline cairo_status_t
_pqueue_push (pqueue_t *pq, cairo_bo_event_t *event)
{
cairo_bo_event_t **elements;
int i, parent;
 
if (unlikely (pq->size + 1 == pq->max_size)) {
cairo_status_t status;
 
status = _pqueue_grow (pq);
if (unlikely (status))
return status;
}
 
elements = pq->elements;
 
for (i = ++pq->size;
i != PQ_FIRST_ENTRY &&
cairo_bo_event_compare (event,
elements[parent = PQ_PARENT_INDEX (i)]) < 0;
i = parent)
{
elements[i] = elements[parent];
}
 
elements[i] = event;
 
return CAIRO_STATUS_SUCCESS;
}
 
static inline void
_pqueue_pop (pqueue_t *pq)
{
cairo_bo_event_t **elements = pq->elements;
cairo_bo_event_t *tail;
int child, i;
 
tail = elements[pq->size--];
if (pq->size == 0) {
elements[PQ_FIRST_ENTRY] = NULL;
return;
}
 
for (i = PQ_FIRST_ENTRY;
(child = PQ_LEFT_CHILD_INDEX (i)) <= pq->size;
i = child)
{
if (child != pq->size &&
cairo_bo_event_compare (elements[child+1],
elements[child]) < 0)
{
child++;
}
 
if (cairo_bo_event_compare (elements[child], tail) >= 0)
break;
 
elements[i] = elements[child];
}
elements[i] = tail;
}
 
static inline cairo_status_t
_cairo_bo_event_queue_insert (cairo_bo_event_queue_t *queue,
cairo_bo_event_type_t type,
cairo_bo_edge_t *e1,
cairo_bo_edge_t *e2,
const cairo_point_t *point)
{
cairo_bo_queue_event_t *event;
 
event = _cairo_freepool_alloc (&queue->pool);
if (unlikely (event == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
event->type = type;
event->e1 = e1;
event->e2 = e2;
event->point = *point;
 
return _pqueue_push (&queue->pqueue, (cairo_bo_event_t *) event);
}
 
static void
_cairo_bo_event_queue_delete (cairo_bo_event_queue_t *queue,
cairo_bo_event_t *event)
{
_cairo_freepool_free (&queue->pool, event);
}
 
static cairo_bo_event_t *
_cairo_bo_event_dequeue (cairo_bo_event_queue_t *event_queue)
{
cairo_bo_event_t *event, *cmp;
 
event = event_queue->pqueue.elements[PQ_FIRST_ENTRY];
cmp = *event_queue->start_events;
if (event == NULL ||
(cmp != NULL && cairo_bo_event_compare (cmp, event) < 0))
{
event = cmp;
event_queue->start_events++;
}
else
{
_pqueue_pop (&event_queue->pqueue);
}
 
return event;
}
 
CAIRO_COMBSORT_DECLARE (_cairo_bo_event_queue_sort,
cairo_bo_event_t *,
cairo_bo_event_compare)
 
static void
_cairo_bo_event_queue_init (cairo_bo_event_queue_t *event_queue,
cairo_bo_event_t **start_events,
int num_events)
{
_cairo_bo_event_queue_sort (start_events, num_events);
start_events[num_events] = NULL;
 
event_queue->start_events = start_events;
 
_cairo_freepool_init (&event_queue->pool,
sizeof (cairo_bo_queue_event_t));
_pqueue_init (&event_queue->pqueue);
event_queue->pqueue.elements[PQ_FIRST_ENTRY] = NULL;
}
 
static cairo_status_t
_cairo_bo_event_queue_insert_stop (cairo_bo_event_queue_t *event_queue,
cairo_bo_edge_t *edge)
{
cairo_bo_point32_t point;
 
point.y = edge->edge.bottom;
point.x = _line_compute_intersection_x_for_y (&edge->edge.line,
point.y);
return _cairo_bo_event_queue_insert (event_queue,
CAIRO_BO_EVENT_TYPE_STOP,
edge, NULL,
&point);
}
 
static void
_cairo_bo_event_queue_fini (cairo_bo_event_queue_t *event_queue)
{
_pqueue_fini (&event_queue->pqueue);
_cairo_freepool_fini (&event_queue->pool);
}
 
static inline cairo_status_t
_cairo_bo_event_queue_insert_if_intersect_below_current_y (cairo_bo_event_queue_t *event_queue,
cairo_bo_edge_t *left,
cairo_bo_edge_t *right)
{
cairo_bo_point32_t intersection;
 
if (_line_equal (&left->edge.line, &right->edge.line))
return CAIRO_STATUS_SUCCESS;
 
/* The names "left" and "right" here are correct descriptions of
* the order of the two edges within the active edge list. So if a
* slope comparison also puts left less than right, then we know
* that the intersection of these two segments has already
* occurred before the current sweep line position. */
if (_slope_compare (left, right) <= 0)
return CAIRO_STATUS_SUCCESS;
 
if (! _cairo_bo_edge_intersect (left, right, &intersection))
return CAIRO_STATUS_SUCCESS;
 
return _cairo_bo_event_queue_insert (event_queue,
CAIRO_BO_EVENT_TYPE_INTERSECTION,
left, right,
&intersection);
}
 
static void
_cairo_bo_sweep_line_init (cairo_bo_sweep_line_t *sweep_line)
{
sweep_line->head = NULL;
sweep_line->stopped = NULL;
sweep_line->current_y = INT32_MIN;
sweep_line->current_edge = NULL;
}
 
static cairo_status_t
_cairo_bo_sweep_line_insert (cairo_bo_sweep_line_t *sweep_line,
cairo_bo_edge_t *edge)
{
if (sweep_line->current_edge != NULL) {
cairo_bo_edge_t *prev, *next;
int cmp;
 
cmp = _cairo_bo_sweep_line_compare_edges (sweep_line,
sweep_line->current_edge,
edge);
if (cmp < 0) {
prev = sweep_line->current_edge;
next = prev->next;
while (next != NULL &&
_cairo_bo_sweep_line_compare_edges (sweep_line,
next, edge) < 0)
{
prev = next, next = prev->next;
}
 
prev->next = edge;
edge->prev = prev;
edge->next = next;
if (next != NULL)
next->prev = edge;
} else if (cmp > 0) {
next = sweep_line->current_edge;
prev = next->prev;
while (prev != NULL &&
_cairo_bo_sweep_line_compare_edges (sweep_line,
prev, edge) > 0)
{
next = prev, prev = next->prev;
}
 
next->prev = edge;
edge->next = next;
edge->prev = prev;
if (prev != NULL)
prev->next = edge;
else
sweep_line->head = edge;
} else {
prev = sweep_line->current_edge;
edge->prev = prev;
edge->next = prev->next;
if (prev->next != NULL)
prev->next->prev = edge;
prev->next = edge;
}
} else {
sweep_line->head = edge;
}
 
sweep_line->current_edge = edge;
 
return CAIRO_STATUS_SUCCESS;
}
 
static void
_cairo_bo_sweep_line_delete (cairo_bo_sweep_line_t *sweep_line,
cairo_bo_edge_t *edge)
{
if (edge->prev != NULL)
edge->prev->next = edge->next;
else
sweep_line->head = edge->next;
 
if (edge->next != NULL)
edge->next->prev = edge->prev;
 
if (sweep_line->current_edge == edge)
sweep_line->current_edge = edge->prev ? edge->prev : edge->next;
}
 
static void
_cairo_bo_sweep_line_swap (cairo_bo_sweep_line_t *sweep_line,
cairo_bo_edge_t *left,
cairo_bo_edge_t *right)
{
if (left->prev != NULL)
left->prev->next = right;
else
sweep_line->head = right;
 
if (right->next != NULL)
right->next->prev = left;
 
left->next = right->next;
right->next = left;
 
right->prev = left->prev;
left->prev = right;
}
 
#if DEBUG_PRINT_STATE
static void
_cairo_bo_edge_print (cairo_bo_edge_t *edge)
{
printf ("(0x%x, 0x%x)-(0x%x, 0x%x)",
edge->edge.line.p1.x, edge->edge.line.p1.y,
edge->edge.line.p2.x, edge->edge.line.p2.y);
}
 
static void
_cairo_bo_event_print (cairo_bo_event_t *event)
{
switch (event->type) {
case CAIRO_BO_EVENT_TYPE_START:
printf ("Start: ");
break;
case CAIRO_BO_EVENT_TYPE_STOP:
printf ("Stop: ");
break;
case CAIRO_BO_EVENT_TYPE_INTERSECTION:
printf ("Intersection: ");
break;
}
printf ("(%d, %d)\t", event->point.x, event->point.y);
_cairo_bo_edge_print (event->e1);
if (event->type == CAIRO_BO_EVENT_TYPE_INTERSECTION) {
printf (" X ");
_cairo_bo_edge_print (event->e2);
}
printf ("\n");
}
 
static void
_cairo_bo_event_queue_print (cairo_bo_event_queue_t *event_queue)
{
/* XXX: fixme to print the start/stop array too. */
printf ("Event queue:\n");
}
 
static void
_cairo_bo_sweep_line_print (cairo_bo_sweep_line_t *sweep_line)
{
cairo_bool_t first = TRUE;
cairo_bo_edge_t *edge;
 
printf ("Sweep line from edge list: ");
first = TRUE;
for (edge = sweep_line->head;
edge;
edge = edge->next)
{
if (!first)
printf (", ");
_cairo_bo_edge_print (edge);
first = FALSE;
}
printf ("\n");
}
 
static void
print_state (const char *msg,
cairo_bo_event_t *event,
cairo_bo_event_queue_t *event_queue,
cairo_bo_sweep_line_t *sweep_line)
{
printf ("%s ", msg);
_cairo_bo_event_print (event);
_cairo_bo_event_queue_print (event_queue);
_cairo_bo_sweep_line_print (sweep_line);
printf ("\n");
}
#endif
 
#if DEBUG_EVENTS
static void CAIRO_PRINTF_FORMAT (1, 2)
event_log (const char *fmt, ...)
{
FILE *file;
 
if (getenv ("CAIRO_DEBUG_EVENTS") == NULL)
return;
 
file = fopen ("bo-events.txt", "a");
if (file != NULL) {
va_list ap;
 
va_start (ap, fmt);
vfprintf (file, fmt, ap);
va_end (ap);
 
fclose (file);
}
}
#endif
 
static inline cairo_bool_t
edges_colinear (const cairo_bo_edge_t *a, const cairo_bo_edge_t *b)
{
if (_line_equal (&a->edge.line, &b->edge.line))
return TRUE;
 
if (_slope_compare (a, b))
return FALSE;
 
/* The choice of y is not truly arbitrary since we must guarantee that it
* is greater than the start of either line.
*/
if (a->edge.line.p1.y == b->edge.line.p1.y) {
return a->edge.line.p1.x == b->edge.line.p1.x;
} else if (a->edge.line.p1.y < b->edge.line.p1.y) {
return edge_compare_for_y_against_x (b,
a->edge.line.p1.y,
a->edge.line.p1.x) == 0;
} else {
return edge_compare_for_y_against_x (a,
b->edge.line.p1.y,
b->edge.line.p1.x) == 0;
}
}
 
/* Adds the trapezoid, if any, of the left edge to the #cairo_traps_t */
static cairo_status_t
_cairo_bo_edge_end_trap (cairo_bo_edge_t *left,
int32_t bot,
cairo_traps_t *traps)
{
cairo_bo_trap_t *trap = &left->deferred_trap;
 
/* Only emit (trivial) non-degenerate trapezoids with positive height. */
if (likely (trap->top < bot)) {
_cairo_traps_add_trap (traps,
trap->top, bot,
&left->edge.line, &trap->right->edge.line);
 
#if DEBUG_PRINT_STATE
printf ("Deferred trap: left=(%x, %x)-(%x,%x) "
"right=(%x,%x)-(%x,%x) top=%x, bot=%x\n",
left->edge.line.p1.x, left->edge.line.p1.y,
left->edge.line.p2.x, left->edge.line.p2.y,
trap->right->edge.line.p1.x, trap->right->edge.line.p1.y,
trap->right->edge.line.p2.x, trap->right->edge.line.p2.y,
trap->top, bot);
#endif
#if DEBUG_EVENTS
event_log ("end trap: %lu %lu %d %d\n",
(long) left,
(long) trap->right,
trap->top,
bot);
#endif
}
 
trap->right = NULL;
 
return _cairo_traps_status (traps);
}
 
 
/* Start a new trapezoid at the given top y coordinate, whose edges
* are `edge' and `edge->next'. If `edge' already has a trapezoid,
* then either add it to the traps in `traps', if the trapezoid's
* right edge differs from `edge->next', or do nothing if the new
* trapezoid would be a continuation of the existing one. */
static inline cairo_status_t
_cairo_bo_edge_start_or_continue_trap (cairo_bo_edge_t *left,
cairo_bo_edge_t *right,
int top,
cairo_traps_t *traps)
{
cairo_status_t status;
 
if (left->deferred_trap.right == right)
return CAIRO_STATUS_SUCCESS;
 
if (left->deferred_trap.right != NULL) {
if (right != NULL && edges_colinear (left->deferred_trap.right, right))
{
/* continuation on right, so just swap edges */
left->deferred_trap.right = right;
return CAIRO_STATUS_SUCCESS;
}
 
status = _cairo_bo_edge_end_trap (left, top, traps);
if (unlikely (status))
return status;
}
 
if (right != NULL && ! edges_colinear (left, right)) {
left->deferred_trap.top = top;
left->deferred_trap.right = right;
 
#if DEBUG_EVENTS
event_log ("begin trap: %lu %lu %d\n",
(long) left,
(long) right,
top);
#endif
}
 
return CAIRO_STATUS_SUCCESS;
}
 
static inline cairo_status_t
_active_edges_to_traps (cairo_bo_edge_t *left,
int32_t top,
cairo_fill_rule_t fill_rule,
cairo_traps_t *traps)
{
cairo_bo_edge_t *right;
cairo_status_t status;
 
#if DEBUG_PRINT_STATE
printf ("Processing active edges for %x\n", top);
#endif
 
if (fill_rule == CAIRO_FILL_RULE_WINDING) {
while (left != NULL) {
int in_out;
 
/* Greedily search for the closing edge, so that we generate the
* maximal span width with the minimal number of trapezoids.
*/
in_out = left->edge.dir;
 
/* Check if there is a co-linear edge with an existing trap */
right = left->next;
if (left->deferred_trap.right == NULL) {
while (right != NULL && right->deferred_trap.right == NULL)
right = right->next;
 
if (right != NULL && edges_colinear (left, right)) {
/* continuation on left */
left->deferred_trap = right->deferred_trap;
right->deferred_trap.right = NULL;
}
}
 
/* End all subsumed traps */
right = left->next;
while (right != NULL) {
if (right->deferred_trap.right != NULL) {
status = _cairo_bo_edge_end_trap (right, top, traps);
if (unlikely (status))
return status;
}
 
in_out += right->edge.dir;
if (in_out == 0) {
cairo_bo_edge_t *next;
cairo_bool_t skip = FALSE;
 
/* skip co-linear edges */
next = right->next;
if (next != NULL)
skip = edges_colinear (right, next);
 
if (! skip)
break;
}
 
right = right->next;
}
 
status = _cairo_bo_edge_start_or_continue_trap (left, right,
top, traps);
if (unlikely (status))
return status;
 
left = right;
if (left != NULL)
left = left->next;
}
} else {
while (left != NULL) {
int in_out = 0;
 
right = left->next;
while (right != NULL) {
if (right->deferred_trap.right != NULL) {
status = _cairo_bo_edge_end_trap (right, top, traps);
if (unlikely (status))
return status;
}
 
if ((in_out++ & 1) == 0) {
cairo_bo_edge_t *next;
cairo_bool_t skip = FALSE;
 
/* skip co-linear edges */
next = right->next;
if (next != NULL)
skip = edges_colinear (right, next);
 
if (! skip)
break;
}
 
right = right->next;
}
 
status = _cairo_bo_edge_start_or_continue_trap (left, right,
top, traps);
if (unlikely (status))
return status;
 
left = right;
if (left != NULL)
left = left->next;
}
}
 
return CAIRO_STATUS_SUCCESS;
}
 
 
/* Execute a single pass of the Bentley-Ottmann algorithm on edges,
* generating trapezoids according to the fill_rule and appending them
* to traps. */
static cairo_status_t
_cairo_bentley_ottmann_tessellate_bo_edges (cairo_bo_event_t **start_events,
int num_events,
cairo_fill_rule_t fill_rule,
cairo_traps_t *traps,
int *num_intersections)
{
cairo_status_t status = CAIRO_STATUS_SUCCESS; /* silence compiler */
int intersection_count = 0;
cairo_bo_event_queue_t event_queue;
cairo_bo_sweep_line_t sweep_line;
cairo_bo_event_t *event;
cairo_bo_edge_t *left, *right;
cairo_bo_edge_t *e1, *e2;
 
#if DEBUG_EVENTS
{
int i;
 
for (i = 0; i < num_events; i++) {
cairo_bo_start_event_t *event =
((cairo_bo_start_event_t **) start_events)[i];
event_log ("edge: %lu (%d, %d) (%d, %d) (%d, %d) %d\n",
(long) &events[i].edge,
event->edge.edge.line.p1.x,
event->edge.edge.line.p1.y,
event->edge.edge.line.p2.x,
event->edge.edge.line.p2.y,
event->edge.top,
event->edge.bottom,
event->edge.edge.dir);
}
}
#endif
 
_cairo_bo_event_queue_init (&event_queue, start_events, num_events);
_cairo_bo_sweep_line_init (&sweep_line);
 
while ((event = _cairo_bo_event_dequeue (&event_queue))) {
if (event->point.y != sweep_line.current_y) {
for (e1 = sweep_line.stopped; e1; e1 = e1->next) {
if (e1->deferred_trap.right != NULL) {
status = _cairo_bo_edge_end_trap (e1,
e1->edge.bottom,
traps);
if (unlikely (status))
goto unwind;
}
}
sweep_line.stopped = NULL;
 
status = _active_edges_to_traps (sweep_line.head,
sweep_line.current_y,
fill_rule, traps);
if (unlikely (status))
goto unwind;
 
sweep_line.current_y = event->point.y;
}
 
#if DEBUG_EVENTS
event_log ("event: %d (%ld, %ld) %lu, %lu\n",
event->type,
(long) event->point.x,
(long) event->point.y,
(long) event->e1,
(long) event->e2);
#endif
 
switch (event->type) {
case CAIRO_BO_EVENT_TYPE_START:
e1 = &((cairo_bo_start_event_t *) event)->edge;
 
status = _cairo_bo_sweep_line_insert (&sweep_line, e1);
if (unlikely (status))
goto unwind;
 
status = _cairo_bo_event_queue_insert_stop (&event_queue, e1);
if (unlikely (status))
goto unwind;
 
/* check to see if this is a continuation of a stopped edge */
/* XXX change to an infinitesimal lengthening rule */
for (left = sweep_line.stopped; left; left = left->next) {
if (e1->edge.top <= left->edge.bottom &&
edges_colinear (e1, left))
{
e1->deferred_trap = left->deferred_trap;
if (left->prev != NULL)
left->prev = left->next;
else
sweep_line.stopped = left->next;
if (left->next != NULL)
left->next->prev = left->prev;
break;
}
}
 
left = e1->prev;
right = e1->next;
 
if (left != NULL) {
status = _cairo_bo_event_queue_insert_if_intersect_below_current_y (&event_queue, left, e1);
if (unlikely (status))
goto unwind;
}
 
if (right != NULL) {
status = _cairo_bo_event_queue_insert_if_intersect_below_current_y (&event_queue, e1, right);
if (unlikely (status))
goto unwind;
}
 
break;
 
case CAIRO_BO_EVENT_TYPE_STOP:
e1 = ((cairo_bo_queue_event_t *) event)->e1;
_cairo_bo_event_queue_delete (&event_queue, event);
 
left = e1->prev;
right = e1->next;
 
_cairo_bo_sweep_line_delete (&sweep_line, e1);
 
/* first, check to see if we have a continuation via a fresh edge */
if (e1->deferred_trap.right != NULL) {
e1->next = sweep_line.stopped;
if (sweep_line.stopped != NULL)
sweep_line.stopped->prev = e1;
sweep_line.stopped = e1;
e1->prev = NULL;
}
 
if (left != NULL && right != NULL) {
status = _cairo_bo_event_queue_insert_if_intersect_below_current_y (&event_queue, left, right);
if (unlikely (status))
goto unwind;
}
 
break;
 
case CAIRO_BO_EVENT_TYPE_INTERSECTION:
e1 = ((cairo_bo_queue_event_t *) event)->e1;
e2 = ((cairo_bo_queue_event_t *) event)->e2;
_cairo_bo_event_queue_delete (&event_queue, event);
 
/* skip this intersection if its edges are not adjacent */
if (e2 != e1->next)
break;
 
intersection_count++;
 
left = e1->prev;
right = e2->next;
 
_cairo_bo_sweep_line_swap (&sweep_line, e1, e2);
 
/* after the swap e2 is left of e1 */
 
if (left != NULL) {
status = _cairo_bo_event_queue_insert_if_intersect_below_current_y (&event_queue, left, e2);
if (unlikely (status))
goto unwind;
}
 
if (right != NULL) {
status = _cairo_bo_event_queue_insert_if_intersect_below_current_y (&event_queue, e1, right);
if (unlikely (status))
goto unwind;
}
 
break;
}
}
 
*num_intersections = intersection_count;
for (e1 = sweep_line.stopped; e1; e1 = e1->next) {
if (e1->deferred_trap.right != NULL) {
status = _cairo_bo_edge_end_trap (e1, e1->edge.bottom, traps);
if (unlikely (status))
break;
}
}
unwind:
_cairo_bo_event_queue_fini (&event_queue);
 
#if DEBUG_EVENTS
event_log ("\n");
#endif
 
return status;
}
 
cairo_status_t
_cairo_bentley_ottmann_tessellate_polygon (cairo_traps_t *traps,
const cairo_polygon_t *polygon,
cairo_fill_rule_t fill_rule)
{
int intersections;
cairo_status_t status;
cairo_bo_start_event_t stack_events[CAIRO_STACK_ARRAY_LENGTH (cairo_bo_start_event_t)];
cairo_bo_start_event_t *events;
cairo_bo_event_t *stack_event_ptrs[ARRAY_LENGTH (stack_events) + 1];
cairo_bo_event_t **event_ptrs;
int num_events;
int i;
 
num_events = polygon->num_edges;
if (unlikely (0 == num_events))
return CAIRO_STATUS_SUCCESS;
 
events = stack_events;
event_ptrs = stack_event_ptrs;
if (num_events > ARRAY_LENGTH (stack_events)) {
events = _cairo_malloc_ab_plus_c (num_events,
sizeof (cairo_bo_start_event_t) +
sizeof (cairo_bo_event_t *),
sizeof (cairo_bo_event_t *));
if (unlikely (events == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
event_ptrs = (cairo_bo_event_t **) (events + num_events);
}
 
for (i = 0; i < num_events; i++) {
event_ptrs[i] = (cairo_bo_event_t *) &events[i];
 
events[i].type = CAIRO_BO_EVENT_TYPE_START;
events[i].point.y = polygon->edges[i].top;
events[i].point.x =
_line_compute_intersection_x_for_y (&polygon->edges[i].line,
events[i].point.y);
 
events[i].edge.edge = polygon->edges[i];
events[i].edge.deferred_trap.right = NULL;
events[i].edge.prev = NULL;
events[i].edge.next = NULL;
}
 
#if DEBUG_TRAPS
dump_edges (events, num_events, "bo-polygon-edges.txt");
#endif
 
/* XXX: This would be the convenient place to throw in multiple
* passes of the Bentley-Ottmann algorithm. It would merely
* require storing the results of each pass into a temporary
* cairo_traps_t. */
status = _cairo_bentley_ottmann_tessellate_bo_edges (event_ptrs,
num_events,
fill_rule, traps,
&intersections);
#if DEBUG_TRAPS
dump_traps (traps, "bo-polygon-out.txt");
#endif
 
if (events != stack_events)
free (events);
 
return status;
}
 
cairo_status_t
_cairo_bentley_ottmann_tessellate_traps (cairo_traps_t *traps,
cairo_fill_rule_t fill_rule)
{
cairo_status_t status;
cairo_polygon_t polygon;
int i;
 
if (unlikely (0 == traps->num_traps))
return CAIRO_STATUS_SUCCESS;
 
#if DEBUG_TRAPS
dump_traps (traps, "bo-traps-in.txt");
#endif
 
_cairo_polygon_init (&polygon);
_cairo_polygon_limit (&polygon, traps->limits, traps->num_limits);
 
for (i = 0; i < traps->num_traps; i++) {
status = _cairo_polygon_add_line (&polygon,
&traps->traps[i].left,
traps->traps[i].top,
traps->traps[i].bottom,
1);
if (unlikely (status))
goto CLEANUP;
 
status = _cairo_polygon_add_line (&polygon,
&traps->traps[i].right,
traps->traps[i].top,
traps->traps[i].bottom,
-1);
if (unlikely (status))
goto CLEANUP;
}
 
_cairo_traps_clear (traps);
status = _cairo_bentley_ottmann_tessellate_polygon (traps,
&polygon,
fill_rule);
 
#if DEBUG_TRAPS
dump_traps (traps, "bo-traps-out.txt");
#endif
 
CLEANUP:
_cairo_polygon_fini (&polygon);
 
return status;
}
 
#if 0
static cairo_bool_t
edges_have_an_intersection_quadratic (cairo_bo_edge_t *edges,
int num_edges)
 
{
int i, j;
cairo_bo_edge_t *a, *b;
cairo_bo_point32_t intersection;
 
/* We must not be given any upside-down edges. */
for (i = 0; i < num_edges; i++) {
assert (_cairo_bo_point32_compare (&edges[i].top, &edges[i].bottom) < 0);
edges[i].line.p1.x <<= CAIRO_BO_GUARD_BITS;
edges[i].line.p1.y <<= CAIRO_BO_GUARD_BITS;
edges[i].line.p2.x <<= CAIRO_BO_GUARD_BITS;
edges[i].line.p2.y <<= CAIRO_BO_GUARD_BITS;
}
 
for (i = 0; i < num_edges; i++) {
for (j = 0; j < num_edges; j++) {
if (i == j)
continue;
 
a = &edges[i];
b = &edges[j];
 
if (! _cairo_bo_edge_intersect (a, b, &intersection))
continue;
 
printf ("Found intersection (%d,%d) between (%d,%d)-(%d,%d) and (%d,%d)-(%d,%d)\n",
intersection.x,
intersection.y,
a->line.p1.x, a->line.p1.y,
a->line.p2.x, a->line.p2.y,
b->line.p1.x, b->line.p1.y,
b->line.p2.x, b->line.p2.y);
 
return TRUE;
}
}
return FALSE;
}
 
#define TEST_MAX_EDGES 10
 
typedef struct test {
const char *name;
const char *description;
int num_edges;
cairo_bo_edge_t edges[TEST_MAX_EDGES];
} test_t;
 
static test_t
tests[] = {
{
"3 near misses",
"3 edges all intersecting very close to each other",
3,
{
{ { 4, 2}, {0, 0}, { 9, 9}, NULL, NULL },
{ { 7, 2}, {0, 0}, { 2, 3}, NULL, NULL },
{ { 5, 2}, {0, 0}, { 1, 7}, NULL, NULL }
}
},
{
"inconsistent data",
"Derived from random testing---was leading to skip list and edge list disagreeing.",
2,
{
{ { 2, 3}, {0, 0}, { 8, 9}, NULL, NULL },
{ { 2, 3}, {0, 0}, { 6, 7}, NULL, NULL }
}
},
{
"failed sort",
"A test derived from random testing that leads to an inconsistent sort --- looks like we just can't attempt to validate the sweep line with edge_compare?",
3,
{
{ { 6, 2}, {0, 0}, { 6, 5}, NULL, NULL },
{ { 3, 5}, {0, 0}, { 5, 6}, NULL, NULL },
{ { 9, 2}, {0, 0}, { 5, 6}, NULL, NULL },
}
},
{
"minimal-intersection",
"Intersection of a two from among the smallest possible edges.",
2,
{
{ { 0, 0}, {0, 0}, { 1, 1}, NULL, NULL },
{ { 1, 0}, {0, 0}, { 0, 1}, NULL, NULL }
}
},
{
"simple",
"A simple intersection of two edges at an integer (2,2).",
2,
{
{ { 1, 1}, {0, 0}, { 3, 3}, NULL, NULL },
{ { 2, 1}, {0, 0}, { 2, 3}, NULL, NULL }
}
},
{
"bend-to-horizontal",
"With intersection truncation one edge bends to horizontal",
2,
{
{ { 9, 1}, {0, 0}, {3, 7}, NULL, NULL },
{ { 3, 5}, {0, 0}, {9, 9}, NULL, NULL }
}
}
};
 
/*
{
"endpoint",
"An intersection that occurs at the endpoint of a segment.",
{
{ { 4, 6}, { 5, 6}, NULL, { { NULL }} },
{ { 4, 5}, { 5, 7}, NULL, { { NULL }} },
{ { 0, 0}, { 0, 0}, NULL, { { NULL }} },
}
}
{
name = "overlapping",
desc = "Parallel segments that share an endpoint, with different slopes.",
edges = {
{ top = { x = 2, y = 0}, bottom = { x = 1, y = 1}},
{ top = { x = 2, y = 0}, bottom = { x = 0, y = 2}},
{ top = { x = 0, y = 3}, bottom = { x = 1, y = 3}},
{ top = { x = 0, y = 3}, bottom = { x = 2, y = 3}},
{ top = { x = 0, y = 4}, bottom = { x = 0, y = 6}},
{ top = { x = 0, y = 5}, bottom = { x = 0, y = 6}}
}
},
{
name = "hobby_stage_3",
desc = "A particularly tricky part of the 3rd stage of the 'hobby' test below.",
edges = {
{ top = { x = -1, y = -2}, bottom = { x = 4, y = 2}},
{ top = { x = 5, y = 3}, bottom = { x = 9, y = 5}},
{ top = { x = 5, y = 3}, bottom = { x = 6, y = 3}},
}
},
{
name = "hobby",
desc = "Example from John Hobby's paper. Requires 3 passes of the iterative algorithm.",
edges = {
{ top = { x = 0, y = 0}, bottom = { x = 9, y = 5}},
{ top = { x = 0, y = 0}, bottom = { x = 13, y = 6}},
{ top = { x = -1, y = -2}, bottom = { x = 9, y = 5}}
}
},
{
name = "slope",
desc = "Edges with same start/stop points but different slopes",
edges = {
{ top = { x = 4, y = 1}, bottom = { x = 6, y = 3}},
{ top = { x = 4, y = 1}, bottom = { x = 2, y = 3}},
{ top = { x = 2, y = 4}, bottom = { x = 4, y = 6}},
{ top = { x = 6, y = 4}, bottom = { x = 4, y = 6}}
}
},
{
name = "horizontal",
desc = "Test of a horizontal edge",
edges = {
{ top = { x = 1, y = 1}, bottom = { x = 6, y = 6}},
{ top = { x = 2, y = 3}, bottom = { x = 5, y = 3}}
}
},
{
name = "vertical",
desc = "Test of a vertical edge",
edges = {
{ top = { x = 5, y = 1}, bottom = { x = 5, y = 7}},
{ top = { x = 2, y = 4}, bottom = { x = 8, y = 5}}
}
},
{
name = "congruent",
desc = "Two overlapping edges with the same slope",
edges = {
{ top = { x = 5, y = 1}, bottom = { x = 5, y = 7}},
{ top = { x = 5, y = 2}, bottom = { x = 5, y = 6}},
{ top = { x = 2, y = 4}, bottom = { x = 8, y = 5}}
}
},
{
name = "multi",
desc = "Several segments with a common intersection point",
edges = {
{ top = { x = 1, y = 2}, bottom = { x = 5, y = 4} },
{ top = { x = 1, y = 1}, bottom = { x = 5, y = 5} },
{ top = { x = 2, y = 1}, bottom = { x = 4, y = 5} },
{ top = { x = 4, y = 1}, bottom = { x = 2, y = 5} },
{ top = { x = 5, y = 1}, bottom = { x = 1, y = 5} },
{ top = { x = 5, y = 2}, bottom = { x = 1, y = 4} }
}
}
};
*/
 
static int
run_test (const char *test_name,
cairo_bo_edge_t *test_edges,
int num_edges)
{
int i, intersections, passes;
cairo_bo_edge_t *edges;
cairo_array_t intersected_edges;
 
printf ("Testing: %s\n", test_name);
 
_cairo_array_init (&intersected_edges, sizeof (cairo_bo_edge_t));
 
intersections = _cairo_bentley_ottmann_intersect_edges (test_edges, num_edges, &intersected_edges);
if (intersections)
printf ("Pass 1 found %d intersections:\n", intersections);
 
 
/* XXX: Multi-pass Bentley-Ottmmann. Preferable would be to add a
* pass of Hobby's tolerance-square algorithm instead. */
passes = 1;
while (intersections) {
int num_edges = _cairo_array_num_elements (&intersected_edges);
passes++;
edges = _cairo_malloc_ab (num_edges, sizeof (cairo_bo_edge_t));
assert (edges != NULL);
memcpy (edges, _cairo_array_index (&intersected_edges, 0), num_edges * sizeof (cairo_bo_edge_t));
_cairo_array_fini (&intersected_edges);
_cairo_array_init (&intersected_edges, sizeof (cairo_bo_edge_t));
intersections = _cairo_bentley_ottmann_intersect_edges (edges, num_edges, &intersected_edges);
free (edges);
 
if (intersections){
printf ("Pass %d found %d remaining intersections:\n", passes, intersections);
} else {
if (passes > 3)
for (i = 0; i < passes; i++)
printf ("*");
printf ("No remainining intersections found after pass %d\n", passes);
}
}
 
if (edges_have_an_intersection_quadratic (_cairo_array_index (&intersected_edges, 0),
_cairo_array_num_elements (&intersected_edges)))
printf ("*** FAIL ***\n");
else
printf ("PASS\n");
 
_cairo_array_fini (&intersected_edges);
 
return 0;
}
 
#define MAX_RANDOM 300
 
int
main (void)
{
char random_name[] = "random-XX";
cairo_bo_edge_t random_edges[MAX_RANDOM], *edge;
unsigned int i, num_random;
test_t *test;
 
for (i = 0; i < ARRAY_LENGTH (tests); i++) {
test = &tests[i];
run_test (test->name, test->edges, test->num_edges);
}
 
for (num_random = 0; num_random < MAX_RANDOM; num_random++) {
srand (0);
for (i = 0; i < num_random; i++) {
do {
edge = &random_edges[i];
edge->line.p1.x = (int32_t) (10.0 * (rand() / (RAND_MAX + 1.0)));
edge->line.p1.y = (int32_t) (10.0 * (rand() / (RAND_MAX + 1.0)));
edge->line.p2.x = (int32_t) (10.0 * (rand() / (RAND_MAX + 1.0)));
edge->line.p2.y = (int32_t) (10.0 * (rand() / (RAND_MAX + 1.0)));
if (edge->line.p1.y > edge->line.p2.y) {
int32_t tmp = edge->line.p1.y;
edge->line.p1.y = edge->line.p2.y;
edge->line.p2.y = tmp;
}
} while (edge->line.p1.y == edge->line.p2.y);
}
 
sprintf (random_name, "random-%02d", num_random);
 
run_test (random_name, random_edges, num_random);
}
 
return 0;
}
#endif
/programs/develop/libraries/cairo/src/cairo-beos.h
0,0 → 1,60
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2005 Christian Biesinger <cbiesinger@web.de>
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Christian Biesinger
* <cbiesinger@web.de>
*
* Contributor(s):
*/
 
#ifndef CAIRO_BEOS_H
#define CAIRO_BEOS_H
 
#include "cairo.h"
 
#if CAIRO_HAS_BEOS_SURFACE
 
#include <View.h>
 
CAIRO_BEGIN_DECLS
 
cairo_public cairo_surface_t *
cairo_beos_surface_create (BView* view);
 
cairo_public cairo_surface_t *
cairo_beos_surface_create_for_bitmap (BView* view,
BBitmap* bmp);
 
CAIRO_END_DECLS
 
#else /* CAIRO_HAS_BEOS_SURFACE */
# error Cairo was not compiled with support for the beos backend
#endif /* CAIRO_HAS_BEOS_SURFACE */
 
#endif /* CAIRO_BEOS_H */
/programs/develop/libraries/cairo/src/cairo-botor-scan-converter.c
0,0 → 1,2199
/*
* Copyright © 2004 Carl Worth
* Copyright © 2006 Red Hat, Inc.
* Copyright © 2007 David Turner
* Copyright © 2008 M Joonas Pihlaja
* Copyright © 2008 Chris Wilson
* Copyright © 2009 Intel Corporation
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Carl Worth
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
* M Joonas Pihlaja <jpihlaja@cc.helsinki.fi>
* Chris Wilson <chris@chris-wilson.co.uk>
*/
 
/* Provide definitions for standalone compilation */
#include "cairoint.h"
 
#include "cairo-error-private.h"
#include "cairo-list-private.h"
#include "cairo-freelist-private.h"
#include "cairo-combsort-private.h"
 
#include <setjmp.h>
 
#define STEP_X CAIRO_FIXED_ONE
#define STEP_Y CAIRO_FIXED_ONE
#define UNROLL3(x) x x x
 
#define STEP_XY (2*STEP_X*STEP_Y) /* Unit area in the step. */
#define AREA_TO_ALPHA(c) (((c)*255 + STEP_XY/2) / STEP_XY)
 
typedef struct _cairo_bo_intersect_ordinate {
int32_t ordinate;
enum { EXACT, INEXACT } exactness;
} cairo_bo_intersect_ordinate_t;
 
typedef struct _cairo_bo_intersect_point {
cairo_bo_intersect_ordinate_t x;
cairo_bo_intersect_ordinate_t y;
} cairo_bo_intersect_point_t;
 
struct quorem {
cairo_fixed_t quo;
cairo_fixed_t rem;
};
 
struct run {
struct run *next;
int sign;
cairo_fixed_t y;
};
 
typedef struct edge {
cairo_list_t link;
 
cairo_edge_t edge;
 
/* Current x coordinate and advancement.
* Initialised to the x coordinate of the top of the
* edge. The quotient is in cairo_fixed_t units and the
* remainder is mod dy in cairo_fixed_t units.
*/
cairo_fixed_t dy;
struct quorem x;
struct quorem dxdy;
struct quorem dxdy_full;
 
cairo_bool_t vertical;
unsigned int flags;
 
int current_sign;
struct run *runs;
} edge_t;
 
enum {
START = 0x1,
STOP = 0x2,
};
 
/* the parent is always given by index/2 */
#define PQ_PARENT_INDEX(i) ((i) >> 1)
#define PQ_FIRST_ENTRY 1
 
/* left and right children are index * 2 and (index * 2) +1 respectively */
#define PQ_LEFT_CHILD_INDEX(i) ((i) << 1)
 
typedef enum {
EVENT_TYPE_STOP,
EVENT_TYPE_INTERSECTION,
EVENT_TYPE_START
} event_type_t;
 
typedef struct _event {
cairo_fixed_t y;
event_type_t type;
} event_t;
 
typedef struct _start_event {
cairo_fixed_t y;
event_type_t type;
edge_t *edge;
} start_event_t;
 
typedef struct _queue_event {
cairo_fixed_t y;
event_type_t type;
edge_t *e1;
edge_t *e2;
} queue_event_t;
 
typedef struct _pqueue {
int size, max_size;
 
event_t **elements;
event_t *elements_embedded[1024];
} pqueue_t;
 
struct cell {
struct cell *prev;
struct cell *next;
int x;
int uncovered_area;
int covered_height;
};
 
typedef struct _sweep_line {
cairo_list_t active;
cairo_list_t stopped;
cairo_list_t *insert_cursor;
cairo_bool_t is_vertical;
 
cairo_fixed_t current_row;
cairo_fixed_t current_subrow;
 
struct coverage {
struct cell head;
struct cell tail;
 
struct cell *cursor;
int count;
 
cairo_freepool_t pool;
} coverage;
 
struct event_queue {
pqueue_t pq;
event_t **start_events;
 
cairo_freepool_t pool;
} queue;
 
cairo_freepool_t runs;
 
jmp_buf unwind;
} sweep_line_t;
 
cairo_always_inline static struct quorem
floored_divrem (int a, int b)
{
struct quorem qr;
qr.quo = a/b;
qr.rem = a%b;
if ((a^b)<0 && qr.rem) {
qr.quo--;
qr.rem += b;
}
return qr;
}
 
static struct quorem
floored_muldivrem(int x, int a, int b)
{
struct quorem qr;
long long xa = (long long)x*a;
qr.quo = xa/b;
qr.rem = xa%b;
if ((xa>=0) != (b>=0) && qr.rem) {
qr.quo--;
qr.rem += b;
}
return qr;
}
 
static cairo_fixed_t
line_compute_intersection_x_for_y (const cairo_line_t *line,
cairo_fixed_t y)
{
cairo_fixed_t x, dy;
 
if (y == line->p1.y)
return line->p1.x;
if (y == line->p2.y)
return line->p2.x;
 
x = line->p1.x;
dy = line->p2.y - line->p1.y;
if (dy != 0) {
x += _cairo_fixed_mul_div_floor (y - line->p1.y,
line->p2.x - line->p1.x,
dy);
}
 
return x;
}
 
/*
* We need to compare the x-coordinates of a pair of lines for a particular y,
* without loss of precision.
*
* The x-coordinate along an edge for a given y is:
* X = A_x + (Y - A_y) * A_dx / A_dy
*
* So the inequality we wish to test is:
* A_x + (Y - A_y) * A_dx / A_dy ∘ B_x + (Y - B_y) * B_dx / B_dy,
* where ∘ is our inequality operator.
*
* By construction, we know that A_dy and B_dy (and (Y - A_y), (Y - B_y)) are
* all positive, so we can rearrange it thus without causing a sign change:
* A_dy * B_dy * (A_x - B_x) ∘ (Y - B_y) * B_dx * A_dy
* - (Y - A_y) * A_dx * B_dy
*
* Given the assumption that all the deltas fit within 32 bits, we can compute
* this comparison directly using 128 bit arithmetic. For certain, but common,
* input we can reduce this down to a single 32 bit compare by inspecting the
* deltas.
*
* (And put the burden of the work on developing fast 128 bit ops, which are
* required throughout the tessellator.)
*
* See the similar discussion for _slope_compare().
*/
static int
edges_compare_x_for_y_general (const cairo_edge_t *a,
const cairo_edge_t *b,
int32_t y)
{
/* XXX: We're assuming here that dx and dy will still fit in 32
* bits. That's not true in general as there could be overflow. We
* should prevent that before the tessellation algorithm
* begins.
*/
int32_t dx;
int32_t adx, ady;
int32_t bdx, bdy;
enum {
HAVE_NONE = 0x0,
HAVE_DX = 0x1,
HAVE_ADX = 0x2,
HAVE_DX_ADX = HAVE_DX | HAVE_ADX,
HAVE_BDX = 0x4,
HAVE_DX_BDX = HAVE_DX | HAVE_BDX,
HAVE_ADX_BDX = HAVE_ADX | HAVE_BDX,
HAVE_ALL = HAVE_DX | HAVE_ADX | HAVE_BDX
} have_dx_adx_bdx = HAVE_ALL;
 
/* don't bother solving for abscissa if the edges' bounding boxes
* can be used to order them. */
{
int32_t amin, amax;
int32_t bmin, bmax;
if (a->line.p1.x < a->line.p2.x) {
amin = a->line.p1.x;
amax = a->line.p2.x;
} else {
amin = a->line.p2.x;
amax = a->line.p1.x;
}
if (b->line.p1.x < b->line.p2.x) {
bmin = b->line.p1.x;
bmax = b->line.p2.x;
} else {
bmin = b->line.p2.x;
bmax = b->line.p1.x;
}
if (amax < bmin) return -1;
if (amin > bmax) return +1;
}
 
ady = a->line.p2.y - a->line.p1.y;
adx = a->line.p2.x - a->line.p1.x;
if (adx == 0)
have_dx_adx_bdx &= ~HAVE_ADX;
 
bdy = b->line.p2.y - b->line.p1.y;
bdx = b->line.p2.x - b->line.p1.x;
if (bdx == 0)
have_dx_adx_bdx &= ~HAVE_BDX;
 
dx = a->line.p1.x - b->line.p1.x;
if (dx == 0)
have_dx_adx_bdx &= ~HAVE_DX;
 
#define L _cairo_int64x32_128_mul (_cairo_int32x32_64_mul (ady, bdy), dx)
#define A _cairo_int64x32_128_mul (_cairo_int32x32_64_mul (adx, bdy), y - a->line.p1.y)
#define B _cairo_int64x32_128_mul (_cairo_int32x32_64_mul (bdx, ady), y - b->line.p1.y)
switch (have_dx_adx_bdx) {
default:
case HAVE_NONE:
return 0;
case HAVE_DX:
/* A_dy * B_dy * (A_x - B_x) ∘ 0 */
return dx; /* ady * bdy is positive definite */
case HAVE_ADX:
/* 0 ∘ - (Y - A_y) * A_dx * B_dy */
return adx; /* bdy * (y - a->top.y) is positive definite */
case HAVE_BDX:
/* 0 ∘ (Y - B_y) * B_dx * A_dy */
return -bdx; /* ady * (y - b->top.y) is positive definite */
case HAVE_ADX_BDX:
/* 0 ∘ (Y - B_y) * B_dx * A_dy - (Y - A_y) * A_dx * B_dy */
if ((adx ^ bdx) < 0) {
return adx;
} else if (a->line.p1.y == b->line.p1.y) { /* common origin */
cairo_int64_t adx_bdy, bdx_ady;
 
/* ∴ A_dx * B_dy ∘ B_dx * A_dy */
 
adx_bdy = _cairo_int32x32_64_mul (adx, bdy);
bdx_ady = _cairo_int32x32_64_mul (bdx, ady);
 
return _cairo_int64_cmp (adx_bdy, bdx_ady);
} else
return _cairo_int128_cmp (A, B);
case HAVE_DX_ADX:
/* A_dy * (A_x - B_x) ∘ - (Y - A_y) * A_dx */
if ((-adx ^ dx) < 0) {
return dx;
} else {
cairo_int64_t ady_dx, dy_adx;
 
ady_dx = _cairo_int32x32_64_mul (ady, dx);
dy_adx = _cairo_int32x32_64_mul (a->line.p1.y - y, adx);
 
return _cairo_int64_cmp (ady_dx, dy_adx);
}
case HAVE_DX_BDX:
/* B_dy * (A_x - B_x) ∘ (Y - B_y) * B_dx */
if ((bdx ^ dx) < 0) {
return dx;
} else {
cairo_int64_t bdy_dx, dy_bdx;
 
bdy_dx = _cairo_int32x32_64_mul (bdy, dx);
dy_bdx = _cairo_int32x32_64_mul (y - b->line.p1.y, bdx);
 
return _cairo_int64_cmp (bdy_dx, dy_bdx);
}
case HAVE_ALL:
/* XXX try comparing (a->line.p2.x - b->line.p2.x) et al */
return _cairo_int128_cmp (L, _cairo_int128_sub (B, A));
}
#undef B
#undef A
#undef L
}
 
/*
* We need to compare the x-coordinate of a line for a particular y wrt to a
* given x, without loss of precision.
*
* The x-coordinate along an edge for a given y is:
* X = A_x + (Y - A_y) * A_dx / A_dy
*
* So the inequality we wish to test is:
* A_x + (Y - A_y) * A_dx / A_dy ∘ X
* where ∘ is our inequality operator.
*
* By construction, we know that A_dy (and (Y - A_y)) are
* all positive, so we can rearrange it thus without causing a sign change:
* (Y - A_y) * A_dx ∘ (X - A_x) * A_dy
*
* Given the assumption that all the deltas fit within 32 bits, we can compute
* this comparison directly using 64 bit arithmetic.
*
* See the similar discussion for _slope_compare() and
* edges_compare_x_for_y_general().
*/
static int
edge_compare_for_y_against_x (const cairo_edge_t *a,
int32_t y,
int32_t x)
{
int32_t adx, ady;
int32_t dx, dy;
cairo_int64_t L, R;
 
if (a->line.p1.x <= a->line.p2.x) {
if (x < a->line.p1.x)
return 1;
if (x > a->line.p2.x)
return -1;
} else {
if (x < a->line.p2.x)
return 1;
if (x > a->line.p1.x)
return -1;
}
 
adx = a->line.p2.x - a->line.p1.x;
dx = x - a->line.p1.x;
 
if (adx == 0)
return -dx;
if (dx == 0 || (adx ^ dx) < 0)
return adx;
 
dy = y - a->line.p1.y;
ady = a->line.p2.y - a->line.p1.y;
 
L = _cairo_int32x32_64_mul (dy, adx);
R = _cairo_int32x32_64_mul (dx, ady);
 
return _cairo_int64_cmp (L, R);
}
 
static int
edges_compare_x_for_y (const cairo_edge_t *a,
const cairo_edge_t *b,
int32_t y)
{
/* If the sweep-line is currently on an end-point of a line,
* then we know its precise x value (and considering that we often need to
* compare events at end-points, this happens frequently enough to warrant
* special casing).
*/
enum {
HAVE_NEITHER = 0x0,
HAVE_AX = 0x1,
HAVE_BX = 0x2,
HAVE_BOTH = HAVE_AX | HAVE_BX
} have_ax_bx = HAVE_BOTH;
int32_t ax, bx;
 
/* XXX given we have x and dx? */
 
if (y == a->line.p1.y)
ax = a->line.p1.x;
else if (y == a->line.p2.y)
ax = a->line.p2.x;
else
have_ax_bx &= ~HAVE_AX;
 
if (y == b->line.p1.y)
bx = b->line.p1.x;
else if (y == b->line.p2.y)
bx = b->line.p2.x;
else
have_ax_bx &= ~HAVE_BX;
 
switch (have_ax_bx) {
default:
case HAVE_NEITHER:
return edges_compare_x_for_y_general (a, b, y);
case HAVE_AX:
return -edge_compare_for_y_against_x (b, y, ax);
case HAVE_BX:
return edge_compare_for_y_against_x (a, y, bx);
case HAVE_BOTH:
return ax - bx;
}
}
 
static inline int
slope_compare (const edge_t *a,
const edge_t *b)
{
cairo_int64_t L, R;
int cmp;
 
cmp = a->dxdy.quo - b->dxdy.quo;
if (cmp)
return cmp;
 
if (a->dxdy.rem == 0)
return -b->dxdy.rem;
if (b->dxdy.rem == 0)
return a->dxdy.rem;
 
L = _cairo_int32x32_64_mul (b->dy, a->dxdy.rem);
R = _cairo_int32x32_64_mul (a->dy, b->dxdy.rem);
return _cairo_int64_cmp (L, R);
}
 
static inline int
line_equal (const cairo_line_t *a, const cairo_line_t *b)
{
return a->p1.x == b->p1.x && a->p1.y == b->p1.y &&
a->p2.x == b->p2.x && a->p2.y == b->p2.y;
}
 
static inline int
sweep_line_compare_edges (const edge_t *a,
const edge_t *b,
cairo_fixed_t y)
{
int cmp;
 
if (line_equal (&a->edge.line, &b->edge.line))
return 0;
 
cmp = edges_compare_x_for_y (&a->edge, &b->edge, y);
if (cmp)
return cmp;
 
return slope_compare (a, b);
}
 
static inline cairo_int64_t
det32_64 (int32_t a, int32_t b,
int32_t c, int32_t d)
{
/* det = a * d - b * c */
return _cairo_int64_sub (_cairo_int32x32_64_mul (a, d),
_cairo_int32x32_64_mul (b, c));
}
 
static inline cairo_int128_t
det64x32_128 (cairo_int64_t a, int32_t b,
cairo_int64_t c, int32_t d)
{
/* det = a * d - b * c */
return _cairo_int128_sub (_cairo_int64x32_128_mul (a, d),
_cairo_int64x32_128_mul (c, b));
}
 
/* Compute the intersection of two lines as defined by two edges. The
* result is provided as a coordinate pair of 128-bit integers.
*
* Returns %CAIRO_BO_STATUS_INTERSECTION if there is an intersection or
* %CAIRO_BO_STATUS_PARALLEL if the two lines are exactly parallel.
*/
static cairo_bool_t
intersect_lines (const edge_t *a, const edge_t *b,
cairo_bo_intersect_point_t *intersection)
{
cairo_int64_t a_det, b_det;
 
/* XXX: We're assuming here that dx and dy will still fit in 32
* bits. That's not true in general as there could be overflow. We
* should prevent that before the tessellation algorithm begins.
* What we're doing to mitigate this is to perform clamping in
* cairo_bo_tessellate_polygon().
*/
int32_t dx1 = a->edge.line.p1.x - a->edge.line.p2.x;
int32_t dy1 = a->edge.line.p1.y - a->edge.line.p2.y;
 
int32_t dx2 = b->edge.line.p1.x - b->edge.line.p2.x;
int32_t dy2 = b->edge.line.p1.y - b->edge.line.p2.y;
 
cairo_int64_t den_det;
cairo_int64_t R;
cairo_quorem64_t qr;
 
den_det = det32_64 (dx1, dy1, dx2, dy2);
 
/* Q: Can we determine that the lines do not intersect (within range)
* much more cheaply than computing the intersection point i.e. by
* avoiding the division?
*
* X = ax + t * adx = bx + s * bdx;
* Y = ay + t * ady = by + s * bdy;
* ∴ t * (ady*bdx - bdy*adx) = bdx * (by - ay) + bdy * (ax - bx)
* => t * L = R
*
* Therefore we can reject any intersection (under the criteria for
* valid intersection events) if:
* L^R < 0 => t < 0, or
* L<R => t > 1
*
* (where top/bottom must at least extend to the line endpoints).
*
* A similar substitution can be performed for s, yielding:
* s * (ady*bdx - bdy*adx) = ady * (ax - bx) - adx * (ay - by)
*/
R = det32_64 (dx2, dy2,
b->edge.line.p1.x - a->edge.line.p1.x,
b->edge.line.p1.y - a->edge.line.p1.y);
if (_cairo_int64_negative (den_det)) {
if (_cairo_int64_ge (den_det, R))
return FALSE;
} else {
if (_cairo_int64_le (den_det, R))
return FALSE;
}
 
R = det32_64 (dy1, dx1,
a->edge.line.p1.y - b->edge.line.p1.y,
a->edge.line.p1.x - b->edge.line.p1.x);
if (_cairo_int64_negative (den_det)) {
if (_cairo_int64_ge (den_det, R))
return FALSE;
} else {
if (_cairo_int64_le (den_det, R))
return FALSE;
}
 
/* We now know that the two lines should intersect within range. */
 
a_det = det32_64 (a->edge.line.p1.x, a->edge.line.p1.y,
a->edge.line.p2.x, a->edge.line.p2.y);
b_det = det32_64 (b->edge.line.p1.x, b->edge.line.p1.y,
b->edge.line.p2.x, b->edge.line.p2.y);
 
/* x = det (a_det, dx1, b_det, dx2) / den_det */
qr = _cairo_int_96by64_32x64_divrem (det64x32_128 (a_det, dx1,
b_det, dx2),
den_det);
if (_cairo_int64_eq (qr.rem, den_det))
return FALSE;
#if 0
intersection->x.exactness = _cairo_int64_is_zero (qr.rem) ? EXACT : INEXACT;
#else
intersection->x.exactness = EXACT;
if (! _cairo_int64_is_zero (qr.rem)) {
if (_cairo_int64_negative (den_det) ^ _cairo_int64_negative (qr.rem))
qr.rem = _cairo_int64_negate (qr.rem);
qr.rem = _cairo_int64_mul (qr.rem, _cairo_int32_to_int64 (2));
if (_cairo_int64_ge (qr.rem, den_det)) {
qr.quo = _cairo_int64_add (qr.quo,
_cairo_int32_to_int64 (_cairo_int64_negative (qr.quo) ? -1 : 1));
} else
intersection->x.exactness = INEXACT;
}
#endif
intersection->x.ordinate = _cairo_int64_to_int32 (qr.quo);
 
/* y = det (a_det, dy1, b_det, dy2) / den_det */
qr = _cairo_int_96by64_32x64_divrem (det64x32_128 (a_det, dy1,
b_det, dy2),
den_det);
if (_cairo_int64_eq (qr.rem, den_det))
return FALSE;
#if 0
intersection->y.exactness = _cairo_int64_is_zero (qr.rem) ? EXACT : INEXACT;
#else
intersection->y.exactness = EXACT;
if (! _cairo_int64_is_zero (qr.rem)) {
/* compute ceiling away from zero */
qr.quo = _cairo_int64_add (qr.quo,
_cairo_int32_to_int64 (_cairo_int64_negative (qr.quo) ? -1 : 1));
intersection->y.exactness = INEXACT;
}
#endif
intersection->y.ordinate = _cairo_int64_to_int32 (qr.quo);
 
return TRUE;
}
 
static int
bo_intersect_ordinate_32_compare (int32_t a, int32_t b, int exactness)
{
int cmp;
 
/* First compare the quotient */
cmp = a - b;
if (cmp)
return cmp;
 
/* With quotient identical, if remainder is 0 then compare equal */
/* Otherwise, the non-zero remainder makes a > b */
return -(INEXACT == exactness);
}
 
/* Does the given edge contain the given point. The point must already
* be known to be contained within the line determined by the edge,
* (most likely the point results from an intersection of this edge
* with another).
*
* If we had exact arithmetic, then this function would simply be a
* matter of examining whether the y value of the point lies within
* the range of y values of the edge. But since intersection points
* are not exact due to being rounded to the nearest integer within
* the available precision, we must also examine the x value of the
* point.
*
* The definition of "contains" here is that the given intersection
* point will be seen by the sweep line after the start event for the
* given edge and before the stop event for the edge. See the comments
* in the implementation for more details.
*/
static cairo_bool_t
bo_edge_contains_intersect_point (const edge_t *edge,
cairo_bo_intersect_point_t *point)
{
int cmp_top, cmp_bottom;
 
/* XXX: When running the actual algorithm, we don't actually need to
* compare against edge->top at all here, since any intersection above
* top is eliminated early via a slope comparison. We're leaving these
* here for now only for the sake of the quadratic-time intersection
* finder which needs them.
*/
 
cmp_top = bo_intersect_ordinate_32_compare (point->y.ordinate,
edge->edge.top,
point->y.exactness);
if (cmp_top < 0)
return FALSE;
 
cmp_bottom = bo_intersect_ordinate_32_compare (point->y.ordinate,
edge->edge.bottom,
point->y.exactness);
if (cmp_bottom > 0)
return FALSE;
 
if (cmp_top > 0 && cmp_bottom < 0)
return TRUE;
 
/* At this stage, the point lies on the same y value as either
* edge->top or edge->bottom, so we have to examine the x value in
* order to properly determine containment. */
 
/* If the y value of the point is the same as the y value of the
* top of the edge, then the x value of the point must be greater
* to be considered as inside the edge. Similarly, if the y value
* of the point is the same as the y value of the bottom of the
* edge, then the x value of the point must be less to be
* considered as inside. */
 
if (cmp_top == 0) {
cairo_fixed_t top_x;
 
top_x = line_compute_intersection_x_for_y (&edge->edge.line,
edge->edge.top);
return bo_intersect_ordinate_32_compare (top_x, point->x.ordinate, point->x.exactness) < 0;
} else { /* cmp_bottom == 0 */
cairo_fixed_t bot_x;
 
bot_x = line_compute_intersection_x_for_y (&edge->edge.line,
edge->edge.bottom);
return bo_intersect_ordinate_32_compare (point->x.ordinate, bot_x, point->x.exactness) < 0;
}
}
 
static cairo_bool_t
edge_intersect (const edge_t *a,
const edge_t *b,
cairo_point_t *intersection)
{
cairo_bo_intersect_point_t quorem;
 
if (! intersect_lines (a, b, &quorem))
return FALSE;
 
if (a->edge.top != a->edge.line.p1.y || a->edge.bottom != a->edge.line.p2.y) {
if (! bo_edge_contains_intersect_point (a, &quorem))
return FALSE;
}
 
if (b->edge.top != b->edge.line.p1.y || b->edge.bottom != b->edge.line.p2.y) {
if (! bo_edge_contains_intersect_point (b, &quorem))
return FALSE;
}
 
/* Now that we've correctly compared the intersection point and
* determined that it lies within the edge, then we know that we
* no longer need any more bits of storage for the intersection
* than we do for our edge coordinates. We also no longer need the
* remainder from the division. */
intersection->x = quorem.x.ordinate;
intersection->y = quorem.y.ordinate;
 
return TRUE;
}
 
static inline int
event_compare (const event_t *a, const event_t *b)
{
return a->y - b->y;
}
 
static void
pqueue_init (pqueue_t *pq)
{
pq->max_size = ARRAY_LENGTH (pq->elements_embedded);
pq->size = 0;
 
pq->elements = pq->elements_embedded;
}
 
static void
pqueue_fini (pqueue_t *pq)
{
if (pq->elements != pq->elements_embedded)
free (pq->elements);
}
 
static cairo_bool_t
pqueue_grow (pqueue_t *pq)
{
event_t **new_elements;
pq->max_size *= 2;
 
if (pq->elements == pq->elements_embedded) {
new_elements = _cairo_malloc_ab (pq->max_size,
sizeof (event_t *));
if (unlikely (new_elements == NULL))
return FALSE;
 
memcpy (new_elements, pq->elements_embedded,
sizeof (pq->elements_embedded));
} else {
new_elements = _cairo_realloc_ab (pq->elements,
pq->max_size,
sizeof (event_t *));
if (unlikely (new_elements == NULL))
return FALSE;
}
 
pq->elements = new_elements;
return TRUE;
}
 
static inline void
pqueue_push (sweep_line_t *sweep_line, event_t *event)
{
event_t **elements;
int i, parent;
 
if (unlikely (sweep_line->queue.pq.size + 1 == sweep_line->queue.pq.max_size)) {
if (unlikely (! pqueue_grow (&sweep_line->queue.pq))) {
longjmp (sweep_line->unwind,
_cairo_error (CAIRO_STATUS_NO_MEMORY));
}
}
 
elements = sweep_line->queue.pq.elements;
for (i = ++sweep_line->queue.pq.size;
i != PQ_FIRST_ENTRY &&
event_compare (event,
elements[parent = PQ_PARENT_INDEX (i)]) < 0;
i = parent)
{
elements[i] = elements[parent];
}
 
elements[i] = event;
}
 
static inline void
pqueue_pop (pqueue_t *pq)
{
event_t **elements = pq->elements;
event_t *tail;
int child, i;
 
tail = elements[pq->size--];
if (pq->size == 0) {
elements[PQ_FIRST_ENTRY] = NULL;
return;
}
 
for (i = PQ_FIRST_ENTRY;
(child = PQ_LEFT_CHILD_INDEX (i)) <= pq->size;
i = child)
{
if (child != pq->size &&
event_compare (elements[child+1],
elements[child]) < 0)
{
child++;
}
 
if (event_compare (elements[child], tail) >= 0)
break;
 
elements[i] = elements[child];
}
elements[i] = tail;
}
 
static inline void
event_insert (sweep_line_t *sweep_line,
event_type_t type,
edge_t *e1,
edge_t *e2,
cairo_fixed_t y)
{
queue_event_t *event;
 
event = _cairo_freepool_alloc (&sweep_line->queue.pool);
if (unlikely (event == NULL)) {
longjmp (sweep_line->unwind,
_cairo_error (CAIRO_STATUS_NO_MEMORY));
}
 
event->y = y;
event->type = type;
event->e1 = e1;
event->e2 = e2;
 
pqueue_push (sweep_line, (event_t *) event);
}
 
static void
event_delete (sweep_line_t *sweep_line,
event_t *event)
{
_cairo_freepool_free (&sweep_line->queue.pool, event);
}
 
static inline event_t *
event_next (sweep_line_t *sweep_line)
{
event_t *event, *cmp;
 
event = sweep_line->queue.pq.elements[PQ_FIRST_ENTRY];
cmp = *sweep_line->queue.start_events;
if (event == NULL ||
(cmp != NULL && event_compare (cmp, event) < 0))
{
event = cmp;
sweep_line->queue.start_events++;
}
else
{
pqueue_pop (&sweep_line->queue.pq);
}
 
return event;
}
 
CAIRO_COMBSORT_DECLARE (start_event_sort, event_t *, event_compare)
 
static inline void
event_insert_stop (sweep_line_t *sweep_line,
edge_t *edge)
{
event_insert (sweep_line,
EVENT_TYPE_STOP,
edge, NULL,
edge->edge.bottom);
}
 
static inline void
event_insert_if_intersect_below_current_y (sweep_line_t *sweep_line,
edge_t *left,
edge_t *right)
{
cairo_point_t intersection;
 
/* start points intersect */
if (left->edge.line.p1.x == right->edge.line.p1.x &&
left->edge.line.p1.y == right->edge.line.p1.y)
{
return;
}
 
/* end points intersect, process DELETE events first */
if (left->edge.line.p2.x == right->edge.line.p2.x &&
left->edge.line.p2.y == right->edge.line.p2.y)
{
return;
}
 
if (slope_compare (left, right) <= 0)
return;
 
if (! edge_intersect (left, right, &intersection))
return;
 
event_insert (sweep_line,
EVENT_TYPE_INTERSECTION,
left, right,
intersection.y);
}
 
static inline edge_t *
link_to_edge (cairo_list_t *link)
{
return (edge_t *) link;
}
 
static void
sweep_line_insert (sweep_line_t *sweep_line,
edge_t *edge)
{
cairo_list_t *pos;
cairo_fixed_t y = sweep_line->current_subrow;
 
pos = sweep_line->insert_cursor;
if (pos == &sweep_line->active)
pos = sweep_line->active.next;
if (pos != &sweep_line->active) {
int cmp;
 
cmp = sweep_line_compare_edges (link_to_edge (pos),
edge,
y);
if (cmp < 0) {
while (pos->next != &sweep_line->active &&
sweep_line_compare_edges (link_to_edge (pos->next),
edge,
y) < 0)
{
pos = pos->next;
}
} else if (cmp > 0) {
do {
pos = pos->prev;
} while (pos != &sweep_line->active &&
sweep_line_compare_edges (link_to_edge (pos),
edge,
y) > 0);
}
}
cairo_list_add (&edge->link, pos);
sweep_line->insert_cursor = &edge->link;
}
 
inline static void
coverage_rewind (struct coverage *cells)
{
cells->cursor = &cells->head;
}
 
static void
coverage_init (struct coverage *cells)
{
_cairo_freepool_init (&cells->pool,
sizeof (struct cell));
cells->head.prev = NULL;
cells->head.next = &cells->tail;
cells->head.x = INT_MIN;
cells->tail.prev = &cells->head;
cells->tail.next = NULL;
cells->tail.x = INT_MAX;
cells->count = 0;
coverage_rewind (cells);
}
 
static void
coverage_fini (struct coverage *cells)
{
_cairo_freepool_fini (&cells->pool);
}
 
inline static void
coverage_reset (struct coverage *cells)
{
cells->head.next = &cells->tail;
cells->tail.prev = &cells->head;
cells->count = 0;
_cairo_freepool_reset (&cells->pool);
coverage_rewind (cells);
}
 
inline static struct cell *
coverage_alloc (sweep_line_t *sweep_line,
struct cell *tail,
int x)
{
struct cell *cell;
 
cell = _cairo_freepool_alloc (&sweep_line->coverage.pool);
if (unlikely (NULL == cell)) {
longjmp (sweep_line->unwind,
_cairo_error (CAIRO_STATUS_NO_MEMORY));
}
 
tail->prev->next = cell;
cell->prev = tail->prev;
cell->next = tail;
tail->prev = cell;
cell->x = x;
cell->uncovered_area = 0;
cell->covered_height = 0;
sweep_line->coverage.count++;
return cell;
}
 
inline static struct cell *
coverage_find (sweep_line_t *sweep_line, int x)
{
struct cell *cell;
 
cell = sweep_line->coverage.cursor;
if (unlikely (cell->x > x)) {
do {
if (cell->prev->x < x)
break;
cell = cell->prev;
} while (TRUE);
} else {
if (cell->x == x)
return cell;
 
do {
UNROLL3({
cell = cell->next;
if (cell->x >= x)
break;
});
} while (TRUE);
}
 
if (cell->x != x)
cell = coverage_alloc (sweep_line, cell, x);
 
return sweep_line->coverage.cursor = cell;
}
 
static void
coverage_render_cells (sweep_line_t *sweep_line,
cairo_fixed_t left, cairo_fixed_t right,
cairo_fixed_t y1, cairo_fixed_t y2,
int sign)
{
int fx1, fx2;
int ix1, ix2;
int dx, dy;
 
/* Orient the edge left-to-right. */
dx = right - left;
if (dx >= 0) {
ix1 = _cairo_fixed_integer_part (left);
fx1 = _cairo_fixed_fractional_part (left);
 
ix2 = _cairo_fixed_integer_part (right);
fx2 = _cairo_fixed_fractional_part (right);
 
dy = y2 - y1;
} else {
ix1 = _cairo_fixed_integer_part (right);
fx1 = _cairo_fixed_fractional_part (right);
 
ix2 = _cairo_fixed_integer_part (left);
fx2 = _cairo_fixed_fractional_part (left);
 
dx = -dx;
sign = -sign;
dy = y1 - y2;
y1 = y2 - dy;
y2 = y1 + dy;
}
 
/* Add coverage for all pixels [ix1,ix2] on this row crossed
* by the edge. */
{
struct quorem y = floored_divrem ((STEP_X - fx1)*dy, dx);
struct cell *cell;
 
cell = sweep_line->coverage.cursor;
if (cell->x != ix1) {
if (unlikely (cell->x > ix1)) {
do {
if (cell->prev->x < ix1)
break;
cell = cell->prev;
} while (TRUE);
} else do {
UNROLL3({
if (cell->x >= ix1)
break;
cell = cell->next;
});
} while (TRUE);
 
if (cell->x != ix1)
cell = coverage_alloc (sweep_line, cell, ix1);
}
 
cell->uncovered_area += sign * y.quo * (STEP_X + fx1);
cell->covered_height += sign * y.quo;
y.quo += y1;
 
cell = cell->next;
if (cell->x != ++ix1)
cell = coverage_alloc (sweep_line, cell, ix1);
if (ix1 < ix2) {
struct quorem dydx_full = floored_divrem (STEP_X*dy, dx);
 
do {
cairo_fixed_t y_skip = dydx_full.quo;
y.rem += dydx_full.rem;
if (y.rem >= dx) {
++y_skip;
y.rem -= dx;
}
 
y.quo += y_skip;
 
y_skip *= sign;
cell->covered_height += y_skip;
cell->uncovered_area += y_skip*STEP_X;
 
cell = cell->next;
if (cell->x != ++ix1)
cell = coverage_alloc (sweep_line, cell, ix1);
} while (ix1 != ix2);
}
cell->uncovered_area += sign*(y2 - y.quo)*fx2;
cell->covered_height += sign*(y2 - y.quo);
sweep_line->coverage.cursor = cell;
}
}
 
inline static void
full_inc_edge (edge_t *edge)
{
edge->x.quo += edge->dxdy_full.quo;
edge->x.rem += edge->dxdy_full.rem;
if (edge->x.rem >= 0) {
++edge->x.quo;
edge->x.rem -= edge->dy;
}
}
 
static void
full_add_edge (sweep_line_t *sweep_line, edge_t *edge, int sign)
{
struct cell *cell;
cairo_fixed_t x1, x2;
int ix1, ix2;
int frac;
 
edge->current_sign = sign;
 
ix1 = _cairo_fixed_integer_part (edge->x.quo);
 
if (edge->vertical) {
frac = _cairo_fixed_fractional_part (edge->x.quo);
cell = coverage_find (sweep_line, ix1);
cell->covered_height += sign * STEP_Y;
cell->uncovered_area += sign * 2 * frac * STEP_Y;
return;
}
 
x1 = edge->x.quo;
full_inc_edge (edge);
x2 = edge->x.quo;
 
ix2 = _cairo_fixed_integer_part (edge->x.quo);
 
/* Edge is entirely within a column? */
if (likely (ix1 == ix2)) {
frac = _cairo_fixed_fractional_part (x1) +
_cairo_fixed_fractional_part (x2);
cell = coverage_find (sweep_line, ix1);
cell->covered_height += sign * STEP_Y;
cell->uncovered_area += sign * frac * STEP_Y;
return;
}
 
coverage_render_cells (sweep_line, x1, x2, 0, STEP_Y, sign);
}
 
static void
full_nonzero (sweep_line_t *sweep_line)
{
cairo_list_t *pos;
 
sweep_line->is_vertical = TRUE;
pos = sweep_line->active.next;
do {
edge_t *left = link_to_edge (pos), *right;
int winding = left->edge.dir;
 
sweep_line->is_vertical &= left->vertical;
 
pos = left->link.next;
do {
if (unlikely (pos == &sweep_line->active)) {
full_add_edge (sweep_line, left, +1);
return;
}
 
right = link_to_edge (pos);
pos = pos->next;
sweep_line->is_vertical &= right->vertical;
 
winding += right->edge.dir;
if (0 == winding) {
if (pos == &sweep_line->active ||
link_to_edge (pos)->x.quo != right->x.quo)
{
break;
}
}
 
if (! right->vertical)
full_inc_edge (right);
} while (TRUE);
 
full_add_edge (sweep_line, left, +1);
full_add_edge (sweep_line, right, -1);
} while (pos != &sweep_line->active);
}
 
static void
full_evenodd (sweep_line_t *sweep_line)
{
cairo_list_t *pos;
 
sweep_line->is_vertical = TRUE;
pos = sweep_line->active.next;
do {
edge_t *left = link_to_edge (pos), *right;
int winding = 0;
 
sweep_line->is_vertical &= left->vertical;
 
pos = left->link.next;
do {
if (pos == &sweep_line->active) {
full_add_edge (sweep_line, left, +1);
return;
}
 
right = link_to_edge (pos);
pos = pos->next;
sweep_line->is_vertical &= right->vertical;
 
if (++winding & 1) {
if (pos == &sweep_line->active ||
link_to_edge (pos)->x.quo != right->x.quo)
{
break;
}
}
 
if (! right->vertical)
full_inc_edge (right);
} while (TRUE);
 
full_add_edge (sweep_line, left, +1);
full_add_edge (sweep_line, right, -1);
} while (pos != &sweep_line->active);
}
 
static void
render_rows (cairo_botor_scan_converter_t *self,
sweep_line_t *sweep_line,
int y, int height,
cairo_span_renderer_t *renderer)
{
cairo_half_open_span_t spans_stack[CAIRO_STACK_ARRAY_LENGTH (cairo_half_open_span_t)];
cairo_half_open_span_t *spans = spans_stack;
struct cell *cell;
int prev_x, cover;
int num_spans;
cairo_status_t status;
 
if (unlikely (sweep_line->coverage.count == 0)) {
status = renderer->render_rows (renderer, y, height, NULL, 0);
if (unlikely (status))
longjmp (sweep_line->unwind, status);
return;
}
 
/* Allocate enough spans for the row. */
 
num_spans = 2*sweep_line->coverage.count+2;
if (unlikely (num_spans > ARRAY_LENGTH (spans_stack))) {
spans = _cairo_malloc_ab (num_spans, sizeof (cairo_half_open_span_t));
if (unlikely (spans == NULL)) {
longjmp (sweep_line->unwind,
_cairo_error (CAIRO_STATUS_NO_MEMORY));
}
}
 
/* Form the spans from the coverage and areas. */
num_spans = 0;
prev_x = self->xmin;
cover = 0;
cell = sweep_line->coverage.head.next;
do {
int x = cell->x;
int area;
 
if (x > prev_x) {
spans[num_spans].x = prev_x;
spans[num_spans].coverage = AREA_TO_ALPHA (cover);
++num_spans;
}
 
cover += cell->covered_height*STEP_X*2;
area = cover - cell->uncovered_area;
 
spans[num_spans].x = x;
spans[num_spans].coverage = AREA_TO_ALPHA (area);
++num_spans;
 
prev_x = x + 1;
} while ((cell = cell->next) != &sweep_line->coverage.tail);
 
if (prev_x <= self->xmax) {
spans[num_spans].x = prev_x;
spans[num_spans].coverage = AREA_TO_ALPHA (cover);
++num_spans;
}
 
if (cover && prev_x < self->xmax) {
spans[num_spans].x = self->xmax;
spans[num_spans].coverage = 0;
++num_spans;
}
 
status = renderer->render_rows (renderer, y, height, spans, num_spans);
 
if (unlikely (spans != spans_stack))
free (spans);
 
coverage_reset (&sweep_line->coverage);
 
if (unlikely (status))
longjmp (sweep_line->unwind, status);
}
 
static void
full_repeat (sweep_line_t *sweep)
{
edge_t *edge;
 
cairo_list_foreach_entry (edge, edge_t, &sweep->active, link) {
if (edge->current_sign)
full_add_edge (sweep, edge, edge->current_sign);
else if (! edge->vertical)
full_inc_edge (edge);
}
}
 
static void
full_reset (sweep_line_t *sweep)
{
edge_t *edge;
 
cairo_list_foreach_entry (edge, edge_t, &sweep->active, link)
edge->current_sign = 0;
}
 
static void
full_step (cairo_botor_scan_converter_t *self,
sweep_line_t *sweep_line,
cairo_fixed_t row,
cairo_span_renderer_t *renderer)
{
int top, bottom;
 
top = _cairo_fixed_integer_part (sweep_line->current_row);
bottom = _cairo_fixed_integer_part (row);
if (cairo_list_is_empty (&sweep_line->active)) {
cairo_status_t status;
 
status = renderer->render_rows (renderer, top, bottom - top, NULL, 0);
if (unlikely (status))
longjmp (sweep_line->unwind, status);
 
return;
}
 
if (self->fill_rule == CAIRO_FILL_RULE_WINDING)
full_nonzero (sweep_line);
else
full_evenodd (sweep_line);
 
if (sweep_line->is_vertical || bottom == top + 1) {
render_rows (self, sweep_line, top, bottom - top, renderer);
full_reset (sweep_line);
return;
}
 
render_rows (self, sweep_line, top++, 1, renderer);
do {
full_repeat (sweep_line);
render_rows (self, sweep_line, top, 1, renderer);
} while (++top != bottom);
 
full_reset (sweep_line);
}
 
cairo_always_inline static void
sub_inc_edge (edge_t *edge,
cairo_fixed_t height)
{
if (height == 1) {
edge->x.quo += edge->dxdy.quo;
edge->x.rem += edge->dxdy.rem;
if (edge->x.rem >= 0) {
++edge->x.quo;
edge->x.rem -= edge->dy;
}
} else {
edge->x.quo += height * edge->dxdy.quo;
edge->x.rem += height * edge->dxdy.rem;
if (edge->x.rem >= 0) {
int carry = edge->x.rem / edge->dy + 1;
edge->x.quo += carry;
edge->x.rem -= carry * edge->dy;
}
}
}
 
static void
sub_add_run (sweep_line_t *sweep_line, edge_t *edge, int y, int sign)
{
struct run *run;
 
run = _cairo_freepool_alloc (&sweep_line->runs);
if (unlikely (run == NULL))
longjmp (sweep_line->unwind, _cairo_error (CAIRO_STATUS_NO_MEMORY));
 
run->y = y;
run->sign = sign;
run->next = edge->runs;
edge->runs = run;
 
edge->current_sign = sign;
}
 
inline static cairo_bool_t
edges_coincident (edge_t *left, edge_t *right, cairo_fixed_t y)
{
/* XXX is compare_x_for_y() worth executing during sub steps? */
return line_equal (&left->edge.line, &right->edge.line);
//edges_compare_x_for_y (&left->edge, &right->edge, y) >= 0;
}
 
static void
sub_nonzero (sweep_line_t *sweep_line)
{
cairo_fixed_t y = sweep_line->current_subrow;
cairo_fixed_t fy = _cairo_fixed_fractional_part (y);
cairo_list_t *pos;
 
pos = sweep_line->active.next;
do {
edge_t *left = link_to_edge (pos), *right;
int winding = left->edge.dir;
 
pos = left->link.next;
do {
if (unlikely (pos == &sweep_line->active)) {
if (left->current_sign != +1)
sub_add_run (sweep_line, left, fy, +1);
return;
}
 
right = link_to_edge (pos);
pos = pos->next;
 
winding += right->edge.dir;
if (0 == winding) {
if (pos == &sweep_line->active ||
! edges_coincident (right, link_to_edge (pos), y))
{
break;
}
}
 
if (right->current_sign)
sub_add_run (sweep_line, right, fy, 0);
} while (TRUE);
 
if (left->current_sign != +1)
sub_add_run (sweep_line, left, fy, +1);
if (right->current_sign != -1)
sub_add_run (sweep_line, right, fy, -1);
} while (pos != &sweep_line->active);
}
 
static void
sub_evenodd (sweep_line_t *sweep_line)
{
cairo_fixed_t y = sweep_line->current_subrow;
cairo_fixed_t fy = _cairo_fixed_fractional_part (y);
cairo_list_t *pos;
 
pos = sweep_line->active.next;
do {
edge_t *left = link_to_edge (pos), *right;
int winding = 0;
 
pos = left->link.next;
do {
if (unlikely (pos == &sweep_line->active)) {
if (left->current_sign != +1)
sub_add_run (sweep_line, left, fy, +1);
return;
}
 
right = link_to_edge (pos);
pos = pos->next;
 
if (++winding & 1) {
if (pos == &sweep_line->active ||
! edges_coincident (right, link_to_edge (pos), y))
{
break;
}
}
 
if (right->current_sign)
sub_add_run (sweep_line, right, fy, 0);
} while (TRUE);
 
if (left->current_sign != +1)
sub_add_run (sweep_line, left, fy, +1);
if (right->current_sign != -1)
sub_add_run (sweep_line, right, fy, -1);
} while (pos != &sweep_line->active);
}
 
cairo_always_inline static void
sub_step (cairo_botor_scan_converter_t *self,
sweep_line_t *sweep_line)
{
if (cairo_list_is_empty (&sweep_line->active))
return;
 
if (self->fill_rule == CAIRO_FILL_RULE_WINDING)
sub_nonzero (sweep_line);
else
sub_evenodd (sweep_line);
}
 
static void
coverage_render_runs (sweep_line_t *sweep, edge_t *edge,
cairo_fixed_t y1, cairo_fixed_t y2)
{
struct run tail;
struct run *run = &tail;
 
tail.next = NULL;
tail.y = y2;
 
/* Order the runs top->bottom */
while (edge->runs) {
struct run *r;
 
r = edge->runs;
edge->runs = r->next;
r->next = run;
run = r;
}
 
if (run->y > y1)
sub_inc_edge (edge, run->y - y1);
 
do {
cairo_fixed_t x1, x2;
 
y1 = run->y;
y2 = run->next->y;
 
x1 = edge->x.quo;
if (y2 - y1 == STEP_Y)
full_inc_edge (edge);
else
sub_inc_edge (edge, y2 - y1);
x2 = edge->x.quo;
 
if (run->sign) {
int ix1, ix2;
 
ix1 = _cairo_fixed_integer_part (x1);
ix2 = _cairo_fixed_integer_part (x2);
 
/* Edge is entirely within a column? */
if (likely (ix1 == ix2)) {
struct cell *cell;
int frac;
 
frac = _cairo_fixed_fractional_part (x1) +
_cairo_fixed_fractional_part (x2);
cell = coverage_find (sweep, ix1);
cell->covered_height += run->sign * (y2 - y1);
cell->uncovered_area += run->sign * (y2 - y1) * frac;
} else {
coverage_render_cells (sweep, x1, x2, y1, y2, run->sign);
}
}
 
run = run->next;
} while (run->next != NULL);
}
 
static void
coverage_render_vertical_runs (sweep_line_t *sweep, edge_t *edge, cairo_fixed_t y2)
{
struct cell *cell;
struct run *run;
int height = 0;
 
for (run = edge->runs; run != NULL; run = run->next) {
if (run->sign)
height += run->sign * (y2 - run->y);
y2 = run->y;
}
 
cell = coverage_find (sweep, _cairo_fixed_integer_part (edge->x.quo));
cell->covered_height += height;
cell->uncovered_area += 2 * _cairo_fixed_fractional_part (edge->x.quo) * height;
}
 
cairo_always_inline static void
sub_emit (cairo_botor_scan_converter_t *self,
sweep_line_t *sweep,
cairo_span_renderer_t *renderer)
{
edge_t *edge;
 
sub_step (self, sweep);
 
/* convert the runs into coverages */
 
cairo_list_foreach_entry (edge, edge_t, &sweep->active, link) {
if (edge->runs == NULL) {
if (! edge->vertical) {
if (edge->flags & START) {
sub_inc_edge (edge,
STEP_Y - _cairo_fixed_fractional_part (edge->edge.top));
edge->flags &= ~START;
} else
full_inc_edge (edge);
}
} else {
if (edge->vertical) {
coverage_render_vertical_runs (sweep, edge, STEP_Y);
} else {
int y1 = 0;
if (edge->flags & START) {
y1 = _cairo_fixed_fractional_part (edge->edge.top);
edge->flags &= ~START;
}
coverage_render_runs (sweep, edge, y1, STEP_Y);
}
}
edge->current_sign = 0;
edge->runs = NULL;
}
 
cairo_list_foreach_entry (edge, edge_t, &sweep->stopped, link) {
int y2 = _cairo_fixed_fractional_part (edge->edge.bottom);
if (edge->vertical) {
coverage_render_vertical_runs (sweep, edge, y2);
} else {
int y1 = 0;
if (edge->flags & START)
y1 = _cairo_fixed_fractional_part (edge->edge.top);
coverage_render_runs (sweep, edge, y1, y2);
}
}
cairo_list_init (&sweep->stopped);
 
_cairo_freepool_reset (&sweep->runs);
 
render_rows (self, sweep,
_cairo_fixed_integer_part (sweep->current_row), 1,
renderer);
}
 
static void
sweep_line_init (sweep_line_t *sweep_line,
event_t **start_events,
int num_events)
{
cairo_list_init (&sweep_line->active);
cairo_list_init (&sweep_line->stopped);
sweep_line->insert_cursor = &sweep_line->active;
 
sweep_line->current_row = INT32_MIN;
sweep_line->current_subrow = INT32_MIN;
 
coverage_init (&sweep_line->coverage);
_cairo_freepool_init (&sweep_line->runs, sizeof (struct run));
 
start_event_sort (start_events, num_events);
start_events[num_events] = NULL;
 
sweep_line->queue.start_events = start_events;
 
_cairo_freepool_init (&sweep_line->queue.pool,
sizeof (queue_event_t));
pqueue_init (&sweep_line->queue.pq);
sweep_line->queue.pq.elements[PQ_FIRST_ENTRY] = NULL;
}
 
static void
sweep_line_delete (sweep_line_t *sweep_line,
edge_t *edge)
{
if (sweep_line->insert_cursor == &edge->link)
sweep_line->insert_cursor = edge->link.prev;
 
cairo_list_del (&edge->link);
if (edge->runs)
cairo_list_add_tail (&edge->link, &sweep_line->stopped);
edge->flags |= STOP;
}
 
static void
sweep_line_swap (sweep_line_t *sweep_line,
edge_t *left,
edge_t *right)
{
right->link.prev = left->link.prev;
left->link.next = right->link.next;
right->link.next = &left->link;
left->link.prev = &right->link;
left->link.next->prev = &left->link;
right->link.prev->next = &right->link;
}
 
static void
sweep_line_fini (sweep_line_t *sweep_line)
{
pqueue_fini (&sweep_line->queue.pq);
_cairo_freepool_fini (&sweep_line->queue.pool);
coverage_fini (&sweep_line->coverage);
_cairo_freepool_fini (&sweep_line->runs);
}
 
static cairo_status_t
botor_generate (cairo_botor_scan_converter_t *self,
event_t **start_events,
cairo_span_renderer_t *renderer)
{
cairo_status_t status;
sweep_line_t sweep_line;
cairo_fixed_t ybot;
event_t *event;
cairo_list_t *left, *right;
edge_t *e1, *e2;
int bottom;
 
sweep_line_init (&sweep_line, start_events, self->num_edges);
if ((status = setjmp (sweep_line.unwind)))
goto unwind;
 
ybot = self->extents.p2.y;
sweep_line.current_subrow = self->extents.p1.y;
sweep_line.current_row = _cairo_fixed_floor (self->extents.p1.y);
event = *sweep_line.queue.start_events++;
do {
/* Can we process a full step in one go? */
if (event->y >= sweep_line.current_row + STEP_Y) {
bottom = _cairo_fixed_floor (event->y);
full_step (self, &sweep_line, bottom, renderer);
sweep_line.current_row = bottom;
sweep_line.current_subrow = bottom;
}
 
do {
if (event->y > sweep_line.current_subrow) {
sub_step (self, &sweep_line);
sweep_line.current_subrow = event->y;
}
 
do {
/* Update the active list using Bentley-Ottmann */
switch (event->type) {
case EVENT_TYPE_START:
e1 = ((start_event_t *) event)->edge;
 
sweep_line_insert (&sweep_line, e1);
event_insert_stop (&sweep_line, e1);
 
left = e1->link.prev;
right = e1->link.next;
 
if (left != &sweep_line.active) {
event_insert_if_intersect_below_current_y (&sweep_line,
link_to_edge (left), e1);
}
 
if (right != &sweep_line.active) {
event_insert_if_intersect_below_current_y (&sweep_line,
e1, link_to_edge (right));
}
 
break;
 
case EVENT_TYPE_STOP:
e1 = ((queue_event_t *) event)->e1;
event_delete (&sweep_line, event);
 
left = e1->link.prev;
right = e1->link.next;
 
sweep_line_delete (&sweep_line, e1);
 
if (left != &sweep_line.active &&
right != &sweep_line.active)
{
event_insert_if_intersect_below_current_y (&sweep_line,
link_to_edge (left),
link_to_edge (right));
}
 
break;
 
case EVENT_TYPE_INTERSECTION:
e1 = ((queue_event_t *) event)->e1;
e2 = ((queue_event_t *) event)->e2;
 
event_delete (&sweep_line, event);
if (e1->flags & STOP)
break;
if (e2->flags & STOP)
break;
 
/* skip this intersection if its edges are not adjacent */
if (&e2->link != e1->link.next)
break;
 
left = e1->link.prev;
right = e2->link.next;
 
sweep_line_swap (&sweep_line, e1, e2);
 
/* after the swap e2 is left of e1 */
if (left != &sweep_line.active) {
event_insert_if_intersect_below_current_y (&sweep_line,
link_to_edge (left), e2);
}
 
if (right != &sweep_line.active) {
event_insert_if_intersect_below_current_y (&sweep_line,
e1, link_to_edge (right));
}
 
break;
}
 
event = event_next (&sweep_line);
if (event == NULL)
goto end;
} while (event->y == sweep_line.current_subrow);
} while (event->y < sweep_line.current_row + STEP_Y);
 
bottom = sweep_line.current_row + STEP_Y;
sub_emit (self, &sweep_line, renderer);
sweep_line.current_subrow = bottom;
sweep_line.current_row = sweep_line.current_subrow;
} while (TRUE);
 
end:
/* flush any partial spans */
if (sweep_line.current_subrow != sweep_line.current_row) {
sub_emit (self, &sweep_line, renderer);
sweep_line.current_row += STEP_Y;
sweep_line.current_subrow = sweep_line.current_row;
}
/* clear the rest */
if (sweep_line.current_subrow < ybot) {
bottom = _cairo_fixed_integer_part (sweep_line.current_row);
status = renderer->render_rows (renderer,
bottom, _cairo_fixed_integer_ceil (ybot) - bottom,
NULL, 0);
}
 
unwind:
sweep_line_fini (&sweep_line);
 
return status;
}
 
static cairo_status_t
_cairo_botor_scan_converter_generate (void *converter,
cairo_span_renderer_t *renderer)
{
cairo_botor_scan_converter_t *self = converter;
start_event_t stack_events[CAIRO_STACK_ARRAY_LENGTH (start_event_t)];
start_event_t *events;
event_t *stack_event_ptrs[ARRAY_LENGTH (stack_events) + 1];
event_t **event_ptrs;
struct _cairo_botor_scan_converter_chunk *chunk;
cairo_status_t status;
int num_events;
int i, j;
 
num_events = self->num_edges;
if (unlikely (0 == num_events)) {
return renderer->render_rows (renderer,
_cairo_fixed_integer_floor (self->extents.p1.y),
_cairo_fixed_integer_ceil (self->extents.p2.y) -
_cairo_fixed_integer_floor (self->extents.p1.y),
NULL, 0);
}
 
events = stack_events;
event_ptrs = stack_event_ptrs;
if (unlikely (num_events >= ARRAY_LENGTH (stack_events))) {
events = _cairo_malloc_ab_plus_c (num_events,
sizeof (start_event_t) + sizeof (event_t *),
sizeof (event_t *));
if (unlikely (events == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
event_ptrs = (event_t **) (events + num_events);
}
 
j = 0;
for (chunk = &self->chunks; chunk != NULL; chunk = chunk->next) {
edge_t *edge;
 
edge = chunk->base;
for (i = 0; i < chunk->count; i++) {
event_ptrs[j] = (event_t *) &events[j];
 
events[j].y = edge->edge.top;
events[j].type = EVENT_TYPE_START;
events[j].edge = edge;
 
edge++, j++;
}
}
 
status = botor_generate (self, event_ptrs, renderer);
 
if (events != stack_events)
free (events);
 
return status;
}
 
static edge_t *
botor_allocate_edge (cairo_botor_scan_converter_t *self)
{
struct _cairo_botor_scan_converter_chunk *chunk;
 
chunk = self->tail;
if (chunk->count == chunk->size) {
int size;
 
size = chunk->size * 2;
chunk->next = _cairo_malloc_ab_plus_c (size,
sizeof (edge_t),
sizeof (struct _cairo_botor_scan_converter_chunk));
if (unlikely (chunk->next == NULL))
return NULL;
 
chunk = chunk->next;
chunk->next = NULL;
chunk->count = 0;
chunk->size = size;
chunk->base = chunk + 1;
self->tail = chunk;
}
 
return (edge_t *) chunk->base + chunk->count++;
}
 
static cairo_status_t
botor_add_edge (cairo_botor_scan_converter_t *self,
const cairo_edge_t *edge)
{
edge_t *e;
cairo_fixed_t dx, dy;
 
e = botor_allocate_edge (self);
if (unlikely (e == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
cairo_list_init (&e->link);
e->edge = *edge;
 
dx = edge->line.p2.x - edge->line.p1.x;
dy = edge->line.p2.y - edge->line.p1.y;
e->dy = dy;
 
if (dx == 0) {
e->vertical = TRUE;
e->x.quo = edge->line.p1.x;
e->x.rem = 0;
e->dxdy.quo = 0;
e->dxdy.rem = 0;
e->dxdy_full.quo = 0;
e->dxdy_full.rem = 0;
} else {
e->vertical = FALSE;
e->dxdy = floored_divrem (dx, dy);
if (edge->top == edge->line.p1.y) {
e->x.quo = edge->line.p1.x;
e->x.rem = 0;
} else {
e->x = floored_muldivrem (edge->top - edge->line.p1.y,
dx, dy);
e->x.quo += edge->line.p1.x;
}
 
if (_cairo_fixed_integer_part (edge->bottom) - _cairo_fixed_integer_part (edge->top) > 1) {
e->dxdy_full = floored_muldivrem (STEP_Y, dx, dy);
} else {
e->dxdy_full.quo = 0;
e->dxdy_full.rem = 0;
}
}
 
e->x.rem = -e->dy;
e->current_sign = 0;
e->runs = NULL;
e->flags = START;
 
self->num_edges++;
 
return CAIRO_STATUS_SUCCESS;
}
 
static cairo_status_t
_cairo_botor_scan_converter_add_edge (void *converter,
const cairo_point_t *p1,
const cairo_point_t *p2,
int top, int bottom,
int dir)
{
cairo_botor_scan_converter_t *self = converter;
cairo_edge_t edge;
 
edge.line.p1 = *p1;
edge.line.p2 = *p2;
edge.top = top;
edge.bottom = bottom;
edge.dir = dir;
 
return botor_add_edge (self, &edge);
}
 
static cairo_status_t
_cairo_botor_scan_converter_add_polygon (void *converter,
const cairo_polygon_t *polygon)
{
cairo_botor_scan_converter_t *self = converter;
cairo_status_t status;
int i;
 
for (i = 0; i < polygon->num_edges; i++) {
status = botor_add_edge (self, &polygon->edges[i]);
if (unlikely (status))
return status;
}
 
return CAIRO_STATUS_SUCCESS;
}
 
static void
_cairo_botor_scan_converter_destroy (void *converter)
{
cairo_botor_scan_converter_t *self = converter;
struct _cairo_botor_scan_converter_chunk *chunk, *next;
 
for (chunk = self->chunks.next; chunk != NULL; chunk = next) {
next = chunk->next;
free (chunk);
}
}
 
void
_cairo_botor_scan_converter_init (cairo_botor_scan_converter_t *self,
const cairo_box_t *extents,
cairo_fill_rule_t fill_rule)
{
self->base.destroy = _cairo_botor_scan_converter_destroy;
self->base.add_edge = _cairo_botor_scan_converter_add_edge;
self->base.add_polygon = _cairo_botor_scan_converter_add_polygon;
self->base.generate = _cairo_botor_scan_converter_generate;
 
self->extents = *extents;
self->fill_rule = fill_rule;
 
self->xmin = _cairo_fixed_integer_floor (extents->p1.x);
self->xmax = _cairo_fixed_integer_ceil (extents->p2.x);
 
self->chunks.base = self->buf;
self->chunks.next = NULL;
self->chunks.count = 0;
self->chunks.size = sizeof (self->buf) / sizeof (edge_t);
self->tail = &self->chunks;
 
self->num_edges = 0;
}
/programs/develop/libraries/cairo/src/cairo-boxes-private.h
0,0 → 1,84
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2009 Intel Corporation
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* Contributor(s):
* Chris Wilson <chris@chris-wilson.co.uk>
*/
 
#ifndef CAIRO_BOXES_H
#define CAIRO_BOXES_H
 
#include "cairo-types-private.h"
#include "cairo-compiler-private.h"
 
struct _cairo_boxes_t {
cairo_status_t status;
cairo_box_t limit;
const cairo_box_t *limits;
int num_limits;
int num_boxes;
unsigned int is_pixel_aligned : 1;
 
struct _cairo_boxes_chunk {
struct _cairo_boxes_chunk *next;
cairo_box_t *base;
int count;
int size;
} chunks, *tail;
cairo_box_t boxes_embedded[32];
};
 
cairo_private void
_cairo_boxes_init (cairo_boxes_t *boxes);
 
cairo_private void
_cairo_boxes_init_for_array (cairo_boxes_t *boxes,
cairo_box_t *array,
int num_boxes);
 
cairo_private void
_cairo_boxes_limit (cairo_boxes_t *boxes,
const cairo_box_t *limits,
int num_limits);
 
cairo_private cairo_status_t
_cairo_boxes_add (cairo_boxes_t *boxes,
const cairo_box_t *box);
 
cairo_private void
_cairo_boxes_extents (const cairo_boxes_t *boxes,
cairo_rectangle_int_t *extents);
 
cairo_private void
_cairo_boxes_clear (cairo_boxes_t *boxes);
 
cairo_private void
_cairo_boxes_fini (cairo_boxes_t *boxes);
 
#endif /* CAIRO_BOXES_H */
/programs/develop/libraries/cairo/src/cairo-boxes.c
0,0 → 1,300
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2009 Intel Corporation
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* Contributor(s):
* Chris Wilson <chris@chris-wilson.co.uk>
*/
 
#include "cairoint.h"
 
#include "cairo-boxes-private.h"
#include "cairo-error-private.h"
 
void
_cairo_boxes_init (cairo_boxes_t *boxes)
{
boxes->status = CAIRO_STATUS_SUCCESS;
boxes->num_limits = 0;
boxes->num_boxes = 0;
 
boxes->tail = &boxes->chunks;
boxes->chunks.next = NULL;
boxes->chunks.base = boxes->boxes_embedded;
boxes->chunks.size = ARRAY_LENGTH (boxes->boxes_embedded);
boxes->chunks.count = 0;
 
boxes->is_pixel_aligned = TRUE;
}
 
void
_cairo_boxes_init_for_array (cairo_boxes_t *boxes,
cairo_box_t *array,
int num_boxes)
{
int n;
 
boxes->status = CAIRO_STATUS_SUCCESS;
boxes->num_limits = 0;
boxes->num_boxes = num_boxes;
 
boxes->tail = &boxes->chunks;
boxes->chunks.next = NULL;
boxes->chunks.base = array;
boxes->chunks.size = num_boxes;
boxes->chunks.count = num_boxes;
 
for (n = 0; n < num_boxes; n++) {
if (! _cairo_fixed_is_integer (array[n].p1.x) ||
! _cairo_fixed_is_integer (array[n].p1.y) ||
! _cairo_fixed_is_integer (array[n].p2.x) ||
! _cairo_fixed_is_integer (array[n].p2.y))
{
break;
}
}
 
boxes->is_pixel_aligned = n == num_boxes;
}
 
void
_cairo_boxes_limit (cairo_boxes_t *boxes,
const cairo_box_t *limits,
int num_limits)
{
int n;
 
boxes->limits = limits;
boxes->num_limits = num_limits;
 
if (boxes->num_limits) {
boxes->limit = limits[0];
for (n = 1; n < num_limits; n++) {
if (limits[n].p1.x < boxes->limit.p1.x)
boxes->limit.p1.x = limits[n].p1.x;
 
if (limits[n].p1.y < boxes->limit.p1.y)
boxes->limit.p1.y = limits[n].p1.y;
 
if (limits[n].p2.x > boxes->limit.p2.x)
boxes->limit.p2.x = limits[n].p2.x;
 
if (limits[n].p2.y > boxes->limit.p2.y)
boxes->limit.p2.y = limits[n].p2.y;
}
}
}
 
static void
_cairo_boxes_add_internal (cairo_boxes_t *boxes,
const cairo_box_t *box)
{
struct _cairo_boxes_chunk *chunk;
 
if (unlikely (boxes->status))
return;
 
chunk = boxes->tail;
if (unlikely (chunk->count == chunk->size)) {
int size;
 
size = chunk->size * 2;
chunk->next = _cairo_malloc_ab_plus_c (size,
sizeof (cairo_box_t),
sizeof (struct _cairo_boxes_chunk));
 
if (unlikely (chunk->next == NULL)) {
boxes->status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
return;
}
 
chunk = chunk->next;
boxes->tail = chunk;
 
chunk->next = NULL;
chunk->count = 0;
chunk->size = size;
chunk->base = (cairo_box_t *) (chunk + 1);
}
 
chunk->base[chunk->count++] = *box;
boxes->num_boxes++;
 
if (boxes->is_pixel_aligned) {
boxes->is_pixel_aligned =
_cairo_fixed_is_integer (box->p1.x) &&
_cairo_fixed_is_integer (box->p1.y) &&
_cairo_fixed_is_integer (box->p2.x) &&
_cairo_fixed_is_integer (box->p2.y);
}
}
 
cairo_status_t
_cairo_boxes_add (cairo_boxes_t *boxes,
const cairo_box_t *box)
{
if (box->p1.y == box->p2.y)
return CAIRO_STATUS_SUCCESS;
 
if (box->p1.x == box->p2.x)
return CAIRO_STATUS_SUCCESS;
 
if (boxes->num_limits) {
cairo_point_t p1, p2;
cairo_bool_t reversed = FALSE;
int n;
 
/* support counter-clockwise winding for rectangular tessellation */
if (box->p1.x < box->p2.x) {
p1.x = box->p1.x;
p2.x = box->p2.x;
} else {
p2.x = box->p1.x;
p1.x = box->p2.x;
reversed = ! reversed;
}
 
if (p1.x >= boxes->limit.p2.x || p2.x <= boxes->limit.p1.x)
return CAIRO_STATUS_SUCCESS;
 
if (box->p1.y < box->p2.y) {
p1.y = box->p1.y;
p2.y = box->p2.y;
} else {
p2.y = box->p1.y;
p1.y = box->p2.y;
reversed = ! reversed;
}
 
if (p1.y >= boxes->limit.p2.y || p2.y <= boxes->limit.p1.y)
return CAIRO_STATUS_SUCCESS;
 
for (n = 0; n < boxes->num_limits; n++) {
const cairo_box_t *limits = &boxes->limits[n];
cairo_box_t _box;
cairo_point_t _p1, _p2;
 
if (p1.x >= limits->p2.x || p2.x <= limits->p1.x)
continue;
if (p1.y >= limits->p2.y || p2.y <= limits->p1.y)
continue;
 
/* Otherwise, clip the box to the limits. */
_p1 = p1;
if (_p1.x < limits->p1.x)
_p1.x = limits->p1.x;
if (_p1.y < limits->p1.y)
_p1.y = limits->p1.y;
 
_p2 = p2;
if (_p2.x > limits->p2.x)
_p2.x = limits->p2.x;
if (_p2.y > limits->p2.y)
_p2.y = limits->p2.y;
 
if (_p2.y <= _p1.y || _p2.x <= _p1.x)
continue;
 
_box.p1.y = _p1.y;
_box.p2.y = _p2.y;
if (reversed) {
_box.p1.x = _p2.x;
_box.p2.x = _p1.x;
} else {
_box.p1.x = _p1.x;
_box.p2.x = _p2.x;
}
 
_cairo_boxes_add_internal (boxes, &_box);
}
} else {
_cairo_boxes_add_internal (boxes, box);
}
 
return boxes->status;
}
 
void
_cairo_boxes_extents (const cairo_boxes_t *boxes,
cairo_rectangle_int_t *extents)
{
const struct _cairo_boxes_chunk *chunk;
cairo_box_t box;
int i;
 
box.p1.y = box.p1.x = INT_MAX;
box.p2.y = box.p2.x = INT_MIN;
 
for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
const cairo_box_t *b = chunk->base;
for (i = 0; i < chunk->count; i++) {
if (b[i].p1.x < box.p1.x)
box.p1.x = b[i].p1.x;
 
if (b[i].p1.y < box.p1.y)
box.p1.y = b[i].p1.y;
 
if (b[i].p2.x > box.p2.x)
box.p2.x = b[i].p2.x;
 
if (b[i].p2.y > box.p2.y)
box.p2.y = b[i].p2.y;
}
}
 
_cairo_box_round_to_rectangle (&box, extents);
}
 
void
_cairo_boxes_clear (cairo_boxes_t *boxes)
{
struct _cairo_boxes_chunk *chunk, *next;
 
for (chunk = boxes->chunks.next; chunk != NULL; chunk = next) {
next = chunk->next;
free (chunk);
}
 
boxes->tail = &boxes->chunks;
boxes->chunks.next = 0;
boxes->chunks.count = 0;
boxes->num_boxes = 0;
 
boxes->is_pixel_aligned = TRUE;
}
 
void
_cairo_boxes_fini (cairo_boxes_t *boxes)
{
struct _cairo_boxes_chunk *chunk, *next;
 
for (chunk = boxes->chunks.next; chunk != NULL; chunk = next) {
next = chunk->next;
free (chunk);
}
}
/programs/develop/libraries/cairo/src/cairo-cache-private.h
0,0 → 1,145
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2004 Red Hat, Inc.
* Copyright © 2005 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
* Keith Packard <keithp@keithp.com>
* Graydon Hoare <graydon@redhat.com>
* Carl Worth <cworth@cworth.org>
*/
 
#ifndef CAIRO_CACHE_PRIVATE_H
#define CAIRO_CACHE_PRIVATE_H
 
#include "cairo-compiler-private.h"
#include "cairo-types-private.h"
 
/**
* cairo_cache_entry_t:
*
* A #cairo_cache_entry_t contains both a key and a value for
* #cairo_cache_t. User-derived types for #cairo_cache_entry_t must
* have a #cairo_cache_entry_t as their first field. For example:
*
* typedef _my_entry {
* cairo_cache_entry_t base;
* ... Remainder of key and value fields here ..
* } my_entry_t;
*
* which then allows a pointer to my_entry_t to be passed to any of
* the #cairo_cache_t functions as follows without requiring a cast:
*
* _cairo_cache_insert (cache, &my_entry->base, size);
*
* IMPORTANT: The caller is responsible for initializing
* my_entry->base.hash with a hash code derived from the key. The
* essential property of the hash code is that keys_equal must never
* return %TRUE for two keys that have different hashes. The best hash
* code will reduce the frequency of two keys with the same code for
* which keys_equal returns %FALSE.
*
* The user must also initialize my_entry->base.size to indicate
* the size of the current entry. What units to use for size is
* entirely up to the caller, (though the same units must be used for
* the max_size parameter passed to _cairo_cache_create()). If all
* entries are close to the same size, the simplest thing to do is to
* just use units of "entries", (eg. set size==1 in all entries and
* set max_size to the number of entries which you want to be saved
* in the cache).
*
* Which parts of the entry make up the "key" and which part make up
* the value are entirely up to the caller, (as determined by the
* computation going into base.hash as well as the keys_equal
* function). A few of the #cairo_cache_t functions accept an entry which
* will be used exclusively as a "key", (indicated by a parameter name
* of key). In these cases, the value-related fields of the entry need
* not be initialized if so desired.
**/
typedef struct _cairo_cache_entry {
unsigned long hash;
unsigned long size;
} cairo_cache_entry_t;
 
typedef cairo_bool_t (*cairo_cache_predicate_func_t) (const void *entry);
 
struct _cairo_cache {
cairo_hash_table_t *hash_table;
 
cairo_cache_predicate_func_t predicate;
cairo_destroy_func_t entry_destroy;
 
unsigned long max_size;
unsigned long size;
 
int freeze_count;
};
 
typedef cairo_bool_t
(*cairo_cache_keys_equal_func_t) (const void *key_a, const void *key_b);
 
typedef void
(*cairo_cache_callback_func_t) (void *entry,
void *closure);
 
cairo_private cairo_status_t
_cairo_cache_init (cairo_cache_t *cache,
cairo_cache_keys_equal_func_t keys_equal,
cairo_cache_predicate_func_t predicate,
cairo_destroy_func_t entry_destroy,
unsigned long max_size);
 
cairo_private void
_cairo_cache_fini (cairo_cache_t *cache);
 
cairo_private void
_cairo_cache_freeze (cairo_cache_t *cache);
 
cairo_private void
_cairo_cache_thaw (cairo_cache_t *cache);
 
cairo_private void *
_cairo_cache_lookup (cairo_cache_t *cache,
cairo_cache_entry_t *key);
 
cairo_private cairo_status_t
_cairo_cache_insert (cairo_cache_t *cache,
cairo_cache_entry_t *entry);
 
cairo_private void
_cairo_cache_remove (cairo_cache_t *cache,
cairo_cache_entry_t *entry);
 
cairo_private void
_cairo_cache_foreach (cairo_cache_t *cache,
cairo_cache_callback_func_t cache_callback,
void *closure);
 
#endif
/programs/develop/libraries/cairo/src/cairo-cache.c
0,0 → 1,338
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2004 Red Hat, Inc.
* Copyright © 2005 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
* Keith Packard <keithp@keithp.com>
* Graydon Hoare <graydon@redhat.com>
* Carl Worth <cworth@cworth.org>
*/
 
#include "cairoint.h"
#include "cairo-error-private.h"
 
static void
_cairo_cache_shrink_to_accommodate (cairo_cache_t *cache,
unsigned long additional);
 
static cairo_bool_t
_cairo_cache_entry_is_non_zero (const void *entry)
{
return ((const cairo_cache_entry_t *) entry)->size;
}
 
 
/**
* _cairo_cache_init:
* @cache: the #cairo_cache_t to initialise
* @keys_equal: a function to return %TRUE if two keys are equal
* @entry_destroy: destroy notifier for cache entries
* @max_size: the maximum size for this cache
* Returns: the newly created #cairo_cache_t
*
* Creates a new cache using the keys_equal() function to determine
* the equality of entries.
*
* Data is provided to the cache in the form of user-derived version
* of #cairo_cache_entry_t. A cache entry must be able to hold hash
* code, a size, and the key/value pair being stored in the
* cache. Sometimes only the key will be necessary, (as in
* _cairo_cache_lookup()), and in these cases the value portion of the
* entry need not be initialized.
*
* The units for max_size can be chosen by the caller, but should be
* consistent with the units of the size field of cache entries. When
* adding an entry with _cairo_cache_insert() if the total size of
* entries in the cache would exceed max_size then entries will be
* removed at random until the new entry would fit or the cache is
* empty. Then the new entry is inserted.
*
* There are cases in which the automatic removal of entries is
* undesired. If the cache entries have reference counts, then it is a
* simple matter to use the reference counts to ensure that entries
* continue to live even after being ejected from the cache. However,
* in some cases the memory overhead of adding a reference count to
* the entry would be objectionable. In such cases, the
* _cairo_cache_freeze() and _cairo_cache_thaw() calls can be
* used to establish a window during which no automatic removal of
* entries will occur.
**/
cairo_status_t
_cairo_cache_init (cairo_cache_t *cache,
cairo_cache_keys_equal_func_t keys_equal,
cairo_cache_predicate_func_t predicate,
cairo_destroy_func_t entry_destroy,
unsigned long max_size)
{
cache->hash_table = _cairo_hash_table_create (keys_equal);
if (unlikely (cache->hash_table == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
if (predicate == NULL)
predicate = _cairo_cache_entry_is_non_zero;
cache->predicate = predicate;
cache->entry_destroy = entry_destroy;
 
cache->max_size = max_size;
cache->size = 0;
 
cache->freeze_count = 0;
 
return CAIRO_STATUS_SUCCESS;
}
 
static void
_cairo_cache_pluck (void *entry, void *closure)
{
_cairo_cache_remove (closure, entry);
}
 
/**
* _cairo_cache_fini:
* @cache: a cache to destroy
*
* Immediately destroys the given cache, freeing all resources
* associated with it. As part of this process, the entry_destroy()
* function, (as passed to _cairo_cache_init()), will be called for
* each entry in the cache.
**/
void
_cairo_cache_fini (cairo_cache_t *cache)
{
_cairo_hash_table_foreach (cache->hash_table,
_cairo_cache_pluck,
cache);
assert (cache->size == 0);
_cairo_hash_table_destroy (cache->hash_table);
}
 
/**
* _cairo_cache_freeze:
* @cache: a cache with some precious entries in it (or about to be
* added)
*
* Disable the automatic ejection of entries from the cache. For as
* long as the cache is "frozen", calls to _cairo_cache_insert() will
* add new entries to the cache regardless of how large the cache
* grows. See _cairo_cache_thaw().
*
* Note: Multiple calls to _cairo_cache_freeze() will stack, in that
* the cache will remain "frozen" until a corresponding number of
* calls are made to _cairo_cache_thaw().
**/
void
_cairo_cache_freeze (cairo_cache_t *cache)
{
assert (cache->freeze_count >= 0);
 
cache->freeze_count++;
}
 
/**
* _cairo_cache_thaw:
* @cache: a cache, just after the entries in it have become less
* precious
*
* Cancels the effects of _cairo_cache_freeze().
*
* When a number of calls to _cairo_cache_thaw() is made corresponding
* to the number of calls to _cairo_cache_freeze() the cache will no
* longer be "frozen". If the cache had grown larger than max_size
* while frozen, entries will immediately be ejected (by random) from
* the cache until the cache is smaller than max_size. Also, the
* automatic ejection of entries on _cairo_cache_insert() will resume.
**/
void
_cairo_cache_thaw (cairo_cache_t *cache)
{
assert (cache->freeze_count > 0);
 
if (--cache->freeze_count == 0)
_cairo_cache_shrink_to_accommodate (cache, 0);
}
 
/**
* _cairo_cache_lookup:
* @cache: a cache
* @key: the key of interest
* @entry_return: pointer for return value
*
* Performs a lookup in @cache looking for an entry which has a key
* that matches @key, (as determined by the keys_equal() function
* passed to _cairo_cache_init()).
*
* Return value: %TRUE if there is an entry in the cache that matches
* @key, (which will now be in *entry_return). %FALSE otherwise, (in
* which case *entry_return will be %NULL).
**/
void *
_cairo_cache_lookup (cairo_cache_t *cache,
cairo_cache_entry_t *key)
{
return _cairo_hash_table_lookup (cache->hash_table,
(cairo_hash_entry_t *) key);
}
 
/**
* _cairo_cache_remove_random:
* @cache: a cache
*
* Remove a random entry from the cache.
*
* Return value: %TRUE if an entry was successfully removed.
* %FALSE if there are no entries that can be removed.
**/
static cairo_bool_t
_cairo_cache_remove_random (cairo_cache_t *cache)
{
cairo_cache_entry_t *entry;
 
entry = _cairo_hash_table_random_entry (cache->hash_table,
cache->predicate);
if (unlikely (entry == NULL))
return FALSE;
 
_cairo_cache_remove (cache, entry);
 
return TRUE;
}
 
/**
* _cairo_cache_shrink_to_accommodate:
* @cache: a cache
* @additional: additional size requested in bytes
*
* If cache is not frozen, eject entries randomly until the size of
* the cache is at least @additional bytes less than
* cache->max_size. That is, make enough room to accommodate a new
* entry of size @additional.
**/
static void
_cairo_cache_shrink_to_accommodate (cairo_cache_t *cache,
unsigned long additional)
{
while (cache->size + additional > cache->max_size) {
if (! _cairo_cache_remove_random (cache))
return;
}
}
 
/**
* _cairo_cache_insert:
* @cache: a cache
* @entry: an entry to be inserted
*
* Insert @entry into the cache. If an entry exists in the cache with
* a matching key, then the old entry will be removed first, (and the
* entry_destroy() callback will be called on it).
*
* Return value: %CAIRO_STATUS_SUCCESS if successful or
* %CAIRO_STATUS_NO_MEMORY if insufficient memory is available.
**/
cairo_status_t
_cairo_cache_insert (cairo_cache_t *cache,
cairo_cache_entry_t *entry)
{
cairo_status_t status;
 
if (entry->size && ! cache->freeze_count)
_cairo_cache_shrink_to_accommodate (cache, entry->size);
 
status = _cairo_hash_table_insert (cache->hash_table,
(cairo_hash_entry_t *) entry);
if (unlikely (status))
return status;
 
cache->size += entry->size;
 
return CAIRO_STATUS_SUCCESS;
}
 
/**
* _cairo_cache_remove:
* @cache: a cache
* @entry: an entry that exists in the cache
*
* Remove an existing entry from the cache.
**/
void
_cairo_cache_remove (cairo_cache_t *cache,
cairo_cache_entry_t *entry)
{
cache->size -= entry->size;
 
_cairo_hash_table_remove (cache->hash_table,
(cairo_hash_entry_t *) entry);
 
if (cache->entry_destroy)
cache->entry_destroy (entry);
}
 
/**
* _cairo_cache_foreach:
* @cache: a cache
* @cache_callback: function to be called for each entry
* @closure: additional argument to be passed to @cache_callback
*
* Call @cache_callback for each entry in the cache, in a
* non-specified order.
**/
void
_cairo_cache_foreach (cairo_cache_t *cache,
cairo_cache_callback_func_t cache_callback,
void *closure)
{
_cairo_hash_table_foreach (cache->hash_table,
cache_callback,
closure);
}
 
unsigned long
_cairo_hash_string (const char *c)
{
/* This is the djb2 hash. */
unsigned long hash = _CAIRO_HASH_INIT_VALUE;
while (c && *c)
hash = ((hash << 5) + hash) + *c++;
return hash;
}
 
unsigned long
_cairo_hash_bytes (unsigned long hash,
const void *ptr,
unsigned int length)
{
const uint8_t *bytes = ptr;
/* This is the djb2 hash. */
while (length--)
hash = ((hash << 5) + hash) + *bytes++;
return hash;
}
/programs/develop/libraries/cairo/src/cairo-clip-private.h
0,0 → 1,151
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2005 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
* Kristian Høgsberg <krh@redhat.com>
*/
 
#ifndef CAIRO_CLIP_PRIVATE_H
#define CAIRO_CLIP_PRIVATE_H
 
#include "cairo-types-private.h"
#include "cairo-compiler-private.h"
#include "cairo-path-fixed-private.h"
#include "cairo-reference-count-private.h"
 
extern const cairo_private cairo_rectangle_list_t _cairo_rectangles_nil;
 
enum {
CAIRO_CLIP_PATH_HAS_REGION = 0x1,
CAIRO_CLIP_PATH_REGION_IS_UNSUPPORTED = 0x2,
CAIRO_CLIP_PATH_IS_BOX = 0x4
};
 
struct _cairo_clip_path {
cairo_reference_count_t ref_count;
cairo_path_fixed_t path;
cairo_fill_rule_t fill_rule;
double tolerance;
cairo_antialias_t antialias;
cairo_clip_path_t *prev;
 
cairo_rectangle_int_t extents;
 
/* partial caches */
unsigned int flags;
cairo_region_t *region;
cairo_surface_t *surface;
};
 
struct _cairo_clip {
/* can be used as a cairo_hash_entry_t for live clips */
cairo_clip_path_t *path;
 
cairo_bool_t all_clipped;
 
};
 
cairo_private void
_cairo_clip_init (cairo_clip_t *clip);
 
cairo_private_no_warn cairo_clip_t *
_cairo_clip_init_copy (cairo_clip_t *clip, cairo_clip_t *other);
 
cairo_private cairo_status_t
_cairo_clip_init_copy_transformed (cairo_clip_t *clip,
cairo_clip_t *other,
const cairo_matrix_t *matrix);
 
cairo_private void
_cairo_clip_reset (cairo_clip_t *clip);
 
cairo_private cairo_bool_t
_cairo_clip_equal (const cairo_clip_t *clip_a,
const cairo_clip_t *clip_b);
 
#define _cairo_clip_fini(clip) _cairo_clip_reset (clip)
 
cairo_private cairo_status_t
_cairo_clip_rectangle (cairo_clip_t *clip,
const cairo_rectangle_int_t *rectangle);
 
cairo_private cairo_status_t
_cairo_clip_clip (cairo_clip_t *clip,
const cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias);
 
cairo_private cairo_status_t
_cairo_clip_apply_clip (cairo_clip_t *clip,
const cairo_clip_t *other);
 
cairo_private const cairo_rectangle_int_t *
_cairo_clip_get_extents (const cairo_clip_t *clip);
 
cairo_private cairo_surface_t *
_cairo_clip_get_surface (cairo_clip_t *clip, cairo_surface_t *dst, int *tx, int *ty);
 
cairo_private cairo_status_t
_cairo_clip_combine_with_surface (cairo_clip_t *clip,
cairo_surface_t *dst,
int dst_x, int dst_y);
 
cairo_private cairo_int_status_t
_cairo_clip_get_region (cairo_clip_t *clip,
cairo_region_t **region);
 
cairo_private cairo_int_status_t
_cairo_clip_get_boxes (cairo_clip_t *clip,
cairo_box_t **boxes,
int *count);
 
cairo_private cairo_status_t
_cairo_clip_to_boxes (cairo_clip_t **clip,
cairo_composite_rectangles_t *extents,
cairo_box_t **boxes,
int *num_boxes);
 
cairo_private cairo_bool_t
_cairo_clip_contains_rectangle (cairo_clip_t *clip,
const cairo_rectangle_int_t *rect);
 
cairo_private cairo_bool_t
_cairo_clip_contains_extents (cairo_clip_t *clip,
const cairo_composite_rectangles_t *extents);
 
cairo_private void
_cairo_clip_drop_cache (cairo_clip_t *clip);
 
cairo_private cairo_rectangle_list_t*
_cairo_clip_copy_rectangle_list (cairo_clip_t *clip, cairo_gstate_t *gstate);
 
#endif /* CAIRO_CLIP_PRIVATE_H */
/programs/develop/libraries/cairo/src/cairo-clip.c
0,0 → 1,1584
/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2002 University of Southern California
* Copyright © 2005 Red Hat, Inc.
* Copyright © 2009 Chris Wilson
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
* Kristian Høgsberg <krh@redhat.com>
* Chris Wilson <chris@chris-wilson.co.uk>
*/
 
#include "cairoint.h"
#include "cairo-clip-private.h"
#include "cairo-error-private.h"
#include "cairo-freed-pool-private.h"
#include "cairo-gstate-private.h"
#include "cairo-path-fixed-private.h"
#include "cairo-composite-rectangles-private.h"
#include "cairo-region-private.h"
 
#if HAS_FREED_POOL
static freed_pool_t clip_path_pool;
#endif
 
static cairo_clip_path_t *
_cairo_clip_path_create (cairo_clip_t *clip)
{
cairo_clip_path_t *clip_path;
 
clip_path = _freed_pool_get (&clip_path_pool);
if (unlikely (clip_path == NULL)) {
clip_path = malloc (sizeof (cairo_clip_path_t));
if (unlikely (clip_path == NULL))
return NULL;
}
 
CAIRO_REFERENCE_COUNT_INIT (&clip_path->ref_count, 1);
 
clip_path->flags = 0;
clip_path->region = NULL;
clip_path->surface = NULL;
 
clip_path->prev = clip->path;
clip->path = clip_path;
 
return clip_path;
}
 
static cairo_clip_path_t *
_cairo_clip_path_reference (cairo_clip_path_t *clip_path)
{
assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&clip_path->ref_count));
 
_cairo_reference_count_inc (&clip_path->ref_count);
 
return clip_path;
}
 
static void
_cairo_clip_path_destroy (cairo_clip_path_t *clip_path)
{
assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&clip_path->ref_count));
 
if (! _cairo_reference_count_dec_and_test (&clip_path->ref_count))
return;
 
_cairo_path_fixed_fini (&clip_path->path);
if (clip_path->region != NULL)
cairo_region_destroy (clip_path->region);
if (clip_path->surface != NULL)
cairo_surface_destroy (clip_path->surface);
 
if (clip_path->prev != NULL)
_cairo_clip_path_destroy (clip_path->prev);
 
_freed_pool_put (&clip_path_pool, clip_path);
}
 
void
_cairo_clip_init (cairo_clip_t *clip)
{
clip->all_clipped = FALSE;
clip->path = NULL;
}
 
static void
_cairo_clip_set_all_clipped (cairo_clip_t *clip)
{
clip->all_clipped = TRUE;
if (clip->path != NULL) {
_cairo_clip_path_destroy (clip->path);
clip->path = NULL;
}
}
 
static cairo_status_t
_cairo_clip_intersect_rectangle (cairo_clip_t *clip,
const cairo_rectangle_int_t *rect)
{
cairo_clip_path_t *clip_path;
cairo_status_t status;
 
if (clip->path != NULL) {
if (rect->x <= clip->path->extents.x &&
rect->y <= clip->path->extents.y &&
rect->x + rect->width >= clip->path->extents.x + clip->path->extents.width &&
rect->y + rect->height >= clip->path->extents.y + clip->path->extents.height)
{
return CAIRO_STATUS_SUCCESS;
}
}
 
clip_path = _cairo_clip_path_create (clip);
if (unlikely (clip_path == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
_cairo_path_fixed_init (&clip_path->path);
 
status = _cairo_path_fixed_move_to (&clip_path->path,
_cairo_fixed_from_int (rect->x),
_cairo_fixed_from_int (rect->y));
assert (status == CAIRO_STATUS_SUCCESS);
status = _cairo_path_fixed_rel_line_to (&clip_path->path,
_cairo_fixed_from_int (rect->width),
_cairo_fixed_from_int (0));
assert (status == CAIRO_STATUS_SUCCESS);
status = _cairo_path_fixed_rel_line_to (&clip_path->path,
_cairo_fixed_from_int (0),
_cairo_fixed_from_int (rect->height));
assert (status == CAIRO_STATUS_SUCCESS);
status = _cairo_path_fixed_rel_line_to (&clip_path->path,
_cairo_fixed_from_int (-rect->width),
_cairo_fixed_from_int (0));
assert (status == CAIRO_STATUS_SUCCESS);
status = _cairo_path_fixed_close_path (&clip_path->path);
assert (status == CAIRO_STATUS_SUCCESS);
 
clip_path->fill_rule = CAIRO_FILL_RULE_WINDING;
clip_path->tolerance = 1;
clip_path->antialias = CAIRO_ANTIALIAS_DEFAULT;
clip_path->flags |= CAIRO_CLIP_PATH_IS_BOX;
 
clip_path->extents = *rect;
if (clip_path->prev != NULL) {
if (! _cairo_rectangle_intersect (&clip_path->extents,
&clip_path->prev->extents))
{
_cairo_clip_set_all_clipped (clip);
}
}
 
/* could preallocate the region if it proves worthwhile */
 
return CAIRO_STATUS_SUCCESS;
}
 
cairo_clip_t *
_cairo_clip_init_copy (cairo_clip_t *clip, cairo_clip_t *other)
{
if (other != NULL) {
clip->all_clipped = other->all_clipped;
if (other->path == NULL) {
clip->path = NULL;
if (! clip->all_clipped)
clip = NULL;
} else {
clip->path = _cairo_clip_path_reference (other->path);
}
} else {
_cairo_clip_init (clip);
clip = NULL;
}
 
return clip;
}
 
void
_cairo_clip_reset (cairo_clip_t *clip)
{
clip->all_clipped = FALSE;
if (clip->path != NULL) {
_cairo_clip_path_destroy (clip->path);
clip->path = NULL;
}
}
 
static cairo_status_t
_cairo_clip_intersect_path (cairo_clip_t *clip,
const cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias)
{
cairo_clip_path_t *clip_path;
cairo_status_t status;
cairo_rectangle_int_t extents;
cairo_box_t box;
cairo_bool_t is_box = FALSE;
 
if (clip->path != NULL) {
if (clip->path->fill_rule == fill_rule &&
(path->is_rectilinear || tolerance == clip->path->tolerance) &&
antialias == clip->path->antialias &&
_cairo_path_fixed_equal (&clip->path->path, path))
{
return CAIRO_STATUS_SUCCESS;
}
}
 
_cairo_path_fixed_approximate_clip_extents (path, &extents);
if (extents.width == 0 || extents.height == 0) {
_cairo_clip_set_all_clipped (clip);
return CAIRO_STATUS_SUCCESS;
}
 
is_box = _cairo_path_fixed_is_box (path, &box);
if (clip->path != NULL) {
if (! _cairo_rectangle_intersect (&extents, &clip->path->extents)) {
_cairo_clip_set_all_clipped (clip);
return CAIRO_STATUS_SUCCESS;
}
 
/* does this clip wholly subsume the others? */
if (is_box &&
box.p1.x <= _cairo_fixed_from_int (clip->path->extents.x) &&
box.p2.x >= _cairo_fixed_from_int (clip->path->extents.x + clip->path->extents.width) &&
box.p1.y <= _cairo_fixed_from_int (clip->path->extents.y) &&
box.p2.y >= _cairo_fixed_from_int (clip->path->extents.y + clip->path->extents.height))
{
return CAIRO_STATUS_SUCCESS;
}
}
 
clip_path = _cairo_clip_path_create (clip);
if (unlikely (clip_path == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
status = _cairo_path_fixed_init_copy (&clip_path->path, path);
if (unlikely (status)) {
clip->path = clip->path->prev;
_cairo_clip_path_destroy (clip_path);
return status;
}
 
clip_path->extents = extents;
clip_path->fill_rule = fill_rule;
clip_path->tolerance = tolerance;
clip_path->antialias = antialias;
if (is_box)
clip_path->flags |= CAIRO_CLIP_PATH_IS_BOX;
 
return CAIRO_STATUS_SUCCESS;
}
 
cairo_bool_t
_cairo_clip_equal (const cairo_clip_t *clip_a,
const cairo_clip_t *clip_b)
{
const cairo_clip_path_t *clip_path_a, *clip_path_b;
 
clip_path_a = clip_a->path;
clip_path_b = clip_b->path;
 
while (clip_path_a && clip_path_b) {
if (clip_path_a == clip_path_b)
return TRUE;
 
if (clip_path_a->fill_rule != clip_path_b->fill_rule)
return FALSE;
 
if (clip_path_a->tolerance != clip_path_b->tolerance)
return FALSE;
 
if (clip_path_a->antialias != clip_path_b->antialias)
return FALSE;
 
if (! _cairo_path_fixed_equal (&clip_path_a->path, &clip_path_b->path))
return FALSE;
 
clip_path_a = clip_path_a->prev;
clip_path_b = clip_path_b->prev;
}
 
return clip_path_a == clip_path_b; /* ie both NULL */
}
 
cairo_status_t
_cairo_clip_clip (cairo_clip_t *clip,
const cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias)
{
if (clip->all_clipped)
return CAIRO_STATUS_SUCCESS;
 
/* catch the empty clip path */
if (_cairo_path_fixed_fill_is_empty (path)) {
_cairo_clip_set_all_clipped (clip);
return CAIRO_STATUS_SUCCESS;
}
 
return _cairo_clip_intersect_path (clip,
path, fill_rule, tolerance,
antialias);
}
 
cairo_status_t
_cairo_clip_rectangle (cairo_clip_t *clip,
const cairo_rectangle_int_t *rectangle)
{
if (clip->all_clipped)
return CAIRO_STATUS_SUCCESS;
 
if (rectangle->width == 0 || rectangle->height == 0) {
_cairo_clip_set_all_clipped (clip);
return CAIRO_STATUS_SUCCESS;
}
 
/* if a smaller clip has already been set, ignore the new path */
if (clip->path != NULL) {
if (rectangle->x <= clip->path->extents.x &&
rectangle->y <= clip->path->extents.y &&
rectangle->x + rectangle->width >= clip->path->extents.x + clip->path->extents.width &&
rectangle->y + rectangle->height >= clip->path->extents.y + clip->path->extents.height)
{
return CAIRO_STATUS_SUCCESS;
}
}
 
return _cairo_clip_intersect_rectangle (clip, rectangle);
}
 
static cairo_status_t
_cairo_clip_path_reapply_clip_path_transform (cairo_clip_t *clip,
cairo_clip_path_t *other_path,
const cairo_matrix_t *matrix)
{
cairo_status_t status;
cairo_clip_path_t *clip_path;
cairo_bool_t is_empty;
 
if (other_path->prev != NULL) {
status = _cairo_clip_path_reapply_clip_path_transform (clip,
other_path->prev,
matrix);
if (unlikely (status))
return status;
}
 
clip_path = _cairo_clip_path_create (clip);
if (unlikely (clip_path == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
status = _cairo_path_fixed_init_copy (&clip_path->path,
&other_path->path);
if (unlikely (status)) {
clip->path = clip->path->prev;
_cairo_clip_path_destroy (clip_path);
return status;
}
 
_cairo_path_fixed_transform (&clip_path->path, matrix);
_cairo_path_fixed_approximate_clip_extents (&clip_path->path,
&clip_path->extents);
if (clip_path->prev != NULL) {
is_empty = _cairo_rectangle_intersect (&clip_path->extents,
&clip_path->prev->extents);
}
 
clip_path->fill_rule = other_path->fill_rule;
clip_path->tolerance = other_path->tolerance;
clip_path->antialias = other_path->antialias;
 
return CAIRO_STATUS_SUCCESS;
}
 
static cairo_status_t
_cairo_clip_path_reapply_clip_path_translate (cairo_clip_t *clip,
cairo_clip_path_t *other_path,
int tx, int ty)
{
cairo_status_t status;
cairo_clip_path_t *clip_path;
 
if (other_path->prev != NULL) {
status = _cairo_clip_path_reapply_clip_path_translate (clip,
other_path->prev,
tx, ty);
if (unlikely (status))
return status;
}
 
clip_path = _cairo_clip_path_create (clip);
if (unlikely (clip_path == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
status = _cairo_path_fixed_init_copy (&clip_path->path,
&other_path->path);
if (unlikely (status)) {
clip->path = clip->path->prev;
_cairo_clip_path_destroy (clip_path);
return status;
}
 
_cairo_path_fixed_translate (&clip_path->path,
_cairo_fixed_from_int (tx),
_cairo_fixed_from_int (ty));
 
clip_path->fill_rule = other_path->fill_rule;
clip_path->tolerance = other_path->tolerance;
clip_path->antialias = other_path->antialias;
 
clip_path->flags = other_path->flags;
if (other_path->region != NULL) {
clip_path->region = cairo_region_copy (other_path->region);
status = clip_path->region->status;
if (unlikely (status)) {
clip->path = clip->path->prev;
_cairo_clip_path_destroy (clip_path);
return status;
}
 
cairo_region_translate (clip_path->region, tx, ty);
}
clip_path->surface = cairo_surface_reference (other_path->surface);
 
clip_path->extents = other_path->extents;
clip_path->extents.x += tx;
clip_path->extents.y += ty;
 
return CAIRO_STATUS_SUCCESS;
}
 
cairo_status_t
_cairo_clip_init_copy_transformed (cairo_clip_t *clip,
cairo_clip_t *other,
const cairo_matrix_t *matrix)
{
cairo_status_t status = CAIRO_STATUS_SUCCESS;
int tx, ty;
 
if (other == NULL) {
_cairo_clip_init (clip);
return CAIRO_STATUS_SUCCESS;
}
 
if (other->all_clipped) {
_cairo_clip_init (clip);
clip->all_clipped = TRUE;
return CAIRO_STATUS_SUCCESS;
}
 
if (_cairo_matrix_is_identity (matrix)) {
_cairo_clip_init_copy (clip, other);
return CAIRO_STATUS_SUCCESS;
}
 
if (other->path != NULL) {
_cairo_clip_init (clip);
 
/* if we only need to translate, so we can reuse the caches... */
/* XXX we still loose the benefit of constructs when the copy is
* deleted though. Indirect clip_paths?
*/
if (_cairo_matrix_is_integer_translation (matrix, &tx, &ty)) {
status = _cairo_clip_path_reapply_clip_path_translate (clip,
other->path,
tx, ty);
} else {
status = _cairo_clip_path_reapply_clip_path_transform (clip,
other->path,
matrix);
if (clip->path->extents.width == 0 &&
clip->path->extents.height == 0)
{
_cairo_clip_set_all_clipped (clip);
}
}
}
 
return status;
}
 
static cairo_status_t
_cairo_clip_apply_clip_path (cairo_clip_t *clip,
const cairo_clip_path_t *path)
{
cairo_status_t status;
 
if (path->prev != NULL)
status = _cairo_clip_apply_clip_path (clip, path->prev);
 
return _cairo_clip_intersect_path (clip,
&path->path,
path->fill_rule,
path->tolerance,
path->antialias);
}
 
cairo_status_t
_cairo_clip_apply_clip (cairo_clip_t *clip,
const cairo_clip_t *other)
{
cairo_status_t status;
 
if (clip->all_clipped)
return CAIRO_STATUS_SUCCESS;
 
if (other->all_clipped) {
_cairo_clip_set_all_clipped (clip);
return CAIRO_STATUS_SUCCESS;
}
 
status = CAIRO_STATUS_SUCCESS;
if (other->path != NULL)
status = _cairo_clip_apply_clip_path (clip, other->path);
 
return status;
}
 
static inline cairo_bool_t
_clip_paths_are_rectilinear (cairo_clip_path_t *clip_path)
{
while (clip_path != NULL) {
if (! clip_path->path.is_rectilinear)
return FALSE;
 
clip_path = clip_path->prev;
}
 
return TRUE;
}
 
static cairo_int_status_t
_cairo_clip_path_to_region_geometric (cairo_clip_path_t *clip_path)
{
cairo_traps_t traps;
cairo_box_t stack_boxes[CAIRO_STACK_ARRAY_LENGTH (cairo_box_t)];
cairo_box_t *boxes = stack_boxes;
cairo_status_t status;
int n;
 
/* If we have nothing to intersect with this path, then it cannot
* magically be reduced into a region.
*/
if (clip_path->prev == NULL)
goto UNSUPPORTED;
 
/* Start simple... Intersect some boxes with an arbitrary path. */
if (! clip_path->path.is_rectilinear)
goto UNSUPPORTED;
if (clip_path->prev->prev != NULL)
goto UNSUPPORTED;
 
_cairo_traps_init (&traps);
_cairo_box_from_rectangle (&boxes[0], &clip_path->extents);
_cairo_traps_limit (&traps, boxes, 1);
 
status = _cairo_path_fixed_fill_rectilinear_to_traps (&clip_path->path,
clip_path->fill_rule,
&traps);
if (unlikely (_cairo_status_is_error (status)))
return status;
if (status == CAIRO_INT_STATUS_UNSUPPORTED)
goto UNSUPPORTED;
 
if (traps.num_traps > ARRAY_LENGTH (stack_boxes)) {
boxes = _cairo_malloc_ab (traps.num_traps, sizeof (cairo_box_t));
if (unlikely (boxes == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
 
for (n = 0; n < traps.num_traps; n++) {
boxes[n].p1.x = traps.traps[n].left.p1.x;
boxes[n].p1.y = traps.traps[n].top;
boxes[n].p2.x = traps.traps[n].right.p1.x;
boxes[n].p2.y = traps.traps[n].bottom;
}
 
_cairo_traps_clear (&traps);
_cairo_traps_limit (&traps, boxes, n);
status = _cairo_path_fixed_fill_to_traps (&clip_path->prev->path,
clip_path->prev->fill_rule,
clip_path->prev->tolerance,
&traps);
if (boxes != stack_boxes)
free (boxes);
 
if (unlikely (status))
return status;
 
status = _cairo_traps_extract_region (&traps, &clip_path->region);
_cairo_traps_fini (&traps);
 
if (status == CAIRO_INT_STATUS_UNSUPPORTED)
goto UNSUPPORTED;
if (unlikely (status))
return status;
 
clip_path->flags |= CAIRO_CLIP_PATH_HAS_REGION;
return CAIRO_STATUS_SUCCESS;
 
UNSUPPORTED:
clip_path->flags |= CAIRO_CLIP_PATH_REGION_IS_UNSUPPORTED;
return CAIRO_INT_STATUS_UNSUPPORTED;
}
 
static cairo_int_status_t
_cairo_clip_path_to_region (cairo_clip_path_t *clip_path)
{
cairo_int_status_t status;
cairo_region_t *prev = NULL;
 
if (clip_path->flags &
(CAIRO_CLIP_PATH_HAS_REGION |
CAIRO_CLIP_PATH_REGION_IS_UNSUPPORTED))
{
return clip_path->flags & CAIRO_CLIP_PATH_REGION_IS_UNSUPPORTED ?
CAIRO_INT_STATUS_UNSUPPORTED :
CAIRO_STATUS_SUCCESS;
}
 
if (! clip_path->path.maybe_fill_region)
return _cairo_clip_path_to_region_geometric (clip_path);
 
/* first retrieve the region for our antecedents */
if (clip_path->prev != NULL) {
status = _cairo_clip_path_to_region (clip_path->prev);
if (status) {
if (status == CAIRO_INT_STATUS_UNSUPPORTED)
return _cairo_clip_path_to_region_geometric (clip_path);
 
return status;
}
 
prev = clip_path->prev->region;
}
 
/* now extract the region for ourselves */
clip_path->region =
_cairo_path_fixed_fill_rectilinear_to_region (&clip_path->path,
clip_path->fill_rule,
&clip_path->extents);
assert (clip_path->region != NULL);
 
status = clip_path->region->status;
if (unlikely (status))
return status;
 
if (prev != NULL) {
status = cairo_region_intersect (clip_path->region, prev);
if (unlikely (status))
return status;
}
 
clip_path->flags |= CAIRO_CLIP_PATH_HAS_REGION;
return CAIRO_STATUS_SUCCESS;
}
 
static inline int
pot (int v)
{
v--;
v |= v >> 1;
v |= v >> 2;
v |= v >> 4;
v |= v >> 8;
v |= v >> 16;
v++;
return v;
}
 
/* XXX there is likely a faster method! ;-) */
static cairo_status_t
_region_clip_to_boxes (const cairo_region_t *region,
cairo_box_t **boxes,
int *num_boxes,
int *size_boxes)
{
cairo_traps_t traps;
cairo_status_t status;
int n, num_rects;
 
_cairo_traps_init (&traps);
_cairo_traps_limit (&traps, *boxes, *num_boxes);
traps.is_rectilinear = TRUE;
traps.is_rectangular = TRUE;
 
num_rects = cairo_region_num_rectangles (region);
for (n = 0; n < num_rects; n++) {
cairo_rectangle_int_t rect;
cairo_point_t p1, p2;
 
cairo_region_get_rectangle (region, n, &rect);
 
p1.x = _cairo_fixed_from_int (rect.x);
p1.y = _cairo_fixed_from_int (rect.y);
p2.x = _cairo_fixed_from_int (rect.x + rect.width);
p2.y = _cairo_fixed_from_int (rect.y + rect.height);
 
status = _cairo_traps_tessellate_rectangle (&traps, &p1, &p2);
if (unlikely (status))
goto CLEANUP;
}
 
status = _cairo_bentley_ottmann_tessellate_rectangular_traps (&traps, CAIRO_FILL_RULE_WINDING);
if (unlikely (status))
goto CLEANUP;
 
n = *size_boxes;
if (n < 0)
n = -n;
 
if (traps.num_traps > n) {
cairo_box_t *new_boxes;
 
new_boxes = _cairo_malloc_ab (traps.num_traps, sizeof (cairo_box_t));
if (unlikely (new_boxes == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto CLEANUP;
}
 
if (*size_boxes > 0)
free (*boxes);
 
*boxes = new_boxes;
*size_boxes = traps.num_traps;
}
 
for (n = 0; n < traps.num_traps; n++) {
(*boxes)[n].p1.x = traps.traps[n].left.p1.x;
(*boxes)[n].p1.y = traps.traps[n].top;
(*boxes)[n].p2.x = traps.traps[n].right.p1.x;
(*boxes)[n].p2.y = traps.traps[n].bottom;
}
*num_boxes = n;
 
CLEANUP:
_cairo_traps_fini (&traps);
 
return status;
}
 
static cairo_status_t
_rectilinear_clip_to_boxes (const cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
cairo_box_t **boxes,
int *num_boxes,
int *size_boxes)
{
cairo_polygon_t polygon;
cairo_traps_t traps;
cairo_status_t status;
 
_cairo_traps_init (&traps);
_cairo_traps_limit (&traps, *boxes, *num_boxes);
 
_cairo_polygon_init (&polygon);
_cairo_polygon_limit (&polygon, *boxes, *num_boxes);
 
status = _cairo_path_fixed_fill_rectilinear_to_traps (path,
fill_rule,
&traps);
if (unlikely (_cairo_status_is_error (status)))
goto CLEANUP;
if (status == CAIRO_STATUS_SUCCESS)
goto BOXES;
 
/* tolerance will be ignored as the path is rectilinear */
status = _cairo_path_fixed_fill_to_polygon (path, 0., &polygon);
if (unlikely (status))
goto CLEANUP;
 
if (polygon.num_edges == 0) {
*num_boxes = 0;
} else {
status = _cairo_bentley_ottmann_tessellate_rectilinear_polygon (&traps,
&polygon,
fill_rule);
if (likely (status == CAIRO_STATUS_SUCCESS)) {
int i;
 
BOXES:
i = *size_boxes;
if (i < 0)
i = -i;
 
if (traps.num_traps > i) {
cairo_box_t *new_boxes;
int new_size;
 
new_size = pot (traps.num_traps);
new_boxes = _cairo_malloc_ab (new_size, sizeof (cairo_box_t));
if (unlikely (new_boxes == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto CLEANUP;
}
 
if (*size_boxes > 0)
free (*boxes);
 
*boxes = new_boxes;
*size_boxes = new_size;
}
 
for (i = 0; i < traps.num_traps; i++) {
(*boxes)[i].p1.x = traps.traps[i].left.p1.x;
(*boxes)[i].p1.y = traps.traps[i].top;
(*boxes)[i].p2.x = traps.traps[i].right.p1.x;
(*boxes)[i].p2.y = traps.traps[i].bottom;
}
*num_boxes = i;
}
}
 
CLEANUP:
_cairo_polygon_fini (&polygon);
_cairo_traps_fini (&traps);
 
return status;
}
 
static cairo_int_status_t
_cairo_clip_path_to_boxes (cairo_clip_path_t *clip_path,
cairo_box_t **boxes,
int *count)
{
int size = -*count;
int num_boxes = 0;
cairo_status_t status;
 
if (clip_path->region != NULL) {
int num_rects, n;
 
num_rects = cairo_region_num_rectangles (clip_path->region);
if (num_rects > -size) {
cairo_box_t *new_boxes;
 
new_boxes = _cairo_malloc_ab (num_rects, sizeof (cairo_box_t));
if (unlikely (new_boxes == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
*boxes = new_boxes;
}
 
for (n = 0; n < num_rects; n++) {
cairo_rectangle_int_t rect;
 
cairo_region_get_rectangle (clip_path->region, n, &rect);
(*boxes)[n].p1.x = _cairo_fixed_from_int (rect.x);
(*boxes)[n].p1.y = _cairo_fixed_from_int (rect.y);
(*boxes)[n].p2.x = _cairo_fixed_from_int (rect.x + rect.width);
(*boxes)[n].p2.y = _cairo_fixed_from_int (rect.y + rect.height);
}
 
*count = num_rects;
return CAIRO_STATUS_SUCCESS;
}
 
/* keep it simple at first */
if (! _clip_paths_are_rectilinear (clip_path))
return CAIRO_INT_STATUS_UNSUPPORTED;
 
assert (-size >= 1);
if (_cairo_path_fixed_is_box (&clip_path->path, *boxes)) {
num_boxes = 1;
} else {
status = _rectilinear_clip_to_boxes (&clip_path->path,
clip_path->fill_rule,
boxes, &num_boxes, &size);
if (unlikely (status))
return status;
}
 
while (num_boxes > 0 && (clip_path = clip_path->prev) != NULL) {
cairo_box_t box;
 
if (clip_path->region != NULL) {
status = _region_clip_to_boxes (clip_path->region,
boxes, &num_boxes, &size);
if (unlikely (status))
return status;
 
break;
} else if (_cairo_path_fixed_is_box (&clip_path->path, &box)) {
int i, j;
 
for (i = j = 0; i < num_boxes; i++) {
if (j != i)
(*boxes)[j] = (*boxes)[i];
 
if (box.p1.x > (*boxes)[j].p1.x)
(*boxes)[j].p1.x = box.p1.x;
if (box.p2.x < (*boxes)[j].p2.x)
(*boxes)[j].p2.x = box.p2.x;
 
if (box.p1.y > (*boxes)[j].p1.y)
(*boxes)[j].p1.y = box.p1.y;
if (box.p2.y < (*boxes)[j].p2.y)
(*boxes)[j].p2.y = box.p2.y;
 
j += (*boxes)[j].p2.x > (*boxes)[j].p1.x &&
(*boxes)[j].p2.y > (*boxes)[j].p1.y;
}
 
num_boxes = j;
} else {
status = _rectilinear_clip_to_boxes (&clip_path->path,
clip_path->fill_rule,
boxes, &num_boxes, &size);
if (unlikely (status))
return status;
}
}
 
*count = num_boxes;
return CAIRO_STATUS_SUCCESS;
}
 
static cairo_surface_t *
_cairo_clip_path_get_surface (cairo_clip_path_t *clip_path,
cairo_surface_t *target,
int *tx, int *ty)
{
const cairo_rectangle_int_t *clip_extents = &clip_path->extents;
cairo_bool_t need_translate;
cairo_surface_t *surface;
cairo_clip_path_t *prev;
cairo_status_t status;
 
while (clip_path->prev != NULL &&
clip_path->flags & CAIRO_CLIP_PATH_IS_BOX &&
clip_path->path.maybe_fill_region)
{
clip_path = clip_path->prev;
}
 
clip_extents = &clip_path->extents;
if (clip_path->surface != NULL &&
clip_path->surface->backend == target->backend)
{
*tx = clip_extents->x;
*ty = clip_extents->y;
return clip_path->surface;
}
 
surface = _cairo_surface_create_similar_scratch (target,
CAIRO_CONTENT_ALPHA,
clip_extents->width,
clip_extents->height);
if (surface == NULL) {
surface = cairo_image_surface_create (CAIRO_FORMAT_A8,
clip_extents->width,
clip_extents->height);
}
if (unlikely (surface->status))
return surface;
 
need_translate = clip_extents->x | clip_extents->y;
if (clip_path->flags & CAIRO_CLIP_PATH_IS_BOX &&
clip_path->path.maybe_fill_region)
{
status = _cairo_surface_paint (surface,
CAIRO_OPERATOR_SOURCE,
&_cairo_pattern_white.base,
NULL);
if (unlikely (status))
goto BAIL;
}
else
{
status = _cairo_surface_paint (surface,
CAIRO_OPERATOR_CLEAR,
&_cairo_pattern_clear.base,
NULL);
if (unlikely (status))
goto BAIL;
 
if (need_translate) {
_cairo_path_fixed_translate (&clip_path->path,
_cairo_fixed_from_int (-clip_extents->x),
_cairo_fixed_from_int (-clip_extents->y));
}
status = _cairo_surface_fill (surface,
CAIRO_OPERATOR_ADD,
&_cairo_pattern_white.base,
&clip_path->path,
clip_path->fill_rule,
clip_path->tolerance,
clip_path->antialias,
NULL);
if (need_translate) {
_cairo_path_fixed_translate (&clip_path->path,
_cairo_fixed_from_int (clip_extents->x),
_cairo_fixed_from_int (clip_extents->y));
}
 
if (unlikely (status))
goto BAIL;
}
 
prev = clip_path->prev;
while (prev != NULL) {
if (prev->flags & CAIRO_CLIP_PATH_IS_BOX &&
prev->path.maybe_fill_region)
{
/* a simple box only affects the extents */
}
else if (prev->path.is_rectilinear ||
prev->surface == NULL ||
prev->surface->backend != target->backend)
{
if (need_translate) {
_cairo_path_fixed_translate (&prev->path,
_cairo_fixed_from_int (-clip_extents->x),
_cairo_fixed_from_int (-clip_extents->y));
}
status = _cairo_surface_fill (surface,
CAIRO_OPERATOR_IN,
&_cairo_pattern_white.base,
&prev->path,
prev->fill_rule,
prev->tolerance,
prev->antialias,
NULL);
if (need_translate) {
_cairo_path_fixed_translate (&prev->path,
_cairo_fixed_from_int (clip_extents->x),
_cairo_fixed_from_int (clip_extents->y));
}
 
if (unlikely (status))
goto BAIL;
}
else
{
cairo_surface_pattern_t pattern;
cairo_surface_t *prev_surface;
int prev_tx, prev_ty;
 
prev_surface = _cairo_clip_path_get_surface (prev, target, &prev_tx, &prev_ty);
status = prev_surface->status;
if (unlikely (status))
goto BAIL;
 
_cairo_pattern_init_for_surface (&pattern, prev_surface);
pattern.base.filter = CAIRO_FILTER_NEAREST;
cairo_matrix_init_translate (&pattern.base.matrix,
clip_extents->x - prev_tx,
clip_extents->y - prev_ty);
status = _cairo_surface_paint (surface,
CAIRO_OPERATOR_IN,
&pattern.base,
NULL);
_cairo_pattern_fini (&pattern.base);
 
if (unlikely (status))
goto BAIL;
 
break;
}
 
prev = prev->prev;
}
 
*tx = clip_extents->x;
*ty = clip_extents->y;
cairo_surface_destroy (clip_path->surface);
return clip_path->surface = surface;
 
BAIL:
cairo_surface_destroy (surface);
return _cairo_surface_create_in_error (status);
}
 
cairo_bool_t
_cairo_clip_contains_rectangle (cairo_clip_t *clip,
const cairo_rectangle_int_t *rect)
{
cairo_clip_path_t *clip_path;
 
if (clip == NULL)
return FALSE;
 
clip_path = clip->path;
if (clip_path->extents.x > rect->x ||
clip_path->extents.y > rect->y ||
clip_path->extents.x + clip_path->extents.width < rect->x + rect->width ||
clip_path->extents.y + clip_path->extents.height < rect->y + rect->height)
{
return FALSE;
}
 
do {
cairo_box_t box;
 
if ((clip_path->flags & CAIRO_CLIP_PATH_IS_BOX) == 0)
return FALSE;
 
if (! _cairo_path_fixed_is_box (&clip_path->path, &box))
return FALSE;
 
if (box.p1.x > _cairo_fixed_from_int (rect->x) ||
box.p1.y > _cairo_fixed_from_int (rect->y) ||
box.p2.x < _cairo_fixed_from_int (rect->x + rect->width) ||
box.p2.y < _cairo_fixed_from_int (rect->y + rect->height))
{
return FALSE;
}
} while ((clip_path = clip_path->prev) != NULL);
 
return TRUE;
}
 
cairo_bool_t
_cairo_clip_contains_extents (cairo_clip_t *clip,
const cairo_composite_rectangles_t *extents)
{
const cairo_rectangle_int_t *rect;
 
if (clip == NULL)
return FALSE;
 
rect = extents->is_bounded ? &extents->bounded : &extents->unbounded;
return _cairo_clip_contains_rectangle (clip, rect);
}
 
void
_cairo_debug_print_clip (FILE *stream, cairo_clip_t *clip)
{
cairo_clip_path_t *clip_path;
 
if (clip == NULL) {
fprintf (stream, "no clip\n");
return;
}
 
if (clip->all_clipped) {
fprintf (stream, "clip: all-clipped\n");
return;
}
 
if (clip->path == NULL) {
fprintf (stream, "clip: empty\n");
return;
}
 
fprintf (stream, "clip:\n");
 
clip_path = clip->path;
do {
fprintf (stream, "path: has region? %s, has surface? %s, aa=%d, tolerance=%f, rule=%d: ",
clip_path->region == NULL ? "no" : "yes",
clip_path->surface == NULL ? "no" : "yes",
clip_path->antialias,
clip_path->tolerance,
clip_path->fill_rule);
_cairo_debug_print_path (stream, &clip_path->path);
fprintf (stream, "\n");
} while ((clip_path = clip_path->prev) != NULL);
}
 
cairo_surface_t *
_cairo_clip_get_surface (cairo_clip_t *clip, cairo_surface_t *target, int *tx, int *ty)
{
/* XXX is_clear -> all_clipped */
assert (clip->path != NULL);
return _cairo_clip_path_get_surface (clip->path, target, tx, ty);
}
 
cairo_status_t
_cairo_clip_combine_with_surface (cairo_clip_t *clip,
cairo_surface_t *dst,
int dst_x, int dst_y)
{
cairo_clip_path_t *clip_path = clip->path;
cairo_bool_t need_translate;
cairo_status_t status;
 
assert (clip_path != NULL);
 
need_translate = dst_x | dst_y;
do {
if (clip_path->surface != NULL &&
clip_path->surface->backend == dst->backend)
{
cairo_surface_pattern_t pattern;
 
_cairo_pattern_init_for_surface (&pattern, clip_path->surface);
cairo_matrix_init_translate (&pattern.base.matrix,
dst_x - clip_path->extents.x,
dst_y - clip_path->extents.y);
pattern.base.filter = CAIRO_FILTER_NEAREST;
status = _cairo_surface_paint (dst,
CAIRO_OPERATOR_IN,
&pattern.base,
NULL);
 
_cairo_pattern_fini (&pattern.base);
 
return status;
}
 
if (clip_path->flags & CAIRO_CLIP_PATH_IS_BOX &&
clip_path->path.maybe_fill_region)
{
continue;
}
 
if (need_translate) {
_cairo_path_fixed_translate (&clip_path->path,
_cairo_fixed_from_int (-dst_x),
_cairo_fixed_from_int (-dst_y));
}
status = _cairo_surface_fill (dst,
CAIRO_OPERATOR_IN,
&_cairo_pattern_white.base,
&clip_path->path,
clip_path->fill_rule,
clip_path->tolerance,
clip_path->antialias,
NULL);
if (need_translate) {
_cairo_path_fixed_translate (&clip_path->path,
_cairo_fixed_from_int (dst_x),
_cairo_fixed_from_int (dst_y));
}
 
if (unlikely (status))
return status;
} while ((clip_path = clip_path->prev) != NULL);
 
return CAIRO_STATUS_SUCCESS;
}
 
static const cairo_rectangle_int_t _cairo_empty_rectangle_int = { 0, 0, 0, 0 };
 
const cairo_rectangle_int_t *
_cairo_clip_get_extents (const cairo_clip_t *clip)
{
if (clip->all_clipped)
return &_cairo_empty_rectangle_int;
 
if (clip->path == NULL)
return NULL;
 
return &clip->path->extents;
}
 
void
_cairo_clip_drop_cache (cairo_clip_t *clip)
{
cairo_clip_path_t *clip_path;
 
if (clip->path == NULL)
return;
 
clip_path = clip->path;
do {
if (clip_path->region != NULL) {
cairo_region_destroy (clip_path->region);
clip_path->region = NULL;
}
 
if (clip_path->surface != NULL) {
cairo_surface_destroy (clip_path->surface);
clip_path->surface = NULL;
}
 
clip_path->flags &= ~CAIRO_CLIP_PATH_HAS_REGION;
} while ((clip_path = clip_path->prev) != NULL);
}
 
const cairo_rectangle_list_t _cairo_rectangles_nil =
{ CAIRO_STATUS_NO_MEMORY, NULL, 0 };
static const cairo_rectangle_list_t _cairo_rectangles_not_representable =
{ CAIRO_STATUS_CLIP_NOT_REPRESENTABLE, NULL, 0 };
 
static cairo_bool_t
_cairo_clip_int_rect_to_user (cairo_gstate_t *gstate,
cairo_rectangle_int_t *clip_rect,
cairo_rectangle_t *user_rect)
{
cairo_bool_t is_tight;
 
double x1 = clip_rect->x;
double y1 = clip_rect->y;
double x2 = clip_rect->x + (int) clip_rect->width;
double y2 = clip_rect->y + (int) clip_rect->height;
 
_cairo_gstate_backend_to_user_rectangle (gstate,
&x1, &y1, &x2, &y2,
&is_tight);
 
user_rect->x = x1;
user_rect->y = y1;
user_rect->width = x2 - x1;
user_rect->height = y2 - y1;
 
return is_tight;
}
 
cairo_int_status_t
_cairo_clip_get_region (cairo_clip_t *clip,
cairo_region_t **region)
{
cairo_int_status_t status;
 
if (clip->all_clipped)
goto CLIPPED;
 
assert (clip->path != NULL);
 
status = _cairo_clip_path_to_region (clip->path);
if (status)
return status;
 
if (cairo_region_is_empty (clip->path->region)) {
_cairo_clip_set_all_clipped (clip);
goto CLIPPED;
}
 
if (region)
*region = clip->path->region;
return CAIRO_STATUS_SUCCESS;
 
CLIPPED:
if (region)
*region = NULL;
return CAIRO_INT_STATUS_NOTHING_TO_DO;
}
 
cairo_int_status_t
_cairo_clip_get_boxes (cairo_clip_t *clip,
cairo_box_t **boxes,
int *count)
{
cairo_int_status_t status;
 
if (clip->all_clipped)
return CAIRO_INT_STATUS_NOTHING_TO_DO;
 
assert (clip->path != NULL);
 
status = _cairo_clip_path_to_boxes (clip->path, boxes, count);
if (status)
return status;
 
if (*count == 0) {
_cairo_clip_set_all_clipped (clip);
return CAIRO_INT_STATUS_NOTHING_TO_DO;
}
 
return CAIRO_STATUS_SUCCESS;
}
 
static cairo_bool_t
box_is_aligned (const cairo_box_t *box)
{
return
_cairo_fixed_is_integer (box->p1.x) &&
_cairo_fixed_is_integer (box->p1.y) &&
_cairo_fixed_is_integer (box->p2.x) &&
_cairo_fixed_is_integer (box->p2.y);
}
 
static void
intersect_with_boxes (cairo_composite_rectangles_t *extents,
cairo_box_t *boxes,
int num_boxes)
{
cairo_rectangle_int_t rect;
cairo_box_t box;
cairo_bool_t is_empty;
 
box.p1.x = box.p1.y = INT_MIN;
box.p2.x = box.p2.y = INT_MAX;
while (num_boxes--) {
if (boxes->p1.x < box.p1.x)
box.p1.x = boxes->p1.x;
if (boxes->p1.y < box.p1.y)
box.p1.y = boxes->p1.y;
 
if (boxes->p2.x > box.p2.x)
box.p2.x = boxes->p2.x;
if (boxes->p2.y > box.p2.y)
box.p2.y = boxes->p2.y;
}
 
_cairo_box_round_to_rectangle (&box, &rect);
is_empty = _cairo_rectangle_intersect (&extents->bounded, &rect);
is_empty = _cairo_rectangle_intersect (&extents->unbounded, &rect);
}
 
cairo_status_t
_cairo_clip_to_boxes (cairo_clip_t **clip,
cairo_composite_rectangles_t *extents,
cairo_box_t **boxes,
int *num_boxes)
{
cairo_status_t status;
const cairo_rectangle_int_t *rect;
 
rect = extents->is_bounded ? &extents->bounded : &extents->unbounded;
 
if (*clip == NULL)
goto EXTENTS;
 
status = _cairo_clip_rectangle (*clip, rect);
if (unlikely (status))
return status;
 
status = _cairo_clip_get_boxes (*clip, boxes, num_boxes);
switch ((int) status) {
case CAIRO_STATUS_SUCCESS:
intersect_with_boxes (extents, *boxes, *num_boxes);
if (rect->width == 0 || rect->height == 0 ||
extents->is_bounded ||
(*num_boxes == 1 && box_is_aligned (*boxes)))
{
*clip = NULL;
}
goto DONE;
 
case CAIRO_INT_STATUS_UNSUPPORTED:
goto EXTENTS;
 
default:
return status;
}
 
EXTENTS:
status = CAIRO_STATUS_SUCCESS;
_cairo_box_from_rectangle (&(*boxes)[0], rect);
*num_boxes = 1;
DONE:
return status;
}
 
 
static cairo_rectangle_list_t *
_cairo_rectangle_list_create_in_error (cairo_status_t status)
{
cairo_rectangle_list_t *list;
 
if (status == CAIRO_STATUS_NO_MEMORY)
return (cairo_rectangle_list_t*) &_cairo_rectangles_nil;
if (status == CAIRO_STATUS_CLIP_NOT_REPRESENTABLE)
return (cairo_rectangle_list_t*) &_cairo_rectangles_not_representable;
 
list = malloc (sizeof (*list));
if (unlikely (list == NULL)) {
_cairo_error_throw (status);
return (cairo_rectangle_list_t*) &_cairo_rectangles_nil;
}
 
list->status = status;
list->rectangles = NULL;
list->num_rectangles = 0;
 
return list;
}
 
cairo_rectangle_list_t *
_cairo_clip_copy_rectangle_list (cairo_clip_t *clip, cairo_gstate_t *gstate)
{
#define ERROR_LIST(S) _cairo_rectangle_list_create_in_error (_cairo_error (S))
 
cairo_rectangle_list_t *list;
cairo_rectangle_t *rectangles = NULL;
cairo_region_t *region = NULL;
cairo_int_status_t status;
int n_rects = 0;
int i;
 
if (clip->all_clipped)
goto DONE;
 
if (!clip->path)
return ERROR_LIST (CAIRO_STATUS_CLIP_NOT_REPRESENTABLE);
 
status = _cairo_clip_get_region (clip, &region);
if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) {
goto DONE;
} else if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
return ERROR_LIST (CAIRO_STATUS_CLIP_NOT_REPRESENTABLE);
} else if (unlikely (status)) {
return ERROR_LIST (status);
}
 
n_rects = cairo_region_num_rectangles (region);
if (n_rects) {
rectangles = _cairo_malloc_ab (n_rects, sizeof (cairo_rectangle_t));
if (unlikely (rectangles == NULL)) {
return ERROR_LIST (CAIRO_STATUS_NO_MEMORY);
}
 
for (i = 0; i < n_rects; ++i) {
cairo_rectangle_int_t clip_rect;
 
cairo_region_get_rectangle (region, i, &clip_rect);
 
if (! _cairo_clip_int_rect_to_user (gstate,
&clip_rect,
&rectangles[i]))
{
free (rectangles);
return ERROR_LIST (CAIRO_STATUS_CLIP_NOT_REPRESENTABLE);
}
}
}
 
DONE:
list = malloc (sizeof (cairo_rectangle_list_t));
if (unlikely (list == NULL)) {
free (rectangles);
return ERROR_LIST (CAIRO_STATUS_NO_MEMORY);
}
 
list->status = CAIRO_STATUS_SUCCESS;
list->rectangles = rectangles;
list->num_rectangles = n_rects;
return list;
 
#undef ERROR_LIST
}
 
/**
* cairo_rectangle_list_destroy:
* @rectangle_list: a rectangle list, as obtained from cairo_copy_clip_rectangles()
*
* Unconditionally frees @rectangle_list and all associated
* references. After this call, the @rectangle_list pointer must not
* be dereferenced.
*
* Since: 1.4
**/
void
cairo_rectangle_list_destroy (cairo_rectangle_list_t *rectangle_list)
{
if (rectangle_list == NULL || rectangle_list == &_cairo_rectangles_nil ||
rectangle_list == &_cairo_rectangles_not_representable)
return;
 
free (rectangle_list->rectangles);
free (rectangle_list);
}
 
void
_cairo_clip_reset_static_data (void)
{
_freed_pool_reset (&clip_path_pool);
}
/programs/develop/libraries/cairo/src/cairo-color.c
0,0 → 1,211
/* 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., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
*/
 
#include "cairoint.h"
 
static cairo_color_t const cairo_color_white = {
1.0, 1.0, 1.0, 1.0,
0xffff, 0xffff, 0xffff, 0xffff
};
 
static cairo_color_t const cairo_color_black = {
0.0, 0.0, 0.0, 1.0,
0x0, 0x0, 0x0, 0xffff
};
 
static cairo_color_t const cairo_color_transparent = {
0.0, 0.0, 0.0, 0.0,
0x0, 0x0, 0x0, 0x0
};
 
static cairo_color_t const cairo_color_magenta = {
1.0, 0.0, 1.0, 1.0,
0xffff, 0x0, 0xffff, 0xffff
};
 
const cairo_color_t *
_cairo_stock_color (cairo_stock_t stock)
{
switch (stock) {
case CAIRO_STOCK_WHITE:
return &cairo_color_white;
case CAIRO_STOCK_BLACK:
return &cairo_color_black;
case CAIRO_STOCK_TRANSPARENT:
return &cairo_color_transparent;
 
case CAIRO_STOCK_NUM_COLORS:
default:
ASSERT_NOT_REACHED;
/* If the user can get here somehow, give a color that indicates a
* problem. */
return &cairo_color_magenta;
}
}
 
void
_cairo_color_init (cairo_color_t *color)
{
*color = cairo_color_white;
}
 
void
_cairo_color_init_rgb (cairo_color_t *color,
double red, double green, double blue)
{
_cairo_color_init_rgba (color, red, green, blue, 1.0);
}
 
/* Convert a double in [0.0, 1.0] to an integer in [0, 65535]
* The conversion is designed to divide the input range into 65536
* equally-sized regions. This is achieved by multiplying by 65536 and
* then special-casing the result of an input value of 1.0 so that it
* maps to 65535 instead of 65536.
*/
uint16_t
_cairo_color_double_to_short (double d)
{
uint32_t i;
i = (uint32_t) (d * 65536);
i -= (i >> 16);
return i;
}
 
static void
_cairo_color_compute_shorts (cairo_color_t *color)
{
color->red_short = _cairo_color_double_to_short (color->red * color->alpha);
color->green_short = _cairo_color_double_to_short (color->green * color->alpha);
color->blue_short = _cairo_color_double_to_short (color->blue * color->alpha);
color->alpha_short = _cairo_color_double_to_short (color->alpha);
}
 
void
_cairo_color_init_rgba (cairo_color_t *color,
double red, double green, double blue,
double alpha)
{
color->red = red;
color->green = green;
color->blue = blue;
color->alpha = alpha;
 
_cairo_color_compute_shorts (color);
}
 
void
_cairo_color_multiply_alpha (cairo_color_t *color,
double alpha)
{
color->alpha *= alpha;
 
_cairo_color_compute_shorts (color);
}
 
void
_cairo_color_get_rgba (cairo_color_t *color,
double *red,
double *green,
double *blue,
double *alpha)
{
*red = color->red;
*green = color->green;
*blue = color->blue;
*alpha = color->alpha;
}
 
void
_cairo_color_get_rgba_premultiplied (cairo_color_t *color,
double *red,
double *green,
double *blue,
double *alpha)
{
*red = color->red * color->alpha;
*green = color->green * color->alpha;
*blue = color->blue * color->alpha;
*alpha = color->alpha;
}
 
/* NB: This function works both for unmultiplied and premultiplied colors */
cairo_bool_t
_cairo_color_equal (const cairo_color_t *color_a,
const cairo_color_t *color_b)
{
if (color_a == color_b)
return TRUE;
 
if (color_a->alpha_short != color_b->alpha_short)
return FALSE;
 
if (color_a->alpha_short == 0)
return TRUE;
 
return color_a->red_short == color_b->red_short &&
color_a->green_short == color_b->green_short &&
color_a->blue_short == color_b->blue_short;
}
 
cairo_bool_t
_cairo_color_stop_equal (const cairo_color_stop_t *color_a,
const cairo_color_stop_t *color_b)
{
if (color_a == color_b)
return TRUE;
 
return color_a->alpha_short == color_b->alpha_short &&
color_a->red_short == color_b->red_short &&
color_a->green_short == color_b->green_short &&
color_a->blue_short == color_b->blue_short;
}
 
cairo_content_t
_cairo_color_get_content (const cairo_color_t *color)
{
if (CAIRO_COLOR_IS_OPAQUE (color))
return CAIRO_CONTENT_COLOR;
 
if (color->red_short == 0 &&
color->green_short == 0 &&
color->blue_short == 0)
{
return CAIRO_CONTENT_ALPHA;
}
 
return CAIRO_CONTENT_COLOR_ALPHA;
}
/programs/develop/libraries/cairo/src/cairo-combsort-private.h
0,0 → 1,71
/*
* Copyright © 2008 Chris Wilson
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Chris Wilson
*
* Contributor(s):
* Chris Wilson <chris@chris-wilson.co.uk>
*/
 
/* This fragment implements a comb sort (specifically combsort11) */
#ifndef _HAVE_CAIRO_COMBSORT_NEWGAP
#define _HAVE_CAIRO_COMBSORT_NEWGAP
static inline unsigned int
_cairo_combsort_newgap (unsigned int gap)
{
gap = 10 * gap / 13;
if (gap == 9 || gap == 10)
gap = 11;
if (gap < 1)
gap = 1;
return gap;
}
#endif
 
#define CAIRO_COMBSORT_DECLARE(NAME, TYPE, CMP) \
static void \
NAME (TYPE *base, unsigned int nmemb) \
{ \
unsigned int gap = nmemb; \
unsigned int i, j; \
int swapped; \
do { \
gap = _cairo_combsort_newgap (gap); \
swapped = gap > 1; \
for (i = 0; i < nmemb-gap ; i++) { \
j = i + gap; \
if (CMP (base[i], base[j]) > 0 ) { \
TYPE tmp; \
tmp = base[i]; \
base[i] = base[j]; \
base[j] = tmp; \
swapped = 1; \
} \
} \
} while (swapped); \
}
/programs/develop/libraries/cairo/src/cairo-compiler-private.h
0,0 → 1,261
/* 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., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
*/
 
#ifndef CAIRO_COMPILER_PRIVATE_H
#define CAIRO_COMPILER_PRIVATE_H
 
#include "cairo.h"
 
#if HAVE_CONFIG_H
#include "config.h"
#endif
 
/* Size in bytes of buffer to use off the stack per functions.
* Mostly used by text functions. For larger allocations, they'll
* malloc(). */
#ifndef CAIRO_STACK_BUFFER_SIZE
#define CAIRO_STACK_BUFFER_SIZE (512 * sizeof (int))
#endif
 
#define CAIRO_STACK_ARRAY_LENGTH(T) (CAIRO_STACK_BUFFER_SIZE / sizeof(T))
 
/*
* The goal of this block is to define the following macros for
* providing faster linkage to functions in the public API for calls
* from within cairo.
*
* slim_hidden_proto(f)
* slim_hidden_proto_no_warn(f)
*
* Declares `f' as a library internal function and hides the
* function from the global symbol table. This macro must be
* expanded after `f' has been declared with a prototype but before
* any calls to the function are seen by the compiler. The no_warn
* variant inhibits warnings about the return value being unused at
* call sites. The macro works by renaming `f' to an internal name
* in the symbol table and hiding that. As far as cairo internal
* calls are concerned they're calling a library internal function
* and thus don't need to bounce via the PLT.
*
* slim_hidden_def(f)
*
* Exports `f' back to the global symbol table. This macro must be
* expanded right after the function definition and only for symbols
* hidden previously with slim_hidden_proto(). The macro works by
* adding a global entry to the symbol table which points at the
* internal name of `f' created by slim_hidden_proto().
*
* Functions in the public API which aren't called by the library
* don't need to be hidden and re-exported using the slim hidden
* macros.
*/
#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 */
#define CAIRO_HAS_HIDDEN_SYMBOLS 1
#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
#undef CAIRO_HAS_HIDDEN_SYMBOLS
#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
 
/*
* Cairo uses the following function attributes in order to improve the
* generated code (effectively by manual inter-procedural analysis).
*
* 'cairo_pure': The function is only allowed to read from its arguments
* and global memory (i.e. following a pointer argument or
* accessing a shared variable). The return value should
* only depend on its arguments, and for an identical set of
* arguments should return the same value.
*
* 'cairo_const': The function is only allowed to read from its arguments.
* It is not allowed to access global memory. The return
* value should only depend its arguments, and for an
* identical set of arguments should return the same value.
* This is currently the most strict function attribute.
*
* Both these function attributes allow gcc to perform CSE and
* constant-folding, with 'cairo_const 'also guaranteeing that pointer contents
* do not change across the function call.
*/
#if __GNUC__ >= 3
#define cairo_pure __attribute__((pure))
#define cairo_const __attribute__((const))
#define cairo_always_inline inline __attribute__((always_inline))
#else
#define cairo_pure
#define cairo_const
#define cairo_always_inline inline
#endif
 
#if defined(__GNUC__) && (__GNUC__ > 2) && defined(__OPTIMIZE__)
#define _CAIRO_BOOLEAN_EXPR(expr) \
__extension__ ({ \
int _cairo_boolean_var_; \
if (expr) \
_cairo_boolean_var_ = 1; \
else \
_cairo_boolean_var_ = 0; \
_cairo_boolean_var_; \
})
#define likely(expr) (__builtin_expect (_CAIRO_BOOLEAN_EXPR(expr), 1))
#define unlikely(expr) (__builtin_expect (_CAIRO_BOOLEAN_EXPR(expr), 0))
#else
#define likely(expr) (expr)
#define unlikely(expr) (expr)
#endif
 
#ifndef __GNUC__
#undef __attribute__
#define __attribute__(x)
#endif
 
#if (defined(__WIN32__) && !defined(__WINE__)) || defined(_MSC_VER)
#define snprintf _snprintf
#define popen _popen
#define pclose _pclose
#define hypot _hypot
#endif
 
#ifdef _MSC_VER
#undef inline
#define inline __inline
 
/* Add a definition of ffs */
#include <intrin.h>
#pragma intrinsic(_BitScanForward)
static __forceinline int
ffs (int x)
{
unsigned long i;
 
if (_BitScanForward(&i, x) != 0)
return i + 1;
 
return 0;
}
 
#endif
 
#if defined(_MSC_VER) && defined(_M_IX86)
/* When compiling with /Gy and /OPT:ICF identical functions will be folded in together.
The CAIRO_ENSURE_UNIQUE macro ensures that a function is always unique and
will never be folded into another one. Something like this might eventually
be needed for GCC but it seems fine for now. */
#define CAIRO_ENSURE_UNIQUE \
do { \
char func[] = __FUNCTION__; \
char file[] = __FILE__; \
__asm { \
__asm jmp __internal_skip_line_no \
__asm _emit (__LINE__ & 0xff) \
__asm _emit ((__LINE__>>8) & 0xff) \
__asm _emit ((__LINE__>>16) & 0xff) \
__asm _emit ((__LINE__>>24) & 0xff) \
__asm lea eax, func \
__asm lea eax, file \
__asm __internal_skip_line_no: \
}; \
} while (0)
#else
#define CAIRO_ENSURE_UNIQUE do { } while (0)
#endif
 
#ifdef __STRICT_ANSI__
#undef inline
#define inline __inline__
#endif
 
#endif
/programs/develop/libraries/cairo/src/cairo-composite-rectangles-private.h
0,0 → 1,105
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2009 Intel Corporation
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Chris Wilson <chris@chris-wilson.co.u>
*/
 
#ifndef CAIRO_COMPOSITE_RECTANGLES_PRIVATE_H
#define CAIRO_COMPOSITE_RECTANGLES_PRIVATE_H
 
#include "cairo-types-private.h"
 
CAIRO_BEGIN_DECLS
 
/* Rectangles that take part in a composite operation.
*
* The source and mask track the extents of the respective patterns in device
* space. The unbounded rectangle is essentially the clip rectangle. And the
* intersection of all is the bounded rectangle, which is the minimum extents
* the operation may require. Whether or not the operation is actually bounded
* is tracked in the is_bounded boolean.
*
*/
struct _cairo_composite_rectangles {
cairo_rectangle_int_t source;
cairo_rectangle_int_t mask;
cairo_rectangle_int_t bounded; /* dst */
cairo_rectangle_int_t unbounded; /* clip */
uint32_t is_bounded;
};
 
cairo_private cairo_int_status_t
_cairo_composite_rectangles_init_for_paint (cairo_composite_rectangles_t *extents,
int surface_width, int surface_height,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_clip_t *clip);
 
cairo_private cairo_int_status_t
_cairo_composite_rectangles_init_for_mask (cairo_composite_rectangles_t *extents,
int surface_width, int surface_height,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_pattern_t *mask,
cairo_clip_t *clip);
 
cairo_private cairo_int_status_t
_cairo_composite_rectangles_init_for_stroke (cairo_composite_rectangles_t *extents,
int surface_width, int surface_height,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_path_fixed_t *path,
const cairo_stroke_style_t *style,
const cairo_matrix_t *ctm,
cairo_clip_t *clip);
 
cairo_private cairo_int_status_t
_cairo_composite_rectangles_init_for_fill (cairo_composite_rectangles_t *extents,
int surface_width, int surface_height,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_path_fixed_t *path,
cairo_clip_t *clip);
 
cairo_private cairo_int_status_t
_cairo_composite_rectangles_init_for_glyphs (cairo_composite_rectangles_t *extents,
int surface_width, int surface_height,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_scaled_font_t *scaled_font,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_clip_t *clip,
cairo_bool_t *overlap);
 
#endif /* CAIRO_COMPOSITE_RECTANGLES_PRIVATE_H */
/programs/develop/libraries/cairo/src/cairo-composite-rectangles.c
0,0 → 1,197
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2009 Intel Corporation
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
* Chris Wilson <chris@chris-wilson.co.uk>
*/
 
#include "cairoint.h"
 
#include "cairo-error-private.h"
#include "cairo-composite-rectangles-private.h"
 
/* A collection of routines to facilitate writing compositors. */
 
static inline cairo_bool_t
_cairo_composite_rectangles_init (cairo_composite_rectangles_t *extents,
int width, int height,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_clip_t *clip)
{
extents->unbounded.x = extents->unbounded.y = 0;
extents->unbounded.width = width;
extents->unbounded.height = height;
 
if (clip != NULL) {
const cairo_rectangle_int_t *clip_extents;
 
clip_extents = _cairo_clip_get_extents (clip);
if (clip_extents == NULL)
return FALSE;
 
if (! _cairo_rectangle_intersect (&extents->unbounded, clip_extents))
return FALSE;
}
 
extents->bounded = extents->unbounded;
extents->is_bounded = _cairo_operator_bounded_by_either (op);
 
_cairo_pattern_get_extents (source, &extents->source);
if (extents->is_bounded & CAIRO_OPERATOR_BOUND_BY_SOURCE) {
if (! _cairo_rectangle_intersect (&extents->bounded, &extents->source))
return FALSE;
}
 
return TRUE;
}
 
cairo_int_status_t
_cairo_composite_rectangles_init_for_paint (cairo_composite_rectangles_t *extents,
int surface_width, int surface_height,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_clip_t *clip)
{
if (! _cairo_composite_rectangles_init (extents,
surface_width, surface_height,
op, source, clip))
{
return CAIRO_INT_STATUS_NOTHING_TO_DO;
}
 
extents->mask = extents->bounded;
return CAIRO_STATUS_SUCCESS;
}
 
static cairo_int_status_t
_cairo_composite_rectangles_intersect (cairo_composite_rectangles_t *extents)
{
cairo_bool_t ret;
 
ret = _cairo_rectangle_intersect (&extents->bounded, &extents->mask);
if (! ret && extents->is_bounded & CAIRO_OPERATOR_BOUND_BY_MASK)
return CAIRO_INT_STATUS_NOTHING_TO_DO;
 
return CAIRO_STATUS_SUCCESS;
}
 
cairo_int_status_t
_cairo_composite_rectangles_init_for_mask (cairo_composite_rectangles_t *extents,
int surface_width, int surface_height,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_pattern_t *mask,
cairo_clip_t *clip)
{
if (! _cairo_composite_rectangles_init (extents,
surface_width, surface_height,
op, source, clip))
{
return CAIRO_INT_STATUS_NOTHING_TO_DO;
}
 
_cairo_pattern_get_extents (mask, &extents->mask);
 
return _cairo_composite_rectangles_intersect (extents);
}
 
cairo_int_status_t
_cairo_composite_rectangles_init_for_stroke (cairo_composite_rectangles_t *extents,
int surface_width, int surface_height,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_path_fixed_t *path,
const cairo_stroke_style_t *style,
const cairo_matrix_t *ctm,
cairo_clip_t *clip)
{
if (! _cairo_composite_rectangles_init (extents,
surface_width, surface_height,
op, source, clip))
{
return CAIRO_INT_STATUS_NOTHING_TO_DO;
}
 
_cairo_path_fixed_approximate_stroke_extents (path, style, ctm, &extents->mask);
 
return _cairo_composite_rectangles_intersect (extents);
}
 
cairo_int_status_t
_cairo_composite_rectangles_init_for_fill (cairo_composite_rectangles_t *extents,
int surface_width, int surface_height,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_path_fixed_t *path,
cairo_clip_t *clip)
{
if (! _cairo_composite_rectangles_init (extents,
surface_width, surface_height,
op, source, clip))
{
return CAIRO_INT_STATUS_NOTHING_TO_DO;
}
 
_cairo_path_fixed_approximate_fill_extents (path, &extents->mask);
 
return _cairo_composite_rectangles_intersect (extents);
}
 
cairo_int_status_t
_cairo_composite_rectangles_init_for_glyphs (cairo_composite_rectangles_t *extents,
int surface_width, int surface_height,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_scaled_font_t *scaled_font,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_clip_t *clip,
cairo_bool_t *overlap)
{
cairo_status_t status;
 
if (! _cairo_composite_rectangles_init (extents,
surface_width, surface_height,
op, source, clip))
{
return CAIRO_INT_STATUS_NOTHING_TO_DO;
}
 
status = _cairo_scaled_font_glyph_device_extents (scaled_font,
glyphs, num_glyphs,
&extents->mask,
overlap);
if (unlikely (status))
return status;
 
return _cairo_composite_rectangles_intersect (extents);
}
/programs/develop/libraries/cairo/src/cairo-debug.c
0,0 → 1,248
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2005 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
*/
 
#include "cairoint.h"
 
/**
* cairo_debug_reset_static_data:
*
* Resets all static data within cairo to its original state,
* (ie. identical to the state at the time of program invocation). For
* example, all caches within cairo will be flushed empty.
*
* This function is intended to be useful when using memory-checking
* tools such as valgrind. When valgrind's memcheck analyzes a
* cairo-using program without a call to cairo_debug_reset_static_data(),
* it will report all data reachable via cairo's static objects as
* "still reachable". Calling cairo_debug_reset_static_data() just prior
* to program termination will make it easier to get squeaky clean
* reports from valgrind.
*
* WARNING: It is only safe to call this function when there are no
* active cairo objects remaining, (ie. the appropriate destroy
* functions have been called as necessary). If there are active cairo
* objects, this call is likely to cause a crash, (eg. an assertion
* failure due to a hash table being destroyed when non-empty).
**/
void
cairo_debug_reset_static_data (void)
{
CAIRO_MUTEX_INITIALIZE ();
 
_cairo_scaled_font_map_destroy ();
 
_cairo_toy_font_face_reset_static_data ();
 
#if CAIRO_HAS_FT_FONT
_cairo_ft_font_reset_static_data ();
#endif
 
_cairo_intern_string_reset_static_data ();
 
_cairo_scaled_font_reset_static_data ();
 
_cairo_pattern_reset_static_data ();
 
_cairo_clip_reset_static_data ();
 
_cairo_image_reset_static_data ();
 
#if CAIRO_HAS_DRM_SURFACE
_cairo_drm_device_reset_static_data ();
#endif
 
_cairo_reset_static_data ();
 
CAIRO_MUTEX_FINALIZE ();
}
 
#if HAVE_VALGRIND
void
_cairo_debug_check_image_surface_is_defined (const cairo_surface_t *surface)
{
const cairo_image_surface_t *image = (cairo_image_surface_t *) surface;
const uint8_t *bits;
int row, width;
 
if (surface == NULL)
return;
 
if (! RUNNING_ON_VALGRIND)
return;
 
bits = image->data;
switch (image->format) {
case CAIRO_FORMAT_A1:
width = (image->width + 7)/8;
break;
case CAIRO_FORMAT_A8:
width = image->width;
break;
case CAIRO_FORMAT_RGB16_565:
width = image->width*2;
break;
case CAIRO_FORMAT_RGB24:
case CAIRO_FORMAT_ARGB32:
width = image->width*4;
break;
case CAIRO_FORMAT_INVALID:
default:
/* XXX compute width from pixman bpp */
return;
}
 
for (row = 0; row < image->height; row++) {
VALGRIND_CHECK_MEM_IS_DEFINED (bits, width);
/* and then silence any future valgrind warnings */
VALGRIND_MAKE_MEM_DEFINED (bits, width);
bits += image->stride;
}
}
#endif
 
 
#if 0
void
_cairo_image_surface_write_to_ppm (cairo_image_surface_t *isurf, const char *fn)
{
char *fmt;
if (isurf->format == CAIRO_FORMAT_ARGB32 || isurf->format == CAIRO_FORMAT_RGB24)
fmt = "P6";
else if (isurf->format == CAIRO_FORMAT_A8)
fmt = "P5";
else
return;
 
FILE *fp = fopen(fn, "wb");
if (!fp)
return;
 
fprintf (fp, "%s %d %d 255\n", fmt,isurf->width, isurf->height);
for (int j = 0; j < isurf->height; j++) {
unsigned char *row = isurf->data + isurf->stride * j;
for (int i = 0; i < isurf->width; i++) {
if (isurf->format == CAIRO_FORMAT_ARGB32 || isurf->format == CAIRO_FORMAT_RGB24) {
unsigned char r = *row++;
unsigned char g = *row++;
unsigned char b = *row++;
*row++;
putc(r, fp);
putc(g, fp);
putc(b, fp);
} else {
unsigned char a = *row++;
putc(a, fp);
}
}
}
 
fclose (fp);
 
fprintf (stderr, "Wrote %s\n", fn);
}
#endif
 
static cairo_status_t
_print_move_to (void *closure,
const cairo_point_t *point)
{
fprintf (closure,
" %f %f m",
_cairo_fixed_to_double (point->x),
_cairo_fixed_to_double (point->y));
 
return CAIRO_STATUS_SUCCESS;
}
 
static cairo_status_t
_print_line_to (void *closure,
const cairo_point_t *point)
{
fprintf (closure,
" %f %f l",
_cairo_fixed_to_double (point->x),
_cairo_fixed_to_double (point->y));
 
return CAIRO_STATUS_SUCCESS;
}
 
static cairo_status_t
_print_curve_to (void *closure,
const cairo_point_t *p1,
const cairo_point_t *p2,
const cairo_point_t *p3)
{
fprintf (closure,
" %f %f %f %f %f %f c",
_cairo_fixed_to_double (p1->x),
_cairo_fixed_to_double (p1->y),
_cairo_fixed_to_double (p2->x),
_cairo_fixed_to_double (p2->y),
_cairo_fixed_to_double (p3->x),
_cairo_fixed_to_double (p3->y));
 
return CAIRO_STATUS_SUCCESS;
}
 
static cairo_status_t
_print_close (void *closure)
{
fprintf (closure, " h");
 
return CAIRO_STATUS_SUCCESS;
}
 
void
_cairo_debug_print_path (FILE *stream, cairo_path_fixed_t *path)
{
cairo_status_t status;
 
printf ("path: extents=(%f, %f), (%f, %f)\n",
_cairo_fixed_to_double (path->extents.p1.x),
_cairo_fixed_to_double (path->extents.p1.y),
_cairo_fixed_to_double (path->extents.p2.x),
_cairo_fixed_to_double (path->extents.p2.y));
 
status = _cairo_path_fixed_interpret (path,
CAIRO_DIRECTION_FORWARD,
_print_move_to,
_print_line_to,
_print_curve_to,
_print_close,
stream);
assert (status == CAIRO_STATUS_SUCCESS);
 
printf ("\n");
}
/programs/develop/libraries/cairo/src/cairo-deprecated.h
0,0 → 1,123
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2006 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
*/
 
#ifndef CAIRO_DEPRECATED_H
#define CAIRO_DEPRECATED_H
 
#define CAIRO_FONT_TYPE_ATSUI CAIRO_FONT_TYPE_QUARTZ
 
/* Obsolete functions. These definitions exist to coerce the compiler
* into providing a little bit of guidance with its error
* messages. The idea is to help users port their old code without
* having to dig through lots of documentation.
*
* The first set of REPLACED_BY functions is for functions whose names
* have just been changed. So fixing these up is mechanical, (and
* automated by means of the cairo/util/cairo-api-update script.
*
* The second set of DEPRECATED_BY functions is for functions where
* the replacement is used in a different way, (ie. different
* arguments, multiple functions instead of one, etc). Fixing these up
* will require a bit more work on the user's part, (and hopefully we
* can get cairo-api-update to find these and print some guiding
* information).
*/
#define cairo_current_font_extents cairo_current_font_extents_REPLACED_BY_cairo_font_extents
#define cairo_get_font_extents cairo_get_font_extents_REPLACED_BY_cairo_font_extents
#define cairo_current_operator cairo_current_operator_REPLACED_BY_cairo_get_operator
#define cairo_current_tolerance cairo_current_tolerance_REPLACED_BY_cairo_get_tolerance
#define cairo_current_point cairo_current_point_REPLACED_BY_cairo_get_current_point
#define cairo_current_fill_rule cairo_current_fill_rule_REPLACED_BY_cairo_get_fill_rule
#define cairo_current_line_width cairo_current_line_width_REPLACED_BY_cairo_get_line_width
#define cairo_current_line_cap cairo_current_line_cap_REPLACED_BY_cairo_get_line_cap
#define cairo_current_line_join cairo_current_line_join_REPLACED_BY_cairo_get_line_join
#define cairo_current_miter_limit cairo_current_miter_limit_REPLACED_BY_cairo_get_miter_limit
#define cairo_current_matrix cairo_current_matrix_REPLACED_BY_cairo_get_matrix
#define cairo_current_target_surface cairo_current_target_surface_REPLACED_BY_cairo_get_target
#define cairo_get_status cairo_get_status_REPLACED_BY_cairo_status
#define cairo_concat_matrix cairo_concat_matrix_REPLACED_BY_cairo_transform
#define cairo_scale_font cairo_scale_font_REPLACED_BY_cairo_set_font_size
#define cairo_select_font cairo_select_font_REPLACED_BY_cairo_select_font_face
#define cairo_transform_font cairo_transform_font_REPLACED_BY_cairo_set_font_matrix
#define cairo_transform_point cairo_transform_point_REPLACED_BY_cairo_user_to_device
#define cairo_transform_distance cairo_transform_distance_REPLACED_BY_cairo_user_to_device_distance
#define cairo_inverse_transform_point cairo_inverse_transform_point_REPLACED_BY_cairo_device_to_user
#define cairo_inverse_transform_distance cairo_inverse_transform_distance_REPLACED_BY_cairo_device_to_user_distance
#define cairo_init_clip cairo_init_clip_REPLACED_BY_cairo_reset_clip
#define cairo_surface_create_for_image cairo_surface_create_for_image_REPLACED_BY_cairo_image_surface_create_for_data
#define cairo_default_matrix cairo_default_matrix_REPLACED_BY_cairo_identity_matrix
#define cairo_matrix_set_affine cairo_matrix_set_affine_REPLACED_BY_cairo_matrix_init
#define cairo_matrix_set_identity cairo_matrix_set_identity_REPLACED_BY_cairo_matrix_init_identity
#define cairo_pattern_add_color_stop cairo_pattern_add_color_stop_REPLACED_BY_cairo_pattern_add_color_stop_rgba
#define cairo_set_rgb_color cairo_set_rgb_color_REPLACED_BY_cairo_set_source_rgb
#define cairo_set_pattern cairo_set_pattern_REPLACED_BY_cairo_set_source
#define cairo_xlib_surface_create_for_pixmap_with_visual cairo_xlib_surface_create_for_pixmap_with_visual_REPLACED_BY_cairo_xlib_surface_create
#define cairo_xlib_surface_create_for_window_with_visual cairo_xlib_surface_create_for_window_with_visual_REPLACED_BY_cairo_xlib_surface_create
#define cairo_xcb_surface_create_for_pixmap_with_visual cairo_xcb_surface_create_for_pixmap_with_visual_REPLACED_BY_cairo_xcb_surface_create
#define cairo_xcb_surface_create_for_window_with_visual cairo_xcb_surface_create_for_window_with_visual_REPLACED_BY_cairo_xcb_surface_create
#define cairo_ps_surface_set_dpi cairo_ps_surface_set_dpi_REPLACED_BY_cairo_surface_set_fallback_resolution
#define cairo_pdf_surface_set_dpi cairo_pdf_surface_set_dpi_REPLACED_BY_cairo_surface_set_fallback_resolution
#define cairo_svg_surface_set_dpi cairo_svg_surface_set_dpi_REPLACED_BY_cairo_surface_set_fallback_resolution
#define cairo_atsui_font_face_create_for_atsu_font_id cairo_atsui_font_face_create_for_atsu_font_id_REPLACED_BY_cairo_quartz_font_face_create_for_atsu_font_id
 
#define cairo_current_path cairo_current_path_DEPRECATED_BY_cairo_copy_path
#define cairo_current_path_flat cairo_current_path_flat_DEPRECATED_BY_cairo_copy_path_flat
#define cairo_get_path cairo_get_path_DEPRECATED_BY_cairo_copy_path
#define cairo_get_path_flat cairo_get_path_flat_DEPRECATED_BY_cairo_get_path_flat
#define cairo_set_alpha cairo_set_alpha_DEPRECATED_BY_cairo_set_source_rgba_OR_cairo_paint_with_alpha
#define cairo_show_surface cairo_show_surface_DEPRECATED_BY_cairo_set_source_surface_AND_cairo_paint
#define cairo_copy cairo_copy_DEPRECATED_BY_cairo_create_AND_MANY_INDIVIDUAL_FUNCTIONS
#define cairo_surface_set_repeat cairo_surface_set_repeat_DEPRECATED_BY_cairo_pattern_set_extend
#define cairo_surface_set_matrix cairo_surface_set_matrix_DEPRECATED_BY_cairo_pattern_set_matrix
#define cairo_surface_get_matrix cairo_surface_get_matrix_DEPRECATED_BY_cairo_pattern_get_matrix
#define cairo_surface_set_filter cairo_surface_set_filter_DEPRECATED_BY_cairo_pattern_set_filter
#define cairo_surface_get_filter cairo_surface_get_filter_DEPRECATED_BY_cairo_pattern_get_filter
#define cairo_matrix_create cairo_matrix_create_DEPRECATED_BY_cairo_matrix_t
#define cairo_matrix_destroy cairo_matrix_destroy_DEPRECATED_BY_cairo_matrix_t
#define cairo_matrix_copy cairo_matrix_copy_DEPRECATED_BY_cairo_matrix_t
#define cairo_matrix_get_affine cairo_matrix_get_affine_DEPRECATED_BY_cairo_matrix_t
#define cairo_set_target_surface cairo_set_target_surface_DEPRECATED_BY_cairo_create
#define cairo_set_target_image cairo_set_target_image_DEPRECATED_BY_cairo_image_surface_create_for_data
#define cairo_set_target_pdf cairo_set_target_pdf_DEPRECATED_BY_cairo_pdf_surface_create
#define cairo_set_target_png cairo_set_target_png_DEPRECATED_BY_cairo_surface_write_to_png
#define cairo_set_target_ps cairo_set_target_ps_DEPRECATED_BY_cairo_ps_surface_create
#define cairo_set_target_quartz cairo_set_target_quartz_DEPRECATED_BY_cairo_quartz_surface_create
#define cairo_set_target_win32 cairo_set_target_win32_DEPRECATED_BY_cairo_win32_surface_create
#define cairo_set_target_xcb cairo_set_target_xcb_DEPRECATED_BY_cairo_xcb_surface_create
#define cairo_set_target_drawable cairo_set_target_drawable_DEPRECATED_BY_cairo_xlib_surface_create
#define cairo_get_status_string cairo_get_status_string_DEPRECATED_BY_cairo_status_AND_cairo_status_to_string
#define cairo_status_string cairo_status_string_DEPRECATED_BY_cairo_status_AND_cairo_status_to_string
 
#endif /* CAIRO_DEPRECATED_H */
/programs/develop/libraries/cairo/src/cairo-device-private.h
0,0 → 1,86
/* Cairo - a vector graphics library with display and print output
*
* Copyright © 2009 Intel Corporation
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Intel Corporation.
*
* Contributors(s):
* Chris Wilson <chris@chris-wilson.co.uk>
*/
 
#ifndef _CAIRO_DEVICE_PRIVATE_H_
#define _CAIRO_DEVICE_PRIVATE_H_
 
#include "cairo-compiler-private.h"
#include "cairo-mutex-private.h"
#include "cairo-reference-count-private.h"
#include "cairo-types-private.h"
 
struct _cairo_device {
cairo_reference_count_t ref_count;
cairo_status_t status;
cairo_user_data_array_t user_data;
 
const cairo_device_backend_t *backend;
 
cairo_recursive_mutex_t mutex;
unsigned mutex_depth;
 
cairo_bool_t finished;
};
 
struct _cairo_device_backend {
cairo_device_type_t type;
 
void (*lock) (void *device);
void (*unlock) (void *device);
 
cairo_warn cairo_status_t (*flush) (void *device);
void (*finish) (void *device);
void (*destroy) (void *device);
};
 
cairo_private cairo_device_t *
_cairo_device_create_in_error (cairo_status_t status);
 
cairo_private void
_cairo_device_init (cairo_device_t *device,
const cairo_device_backend_t *backend);
 
cairo_private cairo_status_t
_cairo_device_set_error (cairo_device_t *device,
cairo_status_t error);
 
slim_hidden_proto_no_warn (cairo_device_reference);
slim_hidden_proto (cairo_device_acquire);
slim_hidden_proto (cairo_device_release);
slim_hidden_proto (cairo_device_flush);
slim_hidden_proto (cairo_device_finish);
slim_hidden_proto (cairo_device_destroy);
 
#endif /* _CAIRO_DEVICE_PRIVATE_H_ */
/programs/develop/libraries/cairo/src/cairo-device.c
0,0 → 1,533
/* Cairo - a vector graphics library with display and print output
*
* Copyright © 2009 Intel Corporation
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Intel Corporation.
*
* Contributors(s):
* Chris Wilson <chris@chris-wilson.co.uk>
*/
 
#include "cairoint.h"
#include "cairo-device-private.h"
#include "cairo-error-private.h"
 
/**
* SECTION:cairo-device
* @Title: cairo_device_t
* @Short_Description: interface to underlying rendering system
* @See_Also: #cairo_surface_t
*
* Devices are the abstraction Cairo employs for the rendering system
* used by a #cairo_surface_t. You can get the device of a surface using
* cairo_surface_get_device().
*
* Devices are created using custom functions specific to the rendering
* system you want to use. See the documentation for the surface types
* for those functions.
*
* An important function that devices fulfill is sharing access to the
* rendering system between Cairo and your application. If you want to
* access a device directly that you used to draw to with Cairo, you must
* first call cairo_device_flush() to ensure that Cairo finishes all
* operations on the device and resets it to a clean state.
*
* Cairo also provides the functions cairo_device_acquire() and
* cairo_device_release() to synchronize access to the rendering system
* in a multithreaded environment. This is done internally, but can also
* be used by applications.
*
* Putting this all together, a function that works with devices should
* look something like this:
* <informalexample><programlisting>
* void
* my_device_modifying_function (cairo_device_t *device)
* {
* cairo_status_t status;
*
* // Ensure the device is properly reset
* cairo_device_flush (device);
* // Try to acquire the device
* status = cairo_device_acquire (device);
* if (status != CAIRO_STATUS_SUCCESS) {
* printf ("Failed to acquire the device: %s\n", cairo_status_to_string (status));
* return;
* }
*
* // Do the custom operations on the device here.
* // But do not call any Cairo functions that might acquire devices.
*
* // Release the device when done.
* cairo_device_release (device);
* }
* </programlisting></informalexample>
*
* <note><para>Please refer to the documentation of each backend for
* additional usage requirements, guarantees provided, and
* interactions with existing surface API of the device functions for
* surfaces of that type.
* </para></note>
*/
 
static const cairo_device_t _nil_device = {
CAIRO_REFERENCE_COUNT_INVALID,
CAIRO_STATUS_NO_MEMORY,
};
 
static const cairo_device_t _mismatch_device = {
CAIRO_REFERENCE_COUNT_INVALID,
CAIRO_STATUS_DEVICE_TYPE_MISMATCH,
};
 
static const cairo_device_t _invalid_device = {
CAIRO_REFERENCE_COUNT_INVALID,
CAIRO_STATUS_DEVICE_ERROR,
};
 
cairo_device_t *
_cairo_device_create_in_error (cairo_status_t status)
{
switch (status) {
case CAIRO_STATUS_NO_MEMORY:
return (cairo_device_t *) &_nil_device;
case CAIRO_STATUS_DEVICE_ERROR:
return (cairo_device_t *) &_invalid_device;
case CAIRO_STATUS_DEVICE_TYPE_MISMATCH:
return (cairo_device_t *) &_mismatch_device;
 
case CAIRO_STATUS_SUCCESS:
case CAIRO_STATUS_LAST_STATUS:
ASSERT_NOT_REACHED;
/* fall-through */
case CAIRO_STATUS_SURFACE_TYPE_MISMATCH:
case CAIRO_STATUS_INVALID_STATUS:
case CAIRO_STATUS_INVALID_FORMAT:
case CAIRO_STATUS_INVALID_VISUAL:
case CAIRO_STATUS_READ_ERROR:
case CAIRO_STATUS_WRITE_ERROR:
case CAIRO_STATUS_FILE_NOT_FOUND:
case CAIRO_STATUS_TEMP_FILE_ERROR:
case CAIRO_STATUS_INVALID_STRIDE:
case CAIRO_STATUS_INVALID_SIZE:
case CAIRO_STATUS_INVALID_RESTORE:
case CAIRO_STATUS_INVALID_POP_GROUP:
case CAIRO_STATUS_NO_CURRENT_POINT:
case CAIRO_STATUS_INVALID_MATRIX:
case CAIRO_STATUS_NULL_POINTER:
case CAIRO_STATUS_INVALID_STRING:
case CAIRO_STATUS_INVALID_PATH_DATA:
case CAIRO_STATUS_SURFACE_FINISHED:
case CAIRO_STATUS_PATTERN_TYPE_MISMATCH:
case CAIRO_STATUS_INVALID_DASH:
case CAIRO_STATUS_INVALID_DSC_COMMENT:
case CAIRO_STATUS_INVALID_INDEX:
case CAIRO_STATUS_CLIP_NOT_REPRESENTABLE:
case CAIRO_STATUS_FONT_TYPE_MISMATCH:
case CAIRO_STATUS_USER_FONT_IMMUTABLE:
case CAIRO_STATUS_USER_FONT_ERROR:
case CAIRO_STATUS_NEGATIVE_COUNT:
case CAIRO_STATUS_INVALID_CLUSTERS:
case CAIRO_STATUS_INVALID_SLANT:
case CAIRO_STATUS_INVALID_WEIGHT:
case CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED:
case CAIRO_STATUS_INVALID_CONTENT:
default:
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_device_t *) &_nil_device;
}
}
 
void
_cairo_device_init (cairo_device_t *device,
const cairo_device_backend_t *backend)
{
CAIRO_REFERENCE_COUNT_INIT (&device->ref_count, 1);
device->status = CAIRO_STATUS_SUCCESS;
 
device->backend = backend;
 
CAIRO_RECURSIVE_MUTEX_INIT (device->mutex);
device->mutex_depth = 0;
 
device->finished = FALSE;
 
_cairo_user_data_array_init (&device->user_data);
}
 
/**
* cairo_device_reference:
* @device: a #cairo_device_t
*
* Increases the reference count on @device by one. This prevents
* @device from being destroyed until a matching call to
* cairo_device_destroy() is made.
*
* The number of references to a #cairo_device_t can be get using
* cairo_device_get_reference_count().
*
* Return value: the referenced #cairo_device_t.
*
* Since: 1.10
**/
cairo_device_t *
cairo_device_reference (cairo_device_t *device)
{
if (device == NULL ||
CAIRO_REFERENCE_COUNT_IS_INVALID (&device->ref_count))
{
return device;
}
 
assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&device->ref_count));
_cairo_reference_count_inc (&device->ref_count);
 
return device;
}
slim_hidden_def (cairo_device_reference);
 
/**
* cairo_device_status:
* @device: a #cairo_device_t
*
* Checks whether an error has previously occurred for this
* device.
*
* Return value: %CAIRO_STATUS_SUCCESS on success or an error code if
* the device is in an error state.
*
* Since: 1.10
**/
cairo_status_t
cairo_device_status (cairo_device_t *device)
{
if (device == NULL)
return CAIRO_STATUS_NULL_POINTER;
 
return device->status;
}
 
/**
* cairo_device_flush:
* @device: a #cairo_device_t
*
* Finish any pending operations for the device and also restore any
* temporary modifications cairo has made to the device's state.
* This function must be called before switching from using the
* device with Cairo to operating on it directly with native APIs.
* If the device doesn't support direct access, then this function
* does nothing.
*
* This function may acquire devices.
*
* Since: 1.10
**/
void
cairo_device_flush (cairo_device_t *device)
{
cairo_status_t status;
 
if (device == NULL || device->status)
return;
 
if (device->backend->flush != NULL) {
status = device->backend->flush (device);
if (unlikely (status))
status = _cairo_device_set_error (device, status);
}
}
slim_hidden_def (cairo_device_flush);
 
/**
* cairo_device_finish:
* @device: the #cairo_device_t to finish
*
* This function finishes the device and drops all references to
* external resources. All surfaces, fonts and other objects created
* for this @device will be finished, too.
* Further operations on the @device will not affect the @device but
* will instead trigger a %CAIRO_STATUS_DEVICE_FINISHED error.
*
* When the last call to cairo_device_destroy() decreases the
* reference count to zero, cairo will call cairo_device_finish() if
* it hasn't been called already, before freeing the resources
* associated with the device.
*
* This function may acquire devices.
*
* Since: 1.10
**/
void
cairo_device_finish (cairo_device_t *device)
{
if (device == NULL ||
CAIRO_REFERENCE_COUNT_IS_INVALID (&device->ref_count))
{
return;
}
 
if (device->finished)
return;
 
cairo_device_flush (device);
 
device->finished = TRUE;
 
if (device->backend->finish != NULL)
device->backend->finish (device);
}
slim_hidden_def (cairo_device_finish);
 
/**
* cairo_device_destroy:
* @device: a #cairo_device_t
*
* Decreases the reference count on @device by one. If the result is
* zero, then @device and all associated resources are freed. See
* cairo_device_reference().
*
* This function may acquire devices if the last reference was dropped.
*
* Since: 1.10
**/
void
cairo_device_destroy (cairo_device_t *device)
{
cairo_user_data_array_t user_data;
 
if (device == NULL ||
CAIRO_REFERENCE_COUNT_IS_INVALID (&device->ref_count))
{
return;
}
 
assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&device->ref_count));
if (! _cairo_reference_count_dec_and_test (&device->ref_count))
return;
 
cairo_device_finish (device);
 
assert (device->mutex_depth == 0);
CAIRO_MUTEX_FINI (device->mutex);
 
user_data = device->user_data;
 
device->backend->destroy (device);
 
_cairo_user_data_array_fini (&user_data);
 
}
slim_hidden_def (cairo_device_destroy);
 
/**
* cairo_device_get_type:
* @device: a #cairo_device_t
*
* This function returns the type of the device. See #cairo_device_type_t
* for available types.
*
* Return value: The type of @device.
*
* Since: 1.10
**/
cairo_device_type_t
cairo_device_get_type (cairo_device_t *device)
{
if (device == NULL ||
CAIRO_REFERENCE_COUNT_IS_INVALID (&device->ref_count))
{
return (cairo_device_type_t) -1;
}
 
return device->backend->type;
}
 
/**
* cairo_device_acquire:
* @device: a #cairo_device_t
*
* Acquires the @device for the current thread. This function will block
* until no other thread has acquired the device.
*
* If the return value is %CAIRO_STATUS_SUCCESS, you successfully acquired the
* device. From now on your thread owns the device and no other thread will be
* able to acquire it until a matching call to cairo_device_release(). It is
* allowed to recursively acquire the device multiple times from the same
* thread.
*
* <note><para>You must never acquire two different devices at the same time
* unless this is explicitly allowed. Otherwise the possibility of deadlocks
* exist.
*
* As various Cairo functions can acquire devices when called, these functions
* may also cause deadlocks when you call them with an acquired device. So you
* must not have a device acquired when calling them. These functions are
* marked in the documentation.
* </para></note>
*
* Return value: %CAIRO_STATUS_SUCCESS on success or an error code if
* the device is in an error state and could not be
* acquired. After a successful call to cairo_device_acquire(),
* a matching call to cairo_device_release() is required.
*
* Since: 1.10
**/
cairo_status_t
cairo_device_acquire (cairo_device_t *device)
{
if (device == NULL)
return CAIRO_STATUS_SUCCESS;
 
if (unlikely (device->status))
return device->status;
 
if (unlikely (device->finished))
return _cairo_device_set_error (device, CAIRO_STATUS_SURFACE_FINISHED); /* XXX */
 
CAIRO_MUTEX_LOCK (device->mutex);
if (device->mutex_depth++ == 0) {
if (device->backend->lock != NULL)
device->backend->lock (device);
}
 
return CAIRO_STATUS_SUCCESS;
}
slim_hidden_def (cairo_device_acquire);
 
/**
* cairo_device_release:
* @device: a #cairo_device_t
*
* Releases a @device previously acquired using cairo_device_acquire(). See
* that function for details.
*
* Since: 1.10
**/
void
cairo_device_release (cairo_device_t *device)
{
if (device == NULL)
return;
 
assert (device->mutex_depth > 0);
 
if (--device->mutex_depth == 0) {
if (device->backend->unlock != NULL)
device->backend->unlock (device);
}
 
CAIRO_MUTEX_UNLOCK (device->mutex);
}
slim_hidden_def (cairo_device_release);
 
cairo_status_t
_cairo_device_set_error (cairo_device_t *device,
cairo_status_t status)
{
if (status == CAIRO_STATUS_SUCCESS || status >= CAIRO_INT_STATUS_UNSUPPORTED)
return status;
 
/* Don't overwrite an existing error. This preserves the first
* error, which is the most significant. */
_cairo_status_set_error (&device->status, status);
 
return _cairo_error (status);
}
 
/**
* cairo_device_get_reference_count:
* @device: a #cairo_device_t
*
* Returns the current reference count of @device.
*
* Return value: the current reference count of @device. If the
* object is a nil object, 0 will be returned.
*
* Since: 1.10
**/
unsigned int
cairo_device_get_reference_count (cairo_device_t *device)
{
if (device == NULL ||
CAIRO_REFERENCE_COUNT_IS_INVALID (&device->ref_count))
return 0;
 
return CAIRO_REFERENCE_COUNT_GET_VALUE (&device->ref_count);
}
 
/**
* cairo_device_get_user_data:
* @device: a #cairo_device_t
* @key: the address of the #cairo_user_data_key_t the user data was
* attached to
*
* Return user data previously attached to @device using the
* specified key. If no user data has been attached with the given
* key this function returns %NULL.
*
* Return value: the user data previously attached or %NULL.
*
* Since: 1.10
**/
void *
cairo_device_get_user_data (cairo_device_t *device,
const cairo_user_data_key_t *key)
{
return _cairo_user_data_array_get_data (&device->user_data,
key);
}
 
/**
* cairo_device_set_user_data:
* @device: a #cairo_device_t
* @key: the address of a #cairo_user_data_key_t to attach the user data to
* @user_data: the user data to attach to the #cairo_device_t
* @destroy: a #cairo_destroy_func_t which will be called when the
* #cairo_t is destroyed or when new user data is attached using the
* same key.
*
* Attach user data to @device. To remove user data from a surface,
* call this function with the key that was used to set it and %NULL
* for @data.
*
* Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY if a
* slot could not be allocated for the user data.
*
* Since: 1.10
**/
cairo_status_t
cairo_device_set_user_data (cairo_device_t *device,
const cairo_user_data_key_t *key,
void *user_data,
cairo_destroy_func_t destroy)
{
if (CAIRO_REFERENCE_COUNT_IS_INVALID (&device->ref_count))
return device->status;
 
return _cairo_user_data_array_set_data (&device->user_data,
key, user_data, destroy);
}
/programs/develop/libraries/cairo/src/cairo-directfb.h
0,0 → 1,67
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2003 University of Southern California
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Carl D. Worth <cworth@isi.edu>
*/
 
/*
* Environment variables affecting the backend:
*
* %CAIRO_DIRECTFB_NO_ACCEL (boolean)
* if found, disables acceleration at all
*
* %CAIRO_DIRECTFB_ARGB_FONT (boolean)
* if found, enables using ARGB fonts instead of A8
*/
 
#ifndef CAIRO_DIRECTFB_H
#define CAIRO_DIRECTFB_H
 
#include "cairo.h"
 
#if CAIRO_HAS_DIRECTFB_SURFACE
 
#include <directfb.h>
 
CAIRO_BEGIN_DECLS
 
cairo_public cairo_surface_t *
cairo_directfb_surface_create (IDirectFB *dfb, IDirectFBSurface *surface);
 
CAIRO_END_DECLS
 
#else /*CAIRO_HAS_DIRECTFB_SURFACE*/
# error Cairo was not compiled with support for the directfb backend
#endif /*CAIRO_HAS_DIRECTFB_SURFACE*/
 
#endif /*CAIRO_DIRECTFB_H*/
/programs/develop/libraries/cairo/src/cairo-drm-xr.h
0,0 → 1,66
/* Cairo - a vector graphics library with display and print output
*
* Copyright © 2010 Intel Coropration
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Chris Wilson.
*/
 
#ifndef CAIRO_DRM_XR_H
#define CAIRO_DRM_XR_H
 
#include "cairo.h"
 
#if CAIRO_HAS_DRM_XR_FUNCTIONS
 
CAIRO_BEGIN_DECLS
 
typedef struct _xr_screen xr_screen_t;
 
cairo_public xr_screen_t *
cairo_drm_xr_enable (ScreenPtr screen, int fd);
 
cairo_public void
cairo_drm_xr_pixmap_link_bo (xr_screen_t *xr,
PixmapPtr pixmap,
uint32_t name,
cairo_format_t format,
int width,
int height,
int stride);
 
cairo_public void
cairo_drm_xr_pixmap_unlink_bo (xr_screen_t *xr,
PixmapPtr pixmap);
 
CAIRO_END_DECLS
 
#else /* CAIRO_HAS_DRM_XR_FUNCTIOSN */
# error Cairo was not compiled with support for the DRM Xr DDX functions
#endif /* CAIRO_HAS_DRM_XR_FUNCTIOSN */
 
#endif /* CAIRO_DRM_XR_H */
/programs/develop/libraries/cairo/src/cairo-drm.h
0,0 → 1,120
/* Cairo - a vector graphics library with display and print output
*
* Copyright © 2009 Chris Wilson
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Chris Wilson.
*/
 
#ifndef CAIRO_DRM_H
#define CAIRO_DRM_H
 
#include "cairo.h"
 
#if CAIRO_HAS_DRM_SURFACE
 
CAIRO_BEGIN_DECLS
 
struct udev_device;
 
cairo_public cairo_device_t *
cairo_drm_device_get (struct udev_device *device);
 
cairo_public cairo_device_t *
cairo_drm_device_get_for_fd (int fd);
 
cairo_public cairo_device_t *
cairo_drm_device_default (void);
 
cairo_public int
cairo_drm_device_get_fd (cairo_device_t *device);
 
cairo_public void
cairo_drm_device_throttle (cairo_device_t *device);
 
cairo_public cairo_surface_t *
cairo_drm_surface_create (cairo_device_t *device,
cairo_format_t format,
int width, int height);
 
cairo_public cairo_surface_t *
cairo_drm_surface_create_for_name (cairo_device_t *device,
unsigned int name,
cairo_format_t format,
int width, int height, int stride);
 
cairo_public cairo_surface_t *
cairo_drm_surface_create_from_cacheable_image (cairo_device_t *device,
cairo_surface_t *surface);
 
cairo_public cairo_status_t
cairo_drm_surface_enable_scan_out (cairo_surface_t *surface);
 
cairo_public unsigned int
cairo_drm_surface_get_handle (cairo_surface_t *surface);
 
cairo_public unsigned int
cairo_drm_surface_get_name (cairo_surface_t *surface);
 
cairo_public cairo_format_t
cairo_drm_surface_get_format (cairo_surface_t *surface);
 
cairo_public int
cairo_drm_surface_get_width (cairo_surface_t *surface);
 
cairo_public int
cairo_drm_surface_get_height (cairo_surface_t *surface);
 
cairo_public int
cairo_drm_surface_get_stride (cairo_surface_t *surface);
 
/* XXX map/unmap, general surface layer? */
 
/* Rough outline, culled from a conversation on IRC:
* map() returns an image-surface representation of the drm-surface,
* which you unmap() when you are finished, i.e. map() pulls the buffer back
* from the GPU, maps it into the CPU domain and gives you direct access to
* the pixels. With the unmap(), the buffer is ready to be used again by the
* GPU and *until* the unmap(), all operations will be done in software.
*
* (Technically calling cairo_surface_flush() on the underlying drm-surface
* will also disassociate the mapping.)
*/
cairo_public cairo_surface_t *
cairo_drm_surface_map_to_image (cairo_surface_t *surface);
 
cairo_public void
cairo_drm_surface_unmap (cairo_surface_t *drm_surface,
cairo_surface_t *image_surface);
 
CAIRO_END_DECLS
 
#else /* CAIRO_HAS_DRM_SURFACE */
# error Cairo was not compiled with support for the DRM backend
#endif /* CAIRO_HAS_DRM_SURFACE */
 
#endif /* CAIRO_DRM_H */
/programs/develop/libraries/cairo/src/cairo-error-private.h
0,0 → 1,60
/* 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., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
*/
 
#ifndef _CAIRO_ERROR_PRIVATE_H_
#define _CAIRO_ERROR_PRIVATE_H_
 
#include "cairo.h"
#include "cairo-compiler-private.h"
 
CAIRO_BEGIN_DECLS
 
#define _cairo_status_is_error(status) \
(status != CAIRO_STATUS_SUCCESS && status <= CAIRO_STATUS_LAST_STATUS)
 
cairo_private cairo_status_t
_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)
 
CAIRO_END_DECLS
 
#endif /* _CAIRO_ERROR_PRIVATE_H_ */
/programs/develop/libraries/cairo/src/cairo-features.h
0,0 → 1,27
/* Generated by configure. Do not edit. */
#ifndef CAIRO_FEATURES_H
#define CAIRO_FEATURES_H
 
#define CAIRO_HAS_IMAGE_SURFACE 1
#define CAIRO_HAS_PNG_FUNCTIONS 1
#define CAIRO_HAS_RECORDING_SURFACE 1
#define CAIRO_HAS_SVG_SURFACE 1
#define CAIRO_HAS_USER_FONT 1
 
/*#undef CAIRO_HAS_EGL_FUNCTIONS */
/*#undef CAIRO_HAS_FC_FONT */
/*#undef CAIRO_HAS_FT_FONT */
/*#undef CAIRO_HAS_GLX_FUNCTIONS */
/*#undef CAIRO_HAS_GOBJECT_FUNCTIONS */
/*#undef CAIRO_HAS_PDF_SURFACE */
/*#undef CAIRO_HAS_PS_SURFACE */
/*#undef CAIRO_HAS_QUARTZ_FONT */
/*#undef CAIRO_HAS_QUARTZ_SURFACE */
/*#undef CAIRO_HAS_WGL_FUNCTIONS */
/*#undef CAIRO_HAS_WIN32_FONT */
/*#undef CAIRO_HAS_WIN32_SURFACE */
/*#undef CAIRO_HAS_XCB_SHM_FUNCTIONS */
/*#undef CAIRO_HAS_XLIB_SURFACE */
/*#undef CAIRO_HAS_XLIB_XRENDER_SURFACE */
 
#endif
/programs/develop/libraries/cairo/src/cairo-fixed-private.h
0,0 → 1,351
/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
/* Cairo - a vector graphics library with display and print output
*
* Copyright © 2007 Mozilla Corporation
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Mozilla Foundation
*
* Contributor(s):
* Vladimir Vukicevic <vladimir@pobox.com>
*/
 
#ifndef CAIRO_FIXED_PRIVATE_H
#define CAIRO_FIXED_PRIVATE_H
 
#include "cairo-fixed-type-private.h"
 
#include "cairo-wideint-private.h"
 
/* Implementation */
 
#if (CAIRO_FIXED_BITS != 32)
# error CAIRO_FIXED_BITS must be 32, and the type must be a 32-bit type.
# error To remove this limitation, you will have to fix the tesselator.
#endif
 
#define CAIRO_FIXED_ONE ((cairo_fixed_t)(1 << CAIRO_FIXED_FRAC_BITS))
#define CAIRO_FIXED_ONE_DOUBLE ((double)(1 << CAIRO_FIXED_FRAC_BITS))
#define CAIRO_FIXED_EPSILON ((cairo_fixed_t)(1))
 
#define CAIRO_FIXED_FRAC_MASK ((cairo_fixed_t)(((cairo_fixed_unsigned_t)(-1)) >> (CAIRO_FIXED_BITS - CAIRO_FIXED_FRAC_BITS)))
#define CAIRO_FIXED_WHOLE_MASK (~CAIRO_FIXED_FRAC_MASK)
 
static inline cairo_fixed_t
_cairo_fixed_from_int (int i)
{
return i << CAIRO_FIXED_FRAC_BITS;
}
 
/* This is the "magic number" approach to converting a double into fixed
* point as described here:
*
* http://www.stereopsis.com/sree/fpu2006.html (an overview)
* http://www.d6.com/users/checker/pdfs/gdmfp.pdf (in detail)
*
* The basic idea is to add a large enough number to the double that the
* literal floating point is moved up to the extent that it forces the
* double's value to be shifted down to the bottom of the mantissa (to make
* room for the large number being added in). Since the mantissa is, at a
* given moment in time, a fixed point integer itself, one can convert a
* float to various fixed point representations by moving around the point
* of a floating point number through arithmetic operations. This behavior
* is reliable on most modern platforms as it is mandated by the IEEE-754
* standard for floating point arithmetic.
*
* For our purposes, a "magic number" must be carefully selected that is
* both large enough to produce the desired point-shifting effect, and also
* has no lower bits in its representation that would interfere with our
* value at the bottom of the mantissa. The magic number is calculated as
* follows:
*
* (2 ^ (MANTISSA_SIZE - FRACTIONAL_SIZE)) * 1.5
*
* where in our case:
* - MANTISSA_SIZE for 64-bit doubles is 52
* - FRACTIONAL_SIZE for 16.16 fixed point is 16
*
* Although this approach provides a very large speedup of this function
* on a wide-array of systems, it does come with two caveats:
*
* 1) It uses banker's rounding as opposed to arithmetic rounding.
* 2) It doesn't function properly if the FPU is in single-precision
* mode.
*/
 
/* The 16.16 number must always be available */
#define CAIRO_MAGIC_NUMBER_FIXED_16_16 (103079215104.0)
 
#if CAIRO_FIXED_BITS <= 32
#define CAIRO_MAGIC_NUMBER_FIXED ((1LL << (52 - CAIRO_FIXED_FRAC_BITS)) * 1.5)
 
/* For 32-bit fixed point numbers */
static inline cairo_fixed_t
_cairo_fixed_from_double (double d)
{
union {
double d;
int32_t i[2];
} u;
 
u.d = d + CAIRO_MAGIC_NUMBER_FIXED;
#ifdef FLOAT_WORDS_BIGENDIAN
return u.i[1];
#else
return u.i[0];
#endif
}
 
#else
# error Please define a magic number for your fixed point type!
# error See cairo-fixed-private.h for details.
#endif
 
static inline cairo_fixed_t
_cairo_fixed_from_26_6 (uint32_t i)
{
#if CAIRO_FIXED_FRAC_BITS > 6
return i << (CAIRO_FIXED_FRAC_BITS - 6);
#else
return i >> (6 - CAIRO_FIXED_FRAC_BITS);
#endif
}
 
static inline cairo_fixed_t
_cairo_fixed_from_16_16 (uint32_t i)
{
#if CAIRO_FIXED_FRAC_BITS > 16
return i << (CAIRO_FIXED_FRAC_BITS - 16);
#else
return i >> (16 - CAIRO_FIXED_FRAC_BITS);
#endif
}
 
static inline double
_cairo_fixed_to_double (cairo_fixed_t f)
{
return ((double) f) / CAIRO_FIXED_ONE_DOUBLE;
}
 
static inline int
_cairo_fixed_is_integer (cairo_fixed_t f)
{
return (f & CAIRO_FIXED_FRAC_MASK) == 0;
}
 
static inline cairo_fixed_t
_cairo_fixed_floor (cairo_fixed_t f)
{
return f & ~CAIRO_FIXED_FRAC_MASK;
}
 
static inline cairo_fixed_t
_cairo_fixed_round (cairo_fixed_t f)
{
return _cairo_fixed_floor (f + (CAIRO_FIXED_FRAC_MASK+1)/2);
}
 
static inline cairo_fixed_t
_cairo_fixed_round_down (cairo_fixed_t f)
{
return _cairo_fixed_floor (f + CAIRO_FIXED_FRAC_MASK/2);
}
 
static inline int
_cairo_fixed_integer_part (cairo_fixed_t f)
{
return f >> CAIRO_FIXED_FRAC_BITS;
}
 
static inline int
_cairo_fixed_integer_round (cairo_fixed_t f)
{
return _cairo_fixed_integer_part (f + (CAIRO_FIXED_FRAC_MASK+1)/2);
}
 
static inline int
_cairo_fixed_integer_round_down (cairo_fixed_t f)
{
return _cairo_fixed_integer_part (f + CAIRO_FIXED_FRAC_MASK/2);
}
 
static inline int
_cairo_fixed_fractional_part (cairo_fixed_t f)
{
return f & CAIRO_FIXED_FRAC_MASK;
}
 
static inline int
_cairo_fixed_integer_floor (cairo_fixed_t f)
{
if (f >= 0)
return f >> CAIRO_FIXED_FRAC_BITS;
else
return -((-f - 1) >> CAIRO_FIXED_FRAC_BITS) - 1;
}
 
static inline int
_cairo_fixed_integer_ceil (cairo_fixed_t f)
{
if (f > 0)
return ((f - 1)>>CAIRO_FIXED_FRAC_BITS) + 1;
else
return - (-f >> CAIRO_FIXED_FRAC_BITS);
}
 
/* A bunch of explicit 16.16 operators; we need these
* to interface with pixman and other backends that require
* 16.16 fixed point types.
*/
static inline cairo_fixed_16_16_t
_cairo_fixed_to_16_16 (cairo_fixed_t f)
{
#if (CAIRO_FIXED_FRAC_BITS == 16) && (CAIRO_FIXED_BITS == 32)
return f;
#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);
#else
cairo_fixed_16_16_t x;
 
/* Handle overflow/underflow by clamping to the lowest/highest
* value representable as 16.16
*/
if ((f >> CAIRO_FIXED_FRAC_BITS) < INT16_MIN) {
x = INT32_MIN;
} else if ((f >> CAIRO_FIXED_FRAC_BITS) > INT16_MAX) {
x = INT32_MAX;
} else {
x = f << (16 - CAIRO_FIXED_FRAC_BITS);
}
 
return x;
#endif
}
 
static inline cairo_fixed_16_16_t
_cairo_fixed_16_16_from_double (double d)
{
union {
double d;
int32_t i[2];
} u;
 
u.d = d + CAIRO_MAGIC_NUMBER_FIXED_16_16;
#ifdef FLOAT_WORDS_BIGENDIAN
return u.i[1];
#else
return u.i[0];
#endif
}
 
static inline int
_cairo_fixed_16_16_floor (cairo_fixed_16_16_t f)
{
if (f >= 0)
return f >> 16;
else
return -((-f - 1) >> 16) - 1;
}
 
static inline double
_cairo_fixed_16_16_to_double (cairo_fixed_16_16_t f)
{
return ((double) f) / (double) (1 << 16);
}
 
#if CAIRO_FIXED_BITS == 32
 
static inline cairo_fixed_t
_cairo_fixed_mul (cairo_fixed_t a, cairo_fixed_t b)
{
cairo_int64_t temp = _cairo_int32x32_64_mul (a, b);
return _cairo_int64_to_int32(_cairo_int64_rsl (temp, CAIRO_FIXED_FRAC_BITS));
}
 
/* computes round (a * b / c) */
static inline cairo_fixed_t
_cairo_fixed_mul_div (cairo_fixed_t a, cairo_fixed_t b, cairo_fixed_t c)
{
cairo_int64_t ab = _cairo_int32x32_64_mul (a, b);
cairo_int64_t c64 = _cairo_int32_to_int64 (c);
return _cairo_int64_to_int32 (_cairo_int64_divrem (ab, c64).quo);
}
 
/* computes floor (a * b / c) */
static inline cairo_fixed_t
_cairo_fixed_mul_div_floor (cairo_fixed_t a, cairo_fixed_t b, cairo_fixed_t c)
{
return _cairo_int64_32_div (_cairo_int32x32_64_mul (a, b), c);
}
 
 
static inline cairo_fixed_t
_cairo_edge_compute_intersection_y_for_x (const cairo_point_t *p1,
const cairo_point_t *p2,
cairo_fixed_t x)
{
cairo_fixed_t y, dx;
 
if (x == p1->x)
return p1->y;
if (x == p2->x)
return p2->y;
 
y = p1->y;
dx = p2->x - p1->x;
if (dx != 0)
y += _cairo_fixed_mul_div_floor (x - p1->x, p2->y - p1->y, dx);
 
return y;
}
 
static inline cairo_fixed_t
_cairo_edge_compute_intersection_x_for_y (const cairo_point_t *p1,
const cairo_point_t *p2,
cairo_fixed_t y)
{
cairo_fixed_t x, dy;
 
if (y == p1->y)
return p1->x;
if (y == p2->y)
return p2->x;
 
x = p1->x;
dy = p2->y - p1->y;
if (dy != 0)
x += _cairo_fixed_mul_div_floor (y - p1->y, p2->x - p1->x, dy);
 
return x;
}
 
#else
# error Please define multiplication and other operands for your fixed-point type size
#endif
 
#endif /* CAIRO_FIXED_PRIVATE_H */
/programs/develop/libraries/cairo/src/cairo-fixed-type-private.h
0,0 → 1,75
/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
/* Cairo - a vector graphics library with display and print output
*
* Copyright © 2007 Mozilla Corporation
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Mozilla Foundation
*
* Contributor(s):
* Vladimir Vukicevic <vladimir@pobox.com>
*/
 
#ifndef CAIRO_FIXED_TYPE_PRIVATE_H
#define CAIRO_FIXED_TYPE_PRIVATE_H
 
#include "cairo-wideint-type-private.h"
 
/*
* Fixed-point configuration
*/
 
typedef int32_t cairo_fixed_16_16_t;
typedef cairo_int64_t cairo_fixed_32_32_t;
typedef cairo_int64_t cairo_fixed_48_16_t;
typedef cairo_int128_t cairo_fixed_64_64_t;
typedef cairo_int128_t cairo_fixed_96_32_t;
 
/* Eventually, we should allow changing this, but I think
* there are some assumptions in the tesselator about the
* size of a fixed type. For now, it must be 32.
*/
#define CAIRO_FIXED_BITS 32
 
/* 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
 
/* A signed type %CAIRO_FIXED_BITS in size; the main fixed point type */
typedef int32_t cairo_fixed_t;
 
/* An unsigned type of the same size as #cairo_fixed_t */
typedef uint32_t cairo_fixed_unsigned_t;
 
typedef struct _cairo_point {
cairo_fixed_t x;
cairo_fixed_t y;
} cairo_point_t;
 
#endif /* CAIRO_FIXED_TYPE_PRIVATE_H */
/programs/develop/libraries/cairo/src/cairo-fixed.c
0,0 → 1,39
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2003 University of Southern California
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
*/
 
#include "cairoint.h"
 
#include "cairo-fixed-private.h"
/programs/develop/libraries/cairo/src/cairo-font-face-twin-data.c
0,0 → 1,1072
/* See cairo-font-face-twin.c for copyright info */
 
#include "cairoint.h"
 
const int8_t _cairo_twin_outlines[] = {
/* 0x0 '\0' offset 0 */
0, 24, 42, 0, 2, 2,
0, 24, /* snap_x */
-42, 0, /* snap_y */
'm', 0, 0,
'l', 0, -42,
'l', 24, -42,
'l', 24, 0,
'l', 0, 0,
'e',
'X', 'X',
/* 0x20 ' ' offset 28 */
0, 4, 0, 0, 0, 0,
/* snap_x */
/* snap_y */
'e',
'X', 'X', 'X',
'X', 'X',
/* 0x21 '!' offset 40 */
0, 0, 42, 0, 1, 3,
0, /* snap_x */
-42, -14, 0, /* snap_y */
'm', 0, -42,
'l', 0, -14,
'm', 0, 0,
'l', 0, 0,
'e',
'X', 'X', 'X', 'X', 'X', 'X',
'X', 'X', 'X', 'X', 'X', 'X',
'X', 'X', 'X', 'X', 'X', 'X',
'X', 'X', 'X', 'X', 'X', 'X',
'X', 'X', 'X',
/* 0x22 '"' offset 90 */
0, 16, 42, -28, 2, 2,
0, 16, /* snap_x */
-42, -28, /* snap_y */
'm', 0, -42,
'l', 0, -28,
'm', 16, -42,
'l', 16, -28,
'e',
'X',
/* 0x23 '#' offset 114 */
0, 30, 50, 14, 2, 5,
0, 30, /* snap_x */
-24, -21, -15, -12, 0, /* snap_y */
'm', 16, -50,
'l', 2, 14,
'm', 28, -50,
'l', 14, 14,
'm', 2, -24,
'l', 30, -24,
'm', 0, -12,
'l', 28, -12,
'e',
/* 0x24 '$' offset 152 */
0, 28, 50, 8, 4, 4,
0, 10, 18, 28, /* snap_x */
-42, -21, -15, 0, /* snap_y */
'm', 10, -50,
'l', 10, 8,
'm', 18, -50,
'l', 18, 8,
'm', 28, -36,
'c', 24, -42, 18, -42, 14, -42,
'c', 10, -42, 0, -42, 0, -34,
'c', 0, -25, 8, -24, 14, -22,
'c', 20, -20, 28, -19, 28, -9,
'c', 28, 0, 18, 0, 14, 0,
'c', 10, 0, 4, 0, 0, -6,
'e',
/* 0x25 '%' offset 224 */
0, 36, 42, 0, 4, 7,
0, 14, 22, 36, /* snap_x */
-42, -38, -28, -21, -15, -14, 0, /* snap_y */
'm', 10, -42,
'c', 12, -41, 14, -40, 14, -36,
'c', 14, -30, 11, -28, 6, -28,
'c', 2, -28, 0, -30, 0, -34,
'c', 0, -39, 3, -42, 8, -42,
'l', 10, -42,
'c', 18, -37, 28, -37, 36, -42,
'l', 0, 0,
'm', 28, -14,
'c', 24, -14, 22, -11, 22, -6,
'c', 22, -2, 24, 0, 28, 0,
'c', 33, 0, 36, -2, 36, -8,
'c', 36, -12, 34, -14, 30, -14,
'l', 28, -14,
'e',
'X', 'X', 'X',
/* 0x26 '&' offset 323 */
0, 40, 42, 0, 4, 4,
0, 10, 22, 40, /* snap_x */
-28, -21, -15, 0, /* snap_y */
'm', 40, -24,
'c', 40, -27, 39, -28, 37, -28,
'c', 29, -28, 32, 0, 12, 0,
'c', 0, 0, 0, -8, 0, -10,
'c', 0, -24, 22, -20, 22, -34,
'c', 22, -45, 10, -45, 10, -34,
'c', 10, -27, 25, 0, 36, 0,
'c', 39, 0, 40, -1, 40, -4,
'e',
/* 0x27 ''' offset 390 */
0, 4, 42, -30, 2, 2,
0, 4, /* snap_x */
-42, -28, /* snap_y */
'm', 2, -38,
'c', -1, -38, -1, -42, 2, -42,
'c', 6, -42, 5, -33, 0, -30,
'e',
'X',
/* 0x28 '(' offset 419 */
0, 14, 50, 14, 2, 2,
0, 14, /* snap_x */
-50, 14, /* snap_y */
'm', 14, -50,
'c', -5, -32, -5, -5, 14, 14,
'e',
'X',
/* 0x29 ')' offset 441 */
0, 14, 50, 14, 2, 2,
0, 14, /* snap_x */
-15, 14, /* snap_y */
'm', 0, -50,
'c', 19, -34, 19, -2, 0, 14,
'e',
'X',
/* 0x2a '*' offset 463 */
0, 20, 30, -6, 3, 3,
0, 10, 20, /* snap_x */
-21, -15, 0, /* snap_y */
'm', 10, -30,
'l', 10, -6,
'm', 0, -24,
'l', 20, -12,
'm', 20, -24,
'l', 0, -12,
'e',
/* 0x2b '+' offset 494 */
0, 36, 36, 0, 3, 4,
0, 18, 36, /* snap_x */
-21, -18, -15, 0, /* snap_y */
'm', 18, -36,
'l', 18, 0,
'm', 0, -18,
'l', 36, -18,
'e',
/* 0x2c ',' offset 520 */
0, 4, 4, 8, 2, 3,
0, 4, /* snap_x */
-21, -15, 0, /* snap_y */
'm', 4, -2,
'c', 4, 1, 0, 1, 0, -2,
'c', 0, -5, 4, -5, 4, -2,
'c', 4, 4, 2, 6, 0, 8,
'e',
/* 0x2d '-' offset 556 */
0, 36, 18, -18, 2, 4,
0, 36, /* snap_x */
-21, -18, -15, 0, /* snap_y */
'm', 0, -18,
'l', 36, -18,
'e',
/* 0x2e '.' offset 575 */
0, 4, 4, 0, 2, 3,
0, 4, /* snap_x */
-21, -15, 0, /* snap_y */
'm', 2, -4,
'c', -1, -4, -1, 0, 2, 0,
'c', 5, 0, 5, -4, 2, -4,
'e',
/* 0x2f '/' offset 604 */
0, 36, 50, 14, 2, 3,
0, 36, /* snap_x */
-21, -15, 0, /* snap_y */
'm', 36, -50,
'l', 0, 14,
'e',
/* 0x30 '0' offset 622 */
0, 28, 42, 0, 2, 4,
0, 28, /* snap_x */
-42, -21, -15, 0, /* snap_y */
'm', 14, -42,
'c', 9, -42, 0, -42, 0, -21,
'c', 0, 0, 9, 0, 14, 0,
'c', 19, 0, 28, 0, 28, -21,
'c', 28, -42, 19, -42, 14, -42,
'E',
/* 0x31 '1' offset 666 */
0, 28, 42, 0, 2, 3,
0, 17, 28 /* snap_x */
-42, -34, 0, /* snap_y */
'm', 7, -34,
'c', 11, -35, 15, -38, 17, -42,
'l', 17, 0,
'e',
/* 0x32 '2' offset 691 */
0, 28, 42, 0, 4, 4,
0, 2, 26, 28, /* snap_x */
-42, -21, -15, 0, /* snap_y */
'm', 2, -32,
'c', 2, -34, 2, -42, 14, -42,
'c', 26, -42, 26, -34, 26, -32,
'c', 26, -30, 25, -25, 10, -10,
'l', 0, 0,
'l', 28, 0,
'e',
/* 0x33 '3' offset 736 */
0, 28, 42, 0, 2, 5,
0, 28, /* snap_x */
-42, -26, -21, -15, 0, /* snap_y */
'm', 4, -42,
'l', 26, -42,
'l', 14, -26,
'c', 21, -26, 28, -26, 28, -14,
'c', 28, 0, 17, 0, 13, 0,
'c', 8, 0, 3, -1, 0, -8,
'e',
/* 0x34 '4' offset 780 */
0, 28, 42, 0, 3, 3,
0, 20, 30, /* snap_x */
-42, -14, 0, /* snap_y */
'm', 20, 0,
'l', 20, -42,
'l', 0, -14,
'l', 30, -14,
'e',
'X', 'X', 'X',
'X',
/* 0x35 '5' offset 809 */
0, 28, 42, 0, 2, 5,
0, 28, /* snap_x */
-42, -28, -21, -15, 0, /* snap_y */
'm', 24, -42,
'l', 4, -42,
'l', 2, -24,
'c', 5, -27, 10, -28, 13, -28,
'c', 16, -28, 28, -28, 28, -14,
'c', 28, 0, 16, 0, 13, 0,
'c', 10, 0, 3, 0, 0, -8,
'e',
/* 0x36 '6' offset 860 */
0, 28, 42, 0, 2, 5,
0, 26, /* snap_x */
-42, -26, -21, -15, 0, /* snap_y */
'm', 24, -36,
'c', 22, -41, 19, -42, 14, -42,
'c', 9, -42, 0, -41, 0, -19,
'c', 0, -1, 9, 0, 13, 0,
'c', 18, 0, 26, -3, 26, -13,
'c', 26, -18, 23, -26, 13, -26,
'c', 10, -26, 1, -24, 0, -14,
'e',
/* 0x37 '7' offset 919 */
0, 28, 42, 0, 2, 4,
0, 28, /* snap_x */
-42, -21, -15, 0, /* snap_y */
'm', 0, -42,
'l', 28, -42,
'l', 8, 0,
'e',
'X', 'X', 'X',
/* 0x38 '8' offset 944 */
0, 28, 42, 0, 4, 4,
0, 2, 26, 28, /* snap_x */
-42, -21, -15, 0, /* snap_y */
'm', 14, -42,
'c', 5, -42, 2, -40, 2, -34,
'c', 2, -18, 28, -32, 28, -11,
'c', 28, 0, 18, 0, 14, 0,
'c', 10, 0, 0, 0, 0, -11,
'c', 0, -32, 26, -18, 26, -34,
'c', 26, -40, 23, -42, 14, -42,
'E',
/* 0x39 '9' offset 1004 */
0, 28, 42, 0, 2, 5,
0, 26, /* snap_x */
-42, -21, -16, -15, 0, /* snap_y */
'm', 26, -28,
'c', 25, -16, 13, -16, 13, -16,
'c', 8, -16, 0, -19, 0, -29,
'c', 0, -34, 3, -42, 13, -42,
'c', 24, -42, 26, -32, 26, -23,
'c', 26, -14, 24, 0, 12, 0,
'c', 7, 0, 4, -2, 2, -6,
'e',
/* 0x3a ':' offset 1063 */
0, 4, 28, 0, 2, 3,
0, 4, /* snap_x */
-21, -15, 0, /* snap_y */
'm', 2, -28,
'c', -1, -28, -1, -24, 2, -24,
'c', 5, -24, 5, -28, 2, -28,
'm', 2, -4,
'c', -1, -4, -1, 0, 2, 0,
'c', 5, 0, 5, -4, 2, -4,
'e',
/* 0x3b ';' offset 1109 */
0, 4, 28, 8, 2, 3,
0, 4, /* snap_x */
-21, -15, 0, /* snap_y */
'm', 2, -28,
'c', -1, -28, -1, -24, 2, -24,
'c', 5, -24, 5, -28, 2, -28,
'm', 4, -2,
'c', 4, 1, 0, 1, 0, -2,
'c', 0, -5, 4, -5, 4, -2,
'c', 4, 3, 2, 6, 0, 8,
'e',
/* 0x3c '<' offset 1162 */
0, 32, 36, 0, 2, 3,
0, 32, /* snap_x */
-36, -18, 0, /* snap_y */
'm', 32, -36,
'l', 0, -18,
'l', 32, 0,
'e',
/* 0x3d '=' offset 1183 */
0, 36, 24, -12, 2, 2,
0, 36, /* snap_x */
-24, -15, /* snap_y */
'm', 0, -24,
'l', 36, -24,
'm', 0, -12,
'l', 36, -12,
'e',
'X', 'X', 'X',
/* 0x3e '>' offset 1209 */
0, 32, 36, 0, 2, 3,
0, 32, /* snap_x */
-36, -18, 0, /* snap_y */
'm', 0, -36,
'l', 32, -18,
'l', 0, 0,
'e',
/* 0x3f '?' offset 1230 */
0, 24, 42, 0, 3, 4,
0, 12, 24, /* snap_x */
-42, -21, -15, 0, /* snap_y */
'm', 0, -32,
'c', 0, -34, 0, -42, 12, -42,
'c', 24, -42, 24, -34, 24, -32,
'c', 24, -29, 24, -24, 12, -20,
'l', 12, -14,
'm', 12, 0,
'l', 12, 0,
'e',
'X', 'X', 'X',
'X', 'X', 'X',
'X', 'X', 'X',
'X', 'X',
/* 0x40 '@' offset 1288 */
0, 42, 42, 0, 1, 6,
30, /* snap_x */
-42, -32, -21, -15, -10, 0, /* snap_y */
'm', 30, -26,
'c', 28, -31, 24, -32, 21, -32,
'c', 10, -32, 10, -23, 10, -19,
'c', 10, -13, 11, -10, 19, -10,
'c', 30, -10, 28, -21, 30, -32,
'c', 27, -10, 30, -10, 34, -10,
'c', 41, -10, 42, -19, 42, -22,
'c', 42, -34, 34, -42, 21, -42,
'c', 9, -42, 0, -34, 0, -21,
'c', 0, -9, 8, 0, 21, 0,
'c', 30, 0, 34, -3, 36, -6,
'e',
/* 0x41 'A' offset 1375 */
0, 32, 42, 0, 2, 3,
0, 32, /* snap_x */
-42, -14, 0, /* snap_y */
'm', 0, 0,
'l', 16, -42,
'l', 32, 0,
'm', 6, -14,
'l', 26, -14,
'e',
'X', 'X', 'X',
'X',
/* 0x42 'B' offset 1406 */
0, 28, 42, 0, 2, 3,
0, 28, /* snap_x */
-42, -22, 0, /* snap_y */
'm', 0, 0,
'l', 0, -42,
'l', 18, -42,
'c', 32, -42, 32, -22, 18, -22,
'l', 0, -22,
'l', 18, -22,
'c', 32, -22, 32, 0, 18, 0,
'E',
'X', 'X', 'X',
'X', 'X', 'X',
'X', 'X',
/* 0x43 'C' offset 1455 */
0, 30, 42, 0, 2, 4,
0, 30, /* snap_x */
-42, -21, -15, 0, /* snap_y */
'm', 30, -32,
'c', 26, -42, 21, -42, 16, -42,
'c', 2, -42, 0, -29, 0, -21,
'c', 0, -13, 2, 0, 16, 0,
'c', 21, 0, 26, 0, 30, -10,
'e',
/* 0x44 'D' offset 1499 */
0, 28, 42, 0, 2, 2,
0, 28, /* snap_x */
-42, 0, /* snap_y */
'm', 0, 0,
'l', 0, -42,
'l', 14, -42,
'c', 33, -42, 33, 0, 14, 0,
'E',
'X', 'X', 'X',
'X', 'X', 'X',
'X', 'X',
/* 0x45 'E' offset 1534 */
0, 26, 42, 0, 2, 3,
0, 26, /* snap_x */
-42, -22, 0, /* snap_y */
'm', 26, -42,
'l', 0, -42,
'l', 0, 0,
'l', 26, 0,
'm', 0, -22,
'l', 16, -22,
'e',
'X', 'X', 'X',
'X', 'X', 'X',
'X', 'X',
/* 0x46 'F' offset 1572 */
0, 26, 42, 0, 2, 3,
0, 26, /* snap_x */
-42, -22, 0, /* snap_y */
'm', 0, 0,
'l', 0, -42,
'l', 26, -42,
'm', 0, -22,
'l', 16, -22,
'e',
'X', 'X', 'X',
'X', 'X',
/* 0x47 'G' offset 1604 */
0, 30, 42, 0, 2, 5,
0, 30, /* snap_x */
-42, -21, -16, -15, 0, /* snap_y */
'm', 30, -32,
'c', 26, -42, 21, -42, 16, -42,
'c', 2, -42, 0, -29, 0, -21,
'c', 0, -13, 2, 0, 16, 0,
'c', 28, 0, 30, -7, 30, -16,
'l', 20, -16,
'e',
'X', 'X', 'X',
/* 0x48 'H' offset 1655 */
0, 28, 42, 0, 2, 3,
0, 28, /* snap_x */
-42, -22, 0, /* snap_y */
'm', 0, -42,
'l', 0, 0,
'm', 28, -42,
'l', 28, 0,
'm', 0, -22,
'l', 28, -22,
'e',
'X',
/* 0x49 'I' offset 1686 */
0, 0, 42, 0, 1, 2,
0, /* snap_x */
-42, 0, /* snap_y */
'm', 0, -42,
'l', 0, 0,
'e',
'X',
/* 0x4a 'J' offset 1703 */
0, 20, 42, 0, 2, 3,
0, 20, /* snap_x */
-42, -15, 0, /* snap_y */
'm', 20, -42,
'l', 20, -10,
'c', 20, 3, 0, 3, 0, -10,
'l', 0, -14,
'e',
/* 0x4b 'K' offset 1731 */
0, 28, 42, 0, 2, 3,
0, 28, /* snap_x */
-42, -15, 0, /* snap_y */
'm', 0, -42,
'l', 0, 0,
'm', 28, -42,
'l', 0, -14,
'm', 10, -24,
'l', 28, 0,
'e',
/* 0x4c 'L' offset 1761 */
0, 24, 42, 0, 2, 2,
0, 24, /* snap_x */
-42, 0, /* snap_y */
'm', 0, -42,
'l', 0, 0,
'l', 24, 0,
'e',
'X', 'X', 'X',
'X',
/* 0x4d 'M' offset 1785 */
0, 32, 42, 0, 2, 2,
0, 32, /* snap_x */
-42, 0, /* snap_y */
'm', 0, 0,
'l', 0, -42,
'l', 16, 0,
'l', 32, -42,
'l', 32, 0,
'e',
'X', 'X', 'X',
'X', 'X', 'X',
'X', 'X', 'X',
'X',
/* 0x4e 'N' offset 1821 */
0, 28, 42, 0, 2, 2,
0, 28, /* snap_x */
-42, 0, /* snap_y */
'm', 0, 0,
'l', 0, -42,
'l', 28, 0,
'l', 28, -42,
'e',
'X', 'X', 'X',
'X', 'X', 'X',
'X',
/* 0x4f 'O' offset 1851 */
0, 32, 42, 0, 2, 4,
0, 32, /* snap_x */
-42, -21, -15, 0, /* snap_y */
'm', 16, -42,
'c', 2, -42, 0, -29, 0, -21,
'c', 0, -13, 2, 0, 16, 0,
'c', 30, 0, 32, -13, 32, -21,
'c', 32, -29, 30, -42, 16, -42,
'E',
/* 0x50 'P' offset 1895 */
0, 28, 42, 0, 2, 5,
0, 28, /* snap_x */
-42, -21, -20, -15, 0, /* snap_y */
'm', 0, 0,
'l', 0, -42,
'l', 18, -42,
'c', 32, -42, 32, -20, 18, -20,
'l', 0, -20,
'e',
'X', 'X', 'X',
/* 0x51 'Q' offset 1931 */
0, 32, 42, 4, 2, 4,
0, 32, /* snap_x */
-42, -21, -15, 0, /* snap_y */
'm', 16, -42,
'c', 2, -42, 0, -29, 0, -21,
'c', 0, -13, 2, 0, 16, 0,
'c', 30, 0, 32, -13, 32, -21,
'c', 32, -29, 30, -42, 16, -42,
'M', 18, -8,
'l', 30, 4,
'e',
/* 0x52 'R' offset 1981 */
0, 28, 42, 0, 2, 5,
0, 28, /* snap_x */
-42, -22, -21, -15, 0, /* snap_y */
'm', 0, 0,
'l', 0, -42,
'l', 18, -42,
'c', 32, -42, 31, -22, 18, -22,
'l', 0, -22,
'm', 14, -22,
'l', 28, 0,
'e',
'X', 'X', 'X',
/* 0x53 'S' offset 2023 */
0, 28, 42, 0, 2, 4,
0, 28, /* snap_x */
-42, -21, -15, 0, /* snap_y */
'm', 28, -36,
'c', 25, -41, 21, -42, 14, -42,
'c', 10, -42, 0, -42, 0, -34,
'c', 0, -17, 28, -28, 28, -9,
'c', 28, 0, 19, 0, 14, 0,
'c', 7, 0, 3, -1, 0, -6,
'e',
/* 0x54 'T' offset 2074 */
0, 28, 42, 0, 3, 4,
0, 14, 28, /* snap_x */
-42, -21, -15, 0, /* snap_y */
'm', 14, -42,
'l', 14, 0,
'm', 0, -42,
'l', 28, -42,
'e',
/* 0x55 'U' offset 2100 */
0, 28, 42, 0, 2, 2,
0, 28, /* snap_x */
-42, 0, /* snap_y */
'm', 0, -42,
'l', 0, -12,
'c', 0, 4, 28, 4, 28, -12,
'l', 28, -42,
'e',
'X',
/* 0x56 'V' offset 2128 */
0, 32, 42, 0, 2, 2,
0, 32, /* snap_x */
-42, 0, /* snap_y */
'm', 0, -42,
'l', 16, 0,
'l', 32, -42,
'e',
'X', 'X', 'X',
'X',
/* 0x57 'W' offset 2152 */
0, 40, 42, 0, 2, 2,
0, 40, /* snap_x */
-42, 0, /* snap_y */
'm', 0, -42,
'l', 10, 0,
'l', 20, -42,
'l', 30, 0,
'l', 40, -42,
'e',
'X', 'X', 'X',
'X', 'X', 'X',
'X', 'X', 'X',
'X',
/* 0x58 'X' offset 2188 */
0, 28, 42, 0, 2, 2,
0, 28, /* snap_x */
-42, 0, /* snap_y */
'm', 0, -42,
'l', 28, 0,
'm', 28, -42,
'l', 0, 0,
'e',
'X',
/* 0x59 'Y' offset 2212 */
0, 32, 42, 0, 3, 3,
0, 16, 32, /* snap_x */
-42, -21, 0, /* snap_y */
'm', 0, -42,
'l', 16, -22,
'l', 16, 0,
'm', 32, -42,
'l', 16, -22,
'e',
/* 0x5a 'Z' offset 2240 */
0, 28, 42, 0, 2, 4,
0, 28, /* snap_x */
-42, -21, -15, 0, /* snap_y */
'm', 28, 0,
'l', 0, 0,
'l', 28, -42,
'l', 0, -42,
'e',
'X', 'X', 'X',
'X', 'X', 'X',
/* 0x5b '[' offset 2271 */
0, 14, 44, 0, 2, 4,
0, 14, /* snap_x */
-44, -21, -15, 0, /* snap_y */
'm', 14, -44,
'l', 0, -44,
'l', 0, 0,
'l', 14, 0,
'e',
/* 0x5c '\' offset 2296 */
0, 36, 50, 14, 2, 3,
0, 36, /* snap_x */
-21, -15, 0, /* snap_y */
'm', 0, -50,
'l', 36, 14,
'e',
/* 0x5d ']' offset 2314 */
0, 14, 44, 0, 2, 4,
0, 14, /* snap_x */
-44, -21, -15, 0, /* snap_y */
'm', 0, -44,
'l', 14, -44,
'l', 14, 0,
'l', 0, 0,
'e',
/* 0x5e '^' offset 2339 */
0, 32, 46, -18, 2, 3,
0, 32, /* snap_x */
-21, -15, 0, /* snap_y */
'm', 0, -18,
'l', 16, -46,
'l', 32, -18,
'e',
'X', 'X', 'X',
/* 0x5f '_' offset 2363 */
0, 36, 0, 0, 2, 1,
0, 36, /* snap_x */
0, /* snap_y */
'm', 0, 0,
'l', 36, 0,
'e',
'X', 'X',
/* 0x60 '`' offset 2381 */
0, 4, 42, -30, 2, 2,
0, 4, /* snap_x */
-42, 0, /* snap_y */
'm', 4, -42,
'c', 2, -40, 0, -39, 0, -32,
'c', 0, -31, 1, -30, 2, -30,
'c', 5, -30, 5, -34, 2, -34,
'e',
'X',
/* 0x61 'a' offset 2417 */
0, 24, 28, 0, 2, 4,
0, 24, /* snap_x */
-28, -21, -15, 0, /* snap_y */
'm', 24, -28,
'l', 24, 0,
'm', 24, -22,
'c', 21, -27, 18, -28, 13, -28,
'c', 2, -28, 0, -19, 0, -14,
'c', 0, -9, 2, 0, 13, 0,
'c', 18, 0, 21, -1, 24, -6,
'e',
/* 0x62 'b' offset 2467 */
0, 24, 42, 0, 2, 4,
0, 24, /* snap_x */
-42, -28, -15, 0, /* snap_y */
'm', 0, -42,
'l', 0, 0,
'm', 0, -22,
'c', 3, -26, 6, -28, 11, -28,
'c', 22, -28, 24, -19, 24, -14,
'c', 24, -9, 22, 0, 11, 0,
'c', 6, 0, 3, -2, 0, -6,
'e',
/* 0x63 'c' offset 2517 */
0, 24, 28, 0, 2, 4,
0, 24, /* snap_x */
-28, -21, -15, 0, /* snap_y */
'm', 24, -22,
'c', 21, -26, 18, -28, 13, -28,
'c', 2, -28, 0, -19, 0, -14,
'c', 0, -9, 2, 0, 13, 0,
'c', 18, 0, 21, -2, 24, -6,
'e',
/* 0x64 'd' offset 2561 */
0, 24, 42, 0, 2, 4,
0, 24, /* snap_x */
-42, -28, -15, 0, /* snap_y */
'm', 24, -42,
'l', 24, 0,
'm', 24, -22,
'c', 21, -26, 18, -28, 13, -28,
'c', 2, -28, 0, -19, 0, -14,
'c', 0, -9, 2, 0, 13, 0,
'c', 18, 0, 21, -2, 24, -6,
'e',
/* 0x65 'e' offset 2611 */
0, 24, 28, 0, 2, 5,
0, 24, /* snap_x */
-28, -21, -16, -15, 0, /* snap_y */
'm', 0, -16,
'l', 24, -16,
'c', 24, -20, 24, -28, 13, -28,
'c', 2, -28, 0, -19, 0, -14,
'c', 0, -9, 2, 0, 13, 0,
'c', 18, 0, 21, -2, 24, -6,
'e',
/* 0x66 'f' offset 2659 */
0, 16, 42, 0, 3, 5,
0, 6, 16, /* snap_x */
-42, -28, -21, -15, 0, /* snap_y */
'm', 16, -42,
'c', 8, -42, 6, -40, 6, -34,
'l', 6, 0,
'm', 0, -28,
'l', 14, -28,
'e',
/* 0x67 'g' offset 2693 */
0, 24, 28, 14, 2, 5,
0, 24, /* snap_x */
-28, -21, -15, 0, 14, /* snap_y */
'm', 24, -28,
'l', 24, 4,
'c', 23, 14, 16, 14, 13, 14,
'c', 10, 14, 8, 14, 6, 12,
'm', 24, -22,
'c', 21, -26, 18, -28, 13, -28,
'c', 2, -28, 0, -19, 0, -14,
'c', 0, -9, 2, 0, 13, 0,
'c', 18, 0, 21, -2, 24, -6,
'e',
/* 0x68 'h' offset 2758 */
0, 22, 42, 0, 2, 4,
0, 22, /* snap_x */
-42, -28, -15, 0, /* snap_y */
'm', 0, -42,
'l', 0, 0,
'm', 0, -20,
'c', 8, -32, 22, -31, 22, -20,
'l', 22, 0,
'e',
/* 0x69 'i' offset 2790 */
0, 0, 44, 0, 1, 3,
0, /* snap_x */
-42, -28, 0, /* snap_y */
'm', 0, -42,
'l', 0, -42,
'm', 0, -28,
'l', 0, 0,
'e',
'X', 'X', 'X',
'X', 'X', 'X',
'X', 'X', 'X',
'X', 'X',
'X', 'X',
/* 0x6a 'j' offset 2826 */
-8, 4, 44, 14, 3, 5,
-8, 2, 4, /* snap_x */
-42, -21, -15, 0, 14, /* snap_y */
'm', 2, -42,
'l', 2, -42,
'm', 2, -28,
'l', 2, 6,
'c', 2, 13, -1, 14, -8, 14,
'e',
'X', 'X', 'X',
'X', 'X', 'X',
'X', 'X', 'X',
'X',
/* 0x6b 'k' offset 2870 */
0, 22, 42, 0, 2, 3,
0, 22, /* snap_x */
-42, -28, 0, /* snap_y */
'm', 0, -42,
'l', 0, 0,
'm', 20, -28,
'l', 0, -8,
'm', 8, -16,
'l', 22, 0,
'e',
/* 0x6c 'l' offset 2900 */
0, 0, 42, 0, 1, 2,
0, /* snap_x */
-42, 0, /* snap_y */
'm', 0, -42,
'l', 0, 0,
'e',
'X',
/* 0x6d 'm' offset 2917 */
0, 44, 28, 0, 3, 3,
0, 22, 44, /* snap_x */
-28, -21, 0, /* snap_y */
'm', 0, -28,
'l', 0, 0,
'm', 0, -20,
'c', 5, -29, 22, -33, 22, -20,
'l', 22, 0,
'm', 22, -20,
'c', 27, -29, 44, -33, 44, -20,
'l', 44, 0,
'e',
'X',
/* 0x6e 'n' offset 2963 */
0, 22, 28, 0, 2, 3,
0, 22, /* snap_x */
-28, -21, 0, /* snap_y */
'm', 0, -28,
'l', 0, 0,
'm', 0, -20,
'c', 4, -28, 22, -34, 22, -20,
'l', 22, 0,
'e',
'X',
/* 0x6f 'o' offset 2995 */
0, 26, 28, 0, 2, 4,
0, 26, /* snap_x */
-28, -21, -15, 0, /* snap_y */
'm', 13, -28,
'c', 2, -28, 0, -19, 0, -14,
'c', 0, -9, 2, 0, 13, 0,
'c', 24, 0, 26, -9, 26, -14,
'c', 26, -19, 24, -28, 13, -28,
'E',
/* 0x70 'p' offset 3039 */
0, 24, 28, 14, 2, 4,
0, 24, /* snap_x */
-28, -21, 0, 14, /* snap_y */
'm', 0, -28,
'l', 0, 14,
'm', 0, -22,
'c', 3, -26, 6, -28, 11, -28,
'c', 22, -28, 24, -19, 24, -14,
'c', 24, -9, 22, 0, 11, 0,
'c', 6, 0, 3, -2, 0, -6,
'e',
/* 0x71 'q' offset 3089 */
0, 24, 28, 14, 2, 4,
0, 24, /* snap_x */
-28, -21, 0, 14, /* snap_y */
'm', 24, -28,
'l', 24, 14,
'm', 24, -22,
'c', 21, -26, 18, -28, 13, -28,
'c', 2, -28, 0, -19, 0, -14,
'c', 0, -9, 2, 0, 13, 0,
'c', 18, 0, 21, -2, 24, -6,
'e',
/* 0x72 'r' offset 3139 */
0, 16, 28, 0, 2, 4,
0, 16, /* snap_x */
-28, -21, -15, 0, /* snap_y */
'm', 0, -28,
'l', 0, 0,
'm', 0, -16,
'c', 2, -27, 7, -28, 16, -28,
'e',
/* 0x73 's' offset 3168 */
0, 22, 28, 0, 2, 4,
0, 22, /* snap_x */
-28, -21, -15, 0, /* snap_y */
'm', 22, -22,
'c', 22, -27, 16, -28, 11, -28,
'c', 4, -28, 0, -26, 0, -22,
'c', 0, -11, 22, -20, 22, -7,
'c', 22, 0, 17, 0, 11, 0,
'c', 6, 0, 0, -1, 0, -6,
'e',
/* 0x74 't' offset 3219 */
0, 16, 42, 0, 3, 4,
0, 6, 16, /* snap_x */
-42, -28, -21, 0, /* snap_y */
'm', 6, -42,
'l', 6, -8,
'c', 6, -2, 8, 0, 16, 0,
'm', 0, -28,
'l', 14, -28,
'e',
/* 0x75 'u' offset 3252 */
0, 22, 28, 0, 2, 3,
0, 22, /* snap_x */
-28, -15, 0, /* snap_y */
'm', 0, -28,
'l', 0, -8,
'c', 0, 6, 18, 0, 22, -8,
'm', 22, -28,
'l', 22, 0,
'e',
/* 0x76 'v' offset 3283 */
0, 24, 28, 0, 2, 3,
0, 24, /* snap_x */
-28, -15, 0, /* snap_y */
'm', 0, -28,
'l', 12, 0,
'l', 24, -28,
'e',
'X', 'X', 'X',
/* 0x77 'w' offset 3307 */
0, 32, 28, 0, 2, 3,
0, 32, /* snap_x */
-28, -15, 0, /* snap_y */
'm', 0, -28,
'l', 8, 0,
'l', 16, -28,
'l', 24, 0,
'l', 32, -28,
'e',
'X', 'X', 'X',
'X', 'X', 'X',
'X', 'X', 'X',
/* 0x78 'x' offset 3343 */
0, 22, 28, 0, 2, 2,
0, 22, /* snap_x */
-28, 0, /* snap_y */
'm', 0, -28,
'l', 22, 0,
'm', 22, -28,
'l', 0, 0,
'e',
'X',
/* 0x79 'y' offset 3367 */
-2, 24, 28, 14, 2, 4,
0, 24, /* snap_x */
-28, -15, 0, 14, /* snap_y */
'm', 0, -28,
'l', 12, 0,
'm', 24, -28,
'l', 12, 0,
'c', 6, 13, 0, 14, -2, 14,
'e',
/* 0x7a 'z' offset 3399 */
0, 22, 28, 0, 2, 4,
0, 22, /* snap_x */
-28, -21, -15, 0, /* snap_y */
'm', 22, 0,
'l', 0, 0,
'l', 22, -28,
'l', 0, -28,
'e',
'X', 'X', 'X',
'X', 'X', 'X',
/* 0x7b '{' offset 3430 */
0, 16, 44, 0, 3, 5,
0, 6, 16, /* snap_x */
-44, -24, -21, -15, 0, /* snap_y */
'm', 16, -44,
'c', 10, -44, 6, -42, 6, -36,
'l', 6, -24,
'l', 0, -24,
'l', 6, -24,
'l', 6, -8,
'c', 6, -2, 10, 0, 16, 0,
'e',
/* 0x7c '|' offset 3474 */
0, 0, 50, 14, 1, 2,
0, /* snap_x */
-50, 14, /* snap_y */
'm', 0, -50,
'l', 0, 14,
'e',
'X',
/* 0x7d '}' offset 3491 */
0, 16, 44, 0, 3, 5,
0, 10, 16, /* snap_x */
-44, -24, -21, -15, 0, /* snap_y */
'm', 0, -44,
'c', 6, -44, 10, -42, 10, -36,
'l', 10, -24,
'l', 16, -24,
'l', 10, -24,
'l', 10, -8,
'c', 10, -2, 6, 0, 0, 0,
'e',
/* 0x7e '~' offset 3535 */
0, 36, 24, -12, 2, 5,
0, 36, /* snap_x */
-24, -21, -15, -12, 0, /* snap_y */
'm', 0, -14,
'c', 1, -21, 4, -24, 8, -24,
'c', 18, -24, 18, -12, 28, -12,
'c', 32, -12, 35, -15, 36, -22,
'e',
};
 
const uint16_t _cairo_twin_charmap[128] = {
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
28, 40, 90, 114, 152, 224, 323, 390,
419, 441, 463, 494, 520, 556, 575, 604,
622, 666, 691, 736, 780, 809, 860, 919,
944, 1004, 1063, 1109, 1162, 1183, 1209, 1230,
1288, 1375, 1406, 1455, 1499, 1534, 1572, 1604,
1655, 1686, 1703, 1731, 1761, 1785, 1821, 1851,
1895, 1931, 1981, 2023, 2074, 2100, 2128, 2152,
2188, 2212, 2240, 2271, 2296, 2314, 2339, 2363,
2381, 2417, 2467, 2517, 2561, 2611, 2659, 2693,
2758, 2790, 2826, 2870, 2900, 2917, 2963, 2995,
3039, 3089, 3139, 3168, 3219, 3252, 3283, 3307,
3343, 3367, 3399, 3430, 3474, 3491, 3535, 0,
};
 
/programs/develop/libraries/cairo/src/cairo-font-face-twin.c
0,0 → 1,761
/*
* Copyright © 2004 Keith Packard
* Copyright © 2008 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Keith Packard
*
* Contributor(s):
* Keith Packard <keithp@keithp.com>
* Behdad Esfahbod <behdad@behdad.org>
*/
 
#include "cairoint.h"
#include "cairo-error-private.h"
 
#include <math.h>
 
/*
* This file implements a user-font rendering the descendant of the Hershey
* font coded by Keith Packard for use in the Twin window system.
* The actual font data is in cairo-font-face-twin-data.c
*
* Ported to cairo user font and extended by Behdad Esfahbod.
*/
 
 
 
static cairo_user_data_key_t twin_properties_key;
 
 
/*
* Face properties
*/
 
/* We synthesize multiple faces from the twin data. Here is the parameters. */
 
/* The following tables and matching code are copied from Pango */
 
/* CSS weight */
typedef enum {
TWIN_WEIGHT_THIN = 100,
TWIN_WEIGHT_ULTRALIGHT = 200,
TWIN_WEIGHT_LIGHT = 300,
TWIN_WEIGHT_BOOK = 380,
TWIN_WEIGHT_NORMAL = 400,
TWIN_WEIGHT_MEDIUM = 500,
TWIN_WEIGHT_SEMIBOLD = 600,
TWIN_WEIGHT_BOLD = 700,
TWIN_WEIGHT_ULTRABOLD = 800,
TWIN_WEIGHT_HEAVY = 900,
TWIN_WEIGHT_ULTRAHEAVY = 1000
} twin_face_weight_t;
 
/* CSS stretch */
typedef enum {
TWIN_STRETCH_ULTRA_CONDENSED,
TWIN_STRETCH_EXTRA_CONDENSED,
TWIN_STRETCH_CONDENSED,
TWIN_STRETCH_SEMI_CONDENSED,
TWIN_STRETCH_NORMAL,
TWIN_STRETCH_SEMI_EXPANDED,
TWIN_STRETCH_EXPANDED,
TWIN_STRETCH_EXTRA_EXPANDED,
TWIN_STRETCH_ULTRA_EXPANDED
} twin_face_stretch_t;
 
typedef struct
{
int value;
const char str[16];
} FieldMap;
 
static const FieldMap slant_map[] = {
{ CAIRO_FONT_SLANT_NORMAL, "" },
{ CAIRO_FONT_SLANT_NORMAL, "Roman" },
{ CAIRO_FONT_SLANT_OBLIQUE, "Oblique" },
{ CAIRO_FONT_SLANT_ITALIC, "Italic" }
};
 
static const FieldMap smallcaps_map[] = {
{ FALSE, "" },
{ TRUE, "Small-Caps" }
};
 
static const FieldMap weight_map[] = {
{ TWIN_WEIGHT_THIN, "Thin" },
{ TWIN_WEIGHT_ULTRALIGHT, "Ultra-Light" },
{ TWIN_WEIGHT_ULTRALIGHT, "Extra-Light" },
{ TWIN_WEIGHT_LIGHT, "Light" },
{ TWIN_WEIGHT_BOOK, "Book" },
{ TWIN_WEIGHT_NORMAL, "" },
{ TWIN_WEIGHT_NORMAL, "Regular" },
{ TWIN_WEIGHT_MEDIUM, "Medium" },
{ TWIN_WEIGHT_SEMIBOLD, "Semi-Bold" },
{ TWIN_WEIGHT_SEMIBOLD, "Demi-Bold" },
{ TWIN_WEIGHT_BOLD, "Bold" },
{ TWIN_WEIGHT_ULTRABOLD, "Ultra-Bold" },
{ TWIN_WEIGHT_ULTRABOLD, "Extra-Bold" },
{ TWIN_WEIGHT_HEAVY, "Heavy" },
{ TWIN_WEIGHT_HEAVY, "Black" },
{ TWIN_WEIGHT_ULTRAHEAVY, "Ultra-Heavy" },
{ TWIN_WEIGHT_ULTRAHEAVY, "Extra-Heavy" },
{ TWIN_WEIGHT_ULTRAHEAVY, "Ultra-Black" },
{ TWIN_WEIGHT_ULTRAHEAVY, "Extra-Black" }
};
 
static const FieldMap stretch_map[] = {
{ TWIN_STRETCH_ULTRA_CONDENSED, "Ultra-Condensed" },
{ TWIN_STRETCH_EXTRA_CONDENSED, "Extra-Condensed" },
{ TWIN_STRETCH_CONDENSED, "Condensed" },
{ TWIN_STRETCH_SEMI_CONDENSED, "Semi-Condensed" },
{ TWIN_STRETCH_NORMAL, "" },
{ TWIN_STRETCH_SEMI_EXPANDED, "Semi-Expanded" },
{ TWIN_STRETCH_EXPANDED, "Expanded" },
{ TWIN_STRETCH_EXTRA_EXPANDED, "Extra-Expanded" },
{ TWIN_STRETCH_ULTRA_EXPANDED, "Ultra-Expanded" }
};
 
static const FieldMap monospace_map[] = {
{ FALSE, "" },
{ TRUE, "Mono" },
{ TRUE, "Monospace" }
};
 
 
typedef struct _twin_face_properties {
cairo_font_slant_t slant;
twin_face_weight_t weight;
twin_face_stretch_t stretch;
 
/* lets have some fun */
cairo_bool_t monospace;
cairo_bool_t smallcaps;
} twin_face_properties_t;
 
static cairo_bool_t
field_matches (const char *s1,
const char *s2,
int len)
{
int c1, c2;
 
while (len && *s1 && *s2)
{
#define TOLOWER(c) \
(((c) >= 'A' && (c) <= 'Z') ? (c) - 'A' + 'a' : (c))
 
c1 = TOLOWER (*s1);
c2 = TOLOWER (*s2);
if (c1 != c2) {
if (c1 == '-') {
s1++;
continue;
}
return FALSE;
}
s1++; s2++;
len--;
}
 
return len == 0 && *s1 == '\0';
}
 
static cairo_bool_t
parse_int (const char *word,
size_t wordlen,
int *out)
{
char *end;
long val = strtol (word, &end, 10);
int i = val;
 
if (end != word && (end == word + wordlen) && val >= 0 && val == i)
{
if (out)
*out = i;
 
return TRUE;
}
 
return FALSE;
}
 
static cairo_bool_t
find_field (const char *what,
const FieldMap *map,
int n_elements,
const char *str,
int len,
int *val)
{
int i;
cairo_bool_t had_prefix = FALSE;
 
if (what)
{
i = strlen (what);
if (len > i && 0 == strncmp (what, str, i) && str[i] == '=')
{
str += i + 1;
len -= i + 1;
had_prefix = TRUE;
}
}
 
for (i=0; i<n_elements; i++)
{
if (map[i].str[0] && field_matches (map[i].str, str, len))
{
if (val)
*val = map[i].value;
return TRUE;
}
}
 
if (!what || had_prefix)
return parse_int (str, len, val);
 
return FALSE;
}
 
static void
parse_field (twin_face_properties_t *props,
const char *str,
int len)
{
if (field_matches ("Normal", str, len))
return;
 
#define FIELD(NAME) \
if (find_field (STRINGIFY (NAME), NAME##_map, ARRAY_LENGTH (NAME##_map), str, len, \
(int *)(void *)&props->NAME)) \
return; \
 
FIELD (weight);
FIELD (slant);
FIELD (stretch);
FIELD (smallcaps);
FIELD (monospace);
 
#undef FIELD
}
 
static void
face_props_parse (twin_face_properties_t *props,
const char *s)
{
const char *start, *end;
 
for (start = end = s; *end; end++) {
if (*end != ' ' && *end != ':')
continue;
 
if (start < end)
parse_field (props, start, end - start);
start = end + 1;
}
if (start < end)
parse_field (props, start, end - start);
}
 
static cairo_status_t
twin_font_face_create_properties (cairo_font_face_t *twin_face,
twin_face_properties_t **props_out)
{
twin_face_properties_t *props;
cairo_status_t status;
 
props = malloc (sizeof (twin_face_properties_t));
if (unlikely (props == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
props->stretch = TWIN_STRETCH_NORMAL;
props->slant = CAIRO_FONT_SLANT_NORMAL;
props->weight = TWIN_WEIGHT_NORMAL;
props->monospace = FALSE;
props->smallcaps = FALSE;
 
status = cairo_font_face_set_user_data (twin_face,
&twin_properties_key,
props, free);
if (unlikely (status)) {
free (props);
return status;
}
 
if (props_out)
*props_out = props;
 
return CAIRO_STATUS_SUCCESS;
}
 
static cairo_status_t
twin_font_face_set_properties_from_toy (cairo_font_face_t *twin_face,
cairo_toy_font_face_t *toy_face)
{
cairo_status_t status;
twin_face_properties_t *props;
 
status = twin_font_face_create_properties (twin_face, &props);
if (unlikely (status))
return status;
 
props->slant = toy_face->slant;
props->weight = toy_face->weight == CAIRO_FONT_WEIGHT_NORMAL ?
TWIN_WEIGHT_NORMAL : TWIN_WEIGHT_BOLD;
face_props_parse (props, toy_face->family);
 
return CAIRO_STATUS_SUCCESS;
}
 
 
/*
* Scaled properties
*/
 
typedef struct _twin_scaled_properties {
twin_face_properties_t *face_props;
 
cairo_bool_t snap; /* hint outlines */
 
double weight; /* unhinted pen width */
double penx, peny; /* hinted pen width */
double marginl, marginr; /* hinted side margins */
 
double stretch; /* stretch factor */
} twin_scaled_properties_t;
 
static void
compute_hinting_scale (cairo_t *cr,
double x, double y,
double *scale, double *inv)
{
cairo_user_to_device_distance (cr, &x, &y);
*scale = x == 0 ? y : y == 0 ? x :sqrt (x*x + y*y);
*inv = 1 / *scale;
}
 
static void
compute_hinting_scales (cairo_t *cr,
double *x_scale, double *x_scale_inv,
double *y_scale, double *y_scale_inv)
{
double x, y;
 
x = 1; y = 0;
compute_hinting_scale (cr, x, y, x_scale, x_scale_inv);
 
x = 0; y = 1;
compute_hinting_scale (cr, x, y, y_scale, y_scale_inv);
}
 
#define SNAPXI(p) (_cairo_round ((p) * x_scale) * x_scale_inv)
#define SNAPYI(p) (_cairo_round ((p) * y_scale) * y_scale_inv)
 
/* This controls the global font size */
#define F(g) ((g) / 72.)
 
static void
twin_hint_pen_and_margins(cairo_t *cr,
double *penx, double *peny,
double *marginl, double *marginr)
{
double x_scale, x_scale_inv;
double y_scale, y_scale_inv;
double margin;
 
compute_hinting_scales (cr,
&x_scale, &x_scale_inv,
&y_scale, &y_scale_inv);
 
*penx = SNAPXI (*penx);
if (*penx < x_scale_inv)
*penx = x_scale_inv;
 
*peny = SNAPYI (*peny);
if (*peny < y_scale_inv)
*peny = y_scale_inv;
 
margin = *marginl + *marginr;
*marginl = SNAPXI (*marginl);
if (*marginl < x_scale_inv)
*marginl = x_scale_inv;
 
*marginr = margin - *marginl;
if (*marginr < 0)
*marginr = 0;
*marginr = SNAPXI (*marginr);
}
 
static cairo_status_t
twin_scaled_font_compute_properties (cairo_scaled_font_t *scaled_font,
cairo_t *cr)
{
cairo_status_t status;
twin_scaled_properties_t *props;
 
props = malloc (sizeof (twin_scaled_properties_t));
if (unlikely (props == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
 
props->face_props = cairo_font_face_get_user_data (cairo_scaled_font_get_font_face (scaled_font),
&twin_properties_key);
 
props->snap = scaled_font->options.hint_style > CAIRO_HINT_STYLE_NONE;
 
/* weight */
props->weight = props->face_props->weight * (F (4) / TWIN_WEIGHT_NORMAL);
 
/* pen & margins */
props->penx = props->peny = props->weight;
props->marginl = props->marginr = F (4);
if (scaled_font->options.hint_style > CAIRO_HINT_STYLE_SLIGHT)
twin_hint_pen_and_margins(cr,
&props->penx, &props->peny,
&props->marginl, &props->marginr);
 
/* stretch */
props->stretch = 1 + .1 * ((int) props->face_props->stretch - (int) TWIN_STRETCH_NORMAL);
 
 
/* Save it */
status = cairo_scaled_font_set_user_data (scaled_font,
&twin_properties_key,
props, free);
if (unlikely (status))
goto FREE_PROPS;
 
return CAIRO_STATUS_SUCCESS;
 
FREE_PROPS:
free (props);
return status;
}
 
 
/*
* User-font implementation
*/
 
static cairo_status_t
twin_scaled_font_init (cairo_scaled_font_t *scaled_font,
cairo_t *cr,
cairo_font_extents_t *metrics)
{
metrics->ascent = F (54);
metrics->descent = 1 - metrics->ascent;
 
return twin_scaled_font_compute_properties (scaled_font, cr);
}
 
#define TWIN_GLYPH_MAX_SNAP_X 4
#define TWIN_GLYPH_MAX_SNAP_Y 7
 
typedef struct {
int n_snap_x;
int8_t snap_x[TWIN_GLYPH_MAX_SNAP_X];
double snapped_x[TWIN_GLYPH_MAX_SNAP_X];
int n_snap_y;
int8_t snap_y[TWIN_GLYPH_MAX_SNAP_Y];
double snapped_y[TWIN_GLYPH_MAX_SNAP_Y];
} twin_snap_info_t;
 
#define twin_glyph_left(g) ((g)[0])
#define twin_glyph_right(g) ((g)[1])
#define twin_glyph_ascent(g) ((g)[2])
#define twin_glyph_descent(g) ((g)[3])
 
#define twin_glyph_n_snap_x(g) ((g)[4])
#define twin_glyph_n_snap_y(g) ((g)[5])
#define twin_glyph_snap_x(g) (&g[6])
#define twin_glyph_snap_y(g) (twin_glyph_snap_x(g) + twin_glyph_n_snap_x(g))
#define twin_glyph_draw(g) (twin_glyph_snap_y(g) + twin_glyph_n_snap_y(g))
 
static void
twin_compute_snap (cairo_t *cr,
twin_snap_info_t *info,
const signed char *b)
{
int s, n;
const signed char *snap;
double x_scale, x_scale_inv;
double y_scale, y_scale_inv;
 
compute_hinting_scales (cr,
&x_scale, &x_scale_inv,
&y_scale, &y_scale_inv);
 
snap = twin_glyph_snap_x (b);
n = twin_glyph_n_snap_x (b);
info->n_snap_x = n;
assert (n <= TWIN_GLYPH_MAX_SNAP_X);
for (s = 0; s < n; s++) {
info->snap_x[s] = snap[s];
info->snapped_x[s] = SNAPXI (F (snap[s]));
}
 
snap = twin_glyph_snap_y (b);
n = twin_glyph_n_snap_y (b);
info->n_snap_y = n;
assert (n <= TWIN_GLYPH_MAX_SNAP_Y);
for (s = 0; s < n; s++) {
info->snap_y[s] = snap[s];
info->snapped_y[s] = SNAPYI (F (snap[s]));
}
}
 
static double
twin_snap (int8_t v, int n, int8_t *snap, double *snapped)
{
int s;
 
if (!n)
return F(v);
 
if (snap[0] == v)
return snapped[0];
 
for (s = 0; s < n - 1; s++)
{
if (snap[s+1] == v)
return snapped[s+1];
 
if (snap[s] <= v && v <= snap[s+1])
{
int before = snap[s];
int after = snap[s+1];
int dist = after - before;
double snap_before = snapped[s];
double snap_after = snapped[s+1];
double dist_before = v - before;
return snap_before + (snap_after - snap_before) * dist_before / dist;
}
}
return F(v);
}
 
#define SNAPX(p) twin_snap (p, info.n_snap_x, info.snap_x, info.snapped_x)
#define SNAPY(p) twin_snap (p, info.n_snap_y, info.snap_y, info.snapped_y)
 
static cairo_status_t
twin_scaled_font_render_glyph (cairo_scaled_font_t *scaled_font,
unsigned long glyph,
cairo_t *cr,
cairo_text_extents_t *metrics)
{
double x1, y1, x2, y2, x3, y3;
double marginl;
twin_scaled_properties_t *props;
twin_snap_info_t info;
const int8_t *b;
const int8_t *g;
int8_t w;
double gw;
 
props = cairo_scaled_font_get_user_data (scaled_font, &twin_properties_key);
 
/* Save glyph space, we need it when stroking */
cairo_save (cr);
 
/* center the pen */
cairo_translate (cr, props->penx * .5, -props->peny * .5);
 
/* small-caps */
if (props->face_props->smallcaps && glyph >= 'a' && glyph <= 'z') {
glyph += 'A' - 'a';
/* 28 and 42 are small and capital letter heights of the glyph data */
cairo_scale (cr, 1, 28. / 42);
}
 
/* slant */
if (props->face_props->slant != CAIRO_FONT_SLANT_NORMAL) {
cairo_matrix_t shear = { 1, 0, -.2, 1, 0, 0};
cairo_transform (cr, &shear);
}
 
b = _cairo_twin_outlines +
_cairo_twin_charmap[unlikely (glyph >= ARRAY_LENGTH (_cairo_twin_charmap)) ? 0 : glyph];
g = twin_glyph_draw(b);
w = twin_glyph_right(b);
gw = F(w);
 
marginl = props->marginl;
 
/* monospace */
if (props->face_props->monospace) {
double monow = F(24);
double extra = props->penx + props->marginl + props->marginr;
cairo_scale (cr, (monow + extra) / (gw + extra), 1);
gw = monow;
 
/* resnap margin for new transform */
{
double x, y, x_scale, x_scale_inv;
x = 1; y = 0;
compute_hinting_scale (cr, x, y, &x_scale, &x_scale_inv);
marginl = SNAPXI (marginl);
}
}
 
cairo_translate (cr, marginl, 0);
 
/* stretch */
cairo_scale (cr, props->stretch, 1);
 
if (props->snap)
twin_compute_snap (cr, &info, b);
else
info.n_snap_x = info.n_snap_y = 0;
 
/* advance width */
metrics->x_advance = gw * props->stretch + props->penx + props->marginl + props->marginr;
 
/* glyph shape */
for (;;) {
switch (*g++) {
case 'M':
cairo_close_path (cr);
/* fall through */
case 'm':
x1 = SNAPX(*g++);
y1 = SNAPY(*g++);
cairo_move_to (cr, x1, y1);
continue;
case 'L':
cairo_close_path (cr);
/* fall through */
case 'l':
x1 = SNAPX(*g++);
y1 = SNAPY(*g++);
cairo_line_to (cr, x1, y1);
continue;
case 'C':
cairo_close_path (cr);
/* fall through */
case 'c':
x1 = SNAPX(*g++);
y1 = SNAPY(*g++);
x2 = SNAPX(*g++);
y2 = SNAPY(*g++);
x3 = SNAPX(*g++);
y3 = SNAPY(*g++);
cairo_curve_to (cr, x1, y1, x2, y2, x3, y3);
continue;
case 'E':
cairo_close_path (cr);
/* fall through */
case 'e':
cairo_restore (cr); /* restore glyph space */
cairo_set_tolerance (cr, 0.01);
cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND);
cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
cairo_set_line_width (cr, 1);
cairo_scale (cr, props->penx, props->peny);
cairo_stroke (cr);
break;
case 'X':
/* filler */
continue;
}
break;
}
 
return CAIRO_STATUS_SUCCESS;
}
 
static cairo_status_t
twin_scaled_font_unicode_to_glyph (cairo_scaled_font_t *scaled_font,
unsigned long unicode,
unsigned long *glyph)
{
/* We use an identity charmap. Which means we could live
* with no unicode_to_glyph method too. But we define this
* to map all unknown chars to a single unknown glyph to
* reduce pressure on cache. */
 
if (likely (unicode < ARRAY_LENGTH (_cairo_twin_charmap)))
*glyph = unicode;
else
*glyph = 0;
 
return CAIRO_STATUS_SUCCESS;
}
 
 
/*
* Face constructor
*/
 
static cairo_font_face_t *
_cairo_font_face_twin_create_internal (void)
{
cairo_font_face_t *twin_font_face;
 
twin_font_face = cairo_user_font_face_create ();
cairo_user_font_face_set_init_func (twin_font_face, twin_scaled_font_init);
cairo_user_font_face_set_render_glyph_func (twin_font_face, twin_scaled_font_render_glyph);
cairo_user_font_face_set_unicode_to_glyph_func (twin_font_face, twin_scaled_font_unicode_to_glyph);
 
return twin_font_face;
}
 
cairo_font_face_t *
_cairo_font_face_twin_create_fallback (void)
{
cairo_font_face_t *twin_font_face;
cairo_status_t status;
 
twin_font_face = _cairo_font_face_twin_create_internal ();
status = twin_font_face_create_properties (twin_font_face, NULL);
if (status) {
cairo_font_face_destroy (twin_font_face);
return (cairo_font_face_t *) &_cairo_font_face_nil;
}
 
return twin_font_face;
}
 
cairo_status_t
_cairo_font_face_twin_create_for_toy (cairo_toy_font_face_t *toy_face,
cairo_font_face_t **font_face)
{
cairo_status_t status;
cairo_font_face_t *twin_font_face;
 
twin_font_face = _cairo_font_face_twin_create_internal ();
status = twin_font_face_set_properties_from_toy (twin_font_face, toy_face);
if (status) {
cairo_font_face_destroy (twin_font_face);
return status;
}
 
*font_face = twin_font_face;
 
return CAIRO_STATUS_SUCCESS;
}
/programs/develop/libraries/cairo/src/cairo-font-face.c
0,0 → 1,308
/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
/* 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., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
* Graydon Hoare <graydon@redhat.com>
* Owen Taylor <otaylor@redhat.com>
*/
 
#include "cairoint.h"
#include "cairo-error-private.h"
 
/**
* SECTION:cairo-font-face
* @Title: cairo_font_face_t
* @Short_Description: Base class for font faces
* @See_Also: #cairo_scaled_font_t
*
* #cairo_font_face_t represents a particular font at a particular weight,
* slant, and other characteristic but no size, transformation, or size.
*
* Font faces are created using <firstterm>font-backend</firstterm>-specific
* constructors, typically of the form
* cairo_<emphasis>backend</emphasis>_font_face_create(), or implicitly
* using the <firstterm>toy</firstterm> text API by way of
* cairo_select_font_face(). The resulting face can be accessed using
* cairo_get_font_face().
*/
 
/* #cairo_font_face_t */
 
const cairo_font_face_t _cairo_font_face_nil = {
{ 0 }, /* hash_entry */
CAIRO_STATUS_NO_MEMORY, /* status */
CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */
{ 0, 0, 0, NULL }, /* user_data */
NULL
};
 
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;
 
/* Don't overwrite an existing error. This preserves the first
* error, which is the most significant. */
_cairo_status_set_error (&font_face->status, status);
 
return _cairo_error (status);
}
 
void
_cairo_font_face_init (cairo_font_face_t *font_face,
const cairo_font_face_backend_t *backend)
{
CAIRO_MUTEX_INITIALIZE ();
 
font_face->status = CAIRO_STATUS_SUCCESS;
CAIRO_REFERENCE_COUNT_INIT (&font_face->ref_count, 1);
font_face->backend = backend;
 
_cairo_user_data_array_init (&font_face->user_data);
}
 
/**
* cairo_font_face_reference:
* @font_face: a #cairo_font_face_t, (may be %NULL in which case this
* function does nothing).
*
* Increases the reference count on @font_face by one. This prevents
* @font_face from being destroyed until a matching call to
* cairo_font_face_destroy() is made.
*
* The number of references to a #cairo_font_face_t can be get using
* cairo_font_face_get_reference_count().
*
* Return value: the referenced #cairo_font_face_t.
**/
cairo_font_face_t *
cairo_font_face_reference (cairo_font_face_t *font_face)
{
if (font_face == NULL ||
CAIRO_REFERENCE_COUNT_IS_INVALID (&font_face->ref_count))
return font_face;
 
/* We would normally assert that we have a reference here but we
* can't get away with that due to the zombie case as documented
* in _cairo_ft_font_face_destroy. */
 
_cairo_reference_count_inc (&font_face->ref_count);
 
return font_face;
}
slim_hidden_def (cairo_font_face_reference);
 
/**
* cairo_font_face_destroy:
* @font_face: a #cairo_font_face_t
*
* Decreases the reference count on @font_face by one. If the result
* is zero, then @font_face and all associated resources are freed.
* See cairo_font_face_reference().
**/
void
cairo_font_face_destroy (cairo_font_face_t *font_face)
{
if (font_face == NULL ||
CAIRO_REFERENCE_COUNT_IS_INVALID (&font_face->ref_count))
return;
 
assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&font_face->ref_count));
 
if (! _cairo_reference_count_dec_and_test (&font_face->ref_count))
return;
 
if (font_face->backend->destroy)
font_face->backend->destroy (font_face);
 
/* We allow resurrection to deal with some memory management for the
* FreeType backend where cairo_ft_font_face_t and cairo_ft_unscaled_font_t
* need to effectively mutually reference each other
*/
if (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&font_face->ref_count))
return;
 
_cairo_user_data_array_fini (&font_face->user_data);
 
free (font_face);
}
slim_hidden_def (cairo_font_face_destroy);
 
/**
* cairo_font_face_get_type:
* @font_face: a font face
*
* This function returns the type of the backend used to create
* a font face. See #cairo_font_type_t for available types.
*
* Return value: The type of @font_face.
*
* Since: 1.2
**/
cairo_font_type_t
cairo_font_face_get_type (cairo_font_face_t *font_face)
{
if (CAIRO_REFERENCE_COUNT_IS_INVALID (&font_face->ref_count))
return CAIRO_FONT_TYPE_TOY;
 
return font_face->backend->type;
}
 
/**
* cairo_font_face_get_reference_count:
* @font_face: a #cairo_font_face_t
*
* Returns the current reference count of @font_face.
*
* Return value: the current reference count of @font_face. If the
* object is a nil object, 0 will be returned.
*
* Since: 1.4
**/
unsigned int
cairo_font_face_get_reference_count (cairo_font_face_t *font_face)
{
if (font_face == NULL ||
CAIRO_REFERENCE_COUNT_IS_INVALID (&font_face->ref_count))
return 0;
 
return CAIRO_REFERENCE_COUNT_GET_VALUE (&font_face->ref_count);
}
 
/**
* cairo_font_face_status:
* @font_face: a #cairo_font_face_t
*
* Checks whether an error has previously occurred for this
* font face
*
* Return value: %CAIRO_STATUS_SUCCESS or another error such as
* %CAIRO_STATUS_NO_MEMORY.
**/
cairo_status_t
cairo_font_face_status (cairo_font_face_t *font_face)
{
return font_face->status;
}
 
/**
* cairo_font_face_get_user_data:
* @font_face: a #cairo_font_face_t
* @key: the address of the #cairo_user_data_key_t the user data was
* attached to
*
* Return user data previously attached to @font_face using the specified
* key. If no user data has been attached with the given key this
* function returns %NULL.
*
* Return value: the user data previously attached or %NULL.
**/
void *
cairo_font_face_get_user_data (cairo_font_face_t *font_face,
const cairo_user_data_key_t *key)
{
return _cairo_user_data_array_get_data (&font_face->user_data,
key);
}
slim_hidden_def (cairo_font_face_get_user_data);
 
/**
* cairo_font_face_set_user_data:
* @font_face: a #cairo_font_face_t
* @key: the address of a #cairo_user_data_key_t to attach the user data to
* @user_data: the user data to attach to the font face
* @destroy: a #cairo_destroy_func_t which will be called when the
* font face is destroyed or when new user data is attached using the
* same key.
*
* Attach user data to @font_face. To remove user data from a font face,
* call this function with the key that was used to set it and %NULL
* for @data.
*
* Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY if a
* slot could not be allocated for the user data.
**/
cairo_status_t
cairo_font_face_set_user_data (cairo_font_face_t *font_face,
const cairo_user_data_key_t *key,
void *user_data,
cairo_destroy_func_t destroy)
{
if (CAIRO_REFERENCE_COUNT_IS_INVALID (&font_face->ref_count))
return font_face->status;
 
return _cairo_user_data_array_set_data (&font_face->user_data,
key, user_data, destroy);
}
slim_hidden_def (cairo_font_face_set_user_data);
 
void
_cairo_unscaled_font_init (cairo_unscaled_font_t *unscaled_font,
const cairo_unscaled_font_backend_t *backend)
{
CAIRO_REFERENCE_COUNT_INIT (&unscaled_font->ref_count, 1);
unscaled_font->backend = backend;
}
 
cairo_unscaled_font_t *
_cairo_unscaled_font_reference (cairo_unscaled_font_t *unscaled_font)
{
if (unscaled_font == NULL)
return NULL;
 
assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&unscaled_font->ref_count));
 
_cairo_reference_count_inc (&unscaled_font->ref_count);
 
return unscaled_font;
}
 
void
_cairo_unscaled_font_destroy (cairo_unscaled_font_t *unscaled_font)
{
if (unscaled_font == NULL)
return;
 
assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&unscaled_font->ref_count));
 
if (! _cairo_reference_count_dec_and_test (&unscaled_font->ref_count))
return;
 
unscaled_font->backend->destroy (unscaled_font);
 
free (unscaled_font);
}
/programs/develop/libraries/cairo/src/cairo-font-options.c
0,0 → 1,468
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2005 Red Hat Inc.
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Owen Taylor <otaylor@redhat.com>
*/
 
#include "cairoint.h"
#include "cairo-error-private.h"
 
/**
* SECTION:cairo-font-options
* @Title: cairo_font_options_t
* @Short_Description: How a font should be rendered
* @See_Also: #cairo_scaled_font_t
*
* The font options specify how fonts should be rendered. Most of the
* time the font options implied by a surface are just right and do not
* need any changes, but for pixel-based targets tweaking font options
* may result in superior output on a particular display.
*/
 
static const cairo_font_options_t _cairo_font_options_nil = {
CAIRO_ANTIALIAS_DEFAULT,
CAIRO_SUBPIXEL_ORDER_DEFAULT,
CAIRO_LCD_FILTER_DEFAULT,
CAIRO_HINT_STYLE_DEFAULT,
CAIRO_HINT_METRICS_DEFAULT
};
 
/**
* _cairo_font_options_init_default:
* @options: a #cairo_font_options_t
*
* Initializes all fields of the font options object to default values.
**/
void
_cairo_font_options_init_default (cairo_font_options_t *options)
{
options->antialias = CAIRO_ANTIALIAS_DEFAULT;
options->subpixel_order = CAIRO_SUBPIXEL_ORDER_DEFAULT;
options->lcd_filter = CAIRO_LCD_FILTER_DEFAULT;
options->hint_style = CAIRO_HINT_STYLE_DEFAULT;
options->hint_metrics = CAIRO_HINT_METRICS_DEFAULT;
}
 
void
_cairo_font_options_init_copy (cairo_font_options_t *options,
const cairo_font_options_t *other)
{
options->antialias = other->antialias;
options->subpixel_order = other->subpixel_order;
options->lcd_filter = other->lcd_filter;
options->hint_style = other->hint_style;
options->hint_metrics = other->hint_metrics;
}
 
/**
* cairo_font_options_create:
*
* Allocates a new font options object with all options initialized
* to default values.
*
* Return value: a newly allocated #cairo_font_options_t. Free with
* cairo_font_options_destroy(). This function always returns a
* valid pointer; if memory cannot be allocated, then a special
* error object is returned where all operations on the object do nothing.
* You can check for this with cairo_font_options_status().
**/
cairo_font_options_t *
cairo_font_options_create (void)
{
cairo_font_options_t *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;
}
 
_cairo_font_options_init_default (options);
 
return options;
}
 
/**
* cairo_font_options_copy:
* @original: a #cairo_font_options_t
*
* Allocates a new font options object copying the option values from
* @original.
*
* Return value: a newly allocated #cairo_font_options_t. Free with
* cairo_font_options_destroy(). This function always returns a
* valid pointer; if memory cannot be allocated, then a special
* error object is returned where all operations on the object do nothing.
* You can check for this with cairo_font_options_status().
**/
cairo_font_options_t *
cairo_font_options_copy (const cairo_font_options_t *original)
{
cairo_font_options_t *options;
 
if (cairo_font_options_status ((cairo_font_options_t *) original))
return (cairo_font_options_t *) &_cairo_font_options_nil;
 
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;
}
 
_cairo_font_options_init_copy (options, original);
 
return options;
}
 
/**
* cairo_font_options_destroy:
* @options: a #cairo_font_options_t
*
* Destroys a #cairo_font_options_t object created with
* cairo_font_options_create() or cairo_font_options_copy().
**/
void
cairo_font_options_destroy (cairo_font_options_t *options)
{
if (cairo_font_options_status (options))
return;
 
free (options);
}
 
/**
* cairo_font_options_status:
* @options: a #cairo_font_options_t
*
* Checks whether an error has previously occurred for this
* font options object
*
* Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY
**/
cairo_status_t
cairo_font_options_status (cairo_font_options_t *options)
{
if (options == NULL)
return CAIRO_STATUS_NULL_POINTER;
else if (options == (cairo_font_options_t *) &_cairo_font_options_nil)
return CAIRO_STATUS_NO_MEMORY;
else
return CAIRO_STATUS_SUCCESS;
}
slim_hidden_def (cairo_font_options_status);
 
/**
* cairo_font_options_merge:
* @options: a #cairo_font_options_t
* @other: another #cairo_font_options_t
*
* Merges non-default options from @other into @options, replacing
* existing values. This operation can be thought of as somewhat
* similar to compositing @other onto @options with the operation
* of %CAIRO_OPERATION_OVER.
**/
void
cairo_font_options_merge (cairo_font_options_t *options,
const cairo_font_options_t *other)
{
if (cairo_font_options_status (options))
return;
 
if (cairo_font_options_status ((cairo_font_options_t *) other))
return;
 
if (other->antialias != CAIRO_ANTIALIAS_DEFAULT)
options->antialias = other->antialias;
if (other->subpixel_order != CAIRO_SUBPIXEL_ORDER_DEFAULT)
options->subpixel_order = other->subpixel_order;
if (other->lcd_filter != CAIRO_LCD_FILTER_DEFAULT)
options->lcd_filter = other->lcd_filter;
if (other->hint_style != CAIRO_HINT_STYLE_DEFAULT)
options->hint_style = other->hint_style;
if (other->hint_metrics != CAIRO_HINT_METRICS_DEFAULT)
options->hint_metrics = other->hint_metrics;
}
slim_hidden_def (cairo_font_options_merge);
 
/**
* cairo_font_options_equal:
* @options: a #cairo_font_options_t
* @other: another #cairo_font_options_t
*
* Compares two font options objects for equality.
*
* Return value: %TRUE if all fields of the two font options objects match.
* Note that this function will return %FALSE if either object is in
* error.
**/
cairo_bool_t
cairo_font_options_equal (const cairo_font_options_t *options,
const cairo_font_options_t *other)
{
if (cairo_font_options_status ((cairo_font_options_t *) options))
return FALSE;
if (cairo_font_options_status ((cairo_font_options_t *) other))
return FALSE;
 
if (options == other)
return TRUE;
 
return (options->antialias == other->antialias &&
options->subpixel_order == other->subpixel_order &&
options->lcd_filter == other->lcd_filter &&
options->hint_style == other->hint_style &&
options->hint_metrics == other->hint_metrics);
}
slim_hidden_def (cairo_font_options_equal);
 
/**
* cairo_font_options_hash:
* @options: a #cairo_font_options_t
*
* Compute a hash for the font options object; this value will
* be useful when storing an object containing a #cairo_font_options_t
* in a hash table.
*
* Return value: the hash value for the font options object.
* The return value can be cast to a 32-bit type if a
* 32-bit hash value is needed.
**/
unsigned long
cairo_font_options_hash (const cairo_font_options_t *options)
{
if (cairo_font_options_status ((cairo_font_options_t *) options))
options = &_cairo_font_options_nil; /* force default values */
 
return ((options->antialias) |
(options->subpixel_order << 4) |
(options->lcd_filter << 8) |
(options->hint_style << 12) |
(options->hint_metrics << 16));
}
slim_hidden_def (cairo_font_options_hash);
 
/**
* cairo_font_options_set_antialias:
* @options: a #cairo_font_options_t
* @antialias: the new antialiasing mode
*
* Sets the antialiasing mode for the font options object. This
* specifies the type of antialiasing to do when rendering text.
**/
void
cairo_font_options_set_antialias (cairo_font_options_t *options,
cairo_antialias_t antialias)
{
if (cairo_font_options_status (options))
return;
 
options->antialias = antialias;
}
slim_hidden_def (cairo_font_options_set_antialias);
 
/**
* cairo_font_options_get_antialias:
* @options: a #cairo_font_options_t
*
* Gets the antialiasing mode for the font options object.
*
* Return value: the antialiasing mode
**/
cairo_antialias_t
cairo_font_options_get_antialias (const cairo_font_options_t *options)
{
if (cairo_font_options_status ((cairo_font_options_t *) options))
return CAIRO_ANTIALIAS_DEFAULT;
 
return options->antialias;
}
 
/**
* cairo_font_options_set_subpixel_order:
* @options: a #cairo_font_options_t
* @subpixel_order: the new subpixel order
*
* Sets the subpixel order for the font options object. The subpixel
* order specifies the order of color elements within each pixel on
* the display device when rendering with an antialiasing mode of
* %CAIRO_ANTIALIAS_SUBPIXEL. See the documentation for
* #cairo_subpixel_order_t for full details.
**/
void
cairo_font_options_set_subpixel_order (cairo_font_options_t *options,
cairo_subpixel_order_t subpixel_order)
{
if (cairo_font_options_status (options))
return;
 
options->subpixel_order = subpixel_order;
}
slim_hidden_def (cairo_font_options_set_subpixel_order);
 
/**
* cairo_font_options_get_subpixel_order:
* @options: a #cairo_font_options_t
*
* Gets the subpixel order for the font options object.
* See the documentation for #cairo_subpixel_order_t for full details.
*
* Return value: the subpixel order for the font options object
**/
cairo_subpixel_order_t
cairo_font_options_get_subpixel_order (const cairo_font_options_t *options)
{
if (cairo_font_options_status ((cairo_font_options_t *) options))
return CAIRO_SUBPIXEL_ORDER_DEFAULT;
 
return options->subpixel_order;
}
 
/**
* _cairo_font_options_set_lcd_filter:
* @options: a #cairo_font_options_t
* @lcd_filter: the new LCD filter
*
* Sets the LCD filter for the font options object. The LCD filter
* specifies how pixels are filtered when rendered with an antialiasing
* mode of %CAIRO_ANTIALIAS_SUBPIXEL. See the documentation for
* #cairo_lcd_filter_t for full details.
*
* Since: 1.8
**/
void
_cairo_font_options_set_lcd_filter (cairo_font_options_t *options,
cairo_lcd_filter_t lcd_filter)
{
if (cairo_font_options_status (options))
return;
 
options->lcd_filter = lcd_filter;
}
 
/**
* _cairo_font_options_get_lcd_filter:
* @options: a #cairo_font_options_t
*
* Gets the LCD filter for the font options object.
* See the documentation for #cairo_lcd_filter_t for full details.
*
* Return value: the LCD filter for the font options object
*
* Since: 1.8
**/
cairo_lcd_filter_t
_cairo_font_options_get_lcd_filter (const cairo_font_options_t *options)
{
if (cairo_font_options_status ((cairo_font_options_t *) options))
return CAIRO_LCD_FILTER_DEFAULT;
 
return options->lcd_filter;
}
 
/**
* cairo_font_options_set_hint_style:
* @options: a #cairo_font_options_t
* @hint_style: the new hint style
*
* Sets the hint style for font outlines for the font options object.
* This controls whether to fit font outlines to the pixel grid,
* and if so, whether to optimize for fidelity or contrast.
* See the documentation for #cairo_hint_style_t for full details.
**/
void
cairo_font_options_set_hint_style (cairo_font_options_t *options,
cairo_hint_style_t hint_style)
{
if (cairo_font_options_status (options))
return;
 
options->hint_style = hint_style;
}
slim_hidden_def (cairo_font_options_set_hint_style);
 
/**
* cairo_font_options_get_hint_style:
* @options: a #cairo_font_options_t
*
* Gets the hint style for font outlines for the font options object.
* See the documentation for #cairo_hint_style_t for full details.
*
* Return value: the hint style for the font options object
**/
cairo_hint_style_t
cairo_font_options_get_hint_style (const cairo_font_options_t *options)
{
if (cairo_font_options_status ((cairo_font_options_t *) options))
return CAIRO_HINT_STYLE_DEFAULT;
 
return options->hint_style;
}
 
/**
* cairo_font_options_set_hint_metrics:
* @options: a #cairo_font_options_t
* @hint_metrics: the new metrics hinting mode
*
* Sets the metrics hinting mode for the font options object. This
* controls whether metrics are quantized to integer values in
* device units.
* See the documentation for #cairo_hint_metrics_t for full details.
**/
void
cairo_font_options_set_hint_metrics (cairo_font_options_t *options,
cairo_hint_metrics_t hint_metrics)
{
if (cairo_font_options_status (options))
return;
 
options->hint_metrics = hint_metrics;
}
slim_hidden_def (cairo_font_options_set_hint_metrics);
 
/**
* cairo_font_options_get_hint_metrics:
* @options: a #cairo_font_options_t
*
* Gets the metrics hinting mode for the font options object.
* See the documentation for #cairo_hint_metrics_t for full details.
*
* Return value: the metrics hinting mode for the font options object
**/
cairo_hint_metrics_t
cairo_font_options_get_hint_metrics (const cairo_font_options_t *options)
{
if (cairo_font_options_status ((cairo_font_options_t *) options))
return CAIRO_HINT_METRICS_DEFAULT;
 
return options->hint_metrics;
}
/programs/develop/libraries/cairo/src/cairo-fontconfig-private.h
0,0 → 1,78
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2000 Keith Packard
* Copyright © 2005 Red Hat, Inc
* Copyright © 2010 Intel Corporation
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
* Graydon Hoare <graydon@redhat.com>
* Owen Taylor <otaylor@redhat.com>
* Keith Packard <keithp@keithp.com>
* Carl Worth <cworth@cworth.org>
* Chris Wilson <chris@chris-wilson.co.uk>
*/
 
#ifndef _CAIRO_FONTCONFIG_PRIVATE_H
#define _CAIRO_FONTCONFIG_PRIVATE_H
 
#include "cairo.h"
 
#if CAIRO_HAS_FC_FONT
#include <fontconfig/fontconfig.h>
#include <fontconfig/fcfreetype.h>
#endif
 
/* sub-pixel order */
#ifndef FC_RGBA_UNKNOWN
#define FC_RGBA_UNKNOWN 0
#define FC_RGBA_RGB 1
#define FC_RGBA_BGR 2
#define FC_RGBA_VRGB 3
#define FC_RGBA_VBGR 4
#define FC_RGBA_NONE 5
#endif
 
/* hinting style */
#ifndef FC_HINT_NONE
#define FC_HINT_NONE 0
#define FC_HINT_SLIGHT 1
#define FC_HINT_MEDIUM 2
#define FC_HINT_FULL 3
#endif
 
/* LCD filter */
#ifndef FC_LCD_NONE
#define FC_LCD_NONE 0
#define FC_LCD_DEFAULT 1
#define FC_LCD_LIGHT 2
#define FC_LCD_LEGACY 3
#endif
 
#endif /* _CAIRO_FONTCONFIG_PRIVATE_H */
/programs/develop/libraries/cairo/src/cairo-freed-pool-private.h
0,0 → 1,129
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2009 Chris Wilson
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Chris Wilson <chris@chris-wilson.co.uk>
*/
 
#ifndef CAIRO_FREED_POOL_H
#define CAIRO_FREED_POOL_H
 
#include "cairoint.h"
#include "cairo-atomic-private.h"
 
#if HAS_ATOMIC_OPS
/* Keep a stash of recently freed clip_paths, since we need to
* reallocate them frequently.
*/
#define MAX_FREED_POOL_SIZE 4
typedef struct {
void *pool[MAX_FREED_POOL_SIZE];
int top;
} freed_pool_t;
 
static cairo_always_inline void *
_atomic_fetch (void **slot)
{
void *ptr;
 
do {
ptr = _cairo_atomic_ptr_get (slot);
} while (! _cairo_atomic_ptr_cmpxchg (slot, ptr, NULL));
 
return ptr;
}
 
static cairo_always_inline cairo_bool_t
_atomic_store (void **slot, void *ptr)
{
return _cairo_atomic_ptr_cmpxchg (slot, NULL, ptr);
}
 
cairo_private void *
_freed_pool_get_search (freed_pool_t *pool);
 
static inline void *
_freed_pool_get (freed_pool_t *pool)
{
void *ptr;
int i;
 
i = pool->top - 1;
if (i < 0)
i = 0;
 
ptr = _atomic_fetch (&pool->pool[i]);
if (likely (ptr != NULL)) {
pool->top = i;
return ptr;
}
 
/* either empty or contended */
return _freed_pool_get_search (pool);
}
 
cairo_private void
_freed_pool_put_search (freed_pool_t *pool, void *ptr);
 
static inline void
_freed_pool_put (freed_pool_t *pool, void *ptr)
{
int i;
 
i = pool->top;
if (likely (i < ARRAY_LENGTH (pool->pool) &&
_atomic_store (&pool->pool[i], ptr)))
{
pool->top = i + 1;
return;
}
 
/* either full or contended */
_freed_pool_put_search (pool, ptr);
}
 
cairo_private void
_freed_pool_reset (freed_pool_t *pool);
 
#define HAS_FREED_POOL 1
 
#else
 
typedef int freed_pool_t;
 
#define _freed_pool_get(pool) NULL
#define _freed_pool_put(pool, ptr) free(ptr)
#define _freed_pool_reset(ptr)
 
#endif
 
#endif /* CAIRO_FREED_POOL_PRIVATE_H */
/programs/develop/libraries/cairo/src/cairo-freed-pool.c
0,0 → 1,93
/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2009 Chris Wilson
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Chris Wilson <chris@chris-wilson.co.uk>
*/
 
#include "cairoint.h"
 
#include "cairo-freed-pool-private.h"
 
#if HAS_FREED_POOL
 
void *
_freed_pool_get_search (freed_pool_t *pool)
{
void *ptr;
int i;
 
for (i = ARRAY_LENGTH (pool->pool); i--;) {
ptr = _atomic_fetch (&pool->pool[i]);
if (ptr != NULL) {
pool->top = i;
return ptr;
}
}
 
/* empty */
pool->top = 0;
return NULL;
}
 
void
_freed_pool_put_search (freed_pool_t *pool, void *ptr)
{
int i;
 
for (i = 0; i < ARRAY_LENGTH (pool->pool); i++) {
if (_atomic_store (&pool->pool[i], ptr)) {
pool->top = i + 1;
return;
}
}
 
/* full */
pool->top = i;
free (ptr);
}
 
void
_freed_pool_reset (freed_pool_t *pool)
{
int i;
 
for (i = 0; i < ARRAY_LENGTH (pool->pool); i++) {
free (pool->pool[i]);
pool->pool[i] = NULL;
}
 
pool->top = 0;
}
 
#endif
/programs/develop/libraries/cairo/src/cairo-freelist-private.h
0,0 → 1,139
/*
* Copyright © 2006 Joonas Pihlaja
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting documentation, and
* that the name of the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THIS SOFTWARE.
*/
#ifndef CAIRO_FREELIST_H
#define CAIRO_FREELIST_H
 
#include "cairo-types-private.h"
#include "cairo-compiler-private.h"
#include "cairo-freelist-type-private.h"
 
/* for stand-alone compilation*/
#ifndef VG
#define VG(x)
#endif
 
#ifndef NULL
#define NULL (void *) 0
#endif
 
/* Initialise a freelist that will be responsible for allocating
* nodes of size nodesize. */
cairo_private void
_cairo_freelist_init (cairo_freelist_t *freelist, unsigned nodesize);
 
/* Deallocate any nodes in the freelist. */
cairo_private void
_cairo_freelist_fini (cairo_freelist_t *freelist);
 
/* Allocate a new node from the freelist. If the freelist contains no
* nodes, a new one will be allocated using malloc(). The caller is
* responsible for calling _cairo_freelist_free() or free() on the
* returned node. Returns %NULL on memory allocation error. */
cairo_private void *
_cairo_freelist_alloc (cairo_freelist_t *freelist);
 
/* Allocate a new node from the freelist. If the freelist contains no
* nodes, a new one will be allocated using calloc(). The caller is
* responsible for calling _cairo_freelist_free() or free() on the
* returned node. Returns %NULL on memory allocation error. */
cairo_private void *
_cairo_freelist_calloc (cairo_freelist_t *freelist);
 
/* Return a node to the freelist. This does not deallocate the memory,
* but makes it available for later reuse by
* _cairo_freelist_alloc(). */
cairo_private void
_cairo_freelist_free (cairo_freelist_t *freelist, void *node);
 
 
cairo_private void
_cairo_freepool_init (cairo_freepool_t *freepool, unsigned nodesize);
 
cairo_private void
_cairo_freepool_fini (cairo_freepool_t *freepool);
 
static inline void
_cairo_freepool_reset (cairo_freepool_t *freepool)
{
while (freepool->pools != &freepool->embedded_pool) {
cairo_freelist_pool_t *pool = freepool->pools;
freepool->pools = pool->next;
pool->next = freepool->freepools;
freepool->freepools = pool;
}
 
freepool->embedded_pool.rem = sizeof (freepool->embedded_data);
freepool->embedded_pool.data = freepool->embedded_data;
}
 
cairo_private void *
_cairo_freepool_alloc_from_new_pool (cairo_freepool_t *freepool);
 
static inline void *
_cairo_freepool_alloc_from_pool (cairo_freepool_t *freepool)
{
cairo_freelist_pool_t *pool;
uint8_t *ptr;
 
pool = freepool->pools;
if (unlikely (freepool->nodesize > pool->rem))
return _cairo_freepool_alloc_from_new_pool (freepool);
 
ptr = pool->data;
pool->data += freepool->nodesize;
pool->rem -= freepool->nodesize;
VG (VALGRIND_MAKE_MEM_UNDEFINED (ptr, freepool->nodesize));
return ptr;
}
 
static inline void *
_cairo_freepool_alloc (cairo_freepool_t *freepool)
{
cairo_freelist_node_t *node;
 
node = freepool->first_free_node;
if (unlikely (node == NULL))
return _cairo_freepool_alloc_from_pool (freepool);
 
VG (VALGRIND_MAKE_MEM_DEFINED (node, sizeof (node->next)));
freepool->first_free_node = node->next;
VG (VALGRIND_MAKE_MEM_UNDEFINED (node, freepool->nodesize));
 
return node;
}
 
cairo_private cairo_status_t
_cairo_freepool_alloc_array (cairo_freepool_t *freepool,
int count,
void **array);
 
static inline void
_cairo_freepool_free (cairo_freepool_t *freepool, void *ptr)
{
cairo_freelist_node_t *node = ptr;
 
node->next = freepool->first_free_node;
freepool->first_free_node = node;
VG (VALGRIND_MAKE_MEM_NOACCESS (node, freepool->nodesize));
}
 
#endif /* CAIRO_FREELIST_H */
/programs/develop/libraries/cairo/src/cairo-freelist-type-private.h
0,0 → 1,54
/*
* Copyright © 2010 Joonas Pihlaja
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting documentation, and
* that the name of the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THIS SOFTWARE.
*/
#ifndef CAIRO_FREELIST_TYPE_H
#define CAIRO_FREELIST_TYPE_H
 
#include "cairo-types-private.h"
#include "cairo-compiler-private.h"
 
typedef struct _cairo_freelist_node cairo_freelist_node_t;
struct _cairo_freelist_node {
cairo_freelist_node_t *next;
};
 
typedef struct _cairo_freelist {
cairo_freelist_node_t *first_free_node;
unsigned nodesize;
} cairo_freelist_t;
 
typedef struct _cairo_freelist_pool cairo_freelist_pool_t;
struct _cairo_freelist_pool {
cairo_freelist_pool_t *next;
unsigned size, rem;
uint8_t *data;
};
 
typedef struct _cairo_freepool {
cairo_freelist_node_t *first_free_node;
cairo_freelist_pool_t *pools;
cairo_freelist_pool_t *freepools;
unsigned nodesize;
cairo_freelist_pool_t embedded_pool;
uint8_t embedded_data[1000];
} cairo_freepool_t;
 
#endif /* CAIRO_FREELIST_TYPE_H */
/programs/develop/libraries/cairo/src/cairo-freelist.c
0,0 → 1,191
/*
* Copyright © 2006 Joonas Pihlaja
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting documentation, and
* that the name of the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THIS SOFTWARE.
*/
 
#include "cairoint.h"
 
#include "cairo-error-private.h"
#include "cairo-freelist-private.h"
 
void
_cairo_freelist_init (cairo_freelist_t *freelist, unsigned nodesize)
{
memset (freelist, 0, sizeof (cairo_freelist_t));
freelist->nodesize = nodesize;
}
 
void
_cairo_freelist_fini (cairo_freelist_t *freelist)
{
cairo_freelist_node_t *node = freelist->first_free_node;
while (node) {
cairo_freelist_node_t *next;
 
VG (VALGRIND_MAKE_MEM_DEFINED (node, sizeof (node->next)));
next = node->next;
 
free (node);
node = next;
}
}
 
void *
_cairo_freelist_alloc (cairo_freelist_t *freelist)
{
if (freelist->first_free_node) {
cairo_freelist_node_t *node;
 
node = freelist->first_free_node;
VG (VALGRIND_MAKE_MEM_DEFINED (node, sizeof (node->next)));
freelist->first_free_node = node->next;
VG (VALGRIND_MAKE_MEM_UNDEFINED (node, freelist->nodesize));
 
return node;
}
 
return malloc (freelist->nodesize);
}
 
void *
_cairo_freelist_calloc (cairo_freelist_t *freelist)
{
void *node = _cairo_freelist_alloc (freelist);
if (node)
memset (node, 0, freelist->nodesize);
return node;
}
 
void
_cairo_freelist_free (cairo_freelist_t *freelist, void *voidnode)
{
cairo_freelist_node_t *node = voidnode;
if (node) {
node->next = freelist->first_free_node;
freelist->first_free_node = node;
VG (VALGRIND_MAKE_MEM_NOACCESS (node, freelist->nodesize));
}
}
 
void
_cairo_freepool_init (cairo_freepool_t *freepool, unsigned nodesize)
{
freepool->first_free_node = NULL;
freepool->pools = &freepool->embedded_pool;
freepool->freepools = NULL;
freepool->nodesize = nodesize;
 
freepool->embedded_pool.next = NULL;
freepool->embedded_pool.size = sizeof (freepool->embedded_data);
freepool->embedded_pool.rem = sizeof (freepool->embedded_data);
freepool->embedded_pool.data = freepool->embedded_data;
 
VG (VALGRIND_MAKE_MEM_NOACCESS (freepool->embedded_data, sizeof (freepool->embedded_data)));
}
 
void
_cairo_freepool_fini (cairo_freepool_t *freepool)
{
cairo_freelist_pool_t *pool;
 
pool = freepool->pools;
while (pool != &freepool->embedded_pool) {
cairo_freelist_pool_t *next = pool->next;
free (pool);
pool = next;
}
 
pool = freepool->freepools;
while (pool != NULL) {
cairo_freelist_pool_t *next = pool->next;
free (pool);
pool = next;
}
 
VG (VALGRIND_MAKE_MEM_NOACCESS (freepool, sizeof (freepool)));
}
 
void *
_cairo_freepool_alloc_from_new_pool (cairo_freepool_t *freepool)
{
cairo_freelist_pool_t *pool;
int poolsize;
 
if (freepool->freepools != NULL) {
pool = freepool->freepools;
freepool->freepools = pool->next;
 
poolsize = pool->size;
} else {
if (freepool->pools != &freepool->embedded_pool)
poolsize = 2 * freepool->pools->size;
else
poolsize = (128 * freepool->nodesize + 8191) & -8192;
 
pool = malloc (sizeof (cairo_freelist_pool_t) + poolsize);
if (unlikely (pool == NULL))
return pool;
 
pool->size = poolsize;
}
 
pool->next = freepool->pools;
freepool->pools = pool;
 
pool->rem = poolsize - freepool->nodesize;
pool->data = (uint8_t *) (pool + 1) + freepool->nodesize;
 
VG (VALGRIND_MAKE_MEM_NOACCESS (pool->data, pool->rem));
 
return pool + 1;
}
 
cairo_status_t
_cairo_freepool_alloc_array (cairo_freepool_t *freepool,
int count,
void **array)
{
int i;
 
for (i = 0; i < count; i++) {
cairo_freelist_node_t *node;
 
node = freepool->first_free_node;
if (likely (node != NULL)) {
VG (VALGRIND_MAKE_MEM_DEFINED (node, sizeof (node->next)));
freepool->first_free_node = node->next;
VG (VALGRIND_MAKE_MEM_UNDEFINED (node, freepool->nodesize));
} else {
node = _cairo_freepool_alloc_from_pool (freepool);
if (unlikely (node == NULL))
goto CLEANUP;
}
 
array[i] = node;
}
 
return CAIRO_STATUS_SUCCESS;
 
CLEANUP:
while (i--)
_cairo_freepool_free (freepool, array[i]);
 
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
/programs/develop/libraries/cairo/src/cairo-ft-private.h
0,0 → 1,73
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2005 Red Hat, Inc
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
* Graydon Hoare <graydon@redhat.com>
* Owen Taylor <otaylor@redhat.com>
*/
 
#ifndef CAIRO_FT_PRIVATE_H
#define CAIRO_FT_PRIVATE_H
 
#include "cairo-ft.h"
#include "cairoint.h"
 
#if CAIRO_HAS_FT_FONT
 
CAIRO_BEGIN_DECLS
 
typedef struct _cairo_ft_unscaled_font cairo_ft_unscaled_font_t;
 
cairo_private cairo_bool_t
_cairo_scaled_font_is_ft (cairo_scaled_font_t *scaled_font);
 
/* These functions are needed by the PDF backend, which needs to keep track of the
* the different fonts-on-disk used by a document, so it can embed them
*/
cairo_private cairo_unscaled_font_t *
_cairo_ft_scaled_font_get_unscaled_font (cairo_scaled_font_t *scaled_font);
 
cairo_private FT_Face
_cairo_ft_unscaled_font_lock_face (cairo_ft_unscaled_font_t *unscaled);
 
cairo_private void
_cairo_ft_unscaled_font_unlock_face (cairo_ft_unscaled_font_t *unscaled);
 
cairo_private cairo_bool_t
_cairo_ft_scaled_font_is_vertical (cairo_scaled_font_t *scaled_font);
 
cairo_private unsigned int
_cairo_ft_scaled_font_get_load_flags (cairo_scaled_font_t *scaled_font);
 
CAIRO_END_DECLS
 
#endif /* CAIRO_HAS_FT_FONT */
#endif /* CAIRO_FT_PRIVATE_H */
/programs/develop/libraries/cairo/src/cairo-ft.h
0,0 → 1,82
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2005 Red Hat, Inc
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
* Graydon Hoare <graydon@redhat.com>
* Owen Taylor <otaylor@redhat.com>
*/
 
#ifndef CAIRO_FT_H
#define CAIRO_FT_H
 
#include "cairo.h"
 
#if CAIRO_HAS_FT_FONT
 
/* Fontconfig/Freetype platform-specific font interface */
 
#include <ft2build.h>
#include FT_FREETYPE_H
 
#if CAIRO_HAS_FC_FONT
#include <fontconfig/fontconfig.h>
#endif
 
CAIRO_BEGIN_DECLS
 
cairo_public cairo_font_face_t *
cairo_ft_font_face_create_for_ft_face (FT_Face face,
int load_flags);
 
cairo_public FT_Face
cairo_ft_scaled_font_lock_face (cairo_scaled_font_t *scaled_font);
 
cairo_public void
cairo_ft_scaled_font_unlock_face (cairo_scaled_font_t *scaled_font);
 
#if CAIRO_HAS_FC_FONT
 
cairo_public cairo_font_face_t *
cairo_ft_font_face_create_for_pattern (FcPattern *pattern);
 
cairo_public void
cairo_ft_font_options_substitute (const cairo_font_options_t *options,
FcPattern *pattern);
 
#endif
 
CAIRO_END_DECLS
 
#else /* CAIRO_HAS_FT_FONT */
# error Cairo was not compiled with support for the freetype font backend
#endif /* CAIRO_HAS_FT_FONT */
 
#endif /* CAIRO_FT_H */
/programs/develop/libraries/cairo/src/cairo-gl-gradient-private.h
0,0 → 1,88
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2009 Eric Anholt
* Copyright © 2009 Chris Wilson
* Copyright © 2005,2010 Red Hat, Inc
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
* Benjamin Otte <otte@gnome.org>
* Carl Worth <cworth@cworth.org>
* Chris Wilson <chris@chris-wilson.co.uk>
* Eric Anholt <eric@anholt.net>
*/
 
#ifndef CAIRO_GL_GRADIENT_PRIVATE_H
#define CAIRO_GL_GRADIENT_PRIVATE_H
 
#include "cairo-cache-private.h"
#include "cairo-device-private.h"
#include "cairo-reference-count-private.h"
#include "cairo-types-private.h"
 
#include <GL/glew.h>
 
#include "cairo-gl.h"
 
#include <GL/gl.h>
#define GL_GLEXT_PROTOTYPES
#include <GL/glext.h>
 
#define CAIRO_GL_GRADIENT_CACHE_SIZE 4096
 
/* XXX: Declare in a better place */
typedef struct _cairo_gl_context cairo_gl_context_t;
 
typedef struct _cairo_gl_gradient {
cairo_cache_entry_t cache_entry;
cairo_reference_count_t ref_count;
cairo_device_t *device; /* NB: we don't hold a reference */
GLuint tex;
unsigned int n_stops;
const cairo_gradient_stop_t *stops;
cairo_gradient_stop_t stops_embedded[1];
} cairo_gl_gradient_t;
 
cairo_private cairo_int_status_t
_cairo_gl_gradient_create (cairo_gl_context_t *ctx,
unsigned int n_stops,
const cairo_gradient_stop_t *stops,
cairo_gl_gradient_t **gradient_out);
 
cairo_private_no_warn cairo_gl_gradient_t *
_cairo_gl_gradient_reference (cairo_gl_gradient_t *gradient);
 
cairo_private void
_cairo_gl_gradient_destroy (cairo_gl_gradient_t *gradient);
 
cairo_private cairo_bool_t
_cairo_gl_gradient_equal (const void *key_a, const void *key_b);
 
 
#endif /* CAIRO_GL_GRADIENT_PRIVATE_H */
/programs/develop/libraries/cairo/src/cairo-gl-private.h
0,0 → 1,485
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2009 Eric Anholt
* Copyright © 2009 Chris Wilson
* Copyright © 2005,2010 Red Hat, Inc
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
* Benjamin Otte <otte@gnome.org>
* Carl Worth <cworth@cworth.org>
* Chris Wilson <chris@chris-wilson.co.uk>
* Eric Anholt <eric@anholt.net>
* T. Zachary Laine <whatwasthataddress@gmail.com>
*/
 
#ifndef CAIRO_GL_PRIVATE_H
#define CAIRO_GL_PRIVATE_H
 
#include "cairoint.h"
 
#include "cairo-gl-gradient-private.h"
 
#include "cairo-device-private.h"
#include "cairo-error-private.h"
#include "cairo-rtree-private.h"
 
#include <assert.h>
 
#include <GL/glew.h>
 
#include "cairo-gl.h"
 
#include <GL/gl.h>
#define GL_GLEXT_PROTOTYPES
#include <GL/glext.h>
 
#define DEBUG_GL 0
 
#if DEBUG_GL && __GNUC__
#define UNSUPPORTED(reason) ({ \
fprintf (stderr, \
"cairo-gl: hit unsupported operation in %s(), line %d: %s\n", \
__FUNCTION__, __LINE__, reason); \
CAIRO_INT_STATUS_UNSUPPORTED; \
})
#else
#define UNSUPPORTED(reason) CAIRO_INT_STATUS_UNSUPPORTED
#endif
 
/* maximal number of shaders we keep in the cache.
* Random number that is hopefully big enough to not cause many cache evictions. */
#define CAIRO_GL_MAX_SHADERS_PER_CONTEXT 64
 
/* VBO size that we allocate, smaller size means we gotta flush more often */
#define CAIRO_GL_VBO_SIZE 16384
 
typedef struct _cairo_gl_surface {
cairo_surface_t base;
 
int width, height;
 
GLuint tex; /* GL texture object containing our data. */
GLuint fb; /* GL framebuffer object wrapping our data. */
GLuint depth; /* GL framebuffer object holding depth */
int owns_tex;
} cairo_gl_surface_t;
 
typedef struct cairo_gl_glyph_cache {
cairo_rtree_t rtree;
cairo_surface_pattern_t pattern;
} cairo_gl_glyph_cache_t;
 
typedef enum cairo_gl_tex {
CAIRO_GL_TEX_SOURCE = 0,
CAIRO_GL_TEX_MASK = 1,
CAIRO_GL_TEX_TEMP = 2
} cairo_gl_tex_t;
 
typedef enum cairo_gl_operand_type {
CAIRO_GL_OPERAND_NONE,
CAIRO_GL_OPERAND_CONSTANT,
CAIRO_GL_OPERAND_TEXTURE,
CAIRO_GL_OPERAND_LINEAR_GRADIENT,
CAIRO_GL_OPERAND_RADIAL_GRADIENT,
CAIRO_GL_OPERAND_SPANS,
 
CAIRO_GL_OPERAND_COUNT
} cairo_gl_operand_type_t;
 
typedef struct cairo_gl_shader_impl cairo_gl_shader_impl_t;
 
typedef struct cairo_gl_shader {
GLuint fragment_shader;
GLuint program;
} cairo_gl_shader_t;
 
typedef enum cairo_gl_shader_in {
CAIRO_GL_SHADER_IN_NORMAL,
CAIRO_GL_SHADER_IN_CA_SOURCE,
CAIRO_GL_SHADER_IN_CA_SOURCE_ALPHA,
 
CAIRO_GL_SHADER_IN_COUNT
} cairo_gl_shader_in_t;
 
typedef enum cairo_gl_var_type {
CAIRO_GL_VAR_NONE,
CAIRO_GL_VAR_TEXCOORDS,
CAIRO_GL_VAR_COVERAGE
} cairo_gl_var_type_t;
 
#define cairo_gl_var_type_hash(src,mask,dest) ((mask) << 2 | (src << 1) | (dest))
#define CAIRO_GL_VAR_TYPE_MAX ((CAIRO_GL_VAR_COVERAGE << 2) | (CAIRO_GL_VAR_TEXCOORDS << 1) | CAIRO_GL_VAR_TEXCOORDS)
 
/* This union structure describes a potential source or mask operand to the
* compositing equation.
*/
typedef struct cairo_gl_operand {
cairo_gl_operand_type_t type;
union {
struct {
GLuint tex;
cairo_gl_surface_t *surface;
cairo_surface_attributes_t attributes;
} texture;
struct {
GLfloat color[4];
} constant;
struct {
cairo_gl_gradient_t *gradient;
cairo_matrix_t m;
float segment_x;
float segment_y;
cairo_extend_t extend;
} linear;
struct {
cairo_gl_gradient_t *gradient;
cairo_matrix_t m;
float circle_1_x;
float circle_1_y;
float radius_0;
float radius_1;
cairo_extend_t extend;
} radial;
};
unsigned int vertex_offset;
} cairo_gl_operand_t;
 
struct _cairo_gl_context {
cairo_device_t base;
 
GLuint dummy_tex;
GLuint texture_load_pbo;
GLuint vbo;
GLint max_framebuffer_size;
GLint max_texture_size;
GLint max_textures;
GLenum tex_target;
 
const cairo_gl_shader_impl_t *shader_impl;
 
GLuint vertex_shaders[CAIRO_GL_VAR_TYPE_MAX + 1];
cairo_gl_shader_t fill_rectangles_shader;
cairo_cache_t shaders;
 
cairo_cache_t gradients;
 
cairo_gl_glyph_cache_t glyph_cache[2];
cairo_list_t fonts;
 
cairo_gl_surface_t *current_target;
cairo_operator_t current_operator;
cairo_gl_shader_t *pre_shader; /* for component alpha */
cairo_gl_shader_t *current_shader;
 
cairo_gl_operand_t operands[2];
 
char *vb;
unsigned int vb_offset;
unsigned int vertex_size;
cairo_region_t *clip_region;
 
void (*acquire) (void *ctx);
void (*release) (void *ctx);
 
void (*make_current) (void *ctx, cairo_gl_surface_t *surface);
void (*swap_buffers)(void *ctx, cairo_gl_surface_t *surface);
void (*destroy) (void *ctx);
};
 
typedef struct _cairo_gl_composite {
cairo_gl_surface_t *dst;
cairo_operator_t op;
cairo_region_t *clip_region;
 
cairo_gl_operand_t src;
cairo_gl_operand_t mask;
} cairo_gl_composite_t;
 
cairo_private extern const cairo_surface_backend_t _cairo_gl_surface_backend;
 
static cairo_always_inline GLenum
_cairo_gl_get_error (void)
{
GLenum err = glGetError();
 
if (unlikely (err))
while (glGetError ());
 
return err;
}
 
static inline cairo_device_t *
_cairo_gl_context_create_in_error (cairo_status_t status)
{
return (cairo_device_t *) _cairo_device_create_in_error (status);
}
 
cairo_private cairo_status_t
_cairo_gl_context_init (cairo_gl_context_t *ctx);
 
cairo_private void
_cairo_gl_surface_init (cairo_device_t *device,
cairo_gl_surface_t *surface,
cairo_content_t content,
int width, int height);
 
static cairo_always_inline cairo_bool_t cairo_warn
_cairo_gl_surface_is_texture (cairo_gl_surface_t *surface)
{
return surface->tex != 0;
}
 
cairo_private cairo_status_t
_cairo_gl_surface_draw_image (cairo_gl_surface_t *dst,
cairo_image_surface_t *src,
int src_x, int src_y,
int width, int height,
int dst_x, int dst_y);
 
static cairo_always_inline cairo_bool_t
_cairo_gl_device_has_glsl (cairo_device_t *device)
{
return ((cairo_gl_context_t *) device)->shader_impl != NULL;
}
 
static cairo_always_inline cairo_bool_t
_cairo_gl_device_requires_power_of_two_textures (cairo_device_t *device)
{
return ((cairo_gl_context_t *) device)->tex_target == GL_TEXTURE_RECTANGLE_EXT;
}
 
static cairo_always_inline cairo_status_t cairo_warn
_cairo_gl_context_acquire (cairo_device_t *device,
cairo_gl_context_t **ctx)
{
cairo_status_t status;
 
status = cairo_device_acquire (device);
if (unlikely (status))
return status;
 
/* clear potential previous GL errors */
_cairo_gl_get_error ();
 
*ctx = (cairo_gl_context_t *) device;
return CAIRO_STATUS_SUCCESS;
}
 
static cairo_always_inline cairo_warn cairo_status_t
_cairo_gl_context_release (cairo_gl_context_t *ctx, cairo_status_t status)
{
GLenum err;
 
err = _cairo_gl_get_error ();
 
if (unlikely (err)) {
cairo_status_t new_status;
new_status = _cairo_error (CAIRO_STATUS_DEVICE_ERROR);
if (status == CAIRO_STATUS_SUCCESS)
status = new_status;
}
 
cairo_device_release (&(ctx)->base);
 
return status;
}
 
cairo_private void
_cairo_gl_context_set_destination (cairo_gl_context_t *ctx, cairo_gl_surface_t *surface);
 
cairo_private void
_cairo_gl_context_activate (cairo_gl_context_t *ctx,
cairo_gl_tex_t tex_unit);
 
cairo_private cairo_bool_t
_cairo_gl_operator_is_supported (cairo_operator_t op);
 
cairo_private cairo_status_t
_cairo_gl_composite_init (cairo_gl_composite_t *setup,
cairo_operator_t op,
cairo_gl_surface_t *dst,
cairo_bool_t has_component_alpha,
const cairo_rectangle_int_t *rect);
 
cairo_private void
_cairo_gl_composite_fini (cairo_gl_composite_t *setup);
 
cairo_private void
_cairo_gl_composite_set_clip_region (cairo_gl_composite_t *setup,
cairo_region_t *clip_region);
 
cairo_private cairo_int_status_t
_cairo_gl_composite_set_source (cairo_gl_composite_t *setup,
const cairo_pattern_t *pattern,
int src_x, int src_y,
int dst_x, int dst_y,
int width, int height);
 
cairo_private cairo_int_status_t
_cairo_gl_composite_set_mask (cairo_gl_composite_t *setup,
const cairo_pattern_t *pattern,
int src_x, int src_y,
int dst_x, int dst_y,
int width, int height);
 
cairo_private void
_cairo_gl_composite_set_mask_spans (cairo_gl_composite_t *setup);
 
cairo_private cairo_status_t
_cairo_gl_composite_begin (cairo_gl_composite_t *setup,
cairo_gl_context_t **ctx);
 
cairo_private void
_cairo_gl_composite_emit_rect (cairo_gl_context_t *ctx,
GLfloat x1,
GLfloat y1,
GLfloat x2,
GLfloat y2,
uint8_t alpha);
 
cairo_private void
_cairo_gl_composite_emit_glyph (cairo_gl_context_t *ctx,
GLfloat x1,
GLfloat y1,
GLfloat x2,
GLfloat y2,
GLfloat glyph_x1,
GLfloat glyph_y1,
GLfloat glyph_x2,
GLfloat glyph_y2);
 
cairo_private void
_cairo_gl_composite_flush (cairo_gl_context_t *ctx);
 
cairo_private void
_cairo_gl_context_destroy_operand (cairo_gl_context_t *ctx,
cairo_gl_tex_t tex_unit);
 
cairo_private cairo_bool_t
_cairo_gl_get_image_format_and_type (pixman_format_code_t pixman_format,
GLenum *internal_format, GLenum *format,
GLenum *type, cairo_bool_t *has_alpha);
 
cairo_private void
_cairo_gl_surface_scaled_font_fini ( cairo_scaled_font_t *scaled_font);
 
cairo_private void
_cairo_gl_surface_scaled_glyph_fini (cairo_scaled_glyph_t *scaled_glyph,
cairo_scaled_font_t *scaled_font);
 
cairo_private void
_cairo_gl_glyph_cache_init (cairo_gl_glyph_cache_t *cache);
 
cairo_private void
_cairo_gl_glyph_cache_fini (cairo_gl_context_t *ctx,
cairo_gl_glyph_cache_t *cache);
 
cairo_private cairo_int_status_t
_cairo_gl_surface_show_glyphs (void *abstract_dst,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font,
cairo_clip_t *clip,
int *remaining_glyphs);
 
static inline int
_cairo_gl_y_flip (cairo_gl_surface_t *surface, int y)
{
if (surface->fb)
return y;
else
return (surface->height - 1) - y;
}
 
cairo_private cairo_status_t
_cairo_gl_context_init_shaders (cairo_gl_context_t *ctx);
 
cairo_private void
_cairo_gl_context_fini_shaders (cairo_gl_context_t *ctx);
 
static cairo_always_inline cairo_bool_t
_cairo_gl_context_is_flushed (cairo_gl_context_t *ctx)
{
return ctx->vb == NULL;
}
 
cairo_private cairo_status_t
_cairo_gl_get_shader_by_type (cairo_gl_context_t *ctx,
cairo_gl_operand_type_t source,
cairo_gl_operand_type_t mask,
cairo_gl_shader_in_t in,
cairo_gl_shader_t **shader);
 
cairo_private void
_cairo_gl_shader_bind_float (cairo_gl_context_t *ctx,
const char *name,
float value);
 
cairo_private void
_cairo_gl_shader_bind_vec2 (cairo_gl_context_t *ctx,
const char *name,
float value0, float value1);
 
cairo_private void
_cairo_gl_shader_bind_vec3 (cairo_gl_context_t *ctx,
const char *name,
float value0,
float value1,
float value2);
 
cairo_private void
_cairo_gl_shader_bind_vec4 (cairo_gl_context_t *ctx,
const char *name,
float value0, float value1,
float value2, float value3);
 
cairo_private void
_cairo_gl_shader_bind_matrix (cairo_gl_context_t *ctx,
const char *name,
cairo_matrix_t* m);
 
cairo_private void
_cairo_gl_shader_bind_texture (cairo_gl_context_t *ctx,
const char *name,
GLuint tex_unit);
 
cairo_private void
_cairo_gl_set_shader (cairo_gl_context_t *ctx,
cairo_gl_shader_t *shader);
 
cairo_private void
_cairo_gl_shader_fini (cairo_gl_context_t *ctx, cairo_gl_shader_t *shader);
 
slim_hidden_proto (cairo_gl_surface_create);
slim_hidden_proto (cairo_gl_surface_create_for_texture);
 
#endif /* CAIRO_GL_PRIVATE_H */
/programs/develop/libraries/cairo/src/cairo-gl.h
0,0 → 1,119
/* Cairo - a vector graphics library with display and print output
*
* Copyright © 2009 Eric Anholt
* Copyright © 2009 Chris Wilson
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Eric Anholt.
*/
 
#ifndef CAIRO_GL_H
#define CAIRO_GL_H
 
#include "cairo.h"
 
#if CAIRO_HAS_GL_SURFACE
 
CAIRO_BEGIN_DECLS
 
cairo_public cairo_surface_t *
cairo_gl_surface_create (cairo_device_t *device,
cairo_content_t content,
int width, int height);
 
cairo_public cairo_surface_t *
cairo_gl_surface_create_for_texture (cairo_device_t *abstract_device,
cairo_content_t content,
unsigned int tex,
int width, int height);
cairo_public void
cairo_gl_surface_set_size (cairo_surface_t *surface, int width, int height);
 
cairo_public int
cairo_gl_surface_get_width (cairo_surface_t *abstract_surface);
 
cairo_public int
cairo_gl_surface_get_height (cairo_surface_t *abstract_surface);
 
cairo_public void
cairo_gl_surface_swapbuffers (cairo_surface_t *surface);
 
#if CAIRO_HAS_GLX_FUNCTIONS
#include <GL/glx.h>
 
cairo_public cairo_device_t *
cairo_glx_device_create (Display *dpy, GLXContext gl_ctx);
 
cairo_public Display *
cairo_glx_device_get_display (cairo_device_t *device);
 
cairo_public GLXContext
cairo_glx_device_get_context (cairo_device_t *device);
 
cairo_public cairo_surface_t *
cairo_gl_surface_create_for_window (cairo_device_t *device,
Window win,
int width, int height);
#endif
 
#if CAIRO_HAS_WGL_FUNCTIONS
#include <windows.h>
 
cairo_public cairo_device_t *
cairo_wgl_device_create (HGLRC rc);
 
cairo_public HGLRC
cairo_wgl_device_get_context (cairo_device_t *device);
 
cairo_public cairo_surface_t *
cairo_gl_surface_create_for_dc (cairo_device_t *device,
HDC dc,
int width,
int height);
#endif
 
#if CAIRO_HAS_EGL_FUNCTIONS
#include <EGL/egl.h>
 
cairo_public cairo_device_t *
cairo_egl_device_create (EGLDisplay dpy, EGLContext egl);
 
cairo_public cairo_surface_t *
cairo_gl_surface_create_for_egl (cairo_device_t *device,
EGLSurface egl,
int width,
int height);
 
#endif
 
CAIRO_END_DECLS
 
#else /* CAIRO_HAS_GL_SURFACE */
# error Cairo was not compiled with support for the GL backend
#endif /* CAIRO_HAS_GL_SURFACE */
 
#endif /* CAIRO_GL_H */
/programs/develop/libraries/cairo/src/cairo-gstate-private.h
0,0 → 1,385
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2005 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
* Carl D. Worth <cworth@redhat.com>
*/
 
#ifndef CAIRO_GSTATE_PRIVATE_H
#define CAIRO_GSTATE_PRIVATE_H
 
#include "cairo-clip-private.h"
 
struct _cairo_gstate {
cairo_operator_t op;
 
double tolerance;
cairo_antialias_t antialias;
 
cairo_stroke_style_t stroke_style;
 
cairo_fill_rule_t fill_rule;
 
cairo_font_face_t *font_face;
cairo_scaled_font_t *scaled_font; /* Specific to the current CTM */
cairo_scaled_font_t *previous_scaled_font; /* holdover */
cairo_matrix_t font_matrix;
cairo_font_options_t font_options;
 
cairo_clip_t clip;
 
cairo_surface_t *target; /* The target to which all rendering is directed */
cairo_surface_t *parent_target; /* The previous target which was receiving rendering */
cairo_surface_t *original_target; /* The original target the initial gstate was created with */
 
/* the user is allowed to update the device after we have cached the matrices... */
cairo_observer_t device_transform_observer;
 
cairo_matrix_t ctm;
cairo_matrix_t ctm_inverse;
cairo_matrix_t source_ctm_inverse; /* At the time ->source was set */
cairo_bool_t is_identity;
 
cairo_pattern_t *source;
 
struct _cairo_gstate *next;
};
 
/* cairo-gstate.c */
cairo_private cairo_status_t
_cairo_gstate_init (cairo_gstate_t *gstate,
cairo_surface_t *target);
 
cairo_private void
_cairo_gstate_fini (cairo_gstate_t *gstate);
 
cairo_private cairo_status_t
_cairo_gstate_save (cairo_gstate_t **gstate, cairo_gstate_t **freelist);
 
cairo_private cairo_status_t
_cairo_gstate_restore (cairo_gstate_t **gstate, cairo_gstate_t **freelist);
 
cairo_private cairo_bool_t
_cairo_gstate_is_redirected (cairo_gstate_t *gstate);
 
cairo_private cairo_status_t
_cairo_gstate_redirect_target (cairo_gstate_t *gstate, cairo_surface_t *child);
 
cairo_private cairo_surface_t *
_cairo_gstate_get_target (cairo_gstate_t *gstate);
 
cairo_private cairo_surface_t *
_cairo_gstate_get_parent_target (cairo_gstate_t *gstate);
 
cairo_private cairo_surface_t *
_cairo_gstate_get_original_target (cairo_gstate_t *gstate);
 
cairo_private cairo_clip_t *
_cairo_gstate_get_clip (cairo_gstate_t *gstate);
 
cairo_private cairo_status_t
_cairo_gstate_set_source (cairo_gstate_t *gstate, cairo_pattern_t *source);
 
cairo_private cairo_pattern_t *
_cairo_gstate_get_source (cairo_gstate_t *gstate);
 
cairo_private cairo_status_t
_cairo_gstate_set_operator (cairo_gstate_t *gstate, cairo_operator_t op);
 
cairo_private cairo_operator_t
_cairo_gstate_get_operator (cairo_gstate_t *gstate);
 
cairo_private cairo_status_t
_cairo_gstate_set_tolerance (cairo_gstate_t *gstate, double tolerance);
 
cairo_private double
_cairo_gstate_get_tolerance (cairo_gstate_t *gstate);
 
cairo_private cairo_status_t
_cairo_gstate_set_fill_rule (cairo_gstate_t *gstate, cairo_fill_rule_t fill_rule);
 
cairo_private cairo_fill_rule_t
_cairo_gstate_get_fill_rule (cairo_gstate_t *gstate);
 
cairo_private cairo_status_t
_cairo_gstate_set_line_width (cairo_gstate_t *gstate, double width);
 
cairo_private double
_cairo_gstate_get_line_width (cairo_gstate_t *gstate);
 
cairo_private cairo_status_t
_cairo_gstate_set_line_cap (cairo_gstate_t *gstate, cairo_line_cap_t line_cap);
 
cairo_private cairo_line_cap_t
_cairo_gstate_get_line_cap (cairo_gstate_t *gstate);
 
cairo_private cairo_status_t
_cairo_gstate_set_line_join (cairo_gstate_t *gstate, cairo_line_join_t line_join);
 
cairo_private cairo_line_join_t
_cairo_gstate_get_line_join (cairo_gstate_t *gstate);
 
cairo_private cairo_status_t
_cairo_gstate_set_dash (cairo_gstate_t *gstate, const double *dash, int num_dashes, double offset);
 
cairo_private void
_cairo_gstate_get_dash (cairo_gstate_t *gstate, double *dash, int *num_dashes, double *offset);
 
cairo_private cairo_status_t
_cairo_gstate_set_miter_limit (cairo_gstate_t *gstate, double limit);
 
cairo_private double
_cairo_gstate_get_miter_limit (cairo_gstate_t *gstate);
 
cairo_private void
_cairo_gstate_get_matrix (cairo_gstate_t *gstate, cairo_matrix_t *matrix);
 
cairo_private cairo_status_t
_cairo_gstate_translate (cairo_gstate_t *gstate, double tx, double ty);
 
cairo_private cairo_status_t
_cairo_gstate_scale (cairo_gstate_t *gstate, double sx, double sy);
 
cairo_private cairo_status_t
_cairo_gstate_rotate (cairo_gstate_t *gstate, double angle);
 
cairo_private cairo_status_t
_cairo_gstate_transform (cairo_gstate_t *gstate,
const cairo_matrix_t *matrix);
 
cairo_private cairo_status_t
_cairo_gstate_set_matrix (cairo_gstate_t *gstate,
const cairo_matrix_t *matrix);
 
cairo_private void
_cairo_gstate_identity_matrix (cairo_gstate_t *gstate);
 
cairo_private void
_cairo_gstate_user_to_device (cairo_gstate_t *gstate, double *x, double *y);
 
cairo_private void
_cairo_gstate_user_to_device_distance (cairo_gstate_t *gstate, double *dx, double *dy);
 
cairo_private void
_cairo_gstate_device_to_user (cairo_gstate_t *gstate, double *x, double *y);
 
cairo_private void
_cairo_gstate_device_to_user_distance (cairo_gstate_t *gstate, double *dx, double *dy);
 
cairo_private void
_do_cairo_gstate_user_to_backend (cairo_gstate_t *gstate, double *x, double *y);
 
static inline void
_cairo_gstate_user_to_backend (cairo_gstate_t *gstate, double *x, double *y)
{
if (! gstate->is_identity)
_do_cairo_gstate_user_to_backend (gstate, x, y);
}
 
cairo_private void
_do_cairo_gstate_backend_to_user (cairo_gstate_t *gstate, double *x, double *y);
 
static inline void
_cairo_gstate_backend_to_user (cairo_gstate_t *gstate, double *x, double *y)
{
if (! gstate->is_identity)
_do_cairo_gstate_backend_to_user (gstate, x, y);
}
 
cairo_private void
_cairo_gstate_backend_to_user_rectangle (cairo_gstate_t *gstate,
double *x1, double *y1,
double *x2, double *y2,
cairo_bool_t *is_tight);
 
cairo_private void
_cairo_gstate_path_extents (cairo_gstate_t *gstate,
cairo_path_fixed_t *path,
double *x1, double *y1,
double *x2, double *y2);
 
cairo_private cairo_status_t
_cairo_gstate_paint (cairo_gstate_t *gstate);
 
cairo_private cairo_status_t
_cairo_gstate_mask (cairo_gstate_t *gstate,
cairo_pattern_t *mask);
 
cairo_private cairo_status_t
_cairo_gstate_stroke (cairo_gstate_t *gstate, cairo_path_fixed_t *path);
 
cairo_private cairo_status_t
_cairo_gstate_fill (cairo_gstate_t *gstate, cairo_path_fixed_t *path);
 
cairo_private cairo_status_t
_cairo_gstate_copy_page (cairo_gstate_t *gstate);
 
cairo_private cairo_status_t
_cairo_gstate_show_page (cairo_gstate_t *gstate);
 
cairo_private cairo_status_t
_cairo_gstate_stroke_extents (cairo_gstate_t *gstate,
cairo_path_fixed_t *path,
double *x1, double *y1,
double *x2, double *y2);
 
cairo_private cairo_status_t
_cairo_gstate_fill_extents (cairo_gstate_t *gstate,
cairo_path_fixed_t *path,
double *x1, double *y1,
double *x2, double *y2);
 
cairo_private cairo_status_t
_cairo_gstate_in_stroke (cairo_gstate_t *gstate,
cairo_path_fixed_t *path,
double x,
double y,
cairo_bool_t *inside_ret);
 
cairo_private cairo_bool_t
_cairo_gstate_in_fill (cairo_gstate_t *gstate,
cairo_path_fixed_t *path,
double x,
double y);
 
cairo_private cairo_bool_t
_cairo_gstate_in_clip (cairo_gstate_t *gstate,
double x,
double y);
 
cairo_private cairo_status_t
_cairo_gstate_clip (cairo_gstate_t *gstate, cairo_path_fixed_t *path);
 
cairo_private cairo_status_t
_cairo_gstate_reset_clip (cairo_gstate_t *gstate);
 
cairo_private cairo_bool_t
_cairo_gstate_clip_extents (cairo_gstate_t *gstate,
double *x1,
double *y1,
double *x2,
double *y2);
 
cairo_private cairo_rectangle_list_t*
_cairo_gstate_copy_clip_rectangle_list (cairo_gstate_t *gstate);
 
cairo_private cairo_status_t
_cairo_gstate_show_surface (cairo_gstate_t *gstate,
cairo_surface_t *surface,
double x,
double y,
double width,
double height);
 
cairo_private cairo_status_t
_cairo_gstate_select_font_face (cairo_gstate_t *gstate,
const char *family,
cairo_font_slant_t slant,
cairo_font_weight_t weight);
 
cairo_private cairo_status_t
_cairo_gstate_set_font_size (cairo_gstate_t *gstate,
double size);
 
cairo_private void
_cairo_gstate_get_font_matrix (cairo_gstate_t *gstate,
cairo_matrix_t *matrix);
 
cairo_private cairo_status_t
_cairo_gstate_set_font_matrix (cairo_gstate_t *gstate,
const cairo_matrix_t *matrix);
 
cairo_private void
_cairo_gstate_get_font_options (cairo_gstate_t *gstate,
cairo_font_options_t *options);
 
cairo_private void
_cairo_gstate_set_font_options (cairo_gstate_t *gstate,
const cairo_font_options_t *options);
 
cairo_private cairo_status_t
_cairo_gstate_get_font_face (cairo_gstate_t *gstate,
cairo_font_face_t **font_face);
 
cairo_private cairo_status_t
_cairo_gstate_get_scaled_font (cairo_gstate_t *gstate,
cairo_scaled_font_t **scaled_font);
 
cairo_private cairo_status_t
_cairo_gstate_get_font_extents (cairo_gstate_t *gstate,
cairo_font_extents_t *extents);
 
cairo_private cairo_status_t
_cairo_gstate_set_font_face (cairo_gstate_t *gstate,
cairo_font_face_t *font_face);
 
cairo_private cairo_status_t
_cairo_gstate_text_to_glyphs (cairo_gstate_t *gstate,
double x,
double y,
const char *utf8,
int utf8_len,
cairo_glyph_t **glyphs,
int *num_glyphs,
cairo_text_cluster_t **clusters,
int *num_clusters,
cairo_text_cluster_flags_t *cluster_flags);
 
cairo_private cairo_status_t
_cairo_gstate_glyph_extents (cairo_gstate_t *gstate,
const cairo_glyph_t *glyphs,
int num_glyphs,
cairo_text_extents_t *extents);
 
cairo_private cairo_status_t
_cairo_gstate_show_text_glyphs (cairo_gstate_t *gstate,
const char *utf8,
int utf8_len,
const cairo_glyph_t *glyphs,
int num_glyphs,
const cairo_text_cluster_t *clusters,
int num_clusters,
cairo_text_cluster_flags_t cluster_flags);
 
cairo_private cairo_status_t
_cairo_gstate_glyph_path (cairo_gstate_t *gstate,
const cairo_glyph_t *glyphs,
int num_glyphs,
cairo_path_fixed_t *path);
 
cairo_private cairo_status_t
_cairo_gstate_set_antialias (cairo_gstate_t *gstate,
cairo_antialias_t antialias);
 
cairo_private cairo_antialias_t
_cairo_gstate_get_antialias (cairo_gstate_t *gstate);
 
#endif /* CAIRO_GSTATE_PRIVATE_H */
/programs/develop/libraries/cairo/src/cairo-gstate.c
0,0 → 1,2309
/* 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., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
*/
 
#include "cairoint.h"
 
#include "cairo-clip-private.h"
#include "cairo-error-private.h"
#include "cairo-gstate-private.h"
 
#if _XOPEN_SOURCE >= 600 || defined (_ISOC99_SOURCE)
#define ISFINITE(x) isfinite (x)
#else
#define ISFINITE(x) ((x) * (x) >= 0.) /* check for NaNs */
#endif
 
static cairo_status_t
_cairo_gstate_init_copy (cairo_gstate_t *gstate, cairo_gstate_t *other);
 
static cairo_status_t
_cairo_gstate_ensure_font_face (cairo_gstate_t *gstate);
 
static cairo_status_t
_cairo_gstate_ensure_scaled_font (cairo_gstate_t *gstate);
 
static void
_cairo_gstate_unset_scaled_font (cairo_gstate_t *gstate);
 
static cairo_status_t
_cairo_gstate_transform_glyphs_to_backend (cairo_gstate_t *gstate,
const cairo_glyph_t *glyphs,
int num_glyphs,
const cairo_text_cluster_t *clusters,
int num_clusters,
cairo_text_cluster_flags_t cluster_flags,
cairo_glyph_t *transformed_glyphs,
int *num_transformed_glyphs,
cairo_text_cluster_t *transformed_clusters);
 
static void
_cairo_gstate_update_device_transform (cairo_observer_t *observer,
void *arg)
{
cairo_gstate_t *gstate = cairo_container_of (observer,
cairo_gstate_t,
device_transform_observer);
 
gstate->is_identity = (_cairo_matrix_is_identity (&gstate->ctm) &&
_cairo_matrix_is_identity (&gstate->target->device_transform));
}
 
cairo_status_t
_cairo_gstate_init (cairo_gstate_t *gstate,
cairo_surface_t *target)
{
cairo_status_t status;
 
VG (VALGRIND_MAKE_MEM_UNDEFINED (gstate, sizeof (cairo_gstate_t)));
 
gstate->next = NULL;
 
gstate->op = CAIRO_GSTATE_OPERATOR_DEFAULT;
 
gstate->tolerance = CAIRO_GSTATE_TOLERANCE_DEFAULT;
gstate->antialias = CAIRO_ANTIALIAS_DEFAULT;
 
_cairo_stroke_style_init (&gstate->stroke_style);
 
gstate->fill_rule = CAIRO_GSTATE_FILL_RULE_DEFAULT;
 
gstate->font_face = NULL;
gstate->scaled_font = NULL;
gstate->previous_scaled_font = NULL;
 
cairo_matrix_init_scale (&gstate->font_matrix,
CAIRO_GSTATE_DEFAULT_FONT_SIZE,
CAIRO_GSTATE_DEFAULT_FONT_SIZE);
 
_cairo_font_options_init_default (&gstate->font_options);
 
_cairo_clip_init (&gstate->clip);
 
gstate->target = cairo_surface_reference (target);
gstate->parent_target = NULL;
gstate->original_target = cairo_surface_reference (target);
 
gstate->device_transform_observer.callback = _cairo_gstate_update_device_transform;
cairo_list_add (&gstate->device_transform_observer.link,
&gstate->target->device_transform_observers);
 
gstate->is_identity = _cairo_matrix_is_identity (&gstate->target->device_transform);
cairo_matrix_init_identity (&gstate->ctm);
gstate->ctm_inverse = gstate->ctm;
gstate->source_ctm_inverse = gstate->ctm;
 
gstate->source = (cairo_pattern_t *) &_cairo_pattern_black.base;
 
/* 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). */
status = target->status;
if (unlikely (status))
return status;
 
status = gstate->source->status;
if (unlikely (status))
return status;
 
return CAIRO_STATUS_SUCCESS;
}
 
/**
* _cairo_gstate_init_copy:
*
* Initialize @gstate by performing a deep copy of state fields from
* @other. Note that gstate->next is not copied but is set to %NULL by
* this function.
**/
static cairo_status_t
_cairo_gstate_init_copy (cairo_gstate_t *gstate, cairo_gstate_t *other)
{
cairo_status_t status;
 
VG (VALGRIND_MAKE_MEM_UNDEFINED (gstate, sizeof (cairo_gstate_t)));
 
gstate->op = other->op;
 
gstate->tolerance = other->tolerance;
gstate->antialias = other->antialias;
 
status = _cairo_stroke_style_init_copy (&gstate->stroke_style,
&other->stroke_style);
if (unlikely (status))
return status;
 
gstate->fill_rule = other->fill_rule;
 
gstate->font_face = cairo_font_face_reference (other->font_face);
gstate->scaled_font = cairo_scaled_font_reference (other->scaled_font);
gstate->previous_scaled_font = cairo_scaled_font_reference (other->previous_scaled_font);
 
gstate->font_matrix = other->font_matrix;
 
_cairo_font_options_init_copy (&gstate->font_options , &other->font_options);
 
_cairo_clip_init_copy (&gstate->clip, &other->clip);
 
gstate->target = cairo_surface_reference (other->target);
/* parent_target is always set to NULL; it's only ever set by redirect_target */
gstate->parent_target = NULL;
gstate->original_target = cairo_surface_reference (other->original_target);
 
gstate->device_transform_observer.callback = _cairo_gstate_update_device_transform;
cairo_list_add (&gstate->device_transform_observer.link,
&gstate->target->device_transform_observers);
 
gstate->is_identity = other->is_identity;
gstate->ctm = other->ctm;
gstate->ctm_inverse = other->ctm_inverse;
gstate->source_ctm_inverse = other->source_ctm_inverse;
 
gstate->source = cairo_pattern_reference (other->source);
 
gstate->next = NULL;
 
return CAIRO_STATUS_SUCCESS;
}
 
void
_cairo_gstate_fini (cairo_gstate_t *gstate)
{
_cairo_stroke_style_fini (&gstate->stroke_style);
 
cairo_font_face_destroy (gstate->font_face);
gstate->font_face = NULL;
 
cairo_scaled_font_destroy (gstate->previous_scaled_font);
gstate->previous_scaled_font = NULL;
 
cairo_scaled_font_destroy (gstate->scaled_font);
gstate->scaled_font = NULL;
 
_cairo_clip_reset (&gstate->clip);
 
cairo_list_del (&gstate->device_transform_observer.link);
 
cairo_surface_destroy (gstate->target);
gstate->target = NULL;
 
cairo_surface_destroy (gstate->parent_target);
gstate->parent_target = NULL;
 
cairo_surface_destroy (gstate->original_target);
gstate->original_target = NULL;
 
cairo_pattern_destroy (gstate->source);
gstate->source = NULL;
 
VG (VALGRIND_MAKE_MEM_NOACCESS (gstate, sizeof (cairo_gstate_t)));
}
 
/**
* _cairo_gstate_save:
* @gstate: input/output gstate pointer
*
* Makes a copy of the current state of @gstate and saves it
* to @gstate->next, then put the address of the newly allcated
* copy into @gstate. _cairo_gstate_restore() reverses this.
**/
cairo_status_t
_cairo_gstate_save (cairo_gstate_t **gstate, cairo_gstate_t **freelist)
{
cairo_gstate_t *top;
cairo_status_t status;
 
if (CAIRO_INJECT_FAULT ())
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
top = *freelist;
if (top == NULL) {
top = malloc (sizeof (cairo_gstate_t));
if (unlikely (top == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
} else
*freelist = top->next;
 
status = _cairo_gstate_init_copy (top, *gstate);
if (unlikely (status)) {
top->next = *freelist;
*freelist = top;
return status;
}
 
top->next = *gstate;
*gstate = top;
 
return CAIRO_STATUS_SUCCESS;
}
 
/**
* _cairo_gstate_restore:
* @gstate: input/output gstate pointer
*
* Reverses the effects of one _cairo_gstate_save() call.
**/
cairo_status_t
_cairo_gstate_restore (cairo_gstate_t **gstate, cairo_gstate_t **freelist)
{
cairo_gstate_t *top;
 
top = *gstate;
if (top->next == NULL)
return _cairo_error (CAIRO_STATUS_INVALID_RESTORE);
 
*gstate = top->next;
 
_cairo_gstate_fini (top);
VG (VALGRIND_MAKE_MEM_UNDEFINED (&top->next, sizeof (cairo_gstate_t *)));
top->next = *freelist;
*freelist = top;
 
return CAIRO_STATUS_SUCCESS;
}
 
/**
* _cairo_gstate_redirect_target:
* @gstate: a #cairo_gstate_t
* @child: the new child target
*
* Redirect @gstate rendering to a "child" target. The original
* "parent" target with which the gstate was created will not be
* affected. See _cairo_gstate_get_target().
*
* Unless the redirected target has the same device offsets as the
* original #cairo_t target, the clip will be INVALID after this call,
* and the caller should either recreate or reset the clip.
**/
cairo_status_t
_cairo_gstate_redirect_target (cairo_gstate_t *gstate, cairo_surface_t *child)
{
cairo_matrix_t matrix;
 
/* If this gstate is already redirected, this is an error; we need a
* new gstate to be able to redirect */
assert (gstate->parent_target == NULL);
 
/* Set up our new parent_target based on our current target;
* gstate->parent_target will take the ref that is held by gstate->target
*/
cairo_surface_destroy (gstate->parent_target);
gstate->parent_target = gstate->target;
 
/* Now set up our new target; we overwrite gstate->target directly,
* since its ref is now owned by gstate->parent_target */
gstate->target = cairo_surface_reference (child);
gstate->is_identity &= _cairo_matrix_is_identity (&child->device_transform);
cairo_list_move (&gstate->device_transform_observer.link,
&gstate->target->device_transform_observers);
 
/* The clip is in surface backend coordinates for the previous target;
* translate it into the child's backend coordinates. */
cairo_matrix_init_translate (&matrix,
child->device_transform.x0 - gstate->parent_target->device_transform.x0,
child->device_transform.y0 - gstate->parent_target->device_transform.y0);
_cairo_clip_reset (&gstate->clip);
return _cairo_clip_init_copy_transformed (&gstate->clip,
&gstate->next->clip,
&matrix);
}
 
/**
* _cairo_gstate_is_redirected
* @gstate: a #cairo_gstate_t
*
* This space left intentionally blank.
*
* Return value: %TRUE if the gstate is redirected to a target
* different than the original, %FALSE otherwise.
**/
cairo_bool_t
_cairo_gstate_is_redirected (cairo_gstate_t *gstate)
{
return (gstate->target != gstate->original_target);
}
 
/**
* _cairo_gstate_get_target:
* @gstate: a #cairo_gstate_t
*
* Return the current drawing target; if drawing is not redirected,
* this will be the same as _cairo_gstate_get_original_target().
*
* Return value: the current target surface
**/
cairo_surface_t *
_cairo_gstate_get_target (cairo_gstate_t *gstate)
{
return gstate->target;
}
 
/**
* _cairo_gstate_get_parent_target:
* @gstate: a #cairo_gstate_t
*
* Return the parent surface of the current drawing target surface;
* if this particular gstate isn't a redirect gstate, this will return %NULL.
**/
cairo_surface_t *
_cairo_gstate_get_parent_target (cairo_gstate_t *gstate)
{
return gstate->parent_target;
}
 
/**
* _cairo_gstate_get_original_target:
* @gstate: a #cairo_gstate_t
*
* Return the original target with which @gstate was created. This
* function always returns the original target independent of any
* child target that may have been set with
* _cairo_gstate_redirect_target.
*
* Return value: the original target surface
**/
cairo_surface_t *
_cairo_gstate_get_original_target (cairo_gstate_t *gstate)
{
return gstate->original_target;
}
 
/**
* _cairo_gstate_get_clip:
* @gstate: a #cairo_gstate_t
*
* This space left intentionally blank.
*
* Return value: a pointer to the gstate's #cairo_clip_t structure.
*/
cairo_clip_t *
_cairo_gstate_get_clip (cairo_gstate_t *gstate)
{
return &gstate->clip;
}
 
cairo_status_t
_cairo_gstate_set_source (cairo_gstate_t *gstate,
cairo_pattern_t *source)
{
if (source->status)
return source->status;
 
source = cairo_pattern_reference (source);
cairo_pattern_destroy (gstate->source);
gstate->source = source;
gstate->source_ctm_inverse = gstate->ctm_inverse;
 
return CAIRO_STATUS_SUCCESS;
}
 
cairo_pattern_t *
_cairo_gstate_get_source (cairo_gstate_t *gstate)
{
if (gstate->source == &_cairo_pattern_black.base) {
/* do not expose the static object to the user */
gstate->source = _cairo_pattern_create_solid (CAIRO_COLOR_BLACK);
}
 
return gstate->source;
}
 
cairo_status_t
_cairo_gstate_set_operator (cairo_gstate_t *gstate, cairo_operator_t op)
{
gstate->op = op;
 
return CAIRO_STATUS_SUCCESS;
}
 
cairo_operator_t
_cairo_gstate_get_operator (cairo_gstate_t *gstate)
{
return gstate->op;
}
 
cairo_status_t
_cairo_gstate_set_tolerance (cairo_gstate_t *gstate, double tolerance)
{
gstate->tolerance = tolerance;
 
return CAIRO_STATUS_SUCCESS;
}
 
double
_cairo_gstate_get_tolerance (cairo_gstate_t *gstate)
{
return gstate->tolerance;
}
 
cairo_status_t
_cairo_gstate_set_fill_rule (cairo_gstate_t *gstate, cairo_fill_rule_t fill_rule)
{
gstate->fill_rule = fill_rule;
 
return CAIRO_STATUS_SUCCESS;
}
 
cairo_fill_rule_t
_cairo_gstate_get_fill_rule (cairo_gstate_t *gstate)
{
return gstate->fill_rule;
}
 
cairo_status_t
_cairo_gstate_set_line_width (cairo_gstate_t *gstate, double width)
{
gstate->stroke_style.line_width = width;
 
return CAIRO_STATUS_SUCCESS;
}
 
double
_cairo_gstate_get_line_width (cairo_gstate_t *gstate)
{
return gstate->stroke_style.line_width;
}
 
cairo_status_t
_cairo_gstate_set_line_cap (cairo_gstate_t *gstate, cairo_line_cap_t line_cap)
{
gstate->stroke_style.line_cap = line_cap;
 
return CAIRO_STATUS_SUCCESS;
}
 
cairo_line_cap_t
_cairo_gstate_get_line_cap (cairo_gstate_t *gstate)
{
return gstate->stroke_style.line_cap;
}
 
cairo_status_t
_cairo_gstate_set_line_join (cairo_gstate_t *gstate, cairo_line_join_t line_join)
{
gstate->stroke_style.line_join = line_join;
 
return CAIRO_STATUS_SUCCESS;
}
 
cairo_line_join_t
_cairo_gstate_get_line_join (cairo_gstate_t *gstate)
{
return gstate->stroke_style.line_join;
}
 
cairo_status_t
_cairo_gstate_set_dash (cairo_gstate_t *gstate, const double *dash, int num_dashes, double offset)
{
unsigned int i;
double dash_total;
 
if (gstate->stroke_style.dash)
free (gstate->stroke_style.dash);
 
gstate->stroke_style.num_dashes = num_dashes;
 
if (gstate->stroke_style.num_dashes == 0) {
gstate->stroke_style.dash = NULL;
gstate->stroke_style.dash_offset = 0.0;
return CAIRO_STATUS_SUCCESS;
}
 
gstate->stroke_style.dash = _cairo_malloc_ab (gstate->stroke_style.num_dashes, sizeof (double));
if (unlikely (gstate->stroke_style.dash == NULL)) {
gstate->stroke_style.num_dashes = 0;
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
 
memcpy (gstate->stroke_style.dash, dash, gstate->stroke_style.num_dashes * sizeof (double));
 
dash_total = 0.0;
for (i = 0; i < gstate->stroke_style.num_dashes; i++) {
if (gstate->stroke_style.dash[i] < 0)
return _cairo_error (CAIRO_STATUS_INVALID_DASH);
 
dash_total += gstate->stroke_style.dash[i];
}
 
if (dash_total == 0.0)
return _cairo_error (CAIRO_STATUS_INVALID_DASH);
 
/* An odd dash value indicate symmetric repeating, so the total
* is twice as long. */
if (gstate->stroke_style.num_dashes & 1)
dash_total *= 2;
 
/* The dashing code doesn't like a negative offset or a big positive
* offset, so we compute an equivalent offset which is guaranteed to be
* positive and less than twice the pattern length. */
offset = fmod (offset, dash_total);
if (offset < 0.0)
offset += dash_total;
if (offset <= 0.0) /* Take care of -0 */
offset = 0.0;
gstate->stroke_style.dash_offset = offset;
 
return CAIRO_STATUS_SUCCESS;
}
 
void
_cairo_gstate_get_dash (cairo_gstate_t *gstate,
double *dashes,
int *num_dashes,
double *offset)
{
if (dashes) {
memcpy (dashes,
gstate->stroke_style.dash,
sizeof (double) * gstate->stroke_style.num_dashes);
}
 
if (num_dashes)
*num_dashes = gstate->stroke_style.num_dashes;
 
if (offset)
*offset = gstate->stroke_style.dash_offset;
}
 
cairo_status_t
_cairo_gstate_set_miter_limit (cairo_gstate_t *gstate, double limit)
{
gstate->stroke_style.miter_limit = limit;
 
return CAIRO_STATUS_SUCCESS;
}
 
double
_cairo_gstate_get_miter_limit (cairo_gstate_t *gstate)
{
return gstate->stroke_style.miter_limit;
}
 
void
_cairo_gstate_get_matrix (cairo_gstate_t *gstate, cairo_matrix_t *matrix)
{
*matrix = gstate->ctm;
}
 
cairo_status_t
_cairo_gstate_translate (cairo_gstate_t *gstate, double tx, double ty)
{
cairo_matrix_t tmp;
 
if (! ISFINITE (tx) || ! ISFINITE (ty))
return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
 
_cairo_gstate_unset_scaled_font (gstate);
 
cairo_matrix_init_translate (&tmp, tx, ty);
cairo_matrix_multiply (&gstate->ctm, &tmp, &gstate->ctm);
gstate->is_identity = FALSE;
 
/* paranoid check against gradual numerical instability */
if (! _cairo_matrix_is_invertible (&gstate->ctm))
return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
 
cairo_matrix_init_translate (&tmp, -tx, -ty);
cairo_matrix_multiply (&gstate->ctm_inverse, &gstate->ctm_inverse, &tmp);
 
return CAIRO_STATUS_SUCCESS;
}
 
cairo_status_t
_cairo_gstate_scale (cairo_gstate_t *gstate, double sx, double sy)
{
cairo_matrix_t tmp;
 
if (sx * sy == 0.) /* either sx or sy is 0, or det == 0 due to underflow */
return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
if (! ISFINITE (sx) || ! ISFINITE (sy))
return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
 
_cairo_gstate_unset_scaled_font (gstate);
 
cairo_matrix_init_scale (&tmp, sx, sy);
cairo_matrix_multiply (&gstate->ctm, &tmp, &gstate->ctm);
gstate->is_identity = FALSE;
 
/* paranoid check against gradual numerical instability */
if (! _cairo_matrix_is_invertible (&gstate->ctm))
return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
 
cairo_matrix_init_scale (&tmp, 1/sx, 1/sy);
cairo_matrix_multiply (&gstate->ctm_inverse, &gstate->ctm_inverse, &tmp);
 
return CAIRO_STATUS_SUCCESS;
}
 
cairo_status_t
_cairo_gstate_rotate (cairo_gstate_t *gstate, double angle)
{
cairo_matrix_t tmp;
 
if (angle == 0.)
return CAIRO_STATUS_SUCCESS;
 
if (! ISFINITE (angle))
return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
 
_cairo_gstate_unset_scaled_font (gstate);
 
cairo_matrix_init_rotate (&tmp, angle);
cairo_matrix_multiply (&gstate->ctm, &tmp, &gstate->ctm);
gstate->is_identity = FALSE;
 
/* paranoid check against gradual numerical instability */
if (! _cairo_matrix_is_invertible (&gstate->ctm))
return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
 
cairo_matrix_init_rotate (&tmp, -angle);
cairo_matrix_multiply (&gstate->ctm_inverse, &gstate->ctm_inverse, &tmp);
 
return CAIRO_STATUS_SUCCESS;
}
 
cairo_status_t
_cairo_gstate_transform (cairo_gstate_t *gstate,
const cairo_matrix_t *matrix)
{
cairo_matrix_t tmp;
cairo_status_t status;
 
if (! _cairo_matrix_is_invertible (matrix))
return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
 
if (_cairo_matrix_is_identity (matrix))
return CAIRO_STATUS_SUCCESS;
 
tmp = *matrix;
status = cairo_matrix_invert (&tmp);
if (unlikely (status))
return status;
 
_cairo_gstate_unset_scaled_font (gstate);
 
cairo_matrix_multiply (&gstate->ctm, matrix, &gstate->ctm);
cairo_matrix_multiply (&gstate->ctm_inverse, &gstate->ctm_inverse, &tmp);
gstate->is_identity = FALSE;
 
/* paranoid check against gradual numerical instability */
if (! _cairo_matrix_is_invertible (&gstate->ctm))
return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
 
return CAIRO_STATUS_SUCCESS;
}
 
cairo_status_t
_cairo_gstate_set_matrix (cairo_gstate_t *gstate,
const cairo_matrix_t *matrix)
{
cairo_status_t status;
 
if (memcmp (matrix, &gstate->ctm, sizeof (cairo_matrix_t)) == 0)
return CAIRO_STATUS_SUCCESS;
 
if (! _cairo_matrix_is_invertible (matrix))
return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
 
if (_cairo_matrix_is_identity (matrix)) {
_cairo_gstate_identity_matrix (gstate);
return CAIRO_STATUS_SUCCESS;
}
 
_cairo_gstate_unset_scaled_font (gstate);
 
gstate->ctm = *matrix;
gstate->ctm_inverse = *matrix;
status = cairo_matrix_invert (&gstate->ctm_inverse);
assert (status == CAIRO_STATUS_SUCCESS);
gstate->is_identity = FALSE;
 
return CAIRO_STATUS_SUCCESS;
}
 
void
_cairo_gstate_identity_matrix (cairo_gstate_t *gstate)
{
if (_cairo_matrix_is_identity (&gstate->ctm))
return;
 
_cairo_gstate_unset_scaled_font (gstate);
 
cairo_matrix_init_identity (&gstate->ctm);
cairo_matrix_init_identity (&gstate->ctm_inverse);
gstate->is_identity = _cairo_matrix_is_identity (&gstate->target->device_transform);
}
 
void
_cairo_gstate_user_to_device (cairo_gstate_t *gstate, double *x, double *y)
{
cairo_matrix_transform_point (&gstate->ctm, x, y);
}
 
void
_cairo_gstate_user_to_device_distance (cairo_gstate_t *gstate,
double *dx, double *dy)
{
cairo_matrix_transform_distance (&gstate->ctm, dx, dy);
}
 
void
_cairo_gstate_device_to_user (cairo_gstate_t *gstate, double *x, double *y)
{
cairo_matrix_transform_point (&gstate->ctm_inverse, x, y);
}
 
void
_cairo_gstate_device_to_user_distance (cairo_gstate_t *gstate,
double *dx, double *dy)
{
cairo_matrix_transform_distance (&gstate->ctm_inverse, dx, dy);
}
 
void
_do_cairo_gstate_user_to_backend (cairo_gstate_t *gstate, double *x, double *y)
{
cairo_matrix_transform_point (&gstate->ctm, x, y);
cairo_matrix_transform_point (&gstate->target->device_transform, x, y);
}
 
void
_do_cairo_gstate_backend_to_user (cairo_gstate_t *gstate, double *x, double *y)
{
cairo_matrix_transform_point (&gstate->target->device_transform_inverse, x, y);
cairo_matrix_transform_point (&gstate->ctm_inverse, x, y);
}
 
void
_cairo_gstate_backend_to_user_rectangle (cairo_gstate_t *gstate,
double *x1, double *y1,
double *x2, double *y2,
cairo_bool_t *is_tight)
{
cairo_matrix_t matrix_inverse;
 
cairo_matrix_multiply (&matrix_inverse,
&gstate->target->device_transform_inverse,
&gstate->ctm_inverse);
_cairo_matrix_transform_bounding_box (&matrix_inverse,
x1, y1, x2, y2, is_tight);
}
 
/* XXX: NYI
cairo_status_t
_cairo_gstate_stroke_to_path (cairo_gstate_t *gstate)
{
cairo_status_t status;
 
_cairo_pen_init (&gstate);
return CAIRO_STATUS_SUCCESS;
}
*/
 
void
_cairo_gstate_path_extents (cairo_gstate_t *gstate,
cairo_path_fixed_t *path,
double *x1, double *y1,
double *x2, double *y2)
{
cairo_box_t box;
double px1, py1, px2, py2;
 
if (_cairo_path_fixed_extents (path, &box)) {
px1 = _cairo_fixed_to_double (box.p1.x);
py1 = _cairo_fixed_to_double (box.p1.y);
px2 = _cairo_fixed_to_double (box.p2.x);
py2 = _cairo_fixed_to_double (box.p2.y);
 
_cairo_gstate_backend_to_user_rectangle (gstate,
&px1, &py1, &px2, &py2,
NULL);
} else {
px1 = 0.0;
py1 = 0.0;
px2 = 0.0;
py2 = 0.0;
}
 
if (x1)
*x1 = px1;
if (y1)
*y1 = py1;
if (x2)
*x2 = px2;
if (y2)
*y2 = py2;
}
 
static void
_cairo_gstate_copy_pattern (cairo_pattern_t *pattern,
const cairo_pattern_t *original)
{
/* First check if the we can replace the original with a much simpler
* pattern. For example, gradients that are uniform or just have a single
* stop can sometimes be replaced with a solid.
*/
 
if (_cairo_pattern_is_clear (original)) {
_cairo_pattern_init_solid ((cairo_solid_pattern_t *) pattern,
CAIRO_COLOR_TRANSPARENT);
return;
}
 
if (original->type == CAIRO_PATTERN_TYPE_LINEAR ||
original->type == CAIRO_PATTERN_TYPE_RADIAL)
{
cairo_color_t color;
if (_cairo_gradient_pattern_is_solid ((cairo_gradient_pattern_t *) original,
NULL,
&color))
{
_cairo_pattern_init_solid ((cairo_solid_pattern_t *) pattern,
&color);
return;
}
}
 
_cairo_pattern_init_static_copy (pattern, original);
}
 
static void
_cairo_gstate_copy_transformed_pattern (cairo_gstate_t *gstate,
cairo_pattern_t *pattern,
const cairo_pattern_t *original,
const cairo_matrix_t *ctm_inverse)
{
_cairo_gstate_copy_pattern (pattern, original);
 
/* apply device_transform first so that it is transformed by ctm_inverse */
if (original->type == CAIRO_PATTERN_TYPE_SURFACE) {
cairo_surface_pattern_t *surface_pattern;
cairo_surface_t *surface;
 
surface_pattern = (cairo_surface_pattern_t *) original;
surface = surface_pattern->surface;
 
if (_cairo_surface_has_device_transform (surface))
_cairo_pattern_transform (pattern, &surface->device_transform);
}
 
if (! _cairo_matrix_is_identity (ctm_inverse))
_cairo_pattern_transform (pattern, ctm_inverse);
 
if (_cairo_surface_has_device_transform (gstate->target)) {
_cairo_pattern_transform (pattern,
&gstate->target->device_transform_inverse);
}
}
 
static void
_cairo_gstate_copy_transformed_source (cairo_gstate_t *gstate,
cairo_pattern_t *pattern)
{
_cairo_gstate_copy_transformed_pattern (gstate, pattern,
gstate->source,
&gstate->source_ctm_inverse);
}
 
static void
_cairo_gstate_copy_transformed_mask (cairo_gstate_t *gstate,
cairo_pattern_t *pattern,
cairo_pattern_t *mask)
{
_cairo_gstate_copy_transformed_pattern (gstate, pattern,
mask,
&gstate->ctm_inverse);
}
 
/* We need to take a copy of the clip so that the lower layers may modify it
* by, perhaps, intersecting it with the operation extents and other paths.
*/
#define _gstate_get_clip(G, C) _cairo_clip_init_copy ((C), &(G)->clip)
 
static cairo_bool_t
_clipped (cairo_gstate_t *gstate)
{
cairo_rectangle_int_t extents;
 
if (gstate->clip.all_clipped)
return TRUE;
 
/* XXX consider applying a surface clip? */
 
if (gstate->clip.path == NULL)
return FALSE;
 
if (_cairo_surface_get_extents (gstate->target, &extents)) {
if (extents.width == 0 || extents.height == 0)
return TRUE;
 
if (! _cairo_rectangle_intersect (&extents,
&gstate->clip.path->extents))
{
return TRUE;
}
}
 
/* perform a simple query to exclude trivial all-clipped cases */
return _cairo_clip_get_region (&gstate->clip, NULL) == CAIRO_INT_STATUS_NOTHING_TO_DO;
}
 
static cairo_operator_t
_reduce_op (cairo_gstate_t *gstate)
{
cairo_operator_t op;
const cairo_pattern_t *pattern;
 
op = gstate->op;
if (op != CAIRO_OPERATOR_SOURCE)
return op;
 
pattern = gstate->source;
if (pattern->type == CAIRO_PATTERN_TYPE_SOLID) {
const cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *) pattern;
if (solid->color.alpha_short <= 0x00ff) {
op = CAIRO_OPERATOR_CLEAR;
} else if ((gstate->target->content & CAIRO_CONTENT_ALPHA) == 0) {
if ((solid->color.red_short |
solid->color.green_short |
solid->color.blue_short) <= 0x00ff)
{
op = CAIRO_OPERATOR_CLEAR;
}
}
} else if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
const cairo_surface_pattern_t *surface = (cairo_surface_pattern_t *) pattern;
if (surface->surface->is_clear &&
surface->surface->content & CAIRO_CONTENT_ALPHA)
{
op = CAIRO_OPERATOR_CLEAR;
}
} else {
const cairo_gradient_pattern_t *gradient = (cairo_gradient_pattern_t *) pattern;
if (gradient->n_stops == 0)
op = CAIRO_OPERATOR_CLEAR;
}
 
return op;
}
 
cairo_status_t
_cairo_gstate_paint (cairo_gstate_t *gstate)
{
cairo_pattern_union_t source_pattern;
const cairo_pattern_t *pattern;
cairo_clip_t clip;
cairo_status_t status;
cairo_operator_t op;
 
if (unlikely (gstate->source->status))
return gstate->source->status;
 
if (gstate->op == CAIRO_OPERATOR_DEST)
return CAIRO_STATUS_SUCCESS;
 
if (_clipped (gstate))
return CAIRO_STATUS_SUCCESS;
 
op = _reduce_op (gstate);
if (op == CAIRO_OPERATOR_CLEAR) {
pattern = &_cairo_pattern_clear.base;
} else {
_cairo_gstate_copy_transformed_source (gstate, &source_pattern.base);
pattern = &source_pattern.base;
}
 
status = _cairo_surface_paint (gstate->target,
op, pattern,
_gstate_get_clip (gstate, &clip));
_cairo_clip_fini (&clip);
 
return status;
}
 
cairo_status_t
_cairo_gstate_mask (cairo_gstate_t *gstate,
cairo_pattern_t *mask)
{
cairo_pattern_union_t source_pattern, mask_pattern;
const cairo_pattern_t *source;
cairo_operator_t op;
cairo_clip_t clip;
cairo_status_t status;
 
if (unlikely (mask->status))
return mask->status;
 
if (unlikely (gstate->source->status))
return gstate->source->status;
 
if (gstate->op == CAIRO_OPERATOR_DEST)
return CAIRO_STATUS_SUCCESS;
 
if (_clipped (gstate))
return CAIRO_STATUS_SUCCESS;
 
if (_cairo_pattern_is_opaque (mask, NULL))
return _cairo_gstate_paint (gstate);
 
if (_cairo_pattern_is_clear (mask) &&
_cairo_operator_bounded_by_mask (gstate->op))
{
return CAIRO_STATUS_SUCCESS;
}
 
op = _reduce_op (gstate);
if (op == CAIRO_OPERATOR_CLEAR) {
source = &_cairo_pattern_clear.base;
} else {
_cairo_gstate_copy_transformed_source (gstate, &source_pattern.base);
source = &source_pattern.base;
}
_cairo_gstate_copy_transformed_mask (gstate, &mask_pattern.base, mask);
 
if (source->type == CAIRO_PATTERN_TYPE_SOLID &&
mask_pattern.type == CAIRO_PATTERN_TYPE_SOLID &&
_cairo_operator_bounded_by_source (op))
{
const cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *) source;
cairo_color_t combined;
 
if (mask_pattern.base.has_component_alpha) {
#define M(R, A, B, c) R.c = A.c * B.c
M(combined, solid->color, mask_pattern.solid.color, red);
M(combined, solid->color, mask_pattern.solid.color, green);
M(combined, solid->color, mask_pattern.solid.color, blue);
M(combined, solid->color, mask_pattern.solid.color, alpha);
#undef M
} else {
combined = solid->color;
_cairo_color_multiply_alpha (&combined, mask_pattern.solid.color.alpha);
}
 
_cairo_pattern_init_solid (&source_pattern.solid, &combined);
 
status = _cairo_surface_paint (gstate->target, op,
&source_pattern.base,
_gstate_get_clip (gstate, &clip));
}
else
{
status = _cairo_surface_mask (gstate->target, op,
source,
&mask_pattern.base,
_gstate_get_clip (gstate, &clip));
}
_cairo_clip_fini (&clip);
 
return status;
}
 
cairo_status_t
_cairo_gstate_stroke (cairo_gstate_t *gstate, cairo_path_fixed_t *path)
{
cairo_pattern_union_t source_pattern;
cairo_stroke_style_t style;
double dash[2];
cairo_clip_t clip;
cairo_status_t status;
 
if (unlikely (gstate->source->status))
return gstate->source->status;
 
if (gstate->op == CAIRO_OPERATOR_DEST)
return CAIRO_STATUS_SUCCESS;
 
if (gstate->stroke_style.line_width <= 0.0)
return CAIRO_STATUS_SUCCESS;
 
if (_clipped (gstate))
return CAIRO_STATUS_SUCCESS;
 
memcpy (&style, &gstate->stroke_style, sizeof (gstate->stroke_style));
if (_cairo_stroke_style_dash_can_approximate (&gstate->stroke_style, &gstate->ctm, gstate->tolerance)) {
style.dash = dash;
_cairo_stroke_style_dash_approximate (&gstate->stroke_style, &gstate->ctm, gstate->tolerance,
&style.dash_offset,
style.dash,
&style.num_dashes);
}
 
_cairo_gstate_copy_transformed_source (gstate, &source_pattern.base);
 
status = _cairo_surface_stroke (gstate->target,
gstate->op,
&source_pattern.base,
path,
&style,
&gstate->ctm,
&gstate->ctm_inverse,
gstate->tolerance,
gstate->antialias,
_gstate_get_clip (gstate, &clip));
_cairo_clip_fini (&clip);
 
return status;
}
 
cairo_status_t
_cairo_gstate_in_stroke (cairo_gstate_t *gstate,
cairo_path_fixed_t *path,
double x,
double y,
cairo_bool_t *inside_ret)
{
cairo_status_t status;
cairo_rectangle_int_t extents;
cairo_box_t limit;
cairo_traps_t traps;
 
if (gstate->stroke_style.line_width <= 0.0) {
*inside_ret = FALSE;
return CAIRO_STATUS_SUCCESS;
}
 
_cairo_gstate_user_to_backend (gstate, &x, &y);
 
/* Before we perform the expensive stroke analysis,
* check whether the point is within the extents of the path.
*/
_cairo_path_fixed_approximate_stroke_extents (path,
&gstate->stroke_style,
&gstate->ctm,
&extents);
if (x < extents.x || x > extents.x + extents.width ||
y < extents.y || y > extents.y + extents.height)
{
*inside_ret = FALSE;
return CAIRO_STATUS_SUCCESS;
}
 
limit.p1.x = _cairo_fixed_from_double (x) - 1;
limit.p1.y = _cairo_fixed_from_double (y) - 1;
limit.p2.x = limit.p1.x + 2;
limit.p2.y = limit.p1.y + 2;
 
_cairo_traps_init (&traps);
_cairo_traps_limit (&traps, &limit, 1);
 
status = _cairo_path_fixed_stroke_to_traps (path,
&gstate->stroke_style,
&gstate->ctm,
&gstate->ctm_inverse,
gstate->tolerance,
&traps);
if (unlikely (status))
goto BAIL;
 
*inside_ret = _cairo_traps_contain (&traps, x, y);
 
BAIL:
_cairo_traps_fini (&traps);
 
return status;
}
 
cairo_status_t
_cairo_gstate_fill (cairo_gstate_t *gstate, cairo_path_fixed_t *path)
{
cairo_clip_t clip;
cairo_status_t status;
 
if (unlikely (gstate->source->status))
return gstate->source->status;
 
if (gstate->op == CAIRO_OPERATOR_DEST)
return CAIRO_STATUS_SUCCESS;
 
if (_clipped (gstate))
return CAIRO_STATUS_SUCCESS;
 
if (_cairo_path_fixed_fill_is_empty (path)) {
if (_cairo_operator_bounded_by_mask (gstate->op))
return CAIRO_STATUS_SUCCESS;
 
status = _cairo_surface_paint (gstate->target,
CAIRO_OPERATOR_CLEAR,
&_cairo_pattern_clear.base,
_gstate_get_clip (gstate, &clip));
} else {
cairo_pattern_union_t source_pattern;
const cairo_pattern_t *pattern;
cairo_operator_t op;
cairo_rectangle_int_t extents;
cairo_box_t box;
 
op = _reduce_op (gstate);
if (op == CAIRO_OPERATOR_CLEAR) {
pattern = &_cairo_pattern_clear.base;
} else {
_cairo_gstate_copy_transformed_source (gstate, &source_pattern.base);
pattern = &source_pattern.base;
}
 
/* Toolkits often paint the entire background with a fill */
if (_cairo_surface_get_extents (gstate->target, &extents) &&
_cairo_path_fixed_is_box (path, &box) &&
box.p1.x <= _cairo_fixed_from_int (extents.x) &&
box.p1.y <= _cairo_fixed_from_int (extents.y) &&
box.p2.x >= _cairo_fixed_from_int (extents.x + extents.width) &&
box.p2.y >= _cairo_fixed_from_int (extents.y + extents.height))
{
status = _cairo_surface_paint (gstate->target, op, pattern,
_gstate_get_clip (gstate, &clip));
}
else
{
status = _cairo_surface_fill (gstate->target, op, pattern,
path,
gstate->fill_rule,
gstate->tolerance,
gstate->antialias,
_gstate_get_clip (gstate, &clip));
}
}
 
_cairo_clip_fini (&clip);
 
return status;
}
 
cairo_bool_t
_cairo_gstate_in_fill (cairo_gstate_t *gstate,
cairo_path_fixed_t *path,
double x,
double y)
{
_cairo_gstate_user_to_backend (gstate, &x, &y);
 
return _cairo_path_fixed_in_fill (path,
gstate->fill_rule,
gstate->tolerance,
x, y);
}
 
cairo_bool_t
_cairo_gstate_in_clip (cairo_gstate_t *gstate,
double x,
double y)
{
cairo_clip_path_t *clip_path;
 
if (gstate->clip.all_clipped)
return FALSE;
 
clip_path = gstate->clip.path;
if (clip_path == NULL)
return TRUE;
 
_cairo_gstate_user_to_backend (gstate, &x, &y);
 
if (x < clip_path->extents.x ||
x >= clip_path->extents.x + clip_path->extents.width ||
y < clip_path->extents.y ||
y >= clip_path->extents.y + clip_path->extents.height)
{
return FALSE;
}
 
do {
if (! _cairo_path_fixed_in_fill (&clip_path->path,
clip_path->fill_rule,
clip_path->tolerance,
x, y))
return FALSE;
} while ((clip_path = clip_path->prev) != NULL);
 
return TRUE;
}
 
cairo_status_t
_cairo_gstate_copy_page (cairo_gstate_t *gstate)
{
cairo_surface_copy_page (gstate->target);
return cairo_surface_status (gstate->target);
}
 
cairo_status_t
_cairo_gstate_show_page (cairo_gstate_t *gstate)
{
cairo_surface_show_page (gstate->target);
return cairo_surface_status (gstate->target);
}
 
static void
_cairo_gstate_traps_extents_to_user_rectangle (cairo_gstate_t *gstate,
cairo_traps_t *traps,
double *x1, double *y1,
double *x2, double *y2)
{
cairo_box_t extents;
 
if (traps->num_traps == 0) {
/* no traps, so we actually won't draw anything */
if (x1)
*x1 = 0.0;
if (y1)
*y1 = 0.0;
if (x2)
*x2 = 0.0;
if (y2)
*y2 = 0.0;
} else {
double px1, py1, px2, py2;
 
_cairo_traps_extents (traps, &extents);
 
px1 = _cairo_fixed_to_double (extents.p1.x);
py1 = _cairo_fixed_to_double (extents.p1.y);
px2 = _cairo_fixed_to_double (extents.p2.x);
py2 = _cairo_fixed_to_double (extents.p2.y);
 
_cairo_gstate_backend_to_user_rectangle (gstate,
&px1, &py1, &px2, &py2,
NULL);
if (x1)
*x1 = px1;
if (y1)
*y1 = py1;
if (x2)
*x2 = px2;
if (y2)
*y2 = py2;
}
}
 
cairo_status_t
_cairo_gstate_stroke_extents (cairo_gstate_t *gstate,
cairo_path_fixed_t *path,
double *x1, double *y1,
double *x2, double *y2)
{
cairo_status_t status;
cairo_traps_t traps;
 
if (gstate->stroke_style.line_width <= 0.0) {
if (x1)
*x1 = 0.0;
if (y1)
*y1 = 0.0;
if (x2)
*x2 = 0.0;
if (y2)
*y2 = 0.0;
return CAIRO_STATUS_SUCCESS;
}
 
_cairo_traps_init (&traps);
 
status = _cairo_path_fixed_stroke_to_traps (path,
&gstate->stroke_style,
&gstate->ctm,
&gstate->ctm_inverse,
gstate->tolerance,
&traps);
if (likely (status == CAIRO_STATUS_SUCCESS)) {
_cairo_gstate_traps_extents_to_user_rectangle (gstate, &traps,
x1, y1, x2, y2);
}
 
_cairo_traps_fini (&traps);
 
return status;
}
 
cairo_status_t
_cairo_gstate_fill_extents (cairo_gstate_t *gstate,
cairo_path_fixed_t *path,
double *x1, double *y1,
double *x2, double *y2)
{
cairo_status_t status;
cairo_traps_t traps;
 
if (path->is_empty_fill) {
if (x1)
*x1 = 0.0;
if (y1)
*y1 = 0.0;
if (x2)
*x2 = 0.0;
if (y2)
*y2 = 0.0;
return CAIRO_STATUS_SUCCESS;
}
 
_cairo_traps_init (&traps);
 
status = _cairo_path_fixed_fill_to_traps (path,
gstate->fill_rule,
gstate->tolerance,
&traps);
if (likely (status == CAIRO_STATUS_SUCCESS)) {
_cairo_gstate_traps_extents_to_user_rectangle (gstate, &traps,
x1, y1, x2, y2);
}
 
_cairo_traps_fini (&traps);
 
return status;
}
 
cairo_status_t
_cairo_gstate_reset_clip (cairo_gstate_t *gstate)
{
_cairo_clip_reset (&gstate->clip);
 
return CAIRO_STATUS_SUCCESS;
}
 
cairo_status_t
_cairo_gstate_clip (cairo_gstate_t *gstate, cairo_path_fixed_t *path)
{
return _cairo_clip_clip (&gstate->clip,
path, gstate->fill_rule,
gstate->tolerance, gstate->antialias);
}
 
static cairo_bool_t
_cairo_gstate_int_clip_extents (cairo_gstate_t *gstate,
cairo_rectangle_int_t *extents)
{
const cairo_rectangle_int_t *clip_extents;
cairo_bool_t is_bounded;
 
is_bounded = _cairo_surface_get_extents (gstate->target, extents);
 
clip_extents = _cairo_clip_get_extents (&gstate->clip);
if (clip_extents != NULL) {
cairo_bool_t is_empty;
 
is_empty = _cairo_rectangle_intersect (extents, clip_extents);
is_bounded = TRUE;
}
 
return is_bounded;
}
 
cairo_bool_t
_cairo_gstate_clip_extents (cairo_gstate_t *gstate,
double *x1,
double *y1,
double *x2,
double *y2)
{
cairo_rectangle_int_t extents;
double px1, py1, px2, py2;
 
if (! _cairo_gstate_int_clip_extents (gstate, &extents))
return FALSE;
 
px1 = extents.x;
py1 = extents.y;
px2 = extents.x + (int) extents.width;
py2 = extents.y + (int) extents.height;
 
_cairo_gstate_backend_to_user_rectangle (gstate,
&px1, &py1, &px2, &py2,
NULL);
 
if (x1)
*x1 = px1;
if (y1)
*y1 = py1;
if (x2)
*x2 = px2;
if (y2)
*y2 = py2;
 
return TRUE;
}
 
cairo_rectangle_list_t*
_cairo_gstate_copy_clip_rectangle_list (cairo_gstate_t *gstate)
{
cairo_clip_t clip;
cairo_rectangle_int_t extents;
cairo_rectangle_list_t *list;
 
_cairo_clip_init_copy (&clip, &gstate->clip);
 
if (_cairo_surface_get_extents (gstate->target, &extents))
_cairo_clip_rectangle (&clip, &extents);
 
list = _cairo_clip_copy_rectangle_list (&clip, gstate);
_cairo_clip_fini (&clip);
 
return list;
}
 
static void
_cairo_gstate_unset_scaled_font (cairo_gstate_t *gstate)
{
if (gstate->scaled_font == NULL)
return;
 
if (gstate->previous_scaled_font != NULL)
cairo_scaled_font_destroy (gstate->previous_scaled_font);
 
gstate->previous_scaled_font = gstate->scaled_font;
gstate->scaled_font = NULL;
}
 
cairo_status_t
_cairo_gstate_select_font_face (cairo_gstate_t *gstate,
const char *family,
cairo_font_slant_t slant,
cairo_font_weight_t weight)
{
cairo_font_face_t *font_face;
cairo_status_t status;
 
font_face = cairo_toy_font_face_create (family, slant, weight);
if (font_face->status)
return font_face->status;
 
status = _cairo_gstate_set_font_face (gstate, font_face);
cairo_font_face_destroy (font_face);
 
return status;
}
 
cairo_status_t
_cairo_gstate_set_font_size (cairo_gstate_t *gstate,
double size)
{
_cairo_gstate_unset_scaled_font (gstate);
 
cairo_matrix_init_scale (&gstate->font_matrix, size, size);
 
return CAIRO_STATUS_SUCCESS;
}
 
cairo_status_t
_cairo_gstate_set_font_matrix (cairo_gstate_t *gstate,
const cairo_matrix_t *matrix)
{
if (memcmp (matrix, &gstate->font_matrix, sizeof (cairo_matrix_t)) == 0)
return CAIRO_STATUS_SUCCESS;
 
if (! _cairo_matrix_is_invertible (matrix))
return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
 
_cairo_gstate_unset_scaled_font (gstate);
 
gstate->font_matrix = *matrix;
 
return CAIRO_STATUS_SUCCESS;
}
 
void
_cairo_gstate_get_font_matrix (cairo_gstate_t *gstate,
cairo_matrix_t *matrix)
{
*matrix = gstate->font_matrix;
}
 
void
_cairo_gstate_set_font_options (cairo_gstate_t *gstate,
const cairo_font_options_t *options)
{
if (memcmp (options, &gstate->font_options, sizeof (cairo_font_options_t)) == 0)
return;
 
_cairo_gstate_unset_scaled_font (gstate);
 
_cairo_font_options_init_copy (&gstate->font_options, options);
}
 
void
_cairo_gstate_get_font_options (cairo_gstate_t *gstate,
cairo_font_options_t *options)
{
*options = gstate->font_options;
}
 
cairo_status_t
_cairo_gstate_get_font_face (cairo_gstate_t *gstate,
cairo_font_face_t **font_face)
{
cairo_status_t status;
 
status = _cairo_gstate_ensure_font_face (gstate);
if (unlikely (status))
return status;
 
*font_face = gstate->font_face;
 
return CAIRO_STATUS_SUCCESS;
}
 
cairo_status_t
_cairo_gstate_get_scaled_font (cairo_gstate_t *gstate,
cairo_scaled_font_t **scaled_font)
{
cairo_status_t status;
 
status = _cairo_gstate_ensure_scaled_font (gstate);
if (unlikely (status))
return status;
 
*scaled_font = gstate->scaled_font;
 
return CAIRO_STATUS_SUCCESS;
}
 
/*
* Like everything else in this file, fonts involve Too Many Coordinate Spaces;
* it is easy to get confused about what's going on.
*
* The user's view
* ---------------
*
* Users ask for things in user space. When cairo starts, a user space unit
* is about 1/96 inch, which is similar to (but importantly different from)
* the normal "point" units most users think in terms of. When a user
* selects a font, its scale is set to "one user unit". The user can then
* independently scale the user coordinate system *or* the font matrix, in
* order to adjust the rendered size of the font.
*
* Metrics are returned in user space, whether they are obtained from
* the currently selected font in a #cairo_t or from a #cairo_scaled_font_t
* which is a font specialized to a particular scale matrix, CTM, and target
* surface.
*
* The font's view
* ---------------
*
* Fonts are designed and stored (in say .ttf files) in "font space", which
* describes an "EM Square" (a design tile) and has some abstract number
* such as 1000, 1024, or 2048 units per "EM". This is basically an
* uninteresting space for us, but we need to remember that it exists.
*
* Font resources (from libraries or operating systems) render themselves
* to a particular device. Since they do not want to make most programmers
* worry about the font design space, the scaling API is simplified to
* involve just telling the font the required pixel size of the EM square
* (that is, in device space).
*
*
* Cairo's gstate view
* -------------------
*
* In addition to the CTM and CTM inverse, we keep a matrix in the gstate
* called the "font matrix" which describes the user's most recent
* font-scaling or font-transforming request. This is kept in terms of an
* abstract scale factor, composed with the CTM and used to set the font's
* pixel size. So if the user asks to "scale the font by 12", the matrix
* is:
*
* [ 12.0, 0.0, 0.0, 12.0, 0.0, 0.0 ]
*
* It is an affine matrix, like all cairo matrices, where its tx and ty
* components are used to "nudging" fonts around and are handled in gstate
* and then ignored by the "scaled-font" layer.
*
* In order to perform any action on a font, we must build an object
* called a #cairo_font_scale_t; this contains the central 2x2 matrix
* resulting from "font matrix * CTM" (sans the font matrix translation
* components as stated in the previous paragraph).
*
* We pass this to the font when making requests of it, which causes it to
* reply for a particular [user request, device] combination, under the CTM
* (to accommodate the "zoom in" == "bigger fonts" issue above).
*
* The other terms in our communication with the font are therefore in
* device space. When we ask it to perform text->glyph conversion, it will
* produce a glyph string in device space. Glyph vectors we pass to it for
* measuring or rendering should be in device space. The metrics which we
* get back from the font will be in device space. The contents of the
* global glyph image cache will be in device space.
*
*
* Cairo's public view
* -------------------
*
* Since the values entering and leaving via public API calls are in user
* space, the gstate functions typically need to multiply arguments by the
* CTM (for user-input glyph vectors), and return values by the CTM inverse
* (for font responses such as metrics or glyph vectors).
*
*/
 
static cairo_status_t
_cairo_gstate_ensure_font_face (cairo_gstate_t *gstate)
{
cairo_font_face_t *font_face;
 
if (gstate->font_face != NULL)
return gstate->font_face->status;
 
 
font_face = cairo_toy_font_face_create (CAIRO_FONT_FAMILY_DEFAULT,
CAIRO_FONT_SLANT_DEFAULT,
CAIRO_FONT_WEIGHT_DEFAULT);
if (font_face->status)
return font_face->status;
 
gstate->font_face = font_face;
 
return CAIRO_STATUS_SUCCESS;
}
 
static cairo_status_t
_cairo_gstate_ensure_scaled_font (cairo_gstate_t *gstate)
{
cairo_status_t status;
cairo_font_options_t options;
cairo_scaled_font_t *scaled_font;
 
if (gstate->scaled_font != NULL)
return gstate->scaled_font->status;
 
status = _cairo_gstate_ensure_font_face (gstate);
if (unlikely (status))
return status;
 
cairo_surface_get_font_options (gstate->target, &options);
cairo_font_options_merge (&options, &gstate->font_options);
 
scaled_font = cairo_scaled_font_create (gstate->font_face,
&gstate->font_matrix,
&gstate->ctm,
&options);
 
status = cairo_scaled_font_status (scaled_font);
if (unlikely (status))
return status;
 
gstate->scaled_font = scaled_font;
 
return CAIRO_STATUS_SUCCESS;
}
 
cairo_status_t
_cairo_gstate_get_font_extents (cairo_gstate_t *gstate,
cairo_font_extents_t *extents)
{
cairo_status_t status = _cairo_gstate_ensure_scaled_font (gstate);
if (unlikely (status))
return status;
 
cairo_scaled_font_extents (gstate->scaled_font, extents);
 
return cairo_scaled_font_status (gstate->scaled_font);
}
 
cairo_status_t
_cairo_gstate_text_to_glyphs (cairo_gstate_t *gstate,
double x,
double y,
const char *utf8,
int utf8_len,
cairo_glyph_t **glyphs,
int *num_glyphs,
cairo_text_cluster_t **clusters,
int *num_clusters,
cairo_text_cluster_flags_t *cluster_flags)
{
cairo_status_t status;
 
status = _cairo_gstate_ensure_scaled_font (gstate);
if (unlikely (status))
return status;
 
return cairo_scaled_font_text_to_glyphs (gstate->scaled_font, x, y,
utf8, utf8_len,
glyphs, num_glyphs,
clusters, num_clusters,
cluster_flags);
}
 
cairo_status_t
_cairo_gstate_set_font_face (cairo_gstate_t *gstate,
cairo_font_face_t *font_face)
{
if (font_face && font_face->status)
return _cairo_error (font_face->status);
 
if (font_face == gstate->font_face)
return CAIRO_STATUS_SUCCESS;
 
cairo_font_face_destroy (gstate->font_face);
gstate->font_face = cairo_font_face_reference (font_face);
 
_cairo_gstate_unset_scaled_font (gstate);
 
return CAIRO_STATUS_SUCCESS;
}
 
cairo_status_t
_cairo_gstate_glyph_extents (cairo_gstate_t *gstate,
const cairo_glyph_t *glyphs,
int num_glyphs,
cairo_text_extents_t *extents)
{
cairo_status_t status;
 
status = _cairo_gstate_ensure_scaled_font (gstate);
if (unlikely (status))
return status;
 
cairo_scaled_font_glyph_extents (gstate->scaled_font,
glyphs, num_glyphs,
extents);
 
return cairo_scaled_font_status (gstate->scaled_font);
}
 
cairo_status_t
_cairo_gstate_show_text_glyphs (cairo_gstate_t *gstate,
const char *utf8,
int utf8_len,
const cairo_glyph_t *glyphs,
int num_glyphs,
const cairo_text_cluster_t *clusters,
int num_clusters,
cairo_text_cluster_flags_t cluster_flags)
{
cairo_pattern_union_t source_pattern;
const cairo_pattern_t *pattern;
cairo_glyph_t stack_transformed_glyphs[CAIRO_STACK_ARRAY_LENGTH (cairo_glyph_t)];
cairo_glyph_t *transformed_glyphs;
cairo_text_cluster_t stack_transformed_clusters[CAIRO_STACK_ARRAY_LENGTH (cairo_text_cluster_t)];
cairo_text_cluster_t *transformed_clusters;
cairo_operator_t op;
cairo_status_t status;
cairo_clip_t clip;
 
if (unlikely (gstate->source->status))
return gstate->source->status;
 
if (gstate->op == CAIRO_OPERATOR_DEST)
return CAIRO_STATUS_SUCCESS;
 
if (_clipped (gstate))
return CAIRO_STATUS_SUCCESS;
 
status = _cairo_gstate_ensure_scaled_font (gstate);
if (unlikely (status))
return status;
 
transformed_glyphs = stack_transformed_glyphs;
transformed_clusters = stack_transformed_clusters;
 
if (num_glyphs > ARRAY_LENGTH (stack_transformed_glyphs)) {
transformed_glyphs = cairo_glyph_allocate (num_glyphs);
if (unlikely (transformed_glyphs == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto CLEANUP_GLYPHS;
}
}
 
/* Just in case */
if (!clusters)
num_clusters = 0;
 
if (num_clusters > ARRAY_LENGTH (stack_transformed_clusters)) {
transformed_clusters = cairo_text_cluster_allocate (num_clusters);
if (unlikely (transformed_clusters == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto CLEANUP_GLYPHS;
}
}
 
status = _cairo_gstate_transform_glyphs_to_backend (gstate,
glyphs, num_glyphs,
clusters,
num_clusters,
cluster_flags,
transformed_glyphs,
&num_glyphs,
transformed_clusters);
 
if (status || num_glyphs == 0)
goto CLEANUP_GLYPHS;
 
op = _reduce_op (gstate);
if (op == CAIRO_OPERATOR_CLEAR) {
pattern = &_cairo_pattern_clear.base;
} else {
_cairo_gstate_copy_transformed_source (gstate, &source_pattern.base);
pattern = &source_pattern.base;
}
 
/* For really huge font sizes, we can just do path;fill instead of
* show_glyphs, as show_glyphs would put excess pressure on the cache,
* and moreover, not all components below us correctly handle huge font
* sizes. I wanted to set the limit at 256. But alas, seems like cairo's
* rasterizer is something like ten times slower than freetype's for huge
* sizes. So, no win just yet. For now, do it for insanely-huge sizes,
* just to make sure we don't make anyone unhappy. When we get a really
* fast rasterizer in cairo, we may want to readjust this.
*
* Needless to say, do this only if show_text_glyphs is not available. */
if (cairo_surface_has_show_text_glyphs (gstate->target) ||
_cairo_scaled_font_get_max_scale (gstate->scaled_font) <= 10240)
{
status = _cairo_surface_show_text_glyphs (gstate->target, op, pattern,
utf8, utf8_len,
transformed_glyphs, num_glyphs,
transformed_clusters, num_clusters,
cluster_flags,
gstate->scaled_font,
_gstate_get_clip (gstate, &clip));
}
else
{
cairo_path_fixed_t path;
 
_cairo_path_fixed_init (&path);
 
status = _cairo_scaled_font_glyph_path (gstate->scaled_font,
transformed_glyphs, num_glyphs,
&path);
 
if (status == CAIRO_STATUS_SUCCESS) {
status = _cairo_surface_fill (gstate->target, op, pattern,
&path,
CAIRO_FILL_RULE_WINDING,
gstate->tolerance,
gstate->scaled_font->options.antialias,
_gstate_get_clip (gstate, &clip));
}
 
_cairo_path_fixed_fini (&path);
}
 
_cairo_clip_fini (&clip);
 
CLEANUP_GLYPHS:
if (transformed_glyphs != stack_transformed_glyphs)
cairo_glyph_free (transformed_glyphs);
if (transformed_clusters != stack_transformed_clusters)
cairo_text_cluster_free (transformed_clusters);
 
return status;
}
 
cairo_status_t
_cairo_gstate_glyph_path (cairo_gstate_t *gstate,
const cairo_glyph_t *glyphs,
int num_glyphs,
cairo_path_fixed_t *path)
{
cairo_status_t status;
cairo_glyph_t *transformed_glyphs;
cairo_glyph_t stack_transformed_glyphs[CAIRO_STACK_ARRAY_LENGTH (cairo_glyph_t)];
 
status = _cairo_gstate_ensure_scaled_font (gstate);
if (unlikely (status))
return status;
 
if (num_glyphs < ARRAY_LENGTH (stack_transformed_glyphs)) {
transformed_glyphs = stack_transformed_glyphs;
} else {
transformed_glyphs = cairo_glyph_allocate (num_glyphs);
if (unlikely (transformed_glyphs == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
 
status = _cairo_gstate_transform_glyphs_to_backend (gstate,
glyphs, num_glyphs,
NULL, 0, 0,
transformed_glyphs,
NULL, NULL);
if (unlikely (status))
goto CLEANUP_GLYPHS;
 
status = _cairo_scaled_font_glyph_path (gstate->scaled_font,
transformed_glyphs, num_glyphs,
path);
 
CLEANUP_GLYPHS:
if (transformed_glyphs != stack_transformed_glyphs)
cairo_glyph_free (transformed_glyphs);
 
return status;
}
 
cairo_status_t
_cairo_gstate_set_antialias (cairo_gstate_t *gstate,
cairo_antialias_t antialias)
{
gstate->antialias = antialias;
 
return CAIRO_STATUS_SUCCESS;
}
 
cairo_antialias_t
_cairo_gstate_get_antialias (cairo_gstate_t *gstate)
{
return gstate->antialias;
}
 
/**
* _cairo_gstate_transform_glyphs_to_backend:
* @gstate: a #cairo_gstate_t
* @glyphs: the array of #cairo_glyph_t objects to be transformed
* @num_glyphs: the number of elements in @glyphs
* @transformed_glyphs: a pre-allocated array of at least @num_glyphs
* #cairo_glyph_t objects
* @num_transformed_glyphs: the number of elements in @transformed_glyphs
* after dropping out of bounds glyphs, or %NULL if glyphs shouldn't be
* dropped
*
* Transform an array of glyphs to backend space by first adding the offset
* of the font matrix, then transforming from user space to backend space.
* The result of the transformation is placed in @transformed_glyphs.
*
* This also uses information from the scaled font and the surface to
* cull/drop glyphs that will not be visible.
**/
static cairo_status_t
_cairo_gstate_transform_glyphs_to_backend (cairo_gstate_t *gstate,
const cairo_glyph_t *glyphs,
int num_glyphs,
const cairo_text_cluster_t *clusters,
int num_clusters,
cairo_text_cluster_flags_t cluster_flags,
cairo_glyph_t *transformed_glyphs,
int *num_transformed_glyphs,
cairo_text_cluster_t *transformed_clusters)
{
int i, j, k;
cairo_matrix_t *ctm = &gstate->ctm;
cairo_matrix_t *font_matrix = &gstate->font_matrix;
cairo_matrix_t *device_transform = &gstate->target->device_transform;
cairo_bool_t drop = FALSE;
double x1 = 0, x2 = 0, y1 = 0, y2 = 0;
 
if (num_transformed_glyphs != NULL) {
cairo_rectangle_int_t surface_extents;
 
drop = TRUE;
if (! _cairo_gstate_int_clip_extents (gstate, &surface_extents)) {
drop = FALSE; /* unbounded surface */
} else {
double scale10 = 10 * _cairo_scaled_font_get_max_scale (gstate->scaled_font);
if (surface_extents.width == 0 || surface_extents.height == 0) {
/* No visible area. Don't draw anything */
*num_transformed_glyphs = 0;
return CAIRO_STATUS_SUCCESS;
}
/* XXX We currently drop any glyphs that has its position outside
* of the surface boundaries by a safety margin depending on the
* font scale. This however can fail in extreme cases where the
* font has really long swashes for example... We can correctly
* handle that by looking the glyph up and using its device bbox
* to device if it's going to be visible, but I'm not inclined to
* do that now.
*/
x1 = surface_extents.x - scale10;
y1 = surface_extents.y - scale10;
x2 = surface_extents.x + (int) surface_extents.width + scale10;
y2 = surface_extents.y + (int) surface_extents.height + scale10;
}
 
if (!drop)
*num_transformed_glyphs = num_glyphs;
} else
num_transformed_glyphs = &j;
 
#define KEEP_GLYPH(glyph) (x1 <= glyph.x && glyph.x <= x2 && y1 <= glyph.y && glyph.y <= y2)
 
j = 0;
if (_cairo_matrix_is_identity (ctm) &&
_cairo_matrix_is_identity (device_transform) &&
font_matrix->x0 == 0 && font_matrix->y0 == 0)
{
if (! drop) {
memcpy (transformed_glyphs, glyphs,
num_glyphs * sizeof (cairo_glyph_t));
j = num_glyphs;
} else if (num_clusters == 0) {
for (i = 0; i < num_glyphs; i++) {
transformed_glyphs[j].index = glyphs[i].index;
transformed_glyphs[j].x = glyphs[i].x;
transformed_glyphs[j].y = glyphs[i].y;
if (KEEP_GLYPH (transformed_glyphs[j]))
j++;
}
} else {
const cairo_glyph_t *cur_glyph;
 
if (cluster_flags & CAIRO_TEXT_CLUSTER_FLAG_BACKWARD)
cur_glyph = glyphs + num_glyphs - 1;
else
cur_glyph = glyphs;
 
for (i = 0; i < num_clusters; i++) {
cairo_bool_t cluster_visible = FALSE;
 
for (k = 0; k < clusters[i].num_glyphs; k++) {
transformed_glyphs[j+k].index = cur_glyph->index;
transformed_glyphs[j+k].x = cur_glyph->x;
transformed_glyphs[j+k].y = cur_glyph->y;
if (KEEP_GLYPH (transformed_glyphs[j+k]))
cluster_visible = TRUE;
 
if (cluster_flags & CAIRO_TEXT_CLUSTER_FLAG_BACKWARD)
cur_glyph--;
else
cur_glyph++;
}
 
transformed_clusters[i] = clusters[i];
if (cluster_visible)
j += k;
else
transformed_clusters[i].num_glyphs = 0;
}
}
}
else if (_cairo_matrix_is_translation (ctm) &&
_cairo_matrix_is_translation (device_transform))
{
double tx = font_matrix->x0 + ctm->x0 + device_transform->x0;
double ty = font_matrix->y0 + ctm->y0 + device_transform->y0;
 
if (! drop || num_clusters == 0) {
for (i = 0; i < num_glyphs; i++) {
transformed_glyphs[j].index = glyphs[i].index;
transformed_glyphs[j].x = glyphs[i].x + tx;
transformed_glyphs[j].y = glyphs[i].y + ty;
if (!drop || KEEP_GLYPH (transformed_glyphs[j]))
j++;
}
} else {
const cairo_glyph_t *cur_glyph;
 
if (cluster_flags & CAIRO_TEXT_CLUSTER_FLAG_BACKWARD)
cur_glyph = glyphs + num_glyphs - 1;
else
cur_glyph = glyphs;
 
for (i = 0; i < num_clusters; i++) {
cairo_bool_t cluster_visible = FALSE;
 
for (k = 0; k < clusters[i].num_glyphs; k++) {
transformed_glyphs[j+k].index = cur_glyph->index;
transformed_glyphs[j+k].x = cur_glyph->x + tx;
transformed_glyphs[j+k].y = cur_glyph->y + ty;
if (KEEP_GLYPH (transformed_glyphs[j+k]))
cluster_visible = TRUE;
 
if (cluster_flags & CAIRO_TEXT_CLUSTER_FLAG_BACKWARD)
cur_glyph--;
else
cur_glyph++;
}
 
transformed_clusters[i] = clusters[i];
if (cluster_visible)
j += k;
else
transformed_clusters[i].num_glyphs = 0;
}
}
}
else
{
cairo_matrix_t aggregate_transform;
 
cairo_matrix_init_translate (&aggregate_transform,
gstate->font_matrix.x0,
gstate->font_matrix.y0);
cairo_matrix_multiply (&aggregate_transform,
&aggregate_transform, ctm);
cairo_matrix_multiply (&aggregate_transform,
&aggregate_transform, device_transform);
 
if (! drop || num_clusters == 0) {
for (i = 0; i < num_glyphs; i++) {
transformed_glyphs[j] = glyphs[i];
cairo_matrix_transform_point (&aggregate_transform,
&transformed_glyphs[j].x,
&transformed_glyphs[j].y);
if (! drop || KEEP_GLYPH (transformed_glyphs[j]))
j++;
}
} else {
const cairo_glyph_t *cur_glyph;
 
if (cluster_flags & CAIRO_TEXT_CLUSTER_FLAG_BACKWARD)
cur_glyph = glyphs + num_glyphs - 1;
else
cur_glyph = glyphs;
 
for (i = 0; i < num_clusters; i++) {
cairo_bool_t cluster_visible = FALSE;
for (k = 0; k < clusters[i].num_glyphs; k++) {
transformed_glyphs[j+k] = *cur_glyph;
cairo_matrix_transform_point (&aggregate_transform,
&transformed_glyphs[j+k].x,
&transformed_glyphs[j+k].y);
if (KEEP_GLYPH (transformed_glyphs[j+k]))
cluster_visible = TRUE;
 
if (cluster_flags & CAIRO_TEXT_CLUSTER_FLAG_BACKWARD)
cur_glyph--;
else
cur_glyph++;
}
 
transformed_clusters[i] = clusters[i];
if (cluster_visible)
j += k;
else
transformed_clusters[i].num_glyphs = 0;
}
}
}
*num_transformed_glyphs = j;
 
if (num_clusters != 0 && cluster_flags & CAIRO_TEXT_CLUSTER_FLAG_BACKWARD) {
for (i = 0; i < --j; i++) {
cairo_glyph_t tmp;
 
tmp = transformed_glyphs[i];
transformed_glyphs[i] = transformed_glyphs[j];
transformed_glyphs[j] = tmp;
}
}
 
return CAIRO_STATUS_SUCCESS;
}
/programs/develop/libraries/cairo/src/cairo-hash-private.h
0,0 → 1,87
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2004 Red Hat, Inc.
* Copyright © 2005 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
* Keith Packard <keithp@keithp.com>
* Graydon Hoare <graydon@redhat.com>
* Carl Worth <cworth@cworth.org>
*/
 
#ifndef CAIRO_HASH_PRIVATE_H
#define CAIRO_HASH_PRIVATE_H
 
#include "cairo-compiler-private.h"
#include "cairo-types-private.h"
 
/* XXX: I'd like this file to be self-contained in terms of
* includeability, but that's not really possible with the current
* monolithic cairoint.h. So, for now, just include cairoint.h instead
* if you want to include this file. */
 
typedef cairo_bool_t
(*cairo_hash_keys_equal_func_t) (const void *key_a, const void *key_b);
 
typedef cairo_bool_t
(*cairo_hash_predicate_func_t) (const void *entry);
 
typedef void
(*cairo_hash_callback_func_t) (void *entry,
void *closure);
 
cairo_private cairo_hash_table_t *
_cairo_hash_table_create (cairo_hash_keys_equal_func_t keys_equal);
 
cairo_private void
_cairo_hash_table_destroy (cairo_hash_table_t *hash_table);
 
cairo_private void *
_cairo_hash_table_lookup (cairo_hash_table_t *hash_table,
cairo_hash_entry_t *key);
 
cairo_private void *
_cairo_hash_table_random_entry (cairo_hash_table_t *hash_table,
cairo_hash_predicate_func_t predicate);
 
cairo_private cairo_status_t
_cairo_hash_table_insert (cairo_hash_table_t *hash_table,
cairo_hash_entry_t *entry);
 
cairo_private void
_cairo_hash_table_remove (cairo_hash_table_t *hash_table,
cairo_hash_entry_t *key);
 
cairo_private void
_cairo_hash_table_foreach (cairo_hash_table_t *hash_table,
cairo_hash_callback_func_t hash_callback,
void *closure);
 
#endif
/programs/develop/libraries/cairo/src/cairo-hash.c
0,0 → 1,542
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2004 Red Hat, Inc.
* Copyright © 2005 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
* Keith Packard <keithp@keithp.com>
* Graydon Hoare <graydon@redhat.com>
* Carl Worth <cworth@cworth.org>
*/
 
#include "cairoint.h"
#include "cairo-error-private.h"
 
/*
* An entry can be in one of three states:
*
* FREE: Entry has never been used, terminates all searches.
* Appears in the table as a %NULL pointer.
*
* DEAD: Entry had been live in the past. A dead entry can be reused
* but does not terminate a search for an exact entry.
* Appears in the table as a pointer to DEAD_ENTRY.
*
* LIVE: Entry is currently being used.
* Appears in the table as any non-%NULL, non-DEAD_ENTRY pointer.
*/
 
#define DEAD_ENTRY ((cairo_hash_entry_t *) 0x1)
 
#define ENTRY_IS_FREE(entry) ((entry) == NULL)
#define ENTRY_IS_DEAD(entry) ((entry) == DEAD_ENTRY)
#define ENTRY_IS_LIVE(entry) ((entry) > DEAD_ENTRY)
 
/* We expect keys will not be destroyed frequently, so our table does not
* contain any explicit shrinking code nor any chain-coalescing code for
* entries randomly deleted by memory pressure (except during rehashing, of
* course). These assumptions are potentially bad, but they make the
* implementation straightforward.
*
* Revisit later if evidence appears that we're using excessive memory from
* a mostly-dead table.
*
* This table is open-addressed with double hashing. Each table size is a
* prime chosen to be a little more than double the high water mark for a
* given arrangement, so the tables should remain < 50% full. The table
* size makes for the "first" hash modulus; a second prime (2 less than the
* first prime) serves as the "second" hash modulus, which is co-prime and
* thus guarantees a complete permutation of table indices.
*
* This structure, and accompanying table, is borrowed/modified from the
* file xserver/render/glyph.c in the freedesktop.org x server, with
* permission (and suggested modification of doubling sizes) by Keith
* Packard.
*/
 
typedef struct _cairo_hash_table_arrangement {
unsigned long high_water_mark;
unsigned long size;
unsigned long rehash;
} cairo_hash_table_arrangement_t;
 
static const cairo_hash_table_arrangement_t hash_table_arrangements [] = {
{ 16, 43, 41 },
{ 32, 73, 71 },
{ 64, 151, 149 },
{ 128, 283, 281 },
{ 256, 571, 569 },
{ 512, 1153, 1151 },
{ 1024, 2269, 2267 },
{ 2048, 4519, 4517 },
{ 4096, 9013, 9011 },
{ 8192, 18043, 18041 },
{ 16384, 36109, 36107 },
{ 32768, 72091, 72089 },
{ 65536, 144409, 144407 },
{ 131072, 288361, 288359 },
{ 262144, 576883, 576881 },
{ 524288, 1153459, 1153457 },
{ 1048576, 2307163, 2307161 },
{ 2097152, 4613893, 4613891 },
{ 4194304, 9227641, 9227639 },
{ 8388608, 18455029, 18455027 },
{ 16777216, 36911011, 36911009 },
{ 33554432, 73819861, 73819859 },
{ 67108864, 147639589, 147639587 },
{ 134217728, 295279081, 295279079 },
{ 268435456, 590559793, 590559791 }
};
 
#define NUM_HASH_TABLE_ARRANGEMENTS ARRAY_LENGTH (hash_table_arrangements)
 
struct _cairo_hash_table {
cairo_hash_keys_equal_func_t keys_equal;
 
const cairo_hash_table_arrangement_t *arrangement;
cairo_hash_entry_t **entries;
 
unsigned long live_entries;
unsigned long iterating; /* Iterating, no insert, no resize */
};
 
/**
* _cairo_hash_table_create:
* @keys_equal: a function to return %TRUE if two keys are equal
*
* Creates a new hash table which will use the keys_equal() function
* to compare hash keys. Data is provided to the hash table in the
* form of user-derived versions of #cairo_hash_entry_t. A hash entry
* must be able to hold both a key (including a hash code) and a
* value. Sometimes only the key will be necessary, (as in
* _cairo_hash_table_remove), and other times both a key and a value
* will be necessary, (as in _cairo_hash_table_insert).
*
* See #cairo_hash_entry_t for more details.
*
* Return value: the new hash table or %NULL if out of memory.
**/
cairo_hash_table_t *
_cairo_hash_table_create (cairo_hash_keys_equal_func_t keys_equal)
{
cairo_hash_table_t *hash_table;
 
hash_table = malloc (sizeof (cairo_hash_table_t));
if (unlikely (hash_table == NULL)) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return NULL;
}
 
hash_table->keys_equal = keys_equal;
 
hash_table->arrangement = &hash_table_arrangements[0];
 
hash_table->entries = calloc (hash_table->arrangement->size,
sizeof(cairo_hash_entry_t *));
if (unlikely (hash_table->entries == NULL)) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
free (hash_table);
return NULL;
}
 
hash_table->live_entries = 0;
hash_table->iterating = 0;
 
return hash_table;
}
 
/**
* _cairo_hash_table_destroy:
* @hash_table: an empty hash table to destroy
*
* Immediately destroys the given hash table, freeing all resources
* associated with it.
*
* WARNING: The hash_table must have no live entries in it before
* _cairo_hash_table_destroy is called. It is a fatal error otherwise,
* and this function will halt. The rationale for this behavior is to
* avoid memory leaks and to avoid needless complication of the API
* with destroy notifiy callbacks.
*
* WARNING: The hash_table must have no running iterators in it when
* _cairo_hash_table_destroy is called. It is a fatal error otherwise,
* and this function will halt.
**/
void
_cairo_hash_table_destroy (cairo_hash_table_t *hash_table)
{
/* The hash table must be empty. Otherwise, halt. */
assert (hash_table->live_entries == 0);
/* No iterators can be running. Otherwise, halt. */
assert (hash_table->iterating == 0);
 
free (hash_table->entries);
hash_table->entries = NULL;
 
free (hash_table);
}
 
static cairo_hash_entry_t **
_cairo_hash_table_lookup_unique_key (cairo_hash_table_t *hash_table,
cairo_hash_entry_t *key)
{
unsigned long table_size, i, idx, step;
cairo_hash_entry_t **entry;
 
table_size = hash_table->arrangement->size;
idx = key->hash % table_size;
 
entry = &hash_table->entries[idx];
if (! ENTRY_IS_LIVE (*entry))
return entry;
 
i = 1;
step = key->hash % hash_table->arrangement->rehash;
if (step == 0)
step = 1;
do {
idx += step;
if (idx >= table_size)
idx -= table_size;
 
entry = &hash_table->entries[idx];
if (! ENTRY_IS_LIVE (*entry))
return entry;
} while (++i < table_size);
 
ASSERT_NOT_REACHED;
return NULL;
}
 
/**
* _cairo_hash_table_resize:
* @hash_table: a hash table
*
* Resize the hash table if the number of entries has gotten much
* bigger or smaller than the ideal number of entries for the current
* size.
*
* Return value: %CAIRO_STATUS_SUCCESS if successful or
* %CAIRO_STATUS_NO_MEMORY if out of memory.
**/
static cairo_status_t
_cairo_hash_table_resize (cairo_hash_table_t *hash_table)
{
cairo_hash_table_t tmp;
unsigned long new_size, i;
 
/* This keeps the hash table between 25% and 50% full. */
unsigned long high = hash_table->arrangement->high_water_mark;
unsigned long low = high >> 2;
 
if (hash_table->live_entries >= low && hash_table->live_entries <= high)
return CAIRO_STATUS_SUCCESS;
 
tmp = *hash_table;
 
if (hash_table->live_entries > high)
{
tmp.arrangement = hash_table->arrangement + 1;
/* This code is being abused if we can't make a table big enough. */
assert (tmp.arrangement - hash_table_arrangements <
NUM_HASH_TABLE_ARRANGEMENTS);
}
else /* hash_table->live_entries < low */
{
/* Can't shrink if we're at the smallest size */
if (hash_table->arrangement == &hash_table_arrangements[0])
return CAIRO_STATUS_SUCCESS;
tmp.arrangement = hash_table->arrangement - 1;
}
 
new_size = tmp.arrangement->size;
tmp.entries = calloc (new_size, sizeof (cairo_hash_entry_t*));
if (unlikely (tmp.entries == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
for (i = 0; i < hash_table->arrangement->size; ++i) {
if (ENTRY_IS_LIVE (hash_table->entries[i])) {
*_cairo_hash_table_lookup_unique_key (&tmp, hash_table->entries[i])
= hash_table->entries[i];
}
}
 
free (hash_table->entries);
hash_table->entries = tmp.entries;
hash_table->arrangement = tmp.arrangement;
 
return CAIRO_STATUS_SUCCESS;
}
 
/**
* _cairo_hash_table_lookup:
* @hash_table: a hash table
* @key: the key of interest
*
* Performs a lookup in @hash_table looking for an entry which has a
* key that matches @key, (as determined by the keys_equal() function
* passed to _cairo_hash_table_create).
*
* Return value: the matching entry, of %NULL if no match was found.
**/
void *
_cairo_hash_table_lookup (cairo_hash_table_t *hash_table,
cairo_hash_entry_t *key)
{
cairo_hash_entry_t *entry;
unsigned long table_size, i, idx, step;
 
table_size = hash_table->arrangement->size;
idx = key->hash % table_size;
 
entry = hash_table->entries[idx];
if (ENTRY_IS_LIVE (entry)) {
if (hash_table->keys_equal (key, entry))
return entry;
} else if (ENTRY_IS_FREE (entry))
return NULL;
 
i = 1;
step = key->hash % hash_table->arrangement->rehash;
if (step == 0)
step = 1;
do {
idx += step;
if (idx >= table_size)
idx -= table_size;
 
entry = hash_table->entries[idx];
if (ENTRY_IS_LIVE (entry)) {
if (hash_table->keys_equal (key, entry))
return entry;
} else if (ENTRY_IS_FREE (entry))
return NULL;
} while (++i < table_size);
 
return NULL;
}
 
/**
* _cairo_hash_table_random_entry:
* @hash_table: a hash table
* @predicate: a predicate function.
*
* Find a random entry in the hash table satisfying the given
* @predicate.
*
* We use the same algorithm as the lookup algorithm to walk over the
* entries in the hash table in a pseudo-random order. Walking
* linearly would favor entries following gaps in the hash table. We
* could also call rand() repeatedly, which works well for almost-full
* tables, but degrades when the table is almost empty, or predicate
* returns %TRUE for most entries.
*
* Return value: a random live entry or %NULL if there are no entries
* that match the given predicate. In particular, if predicate is
* %NULL, a %NULL return value indicates that the table is empty.
**/
void *
_cairo_hash_table_random_entry (cairo_hash_table_t *hash_table,
cairo_hash_predicate_func_t predicate)
{
cairo_hash_entry_t *entry;
unsigned long hash;
unsigned long table_size, i, idx, step;
 
assert (predicate != NULL);
 
table_size = hash_table->arrangement->size;
hash = rand ();
idx = hash % table_size;
 
entry = hash_table->entries[idx];
if (ENTRY_IS_LIVE (entry) && predicate (entry))
return entry;
 
i = 1;
step = hash % hash_table->arrangement->rehash;
if (step == 0)
step = 1;
do {
idx += step;
if (idx >= table_size)
idx -= table_size;
 
entry = hash_table->entries[idx];
if (ENTRY_IS_LIVE (entry) && predicate (entry))
return entry;
} while (++i < table_size);
 
return NULL;
}
 
/**
* _cairo_hash_table_insert:
* @hash_table: a hash table
* @key_and_value: an entry to be inserted
*
* Insert the entry #key_and_value into the hash table.
*
* WARNING: There must not be an existing entry in the hash table
* with a matching key.
*
* WARNING: It is a fatal error to insert an element while
* an iterator is running
*
* Instead of using insert to replace an entry, consider just editing
* the entry obtained with _cairo_hash_table_lookup. Or if absolutely
* necessary, use _cairo_hash_table_remove first.
*
* Return value: %CAIRO_STATUS_SUCCESS if successful or
* %CAIRO_STATUS_NO_MEMORY if insufficient memory is available.
**/
cairo_status_t
_cairo_hash_table_insert (cairo_hash_table_t *hash_table,
cairo_hash_entry_t *key_and_value)
{
cairo_status_t status;
 
/* Insert is illegal while an iterator is running. */
assert (hash_table->iterating == 0);
 
hash_table->live_entries++;
status = _cairo_hash_table_resize (hash_table);
if (unlikely (status)) {
/* abort the insert... */
hash_table->live_entries--;
return status;
}
 
*_cairo_hash_table_lookup_unique_key (hash_table,
key_and_value) = key_and_value;
 
return CAIRO_STATUS_SUCCESS;
}
 
static cairo_hash_entry_t **
_cairo_hash_table_lookup_exact_key (cairo_hash_table_t *hash_table,
cairo_hash_entry_t *key)
{
unsigned long table_size, i, idx, step;
cairo_hash_entry_t **entry;
 
table_size = hash_table->arrangement->size;
idx = key->hash % table_size;
 
entry = &hash_table->entries[idx];
if (*entry == key)
return entry;
 
i = 1;
step = key->hash % hash_table->arrangement->rehash;
if (step == 0)
step = 1;
do {
idx += step;
if (idx >= table_size)
idx -= table_size;
 
entry = &hash_table->entries[idx];
if (*entry == key)
return entry;
} while (++i < table_size);
 
ASSERT_NOT_REACHED;
return NULL;
}
/**
* _cairo_hash_table_remove:
* @hash_table: a hash table
* @key: key of entry to be removed
*
* Remove an entry from the hash table which points to @key.
*
* Return value: %CAIRO_STATUS_SUCCESS if successful or
* %CAIRO_STATUS_NO_MEMORY if out of memory.
**/
void
_cairo_hash_table_remove (cairo_hash_table_t *hash_table,
cairo_hash_entry_t *key)
{
*_cairo_hash_table_lookup_exact_key (hash_table, key) = DEAD_ENTRY;
hash_table->live_entries--;
 
/* Check for table resize. Don't do this when iterating as this will
* reorder elements of the table and cause the iteration to potentially
* skip some elements. */
if (hash_table->iterating == 0) {
/* This call _can_ fail, but only in failing to allocate new
* memory to shrink the hash table. It does leave the table in a
* consistent state, and we've already succeeded in removing the
* entry, so we don't examine the failure status of this call. */
_cairo_hash_table_resize (hash_table);
}
}
 
/**
* _cairo_hash_table_foreach:
* @hash_table: a hash table
* @hash_callback: function to be called for each live entry
* @closure: additional argument to be passed to @hash_callback
*
* Call @hash_callback for each live entry in the hash table, in a
* non-specified order.
*
* Entries in @hash_table may be removed by code executed from @hash_callback.
*
* Entries may not be inserted to @hash_table, nor may @hash_table
* be destroyed by code executed from @hash_callback. The relevant
* functions will halt in these cases.
**/
void
_cairo_hash_table_foreach (cairo_hash_table_t *hash_table,
cairo_hash_callback_func_t hash_callback,
void *closure)
{
unsigned long i;
cairo_hash_entry_t *entry;
 
/* Mark the table for iteration */
++hash_table->iterating;
for (i = 0; i < hash_table->arrangement->size; i++) {
entry = hash_table->entries[i];
if (ENTRY_IS_LIVE(entry))
hash_callback (entry, closure);
}
/* If some elements were deleted during the iteration,
* the table may need resizing. Just do this every time
* as the check is inexpensive.
*/
if (--hash_table->iterating == 0) {
/* Should we fail to shrink the hash table, it is left unaltered,
* and we don't need to propagate the error status. */
_cairo_hash_table_resize (hash_table);
}
}
/programs/develop/libraries/cairo/src/cairo-hull.c
0,0 → 1,235
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2003 University of Southern California
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
*/
 
#include "cairoint.h"
 
#include "cairo-error-private.h"
#include "cairo-slope-private.h"
 
typedef struct cairo_hull {
cairo_point_t point;
cairo_slope_t slope;
int discard;
int id;
} cairo_hull_t;
 
static void
_cairo_hull_init (cairo_hull_t *hull,
cairo_pen_vertex_t *vertices,
int num_vertices)
{
cairo_point_t *p, *extremum, tmp;
int i;
 
extremum = &vertices[0].point;
for (i = 1; i < num_vertices; i++) {
p = &vertices[i].point;
if (p->y < extremum->y || (p->y == extremum->y && p->x < extremum->x))
extremum = p;
}
/* Put the extremal point at the beginning of the array */
tmp = *extremum;
*extremum = vertices[0].point;
vertices[0].point = tmp;
 
for (i = 0; i < num_vertices; i++) {
hull[i].point = vertices[i].point;
_cairo_slope_init (&hull[i].slope, &hull[0].point, &hull[i].point);
 
/* give each point a unique id for later comparison */
hull[i].id = i;
 
/* Don't discard by default */
hull[i].discard = 0;
 
/* Discard all points coincident with the extremal point */
if (i != 0 && hull[i].slope.dx == 0 && hull[i].slope.dy == 0)
hull[i].discard = 1;
}
}
 
static inline cairo_int64_t
_slope_length (cairo_slope_t *slope)
{
return _cairo_int64_add (_cairo_int32x32_64_mul (slope->dx, slope->dx),
_cairo_int32x32_64_mul (slope->dy, slope->dy));
}
 
static int
_cairo_hull_vertex_compare (const void *av, const void *bv)
{
cairo_hull_t *a = (cairo_hull_t *) av;
cairo_hull_t *b = (cairo_hull_t *) bv;
int ret;
 
/* Some libraries are reported to actually compare identical
* pointers and require the result to be 0. This is the crazy world we
* have to live in.
*/
if (a == b)
return 0;
 
ret = _cairo_slope_compare (&a->slope, &b->slope);
 
/*
* In the case of two vertices with identical slope from the
* extremal point discard the nearer point.
*/
if (ret == 0) {
int cmp;
 
cmp = _cairo_int64_cmp (_slope_length (&a->slope),
_slope_length (&b->slope));
 
/*
* Use the points' ids to ensure a well-defined ordering,
* and avoid setting discard on both points.
*/
if (cmp < 0 || (cmp == 0 && a->id < b->id)) {
a->discard = 1;
ret = -1;
} else {
b->discard = 1;
ret = 1;
}
}
 
return ret;
}
 
static int
_cairo_hull_prev_valid (cairo_hull_t *hull, int num_hull, int index)
{
/* hull[0] is always valid, and we never need to wraparound, (if
* we are passed an index of 0 here, then the calling loop is just
* about to terminate). */
if (index == 0)
return 0;
 
do {
index--;
} while (hull[index].discard);
 
return index;
}
 
static int
_cairo_hull_next_valid (cairo_hull_t *hull, int num_hull, int index)
{
do {
index = (index + 1) % num_hull;
} while (hull[index].discard);
 
return index;
}
 
static void
_cairo_hull_eliminate_concave (cairo_hull_t *hull, int num_hull)
{
int i, j, k;
cairo_slope_t slope_ij, slope_jk;
 
i = 0;
j = _cairo_hull_next_valid (hull, num_hull, i);
k = _cairo_hull_next_valid (hull, num_hull, j);
 
do {
_cairo_slope_init (&slope_ij, &hull[i].point, &hull[j].point);
_cairo_slope_init (&slope_jk, &hull[j].point, &hull[k].point);
 
/* Is the angle formed by ij and jk concave? */
if (_cairo_slope_compare (&slope_ij, &slope_jk) >= 0) {
if (i == k)
return;
hull[j].discard = 1;
j = i;
i = _cairo_hull_prev_valid (hull, num_hull, j);
} else {
i = j;
j = k;
k = _cairo_hull_next_valid (hull, num_hull, j);
}
} while (j != 0);
}
 
static void
_cairo_hull_to_pen (cairo_hull_t *hull, cairo_pen_vertex_t *vertices, int *num_vertices)
{
int i, j = 0;
 
for (i = 0; i < *num_vertices; i++) {
if (hull[i].discard)
continue;
vertices[j++].point = hull[i].point;
}
 
*num_vertices = j;
}
 
/* Given a set of vertices, compute the convex hull using the Graham
scan algorithm. */
cairo_status_t
_cairo_hull_compute (cairo_pen_vertex_t *vertices, int *num_vertices)
{
cairo_hull_t hull_stack[CAIRO_STACK_ARRAY_LENGTH (cairo_hull_t)];
cairo_hull_t *hull;
int num_hull = *num_vertices;
 
if (CAIRO_INJECT_FAULT ())
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
if (num_hull > ARRAY_LENGTH (hull_stack)) {
hull = _cairo_malloc_ab (num_hull, sizeof (cairo_hull_t));
if (unlikely (hull == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
} else {
hull = hull_stack;
}
 
_cairo_hull_init (hull, vertices, num_hull);
 
qsort (hull + 1, num_hull - 1,
sizeof (cairo_hull_t), _cairo_hull_vertex_compare);
 
_cairo_hull_eliminate_concave (hull, num_hull);
 
_cairo_hull_to_pen (hull, vertices, num_vertices);
 
if (hull != hull_stack)
free (hull);
 
return CAIRO_STATUS_SUCCESS;
}
/programs/develop/libraries/cairo/src/cairo-image-info-private.h
0,0 → 1,63
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2008 Adrian Johnson
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Adrian Johnson.
*
* Contributor(s):
* Adrian Johnson <ajohnson@redneon.com>
*/
 
#ifndef CAIRO_IMAGE_INFO_PRIVATE_H
#define CAIRO_IMAGE_INFO_PRIVATE_H
 
#include "cairoint.h"
 
typedef struct _cairo_image_info {
int width;
int height;
int num_components;
int bits_per_component;
} cairo_image_info_t;
 
cairo_private cairo_int_status_t
_cairo_image_info_get_jpeg_info (cairo_image_info_t *info,
const unsigned char *data,
long length);
 
cairo_private cairo_int_status_t
_cairo_image_info_get_jpx_info (cairo_image_info_t *info,
const unsigned char *data,
unsigned long length);
 
cairo_private cairo_int_status_t
_cairo_image_info_get_png_info (cairo_image_info_t *info,
const unsigned char *data,
unsigned long length);
 
#endif /* CAIRO_IMAGE_INFO_PRIVATE_H */
/programs/develop/libraries/cairo/src/cairo-image-info.c
0,0 → 1,290
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2008 Adrian Johnson
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Adrian Johnson.
*
* Contributor(s):
* Adrian Johnson <ajohnson@redneon.com>
*/
 
#include "cairoint.h"
#include "cairo-image-info-private.h"
 
static uint32_t
_get_be32 (const unsigned char *p)
{
return p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3];
}
 
/* JPEG (image/jpeg)
*
* http://www.w3.org/Graphics/JPEG/itu-t81.pdf
*/
 
/* Markers with no parameters. All other markers are followed by a two
* byte length of the parameters. */
#define TEM 0x01
#define RST_begin 0xd0
#define RST_end 0xd7
#define SOI 0xd8
#define EOI 0xd9
 
/* Start of frame markers. */
#define SOF0 0xc0
#define SOF1 0xc1
#define SOF2 0xc2
#define SOF3 0xc3
#define SOF5 0xc5
#define SOF6 0xc6
#define SOF7 0xc7
#define SOF9 0xc9
#define SOF10 0xca
#define SOF11 0xcb
#define SOF13 0xcd
#define SOF14 0xce
#define SOF15 0xcf
 
static const unsigned char *
_jpeg_skip_segment (const unsigned char *p)
{
int len;
 
p++;
len = (p[0] << 8) | p[1];
 
return p + len;
}
 
static void
_jpeg_extract_info (cairo_image_info_t *info, const unsigned char *p)
{
info->width = (p[6] << 8) + p[7];
info->height = (p[4] << 8) + p[5];
info->num_components = p[8];
info->bits_per_component = p[3];
}
 
cairo_int_status_t
_cairo_image_info_get_jpeg_info (cairo_image_info_t *info,
const unsigned char *data,
long length)
{
const unsigned char *p = data;
 
while (p + 1 < data + length) {
if (*p != 0xff)
return CAIRO_INT_STATUS_UNSUPPORTED;
p++;
 
switch (*p) {
/* skip fill bytes */
case 0xff:
p++;
break;
 
case TEM:
case SOI:
case EOI:
p++;
break;
 
case SOF0:
case SOF1:
case SOF2:
case SOF3:
case SOF5:
case SOF6:
case SOF7:
case SOF9:
case SOF10:
case SOF11:
case SOF13:
case SOF14:
case SOF15:
/* Start of frame found. Extract the image parameters. */
if (p + 8 > data + length)
return CAIRO_INT_STATUS_UNSUPPORTED;
 
_jpeg_extract_info (info, p);
return CAIRO_STATUS_SUCCESS;
 
default:
if (*p >= RST_begin && *p <= RST_end) {
p++;
break;
}
 
if (p + 2 > data + length)
return CAIRO_INT_STATUS_UNSUPPORTED;
 
p = _jpeg_skip_segment (p);
break;
}
}
 
return CAIRO_STATUS_SUCCESS;
}
 
/* JPEG 2000 (image/jp2)
*
* http://www.jpeg.org/public/15444-1annexi.pdf
*/
 
#define JPX_FILETYPE 0x66747970
#define JPX_JP2_HEADER 0x6A703268
#define JPX_IMAGE_HEADER 0x69686472
 
static const unsigned char _jpx_signature[] = {
0x00, 0x00, 0x00, 0x0c, 0x6a, 0x50, 0x20, 0x20, 0x0d, 0x0a, 0x87, 0x0a
};
 
static const unsigned char *
_jpx_next_box (const unsigned char *p)
{
return p + _get_be32 (p);
}
 
static const unsigned char *
_jpx_get_box_contents (const unsigned char *p)
{
return p + 8;
}
 
static cairo_bool_t
_jpx_match_box (const unsigned char *p, const unsigned char *end, uint32_t type)
{
uint32_t length;
 
if (p + 8 < end) {
length = _get_be32 (p);
if (_get_be32 (p + 4) == type && p + length < end)
return TRUE;
}
 
return FALSE;
}
 
static const unsigned char *
_jpx_find_box (const unsigned char *p, const unsigned char *end, uint32_t type)
{
while (p < end) {
if (_jpx_match_box (p, end, type))
return p;
p = _jpx_next_box (p);
}
 
return NULL;
}
 
static void
_jpx_extract_info (const unsigned char *p, cairo_image_info_t *info)
{
info->height = _get_be32 (p);
info->width = _get_be32 (p + 4);
info->num_components = (p[8] << 8) + p[9];
info->bits_per_component = p[10];
}
 
cairo_int_status_t
_cairo_image_info_get_jpx_info (cairo_image_info_t *info,
const unsigned char *data,
unsigned long length)
{
const unsigned char *p = data;
const unsigned char *end = data + length;
 
/* First 12 bytes must be the JPEG 2000 signature box. */
if (length < ARRAY_LENGTH(_jpx_signature) ||
memcmp(p, _jpx_signature, ARRAY_LENGTH(_jpx_signature)) != 0)
return CAIRO_INT_STATUS_UNSUPPORTED;
 
p += ARRAY_LENGTH(_jpx_signature);
 
/* Next box must be a File Type Box */
if (! _jpx_match_box (p, end, JPX_FILETYPE))
return CAIRO_INT_STATUS_UNSUPPORTED;
 
p = _jpx_next_box (p);
 
/* Locate the JP2 header box. */
p = _jpx_find_box (p, end, JPX_JP2_HEADER);
if (!p)
return CAIRO_INT_STATUS_UNSUPPORTED;
 
/* Step into the JP2 header box. First box must be the Image
* Header */
p = _jpx_get_box_contents (p);
if (! _jpx_match_box (p, end, JPX_IMAGE_HEADER))
return CAIRO_INT_STATUS_UNSUPPORTED;
 
/* Get the image info */
p = _jpx_get_box_contents (p);
_jpx_extract_info (p, info);
 
return CAIRO_STATUS_SUCCESS;
}
 
/* PNG (image/png)
*
* http://www.w3.org/TR/2003/REC-PNG-20031110/
*/
 
#define PNG_IHDR 0x49484452
 
static const unsigned char _png_magic[8] = { 137, 80, 78, 71, 13, 10, 26, 10 };
 
cairo_int_status_t
_cairo_image_info_get_png_info (cairo_image_info_t *info,
const unsigned char *data,
unsigned long length)
{
const unsigned char *p = data;
const unsigned char *end = data + length;
 
if (length < 8 || memcmp (data, _png_magic, 8) != 0)
return CAIRO_INT_STATUS_UNSUPPORTED;
 
p += 8;
 
/* The first chunk must be IDHR. IDHR has 13 bytes of data plus
* the 12 bytes of overhead for the chunk. */
if (p + 13 + 12 > end)
return CAIRO_INT_STATUS_UNSUPPORTED;
 
p += 4;
if (_get_be32 (p) != PNG_IHDR)
return CAIRO_INT_STATUS_UNSUPPORTED;
 
p += 4;
info->width = _get_be32 (p);
p += 4;
info->height = _get_be32 (p);
 
return CAIRO_STATUS_SUCCESS;
}
/programs/develop/libraries/cairo/src/cairo-image-surface.c
0,0 → 1,4702
/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2003 University of Southern California
* Copyright © 2009,2010 Intel Corporation
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
* Chris Wilson <chris@chris-wilson.co.uk>
*/
 
#include "cairoint.h"
 
#include "cairo-boxes-private.h"
#include "cairo-clip-private.h"
#include "cairo-composite-rectangles-private.h"
#include "cairo-error-private.h"
#include "cairo-region-private.h"
#include "cairo-scaled-font-private.h"
#include "cairo-surface-snapshot-private.h"
#include "cairo-surface-subsurface-private.h"
 
/* Limit on the width / height of an image surface in pixels. This is
* mainly determined by coordinates of things sent to pixman at the
* moment being in 16.16 format. */
#define MAX_IMAGE_SIZE 32767
#define PIXMAN_MAX_INT ((pixman_fixed_1 >> 1) - pixman_fixed_e) /* need to ensure deltas also fit */
 
/**
* SECTION:cairo-image
* @Title: Image Surfaces
* @Short_Description: Rendering to memory buffers
* @See_Also: #cairo_surface_t
*
* Image surfaces provide the ability to render to memory buffers
* either allocated by cairo or by the calling code. The supported
* image formats are those defined in #cairo_format_t.
*/
 
/**
* CAIRO_HAS_IMAGE_SURFACE:
*
* Defined if the image surface backend is available.
* The image surface backend is always built in.
* This macro was added for completeness in cairo 1.8.
*
* @Since: 1.8
*/
 
static cairo_int_status_t
_cairo_image_surface_fill (void *dst,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias,
cairo_clip_t *clip);
 
static pixman_image_t *
_pixman_image_for_solid (const cairo_solid_pattern_t *pattern);
 
static cairo_bool_t
_cairo_image_surface_is_size_valid (int width, int height)
{
return 0 <= width && width <= MAX_IMAGE_SIZE &&
0 <= height && height <= MAX_IMAGE_SIZE;
}
 
cairo_format_t
_cairo_format_from_pixman_format (pixman_format_code_t pixman_format)
{
switch (pixman_format) {
case PIXMAN_a8r8g8b8:
return CAIRO_FORMAT_ARGB32;
case PIXMAN_x8r8g8b8:
return CAIRO_FORMAT_RGB24;
case PIXMAN_a8:
return CAIRO_FORMAT_A8;
case PIXMAN_a1:
return CAIRO_FORMAT_A1;
case PIXMAN_r5g6b5:
return CAIRO_FORMAT_RGB16_565;
case PIXMAN_a8b8g8r8: case PIXMAN_x8b8g8r8: case PIXMAN_r8g8b8:
case PIXMAN_b8g8r8: case PIXMAN_b5g6r5:
case PIXMAN_a1r5g5b5: case PIXMAN_x1r5g5b5: case PIXMAN_a1b5g5r5:
case PIXMAN_x1b5g5r5: case PIXMAN_a4r4g4b4: case PIXMAN_x4r4g4b4:
case PIXMAN_a4b4g4r4: case PIXMAN_x4b4g4r4: case PIXMAN_r3g3b2:
case PIXMAN_b2g3r3: case PIXMAN_a2r2g2b2: case PIXMAN_a2b2g2r2:
case PIXMAN_c8: case PIXMAN_g8: case PIXMAN_x4a4:
case PIXMAN_a4: case PIXMAN_r1g2b1: case PIXMAN_b1g2r1:
case PIXMAN_a1r1g1b1: case PIXMAN_a1b1g1r1: case PIXMAN_c4:
case PIXMAN_g4: case PIXMAN_g1:
case PIXMAN_yuy2: case PIXMAN_yv12:
case PIXMAN_b8g8r8x8:
case PIXMAN_b8g8r8a8:
case PIXMAN_x2b10g10r10:
case PIXMAN_a2b10g10r10:
case PIXMAN_x2r10g10b10:
case PIXMAN_a2r10g10b10:
default:
return CAIRO_FORMAT_INVALID;
}
 
return CAIRO_FORMAT_INVALID;
}
 
cairo_content_t
_cairo_content_from_pixman_format (pixman_format_code_t pixman_format)
{
cairo_content_t content;
 
content = 0;
if (PIXMAN_FORMAT_RGB (pixman_format))
content |= CAIRO_CONTENT_COLOR;
if (PIXMAN_FORMAT_A (pixman_format))
content |= CAIRO_CONTENT_ALPHA;
 
return content;
}
 
cairo_surface_t *
_cairo_image_surface_create_for_pixman_image (pixman_image_t *pixman_image,
pixman_format_code_t pixman_format)
{
cairo_image_surface_t *surface;
int width = pixman_image_get_width (pixman_image);
int height = pixman_image_get_height (pixman_image);
 
surface = malloc (sizeof (cairo_image_surface_t));
if (unlikely (surface == NULL))
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
 
_cairo_surface_init (&surface->base,
&_cairo_image_surface_backend,
NULL, /* device */
_cairo_content_from_pixman_format (pixman_format));
 
surface->pixman_image = pixman_image;
 
surface->pixman_format = pixman_format;
surface->format = _cairo_format_from_pixman_format (pixman_format);
surface->data = (uint8_t *) pixman_image_get_data (pixman_image);
surface->owns_data = FALSE;
surface->transparency = CAIRO_IMAGE_UNKNOWN;
 
surface->width = width;
surface->height = height;
surface->stride = pixman_image_get_stride (pixman_image);
surface->depth = pixman_image_get_depth (pixman_image);
 
return &surface->base;
}
 
cairo_bool_t
_pixman_format_from_masks (cairo_format_masks_t *masks,
pixman_format_code_t *format_ret)
{
pixman_format_code_t format;
int format_type;
int a, r, g, b;
cairo_format_masks_t format_masks;
 
a = _cairo_popcount (masks->alpha_mask);
r = _cairo_popcount (masks->red_mask);
g = _cairo_popcount (masks->green_mask);
b = _cairo_popcount (masks->blue_mask);
 
if (masks->red_mask) {
if (masks->red_mask > masks->blue_mask)
format_type = PIXMAN_TYPE_ARGB;
else
format_type = PIXMAN_TYPE_ABGR;
} else if (masks->alpha_mask) {
format_type = PIXMAN_TYPE_A;
} else {
return FALSE;
}
 
format = PIXMAN_FORMAT (masks->bpp, format_type, a, r, g, b);
 
if (! pixman_format_supported_destination (format))
return FALSE;
 
/* Sanity check that we got out of PIXMAN_FORMAT exactly what we
* expected. This avoid any problems from something bizarre like
* alpha in the least-significant bits, or insane channel order,
* or whatever. */
if (!_pixman_format_to_masks (format, &format_masks) ||
masks->bpp != format_masks.bpp ||
masks->red_mask != format_masks.red_mask ||
masks->green_mask != format_masks.green_mask ||
masks->blue_mask != format_masks.blue_mask)
{
return FALSE;
}
 
*format_ret = format;
return TRUE;
}
 
/* A mask consisting of N bits set to 1. */
#define MASK(N) ((1UL << (N))-1)
 
cairo_bool_t
_pixman_format_to_masks (pixman_format_code_t format,
cairo_format_masks_t *masks)
{
int a, r, g, b;
 
masks->bpp = PIXMAN_FORMAT_BPP (format);
 
/* Number of bits in each channel */
a = PIXMAN_FORMAT_A (format);
r = PIXMAN_FORMAT_R (format);
g = PIXMAN_FORMAT_G (format);
b = PIXMAN_FORMAT_B (format);
 
switch (PIXMAN_FORMAT_TYPE (format)) {
case PIXMAN_TYPE_ARGB:
masks->alpha_mask = MASK (a) << (r + g + b);
masks->red_mask = MASK (r) << (g + b);
masks->green_mask = MASK (g) << (b);
masks->blue_mask = MASK (b);
return TRUE;
case PIXMAN_TYPE_ABGR:
masks->alpha_mask = MASK (a) << (b + g + r);
masks->blue_mask = MASK (b) << (g + r);
masks->green_mask = MASK (g) << (r);
masks->red_mask = MASK (r);
return TRUE;
#ifdef PIXMAN_TYPE_BGRA
case PIXMAN_TYPE_BGRA:
masks->blue_mask = MASK (b) << (masks->bpp - b);
masks->green_mask = MASK (g) << (masks->bpp - b - g);
masks->red_mask = MASK (r) << (masks->bpp - b - g - r);
masks->alpha_mask = MASK (a);
return TRUE;
#endif
case PIXMAN_TYPE_A:
masks->alpha_mask = MASK (a);
masks->red_mask = 0;
masks->green_mask = 0;
masks->blue_mask = 0;
return TRUE;
case PIXMAN_TYPE_OTHER:
case PIXMAN_TYPE_COLOR:
case PIXMAN_TYPE_GRAY:
case PIXMAN_TYPE_YUY2:
case PIXMAN_TYPE_YV12:
default:
masks->alpha_mask = 0;
masks->red_mask = 0;
masks->green_mask = 0;
masks->blue_mask = 0;
return FALSE;
}
}
 
pixman_format_code_t
_cairo_format_to_pixman_format_code (cairo_format_t format)
{
pixman_format_code_t ret;
switch (format) {
case CAIRO_FORMAT_A1:
ret = PIXMAN_a1;
break;
case CAIRO_FORMAT_A8:
ret = PIXMAN_a8;
break;
case CAIRO_FORMAT_RGB24:
ret = PIXMAN_x8r8g8b8;
break;
case CAIRO_FORMAT_RGB16_565:
ret = PIXMAN_r5g6b5;
break;
case CAIRO_FORMAT_ARGB32:
case CAIRO_FORMAT_INVALID:
default:
ret = PIXMAN_a8r8g8b8;
break;
}
return ret;
}
 
cairo_surface_t *
_cairo_image_surface_create_with_pixman_format (unsigned char *data,
pixman_format_code_t pixman_format,
int width,
int height,
int stride)
{
cairo_surface_t *surface;
pixman_image_t *pixman_image;
 
if (! _cairo_image_surface_is_size_valid (width, height))
{
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE));
}
 
pixman_image = pixman_image_create_bits (pixman_format, width, height,
(uint32_t *) data, stride);
 
if (unlikely (pixman_image == NULL))
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
 
surface = _cairo_image_surface_create_for_pixman_image (pixman_image,
pixman_format);
if (unlikely (surface->status)) {
pixman_image_unref (pixman_image);
return surface;
}
 
/* we can not make any assumptions about the initial state of user data */
surface->is_clear = data == NULL;
return surface;
}
 
/**
* cairo_image_surface_create:
* @format: format of pixels in the surface to create
* @width: width of the surface, in pixels
* @height: height of the surface, in pixels
*
* Creates an image surface of the specified format and
* dimensions. Initially the surface contents are all
* 0. (Specifically, within each pixel, each color or alpha channel
* belonging to format will be 0. The contents of bits within a pixel,
* but not belonging to the given format are undefined).
*
* Return value: a pointer to the newly created surface. The caller
* owns the surface and should call cairo_surface_destroy() when done
* with it.
*
* This function always returns a valid pointer, but it will return a
* pointer to a "nil" surface if an error such as out of memory
* occurs. You can use cairo_surface_status() to check for this.
**/
cairo_surface_t *
cairo_image_surface_create (cairo_format_t format,
int width,
int height)
{
pixman_format_code_t pixman_format;
 
if (! CAIRO_FORMAT_VALID (format))
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT));
 
pixman_format = _cairo_format_to_pixman_format_code (format);
 
return _cairo_image_surface_create_with_pixman_format (NULL, pixman_format,
width, height, -1);
}
slim_hidden_def (cairo_image_surface_create);
 
cairo_surface_t *
_cairo_image_surface_create_with_content (cairo_content_t content,
int width,
int height)
{
return cairo_image_surface_create (_cairo_format_from_content (content),
width, height);
}
 
/**
* cairo_format_stride_for_width:
* @format: A #cairo_format_t value
* @width: The desired width of an image surface to be created.
*
* This function provides a stride value that will respect all
* alignment requirements of the accelerated image-rendering code
* within cairo. Typical usage will be of the form:
*
* <informalexample><programlisting>
* int stride;
* unsigned char *data;
* #cairo_surface_t *surface;
*
* stride = cairo_format_stride_for_width (format, width);
* data = malloc (stride * height);
* surface = cairo_image_surface_create_for_data (data, format,
* width, height,
* stride);
* </programlisting></informalexample>
*
* Return value: the appropriate stride to use given the desired
* format and width, or -1 if either the format is invalid or the width
* too large.
*
* Since: 1.6
**/
int
cairo_format_stride_for_width (cairo_format_t format,
int width)
{
int bpp;
 
if (! CAIRO_FORMAT_VALID (format)) {
_cairo_error_throw (CAIRO_STATUS_INVALID_FORMAT);
return -1;
}
 
bpp = _cairo_format_bits_per_pixel (format);
if ((unsigned) (width) >= (INT32_MAX - 7) / (unsigned) (bpp))
return -1;
 
return CAIRO_STRIDE_FOR_WIDTH_BPP (width, bpp);
}
slim_hidden_def (cairo_format_stride_for_width);
 
/**
* cairo_image_surface_create_for_data:
* @data: a pointer to a buffer supplied by the application in which
* to write contents. This pointer must be suitably aligned for any
* kind of variable, (for example, a pointer returned by malloc).
* @format: the format of pixels in the buffer
* @width: the width of the image to be stored in the buffer
* @height: the height of the image to be stored in the buffer
* @stride: the number of bytes between the start of rows in the
* buffer as allocated. This value should always be computed by
* cairo_format_stride_for_width() before allocating the data
* buffer.
*
* Creates an image surface for the provided pixel data. The output
* buffer must be kept around until the #cairo_surface_t is destroyed
* or cairo_surface_finish() is called on the surface. The initial
* contents of @data will be used as the initial image contents; you
* must explicitly clear the buffer, using, for example,
* cairo_rectangle() and cairo_fill() if you want it cleared.
*
* Note that the stride may be larger than
* width*bytes_per_pixel to provide proper alignment for each pixel
* and row. This alignment is required to allow high-performance rendering
* within cairo. The correct way to obtain a legal stride value is to
* call cairo_format_stride_for_width() with the desired format and
* maximum image width value, and then use the resulting stride value
* to allocate the data and to create the image surface. See
* cairo_format_stride_for_width() for example code.
*
* Return value: a pointer to the newly created surface. The caller
* owns the surface and should call cairo_surface_destroy() when done
* with it.
*
* This function always returns a valid pointer, but it will return a
* pointer to a "nil" surface in the case of an error such as out of
* memory or an invalid stride value. In case of invalid stride value
* the error status of the returned surface will be
* %CAIRO_STATUS_INVALID_STRIDE. You can use
* cairo_surface_status() to check for this.
*
* See cairo_surface_set_user_data() for a means of attaching a
* destroy-notification fallback to the surface if necessary.
**/
cairo_surface_t *
cairo_image_surface_create_for_data (unsigned char *data,
cairo_format_t format,
int width,
int height,
int stride)
{
pixman_format_code_t pixman_format;
int minstride;
 
if (! CAIRO_FORMAT_VALID (format))
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT));
 
if ((stride & (CAIRO_STRIDE_ALIGNMENT-1)) != 0)
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_STRIDE));
 
if (! _cairo_image_surface_is_size_valid (width, height))
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE));
 
minstride = cairo_format_stride_for_width (format, width);
if (stride < 0) {
if (stride > -minstride) {
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_STRIDE));
}
} else {
if (stride < minstride) {
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_STRIDE));
}
}
 
pixman_format = _cairo_format_to_pixman_format_code (format);
return _cairo_image_surface_create_with_pixman_format (data,
pixman_format,
width, height,
stride);
}
slim_hidden_def (cairo_image_surface_create_for_data);
 
/**
* cairo_image_surface_get_data:
* @surface: a #cairo_image_surface_t
*
* Get a pointer to the data of the image surface, for direct
* inspection or modification.
*
* Return value: a pointer to the image data of this surface or %NULL
* if @surface is not an image surface, or if cairo_surface_finish()
* has been called.
*
* Since: 1.2
**/
unsigned char *
cairo_image_surface_get_data (cairo_surface_t *surface)
{
cairo_image_surface_t *image_surface = (cairo_image_surface_t *) surface;
 
if (! _cairo_surface_is_image (surface)) {
_cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
return NULL;
}
 
return image_surface->data;
}
slim_hidden_def (cairo_image_surface_get_data);
 
/**
* cairo_image_surface_get_format:
* @surface: a #cairo_image_surface_t
*
* Get the format of the surface.
*
* Return value: the format of the surface
*
* Since: 1.2
**/
cairo_format_t
cairo_image_surface_get_format (cairo_surface_t *surface)
{
cairo_image_surface_t *image_surface = (cairo_image_surface_t *) surface;
 
if (! _cairo_surface_is_image (surface)) {
_cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
return CAIRO_FORMAT_INVALID;
}
 
return image_surface->format;
}
slim_hidden_def (cairo_image_surface_get_format);
 
/**
* cairo_image_surface_get_width:
* @surface: a #cairo_image_surface_t
*
* Get the width of the image surface in pixels.
*
* Return value: the width of the surface in pixels.
**/
int
cairo_image_surface_get_width (cairo_surface_t *surface)
{
cairo_image_surface_t *image_surface = (cairo_image_surface_t *) surface;
 
if (! _cairo_surface_is_image (surface)) {
_cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
return 0;
}
 
return image_surface->width;
}
slim_hidden_def (cairo_image_surface_get_width);
 
/**
* cairo_image_surface_get_height:
* @surface: a #cairo_image_surface_t
*
* Get the height of the image surface in pixels.
*
* Return value: the height of the surface in pixels.
**/
int
cairo_image_surface_get_height (cairo_surface_t *surface)
{
cairo_image_surface_t *image_surface = (cairo_image_surface_t *) surface;
 
if (! _cairo_surface_is_image (surface)) {
_cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
return 0;
}
 
return image_surface->height;
}
slim_hidden_def (cairo_image_surface_get_height);
 
/**
* cairo_image_surface_get_stride:
* @surface: a #cairo_image_surface_t
*
* Get the stride of the image surface in bytes
*
* Return value: the stride of the image surface in bytes (or 0 if
* @surface is not an image surface). The stride is the distance in
* bytes from the beginning of one row of the image data to the
* beginning of the next row.
*
* Since: 1.2
**/
int
cairo_image_surface_get_stride (cairo_surface_t *surface)
{
 
cairo_image_surface_t *image_surface = (cairo_image_surface_t *) surface;
 
if (! _cairo_surface_is_image (surface)) {
_cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
return 0;
}
 
return image_surface->stride;
}
slim_hidden_def (cairo_image_surface_get_stride);
 
cairo_format_t
_cairo_format_from_content (cairo_content_t content)
{
switch (content) {
case CAIRO_CONTENT_COLOR:
return CAIRO_FORMAT_RGB24;
case CAIRO_CONTENT_ALPHA:
return CAIRO_FORMAT_A8;
case CAIRO_CONTENT_COLOR_ALPHA:
return CAIRO_FORMAT_ARGB32;
}
 
ASSERT_NOT_REACHED;
return CAIRO_FORMAT_INVALID;
}
 
cairo_content_t
_cairo_content_from_format (cairo_format_t format)
{
switch (format) {
case CAIRO_FORMAT_ARGB32:
return CAIRO_CONTENT_COLOR_ALPHA;
case CAIRO_FORMAT_RGB24:
return CAIRO_CONTENT_COLOR;
case CAIRO_FORMAT_RGB16_565:
return CAIRO_CONTENT_COLOR;
case CAIRO_FORMAT_A8:
case CAIRO_FORMAT_A1:
return CAIRO_CONTENT_ALPHA;
case CAIRO_FORMAT_INVALID:
break;
}
 
ASSERT_NOT_REACHED;
return CAIRO_CONTENT_COLOR_ALPHA;
}
 
int
_cairo_format_bits_per_pixel (cairo_format_t format)
{
switch (format) {
case CAIRO_FORMAT_ARGB32:
return 32;
case CAIRO_FORMAT_RGB24:
return 32;
case CAIRO_FORMAT_RGB16_565:
return 16;
case CAIRO_FORMAT_A8:
return 8;
case CAIRO_FORMAT_A1:
return 1;
case CAIRO_FORMAT_INVALID:
default:
ASSERT_NOT_REACHED;
return 0;
}
}
 
static cairo_surface_t *
_cairo_image_surface_create_similar (void *abstract_other,
cairo_content_t content,
int width,
int height)
{
cairo_image_surface_t *other = abstract_other;
 
if (! _cairo_image_surface_is_size_valid (width, height))
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE));
 
if (content == other->base.content) {
return _cairo_image_surface_create_with_pixman_format (NULL,
other->pixman_format,
width, height,
0);
}
 
return _cairo_image_surface_create_with_content (content,
width, height);
}
 
static cairo_status_t
_cairo_image_surface_finish (void *abstract_surface)
{
cairo_image_surface_t *surface = abstract_surface;
 
if (surface->pixman_image) {
pixman_image_unref (surface->pixman_image);
surface->pixman_image = NULL;
}
 
if (surface->owns_data) {
free (surface->data);
surface->data = NULL;
}
 
return CAIRO_STATUS_SUCCESS;
}
 
void
_cairo_image_surface_assume_ownership_of_data (cairo_image_surface_t *surface)
{
surface->owns_data = TRUE;
}
 
static cairo_status_t
_cairo_image_surface_acquire_source_image (void *abstract_surface,
cairo_image_surface_t **image_out,
void **image_extra)
{
*image_out = abstract_surface;
*image_extra = NULL;
 
return CAIRO_STATUS_SUCCESS;
}
 
static void
_cairo_image_surface_release_source_image (void *abstract_surface,
cairo_image_surface_t *image,
void *image_extra)
{
}
 
/* XXX: I think we should fix pixman to match the names/order of the
* cairo operators, but that will likely be better done at the same
* time the X server is ported to pixman, (which will change a lot of
* things in pixman I think).
*/
static pixman_op_t
_pixman_operator (cairo_operator_t op)
{
switch (op) {
case CAIRO_OPERATOR_CLEAR:
return PIXMAN_OP_CLEAR;
 
case CAIRO_OPERATOR_SOURCE:
return PIXMAN_OP_SRC;
case CAIRO_OPERATOR_OVER:
return PIXMAN_OP_OVER;
case CAIRO_OPERATOR_IN:
return PIXMAN_OP_IN;
case CAIRO_OPERATOR_OUT:
return PIXMAN_OP_OUT;
case CAIRO_OPERATOR_ATOP:
return PIXMAN_OP_ATOP;
 
case CAIRO_OPERATOR_DEST:
return PIXMAN_OP_DST;
case CAIRO_OPERATOR_DEST_OVER:
return PIXMAN_OP_OVER_REVERSE;
case CAIRO_OPERATOR_DEST_IN:
return PIXMAN_OP_IN_REVERSE;
case CAIRO_OPERATOR_DEST_OUT:
return PIXMAN_OP_OUT_REVERSE;
case CAIRO_OPERATOR_DEST_ATOP:
return PIXMAN_OP_ATOP_REVERSE;
 
case CAIRO_OPERATOR_XOR:
return PIXMAN_OP_XOR;
case CAIRO_OPERATOR_ADD:
return PIXMAN_OP_ADD;
case CAIRO_OPERATOR_SATURATE:
return PIXMAN_OP_SATURATE;
 
case CAIRO_OPERATOR_MULTIPLY:
return PIXMAN_OP_MULTIPLY;
case CAIRO_OPERATOR_SCREEN:
return PIXMAN_OP_SCREEN;
case CAIRO_OPERATOR_OVERLAY:
return PIXMAN_OP_OVERLAY;
case CAIRO_OPERATOR_DARKEN:
return PIXMAN_OP_DARKEN;
case CAIRO_OPERATOR_LIGHTEN:
return PIXMAN_OP_LIGHTEN;
case CAIRO_OPERATOR_COLOR_DODGE:
return PIXMAN_OP_COLOR_DODGE;
case CAIRO_OPERATOR_COLOR_BURN:
return PIXMAN_OP_COLOR_BURN;
case CAIRO_OPERATOR_HARD_LIGHT:
return PIXMAN_OP_HARD_LIGHT;
case CAIRO_OPERATOR_SOFT_LIGHT:
return PIXMAN_OP_SOFT_LIGHT;
case CAIRO_OPERATOR_DIFFERENCE:
return PIXMAN_OP_DIFFERENCE;
case CAIRO_OPERATOR_EXCLUSION:
return PIXMAN_OP_EXCLUSION;
case CAIRO_OPERATOR_HSL_HUE:
return PIXMAN_OP_HSL_HUE;
case CAIRO_OPERATOR_HSL_SATURATION:
return PIXMAN_OP_HSL_SATURATION;
case CAIRO_OPERATOR_HSL_COLOR:
return PIXMAN_OP_HSL_COLOR;
case CAIRO_OPERATOR_HSL_LUMINOSITY:
return PIXMAN_OP_HSL_LUMINOSITY;
 
default:
ASSERT_NOT_REACHED;
return PIXMAN_OP_OVER;
}
}
 
static cairo_status_t
_cairo_image_surface_set_clip_region (cairo_image_surface_t *surface,
cairo_region_t *region)
{
if (! pixman_image_set_clip_region32 (surface->pixman_image, &region->rgn))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
return CAIRO_STATUS_SUCCESS;
}
 
static void
_cairo_image_surface_unset_clip_region (cairo_image_surface_t *surface)
{
pixman_image_set_clip_region32 (surface->pixman_image, NULL);
}
 
static double
_pixman_nearest_sample (double d)
{
return ceil (d - .5);
}
 
static cairo_bool_t
_nearest_sample (cairo_filter_t filter, double *tx, double *ty)
{
if (filter == CAIRO_FILTER_FAST || filter == CAIRO_FILTER_NEAREST) {
*tx = _pixman_nearest_sample (*tx);
*ty = _pixman_nearest_sample (*ty);
} else {
if (*tx != floor (*tx) || *ty != floor (*ty))
return FALSE;
}
return fabs (*tx) < PIXMAN_MAX_INT && fabs (*ty) < PIXMAN_MAX_INT;
}
 
#if HAS_ATOMIC_OPS
static pixman_image_t *__pixman_transparent_image;
static pixman_image_t *__pixman_black_image;
static pixman_image_t *__pixman_white_image;
 
static pixman_image_t *
_pixman_transparent_image (void)
{
pixman_image_t *image;
 
image = __pixman_transparent_image;
if (unlikely (image == NULL)) {
pixman_color_t color;
 
color.red = 0x00;
color.green = 0x00;
color.blue = 0x00;
color.alpha = 0x00;
 
image = pixman_image_create_solid_fill (&color);
if (unlikely (image == NULL))
return NULL;
 
if (_cairo_atomic_ptr_cmpxchg (&__pixman_transparent_image,
NULL, image))
{
pixman_image_ref (image);
}
} else {
pixman_image_ref (image);
}
 
return image;
}
 
static pixman_image_t *
_pixman_black_image (void)
{
pixman_image_t *image;
 
image = __pixman_black_image;
if (unlikely (image == NULL)) {
pixman_color_t color;
 
color.red = 0x00;
color.green = 0x00;
color.blue = 0x00;
color.alpha = 0xffff;
 
image = pixman_image_create_solid_fill (&color);
if (unlikely (image == NULL))
return NULL;
 
if (_cairo_atomic_ptr_cmpxchg (&__pixman_black_image,
NULL, image))
{
pixman_image_ref (image);
}
} else {
pixman_image_ref (image);
}
 
return image;
}
 
static pixman_image_t *
_pixman_white_image (void)
{
pixman_image_t *image;
 
image = __pixman_white_image;
if (unlikely (image == NULL)) {
pixman_color_t color;
 
color.red = 0xffff;
color.green = 0xffff;
color.blue = 0xffff;
color.alpha = 0xffff;
 
image = pixman_image_create_solid_fill (&color);
if (unlikely (image == NULL))
return NULL;
 
if (_cairo_atomic_ptr_cmpxchg (&__pixman_white_image,
NULL, image))
{
pixman_image_ref (image);
}
} else {
pixman_image_ref (image);
}
 
return image;
}
#else
static pixman_image_t *
_pixman_transparent_image (void)
{
return _pixman_image_for_solid (&_cairo_pattern_clear);
}
static pixman_image_t *
_pixman_black_image (void)
{
return _pixman_image_for_solid (&_cairo_pattern_black);
}
static pixman_image_t *
_pixman_white_image (void)
{
return _pixman_image_for_solid (&_cairo_pattern_white);
}
#endif
 
static uint32_t
hars_petruska_f54_1_random (void)
{
#define rol(x,k) ((x << k) | (x >> (32-k)))
static uint32_t x;
return x = (x ^ rol (x, 5) ^ rol (x, 24)) + 0x37798849;
#undef rol
}
 
static struct {
cairo_color_t color;
pixman_image_t *image;
} cache[16];
static int n_cached;
 
void
_cairo_image_reset_static_data (void)
{
while (n_cached)
pixman_image_unref (cache[--n_cached].image);
 
#if HAS_ATOMIC_OPS
if (__pixman_transparent_image) {
pixman_image_unref (__pixman_transparent_image);
__pixman_transparent_image = NULL;
}
 
if (__pixman_black_image) {
pixman_image_unref (__pixman_black_image);
__pixman_black_image = NULL;
}
 
if (__pixman_white_image) {
pixman_image_unref (__pixman_white_image);
__pixman_white_image = NULL;
}
#endif
}
 
static pixman_image_t *
_pixman_image_for_solid (const cairo_solid_pattern_t *pattern)
{
pixman_color_t color;
pixman_image_t *image;
int i;
 
#if HAS_ATOMIC_OPS
if (pattern->color.alpha_short <= 0x00ff)
return _pixman_transparent_image ();
 
if (pattern->color.alpha_short >= 0xff00) {
if (pattern->color.red_short <= 0x00ff &&
pattern->color.green_short <= 0x00ff &&
pattern->color.blue_short <= 0x00ff)
{
return _pixman_black_image ();
}
 
if (pattern->color.red_short >= 0xff00 &&
pattern->color.green_short >= 0xff00 &&
pattern->color.blue_short >= 0xff00)
{
return _pixman_white_image ();
}
}
#endif
 
CAIRO_MUTEX_LOCK (_cairo_image_solid_cache_mutex);
for (i = 0; i < n_cached; i++) {
if (_cairo_color_equal (&cache[i].color, &pattern->color)) {
image = pixman_image_ref (cache[i].image);
goto UNLOCK;
}
}
 
color.red = pattern->color.red_short;
color.green = pattern->color.green_short;
color.blue = pattern->color.blue_short;
color.alpha = pattern->color.alpha_short;
 
image = pixman_image_create_solid_fill (&color);
if (image == NULL)
goto UNLOCK;
 
if (n_cached < ARRAY_LENGTH (cache)) {
i = n_cached++;
} else {
i = hars_petruska_f54_1_random () % ARRAY_LENGTH (cache);
pixman_image_unref (cache[i].image);
}
cache[i].image = pixman_image_ref (image);
cache[i].color = pattern->color;
 
UNLOCK:
CAIRO_MUTEX_UNLOCK (_cairo_image_solid_cache_mutex);
return image;
}
 
static pixman_image_t *
_pixman_image_for_gradient (const cairo_gradient_pattern_t *pattern,
const cairo_rectangle_int_t *extents,
int *ix, int *iy)
{
pixman_image_t *pixman_image;
pixman_gradient_stop_t pixman_stops_static[2];
pixman_gradient_stop_t *pixman_stops = pixman_stops_static;
cairo_matrix_t matrix = pattern->base.matrix;
double tx, ty;
unsigned int i;
 
if (pattern->n_stops > ARRAY_LENGTH(pixman_stops_static)) {
pixman_stops = _cairo_malloc_ab (pattern->n_stops,
sizeof(pixman_gradient_stop_t));
if (unlikely (pixman_stops == NULL))
return NULL;
}
 
for (i = 0; i < pattern->n_stops; i++) {
pixman_stops[i].x = _cairo_fixed_16_16_from_double (pattern->stops[i].offset);
pixman_stops[i].color.red = pattern->stops[i].color.red_short;
pixman_stops[i].color.green = pattern->stops[i].color.green_short;
pixman_stops[i].color.blue = pattern->stops[i].color.blue_short;
pixman_stops[i].color.alpha = pattern->stops[i].color.alpha_short;
}
 
if (pattern->base.type == CAIRO_PATTERN_TYPE_LINEAR) {
cairo_linear_pattern_t *linear = (cairo_linear_pattern_t *) pattern;
pixman_point_fixed_t p1, p2;
cairo_fixed_t xdim, ydim;
 
xdim = fabs (linear->p2.x - linear->p1.x);
ydim = fabs (linear->p2.y - linear->p1.y);
 
/*
* Transform the matrix to avoid overflow when converting between
* cairo_fixed_t and pixman_fixed_t (without incurring performance
* loss when the transformation is unnecessary).
*
* XXX: Consider converting out-of-range co-ordinates and transforms.
* Having a function to compute the required transformation to
* "normalize" a given bounding box would be generally useful -
* cf linear patterns, gradient patterns, surface patterns...
*/
if (_cairo_fixed_integer_ceil (xdim) > PIXMAN_MAX_INT ||
_cairo_fixed_integer_ceil (ydim) > PIXMAN_MAX_INT)
{
double sf;
 
if (xdim > ydim)
sf = PIXMAN_MAX_INT / _cairo_fixed_to_double (xdim);
else
sf = PIXMAN_MAX_INT / _cairo_fixed_to_double (ydim);
 
p1.x = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (linear->p1.x) * sf);
p1.y = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (linear->p1.y) * sf);
p2.x = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (linear->p2.x) * sf);
p2.y = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (linear->p2.y) * sf);
 
cairo_matrix_scale (&matrix, sf, sf);
}
else
{
p1.x = _cairo_fixed_to_16_16 (linear->p1.x);
p1.y = _cairo_fixed_to_16_16 (linear->p1.y);
p2.x = _cairo_fixed_to_16_16 (linear->p2.x);
p2.y = _cairo_fixed_to_16_16 (linear->p2.y);
}
 
pixman_image = pixman_image_create_linear_gradient (&p1, &p2,
pixman_stops,
pattern->n_stops);
} else {
cairo_radial_pattern_t *radial = (cairo_radial_pattern_t *) pattern;
pixman_point_fixed_t c1, c2;
pixman_fixed_t r1, r2;
 
c1.x = _cairo_fixed_to_16_16 (radial->c1.x);
c1.y = _cairo_fixed_to_16_16 (radial->c1.y);
r1 = _cairo_fixed_to_16_16 (radial->r1);
 
c2.x = _cairo_fixed_to_16_16 (radial->c2.x);
c2.y = _cairo_fixed_to_16_16 (radial->c2.y);
r2 = _cairo_fixed_to_16_16 (radial->r2);
 
pixman_image = pixman_image_create_radial_gradient (&c1, &c2, r1, r2,
pixman_stops,
pattern->n_stops);
}
 
if (pixman_stops != pixman_stops_static)
free (pixman_stops);
 
if (unlikely (pixman_image == NULL))
return NULL;
 
tx = pattern->base.matrix.x0;
ty = pattern->base.matrix.y0;
if (! _cairo_matrix_is_translation (&pattern->base.matrix) ||
! _nearest_sample (pattern->base.filter, &tx, &ty))
{
pixman_transform_t pixman_transform;
 
if (tx != 0. || ty != 0.) {
cairo_matrix_t m, inv;
cairo_status_t status;
double x, y;
 
/* pixman also limits the [xy]_offset to 16 bits so evenly
* spread the bits between the two.
*/
inv = pattern->base.matrix;
status = cairo_matrix_invert (&inv);
assert (status == CAIRO_STATUS_SUCCESS);
 
x = floor (inv.x0 / 2);
y = floor (inv.y0 / 2);
tx = -x;
ty = -y;
cairo_matrix_init_translate (&inv, x, y);
cairo_matrix_multiply (&m, &inv, &pattern->base.matrix);
_cairo_matrix_to_pixman_matrix (&m, &pixman_transform,
extents->x + extents->width/2.,
extents->y + extents->height/2.);
} else {
tx = ty = 0;
_cairo_matrix_to_pixman_matrix (&pattern->base.matrix,
&pixman_transform,
extents->x + extents->width/2.,
extents->y + extents->height/2.);
}
 
if (! pixman_image_set_transform (pixman_image, &pixman_transform)) {
pixman_image_unref (pixman_image);
return NULL;
}
}
*ix = tx;
*iy = ty;
 
{
pixman_repeat_t pixman_repeat;
 
switch (pattern->base.extend) {
default:
case CAIRO_EXTEND_NONE:
pixman_repeat = PIXMAN_REPEAT_NONE;
break;
case CAIRO_EXTEND_REPEAT:
pixman_repeat = PIXMAN_REPEAT_NORMAL;
break;
case CAIRO_EXTEND_REFLECT:
pixman_repeat = PIXMAN_REPEAT_REFLECT;
break;
case CAIRO_EXTEND_PAD:
pixman_repeat = PIXMAN_REPEAT_PAD;
break;
}
 
pixman_image_set_repeat (pixman_image, pixman_repeat);
}
 
return pixman_image;
}
 
struct acquire_source_cleanup {
cairo_surface_t *surface;
cairo_image_surface_t *image;
void *image_extra;
};
 
static void
_acquire_source_cleanup (pixman_image_t *pixman_image,
void *closure)
{
struct acquire_source_cleanup *data = closure;
 
_cairo_surface_release_source_image (data->surface,
data->image,
data->image_extra);
free (data);
}
 
static cairo_filter_t
sampled_area (const cairo_surface_pattern_t *pattern,
const cairo_rectangle_int_t *extents,
cairo_rectangle_int_t *sample)
{
cairo_filter_t filter;
double x1, x2, y1, y2;
double pad;
 
x1 = extents->x;
y1 = extents->y;
x2 = extents->x + (int) extents->width;
y2 = extents->y + (int) extents->height;
 
_cairo_matrix_transform_bounding_box (&pattern->base.matrix,
&x1, &y1, &x2, &y2,
NULL);
 
filter = _cairo_pattern_analyze_filter (&pattern->base, &pad);
sample->x = floor (x1 - pad);
sample->y = floor (y1 - pad);
sample->width = ceil (x2 + pad) - sample->x;
sample->height = ceil (y2 + pad) - sample->y;
 
return filter;
}
 
static uint16_t
expand_channel (uint16_t v, uint32_t bits)
{
int offset = 16 - bits;
while (offset > 0) {
v |= v >> bits;
offset -= bits;
bits += bits;
}
return v;
}
 
static pixman_image_t *
_pixel_to_solid (cairo_image_surface_t *image, int x, int y)
{
uint32_t pixel;
pixman_color_t color;
 
switch (image->format) {
default:
case CAIRO_FORMAT_INVALID:
ASSERT_NOT_REACHED;
return NULL;
 
case CAIRO_FORMAT_A1:
pixel = *(uint8_t *) (image->data + y * image->stride + x/8);
return pixel & (1 << (x&7)) ? _pixman_white_image () : _pixman_transparent_image ();
 
case CAIRO_FORMAT_A8:
color.alpha = *(uint8_t *) (image->data + y * image->stride + x);
color.alpha |= color.alpha << 8;
if (color.alpha == 0)
return _pixman_transparent_image ();
 
color.red = color.green = color.blue = 0;
return pixman_image_create_solid_fill (&color);
 
case CAIRO_FORMAT_RGB16_565:
pixel = *(uint16_t *) (image->data + y * image->stride + 2 * x);
if (pixel == 0)
return _pixman_black_image ();
if (pixel == 0xffff)
return _pixman_white_image ();
 
color.alpha = 0xffff;
color.red = expand_channel ((pixel >> 11 & 0x1f) << 11, 5);
color.green = expand_channel ((pixel >> 5 & 0x3f) << 10, 6);
color.blue = expand_channel ((pixel & 0x1f) << 11, 5);
return pixman_image_create_solid_fill (&color);
 
case CAIRO_FORMAT_ARGB32:
case CAIRO_FORMAT_RGB24:
pixel = *(uint32_t *) (image->data + y * image->stride + 4 * x);
color.alpha = image->format == CAIRO_FORMAT_ARGB32 ? (pixel >> 24) | (pixel >> 16 & 0xff00) : 0xffff;
if (color.alpha == 0)
return _pixman_transparent_image ();
if (pixel == 0xffffffff)
return _pixman_white_image ();
if (color.alpha == 0xffff && (pixel & 0xffffff) == 0)
return _pixman_black_image ();
 
color.red = (pixel >> 16 & 0xff) | (pixel >> 8 & 0xff00);
color.green = (pixel >> 8 & 0xff) | (pixel & 0xff00);
color.blue = (pixel & 0xff) | (pixel << 8 & 0xff00);
return pixman_image_create_solid_fill (&color);
}
}
 
static pixman_image_t *
_pixman_image_for_surface (const cairo_surface_pattern_t *pattern,
cairo_bool_t is_mask,
const cairo_rectangle_int_t *extents,
int *ix, int *iy)
{
pixman_image_t *pixman_image;
cairo_rectangle_int_t sample;
cairo_extend_t extend;
cairo_filter_t filter;
double tx, ty;
 
tx = pattern->base.matrix.x0;
ty = pattern->base.matrix.y0;
 
extend = pattern->base.extend;
filter = sampled_area (pattern, extents, &sample);
 
pixman_image = NULL;
if (pattern->surface->type == CAIRO_SURFACE_TYPE_IMAGE &&
(! is_mask || ! pattern->base.has_component_alpha ||
(pattern->surface->content & CAIRO_CONTENT_COLOR) == 0))
{
cairo_image_surface_t *source = (cairo_image_surface_t *) pattern->surface;
cairo_surface_type_t type;
 
if (source->base.backend->type == CAIRO_INTERNAL_SURFACE_TYPE_SNAPSHOT)
source = (cairo_image_surface_t *) ((cairo_surface_snapshot_t *) pattern->surface)->target;
 
type = source->base.backend->type;
if (type == CAIRO_SURFACE_TYPE_IMAGE) {
if (extend != CAIRO_EXTEND_NONE &&
sample.x >= 0 &&
sample.y >= 0 &&
sample.x + sample.width <= source->width &&
sample.y + sample.height <= source->height)
{
extend = CAIRO_EXTEND_NONE;
}
 
if (sample.width == 1 && sample.height == 1) {
if (sample.x < 0 ||
sample.y < 0 ||
sample.x >= source->width ||
sample.y >= source->height)
{
if (extend == CAIRO_EXTEND_NONE)
return _pixman_transparent_image ();
}
else
{
return _pixel_to_solid (source, sample.x, sample.y);
}
}
 
/* avoid allocating a 'pattern' image if we can reuse the original */
if (extend == CAIRO_EXTEND_NONE &&
_cairo_matrix_is_translation (&pattern->base.matrix) &&
_nearest_sample (filter, &tx, &ty))
{
*ix = tx;
*iy = ty;
return pixman_image_ref (source->pixman_image);
}
 
pixman_image = pixman_image_create_bits (source->pixman_format,
source->width,
source->height,
(uint32_t *) source->data,
source->stride);
if (unlikely (pixman_image == NULL))
return NULL;
} else if (type == CAIRO_SURFACE_TYPE_SUBSURFACE) {
cairo_surface_subsurface_t *sub;
cairo_bool_t is_contained = FALSE;
 
sub = (cairo_surface_subsurface_t *) source;
source = (cairo_image_surface_t *) sub->target;
 
if (sample.x >= 0 &&
sample.y >= 0 &&
sample.x + sample.width <= sub->extents.width &&
sample.y + sample.height <= sub->extents.height)
{
is_contained = TRUE;
}
 
if (sample.width == 1 && sample.height == 1) {
if (is_contained) {
return _pixel_to_solid (source,
sub->extents.x + sample.x,
sub->extents.y + sample.y);
} else {
if (extend == CAIRO_EXTEND_NONE)
return _pixman_transparent_image ();
}
}
 
if (is_contained &&
_cairo_matrix_is_translation (&pattern->base.matrix) &&
_nearest_sample (filter, &tx, &ty))
{
*ix = tx + sub->extents.x;
*iy = ty + sub->extents.y;
return pixman_image_ref (source->pixman_image);
}
 
/* Avoid sub-byte offsets, force a copy in that case. */
if (PIXMAN_FORMAT_BPP (source->pixman_format) >= 8) {
pixman_image = pixman_image_create_bits (source->pixman_format,
sub->extents.width,
sub->extents.height,
(uint32_t *) (source->data + sub->extents.x * PIXMAN_FORMAT_BPP(source->pixman_format)/8 + sub->extents.y * source->stride),
source->stride);
if (unlikely (pixman_image == NULL))
return NULL;
}
}
}
 
if (pixman_image == NULL) {
struct acquire_source_cleanup *cleanup;
cairo_image_surface_t *image;
void *extra;
cairo_status_t status;
 
status = _cairo_surface_acquire_source_image (pattern->surface, &image, &extra);
if (unlikely (status))
return NULL;
 
if (sample.width == 1 && sample.height == 1) {
if (sample.x < 0 ||
sample.y < 0 ||
sample.x >= image->width ||
sample.y >= image->height)
{
if (extend == CAIRO_EXTEND_NONE) {
pixman_image = _pixman_transparent_image ();
_cairo_surface_release_source_image (pattern->surface, image, extra);
return pixman_image;
}
}
else
{
pixman_image = _pixel_to_solid (image, sample.x, sample.y);
_cairo_surface_release_source_image (pattern->surface, image, extra);
return pixman_image;
}
}
 
pixman_image = pixman_image_create_bits (image->pixman_format,
image->width,
image->height,
(uint32_t *) image->data,
image->stride);
if (unlikely (pixman_image == NULL)) {
_cairo_surface_release_source_image (pattern->surface, image, extra);
return NULL;
}
 
cleanup = malloc (sizeof (*cleanup));
if (unlikely (cleanup == NULL)) {
_cairo_surface_release_source_image (pattern->surface, image, extra);
pixman_image_unref (pixman_image);
return NULL;
}
 
cleanup->surface = pattern->surface;
cleanup->image = image;
cleanup->image_extra = extra;
pixman_image_set_destroy_function (pixman_image,
_acquire_source_cleanup, cleanup);
}
 
if (! _cairo_matrix_is_translation (&pattern->base.matrix) ||
! _nearest_sample (filter, &tx, &ty))
{
pixman_transform_t pixman_transform;
cairo_matrix_t m;
 
m = pattern->base.matrix;
if (m.x0 != 0. || m.y0 != 0.) {
cairo_matrix_t inv;
cairo_status_t status;
double x, y;
 
/* pixman also limits the [xy]_offset to 16 bits so evenly
* spread the bits between the two.
*/
inv = m;
status = cairo_matrix_invert (&inv);
assert (status == CAIRO_STATUS_SUCCESS);
 
x = floor (inv.x0 / 2);
y = floor (inv.y0 / 2);
tx = -x;
ty = -y;
cairo_matrix_init_translate (&inv, x, y);
cairo_matrix_multiply (&m, &inv, &m);
} else {
tx = ty = 0;
}
 
_cairo_matrix_to_pixman_matrix (&m, &pixman_transform,
extents->x + extents->width/2.,
extents->y + extents->height/2.);
if (! pixman_image_set_transform (pixman_image, &pixman_transform)) {
pixman_image_unref (pixman_image);
return NULL;
}
}
*ix = tx;
*iy = ty;
 
if (_cairo_matrix_has_unity_scale (&pattern->base.matrix) &&
tx == pattern->base.matrix.x0 &&
ty == pattern->base.matrix.y0)
{
pixman_image_set_filter (pixman_image, PIXMAN_FILTER_NEAREST, NULL, 0);
}
else
{
pixman_filter_t pixman_filter;
 
switch (filter) {
case CAIRO_FILTER_FAST:
pixman_filter = PIXMAN_FILTER_FAST;
break;
case CAIRO_FILTER_GOOD:
pixman_filter = PIXMAN_FILTER_GOOD;
break;
case CAIRO_FILTER_BEST:
pixman_filter = PIXMAN_FILTER_BEST;
break;
case CAIRO_FILTER_NEAREST:
pixman_filter = PIXMAN_FILTER_NEAREST;
break;
case CAIRO_FILTER_BILINEAR:
pixman_filter = PIXMAN_FILTER_BILINEAR;
break;
case CAIRO_FILTER_GAUSSIAN:
/* XXX: The GAUSSIAN value has no implementation in cairo
* whatsoever, so it was really a mistake to have it in the
* API. We could fix this by officially deprecating it, or
* else inventing semantics and providing an actual
* implementation for it. */
default:
pixman_filter = PIXMAN_FILTER_BEST;
}
 
pixman_image_set_filter (pixman_image, pixman_filter, NULL, 0);
}
 
{
pixman_repeat_t pixman_repeat;
 
switch (extend) {
default:
case CAIRO_EXTEND_NONE:
pixman_repeat = PIXMAN_REPEAT_NONE;
break;
case CAIRO_EXTEND_REPEAT:
pixman_repeat = PIXMAN_REPEAT_NORMAL;
break;
case CAIRO_EXTEND_REFLECT:
pixman_repeat = PIXMAN_REPEAT_REFLECT;
break;
case CAIRO_EXTEND_PAD:
pixman_repeat = PIXMAN_REPEAT_PAD;
break;
}
 
pixman_image_set_repeat (pixman_image, pixman_repeat);
}
 
if (pattern->base.has_component_alpha)
pixman_image_set_component_alpha (pixman_image, TRUE);
 
return pixman_image;
}
 
static pixman_image_t *
_pixman_image_for_pattern (const cairo_pattern_t *pattern,
cairo_bool_t is_mask,
const cairo_rectangle_int_t *extents,
int *tx, int *ty)
{
*tx = *ty = 0;
 
if (pattern == NULL)
return _pixman_white_image ();
 
switch (pattern->type) {
default:
ASSERT_NOT_REACHED;
case CAIRO_PATTERN_TYPE_SOLID:
return _pixman_image_for_solid ((const cairo_solid_pattern_t *) pattern);
 
case CAIRO_PATTERN_TYPE_RADIAL:
case CAIRO_PATTERN_TYPE_LINEAR:
return _pixman_image_for_gradient ((const cairo_gradient_pattern_t *) pattern,
extents, tx, ty);
 
case CAIRO_PATTERN_TYPE_SURFACE:
return _pixman_image_for_surface ((const cairo_surface_pattern_t *) pattern,
is_mask, extents, tx, ty);
}
}
 
static cairo_status_t
_cairo_image_surface_fixup_unbounded (cairo_image_surface_t *dst,
const cairo_composite_rectangles_t *rects,
cairo_clip_t *clip)
{
pixman_image_t *mask = NULL;
pixman_box32_t boxes[4];
int i, mask_x = 0, mask_y = 0, n_boxes = 0;
 
if (clip != NULL) {
cairo_surface_t *clip_surface;
int clip_x, clip_y;
 
clip_surface = _cairo_clip_get_surface (clip, &dst->base, &clip_x, &clip_y);
if (unlikely (clip_surface->status))
return clip_surface->status;
 
mask = ((cairo_image_surface_t *) clip_surface)->pixman_image;
mask_x = -clip_x;
mask_y = -clip_y;
} else {
if (rects->bounded.width == rects->unbounded.width &&
rects->bounded.height == rects->unbounded.height)
{
return CAIRO_STATUS_SUCCESS;
}
}
 
/* wholly unbounded? */
if (rects->bounded.width == 0 || rects->bounded.height == 0) {
int x = rects->unbounded.x;
int y = rects->unbounded.y;
int width = rects->unbounded.width;
int height = rects->unbounded.height;
 
if (mask != NULL) {
pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE,
mask, NULL, dst->pixman_image,
x + mask_x, y + mask_y,
0, 0,
x, y,
width, height);
} else {
pixman_color_t color = { 0, };
pixman_box32_t box = { x, y, x + width, y + height };
 
if (! pixman_image_fill_boxes (PIXMAN_OP_CLEAR,
dst->pixman_image,
&color,
1, &box))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
 
return CAIRO_STATUS_SUCCESS;
}
 
/* top */
if (rects->bounded.y != rects->unbounded.y) {
boxes[n_boxes].x1 = rects->unbounded.x;
boxes[n_boxes].y1 = rects->unbounded.y;
boxes[n_boxes].x2 = rects->unbounded.x + rects->unbounded.width;
boxes[n_boxes].y2 = rects->bounded.y;
n_boxes++;
}
 
/* left */
if (rects->bounded.x != rects->unbounded.x) {
boxes[n_boxes].x1 = rects->unbounded.x;
boxes[n_boxes].y1 = rects->bounded.y;
boxes[n_boxes].x2 = rects->bounded.x;
boxes[n_boxes].y2 = rects->bounded.y + rects->bounded.height;
n_boxes++;
}
 
/* right */
if (rects->bounded.x + rects->bounded.width != rects->unbounded.x + rects->unbounded.width) {
boxes[n_boxes].x1 = rects->bounded.x + rects->bounded.width;
boxes[n_boxes].y1 = rects->bounded.y;
boxes[n_boxes].x2 = rects->unbounded.x + rects->unbounded.width;
boxes[n_boxes].y2 = rects->bounded.y + rects->bounded.height;
n_boxes++;
}
 
/* bottom */
if (rects->bounded.y + rects->bounded.height != rects->unbounded.y + rects->unbounded.height) {
boxes[n_boxes].x1 = rects->unbounded.x;
boxes[n_boxes].y1 = rects->bounded.y + rects->bounded.height;
boxes[n_boxes].x2 = rects->unbounded.x + rects->unbounded.width;
boxes[n_boxes].y2 = rects->unbounded.y + rects->unbounded.height;
n_boxes++;
}
 
if (mask != NULL) {
for (i = 0; i < n_boxes; i++) {
pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE,
mask, NULL, dst->pixman_image,
boxes[i].x1 + mask_x, boxes[i].y1 + mask_y,
0, 0,
boxes[i].x1, boxes[i].y1,
boxes[i].x2 - boxes[i].x1, boxes[i].y2 - boxes[i].y1);
}
} else {
pixman_color_t color = { 0, };
 
if (! pixman_image_fill_boxes (PIXMAN_OP_CLEAR,
dst->pixman_image,
&color,
n_boxes,
boxes))
{
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
}
 
return CAIRO_STATUS_SUCCESS;
}
 
static cairo_status_t
_cairo_image_surface_fixup_unbounded_boxes (cairo_image_surface_t *dst,
const cairo_composite_rectangles_t *extents,
cairo_region_t *clip_region,
cairo_boxes_t *boxes)
{
cairo_boxes_t clear;
cairo_box_t box;
cairo_status_t status;
struct _cairo_boxes_chunk *chunk;
int i;
 
if (boxes->num_boxes <= 1 && clip_region == NULL)
return _cairo_image_surface_fixup_unbounded (dst, extents, NULL);
 
_cairo_boxes_init (&clear);
 
box.p1.x = _cairo_fixed_from_int (extents->unbounded.x + extents->unbounded.width);
box.p1.y = _cairo_fixed_from_int (extents->unbounded.y);
box.p2.x = _cairo_fixed_from_int (extents->unbounded.x);
box.p2.y = _cairo_fixed_from_int (extents->unbounded.y + extents->unbounded.height);
 
if (clip_region == NULL) {
cairo_boxes_t tmp;
 
_cairo_boxes_init (&tmp);
 
status = _cairo_boxes_add (&tmp, &box);
assert (status == CAIRO_STATUS_SUCCESS);
 
tmp.chunks.next = &boxes->chunks;
tmp.num_boxes += boxes->num_boxes;
 
status = _cairo_bentley_ottmann_tessellate_boxes (&tmp,
CAIRO_FILL_RULE_WINDING,
&clear);
 
tmp.chunks.next = NULL;
} else {
pixman_box32_t *pbox;
 
pbox = pixman_region32_rectangles (&clip_region->rgn, &i);
_cairo_boxes_limit (&clear, (cairo_box_t *) pbox, i);
 
status = _cairo_boxes_add (&clear, &box);
assert (status == CAIRO_STATUS_SUCCESS);
 
for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
for (i = 0; i < chunk->count; i++) {
status = _cairo_boxes_add (&clear, &chunk->base[i]);
if (unlikely (status)) {
_cairo_boxes_fini (&clear);
return status;
}
}
}
 
status = _cairo_bentley_ottmann_tessellate_boxes (&clear,
CAIRO_FILL_RULE_WINDING,
&clear);
}
 
if (likely (status == CAIRO_STATUS_SUCCESS)) {
for (chunk = &clear.chunks; chunk != NULL; chunk = chunk->next) {
for (i = 0; i < chunk->count; i++) {
int x1 = _cairo_fixed_integer_part (chunk->base[i].p1.x);
int y1 = _cairo_fixed_integer_part (chunk->base[i].p1.y);
int x2 = _cairo_fixed_integer_part (chunk->base[i].p2.x);
int y2 = _cairo_fixed_integer_part (chunk->base[i].p2.y);
 
pixman_fill ((uint32_t *) dst->data, dst->stride / sizeof (uint32_t),
PIXMAN_FORMAT_BPP (dst->pixman_format),
x1, y1, x2 - x1, y2 - y1,
0);
}
}
}
 
_cairo_boxes_fini (&clear);
 
return status;
}
 
static cairo_bool_t
can_reduce_alpha_op (cairo_operator_t op)
{
int iop = op;
switch (iop) {
case CAIRO_OPERATOR_OVER:
case CAIRO_OPERATOR_SOURCE:
case CAIRO_OPERATOR_ADD:
return TRUE;
default:
return FALSE;
}
}
 
static cairo_bool_t
reduce_alpha_op (cairo_image_surface_t *dst,
cairo_operator_t op,
const cairo_pattern_t *pattern)
{
return dst->base.is_clear &&
dst->base.content == CAIRO_CONTENT_ALPHA &&
_cairo_pattern_is_opaque_solid (pattern) &&
can_reduce_alpha_op (op);
}
 
/* low level compositor */
typedef cairo_status_t
(*image_draw_func_t) (void *closure,
pixman_image_t *dst,
pixman_format_code_t dst_format,
cairo_operator_t op,
const cairo_pattern_t *src,
int dst_x,
int dst_y,
const cairo_rectangle_int_t *extents,
cairo_region_t *clip_region);
 
static pixman_image_t *
_create_composite_mask_pattern (cairo_clip_t *clip,
image_draw_func_t draw_func,
void *draw_closure,
cairo_image_surface_t *dst,
const cairo_rectangle_int_t *extents)
{
cairo_region_t *clip_region = NULL;
pixman_image_t *mask;
cairo_status_t status;
cairo_bool_t need_clip_surface = FALSE;
 
if (clip != NULL) {
status = _cairo_clip_get_region (clip, &clip_region);
assert (! _cairo_status_is_error (status));
 
/* The all-clipped state should never propagate this far. */
assert (status != CAIRO_INT_STATUS_NOTHING_TO_DO);
 
need_clip_surface = status == CAIRO_INT_STATUS_UNSUPPORTED;
 
if (clip_region != NULL && cairo_region_num_rectangles (clip_region) == 1)
clip_region = NULL;
}
 
mask = pixman_image_create_bits (PIXMAN_a8, extents->width, extents->height,
NULL, 0);
if (unlikely (mask == NULL))
return NULL;
 
/* Is it worth setting the clip region here? */
if (clip_region != NULL) {
pixman_bool_t ret;
 
pixman_region32_translate (&clip_region->rgn, -extents->x, -extents->y);
ret = pixman_image_set_clip_region32 (mask, &clip_region->rgn);
pixman_region32_translate (&clip_region->rgn, extents->x, extents->y);
 
if (! ret) {
pixman_image_unref (mask);
return NULL;
}
}
 
status = draw_func (draw_closure,
mask, PIXMAN_a8,
CAIRO_OPERATOR_ADD, NULL,
extents->x, extents->y,
extents, NULL);
if (unlikely (status)) {
pixman_image_unref (mask);
return NULL;
}
 
if (need_clip_surface) {
cairo_surface_t *tmp;
 
tmp = _cairo_image_surface_create_for_pixman_image (mask, PIXMAN_a8);
if (unlikely (tmp->status)) {
pixman_image_unref (mask);
return NULL;
}
 
pixman_image_ref (mask);
 
status = _cairo_clip_combine_with_surface (clip, tmp, extents->x, extents->y);
cairo_surface_destroy (tmp);
if (unlikely (status)) {
pixman_image_unref (mask);
return NULL;
}
}
 
if (clip_region != NULL)
pixman_image_set_clip_region (mask, NULL);
 
return mask;
}
 
/* Handles compositing with a clip surface when the operator allows
* us to combine the clip with the mask
*/
static cairo_status_t
_clip_and_composite_with_mask (cairo_clip_t *clip,
cairo_operator_t op,
const cairo_pattern_t *pattern,
image_draw_func_t draw_func,
void *draw_closure,
cairo_image_surface_t *dst,
const cairo_rectangle_int_t *extents)
{
pixman_image_t *mask;
 
mask = _create_composite_mask_pattern (clip, draw_func, draw_closure, dst, extents);
if (unlikely (mask == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
if (pattern == NULL) {
if (dst->pixman_format == PIXMAN_a8) {
pixman_image_composite32 (_pixman_operator (op),
mask, NULL, dst->pixman_image,
0, 0, 0, 0,
extents->x, extents->y,
extents->width, extents->height);
} else {
pixman_image_t *src;
 
src = _pixman_white_image ();
if (unlikely (src == NULL)) {
pixman_image_unref (mask);
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
 
pixman_image_composite32 (_pixman_operator (op),
src, mask, dst->pixman_image,
0, 0, 0, 0,
extents->x, extents->y,
extents->width, extents->height);
pixman_image_unref (src);
}
} else {
pixman_image_t *src;
int src_x, src_y;
 
src = _pixman_image_for_pattern (pattern, FALSE, extents, &src_x, &src_y);
if (unlikely (src == NULL)) {
pixman_image_unref (mask);
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
 
pixman_image_composite32 (_pixman_operator (op),
src, mask, dst->pixman_image,
extents->x + src_x, extents->y + src_y,
0, 0,
extents->x, extents->y,
extents->width, extents->height);
pixman_image_unref (src);
}
 
pixman_image_unref (mask);
 
return CAIRO_STATUS_SUCCESS;
}
 
/* Handles compositing with a clip surface when we have to do the operation
* in two pieces and combine them together.
*/
static cairo_status_t
_clip_and_composite_combine (cairo_clip_t *clip,
cairo_operator_t op,
const cairo_pattern_t *src,
image_draw_func_t draw_func,
void *draw_closure,
cairo_image_surface_t *dst,
const cairo_rectangle_int_t *extents)
{
pixman_image_t *tmp;
cairo_surface_t *clip_surface;
int clip_x, clip_y;
cairo_status_t status;
 
tmp = pixman_image_create_bits (dst->pixman_format,
extents->width, extents->height,
NULL, 0);
if (unlikely (tmp == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
if (src == NULL) {
status = (*draw_func) (draw_closure,
tmp, dst->pixman_format,
CAIRO_OPERATOR_ADD, NULL,
extents->x, extents->y,
extents, NULL);
} else {
/* Initialize the temporary surface from the destination surface */
if (! dst->base.is_clear) {
pixman_image_composite32 (PIXMAN_OP_SRC,
dst->pixman_image, NULL, tmp,
extents->x, extents->y,
0, 0,
0, 0,
extents->width, extents->height);
}
 
status = (*draw_func) (draw_closure,
tmp, dst->pixman_format,
op, src,
extents->x, extents->y,
extents, NULL);
}
if (unlikely (status))
goto CLEANUP_SURFACE;
 
assert (clip->path != NULL);
clip_surface = _cairo_clip_get_surface (clip, &dst->base, &clip_x, &clip_y);
if (unlikely (clip_surface->status))
goto CLEANUP_SURFACE;
 
if (! dst->base.is_clear) {
#if PIXMAN_HAS_OP_LERP
pixman_image_composite32 (PIXMAN_OP_LERP,
tmp,
((cairo_image_surface_t *) clip_surface)->pixman_image,
dst->pixman_image,
0, 0,
extents->x - clip_x,
extents->y - clip_y,
extents->x, extents->y,
extents->width, extents->height);
#else
/* Punch the clip out of the destination */
pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE,
((cairo_image_surface_t *) clip_surface)->pixman_image,
NULL, dst->pixman_image,
extents->x - clip_x,
extents->y - clip_y,
0, 0,
extents->x, extents->y,
extents->width, extents->height);
 
/* Now add the two results together */
pixman_image_composite32 (PIXMAN_OP_ADD,
tmp,
((cairo_image_surface_t *) clip_surface)->pixman_image,
dst->pixman_image,
0, 0,
extents->x - clip_x,
extents->y - clip_y,
extents->x, extents->y,
extents->width, extents->height);
#endif
} else {
pixman_image_composite32 (PIXMAN_OP_SRC,
tmp,
((cairo_image_surface_t *) clip_surface)->pixman_image,
dst->pixman_image,
0, 0,
extents->x - clip_x,
extents->y - clip_y,
extents->x, extents->y,
extents->width, extents->height);
}
 
CLEANUP_SURFACE:
pixman_image_unref (tmp);
 
return status;
}
 
/* Handles compositing for %CAIRO_OPERATOR_SOURCE, which is special; it's
* defined as (src IN mask IN clip) ADD (dst OUT (mask IN clip))
*/
static cairo_status_t
_clip_and_composite_source (cairo_clip_t *clip,
const cairo_pattern_t *pattern,
image_draw_func_t draw_func,
void *draw_closure,
cairo_image_surface_t *dst,
const cairo_rectangle_int_t *extents)
{
pixman_image_t *mask, *src;
int src_x, src_y;
 
if (pattern == NULL) {
cairo_region_t *clip_region;
cairo_status_t status;
 
status = draw_func (draw_closure,
dst->pixman_image, dst->pixman_format,
CAIRO_OPERATOR_SOURCE, NULL,
extents->x, extents->y,
extents, NULL);
if (unlikely (status))
return status;
 
if (_cairo_clip_get_region (clip, &clip_region) == CAIRO_INT_STATUS_UNSUPPORTED)
status = _cairo_clip_combine_with_surface (clip, &dst->base, 0, 0);
 
return status;
}
 
/* Create a surface that is mask IN clip */
mask = _create_composite_mask_pattern (clip, draw_func, draw_closure, dst, extents);
if (unlikely (mask == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
src = _pixman_image_for_pattern (pattern, FALSE, extents, &src_x, &src_y);
if (unlikely (src == NULL)) {
pixman_image_unref (mask);
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
 
if (! dst->base.is_clear) {
#if PIXMAN_HAS_OP_LERP
pixman_image_composite32 (PIXMAN_OP_LERP,
src, mask, dst->pixman_image,
extents->x + src_x, extents->y + src_y,
0, 0,
extents->x, extents->y,
extents->width, extents->height);
#else
/* Compute dest' = dest OUT (mask IN clip) */
pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE,
mask, NULL, dst->pixman_image,
0, 0, 0, 0,
extents->x, extents->y,
extents->width, extents->height);
 
/* Now compute (src IN (mask IN clip)) ADD dest' */
pixman_image_composite32 (PIXMAN_OP_ADD,
src, mask, dst->pixman_image,
extents->x + src_x, extents->y + src_y,
0, 0,
extents->x, extents->y,
extents->width, extents->height);
#endif
} else {
pixman_image_composite32 (PIXMAN_OP_SRC,
src, mask, dst->pixman_image,
extents->x + src_x, extents->y + src_y,
0, 0,
extents->x, extents->y,
extents->width, extents->height);
}
 
pixman_image_unref (src);
pixman_image_unref (mask);
 
return CAIRO_STATUS_SUCCESS;
}
 
static cairo_status_t
_clip_and_composite (cairo_image_surface_t *dst,
cairo_operator_t op,
const cairo_pattern_t *src,
image_draw_func_t draw_func,
void *draw_closure,
cairo_composite_rectangles_t*extents,
cairo_clip_t *clip)
{
cairo_status_t status;
cairo_region_t *clip_region = NULL;
cairo_bool_t need_clip_surface = FALSE;
 
if (clip != NULL) {
status = _cairo_clip_get_region (clip, &clip_region);
if (unlikely (status == CAIRO_INT_STATUS_NOTHING_TO_DO))
return CAIRO_STATUS_SUCCESS;
if (unlikely (_cairo_status_is_error (status)))
return status;
 
need_clip_surface = status == CAIRO_INT_STATUS_UNSUPPORTED;
 
if (clip_region != NULL) {
cairo_rectangle_int_t rect;
cairo_bool_t is_empty;
 
cairo_region_get_extents (clip_region, &rect);
is_empty = ! _cairo_rectangle_intersect (&extents->unbounded, &rect);
if (unlikely (is_empty))
return CAIRO_STATUS_SUCCESS;
 
is_empty = ! _cairo_rectangle_intersect (&extents->bounded, &rect);
if (unlikely (is_empty && extents->is_bounded))
return CAIRO_STATUS_SUCCESS;
 
if (cairo_region_num_rectangles (clip_region) == 1)
clip_region = NULL;
}
}
 
if (clip_region != NULL) {
status = _cairo_image_surface_set_clip_region (dst, clip_region);
if (unlikely (status))
return status;
}
 
if (reduce_alpha_op (dst, op, src)) {
op = CAIRO_OPERATOR_ADD;
src = NULL;
}
 
if (op == CAIRO_OPERATOR_SOURCE) {
status = _clip_and_composite_source (clip, src,
draw_func, draw_closure,
dst, &extents->bounded);
} else {
if (op == CAIRO_OPERATOR_CLEAR) {
src = NULL;
op = CAIRO_OPERATOR_DEST_OUT;
}
 
if (need_clip_surface) {
if (extents->is_bounded) {
status = _clip_and_composite_with_mask (clip, op, src,
draw_func, draw_closure,
dst, &extents->bounded);
} else {
status = _clip_and_composite_combine (clip, op, src,
draw_func, draw_closure,
dst, &extents->bounded);
}
} else {
status = draw_func (draw_closure,
dst->pixman_image, dst->pixman_format,
op, src,
0, 0,
&extents->bounded,
clip_region);
}
}
 
if (status == CAIRO_STATUS_SUCCESS && ! extents->is_bounded) {
status = _cairo_image_surface_fixup_unbounded (dst, extents,
need_clip_surface ? clip : NULL);
}
 
if (clip_region != NULL)
_cairo_image_surface_unset_clip_region (dst);
 
return status;
}
 
#define CAIRO_FIXED_16_16_MIN _cairo_fixed_from_int (-32768)
#define CAIRO_FIXED_16_16_MAX _cairo_fixed_from_int (32767)
 
static cairo_bool_t
_line_exceeds_16_16 (const cairo_line_t *line)
{
return
line->p1.x <= CAIRO_FIXED_16_16_MIN ||
line->p1.x >= CAIRO_FIXED_16_16_MAX ||
 
line->p2.x <= CAIRO_FIXED_16_16_MIN ||
line->p2.x >= CAIRO_FIXED_16_16_MAX ||
 
line->p1.y <= CAIRO_FIXED_16_16_MIN ||
line->p1.y >= CAIRO_FIXED_16_16_MAX ||
 
line->p2.y <= CAIRO_FIXED_16_16_MIN ||
line->p2.y >= CAIRO_FIXED_16_16_MAX;
}
 
static void
_project_line_x_onto_16_16 (const cairo_line_t *line,
cairo_fixed_t top,
cairo_fixed_t bottom,
pixman_line_fixed_t *out)
{
cairo_point_double_t p1, p2;
double m;
 
p1.x = _cairo_fixed_to_double (line->p1.x);
p1.y = _cairo_fixed_to_double (line->p1.y);
 
p2.x = _cairo_fixed_to_double (line->p2.x);
p2.y = _cairo_fixed_to_double (line->p2.y);
 
m = (p2.x - p1.x) / (p2.y - p1.y);
out->p1.x = _cairo_fixed_16_16_from_double (p1.x + m * _cairo_fixed_to_double (top - line->p1.y));
out->p2.x = _cairo_fixed_16_16_from_double (p1.x + m * _cairo_fixed_to_double (bottom - line->p1.y));
}
 
 
typedef struct {
cairo_trapezoid_t *traps;
int num_traps;
cairo_antialias_t antialias;
} composite_traps_info_t;
 
static void
_pixman_image_add_traps (pixman_image_t *image,
int dst_x, int dst_y,
composite_traps_info_t *info)
{
cairo_trapezoid_t *t = info->traps;
int num_traps = info->num_traps;
while (num_traps--) {
pixman_trapezoid_t trap;
 
/* top/bottom will be clamped to surface bounds */
trap.top = _cairo_fixed_to_16_16 (t->top);
trap.bottom = _cairo_fixed_to_16_16 (t->bottom);
 
/* However, all the other coordinates will have been left untouched so
* as not to introduce numerical error. Recompute them if they
* exceed the 16.16 limits.
*/
if (unlikely (_line_exceeds_16_16 (&t->left))) {
_project_line_x_onto_16_16 (&t->left, t->top, t->bottom, &trap.left);
trap.left.p1.y = trap.top;
trap.left.p2.y = trap.bottom;
} else {
trap.left.p1.x = _cairo_fixed_to_16_16 (t->left.p1.x);
trap.left.p1.y = _cairo_fixed_to_16_16 (t->left.p1.y);
trap.left.p2.x = _cairo_fixed_to_16_16 (t->left.p2.x);
trap.left.p2.y = _cairo_fixed_to_16_16 (t->left.p2.y);
}
 
if (unlikely (_line_exceeds_16_16 (&t->right))) {
_project_line_x_onto_16_16 (&t->right, t->top, t->bottom, &trap.right);
trap.right.p1.y = trap.top;
trap.right.p2.y = trap.bottom;
} else {
trap.right.p1.x = _cairo_fixed_to_16_16 (t->right.p1.x);
trap.right.p1.y = _cairo_fixed_to_16_16 (t->right.p1.y);
trap.right.p2.x = _cairo_fixed_to_16_16 (t->right.p2.x);
trap.right.p2.y = _cairo_fixed_to_16_16 (t->right.p2.y);
}
 
pixman_rasterize_trapezoid (image, &trap, -dst_x, -dst_y);
 
t++;
}
}
 
static cairo_status_t
_composite_traps (void *closure,
pixman_image_t *dst,
pixman_format_code_t dst_format,
cairo_operator_t op,
const cairo_pattern_t *pattern,
int dst_x,
int dst_y,
const cairo_rectangle_int_t *extents,
cairo_region_t *clip_region)
{
composite_traps_info_t *info = closure;
pixman_image_t *src, *mask;
pixman_format_code_t format;
int src_x = 0, src_y = 0;
cairo_status_t status;
 
/* Special case adding trapezoids onto a mask surface; we want to avoid
* creating an intermediate temporary mask unnecessarily.
*
* We make the assumption here that the portion of the trapezoids
* contained within the surface is bounded by [dst_x,dst_y,width,height];
* the Cairo core code passes bounds based on the trapezoid extents.
*/
format = info->antialias == CAIRO_ANTIALIAS_NONE ? PIXMAN_a1 : PIXMAN_a8;
if (dst_format == format &&
(pattern == NULL ||
(op == CAIRO_OPERATOR_ADD && _cairo_pattern_is_opaque_solid (pattern))))
{
_pixman_image_add_traps (dst, dst_x, dst_y, info);
return CAIRO_STATUS_SUCCESS;
}
 
src = _pixman_image_for_pattern (pattern, FALSE, extents, &src_x, &src_y);
if (unlikely (src == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
mask = pixman_image_create_bits (format, extents->width, extents->height,
NULL, 0);
if (unlikely (mask == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto CLEANUP_SOURCE;
}
 
_pixman_image_add_traps (mask, extents->x, extents->y, info);
pixman_image_composite32 (_pixman_operator (op),
src, mask, dst,
extents->x + src_x, extents->y + src_y,
0, 0,
extents->x - dst_x, extents->y - dst_y,
extents->width, extents->height);
 
pixman_image_unref (mask);
 
status = CAIRO_STATUS_SUCCESS;
CLEANUP_SOURCE:
pixman_image_unref (src);
 
return status;
}
 
static inline uint32_t
color_to_uint32 (const cairo_color_t *color)
{
return
(color->alpha_short >> 8 << 24) |
(color->red_short >> 8 << 16) |
(color->green_short & 0xff00) |
(color->blue_short >> 8);
}
 
static inline cairo_bool_t
color_to_pixel (const cairo_color_t *color,
pixman_format_code_t format,
uint32_t *pixel)
{
uint32_t c;
 
if (!(format == PIXMAN_a8r8g8b8 ||
format == PIXMAN_x8r8g8b8 ||
format == PIXMAN_a8b8g8r8 ||
format == PIXMAN_x8b8g8r8 ||
format == PIXMAN_b8g8r8a8 ||
format == PIXMAN_b8g8r8x8 ||
format == PIXMAN_r5g6b5 ||
format == PIXMAN_b5g6r5 ||
format == PIXMAN_a8))
{
return FALSE;
}
 
c = color_to_uint32 (color);
 
if (PIXMAN_FORMAT_TYPE (format) == PIXMAN_TYPE_ABGR) {
c = ((c & 0xff000000) >> 0) |
((c & 0x00ff0000) >> 16) |
((c & 0x0000ff00) >> 0) |
((c & 0x000000ff) << 16);
}
 
if (PIXMAN_FORMAT_TYPE (format) == PIXMAN_TYPE_BGRA) {
c = ((c & 0xff000000) >> 24) |
((c & 0x00ff0000) >> 8) |
((c & 0x0000ff00) << 8) |
((c & 0x000000ff) << 24);
}
 
if (format == PIXMAN_a8) {
c = c >> 24;
} else if (format == PIXMAN_r5g6b5 || format == PIXMAN_b5g6r5) {
c = ((((c) >> 3) & 0x001f) |
(((c) >> 5) & 0x07e0) |
(((c) >> 8) & 0xf800));
}
 
*pixel = c;
return TRUE;
}
 
static inline cairo_bool_t
pattern_to_pixel (const cairo_solid_pattern_t *solid,
cairo_operator_t op,
pixman_format_code_t format,
uint32_t *pixel)
{
if (op == CAIRO_OPERATOR_CLEAR) {
*pixel = 0;
return TRUE;
}
 
if (solid->base.type != CAIRO_PATTERN_TYPE_SOLID)
return FALSE;
 
if (op == CAIRO_OPERATOR_OVER) {
if (solid->color.alpha_short >= 0xff00)
op = CAIRO_OPERATOR_SOURCE;
}
 
if (op != CAIRO_OPERATOR_SOURCE)
return FALSE;
 
return color_to_pixel (&solid->color, format, pixel);
}
 
typedef struct _fill_span {
cairo_span_renderer_t base;
 
uint8_t *mask_data;
pixman_image_t *src, *dst, *mask;
} fill_span_renderer_t;
 
static cairo_status_t
_fill_span (void *abstract_renderer,
int y, int height,
const cairo_half_open_span_t *spans,
unsigned num_spans)
{
fill_span_renderer_t *renderer = abstract_renderer;
uint8_t *row;
unsigned i;
 
if (num_spans == 0)
return CAIRO_STATUS_SUCCESS;
 
row = renderer->mask_data - spans[0].x;
for (i = 0; i < num_spans - 1; i++) {
/* We implement setting the most common single pixel wide
* span case to avoid the overhead of a memset call.
* Open coding setting longer spans didn't show a
* noticeable improvement over memset.
*/
if (spans[i+1].x == spans[i].x + 1) {
row[spans[i].x] = spans[i].coverage;
} else {
memset (row + spans[i].x,
spans[i].coverage,
spans[i+1].x - spans[i].x);
}
}
 
do {
pixman_image_composite32 (PIXMAN_OP_OVER,
renderer->src, renderer->mask, renderer->dst,
0, 0, 0, 0,
spans[0].x, y++,
spans[i].x - spans[0].x, 1);
} while (--height);
 
return CAIRO_STATUS_SUCCESS;
}
 
/* avoid using region code to re-validate boxes */
static cairo_status_t
_fill_unaligned_boxes (cairo_image_surface_t *dst,
const cairo_pattern_t *pattern,
uint32_t pixel,
const cairo_boxes_t *boxes,
const cairo_composite_rectangles_t *extents)
{
uint8_t buf[CAIRO_STACK_BUFFER_SIZE];
fill_span_renderer_t renderer;
cairo_rectangular_scan_converter_t converter;
const struct _cairo_boxes_chunk *chunk;
cairo_status_t status;
int i;
 
/* XXX
* using composite for fill:
* spiral-box-nonalign-evenodd-fill.512 2201957 2.202
* spiral-box-nonalign-nonzero-fill.512 336726 0.337
* spiral-box-pixalign-evenodd-fill.512 352256 0.352
* spiral-box-pixalign-nonzero-fill.512 147056 0.147
* using fill:
* spiral-box-nonalign-evenodd-fill.512 3174565 3.175
* spiral-box-nonalign-nonzero-fill.512 182710 0.183
* spiral-box-pixalign-evenodd-fill.512 353863 0.354
* spiral-box-pixalign-nonzero-fill.512 147402 0.147
*
* cairo-perf-trace seems to favour using fill.
*/
 
renderer.base.render_rows = _fill_span;
renderer.dst = dst->pixman_image;
 
if ((unsigned) extents->bounded.width <= sizeof (buf)) {
renderer.mask = pixman_image_create_bits (PIXMAN_a8,
extents->bounded.width, 1,
(uint32_t *) buf,
sizeof (buf));
} else {
renderer.mask = pixman_image_create_bits (PIXMAN_a8,
extents->bounded.width, 1,
NULL, 0);
}
if (unlikely (renderer.mask == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
renderer.mask_data = (uint8_t *) pixman_image_get_data (renderer.mask);
 
renderer.src = _pixman_image_for_solid ((const cairo_solid_pattern_t *) pattern);
if (unlikely (renderer.src == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto CLEANUP_MASK;
}
 
_cairo_rectangular_scan_converter_init (&converter, &extents->bounded);
 
/* first blit any aligned part of the boxes */
for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
const cairo_box_t *box = chunk->base;
 
for (i = 0; i < chunk->count; i++) {
int x1 = _cairo_fixed_integer_ceil (box[i].p1.x);
int y1 = _cairo_fixed_integer_ceil (box[i].p1.y);
int x2 = _cairo_fixed_integer_floor (box[i].p2.x);
int y2 = _cairo_fixed_integer_floor (box[i].p2.y);
 
if (x2 > x1 && y2 > y1) {
cairo_box_t b;
 
pixman_fill ((uint32_t *) dst->data,
dst->stride / sizeof (uint32_t),
PIXMAN_FORMAT_BPP (dst->pixman_format),
x1, y1, x2 - x1, y2 - y1,
pixel);
 
/*
* Corners have to be included only once if the rects
* are passed to the rectangular scan converter
* because it can only handle disjoint rectangles.
*/
 
/* top (including top-left and top-right corners) */
if (! _cairo_fixed_is_integer (box[i].p1.y)) {
b.p1.x = box[i].p1.x;
b.p1.y = box[i].p1.y;
b.p2.x = box[i].p2.x;
b.p2.y = _cairo_fixed_from_int (y1);
 
status = _cairo_rectangular_scan_converter_add_box (&converter, &b, 1);
if (unlikely (status))
goto CLEANUP_CONVERTER;
}
 
/* left (no corners) */
if (! _cairo_fixed_is_integer (box[i].p1.x)) {
b.p1.x = box[i].p1.x;
b.p1.y = _cairo_fixed_from_int (y1);
b.p2.x = _cairo_fixed_from_int (x1);
b.p2.y = _cairo_fixed_from_int (y2);
 
status = _cairo_rectangular_scan_converter_add_box (&converter, &b, 1);
if (unlikely (status))
goto CLEANUP_CONVERTER;
}
 
/* right (no corners) */
if (! _cairo_fixed_is_integer (box[i].p2.x)) {
b.p1.x = _cairo_fixed_from_int (x2);
b.p1.y = _cairo_fixed_from_int (y1);
b.p2.x = box[i].p2.x;
b.p2.y = _cairo_fixed_from_int (y2);
 
status = _cairo_rectangular_scan_converter_add_box (&converter, &b, 1);
if (unlikely (status))
goto CLEANUP_CONVERTER;
}
 
/* bottom (including bottom-left and bottom-right corners) */
if (! _cairo_fixed_is_integer (box[i].p2.y)) {
b.p1.x = box[i].p1.x;
b.p1.y = _cairo_fixed_from_int (y2);
b.p2.x = box[i].p2.x;
b.p2.y = box[i].p2.y;
 
status = _cairo_rectangular_scan_converter_add_box (&converter, &b, 1);
if (unlikely (status))
goto CLEANUP_CONVERTER;
}
} else {
status = _cairo_rectangular_scan_converter_add_box (&converter, &box[i], 1);
if (unlikely (status))
goto CLEANUP_CONVERTER;
}
}
}
 
status = converter.base.generate (&converter.base, &renderer.base);
 
CLEANUP_CONVERTER:
converter.base.destroy (&converter.base);
pixman_image_unref (renderer.src);
CLEANUP_MASK:
pixman_image_unref (renderer.mask);
 
return status;
}
 
typedef struct _cairo_image_surface_span_renderer {
cairo_span_renderer_t base;
 
uint8_t *mask_data;
uint32_t mask_stride;
} cairo_image_surface_span_renderer_t;
 
static cairo_status_t
_cairo_image_surface_span (void *abstract_renderer,
int y, int height,
const cairo_half_open_span_t *spans,
unsigned num_spans)
{
cairo_image_surface_span_renderer_t *renderer = abstract_renderer;
uint8_t *row;
unsigned i;
 
if (num_spans == 0)
return CAIRO_STATUS_SUCCESS;
 
/* XXX will it be quicker to repeat the sparse memset,
* or perform a simpler memcpy?
* The fairly dense spiral benchmarks suggests that the sparse
* memset is a win there as well.
*/
row = renderer->mask_data + y * renderer->mask_stride;
do {
for (i = 0; i < num_spans - 1; i++) {
if (! spans[i].coverage)
continue;
 
/* We implement setting rendering the most common single
* pixel wide span case to avoid the overhead of a memset
* call. Open coding setting longer spans didn't show a
* noticeable improvement over memset. */
if (spans[i+1].x == spans[i].x + 1) {
row[spans[i].x] = spans[i].coverage;
} else {
memset (row + spans[i].x,
spans[i].coverage,
spans[i+1].x - spans[i].x);
}
}
row += renderer->mask_stride;
} while (--height);
 
return CAIRO_STATUS_SUCCESS;
}
 
static cairo_status_t
_composite_unaligned_boxes (cairo_image_surface_t *dst,
cairo_operator_t op,
const cairo_pattern_t *pattern,
const cairo_boxes_t *boxes,
const cairo_composite_rectangles_t *extents)
{
uint8_t buf[CAIRO_STACK_BUFFER_SIZE];
cairo_image_surface_span_renderer_t renderer;
cairo_rectangular_scan_converter_t converter;
pixman_image_t *mask, *src;
cairo_status_t status;
const struct _cairo_boxes_chunk *chunk;
int i, src_x, src_y;
 
i = CAIRO_STRIDE_FOR_WIDTH_BPP (extents->bounded.width, 8) * extents->bounded.height;
if ((unsigned) i <= sizeof (buf)) {
mask = pixman_image_create_bits (PIXMAN_a8,
extents->bounded.width,
extents->bounded.height,
(uint32_t *) buf,
CAIRO_STRIDE_FOR_WIDTH_BPP (extents->bounded.width, 8));
memset (buf, 0, i);
} else {
mask = pixman_image_create_bits (PIXMAN_a8,
extents->bounded.width,
extents->bounded.height,
NULL, 0);
}
if (unlikely (mask == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
renderer.base.render_rows = _cairo_image_surface_span;
renderer.mask_stride = pixman_image_get_stride (mask);
renderer.mask_data = (uint8_t *) pixman_image_get_data (mask);
renderer.mask_data -= extents->bounded.y * renderer.mask_stride + extents->bounded.x;
 
_cairo_rectangular_scan_converter_init (&converter, &extents->bounded);
 
for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
const cairo_box_t *box = chunk->base;
 
for (i = 0; i < chunk->count; i++) {
status = _cairo_rectangular_scan_converter_add_box (&converter, &box[i], 1);
if (unlikely (status))
goto CLEANUP;
}
}
 
status = converter.base.generate (&converter.base, &renderer.base);
if (unlikely (status))
goto CLEANUP;
 
src = _pixman_image_for_pattern (pattern, FALSE, &extents->bounded, &src_x, &src_y);
if (unlikely (src == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto CLEANUP;
}
 
pixman_image_composite32 (_pixman_operator (op),
src, mask, dst->pixman_image,
extents->bounded.x + src_x, extents->bounded.y + src_y,
0, 0,
extents->bounded.x, extents->bounded.y,
extents->bounded.width, extents->bounded.height);
pixman_image_unref (src);
 
CLEANUP:
converter.base.destroy (&converter.base);
pixman_image_unref (mask);
 
return status;
}
 
static cairo_status_t
_composite_boxes (cairo_image_surface_t *dst,
cairo_operator_t op,
const cairo_pattern_t *pattern,
cairo_boxes_t *boxes,
cairo_antialias_t antialias,
cairo_clip_t *clip,
const cairo_composite_rectangles_t *extents)
{
cairo_region_t *clip_region = NULL;
cairo_bool_t need_clip_mask = FALSE;
cairo_status_t status;
struct _cairo_boxes_chunk *chunk;
uint32_t pixel;
int i;
 
if (clip != NULL) {
status = _cairo_clip_get_region (clip, &clip_region);
need_clip_mask = status == CAIRO_INT_STATUS_UNSUPPORTED;
if (need_clip_mask &&
(op == CAIRO_OPERATOR_SOURCE || ! extents->is_bounded))
{
return CAIRO_INT_STATUS_UNSUPPORTED;
}
 
if (clip_region != NULL && cairo_region_num_rectangles (clip_region) == 1)
clip_region = NULL;
}
 
if (antialias != CAIRO_ANTIALIAS_NONE) {
if (! boxes->is_pixel_aligned) {
if (need_clip_mask)
return CAIRO_INT_STATUS_UNSUPPORTED;
 
if (pattern_to_pixel ((cairo_solid_pattern_t *) pattern, op,
dst->pixman_format, &pixel))
{
return _fill_unaligned_boxes (dst, pattern, pixel, boxes, extents);
}
else
{
return _composite_unaligned_boxes (dst, op, pattern, boxes, extents);
}
}
}
 
status = CAIRO_STATUS_SUCCESS;
if (! need_clip_mask &&
pattern_to_pixel ((cairo_solid_pattern_t *) pattern, op, dst->pixman_format,
&pixel))
{
for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
cairo_box_t *box = chunk->base;
 
for (i = 0; i < chunk->count; i++) {
int x1 = _cairo_fixed_integer_round_down (box[i].p1.x);
int y1 = _cairo_fixed_integer_round_down (box[i].p1.y);
int x2 = _cairo_fixed_integer_round_down (box[i].p2.x);
int y2 = _cairo_fixed_integer_round_down (box[i].p2.y);
 
if (x2 == x1 || y2 == y1)
continue;
 
pixman_fill ((uint32_t *) dst->data, dst->stride / sizeof (uint32_t),
PIXMAN_FORMAT_BPP (dst->pixman_format),
x1, y1, x2 - x1, y2 - y1,
pixel);
}
}
}
else
{
pixman_image_t *src = NULL, *mask = NULL;
int src_x, src_y, mask_x = 0, mask_y = 0;
pixman_op_t pixman_op = _pixman_operator (op);
 
if (need_clip_mask) {
cairo_surface_t *clip_surface;
int clip_x, clip_y;
 
clip_surface = _cairo_clip_get_surface (clip, &dst->base, &clip_x, &clip_y);
if (unlikely (clip_surface->status))
return clip_surface->status;
 
mask_x = -clip_x;
mask_y = -clip_y;
 
if (op == CAIRO_OPERATOR_CLEAR) {
pattern = NULL;
pixman_op = PIXMAN_OP_OUT_REVERSE;
}
 
mask = ((cairo_image_surface_t *) clip_surface)->pixman_image;
}
 
if (pattern != NULL) {
src = _pixman_image_for_pattern (pattern, FALSE, &extents->bounded, &src_x, &src_y);
if (unlikely (src == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
} else {
src = mask;
src_x = mask_x;
src_y = mask_y;
mask = NULL;
}
 
for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
const cairo_box_t *box = chunk->base;
 
for (i = 0; i < chunk->count; i++) {
int x1 = _cairo_fixed_integer_round_down (box[i].p1.x);
int y1 = _cairo_fixed_integer_round_down (box[i].p1.y);
int x2 = _cairo_fixed_integer_round_down (box[i].p2.x);
int y2 = _cairo_fixed_integer_round_down (box[i].p2.y);
 
if (x2 == x1 || y2 == y1)
continue;
 
pixman_image_composite32 (pixman_op,
src, mask, dst->pixman_image,
x1 + src_x, y1 + src_y,
x1 + mask_x, y1 + mask_y,
x1, y1,
x2 - x1, y2 - y1);
}
}
 
if (pattern != NULL)
pixman_image_unref (src);
 
if (! extents->is_bounded) {
status =
_cairo_image_surface_fixup_unbounded_boxes (dst, extents,
clip_region, boxes);
}
}
 
return status;
}
 
static cairo_status_t
_clip_and_composite_boxes (cairo_image_surface_t *dst,
cairo_operator_t op,
const cairo_pattern_t *src,
cairo_boxes_t *boxes,
cairo_antialias_t antialias,
cairo_composite_rectangles_t *extents,
cairo_clip_t *clip)
{
cairo_traps_t traps;
cairo_status_t status;
composite_traps_info_t info;
 
if (boxes->num_boxes == 0 && extents->is_bounded)
return CAIRO_STATUS_SUCCESS;
 
/* Use a fast path if the boxes are pixel aligned */
status = _composite_boxes (dst, op, src, boxes, antialias, clip, extents);
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
return status;
 
/* Otherwise render via a mask and composite in the usual fashion. */
status = _cairo_traps_init_boxes (&traps, boxes);
if (unlikely (status))
return status;
 
info.num_traps = traps.num_traps;
info.traps = traps.traps;
info.antialias = antialias;
status = _clip_and_composite (dst, op, src,
_composite_traps, &info,
extents, clip);
 
_cairo_traps_fini (&traps);
return status;
}
 
static cairo_bool_t
_mono_edge_is_vertical (const cairo_line_t *line)
{
return _cairo_fixed_integer_round_down (line->p1.x) == _cairo_fixed_integer_round_down (line->p2.x);
}
 
static cairo_bool_t
_traps_are_pixel_aligned (cairo_traps_t *traps,
cairo_antialias_t antialias)
{
int i;
 
if (antialias == CAIRO_ANTIALIAS_NONE) {
for (i = 0; i < traps->num_traps; i++) {
if (! _mono_edge_is_vertical (&traps->traps[i].left) ||
! _mono_edge_is_vertical (&traps->traps[i].right))
{
traps->maybe_region = FALSE;
return FALSE;
}
}
} else {
for (i = 0; i < traps->num_traps; i++) {
if (traps->traps[i].left.p1.x != traps->traps[i].left.p2.x ||
traps->traps[i].right.p1.x != traps->traps[i].right.p2.x ||
! _cairo_fixed_is_integer (traps->traps[i].top) ||
! _cairo_fixed_is_integer (traps->traps[i].bottom) ||
! _cairo_fixed_is_integer (traps->traps[i].left.p1.x) ||
! _cairo_fixed_is_integer (traps->traps[i].right.p1.x))
{
traps->maybe_region = FALSE;
return FALSE;
}
}
}
 
return TRUE;
}
 
static void
_boxes_for_traps (cairo_boxes_t *boxes,
cairo_traps_t *traps,
cairo_antialias_t antialias)
{
int i;
 
_cairo_boxes_init (boxes);
 
boxes->num_boxes = traps->num_traps;
boxes->chunks.base = (cairo_box_t *) traps->traps;
boxes->chunks.count = traps->num_traps;
boxes->chunks.size = traps->num_traps;
 
if (antialias != CAIRO_ANTIALIAS_NONE) {
for (i = 0; i < traps->num_traps; i++) {
/* Note the traps and boxes alias so we need to take the local copies first. */
cairo_fixed_t x1 = traps->traps[i].left.p1.x;
cairo_fixed_t x2 = traps->traps[i].right.p1.x;
cairo_fixed_t y1 = traps->traps[i].top;
cairo_fixed_t y2 = traps->traps[i].bottom;
 
boxes->chunks.base[i].p1.x = x1;
boxes->chunks.base[i].p1.y = y1;
boxes->chunks.base[i].p2.x = x2;
boxes->chunks.base[i].p2.y = y2;
 
if (boxes->is_pixel_aligned) {
boxes->is_pixel_aligned =
_cairo_fixed_is_integer (x1) && _cairo_fixed_is_integer (y1) &&
_cairo_fixed_is_integer (x2) && _cairo_fixed_is_integer (y2);
}
}
} else {
boxes->is_pixel_aligned = TRUE;
 
for (i = 0; i < traps->num_traps; i++) {
/* Note the traps and boxes alias so we need to take the local copies first. */
cairo_fixed_t x1 = traps->traps[i].left.p1.x;
cairo_fixed_t x2 = traps->traps[i].right.p1.x;
cairo_fixed_t y1 = traps->traps[i].top;
cairo_fixed_t y2 = traps->traps[i].bottom;
 
/* round down here to match Pixman's behavior when using traps. */
boxes->chunks.base[i].p1.x = _cairo_fixed_round_down (x1);
boxes->chunks.base[i].p1.y = _cairo_fixed_round_down (y1);
boxes->chunks.base[i].p2.x = _cairo_fixed_round_down (x2);
boxes->chunks.base[i].p2.y = _cairo_fixed_round_down (y2);
}
}
}
 
static cairo_status_t
_clip_and_composite_trapezoids (cairo_image_surface_t *dst,
cairo_operator_t op,
const cairo_pattern_t *src,
cairo_traps_t *traps,
cairo_antialias_t antialias,
cairo_composite_rectangles_t *extents,
cairo_clip_t *clip)
{
composite_traps_info_t info;
cairo_bool_t need_clip_surface = FALSE;
cairo_status_t status;
 
if (traps->num_traps == 0 && extents->is_bounded)
return CAIRO_STATUS_SUCCESS;
 
if (clip != NULL) {
cairo_region_t *clip_region;
 
status = _cairo_clip_get_region (clip, &clip_region);
need_clip_surface = status == CAIRO_INT_STATUS_UNSUPPORTED;
}
 
if (traps->has_intersections) {
if (traps->is_rectangular)
status = _cairo_bentley_ottmann_tessellate_rectangular_traps (traps, CAIRO_FILL_RULE_WINDING);
else if (traps->is_rectilinear)
status = _cairo_bentley_ottmann_tessellate_rectilinear_traps (traps, CAIRO_FILL_RULE_WINDING);
else
status = _cairo_bentley_ottmann_tessellate_traps (traps, CAIRO_FILL_RULE_WINDING);
if (unlikely (status))
return status;
}
 
/* Use a fast path if the trapezoids consist of a simple region,
* but we can only do this if we do not have a clip surface, or can
* substitute the mask with the clip.
*/
if (traps->maybe_region && _traps_are_pixel_aligned (traps, antialias) &&
(! need_clip_surface ||
(extents->is_bounded && op != CAIRO_OPERATOR_SOURCE)))
{
cairo_boxes_t boxes;
 
_boxes_for_traps (&boxes, traps, antialias);
return _clip_and_composite_boxes (dst, op, src,
&boxes, antialias,
extents, clip);
}
 
/* No fast path, exclude self-intersections and clip trapezoids. */
/* Otherwise render the trapezoids to a mask and composite in the usual
* fashion.
*/
info.traps = traps->traps;
info.num_traps = traps->num_traps;
info.antialias = antialias;
return _clip_and_composite (dst, op, src,
_composite_traps, &info,
extents, clip);
}
 
static cairo_clip_path_t *
_clip_get_single_path (cairo_clip_t *clip)
{
cairo_clip_path_t *iter = clip->path;
cairo_clip_path_t *path = NULL;
 
do {
if ((iter->flags & CAIRO_CLIP_PATH_IS_BOX) == 0) {
if (path != NULL)
return FALSE;
 
path = iter;
}
iter = iter->prev;
} while (iter != NULL);
 
return path;
}
 
/* high level image interface */
 
static cairo_int_status_t
_cairo_image_surface_paint (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_clip_t *clip)
{
cairo_image_surface_t *surface = abstract_surface;
cairo_composite_rectangles_t extents;
cairo_clip_path_t *clip_path;
cairo_clip_t local_clip;
cairo_bool_t have_clip = FALSE;
cairo_box_t boxes_stack[32], *clip_boxes = boxes_stack;
int num_boxes = ARRAY_LENGTH (boxes_stack);
cairo_status_t status;
 
status = _cairo_composite_rectangles_init_for_paint (&extents,
surface->width,
surface->height,
op, source,
clip);
if (unlikely (status))
return status;
 
if (_cairo_clip_contains_extents (clip, &extents))
clip = NULL;
 
if (clip != NULL) {
clip = _cairo_clip_init_copy (&local_clip, clip);
have_clip = TRUE;
}
 
status = _cairo_clip_to_boxes (&clip, &extents, &clip_boxes, &num_boxes);
if (unlikely (status)) {
if (have_clip)
_cairo_clip_fini (&local_clip);
 
return status;
}
 
/* If the clip cannot be reduced to a set of boxes, we will need to
* use a clipmask. Paint is special as it is the only operation that
* does not implicitly use a mask, so we may be able to reduce this
* operation to a fill...
*/
if (clip != NULL &&
extents.is_bounded &&
(clip_path = _clip_get_single_path (clip)) != NULL)
{
status = _cairo_image_surface_fill (surface, op, source,
&clip_path->path,
clip_path->fill_rule,
clip_path->tolerance,
clip_path->antialias,
NULL);
}
else
{
cairo_boxes_t boxes;
 
_cairo_boxes_init_for_array (&boxes, clip_boxes, num_boxes);
status = _clip_and_composite_boxes (surface, op, source,
&boxes, CAIRO_ANTIALIAS_DEFAULT,
&extents, clip);
}
 
if (clip_boxes != boxes_stack)
free (clip_boxes);
 
if (have_clip)
_cairo_clip_fini (&local_clip);
 
return status;
}
 
static cairo_status_t
_composite_mask (void *closure,
pixman_image_t *dst,
pixman_format_code_t dst_format,
cairo_operator_t op,
const cairo_pattern_t *src_pattern,
int dst_x,
int dst_y,
const cairo_rectangle_int_t *extents,
cairo_region_t *clip_region)
{
const cairo_pattern_t *mask_pattern = closure;
pixman_image_t *src, *mask = NULL;
int src_x = 0, src_y = 0;
int mask_x = 0, mask_y = 0;
 
if (src_pattern != NULL) {
src = _pixman_image_for_pattern (src_pattern, FALSE, extents, &src_x, &src_y);
if (unlikely (src == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
mask = _pixman_image_for_pattern (mask_pattern, TRUE, extents, &mask_x, &mask_y);
if (unlikely (mask == NULL)) {
pixman_image_unref (src);
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
 
if (mask_pattern->has_component_alpha)
pixman_image_set_component_alpha (mask, TRUE);
} else {
src = _pixman_image_for_pattern (mask_pattern, FALSE, extents, &src_x, &src_y);
if (unlikely (src == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
 
pixman_image_composite32 (_pixman_operator (op), src, mask, dst,
extents->x + src_x, extents->y + src_y,
extents->x + mask_x, extents->y + mask_y,
extents->x - dst_x, extents->y - dst_y,
extents->width, extents->height);
 
if (mask != NULL)
pixman_image_unref (mask);
pixman_image_unref (src);
 
return CAIRO_STATUS_SUCCESS;
}
 
static cairo_int_status_t
_cairo_image_surface_mask (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_pattern_t *mask,
cairo_clip_t *clip)
{
cairo_image_surface_t *surface = abstract_surface;
cairo_composite_rectangles_t extents;
cairo_clip_t local_clip;
cairo_bool_t have_clip = FALSE;
cairo_status_t status;
 
status = _cairo_composite_rectangles_init_for_mask (&extents,
surface->width, surface->height,
op, source, mask, clip);
if (unlikely (status))
return status;
 
if (_cairo_clip_contains_extents (clip, &extents))
clip = NULL;
 
if (clip != NULL && extents.is_bounded) {
clip = _cairo_clip_init_copy (&local_clip, clip);
status = _cairo_clip_rectangle (clip, &extents.bounded);
if (unlikely (status)) {
_cairo_clip_fini (&local_clip);
return status;
}
 
have_clip = TRUE;
}
 
status = _clip_and_composite (surface, op, source,
_composite_mask, (void *) mask,
&extents, clip);
 
if (have_clip)
_cairo_clip_fini (&local_clip);
 
return status;
}
 
typedef struct {
cairo_polygon_t *polygon;
cairo_fill_rule_t fill_rule;
cairo_antialias_t antialias;
} composite_spans_info_t;
 
//#define USE_BOTOR_SCAN_CONVERTER
static cairo_status_t
_composite_spans (void *closure,
pixman_image_t *dst,
pixman_format_code_t dst_format,
cairo_operator_t op,
const cairo_pattern_t *pattern,
int dst_x,
int dst_y,
const cairo_rectangle_int_t *extents,
cairo_region_t *clip_region)
{
uint8_t mask_buf[CAIRO_STACK_BUFFER_SIZE];
composite_spans_info_t *info = closure;
cairo_image_surface_span_renderer_t renderer;
#if USE_BOTOR_SCAN_CONVERTER
cairo_box_t box;
cairo_botor_scan_converter_t converter;
#else
cairo_scan_converter_t *converter;
#endif
pixman_image_t *mask;
cairo_status_t status;
 
#if USE_BOTOR_SCAN_CONVERTER
box.p1.x = _cairo_fixed_from_int (extents->x);
box.p1.y = _cairo_fixed_from_int (extents->y);
box.p2.x = _cairo_fixed_from_int (extents->x + extents->width);
box.p2.y = _cairo_fixed_from_int (extents->y + extents->height);
_cairo_botor_scan_converter_init (&converter, &box, info->fill_rule);
status = converter.base.add_polygon (&converter.base, info->polygon);
#else
converter = _cairo_tor_scan_converter_create (extents->x, extents->y,
extents->x + extents->width,
extents->y + extents->height,
info->fill_rule);
status = converter->add_polygon (converter, info->polygon);
#endif
if (unlikely (status))
goto CLEANUP_CONVERTER;
 
/* TODO: support rendering to A1 surfaces (or: go add span
* compositing to pixman.) */
 
if (pattern == NULL &&
dst_format == PIXMAN_a8 &&
op == CAIRO_OPERATOR_SOURCE)
{
mask = dst;
dst = NULL;
}
else
{
int stride = CAIRO_STRIDE_FOR_WIDTH_BPP (extents->width, 8);
uint8_t *data = mask_buf;
 
if (extents->height * stride <= (int) sizeof (mask_buf))
memset (data, 0, extents->height * stride);
else
data = NULL, stride = 0;
 
mask = pixman_image_create_bits (PIXMAN_a8,
extents->width,
extents->height,
(uint32_t *) data,
stride);
if (unlikely (mask == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto CLEANUP_CONVERTER;
}
}
 
renderer.base.render_rows = _cairo_image_surface_span;
renderer.mask_stride = pixman_image_get_stride (mask);
renderer.mask_data = (uint8_t *) pixman_image_get_data (mask);
if (dst != NULL)
renderer.mask_data -= extents->y * renderer.mask_stride + extents->x;
else
renderer.mask_data -= dst_y * renderer.mask_stride + dst_x;
 
#if USE_BOTOR_SCAN_CONVERTER
status = converter.base.generate (&converter.base, &renderer.base);
#else
status = converter->generate (converter, &renderer.base);
#endif
if (unlikely (status))
goto CLEANUP_RENDERER;
 
if (dst != NULL) {
pixman_image_t *src;
int src_x, src_y;
 
src = _pixman_image_for_pattern (pattern, FALSE, extents, &src_x, &src_y);
if (unlikely (src == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto CLEANUP_RENDERER;
}
 
pixman_image_composite32 (_pixman_operator (op), src, mask, dst,
extents->x + src_x, extents->y + src_y,
0, 0, /* mask.x, mask.y */
extents->x - dst_x, extents->y - dst_y,
extents->width, extents->height);
pixman_image_unref (src);
}
 
CLEANUP_RENDERER:
if (dst != NULL)
pixman_image_unref (mask);
CLEANUP_CONVERTER:
#if USE_BOTOR_SCAN_CONVERTER
converter.base.destroy (&converter.base);
#else
converter->destroy (converter);
#endif
return status;
}
 
static cairo_status_t
_clip_and_composite_polygon (cairo_image_surface_t *dst,
cairo_operator_t op,
const cairo_pattern_t *src,
cairo_polygon_t *polygon,
cairo_fill_rule_t fill_rule,
cairo_antialias_t antialias,
cairo_composite_rectangles_t *extents,
cairo_clip_t *clip)
{
cairo_status_t status;
 
if (polygon->num_edges == 0) {
cairo_traps_t traps;
 
if (extents->is_bounded)
return CAIRO_STATUS_SUCCESS;
 
_cairo_traps_init (&traps);
status = _clip_and_composite_trapezoids (dst, op, src,
&traps, antialias,
extents, clip);
_cairo_traps_fini (&traps);
 
return status;
}
 
_cairo_box_round_to_rectangle (&polygon->extents, &extents->mask);
if (! _cairo_rectangle_intersect (&extents->bounded, &extents->mask))
return CAIRO_STATUS_SUCCESS;
 
if (antialias != CAIRO_ANTIALIAS_NONE) {
composite_spans_info_t info;
 
info.polygon = polygon;
info.fill_rule = fill_rule;
info.antialias = antialias;
 
status = _clip_and_composite (dst, op, src,
_composite_spans, &info,
extents, clip);
} else {
cairo_traps_t traps;
 
_cairo_traps_init (&traps);
 
/* Fall back to trapezoid fills. */
status = _cairo_bentley_ottmann_tessellate_polygon (&traps,
polygon,
fill_rule);
if (likely (status == CAIRO_STATUS_SUCCESS)) {
status = _clip_and_composite_trapezoids (dst, op, src,
&traps, antialias,
extents, clip);
}
 
_cairo_traps_fini (&traps);
}
 
return status;
}
 
static cairo_int_status_t
_cairo_image_surface_stroke (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_path_fixed_t *path,
const cairo_stroke_style_t *style,
const cairo_matrix_t *ctm,
const cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
cairo_clip_t *clip)
{
cairo_image_surface_t *surface = abstract_surface;
cairo_composite_rectangles_t extents;
cairo_box_t boxes_stack[32], *clip_boxes = boxes_stack;
int num_boxes = ARRAY_LENGTH (boxes_stack);
cairo_clip_t local_clip;
cairo_bool_t have_clip = FALSE;
cairo_status_t status;
 
status = _cairo_composite_rectangles_init_for_stroke (&extents,
surface->width,
surface->height,
op, source,
path, style, ctm,
clip);
if (unlikely (status))
return status;
 
if (_cairo_clip_contains_extents (clip, &extents))
clip = NULL;
 
if (clip != NULL) {
clip = _cairo_clip_init_copy (&local_clip, clip);
have_clip = TRUE;
}
 
status = _cairo_clip_to_boxes (&clip, &extents, &clip_boxes, &num_boxes);
if (unlikely (status)) {
if (have_clip)
_cairo_clip_fini (&local_clip);
 
return status;
}
 
status = CAIRO_INT_STATUS_UNSUPPORTED;
if (path->is_rectilinear) {
cairo_boxes_t boxes;
 
_cairo_boxes_init (&boxes);
_cairo_boxes_limit (&boxes, clip_boxes, num_boxes);
 
status = _cairo_path_fixed_stroke_rectilinear_to_boxes (path,
style,
ctm,
&boxes);
if (likely (status == CAIRO_STATUS_SUCCESS)) {
status = _clip_and_composite_boxes (surface, op, source,
&boxes, antialias,
&extents, clip);
}
 
_cairo_boxes_fini (&boxes);
}
 
if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
cairo_polygon_t polygon;
 
_cairo_polygon_init (&polygon);
_cairo_polygon_limit (&polygon, clip_boxes, num_boxes);
 
status = _cairo_path_fixed_stroke_to_polygon (path,
style,
ctm, ctm_inverse,
tolerance,
&polygon);
if (likely (status == CAIRO_STATUS_SUCCESS)) {
status = _clip_and_composite_polygon (surface, op, source, &polygon,
CAIRO_FILL_RULE_WINDING, antialias,
&extents, clip);
}
 
_cairo_polygon_fini (&polygon);
}
 
if (clip_boxes != boxes_stack)
free (clip_boxes);
 
if (have_clip)
_cairo_clip_fini (&local_clip);
 
return status;
}
 
static cairo_int_status_t
_cairo_image_surface_fill (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias,
cairo_clip_t *clip)
{
cairo_image_surface_t *surface = abstract_surface;
cairo_composite_rectangles_t extents;
cairo_box_t boxes_stack[32], *clip_boxes = boxes_stack;
cairo_clip_t local_clip;
cairo_bool_t have_clip = FALSE;
int num_boxes = ARRAY_LENGTH (boxes_stack);
cairo_status_t status;
 
status = _cairo_composite_rectangles_init_for_fill (&extents,
surface->width,
surface->height,
op, source, path,
clip);
if (unlikely (status))
return status;
 
if (_cairo_clip_contains_extents (clip, &extents))
clip = NULL;
 
if (extents.is_bounded && clip != NULL) {
cairo_clip_path_t *clip_path;
 
if (((clip_path = _clip_get_single_path (clip)) != NULL) &&
_cairo_path_fixed_equal (&clip_path->path, path))
{
clip = NULL;
}
}
 
if (clip != NULL) {
clip = _cairo_clip_init_copy (&local_clip, clip);
have_clip = TRUE;
}
 
status = _cairo_clip_to_boxes (&clip, &extents, &clip_boxes, &num_boxes);
if (unlikely (status)) {
if (have_clip)
_cairo_clip_fini (&local_clip);
 
return status;
}
 
if (_cairo_path_fixed_is_rectilinear_fill (path)) {
cairo_boxes_t boxes;
 
_cairo_boxes_init (&boxes);
_cairo_boxes_limit (&boxes, clip_boxes, num_boxes);
 
status = _cairo_path_fixed_fill_rectilinear_to_boxes (path,
fill_rule,
&boxes);
if (likely (status == CAIRO_STATUS_SUCCESS)) {
status = _clip_and_composite_boxes (surface, op, source,
&boxes, antialias,
&extents, clip);
}
 
_cairo_boxes_fini (&boxes);
} else {
cairo_polygon_t polygon;
 
assert (! path->is_empty_fill);
 
_cairo_polygon_init (&polygon);
_cairo_polygon_limit (&polygon, clip_boxes, num_boxes);
 
status = _cairo_path_fixed_fill_to_polygon (path, tolerance, &polygon);
if (likely (status == CAIRO_STATUS_SUCCESS)) {
status = _clip_and_composite_polygon (surface, op, source, &polygon,
fill_rule, antialias,
&extents, clip);
}
 
_cairo_polygon_fini (&polygon);
}
 
if (clip_boxes != boxes_stack)
free (clip_boxes);
 
if (have_clip)
_cairo_clip_fini (&local_clip);
 
return status;
}
 
typedef struct {
cairo_scaled_font_t *font;
cairo_glyph_t *glyphs;
int num_glyphs;
} composite_glyphs_info_t;
 
static cairo_status_t
_composite_glyphs_via_mask (void *closure,
pixman_image_t *dst,
pixman_format_code_t dst_format,
cairo_operator_t op,
const cairo_pattern_t *pattern,
int dst_x,
int dst_y,
const cairo_rectangle_int_t *extents,
cairo_region_t *clip_region)
{
composite_glyphs_info_t *info = closure;
cairo_scaled_font_t *font = info->font;
cairo_glyph_t *glyphs = info->glyphs;
int num_glyphs = info->num_glyphs;
pixman_image_t *mask = NULL;
pixman_image_t *src;
pixman_image_t *white;
pixman_format_code_t mask_format = 0; /* silence gcc */
cairo_status_t status;
int src_x, src_y;
int i;
 
src = _pixman_image_for_pattern (pattern, FALSE, extents, &src_x, &src_y);
if (unlikely (src == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
white = _pixman_white_image ();
if (unlikely (white == NULL)) {
pixman_image_unref (src);
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
 
_cairo_scaled_font_freeze_cache (font);
 
for (i = 0; i < num_glyphs; i++) {
int x, y;
cairo_image_surface_t *glyph_surface;
cairo_scaled_glyph_t *scaled_glyph;
 
status = _cairo_scaled_glyph_lookup (font, glyphs[i].index,
CAIRO_SCALED_GLYPH_INFO_SURFACE,
&scaled_glyph);
 
if (unlikely (status))
goto CLEANUP;
 
glyph_surface = scaled_glyph->surface;
 
if (glyph_surface->width == 0 || glyph_surface->height == 0)
continue;
 
/* To start, create the mask using the format from the first
* glyph. Later we'll deal with different formats. */
if (mask == NULL) {
mask_format = glyph_surface->pixman_format;
mask = pixman_image_create_bits (mask_format,
extents->width, extents->height,
NULL, 0);
if (unlikely (mask == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto CLEANUP;
}
 
if (PIXMAN_FORMAT_RGB (mask_format))
pixman_image_set_component_alpha (mask, TRUE);
}
 
/* If we have glyphs of different formats, we "upgrade" the mask
* to the wider of the formats. */
if (glyph_surface->pixman_format != mask_format &&
PIXMAN_FORMAT_BPP (mask_format) <
PIXMAN_FORMAT_BPP (glyph_surface->pixman_format))
{
pixman_image_t *new_mask;
 
mask_format = glyph_surface->pixman_format;
new_mask = pixman_image_create_bits (mask_format,
extents->width, extents->height,
NULL, 0);
if (unlikely (new_mask == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto CLEANUP;
}
 
pixman_image_composite32 (PIXMAN_OP_SRC,
white, mask, new_mask,
0, 0, 0, 0, 0, 0,
extents->width, extents->height);
 
pixman_image_unref (mask);
mask = new_mask;
if (PIXMAN_FORMAT_RGB (mask_format))
pixman_image_set_component_alpha (mask, TRUE);
}
 
/* round glyph locations to the nearest pixel */
/* XXX: FRAGILE: We're ignoring device_transform scaling here. A bug? */
x = _cairo_lround (glyphs[i].x -
glyph_surface->base.device_transform.x0);
y = _cairo_lround (glyphs[i].y -
glyph_surface->base.device_transform.y0);
if (glyph_surface->pixman_format == mask_format) {
pixman_image_composite32 (PIXMAN_OP_ADD,
glyph_surface->pixman_image, NULL, mask,
0, 0, 0, 0,
x - extents->x, y - extents->y,
glyph_surface->width,
glyph_surface->height);
} else {
pixman_image_composite32 (PIXMAN_OP_ADD,
white, glyph_surface->pixman_image, mask,
0, 0, 0, 0,
x - extents->x, y - extents->y,
glyph_surface->width,
glyph_surface->height);
}
}
 
pixman_image_composite32 (_pixman_operator (op),
src, mask, dst,
extents->x + src_x, extents->y + src_y,
0, 0,
extents->x - dst_x, extents->y - dst_y,
extents->width, extents->height);
 
CLEANUP:
_cairo_scaled_font_thaw_cache (font);
if (mask != NULL)
pixman_image_unref (mask);
pixman_image_unref (src);
pixman_image_unref (white);
 
return status;
}
 
static cairo_status_t
_composite_glyphs (void *closure,
pixman_image_t *dst,
pixman_format_code_t dst_format,
cairo_operator_t op,
const cairo_pattern_t *pattern,
int dst_x,
int dst_y,
const cairo_rectangle_int_t *extents,
cairo_region_t *clip_region)
{
composite_glyphs_info_t *info = closure;
cairo_scaled_glyph_t *glyph_cache[64];
pixman_op_t pixman_op = _pixman_operator (op);
pixman_image_t *src = NULL;
int src_x = 0, src_y = 0;
cairo_status_t status;
int i;
 
if (pattern != NULL) {
src = _pixman_image_for_pattern (pattern, FALSE, extents, &src_x, &src_y);
src_x -= dst_x;
src_y -= dst_y;
} else {
src = _pixman_white_image ();
}
if (unlikely (src == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
memset (glyph_cache, 0, sizeof (glyph_cache));
status = CAIRO_STATUS_SUCCESS;
 
_cairo_scaled_font_freeze_cache (info->font);
for (i = 0; i < info->num_glyphs; i++) {
int x, y;
cairo_image_surface_t *glyph_surface;
cairo_scaled_glyph_t *scaled_glyph;
unsigned long glyph_index = info->glyphs[i].index;
int cache_index = glyph_index % ARRAY_LENGTH (glyph_cache);
 
scaled_glyph = glyph_cache[cache_index];
if (scaled_glyph == NULL ||
_cairo_scaled_glyph_index (scaled_glyph) != glyph_index)
{
status = _cairo_scaled_glyph_lookup (info->font, glyph_index,
CAIRO_SCALED_GLYPH_INFO_SURFACE,
&scaled_glyph);
 
if (unlikely (status))
break;
 
glyph_cache[cache_index] = scaled_glyph;
}
 
glyph_surface = scaled_glyph->surface;
if (glyph_surface->width && glyph_surface->height) {
int x1, y1, x2, y2;
 
/* round glyph locations to the nearest pixel */
/* XXX: FRAGILE: We're ignoring device_transform scaling here. A bug? */
x = _cairo_lround (info->glyphs[i].x -
glyph_surface->base.device_transform.x0);
y = _cairo_lround (info->glyphs[i].y -
glyph_surface->base.device_transform.y0);
 
x1 = x;
if (x1 < extents->x)
x1 = extents->x;
x2 = x + glyph_surface->width;
if (x2 > extents->x + extents->width)
x2 = extents->x + extents->width;
 
y1 = y;
if (y1 < extents->y)
y1 = extents->y;
y2 = y + glyph_surface->height;
if (y2 > extents->y + extents->height)
y2 = extents->y + extents->height;
 
pixman_image_composite32 (pixman_op,
src, glyph_surface->pixman_image, dst,
x1 + src_x, y1 + src_y,
x1 - x, y1 - y,
x1 - dst_x, y1 - dst_y,
x2 - x1, y2 - y1);
}
}
_cairo_scaled_font_thaw_cache (info->font);
 
pixman_image_unref (src);
 
return status;
}
 
static cairo_int_status_t
_cairo_image_surface_glyphs (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font,
cairo_clip_t *clip,
int *num_remaining)
{
cairo_image_surface_t *surface = abstract_surface;
cairo_composite_rectangles_t extents;
composite_glyphs_info_t glyph_info;
cairo_clip_t local_clip;
cairo_bool_t have_clip = FALSE;
cairo_bool_t overlap;
cairo_status_t status;
 
status = _cairo_composite_rectangles_init_for_glyphs (&extents,
surface->width,
surface->height,
op, source,
scaled_font,
glyphs, num_glyphs,
clip,
&overlap);
if (unlikely (status))
return status;
 
if (_cairo_clip_contains_rectangle (clip, &extents.mask))
clip = NULL;
 
if (clip != NULL && extents.is_bounded) {
clip = _cairo_clip_init_copy (&local_clip, clip);
status = _cairo_clip_rectangle (clip, &extents.bounded);
if (unlikely (status))
return status;
 
have_clip = TRUE;
}
 
glyph_info.font = scaled_font;
glyph_info.glyphs = glyphs;
glyph_info.num_glyphs = num_glyphs;
 
status = _clip_and_composite (surface, op, source,
overlap || extents.is_bounded == 0 ? _composite_glyphs_via_mask : _composite_glyphs,
&glyph_info,
&extents, clip);
 
if (have_clip)
_cairo_clip_fini (&local_clip);
 
*num_remaining = 0;
return status;
}
 
static cairo_bool_t
_cairo_image_surface_get_extents (void *abstract_surface,
cairo_rectangle_int_t *rectangle)
{
cairo_image_surface_t *surface = abstract_surface;
 
rectangle->x = 0;
rectangle->y = 0;
rectangle->width = surface->width;
rectangle->height = surface->height;
 
return TRUE;
}
 
static void
_cairo_image_surface_get_font_options (void *abstract_surface,
cairo_font_options_t *options)
{
_cairo_font_options_init_default (options);
 
cairo_font_options_set_hint_metrics (options, CAIRO_HINT_METRICS_ON);
}
 
/* legacy interface kept for compatibility until surface-fallback is removed */
static cairo_status_t
_cairo_image_surface_acquire_dest_image (void *abstract_surface,
cairo_rectangle_int_t *interest_rect,
cairo_image_surface_t **image_out,
cairo_rectangle_int_t *image_rect_out,
void **image_extra)
{
cairo_image_surface_t *surface = abstract_surface;
 
image_rect_out->x = 0;
image_rect_out->y = 0;
image_rect_out->width = surface->width;
image_rect_out->height = surface->height;
 
*image_out = surface;
*image_extra = NULL;
 
return CAIRO_STATUS_SUCCESS;
}
 
static void
_cairo_image_surface_release_dest_image (void *abstract_surface,
cairo_rectangle_int_t *interest_rect,
cairo_image_surface_t *image,
cairo_rectangle_int_t *image_rect,
void *image_extra)
{
}
 
static cairo_status_t
_cairo_image_surface_clone_similar (void *abstract_surface,
cairo_surface_t *src,
int src_x,
int src_y,
int width,
int height,
int *clone_offset_x,
int *clone_offset_y,
cairo_surface_t **clone_out)
{
cairo_image_surface_t *surface = abstract_surface;
 
if (src->backend == surface->base.backend) {
*clone_offset_x = *clone_offset_y = 0;
*clone_out = cairo_surface_reference (src);
 
return CAIRO_STATUS_SUCCESS;
}
 
return CAIRO_INT_STATUS_UNSUPPORTED;
}
 
static cairo_int_status_t
_cairo_image_surface_composite (cairo_operator_t op,
const cairo_pattern_t *src_pattern,
const cairo_pattern_t *mask_pattern,
void *abstract_dst,
int src_x,
int src_y,
int mask_x,
int mask_y,
int dst_x,
int dst_y,
unsigned int width,
unsigned int height,
cairo_region_t *clip_region)
{
cairo_image_surface_t *dst = abstract_dst;
cairo_composite_rectangles_t extents;
pixman_image_t *src;
int src_offset_x, src_offset_y;
cairo_status_t status;
 
if (clip_region != NULL) {
status = _cairo_image_surface_set_clip_region (dst, clip_region);
if (unlikely (status))
return status;
}
 
extents.source.x = src_x;
extents.source.y = src_y;
extents.source.width = width;
extents.source.height = height;
 
extents.mask.x = mask_x;
extents.mask.y = mask_y;
extents.mask.width = width;
extents.mask.height = height;
 
extents.bounded.x = dst_x;
extents.bounded.y = dst_y;
extents.bounded.width = width;
extents.bounded.height = height;
 
extents.unbounded.x = 0;
extents.unbounded.y = 0;
extents.unbounded.width = dst->width;
extents.unbounded.height = dst->height;
 
if (clip_region != NULL) {
cairo_rectangle_int_t rect;
 
cairo_region_get_extents (clip_region, &rect);
if (! _cairo_rectangle_intersect (&extents.unbounded, &rect))
return CAIRO_STATUS_SUCCESS;
}
 
extents.is_bounded = _cairo_operator_bounded_by_either (op);
 
src = _pixman_image_for_pattern (src_pattern, FALSE, &extents.source, &src_offset_x, &src_offset_y);
if (unlikely (src == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
status = CAIRO_STATUS_SUCCESS;
if (mask_pattern != NULL) {
pixman_image_t *mask;
int mask_offset_x, mask_offset_y;
 
mask = _pixman_image_for_pattern (mask_pattern, TRUE, &extents.mask, &mask_offset_x, &mask_offset_y);
if (unlikely (mask == NULL)) {
pixman_image_unref (src);
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
 
pixman_image_composite32 (_pixman_operator (op),
src, mask, dst->pixman_image,
src_x + src_offset_x,
src_y + src_offset_y,
mask_x + mask_offset_x,
mask_y + mask_offset_y,
dst_x, dst_y, width, height);
 
pixman_image_unref (mask);
} else {
pixman_image_composite32 (_pixman_operator (op),
src, NULL, dst->pixman_image,
src_x + src_offset_x,
src_y + src_offset_y,
0, 0,
dst_x, dst_y, width, height);
}
 
pixman_image_unref (src);
 
if (! extents.is_bounded)
status = _cairo_image_surface_fixup_unbounded (dst, &extents, NULL);
 
if (clip_region != NULL)
_cairo_image_surface_unset_clip_region (dst);
 
return status;
}
 
static cairo_int_status_t
_cairo_image_surface_fill_rectangles (void *abstract_surface,
cairo_operator_t op,
const cairo_color_t *color,
cairo_rectangle_int_t *rects,
int num_rects)
{
cairo_image_surface_t *surface = abstract_surface;
 
pixman_color_t pixman_color;
pixman_box32_t stack_boxes[CAIRO_STACK_ARRAY_LENGTH (pixman_box32_t)];
pixman_box32_t *pixman_boxes = stack_boxes;
int i;
 
cairo_int_status_t status;
 
if (CAIRO_INJECT_FAULT ())
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
pixman_color.red = color->red_short;
pixman_color.green = color->green_short;
pixman_color.blue = color->blue_short;
pixman_color.alpha = color->alpha_short;
 
if (num_rects > ARRAY_LENGTH (stack_boxes)) {
pixman_boxes = _cairo_malloc_ab (num_rects, sizeof (pixman_box32_t));
if (unlikely (pixman_boxes == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
 
for (i = 0; i < num_rects; i++) {
pixman_boxes[i].x1 = rects[i].x;
pixman_boxes[i].y1 = rects[i].y;
pixman_boxes[i].x2 = rects[i].x + rects[i].width;
pixman_boxes[i].y2 = rects[i].y + rects[i].height;
}
 
status = CAIRO_STATUS_SUCCESS;
if (! pixman_image_fill_boxes (_pixman_operator (op),
surface->pixman_image,
&pixman_color,
num_rects,
pixman_boxes))
{
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
 
if (pixman_boxes != stack_boxes)
free (pixman_boxes);
 
return status;
}
 
static cairo_int_status_t
_cairo_image_surface_composite_trapezoids (cairo_operator_t op,
const cairo_pattern_t *pattern,
void *abstract_dst,
cairo_antialias_t antialias,
int src_x,
int src_y,
int dst_x,
int dst_y,
unsigned int width,
unsigned int height,
cairo_trapezoid_t *traps,
int num_traps,
cairo_region_t *clip_region)
{
cairo_image_surface_t *dst = abstract_dst;
cairo_composite_rectangles_t extents;
cairo_pattern_union_t source_pattern;
composite_traps_info_t info;
cairo_status_t status;
 
if (height == 0 || width == 0)
return CAIRO_STATUS_SUCCESS;
 
if (CAIRO_INJECT_FAULT ())
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
extents.source.x = src_x;
extents.source.y = src_y;
extents.source.width = width;
extents.source.height = height;
 
extents.mask.x = dst_x;
extents.mask.y = dst_y;
extents.mask.width = width;
extents.mask.height = height;
 
extents.bounded.x = dst_x;
extents.bounded.y = dst_y;
extents.bounded.width = width;
extents.bounded.height = height;
 
extents.unbounded.x = 0;
extents.unbounded.y = 0;
extents.unbounded.width = dst->width;
extents.unbounded.height = dst->height;
 
if (clip_region != NULL) {
cairo_rectangle_int_t rect;
 
cairo_region_get_extents (clip_region, &rect);
if (! _cairo_rectangle_intersect (&extents.unbounded, &rect))
return CAIRO_STATUS_SUCCESS;
}
 
extents.is_bounded = _cairo_operator_bounded_by_either (op);
 
if (clip_region != NULL) {
status = _cairo_image_surface_set_clip_region (dst, clip_region);
if (unlikely (status))
return status;
}
 
_cairo_pattern_init_static_copy (&source_pattern.base, pattern);
cairo_matrix_translate (&source_pattern.base.matrix,
src_x - extents.bounded.x,
src_y - extents.bounded.y);
 
info.traps = traps;
info.num_traps = num_traps;
info.antialias = antialias;
status = _composite_traps (&info,
dst->pixman_image,
dst->pixman_format,
op,
&source_pattern.base,
0, 0,
&extents.bounded,
clip_region);
 
if (status == CAIRO_STATUS_SUCCESS && ! extents.is_bounded)
status = _cairo_image_surface_fixup_unbounded (dst, &extents, NULL);
 
if (clip_region != NULL)
_cairo_image_surface_unset_clip_region (dst);
 
return status;
}
 
typedef struct _legacy_image_surface_span_renderer {
cairo_span_renderer_t base;
 
cairo_operator_t op;
const cairo_pattern_t *pattern;
cairo_antialias_t antialias;
cairo_region_t *clip_region;
 
pixman_image_t *mask;
uint8_t *mask_data;
uint32_t mask_stride;
 
cairo_image_surface_t *dst;
cairo_composite_rectangles_t composite_rectangles;
} legacy_image_surface_span_renderer_t;
 
void
_cairo_image_surface_span_render_row (
int y,
const cairo_half_open_span_t *spans,
unsigned num_spans,
uint8_t *data,
uint32_t stride)
{
uint8_t *row;
unsigned i;
 
if (num_spans == 0)
return;
 
row = data + y * stride;
for (i = 0; i < num_spans - 1; i++) {
if (! spans[i].coverage)
continue;
 
/* We implement setting the most common single pixel wide
* span case to avoid the overhead of a memset call.
* Open coding setting longer spans didn't show a
* noticeable improvement over memset.
*/
if (spans[i+1].x == spans[i].x + 1) {
row[spans[i].x] = spans[i].coverage;
} else {
memset (row + spans[i].x,
spans[i].coverage,
spans[i+1].x - spans[i].x);
}
}
}
 
static cairo_status_t
_cairo_image_surface_span_renderer_render_rows (
void *abstract_renderer,
int y,
int height,
const cairo_half_open_span_t *spans,
unsigned num_spans)
{
legacy_image_surface_span_renderer_t *renderer = abstract_renderer;
while (height--)
_cairo_image_surface_span_render_row (y++, spans, num_spans, renderer->mask_data, renderer->mask_stride);
return CAIRO_STATUS_SUCCESS;
}
 
static void
_cairo_image_surface_span_renderer_destroy (void *abstract_renderer)
{
legacy_image_surface_span_renderer_t *renderer = abstract_renderer;
if (renderer == NULL)
return;
 
pixman_image_unref (renderer->mask);
 
free (renderer);
}
 
static cairo_status_t
_cairo_image_surface_span_renderer_finish (void *abstract_renderer)
{
legacy_image_surface_span_renderer_t *renderer = abstract_renderer;
cairo_composite_rectangles_t *rects = &renderer->composite_rectangles;
cairo_image_surface_t *dst = renderer->dst;
pixman_image_t *src;
int src_x, src_y;
cairo_status_t status;
 
if (renderer->clip_region != NULL) {
status = _cairo_image_surface_set_clip_region (dst, renderer->clip_region);
if (unlikely (status))
return status;
}
 
src = _pixman_image_for_pattern (renderer->pattern, FALSE, &rects->bounded, &src_x, &src_y);
if (src == NULL)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
status = CAIRO_STATUS_SUCCESS;
pixman_image_composite32 (_pixman_operator (renderer->op),
src,
renderer->mask,
dst->pixman_image,
rects->bounded.x + src_x,
rects->bounded.y + src_y,
0, 0,
rects->bounded.x, rects->bounded.y,
rects->bounded.width, rects->bounded.height);
 
if (! rects->is_bounded)
status = _cairo_image_surface_fixup_unbounded (dst, rects, NULL);
 
if (renderer->clip_region != NULL)
_cairo_image_surface_unset_clip_region (dst);
 
return status;
}
 
static cairo_bool_t
_cairo_image_surface_check_span_renderer (cairo_operator_t op,
const cairo_pattern_t *pattern,
void *abstract_dst,
cairo_antialias_t antialias)
{
return TRUE;
(void) op;
(void) pattern;
(void) abstract_dst;
(void) antialias;
}
 
static cairo_span_renderer_t *
_cairo_image_surface_create_span_renderer (cairo_operator_t op,
const cairo_pattern_t *pattern,
void *abstract_dst,
cairo_antialias_t antialias,
const cairo_composite_rectangles_t *rects,
cairo_region_t *clip_region)
{
cairo_image_surface_t *dst = abstract_dst;
legacy_image_surface_span_renderer_t *renderer;
 
renderer = calloc(1, sizeof(*renderer));
if (unlikely (renderer == NULL))
return _cairo_span_renderer_create_in_error (CAIRO_STATUS_NO_MEMORY);
 
renderer->base.destroy = _cairo_image_surface_span_renderer_destroy;
renderer->base.finish = _cairo_image_surface_span_renderer_finish;
renderer->base.render_rows = _cairo_image_surface_span_renderer_render_rows;
renderer->op = op;
renderer->pattern = pattern;
renderer->antialias = antialias;
renderer->dst = dst;
renderer->clip_region = clip_region;
 
renderer->composite_rectangles = *rects;
 
/* TODO: support rendering to A1 surfaces (or: go add span
* compositing to pixman.) */
renderer->mask = pixman_image_create_bits (PIXMAN_a8,
rects->bounded.width,
rects->bounded.height,
NULL, 0);
if (renderer->mask == NULL) {
free (renderer);
return _cairo_span_renderer_create_in_error (CAIRO_STATUS_NO_MEMORY);
}
 
renderer->mask_stride = pixman_image_get_stride (renderer->mask);
renderer->mask_data = (uint8_t *) pixman_image_get_data (renderer->mask) - rects->bounded.x - rects->bounded.y * renderer->mask_stride;
 
return &renderer->base;
}
 
/**
* _cairo_surface_is_image:
* @surface: a #cairo_surface_t
*
* Checks if a surface is an #cairo_image_surface_t
*
* Return value: %TRUE if the surface is an image surface
**/
cairo_bool_t
_cairo_surface_is_image (const cairo_surface_t *surface)
{
return surface->backend == &_cairo_image_surface_backend;
}
 
const cairo_surface_backend_t _cairo_image_surface_backend = {
CAIRO_SURFACE_TYPE_IMAGE,
_cairo_image_surface_create_similar,
_cairo_image_surface_finish,
_cairo_image_surface_acquire_source_image,
_cairo_image_surface_release_source_image,
_cairo_image_surface_acquire_dest_image,
_cairo_image_surface_release_dest_image,
_cairo_image_surface_clone_similar,
_cairo_image_surface_composite,
_cairo_image_surface_fill_rectangles,
_cairo_image_surface_composite_trapezoids,
_cairo_image_surface_create_span_renderer,
_cairo_image_surface_check_span_renderer,
 
NULL, /* copy_page */
NULL, /* show_page */
_cairo_image_surface_get_extents,
NULL, /* old_show_glyphs */
_cairo_image_surface_get_font_options,
NULL, /* flush */
NULL, /* mark dirty */
NULL, /* font_fini */
NULL, /* glyph_fini */
 
_cairo_image_surface_paint,
_cairo_image_surface_mask,
_cairo_image_surface_stroke,
_cairo_image_surface_fill,
_cairo_image_surface_glyphs,
NULL, /* show_text_glyphs */
NULL, /* snapshot */
NULL, /* is_similar */
};
 
/* A convenience function for when one needs to coerce an image
* surface to an alternate format. */
cairo_image_surface_t *
_cairo_image_surface_coerce (cairo_image_surface_t *surface)
{
return _cairo_image_surface_coerce_to_format (surface,
_cairo_format_from_content (surface->base.content));
}
 
/* A convenience function for when one needs to coerce an image
* surface to an alternate format. */
cairo_image_surface_t *
_cairo_image_surface_coerce_to_format (cairo_image_surface_t *surface,
cairo_format_t format)
{
cairo_image_surface_t *clone;
cairo_status_t status;
 
status = surface->base.status;
if (unlikely (status))
return (cairo_image_surface_t *)_cairo_surface_create_in_error (status);
 
if (surface->format == format)
return (cairo_image_surface_t *)cairo_surface_reference(&surface->base);
 
clone = (cairo_image_surface_t *)
cairo_image_surface_create (format, surface->width, surface->height);
if (unlikely (clone->base.status))
return clone;
 
pixman_image_composite32 (PIXMAN_OP_SRC,
surface->pixman_image, NULL, clone->pixman_image,
0, 0,
0, 0,
0, 0,
surface->width, surface->height);
clone->base.is_clear = FALSE;
 
clone->base.device_transform =
surface->base.device_transform;
clone->base.device_transform_inverse =
surface->base.device_transform_inverse;
 
return clone;
}
 
cairo_image_transparency_t
_cairo_image_analyze_transparency (cairo_image_surface_t *image)
{
int x, y;
 
if (image->transparency != CAIRO_IMAGE_UNKNOWN)
return image->transparency;
 
if ((image->base.content & CAIRO_CONTENT_ALPHA) == 0)
return image->transparency = CAIRO_IMAGE_IS_OPAQUE;
 
if ((image->base.content & CAIRO_CONTENT_COLOR) == 0) {
if (image->format == CAIRO_FORMAT_A1)
return image->transparency = CAIRO_IMAGE_HAS_BILEVEL_ALPHA;
else
return image->transparency = CAIRO_IMAGE_HAS_ALPHA;
}
 
if (image->format == CAIRO_FORMAT_RGB16_565) {
image->transparency = CAIRO_IMAGE_IS_OPAQUE;
return CAIRO_IMAGE_IS_OPAQUE;
}
 
if (image->format != CAIRO_FORMAT_ARGB32)
return image->transparency = CAIRO_IMAGE_HAS_ALPHA;
 
image->transparency = CAIRO_IMAGE_IS_OPAQUE;
for (y = 0; y < image->height; y++) {
uint32_t *pixel = (uint32_t *) (image->data + y * image->stride);
 
for (x = 0; x < image->width; x++, pixel++) {
int a = (*pixel & 0xff000000) >> 24;
if (a > 0 && a < 255) {
return image->transparency = CAIRO_IMAGE_HAS_ALPHA;
} else if (a == 0) {
image->transparency = CAIRO_IMAGE_HAS_BILEVEL_ALPHA;
}
}
}
 
return image->transparency;
}
/programs/develop/libraries/cairo/src/cairo-list-private.h
0,0 → 1,215
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2009 Chris Wilson
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Chris Wilson.
*
* Contributor(s):
* Chris Wilson <chris@chris-wilson.co.uk>
*
*/
 
#ifndef CAIRO_LIST_PRIVATE_H
#define CAIRO_LIST_PRIVATE_H
 
#include "cairo-compiler-private.h"
 
/* Basic circular, doubly linked list implementation */
 
typedef struct _cairo_list {
struct _cairo_list *next, *prev;
} cairo_list_t;
 
#define cairo_list_entry(ptr, type, member) \
cairo_container_of(ptr, type, member)
 
#define cairo_list_first_entry(ptr, type, member) \
cairo_list_entry((ptr)->next, type, member)
 
#define cairo_list_last_entry(ptr, type, member) \
cairo_list_entry((ptr)->prev, type, member)
 
#define cairo_list_foreach(pos, head) \
for (pos = (head)->next; pos != (head); pos = pos->next)
 
#define cairo_list_foreach_entry(pos, type, head, member) \
for (pos = cairo_list_entry((head)->next, type, member);\
&pos->member != (head); \
pos = cairo_list_entry(pos->member.next, type, member))
 
#define cairo_list_foreach_entry_safe(pos, n, type, head, member) \
for (pos = cairo_list_entry ((head)->next, type, member),\
n = cairo_list_entry (pos->member.next, type, member);\
&pos->member != (head); \
pos = n, n = cairo_list_entry (n->member.next, type, member))
 
#define cairo_list_foreach_entry_reverse(pos, type, head, member) \
for (pos = cairo_list_entry((head)->prev, type, member);\
&pos->member != (head); \
pos = cairo_list_entry(pos->member.prev, type, member))
 
#define cairo_list_foreach_entry_reverse_safe(pos, n, type, head, member) \
for (pos = cairo_list_entry((head)->prev, type, member),\
n = cairo_list_entry (pos->member.prev, type, member);\
&pos->member != (head); \
pos = n, n = cairo_list_entry (n->member.prev, type, member))
 
#ifdef CAIRO_LIST_DEBUG
static inline void
_cairo_list_validate (const cairo_list_t *link)
{
assert (link->next->prev == link);
assert (link->prev->next == link);
}
static inline void
cairo_list_validate (const cairo_list_t *head)
{
cairo_list_t *link;
 
cairo_list_foreach (link, head)
_cairo_list_validate (link);
}
static inline cairo_bool_t
cairo_list_is_empty (const cairo_list_t *head);
static inline void
cairo_list_validate_is_empty (const cairo_list_t *head)
{
assert (head->next == NULL || (cairo_list_is_empty (head) && head->next == head->prev));
}
#else
#define _cairo_list_validate(link)
#define cairo_list_validate(head)
#define cairo_list_validate_is_empty(head)
#endif
 
static inline void
cairo_list_init (cairo_list_t *entry)
{
entry->next = entry;
entry->prev = entry;
}
 
static inline void
__cairo_list_add (cairo_list_t *entry,
cairo_list_t *prev,
cairo_list_t *next)
{
next->prev = entry;
entry->next = next;
entry->prev = prev;
prev->next = entry;
}
 
static inline void
cairo_list_add (cairo_list_t *entry, cairo_list_t *head)
{
cairo_list_validate (head);
cairo_list_validate_is_empty (entry);
__cairo_list_add (entry, head, head->next);
cairo_list_validate (head);
}
 
static inline void
cairo_list_add_tail (cairo_list_t *entry, cairo_list_t *head)
{
cairo_list_validate (head);
cairo_list_validate_is_empty (entry);
__cairo_list_add (entry, head->prev, head);
cairo_list_validate (head);
}
 
static inline void
__cairo_list_del (cairo_list_t *prev, cairo_list_t *next)
{
next->prev = prev;
prev->next = next;
}
 
static inline void
cairo_list_del (cairo_list_t *entry)
{
__cairo_list_del (entry->prev, entry->next);
cairo_list_init (entry);
}
 
static inline void
cairo_list_move (cairo_list_t *entry, cairo_list_t *head)
{
cairo_list_validate (head);
__cairo_list_del (entry->prev, entry->next);
__cairo_list_add (entry, head, head->next);
cairo_list_validate (head);
}
 
static inline void
cairo_list_move_tail (cairo_list_t *entry, cairo_list_t *head)
{
cairo_list_validate (head);
__cairo_list_del (entry->prev, entry->next);
__cairo_list_add (entry, head->prev, head);
cairo_list_validate (head);
}
 
static inline void
cairo_list_swap (cairo_list_t *entry, cairo_list_t *other)
{
__cairo_list_add (entry, other->prev, other->next);
cairo_list_init (other);
}
 
static inline cairo_bool_t
cairo_list_is_first (const cairo_list_t *entry,
const cairo_list_t *head)
{
cairo_list_validate (head);
return entry->prev == head;
}
 
static inline cairo_bool_t
cairo_list_is_last (const cairo_list_t *entry,
const cairo_list_t *head)
{
cairo_list_validate (head);
return entry->next == head;
}
 
static inline cairo_bool_t
cairo_list_is_empty (const cairo_list_t *head)
{
cairo_list_validate (head);
return head->next == head;
}
 
static inline cairo_bool_t
cairo_list_is_singular (const cairo_list_t *head)
{
cairo_list_validate (head);
return head->next == head || head->next == head->prev;
}
 
#endif /* CAIRO_LIST_PRIVATE_H */
/programs/develop/libraries/cairo/src/cairo-lzw.c
0,0 → 1,404
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2006 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
*/
 
#include "cairoint.h"
#include "cairo-error-private.h"
 
typedef struct _lzw_buf {
cairo_status_t status;
 
unsigned char *data;
int data_size;
int num_data;
uint32_t pending;
unsigned int pending_bits;
} lzw_buf_t;
 
/* An lzw_buf_t is a simple, growable chunk of memory for holding
* variable-size objects of up to 16 bits each.
*
* Initialize an lzw_buf_t to the given size in bytes.
*
* To store objects into the lzw_buf_t, call _lzw_buf_store_bits and
* when finished, call _lzw_buf_store_pending, (which flushes out the
* last few bits that hadn't yet made a complete byte yet).
*
* Instead of returning failure from any functions, lzw_buf_t provides
* a status value that the caller can query, (and should query at
* least once when done with the object). The status value will be
* either %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY;
*/
static void
_lzw_buf_init (lzw_buf_t *buf, int size)
{
if (size == 0)
size = 16;
 
buf->status = CAIRO_STATUS_SUCCESS;
buf->data_size = size;
buf->num_data = 0;
buf->pending = 0;
buf->pending_bits = 0;
 
buf->data = malloc (size);
if (unlikely (buf->data == NULL)) {
buf->data_size = 0;
buf->status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
return;
}
}
 
/* Increase the buffer size by doubling.
*
* Returns %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY
*/
static cairo_status_t
_lzw_buf_grow (lzw_buf_t *buf)
{
int new_size = buf->data_size * 2;
unsigned char *new_data;
 
if (buf->status)
return buf->status;
 
new_data = NULL;
/* check for integer overflow */
if (new_size / 2 == buf->data_size)
new_data = realloc (buf->data, new_size);
 
if (unlikely (new_data == NULL)) {
free (buf->data);
buf->data_size = 0;
buf->status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
return buf->status;
}
 
buf->data = new_data;
buf->data_size = new_size;
 
return CAIRO_STATUS_SUCCESS;
}
 
/* Store the lowest num_bits bits of values into buf.
*
* Note: The bits of value above size_in_bits must be 0, (so don't lie
* about the size).
*
* See also _lzw_buf_store_pending which must be called after the last
* call to _lzw_buf_store_bits.
*
* Sets buf->status to either %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY.
*/
static void
_lzw_buf_store_bits (lzw_buf_t *buf, uint16_t value, int num_bits)
{
cairo_status_t status;
 
assert (value <= (1 << num_bits) - 1);
 
if (buf->status)
return;
 
buf->pending = (buf->pending << num_bits) | value;
buf->pending_bits += num_bits;
 
while (buf->pending_bits >= 8) {
if (buf->num_data >= buf->data_size) {
status = _lzw_buf_grow (buf);
if (unlikely (status))
return;
}
buf->data[buf->num_data++] = buf->pending >> (buf->pending_bits - 8);
buf->pending_bits -= 8;
}
}
 
/* Store the last remaining pending bits into the buffer.
*
* Note: This function must be called after the last call to
* _lzw_buf_store_bits.
*
* Sets buf->status to either %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY.
*/
static void
_lzw_buf_store_pending (lzw_buf_t *buf)
{
cairo_status_t status;
 
if (buf->status)
return;
 
if (buf->pending_bits == 0)
return;
 
assert (buf->pending_bits < 8);
 
if (buf->num_data >= buf->data_size) {
status = _lzw_buf_grow (buf);
if (unlikely (status))
return;
}
 
buf->data[buf->num_data++] = buf->pending << (8 - buf->pending_bits);
buf->pending_bits = 0;
}
 
/* LZW defines a few magic code values */
#define LZW_CODE_CLEAR_TABLE 256
#define LZW_CODE_EOD 257
#define LZW_CODE_FIRST 258
 
/* We pack three separate values into a symbol as follows:
*
* 12 bits (31 down to 20): CODE: code value used to represent this symbol
* 12 bits (19 down to 8): PREV: previous code value in chain
* 8 bits ( 7 down to 0): NEXT: next byte value in chain
*/
typedef uint32_t lzw_symbol_t;
 
#define LZW_SYMBOL_SET(sym, prev, next) ((sym) = ((prev) << 8)|(next))
#define LZW_SYMBOL_SET_CODE(sym, code, prev, next) ((sym) = ((code << 20)|(prev) << 8)|(next))
#define LZW_SYMBOL_GET_CODE(sym) (((sym) >> 20))
#define LZW_SYMBOL_GET_PREV(sym) (((sym) >> 8) & 0x7ff)
#define LZW_SYMBOL_GET_BYTE(sym) (((sym) >> 0) & 0x0ff)
 
/* The PREV+NEXT fields can be seen as the key used to fetch values
* from the hash table, while the code is the value fetched.
*/
#define LZW_SYMBOL_KEY_MASK 0x000fffff
 
/* Since code values are only stored starting with 258 we can safely
* use a zero value to represent free slots in the hash table. */
#define LZW_SYMBOL_FREE 0x00000000
 
/* These really aren't very free for modifying. First, the PostScript
* specification sets the 9-12 bit range. Second, the encoding of
* lzw_symbol_t above also relies on 2 of LZW_BITS_MAX plus one byte
* fitting within 32 bits.
*
* But other than that, the LZW compression scheme could function with
* more bits per code.
*/
#define LZW_BITS_MIN 9
#define LZW_BITS_MAX 12
#define LZW_BITS_BOUNDARY(bits) ((1<<(bits))-1)
#define LZW_MAX_SYMBOLS (1<<LZW_BITS_MAX)
 
#define LZW_SYMBOL_TABLE_SIZE 9013
#define LZW_SYMBOL_MOD1 LZW_SYMBOL_TABLE_SIZE
#define LZW_SYMBOL_MOD2 9011
 
typedef struct _lzw_symbol_table {
lzw_symbol_t table[LZW_SYMBOL_TABLE_SIZE];
} lzw_symbol_table_t;
 
/* Initialize the hash table to entirely empty */
static void
_lzw_symbol_table_init (lzw_symbol_table_t *table)
{
memset (table->table, 0, LZW_SYMBOL_TABLE_SIZE * sizeof (lzw_symbol_t));
}
 
/* Lookup a symbol in the symbol table. The PREV and NEXT fields of
* symbol form the key for the lookup.
*
* If successful, then this function returns %TRUE and slot_ret will be
* left pointing at the result that will have the CODE field of
* interest.
*
* If the lookup fails, then this function returns %FALSE and slot_ret
* will be pointing at the location in the table to which a new CODE
* value should be stored along with PREV and NEXT.
*/
static cairo_bool_t
_lzw_symbol_table_lookup (lzw_symbol_table_t *table,
lzw_symbol_t symbol,
lzw_symbol_t **slot_ret)
{
/* The algorithm here is identical to that in cairo-hash.c. We
* copy it here to allow for a rather more efficient
* implementation due to several circumstances that do not apply
* to the more general case:
*
* 1) We have a known bound on the total number of symbols, so we
* have a fixed-size table without any copying when growing
*
* 2) We never delete any entries, so we don't need to
* support/check for DEAD entries during lookup.
*
* 3) The object fits in 32 bits so we store each object in its
* entirety within the table rather than storing objects
* externally and putting pointers in the table, (which here
* would just double the storage requirements and have negative
* impacts on memory locality).
*/
int i, idx, step, hash = symbol & LZW_SYMBOL_KEY_MASK;
lzw_symbol_t candidate;
 
idx = hash % LZW_SYMBOL_MOD1;
step = 0;
 
*slot_ret = NULL;
for (i = 0; i < LZW_SYMBOL_TABLE_SIZE; i++)
{
candidate = table->table[idx];
if (candidate == LZW_SYMBOL_FREE)
{
*slot_ret = &table->table[idx];
return FALSE;
}
else /* candidate is LIVE */
{
if ((candidate & LZW_SYMBOL_KEY_MASK) ==
(symbol & LZW_SYMBOL_KEY_MASK))
{
*slot_ret = &table->table[idx];
return TRUE;
}
}
 
if (step == 0) {
step = hash % LZW_SYMBOL_MOD2;
if (step == 0)
step = 1;
}
 
idx += step;
if (idx >= LZW_SYMBOL_TABLE_SIZE)
idx -= LZW_SYMBOL_TABLE_SIZE;
}
 
return FALSE;
}
 
/* Compress a bytestream using the LZW algorithm.
*
* This is an original implementation based on reading the
* specification of the LZWDecode filter in the PostScript Language
* Reference. The free parameters in the LZW algorithm are set to the
* values mandated by PostScript, (symbols encoded with widths from 9
* to 12 bits).
*
* This function returns a pointer to a newly allocated buffer holding
* the compressed data, or %NULL if an out-of-memory situation
* occurs.
*
* Notice that any one of the _lzw_buf functions called here could
* trigger an out-of-memory condition. But lzw_buf_t uses cairo's
* shutdown-on-error idiom, so it's safe to continue to call into
* lzw_buf without having to check for errors, (until a final check at
* the end).
*/
unsigned char *
_cairo_lzw_compress (unsigned char *data, unsigned long *size_in_out)
{
int bytes_remaining = *size_in_out;
lzw_buf_t buf;
lzw_symbol_table_t table;
lzw_symbol_t symbol, *slot = NULL; /* just to squelch a warning */
int code_next = LZW_CODE_FIRST;
int code_bits = LZW_BITS_MIN;
int prev, next = 0; /* just to squelch a warning */
 
if (*size_in_out == 0)
return NULL;
 
_lzw_buf_init (&buf, *size_in_out);
 
_lzw_symbol_table_init (&table);
 
/* The LZW header is a clear table code. */
_lzw_buf_store_bits (&buf, LZW_CODE_CLEAR_TABLE, code_bits);
 
while (1) {
 
/* Find the longest existing code in the symbol table that
* matches the current input, if any. */
prev = *data++;
bytes_remaining--;
if (bytes_remaining) {
do
{
next = *data++;
bytes_remaining--;
LZW_SYMBOL_SET (symbol, prev, next);
if (_lzw_symbol_table_lookup (&table, symbol, &slot))
prev = LZW_SYMBOL_GET_CODE (*slot);
} while (bytes_remaining && *slot != LZW_SYMBOL_FREE);
if (*slot == LZW_SYMBOL_FREE) {
data--;
bytes_remaining++;
}
}
 
/* Write the code into the output. This is either a byte read
* directly from the input, or a code from the last successful
* lookup. */
_lzw_buf_store_bits (&buf, prev, code_bits);
 
if (bytes_remaining == 0)
break;
 
LZW_SYMBOL_SET_CODE (*slot, code_next++, prev, next);
 
if (code_next > LZW_BITS_BOUNDARY(code_bits))
{
code_bits++;
if (code_bits > LZW_BITS_MAX) {
_lzw_symbol_table_init (&table);
_lzw_buf_store_bits (&buf, LZW_CODE_CLEAR_TABLE, code_bits - 1);
code_bits = LZW_BITS_MIN;
code_next = LZW_CODE_FIRST;
}
}
}
 
/* The LZW footer is an end-of-data code. */
_lzw_buf_store_bits (&buf, LZW_CODE_EOD, code_bits);
 
_lzw_buf_store_pending (&buf);
 
/* See if we ever ran out of memory while writing to buf. */
if (buf.status == CAIRO_STATUS_NO_MEMORY) {
*size_in_out = 0;
return NULL;
}
 
assert (buf.status == CAIRO_STATUS_SUCCESS);
 
*size_in_out = buf.num_data;
return buf.data;
}
/programs/develop/libraries/cairo/src/cairo-malloc-private.h
0,0 → 1,148
/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
/* Cairo - a vector graphics library with display and print output
*
* Copyright © 2007 Mozilla Corporation
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Mozilla Foundation
*
* Contributor(s):
* Vladimir Vukicevic <vladimir@pobox.com>
*/
 
#ifndef CAIRO_MALLOC_PRIVATE_H
#define CAIRO_MALLOC_PRIVATE_H
 
#include "cairo-wideint-private.h"
 
#if HAVE_MEMFAULT
#include <memfault.h>
#define CAIRO_INJECT_FAULT() MEMFAULT_INJECT_FAULT()
#else
#define CAIRO_INJECT_FAULT() 0
#endif
 
/**
* _cairo_malloc:
* @size: size in bytes
*
* Allocate @size memory using malloc().
* The memory should be freed using free().
* malloc is skipped, if 0 bytes are requested, and %NULL will be returned.
*
* Return value: A pointer to the newly allocated memory, or %NULL in
* case of malloc() failure or size is 0.
*/
 
#define _cairo_malloc(size) \
((size) ? malloc((unsigned) (size)) : NULL)
 
/**
* _cairo_malloc_ab:
* @n: number of elements to allocate
* @size: size of each element
*
* Allocates @n*@size memory using _cairo_malloc(), taking care to not
* overflow when doing the multiplication. Behaves much like
* calloc(), except that the returned memory is not set to zero.
* 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 malloc() failure or overflow.
*/
 
#define _cairo_malloc_ab(a, size) \
((size) && (unsigned) (a) >= INT32_MAX / (unsigned) (size) ? NULL : \
_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:
* @n: first factor of number of elements to allocate
* @b: second factor of number of elements to allocate
* @size: size of each element
*
* Allocates @n*@b*@size memory using _cairo_malloc(), taking care to not
* overflow when doing the multiplication. Behaves like
* _cairo_malloc_ab(). 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 malloc() failure or overflow.
*/
 
#define _cairo_malloc_abc(a, b, size) \
((b) && (unsigned) (a) >= INT32_MAX / (unsigned) (b) ? NULL : \
(size) && (unsigned) ((a)*(b)) >= INT32_MAX / (unsigned) (size) ? NULL : \
_cairo_malloc((unsigned) (a) * (unsigned) (b) * (unsigned) (size)))
 
/**
* _cairo_malloc_ab_plus_c:
* @n: number of elements to allocate
* @size: size of each element
* @k: additional size to allocate
*
* Allocates @n*@ksize+@k memory using _cairo_malloc(), taking care to not
* overflow when doing the arithmetic. Behaves like
* _cairo_malloc_ab(). The memory should be freed using free().
*
* Return value: A pointer to the newly allocated memory, or %NULL in
* case of malloc() failure or overflow.
*/
 
#define _cairo_malloc_ab_plus_c(n, size, k) \
((size) && (unsigned) (n) >= INT32_MAX / (unsigned) (size) ? NULL : \
(unsigned) (k) >= INT32_MAX - (unsigned) (n) * (unsigned) (size) ? NULL : \
_cairo_malloc((unsigned) (n) * (unsigned) (size) + (unsigned) (k)))
 
#endif /* CAIRO_MALLOC_PRIVATE_H */
/programs/develop/libraries/cairo/src/cairo-matrix.c
0,0 → 1,992
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2002 University of Southern California
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
*/
 
#include "cairoint.h"
#include "cairo-error-private.h"
 
#if _XOPEN_SOURCE >= 600 || defined (_ISOC99_SOURCE)
#define ISFINITE(x) isfinite (x)
#else
#define ISFINITE(x) ((x) * (x) >= 0.) /* check for NaNs */
#endif
 
/**
* SECTION:cairo-matrix
* @Title: cairo_matrix_t
* @Short_Description: Generic matrix operations
* @See_Also: #cairo_t
*
* #cairo_matrix_t is used throughout cairo to convert between different
* coordinate spaces. A #cairo_matrix_t holds an affine transformation,
* such as a scale, rotation, shear, or a combination of these.
* The transformation of a point (<literal>x</literal>,<literal>y</literal>)
* is given by:
*
* <programlisting>
* x_new = xx * x + xy * y + x0;
* y_new = yx * x + yy * y + y0;
* </programlisting>
*
* The current transformation matrix of a #cairo_t, represented as a
* #cairo_matrix_t, defines the transformation from user-space
* coordinates to device-space coordinates. See cairo_get_matrix() and
* cairo_set_matrix().
*/
 
static void
_cairo_matrix_scalar_multiply (cairo_matrix_t *matrix, double scalar);
 
static void
_cairo_matrix_compute_adjoint (cairo_matrix_t *matrix);
 
/**
* cairo_matrix_init_identity:
* @matrix: a #cairo_matrix_t
*
* Modifies @matrix to be an identity transformation.
**/
void
cairo_matrix_init_identity (cairo_matrix_t *matrix)
{
cairo_matrix_init (matrix,
1, 0,
0, 1,
0, 0);
}
slim_hidden_def(cairo_matrix_init_identity);
 
/**
* cairo_matrix_init:
* @matrix: a #cairo_matrix_t
* @xx: xx component of the affine transformation
* @yx: yx component of the affine transformation
* @xy: xy component of the affine transformation
* @yy: yy component of the affine transformation
* @x0: X translation component of the affine transformation
* @y0: Y translation component of the affine transformation
*
* Sets @matrix to be the affine transformation given by
* @xx, @yx, @xy, @yy, @x0, @y0. The transformation is given
* by:
* <programlisting>
* x_new = xx * x + xy * y + x0;
* y_new = yx * x + yy * y + y0;
* </programlisting>
**/
void
cairo_matrix_init (cairo_matrix_t *matrix,
double xx, double yx,
 
double xy, double yy,
double x0, double y0)
{
matrix->xx = xx; matrix->yx = yx;
matrix->xy = xy; matrix->yy = yy;
matrix->x0 = x0; matrix->y0 = y0;
}
slim_hidden_def(cairo_matrix_init);
 
/**
* _cairo_matrix_get_affine:
* @matrix: a #cairo_matrix_t
* @xx: location to store xx component of matrix
* @yx: location to store yx component of matrix
* @xy: location to store xy component of matrix
* @yy: location to store yy component of matrix
* @x0: location to store x0 (X-translation component) of matrix, or %NULL
* @y0: location to store y0 (Y-translation component) of matrix, or %NULL
*
* Gets the matrix values for the affine transformation that @matrix represents.
* See cairo_matrix_init().
*
*
* This function is a leftover from the old public API, but is still
* mildly useful as an internal means for getting at the matrix
* members in a positional way. For example, when reassigning to some
* external matrix type, or when renaming members to more meaningful
* names (such as a,b,c,d,e,f) for particular manipulations.
**/
void
_cairo_matrix_get_affine (const cairo_matrix_t *matrix,
double *xx, double *yx,
double *xy, double *yy,
double *x0, double *y0)
{
*xx = matrix->xx;
*yx = matrix->yx;
 
*xy = matrix->xy;
*yy = matrix->yy;
 
if (x0)
*x0 = matrix->x0;
if (y0)
*y0 = matrix->y0;
}
 
/**
* cairo_matrix_init_translate:
* @matrix: a #cairo_matrix_t
* @tx: amount to translate in the X direction
* @ty: amount to translate in the Y direction
*
* Initializes @matrix to a transformation that translates by @tx and
* @ty in the X and Y dimensions, respectively.
**/
void
cairo_matrix_init_translate (cairo_matrix_t *matrix,
double tx, double ty)
{
cairo_matrix_init (matrix,
1, 0,
0, 1,
tx, ty);
}
slim_hidden_def(cairo_matrix_init_translate);
 
/**
* cairo_matrix_translate:
* @matrix: a #cairo_matrix_t
* @tx: amount to translate in the X direction
* @ty: amount to translate in the Y direction
*
* Applies a translation by @tx, @ty to the transformation in
* @matrix. The effect of the new transformation is to first translate
* the coordinates by @tx and @ty, then apply the original transformation
* to the coordinates.
**/
void
cairo_matrix_translate (cairo_matrix_t *matrix, double tx, double ty)
{
cairo_matrix_t tmp;
 
cairo_matrix_init_translate (&tmp, tx, ty);
 
cairo_matrix_multiply (matrix, &tmp, matrix);
}
slim_hidden_def (cairo_matrix_translate);
 
/**
* cairo_matrix_init_scale:
* @matrix: a #cairo_matrix_t
* @sx: scale factor in the X direction
* @sy: scale factor in the Y direction
*
* Initializes @matrix to a transformation that scales by @sx and @sy
* in the X and Y dimensions, respectively.
**/
void
cairo_matrix_init_scale (cairo_matrix_t *matrix,
double sx, double sy)
{
cairo_matrix_init (matrix,
sx, 0,
0, sy,
0, 0);
}
slim_hidden_def(cairo_matrix_init_scale);
 
/**
* cairo_matrix_scale:
* @matrix: a #cairo_matrix_t
* @sx: scale factor in the X direction
* @sy: scale factor in the Y direction
*
* Applies scaling by @sx, @sy to the transformation in @matrix. The
* effect of the new transformation is to first scale the coordinates
* by @sx and @sy, then apply the original transformation to the coordinates.
**/
void
cairo_matrix_scale (cairo_matrix_t *matrix, double sx, double sy)
{
cairo_matrix_t tmp;
 
cairo_matrix_init_scale (&tmp, sx, sy);
 
cairo_matrix_multiply (matrix, &tmp, matrix);
}
slim_hidden_def(cairo_matrix_scale);
 
/**
* cairo_matrix_init_rotate:
* @matrix: a #cairo_matrix_t
* @radians: angle of rotation, in radians. The direction of rotation
* is defined such that positive angles rotate in the direction from
* the positive X axis toward the positive Y axis. With the default
* axis orientation of cairo, positive angles rotate in a clockwise
* direction.
*
* Initialized @matrix to a transformation that rotates by @radians.
**/
void
cairo_matrix_init_rotate (cairo_matrix_t *matrix,
double radians)
{
double s;
double c;
 
s = sin (radians);
c = cos (radians);
 
cairo_matrix_init (matrix,
c, s,
-s, c,
0, 0);
}
slim_hidden_def(cairo_matrix_init_rotate);
 
/**
* cairo_matrix_rotate:
* @matrix: a #cairo_matrix_t
* @radians: angle of rotation, in radians. The direction of rotation
* is defined such that positive angles rotate in the direction from
* the positive X axis toward the positive Y axis. With the default
* axis orientation of cairo, positive angles rotate in a clockwise
* direction.
*
* Applies rotation by @radians to the transformation in
* @matrix. The effect of the new transformation is to first rotate the
* coordinates by @radians, then apply the original transformation
* to the coordinates.
**/
void
cairo_matrix_rotate (cairo_matrix_t *matrix, double radians)
{
cairo_matrix_t tmp;
 
cairo_matrix_init_rotate (&tmp, radians);
 
cairo_matrix_multiply (matrix, &tmp, matrix);
}
 
/**
* cairo_matrix_multiply:
* @result: a #cairo_matrix_t in which to store the result
* @a: a #cairo_matrix_t
* @b: a #cairo_matrix_t
*
* Multiplies the affine transformations in @a and @b together
* and stores the result in @result. The effect of the resulting
* transformation is to first apply the transformation in @a to the
* coordinates and then apply the transformation in @b to the
* coordinates.
*
* It is allowable for @result to be identical to either @a or @b.
**/
/*
* XXX: The ordering of the arguments to this function corresponds
* to [row_vector]*A*B. If we want to use column vectors instead,
* then we need to switch the two arguments and fix up all
* uses.
*/
void
cairo_matrix_multiply (cairo_matrix_t *result, const cairo_matrix_t *a, const cairo_matrix_t *b)
{
cairo_matrix_t r;
 
r.xx = a->xx * b->xx + a->yx * b->xy;
r.yx = a->xx * b->yx + a->yx * b->yy;
 
r.xy = a->xy * b->xx + a->yy * b->xy;
r.yy = a->xy * b->yx + a->yy * b->yy;
 
r.x0 = a->x0 * b->xx + a->y0 * b->xy + b->x0;
r.y0 = a->x0 * b->yx + a->y0 * b->yy + b->y0;
 
*result = r;
}
slim_hidden_def(cairo_matrix_multiply);
 
/**
* cairo_matrix_transform_distance:
* @matrix: a #cairo_matrix_t
* @dx: X component of a distance vector. An in/out parameter
* @dy: Y component of a distance vector. An in/out parameter
*
* Transforms the distance vector (@dx,@dy) by @matrix. This is
* similar to cairo_matrix_transform_point() except that the translation
* components of the transformation are ignored. The calculation of
* the returned vector is as follows:
*
* <programlisting>
* dx2 = dx1 * a + dy1 * c;
* dy2 = dx1 * b + dy1 * d;
* </programlisting>
*
* Affine transformations are position invariant, so the same vector
* always transforms to the same vector. If (@x1,@y1) transforms
* to (@x2,@y2) then (@x1+@dx1,@y1+@dy1) will transform to
* (@x1+@dx2,@y1+@dy2) for all values of @x1 and @x2.
**/
void
cairo_matrix_transform_distance (const cairo_matrix_t *matrix, double *dx, double *dy)
{
double new_x, new_y;
 
new_x = (matrix->xx * *dx + matrix->xy * *dy);
new_y = (matrix->yx * *dx + matrix->yy * *dy);
 
*dx = new_x;
*dy = new_y;
}
slim_hidden_def(cairo_matrix_transform_distance);
 
/**
* cairo_matrix_transform_point:
* @matrix: a #cairo_matrix_t
* @x: X position. An in/out parameter
* @y: Y position. An in/out parameter
*
* Transforms the point (@x, @y) by @matrix.
**/
void
cairo_matrix_transform_point (const cairo_matrix_t *matrix, double *x, double *y)
{
cairo_matrix_transform_distance (matrix, x, y);
 
*x += matrix->x0;
*y += matrix->y0;
}
slim_hidden_def(cairo_matrix_transform_point);
 
void
_cairo_matrix_transform_bounding_box (const cairo_matrix_t *matrix,
double *x1, double *y1,
double *x2, double *y2,
cairo_bool_t *is_tight)
{
int i;
double quad_x[4], quad_y[4];
double min_x, max_x;
double min_y, max_y;
 
if (matrix->xy == 0. && matrix->yx == 0.) {
/* non-rotation/skew matrix, just map the two extreme points */
 
if (matrix->xx != 1.) {
quad_x[0] = *x1 * matrix->xx;
quad_x[1] = *x2 * matrix->xx;
if (quad_x[0] < quad_x[1]) {
*x1 = quad_x[0];
*x2 = quad_x[1];
} else {
*x1 = quad_x[1];
*x2 = quad_x[0];
}
}
if (matrix->x0 != 0.) {
*x1 += matrix->x0;
*x2 += matrix->x0;
}
 
if (matrix->yy != 1.) {
quad_y[0] = *y1 * matrix->yy;
quad_y[1] = *y2 * matrix->yy;
if (quad_y[0] < quad_y[1]) {
*y1 = quad_y[0];
*y2 = quad_y[1];
} else {
*y1 = quad_y[1];
*y2 = quad_y[0];
}
}
if (matrix->y0 != 0.) {
*y1 += matrix->y0;
*y2 += matrix->y0;
}
 
if (is_tight)
*is_tight = TRUE;
 
return;
}
 
/* general matrix */
quad_x[0] = *x1;
quad_y[0] = *y1;
cairo_matrix_transform_point (matrix, &quad_x[0], &quad_y[0]);
 
quad_x[1] = *x2;
quad_y[1] = *y1;
cairo_matrix_transform_point (matrix, &quad_x[1], &quad_y[1]);
 
quad_x[2] = *x1;
quad_y[2] = *y2;
cairo_matrix_transform_point (matrix, &quad_x[2], &quad_y[2]);
 
quad_x[3] = *x2;
quad_y[3] = *y2;
cairo_matrix_transform_point (matrix, &quad_x[3], &quad_y[3]);
 
min_x = max_x = quad_x[0];
min_y = max_y = quad_y[0];
 
for (i=1; i < 4; i++) {
if (quad_x[i] < min_x)
min_x = quad_x[i];
if (quad_x[i] > max_x)
max_x = quad_x[i];
 
if (quad_y[i] < min_y)
min_y = quad_y[i];
if (quad_y[i] > max_y)
max_y = quad_y[i];
}
 
*x1 = min_x;
*y1 = min_y;
*x2 = max_x;
*y2 = max_y;
 
if (is_tight) {
/* it's tight if and only if the four corner points form an axis-aligned
rectangle.
And that's true if and only if we can derive corners 0 and 3 from
corners 1 and 2 in one of two straightforward ways...
We could use a tolerance here but for now we'll fall back to FALSE in the case
of floating point error.
*/
*is_tight =
(quad_x[1] == quad_x[0] && quad_y[1] == quad_y[3] &&
quad_x[2] == quad_x[3] && quad_y[2] == quad_y[0]) ||
(quad_x[1] == quad_x[3] && quad_y[1] == quad_y[0] &&
quad_x[2] == quad_x[0] && quad_y[2] == quad_y[3]);
}
}
 
cairo_private void
_cairo_matrix_transform_bounding_box_fixed (const cairo_matrix_t *matrix,
cairo_box_t *bbox,
cairo_bool_t *is_tight)
{
double x1, y1, x2, y2;
 
_cairo_box_to_doubles (bbox, &x1, &y1, &x2, &y2);
_cairo_matrix_transform_bounding_box (matrix, &x1, &y1, &x2, &y2, is_tight);
_cairo_box_from_doubles (bbox, &x1, &y1, &x2, &y2);
}
 
static void
_cairo_matrix_scalar_multiply (cairo_matrix_t *matrix, double scalar)
{
matrix->xx *= scalar;
matrix->yx *= scalar;
 
matrix->xy *= scalar;
matrix->yy *= scalar;
 
matrix->x0 *= scalar;
matrix->y0 *= scalar;
}
 
/* This function isn't a correct adjoint in that the implicit 1 in the
homogeneous result should actually be ad-bc instead. But, since this
adjoint is only used in the computation of the inverse, which
divides by det (A)=ad-bc anyway, everything works out in the end. */
static void
_cairo_matrix_compute_adjoint (cairo_matrix_t *matrix)
{
/* adj (A) = transpose (C:cofactor (A,i,j)) */
double a, b, c, d, tx, ty;
 
_cairo_matrix_get_affine (matrix,
&a, &b,
&c, &d,
&tx, &ty);
 
cairo_matrix_init (matrix,
d, -b,
-c, a,
c*ty - d*tx, b*tx - a*ty);
}
 
/**
* cairo_matrix_invert:
* @matrix: a #cairo_matrix_t
*
* Changes @matrix to be the inverse of its original value. Not
* all transformation matrices have inverses; if the matrix
* collapses points together (it is <firstterm>degenerate</firstterm>),
* then it has no inverse and this function will fail.
*
* Returns: If @matrix has an inverse, modifies @matrix to
* be the inverse matrix and returns %CAIRO_STATUS_SUCCESS. Otherwise,
* returns %CAIRO_STATUS_INVALID_MATRIX.
**/
cairo_status_t
cairo_matrix_invert (cairo_matrix_t *matrix)
{
double det;
 
/* Simple scaling|translation matrices are quite common... */
if (matrix->xy == 0. && matrix->yx == 0.) {
matrix->x0 = -matrix->x0;
matrix->y0 = -matrix->y0;
 
if (matrix->xx != 1.) {
if (matrix->xx == 0.)
return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
 
matrix->xx = 1. / matrix->xx;
matrix->x0 *= matrix->xx;
}
 
if (matrix->yy != 1.) {
if (matrix->yy == 0.)
return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
 
matrix->yy = 1. / matrix->yy;
matrix->y0 *= matrix->yy;
}
 
return CAIRO_STATUS_SUCCESS;
}
 
/* inv (A) = 1/det (A) * adj (A) */
det = _cairo_matrix_compute_determinant (matrix);
 
if (! ISFINITE (det))
return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
 
if (det == 0)
return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
 
_cairo_matrix_compute_adjoint (matrix);
_cairo_matrix_scalar_multiply (matrix, 1 / det);
 
return CAIRO_STATUS_SUCCESS;
}
slim_hidden_def(cairo_matrix_invert);
 
cairo_bool_t
_cairo_matrix_is_invertible (const cairo_matrix_t *matrix)
{
double det;
 
det = _cairo_matrix_compute_determinant (matrix);
 
return ISFINITE (det) && det != 0.;
}
 
cairo_bool_t
_cairo_matrix_is_scale_0 (const cairo_matrix_t *matrix)
{
return matrix->xx == 0. &&
matrix->xy == 0. &&
matrix->yx == 0. &&
matrix->yy == 0.;
}
 
double
_cairo_matrix_compute_determinant (const cairo_matrix_t *matrix)
{
double a, b, c, d;
 
a = matrix->xx; b = matrix->yx;
c = matrix->xy; d = matrix->yy;
 
return a*d - b*c;
}
 
/**
* _cairo_matrix_compute_basis_scale_factors:
* @matrix: a matrix
* @basis_scale: the scale factor in the direction of basis
* @normal_scale: the scale factor in the direction normal to the basis
* @x_basis: basis to use. X basis if true, Y basis otherwise.
*
* Computes |Mv| and det(M)/|Mv| for v=[1,0] if x_basis is true, and v=[0,1]
* otherwise, and M is @matrix.
*
* Return value: the scale factor of @matrix on the height of the font,
* or 1.0 if @matrix is %NULL.
**/
cairo_status_t
_cairo_matrix_compute_basis_scale_factors (const cairo_matrix_t *matrix,
double *basis_scale, double *normal_scale,
cairo_bool_t x_basis)
{
double det;
 
det = _cairo_matrix_compute_determinant (matrix);
 
if (! ISFINITE (det))
return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
 
if (det == 0)
{
*basis_scale = *normal_scale = 0;
}
else
{
double x = x_basis != 0;
double y = x == 0;
double major, minor;
 
cairo_matrix_transform_distance (matrix, &x, &y);
major = hypot (x, y);
/*
* ignore mirroring
*/
if (det < 0)
det = -det;
if (major)
minor = det / major;
else
minor = 0.0;
if (x_basis)
{
*basis_scale = major;
*normal_scale = minor;
}
else
{
*basis_scale = minor;
*normal_scale = major;
}
}
 
return CAIRO_STATUS_SUCCESS;
}
 
cairo_bool_t
_cairo_matrix_is_identity (const cairo_matrix_t *matrix)
{
return (matrix->xx == 1.0 && matrix->yx == 0.0 &&
matrix->xy == 0.0 && matrix->yy == 1.0 &&
matrix->x0 == 0.0 && matrix->y0 == 0.0);
}
 
cairo_bool_t
_cairo_matrix_is_translation (const cairo_matrix_t *matrix)
{
return (matrix->xx == 1.0 && matrix->yx == 0.0 &&
matrix->xy == 0.0 && matrix->yy == 1.0);
}
 
cairo_bool_t
_cairo_matrix_is_integer_translation (const cairo_matrix_t *matrix,
int *itx, int *ity)
{
if (_cairo_matrix_is_translation (matrix))
{
cairo_fixed_t x0_fixed = _cairo_fixed_from_double (matrix->x0);
cairo_fixed_t y0_fixed = _cairo_fixed_from_double (matrix->y0);
 
if (_cairo_fixed_is_integer (x0_fixed) &&
_cairo_fixed_is_integer (y0_fixed))
{
if (itx)
*itx = _cairo_fixed_integer_part (x0_fixed);
if (ity)
*ity = _cairo_fixed_integer_part (y0_fixed);
 
return TRUE;
}
}
 
return FALSE;
}
 
cairo_bool_t
_cairo_matrix_has_unity_scale (const cairo_matrix_t *matrix)
{
if (matrix->xy == 0.0 && matrix->yx == 0.0) {
if (! (matrix->xx == 1.0 || matrix->xx == -1.0))
return FALSE;
if (! (matrix->yy == 1.0 || matrix->yy == -1.0))
return FALSE;
} else if (matrix->xx == 0.0 && matrix->yy == 0.0) {
if (! (matrix->xy == 1.0 || matrix->xy == -1.0))
return FALSE;
if (! (matrix->yx == 1.0 || matrix->yx == -1.0))
return FALSE;
} else
return FALSE;
 
return TRUE;
}
 
/* By pixel exact here, we mean a matrix that is composed only of
* 90 degree rotations, flips, and integer translations and produces a 1:1
* mapping between source and destination pixels. If we transform an image
* with a pixel-exact matrix, filtering is not useful.
*/
cairo_bool_t
_cairo_matrix_is_pixel_exact (const cairo_matrix_t *matrix)
{
cairo_fixed_t x0_fixed, y0_fixed;
 
if (! _cairo_matrix_has_unity_scale (matrix))
return FALSE;
 
x0_fixed = _cairo_fixed_from_double (matrix->x0);
y0_fixed = _cairo_fixed_from_double (matrix->y0);
 
return _cairo_fixed_is_integer (x0_fixed) && _cairo_fixed_is_integer (y0_fixed);
}
 
/*
A circle in user space is transformed into an ellipse in device space.
 
The following is a derivation of a formula to calculate the length of the
major axis for this ellipse; this is useful for error bounds calculations.
 
Thanks to Walter Brisken <wbrisken@aoc.nrao.edu> for this derivation:
 
1. First some notation:
 
All capital letters represent vectors in two dimensions. A prime '
represents a transformed coordinate. Matrices are written in underlined
form, ie _R_. Lowercase letters represent scalar real values.
 
2. The question has been posed: What is the maximum expansion factor
achieved by the linear transformation
 
X' = X _R_
 
where _R_ is a real-valued 2x2 matrix with entries:
 
_R_ = [a b]
[c d] .
 
In other words, what is the maximum radius, MAX[ |X'| ], reached for any
X on the unit circle ( |X| = 1 ) ?
 
3. Some useful formulae
 
(A) through (C) below are standard double-angle formulae. (D) is a lesser
known result and is derived below:
 
(A) sin²(θ) = (1 - cos(2*θ))/2
(B) cos²(θ) = (1 + cos(2*θ))/2
(C) sin(θ)*cos(θ) = sin(2*θ)/2
(D) MAX[a*cos(θ) + b*sin(θ)] = sqrt(a² + b²)
 
Proof of (D):
 
find the maximum of the function by setting the derivative to zero:
 
-a*sin(θ)+b*cos(θ) = 0
 
From this it follows that
 
tan(θ) = b/a
 
and hence
 
sin(θ) = b/sqrt(a² + b²)
 
and
 
cos(θ) = a/sqrt(a² + b²)
 
Thus the maximum value is
 
MAX[a*cos(θ) + b*sin(θ)] = (a² + b²)/sqrt(a² + b²)
= sqrt(a² + b²)
 
4. Derivation of maximum expansion
 
To find MAX[ |X'| ] we search brute force method using calculus. The unit
circle on which X is constrained is to be parameterized by t:
 
X(θ) = (cos(θ), sin(θ))
 
Thus
 
X'(θ) = X(θ) * _R_ = (cos(θ), sin(θ)) * [a b]
[c d]
= (a*cos(θ) + c*sin(θ), b*cos(θ) + d*sin(θ)).
 
Define
 
r(θ) = |X'(θ)|
 
Thus
 
r²(θ) = (a*cos(θ) + c*sin(θ))² + (b*cos(θ) + d*sin(θ))²
= (a² + b²)*cos²(θ) + (c² + d²)*sin²(θ)
+ 2*(a*c + b*d)*cos(θ)*sin(θ)
 
Now apply the double angle formulae (A) to (C) from above:
 
r²(θ) = (a² + b² + c² + d²)/2
+ (a² + b² - c² - d²)*cos(2*θ)/2
+ (a*c + b*d)*sin(2*θ)
= f + g*cos(φ) + h*sin(φ)
 
Where
 
f = (a² + b² + c² + d²)/2
g = (a² + b² - c² - d²)/2
h = (a*c + d*d)
φ = 2*θ
 
It is clear that MAX[ |X'| ] = sqrt(MAX[ r² ]). Here we determine MAX[ r² ]
using (D) from above:
 
MAX[ r² ] = f + sqrt(g² + h²)
 
And finally
 
MAX[ |X'| ] = sqrt( f + sqrt(g² + h²) )
 
Which is the solution to this problem.
 
Walter Brisken
2004/10/08
 
(Note that the minor axis length is at the minimum of the above solution,
which is just sqrt ( f - sqrt(g² + h²) ) given the symmetry of (D)).
 
 
For another derivation of the same result, using Singular Value Decomposition,
see doc/tutorial/src/singular.c.
*/
 
/* determine the length of the major axis of a circle of the given radius
after applying the transformation matrix. */
double
_cairo_matrix_transformed_circle_major_axis (const cairo_matrix_t *matrix,
double radius)
{
double a, b, c, d, f, g, h, i, j;
 
_cairo_matrix_get_affine (matrix,
&a, &b,
&c, &d,
NULL, NULL);
 
i = a*a + b*b;
j = c*c + d*d;
 
f = 0.5 * (i + j);
g = 0.5 * (i - j);
h = a*c + b*d;
 
return radius * sqrt (f + hypot (g, h));
 
/*
* we don't need the minor axis length, which is
* double min = radius * sqrt (f - sqrt (g*g+h*h));
*/
}
 
void
_cairo_matrix_to_pixman_matrix (const cairo_matrix_t *matrix,
pixman_transform_t *pixman_transform,
double xc,
double yc)
{
static const pixman_transform_t pixman_identity_transform = {{
{1 << 16, 0, 0},
{ 0, 1 << 16, 0},
{ 0, 0, 1 << 16}
}};
 
if (_cairo_matrix_is_identity (matrix)) {
*pixman_transform = pixman_identity_transform;
} else {
cairo_matrix_t inv;
unsigned max_iterations;
 
pixman_transform->matrix[0][0] = _cairo_fixed_16_16_from_double (matrix->xx);
pixman_transform->matrix[0][1] = _cairo_fixed_16_16_from_double (matrix->xy);
pixman_transform->matrix[0][2] = _cairo_fixed_16_16_from_double (matrix->x0);
 
pixman_transform->matrix[1][0] = _cairo_fixed_16_16_from_double (matrix->yx);
pixman_transform->matrix[1][1] = _cairo_fixed_16_16_from_double (matrix->yy);
pixman_transform->matrix[1][2] = _cairo_fixed_16_16_from_double (matrix->y0);
 
pixman_transform->matrix[2][0] = 0;
pixman_transform->matrix[2][1] = 0;
pixman_transform->matrix[2][2] = 1 << 16;
 
/* The conversion above breaks cairo's translation invariance:
* a translation of (a, b) in device space translates to
* a translation of (xx * a + xy * b, yx * a + yy * b)
* for cairo, while pixman uses rounded versions of xx ... yy.
* This error increases as a and b get larger.
*
* To compensate for this, we fix the point (xc, yc) in pattern
* space and adjust pixman's transform to agree with cairo's at
* that point.
*/
 
if (_cairo_matrix_has_unity_scale (matrix))
return;
 
/* Note: If we can't invert the transformation, skip the adjustment. */
inv = *matrix;
if (cairo_matrix_invert (&inv) != CAIRO_STATUS_SUCCESS)
return;
 
/* find the pattern space coordinate that maps to (xc, yc) */
xc += .5; yc += .5; /* offset for the pixel centre */
max_iterations = 5;
do {
double x,y;
pixman_vector_t vector;
cairo_fixed_16_16_t dx, dy;
 
vector.vector[0] = _cairo_fixed_16_16_from_double (xc);
vector.vector[1] = _cairo_fixed_16_16_from_double (yc);
vector.vector[2] = 1 << 16;
 
if (! pixman_transform_point_3d (pixman_transform, &vector))
return;
 
x = pixman_fixed_to_double (vector.vector[0]);
y = pixman_fixed_to_double (vector.vector[1]);
cairo_matrix_transform_point (&inv, &x, &y);
 
/* Ideally, the vector should now be (xc, yc).
* We can now compensate for the resulting error.
*/
x -= xc;
y -= yc;
cairo_matrix_transform_distance (matrix, &x, &y);
dx = _cairo_fixed_16_16_from_double (x);
dy = _cairo_fixed_16_16_from_double (y);
pixman_transform->matrix[0][2] -= dx;
pixman_transform->matrix[1][2] -= dy;
 
if (dx == 0 && dy == 0)
break;
} while (--max_iterations);
}
}
/programs/develop/libraries/cairo/src/cairo-misc.c
0,0 → 1,931
/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2002 University of Southern California
* Copyright © 2005 Red Hat, Inc.
* Copyright © 2007 Adrian Johnson
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
* Adrian Johnson <ajohnson@redneon.com>
*/
 
#include "cairoint.h"
#include "cairo-error-private.h"
 
COMPILE_TIME_ASSERT (CAIRO_STATUS_LAST_STATUS < CAIRO_INT_STATUS_UNSUPPORTED);
COMPILE_TIME_ASSERT (CAIRO_INT_STATUS_LAST_STATUS <= 127);
 
/**
* SECTION:cairo-status
* @Title: Error handling
* @Short_Description: Decoding cairo's status
* @See_Also: cairo_status(), cairo_surface_status(), cairo_pattern_status(),
* cairo_font_face_status(), cairo_scaled_font_status(),
* cairo_region_status()
*
* Cairo uses a single status type to represent all kinds of errors. A status
* value of %CAIRO_STATUS_SUCCESS represents no error and has an integer value
* of zero. All other status values represent an error.
*
* Cairo's error handling is designed to be easy to use and safe. All major
* cairo objects <firstterm>retain</firstterm> an error status internally which
* can be queried anytime by the users using cairo*_status() calls. In
* the mean time, it is safe to call all cairo functions normally even if the
* underlying object is in an error status. This means that no error handling
* code is required before or after each individual cairo function call.
*/
 
/* Public stuff */
 
/**
* cairo_status_to_string:
* @status: a cairo status
*
* Provides a human-readable description of a #cairo_status_t.
*
* Returns: a string representation of the status
*/
const char *
cairo_status_to_string (cairo_status_t status)
{
switch (status) {
case CAIRO_STATUS_SUCCESS:
return "no error has occurred";
case CAIRO_STATUS_NO_MEMORY:
return "out of memory";
case CAIRO_STATUS_INVALID_RESTORE:
return "cairo_restore() without matching cairo_save()";
case CAIRO_STATUS_INVALID_POP_GROUP:
return "no saved group to pop, i.e. cairo_pop_group() without matching cairo_push_group()";
case CAIRO_STATUS_NO_CURRENT_POINT:
return "no current point defined";
case CAIRO_STATUS_INVALID_MATRIX:
return "invalid matrix (not invertible)";
case CAIRO_STATUS_INVALID_STATUS:
return "invalid value for an input cairo_status_t";
case CAIRO_STATUS_NULL_POINTER:
return "NULL pointer";
case CAIRO_STATUS_INVALID_STRING:
return "input string not valid UTF-8";
case CAIRO_STATUS_INVALID_PATH_DATA:
return "input path data not valid";
case CAIRO_STATUS_READ_ERROR:
return "error while reading from input stream";
case CAIRO_STATUS_WRITE_ERROR:
return "error while writing to output stream";
case CAIRO_STATUS_SURFACE_FINISHED:
return "the target surface has been finished";
case CAIRO_STATUS_SURFACE_TYPE_MISMATCH:
return "the surface type is not appropriate for the operation";
case CAIRO_STATUS_PATTERN_TYPE_MISMATCH:
return "the pattern type is not appropriate for the operation";
case CAIRO_STATUS_INVALID_CONTENT:
return "invalid value for an input cairo_content_t";
case CAIRO_STATUS_INVALID_FORMAT:
return "invalid value for an input cairo_format_t";
case CAIRO_STATUS_INVALID_VISUAL:
return "invalid value for an input Visual*";
case CAIRO_STATUS_FILE_NOT_FOUND:
return "file not found";
case CAIRO_STATUS_INVALID_DASH:
return "invalid value for a dash setting";
case CAIRO_STATUS_INVALID_DSC_COMMENT:
return "invalid value for a DSC comment";
case CAIRO_STATUS_INVALID_INDEX:
return "invalid index passed to getter";
case CAIRO_STATUS_CLIP_NOT_REPRESENTABLE:
return "clip region not representable in desired format";
case CAIRO_STATUS_TEMP_FILE_ERROR:
return "error creating or writing to a temporary file";
case CAIRO_STATUS_INVALID_STRIDE:
return "invalid value for stride";
case CAIRO_STATUS_FONT_TYPE_MISMATCH:
return "the font type is not appropriate for the operation";
case CAIRO_STATUS_USER_FONT_IMMUTABLE:
return "the user-font is immutable";
case CAIRO_STATUS_USER_FONT_ERROR:
return "error occurred in a user-font callback function";
case CAIRO_STATUS_NEGATIVE_COUNT:
return "negative number used where it is not allowed";
case CAIRO_STATUS_INVALID_CLUSTERS:
return "input clusters do not represent the accompanying text and glyph arrays";
case CAIRO_STATUS_INVALID_SLANT:
return "invalid value for an input cairo_font_slant_t";
case CAIRO_STATUS_INVALID_WEIGHT:
return "invalid value for an input cairo_font_weight_t";
case CAIRO_STATUS_INVALID_SIZE:
return "invalid value (typically too big) for the size of the input (surface, pattern, etc.)";
case CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED:
return "user-font method not implemented";
case CAIRO_STATUS_DEVICE_TYPE_MISMATCH:
return "the device type is not appropriate for the operation";
case CAIRO_STATUS_DEVICE_ERROR:
return "an operation to the device caused an unspecified error";
default:
case CAIRO_STATUS_LAST_STATUS:
return "<unknown error status>";
}
}
 
 
/**
* cairo_glyph_allocate:
* @num_glyphs: number of glyphs to allocate
*
* Allocates an array of #cairo_glyph_t's.
* This function is only useful in implementations of
* #cairo_user_scaled_font_text_to_glyphs_func_t where the user
* needs to allocate an array of glyphs that cairo will free.
* For all other uses, user can use their own allocation method
* for glyphs.
*
* This function returns %NULL if @num_glyphs is not positive,
* or if out of memory. That means, the %NULL return value
* signals out-of-memory only if @num_glyphs was positive.
*
* Returns: the newly allocated array of glyphs that should be
* freed using cairo_glyph_free()
*
* Since: 1.8
*/
cairo_glyph_t *
cairo_glyph_allocate (int num_glyphs)
{
if (num_glyphs <= 0)
return NULL;
 
return _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t));
}
slim_hidden_def (cairo_glyph_allocate);
 
/**
* cairo_glyph_free:
* @glyphs: array of glyphs to free, or %NULL
*
* Frees an array of #cairo_glyph_t's allocated using cairo_glyph_allocate().
* This function is only useful to free glyph array returned
* by cairo_scaled_font_text_to_glyphs() where cairo returns
* an array of glyphs that the user will free.
* For all other uses, user can use their own allocation method
* for glyphs.
*
* Since: 1.8
*/
void
cairo_glyph_free (cairo_glyph_t *glyphs)
{
if (glyphs)
free (glyphs);
}
slim_hidden_def (cairo_glyph_free);
 
/**
* cairo_text_cluster_allocate:
* @num_clusters: number of text_clusters to allocate
*
* Allocates an array of #cairo_text_cluster_t's.
* This function is only useful in implementations of
* #cairo_user_scaled_font_text_to_glyphs_func_t where the user
* needs to allocate an array of text clusters that cairo will free.
* For all other uses, user can use their own allocation method
* for text clusters.
*
* This function returns %NULL if @num_clusters is not positive,
* or if out of memory. That means, the %NULL return value
* signals out-of-memory only if @num_clusters was positive.
*
* Returns: the newly allocated array of text clusters that should be
* freed using cairo_text_cluster_free()
*
* Since: 1.8
*/
cairo_text_cluster_t *
cairo_text_cluster_allocate (int num_clusters)
{
if (num_clusters <= 0)
return NULL;
 
return _cairo_malloc_ab (num_clusters, sizeof (cairo_text_cluster_t));
}
slim_hidden_def (cairo_text_cluster_allocate);
 
/**
* cairo_text_cluster_free:
* @clusters: array of text clusters to free, or %NULL
*
* Frees an array of #cairo_text_cluster's allocated using cairo_text_cluster_allocate().
* This function is only useful to free text cluster array returned
* by cairo_scaled_font_text_to_glyphs() where cairo returns
* an array of text clusters that the user will free.
* For all other uses, user can use their own allocation method
* for text clusters.
*
* Since: 1.8
*/
void
cairo_text_cluster_free (cairo_text_cluster_t *clusters)
{
if (clusters)
free (clusters);
}
slim_hidden_def (cairo_text_cluster_free);
 
 
/* Private stuff */
 
/**
* _cairo_validate_text_clusters:
* @utf8: UTF-8 text
* @utf8_len: length of @utf8 in bytes
* @glyphs: array of glyphs
* @num_glyphs: number of glyphs
* @clusters: array of cluster mapping information
* @num_clusters: number of clusters in the mapping
* @cluster_flags: cluster flags
*
* Check that clusters cover the entire glyphs and utf8 arrays,
* and that cluster boundaries are UTF-8 boundaries.
*
* Return value: %CAIRO_STATUS_SUCCESS upon success, or
* %CAIRO_STATUS_INVALID_CLUSTERS on error.
* The error is either invalid UTF-8 input,
* or bad cluster mapping.
*/
cairo_status_t
_cairo_validate_text_clusters (const char *utf8,
int utf8_len,
const cairo_glyph_t *glyphs,
int num_glyphs,
const cairo_text_cluster_t *clusters,
int num_clusters,
cairo_text_cluster_flags_t cluster_flags)
{
cairo_status_t status;
unsigned int n_bytes = 0;
unsigned int n_glyphs = 0;
int i;
 
for (i = 0; i < num_clusters; i++) {
int cluster_bytes = clusters[i].num_bytes;
int cluster_glyphs = clusters[i].num_glyphs;
 
if (cluster_bytes < 0 || cluster_glyphs < 0)
goto BAD;
 
/* A cluster should cover at least one character or glyph.
* I can't see any use for a 0,0 cluster.
* I can't see an immediate use for a zero-text cluster
* right now either, but they don't harm.
* Zero-glyph clusters on the other hand are useful for
* things like U+200C ZERO WIDTH NON-JOINER */
if (cluster_bytes == 0 && cluster_glyphs == 0)
goto BAD;
 
/* Since n_bytes and n_glyphs are unsigned, but the rest of
* values involved are signed, we can detect overflow easily */
if (n_bytes+cluster_bytes > (unsigned int)utf8_len || n_glyphs+cluster_glyphs > (unsigned int)num_glyphs)
goto BAD;
 
/* Make sure we've got valid UTF-8 for the cluster */
status = _cairo_utf8_to_ucs4 (utf8+n_bytes, cluster_bytes, NULL, NULL);
if (unlikely (status))
return _cairo_error (CAIRO_STATUS_INVALID_CLUSTERS);
 
n_bytes += cluster_bytes ;
n_glyphs += cluster_glyphs;
}
 
if (n_bytes != (unsigned int) utf8_len || n_glyphs != (unsigned int) num_glyphs) {
BAD:
return _cairo_error (CAIRO_STATUS_INVALID_CLUSTERS);
}
 
return CAIRO_STATUS_SUCCESS;
}
 
/**
* _cairo_operator_bounded_by_mask:
* @op: a #cairo_operator_t
*
* A bounded operator is one where mask pixel
* of zero results in no effect on the destination image.
*
* Unbounded operators often require special handling; if you, for
* example, draw trapezoids with an unbounded operator, the effect
* extends past the bounding box of the trapezoids.
*
* Return value: %TRUE if the operator is bounded by the mask operand
**/
cairo_bool_t
_cairo_operator_bounded_by_mask (cairo_operator_t op)
{
switch (op) {
case CAIRO_OPERATOR_CLEAR:
case CAIRO_OPERATOR_SOURCE:
case CAIRO_OPERATOR_OVER:
case CAIRO_OPERATOR_ATOP:
case CAIRO_OPERATOR_DEST:
case CAIRO_OPERATOR_DEST_OVER:
case CAIRO_OPERATOR_DEST_OUT:
case CAIRO_OPERATOR_XOR:
case CAIRO_OPERATOR_ADD:
case CAIRO_OPERATOR_SATURATE:
case CAIRO_OPERATOR_MULTIPLY:
case CAIRO_OPERATOR_SCREEN:
case CAIRO_OPERATOR_OVERLAY:
case CAIRO_OPERATOR_DARKEN:
case CAIRO_OPERATOR_LIGHTEN:
case CAIRO_OPERATOR_COLOR_DODGE:
case CAIRO_OPERATOR_COLOR_BURN:
case CAIRO_OPERATOR_HARD_LIGHT:
case CAIRO_OPERATOR_SOFT_LIGHT:
case CAIRO_OPERATOR_DIFFERENCE:
case CAIRO_OPERATOR_EXCLUSION:
case CAIRO_OPERATOR_HSL_HUE:
case CAIRO_OPERATOR_HSL_SATURATION:
case CAIRO_OPERATOR_HSL_COLOR:
case CAIRO_OPERATOR_HSL_LUMINOSITY:
return TRUE;
case CAIRO_OPERATOR_OUT:
case CAIRO_OPERATOR_IN:
case CAIRO_OPERATOR_DEST_IN:
case CAIRO_OPERATOR_DEST_ATOP:
return FALSE;
}
 
ASSERT_NOT_REACHED;
return FALSE;
}
 
/**
* _cairo_operator_bounded_by_source:
* @op: a #cairo_operator_t
*
* A bounded operator is one where source pixels of zero
* (in all four components, r, g, b and a) effect no change
* in the resulting destination image.
*
* Unbounded operators often require special handling; if you, for
* example, copy a surface with the SOURCE operator, the effect
* extends past the bounding box of the source surface.
*
* Return value: %TRUE if the operator is bounded by the source operand
**/
cairo_bool_t
_cairo_operator_bounded_by_source (cairo_operator_t op)
{
switch (op) {
case CAIRO_OPERATOR_OVER:
case CAIRO_OPERATOR_ATOP:
case CAIRO_OPERATOR_DEST:
case CAIRO_OPERATOR_DEST_OVER:
case CAIRO_OPERATOR_DEST_OUT:
case CAIRO_OPERATOR_XOR:
case CAIRO_OPERATOR_ADD:
case CAIRO_OPERATOR_SATURATE:
case CAIRO_OPERATOR_MULTIPLY:
case CAIRO_OPERATOR_SCREEN:
case CAIRO_OPERATOR_OVERLAY:
case CAIRO_OPERATOR_DARKEN:
case CAIRO_OPERATOR_LIGHTEN:
case CAIRO_OPERATOR_COLOR_DODGE:
case CAIRO_OPERATOR_COLOR_BURN:
case CAIRO_OPERATOR_HARD_LIGHT:
case CAIRO_OPERATOR_SOFT_LIGHT:
case CAIRO_OPERATOR_DIFFERENCE:
case CAIRO_OPERATOR_EXCLUSION:
case CAIRO_OPERATOR_HSL_HUE:
case CAIRO_OPERATOR_HSL_SATURATION:
case CAIRO_OPERATOR_HSL_COLOR:
case CAIRO_OPERATOR_HSL_LUMINOSITY:
return TRUE;
case CAIRO_OPERATOR_CLEAR:
case CAIRO_OPERATOR_SOURCE:
case CAIRO_OPERATOR_OUT:
case CAIRO_OPERATOR_IN:
case CAIRO_OPERATOR_DEST_IN:
case CAIRO_OPERATOR_DEST_ATOP:
return FALSE;
}
 
ASSERT_NOT_REACHED;
return FALSE;
}
 
uint32_t
_cairo_operator_bounded_by_either (cairo_operator_t op)
{
switch (op) {
default:
ASSERT_NOT_REACHED;
case CAIRO_OPERATOR_OVER:
case CAIRO_OPERATOR_ATOP:
case CAIRO_OPERATOR_DEST:
case CAIRO_OPERATOR_DEST_OVER:
case CAIRO_OPERATOR_DEST_OUT:
case CAIRO_OPERATOR_XOR:
case CAIRO_OPERATOR_ADD:
case CAIRO_OPERATOR_SATURATE:
case CAIRO_OPERATOR_MULTIPLY:
case CAIRO_OPERATOR_SCREEN:
case CAIRO_OPERATOR_OVERLAY:
case CAIRO_OPERATOR_DARKEN:
case CAIRO_OPERATOR_LIGHTEN:
case CAIRO_OPERATOR_COLOR_DODGE:
case CAIRO_OPERATOR_COLOR_BURN:
case CAIRO_OPERATOR_HARD_LIGHT:
case CAIRO_OPERATOR_SOFT_LIGHT:
case CAIRO_OPERATOR_DIFFERENCE:
case CAIRO_OPERATOR_EXCLUSION:
case CAIRO_OPERATOR_HSL_HUE:
case CAIRO_OPERATOR_HSL_SATURATION:
case CAIRO_OPERATOR_HSL_COLOR:
case CAIRO_OPERATOR_HSL_LUMINOSITY:
return CAIRO_OPERATOR_BOUND_BY_MASK | CAIRO_OPERATOR_BOUND_BY_SOURCE;
case CAIRO_OPERATOR_CLEAR:
case CAIRO_OPERATOR_SOURCE:
return CAIRO_OPERATOR_BOUND_BY_MASK;
case CAIRO_OPERATOR_OUT:
case CAIRO_OPERATOR_IN:
case CAIRO_OPERATOR_DEST_IN:
case CAIRO_OPERATOR_DEST_ATOP:
return 0;
}
 
}
 
#if DISABLE_SOME_FLOATING_POINT
/* This function is identical to the C99 function lround(), except that it
* performs arithmetic rounding (floor(d + .5) instead of away-from-zero rounding) and
* has a valid input range of (INT_MIN, INT_MAX] instead of
* [INT_MIN, INT_MAX]. It is much faster on both x86 and FPU-less systems
* than other commonly used methods for rounding (lround, round, rint, lrint
* or float (d + 0.5)).
*
* The reason why this function is much faster on x86 than other
* methods is due to the fact that it avoids the fldcw instruction.
* This instruction incurs a large performance penalty on modern Intel
* processors due to how it prevents efficient instruction pipelining.
*
* The reason why this function is much faster on FPU-less systems is for
* an entirely different reason. All common rounding methods involve multiple
* floating-point operations. Each one of these operations has to be
* emulated in software, which adds up to be a large performance penalty.
* This function doesn't perform any floating-point calculations, and thus
* avoids this penalty.
*/
int
_cairo_lround (double d)
{
uint32_t top, shift_amount, output;
union {
double d;
uint64_t ui64;
uint32_t ui32[2];
} u;
 
u.d = d;
 
/* If the integer word order doesn't match the float word order, we swap
* the words of the input double. This is needed because we will be
* treating the whole double as a 64-bit unsigned integer. Notice that we
* use WORDS_BIGENDIAN to detect the integer word order, which isn't
* exactly correct because WORDS_BIGENDIAN refers to byte order, not word
* order. Thus, we are making the assumption that the byte order is the
* same as the integer word order which, on the modern machines that we
* care about, is OK.
*/
#if ( defined(FLOAT_WORDS_BIGENDIAN) && !defined(WORDS_BIGENDIAN)) || \
(!defined(FLOAT_WORDS_BIGENDIAN) && defined(WORDS_BIGENDIAN))
{
uint32_t temp = u.ui32[0];
u.ui32[0] = u.ui32[1];
u.ui32[1] = temp;
}
#endif
 
#ifdef WORDS_BIGENDIAN
#define MSW (0) /* Most Significant Word */
#define LSW (1) /* Least Significant Word */
#else
#define MSW (1)
#define LSW (0)
#endif
 
/* By shifting the most significant word of the input double to the
* right 20 places, we get the very "top" of the double where the exponent
* and sign bit lie.
*/
top = u.ui32[MSW] >> 20;
 
/* Here, we calculate how much we have to shift the mantissa to normalize
* it to an integer value. We extract the exponent "top" by masking out the
* sign bit, then we calculate the shift amount by subtracting the exponent
* from the bias. Notice that the correct bias for 64-bit doubles is
* actually 1075, but we use 1053 instead for two reasons:
*
* 1) To perform rounding later on, we will first need the target
* value in a 31.1 fixed-point format. Thus, the bias needs to be one
* less: (1075 - 1: 1074).
*
* 2) To avoid shifting the mantissa as a full 64-bit integer (which is
* costly on certain architectures), we break the shift into two parts.
* First, the upper and lower parts of the mantissa are shifted
* individually by a constant amount that all valid inputs will require
* at the very least. This amount is chosen to be 21, because this will
* allow the two parts of the mantissa to later be combined into a
* single 32-bit representation, on which the remainder of the shift
* will be performed. Thus, we decrease the bias by an additional 21:
* (1074 - 21: 1053).
*/
shift_amount = 1053 - (top & 0x7FF);
 
/* We are done with the exponent portion in "top", so here we shift it off
* the end.
*/
top >>= 11;
 
/* Before we perform any operations on the mantissa, we need to OR in
* the implicit 1 at the top (see the IEEE-754 spec). We needn't mask
* off the sign bit nor the exponent bits because these higher bits won't
* make a bit of difference in the rest of our calculations.
*/
u.ui32[MSW] |= 0x100000;
 
/* If the input double is negative, we have to decrease the mantissa
* by a hair. This is an important part of performing arithmetic rounding,
* as negative numbers must round towards positive infinity in the
* halfwase case of -x.5. Since "top" contains only the sign bit at this
* point, we can just decrease the mantissa by the value of "top".
*/
u.ui64 -= top;
 
/* By decrementing "top", we create a bitmask with a value of either
* 0x0 (if the input was negative) or 0xFFFFFFFF (if the input was positive
* and thus the unsigned subtraction underflowed) that we'll use later.
*/
top--;
 
/* Here, we shift the mantissa by the constant value as described above.
* We can emulate a 64-bit shift right by 21 through shifting the top 32
* bits left 11 places and ORing in the bottom 32 bits shifted 21 places
* to the right. Both parts of the mantissa are now packed into a single
* 32-bit integer. Although we severely truncate the lower part in the
* process, we still have enough significant bits to perform the conversion
* without error (for all valid inputs).
*/
output = (u.ui32[MSW] << 11) | (u.ui32[LSW] >> 21);
 
/* Next, we perform the shift that converts the X.Y fixed-point number
* currently found in "output" to the desired 31.1 fixed-point format
* needed for the following rounding step. It is important to consider
* all possible values for "shift_amount" at this point:
*
* - {shift_amount < 0} Since shift_amount is an unsigned integer, it
* really can't have a value less than zero. But, if the shift_amount
* calculation above caused underflow (which would happen with
* input > INT_MAX or input <= INT_MIN) then shift_amount will now be
* a very large number, and so this shift will result in complete
* garbage. But that's OK, as the input was out of our range, so our
* output is undefined.
*
* - {shift_amount > 31} If the magnitude of the input was very small
* (i.e. |input| << 1.0), shift_amount will have a value greater than
* 31. Thus, this shift will also result in garbage. After performing
* the shift, we will zero-out "output" if this is the case.
*
* - {0 <= shift_amount < 32} In this case, the shift will properly convert
* the mantissa into a 31.1 fixed-point number.
*/
output >>= shift_amount;
 
/* This is where we perform rounding with the 31.1 fixed-point number.
* Since what we're after is arithmetic rounding, we simply add the single
* fractional bit into the integer part of "output", and just keep the
* integer part.
*/
output = (output >> 1) + (output & 1);
 
/* Here, we zero-out the result if the magnitude if the input was very small
* (as explained in the section above). Notice that all input out of the
* valid range is also caught by this condition, which means we produce 0
* for all invalid input, which is a nice side effect.
*
* The most straightforward way to do this would be:
*
* if (shift_amount > 31)
* output = 0;
*
* But we can use a little trick to avoid the potential branch. The
* expression (shift_amount > 31) will be either 1 or 0, which when
* decremented will be either 0x0 or 0xFFFFFFFF (unsigned underflow),
* which can be used to conditionally mask away all the bits in "output"
* (in the 0x0 case), effectively zeroing it out. Certain, compilers would
* have done this for us automatically.
*/
output &= ((shift_amount > 31) - 1);
 
/* If the input double was a negative number, then we have to negate our
* output. The most straightforward way to do this would be:
*
* if (!top)
* output = -output;
*
* as "top" at this point is either 0x0 (if the input was negative) or
* 0xFFFFFFFF (if the input was positive). But, we can use a trick to
* avoid the branch. Observe that the following snippet of code has the
* same effect as the reference snippet above:
*
* if (!top)
* output = 0 - output;
* else
* output = output - 0;
*
* Armed with the bitmask found in "top", we can condense the two statements
* into the following:
*
* output = (output & top) - (output & ~top);
*
* where, in the case that the input double was negative, "top" will be 0,
* and the statement will be equivalent to:
*
* output = (0) - (output);
*
* and if the input double was positive, "top" will be 0xFFFFFFFF, and the
* statement will be equivalent to:
*
* output = (output) - (0);
*
* Which, as pointed out earlier, is equivalent to the original reference
* snippet.
*/
output = (output & top) - (output & ~top);
 
return output;
#undef MSW
#undef LSW
}
#endif
 
/* Convert a 32-bit IEEE single precision floating point number to a
* 'half' representation (s10.5)
*/
uint16_t
_cairo_half_from_float (float f)
{
union {
uint32_t ui;
float f;
} u;
int s, e, m;
 
u.f = f;
s = (u.ui >> 16) & 0x00008000;
e = ((u.ui >> 23) & 0x000000ff) - (127 - 15);
m = u.ui & 0x007fffff;
if (e <= 0) {
if (e < -10) {
/* underflow */
return 0;
}
 
m = (m | 0x00800000) >> (1 - e);
 
/* round to nearest, round 0.5 up. */
if (m & 0x00001000)
m += 0x00002000;
return s | (m >> 13);
} else if (e == 0xff - (127 - 15)) {
if (m == 0) {
/* infinity */
return s | 0x7c00;
} else {
/* nan */
m >>= 13;
return s | 0x7c00 | m | (m == 0);
}
} else {
/* round to nearest, round 0.5 up. */
if (m & 0x00001000) {
m += 0x00002000;
 
if (m & 0x00800000) {
m = 0;
e += 1;
}
}
 
if (e > 30) {
/* overflow -> infinity */
return s | 0x7c00;
}
 
return s | (e << 10) | (m >> 13);
}
}
 
 
#ifdef _WIN32
 
#define WIN32_LEAN_AND_MEAN
/* We require Windows 2000 features such as ETO_PDY */
#if !defined(WINVER) || (WINVER < 0x0500)
# define WINVER 0x0500
#endif
#if !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0500)
# define _WIN32_WINNT 0x0500
#endif
 
#include <windows.h>
#include <io.h>
 
#if !_WIN32_WCE
/* tmpfile() replacement for Windows.
*
* On Windows tmpfile() creates the file in the root directory. This
* may fail due to unsufficient privileges. However, this isn't a
* problem on Windows CE so we don't use it there.
*/
FILE *
_cairo_win32_tmpfile (void)
{
DWORD path_len;
WCHAR path_name[MAX_PATH + 1];
WCHAR file_name[MAX_PATH + 1];
HANDLE handle;
int fd;
FILE *fp;
 
path_len = GetTempPathW (MAX_PATH, path_name);
if (path_len <= 0 || path_len >= MAX_PATH)
return NULL;
 
if (GetTempFileNameW (path_name, L"ps_", 0, file_name) == 0)
return NULL;
 
handle = CreateFileW (file_name,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE,
NULL);
if (handle == INVALID_HANDLE_VALUE) {
DeleteFileW (file_name);
return NULL;
}
 
fd = _open_osfhandle((intptr_t) handle, 0);
if (fd < 0) {
CloseHandle (handle);
return NULL;
}
 
fp = fdopen(fd, "w+b");
if (fp == NULL) {
_close(fd);
return NULL;
}
 
return fp;
}
#endif /* !_WIN32_WCE */
 
#endif /* _WIN32 */
 
typedef struct _cairo_intern_string {
cairo_hash_entry_t hash_entry;
int len;
char *string;
} cairo_intern_string_t;
 
static cairo_hash_table_t *_cairo_intern_string_ht;
 
static unsigned long
_intern_string_hash (const char *str, int len)
{
const signed char *p = (const signed char *) str;
unsigned int h = *p;
 
for (p += 1; --len; p++)
h = (h << 5) - h + *p;
 
return h;
}
 
static cairo_bool_t
_intern_string_equal (const void *_a, const void *_b)
{
const cairo_intern_string_t *a = _a;
const cairo_intern_string_t *b = _b;
 
if (a->len != b->len)
return FALSE;
 
return memcmp (a->string, b->string, a->len) == 0;
}
 
cairo_status_t
_cairo_intern_string (const char **str_inout, int len)
{
char *str = (char *) *str_inout;
cairo_intern_string_t tmpl, *istring;
cairo_status_t status = CAIRO_STATUS_SUCCESS;
 
if (CAIRO_INJECT_FAULT ())
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
if (len < 0)
len = strlen (str);
tmpl.hash_entry.hash = _intern_string_hash (str, len);
tmpl.len = len;
tmpl.string = (char *) str;
 
CAIRO_MUTEX_LOCK (_cairo_intern_string_mutex);
if (_cairo_intern_string_ht == NULL) {
_cairo_intern_string_ht = _cairo_hash_table_create (_intern_string_equal);
if (unlikely (_cairo_intern_string_ht == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto BAIL;
}
}
 
istring = _cairo_hash_table_lookup (_cairo_intern_string_ht,
&tmpl.hash_entry);
if (istring == NULL) {
istring = malloc (sizeof (cairo_intern_string_t) + len + 1);
if (likely (istring != NULL)) {
istring->hash_entry.hash = tmpl.hash_entry.hash;
istring->len = tmpl.len;
istring->string = (char *) (istring + 1);
memcpy (istring->string, str, len);
istring->string[len] = '\0';
 
status = _cairo_hash_table_insert (_cairo_intern_string_ht,
&istring->hash_entry);
if (unlikely (status)) {
free (istring);
goto BAIL;
}
} else {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto BAIL;
}
}
 
*str_inout = istring->string;
 
BAIL:
CAIRO_MUTEX_UNLOCK (_cairo_intern_string_mutex);
return status;
}
 
static void
_intern_string_pluck (void *entry, void *closure)
{
_cairo_hash_table_remove (closure, entry);
free (entry);
}
 
void
_cairo_intern_string_reset_static_data (void)
{
CAIRO_MUTEX_LOCK (_cairo_intern_string_mutex);
if (_cairo_intern_string_ht != NULL) {
_cairo_hash_table_foreach (_cairo_intern_string_ht,
_intern_string_pluck,
_cairo_intern_string_ht);
_cairo_hash_table_destroy(_cairo_intern_string_ht);
_cairo_intern_string_ht = NULL;
}
CAIRO_MUTEX_UNLOCK (_cairo_intern_string_mutex);
}
/programs/develop/libraries/cairo/src/cairo-mutex-impl-private.h
0,0 → 1,278
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2002 University of Southern California
* Copyright © 2005,2007 Red Hat, Inc.
* Copyright © 2007 Mathias Hasselmann
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
* Mathias Hasselmann <mathias.hasselmann@gmx.de>
* Behdad Esfahbod <behdad@behdad.org>
*/
 
#ifndef CAIRO_MUTEX_IMPL_PRIVATE_H
#define CAIRO_MUTEX_IMPL_PRIVATE_H
 
#include "cairo.h"
 
#if HAVE_CONFIG_H
#include "config.h"
#endif
 
#if HAVE_LOCKDEP
#include <lockdep.h>
#endif
 
/* A fully qualified no-operation statement */
#define CAIRO_MUTEX_IMPL_NOOP do {/*no-op*/} while (0)
/* And one that evaluates its argument once */
#define CAIRO_MUTEX_IMPL_NOOP1(expr) do { (void)(expr); } while (0)
/* Note: 'if (expr) {}' is an alternative to '(void)(expr);' that will 'use' the
* result of __attribute__((warn_used_result)) functions. */
 
/* Cairo mutex implementation:
*
* Any new mutex implementation needs to do the following:
*
* - Condition on the right header or feature. Headers are
* preferred as eg. you still can use win32 mutex implementation
* on a win32 system even if you do not compile the win32
* surface/backend.
*
* - typedef #cairo_mutex_impl_t to the proper mutex type on your target
* system. Note that you may or may not need to use a pointer,
* depending on what kinds of initialization your mutex
* implementation supports. No trailing semicolon needed.
* You should be able to compile the following snippet (don't try
* running it):
*
* <programlisting>
* cairo_mutex_impl_t _cairo_some_mutex;
* </programlisting>
*
* - #define %CAIRO_MUTEX_IMPL_<NAME> 1 with suitable name for your platform. You
* can later use this symbol in cairo-system.c.
*
* - #define CAIRO_MUTEX_IMPL_LOCK(mutex) and CAIRO_MUTEX_IMPL_UNLOCK(mutex) to
* proper statement to lock/unlock the mutex object passed in.
* You can (and should) assume that the mutex is already
* initialized, and is-not-already-locked/is-locked,
* respectively. Use the "do { ... } while (0)" idiom if necessary.
* No trailing semicolons are needed (in any macro you define here).
* You should be able to compile the following snippet:
*
* <programlisting>
* cairo_mutex_impl_t _cairo_some_mutex;
*
* if (1)
* CAIRO_MUTEX_IMPL_LOCK (_cairo_some_mutex);
* else
* CAIRO_MUTEX_IMPL_UNLOCK (_cairo_some_mutex);
* </programlisting>
*
* - #define %CAIRO_MUTEX_IMPL_NIL_INITIALIZER to something that can
* initialize the #cairo_mutex_impl_t type you defined. Most of the
* time one of 0, %NULL, or {} works. At this point
* you should be able to compile the following snippet:
*
* <programlisting>
* cairo_mutex_impl_t _cairo_some_mutex = CAIRO_MUTEX_IMPL_NIL_INITIALIZER;
*
* if (1)
* CAIRO_MUTEX_IMPL_LOCK (_cairo_some_mutex);
* else
* CAIRO_MUTEX_IMPL_UNLOCK (_cairo_some_mutex);
* </programlisting>
*
* - If the above code is not enough to initialize a mutex on
* your platform, #define CAIRO_MUTEX_IMPL_INIT(mutex) to statement
* to initialize the mutex (allocate resources, etc). Such that
* you should be able to compile AND RUN the following snippet:
*
* <programlisting>
* cairo_mutex_impl_t _cairo_some_mutex = CAIRO_MUTEX_IMPL_NIL_INITIALIZER;
*
* CAIRO_MUTEX_IMPL_INIT (_cairo_some_mutex);
*
* if (1)
* CAIRO_MUTEX_IMPL_LOCK (_cairo_some_mutex);
* else
* CAIRO_MUTEX_IMPL_UNLOCK (_cairo_some_mutex);
* </programlisting>
*
* - If you define CAIRO_MUTEX_IMPL_INIT(mutex), cairo will use it to
* initialize all static mutex'es. If for any reason that should
* not happen (eg. %CAIRO_MUTEX_IMPL_INIT is just a faster way than
* what cairo does using %CAIRO_MUTEX_IMPL_NIL_INITIALIZER), then
* <programlisting>
* #define CAIRO_MUTEX_IMPL_INITIALIZE() CAIRO_MUTEX_IMPL_NOOP
* </programlisting>
*
* - If your system supports freeing a mutex object (deallocating
* resources, etc), then #define CAIRO_MUTEX_IMPL_FINI(mutex) to do
* that.
*
* - If you define CAIRO_MUTEX_IMPL_FINI(mutex), cairo will use it to
* define a finalizer function to finalize all static mutex'es.
* However, it's up to you to call CAIRO_MUTEX_IMPL_FINALIZE() at
* proper places, eg. when the system is unloading the cairo library.
* So, if for any reason finalizing static mutex'es is not needed
* (eg. you never call CAIRO_MUTEX_IMPL_FINALIZE()), then
* <programlisting>
* #define CAIRO_MUTEX_IMPL_FINALIZE() CAIRO_MUTEX_IMPL_NOOP
* </programlisting>
*
* - That is all. If for any reason you think the above API is
* not enough to implement #cairo_mutex_impl_t on your system, please
* stop and write to the cairo mailing list about it. DO NOT
* poke around cairo-mutex-private.h for possible solutions.
*/
 
#if CAIRO_NO_MUTEX
 
/* No mutexes */
 
typedef int cairo_mutex_impl_t;
 
# define CAIRO_MUTEX_IMPL_NO 1
# define CAIRO_MUTEX_IMPL_INITIALIZE() CAIRO_MUTEX_IMPL_NOOP
# define CAIRO_MUTEX_IMPL_LOCK(mutex) CAIRO_MUTEX_IMPL_NOOP1(mutex)
# define CAIRO_MUTEX_IMPL_UNLOCK(mutex) CAIRO_MUTEX_IMPL_NOOP1(mutex)
# define CAIRO_MUTEX_IMPL_NIL_INITIALIZER 0
 
# define CAIRO_MUTEX_HAS_RECURSIVE_IMPL 1
 
typedef int cairo_recursive_mutex_impl_t;
 
# define CAIRO_RECURSIVE_MUTEX_IMPL_INIT(mutex)
# define CAIRO_RECURSIVE_MUTEX_IMPL_NIL_INITIALIZER 0
 
#elif defined(_WIN32) /******************************************************/
 
#define WIN32_LEAN_AND_MEAN
/* We require Windows 2000 features such as ETO_PDY */
#if !defined(WINVER) || (WINVER < 0x0500)
# define WINVER 0x0500
#endif
#if !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0500)
# define _WIN32_WINNT 0x0500
#endif
 
# include <windows.h>
 
typedef CRITICAL_SECTION cairo_mutex_impl_t;
 
# define CAIRO_MUTEX_IMPL_WIN32 1
# define CAIRO_MUTEX_IMPL_LOCK(mutex) EnterCriticalSection (&(mutex))
# define CAIRO_MUTEX_IMPL_UNLOCK(mutex) LeaveCriticalSection (&(mutex))
# define CAIRO_MUTEX_IMPL_INIT(mutex) InitializeCriticalSection (&(mutex))
# define CAIRO_MUTEX_IMPL_FINI(mutex) DeleteCriticalSection (&(mutex))
# define CAIRO_MUTEX_IMPL_NIL_INITIALIZER { NULL, 0, 0, NULL, NULL, 0 }
 
#elif defined __OS2__ /******************************************************/
 
# define INCL_BASE
# define INCL_PM
# include <os2.h>
 
typedef HMTX cairo_mutex_impl_t;
 
# define CAIRO_MUTEX_IMPL_OS2 1
# define CAIRO_MUTEX_IMPL_LOCK(mutex) DosRequestMutexSem(mutex, SEM_INDEFINITE_WAIT)
# define CAIRO_MUTEX_IMPL_UNLOCK(mutex) DosReleaseMutexSem(mutex)
# define CAIRO_MUTEX_IMPL_INIT(mutex) DosCreateMutexSem (NULL, &(mutex), 0L, FALSE)
# define CAIRO_MUTEX_IMPL_FINI(mutex) DosCloseMutexSem (mutex)
# define CAIRO_MUTEX_IMPL_NIL_INITIALIZER 0
 
#elif CAIRO_HAS_BEOS_SURFACE /***********************************************/
 
typedef BLocker* cairo_mutex_impl_t;
 
# define CAIRO_MUTEX_IMPL_BEOS 1
# define CAIRO_MUTEX_IMPL_LOCK(mutex) (mutex)->Lock()
# define CAIRO_MUTEX_IMPL_UNLOCK(mutex) (mutex)->Unlock()
# define CAIRO_MUTEX_IMPL_INIT(mutex) (mutex) = new BLocker()
# define CAIRO_MUTEX_IMPL_FINI(mutex) delete (mutex)
# define CAIRO_MUTEX_IMPL_NIL_INITIALIZER NULL
 
#elif CAIRO_HAS_PTHREAD /* and finally if there are no native mutexes ********/
 
# include <pthread.h>
 
typedef pthread_mutex_t cairo_mutex_impl_t;
typedef pthread_mutex_t cairo_recursive_mutex_impl_t;
 
# define CAIRO_MUTEX_IMPL_PTHREAD 1
#if HAVE_LOCKDEP
/* expose all mutexes to the validator */
# define CAIRO_MUTEX_IMPL_INIT(mutex) pthread_mutex_init (&(mutex), NULL)
#endif
# define CAIRO_MUTEX_IMPL_LOCK(mutex) pthread_mutex_lock (&(mutex))
# define CAIRO_MUTEX_IMPL_UNLOCK(mutex) pthread_mutex_unlock (&(mutex))
#if HAVE_LOCKDEP
# define CAIRO_MUTEX_IS_LOCKED(mutex) LOCKDEP_IS_LOCKED (&(mutex))
# define CAIRO_MUTEX_IS_UNLOCKED(mutex) LOCKDEP_IS_UNLOCKED (&(mutex))
#endif
# define CAIRO_MUTEX_IMPL_FINI(mutex) pthread_mutex_destroy (&(mutex))
#if ! HAVE_LOCKDEP
# define CAIRO_MUTEX_IMPL_FINALIZE() CAIRO_MUTEX_IMPL_NOOP
#endif
# define CAIRO_MUTEX_IMPL_NIL_INITIALIZER PTHREAD_MUTEX_INITIALIZER
 
# define CAIRO_MUTEX_HAS_RECURSIVE_IMPL 1
# define CAIRO_RECURSIVE_MUTEX_IMPL_INIT(mutex) do { \
pthread_mutexattr_t attr; \
pthread_mutexattr_init (&attr); \
pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_RECURSIVE); \
pthread_mutex_init (&(mutex), &attr); \
pthread_mutexattr_destroy (&attr); \
} while (0)
# define CAIRO_RECURSIVE_MUTEX_IMPL_NIL_INITIALIZER PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
 
#else /**********************************************************************/
 
# error "XXX: No mutex implementation found. Cairo will not work with multiple threads. Define CAIRO_NO_MUTEX to 1 to acknowledge and accept this limitation and compile cairo without thread-safety support."
 
#endif
 
/* By default mutex implementations are assumed to be recursive */
#if ! CAIRO_MUTEX_HAS_RECURSIVE_IMPL
 
# define CAIRO_MUTEX_HAS_RECURSIVE_IMPL 1
 
typedef cairo_mutex_impl_t cairo_recursive_mutex_impl_t;
 
# define CAIRO_RECURSIVE_MUTEX_IMPL_INIT(mutex) CAIRO_MUTEX_IMPL_INIT(mutex)
# define CAIRO_RECURSIVE_MUTEX_IMPL_NIL_INITIALIZER CAIRO_MUTEX_IMPL_NIL_INITIALIZER
 
#endif
 
#endif
/programs/develop/libraries/cairo/src/cairo-mutex-list-private.h
0,0 → 1,74
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2007 Mathias Hasselmann
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* Contributor(s):
* Mathias Hasselmann <mathias.hasselmann@gmx.de>
*/
 
#ifndef CAIRO_FEATURES_H
/* This block is to just make this header file standalone */
#define CAIRO_MUTEX_DECLARE(mutex)
#endif
 
CAIRO_MUTEX_DECLARE (_cairo_pattern_solid_surface_cache_lock)
 
CAIRO_MUTEX_DECLARE (_cairo_image_solid_cache_mutex)
 
CAIRO_MUTEX_DECLARE (_cairo_error_mutex)
CAIRO_MUTEX_DECLARE (_cairo_toy_font_face_mutex)
CAIRO_MUTEX_DECLARE (_cairo_intern_string_mutex)
CAIRO_MUTEX_DECLARE (_cairo_scaled_font_map_mutex)
CAIRO_MUTEX_DECLARE (_cairo_scaled_glyph_page_cache_mutex)
CAIRO_MUTEX_DECLARE (_cairo_scaled_font_error_mutex)
 
#if CAIRO_HAS_FT_FONT
CAIRO_MUTEX_DECLARE (_cairo_ft_unscaled_font_map_mutex)
#endif
 
#if CAIRO_HAS_XLIB_SURFACE
CAIRO_MUTEX_DECLARE (_cairo_xlib_display_mutex)
#endif
 
#if CAIRO_HAS_XCB_SURFACE
CAIRO_MUTEX_DECLARE (_cairo_xcb_connections_mutex)
#endif
 
#if CAIRO_HAS_GL_SURFACE
CAIRO_MUTEX_DECLARE (_cairo_gl_context_mutex)
#endif
 
#if !defined (HAS_ATOMIC_OPS) || defined (ATOMIC_OP_NEEDS_MEMORY_BARRIER)
CAIRO_MUTEX_DECLARE (_cairo_atomic_mutex)
#endif
 
#if CAIRO_HAS_DRM_SURFACE
CAIRO_MUTEX_DECLARE (_cairo_drm_device_mutex)
#endif
/* Undefine, to err on unintended inclusion */
#undef CAIRO_MUTEX_DECLARE
/programs/develop/libraries/cairo/src/cairo-mutex-private.h
0,0 → 1,67
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2002 University of Southern California
* Copyright © 2005,2007 Red Hat, Inc.
* Copyright © 2007 Mathias Hasselmann
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
* Mathias Hasselmann <mathias.hasselmann@gmx.de>
* Behdad Esfahbod <behdad@behdad.org>
*/
 
#ifndef CAIRO_MUTEX_PRIVATE_H
#define CAIRO_MUTEX_PRIVATE_H
 
#include "cairo-mutex-type-private.h"
 
CAIRO_BEGIN_DECLS
 
#if _CAIRO_MUTEX_IMPL_USE_STATIC_INITIALIZER
cairo_private void _cairo_mutex_initialize (void);
#endif
#if _CAIRO_MUTEX_IMPL_USE_STATIC_FINALIZER
cairo_private void _cairo_mutex_finalize (void);
#endif
/* only if using static initializer and/or finalizer define the boolean */
#if _CAIRO_MUTEX_IMPL_USE_STATIC_INITIALIZER || _CAIRO_MUTEX_IMPL_USE_STATIC_FINALIZER
cairo_private extern cairo_bool_t _cairo_mutex_initialized;
#endif
 
/* Finally, extern the static mutexes and undef */
 
#define CAIRO_MUTEX_DECLARE(mutex) cairo_private extern cairo_mutex_t mutex;
#include "cairo-mutex-list-private.h"
#undef CAIRO_MUTEX_DECLARE
 
CAIRO_END_DECLS
 
#endif
/programs/develop/libraries/cairo/src/cairo-mutex-type-private.h
0,0 → 1,194
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2002 University of Southern California
* Copyright © 2005,2007 Red Hat, Inc.
* Copyright © 2007 Mathias Hasselmann
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
* Mathias Hasselmann <mathias.hasselmann@gmx.de>
* Behdad Esfahbod <behdad@behdad.org>
*/
 
#ifndef CAIRO_MUTEX_TYPE_PRIVATE_H
#define CAIRO_MUTEX_TYPE_PRIVATE_H
 
#include "cairo-compiler-private.h"
#include "cairo-mutex-impl-private.h"
 
/* Only the following four are mandatory at this point */
#ifndef CAIRO_MUTEX_IMPL_LOCK
# error "CAIRO_MUTEX_IMPL_LOCK not defined. Check cairo-mutex-impl-private.h."
#endif
#ifndef CAIRO_MUTEX_IMPL_UNLOCK
# error "CAIRO_MUTEX_IMPL_UNLOCK not defined. Check cairo-mutex-impl-private.h."
#endif
#ifndef CAIRO_MUTEX_IMPL_NIL_INITIALIZER
# error "CAIRO_MUTEX_IMPL_NIL_INITIALIZER not defined. Check cairo-mutex-impl-private.h."
#endif
#ifndef CAIRO_RECURSIVE_MUTEX_IMPL_INIT
# error "CAIRO_RECURSIVE_MUTEX_IMPL_INIT not defined. Check cairo-mutex-impl-private.h."
#endif
 
 
/* make sure implementations don't fool us: we decide these ourself */
#undef _CAIRO_MUTEX_IMPL_USE_STATIC_INITIALIZER
#undef _CAIRO_MUTEX_IMPL_USE_STATIC_FINALIZER
 
 
#ifdef CAIRO_MUTEX_IMPL_INIT
 
/* If %CAIRO_MUTEX_IMPL_INIT is defined, we may need to initialize all
* static mutex'es. */
# ifndef CAIRO_MUTEX_IMPL_INITIALIZE
# define CAIRO_MUTEX_IMPL_INITIALIZE() do { \
if (!_cairo_mutex_initialized) \
_cairo_mutex_initialize (); \
} while(0)
 
/* and make sure we implement the above */
# define _CAIRO_MUTEX_IMPL_USE_STATIC_INITIALIZER 1
# endif /* CAIRO_MUTEX_IMPL_INITIALIZE */
 
#else /* no CAIRO_MUTEX_IMPL_INIT */
 
/* Otherwise we probably don't need to initialize static mutex'es, */
# ifndef CAIRO_MUTEX_IMPL_INITIALIZE
# define CAIRO_MUTEX_IMPL_INITIALIZE() CAIRO_MUTEX_IMPL_NOOP
# endif /* CAIRO_MUTEX_IMPL_INITIALIZE */
 
/* and dynamic ones can be initialized using the static initializer. */
# define CAIRO_MUTEX_IMPL_INIT(mutex) do { \
cairo_mutex_t _tmp_mutex = CAIRO_MUTEX_IMPL_NIL_INITIALIZER; \
memcpy (&(mutex), &_tmp_mutex, sizeof (_tmp_mutex)); \
} while (0)
 
#endif /* CAIRO_MUTEX_IMPL_INIT */
 
#ifdef CAIRO_MUTEX_IMPL_FINI
 
/* If %CAIRO_MUTEX_IMPL_FINI is defined, we may need to finalize all
* static mutex'es. */
# ifndef CAIRO_MUTEX_IMPL_FINALIZE
# define CAIRO_MUTEX_IMPL_FINALIZE() do { \
if (_cairo_mutex_initialized) \
_cairo_mutex_finalize (); \
} while(0)
 
/* and make sure we implement the above */
# define _CAIRO_MUTEX_IMPL_USE_STATIC_FINALIZER 1
# endif /* CAIRO_MUTEX_IMPL_FINALIZE */
 
#else /* no CAIRO_MUTEX_IMPL_FINI */
 
/* Otherwise we probably don't need to finalize static mutex'es, */
# ifndef CAIRO_MUTEX_IMPL_FINALIZE
# define CAIRO_MUTEX_IMPL_FINALIZE() CAIRO_MUTEX_IMPL_NOOP
# endif /* CAIRO_MUTEX_IMPL_FINALIZE */
 
/* neither do the dynamic ones. */
# define CAIRO_MUTEX_IMPL_FINI(mutex) CAIRO_MUTEX_IMPL_NOOP1(mutex)
 
#endif /* CAIRO_MUTEX_IMPL_FINI */
 
 
#ifndef _CAIRO_MUTEX_IMPL_USE_STATIC_INITIALIZER
#define _CAIRO_MUTEX_IMPL_USE_STATIC_INITIALIZER 0
#endif
#ifndef _CAIRO_MUTEX_IMPL_USE_STATIC_FINALIZER
#define _CAIRO_MUTEX_IMPL_USE_STATIC_FINALIZER 0
#endif
 
 
/* Make sure everything we want is defined */
#ifndef CAIRO_MUTEX_IMPL_INITIALIZE
# error "CAIRO_MUTEX_IMPL_INITIALIZE not defined"
#endif
#ifndef CAIRO_MUTEX_IMPL_FINALIZE
# error "CAIRO_MUTEX_IMPL_FINALIZE not defined"
#endif
#ifndef CAIRO_MUTEX_IMPL_LOCK
# error "CAIRO_MUTEX_IMPL_LOCK not defined"
#endif
#ifndef CAIRO_MUTEX_IMPL_UNLOCK
# error "CAIRO_MUTEX_IMPL_UNLOCK not defined"
#endif
#ifndef CAIRO_MUTEX_IMPL_INIT
# error "CAIRO_MUTEX_IMPL_INIT not defined"
#endif
#ifndef CAIRO_MUTEX_IMPL_FINI
# error "CAIRO_MUTEX_IMPL_FINI not defined"
#endif
#ifndef CAIRO_MUTEX_IMPL_NIL_INITIALIZER
# error "CAIRO_MUTEX_IMPL_NIL_INITIALIZER not defined"
#endif
 
 
/* Public interface. */
 
/* By default it simply uses the implementation provided.
* But we can provide for debugging features by overriding them */
 
#ifndef CAIRO_MUTEX_DEBUG
typedef cairo_mutex_impl_t cairo_mutex_t;
typedef cairo_recursive_mutex_impl_t cairo_recursive_mutex_t;
#else
# define cairo_mutex_t cairo_mutex_impl_t
#endif
 
#define CAIRO_MUTEX_INITIALIZE CAIRO_MUTEX_IMPL_INITIALIZE
#define CAIRO_MUTEX_FINALIZE CAIRO_MUTEX_IMPL_FINALIZE
#define CAIRO_MUTEX_LOCK CAIRO_MUTEX_IMPL_LOCK
#define CAIRO_MUTEX_UNLOCK CAIRO_MUTEX_IMPL_UNLOCK
#define CAIRO_MUTEX_INIT CAIRO_MUTEX_IMPL_INIT
#define CAIRO_MUTEX_FINI CAIRO_MUTEX_IMPL_FINI
#define CAIRO_MUTEX_NIL_INITIALIZER CAIRO_MUTEX_IMPL_NIL_INITIALIZER
 
#define CAIRO_RECURSIVE_MUTEX_INIT CAIRO_RECURSIVE_MUTEX_IMPL_INIT
#define CAIRO_RECURSIVE_MUTEX_NIL_INITIALIZER CAIRO_RECURSIVE_MUTEX_IMPL_NIL_INITIALIZER
 
#ifndef CAIRO_MUTEX_IS_LOCKED
# define CAIRO_MUTEX_IS_LOCKED(name) 1
#endif
#ifndef CAIRO_MUTEX_IS_UNLOCKED
# define CAIRO_MUTEX_IS_UNLOCKED(name) 1
#endif
 
 
/* Debugging support */
 
#ifdef CAIRO_MUTEX_DEBUG
 
/* TODO add mutex debugging facilities here (eg deadlock detection) */
 
#endif /* CAIRO_MUTEX_DEBUG */
 
#endif
/programs/develop/libraries/cairo/src/cairo-mutex.c
0,0 → 1,82
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2007 Mathias Hasselmann
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* Contributor(s):
* Mathias Hasselmann <mathias.hasselmann@gmx.de>
*/
 
#include "cairoint.h"
 
#include "cairo-mutex-private.h"
 
#define CAIRO_MUTEX_DECLARE(mutex) cairo_mutex_t mutex = CAIRO_MUTEX_NIL_INITIALIZER;
#include "cairo-mutex-list-private.h"
#undef CAIRO_MUTEX_DECLARE
 
#if _CAIRO_MUTEX_IMPL_USE_STATIC_INITIALIZER || _CAIRO_MUTEX_IMPL_USE_STATIC_FINALIZER
 
# if _CAIRO_MUTEX_IMPL_USE_STATIC_INITIALIZER
# define _CAIRO_MUTEX_IMPL_INITIALIZED_DEFAULT_VALUE FALSE
# else
# define _CAIRO_MUTEX_IMPL_INITIALIZED_DEFAULT_VALUE TRUE
# endif
 
cairo_bool_t _cairo_mutex_initialized = _CAIRO_MUTEX_IMPL_INITIALIZED_DEFAULT_VALUE;
 
# undef _CAIRO_MUTEX_IMPL_INITIALIZED_DEFAULT_VALUE
 
#endif
 
#if _CAIRO_MUTEX_IMPL_USE_STATIC_INITIALIZER
void _cairo_mutex_initialize (void)
{
if (_cairo_mutex_initialized)
return;
 
_cairo_mutex_initialized = TRUE;
 
#define CAIRO_MUTEX_DECLARE(mutex) CAIRO_MUTEX_INIT (mutex);
#include "cairo-mutex-list-private.h"
#undef CAIRO_MUTEX_DECLARE
}
#endif
 
#if _CAIRO_MUTEX_IMPL_USE_STATIC_FINALIZER
void _cairo_mutex_finalize (void)
{
if (!_cairo_mutex_initialized)
return;
 
_cairo_mutex_initialized = FALSE;
 
#define CAIRO_MUTEX_DECLARE(mutex) CAIRO_MUTEX_FINI (mutex);
#include "cairo-mutex-list-private.h"
#undef CAIRO_MUTEX_DECLARE
}
#endif
/programs/develop/libraries/cairo/src/cairo-observer.c
0,0 → 1,50
/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2010 Intel Corporation
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Intel Corporation
*
* Contributor(s):
* Chris Wilson <chris@chris-wilson.co.uk>
*/
 
#include "cairoint.h"
 
void
_cairo_observers_notify (cairo_list_t *observers, void *arg)
{
cairo_observer_t *obs, *next;
 
cairo_list_foreach_entry_safe (obs, next,
cairo_observer_t,
observers, link)
{
obs->callback (obs, arg);
}
}
/programs/develop/libraries/cairo/src/cairo-os2-private.h
0,0 → 1,67
/* vim: set sw=4 sts=4 et cin: */
/* cairo - a vector graphics library with display and print output
*
* Copyright (c) 2005-2006 netlabs.org
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is
* Doodle <doodle@scenergy.dfmk.hu>
*
* Contributor(s):
* Peter Weilbacher <mozilla@Weilbacher.org>
*/
 
#ifndef CAIRO_OS2_PRIVATE_H
#define CAIRO_OS2_PRIVATE_H
 
#include "cairo-os2.h"
#include "cairoint.h"
 
typedef struct _cairo_os2_surface
{
cairo_surface_t base;
 
/* Mutex semaphore to protect private fields from concurrent access */
HMTX hmtx_use_private_fields;
/* Private fields: */
HPS hps_client_window;
HWND hwnd_client_window;
BITMAPINFO2 bitmap_info;
unsigned char *pixels;
cairo_image_surface_t *image_surface;
int pixel_array_lend_count;
HEV hev_pixel_array_came_back;
 
RECTL rcl_dirty_area;
cairo_bool_t dirty_area_present;
 
/* General flags: */
cairo_bool_t blit_as_changes;
cairo_bool_t use_24bpp;
} cairo_os2_surface_t;
 
#endif /* CAIRO_OS2_PRIVATE_H */
/programs/develop/libraries/cairo/src/cairo-os2.h
0,0 → 1,110
/* vim: set sw=4 sts=4 et cin: */
/* cairo - a vector graphics library with display and print output
*
* Copyright (c) 2005-2006 netlabs.org
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is
* Doodle <doodle@scenergy.dfmk.hu>
*
* Contributor(s):
* Peter Weilbacher <mozilla@Weilbacher.org>
* Rich Walsh <dragtext@e-vertise.com>
*/
 
#ifndef _CAIRO_OS2_H_
#define _CAIRO_OS2_H_
 
#define INCL_DOS
#define INCL_DOSSEMAPHORES
#define INCL_DOSERRORS
#define INCL_WIN
#define INCL_GPI
 
#include "cairo.h"
 
#include <os2.h>
 
CAIRO_BEGIN_DECLS
 
/* The OS/2 Specific Cairo API */
 
cairo_public void
cairo_os2_init (void);
 
cairo_public void
cairo_os2_fini (void);
 
#if CAIRO_HAS_OS2_SURFACE
 
cairo_public cairo_surface_t *
cairo_os2_surface_create (HPS hps_client_window,
int width,
int height);
 
cairo_public cairo_surface_t *
cairo_os2_surface_create_for_window (HWND hwnd_client_window,
int width,
int height);
 
cairo_public void
cairo_os2_surface_set_hwnd (cairo_surface_t *surface,
HWND hwnd_client_window);
 
cairo_public int
cairo_os2_surface_set_size (cairo_surface_t *surface,
int new_width,
int new_height,
int timeout);
 
cairo_public void
cairo_os2_surface_refresh_window (cairo_surface_t *surface,
HPS hps_begin_paint,
PRECTL prcl_begin_paint_rect);
 
cairo_public void
cairo_os2_surface_set_manual_window_refresh (cairo_surface_t *surface,
cairo_bool_t manual_refresh);
 
cairo_public cairo_bool_t
cairo_os2_surface_get_manual_window_refresh (cairo_surface_t *surface);
 
cairo_public cairo_status_t
cairo_os2_surface_get_hps (cairo_surface_t *surface,
HPS *hps);
 
cairo_public cairo_status_t
cairo_os2_surface_set_hps (cairo_surface_t *surface,
HPS hps);
 
#else /* CAIRO_HAS_OS2_SURFACE */
# error Cairo was not compiled with support for the OS/2 backend
#endif /* CAIRO_HAS_OS2_SURFACE */
 
CAIRO_END_DECLS
 
#endif /* _CAIRO_OS2_H_ */
/programs/develop/libraries/cairo/src/cairo-output-stream-private.h
0,0 → 1,196
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2006 Red Hat, Inc
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Author(s):
* Kristian Høgsberg <krh@redhat.com>
*/
 
#ifndef CAIRO_OUTPUT_STREAM_PRIVATE_H
#define CAIRO_OUTPUT_STREAM_PRIVATE_H
 
#include "cairo-compiler-private.h"
#include "cairo-types-private.h"
 
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
 
typedef cairo_status_t
(*cairo_output_stream_write_func_t) (cairo_output_stream_t *output_stream,
const unsigned char *data,
unsigned int length);
 
typedef cairo_status_t
(*cairo_output_stream_flush_func_t) (cairo_output_stream_t *output_stream);
 
typedef cairo_status_t
(*cairo_output_stream_close_func_t) (cairo_output_stream_t *output_stream);
 
struct _cairo_output_stream {
cairo_output_stream_write_func_t write_func;
cairo_output_stream_flush_func_t flush_func;
cairo_output_stream_close_func_t close_func;
unsigned long position;
cairo_status_t status;
cairo_bool_t closed;
};
 
extern const cairo_private cairo_output_stream_t _cairo_output_stream_nil;
 
cairo_private void
_cairo_output_stream_init (cairo_output_stream_t *stream,
cairo_output_stream_write_func_t write_func,
cairo_output_stream_flush_func_t flush_func,
cairo_output_stream_close_func_t close_func);
 
cairo_private cairo_status_t
_cairo_output_stream_fini (cairo_output_stream_t *stream);
 
 
/* We already have the following declared in cairo.h:
 
typedef cairo_status_t (*cairo_write_func_t) (void *closure,
const unsigned char *data,
unsigned int length);
*/
typedef cairo_status_t (*cairo_close_func_t) (void *closure);
 
 
/* This function never returns %NULL. If an error occurs (NO_MEMORY)
* while trying to create the output stream this function returns a
* valid pointer to a nil output stream.
*
* Note that even with a nil surface, the close_func callback will be
* called by a call to _cairo_output_stream_close or
* _cairo_output_stream_destroy.
*/
cairo_private cairo_output_stream_t *
_cairo_output_stream_create (cairo_write_func_t write_func,
cairo_close_func_t close_func,
void *closure);
 
cairo_private cairo_output_stream_t *
_cairo_output_stream_create_in_error (cairo_status_t status);
 
/* Tries to flush any buffer maintained by the stream or its delegates. */
cairo_private cairo_status_t
_cairo_output_stream_flush (cairo_output_stream_t *stream);
 
/* Returns the final status value associated with this object, just
* before its last gasp. This final status value will capture any
* status failure returned by the stream's close_func as well. */
cairo_private cairo_status_t
_cairo_output_stream_close (cairo_output_stream_t *stream);
 
/* Returns the final status value associated with this object, just
* before its last gasp. This final status value will capture any
* status failure returned by the stream's close_func as well. */
cairo_private cairo_status_t
_cairo_output_stream_destroy (cairo_output_stream_t *stream);
 
cairo_private void
_cairo_output_stream_write (cairo_output_stream_t *stream,
const void *data, size_t length);
 
cairo_private void
_cairo_output_stream_write_hex_string (cairo_output_stream_t *stream,
const unsigned char *data,
size_t length);
 
cairo_private void
_cairo_output_stream_vprintf (cairo_output_stream_t *stream,
const char *fmt,
va_list ap) CAIRO_PRINTF_FORMAT ( 2, 0);
 
cairo_private void
_cairo_output_stream_printf (cairo_output_stream_t *stream,
const char *fmt,
...) CAIRO_PRINTF_FORMAT (2, 3);
 
cairo_private long
_cairo_output_stream_get_position (cairo_output_stream_t *stream);
 
cairo_private cairo_status_t
_cairo_output_stream_get_status (cairo_output_stream_t *stream);
 
/* This function never returns %NULL. If an error occurs (NO_MEMORY or
* WRITE_ERROR) while trying to create the output stream this function
* returns a valid pointer to a nil output stream.
*
* Note: Even if a nil surface is returned, the caller should still
* call _cairo_output_stream_destroy (or _cairo_output_stream_close at
* least) in order to ensure that everything is properly cleaned up.
*/
cairo_private cairo_output_stream_t *
_cairo_output_stream_create_for_filename (const char *filename);
 
/* This function never returns %NULL. If an error occurs (NO_MEMORY or
* WRITE_ERROR) while trying to create the output stream this function
* returns a valid pointer to a nil output stream.
*
* The caller still "owns" file and is responsible for calling fclose
* on it when finished. The stream will not do this itself.
*/
cairo_private cairo_output_stream_t *
_cairo_output_stream_create_for_file (FILE *file);
 
cairo_private cairo_output_stream_t *
_cairo_memory_stream_create (void);
 
cairo_private void
_cairo_memory_stream_copy (cairo_output_stream_t *base,
cairo_output_stream_t *dest);
 
cairo_private int
_cairo_memory_stream_length (cairo_output_stream_t *stream);
 
cairo_private cairo_status_t
_cairo_memory_stream_destroy (cairo_output_stream_t *abstract_stream,
unsigned char **data_out,
unsigned long *length_out);
 
cairo_private cairo_output_stream_t *
_cairo_null_stream_create (void);
 
/* cairo-base85-stream.c */
cairo_private cairo_output_stream_t *
_cairo_base85_stream_create (cairo_output_stream_t *output);
 
/* cairo-base64-stream.c */
cairo_private cairo_output_stream_t *
_cairo_base64_stream_create (cairo_output_stream_t *output);
 
/* cairo-deflate-stream.c */
cairo_private cairo_output_stream_t *
_cairo_deflate_stream_create (cairo_output_stream_t *output);
 
 
#endif /* CAIRO_OUTPUT_STREAM_PRIVATE_H */
/programs/develop/libraries/cairo/src/cairo-output-stream.c
0,0 → 1,764
/* cairo-output-stream.c: Output stream abstraction
*
* Copyright © 2005 Red Hat, Inc
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Author(s):
* Kristian Høgsberg <krh@redhat.com>
*/
 
#define _BSD_SOURCE /* for snprintf() */
#include "cairoint.h"
 
#include "cairo-output-stream-private.h"
#include "cairo-error-private.h"
#include "cairo-compiler-private.h"
 
#include <stdio.h>
#include <locale.h>
#include <errno.h>
 
/* Numbers printed with %f are printed with this number of significant
* digits after the decimal.
*/
#define SIGNIFICANT_DIGITS_AFTER_DECIMAL 6
 
/* Numbers printed with %g are assumed to only have %CAIRO_FIXED_FRAC_BITS
* bits of precision available after the decimal point.
*
* FIXED_POINT_DECIMAL_DIGITS specifies the minimum number of decimal
* digits after the decimal point required to preserve the available
* precision.
*
* The conversion is:
*
* <programlisting>
* FIXED_POINT_DECIMAL_DIGITS = ceil( CAIRO_FIXED_FRAC_BITS * ln(2)/ln(10) )
* </programlisting>
*
* We can replace ceil(x) with (int)(x+1) since x will never be an
* integer for any likely value of %CAIRO_FIXED_FRAC_BITS.
*/
#define FIXED_POINT_DECIMAL_DIGITS ((int)(CAIRO_FIXED_FRAC_BITS*0.301029996 + 1))
 
void
_cairo_output_stream_init (cairo_output_stream_t *stream,
cairo_output_stream_write_func_t write_func,
cairo_output_stream_flush_func_t flush_func,
cairo_output_stream_close_func_t close_func)
{
stream->write_func = write_func;
stream->flush_func = flush_func;
stream->close_func = close_func;
stream->position = 0;
stream->status = CAIRO_STATUS_SUCCESS;
stream->closed = FALSE;
}
 
cairo_status_t
_cairo_output_stream_fini (cairo_output_stream_t *stream)
{
return _cairo_output_stream_close (stream);
}
 
const cairo_output_stream_t _cairo_output_stream_nil = {
NULL, /* write_func */
NULL, /* flush_func */
NULL, /* close_func */
0, /* position */
CAIRO_STATUS_NO_MEMORY,
FALSE /* closed */
};
 
static const cairo_output_stream_t _cairo_output_stream_nil_write_error = {
NULL, /* write_func */
NULL, /* flush_func */
NULL, /* close_func */
0, /* position */
CAIRO_STATUS_WRITE_ERROR,
FALSE /* closed */
};
 
typedef struct _cairo_output_stream_with_closure {
cairo_output_stream_t base;
cairo_write_func_t write_func;
cairo_close_func_t close_func;
void *closure;
} cairo_output_stream_with_closure_t;
 
 
static cairo_status_t
closure_write (cairo_output_stream_t *stream,
const unsigned char *data, unsigned int length)
{
cairo_output_stream_with_closure_t *stream_with_closure =
(cairo_output_stream_with_closure_t *) stream;
 
if (stream_with_closure->write_func == NULL)
return CAIRO_STATUS_SUCCESS;
 
return stream_with_closure->write_func (stream_with_closure->closure,
data, length);
}
 
static cairo_status_t
closure_close (cairo_output_stream_t *stream)
{
cairo_output_stream_with_closure_t *stream_with_closure =
(cairo_output_stream_with_closure_t *) stream;
 
if (stream_with_closure->close_func != NULL)
return stream_with_closure->close_func (stream_with_closure->closure);
else
return CAIRO_STATUS_SUCCESS;
}
 
cairo_output_stream_t *
_cairo_output_stream_create (cairo_write_func_t write_func,
cairo_close_func_t close_func,
void *closure)
{
cairo_output_stream_with_closure_t *stream;
 
stream = malloc (sizeof (cairo_output_stream_with_closure_t));
if (unlikely (stream == NULL)) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_output_stream_t *) &_cairo_output_stream_nil;
}
 
_cairo_output_stream_init (&stream->base,
closure_write, NULL, closure_close);
stream->write_func = write_func;
stream->close_func = close_func;
stream->closure = closure;
 
return &stream->base;
}
 
cairo_output_stream_t *
_cairo_output_stream_create_in_error (cairo_status_t status)
{
cairo_output_stream_t *stream;
 
/* check for the common ones */
if (status == CAIRO_STATUS_NO_MEMORY)
return (cairo_output_stream_t *) &_cairo_output_stream_nil;
if (status == CAIRO_STATUS_WRITE_ERROR)
return (cairo_output_stream_t *) &_cairo_output_stream_nil_write_error;
 
stream = malloc (sizeof (cairo_output_stream_t));
if (unlikely (stream == NULL)) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_output_stream_t *) &_cairo_output_stream_nil;
}
 
_cairo_output_stream_init (stream, NULL, NULL, NULL);
stream->status = status;
 
return stream;
}
 
cairo_status_t
_cairo_output_stream_flush (cairo_output_stream_t *stream)
{
cairo_status_t status;
 
if (stream->closed)
return stream->status;
 
if (stream == &_cairo_output_stream_nil ||
stream == &_cairo_output_stream_nil_write_error)
{
return stream->status;
}
 
if (stream->flush_func) {
status = stream->flush_func (stream);
/* Don't overwrite a pre-existing status failure. */
if (stream->status == CAIRO_STATUS_SUCCESS)
stream->status = status;
}
 
return stream->status;
}
 
cairo_status_t
_cairo_output_stream_close (cairo_output_stream_t *stream)
{
cairo_status_t status;
 
if (stream->closed)
return stream->status;
 
if (stream == &_cairo_output_stream_nil ||
stream == &_cairo_output_stream_nil_write_error)
{
return stream->status;
}
 
if (stream->close_func) {
status = stream->close_func (stream);
/* Don't overwrite a pre-existing status failure. */
if (stream->status == CAIRO_STATUS_SUCCESS)
stream->status = status;
}
 
stream->closed = TRUE;
 
return stream->status;
}
 
cairo_status_t
_cairo_output_stream_destroy (cairo_output_stream_t *stream)
{
cairo_status_t status;
 
assert (stream != NULL);
 
if (stream == &_cairo_output_stream_nil ||
stream == &_cairo_output_stream_nil_write_error)
{
return stream->status;
}
 
status = _cairo_output_stream_fini (stream);
free (stream);
 
return status;
}
 
void
_cairo_output_stream_write (cairo_output_stream_t *stream,
const void *data, size_t length)
{
if (length == 0)
return;
 
if (stream->status)
return;
 
stream->status = stream->write_func (stream, data, length);
stream->position += length;
}
 
void
_cairo_output_stream_write_hex_string (cairo_output_stream_t *stream,
const unsigned char *data,
size_t length)
{
const char hex_chars[] = "0123456789abcdef";
char buffer[2];
unsigned int i, column;
 
if (stream->status)
return;
 
for (i = 0, column = 0; i < length; i++, column++) {
if (column == 38) {
_cairo_output_stream_write (stream, "\n", 1);
column = 0;
}
buffer[0] = hex_chars[(data[i] >> 4) & 0x0f];
buffer[1] = hex_chars[data[i] & 0x0f];
_cairo_output_stream_write (stream, buffer, 2);
}
}
 
/* Format a double in a locale independent way and trim trailing
* zeros. Based on code from Alex Larson <alexl@redhat.com>.
* http://mail.gnome.org/archives/gtk-devel-list/2001-October/msg00087.html
*
* The code in the patch is copyright Red Hat, Inc under the LGPL, but
* has been relicensed under the LGPL/MPL dual license for inclusion
* into cairo (see COPYING). -- Kristian Høgsberg <krh@redhat.com>
*/
static void
_cairo_dtostr (char *buffer, size_t size, double d, cairo_bool_t limited_precision)
{
struct lconv *locale_data;
const char *decimal_point;
int decimal_point_len;
char *p;
int decimal_len;
int num_zeros, decimal_digits;
 
/* Omit the minus sign from negative zero. */
if (d == 0.0)
d = 0.0;
 
locale_data = localeconv ();
decimal_point = locale_data->decimal_point;
decimal_point_len = strlen (decimal_point);
 
assert (decimal_point_len != 0);
 
if (limited_precision) {
snprintf (buffer, size, "%.*f", FIXED_POINT_DECIMAL_DIGITS, d);
} else {
/* 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 (_cairo_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;
 
if (*p == '+' || *p == '-')
p++;
 
while (_cairo_isdigit (*p))
p++;
 
if (strncmp (p, decimal_point, decimal_point_len) == 0) {
*p = '.';
decimal_len = strlen (p + decimal_point_len);
memmove (p + 1, p + decimal_point_len, decimal_len);
p[1 + decimal_len] = 0;
 
/* Remove trailing zeros and decimal point if possible. */
for (p = p + decimal_len; *p == '0'; p--)
*p = 0;
 
if (*p == '.') {
*p = 0;
p--;
}
}
}
 
enum {
LENGTH_MODIFIER_LONG = 0x100
};
 
/* Here's a limited reimplementation of printf. The reason for doing
* this is primarily to special case handling of doubles. We want
* locale independent formatting of doubles and we want to trim
* trailing zeros. This is handled by dtostr() above, and the code
* below handles everything else by calling snprintf() to do the
* formatting. This functionality is only for internal use and we
* only implement the formats we actually use.
*/
void
_cairo_output_stream_vprintf (cairo_output_stream_t *stream,
const char *fmt, va_list ap)
{
#define SINGLE_FMT_BUFFER_SIZE 32
char buffer[512], single_fmt[SINGLE_FMT_BUFFER_SIZE];
int single_fmt_length;
char *p;
const char *f, *start;
int length_modifier, width;
cairo_bool_t var_width;
 
if (stream->status)
return;
 
f = fmt;
p = buffer;
while (*f != '\0') {
if (p == buffer + sizeof (buffer)) {
_cairo_output_stream_write (stream, buffer, sizeof (buffer));
p = buffer;
}
 
if (*f != '%') {
*p++ = *f++;
continue;
}
 
start = f;
f++;
 
if (*f == '0')
f++;
 
var_width = FALSE;
if (*f == '*') {
var_width = TRUE;
f++;
}
 
while (_cairo_isdigit (*f))
f++;
 
length_modifier = 0;
if (*f == 'l') {
length_modifier = LENGTH_MODIFIER_LONG;
f++;
}
 
/* The only format strings exist in the cairo implementation
* itself. So there's an internal consistency problem if any
* of them is larger than our format buffer size. */
single_fmt_length = f - start + 1;
assert (single_fmt_length + 1 <= SINGLE_FMT_BUFFER_SIZE);
 
/* Reuse the format string for this conversion. */
memcpy (single_fmt, start, single_fmt_length);
single_fmt[single_fmt_length] = '\0';
 
/* Flush contents of buffer before snprintf()'ing into it. */
_cairo_output_stream_write (stream, buffer, p - buffer);
 
/* We group signed and unsigned together in this switch, the
* only thing that matters here is the size of the arguments,
* since we're just passing the data through to sprintf(). */
switch (*f | length_modifier) {
case '%':
buffer[0] = *f;
buffer[1] = 0;
break;
case 'd':
case 'u':
case 'o':
case 'x':
case 'X':
if (var_width) {
width = va_arg (ap, int);
snprintf (buffer, sizeof buffer,
single_fmt, width, va_arg (ap, int));
} else {
snprintf (buffer, sizeof buffer, single_fmt, va_arg (ap, int));
}
break;
case 'd' | LENGTH_MODIFIER_LONG:
case 'u' | LENGTH_MODIFIER_LONG:
case 'o' | LENGTH_MODIFIER_LONG:
case 'x' | LENGTH_MODIFIER_LONG:
case 'X' | LENGTH_MODIFIER_LONG:
if (var_width) {
width = va_arg (ap, int);
snprintf (buffer, sizeof buffer,
single_fmt, width, va_arg (ap, long int));
} else {
snprintf (buffer, sizeof buffer,
single_fmt, va_arg (ap, long int));
}
break;
case 's':
snprintf (buffer, sizeof buffer,
single_fmt, va_arg (ap, const char *));
break;
case 'f':
_cairo_dtostr (buffer, sizeof buffer, va_arg (ap, double), FALSE);
break;
case 'g':
_cairo_dtostr (buffer, sizeof buffer, va_arg (ap, double), TRUE);
break;
case 'c':
buffer[0] = va_arg (ap, int);
buffer[1] = 0;
break;
default:
ASSERT_NOT_REACHED;
}
p = buffer + strlen (buffer);
f++;
}
 
_cairo_output_stream_write (stream, buffer, p - buffer);
}
 
void
_cairo_output_stream_printf (cairo_output_stream_t *stream,
const char *fmt, ...)
{
va_list ap;
 
va_start (ap, fmt);
 
_cairo_output_stream_vprintf (stream, fmt, ap);
 
va_end (ap);
}
 
long
_cairo_output_stream_get_position (cairo_output_stream_t *stream)
{
return stream->position;
}
 
cairo_status_t
_cairo_output_stream_get_status (cairo_output_stream_t *stream)
{
return stream->status;
}
 
/* Maybe this should be a configure time option, so embedded targets
* don't have to pull in stdio. */
 
 
typedef struct _stdio_stream {
cairo_output_stream_t base;
FILE *file;
} stdio_stream_t;
 
static cairo_status_t
stdio_write (cairo_output_stream_t *base,
const unsigned char *data, unsigned int length)
{
stdio_stream_t *stream = (stdio_stream_t *) base;
 
if (fwrite (data, 1, length, stream->file) != length)
return _cairo_error (CAIRO_STATUS_WRITE_ERROR);
 
return CAIRO_STATUS_SUCCESS;
}
 
static cairo_status_t
stdio_flush (cairo_output_stream_t *base)
{
stdio_stream_t *stream = (stdio_stream_t *) base;
 
fflush (stream->file);
 
if (ferror (stream->file))
return _cairo_error (CAIRO_STATUS_WRITE_ERROR);
else
return CAIRO_STATUS_SUCCESS;
}
 
static cairo_status_t
stdio_close (cairo_output_stream_t *base)
{
cairo_status_t status;
stdio_stream_t *stream = (stdio_stream_t *) base;
 
status = stdio_flush (base);
 
fclose (stream->file);
 
return status;
}
 
cairo_output_stream_t *
_cairo_output_stream_create_for_file (FILE *file)
{
stdio_stream_t *stream;
 
if (file == NULL) {
_cairo_error_throw (CAIRO_STATUS_WRITE_ERROR);
return (cairo_output_stream_t *) &_cairo_output_stream_nil_write_error;
}
 
stream = malloc (sizeof *stream);
if (unlikely (stream == NULL)) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_output_stream_t *) &_cairo_output_stream_nil;
}
 
_cairo_output_stream_init (&stream->base,
stdio_write, stdio_flush, stdio_flush);
stream->file = file;
 
return &stream->base;
}
 
cairo_output_stream_t *
_cairo_output_stream_create_for_filename (const char *filename)
{
stdio_stream_t *stream;
FILE *file;
 
if (filename == NULL)
return _cairo_null_stream_create ();
 
file = fopen (filename, "wb");
if (file == NULL) {
switch (errno) {
case ENOMEM:
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_output_stream_t *) &_cairo_output_stream_nil;
default:
_cairo_error_throw (CAIRO_STATUS_WRITE_ERROR);
return (cairo_output_stream_t *) &_cairo_output_stream_nil_write_error;
}
}
 
stream = malloc (sizeof *stream);
if (unlikely (stream == NULL)) {
fclose (file);
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_output_stream_t *) &_cairo_output_stream_nil;
}
 
_cairo_output_stream_init (&stream->base,
stdio_write, stdio_flush, stdio_close);
stream->file = file;
 
return &stream->base;
}
 
 
typedef struct _memory_stream {
cairo_output_stream_t base;
cairo_array_t array;
} memory_stream_t;
 
static cairo_status_t
memory_write (cairo_output_stream_t *base,
const unsigned char *data, unsigned int length)
{
memory_stream_t *stream = (memory_stream_t *) base;
 
return _cairo_array_append_multiple (&stream->array, data, length);
}
 
static cairo_status_t
memory_close (cairo_output_stream_t *base)
{
memory_stream_t *stream = (memory_stream_t *) base;
 
_cairo_array_fini (&stream->array);
 
return CAIRO_STATUS_SUCCESS;
}
 
cairo_output_stream_t *
_cairo_memory_stream_create (void)
{
memory_stream_t *stream;
 
stream = malloc (sizeof *stream);
if (unlikely (stream == NULL)) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_output_stream_t *) &_cairo_output_stream_nil;
}
 
_cairo_output_stream_init (&stream->base, memory_write, NULL, memory_close);
_cairo_array_init (&stream->array, 1);
 
return &stream->base;
}
 
cairo_status_t
_cairo_memory_stream_destroy (cairo_output_stream_t *abstract_stream,
unsigned char **data_out,
unsigned long *length_out)
{
memory_stream_t *stream;
cairo_status_t status;
 
status = abstract_stream->status;
if (unlikely (status))
return _cairo_output_stream_destroy (abstract_stream);
 
stream = (memory_stream_t *) abstract_stream;
 
*length_out = _cairo_array_num_elements (&stream->array);
*data_out = malloc (*length_out);
if (unlikely (*data_out == NULL)) {
status = _cairo_output_stream_destroy (abstract_stream);
assert (status == CAIRO_STATUS_SUCCESS);
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
memcpy (*data_out, _cairo_array_index (&stream->array, 0), *length_out);
 
return _cairo_output_stream_destroy (abstract_stream);
}
 
void
_cairo_memory_stream_copy (cairo_output_stream_t *base,
cairo_output_stream_t *dest)
{
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_array_index (&stream->array, 0),
_cairo_array_num_elements (&stream->array));
}
 
int
_cairo_memory_stream_length (cairo_output_stream_t *base)
{
memory_stream_t *stream = (memory_stream_t *) base;
 
return _cairo_array_num_elements (&stream->array);
}
 
static cairo_status_t
null_write (cairo_output_stream_t *base,
const unsigned char *data, unsigned int length)
{
return CAIRO_STATUS_SUCCESS;
}
 
cairo_output_stream_t *
_cairo_null_stream_create (void)
{
cairo_output_stream_t *stream;
 
stream = malloc (sizeof *stream);
if (unlikely (stream == NULL)) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_output_stream_t *) &_cairo_output_stream_nil;
}
 
_cairo_output_stream_init (stream, null_write, NULL, NULL);
 
return stream;
}
/programs/develop/libraries/cairo/src/cairo-paginated-private.h
0,0 → 1,165
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2005 Red Hat, Inc
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
* Carl Worth <cworth@cworth.org>
*/
 
#ifndef CAIRO_PAGINATED_H
#define CAIRO_PAGINATED_H
 
#include "cairoint.h"
 
struct _cairo_paginated_surface_backend {
/* Optional. Will be called once for each page.
*
* Note: With respect to the order of drawing operations as seen
* by the target, this call will occur before any drawing
* operations for the relevant page. However, with respect to the
* function calls as made by the user, this call will be *after*
* any drawing operations for the page, (that is, it will occur
* during the user's call to cairo_show_page or cairo_copy_page).
*/
cairo_warn cairo_int_status_t
(*start_page) (void *surface);
 
/* Required. Will be called twice for each page, once with an
* argument of CAIRO_PAGINATED_MODE_ANALYZE and once with
* CAIRO_PAGINATED_MODE_RENDER. See more details in the
* documentation for _cairo_paginated_surface_create below.
*/
void
(*set_paginated_mode) (void *surface,
cairo_paginated_mode_t mode);
 
/* 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);
 
/* Optional. Indicates whether the page requires fallback images.
* 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_fallback_images_required) (void *surface,
cairo_bool_t fallbacks_required);
 
cairo_bool_t
(*supports_fine_grained_fallbacks) (void *surface);
};
 
/* A #cairo_paginated_surface_t provides a very convenient wrapper that
* is well-suited for doing the analysis common to most surfaces that
* have paginated output, (that is, things directed at printers, or
* for saving content in files such as PostScript or PDF files).
*
* To use the paginated surface, you'll first need to create your
* 'real' surface using _cairo_surface_init() and the standard
* #cairo_surface_backend_t. Then you also call
* _cairo_paginated_surface_create which takes its own, much simpler,
* #cairo_paginated_surface_backend_t. You are free to return the result
* of _cairo_paginated_surface_create() from your public
* cairo_<foo>_surface_create(). The paginated backend will be careful
* to not let the user see that they really got a "wrapped"
* surface. See test-paginated-surface.c for a fairly minimal example
* of a paginated-using surface. That should be a reasonable example
* to follow.
*
* What the paginated surface does is first save all drawing
* operations for a page into a recording-surface. Then when the user calls
* cairo_show_page(), the paginated surface performs the following
* sequence of operations (using the backend functions passed to
* cairo_paginated_surface_create()):
*
* 1. Calls start_page() (if not %NULL). At this point, it is appropriate
* for the target to emit any page-specific header information into
* its output.
*
* 2. Calls set_paginated_mode() with an argument of %CAIRO_PAGINATED_MODE_ANALYZE
*
* 3. Replays the recording-surface to the target surface, (with an
* analysis surface inserted between which watches the return value
* from each operation). This analysis stage is used to decide which
* operations will require fallbacks.
*
* 4. Calls set_bounding_box() to provide the target surface with the
* tight bounding box of the page.
*
* 5. Calls set_paginated_mode() with an argument of %CAIRO_PAGINATED_MODE_RENDER
*
* 6. Replays a subset of the recording-surface operations to the target surface
*
* 7. Calls set_paginated_mode() with an argument of %CAIRO_PAGINATED_MODE_FALLBACK
*
* 8. Replays the remaining operations to an image surface, sets an
* appropriate clip on the target, then paints the resulting image
* surface to the target.
*
* So, the target will see drawing operations during three separate
* stages, (ANALYZE, RENDER and FALLBACK). During the ANALYZE phase
* the target should not actually perform any rendering, (for example,
* if performing output to a file, no output should be generated
* during this stage). Instead the drawing functions simply need to
* return %CAIRO_STATUS_SUCCESS or %CAIRO_INT_STATUS_UNSUPPORTED to
* indicate whether rendering would be supported. And it should do
* this as quickly as possible. The FALLBACK phase allows the surface
* to distinguish fallback images from native rendering in case they
* need to be handled as a special case.
*
* Note: The paginated surface layer assumes that the target surface
* is "blank" by default at the beginning of each page, without any
* need for an explicit erase operation, (as opposed to an image
* surface, for example, which might have uninitialized content
* originally). As such, it optimizes away CLEAR operations that
* happen at the beginning of each page---the target surface will not
* even see these operations.
*/
cairo_private cairo_surface_t *
_cairo_paginated_surface_create (cairo_surface_t *target,
cairo_content_t content,
const cairo_paginated_surface_backend_t *backend);
 
cairo_private cairo_surface_t *
_cairo_paginated_surface_get_target (cairo_surface_t *surface);
 
cairo_private cairo_bool_t
_cairo_surface_is_paginated (cairo_surface_t *surface);
 
cairo_private cairo_status_t
_cairo_paginated_surface_set_size (cairo_surface_t *surface,
int width,
int height);
 
#endif /* CAIRO_PAGINATED_H */
/programs/develop/libraries/cairo/src/cairo-paginated-surface-private.h
0,0 → 1,62
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2005 Red Hat, Inc
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
* Carl Worth <cworth@cworth.org>
*/
 
#ifndef CAIRO_PAGINATED_SURFACE_H
#define CAIRO_PAGINATED_SURFACE_H
 
#include "cairo.h"
 
#include "cairo-surface-private.h"
 
typedef struct _cairo_paginated_surface {
cairo_surface_t base;
 
/* The target surface to hold the final result. */
cairo_surface_t *target;
 
cairo_content_t content;
 
/* Paginated-surface specific functions for the target */
const cairo_paginated_surface_backend_t *backend;
 
/* A cairo_recording_surface to record all operations. To be replayed
* against target, and also against image surface as necessary for
* fallbacks. */
cairo_surface_t *recording_surface;
 
int page_num;
} cairo_paginated_surface_t;
 
#endif /* CAIRO_PAGINATED_SURFACE_H */
/programs/develop/libraries/cairo/src/cairo-paginated-surface.c
0,0 → 1,679
/* 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
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
* Carl Worth <cworth@cworth.org>
* Keith Packard <keithp@keithp.com>
* Adrian Johnson <ajohnson@redneon.com>
*/
 
/* The paginated surface layer exists to provide as much code sharing
* as possible for the various paginated surface backends in cairo
* (PostScript, PDF, etc.). See cairo-paginated-private.h for
* more details on how it works and how to use it.
*/
 
#include "cairoint.h"
 
#include "cairo-paginated-private.h"
#include "cairo-paginated-surface-private.h"
#include "cairo-recording-surface-private.h"
#include "cairo-analysis-surface-private.h"
#include "cairo-error-private.h"
 
static const cairo_surface_backend_t cairo_paginated_surface_backend;
 
static cairo_int_status_t
_cairo_paginated_surface_show_page (void *abstract_surface);
 
static cairo_surface_t *
_cairo_paginated_surface_create_similar (void *abstract_surface,
cairo_content_t content,
int width,
int height)
{
cairo_rectangle_t rect;
rect.x = rect.y = 0.;
rect.width = width;
rect.height = height;
return cairo_recording_surface_create (content, &rect);
}
 
static cairo_surface_t *
_create_recording_surface_for_target (cairo_surface_t *target,
cairo_content_t content)
{
cairo_rectangle_int_t rect;
 
if (_cairo_surface_get_extents (target, &rect)) {
cairo_rectangle_t recording_extents;
 
recording_extents.x = rect.x;
recording_extents.y = rect.y;
recording_extents.width = rect.width;
recording_extents.height = rect.height;
 
return cairo_recording_surface_create (content, &recording_extents);
} else {
return cairo_recording_surface_create (content, NULL);
}
}
 
cairo_surface_t *
_cairo_paginated_surface_create (cairo_surface_t *target,
cairo_content_t content,
const cairo_paginated_surface_backend_t *backend)
{
cairo_paginated_surface_t *surface;
cairo_status_t status;
 
surface = malloc (sizeof (cairo_paginated_surface_t));
if (unlikely (surface == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto FAIL;
}
 
_cairo_surface_init (&surface->base,
&cairo_paginated_surface_backend,
NULL, /* device */
content);
 
/* Override surface->base.type with target's type so we don't leak
* evidence of the paginated wrapper out to the user. */
surface->base.type = target->type;
 
surface->target = cairo_surface_reference (target);
 
surface->content = content;
surface->backend = backend;
 
surface->recording_surface = _create_recording_surface_for_target (target, content);
status = surface->recording_surface->status;
if (unlikely (status))
goto FAIL_CLEANUP_SURFACE;
 
surface->page_num = 1;
surface->base.is_clear = TRUE;
 
return &surface->base;
 
FAIL_CLEANUP_SURFACE:
cairo_surface_destroy (target);
free (surface);
FAIL:
return _cairo_surface_create_in_error (status);
}
 
cairo_bool_t
_cairo_surface_is_paginated (cairo_surface_t *surface)
{
return surface->backend == &cairo_paginated_surface_backend;
}
 
cairo_surface_t *
_cairo_paginated_surface_get_target (cairo_surface_t *surface)
{
cairo_paginated_surface_t *paginated_surface;
 
assert (_cairo_surface_is_paginated (surface));
 
paginated_surface = (cairo_paginated_surface_t *) surface;
 
return paginated_surface->target;
}
 
cairo_status_t
_cairo_paginated_surface_set_size (cairo_surface_t *surface,
int width,
int height)
{
cairo_paginated_surface_t *paginated_surface;
cairo_status_t status;
cairo_rectangle_t recording_extents;
 
assert (_cairo_surface_is_paginated (surface));
 
paginated_surface = (cairo_paginated_surface_t *) surface;
 
recording_extents.x = 0;
recording_extents.y = 0;
recording_extents.width = width;
recording_extents.height = height;
 
cairo_surface_destroy (paginated_surface->recording_surface);
paginated_surface->recording_surface = cairo_recording_surface_create (paginated_surface->content,
&recording_extents);
status = paginated_surface->recording_surface->status;
if (unlikely (status))
return _cairo_surface_set_error (surface, status);
 
return CAIRO_STATUS_SUCCESS;
}
 
static cairo_status_t
_cairo_paginated_surface_finish (void *abstract_surface)
{
cairo_paginated_surface_t *surface = abstract_surface;
cairo_status_t status = CAIRO_STATUS_SUCCESS;
 
if (! surface->base.is_clear || surface->page_num == 1) {
/* Bypass some of the sanity checking in cairo-surface.c, as we
* know that the surface is finished...
*/
status = _cairo_paginated_surface_show_page (surface);
}
 
/* XXX We want to propagate any errors from destroy(), but those are not
* returned via the api. So we need to explicitly finish the target,
* and check the status afterwards. However, we can only call finish()
* on the target, if we own it.
*/
if (CAIRO_REFERENCE_COUNT_GET_VALUE (&surface->target->ref_count) == 1)
cairo_surface_finish (surface->target);
if (status == CAIRO_STATUS_SUCCESS)
status = cairo_surface_status (surface->target);
cairo_surface_destroy (surface->target);
 
cairo_surface_finish (surface->recording_surface);
if (status == CAIRO_STATUS_SUCCESS)
status = cairo_surface_status (surface->recording_surface);
cairo_surface_destroy (surface->recording_surface);
 
return status;
}
 
static cairo_surface_t *
_cairo_paginated_surface_create_image_surface (void *abstract_surface,
int width,
int height)
{
cairo_paginated_surface_t *surface = abstract_surface;
cairo_surface_t *image;
cairo_font_options_t options;
 
image = _cairo_image_surface_create_with_content (surface->content,
width,
height);
 
cairo_surface_get_font_options (&surface->base, &options);
_cairo_surface_set_font_options (image, &options);
 
return image;
}
 
static cairo_status_t
_cairo_paginated_surface_acquire_source_image (void *abstract_surface,
cairo_image_surface_t **image_out,
void **image_extra)
{
cairo_paginated_surface_t *surface = abstract_surface;
cairo_bool_t is_bounded;
cairo_surface_t *image;
cairo_status_t status;
cairo_rectangle_int_t extents;
 
is_bounded = _cairo_surface_get_extents (surface->target, &extents);
if (! is_bounded)
return CAIRO_INT_STATUS_UNSUPPORTED;
 
image = _cairo_paginated_surface_create_image_surface (surface,
extents.width,
extents.height);
 
status = _cairo_recording_surface_replay (surface->recording_surface, image);
if (unlikely (status)) {
cairo_surface_destroy (image);
return status;
}
 
*image_out = (cairo_image_surface_t*) image;
*image_extra = NULL;
 
return CAIRO_STATUS_SUCCESS;
}
 
static void
_cairo_paginated_surface_release_source_image (void *abstract_surface,
cairo_image_surface_t *image,
void *image_extra)
{
cairo_surface_destroy (&image->base);
}
 
static cairo_int_status_t
_paint_fallback_image (cairo_paginated_surface_t *surface,
cairo_rectangle_int_t *rect)
{
double x_scale = surface->base.x_fallback_resolution / surface->target->x_resolution;
double y_scale = surface->base.y_fallback_resolution / surface->target->y_resolution;
int x, y, width, height;
cairo_status_t status;
cairo_surface_t *image;
cairo_surface_pattern_t pattern;
cairo_clip_t clip;
 
x = rect->x;
y = rect->y;
width = rect->width;
height = rect->height;
image = _cairo_paginated_surface_create_image_surface (surface,
ceil (width * x_scale),
ceil (height * y_scale));
_cairo_surface_set_device_scale (image, x_scale, y_scale);
/* set_device_offset just sets the x0/y0 components of the matrix;
* so we have to do the scaling manually. */
cairo_surface_set_device_offset (image, -x*x_scale, -y*y_scale);
 
status = _cairo_recording_surface_replay (surface->recording_surface, image);
if (unlikely (status))
goto CLEANUP_IMAGE;
 
_cairo_pattern_init_for_surface (&pattern, image);
cairo_matrix_init (&pattern.base.matrix,
x_scale, 0, 0, y_scale, -x*x_scale, -y*y_scale);
/* the fallback should be rendered at native resolution, so disable
* filtering (if possible) to avoid introducing potential artifacts. */
pattern.base.filter = CAIRO_FILTER_NEAREST;
 
_cairo_clip_init (&clip);
status = _cairo_clip_rectangle (&clip, rect);
if (likely (status == CAIRO_STATUS_SUCCESS)) {
status = _cairo_surface_paint (surface->target,
CAIRO_OPERATOR_SOURCE,
&pattern.base, &clip);
}
 
_cairo_clip_fini (&clip);
_cairo_pattern_fini (&pattern.base);
 
CLEANUP_IMAGE:
cairo_surface_destroy (image);
 
return status;
}
 
static cairo_int_status_t
_paint_page (cairo_paginated_surface_t *surface)
{
cairo_surface_t *analysis;
cairo_status_t status;
cairo_bool_t has_supported, has_page_fallback, has_finegrained_fallback;
 
if (unlikely (surface->target->status))
return surface->target->status;
 
analysis = _cairo_analysis_surface_create (surface->target);
if (unlikely (analysis->status))
return _cairo_surface_set_error (surface->target, analysis->status);
 
surface->backend->set_paginated_mode (surface->target,
CAIRO_PAGINATED_MODE_ANALYZE);
status = _cairo_recording_surface_replay_and_create_regions (surface->recording_surface,
analysis);
if (status || analysis->status) {
if (status == CAIRO_STATUS_SUCCESS)
status = analysis->status;
goto FAIL;
}
 
if (surface->backend->set_bounding_box) {
cairo_box_t bbox;
 
_cairo_analysis_surface_get_bounding_box (analysis, &bbox);
status = surface->backend->set_bounding_box (surface->target, &bbox);
if (unlikely (status))
goto FAIL;
}
 
if (surface->backend->set_fallback_images_required) {
cairo_bool_t has_fallbacks = _cairo_analysis_surface_has_unsupported (analysis);
 
status = surface->backend->set_fallback_images_required (surface->target,
has_fallbacks);
if (unlikely (status))
goto FAIL;
}
 
/* Finer grained fallbacks are currently only supported for some
* surface types */
if (surface->backend->supports_fine_grained_fallbacks != NULL &&
surface->backend->supports_fine_grained_fallbacks (surface->target))
{
has_supported = _cairo_analysis_surface_has_supported (analysis);
has_page_fallback = FALSE;
has_finegrained_fallback = _cairo_analysis_surface_has_unsupported (analysis);
}
else
{
if (_cairo_analysis_surface_has_unsupported (analysis)) {
has_supported = FALSE;
has_page_fallback = TRUE;
} else {
has_supported = TRUE;
has_page_fallback = FALSE;
}
has_finegrained_fallback = FALSE;
}
 
if (has_supported) {
surface->backend->set_paginated_mode (surface->target,
CAIRO_PAGINATED_MODE_RENDER);
 
status = _cairo_recording_surface_replay_region (surface->recording_surface,
NULL,
surface->target,
CAIRO_RECORDING_REGION_NATIVE);
assert (status != CAIRO_INT_STATUS_UNSUPPORTED);
if (unlikely (status))
goto FAIL;
}
 
if (has_page_fallback) {
cairo_rectangle_int_t extents;
cairo_bool_t is_bounded;
 
surface->backend->set_paginated_mode (surface->target,
CAIRO_PAGINATED_MODE_FALLBACK);
 
is_bounded = _cairo_surface_get_extents (surface->target, &extents);
if (! is_bounded) {
status = CAIRO_INT_STATUS_UNSUPPORTED;
goto FAIL;
}
 
status = _paint_fallback_image (surface, &extents);
if (unlikely (status))
goto FAIL;
}
 
if (has_finegrained_fallback) {
cairo_region_t *region;
int num_rects, i;
 
surface->backend->set_paginated_mode (surface->target,
CAIRO_PAGINATED_MODE_FALLBACK);
 
region = _cairo_analysis_surface_get_unsupported (analysis);
 
num_rects = cairo_region_num_rectangles (region);
for (i = 0; i < num_rects; i++) {
cairo_rectangle_int_t rect;
 
cairo_region_get_rectangle (region, i, &rect);
status = _paint_fallback_image (surface, &rect);
if (unlikely (status))
goto FAIL;
}
}
 
FAIL:
cairo_surface_destroy (analysis);
 
return _cairo_surface_set_error (surface->target, status);
}
 
static cairo_status_t
_start_page (cairo_paginated_surface_t *surface)
{
if (surface->target->status)
return surface->target->status;
 
if (! surface->backend->start_page)
return CAIRO_STATUS_SUCCESS;
 
return _cairo_surface_set_error (surface->target,
surface->backend->start_page (surface->target));
}
 
static cairo_int_status_t
_cairo_paginated_surface_copy_page (void *abstract_surface)
{
cairo_status_t status;
cairo_paginated_surface_t *surface = abstract_surface;
 
status = _start_page (surface);
if (unlikely (status))
return status;
 
status = _paint_page (surface);
if (unlikely (status))
return status;
 
surface->page_num++;
 
/* XXX: It might make sense to add some support here for calling
* cairo_surface_copy_page on the target surface. It would be an
* optimization for the output, but the interaction with image
* fallbacks gets tricky. For now, we just let the target see a
* show_page and we implement the copying by simply not destroying
* the recording-surface. */
 
cairo_surface_show_page (surface->target);
return cairo_surface_status (surface->target);
}
 
static cairo_int_status_t
_cairo_paginated_surface_show_page (void *abstract_surface)
{
cairo_status_t status;
cairo_paginated_surface_t *surface = abstract_surface;
 
status = _start_page (surface);
if (unlikely (status))
return status;
 
status = _paint_page (surface);
if (unlikely (status))
return status;
 
cairo_surface_show_page (surface->target);
status = surface->target->status;
if (unlikely (status))
return status;
 
status = surface->recording_surface->status;
if (unlikely (status))
return status;
 
if (! surface->base.finished) {
cairo_surface_destroy (surface->recording_surface);
 
surface->recording_surface = _create_recording_surface_for_target (surface->target,
surface->content);
status = surface->recording_surface->status;
if (unlikely (status))
return status;
 
surface->page_num++;
surface->base.is_clear = TRUE;
}
 
return CAIRO_STATUS_SUCCESS;
}
 
static cairo_bool_t
_cairo_paginated_surface_get_extents (void *abstract_surface,
cairo_rectangle_int_t *rectangle)
{
cairo_paginated_surface_t *surface = abstract_surface;
 
return _cairo_surface_get_extents (surface->target, rectangle);
}
 
static void
_cairo_paginated_surface_get_font_options (void *abstract_surface,
cairo_font_options_t *options)
{
cairo_paginated_surface_t *surface = abstract_surface;
 
cairo_surface_get_font_options (surface->target, options);
}
 
static cairo_int_status_t
_cairo_paginated_surface_paint (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_clip_t *clip)
{
cairo_paginated_surface_t *surface = abstract_surface;
 
return _cairo_surface_paint (surface->recording_surface, op, source, clip);
}
 
static cairo_int_status_t
_cairo_paginated_surface_mask (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_pattern_t *mask,
cairo_clip_t *clip)
{
cairo_paginated_surface_t *surface = abstract_surface;
 
return _cairo_surface_mask (surface->recording_surface, op, source, mask, clip);
}
 
static cairo_int_status_t
_cairo_paginated_surface_stroke (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_path_fixed_t *path,
const cairo_stroke_style_t *style,
const cairo_matrix_t *ctm,
const cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
cairo_clip_t *clip)
{
cairo_paginated_surface_t *surface = abstract_surface;
 
return _cairo_surface_stroke (surface->recording_surface, op, source,
path, style,
ctm, ctm_inverse,
tolerance, antialias,
clip);
}
 
static cairo_int_status_t
_cairo_paginated_surface_fill (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias,
cairo_clip_t *clip)
{
cairo_paginated_surface_t *surface = abstract_surface;
 
return _cairo_surface_fill (surface->recording_surface, op, source,
path, fill_rule,
tolerance, antialias,
clip);
}
 
static cairo_bool_t
_cairo_paginated_surface_has_show_text_glyphs (void *abstract_surface)
{
cairo_paginated_surface_t *surface = abstract_surface;
 
return cairo_surface_has_show_text_glyphs (surface->target);
}
 
static cairo_int_status_t
_cairo_paginated_surface_show_text_glyphs (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const char *utf8,
int utf8_len,
cairo_glyph_t *glyphs,
int num_glyphs,
const cairo_text_cluster_t *clusters,
int num_clusters,
cairo_text_cluster_flags_t cluster_flags,
cairo_scaled_font_t *scaled_font,
cairo_clip_t *clip)
{
cairo_paginated_surface_t *surface = abstract_surface;
 
return _cairo_surface_show_text_glyphs (surface->recording_surface, op, source,
utf8, utf8_len,
glyphs, num_glyphs,
clusters, num_clusters,
cluster_flags,
scaled_font,
clip);
}
 
static cairo_surface_t *
_cairo_paginated_surface_snapshot (void *abstract_other)
{
cairo_paginated_surface_t *other = abstract_other;
 
return _cairo_surface_snapshot (other->recording_surface);
}
 
static const cairo_surface_backend_t cairo_paginated_surface_backend = {
CAIRO_INTERNAL_SURFACE_TYPE_PAGINATED,
_cairo_paginated_surface_create_similar,
_cairo_paginated_surface_finish,
_cairo_paginated_surface_acquire_source_image,
_cairo_paginated_surface_release_source_image,
NULL, /* acquire_dest_image */
NULL, /* release_dest_image */
NULL, /* clone_similar */
NULL, /* composite */
NULL, /* fill_rectangles */
NULL, /* composite_trapezoids */
NULL, /* create_span_renderer */
NULL, /* check_span_renderer */
_cairo_paginated_surface_copy_page,
_cairo_paginated_surface_show_page,
_cairo_paginated_surface_get_extents,
NULL, /* old_show_glyphs */
_cairo_paginated_surface_get_font_options,
NULL, /* flush */
NULL, /* mark_dirty_rectangle */
NULL, /* scaled_font_fini */
NULL, /* scaled_glyph_fini */
_cairo_paginated_surface_paint,
_cairo_paginated_surface_mask,
_cairo_paginated_surface_stroke,
_cairo_paginated_surface_fill,
NULL, /* show_glyphs */
_cairo_paginated_surface_snapshot,
NULL, /* is_similar */
NULL, /* fill_stroke */
NULL, /* create_solid_pattern_surface */
NULL, /* can_repaint_solid_pattern_surface */
_cairo_paginated_surface_has_show_text_glyphs,
_cairo_paginated_surface_show_text_glyphs
};
/programs/develop/libraries/cairo/src/cairo-path-bounds.c
0,0 → 1,353
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2003 University of Southern California
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
*/
 
#include "cairoint.h"
#include "cairo-path-fixed-private.h"
 
typedef struct cairo_path_bounder {
cairo_point_t current_point;
cairo_bool_t has_initial_point;
cairo_bool_t has_point;
 
cairo_box_t extents;
} cairo_path_bounder_t;
 
static void
_cairo_path_bounder_init (cairo_path_bounder_t *bounder)
{
bounder->has_initial_point = FALSE;
bounder->has_point = FALSE;
}
 
static void
_cairo_path_bounder_add_point (cairo_path_bounder_t *bounder,
const cairo_point_t *point)
{
if (bounder->has_point) {
if (point->x < bounder->extents.p1.x)
bounder->extents.p1.x = point->x;
 
if (point->y < bounder->extents.p1.y)
bounder->extents.p1.y = point->y;
 
if (point->x > bounder->extents.p2.x)
bounder->extents.p2.x = point->x;
 
if (point->y > bounder->extents.p2.y)
bounder->extents.p2.y = point->y;
} else {
bounder->extents.p1.x = point->x;
bounder->extents.p1.y = point->y;
bounder->extents.p2.x = point->x;
bounder->extents.p2.y = point->y;
bounder->has_point = TRUE;
}
}
 
static cairo_status_t
_cairo_path_bounder_move_to (void *closure,
const cairo_point_t *point)
{
cairo_path_bounder_t *bounder = closure;
 
bounder->current_point = *point;
bounder->has_initial_point = TRUE;
 
return CAIRO_STATUS_SUCCESS;
}
 
static cairo_status_t
_cairo_path_bounder_line_to (void *closure,
const cairo_point_t *point)
{
cairo_path_bounder_t *bounder = closure;
 
if (bounder->has_initial_point) {
_cairo_path_bounder_add_point (bounder, &bounder->current_point);
bounder->has_initial_point = FALSE;
}
 
_cairo_path_bounder_add_point (bounder, point);
bounder->current_point = *point;
 
return CAIRO_STATUS_SUCCESS;
}
 
static cairo_status_t
_cairo_path_bounder_curve_to (void *closure,
const cairo_point_t *b,
const cairo_point_t *c,
const cairo_point_t *d)
{
cairo_path_bounder_t *bounder = closure;
 
/* If the bbox of the control points is entirely inside, then we
* do not need to further evaluate the spline.
*/
if (! bounder->has_point ||
b->x < bounder->extents.p1.x || b->x > bounder->extents.p2.x ||
b->y < bounder->extents.p1.y || b->y > bounder->extents.p2.y ||
c->x < bounder->extents.p1.x || c->x > bounder->extents.p2.x ||
c->y < bounder->extents.p1.y || c->y > bounder->extents.p2.y ||
d->x < bounder->extents.p1.x || d->x > bounder->extents.p2.x ||
d->y < bounder->extents.p1.y || d->y > bounder->extents.p2.y)
{
return _cairo_spline_bound (_cairo_path_bounder_line_to, bounder,
&bounder->current_point, b, c, d);
}
else
{
/* All control points are within the current extents. */
bounder->current_point = *d;
 
return CAIRO_STATUS_SUCCESS;
}
}
 
static cairo_status_t
_cairo_path_bounder_close_path (void *closure)
{
return CAIRO_STATUS_SUCCESS;
}
 
/* This computes the extents of all the points in the path, not those of
* the damage area (i.e it does not consider winding and it only inspects
* the control points of the curves, not the flattened path).
*/
void
_cairo_path_fixed_approximate_clip_extents (const cairo_path_fixed_t *path,
cairo_rectangle_int_t *extents)
{
if (path->extents.p1.x < path->extents.p2.x) {
_cairo_box_round_to_rectangle (&path->extents, extents);
} else {
extents->x = extents->y = 0;
extents->width = extents->height = 0;
}
}
 
/* A slightly better approximation than above - we actually decompose the
* Bezier, but we continue to ignore winding.
*/
void
_cairo_path_fixed_approximate_fill_extents (const cairo_path_fixed_t *path,
cairo_rectangle_int_t *extents)
{
cairo_path_bounder_t bounder;
cairo_status_t status;
 
if (! path->has_curve_to) {
bounder.extents = path->extents;
bounder.has_point = path->extents.p1.x < path->extents.p2.x;
} else {
_cairo_path_bounder_init (&bounder);
 
status = _cairo_path_fixed_interpret (path, CAIRO_DIRECTION_FORWARD,
_cairo_path_bounder_move_to,
_cairo_path_bounder_line_to,
_cairo_path_bounder_curve_to,
_cairo_path_bounder_close_path,
&bounder);
assert (status == CAIRO_STATUS_SUCCESS);
}
 
if (bounder.has_point) {
_cairo_box_round_to_rectangle (&bounder.extents, extents);
} else {
extents->x = extents->y = 0;
extents->width = extents->height = 0;
}
}
 
void
_cairo_path_fixed_fill_extents (const cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_rectangle_int_t *extents)
{
cairo_path_bounder_t bounder;
cairo_status_t status;
 
if (! path->has_curve_to) {
bounder.extents = path->extents;
bounder.has_point = path->extents.p1.x < path->extents.p2.x;
} else {
_cairo_path_bounder_init (&bounder);
 
status = _cairo_path_fixed_interpret_flat (path, CAIRO_DIRECTION_FORWARD,
_cairo_path_bounder_move_to,
_cairo_path_bounder_line_to,
_cairo_path_bounder_close_path,
&bounder, tolerance);
assert (status == CAIRO_STATUS_SUCCESS);
}
 
if (bounder.has_point) {
_cairo_box_round_to_rectangle (&bounder.extents, extents);
} else {
extents->x = extents->y = 0;
extents->width = extents->height = 0;
}
}
 
/* Adjusts the fill extents (above) by the device-space pen. */
void
_cairo_path_fixed_approximate_stroke_extents (const cairo_path_fixed_t *path,
const cairo_stroke_style_t *style,
const cairo_matrix_t *ctm,
cairo_rectangle_int_t *extents)
{
cairo_path_bounder_t bounder;
cairo_status_t status;
 
if (! path->has_curve_to) {
bounder.extents = path->extents;
 
/* include trailing move-to for degenerate segments */
if (path->has_last_move_point) {
const cairo_point_t *point = &path->last_move_point;
 
if (point->x < bounder.extents.p1.x)
bounder.extents.p1.x = point->x;
if (point->y < bounder.extents.p1.y)
bounder.extents.p1.y = point->y;
 
if (point->x > bounder.extents.p2.x)
bounder.extents.p2.x = point->x;
if (point->y > bounder.extents.p2.y)
bounder.extents.p2.y = point->y;
}
 
bounder.has_point = bounder.extents.p1.x <= bounder.extents.p2.x;
bounder.has_initial_point = FALSE;
} else {
_cairo_path_bounder_init (&bounder);
 
status = _cairo_path_fixed_interpret (path, CAIRO_DIRECTION_FORWARD,
_cairo_path_bounder_move_to,
_cairo_path_bounder_line_to,
_cairo_path_bounder_curve_to,
_cairo_path_bounder_close_path,
&bounder);
assert (status == CAIRO_STATUS_SUCCESS);
}
 
if (bounder.has_point) {
double dx, dy;
 
_cairo_stroke_style_max_distance_from_path (style, ctm, &dx, &dy);
 
bounder.extents.p1.x -= _cairo_fixed_from_double (dx);
bounder.extents.p2.x += _cairo_fixed_from_double (dx);
bounder.extents.p1.y -= _cairo_fixed_from_double (dy);
bounder.extents.p2.y += _cairo_fixed_from_double (dy);
 
_cairo_box_round_to_rectangle (&bounder.extents, extents);
} else if (bounder.has_initial_point) {
double dx, dy;
 
/* accommodate capping of degenerate paths */
 
_cairo_stroke_style_max_distance_from_path (style, ctm, &dx, &dy);
 
bounder.extents.p1.x = bounder.current_point.x - _cairo_fixed_from_double (dx);
bounder.extents.p2.x = bounder.current_point.x + _cairo_fixed_from_double (dx);
bounder.extents.p1.y = bounder.current_point.y - _cairo_fixed_from_double (dy);
bounder.extents.p2.y = bounder.current_point.y + _cairo_fixed_from_double (dy);
 
_cairo_box_round_to_rectangle (&bounder.extents, extents);
} else {
extents->x = extents->y = 0;
extents->width = extents->height = 0;
}
}
 
cairo_status_t
_cairo_path_fixed_stroke_extents (const cairo_path_fixed_t *path,
const cairo_stroke_style_t *stroke_style,
const cairo_matrix_t *ctm,
const cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_rectangle_int_t *extents)
{
cairo_traps_t traps;
cairo_box_t bbox;
cairo_status_t status;
 
_cairo_traps_init (&traps);
 
status = _cairo_path_fixed_stroke_to_traps (path,
stroke_style,
ctm,
ctm_inverse,
tolerance,
&traps);
 
_cairo_traps_extents (&traps, &bbox);
_cairo_traps_fini (&traps);
 
_cairo_box_round_to_rectangle (&bbox, extents);
 
return status;
}
 
cairo_bool_t
_cairo_path_fixed_extents (const cairo_path_fixed_t *path,
cairo_box_t *box)
{
cairo_path_bounder_t bounder;
cairo_status_t status;
 
if (! path->has_curve_to) {
*box = path->extents;
/* empty extents should still have an origin and should not
* be {0, 0, 0, 0} */
return path->extents.p1.x <= path->extents.p2.x;
}
 
_cairo_path_bounder_init (&bounder);
 
status = _cairo_path_fixed_interpret (path, CAIRO_DIRECTION_FORWARD,
_cairo_path_bounder_move_to,
_cairo_path_bounder_line_to,
_cairo_path_bounder_curve_to,
_cairo_path_bounder_close_path,
&bounder);
assert (status == CAIRO_STATUS_SUCCESS);
 
*box = bounder.extents;
return bounder.has_point;
}
/programs/develop/libraries/cairo/src/cairo-path-fill.c
0,0 → 1,465
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2002 University of Southern California
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
*/
 
#include "cairoint.h"
#include "cairo-boxes-private.h"
#include "cairo-error-private.h"
#include "cairo-path-fixed-private.h"
#include "cairo-region-private.h"
 
typedef struct cairo_filler {
double tolerance;
cairo_polygon_t *polygon;
} cairo_filler_t;
 
static void
_cairo_filler_init (cairo_filler_t *filler,
double tolerance,
cairo_polygon_t *polygon)
{
filler->tolerance = tolerance;
filler->polygon = polygon;
}
 
static void
_cairo_filler_fini (cairo_filler_t *filler)
{
}
 
static cairo_status_t
_cairo_filler_move_to (void *closure,
const cairo_point_t *point)
{
cairo_filler_t *filler = closure;
cairo_polygon_t *polygon = filler->polygon;
 
return _cairo_polygon_close (polygon) ||
_cairo_polygon_move_to (polygon, point);
}
 
static cairo_status_t
_cairo_filler_line_to (void *closure,
const cairo_point_t *point)
{
cairo_filler_t *filler = closure;
return _cairo_polygon_line_to (filler->polygon, point);
}
 
static cairo_status_t
_cairo_filler_curve_to (void *closure,
const cairo_point_t *b,
const cairo_point_t *c,
const cairo_point_t *d)
{
cairo_filler_t *filler = closure;
cairo_spline_t spline;
 
if (! _cairo_spline_init (&spline,
_cairo_filler_line_to, filler,
&filler->polygon->current_point, b, c, d))
{
return _cairo_filler_line_to (closure, d);
}
 
return _cairo_spline_decompose (&spline, filler->tolerance);
}
 
static cairo_status_t
_cairo_filler_close_path (void *closure)
{
cairo_filler_t *filler = closure;
return _cairo_polygon_close (filler->polygon);
}
 
cairo_status_t
_cairo_path_fixed_fill_to_polygon (const cairo_path_fixed_t *path,
double tolerance,
cairo_polygon_t *polygon)
{
cairo_filler_t filler;
cairo_status_t status;
 
_cairo_filler_init (&filler, tolerance, polygon);
 
status = _cairo_path_fixed_interpret (path,
CAIRO_DIRECTION_FORWARD,
_cairo_filler_move_to,
_cairo_filler_line_to,
_cairo_filler_curve_to,
_cairo_filler_close_path,
&filler);
if (unlikely (status))
return status;
 
status = _cairo_polygon_close (polygon);
_cairo_filler_fini (&filler);
 
return status;
}
 
cairo_status_t
_cairo_path_fixed_fill_to_traps (const cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_traps_t *traps)
{
cairo_polygon_t polygon;
cairo_status_t status;
 
if (path->is_empty_fill)
return CAIRO_STATUS_SUCCESS;
 
_cairo_polygon_init (&polygon);
if (traps->num_limits)
_cairo_polygon_limit (&polygon, traps->limits, traps->num_limits);
 
status = _cairo_path_fixed_fill_to_polygon (path,
tolerance,
&polygon);
if (unlikely (status || polygon.num_edges == 0))
goto CLEANUP;
 
if (path->is_rectilinear) {
status = _cairo_bentley_ottmann_tessellate_rectilinear_polygon (traps,
&polygon,
fill_rule);
} else {
status = _cairo_bentley_ottmann_tessellate_polygon (traps,
&polygon,
fill_rule);
}
 
CLEANUP:
_cairo_polygon_fini (&polygon);
return status;
}
 
static cairo_region_t *
_cairo_path_fixed_fill_rectilinear_tessellate_to_region (const cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
const cairo_rectangle_int_t *extents)
{
cairo_box_t box;
cairo_polygon_t polygon;
cairo_traps_t traps;
cairo_status_t status;
cairo_region_t *region;
 
/* first try to bypass fill-to-polygon */
_cairo_traps_init (&traps);
status = _cairo_path_fixed_fill_rectilinear_to_traps (path,
fill_rule,
&traps);
if (_cairo_status_is_error (status))
goto CLEANUP_TRAPS;
 
if (status == CAIRO_STATUS_SUCCESS) {
status = _cairo_traps_extract_region (&traps, &region);
goto CLEANUP_TRAPS;
}
 
/* path is not rectangular, try extracting clipped rectilinear edges */
_cairo_polygon_init (&polygon);
if (extents != NULL) {
_cairo_box_from_rectangle (&box, extents);
_cairo_polygon_limit (&polygon, &box, 1);
}
 
/* tolerance will be ignored as the path is rectilinear */
status = _cairo_path_fixed_fill_to_polygon (path, 0., &polygon);
if (unlikely (status))
goto CLEANUP_POLYGON;
 
if (polygon.num_edges == 0) {
region = cairo_region_create ();
} else {
status =
_cairo_bentley_ottmann_tessellate_rectilinear_polygon (&traps,
&polygon,
fill_rule);
if (likely (status == CAIRO_STATUS_SUCCESS))
status = _cairo_traps_extract_region (&traps, &region);
}
 
CLEANUP_POLYGON:
_cairo_polygon_fini (&polygon);
 
CLEANUP_TRAPS:
_cairo_traps_fini (&traps);
 
if (unlikely (status))
region = _cairo_region_create_in_error (status);
 
return region;
}
 
/* This special-case filler supports only a path that describes a
* device-axis aligned rectangle. It exists to avoid the overhead of
* the general tessellator when drawing very common rectangles.
*
* If the path described anything but a device-axis aligned rectangle,
* this function will abort.
*/
cairo_region_t *
_cairo_path_fixed_fill_rectilinear_to_region (const cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
const cairo_rectangle_int_t *extents)
{
cairo_rectangle_int_t rectangle_stack[CAIRO_STACK_ARRAY_LENGTH (cairo_rectangle_int_t)];
cairo_box_t box;
cairo_region_t *region = NULL;
 
assert (path->maybe_fill_region);
assert (! path->is_empty_fill);
 
if (_cairo_path_fixed_is_box (path, &box)) {
rectangle_stack[0].x = _cairo_fixed_integer_part (box.p1.x);
rectangle_stack[0].y = _cairo_fixed_integer_part (box.p1.y);
rectangle_stack[0].width = _cairo_fixed_integer_part (box.p2.x) -
rectangle_stack[0].x;
rectangle_stack[0].height = _cairo_fixed_integer_part (box.p2.y) -
rectangle_stack[0].y;
if (! _cairo_rectangle_intersect (&rectangle_stack[0], extents))
region = cairo_region_create ();
else
region = cairo_region_create_rectangle (&rectangle_stack[0]);
} else if (fill_rule == CAIRO_FILL_RULE_WINDING) {
cairo_rectangle_int_t *rects = rectangle_stack;
cairo_path_fixed_iter_t iter;
int last_cw = -1;
int size = ARRAY_LENGTH (rectangle_stack);
int count = 0;
 
/* Support a series of rectangles as can be expected to describe a
* GdkRegion clip region during exposes.
*/
_cairo_path_fixed_iter_init (&iter, path);
while (_cairo_path_fixed_iter_is_fill_box (&iter, &box)) {
int cw = 0;
 
if (box.p1.x > box.p2.x) {
cairo_fixed_t t;
 
t = box.p1.x;
box.p1.x = box.p2.x;
box.p2.x = t;
 
cw = ! cw;
}
 
if (box.p1.y > box.p2.y) {
cairo_fixed_t t;
 
t = box.p1.y;
box.p1.y = box.p2.y;
box.p2.y = t;
 
cw = ! cw;
}
 
if (last_cw < 0)
last_cw = cw;
else if (last_cw != cw)
goto TESSELLATE;
 
if (count == size) {
cairo_rectangle_int_t *new_rects;
 
size *= 4;
if (rects == rectangle_stack) {
new_rects = _cairo_malloc_ab (size,
sizeof (cairo_rectangle_int_t));
if (unlikely (new_rects == NULL)) {
/* XXX _cairo_region_nil */
break;
}
memcpy (new_rects, rects, sizeof (rectangle_stack));
} else {
new_rects = _cairo_realloc_ab (rects, size,
sizeof (cairo_rectangle_int_t));
if (unlikely (new_rects == NULL)) {
/* XXX _cairo_region_nil */
break;
}
}
rects = new_rects;
}
 
rects[count].x = _cairo_fixed_integer_part (box.p1.x);
rects[count].y = _cairo_fixed_integer_part (box.p1.y);
rects[count].width = _cairo_fixed_integer_part (box.p2.x) - rects[count].x;
rects[count].height = _cairo_fixed_integer_part (box.p2.y) - rects[count].y;
if (_cairo_rectangle_intersect (&rects[count], extents))
count++;
}
 
if (_cairo_path_fixed_iter_at_end (&iter))
region = cairo_region_create_rectangles (rects, count);
 
TESSELLATE:
if (rects != rectangle_stack)
free (rects);
}
 
if (region == NULL) {
/* Hmm, complex polygon */
region = _cairo_path_fixed_fill_rectilinear_tessellate_to_region (path,
fill_rule,
extents);
 
 
}
 
return region;
}
 
cairo_int_status_t
_cairo_path_fixed_fill_rectilinear_to_traps (const cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
cairo_traps_t *traps)
{
cairo_box_t box;
cairo_status_t status;
 
traps->is_rectilinear = TRUE;
traps->is_rectangular = TRUE;
 
if (_cairo_path_fixed_is_box (path, &box)) {
return _cairo_traps_tessellate_rectangle (traps, &box.p1, &box.p2);
} else {
cairo_path_fixed_iter_t iter;
 
_cairo_path_fixed_iter_init (&iter, path);
while (_cairo_path_fixed_iter_is_fill_box (&iter, &box)) {
if (box.p1.y > box.p2.y) {
cairo_fixed_t t;
 
t = box.p1.y;
box.p1.y = box.p2.y;
box.p2.y = t;
 
t = box.p1.x;
box.p1.x = box.p2.x;
box.p2.x = t;
}
 
status = _cairo_traps_tessellate_rectangle (traps,
&box.p1, &box.p2);
if (unlikely (status)) {
_cairo_traps_clear (traps);
return status;
}
}
 
if (_cairo_path_fixed_iter_at_end (&iter))
return _cairo_bentley_ottmann_tessellate_rectangular_traps (traps, fill_rule);
 
_cairo_traps_clear (traps);
return CAIRO_INT_STATUS_UNSUPPORTED;
}
}
 
static cairo_status_t
_cairo_path_fixed_fill_rectilinear_tessellate_to_boxes (const cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
cairo_boxes_t *boxes)
{
cairo_polygon_t polygon;
cairo_status_t status;
 
_cairo_polygon_init (&polygon);
if (boxes->num_limits) {
_cairo_polygon_limit (&polygon, boxes->limits, boxes->num_limits);
boxes->num_limits = 0;
}
 
/* tolerance will be ignored as the path is rectilinear */
status = _cairo_path_fixed_fill_to_polygon (path, 0., &polygon);
if (likely (status == CAIRO_STATUS_SUCCESS)) {
status =
_cairo_bentley_ottmann_tessellate_rectilinear_polygon_to_boxes (&polygon,
fill_rule,
boxes);
}
 
_cairo_polygon_fini (&polygon);
 
return status;
}
 
cairo_status_t
_cairo_path_fixed_fill_rectilinear_to_boxes (const cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
cairo_boxes_t *boxes)
{
cairo_path_fixed_iter_t iter;
cairo_status_t status;
cairo_box_t box;
 
if (_cairo_path_fixed_is_box (path, &box))
return _cairo_boxes_add (boxes, &box);
 
_cairo_path_fixed_iter_init (&iter, path);
while (_cairo_path_fixed_iter_is_fill_box (&iter, &box)) {
if (box.p1.y == box.p2.y || box.p1.x == box.p2.x)
continue;
 
if (box.p1.y > box.p2.y) {
cairo_fixed_t t;
 
t = box.p1.y;
box.p1.y = box.p2.y;
box.p2.y = t;
 
t = box.p1.x;
box.p1.x = box.p2.x;
box.p2.x = t;
}
 
status = _cairo_boxes_add (boxes, &box);
if (unlikely (status))
return status;
}
 
if (_cairo_path_fixed_iter_at_end (&iter))
return _cairo_bentley_ottmann_tessellate_boxes (boxes, fill_rule, boxes);
 
/* path is not rectangular, try extracting clipped rectilinear edges */
_cairo_boxes_clear (boxes);
return _cairo_path_fixed_fill_rectilinear_tessellate_to_boxes (path,
fill_rule,
boxes);
}
/programs/develop/libraries/cairo/src/cairo-path-fixed-private.h
0,0 → 1,165
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2005 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
* Carl D. Worth <cworth@redhat.com>
*/
 
#ifndef CAIRO_PATH_FIXED_PRIVATE_H
#define CAIRO_PATH_FIXED_PRIVATE_H
 
#include "cairo-types-private.h"
#include "cairo-compiler-private.h"
#include "cairo-list-private.h"
 
#define WATCH_PATH 0
#if WATCH_PATH
#include <stdio.h>
#endif
 
enum cairo_path_op {
CAIRO_PATH_OP_MOVE_TO = 0,
CAIRO_PATH_OP_LINE_TO = 1,
CAIRO_PATH_OP_CURVE_TO = 2,
CAIRO_PATH_OP_CLOSE_PATH = 3
};
 
/* we want to make sure a single byte is used for the enum */
typedef char cairo_path_op_t;
 
/* make _cairo_path_fixed fit into ~512 bytes -- about 50 items */
#define CAIRO_PATH_BUF_SIZE ((512 - sizeof (cairo_path_buf_t)) \
/ (2 * sizeof (cairo_point_t) + sizeof (cairo_path_op_t)))
 
typedef struct _cairo_path_buf {
cairo_list_t link;
unsigned int num_ops;
unsigned int size_ops;
unsigned int num_points;
unsigned int size_points;
 
cairo_path_op_t *op;
cairo_point_t *points;
} 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 {
cairo_point_t last_move_point;
cairo_point_t current_point;
unsigned int has_current_point : 1;
unsigned int has_last_move_point : 1;
unsigned int has_curve_to : 1;
unsigned int is_rectilinear : 1;
unsigned int maybe_fill_region : 1;
unsigned int is_empty_fill : 1;
 
cairo_box_t extents;
 
cairo_path_buf_fixed_t buf;
};
 
cairo_private void
_cairo_path_fixed_translate (cairo_path_fixed_t *path,
cairo_fixed_t offx,
cairo_fixed_t offy);
 
cairo_private cairo_status_t
_cairo_path_fixed_append (cairo_path_fixed_t *path,
const cairo_path_fixed_t *other,
cairo_direction_t dir,
cairo_fixed_t tx,
cairo_fixed_t ty);
 
cairo_private unsigned long
_cairo_path_fixed_hash (const cairo_path_fixed_t *path);
 
cairo_private unsigned long
_cairo_path_fixed_size (const cairo_path_fixed_t *path);
 
cairo_private cairo_bool_t
_cairo_path_fixed_equal (const cairo_path_fixed_t *a,
const cairo_path_fixed_t *b);
 
typedef struct _cairo_path_fixed_iter {
const cairo_path_buf_t *first;
const cairo_path_buf_t *buf;
unsigned int n_op;
unsigned int n_point;
} cairo_path_fixed_iter_t;
 
cairo_private void
_cairo_path_fixed_iter_init (cairo_path_fixed_iter_t *iter,
const cairo_path_fixed_t *path);
 
cairo_private cairo_bool_t
_cairo_path_fixed_iter_is_fill_box (cairo_path_fixed_iter_t *_iter,
cairo_box_t *box);
 
cairo_private cairo_bool_t
_cairo_path_fixed_iter_at_end (const cairo_path_fixed_iter_t *iter);
 
static inline cairo_bool_t
_cairo_path_fixed_fill_is_empty (const cairo_path_fixed_t *path)
{
return path->is_empty_fill;
}
 
static inline cairo_bool_t
_cairo_path_fixed_is_rectilinear_fill (const cairo_path_fixed_t *path)
{
if (! path->is_rectilinear)
return 0;
 
if (! path->has_current_point)
return 1;
 
/* check whether the implicit close preserves the rectilinear property */
return path->current_point.x == path->last_move_point.x ||
path->current_point.y == path->last_move_point.y;
}
 
static inline cairo_bool_t
_cairo_path_fixed_maybe_fill_region (const cairo_path_fixed_t *path)
{
#if WATCH_PATH
fprintf (stderr, "_cairo_path_fixed_maybe_fill_region () = %s\n",
path->maybe_fill_region ? "true" : "false");
#endif
return path->maybe_fill_region;
}
 
#endif /* CAIRO_PATH_FIXED_PRIVATE_H */
/programs/develop/libraries/cairo/src/cairo-path-fixed.c
0,0 → 1,1424
/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2002 University of Southern California
* Copyright © 2005 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
*/
 
#include "cairoint.h"
 
#include "cairo-error-private.h"
#include "cairo-path-fixed-private.h"
#include "cairo-slope-private.h"
 
static cairo_status_t
_cairo_path_fixed_add (cairo_path_fixed_t *path,
cairo_path_op_t op,
const cairo_point_t *points,
int num_points);
 
static void
_cairo_path_fixed_add_buf (cairo_path_fixed_t *path,
cairo_path_buf_t *buf);
 
static cairo_path_buf_t *
_cairo_path_buf_create (int size_ops, int size_points);
 
static void
_cairo_path_buf_destroy (cairo_path_buf_t *buf);
 
static void
_cairo_path_buf_add_op (cairo_path_buf_t *buf,
cairo_path_op_t op);
 
static void
_cairo_path_buf_add_points (cairo_path_buf_t *buf,
const cairo_point_t *points,
int num_points);
 
#define cairo_path_head(path__) (&(path__)->buf.base)
#define cairo_path_tail(path__) cairo_path_buf_prev (cairo_path_head (path__))
 
#define cairo_path_buf_next(pos__) \
cairo_list_entry ((pos__)->link.next, cairo_path_buf_t, link)
#define cairo_path_buf_prev(pos__) \
cairo_list_entry ((pos__)->link.prev, cairo_path_buf_t, link)
 
#define cairo_path_foreach_buf_start(pos__, path__) \
pos__ = cairo_path_head (path__); do
#define cairo_path_foreach_buf_end(pos__, path__) \
while ((pos__ = cairo_path_buf_next (pos__)) != cairo_path_head (path__))
 
void
_cairo_path_fixed_init (cairo_path_fixed_t *path)
{
VG (VALGRIND_MAKE_MEM_UNDEFINED (path, sizeof (cairo_path_fixed_t)));
 
cairo_list_init (&path->buf.base.link);
 
path->buf.base.num_ops = 0;
path->buf.base.num_points = 0;
path->buf.base.size_ops = ARRAY_LENGTH (path->buf.op);
path->buf.base.size_points = ARRAY_LENGTH (path->buf.points);
path->buf.base.op = path->buf.op;
path->buf.base.points = path->buf.points;
 
path->current_point.x = 0;
path->current_point.y = 0;
path->last_move_point = path->current_point;
path->has_last_move_point = FALSE;
path->has_current_point = FALSE;
path->has_curve_to = FALSE;
path->is_rectilinear = TRUE;
path->maybe_fill_region = TRUE;
path->is_empty_fill = TRUE;
 
path->extents.p1.x = path->extents.p1.y = INT_MAX;
path->extents.p2.x = path->extents.p2.y = INT_MIN;
}
 
cairo_status_t
_cairo_path_fixed_init_copy (cairo_path_fixed_t *path,
const cairo_path_fixed_t *other)
{
cairo_path_buf_t *buf, *other_buf;
unsigned int num_points, num_ops;
 
VG (VALGRIND_MAKE_MEM_UNDEFINED (path, sizeof (cairo_path_fixed_t)));
 
cairo_list_init (&path->buf.base.link);
 
path->buf.base.op = path->buf.op;
path->buf.base.points = path->buf.points;
path->buf.base.size_ops = ARRAY_LENGTH (path->buf.op);
path->buf.base.size_points = ARRAY_LENGTH (path->buf.points);
 
path->current_point = other->current_point;
path->last_move_point = other->last_move_point;
path->has_last_move_point = other->has_last_move_point;
path->has_current_point = other->has_current_point;
path->has_curve_to = other->has_curve_to;
path->is_rectilinear = other->is_rectilinear;
path->maybe_fill_region = other->maybe_fill_region;
path->is_empty_fill = other->is_empty_fill;
 
path->extents = other->extents;
 
path->buf.base.num_ops = other->buf.base.num_ops;
path->buf.base.num_points = other->buf.base.num_points;
memcpy (path->buf.op, other->buf.base.op,
other->buf.base.num_ops * sizeof (other->buf.op[0]));
memcpy (path->buf.points, other->buf.points,
other->buf.base.num_points * sizeof (other->buf.points[0]));
 
num_points = num_ops = 0;
for (other_buf = cairo_path_buf_next (cairo_path_head (other));
other_buf != cairo_path_head (other);
other_buf = cairo_path_buf_next (other_buf))
{
num_ops += other_buf->num_ops;
num_points += other_buf->num_points;
}
 
if (num_ops) {
buf = _cairo_path_buf_create (num_ops, num_points);
if (unlikely (buf == NULL)) {
_cairo_path_fixed_fini (path);
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
 
for (other_buf = cairo_path_buf_next (cairo_path_head (other));
other_buf != cairo_path_head (other);
other_buf = cairo_path_buf_next (other_buf))
{
memcpy (buf->op + buf->num_ops, other_buf->op,
other_buf->num_ops * sizeof (buf->op[0]));
buf->num_ops += other_buf->num_ops;
 
memcpy (buf->points + buf->num_points, other_buf->points,
other_buf->num_points * sizeof (buf->points[0]));
buf->num_points += other_buf->num_points;
}
 
_cairo_path_fixed_add_buf (path, buf);
}
 
return CAIRO_STATUS_SUCCESS;
}
 
unsigned long
_cairo_path_fixed_hash (const cairo_path_fixed_t *path)
{
unsigned long hash = _CAIRO_HASH_INIT_VALUE;
const cairo_path_buf_t *buf;
int num_points, num_ops;
 
hash = _cairo_hash_bytes (hash, &path->extents, sizeof (path->extents));
 
num_ops = num_points = 0;
cairo_path_foreach_buf_start (buf, path) {
hash = _cairo_hash_bytes (hash, buf->op,
buf->num_ops * sizeof (buf->op[0]));
hash = _cairo_hash_bytes (hash, buf->points,
buf->num_points * sizeof (buf->points[0]));
 
num_ops += buf->num_ops;
num_points += buf->num_points;
} cairo_path_foreach_buf_end (buf, path);
 
hash = _cairo_hash_bytes (hash, &num_ops, sizeof (num_ops));
hash = _cairo_hash_bytes (hash, &num_points, sizeof (num_points));
 
return hash;
}
 
unsigned long
_cairo_path_fixed_size (const cairo_path_fixed_t *path)
{
const cairo_path_buf_t *buf;
int num_points, num_ops;
 
num_ops = num_points = 0;
cairo_path_foreach_buf_start (buf, path) {
num_ops += buf->num_ops;
num_points += buf->num_points;
} cairo_path_foreach_buf_end (buf, path);
 
return num_ops * sizeof (buf->op[0]) +
num_points * sizeof (buf->points[0]);
}
 
cairo_bool_t
_cairo_path_fixed_equal (const cairo_path_fixed_t *a,
const cairo_path_fixed_t *b)
{
const cairo_path_buf_t *buf_a, *buf_b;
const cairo_path_op_t *ops_a, *ops_b;
const cairo_point_t *points_a, *points_b;
int num_points_a, num_ops_a;
int num_points_b, num_ops_b;
 
if (a == b)
return TRUE;
 
/* use the flags to quickly differentiate based on contents */
if (a->is_empty_fill != b->is_empty_fill ||
a->has_curve_to != b->has_curve_to ||
a->maybe_fill_region != b->maybe_fill_region ||
a->is_rectilinear != b->is_rectilinear)
{
return FALSE;
}
 
if (a->extents.p1.x != b->extents.p1.x ||
a->extents.p1.y != b->extents.p1.y ||
a->extents.p2.x != b->extents.p2.x ||
a->extents.p2.y != b->extents.p2.y)
{
return FALSE;
}
 
num_ops_a = num_points_a = 0;
cairo_path_foreach_buf_start (buf_a, a) {
num_ops_a += buf_a->num_ops;
num_points_a += buf_a->num_points;
} cairo_path_foreach_buf_end (buf_a, a);
 
num_ops_b = num_points_b = 0;
cairo_path_foreach_buf_start (buf_b, b) {
num_ops_b += buf_b->num_ops;
num_points_b += buf_b->num_points;
} cairo_path_foreach_buf_end (buf_b, b);
 
if (num_ops_a == 0 && num_ops_b == 0)
return TRUE;
 
if (num_ops_a != num_ops_b || num_points_a != num_points_b)
return FALSE;
 
buf_a = cairo_path_head (a);
num_points_a = buf_a->num_points;
num_ops_a = buf_a->num_ops;
ops_a = buf_a->op;
points_a = buf_a->points;
 
buf_b = cairo_path_head (b);
num_points_b = buf_b->num_points;
num_ops_b = buf_b->num_ops;
ops_b = buf_b->op;
points_b = buf_b->points;
 
while (TRUE) {
int num_ops = MIN (num_ops_a, num_ops_b);
int num_points = MIN (num_points_a, num_points_b);
 
if (memcmp (ops_a, ops_b, num_ops * sizeof (cairo_path_op_t)))
return FALSE;
if (memcmp (points_a, points_b, num_points * sizeof (cairo_point_t)))
return FALSE;
 
num_ops_a -= num_ops;
ops_a += num_ops;
num_points_a -= num_points;
points_a += num_points;
if (num_ops_a == 0 || num_points_a == 0) {
if (num_ops_a || num_points_a)
return FALSE;
 
buf_a = cairo_path_buf_next (buf_a);
if (buf_a == cairo_path_head (a))
break;
 
num_points_a = buf_a->num_points;
num_ops_a = buf_a->num_ops;
ops_a = buf_a->op;
points_a = buf_a->points;
}
 
num_ops_b -= num_ops;
ops_b += num_ops;
num_points_b -= num_points;
points_b += num_points;
if (num_ops_b == 0 || num_points_b == 0) {
if (num_ops_b || num_points_b)
return FALSE;
 
buf_b = cairo_path_buf_next (buf_b);
if (buf_b == cairo_path_head (b))
break;
 
num_points_b = buf_b->num_points;
num_ops_b = buf_b->num_ops;
ops_b = buf_b->op;
points_b = buf_b->points;
}
}
 
return TRUE;
}
 
cairo_path_fixed_t *
_cairo_path_fixed_create (void)
{
cairo_path_fixed_t *path;
 
path = malloc (sizeof (cairo_path_fixed_t));
if (!path) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return NULL;
}
 
_cairo_path_fixed_init (path);
return path;
}
 
void
_cairo_path_fixed_fini (cairo_path_fixed_t *path)
{
cairo_path_buf_t *buf;
 
buf = cairo_path_buf_next (cairo_path_head (path));
while (buf != cairo_path_head (path)) {
cairo_path_buf_t *this = buf;
buf = cairo_path_buf_next (buf);
_cairo_path_buf_destroy (this);
}
 
VG (VALGRIND_MAKE_MEM_NOACCESS (path, sizeof (cairo_path_fixed_t)));
}
 
void
_cairo_path_fixed_destroy (cairo_path_fixed_t *path)
{
_cairo_path_fixed_fini (path);
free (path);
}
 
static cairo_path_op_t
_cairo_path_last_op (cairo_path_fixed_t *path)
{
cairo_path_buf_t *buf;
 
buf = cairo_path_tail (path);
if (buf->num_ops == 0)
return -1;
 
return buf->op[buf->num_ops - 1];
}
 
static inline void
_cairo_path_fixed_extents_add (cairo_path_fixed_t *path,
const cairo_point_t *point)
{
if (point->x < path->extents.p1.x)
path->extents.p1.x = point->x;
if (point->y < path->extents.p1.y)
path->extents.p1.y = point->y;
 
if (point->x > path->extents.p2.x)
path->extents.p2.x = point->x;
if (point->y > path->extents.p2.y)
path->extents.p2.y = point->y;
}
 
cairo_status_t
_cairo_path_fixed_move_to (cairo_path_fixed_t *path,
cairo_fixed_t x,
cairo_fixed_t y)
{
cairo_status_t status;
cairo_point_t point;
 
point.x = x;
point.y = y;
 
/* If the previous op was also a MOVE_TO, then just change its
* point rather than adding a new op. */
if (_cairo_path_last_op (path) == CAIRO_PATH_OP_MOVE_TO) {
cairo_path_buf_t *buf;
 
buf = cairo_path_tail (path);
buf->points[buf->num_points - 1] = point;
} else {
status = _cairo_path_fixed_add (path, CAIRO_PATH_OP_MOVE_TO, &point, 1);
if (unlikely (status))
return status;
 
if (path->has_current_point && path->is_rectilinear) {
/* a move-to is first an implicit close */
path->is_rectilinear = path->current_point.x == path->last_move_point.x ||
path->current_point.y == path->last_move_point.y;
path->maybe_fill_region &= path->is_rectilinear;
}
if (path->maybe_fill_region) {
path->maybe_fill_region =
_cairo_fixed_is_integer (path->last_move_point.x) &&
_cairo_fixed_is_integer (path->last_move_point.y);
}
}
 
path->current_point = point;
path->last_move_point = point;
path->has_last_move_point = TRUE;
path->has_current_point = TRUE;
 
return CAIRO_STATUS_SUCCESS;
}
 
void
_cairo_path_fixed_new_sub_path (cairo_path_fixed_t *path)
{
path->has_current_point = FALSE;
}
 
cairo_status_t
_cairo_path_fixed_rel_move_to (cairo_path_fixed_t *path,
cairo_fixed_t dx,
cairo_fixed_t dy)
{
if (unlikely (! path->has_current_point))
return _cairo_error (CAIRO_STATUS_NO_CURRENT_POINT);
 
return _cairo_path_fixed_move_to (path,
path->current_point.x + dx,
path->current_point.y + dy);
 
}
 
cairo_status_t
_cairo_path_fixed_line_to (cairo_path_fixed_t *path,
cairo_fixed_t x,
cairo_fixed_t y)
{
cairo_status_t status;
cairo_point_t point;
 
point.x = x;
point.y = y;
 
/* When there is not yet a current point, the line_to operation
* becomes a move_to instead. Note: We have to do this by
* explicitly calling into _cairo_path_fixed_move_to to ensure
* that the last_move_point state is updated properly.
*/
if (! path->has_current_point)
return _cairo_path_fixed_move_to (path, point.x, point.y);
 
/* If the previous op was but the initial MOVE_TO and this segment
* is degenerate, then we can simply skip this point. Note that
* a move-to followed by a degenerate line-to is a valid path for
* stroking, but at all other times is simply a degenerate segment.
*/
if (_cairo_path_last_op (path) != CAIRO_PATH_OP_MOVE_TO) {
if (x == path->current_point.x && y == path->current_point.y)
return CAIRO_STATUS_SUCCESS;
}
 
/* If the previous op was also a LINE_TO with the same gradient,
* then just change its end-point rather than adding a new op.
*/
if (_cairo_path_last_op (path) == CAIRO_PATH_OP_LINE_TO) {
cairo_path_buf_t *buf;
const cairo_point_t *p;
 
buf = cairo_path_tail (path);
if (likely (buf->num_points >= 2)) {
p = &buf->points[buf->num_points-2];
} else {
cairo_path_buf_t *prev_buf = cairo_path_buf_prev (buf);
p = &prev_buf->points[prev_buf->num_points - (2 - buf->num_points)];
}
 
if (p->x == path->current_point.x && p->y == path->current_point.y) {
/* previous line element was degenerate, replace */
buf->points[buf->num_points - 1] = point;
goto FLAGS;
} else {
cairo_slope_t prev, self;
 
_cairo_slope_init (&prev, p, &path->current_point);
_cairo_slope_init (&self, &path->current_point, &point);
if (_cairo_slope_equal (&prev, &self) &&
/* cannot trim anti-parallel segments whilst stroking */
! _cairo_slope_backwards (&prev, &self))
{
buf->points[buf->num_points - 1] = point;
goto FLAGS;
}
}
}
 
status = _cairo_path_fixed_add (path, CAIRO_PATH_OP_LINE_TO, &point, 1);
if (unlikely (status))
return status;
 
FLAGS:
if (path->is_rectilinear) {
path->is_rectilinear = path->current_point.x == x ||
path->current_point.y == y;
path->maybe_fill_region &= path->is_rectilinear;
}
if (path->maybe_fill_region) {
path->maybe_fill_region = _cairo_fixed_is_integer (x) &&
_cairo_fixed_is_integer (y);
}
if (path->is_empty_fill) {
path->is_empty_fill = path->current_point.x == x &&
path->current_point.y == y;
}
 
path->current_point = point;
if (path->has_last_move_point) {
_cairo_path_fixed_extents_add (path, &path->last_move_point);
path->has_last_move_point = FALSE;
}
_cairo_path_fixed_extents_add (path, &point);
return CAIRO_STATUS_SUCCESS;
}
 
cairo_status_t
_cairo_path_fixed_rel_line_to (cairo_path_fixed_t *path,
cairo_fixed_t dx,
cairo_fixed_t dy)
{
if (unlikely (! path->has_current_point))
return _cairo_error (CAIRO_STATUS_NO_CURRENT_POINT);
 
return _cairo_path_fixed_line_to (path,
path->current_point.x + dx,
path->current_point.y + dy);
}
 
cairo_status_t
_cairo_path_fixed_curve_to (cairo_path_fixed_t *path,
cairo_fixed_t x0, cairo_fixed_t y0,
cairo_fixed_t x1, cairo_fixed_t y1,
cairo_fixed_t x2, cairo_fixed_t y2)
{
cairo_status_t status;
cairo_point_t point[3];
 
/* make sure subpaths are started properly */
if (! path->has_current_point) {
status = _cairo_path_fixed_move_to (path, x0, y0);
if (unlikely (status))
return status;
}
 
point[0].x = x0; point[0].y = y0;
point[1].x = x1; point[1].y = y1;
point[2].x = x2; point[2].y = y2;
status = _cairo_path_fixed_add (path, CAIRO_PATH_OP_CURVE_TO, point, 3);
if (unlikely (status))
return status;
 
path->current_point = point[2];
path->has_current_point = TRUE;
path->is_empty_fill = FALSE;
path->has_curve_to = TRUE;
path->is_rectilinear = FALSE;
path->maybe_fill_region = FALSE;
 
/* coarse bounds */
if (path->has_last_move_point) {
_cairo_path_fixed_extents_add (path, &path->last_move_point);
path->has_last_move_point = FALSE;
}
_cairo_path_fixed_extents_add (path, &point[0]);
_cairo_path_fixed_extents_add (path, &point[1]);
_cairo_path_fixed_extents_add (path, &point[2]);
 
return CAIRO_STATUS_SUCCESS;
}
 
cairo_status_t
_cairo_path_fixed_rel_curve_to (cairo_path_fixed_t *path,
cairo_fixed_t dx0, cairo_fixed_t dy0,
cairo_fixed_t dx1, cairo_fixed_t dy1,
cairo_fixed_t dx2, cairo_fixed_t dy2)
{
if (unlikely (! path->has_current_point))
return _cairo_error (CAIRO_STATUS_NO_CURRENT_POINT);
 
return _cairo_path_fixed_curve_to (path,
path->current_point.x + dx0,
path->current_point.y + dy0,
 
path->current_point.x + dx1,
path->current_point.y + dy1,
 
path->current_point.x + dx2,
path->current_point.y + dy2);
}
 
cairo_status_t
_cairo_path_fixed_close_path (cairo_path_fixed_t *path)
{
cairo_status_t status;
 
if (! path->has_current_point)
return CAIRO_STATUS_SUCCESS;
 
/* If the previous op was also a LINE_TO back to the start, discard it */
if (_cairo_path_last_op (path) == CAIRO_PATH_OP_LINE_TO) {
if (path->current_point.x == path->last_move_point.x &&
path->current_point.y == path->last_move_point.y)
{
cairo_path_buf_t *buf;
cairo_point_t *p;
 
buf = cairo_path_tail (path);
if (likely (buf->num_points >= 2)) {
p = &buf->points[buf->num_points-2];
} else {
cairo_path_buf_t *prev_buf = cairo_path_buf_prev (buf);
p = &prev_buf->points[prev_buf->num_points - (2 - buf->num_points)];
}
 
path->current_point = *p;
buf->num_ops--;
buf->num_points--;
}
}
 
status = _cairo_path_fixed_add (path, CAIRO_PATH_OP_CLOSE_PATH, NULL, 0);
if (unlikely (status))
return status;
 
return _cairo_path_fixed_move_to (path,
path->last_move_point.x,
path->last_move_point.y);
}
 
cairo_bool_t
_cairo_path_fixed_get_current_point (cairo_path_fixed_t *path,
cairo_fixed_t *x,
cairo_fixed_t *y)
{
if (! path->has_current_point)
return FALSE;
 
*x = path->current_point.x;
*y = path->current_point.y;
 
return TRUE;
}
 
static cairo_status_t
_cairo_path_fixed_add (cairo_path_fixed_t *path,
cairo_path_op_t op,
const cairo_point_t *points,
int num_points)
{
cairo_path_buf_t *buf = cairo_path_tail (path);
 
if (buf->num_ops + 1 > buf->size_ops ||
buf->num_points + num_points > buf->size_points)
{
buf = _cairo_path_buf_create (buf->num_ops * 2, buf->num_points * 2);
if (unlikely (buf == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
_cairo_path_fixed_add_buf (path, buf);
}
 
if (WATCH_PATH) {
const char *op_str[] = {
"move-to",
"line-to",
"curve-to",
"close-path",
};
char buf[1024];
int len = 0;
int i;
 
len += snprintf (buf + len, sizeof (buf), "[");
for (i = 0; i < num_points; i++) {
if (i != 0)
len += snprintf (buf + len, sizeof (buf), " ");
len += snprintf (buf + len, sizeof (buf), "(%f, %f)",
_cairo_fixed_to_double (points[i].x),
_cairo_fixed_to_double (points[i].y));
}
len += snprintf (buf + len, sizeof (buf), "]");
 
fprintf (stderr,
"_cairo_path_fixed_add (%s, %s)\n",
op_str[(int) op], buf);
}
 
_cairo_path_buf_add_op (buf, op);
_cairo_path_buf_add_points (buf, points, num_points);
 
return CAIRO_STATUS_SUCCESS;
}
 
static void
_cairo_path_fixed_add_buf (cairo_path_fixed_t *path,
cairo_path_buf_t *buf)
{
cairo_list_add_tail (&buf->link, &cairo_path_head (path)->link);
}
 
COMPILE_TIME_ASSERT (sizeof (cairo_path_op_t) == 1);
static cairo_path_buf_t *
_cairo_path_buf_create (int size_ops, int size_points)
{
cairo_path_buf_t *buf;
 
/* adjust size_ops to ensure that buf->points is naturally aligned */
size_ops += sizeof (double) - ((sizeof (cairo_path_buf_t) + size_ops) % sizeof (double));
buf = _cairo_malloc_ab_plus_c (size_points, sizeof (cairo_point_t), size_ops + sizeof (cairo_path_buf_t));
if (buf) {
buf->num_ops = 0;
buf->num_points = 0;
buf->size_ops = size_ops;
buf->size_points = size_points;
 
buf->op = (cairo_path_op_t *) (buf + 1);
buf->points = (cairo_point_t *) (buf->op + size_ops);
}
 
return buf;
}
 
static void
_cairo_path_buf_destroy (cairo_path_buf_t *buf)
{
free (buf);
}
 
static void
_cairo_path_buf_add_op (cairo_path_buf_t *buf,
cairo_path_op_t op)
{
buf->op[buf->num_ops++] = op;
}
 
static void
_cairo_path_buf_add_points (cairo_path_buf_t *buf,
const cairo_point_t *points,
int num_points)
{
memcpy (buf->points + buf->num_points,
points,
sizeof (points[0]) * num_points);
buf->num_points += num_points;
}
 
cairo_status_t
_cairo_path_fixed_interpret (const cairo_path_fixed_t *path,
cairo_direction_t dir,
cairo_path_fixed_move_to_func_t *move_to,
cairo_path_fixed_line_to_func_t *line_to,
cairo_path_fixed_curve_to_func_t *curve_to,
cairo_path_fixed_close_path_func_t *close_path,
void *closure)
{
const uint8_t num_args[] = {
1, /* cairo_path_move_to */
1, /* cairo_path_op_line_to */
3, /* cairo_path_op_curve_to */
0, /* cairo_path_op_close_path */
};
cairo_status_t status;
const cairo_path_buf_t *buf, *first;
cairo_bool_t forward = (dir == CAIRO_DIRECTION_FORWARD);
int step = forward ? 1 : -1;
 
buf = first = forward ? cairo_path_head (path) : cairo_path_tail (path);
do {
cairo_point_t *points;
int start, stop, i;
 
if (forward) {
start = 0;
stop = buf->num_ops;
points = buf->points;
} else {
start = buf->num_ops - 1;
stop = -1;
points = buf->points + buf->num_points;
}
 
for (i = start; i != stop; i += step) {
cairo_path_op_t op = buf->op[i];
 
if (! forward)
points -= num_args[(int) op];
 
switch (op) {
case CAIRO_PATH_OP_MOVE_TO:
status = (*move_to) (closure, &points[0]);
break;
case CAIRO_PATH_OP_LINE_TO:
status = (*line_to) (closure, &points[0]);
break;
case CAIRO_PATH_OP_CURVE_TO:
status = (*curve_to) (closure, &points[0], &points[1], &points[2]);
break;
default:
ASSERT_NOT_REACHED;
case CAIRO_PATH_OP_CLOSE_PATH:
status = (*close_path) (closure);
break;
}
if (unlikely (status))
return status;
 
if (forward)
points += num_args[(int) op];
}
} while ((buf = forward ? cairo_path_buf_next (buf) : cairo_path_buf_prev (buf)) != first);
 
return CAIRO_STATUS_SUCCESS;
}
 
typedef struct _cairo_path_fixed_append_closure {
cairo_point_t offset;
cairo_path_fixed_t *path;
} cairo_path_fixed_append_closure_t;
 
static cairo_status_t
_append_move_to (void *abstract_closure,
const cairo_point_t *point)
{
cairo_path_fixed_append_closure_t *closure = abstract_closure;
 
return _cairo_path_fixed_move_to (closure->path,
point->x + closure->offset.x,
point->y + closure->offset.y);
}
 
static cairo_status_t
_append_line_to (void *abstract_closure,
const cairo_point_t *point)
{
cairo_path_fixed_append_closure_t *closure = abstract_closure;
 
return _cairo_path_fixed_line_to (closure->path,
point->x + closure->offset.x,
point->y + closure->offset.y);
}
 
static cairo_status_t
_append_curve_to (void *abstract_closure,
const cairo_point_t *p0,
const cairo_point_t *p1,
const cairo_point_t *p2)
{
cairo_path_fixed_append_closure_t *closure = abstract_closure;
 
return _cairo_path_fixed_curve_to (closure->path,
p0->x + closure->offset.x,
p0->y + closure->offset.y,
p1->x + closure->offset.x,
p1->y + closure->offset.y,
p2->x + closure->offset.x,
p2->y + closure->offset.y);
}
 
static cairo_status_t
_append_close_path (void *abstract_closure)
{
cairo_path_fixed_append_closure_t *closure = abstract_closure;
 
return _cairo_path_fixed_close_path (closure->path);
}
 
cairo_status_t
_cairo_path_fixed_append (cairo_path_fixed_t *path,
const cairo_path_fixed_t *other,
cairo_direction_t dir,
cairo_fixed_t tx,
cairo_fixed_t ty)
{
cairo_path_fixed_append_closure_t closure;
 
closure.path = path;
closure.offset.x = tx;
closure.offset.y = ty;
 
return _cairo_path_fixed_interpret (other, dir,
_append_move_to,
_append_line_to,
_append_curve_to,
_append_close_path,
&closure);
}
 
static void
_cairo_path_fixed_offset_and_scale (cairo_path_fixed_t *path,
cairo_fixed_t offx,
cairo_fixed_t offy,
cairo_fixed_t scalex,
cairo_fixed_t scaley)
{
cairo_path_buf_t *buf;
unsigned int i;
 
if (path->maybe_fill_region) {
path->maybe_fill_region = _cairo_fixed_is_integer (offx) &&
_cairo_fixed_is_integer (offy) &&
_cairo_fixed_is_integer (scalex) &&
_cairo_fixed_is_integer (scaley);
}
 
cairo_path_foreach_buf_start (buf, path) {
for (i = 0; i < buf->num_points; i++) {
if (scalex != CAIRO_FIXED_ONE)
buf->points[i].x = _cairo_fixed_mul (buf->points[i].x, scalex);
buf->points[i].x += offx;
 
if (scaley != CAIRO_FIXED_ONE)
buf->points[i].y = _cairo_fixed_mul (buf->points[i].y, scaley);
buf->points[i].y += offy;
}
} cairo_path_foreach_buf_end (buf, path);
 
path->extents.p1.x = _cairo_fixed_mul (scalex, path->extents.p1.x) + offx;
path->extents.p2.x = _cairo_fixed_mul (scalex, path->extents.p2.x) + offx;
 
path->extents.p1.y = _cairo_fixed_mul (scaley, path->extents.p1.y) + offy;
path->extents.p2.y = _cairo_fixed_mul (scaley, path->extents.p2.y) + offy;
}
 
void
_cairo_path_fixed_translate (cairo_path_fixed_t *path,
cairo_fixed_t offx,
cairo_fixed_t offy)
{
cairo_path_buf_t *buf;
unsigned int i;
 
if (offx == 0 && offy == 0)
return;
 
if (path->maybe_fill_region &&
! (_cairo_fixed_is_integer (offx) && _cairo_fixed_is_integer (offy)))
{
path->maybe_fill_region = FALSE;
}
 
path->last_move_point.x += offx;
path->last_move_point.y += offy;
path->current_point.x += offx;
path->current_point.y += offy;
 
cairo_path_foreach_buf_start (buf, path) {
for (i = 0; i < buf->num_points; i++) {
buf->points[i].x += offx;
buf->points[i].y += offy;
}
} cairo_path_foreach_buf_end (buf, path);
 
path->extents.p1.x += offx;
path->extents.p1.y += offy;
path->extents.p2.x += offx;
path->extents.p2.y += offy;
}
 
/**
* _cairo_path_fixed_transform:
* @path: a #cairo_path_fixed_t to be transformed
* @matrix: a #cairo_matrix_t
*
* Transform the fixed-point path according to the given matrix.
* There is a fast path for the case where @matrix has no rotation
* or shear.
**/
void
_cairo_path_fixed_transform (cairo_path_fixed_t *path,
const cairo_matrix_t *matrix)
{
cairo_path_buf_t *buf;
unsigned int i;
double dx, dy;
 
/* XXX current_point, last_move_to */
 
if (matrix->yx == 0.0 && matrix->xy == 0.0) {
/* Fast path for the common case of scale+transform */
if (matrix->xx == 1. && matrix->yy == 1.) {
_cairo_path_fixed_translate (path,
_cairo_fixed_from_double (matrix->x0),
_cairo_fixed_from_double (matrix->y0));
} else {
_cairo_path_fixed_offset_and_scale (path,
_cairo_fixed_from_double (matrix->x0),
_cairo_fixed_from_double (matrix->y0),
_cairo_fixed_from_double (matrix->xx),
_cairo_fixed_from_double (matrix->yy));
}
return;
}
 
path->extents.p1.x = path->extents.p1.y = INT_MAX;
path->extents.p2.x = path->extents.p2.y = INT_MIN;
path->maybe_fill_region = FALSE;
cairo_path_foreach_buf_start (buf, path) {
for (i = 0; i < buf->num_points; i++) {
dx = _cairo_fixed_to_double (buf->points[i].x);
dy = _cairo_fixed_to_double (buf->points[i].y);
 
cairo_matrix_transform_point (matrix, &dx, &dy);
 
buf->points[i].x = _cairo_fixed_from_double (dx);
buf->points[i].y = _cairo_fixed_from_double (dy);
 
/* XXX need to eliminate surplus move-to's? */
_cairo_path_fixed_extents_add (path, &buf->points[i]);
}
} cairo_path_foreach_buf_end (buf, path);
}
 
cairo_bool_t
_cairo_path_fixed_is_equal (const cairo_path_fixed_t *path,
const cairo_path_fixed_t *other)
{
const cairo_path_buf_t *path_buf, *other_buf;
 
if (path->current_point.x != other->current_point.x ||
path->current_point.y != other->current_point.y ||
path->has_current_point != other->has_current_point ||
path->has_curve_to != other->has_curve_to ||
path->is_rectilinear != other->is_rectilinear ||
path->maybe_fill_region != other->maybe_fill_region ||
path->last_move_point.x != other->last_move_point.x ||
path->last_move_point.y != other->last_move_point.y)
{
return FALSE;
}
 
other_buf = cairo_path_head (other);
cairo_path_foreach_buf_start (path_buf, path) {
if (path_buf->num_ops != other_buf->num_ops ||
path_buf->num_points != other_buf->num_points ||
memcmp (path_buf->op, other_buf->op,
sizeof (cairo_path_op_t) * path_buf->num_ops) != 0 ||
memcmp (path_buf->points, other_buf->points,
sizeof (cairo_point_t) * path_buf->num_points) != 0)
{
return FALSE;
}
other_buf = cairo_path_buf_next (other_buf);
} cairo_path_foreach_buf_end (path_buf, path);
 
return TRUE;
}
 
/* Closure for path flattening */
typedef struct cairo_path_flattener {
double tolerance;
cairo_point_t current_point;
cairo_path_fixed_move_to_func_t *move_to;
cairo_path_fixed_line_to_func_t *line_to;
cairo_path_fixed_close_path_func_t *close_path;
void *closure;
} cpf_t;
 
static cairo_status_t
_cpf_move_to (void *closure,
const cairo_point_t *point)
{
cpf_t *cpf = closure;
 
cpf->current_point = *point;
 
return cpf->move_to (cpf->closure, point);
}
 
static cairo_status_t
_cpf_line_to (void *closure,
const cairo_point_t *point)
{
cpf_t *cpf = closure;
 
cpf->current_point = *point;
 
return cpf->line_to (cpf->closure, point);
}
 
static cairo_status_t
_cpf_curve_to (void *closure,
const cairo_point_t *p1,
const cairo_point_t *p2,
const cairo_point_t *p3)
{
cpf_t *cpf = closure;
cairo_spline_t spline;
 
cairo_point_t *p0 = &cpf->current_point;
 
if (! _cairo_spline_init (&spline,
cpf->line_to,
cpf->closure,
p0, p1, p2, p3))
{
return _cpf_line_to (closure, p3);
}
 
cpf->current_point = *p3;
 
return _cairo_spline_decompose (&spline, cpf->tolerance);
}
 
static cairo_status_t
_cpf_close_path (void *closure)
{
cpf_t *cpf = closure;
 
return cpf->close_path (cpf->closure);
}
 
cairo_status_t
_cairo_path_fixed_interpret_flat (const cairo_path_fixed_t *path,
cairo_direction_t dir,
cairo_path_fixed_move_to_func_t *move_to,
cairo_path_fixed_line_to_func_t *line_to,
cairo_path_fixed_close_path_func_t *close_path,
void *closure,
double tolerance)
{
cpf_t flattener;
 
if (! path->has_curve_to) {
return _cairo_path_fixed_interpret (path, dir,
move_to,
line_to,
NULL,
close_path,
closure);
}
 
flattener.tolerance = tolerance;
flattener.move_to = move_to;
flattener.line_to = line_to;
flattener.close_path = close_path;
flattener.closure = closure;
return _cairo_path_fixed_interpret (path, dir,
_cpf_move_to,
_cpf_line_to,
_cpf_curve_to,
_cpf_close_path,
&flattener);
}
 
static inline void
_canonical_box (cairo_box_t *box,
const cairo_point_t *p1,
const cairo_point_t *p2)
{
if (p1->x <= p2->x) {
box->p1.x = p1->x;
box->p2.x = p2->x;
} else {
box->p1.x = p2->x;
box->p2.x = p1->x;
}
 
if (p1->y <= p2->y) {
box->p1.y = p1->y;
box->p2.y = p2->y;
} else {
box->p1.y = p2->y;
box->p2.y = p1->y;
}
}
 
/*
* Check whether the given path contains a single rectangle.
*/
cairo_bool_t
_cairo_path_fixed_is_box (const cairo_path_fixed_t *path,
cairo_box_t *box)
{
const cairo_path_buf_t *buf = cairo_path_head (path);
 
if (! path->is_rectilinear)
return FALSE;
 
/* Do we have the right number of ops? */
if (buf->num_ops < 4 || buf->num_ops > 6)
return FALSE;
 
/* Check whether the ops are those that would be used for a rectangle */
if (buf->op[0] != CAIRO_PATH_OP_MOVE_TO ||
buf->op[1] != CAIRO_PATH_OP_LINE_TO ||
buf->op[2] != CAIRO_PATH_OP_LINE_TO ||
buf->op[3] != CAIRO_PATH_OP_LINE_TO)
{
return FALSE;
}
 
/* we accept an implicit close for filled paths */
if (buf->num_ops > 4) {
/* Now, there are choices. The rectangle might end with a LINE_TO
* (to the original point), but this isn't required. If it
* doesn't, then it must end with a CLOSE_PATH. */
if (buf->op[4] == CAIRO_PATH_OP_LINE_TO) {
if (buf->points[4].x != buf->points[0].x ||
buf->points[4].y != buf->points[0].y)
return FALSE;
} else if (buf->op[4] != CAIRO_PATH_OP_CLOSE_PATH) {
return FALSE;
}
 
if (buf->num_ops == 6) {
/* A trailing CLOSE_PATH or MOVE_TO is ok */
if (buf->op[5] != CAIRO_PATH_OP_MOVE_TO &&
buf->op[5] != CAIRO_PATH_OP_CLOSE_PATH)
return FALSE;
}
}
 
/* Ok, we may have a box, if the points line up */
if (buf->points[0].y == buf->points[1].y &&
buf->points[1].x == buf->points[2].x &&
buf->points[2].y == buf->points[3].y &&
buf->points[3].x == buf->points[0].x)
{
_canonical_box (box, &buf->points[0], &buf->points[2]);
return TRUE;
}
 
if (buf->points[0].x == buf->points[1].x &&
buf->points[1].y == buf->points[2].y &&
buf->points[2].x == buf->points[3].x &&
buf->points[3].y == buf->points[0].y)
{
_canonical_box (box, &buf->points[0], &buf->points[2]);
return TRUE;
}
 
return FALSE;
}
 
/*
* Check whether the given path contains a single rectangle
* that is logically equivalent to:
* <informalexample><programlisting>
* cairo_move_to (cr, x, y);
* cairo_rel_line_to (cr, width, 0);
* cairo_rel_line_to (cr, 0, height);
* cairo_rel_line_to (cr, -width, 0);
* cairo_close_path (cr);
* </programlisting></informalexample>
*/
cairo_bool_t
_cairo_path_fixed_is_rectangle (const cairo_path_fixed_t *path,
cairo_box_t *box)
{
const cairo_path_buf_t *buf;
 
if (! _cairo_path_fixed_is_box (path, box))
return FALSE;
 
buf = cairo_path_head (path);
if (buf->points[0].y == buf->points[1].y)
return TRUE;
 
return FALSE;
}
 
void
_cairo_path_fixed_iter_init (cairo_path_fixed_iter_t *iter,
const cairo_path_fixed_t *path)
{
iter->first = iter->buf = cairo_path_head (path);
iter->n_op = 0;
iter->n_point = 0;
}
 
static cairo_bool_t
_cairo_path_fixed_iter_next_op (cairo_path_fixed_iter_t *iter)
{
if (++iter->n_op >= iter->buf->num_ops) {
iter->buf = cairo_path_buf_next (iter->buf);
if (iter->buf == iter->first) {
iter->buf = NULL;
return FALSE;
}
 
iter->n_op = 0;
iter->n_point = 0;
}
 
return TRUE;
}
 
cairo_bool_t
_cairo_path_fixed_iter_is_fill_box (cairo_path_fixed_iter_t *_iter,
cairo_box_t *box)
{
cairo_point_t points[5];
cairo_path_fixed_iter_t iter;
 
if (_iter->buf == NULL)
return FALSE;
 
iter = *_iter;
 
if (iter.n_op == iter.buf->num_ops &&
! _cairo_path_fixed_iter_next_op (&iter))
{
return FALSE;
}
 
/* Check whether the ops are those that would be used for a rectangle */
if (iter.buf->op[iter.n_op] != CAIRO_PATH_OP_MOVE_TO)
return FALSE;
points[0] = iter.buf->points[iter.n_point++];
if (! _cairo_path_fixed_iter_next_op (&iter))
return FALSE;
 
if (iter.buf->op[iter.n_op] != CAIRO_PATH_OP_LINE_TO)
return FALSE;
points[1] = iter.buf->points[iter.n_point++];
if (! _cairo_path_fixed_iter_next_op (&iter))
return FALSE;
 
if (iter.buf->op[iter.n_op] != CAIRO_PATH_OP_LINE_TO)
return FALSE;
points[2] = iter.buf->points[iter.n_point++];
if (! _cairo_path_fixed_iter_next_op (&iter))
return FALSE;
 
if (iter.buf->op[iter.n_op] != CAIRO_PATH_OP_LINE_TO)
return FALSE;
points[3] = iter.buf->points[iter.n_point++];
if (! _cairo_path_fixed_iter_next_op (&iter))
return FALSE;
 
/* Now, there are choices. The rectangle might end with a LINE_TO
* (to the original point), but this isn't required. If it
* doesn't, then it must end with a CLOSE_PATH (which may be implicit). */
if (iter.buf->op[iter.n_op] == CAIRO_PATH_OP_LINE_TO)
{
points[4] = iter.buf->points[iter.n_point++];
if (points[4].x != points[0].x || points[4].y != points[0].y)
return FALSE;
}
else if (! (iter.buf->op[iter.n_op] == CAIRO_PATH_OP_CLOSE_PATH ||
iter.buf->op[iter.n_op] == CAIRO_PATH_OP_MOVE_TO))
{
return FALSE;
}
if (! _cairo_path_fixed_iter_next_op (&iter))
return FALSE;
 
/* Ok, we may have a box, if the points line up */
if (points[0].y == points[1].y &&
points[1].x == points[2].x &&
points[2].y == points[3].y &&
points[3].x == points[0].x)
{
box->p1 = points[0];
box->p2 = points[2];
*_iter = iter;
return TRUE;
}
 
if (points[0].x == points[1].x &&
points[1].y == points[2].y &&
points[2].x == points[3].x &&
points[3].y == points[0].y)
{
box->p1 = points[1];
box->p2 = points[3];
*_iter = iter;
return TRUE;
}
 
return FALSE;
}
 
cairo_bool_t
_cairo_path_fixed_iter_at_end (const cairo_path_fixed_iter_t *iter)
{
if (iter->buf == NULL)
return TRUE;
 
if (iter->n_op == iter->buf->num_ops)
return TRUE;
 
if (iter->buf->op[iter->n_op] == CAIRO_PATH_OP_MOVE_TO &&
iter->buf->num_ops == iter->n_op + 1)
{
return TRUE;
}
 
return FALSE;
}
/programs/develop/libraries/cairo/src/cairo-path-in-fill.c
0,0 → 1,291
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2008 Chris Wilson
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Chris Wilson.
*
* Contributor(s):
* Chris Wilson <chris@chris-wilson.co.uk>
*/
 
#include "cairoint.h"
#include "cairo-path-fixed-private.h"
 
typedef struct cairo_in_fill {
double tolerance;
cairo_bool_t on_edge;
int winding;
 
cairo_fixed_t x, y;
 
cairo_bool_t has_current_point;
cairo_point_t current_point;
cairo_point_t first_point;
} cairo_in_fill_t;
 
static void
_cairo_in_fill_init (cairo_in_fill_t *in_fill,
double tolerance,
double x,
double y)
{
in_fill->on_edge = FALSE;
in_fill->winding = 0;
in_fill->tolerance = tolerance;
 
in_fill->x = _cairo_fixed_from_double (x);
in_fill->y = _cairo_fixed_from_double (y);
 
in_fill->has_current_point = FALSE;
in_fill->current_point.x = 0;
in_fill->current_point.y = 0;
}
 
static void
_cairo_in_fill_fini (cairo_in_fill_t *in_fill)
{
}
 
static int
edge_compare_for_y_against_x (const cairo_point_t *p1,
const cairo_point_t *p2,
cairo_fixed_t y,
cairo_fixed_t x)
{
cairo_fixed_t adx, ady;
cairo_fixed_t dx, dy;
cairo_int64_t L, R;
 
adx = p2->x - p1->x;
dx = x - p1->x;
 
if (adx == 0)
return -dx;
if ((adx ^ dx) < 0)
return adx;
 
dy = y - p1->y;
ady = p2->y - p1->y;
 
L = _cairo_int32x32_64_mul (dy, adx);
R = _cairo_int32x32_64_mul (dx, ady);
 
return _cairo_int64_cmp (L, R);
}
 
static void
_cairo_in_fill_add_edge (cairo_in_fill_t *in_fill,
const cairo_point_t *p1,
const cairo_point_t *p2)
{
int dir;
 
if (in_fill->on_edge)
return;
 
/* count the number of edge crossing to -∞ */
 
dir = 1;
if (p2->y < p1->y) {
const cairo_point_t *tmp;
 
tmp = p1;
p1 = p2;
p2 = tmp;
 
dir = -1;
}
 
/* First check whether the query is on an edge */
if ((p1->x == in_fill->x && p1->y == in_fill->y) ||
(p2->x == in_fill->x && p2->y == in_fill->y) ||
(! (p2->y < in_fill->y || p1->y > in_fill->y ||
(p1->x > in_fill->x && p2->x > in_fill->x) ||
(p1->x < in_fill->x && p2->x < in_fill->x)) &&
edge_compare_for_y_against_x (p1, p2, in_fill->y, in_fill->x) == 0))
{
in_fill->on_edge = TRUE;
return;
}
 
/* edge is entirely above or below, note the shortening rule */
if (p2->y <= in_fill->y || p1->y > in_fill->y)
return;
 
/* edge lies wholly to the right */
if (p1->x >= in_fill->x && p2->x >= in_fill->x)
return;
 
if ((p1->x <= in_fill->x && p2->x <= in_fill->x) ||
edge_compare_for_y_against_x (p1, p2, in_fill->y, in_fill->x) < 0)
{
in_fill->winding += dir;
}
}
 
static cairo_status_t
_cairo_in_fill_move_to (void *closure,
const cairo_point_t *point)
{
cairo_in_fill_t *in_fill = closure;
 
/* implicit close path */
if (in_fill->has_current_point) {
_cairo_in_fill_add_edge (in_fill,
&in_fill->current_point,
&in_fill->first_point);
}
 
in_fill->first_point = *point;
in_fill->current_point = *point;
in_fill->has_current_point = TRUE;
 
return CAIRO_STATUS_SUCCESS;
}
 
static cairo_status_t
_cairo_in_fill_line_to (void *closure,
const cairo_point_t *point)
{
cairo_in_fill_t *in_fill = closure;
 
if (in_fill->has_current_point)
_cairo_in_fill_add_edge (in_fill, &in_fill->current_point, point);
 
in_fill->current_point = *point;
in_fill->has_current_point = TRUE;
 
return CAIRO_STATUS_SUCCESS;
}
 
static cairo_status_t
_cairo_in_fill_curve_to (void *closure,
const cairo_point_t *b,
const cairo_point_t *c,
const cairo_point_t *d)
{
cairo_in_fill_t *in_fill = closure;
cairo_spline_t spline;
cairo_fixed_t top, bot, left;
 
/* first reject based on bbox */
bot = top = in_fill->current_point.y;
if (b->y < top) top = b->y;
if (b->y > bot) bot = b->y;
if (c->y < top) top = c->y;
if (c->y > bot) bot = c->y;
if (d->y < top) top = d->y;
if (d->y > bot) bot = d->y;
if (bot < in_fill->y || top > in_fill->y) {
in_fill->current_point = *d;
return CAIRO_STATUS_SUCCESS;
}
 
left = in_fill->current_point.x;
if (b->x < left) left = b->x;
if (c->x < left) left = c->x;
if (d->x < left) left = d->x;
if (left > in_fill->x) {
in_fill->current_point = *d;
return CAIRO_STATUS_SUCCESS;
}
 
/* XXX Investigate direct inspection of the inflections? */
if (! _cairo_spline_init (&spline,
_cairo_in_fill_line_to,
in_fill,
&in_fill->current_point, b, c, d))
{
return CAIRO_STATUS_SUCCESS;
}
 
return _cairo_spline_decompose (&spline, in_fill->tolerance);
}
 
static cairo_status_t
_cairo_in_fill_close_path (void *closure)
{
cairo_in_fill_t *in_fill = closure;
 
if (in_fill->has_current_point) {
_cairo_in_fill_add_edge (in_fill,
&in_fill->current_point,
&in_fill->first_point);
 
in_fill->has_current_point = FALSE;
}
 
return CAIRO_STATUS_SUCCESS;
}
 
cairo_bool_t
_cairo_path_fixed_in_fill (const cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
double x,
double y)
{
cairo_in_fill_t in_fill;
cairo_status_t status;
cairo_bool_t is_inside;
 
if (path->is_empty_fill)
return FALSE;
 
_cairo_in_fill_init (&in_fill, tolerance, x, y);
 
status = _cairo_path_fixed_interpret (path,
CAIRO_DIRECTION_FORWARD,
_cairo_in_fill_move_to,
_cairo_in_fill_line_to,
_cairo_in_fill_curve_to,
_cairo_in_fill_close_path,
&in_fill);
assert (status == CAIRO_STATUS_SUCCESS);
 
_cairo_in_fill_close_path (&in_fill);
 
if (in_fill.on_edge) {
is_inside = TRUE;
} else switch (fill_rule) {
case CAIRO_FILL_RULE_EVEN_ODD:
is_inside = in_fill.winding & 1;
break;
case CAIRO_FILL_RULE_WINDING:
is_inside = in_fill.winding != 0;
break;
default:
ASSERT_NOT_REACHED;
is_inside = FALSE;
break;
}
 
_cairo_in_fill_fini (&in_fill);
 
return is_inside;
}
/programs/develop/libraries/cairo/src/cairo-path-private.h
0,0 → 1,57
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2005 Red Hat, Inc.
* Copyright © 2006 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
* Carl D. Worth <cworth@redhat.com>
*/
 
#ifndef CAIRO_PATH_PRIVATE_H
#define CAIRO_PATH_PRIVATE_H
 
#include "cairoint.h"
 
cairo_private cairo_path_t *
_cairo_path_create (cairo_path_fixed_t *path,
cairo_gstate_t *gstate);
 
cairo_private cairo_path_t *
_cairo_path_create_flat (cairo_path_fixed_t *path,
cairo_gstate_t *gstate);
 
cairo_private cairo_path_t *
_cairo_path_create_in_error (cairo_status_t status);
 
cairo_private cairo_status_t
_cairo_path_append_to_context (const cairo_path_t *path,
cairo_t *cr);
 
#endif /* CAIRO_PATH_DATA_PRIVATE_H */
/programs/develop/libraries/cairo/src/cairo-path-stroke.c
0,0 → 1,2143
/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2002 University of Southern California
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
* Chris Wilson <chris@chris-wilson.co.uk>
*/
 
#define _BSD_SOURCE /* for hypot() */
#include "cairoint.h"
 
#include "cairo-boxes-private.h"
#include "cairo-error-private.h"
#include "cairo-path-fixed-private.h"
#include "cairo-slope-private.h"
 
typedef struct _cairo_stroker_dash {
cairo_bool_t dashed;
unsigned int dash_index;
cairo_bool_t dash_on;
cairo_bool_t dash_starts_on;
double dash_remain;
 
double dash_offset;
const double *dashes;
unsigned int num_dashes;
} cairo_stroker_dash_t;
 
typedef struct cairo_stroker {
cairo_stroke_style_t style;
 
const cairo_matrix_t *ctm;
const cairo_matrix_t *ctm_inverse;
double tolerance;
double ctm_determinant;
cairo_bool_t ctm_det_positive;
 
void *closure;
cairo_status_t (*add_external_edge) (void *closure,
const cairo_point_t *p1,
const cairo_point_t *p2);
cairo_status_t (*add_triangle) (void *closure,
const cairo_point_t triangle[3]);
cairo_status_t (*add_triangle_fan) (void *closure,
const cairo_point_t *midpt,
const cairo_point_t *points,
int npoints);
cairo_status_t (*add_convex_quad) (void *closure,
const cairo_point_t quad[4]);
 
cairo_pen_t pen;
 
cairo_point_t current_point;
cairo_point_t first_point;
 
cairo_bool_t has_initial_sub_path;
 
cairo_bool_t has_current_face;
cairo_stroke_face_t current_face;
 
cairo_bool_t has_first_face;
cairo_stroke_face_t first_face;
 
cairo_stroker_dash_t dash;
 
cairo_bool_t has_bounds;
cairo_box_t bounds;
} cairo_stroker_t;
 
static void
_cairo_stroker_dash_start (cairo_stroker_dash_t *dash)
{
double offset;
cairo_bool_t on = TRUE;
unsigned int i = 0;
 
if (! dash->dashed)
return;
 
offset = dash->dash_offset;
 
/* We stop searching for a starting point as soon as the
offset reaches zero. Otherwise when an initial dash
segment shrinks to zero it will be skipped over. */
while (offset > 0.0 && offset >= dash->dashes[i]) {
offset -= dash->dashes[i];
on = !on;
if (++i == dash->num_dashes)
i = 0;
}
 
dash->dash_index = i;
dash->dash_on = dash->dash_starts_on = on;
dash->dash_remain = dash->dashes[i] - offset;
}
 
static void
_cairo_stroker_dash_step (cairo_stroker_dash_t *dash, double step)
{
dash->dash_remain -= step;
if (dash->dash_remain <= 0.) {
if (++dash->dash_index == dash->num_dashes)
dash->dash_index = 0;
 
dash->dash_on = ! dash->dash_on;
dash->dash_remain = dash->dashes[dash->dash_index];
}
}
 
static void
_cairo_stroker_dash_init (cairo_stroker_dash_t *dash,
const cairo_stroke_style_t *style)
{
dash->dashed = style->dash != NULL;
if (! dash->dashed)
return;
 
dash->dashes = style->dash;
dash->num_dashes = style->num_dashes;
dash->dash_offset = style->dash_offset;
 
_cairo_stroker_dash_start (dash);
}
 
static cairo_status_t
_cairo_stroker_init (cairo_stroker_t *stroker,
const cairo_stroke_style_t *stroke_style,
const cairo_matrix_t *ctm,
const cairo_matrix_t *ctm_inverse,
double tolerance)
{
cairo_status_t status;
 
stroker->style = *stroke_style;
stroker->ctm = ctm;
stroker->ctm_inverse = ctm_inverse;
stroker->tolerance = tolerance;
 
stroker->ctm_determinant = _cairo_matrix_compute_determinant (stroker->ctm);
stroker->ctm_det_positive = stroker->ctm_determinant >= 0.0;
 
status = _cairo_pen_init (&stroker->pen,
stroke_style->line_width / 2.0,
tolerance, ctm);
if (unlikely (status))
return status;
 
stroker->has_bounds = FALSE;
 
stroker->has_current_face = FALSE;
stroker->has_first_face = FALSE;
stroker->has_initial_sub_path = FALSE;
 
_cairo_stroker_dash_init (&stroker->dash, stroke_style);
 
stroker->add_external_edge = NULL;
 
return CAIRO_STATUS_SUCCESS;
}
 
static void
_cairo_stroker_limit (cairo_stroker_t *stroker,
const cairo_box_t *boxes,
int num_boxes)
{
double dx, dy;
cairo_fixed_t fdx, fdy;
 
stroker->has_bounds = TRUE;
_cairo_boxes_get_extents (boxes, num_boxes, &stroker->bounds);
 
/* Extend the bounds in each direction to account for the maximum area
* we might generate trapezoids, to capture line segments that are outside
* of the bounds but which might generate rendering that's within bounds.
*/
 
_cairo_stroke_style_max_distance_from_path (&stroker->style, stroker->ctm,
&dx, &dy);
 
fdx = _cairo_fixed_from_double (dx);
fdy = _cairo_fixed_from_double (dy);
 
stroker->bounds.p1.x -= fdx;
stroker->bounds.p2.x += fdx;
 
stroker->bounds.p1.y -= fdy;
stroker->bounds.p2.y += fdy;
}
 
static void
_cairo_stroker_fini (cairo_stroker_t *stroker)
{
_cairo_pen_fini (&stroker->pen);
}
 
static void
_translate_point (cairo_point_t *point, const cairo_point_t *offset)
{
point->x += offset->x;
point->y += offset->y;
}
 
static int
_cairo_stroker_join_is_clockwise (const cairo_stroke_face_t *in,
const cairo_stroke_face_t *out)
{
cairo_slope_t in_slope, out_slope;
 
_cairo_slope_init (&in_slope, &in->point, &in->cw);
_cairo_slope_init (&out_slope, &out->point, &out->cw);
 
return _cairo_slope_compare (&in_slope, &out_slope) < 0;
}
 
/**
* _cairo_slope_compare_sgn
*
* Return -1, 0 or 1 depending on the relative slopes of
* two lines.
*/
static int
_cairo_slope_compare_sgn (double dx1, double dy1, double dx2, double dy2)
{
double c = (dx1 * dy2 - dx2 * dy1);
 
if (c > 0) return 1;
if (c < 0) return -1;
return 0;
}
 
static inline int
_range_step (int i, int step, int max)
{
i += step;
if (i < 0)
i = max - 1;
if (i >= max)
i = 0;
return i;
}
 
/*
* Construct a fan around the midpoint using the vertices from pen between
* inpt and outpt.
*/
static cairo_status_t
_tessellate_fan (cairo_stroker_t *stroker,
const cairo_slope_t *in_vector,
const cairo_slope_t *out_vector,
const cairo_point_t *midpt,
const cairo_point_t *inpt,
const cairo_point_t *outpt,
cairo_bool_t clockwise)
{
cairo_point_t stack_points[64], *points = stack_points;
int start, stop, step, i, npoints;
cairo_status_t status;
 
if (clockwise) {
step = -1;
 
start = _cairo_pen_find_active_ccw_vertex_index (&stroker->pen,
in_vector);
if (_cairo_slope_compare (&stroker->pen.vertices[start].slope_ccw,
in_vector) < 0)
start = _range_step (start, -1, stroker->pen.num_vertices);
 
stop = _cairo_pen_find_active_ccw_vertex_index (&stroker->pen,
out_vector);
if (_cairo_slope_compare (&stroker->pen.vertices[stop].slope_cw,
out_vector) > 0)
{
stop = _range_step (stop, 1, stroker->pen.num_vertices);
if (_cairo_slope_compare (&stroker->pen.vertices[stop].slope_ccw,
in_vector) < 0)
{
goto BEVEL;
}
}
 
npoints = start - stop;
} else {
step = 1;
 
start = _cairo_pen_find_active_cw_vertex_index (&stroker->pen,
in_vector);
if (_cairo_slope_compare (&stroker->pen.vertices[start].slope_cw,
in_vector) < 0)
start = _range_step (start, 1, stroker->pen.num_vertices);
 
stop = _cairo_pen_find_active_cw_vertex_index (&stroker->pen,
out_vector);
if (_cairo_slope_compare (&stroker->pen.vertices[stop].slope_ccw,
out_vector) > 0)
{
stop = _range_step (stop, -1, stroker->pen.num_vertices);
if (_cairo_slope_compare (&stroker->pen.vertices[stop].slope_cw,
in_vector) < 0)
{
goto BEVEL;
}
}
 
npoints = stop - start;
}
stop = _range_step (stop, step, stroker->pen.num_vertices);
 
if (npoints < 0)
npoints += stroker->pen.num_vertices;
npoints += 3;
 
if (npoints <= 1)
goto BEVEL;
 
if (npoints > ARRAY_LENGTH (stack_points)) {
points = _cairo_malloc_ab (npoints, sizeof (cairo_point_t));
if (unlikely (points == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
 
 
/* Construct the fan. */
npoints = 0;
points[npoints++] = *inpt;
for (i = start;
i != stop;
i = _range_step (i, step, stroker->pen.num_vertices))
{
points[npoints] = *midpt;
_translate_point (&points[npoints], &stroker->pen.vertices[i].point);
npoints++;
}
points[npoints++] = *outpt;
 
if (stroker->add_external_edge != NULL) {
for (i = 0; i < npoints - 1; i++) {
if (clockwise) {
status = stroker->add_external_edge (stroker->closure,
&points[i], &points[i+1]);
} else {
status = stroker->add_external_edge (stroker->closure,
&points[i+1], &points[i]);
}
if (unlikely (status))
break;
}
} else {
status = stroker->add_triangle_fan (stroker->closure,
midpt, points, npoints);
}
 
if (points != stack_points)
free (points);
 
return status;
 
BEVEL:
/* Ensure a leak free connection... */
if (stroker->add_external_edge != NULL) {
if (clockwise)
return stroker->add_external_edge (stroker->closure, inpt, outpt);
else
return stroker->add_external_edge (stroker->closure, outpt, inpt);
} else {
stack_points[0] = *midpt;
stack_points[1] = *inpt;
stack_points[2] = *outpt;
return stroker->add_triangle (stroker->closure, stack_points);
}
}
 
static cairo_status_t
_cairo_stroker_join (cairo_stroker_t *stroker,
const cairo_stroke_face_t *in,
const cairo_stroke_face_t *out)
{
int clockwise = _cairo_stroker_join_is_clockwise (out, in);
const cairo_point_t *inpt, *outpt;
cairo_point_t points[4];
cairo_status_t status;
 
if (in->cw.x == out->cw.x && in->cw.y == out->cw.y &&
in->ccw.x == out->ccw.x && in->ccw.y == out->ccw.y)
{
return CAIRO_STATUS_SUCCESS;
}
 
if (clockwise) {
if (stroker->add_external_edge != NULL) {
status = stroker->add_external_edge (stroker->closure,
&out->cw, &in->point);
if (unlikely (status))
return status;
 
status = stroker->add_external_edge (stroker->closure,
&in->point, &in->cw);
if (unlikely (status))
return status;
}
 
inpt = &in->ccw;
outpt = &out->ccw;
} else {
if (stroker->add_external_edge != NULL) {
status = stroker->add_external_edge (stroker->closure,
&in->ccw, &in->point);
if (unlikely (status))
return status;
 
status = stroker->add_external_edge (stroker->closure,
&in->point, &out->ccw);
if (unlikely (status))
return status;
}
 
inpt = &in->cw;
outpt = &out->cw;
}
 
switch (stroker->style.line_join) {
case CAIRO_LINE_JOIN_ROUND:
/* construct a fan around the common midpoint */
return _tessellate_fan (stroker,
&in->dev_vector,
&out->dev_vector,
&in->point, inpt, outpt,
clockwise);
 
case CAIRO_LINE_JOIN_MITER:
default: {
/* dot product of incoming slope vector with outgoing slope vector */
double in_dot_out = -in->usr_vector.x * out->usr_vector.x +
-in->usr_vector.y * out->usr_vector.y;
double ml = stroker->style.miter_limit;
 
/* Check the miter limit -- lines meeting at an acute angle
* can generate long miters, the limit converts them to bevel
*
* Consider the miter join formed when two line segments
* meet at an angle psi:
*
* /.\
* /. .\
* /./ \.\
* /./psi\.\
*
* 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:
*
* 1/sin(psi/2) <= ml
* 1 <= ml sin(psi/2)
* 1 <= ml² sin²(psi/2)
* 2 <= ml² 2 sin²(psi/2)
* 2·sin²(psi/2) = 1-cos(psi)
* 2 <= ml² (1-cos(psi))
*
* in · out = |in| |out| cos (psi)
*
* in and out are both unit vectors, so:
*
* in · out = cos (psi)
*
* 2 <= ml² (1 - in · out)
*
*/
if (2 <= ml * ml * (1 - in_dot_out)) {
double x1, y1, x2, y2;
double mx, my;
double dx1, dx2, dy1, dy2;
double ix, iy;
double fdx1, fdy1, fdx2, fdy2;
double mdx, mdy;
 
/*
* we've got the points already transformed to device
* space, but need to do some computation with them and
* also need to transform the slope from user space to
* device space
*/
/* outer point of incoming line face */
x1 = _cairo_fixed_to_double (inpt->x);
y1 = _cairo_fixed_to_double (inpt->y);
dx1 = in->usr_vector.x;
dy1 = in->usr_vector.y;
cairo_matrix_transform_distance (stroker->ctm, &dx1, &dy1);
 
/* outer point of outgoing line face */
x2 = _cairo_fixed_to_double (outpt->x);
y2 = _cairo_fixed_to_double (outpt->y);
dx2 = out->usr_vector.x;
dy2 = out->usr_vector.y;
cairo_matrix_transform_distance (stroker->ctm, &dx2, &dy2);
 
/*
* Compute the location of the outer corner of the miter.
* That's pretty easy -- just the intersection of the two
* outer edges. We've got slopes and points on each
* of those edges. Compute my directly, then compute
* mx by using the edge with the larger dy; that avoids
* dividing by values close to zero.
*/
my = (((x2 - x1) * dy1 * dy2 - y2 * dx2 * dy1 + y1 * dx1 * dy2) /
(dx1 * dy2 - dx2 * dy1));
if (fabs (dy1) >= fabs (dy2))
mx = (my - y1) * dx1 / dy1 + x1;
else
mx = (my - y2) * dx2 / dy2 + x2;
 
/*
* When the two outer edges are nearly parallel, slight
* perturbations in the position of the outer points of the lines
* caused by representing them in fixed point form can cause the
* intersection point of the miter to move a large amount. If
* that moves the miter intersection from between the two faces,
* then draw a bevel instead.
*/
 
ix = _cairo_fixed_to_double (in->point.x);
iy = _cairo_fixed_to_double (in->point.y);
 
/* slope of one face */
fdx1 = x1 - ix; fdy1 = y1 - iy;
 
/* slope of the other face */
fdx2 = x2 - ix; fdy2 = y2 - iy;
 
/* slope from the intersection to the miter point */
mdx = mx - ix; mdy = my - iy;
 
/*
* Make sure the miter point line lies between the two
* faces by comparing the slopes
*/
if (_cairo_slope_compare_sgn (fdx1, fdy1, mdx, mdy) !=
_cairo_slope_compare_sgn (fdx2, fdy2, mdx, mdy))
{
if (stroker->add_external_edge != NULL) {
points[0].x = _cairo_fixed_from_double (mx);
points[0].y = _cairo_fixed_from_double (my);
 
if (clockwise) {
status = stroker->add_external_edge (stroker->closure,
inpt, &points[0]);
if (unlikely (status))
return status;
 
status = stroker->add_external_edge (stroker->closure,
&points[0], outpt);
if (unlikely (status))
return status;
} else {
status = stroker->add_external_edge (stroker->closure,
outpt, &points[0]);
if (unlikely (status))
return status;
 
status = stroker->add_external_edge (stroker->closure,
&points[0], inpt);
if (unlikely (status))
return status;
}
 
return CAIRO_STATUS_SUCCESS;
} else {
points[0] = in->point;
points[1] = *inpt;
points[2].x = _cairo_fixed_from_double (mx);
points[2].y = _cairo_fixed_from_double (my);
points[3] = *outpt;
 
return stroker->add_convex_quad (stroker->closure, points);
}
}
}
}
 
/* fall through ... */
 
case CAIRO_LINE_JOIN_BEVEL:
if (stroker->add_external_edge != NULL) {
if (clockwise) {
return stroker->add_external_edge (stroker->closure,
inpt, outpt);
} else {
return stroker->add_external_edge (stroker->closure,
outpt, inpt);
}
} else {
points[0] = in->point;
points[1] = *inpt;
points[2] = *outpt;
 
return stroker->add_triangle (stroker->closure, points);
}
}
}
 
static cairo_status_t
_cairo_stroker_add_cap (cairo_stroker_t *stroker,
const cairo_stroke_face_t *f)
{
switch (stroker->style.line_cap) {
case CAIRO_LINE_CAP_ROUND: {
cairo_slope_t slope;
 
slope.dx = -f->dev_vector.dx;
slope.dy = -f->dev_vector.dy;
 
return _tessellate_fan (stroker,
&f->dev_vector,
&slope,
&f->point, &f->cw, &f->ccw,
FALSE);
 
}
 
case CAIRO_LINE_CAP_SQUARE: {
double dx, dy;
cairo_slope_t fvector;
cairo_point_t quad[4];
 
dx = f->usr_vector.x;
dy = f->usr_vector.y;
dx *= stroker->style.line_width / 2.0;
dy *= stroker->style.line_width / 2.0;
cairo_matrix_transform_distance (stroker->ctm, &dx, &dy);
fvector.dx = _cairo_fixed_from_double (dx);
fvector.dy = _cairo_fixed_from_double (dy);
 
quad[0] = f->ccw;
quad[1].x = f->ccw.x + fvector.dx;
quad[1].y = f->ccw.y + fvector.dy;
quad[2].x = f->cw.x + fvector.dx;
quad[2].y = f->cw.y + fvector.dy;
quad[3] = f->cw;
 
if (stroker->add_external_edge != NULL) {
cairo_status_t status;
 
status = stroker->add_external_edge (stroker->closure,
&quad[0], &quad[1]);
if (unlikely (status))
return status;
 
status = stroker->add_external_edge (stroker->closure,
&quad[1], &quad[2]);
if (unlikely (status))
return status;
 
status = stroker->add_external_edge (stroker->closure,
&quad[2], &quad[3]);
if (unlikely (status))
return status;
 
return CAIRO_STATUS_SUCCESS;
} else {
return stroker->add_convex_quad (stroker->closure, quad);
}
}
 
case CAIRO_LINE_CAP_BUTT:
default:
if (stroker->add_external_edge != NULL) {
return stroker->add_external_edge (stroker->closure,
&f->ccw, &f->cw);
} else {
return CAIRO_STATUS_SUCCESS;
}
}
}
 
static cairo_status_t
_cairo_stroker_add_leading_cap (cairo_stroker_t *stroker,
const cairo_stroke_face_t *face)
{
cairo_stroke_face_t reversed;
cairo_point_t t;
 
reversed = *face;
 
/* The initial cap needs an outward facing vector. Reverse everything */
reversed.usr_vector.x = -reversed.usr_vector.x;
reversed.usr_vector.y = -reversed.usr_vector.y;
reversed.dev_vector.dx = -reversed.dev_vector.dx;
reversed.dev_vector.dy = -reversed.dev_vector.dy;
t = reversed.cw;
reversed.cw = reversed.ccw;
reversed.ccw = t;
 
return _cairo_stroker_add_cap (stroker, &reversed);
}
 
static cairo_status_t
_cairo_stroker_add_trailing_cap (cairo_stroker_t *stroker,
const cairo_stroke_face_t *face)
{
return _cairo_stroker_add_cap (stroker, face);
}
 
static inline cairo_bool_t
_compute_normalized_device_slope (double *dx, double *dy,
const cairo_matrix_t *ctm_inverse,
double *mag_out)
{
double dx0 = *dx, dy0 = *dy;
double mag;
 
cairo_matrix_transform_distance (ctm_inverse, &dx0, &dy0);
 
if (dx0 == 0.0 && dy0 == 0.0) {
if (mag_out)
*mag_out = 0.0;
return FALSE;
}
 
if (dx0 == 0.0) {
*dx = 0.0;
if (dy0 > 0.0) {
mag = dy0;
*dy = 1.0;
} else {
mag = -dy0;
*dy = -1.0;
}
} else if (dy0 == 0.0) {
*dy = 0.0;
if (dx0 > 0.0) {
mag = dx0;
*dx = 1.0;
} else {
mag = -dx0;
*dx = -1.0;
}
} else {
mag = hypot (dx0, dy0);
*dx = dx0 / mag;
*dy = dy0 / mag;
}
 
if (mag_out)
*mag_out = mag;
 
return TRUE;
}
 
static void
_compute_face (const cairo_point_t *point, cairo_slope_t *dev_slope,
double slope_dx, double slope_dy,
cairo_stroker_t *stroker, cairo_stroke_face_t *face)
{
double face_dx, face_dy;
cairo_point_t offset_ccw, offset_cw;
 
/*
* rotate to get a line_width/2 vector along the face, note that
* the vector must be rotated the right direction in device space,
* but by 90° in user space. So, the rotation depends on
* whether the ctm reflects or not, and that can be determined
* by looking at the determinant of the matrix.
*/
if (stroker->ctm_det_positive)
{
face_dx = - slope_dy * (stroker->style.line_width / 2.0);
face_dy = slope_dx * (stroker->style.line_width / 2.0);
}
else
{
face_dx = slope_dy * (stroker->style.line_width / 2.0);
face_dy = - slope_dx * (stroker->style.line_width / 2.0);
}
 
/* back to device space */
cairo_matrix_transform_distance (stroker->ctm, &face_dx, &face_dy);
 
offset_ccw.x = _cairo_fixed_from_double (face_dx);
offset_ccw.y = _cairo_fixed_from_double (face_dy);
offset_cw.x = -offset_ccw.x;
offset_cw.y = -offset_ccw.y;
 
face->ccw = *point;
_translate_point (&face->ccw, &offset_ccw);
 
face->point = *point;
 
face->cw = *point;
_translate_point (&face->cw, &offset_cw);
 
face->usr_vector.x = slope_dx;
face->usr_vector.y = slope_dy;
 
face->dev_vector = *dev_slope;
}
 
static cairo_status_t
_cairo_stroker_add_caps (cairo_stroker_t *stroker)
{
cairo_status_t status;
 
/* check for a degenerative sub_path */
if (stroker->has_initial_sub_path
&& ! stroker->has_first_face
&& ! stroker->has_current_face
&& stroker->style.line_cap == CAIRO_LINE_JOIN_ROUND)
{
/* pick an arbitrary slope to use */
double dx = 1.0, dy = 0.0;
cairo_slope_t slope = { CAIRO_FIXED_ONE, 0 };
cairo_stroke_face_t face;
 
_compute_normalized_device_slope (&dx, &dy,
stroker->ctm_inverse, NULL);
 
/* arbitrarily choose first_point
* first_point and current_point should be the same */
_compute_face (&stroker->first_point, &slope, dx, dy, stroker, &face);
 
status = _cairo_stroker_add_leading_cap (stroker, &face);
if (unlikely (status))
return status;
 
status = _cairo_stroker_add_trailing_cap (stroker, &face);
if (unlikely (status))
return status;
}
 
if (stroker->has_first_face) {
status = _cairo_stroker_add_leading_cap (stroker,
&stroker->first_face);
if (unlikely (status))
return status;
}
 
if (stroker->has_current_face) {
status = _cairo_stroker_add_trailing_cap (stroker,
&stroker->current_face);
if (unlikely (status))
return status;
}
 
return CAIRO_STATUS_SUCCESS;
}
 
static cairo_status_t
_cairo_stroker_add_sub_edge (cairo_stroker_t *stroker,
const cairo_point_t *p1,
const cairo_point_t *p2,
cairo_slope_t *dev_slope,
double slope_dx, double slope_dy,
cairo_stroke_face_t *start,
cairo_stroke_face_t *end)
{
_compute_face (p1, dev_slope, slope_dx, slope_dy, stroker, start);
*end = *start;
 
if (p1->x == p2->x && p1->y == p2->y)
return CAIRO_STATUS_SUCCESS;
 
end->point = *p2;
end->ccw.x += p2->x - p1->x;
end->ccw.y += p2->y - p1->y;
end->cw.x += p2->x - p1->x;
end->cw.y += p2->y - p1->y;
 
if (stroker->add_external_edge != NULL) {
cairo_status_t status;
 
status = stroker->add_external_edge (stroker->closure,
&end->cw, &start->cw);
if (unlikely (status))
return status;
 
status = stroker->add_external_edge (stroker->closure,
&start->ccw, &end->ccw);
if (unlikely (status))
return status;
 
return CAIRO_STATUS_SUCCESS;
} else {
cairo_point_t quad[4];
 
quad[0] = start->cw;
quad[1] = end->cw;
quad[2] = end->ccw;
quad[3] = start->ccw;
 
return stroker->add_convex_quad (stroker->closure, quad);
}
}
 
static cairo_status_t
_cairo_stroker_move_to (void *closure,
const cairo_point_t *point)
{
cairo_stroker_t *stroker = closure;
cairo_status_t status;
 
/* reset the dash pattern for new sub paths */
_cairo_stroker_dash_start (&stroker->dash);
 
/* Cap the start and end of the previous sub path as needed */
status = _cairo_stroker_add_caps (stroker);
if (unlikely (status))
return status;
 
stroker->first_point = *point;
stroker->current_point = *point;
 
stroker->has_first_face = FALSE;
stroker->has_current_face = FALSE;
stroker->has_initial_sub_path = FALSE;
 
return CAIRO_STATUS_SUCCESS;
}
 
static cairo_status_t
_cairo_stroker_line_to (void *closure,
const cairo_point_t *point)
{
cairo_stroker_t *stroker = closure;
cairo_stroke_face_t start, end;
cairo_point_t *p1 = &stroker->current_point;
cairo_slope_t dev_slope;
double slope_dx, slope_dy;
cairo_status_t status;
 
stroker->has_initial_sub_path = TRUE;
 
if (p1->x == point->x && p1->y == point->y)
return CAIRO_STATUS_SUCCESS;
 
_cairo_slope_init (&dev_slope, p1, point);
slope_dx = _cairo_fixed_to_double (point->x - p1->x);
slope_dy = _cairo_fixed_to_double (point->y - p1->y);
_compute_normalized_device_slope (&slope_dx, &slope_dy,
stroker->ctm_inverse, NULL);
 
status = _cairo_stroker_add_sub_edge (stroker,
p1, point,
&dev_slope,
slope_dx, slope_dy,
&start, &end);
if (unlikely (status))
return status;
 
if (stroker->has_current_face) {
/* Join with final face from previous segment */
status = _cairo_stroker_join (stroker,
&stroker->current_face,
&start);
if (unlikely (status))
return status;
} else if (! stroker->has_first_face) {
/* Save sub path's first face in case needed for closing join */
stroker->first_face = start;
stroker->has_first_face = TRUE;
}
stroker->current_face = end;
stroker->has_current_face = TRUE;
 
stroker->current_point = *point;
 
return CAIRO_STATUS_SUCCESS;
}
 
/*
* Dashed lines. Cap each dash end, join around turns when on
*/
static cairo_status_t
_cairo_stroker_line_to_dashed (void *closure,
const cairo_point_t *p2)
{
cairo_stroker_t *stroker = closure;
double mag, remain, step_length = 0;
double slope_dx, slope_dy;
double dx2, dy2;
cairo_stroke_face_t sub_start, sub_end;
cairo_point_t *p1 = &stroker->current_point;
cairo_slope_t dev_slope;
cairo_line_t segment;
cairo_bool_t fully_in_bounds;
cairo_status_t status;
 
stroker->has_initial_sub_path = stroker->dash.dash_starts_on;
 
if (p1->x == p2->x && p1->y == p2->y)
return CAIRO_STATUS_SUCCESS;
 
fully_in_bounds = TRUE;
if (stroker->has_bounds &&
(! _cairo_box_contains_point (&stroker->bounds, p1) ||
! _cairo_box_contains_point (&stroker->bounds, p2)))
{
fully_in_bounds = FALSE;
}
 
_cairo_slope_init (&dev_slope, p1, p2);
 
slope_dx = _cairo_fixed_to_double (p2->x - p1->x);
slope_dy = _cairo_fixed_to_double (p2->y - p1->y);
 
if (! _compute_normalized_device_slope (&slope_dx, &slope_dy,
stroker->ctm_inverse, &mag))
{
return CAIRO_STATUS_SUCCESS;
}
 
remain = mag;
segment.p1 = *p1;
while (remain) {
step_length = MIN (stroker->dash.dash_remain, remain);
remain -= step_length;
dx2 = slope_dx * (mag - remain);
dy2 = slope_dy * (mag - remain);
cairo_matrix_transform_distance (stroker->ctm, &dx2, &dy2);
segment.p2.x = _cairo_fixed_from_double (dx2) + p1->x;
segment.p2.y = _cairo_fixed_from_double (dy2) + p1->y;
 
if (stroker->dash.dash_on &&
(fully_in_bounds ||
(! stroker->has_first_face && stroker->dash.dash_starts_on) ||
_cairo_box_intersects_line_segment (&stroker->bounds, &segment)))
{
status = _cairo_stroker_add_sub_edge (stroker,
&segment.p1, &segment.p2,
&dev_slope,
slope_dx, slope_dy,
&sub_start, &sub_end);
if (unlikely (status))
return status;
 
if (stroker->has_current_face)
{
/* Join with final face from previous segment */
status = _cairo_stroker_join (stroker,
&stroker->current_face,
&sub_start);
if (unlikely (status))
return status;
 
stroker->has_current_face = FALSE;
}
else if (! stroker->has_first_face &&
stroker->dash.dash_starts_on)
{
/* Save sub path's first face in case needed for closing join */
stroker->first_face = sub_start;
stroker->has_first_face = TRUE;
}
else
{
/* Cap dash start if not connecting to a previous segment */
status = _cairo_stroker_add_leading_cap (stroker, &sub_start);
if (unlikely (status))
return status;
}
 
if (remain) {
/* Cap dash end if not at end of segment */
status = _cairo_stroker_add_trailing_cap (stroker, &sub_end);
if (unlikely (status))
return status;
} else {
stroker->current_face = sub_end;
stroker->has_current_face = TRUE;
}
} else {
if (stroker->has_current_face) {
/* Cap final face from previous segment */
status = _cairo_stroker_add_trailing_cap (stroker,
&stroker->current_face);
if (unlikely (status))
return status;
 
stroker->has_current_face = FALSE;
}
}
 
_cairo_stroker_dash_step (&stroker->dash, step_length);
segment.p1 = segment.p2;
}
 
if (stroker->dash.dash_on && ! stroker->has_current_face) {
/* This segment ends on a transition to dash_on, compute a new face
* and add cap for the beginning of the next dash_on step.
*
* Note: this will create a degenerate cap if this is not the last line
* in the path. Whether this behaviour is desirable or not is debatable.
* On one side these degenerate caps can not be reproduced with regular
* path stroking.
* On the other hand, Acroread 7 also produces the degenerate caps.
*/
_compute_face (p2, &dev_slope,
slope_dx, slope_dy,
stroker,
&stroker->current_face);
 
status = _cairo_stroker_add_leading_cap (stroker,
&stroker->current_face);
if (unlikely (status))
return status;
 
stroker->has_current_face = TRUE;
}
 
stroker->current_point = *p2;
 
return CAIRO_STATUS_SUCCESS;
}
 
static cairo_status_t
_cairo_stroker_curve_to (void *closure,
const cairo_point_t *b,
const cairo_point_t *c,
const cairo_point_t *d)
{
cairo_stroker_t *stroker = closure;
cairo_spline_t spline;
cairo_line_join_t line_join_save;
cairo_stroke_face_t face;
double slope_dx, slope_dy;
cairo_path_fixed_line_to_func_t *line_to;
cairo_status_t status = CAIRO_STATUS_SUCCESS;
 
line_to = stroker->dash.dashed ?
_cairo_stroker_line_to_dashed :
_cairo_stroker_line_to;
 
if (! _cairo_spline_init (&spline,
line_to, stroker,
&stroker->current_point, b, c, d))
{
return line_to (closure, d);
}
 
/* If the line width is so small that the pen is reduced to a
single point, then we have nothing to do. */
if (stroker->pen.num_vertices <= 1)
return CAIRO_STATUS_SUCCESS;
 
/* Compute the initial face */
if (! stroker->dash.dashed || stroker->dash.dash_on) {
slope_dx = _cairo_fixed_to_double (spline.initial_slope.dx);
slope_dy = _cairo_fixed_to_double (spline.initial_slope.dy);
if (_compute_normalized_device_slope (&slope_dx, &slope_dy,
stroker->ctm_inverse, NULL))
{
_compute_face (&stroker->current_point,
&spline.initial_slope,
slope_dx, slope_dy,
stroker, &face);
}
if (stroker->has_current_face) {
status = _cairo_stroker_join (stroker,
&stroker->current_face, &face);
if (unlikely (status))
return status;
} else if (! stroker->has_first_face) {
stroker->first_face = face;
stroker->has_first_face = TRUE;
}
 
stroker->current_face = face;
stroker->has_current_face = TRUE;
}
 
/* Temporarily modify the stroker to use round joins to guarantee
* smooth stroked curves. */
line_join_save = stroker->style.line_join;
stroker->style.line_join = CAIRO_LINE_JOIN_ROUND;
 
status = _cairo_spline_decompose (&spline, stroker->tolerance);
if (unlikely (status))
return status;
 
/* And join the final face */
if (! stroker->dash.dashed || stroker->dash.dash_on) {
slope_dx = _cairo_fixed_to_double (spline.final_slope.dx);
slope_dy = _cairo_fixed_to_double (spline.final_slope.dy);
if (_compute_normalized_device_slope (&slope_dx, &slope_dy,
stroker->ctm_inverse, NULL))
{
_compute_face (&stroker->current_point,
&spline.final_slope,
slope_dx, slope_dy,
stroker, &face);
}
 
status = _cairo_stroker_join (stroker, &stroker->current_face, &face);
if (unlikely (status))
return status;
 
stroker->current_face = face;
}
 
stroker->style.line_join = line_join_save;
 
return CAIRO_STATUS_SUCCESS;
}
 
static cairo_status_t
_cairo_stroker_close_path (void *closure)
{
cairo_stroker_t *stroker = closure;
cairo_status_t status;
 
if (stroker->dash.dashed)
status = _cairo_stroker_line_to_dashed (stroker, &stroker->first_point);
else
status = _cairo_stroker_line_to (stroker, &stroker->first_point);
if (unlikely (status))
return status;
 
if (stroker->has_first_face && stroker->has_current_face) {
/* Join first and final faces of sub path */
status = _cairo_stroker_join (stroker,
&stroker->current_face,
&stroker->first_face);
if (unlikely (status))
return status;
} else {
/* Cap the start and end of the sub path as needed */
status = _cairo_stroker_add_caps (stroker);
if (unlikely (status))
return status;
}
 
stroker->has_initial_sub_path = FALSE;
stroker->has_first_face = FALSE;
stroker->has_current_face = FALSE;
 
return CAIRO_STATUS_SUCCESS;
}
 
cairo_status_t
_cairo_path_fixed_stroke_to_shaper (cairo_path_fixed_t *path,
const cairo_stroke_style_t *stroke_style,
const cairo_matrix_t *ctm,
const cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_status_t (*add_triangle) (void *closure,
const cairo_point_t triangle[3]),
cairo_status_t (*add_triangle_fan) (void *closure,
const cairo_point_t *midpt,
const cairo_point_t *points,
int npoints),
cairo_status_t (*add_convex_quad) (void *closure,
const cairo_point_t quad[4]),
void *closure)
{
cairo_stroker_t stroker;
cairo_status_t status;
 
status = _cairo_stroker_init (&stroker, stroke_style,
ctm, ctm_inverse, tolerance);
if (unlikely (status))
return status;
 
stroker.add_triangle = add_triangle;
stroker.add_triangle_fan = add_triangle_fan;
stroker.add_convex_quad = add_convex_quad;
stroker.closure = closure;
 
status = _cairo_path_fixed_interpret (path,
CAIRO_DIRECTION_FORWARD,
_cairo_stroker_move_to,
stroker.dash.dashed ?
_cairo_stroker_line_to_dashed :
_cairo_stroker_line_to,
_cairo_stroker_curve_to,
_cairo_stroker_close_path,
&stroker);
 
if (unlikely (status))
goto BAIL;
 
/* Cap the start and end of the final sub path as needed */
status = _cairo_stroker_add_caps (&stroker);
 
BAIL:
_cairo_stroker_fini (&stroker);
 
return status;
}
 
cairo_status_t
_cairo_path_fixed_stroke_to_polygon (const cairo_path_fixed_t *path,
const cairo_stroke_style_t *stroke_style,
const cairo_matrix_t *ctm,
const cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_polygon_t *polygon)
{
cairo_stroker_t stroker;
cairo_status_t status;
 
status = _cairo_stroker_init (&stroker, stroke_style,
ctm, ctm_inverse, tolerance);
if (unlikely (status))
return status;
 
stroker.add_external_edge = _cairo_polygon_add_external_edge,
stroker.closure = polygon;
 
if (polygon->num_limits)
_cairo_stroker_limit (&stroker, polygon->limits, polygon->num_limits);
 
status = _cairo_path_fixed_interpret (path,
CAIRO_DIRECTION_FORWARD,
_cairo_stroker_move_to,
stroker.dash.dashed ?
_cairo_stroker_line_to_dashed :
_cairo_stroker_line_to,
_cairo_stroker_curve_to,
_cairo_stroker_close_path,
&stroker);
 
if (unlikely (status))
goto BAIL;
 
/* Cap the start and end of the final sub path as needed */
status = _cairo_stroker_add_caps (&stroker);
 
BAIL:
_cairo_stroker_fini (&stroker);
 
return status;
}
 
cairo_status_t
_cairo_path_fixed_stroke_to_traps (const cairo_path_fixed_t *path,
const cairo_stroke_style_t *stroke_style,
const cairo_matrix_t *ctm,
const cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_traps_t *traps)
{
cairo_status_t status;
cairo_polygon_t polygon;
 
/* Before we do anything else, we attempt the rectilinear
* stroker. It's careful to generate trapezoids that align to
* device-pixel boundaries when possible. Many backends can render
* those much faster than non-aligned trapezoids, (by using clip
* regions, etc.) */
if (path->is_rectilinear) {
status = _cairo_path_fixed_stroke_rectilinear_to_traps (path,
stroke_style,
ctm,
traps);
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
return status;
}
 
_cairo_polygon_init (&polygon);
if (traps->num_limits)
_cairo_polygon_limit (&polygon, traps->limits, traps->num_limits);
 
status = _cairo_path_fixed_stroke_to_polygon (path,
stroke_style,
ctm,
ctm_inverse,
tolerance,
&polygon);
if (unlikely (status))
goto BAIL;
 
status = _cairo_polygon_status (&polygon);
if (unlikely (status))
goto BAIL;
 
status = _cairo_bentley_ottmann_tessellate_polygon (traps, &polygon,
CAIRO_FILL_RULE_WINDING);
 
BAIL:
_cairo_polygon_fini (&polygon);
 
return status;
}
 
typedef struct _segment_t {
cairo_point_t p1, p2;
cairo_bool_t is_horizontal;
cairo_bool_t has_join;
} segment_t;
 
typedef struct _cairo_rectilinear_stroker {
const cairo_stroke_style_t *stroke_style;
const cairo_matrix_t *ctm;
 
cairo_fixed_t half_line_width;
cairo_bool_t do_traps;
void *container;
cairo_point_t current_point;
cairo_point_t first_point;
cairo_bool_t open_sub_path;
 
cairo_stroker_dash_t dash;
 
cairo_bool_t has_bounds;
cairo_box_t bounds;
 
int num_segments;
int segments_size;
segment_t *segments;
segment_t segments_embedded[8]; /* common case is a single rectangle */
} cairo_rectilinear_stroker_t;
 
static void
_cairo_rectilinear_stroker_limit (cairo_rectilinear_stroker_t *stroker,
const cairo_box_t *boxes,
int num_boxes)
{
stroker->has_bounds = TRUE;
_cairo_boxes_get_extents (boxes, num_boxes, &stroker->bounds);
 
stroker->bounds.p1.x -= stroker->half_line_width;
stroker->bounds.p2.x += stroker->half_line_width;
 
stroker->bounds.p1.y -= stroker->half_line_width;
stroker->bounds.p2.y += stroker->half_line_width;
}
 
static cairo_bool_t
_cairo_rectilinear_stroker_init (cairo_rectilinear_stroker_t *stroker,
const cairo_stroke_style_t *stroke_style,
const cairo_matrix_t *ctm,
cairo_bool_t do_traps,
void *container)
{
/* This special-case rectilinear stroker only supports
* miter-joined lines (not curves) and a translation-only matrix
* (though it could probably be extended to support a matrix with
* uniform, integer scaling).
*
* It also only supports horizontal and vertical line_to
* elements. But we don't catch that here, but instead return
* UNSUPPORTED from _cairo_rectilinear_stroker_line_to if any
* non-rectilinear line_to is encountered.
*/
if (stroke_style->line_join != CAIRO_LINE_JOIN_MITER)
return FALSE;
 
/* If the miter limit turns right angles into bevels, then we
* can't use this optimization. Remember, the ratio is
* 1/sin(ɸ/2). So the cutoff is 1/sin(π/4.0) or ⎷2,
* which we round for safety. */
if (stroke_style->miter_limit < M_SQRT2)
return FALSE;
 
if (! (stroke_style->line_cap == CAIRO_LINE_CAP_BUTT ||
stroke_style->line_cap == CAIRO_LINE_CAP_SQUARE))
{
return FALSE;
}
 
if (! _cairo_matrix_has_unity_scale (ctm))
return FALSE;
 
stroker->stroke_style = stroke_style;
stroker->ctm = ctm;
 
stroker->half_line_width =
_cairo_fixed_from_double (stroke_style->line_width / 2.0);
stroker->open_sub_path = FALSE;
stroker->segments = stroker->segments_embedded;
stroker->segments_size = ARRAY_LENGTH (stroker->segments_embedded);
stroker->num_segments = 0;
 
_cairo_stroker_dash_init (&stroker->dash, stroke_style);
 
stroker->has_bounds = FALSE;
 
stroker->do_traps = do_traps;
stroker->container = container;
 
return TRUE;
}
 
static void
_cairo_rectilinear_stroker_fini (cairo_rectilinear_stroker_t *stroker)
{
if (stroker->segments != stroker->segments_embedded)
free (stroker->segments);
}
 
static cairo_status_t
_cairo_rectilinear_stroker_add_segment (cairo_rectilinear_stroker_t *stroker,
const cairo_point_t *p1,
const cairo_point_t *p2,
cairo_bool_t is_horizontal,
cairo_bool_t has_join)
{
if (CAIRO_INJECT_FAULT ())
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
if (stroker->num_segments == stroker->segments_size) {
int new_size = stroker->segments_size * 2;
segment_t *new_segments;
 
if (stroker->segments == stroker->segments_embedded) {
new_segments = _cairo_malloc_ab (new_size, sizeof (segment_t));
if (unlikely (new_segments == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
memcpy (new_segments, stroker->segments,
stroker->num_segments * sizeof (segment_t));
} else {
new_segments = _cairo_realloc_ab (stroker->segments,
new_size, sizeof (segment_t));
if (unlikely (new_segments == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
 
stroker->segments_size = new_size;
stroker->segments = new_segments;
}
 
stroker->segments[stroker->num_segments].p1 = *p1;
stroker->segments[stroker->num_segments].p2 = *p2;
stroker->segments[stroker->num_segments].has_join = has_join;
stroker->segments[stroker->num_segments].is_horizontal = is_horizontal;
stroker->num_segments++;
 
return CAIRO_STATUS_SUCCESS;
}
 
static cairo_status_t
_cairo_rectilinear_stroker_emit_segments (cairo_rectilinear_stroker_t *stroker)
{
cairo_status_t status;
cairo_line_cap_t line_cap = stroker->stroke_style->line_cap;
cairo_fixed_t half_line_width = stroker->half_line_width;
int i;
 
for (i = 0; i < stroker->num_segments; i++) {
cairo_point_t *a, *b;
cairo_bool_t lengthen_initial, shorten_final, lengthen_final;
 
a = &stroker->segments[i].p1;
b = &stroker->segments[i].p2;
 
/* For each segment we generate a single rectangular
* trapezoid. This rectangle is based on a perpendicular
* extension (by half the line width) of the segment endpoints
* after some adjustments of the endpoints to account for caps
* and joins.
*/
 
/* We adjust the initial point of the segment to extend the
* rectangle to include the previous cap or join, (this
* adjustment applies to all segments except for the first
* segment of open, butt-capped paths).
*/
lengthen_initial = TRUE;
if (i == 0 && stroker->open_sub_path && line_cap == CAIRO_LINE_CAP_BUTT)
lengthen_initial = FALSE;
 
/* The adjustment of the final point is trickier. For all but
* the last segment we shorten the segment at the final
* endpoint to not overlap with the subsequent join. For the
* last segment we do the same shortening if the path is
* closed. If the path is open and butt-capped we do no
* adjustment, while if it's open and square-capped we do a
* lengthening adjustment instead to include the cap.
*/
shorten_final = TRUE;
lengthen_final = FALSE;
if (i == stroker->num_segments - 1 && stroker->open_sub_path) {
shorten_final = FALSE;
if (line_cap == CAIRO_LINE_CAP_SQUARE)
lengthen_final = TRUE;
}
 
/* Perform the adjustments of the endpoints. */
if (a->y == b->y) {
if (a->x < b->x) {
if (lengthen_initial)
a->x -= half_line_width;
if (shorten_final)
b->x -= half_line_width;
else if (lengthen_final)
b->x += half_line_width;
} else {
if (lengthen_initial)
a->x += half_line_width;
if (shorten_final)
b->x += half_line_width;
else if (lengthen_final)
b->x -= half_line_width;
}
 
if (a->x > b->x) {
cairo_point_t *t;
 
t = a;
a = b;
b = t;
}
} else {
if (a->y < b->y) {
if (lengthen_initial)
a->y -= half_line_width;
if (shorten_final)
b->y -= half_line_width;
else if (lengthen_final)
b->y += half_line_width;
} else {
if (lengthen_initial)
a->y += half_line_width;
if (shorten_final)
b->y += half_line_width;
else if (lengthen_final)
b->y -= half_line_width;
}
 
if (a->y > b->y) {
cairo_point_t *t;
 
t = a;
a = b;
b = t;
}
}
 
/* Form the rectangle by expanding by half the line width in
* either perpendicular direction. */
if (a->y == b->y) {
a->y -= half_line_width;
b->y += half_line_width;
} else {
a->x -= half_line_width;
b->x += half_line_width;
}
 
if (stroker->do_traps) {
status = _cairo_traps_tessellate_rectangle (stroker->container, a, b);
} else {
cairo_box_t box;
 
box.p1 = *a;
box.p2 = *b;
 
status = _cairo_boxes_add (stroker->container, &box);
}
if (unlikely (status))
return status;
}
 
stroker->num_segments = 0;
 
return CAIRO_STATUS_SUCCESS;
}
 
static cairo_status_t
_cairo_rectilinear_stroker_emit_segments_dashed (cairo_rectilinear_stroker_t *stroker)
{
cairo_status_t status;
cairo_line_cap_t line_cap = stroker->stroke_style->line_cap;
cairo_fixed_t half_line_width = stroker->half_line_width;
int i;
 
for (i = 0; i < stroker->num_segments; i++) {
cairo_point_t *a, *b;
cairo_bool_t is_horizontal;
 
a = &stroker->segments[i].p1;
b = &stroker->segments[i].p2;
 
is_horizontal = stroker->segments[i].is_horizontal;
 
/* Handle the joins for a potentially degenerate segment. */
if (line_cap == CAIRO_LINE_CAP_BUTT &&
stroker->segments[i].has_join &&
(i != stroker->num_segments - 1 ||
(! stroker->open_sub_path && stroker->dash.dash_starts_on)))
{
cairo_point_t p1 = stroker->segments[i].p1;
cairo_point_t p2 = stroker->segments[i].p2;
cairo_slope_t out_slope;
int j = (i + 1) % stroker->num_segments;
 
_cairo_slope_init (&out_slope,
&stroker->segments[j].p1,
&stroker->segments[j].p2);
 
if (is_horizontal) {
if (p1.x <= p2.x) {
p1.x = p2.x;
p2.x += half_line_width;
} else {
p1.x = p2.x - half_line_width;
}
if (out_slope.dy >= 0)
p1.y -= half_line_width;
if (out_slope.dy <= 0)
p2.y += half_line_width;
} else {
if (p1.y <= p2.y) {
p1.y = p2.y;
p2.y += half_line_width;
} else {
p1.y = p2.y - half_line_width;
}
if (out_slope.dx >= 0)
p1.x -= half_line_width;
if (out_slope.dx <= 0)
p2.x += half_line_width;
}
 
if (stroker->do_traps) {
status = _cairo_traps_tessellate_rectangle (stroker->container, &p1, &p2);
} else {
cairo_box_t box;
 
box.p1 = p1;
box.p2 = p2;
 
status = _cairo_boxes_add (stroker->container, &box);
}
if (unlikely (status))
return status;
}
 
/* Perform the adjustments of the endpoints. */
if (is_horizontal) {
if (line_cap == CAIRO_LINE_CAP_SQUARE) {
if (a->x <= b->x) {
a->x -= half_line_width;
b->x += half_line_width;
} else {
a->x += half_line_width;
b->x -= half_line_width;
}
}
 
if (a->x > b->x) {
cairo_point_t *t;
 
t = a;
a = b;
b = t;
}
 
a->y -= half_line_width;
b->y += half_line_width;
} else {
if (line_cap == CAIRO_LINE_CAP_SQUARE) {
if (a->y <= b->y) {
a->y -= half_line_width;
b->y += half_line_width;
} else {
a->y += half_line_width;
b->y -= half_line_width;
}
}
 
if (a->y > b->y) {
cairo_point_t *t;
 
t = a;
a = b;
b = t;
}
 
a->x -= half_line_width;
b->x += half_line_width;
}
 
if (a->x == b->x && a->y == b->y)
continue;
 
if (stroker->do_traps) {
status = _cairo_traps_tessellate_rectangle (stroker->container, a, b);
} else {
cairo_box_t box;
 
box.p1 = *a;
box.p2 = *b;
 
status = _cairo_boxes_add (stroker->container, &box);
}
if (unlikely (status))
return status;
}
 
stroker->num_segments = 0;
 
return CAIRO_STATUS_SUCCESS;
}
 
static cairo_status_t
_cairo_rectilinear_stroker_move_to (void *closure,
const cairo_point_t *point)
{
cairo_rectilinear_stroker_t *stroker = closure;
cairo_status_t status;
 
if (stroker->dash.dashed)
status = _cairo_rectilinear_stroker_emit_segments_dashed (stroker);
else
status = _cairo_rectilinear_stroker_emit_segments (stroker);
if (unlikely (status))
return status;
 
/* reset the dash pattern for new sub paths */
_cairo_stroker_dash_start (&stroker->dash);
 
stroker->current_point = *point;
stroker->first_point = *point;
 
return CAIRO_STATUS_SUCCESS;
}
 
static cairo_status_t
_cairo_rectilinear_stroker_line_to (void *closure,
const cairo_point_t *b)
{
cairo_rectilinear_stroker_t *stroker = closure;
cairo_point_t *a = &stroker->current_point;
cairo_status_t status;
 
/* We only support horizontal or vertical elements. */
assert (a->x == b->x || a->y == b->y);
 
/* We don't draw anything for degenerate paths. */
if (a->x == b->x && a->y == b->y)
return CAIRO_STATUS_SUCCESS;
 
status = _cairo_rectilinear_stroker_add_segment (stroker, a, b,
a->y == b->y,
TRUE);
 
stroker->current_point = *b;
stroker->open_sub_path = TRUE;
 
return status;
}
 
static cairo_status_t
_cairo_rectilinear_stroker_line_to_dashed (void *closure,
const cairo_point_t *point)
{
cairo_rectilinear_stroker_t *stroker = closure;
const cairo_point_t *a = &stroker->current_point;
const cairo_point_t *b = point;
cairo_bool_t fully_in_bounds;
double sign, remain;
cairo_fixed_t mag;
cairo_status_t status;
cairo_line_t segment;
cairo_bool_t dash_on = FALSE;
cairo_bool_t is_horizontal;
 
/* We don't draw anything for degenerate paths. */
if (a->x == b->x && a->y == b->y)
return CAIRO_STATUS_SUCCESS;
 
/* We only support horizontal or vertical elements. */
assert (a->x == b->x || a->y == b->y);
 
fully_in_bounds = TRUE;
if (stroker->has_bounds &&
(! _cairo_box_contains_point (&stroker->bounds, a) ||
! _cairo_box_contains_point (&stroker->bounds, b)))
{
fully_in_bounds = FALSE;
}
 
is_horizontal = a->y == b->y;
if (is_horizontal)
mag = b->x - a->x;
else
mag = b->y - a->y;
if (mag < 0) {
remain = _cairo_fixed_to_double (-mag);
sign = 1.;
} else {
remain = _cairo_fixed_to_double (mag);
sign = -1.;
}
 
segment.p2 = segment.p1 = *a;
while (remain > 0.) {
double step_length;
 
step_length = MIN (stroker->dash.dash_remain, remain);
remain -= step_length;
 
mag = _cairo_fixed_from_double (sign*remain);
if (is_horizontal)
segment.p2.x = b->x + mag;
else
segment.p2.y = b->y + mag;
 
if (stroker->dash.dash_on &&
(fully_in_bounds ||
_cairo_box_intersects_line_segment (&stroker->bounds, &segment)))
{
status = _cairo_rectilinear_stroker_add_segment (stroker,
&segment.p1,
&segment.p2,
is_horizontal,
remain <= 0.);
if (unlikely (status))
return status;
 
dash_on = TRUE;
}
else
{
dash_on = FALSE;
}
 
_cairo_stroker_dash_step (&stroker->dash, step_length);
segment.p1 = segment.p2;
}
 
if (stroker->dash.dash_on && ! dash_on &&
(fully_in_bounds ||
_cairo_box_intersects_line_segment (&stroker->bounds, &segment)))
{
 
/* This segment ends on a transition to dash_on, compute a new face
* and add cap for the beginning of the next dash_on step.
*/
 
status = _cairo_rectilinear_stroker_add_segment (stroker,
&segment.p1,
&segment.p1,
is_horizontal,
TRUE);
if (unlikely (status))
return status;
}
 
stroker->current_point = *point;
stroker->open_sub_path = TRUE;
 
return CAIRO_STATUS_SUCCESS;
}
 
static cairo_status_t
_cairo_rectilinear_stroker_close_path (void *closure)
{
cairo_rectilinear_stroker_t *stroker = closure;
cairo_status_t status;
 
/* We don't draw anything for degenerate paths. */
if (! stroker->open_sub_path)
return CAIRO_STATUS_SUCCESS;
 
if (stroker->dash.dashed) {
status = _cairo_rectilinear_stroker_line_to_dashed (stroker,
&stroker->first_point);
} else {
status = _cairo_rectilinear_stroker_line_to (stroker,
&stroker->first_point);
}
if (unlikely (status))
return status;
 
stroker->open_sub_path = FALSE;
 
if (stroker->dash.dashed)
status = _cairo_rectilinear_stroker_emit_segments_dashed (stroker);
else
status = _cairo_rectilinear_stroker_emit_segments (stroker);
if (unlikely (status))
return status;
 
return CAIRO_STATUS_SUCCESS;
}
 
cairo_int_status_t
_cairo_path_fixed_stroke_rectilinear_to_traps (const cairo_path_fixed_t *path,
const cairo_stroke_style_t *stroke_style,
const cairo_matrix_t *ctm,
cairo_traps_t *traps)
{
cairo_rectilinear_stroker_t rectilinear_stroker;
cairo_int_status_t status;
 
assert (path->is_rectilinear);
 
if (! _cairo_rectilinear_stroker_init (&rectilinear_stroker,
stroke_style, ctm,
TRUE, traps))
{
return CAIRO_INT_STATUS_UNSUPPORTED;
}
 
if (traps->num_limits) {
_cairo_rectilinear_stroker_limit (&rectilinear_stroker,
traps->limits,
traps->num_limits);
}
 
status = _cairo_path_fixed_interpret (path,
CAIRO_DIRECTION_FORWARD,
_cairo_rectilinear_stroker_move_to,
rectilinear_stroker.dash.dashed ?
_cairo_rectilinear_stroker_line_to_dashed :
_cairo_rectilinear_stroker_line_to,
NULL,
_cairo_rectilinear_stroker_close_path,
&rectilinear_stroker);
if (unlikely (status))
goto BAIL;
 
if (rectilinear_stroker.dash.dashed)
status = _cairo_rectilinear_stroker_emit_segments_dashed (&rectilinear_stroker);
else
status = _cairo_rectilinear_stroker_emit_segments (&rectilinear_stroker);
 
traps->is_rectilinear = 1;
traps->is_rectangular = 1;
/* As we incrementally tessellate, we do not eliminate self-intersections */
traps->has_intersections = traps->num_traps > 1;
BAIL:
_cairo_rectilinear_stroker_fini (&rectilinear_stroker);
 
if (unlikely (status))
_cairo_traps_clear (traps);
 
return status;
}
 
cairo_int_status_t
_cairo_path_fixed_stroke_rectilinear_to_boxes (const cairo_path_fixed_t *path,
const cairo_stroke_style_t *stroke_style,
const cairo_matrix_t *ctm,
cairo_boxes_t *boxes)
{
cairo_rectilinear_stroker_t rectilinear_stroker;
cairo_int_status_t status;
 
assert (path->is_rectilinear);
 
if (! _cairo_rectilinear_stroker_init (&rectilinear_stroker,
stroke_style, ctm,
FALSE, boxes))
{
return CAIRO_INT_STATUS_UNSUPPORTED;
}
 
if (boxes->num_limits) {
_cairo_rectilinear_stroker_limit (&rectilinear_stroker,
boxes->limits,
boxes->num_limits);
}
 
status = _cairo_path_fixed_interpret (path,
CAIRO_DIRECTION_FORWARD,
_cairo_rectilinear_stroker_move_to,
rectilinear_stroker.dash.dashed ?
_cairo_rectilinear_stroker_line_to_dashed :
_cairo_rectilinear_stroker_line_to,
NULL,
_cairo_rectilinear_stroker_close_path,
&rectilinear_stroker);
if (unlikely (status))
goto BAIL;
 
if (rectilinear_stroker.dash.dashed)
status = _cairo_rectilinear_stroker_emit_segments_dashed (&rectilinear_stroker);
else
status = _cairo_rectilinear_stroker_emit_segments (&rectilinear_stroker);
if (unlikely (status))
goto BAIL;
 
/* As we incrementally tessellate, we do not eliminate self-intersections */
status = _cairo_bentley_ottmann_tessellate_boxes (boxes,
CAIRO_FILL_RULE_WINDING,
boxes);
if (unlikely (status))
goto BAIL;
 
_cairo_rectilinear_stroker_fini (&rectilinear_stroker);
 
return CAIRO_STATUS_SUCCESS;
 
BAIL:
_cairo_rectilinear_stroker_fini (&rectilinear_stroker);
_cairo_boxes_clear (boxes);
return status;
}
/programs/develop/libraries/cairo/src/cairo-path.c
0,0 → 1,536
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2005 Red Hat, Inc.
* Copyright © 2006 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
* Carl D. Worth <cworth@redhat.com>
*/
 
#include "cairoint.h"
 
#include "cairo-private.h"
#include "cairo-error-private.h"
#include "cairo-path-private.h"
#include "cairo-path-fixed-private.h"
 
/**
* SECTION:cairo-paths
* @Title: Paths
* @Short_Description: Creating paths and manipulating path data
*
* Paths are the most basic drawing tools and are primarily used to implicitly
* generate simple masks.
*/
 
static const cairo_path_t _cairo_path_nil = { CAIRO_STATUS_NO_MEMORY, NULL, 0 };
 
/* Closure for path interpretation. */
typedef struct cairo_path_count {
int count;
cairo_point_t current_point;
} cpc_t;
 
static cairo_status_t
_cpc_move_to (void *closure,
const cairo_point_t *point)
{
cpc_t *cpc = closure;
 
cpc->count += 2;
 
cpc->current_point = *point;
 
return CAIRO_STATUS_SUCCESS;
}
 
static cairo_status_t
_cpc_line_to (void *closure,
const cairo_point_t *point)
{
cpc_t *cpc = closure;
 
cpc->count += 2;
 
cpc->current_point = *point;
 
return CAIRO_STATUS_SUCCESS;
}
 
static cairo_status_t
_cpc_curve_to (void *closure,
const cairo_point_t *p1,
const cairo_point_t *p2,
const cairo_point_t *p3)
{
cpc_t *cpc = closure;
 
cpc->count += 4;
 
cpc->current_point = *p3;
 
return CAIRO_STATUS_SUCCESS;
}
 
static cairo_status_t
_cpc_close_path (void *closure)
{
cpc_t *cpc = closure;
 
cpc->count += 1;
 
return CAIRO_STATUS_SUCCESS;
}
 
static int
_cairo_path_count (cairo_path_t *path,
cairo_path_fixed_t *path_fixed,
double tolerance,
cairo_bool_t flatten)
{
cairo_status_t status;
cpc_t cpc;
 
cpc.count = 0;
cpc.current_point.x = 0;
cpc.current_point.y = 0;
 
if (flatten) {
status = _cairo_path_fixed_interpret_flat (path_fixed,
CAIRO_DIRECTION_FORWARD,
_cpc_move_to,
_cpc_line_to,
_cpc_close_path,
&cpc,
tolerance);
} else {
status = _cairo_path_fixed_interpret (path_fixed,
CAIRO_DIRECTION_FORWARD,
_cpc_move_to,
_cpc_line_to,
_cpc_curve_to,
_cpc_close_path,
&cpc);
}
 
if (unlikely (status))
return -1;
 
return cpc.count;
}
 
/* Closure for path interpretation. */
typedef struct cairo_path_populate {
cairo_path_data_t *data;
cairo_gstate_t *gstate;
cairo_point_t current_point;
} cpp_t;
 
static cairo_status_t
_cpp_move_to (void *closure,
const cairo_point_t *point)
{
cpp_t *cpp = closure;
cairo_path_data_t *data = cpp->data;
double x, y;
 
x = _cairo_fixed_to_double (point->x);
y = _cairo_fixed_to_double (point->y);
 
_cairo_gstate_backend_to_user (cpp->gstate, &x, &y);
 
data->header.type = CAIRO_PATH_MOVE_TO;
data->header.length = 2;
 
/* We index from 1 to leave room for data->header */
data[1].point.x = x;
data[1].point.y = y;
 
cpp->data += data->header.length;
 
cpp->current_point = *point;
 
return CAIRO_STATUS_SUCCESS;
}
 
static cairo_status_t
_cpp_line_to (void *closure,
const cairo_point_t *point)
{
cpp_t *cpp = closure;
cairo_path_data_t *data = cpp->data;
double x, y;
 
x = _cairo_fixed_to_double (point->x);
y = _cairo_fixed_to_double (point->y);
 
_cairo_gstate_backend_to_user (cpp->gstate, &x, &y);
 
data->header.type = CAIRO_PATH_LINE_TO;
data->header.length = 2;
 
/* We index from 1 to leave room for data->header */
data[1].point.x = x;
data[1].point.y = y;
 
cpp->data += data->header.length;
 
cpp->current_point = *point;
 
return CAIRO_STATUS_SUCCESS;
}
 
static cairo_status_t
_cpp_curve_to (void *closure,
const cairo_point_t *p1,
const cairo_point_t *p2,
const cairo_point_t *p3)
{
cpp_t *cpp = closure;
cairo_path_data_t *data = cpp->data;
double x1, y1;
double x2, y2;
double x3, y3;
 
x1 = _cairo_fixed_to_double (p1->x);
y1 = _cairo_fixed_to_double (p1->y);
_cairo_gstate_backend_to_user (cpp->gstate, &x1, &y1);
 
x2 = _cairo_fixed_to_double (p2->x);
y2 = _cairo_fixed_to_double (p2->y);
_cairo_gstate_backend_to_user (cpp->gstate, &x2, &y2);
 
x3 = _cairo_fixed_to_double (p3->x);
y3 = _cairo_fixed_to_double (p3->y);
_cairo_gstate_backend_to_user (cpp->gstate, &x3, &y3);
 
data->header.type = CAIRO_PATH_CURVE_TO;
data->header.length = 4;
 
/* We index from 1 to leave room for data->header */
data[1].point.x = x1;
data[1].point.y = y1;
 
data[2].point.x = x2;
data[2].point.y = y2;
 
data[3].point.x = x3;
data[3].point.y = y3;
 
cpp->data += data->header.length;
 
cpp->current_point = *p3;
 
return CAIRO_STATUS_SUCCESS;
}
 
static cairo_status_t
_cpp_close_path (void *closure)
{
cpp_t *cpp = closure;
cairo_path_data_t *data = cpp->data;
 
data->header.type = CAIRO_PATH_CLOSE_PATH;
data->header.length = 1;
 
cpp->data += data->header.length;
 
return CAIRO_STATUS_SUCCESS;
}
 
static cairo_status_t
_cairo_path_populate (cairo_path_t *path,
cairo_path_fixed_t *path_fixed,
cairo_gstate_t *gstate,
cairo_bool_t flatten)
{
cairo_status_t status;
cpp_t cpp;
 
cpp.data = path->data;
cpp.gstate = gstate;
cpp.current_point.x = 0;
cpp.current_point.y = 0;
 
if (flatten) {
double tolerance = _cairo_gstate_get_tolerance (gstate);
status = _cairo_path_fixed_interpret_flat (path_fixed,
CAIRO_DIRECTION_FORWARD,
_cpp_move_to,
_cpp_line_to,
_cpp_close_path,
&cpp,
tolerance);
} else {
status = _cairo_path_fixed_interpret (path_fixed,
CAIRO_DIRECTION_FORWARD,
_cpp_move_to,
_cpp_line_to,
_cpp_curve_to,
_cpp_close_path,
&cpp);
}
 
if (unlikely (status))
return status;
 
/* Sanity check the count */
assert (cpp.data - path->data == path->num_data);
 
return CAIRO_STATUS_SUCCESS;
}
 
cairo_path_t *
_cairo_path_create_in_error (cairo_status_t status)
{
cairo_path_t *path;
 
/* special case NO_MEMORY so as to avoid allocations */
if (status == CAIRO_STATUS_NO_MEMORY)
return (cairo_path_t*) &_cairo_path_nil;
 
path = malloc (sizeof (cairo_path_t));
if (unlikely (path == NULL)) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_path_t*) &_cairo_path_nil;
}
 
path->num_data = 0;
path->data = NULL;
path->status = status;
 
return path;
}
 
static cairo_path_t *
_cairo_path_create_internal (cairo_path_fixed_t *path_fixed,
cairo_gstate_t *gstate,
cairo_bool_t flatten)
{
cairo_path_t *path;
 
path = malloc (sizeof (cairo_path_t));
if (unlikely (path == NULL)) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_path_t*) &_cairo_path_nil;
}
 
path->num_data = _cairo_path_count (path, path_fixed,
_cairo_gstate_get_tolerance (gstate),
flatten);
if (path->num_data < 0) {
free (path);
return (cairo_path_t*) &_cairo_path_nil;
}
 
if (path->num_data) {
path->data = _cairo_malloc_ab (path->num_data,
sizeof (cairo_path_data_t));
if (unlikely (path->data == NULL)) {
free (path);
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_path_t*) &_cairo_path_nil;
}
 
path->status = _cairo_path_populate (path, path_fixed,
gstate, flatten);
} else {
path->data = NULL;
path->status = CAIRO_STATUS_SUCCESS;
}
 
return path;
}
 
/**
* cairo_path_destroy:
* @path: a path previously returned by either cairo_copy_path() or
* cairo_copy_path_flat().
*
* Immediately releases all memory associated with @path. After a call
* to cairo_path_destroy() the @path pointer is no longer valid and
* should not be used further.
*
* Note: cairo_path_destroy() should only be called with a
* pointer to a #cairo_path_t returned by a cairo function. Any path
* that is created manually (ie. outside of cairo) should be destroyed
* manually as well.
**/
void
cairo_path_destroy (cairo_path_t *path)
{
if (path == NULL || path == &_cairo_path_nil)
return;
 
if (path->data)
free (path->data);
 
free (path);
}
 
/**
* _cairo_path_create:
* @path: a fixed-point, device-space path to be converted and copied
* @gstate: the current graphics state
*
* Creates a user-space #cairo_path_t copy of the given device-space
* @path. The @gstate parameter provides the inverse CTM for the
* conversion.
*
* Return value: the new copy of the path. If there is insufficient
* memory a pointer to a special static nil #cairo_path_t will be
* returned instead with status==%CAIRO_STATUS_NO_MEMORY and
* data==%NULL.
**/
cairo_path_t *
_cairo_path_create (cairo_path_fixed_t *path,
cairo_gstate_t *gstate)
{
return _cairo_path_create_internal (path, gstate, FALSE);
}
 
/**
* _cairo_path_create_flat:
* @path: a fixed-point, device-space path to be flattened, converted and copied
* @gstate: the current graphics state
*
* Creates a flattened, user-space #cairo_path_t copy of the given
* device-space @path. The @gstate parameter provide the inverse CTM
* for the conversion, as well as the tolerance value to control the
* accuracy of the flattening.
*
* Return value: the flattened copy of the path. If there is insufficient
* memory a pointer to a special static nil #cairo_path_t will be
* returned instead with status==%CAIRO_STATUS_NO_MEMORY and
* data==%NULL.
**/
cairo_path_t *
_cairo_path_create_flat (cairo_path_fixed_t *path,
cairo_gstate_t *gstate)
{
return _cairo_path_create_internal (path, gstate, TRUE);
}
 
/**
* _cairo_path_append_to_context:
* @path: the path data to be appended
* @cr: a cairo context
*
* Append @path to the current path within @cr.
*
* Return value: %CAIRO_STATUS_INVALID_PATH_DATA if the data in @path
* is invalid, and %CAIRO_STATUS_SUCCESS otherwise.
**/
cairo_status_t
_cairo_path_append_to_context (const cairo_path_t *path,
cairo_t *cr)
{
const cairo_path_data_t *p, *end;
cairo_fixed_t x1_fixed, y1_fixed;
cairo_fixed_t x2_fixed, y2_fixed;
cairo_fixed_t x3_fixed, y3_fixed;
cairo_matrix_t user_to_backend;
cairo_status_t status;
double x, y;
 
user_to_backend = cr->gstate->ctm;
cairo_matrix_multiply (&user_to_backend,
&user_to_backend,
&cr->gstate->target->device_transform);
 
end = &path->data[path->num_data];
for (p = &path->data[0]; p < end; p += p->header.length) {
switch (p->header.type) {
case CAIRO_PATH_MOVE_TO:
if (unlikely (p->header.length < 2))
return _cairo_error (CAIRO_STATUS_INVALID_PATH_DATA);
 
x = p[1].point.x, y = p[1].point.y;
cairo_matrix_transform_point (&user_to_backend, &x, &y);
x1_fixed = _cairo_fixed_from_double (x);
y1_fixed = _cairo_fixed_from_double (y);
 
status = _cairo_path_fixed_move_to (cr->path, x1_fixed, y1_fixed);
break;
 
case CAIRO_PATH_LINE_TO:
if (unlikely (p->header.length < 2))
return _cairo_error (CAIRO_STATUS_INVALID_PATH_DATA);
 
x = p[1].point.x, y = p[1].point.y;
cairo_matrix_transform_point (&user_to_backend, &x, &y);
x1_fixed = _cairo_fixed_from_double (x);
y1_fixed = _cairo_fixed_from_double (y);
 
status = _cairo_path_fixed_line_to (cr->path, x1_fixed, y1_fixed);
break;
 
case CAIRO_PATH_CURVE_TO:
if (unlikely (p->header.length < 4))
return _cairo_error (CAIRO_STATUS_INVALID_PATH_DATA);
 
x = p[1].point.x, y = p[1].point.y;
cairo_matrix_transform_point (&user_to_backend, &x, &y);
x1_fixed = _cairo_fixed_from_double (x);
y1_fixed = _cairo_fixed_from_double (y);
 
x = p[2].point.x, y = p[2].point.y;
cairo_matrix_transform_point (&user_to_backend, &x, &y);
x2_fixed = _cairo_fixed_from_double (x);
y2_fixed = _cairo_fixed_from_double (y);
 
x = p[3].point.x, y = p[3].point.y;
cairo_matrix_transform_point (&user_to_backend, &x, &y);
x3_fixed = _cairo_fixed_from_double (x);
y3_fixed = _cairo_fixed_from_double (y);
 
status = _cairo_path_fixed_curve_to (cr->path,
x1_fixed, y1_fixed,
x2_fixed, y2_fixed,
x3_fixed, y3_fixed);
break;
 
case CAIRO_PATH_CLOSE_PATH:
if (unlikely (p->header.length < 1))
return _cairo_error (CAIRO_STATUS_INVALID_PATH_DATA);
 
status = _cairo_path_fixed_close_path (cr->path);
break;
 
default:
return _cairo_error (CAIRO_STATUS_INVALID_PATH_DATA);
}
 
if (unlikely (status))
return status;
}
 
return CAIRO_STATUS_SUCCESS;
}
/programs/develop/libraries/cairo/src/cairo-pattern.c
0,0 → 1,3342
/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2004 David Reveman
* Copyright © 2005 Red Hat, Inc.
*
* Permission to use, copy, modify, distribute, and sell this software
* and its documentation for any purpose is hereby granted without
* fee, provided that the above copyright notice appear in all copies
* and that both that copyright notice and this permission notice
* appear in supporting documentation, and that the name of David
* Reveman not be used in advertising or publicity pertaining to
* distribution of the software without specific, written prior
* permission. David Reveman makes no representations about the
* suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* DAVID REVEMAN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS, IN NO EVENT SHALL DAVID REVEMAN BE LIABLE FOR ANY SPECIAL,
* INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
* RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
* IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Authors: David Reveman <davidr@novell.com>
* Keith Packard <keithp@keithp.com>
* Carl Worth <cworth@cworth.org>
*/
 
#include "cairoint.h"
#include "cairo-error-private.h"
#include "cairo-freed-pool-private.h"
 
/**
* SECTION:cairo-pattern
* @Title: cairo_pattern_t
* @Short_Description: Sources for drawing
* @See_Also: #cairo_t, #cairo_surface_t
*
* #cairo_pattern_t is the paint with which cairo draws.
* The primary use of patterns is as the source for all cairo drawing
* operations, although they can also be used as masks, that is, as the
* brush too.
*
* A cairo pattern is created by using one of the many constructors,
* of the form cairo_pattern_create_<emphasis>type</emphasis>()
* or implicitly through
* cairo_set_source_<emphasis>type</emphasis>() functions.
*/
 
#if HAS_FREED_POOL
static freed_pool_t freed_pattern_pool[4];
#endif
 
static const cairo_solid_pattern_t _cairo_pattern_nil = {
{ CAIRO_PATTERN_TYPE_SOLID, /* type */
CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */
CAIRO_STATUS_NO_MEMORY, /* status */
{ 0, 0, 0, NULL }, /* user_data */
{ 1., 0., 0., 1., 0., 0., }, /* matrix */
CAIRO_FILTER_DEFAULT, /* filter */
CAIRO_EXTEND_GRADIENT_DEFAULT }, /* extend */
};
 
static const cairo_solid_pattern_t _cairo_pattern_nil_null_pointer = {
{ CAIRO_PATTERN_TYPE_SOLID, /* type */
CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */
CAIRO_STATUS_NULL_POINTER, /* status */
{ 0, 0, 0, NULL }, /* user_data */
{ 1., 0., 0., 1., 0., 0., }, /* matrix */
CAIRO_FILTER_DEFAULT, /* filter */
CAIRO_EXTEND_GRADIENT_DEFAULT }, /* extend */
};
 
const cairo_solid_pattern_t _cairo_pattern_black = {
{ CAIRO_PATTERN_TYPE_SOLID, /* type */
CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */
CAIRO_STATUS_SUCCESS, /* status */
{ 0, 0, 0, NULL }, /* user_data */
{ 1., 0., 0., 1., 0., 0., }, /* matrix */
CAIRO_FILTER_DEFAULT, /* filter */
CAIRO_EXTEND_GRADIENT_DEFAULT}, /* extend */
{ 0., 0., 0., 1., 0, 0, 0, 0xffff },/* color (double rgba, short rgba) */
};
 
const cairo_solid_pattern_t _cairo_pattern_clear = {
{ CAIRO_PATTERN_TYPE_SOLID, /* type */
CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */
CAIRO_STATUS_SUCCESS, /* status */
{ 0, 0, 0, NULL }, /* user_data */
{ 1., 0., 0., 1., 0., 0., }, /* matrix */
CAIRO_FILTER_DEFAULT, /* filter */
CAIRO_EXTEND_GRADIENT_DEFAULT}, /* extend */
{ 0., 0., 0., 0., 0, 0, 0, 0 },/* color (double rgba, short rgba) */
};
 
const cairo_solid_pattern_t _cairo_pattern_white = {
{ CAIRO_PATTERN_TYPE_SOLID, /* type */
CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */
CAIRO_STATUS_SUCCESS, /* status */
{ 0, 0, 0, NULL }, /* user_data */
{ 1., 0., 0., 1., 0., 0., }, /* matrix */
CAIRO_FILTER_DEFAULT, /* filter */
CAIRO_EXTEND_GRADIENT_DEFAULT}, /* extend */
{ 1., 1., 1., 1., 0xffff, 0xffff, 0xffff, 0xffff },/* color (double rgba, short rgba) */
};
 
/**
* _cairo_pattern_set_error:
* @pattern: a pattern
* @status: a status value indicating an error
*
* Atomically sets pattern->status to @status and calls _cairo_error;
* Does nothing if status is %CAIRO_STATUS_SUCCESS.
*
* All assignments of an error status to pattern->status should happen
* through _cairo_pattern_set_error(). Note that due to the nature of
* 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
* breakpoint in _cairo_error() to generate a stack trace for when the
* user causes cairo to detect an error.
**/
static cairo_status_t
_cairo_pattern_set_error (cairo_pattern_t *pattern,
cairo_status_t status)
{
if (status == CAIRO_STATUS_SUCCESS)
return status;
 
/* Don't overwrite an existing error. This preserves the first
* error, which is the most significant. */
_cairo_status_set_error (&pattern->status, status);
 
return _cairo_error (status);
}
 
static void
_cairo_pattern_init (cairo_pattern_t *pattern, cairo_pattern_type_t type)
{
#if HAVE_VALGRIND
switch (type) {
case CAIRO_PATTERN_TYPE_SOLID:
VALGRIND_MAKE_MEM_UNDEFINED (pattern, sizeof (cairo_solid_pattern_t));
break;
case CAIRO_PATTERN_TYPE_SURFACE:
VALGRIND_MAKE_MEM_UNDEFINED (pattern, sizeof (cairo_surface_pattern_t));
break;
case CAIRO_PATTERN_TYPE_LINEAR:
VALGRIND_MAKE_MEM_UNDEFINED (pattern, sizeof (cairo_linear_pattern_t));
break;
case CAIRO_PATTERN_TYPE_RADIAL:
VALGRIND_MAKE_MEM_UNDEFINED (pattern, sizeof (cairo_radial_pattern_t));
break;
}
#endif
 
pattern->type = type;
pattern->status = CAIRO_STATUS_SUCCESS;
 
/* Set the reference count to zero for on-stack patterns.
* Callers needs to explicitly increment the count for heap allocations. */
CAIRO_REFERENCE_COUNT_INIT (&pattern->ref_count, 0);
 
_cairo_user_data_array_init (&pattern->user_data);
 
if (type == CAIRO_PATTERN_TYPE_SURFACE)
pattern->extend = CAIRO_EXTEND_SURFACE_DEFAULT;
else
pattern->extend = CAIRO_EXTEND_GRADIENT_DEFAULT;
 
pattern->filter = CAIRO_FILTER_DEFAULT;
 
pattern->has_component_alpha = FALSE;
 
cairo_matrix_init_identity (&pattern->matrix);
}
 
static cairo_status_t
_cairo_gradient_pattern_init_copy (cairo_gradient_pattern_t *pattern,
const cairo_gradient_pattern_t *other)
{
if (CAIRO_INJECT_FAULT ())
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
if (other->base.type == CAIRO_PATTERN_TYPE_LINEAR)
{
cairo_linear_pattern_t *dst = (cairo_linear_pattern_t *) pattern;
cairo_linear_pattern_t *src = (cairo_linear_pattern_t *) other;
 
*dst = *src;
}
else
{
cairo_radial_pattern_t *dst = (cairo_radial_pattern_t *) pattern;
cairo_radial_pattern_t *src = (cairo_radial_pattern_t *) other;
 
*dst = *src;
}
 
if (other->stops == other->stops_embedded)
pattern->stops = pattern->stops_embedded;
else if (other->stops)
{
pattern->stops = _cairo_malloc_ab (other->stops_size,
sizeof (cairo_gradient_stop_t));
if (unlikely (pattern->stops == NULL)) {
pattern->stops_size = 0;
pattern->n_stops = 0;
return _cairo_pattern_set_error (&pattern->base, CAIRO_STATUS_NO_MEMORY);
}
 
memcpy (pattern->stops, other->stops,
other->n_stops * sizeof (cairo_gradient_stop_t));
}
 
return CAIRO_STATUS_SUCCESS;
}
 
cairo_status_t
_cairo_pattern_init_copy (cairo_pattern_t *pattern,
const cairo_pattern_t *other)
{
if (other->status)
return _cairo_pattern_set_error (pattern, other->status);
 
switch (other->type) {
case CAIRO_PATTERN_TYPE_SOLID: {
cairo_solid_pattern_t *dst = (cairo_solid_pattern_t *) pattern;
cairo_solid_pattern_t *src = (cairo_solid_pattern_t *) other;
 
VG (VALGRIND_MAKE_MEM_UNDEFINED (pattern, sizeof (cairo_solid_pattern_t)));
 
*dst = *src;
} break;
case CAIRO_PATTERN_TYPE_SURFACE: {
cairo_surface_pattern_t *dst = (cairo_surface_pattern_t *) pattern;
cairo_surface_pattern_t *src = (cairo_surface_pattern_t *) other;
 
VG (VALGRIND_MAKE_MEM_UNDEFINED (pattern, sizeof (cairo_surface_pattern_t)));
 
*dst = *src;
cairo_surface_reference (dst->surface);
} break;
case CAIRO_PATTERN_TYPE_LINEAR:
case CAIRO_PATTERN_TYPE_RADIAL: {
cairo_gradient_pattern_t *dst = (cairo_gradient_pattern_t *) pattern;
cairo_gradient_pattern_t *src = (cairo_gradient_pattern_t *) other;
cairo_status_t status;
 
if (other->type == CAIRO_PATTERN_TYPE_LINEAR) {
VG (VALGRIND_MAKE_MEM_UNDEFINED (pattern, sizeof (cairo_linear_pattern_t)));
} else {
VG (VALGRIND_MAKE_MEM_UNDEFINED (pattern, sizeof (cairo_radial_pattern_t)));
}
 
status = _cairo_gradient_pattern_init_copy (dst, src);
if (unlikely (status))
return status;
 
} break;
}
 
/* The reference count and user_data array are unique to the copy. */
CAIRO_REFERENCE_COUNT_INIT (&pattern->ref_count, 0);
_cairo_user_data_array_init (&pattern->user_data);
 
return CAIRO_STATUS_SUCCESS;
}
 
void
_cairo_pattern_init_static_copy (cairo_pattern_t *pattern,
const cairo_pattern_t *other)
{
int size;
 
assert (other->status == CAIRO_STATUS_SUCCESS);
 
switch (other->type) {
default:
ASSERT_NOT_REACHED;
case CAIRO_PATTERN_TYPE_SOLID:
size = sizeof (cairo_solid_pattern_t);
break;
case CAIRO_PATTERN_TYPE_SURFACE:
size = sizeof (cairo_surface_pattern_t);
break;
case CAIRO_PATTERN_TYPE_LINEAR:
size = sizeof (cairo_linear_pattern_t);
break;
case CAIRO_PATTERN_TYPE_RADIAL:
size = sizeof (cairo_radial_pattern_t);
break;
}
 
memcpy (pattern, other, size);
 
CAIRO_REFERENCE_COUNT_INIT (&pattern->ref_count, 0);
_cairo_user_data_array_init (&pattern->user_data);
}
 
cairo_status_t
_cairo_pattern_init_snapshot (cairo_pattern_t *pattern,
const cairo_pattern_t *other)
{
cairo_status_t status;
 
/* We don't bother doing any fancy copy-on-write implementation
* for the pattern's data. It's generally quite tiny. */
status = _cairo_pattern_init_copy (pattern, other);
if (unlikely (status))
return status;
 
/* But we do let the surface snapshot stuff be as fancy as it
* would like to be. */
if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
cairo_surface_pattern_t *surface_pattern =
(cairo_surface_pattern_t *) pattern;
cairo_surface_t *surface = surface_pattern->surface;
 
surface_pattern->surface = _cairo_surface_snapshot (surface);
 
cairo_surface_destroy (surface);
 
if (surface_pattern->surface->status)
return surface_pattern->surface->status;
}
 
return CAIRO_STATUS_SUCCESS;
}
 
void
_cairo_pattern_fini (cairo_pattern_t *pattern)
{
_cairo_user_data_array_fini (&pattern->user_data);
 
switch (pattern->type) {
case CAIRO_PATTERN_TYPE_SOLID:
break;
case CAIRO_PATTERN_TYPE_SURFACE: {
cairo_surface_pattern_t *surface_pattern =
(cairo_surface_pattern_t *) pattern;
 
cairo_surface_destroy (surface_pattern->surface);
} break;
case CAIRO_PATTERN_TYPE_LINEAR:
case CAIRO_PATTERN_TYPE_RADIAL: {
cairo_gradient_pattern_t *gradient =
(cairo_gradient_pattern_t *) pattern;
 
if (gradient->stops && gradient->stops != gradient->stops_embedded)
free (gradient->stops);
} break;
}
 
#if HAVE_VALGRIND
switch (pattern->type) {
case CAIRO_PATTERN_TYPE_SOLID:
VALGRIND_MAKE_MEM_NOACCESS (pattern, sizeof (cairo_solid_pattern_t));
break;
case CAIRO_PATTERN_TYPE_SURFACE:
VALGRIND_MAKE_MEM_NOACCESS (pattern, sizeof (cairo_surface_pattern_t));
break;
case CAIRO_PATTERN_TYPE_LINEAR:
VALGRIND_MAKE_MEM_NOACCESS (pattern, sizeof (cairo_linear_pattern_t));
break;
case CAIRO_PATTERN_TYPE_RADIAL:
VALGRIND_MAKE_MEM_NOACCESS (pattern, sizeof (cairo_radial_pattern_t));
break;
}
#endif
}
 
cairo_status_t
_cairo_pattern_create_copy (cairo_pattern_t **pattern_out,
const cairo_pattern_t *other)
{
cairo_pattern_t *pattern;
cairo_status_t status;
 
if (other->status)
return other->status;
 
switch (other->type) {
case CAIRO_PATTERN_TYPE_SOLID:
pattern = malloc (sizeof (cairo_solid_pattern_t));
break;
case CAIRO_PATTERN_TYPE_SURFACE:
pattern = malloc (sizeof (cairo_surface_pattern_t));
break;
case CAIRO_PATTERN_TYPE_LINEAR:
pattern = malloc (sizeof (cairo_linear_pattern_t));
break;
case CAIRO_PATTERN_TYPE_RADIAL:
pattern = malloc (sizeof (cairo_radial_pattern_t));
break;
default:
ASSERT_NOT_REACHED;
return _cairo_error (CAIRO_STATUS_PATTERN_TYPE_MISMATCH);
}
if (unlikely (pattern == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
status = _cairo_pattern_init_copy (pattern, other);
if (unlikely (status)) {
free (pattern);
return status;
}
 
CAIRO_REFERENCE_COUNT_INIT (&pattern->ref_count, 1);
*pattern_out = pattern;
return CAIRO_STATUS_SUCCESS;
}
 
 
void
_cairo_pattern_init_solid (cairo_solid_pattern_t *pattern,
const cairo_color_t *color)
{
_cairo_pattern_init (&pattern->base, CAIRO_PATTERN_TYPE_SOLID);
pattern->color = *color;
}
 
void
_cairo_pattern_init_for_surface (cairo_surface_pattern_t *pattern,
cairo_surface_t *surface)
{
if (surface->status) {
/* Force to solid to simplify the pattern_fini process. */
_cairo_pattern_init (&pattern->base, CAIRO_PATTERN_TYPE_SOLID);
_cairo_pattern_set_error (&pattern->base, surface->status);
return;
}
 
_cairo_pattern_init (&pattern->base, CAIRO_PATTERN_TYPE_SURFACE);
 
pattern->surface = cairo_surface_reference (surface);
}
 
static void
_cairo_pattern_init_gradient (cairo_gradient_pattern_t *pattern,
cairo_pattern_type_t type)
{
_cairo_pattern_init (&pattern->base, type);
 
pattern->n_stops = 0;
pattern->stops_size = 0;
pattern->stops = NULL;
}
 
void
_cairo_pattern_init_linear (cairo_linear_pattern_t *pattern,
double x0, double y0, double x1, double y1)
{
_cairo_pattern_init_gradient (&pattern->base, CAIRO_PATTERN_TYPE_LINEAR);
 
pattern->p1.x = _cairo_fixed_from_double (x0);
pattern->p1.y = _cairo_fixed_from_double (y0);
pattern->p2.x = _cairo_fixed_from_double (x1);
pattern->p2.y = _cairo_fixed_from_double (y1);
}
 
void
_cairo_pattern_init_radial (cairo_radial_pattern_t *pattern,
double cx0, double cy0, double radius0,
double cx1, double cy1, double radius1)
{
_cairo_pattern_init_gradient (&pattern->base, CAIRO_PATTERN_TYPE_RADIAL);
 
pattern->c1.x = _cairo_fixed_from_double (cx0);
pattern->c1.y = _cairo_fixed_from_double (cy0);
pattern->r1 = _cairo_fixed_from_double (fabs (radius0));
pattern->c2.x = _cairo_fixed_from_double (cx1);
pattern->c2.y = _cairo_fixed_from_double (cy1);
pattern->r2 = _cairo_fixed_from_double (fabs (radius1));
}
 
cairo_pattern_t *
_cairo_pattern_create_solid (const cairo_color_t *color)
{
cairo_solid_pattern_t *pattern;
 
pattern =
_freed_pool_get (&freed_pattern_pool[CAIRO_PATTERN_TYPE_SOLID]);
if (unlikely (pattern == NULL)) {
/* None cached, need to create a new pattern. */
pattern = malloc (sizeof (cairo_solid_pattern_t));
if (unlikely (pattern == NULL)) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_pattern_t *) &_cairo_pattern_nil;
}
}
 
_cairo_pattern_init_solid (pattern, color);
CAIRO_REFERENCE_COUNT_INIT (&pattern->base.ref_count, 1);
 
return &pattern->base;
}
 
cairo_pattern_t *
_cairo_pattern_create_in_error (cairo_status_t status)
{
cairo_pattern_t *pattern;
 
if (status == CAIRO_STATUS_NO_MEMORY)
return (cairo_pattern_t *)&_cairo_pattern_nil.base;
 
CAIRO_MUTEX_INITIALIZE ();
 
pattern = _cairo_pattern_create_solid (CAIRO_COLOR_BLACK);
if (pattern->status == CAIRO_STATUS_SUCCESS)
status = _cairo_pattern_set_error (pattern, status);
 
return pattern;
}
 
/**
* cairo_pattern_create_rgb:
* @red: red component of the color
* @green: green component of the color
* @blue: blue component of the color
*
* Creates a new #cairo_pattern_t corresponding to an opaque color. The
* color components are floating point numbers in the range 0 to 1.
* If the values passed in are outside that range, they will be
* clamped.
*
* Return value: the newly created #cairo_pattern_t if successful, or
* an error pattern in case of no memory. The caller owns the
* returned object and should call cairo_pattern_destroy() when
* finished with it.
*
* This function will always return a valid pointer, but if an error
* occurred the pattern status will be set to an error. To inspect
* the status of a pattern use cairo_pattern_status().
**/
cairo_pattern_t *
cairo_pattern_create_rgb (double red, double green, double blue)
{
cairo_color_t color;
 
red = _cairo_restrict_value (red, 0.0, 1.0);
green = _cairo_restrict_value (green, 0.0, 1.0);
blue = _cairo_restrict_value (blue, 0.0, 1.0);
 
_cairo_color_init_rgb (&color, red, green, blue);
 
CAIRO_MUTEX_INITIALIZE ();
 
return _cairo_pattern_create_solid (&color);
}
slim_hidden_def (cairo_pattern_create_rgb);
 
/**
* cairo_pattern_create_rgba:
* @red: red component of the color
* @green: green component of the color
* @blue: blue component of the color
* @alpha: alpha component of the color
*
* Creates a new #cairo_pattern_t corresponding to a translucent color.
* The color components are floating point numbers in the range 0 to
* 1. If the values passed in are outside that range, they will be
* clamped.
*
* Return value: the newly created #cairo_pattern_t if successful, or
* an error pattern in case of no memory. The caller owns the
* returned object and should call cairo_pattern_destroy() when
* finished with it.
*
* This function will always return a valid pointer, but if an error
* occurred the pattern status will be set to an error. To inspect
* the status of a pattern use cairo_pattern_status().
**/
cairo_pattern_t *
cairo_pattern_create_rgba (double red, double green, double blue,
double alpha)
{
cairo_color_t color;
 
red = _cairo_restrict_value (red, 0.0, 1.0);
green = _cairo_restrict_value (green, 0.0, 1.0);
blue = _cairo_restrict_value (blue, 0.0, 1.0);
alpha = _cairo_restrict_value (alpha, 0.0, 1.0);
 
_cairo_color_init_rgba (&color, red, green, blue, alpha);
 
CAIRO_MUTEX_INITIALIZE ();
 
return _cairo_pattern_create_solid (&color);
}
slim_hidden_def (cairo_pattern_create_rgba);
 
/**
* cairo_pattern_create_for_surface:
* @surface: the surface
*
* Create a new #cairo_pattern_t for the given surface.
*
* Return value: the newly created #cairo_pattern_t if successful, or
* an error pattern in case of no memory. The caller owns the
* returned object and should call cairo_pattern_destroy() when
* finished with it.
*
* This function will always return a valid pointer, but if an error
* occurred the pattern status will be set to an error. To inspect
* the status of a pattern use cairo_pattern_status().
**/
cairo_pattern_t *
cairo_pattern_create_for_surface (cairo_surface_t *surface)
{
cairo_surface_pattern_t *pattern;
 
if (surface == NULL) {
_cairo_error_throw (CAIRO_STATUS_NULL_POINTER);
return (cairo_pattern_t*) &_cairo_pattern_nil_null_pointer;
}
 
if (surface->status)
return _cairo_pattern_create_in_error (surface->status);
 
pattern =
_freed_pool_get (&freed_pattern_pool[CAIRO_PATTERN_TYPE_SURFACE]);
if (unlikely (pattern == NULL)) {
pattern = malloc (sizeof (cairo_surface_pattern_t));
if (unlikely (pattern == NULL)) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_pattern_t *)&_cairo_pattern_nil.base;
}
}
 
CAIRO_MUTEX_INITIALIZE ();
 
_cairo_pattern_init_for_surface (pattern, surface);
CAIRO_REFERENCE_COUNT_INIT (&pattern->base.ref_count, 1);
 
return &pattern->base;
}
slim_hidden_def (cairo_pattern_create_for_surface);
 
/**
* cairo_pattern_create_linear:
* @x0: x coordinate of the start point
* @y0: y coordinate of the start point
* @x1: x coordinate of the end point
* @y1: y coordinate of the end point
*
* Create a new linear gradient #cairo_pattern_t along the line defined
* by (x0, y0) and (x1, y1). Before using the gradient pattern, a
* number of color stops should be defined using
* cairo_pattern_add_color_stop_rgb() or
* cairo_pattern_add_color_stop_rgba().
*
* Note: The coordinates here are in pattern space. For a new pattern,
* pattern space is identical to user space, but the relationship
* between the spaces can be changed with cairo_pattern_set_matrix().
*
* Return value: the newly created #cairo_pattern_t if successful, or
* an error pattern in case of no memory. The caller owns the
* returned object and should call cairo_pattern_destroy() when
* finished with it.
*
* This function will always return a valid pointer, but if an error
* occurred the pattern status will be set to an error. To inspect
* the status of a pattern use cairo_pattern_status().
**/
cairo_pattern_t *
cairo_pattern_create_linear (double x0, double y0, double x1, double y1)
{
cairo_linear_pattern_t *pattern;
 
pattern =
_freed_pool_get (&freed_pattern_pool[CAIRO_PATTERN_TYPE_LINEAR]);
if (unlikely (pattern == NULL)) {
pattern = malloc (sizeof (cairo_linear_pattern_t));
if (unlikely (pattern == NULL)) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_pattern_t *) &_cairo_pattern_nil.base;
}
}
 
CAIRO_MUTEX_INITIALIZE ();
 
_cairo_pattern_init_linear (pattern, x0, y0, x1, y1);
CAIRO_REFERENCE_COUNT_INIT (&pattern->base.base.ref_count, 1);
 
return &pattern->base.base;
}
 
/**
* cairo_pattern_create_radial:
* @cx0: x coordinate for the center of the start circle
* @cy0: y coordinate for the center of the start circle
* @radius0: radius of the start circle
* @cx1: x coordinate for the center of the end circle
* @cy1: y coordinate for the center of the end circle
* @radius1: radius of the end circle
*
* Creates a new radial gradient #cairo_pattern_t between the two
* circles defined by (cx0, cy0, radius0) and (cx1, cy1, radius1). Before using the
* gradient pattern, a number of color stops should be defined using
* cairo_pattern_add_color_stop_rgb() or
* cairo_pattern_add_color_stop_rgba().
*
* Note: The coordinates here are in pattern space. For a new pattern,
* pattern space is identical to user space, but the relationship
* between the spaces can be changed with cairo_pattern_set_matrix().
*
* Return value: the newly created #cairo_pattern_t if successful, or
* an error pattern in case of no memory. The caller owns the
* returned object and should call cairo_pattern_destroy() when
* finished with it.
*
* This function will always return a valid pointer, but if an error
* occurred the pattern status will be set to an error. To inspect
* the status of a pattern use cairo_pattern_status().
**/
cairo_pattern_t *
cairo_pattern_create_radial (double cx0, double cy0, double radius0,
double cx1, double cy1, double radius1)
{
cairo_radial_pattern_t *pattern;
 
pattern =
_freed_pool_get (&freed_pattern_pool[CAIRO_PATTERN_TYPE_RADIAL]);
if (unlikely (pattern == NULL)) {
pattern = malloc (sizeof (cairo_radial_pattern_t));
if (unlikely (pattern == NULL)) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_pattern_t *) &_cairo_pattern_nil.base;
}
}
 
CAIRO_MUTEX_INITIALIZE ();
 
_cairo_pattern_init_radial (pattern, cx0, cy0, radius0, cx1, cy1, radius1);
CAIRO_REFERENCE_COUNT_INIT (&pattern->base.base.ref_count, 1);
 
return &pattern->base.base;
}
 
/**
* cairo_pattern_reference:
* @pattern: a #cairo_pattern_t
*
* Increases the reference count on @pattern by one. This prevents
* @pattern from being destroyed until a matching call to
* cairo_pattern_destroy() is made.
*
* The number of references to a #cairo_pattern_t can be get using
* cairo_pattern_get_reference_count().
*
* Return value: the referenced #cairo_pattern_t.
**/
cairo_pattern_t *
cairo_pattern_reference (cairo_pattern_t *pattern)
{
if (pattern == NULL ||
CAIRO_REFERENCE_COUNT_IS_INVALID (&pattern->ref_count))
return pattern;
 
assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&pattern->ref_count));
 
_cairo_reference_count_inc (&pattern->ref_count);
 
return pattern;
}
slim_hidden_def (cairo_pattern_reference);
 
/**
* cairo_pattern_get_type:
* @pattern: a #cairo_pattern_t
*
* This function returns the type a pattern.
* See #cairo_pattern_type_t for available types.
*
* Return value: The type of @pattern.
*
* Since: 1.2
**/
cairo_pattern_type_t
cairo_pattern_get_type (cairo_pattern_t *pattern)
{
return pattern->type;
}
 
/**
* cairo_pattern_status:
* @pattern: a #cairo_pattern_t
*
* Checks whether an error has previously occurred for this
* pattern.
*
* Return value: %CAIRO_STATUS_SUCCESS, %CAIRO_STATUS_NO_MEMORY, or
* %CAIRO_STATUS_PATTERN_TYPE_MISMATCH.
**/
cairo_status_t
cairo_pattern_status (cairo_pattern_t *pattern)
{
return pattern->status;
}
 
/**
* cairo_pattern_destroy:
* @pattern: a #cairo_pattern_t
*
* Decreases the reference count on @pattern by one. If the result is
* zero, then @pattern and all associated resources are freed. See
* cairo_pattern_reference().
**/
void
cairo_pattern_destroy (cairo_pattern_t *pattern)
{
cairo_pattern_type_t type;
 
if (pattern == NULL ||
CAIRO_REFERENCE_COUNT_IS_INVALID (&pattern->ref_count))
return;
 
assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&pattern->ref_count));
 
if (! _cairo_reference_count_dec_and_test (&pattern->ref_count))
return;
 
type = pattern->type;
_cairo_pattern_fini (pattern);
 
/* maintain a small cache of freed patterns */
_freed_pool_put (&freed_pattern_pool[type], pattern);
}
slim_hidden_def (cairo_pattern_destroy);
 
/**
* cairo_pattern_get_reference_count:
* @pattern: a #cairo_pattern_t
*
* Returns the current reference count of @pattern.
*
* Return value: the current reference count of @pattern. If the
* object is a nil object, 0 will be returned.
*
* Since: 1.4
**/
unsigned int
cairo_pattern_get_reference_count (cairo_pattern_t *pattern)
{
if (pattern == NULL ||
CAIRO_REFERENCE_COUNT_IS_INVALID (&pattern->ref_count))
return 0;
 
return CAIRO_REFERENCE_COUNT_GET_VALUE (&pattern->ref_count);
}
 
/**
* cairo_pattern_get_user_data:
* @pattern: a #cairo_pattern_t
* @key: the address of the #cairo_user_data_key_t the user data was
* attached to
*
* Return user data previously attached to @pattern using the
* specified key. If no user data has been attached with the given
* key this function returns %NULL.
*
* Return value: the user data previously attached or %NULL.
*
* Since: 1.4
**/
void *
cairo_pattern_get_user_data (cairo_pattern_t *pattern,
const cairo_user_data_key_t *key)
{
return _cairo_user_data_array_get_data (&pattern->user_data,
key);
}
 
/**
* cairo_pattern_set_user_data:
* @pattern: a #cairo_pattern_t
* @key: the address of a #cairo_user_data_key_t to attach the user data to
* @user_data: the user data to attach to the #cairo_pattern_t
* @destroy: a #cairo_destroy_func_t which will be called when the
* #cairo_t is destroyed or when new user data is attached using the
* same key.
*
* Attach user data to @pattern. To remove user data from a surface,
* call this function with the key that was used to set it and %NULL
* for @data.
*
* Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY if a
* slot could not be allocated for the user data.
*
* Since: 1.4
**/
cairo_status_t
cairo_pattern_set_user_data (cairo_pattern_t *pattern,
const cairo_user_data_key_t *key,
void *user_data,
cairo_destroy_func_t destroy)
{
if (CAIRO_REFERENCE_COUNT_IS_INVALID (&pattern->ref_count))
return pattern->status;
 
return _cairo_user_data_array_set_data (&pattern->user_data,
key, user_data, destroy);
}
 
/* make room for at least one more color stop */
static cairo_status_t
_cairo_pattern_gradient_grow (cairo_gradient_pattern_t *pattern)
{
cairo_gradient_stop_t *new_stops;
int old_size = pattern->stops_size;
int embedded_size = ARRAY_LENGTH (pattern->stops_embedded);
int new_size = 2 * MAX (old_size, 4);
 
/* we have a local buffer at pattern->stops_embedded. try to fulfill the request
* from there. */
if (old_size < embedded_size) {
pattern->stops = pattern->stops_embedded;
pattern->stops_size = embedded_size;
return CAIRO_STATUS_SUCCESS;
}
 
if (CAIRO_INJECT_FAULT ())
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
assert (pattern->n_stops <= pattern->stops_size);
 
if (pattern->stops == pattern->stops_embedded) {
new_stops = _cairo_malloc_ab (new_size, sizeof (cairo_gradient_stop_t));
if (new_stops)
memcpy (new_stops, pattern->stops, old_size * sizeof (cairo_gradient_stop_t));
} else {
new_stops = _cairo_realloc_ab (pattern->stops,
new_size,
sizeof (cairo_gradient_stop_t));
}
 
if (unlikely (new_stops == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
pattern->stops = new_stops;
pattern->stops_size = new_size;
 
return CAIRO_STATUS_SUCCESS;
}
 
static void
_cairo_pattern_add_color_stop (cairo_gradient_pattern_t *pattern,
double offset,
double red,
double green,
double blue,
double alpha)
{
cairo_gradient_stop_t *stops;
unsigned int i;
 
if (pattern->n_stops >= pattern->stops_size) {
cairo_status_t status = _cairo_pattern_gradient_grow (pattern);
if (unlikely (status)) {
status = _cairo_pattern_set_error (&pattern->base, status);
return;
}
}
 
stops = pattern->stops;
 
for (i = 0; i < pattern->n_stops; i++)
{
if (offset < stops[i].offset)
{
memmove (&stops[i + 1], &stops[i],
sizeof (cairo_gradient_stop_t) * (pattern->n_stops - i));
 
break;
}
}
 
stops[i].offset = offset;
 
stops[i].color.red = red;
stops[i].color.green = green;
stops[i].color.blue = blue;
stops[i].color.alpha = alpha;
 
stops[i].color.red_short = _cairo_color_double_to_short (red);
stops[i].color.green_short = _cairo_color_double_to_short (green);
stops[i].color.blue_short = _cairo_color_double_to_short (blue);
stops[i].color.alpha_short = _cairo_color_double_to_short (alpha);
 
pattern->n_stops++;
}
 
/**
* cairo_pattern_add_color_stop_rgb:
* @pattern: a #cairo_pattern_t
* @offset: an offset in the range [0.0 .. 1.0]
* @red: red component of color
* @green: green component of color
* @blue: blue component of color
*
* Adds an opaque color stop to a gradient pattern. The offset
* specifies the location along the gradient's control vector. For
* example, a linear gradient's control vector is from (x0,y0) to
* (x1,y1) while a radial gradient's control vector is from any point
* on the start circle to the corresponding point on the end circle.
*
* The color is specified in the same way as in cairo_set_source_rgb().
*
* If two (or more) stops are specified with identical offset values,
* they will be sorted according to the order in which the stops are
* added, (stops added earlier will compare less than stops added
* later). This can be useful for reliably making sharp color
* transitions instead of the typical blend.
*
*
* Note: If the pattern is not a gradient pattern, (eg. a linear or
* radial pattern), then the pattern will be put into an error status
* with a status of %CAIRO_STATUS_PATTERN_TYPE_MISMATCH.
**/
void
cairo_pattern_add_color_stop_rgb (cairo_pattern_t *pattern,
double offset,
double red,
double green,
double blue)
{
if (pattern->status)
return;
 
if (pattern->type != CAIRO_PATTERN_TYPE_LINEAR &&
pattern->type != CAIRO_PATTERN_TYPE_RADIAL)
{
_cairo_pattern_set_error (pattern, CAIRO_STATUS_PATTERN_TYPE_MISMATCH);
return;
}
 
offset = _cairo_restrict_value (offset, 0.0, 1.0);
red = _cairo_restrict_value (red, 0.0, 1.0);
green = _cairo_restrict_value (green, 0.0, 1.0);
blue = _cairo_restrict_value (blue, 0.0, 1.0);
 
_cairo_pattern_add_color_stop ((cairo_gradient_pattern_t *) pattern,
offset, red, green, blue, 1.0);
}
 
/**
* cairo_pattern_add_color_stop_rgba:
* @pattern: a #cairo_pattern_t
* @offset: an offset in the range [0.0 .. 1.0]
* @red: red component of color
* @green: green component of color
* @blue: blue component of color
* @alpha: alpha component of color
*
* Adds a translucent color stop to a gradient pattern. The offset
* specifies the location along the gradient's control vector. For
* example, a linear gradient's control vector is from (x0,y0) to
* (x1,y1) while a radial gradient's control vector is from any point
* on the start circle to the corresponding point on the end circle.
*
* The color is specified in the same way as in cairo_set_source_rgba().
*
* If two (or more) stops are specified with identical offset values,
* they will be sorted according to the order in which the stops are
* added, (stops added earlier will compare less than stops added
* later). This can be useful for reliably making sharp color
* transitions instead of the typical blend.
*
* Note: If the pattern is not a gradient pattern, (eg. a linear or
* radial pattern), then the pattern will be put into an error status
* with a status of %CAIRO_STATUS_PATTERN_TYPE_MISMATCH.
*/
void
cairo_pattern_add_color_stop_rgba (cairo_pattern_t *pattern,
double offset,
double red,
double green,
double blue,
double alpha)
{
if (pattern->status)
return;
 
if (pattern->type != CAIRO_PATTERN_TYPE_LINEAR &&
pattern->type != CAIRO_PATTERN_TYPE_RADIAL)
{
_cairo_pattern_set_error (pattern, CAIRO_STATUS_PATTERN_TYPE_MISMATCH);
return;
}
 
offset = _cairo_restrict_value (offset, 0.0, 1.0);
red = _cairo_restrict_value (red, 0.0, 1.0);
green = _cairo_restrict_value (green, 0.0, 1.0);
blue = _cairo_restrict_value (blue, 0.0, 1.0);
alpha = _cairo_restrict_value (alpha, 0.0, 1.0);
 
_cairo_pattern_add_color_stop ((cairo_gradient_pattern_t *) pattern,
offset, red, green, blue, alpha);
}
 
/**
* cairo_pattern_set_matrix:
* @pattern: a #cairo_pattern_t
* @matrix: a #cairo_matrix_t
*
* Sets the pattern's transformation matrix to @matrix. This matrix is
* a transformation from user space to pattern space.
*
* When a pattern is first created it always has the identity matrix
* for its transformation matrix, which means that pattern space is
* initially identical to user space.
*
* Important: Please note that the direction of this transformation
* matrix is from user space to pattern space. This means that if you
* imagine the flow from a pattern to user space (and on to device
* space), then coordinates in that flow will be transformed by the
* inverse of the pattern matrix.
*
* For example, if you want to make a pattern appear twice as large as
* it does by default the correct code to use is:
*
* <informalexample><programlisting>
* cairo_matrix_init_scale (&amp;matrix, 0.5, 0.5);
* cairo_pattern_set_matrix (pattern, &amp;matrix);
* </programlisting></informalexample>
*
* Meanwhile, using values of 2.0 rather than 0.5 in the code above
* would cause the pattern to appear at half of its default size.
*
* Also, please note the discussion of the user-space locking
* semantics of cairo_set_source().
**/
void
cairo_pattern_set_matrix (cairo_pattern_t *pattern,
const cairo_matrix_t *matrix)
{
cairo_matrix_t inverse;
cairo_status_t status;
 
if (pattern->status)
return;
 
if (memcmp (&pattern->matrix, matrix, sizeof (cairo_matrix_t)) == 0)
return;
 
pattern->matrix = *matrix;
 
inverse = *matrix;
status = cairo_matrix_invert (&inverse);
if (unlikely (status))
status = _cairo_pattern_set_error (pattern, status);
}
slim_hidden_def (cairo_pattern_set_matrix);
 
/**
* cairo_pattern_get_matrix:
* @pattern: a #cairo_pattern_t
* @matrix: return value for the matrix
*
* Stores the pattern's transformation matrix into @matrix.
**/
void
cairo_pattern_get_matrix (cairo_pattern_t *pattern, cairo_matrix_t *matrix)
{
*matrix = pattern->matrix;
}
 
/**
* cairo_pattern_set_filter:
* @pattern: a #cairo_pattern_t
* @filter: a #cairo_filter_t describing the filter to use for resizing
* the pattern
*
* Sets the filter to be used for resizing when using this pattern.
* See #cairo_filter_t for details on each filter.
*
* * Note that you might want to control filtering even when you do not
* have an explicit #cairo_pattern_t object, (for example when using
* cairo_set_source_surface()). In these cases, it is convenient to
* use cairo_get_source() to get access to the pattern that cairo
* creates implicitly. For example:
*
* <informalexample><programlisting>
* cairo_set_source_surface (cr, image, x, y);
* cairo_pattern_set_filter (cairo_get_source (cr), CAIRO_FILTER_NEAREST);
* </programlisting></informalexample>
**/
void
cairo_pattern_set_filter (cairo_pattern_t *pattern, cairo_filter_t filter)
{
if (pattern->status)
return;
 
pattern->filter = filter;
}
 
/**
* cairo_pattern_get_filter:
* @pattern: a #cairo_pattern_t
*
* Gets the current filter for a pattern. See #cairo_filter_t
* for details on each filter.
*
* Return value: the current filter used for resizing the pattern.
**/
cairo_filter_t
cairo_pattern_get_filter (cairo_pattern_t *pattern)
{
return pattern->filter;
}
 
/**
* cairo_pattern_set_extend:
* @pattern: a #cairo_pattern_t
* @extend: a #cairo_extend_t describing how the area outside of the
* pattern will be drawn
*
* Sets the mode to be used for drawing outside the area of a pattern.
* See #cairo_extend_t for details on the semantics of each extend
* strategy.
*
* The default extend mode is %CAIRO_EXTEND_NONE for surface patterns
* and %CAIRO_EXTEND_PAD for gradient patterns.
**/
void
cairo_pattern_set_extend (cairo_pattern_t *pattern, cairo_extend_t extend)
{
if (pattern->status)
return;
 
pattern->extend = extend;
}
 
/**
* cairo_pattern_get_extend:
* @pattern: a #cairo_pattern_t
*
* Gets the current extend mode for a pattern. See #cairo_extend_t
* for details on the semantics of each extend strategy.
*
* Return value: the current extend strategy used for drawing the
* pattern.
**/
cairo_extend_t
cairo_pattern_get_extend (cairo_pattern_t *pattern)
{
return pattern->extend;
}
slim_hidden_def (cairo_pattern_get_extend);
 
void
_cairo_pattern_transform (cairo_pattern_t *pattern,
const cairo_matrix_t *ctm_inverse)
{
if (pattern->status)
return;
 
cairo_matrix_multiply (&pattern->matrix, ctm_inverse, &pattern->matrix);
}
 
static void
_cairo_linear_pattern_classify (cairo_linear_pattern_t *pattern,
double offset_x,
double offset_y,
int width,
int height,
cairo_bool_t *is_horizontal,
cairo_bool_t *is_vertical)
{
cairo_point_double_t point0, point1;
double a, b, c, d, tx, ty;
double scale, start, dx, dy;
cairo_fixed_t factors[3];
int i;
 
/* To classify a pattern as horizontal or vertical, we first
* compute the (fixed point) factors at the corners of the
* pattern. We actually only need 3/4 corners, so we skip the
* fourth.
*/
point0.x = _cairo_fixed_to_double (pattern->p1.x);
point0.y = _cairo_fixed_to_double (pattern->p1.y);
point1.x = _cairo_fixed_to_double (pattern->p2.x);
point1.y = _cairo_fixed_to_double (pattern->p2.y);
 
_cairo_matrix_get_affine (&pattern->base.base.matrix,
&a, &b, &c, &d, &tx, &ty);
 
dx = point1.x - point0.x;
dy = point1.y - point0.y;
scale = dx * dx + dy * dy;
scale = (scale) ? 1.0 / scale : 1.0;
 
start = dx * point0.x + dy * point0.y;
 
for (i = 0; i < 3; i++) {
double qx_device = (i % 2) * (width - 1) + offset_x;
double qy_device = (i / 2) * (height - 1) + offset_y;
 
/* transform fragment into pattern space */
double qx = a * qx_device + c * qy_device + tx;
double qy = b * qx_device + d * qy_device + ty;
 
factors[i] = _cairo_fixed_from_double (((dx * qx + dy * qy) - start) * scale);
}
 
/* We consider a pattern to be vertical if the fixed point factor
* at the two upper corners is the same. We could accept a small
* change, but determining what change is acceptable would require
* sorting the stops in the pattern and looking at the differences.
*
* Horizontal works the same way with the two left corners.
*/
 
*is_vertical = factors[1] == factors[0];
*is_horizontal = factors[2] == factors[0];
}
 
static cairo_int_status_t
_cairo_pattern_acquire_surface_for_gradient (const cairo_gradient_pattern_t *pattern,
cairo_surface_t *dst,
int x,
int y,
unsigned int width,
unsigned int height,
cairo_surface_t **out,
cairo_surface_attributes_t *attr)
{
cairo_image_surface_t *image;
pixman_image_t *pixman_image;
pixman_transform_t pixman_transform;
cairo_status_t status;
cairo_bool_t repeat = FALSE;
cairo_bool_t opaque = TRUE;
 
pixman_gradient_stop_t pixman_stops_static[2];
pixman_gradient_stop_t *pixman_stops = pixman_stops_static;
unsigned int i;
int clone_offset_x, clone_offset_y;
cairo_matrix_t matrix = pattern->base.matrix;
 
if (CAIRO_INJECT_FAULT ())
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
if (pattern->n_stops > ARRAY_LENGTH(pixman_stops_static)) {
pixman_stops = _cairo_malloc_ab (pattern->n_stops,
sizeof(pixman_gradient_stop_t));
if (unlikely (pixman_stops == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
 
for (i = 0; i < pattern->n_stops; i++) {
pixman_stops[i].x = _cairo_fixed_16_16_from_double (pattern->stops[i].offset);
pixman_stops[i].color.red = pattern->stops[i].color.red_short;
pixman_stops[i].color.green = pattern->stops[i].color.green_short;
pixman_stops[i].color.blue = pattern->stops[i].color.blue_short;
pixman_stops[i].color.alpha = pattern->stops[i].color.alpha_short;
if (! CAIRO_ALPHA_SHORT_IS_OPAQUE (pixman_stops[i].color.alpha))
opaque = FALSE;
}
 
if (pattern->base.type == CAIRO_PATTERN_TYPE_LINEAR)
{
cairo_linear_pattern_t *linear = (cairo_linear_pattern_t *) pattern;
pixman_point_fixed_t p1, p2;
cairo_fixed_t xdim, ydim;
 
xdim = linear->p2.x - linear->p1.x;
ydim = linear->p2.y - linear->p1.y;
 
/*
* Transform the matrix to avoid overflow when converting between
* cairo_fixed_t and pixman_fixed_t (without incurring performance
* loss when the transformation is unnecessary).
*
* XXX: Consider converting out-of-range co-ordinates and transforms.
* Having a function to compute the required transformation to
* "normalize" a given bounding box would be generally useful -
* cf linear patterns, gradient patterns, surface patterns...
*/
#define PIXMAN_MAX_INT ((pixman_fixed_1 >> 1) - pixman_fixed_e) /* need to ensure deltas also fit */
if (_cairo_fixed_integer_ceil (xdim) > PIXMAN_MAX_INT ||
_cairo_fixed_integer_ceil (ydim) > PIXMAN_MAX_INT)
{
double sf;
 
if (xdim > ydim)
sf = PIXMAN_MAX_INT / _cairo_fixed_to_double (xdim);
else
sf = PIXMAN_MAX_INT / _cairo_fixed_to_double (ydim);
 
p1.x = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (linear->p1.x) * sf);
p1.y = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (linear->p1.y) * sf);
p2.x = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (linear->p2.x) * sf);
p2.y = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (linear->p2.y) * sf);
 
cairo_matrix_scale (&matrix, sf, sf);
}
else
{
p1.x = _cairo_fixed_to_16_16 (linear->p1.x);
p1.y = _cairo_fixed_to_16_16 (linear->p1.y);
p2.x = _cairo_fixed_to_16_16 (linear->p2.x);
p2.y = _cairo_fixed_to_16_16 (linear->p2.y);
}
 
pixman_image = pixman_image_create_linear_gradient (&p1, &p2,
pixman_stops,
pattern->n_stops);
}
else
{
cairo_radial_pattern_t *radial = (cairo_radial_pattern_t *) pattern;
pixman_point_fixed_t c1, c2;
pixman_fixed_t r1, r2;
 
c1.x = _cairo_fixed_to_16_16 (radial->c1.x);
c1.y = _cairo_fixed_to_16_16 (radial->c1.y);
r1 = _cairo_fixed_to_16_16 (radial->r1);
 
c2.x = _cairo_fixed_to_16_16 (radial->c2.x);
c2.y = _cairo_fixed_to_16_16 (radial->c2.y);
r2 = _cairo_fixed_to_16_16 (radial->r2);
 
pixman_image = pixman_image_create_radial_gradient (&c1, &c2,
r1, r2,
pixman_stops,
pattern->n_stops);
}
 
if (pixman_stops != pixman_stops_static)
free (pixman_stops);
 
if (unlikely (pixman_image == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
if (_cairo_surface_is_image (dst))
{
image = (cairo_image_surface_t *)
_cairo_image_surface_create_for_pixman_image (pixman_image,
PIXMAN_a8r8g8b8);
if (image->base.status)
{
pixman_image_unref (pixman_image);
return image->base.status;
}
 
attr->x_offset = attr->y_offset = 0;
attr->matrix = matrix;
attr->extend = pattern->base.extend;
attr->filter = CAIRO_FILTER_NEAREST;
attr->has_component_alpha = pattern->base.has_component_alpha;
 
*out = &image->base;
 
return CAIRO_STATUS_SUCCESS;
}
 
if (pattern->base.type == CAIRO_PATTERN_TYPE_LINEAR) {
cairo_bool_t is_horizontal;
cairo_bool_t is_vertical;
 
_cairo_linear_pattern_classify ((cairo_linear_pattern_t *)pattern,
x, y, width, height,
&is_horizontal, &is_vertical);
if (is_horizontal) {
height = 1;
repeat = TRUE;
}
/* width-1 repeating patterns are quite slow with scan-line based
* compositing code, so we use a wider strip and spend some extra
* expense in computing the gradient. It's possible that for narrow
* gradients we'd be better off using a 2 or 4 pixel strip; the
* wider the gradient, the more it's worth spending extra time
* computing a sample.
*/
if (is_vertical && width > 8) {
width = 8;
repeat = TRUE;
}
}
 
if (! pixman_image_set_filter (pixman_image, PIXMAN_FILTER_BILINEAR,
NULL, 0))
{
pixman_image_unref (pixman_image);
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
 
image = (cairo_image_surface_t *)
cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
if (image->base.status) {
pixman_image_unref (pixman_image);
return image->base.status;
}
 
_cairo_matrix_to_pixman_matrix (&matrix, &pixman_transform,
width/2., height/2.);
if (!pixman_image_set_transform (pixman_image, &pixman_transform)) {
cairo_surface_destroy (&image->base);
pixman_image_unref (pixman_image);
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
 
switch (pattern->base.extend) {
case CAIRO_EXTEND_NONE:
pixman_image_set_repeat (pixman_image, PIXMAN_REPEAT_NONE);
break;
case CAIRO_EXTEND_REPEAT:
pixman_image_set_repeat (pixman_image, PIXMAN_REPEAT_NORMAL);
break;
case CAIRO_EXTEND_REFLECT:
pixman_image_set_repeat (pixman_image, PIXMAN_REPEAT_REFLECT);
break;
case CAIRO_EXTEND_PAD:
pixman_image_set_repeat (pixman_image, PIXMAN_REPEAT_PAD);
break;
}
 
pixman_image_composite32 (PIXMAN_OP_SRC,
pixman_image,
NULL,
image->pixman_image,
x, y,
0, 0,
0, 0,
width, height);
 
pixman_image_unref (pixman_image);
 
_cairo_debug_check_image_surface_is_defined (&image->base);
 
status = _cairo_surface_clone_similar (dst, &image->base,
0, 0, width, height,
&clone_offset_x,
&clone_offset_y,
out);
 
cairo_surface_destroy (&image->base);
 
attr->x_offset = -x;
attr->y_offset = -y;
cairo_matrix_init_identity (&attr->matrix);
attr->extend = repeat ? CAIRO_EXTEND_REPEAT : CAIRO_EXTEND_NONE;
attr->filter = CAIRO_FILTER_NEAREST;
attr->has_component_alpha = pattern->base.has_component_alpha;
 
return status;
}
 
/* We maintain a small cache here, because we don't want to constantly
* recreate surfaces for simple solid colors. */
#define MAX_SURFACE_CACHE_SIZE 16
static struct {
struct _cairo_pattern_solid_surface_cache{
cairo_color_t color;
cairo_surface_t *surface;
} cache[MAX_SURFACE_CACHE_SIZE];
int size;
} solid_surface_cache;
 
static cairo_bool_t
_cairo_pattern_solid_surface_matches (
const struct _cairo_pattern_solid_surface_cache *cache,
const cairo_solid_pattern_t *pattern,
cairo_surface_t *dst)
{
if (cairo_surface_get_content (cache->surface) != _cairo_color_get_content (&pattern->color))
return FALSE;
 
if (CAIRO_REFERENCE_COUNT_GET_VALUE (&cache->surface->ref_count) != 1)
return FALSE;
 
if (! _cairo_surface_is_similar (cache->surface, dst))
return FALSE;
 
return TRUE;
}
 
static cairo_bool_t
_cairo_pattern_solid_surface_matches_color (
const struct _cairo_pattern_solid_surface_cache *cache,
const cairo_solid_pattern_t *pattern,
cairo_surface_t *dst)
{
if (! _cairo_color_equal (&cache->color, &pattern->color))
return FALSE;
 
return _cairo_pattern_solid_surface_matches (cache, pattern, dst);
}
 
static cairo_int_status_t
_cairo_pattern_acquire_surface_for_solid (const cairo_solid_pattern_t *pattern,
cairo_surface_t *dst,
int x,
int y,
unsigned int width,
unsigned int height,
cairo_surface_t **out,
cairo_surface_attributes_t *attribs)
{
static int i;
 
cairo_surface_t *surface, *to_destroy = NULL;
cairo_status_t status;
 
CAIRO_MUTEX_LOCK (_cairo_pattern_solid_surface_cache_lock);
 
/* Check cache first */
if (i < solid_surface_cache.size &&
_cairo_pattern_solid_surface_matches_color (&solid_surface_cache.cache[i],
pattern,
dst))
{
goto DONE;
}
 
for (i = 0 ; i < solid_surface_cache.size; i++) {
if (_cairo_pattern_solid_surface_matches_color (&solid_surface_cache.cache[i],
pattern,
dst))
{
goto DONE;
}
}
 
/* Choose a surface to repaint/evict */
surface = NULL;
if (solid_surface_cache.size == MAX_SURFACE_CACHE_SIZE) {
i = rand () % MAX_SURFACE_CACHE_SIZE;
surface = solid_surface_cache.cache[i].surface;
 
if (_cairo_pattern_solid_surface_matches (&solid_surface_cache.cache[i],
pattern,
dst))
{
/* Reuse the surface instead of evicting */
status = _cairo_surface_repaint_solid_pattern_surface (dst, surface, pattern);
if (unlikely (status))
goto EVICT;
 
cairo_surface_reference (surface);
}
else
{
EVICT:
surface = NULL;
}
}
 
if (surface == NULL) {
/* Not cached, need to create new */
surface = _cairo_surface_create_solid_pattern_surface (dst, pattern);
if (surface == NULL) {
status = CAIRO_INT_STATUS_UNSUPPORTED;
goto UNLOCK;
}
if (unlikely (surface->status)) {
status = surface->status;
goto UNLOCK;
}
 
if (unlikely (! _cairo_surface_is_similar (surface, dst)))
{
/* In the rare event of a substitute surface being returned,
* don't cache the fallback.
*/
*out = surface;
goto NOCACHE;
}
}
 
if (i == solid_surface_cache.size)
solid_surface_cache.size++;
 
to_destroy = solid_surface_cache.cache[i].surface;
solid_surface_cache.cache[i].surface = surface;
solid_surface_cache.cache[i].color = pattern->color;
 
DONE:
*out = cairo_surface_reference (solid_surface_cache.cache[i].surface);
 
NOCACHE:
attribs->x_offset = attribs->y_offset = 0;
cairo_matrix_init_identity (&attribs->matrix);
attribs->extend = CAIRO_EXTEND_REPEAT;
attribs->filter = CAIRO_FILTER_NEAREST;
attribs->has_component_alpha = pattern->base.has_component_alpha;
 
status = CAIRO_STATUS_SUCCESS;
 
UNLOCK:
CAIRO_MUTEX_UNLOCK (_cairo_pattern_solid_surface_cache_lock);
 
if (to_destroy)
cairo_surface_destroy (to_destroy);
 
return status;
}
 
static void
_cairo_pattern_reset_solid_surface_cache (void)
{
CAIRO_MUTEX_LOCK (_cairo_pattern_solid_surface_cache_lock);
 
/* remove surfaces starting from the end so that solid_surface_cache.cache
* is always in a consistent state when we release the mutex. */
while (solid_surface_cache.size) {
cairo_surface_t *surface;
 
solid_surface_cache.size--;
surface = solid_surface_cache.cache[solid_surface_cache.size].surface;
solid_surface_cache.cache[solid_surface_cache.size].surface = NULL;
 
/* release the lock to avoid the possibility of a recursive
* deadlock when the surface destroy closure gets called */
CAIRO_MUTEX_UNLOCK (_cairo_pattern_solid_surface_cache_lock);
cairo_surface_destroy (surface);
CAIRO_MUTEX_LOCK (_cairo_pattern_solid_surface_cache_lock);
}
 
CAIRO_MUTEX_UNLOCK (_cairo_pattern_solid_surface_cache_lock);
}
 
static void
_extents_to_linear_parameter (const cairo_linear_pattern_t *linear,
const cairo_rectangle_int_t *extents,
double t[2])
{
double t0, tdx, tdy;
double p1x, p1y, pdx, pdy, invsqnorm;
 
p1x = _cairo_fixed_to_double (linear->p1.x);
p1y = _cairo_fixed_to_double (linear->p1.y);
pdx = _cairo_fixed_to_double (linear->p2.x) - p1x;
pdy = _cairo_fixed_to_double (linear->p2.y) - p1y;
invsqnorm = 1.0 / (pdx * pdx + pdy * pdy);
pdx *= invsqnorm;
pdy *= invsqnorm;
 
t0 = (extents->x - p1x) * pdx + (extents->y - p1y) * pdy;
tdx = extents->width * pdx;
tdy = extents->height * pdy;
 
t[0] = t[1] = t0;
if (tdx < 0)
t[0] += tdx;
else
t[1] += tdx;
 
if (tdy < 0)
t[0] += tdy;
else
t[1] += tdy;
}
 
static cairo_bool_t
_linear_pattern_is_degenerate (const cairo_linear_pattern_t *linear)
{
return linear->p1.x == linear->p2.x && linear->p1.y == linear->p2.y;
}
 
static cairo_bool_t
_radial_pattern_is_degenerate (const cairo_radial_pattern_t *radial)
{
return radial->r1 == radial->r2 &&
(radial->r1 == 0 /* && radial->r2 == 0 */ ||
(radial->c1.x == radial->c2.x && radial->c1.y == radial->c2.y));
}
 
static cairo_bool_t
_gradient_is_clear (const cairo_gradient_pattern_t *gradient,
const cairo_rectangle_int_t *extents)
{
unsigned int i;
 
assert (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR ||
gradient->base.type == CAIRO_PATTERN_TYPE_RADIAL);
 
if (gradient->n_stops == 0 ||
(gradient->base.extend == CAIRO_EXTEND_NONE &&
gradient->stops[0].offset == gradient->stops[gradient->n_stops - 1].offset))
return TRUE;
 
/* Check if the extents intersect the drawn part of the pattern. */
if (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR) {
if (gradient->base.extend == CAIRO_EXTEND_NONE) {
cairo_linear_pattern_t *linear = (cairo_linear_pattern_t *) gradient;
/* EXTEND_NONE degenerate linear gradients are clear */
if (_linear_pattern_is_degenerate (linear))
return TRUE;
 
if (extents != NULL) {
double t[2];
_extents_to_linear_parameter (linear, extents, t);
if ((t[0] <= 0.0 && t[1] <= 0.0) || (t[0] >= 1.0 && t[1] >= 1.0))
return TRUE;
}
}
} else {
cairo_radial_pattern_t *radial = (cairo_radial_pattern_t *) gradient;
/* degenerate radial gradients are clear */
if (_radial_pattern_is_degenerate (radial))
return TRUE;
/* TODO: check actual intersection */
}
 
for (i = 0; i < gradient->n_stops; i++)
if (! CAIRO_COLOR_IS_CLEAR (&gradient->stops[i].color))
return FALSE;
 
return TRUE;
}
 
static void
_gradient_color_average (const cairo_gradient_pattern_t *gradient,
cairo_color_t *color)
{
double delta0, delta1;
double r, g, b, a;
unsigned int i, start = 1, end;
 
assert (gradient->n_stops > 0);
assert (gradient->base.extend != CAIRO_EXTEND_NONE);
 
if (gradient->n_stops == 1) {
_cairo_color_init_rgba (color,
gradient->stops[0].color.red,
gradient->stops[0].color.green,
gradient->stops[0].color.blue,
gradient->stops[0].color.alpha);
return;
}
 
end = gradient->n_stops - 1;
 
switch (gradient->base.extend) {
case CAIRO_EXTEND_REPEAT:
/*
* Sa, Sb and Sy, Sz are the first two and last two stops respectively.
* The weight of the first and last stop can be computed as the area of
* the following triangles (taken with height 1, since the whole [0-1]
* will have total weight 1 this way): b*h/2
*
* + +
* / |\ / | \
* / | \ / | \
* / | \ / | \
* ~~~~~+---+---+---+~~~~~~~+-------+---+---+~~~~~
* -1+Sz 0 Sa Sb Sy Sz 1 1+Sa
*
* For the first stop: (Sb-(-1+Sz)/2 = (1+Sb-Sz)/2
* For the last stop: ((1+Sa)-Sy)/2 = (1+Sa-Sy)/2
* Halving the result is done after summing up all the areas.
*/
delta0 = 1.0 + gradient->stops[1].offset - gradient->stops[end].offset;
delta1 = 1.0 + gradient->stops[0].offset - gradient->stops[end-1].offset;
break;
 
case CAIRO_EXTEND_REFLECT:
/*
* Sa, Sb and Sy, Sz are the first two and last two stops respectively.
* The weight of the first and last stop can be computed as the area of
* the following trapezoids (taken with height 1, since the whole [0-1]
* will have total weight 1 this way): (b+B)*h/2
*
* +-------+ +---+
* | |\ / | |
* | | \ / | |
* | | \ / | |
* +-------+---+~~~~~~~+-------+---+
* 0 Sa Sb Sy Sz 1
*
* For the first stop: (Sa+Sb)/2
* For the last stop: ((1-Sz) + (1-Sy))/2 = (2-Sy-Sz)/2
* Halving the result is done after summing up all the areas.
*/
delta0 = gradient->stops[0].offset + gradient->stops[1].offset;
delta1 = 2.0 - gradient->stops[end-1].offset - gradient->stops[end].offset;
break;
 
case CAIRO_EXTEND_PAD:
/* PAD is computed as the average of the first and last stop:
* - take both of them with weight 1 (they will be halved
* after the whole sum has been computed).
* - avoid summing any of the inner stops.
*/
delta0 = delta1 = 1.0;
start = end;
break;
 
case CAIRO_EXTEND_NONE:
default:
ASSERT_NOT_REACHED;
_cairo_color_init_rgba (color, 0, 0, 0, 0);
return;
}
 
r = delta0 * gradient->stops[0].color.red;
g = delta0 * gradient->stops[0].color.green;
b = delta0 * gradient->stops[0].color.blue;
a = delta0 * gradient->stops[0].color.alpha;
 
for (i = start; i < end; ++i) {
/* Inner stops weight is the same as the area of the triangle they influence
* (which goes from the stop before to the stop after), again with height 1
* since the whole must sum up to 1: b*h/2
* Halving is done after the whole sum has been computed.
*/
double delta = gradient->stops[i+1].offset - gradient->stops[i-1].offset;
r += delta * gradient->stops[i].color.red;
g += delta * gradient->stops[i].color.green;
b += delta * gradient->stops[i].color.blue;
a += delta * gradient->stops[i].color.alpha;
}
 
r += delta1 * gradient->stops[end].color.red;
g += delta1 * gradient->stops[end].color.green;
b += delta1 * gradient->stops[end].color.blue;
a += delta1 * gradient->stops[end].color.alpha;
 
_cairo_color_init_rgba (color, r * .5, g * .5, b * .5, a * .5);
}
 
/**
* _cairo_gradient_pattern_is_solid
*
* Convenience function to determine whether a gradient pattern is
* a solid color within the given extents. In this case the color
* argument is initialized to the color the pattern represents.
* This functions doesn't handle completely transparent gradients,
* thus it should be called only after _cairo_pattern_is_clear has
* returned FALSE.
*
* Return value: %TRUE if the pattern is a solid color.
**/
cairo_bool_t
_cairo_gradient_pattern_is_solid (const cairo_gradient_pattern_t *gradient,
const cairo_rectangle_int_t *extents,
cairo_color_t *color)
{
unsigned int i;
 
assert (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR ||
gradient->base.type == CAIRO_PATTERN_TYPE_RADIAL);
 
/* TODO: radial */
if (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR) {
cairo_linear_pattern_t *linear = (cairo_linear_pattern_t *) gradient;
if (_linear_pattern_is_degenerate (linear)) {
_gradient_color_average (gradient, color);
return TRUE;
}
 
if (gradient->base.extend == CAIRO_EXTEND_NONE) {
double t[2];
 
/* We already know that the pattern is not clear, thus if some
* part of it is clear, the whole is not solid.
*/
 
if (extents == NULL)
return FALSE;
 
_extents_to_linear_parameter (linear, extents, t);
if (t[0] < 0.0 || t[1] > 1.0)
return FALSE;
}
} else
return FALSE;
 
for (i = 1; i < gradient->n_stops; i++)
if (! _cairo_color_stop_equal (&gradient->stops[0].color,
&gradient->stops[i].color))
return FALSE;
 
_cairo_color_init_rgba (color,
gradient->stops[0].color.red,
gradient->stops[0].color.green,
gradient->stops[0].color.blue,
gradient->stops[0].color.alpha);
 
return TRUE;
}
 
/**
* _cairo_pattern_is_opaque_solid
*
* Convenience function to determine whether a pattern is an opaque
* (alpha==1.0) solid color pattern. This is done by testing whether
* the pattern's alpha value when converted to a byte is 255, so if a
* backend actually supported deep alpha channels this function might
* not do the right thing.
*
* Return value: %TRUE if the pattern is an opaque, solid color.
**/
cairo_bool_t
_cairo_pattern_is_opaque_solid (const cairo_pattern_t *pattern)
{
cairo_solid_pattern_t *solid;
 
if (pattern->type != CAIRO_PATTERN_TYPE_SOLID)
return FALSE;
 
solid = (cairo_solid_pattern_t *) pattern;
 
return CAIRO_COLOR_IS_OPAQUE (&solid->color);
}
 
static cairo_bool_t
_surface_is_opaque (const cairo_surface_pattern_t *pattern,
const cairo_rectangle_int_t *r)
{
if (pattern->surface->content & CAIRO_CONTENT_ALPHA)
return FALSE;
 
if (pattern->base.extend != CAIRO_EXTEND_NONE)
return TRUE;
 
if (r != NULL) {
cairo_rectangle_int_t extents;
 
if (! _cairo_surface_get_extents (pattern->surface, &extents))
return TRUE;
 
if (r->x >= extents.x &&
r->y >= extents.y &&
r->x + r->width <= extents.x + extents.width &&
r->y + r->height <= extents.y + extents.height)
{
return TRUE;
}
}
 
return FALSE;
}
 
static cairo_bool_t
_surface_is_clear (const cairo_surface_pattern_t *pattern)
{
cairo_rectangle_int_t extents;
 
if (_cairo_surface_get_extents (pattern->surface, &extents) &&
(extents.width == 0 || extents.height == 0))
return TRUE;
 
return pattern->surface->is_clear &&
pattern->surface->content & CAIRO_CONTENT_ALPHA;
}
 
static cairo_bool_t
_gradient_is_opaque (const cairo_gradient_pattern_t *gradient,
const cairo_rectangle_int_t *extents)
{
unsigned int i;
 
assert (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR ||
gradient->base.type == CAIRO_PATTERN_TYPE_RADIAL);
 
if (gradient->n_stops == 0 ||
(gradient->base.extend == CAIRO_EXTEND_NONE &&
gradient->stops[0].offset == gradient->stops[gradient->n_stops - 1].offset))
return FALSE;
 
if (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR) {
if (gradient->base.extend == CAIRO_EXTEND_NONE) {
double t[2];
cairo_linear_pattern_t *linear = (cairo_linear_pattern_t *) gradient;
 
/* EXTEND_NONE degenerate radial gradients are clear */
if (_linear_pattern_is_degenerate (linear))
return FALSE;
 
if (extents == NULL)
return FALSE;
 
_extents_to_linear_parameter (linear, extents, t);
if (t[0] < 0.0 || t[1] > 1.0)
return FALSE;
}
} else
return FALSE; /* TODO: check actual intersection */
 
for (i = 0; i < gradient->n_stops; i++)
if (! CAIRO_COLOR_IS_OPAQUE (&gradient->stops[i].color))
return FALSE;
 
return TRUE;
}
 
/**
* _cairo_pattern_is_opaque
*
* Convenience function to determine whether a pattern is an opaque
* pattern (of any type). The same caveats that apply to
* _cairo_pattern_is_opaque_solid apply here as well.
*
* Return value: %TRUE if the pattern is a opaque.
**/
cairo_bool_t
_cairo_pattern_is_opaque (const cairo_pattern_t *abstract_pattern,
const cairo_rectangle_int_t *extents)
{
const cairo_pattern_union_t *pattern;
 
if (abstract_pattern->has_component_alpha)
return FALSE;
 
pattern = (cairo_pattern_union_t *) abstract_pattern;
switch (pattern->base.type) {
case CAIRO_PATTERN_TYPE_SOLID:
return _cairo_pattern_is_opaque_solid (abstract_pattern);
case CAIRO_PATTERN_TYPE_SURFACE:
return _surface_is_opaque (&pattern->surface, extents);
case CAIRO_PATTERN_TYPE_LINEAR:
case CAIRO_PATTERN_TYPE_RADIAL:
return _gradient_is_opaque (&pattern->gradient.base, extents);
}
 
ASSERT_NOT_REACHED;
return FALSE;
}
 
cairo_bool_t
_cairo_pattern_is_clear (const cairo_pattern_t *abstract_pattern)
{
const cairo_pattern_union_t *pattern;
 
if (abstract_pattern->has_component_alpha)
return FALSE;
 
pattern = (cairo_pattern_union_t *) abstract_pattern;
switch (pattern->type) {
case CAIRO_PATTERN_TYPE_SOLID:
return CAIRO_COLOR_IS_CLEAR (&pattern->solid.color);
case CAIRO_PATTERN_TYPE_SURFACE:
return _surface_is_clear (&pattern->surface);
case CAIRO_PATTERN_TYPE_LINEAR:
case CAIRO_PATTERN_TYPE_RADIAL:
return _gradient_is_clear (&pattern->gradient.base, NULL);
}
 
ASSERT_NOT_REACHED;
return FALSE;
}
 
/**
* _cairo_pattern_analyze_filter:
* @pattern: surface pattern
* @pad_out: location to store necessary padding in the source image, or %NULL
* Returns: the optimized #cairo_filter_t to use with @pattern.
*
* Analyze the filter to determine how much extra needs to be sampled
* from the source image to account for the filter radius and whether
* we can optimize the filter to a simpler value.
*
* XXX: We don't actually have any way of querying the backend for
* the filter radius, so we just guess base on what we know that
* backends do currently (see bug #10508)
*/
cairo_filter_t
_cairo_pattern_analyze_filter (const cairo_pattern_t *pattern,
double *pad_out)
{
double pad;
cairo_filter_t optimized_filter;
 
switch (pattern->filter) {
case CAIRO_FILTER_GOOD:
case CAIRO_FILTER_BEST:
case CAIRO_FILTER_BILINEAR:
/* If source pixels map 1:1 onto destination pixels, we do
* not need to filter (and do not want to filter, since it
* will cause blurriness)
*/
if (_cairo_matrix_is_pixel_exact (&pattern->matrix)) {
pad = 0.;
optimized_filter = CAIRO_FILTER_NEAREST;
} else {
/* 0.5 is enough for a bilinear filter. It's possible we
* should defensively use more for CAIRO_FILTER_BEST, but
* without a single example, it's hard to know how much
* more would be defensive...
*/
pad = 0.5;
optimized_filter = pattern->filter;
}
break;
 
case CAIRO_FILTER_FAST:
case CAIRO_FILTER_NEAREST:
case CAIRO_FILTER_GAUSSIAN:
default:
pad = 0.;
optimized_filter = pattern->filter;
break;
}
 
if (pad_out)
*pad_out = pad;
 
return optimized_filter;
}
 
 
static double
_pixman_nearest_sample (double d)
{
return ceil (d - .5);
}
 
static cairo_int_status_t
_cairo_pattern_acquire_surface_for_surface (const cairo_surface_pattern_t *pattern,
cairo_surface_t *dst,
int x,
int y,
unsigned int width,
unsigned int height,
unsigned int flags,
cairo_surface_t **out,
cairo_surface_attributes_t *attr)
{
cairo_surface_t *surface;
cairo_rectangle_int_t extents;
cairo_rectangle_int_t sampled_area;
double x1, y1, x2, y2;
int tx, ty;
double pad;
cairo_bool_t is_identity;
cairo_bool_t is_empty;
cairo_bool_t is_bounded;
cairo_int_status_t status;
 
surface = cairo_surface_reference (pattern->surface);
 
is_identity = FALSE;
attr->matrix = pattern->base.matrix;
attr->extend = pattern->base.extend;
attr->filter = _cairo_pattern_analyze_filter (&pattern->base, &pad);
attr->has_component_alpha = pattern->base.has_component_alpha;
 
attr->x_offset = attr->y_offset = tx = ty = 0;
if (_cairo_matrix_is_integer_translation (&attr->matrix, &tx, &ty)) {
cairo_matrix_init_identity (&attr->matrix);
attr->x_offset = tx;
attr->y_offset = ty;
is_identity = TRUE;
} else if (attr->filter == CAIRO_FILTER_NEAREST) {
/*
* For NEAREST, we can remove the fractional translation component
* from the transformation - this ensures that the pattern will always
* hit fast-paths in the backends for simple transformations that
* become (almost) identity, without loss of quality.
*/
attr->matrix.x0 = 0;
attr->matrix.y0 = 0;
if (_cairo_matrix_is_pixel_exact (&attr->matrix)) {
/* The rounding here is rather peculiar as it needs to match the
* rounding performed on the sample coordinate used by pixman.
*/
attr->matrix.x0 = _pixman_nearest_sample (pattern->base.matrix.x0);
attr->matrix.y0 = _pixman_nearest_sample (pattern->base.matrix.y0);
} else {
attr->matrix.x0 = pattern->base.matrix.x0;
attr->matrix.y0 = pattern->base.matrix.y0;
}
 
if (_cairo_matrix_is_integer_translation (&attr->matrix, &tx, &ty)) {
cairo_matrix_init_identity (&attr->matrix);
attr->x_offset = tx;
attr->y_offset = ty;
is_identity = TRUE;
}
}
 
/* XXX: Hack:
*
* The way we currently support CAIRO_EXTEND_REFLECT is to create
* an image twice bigger on each side, and create a pattern of four
* images such that the new image, when repeated, has the same effect
* of reflecting the original pattern.
*/
if (flags & CAIRO_PATTERN_ACQUIRE_NO_REFLECT &&
attr->extend == CAIRO_EXTEND_REFLECT)
{
cairo_t *cr;
cairo_surface_t *src;
int w, h;
 
is_bounded = _cairo_surface_get_extents (surface, &extents);
assert (is_bounded);
 
status = _cairo_surface_clone_similar (dst, surface,
extents.x, extents.y,
extents.width, extents.height,
&extents.x, &extents.y, &src);
if (unlikely (status))
goto BAIL;
 
w = 2 * extents.width;
h = 2 * extents.height;
 
if (is_identity) {
attr->x_offset = -x;
x += tx;
while (x <= -w)
x += w;
while (x >= w)
x -= w;
extents.x += x;
tx = x = 0;
 
attr->y_offset = -y;
y += ty;
while (y <= -h)
y += h;
while (y >= h)
y -= h;
extents.y += y;
ty = y = 0;
}
 
cairo_surface_destroy (surface);
surface = _cairo_surface_create_similar_solid (dst,
dst->content, w, h,
CAIRO_COLOR_TRANSPARENT,
FALSE);
if (surface == NULL)
return CAIRO_INT_STATUS_UNSUPPORTED;
if (unlikely (surface->status)) {
cairo_surface_destroy (src);
return surface->status;
}
 
surface->device_transform = pattern->surface->device_transform;
surface->device_transform_inverse = pattern->surface->device_transform_inverse;
 
cr = cairo_create (surface);
 
cairo_set_source_surface (cr, src, -extents.x, -extents.y);
cairo_paint (cr);
 
cairo_scale (cr, -1, +1);
cairo_set_source_surface (cr, src, extents.x-w, -extents.y);
cairo_paint (cr);
cairo_set_source_surface (cr, src, extents.x, -extents.y);
cairo_paint (cr);
 
cairo_scale (cr, +1, -1);
cairo_set_source_surface (cr, src, extents.x-w, extents.y-h);
cairo_paint (cr);
cairo_set_source_surface (cr, src, extents.x, extents.y-h);
cairo_paint (cr);
cairo_set_source_surface (cr, src, extents.x-w, extents.y);
cairo_paint (cr);
cairo_set_source_surface (cr, src, extents.x, extents.y);
cairo_paint (cr);
 
cairo_scale (cr, -1, +1);
cairo_set_source_surface (cr, src, -extents.x, extents.y-h);
cairo_paint (cr);
cairo_set_source_surface (cr, src, -extents.x, extents.y);
cairo_paint (cr);
 
status = cairo_status (cr);
cairo_destroy (cr);
 
cairo_surface_destroy (src);
 
if (unlikely (status))
goto BAIL;
 
attr->extend = CAIRO_EXTEND_REPEAT;
}
 
/* We first transform the rectangle to the coordinate space of the
* source surface so that we only need to clone that portion of the
* surface that will be read.
*/
x1 = x;
y1 = y;
x2 = x + (int) width;
y2 = y + (int) height;
if (! is_identity) {
_cairo_matrix_transform_bounding_box (&attr->matrix,
&x1, &y1, &x2, &y2,
NULL);
}
 
sampled_area.x = floor (x1 - pad);
sampled_area.y = floor (y1 - pad);
sampled_area.width = ceil (x2 + pad) - sampled_area.x;
sampled_area.height = ceil (y2 + pad) - sampled_area.y;
 
sampled_area.x += tx;
sampled_area.y += ty;
 
if ( _cairo_surface_get_extents (surface, &extents)) {
if (attr->extend == CAIRO_EXTEND_NONE) {
/* Never acquire a larger area than the source itself */
is_empty = _cairo_rectangle_intersect (&extents, &sampled_area);
} else {
int trim = 0;
 
if (sampled_area.x >= extents.x &&
sampled_area.x + (int) sampled_area.width <= extents.x + (int) extents.width)
{
/* source is horizontally contained within extents, trim */
extents.x = sampled_area.x;
extents.width = sampled_area.width;
trim |= 0x1;
}
 
if (sampled_area.y >= extents.y &&
sampled_area.y + (int) sampled_area.height <= extents.y + (int) extents.height)
{
/* source is vertically contained within extents, trim */
extents.y = sampled_area.y;
extents.height = sampled_area.height;
trim |= 0x2;
}
 
if (trim == 0x3) {
/* source is wholly contained within extents, drop the REPEAT */
attr->extend = CAIRO_EXTEND_NONE;
}
 
is_empty = extents.width == 0 || extents.height == 0;
}
}
 
/* XXX can we use is_empty? */
 
status = _cairo_surface_clone_similar (dst, surface,
extents.x, extents.y,
extents.width, extents.height,
&x, &y, out);
if (unlikely (status))
goto BAIL;
 
if (x != 0 || y != 0) {
if (is_identity) {
attr->x_offset -= x;
attr->y_offset -= y;
} else {
cairo_matrix_t m;
 
x -= attr->x_offset;
y -= attr->y_offset;
attr->x_offset = 0;
attr->y_offset = 0;
 
cairo_matrix_init_translate (&m, -x, -y);
cairo_matrix_multiply (&attr->matrix, &attr->matrix, &m);
}
}
 
/* reduce likelihood of range overflow with large downscaling */
if (! is_identity) {
cairo_matrix_t m;
cairo_status_t invert_status;
 
m = attr->matrix;
invert_status = cairo_matrix_invert (&m);
assert (invert_status == CAIRO_STATUS_SUCCESS);
 
if (m.x0 != 0. || m.y0 != 0.) {
/* pixman also limits the [xy]_offset to 16 bits so evenly
* spread the bits between the two.
*/
x = floor (m.x0 / 2);
y = floor (m.y0 / 2);
attr->x_offset -= x;
attr->y_offset -= y;
cairo_matrix_init_translate (&m, x, y);
cairo_matrix_multiply (&attr->matrix, &m, &attr->matrix);
}
}
 
BAIL:
cairo_surface_destroy (surface);
return status;
}
 
/**
* _cairo_pattern_acquire_surface:
* @pattern: a #cairo_pattern_t
* @dst: destination surface
* @x: X coordinate in source corresponding to left side of destination area
* @y: Y coordinate in source corresponding to top side of destination area
* @width: width of destination area
* @height: height of destination area
* @surface_out: location to store a pointer to a surface
* @attributes: surface attributes that destination backend should apply to
* the returned surface
*
* A convenience function to obtain a surface to use as the source for
* drawing on @dst.
*
* Note that this function is only suitable for use when the destination
* surface is pixel based and 1 device unit maps to one pixel.
*
* Return value: %CAIRO_STATUS_SUCCESS if a surface was stored in @surface_out.
**/
cairo_int_status_t
_cairo_pattern_acquire_surface (const cairo_pattern_t *pattern,
cairo_surface_t *dst,
int x,
int y,
unsigned int width,
unsigned int height,
unsigned int flags,
cairo_surface_t **surface_out,
cairo_surface_attributes_t *attributes)
{
if (unlikely (pattern->status)) {
*surface_out = NULL;
return pattern->status;
}
 
switch (pattern->type) {
case CAIRO_PATTERN_TYPE_SOLID:
return _cairo_pattern_acquire_surface_for_solid ((cairo_solid_pattern_t *) pattern,
dst, x, y, width, height,
surface_out,
attributes);
 
case CAIRO_PATTERN_TYPE_LINEAR:
case CAIRO_PATTERN_TYPE_RADIAL:
return _cairo_pattern_acquire_surface_for_gradient ((cairo_gradient_pattern_t *) pattern,
dst, x, y, width, height,
surface_out,
attributes);
 
case CAIRO_PATTERN_TYPE_SURFACE:
return _cairo_pattern_acquire_surface_for_surface ((cairo_surface_pattern_t *) pattern,
dst, x, y, width, height,
flags,
surface_out,
attributes);
 
default:
ASSERT_NOT_REACHED;
return _cairo_error (CAIRO_STATUS_PATTERN_TYPE_MISMATCH);
}
}
 
/**
* _cairo_pattern_release_surface:
* @pattern: a #cairo_pattern_t
* @surface: a surface obtained by _cairo_pattern_acquire_surface
* @attributes: attributes obtained by _cairo_pattern_acquire_surface
*
* Releases resources obtained by _cairo_pattern_acquire_surface.
**/
void
_cairo_pattern_release_surface (const cairo_pattern_t *pattern,
cairo_surface_t *surface,
cairo_surface_attributes_t *attributes)
{
cairo_surface_destroy (surface);
}
 
cairo_int_status_t
_cairo_pattern_acquire_surfaces (const cairo_pattern_t *src,
const cairo_pattern_t *mask,
cairo_surface_t *dst,
int src_x,
int src_y,
int mask_x,
int mask_y,
unsigned int width,
unsigned int height,
unsigned int flags,
cairo_surface_t **src_out,
cairo_surface_t **mask_out,
cairo_surface_attributes_t *src_attributes,
cairo_surface_attributes_t *mask_attributes)
{
cairo_int_status_t status;
cairo_pattern_union_t src_tmp;
 
if (unlikely (src->status))
return src->status;
if (unlikely (mask != NULL && mask->status))
return mask->status;
 
/* If src and mask are both solid, then the mask alpha can be
* combined into src and mask can be ignored. */
 
if (src->type == CAIRO_PATTERN_TYPE_SOLID &&
mask &&
! mask->has_component_alpha &&
mask->type == CAIRO_PATTERN_TYPE_SOLID)
{
cairo_color_t combined;
cairo_solid_pattern_t *src_solid = (cairo_solid_pattern_t *) src;
cairo_solid_pattern_t *mask_solid = (cairo_solid_pattern_t *) mask;
 
combined = src_solid->color;
_cairo_color_multiply_alpha (&combined, mask_solid->color.alpha);
 
_cairo_pattern_init_solid (&src_tmp.solid, &combined);
 
src = &src_tmp.base;
mask = NULL;
}
 
status = _cairo_pattern_acquire_surface (src, dst,
src_x, src_y,
width, height,
flags,
src_out, src_attributes);
if (unlikely (status))
goto BAIL;
 
if (mask == NULL) {
*mask_out = NULL;
goto BAIL;
}
 
status = _cairo_pattern_acquire_surface (mask, dst,
mask_x, mask_y,
width, height,
flags,
mask_out, mask_attributes);
if (unlikely (status))
_cairo_pattern_release_surface (src, *src_out, src_attributes);
 
BAIL:
if (src == &src_tmp.base)
_cairo_pattern_fini (&src_tmp.base);
 
return status;
}
 
/**
* _cairo_pattern_get_extents:
*
* Return the "target-space" extents of @pattern in @extents.
*
* For unbounded patterns, the @extents will be initialized with
* "infinite" extents, (minimum and maximum fixed-point values).
*
* XXX: Currently, bounded gradient patterns will also return
* "infinite" extents, though it would be possible to optimize these
* with a little more work.
**/
void
_cairo_pattern_get_extents (const cairo_pattern_t *pattern,
cairo_rectangle_int_t *extents)
{
double x1, y1, x2, y2;
cairo_status_t status;
 
switch (pattern->type) {
case CAIRO_PATTERN_TYPE_SOLID:
goto UNBOUNDED;
 
case CAIRO_PATTERN_TYPE_SURFACE:
{
cairo_rectangle_int_t surface_extents;
const cairo_surface_pattern_t *surface_pattern =
(const cairo_surface_pattern_t *) pattern;
cairo_surface_t *surface = surface_pattern->surface;
double pad;
 
if (! _cairo_surface_get_extents (surface, &surface_extents))
goto UNBOUNDED;
 
if (surface_extents.width == 0 || surface_extents.height == 0)
goto EMPTY;
 
if (pattern->extend != CAIRO_EXTEND_NONE)
goto UNBOUNDED;
 
/* The filter can effectively enlarge the extents of the
* pattern, so extend as necessary.
*/
_cairo_pattern_analyze_filter (&surface_pattern->base, &pad);
x1 = surface_extents.x - pad;
y1 = surface_extents.y - pad;
x2 = surface_extents.x + (int) surface_extents.width + pad;
y2 = surface_extents.y + (int) surface_extents.height + pad;
}
break;
 
case CAIRO_PATTERN_TYPE_RADIAL:
{
const cairo_radial_pattern_t *radial =
(const cairo_radial_pattern_t *) pattern;
double cx1, cy1;
double cx2, cy2;
double r, D;
 
if (radial->r1 == 0 && radial->r2 == 0)
goto EMPTY;
 
cx1 = _cairo_fixed_to_double (radial->c1.x);
cy1 = _cairo_fixed_to_double (radial->c1.y);
r = _cairo_fixed_to_double (radial->r1);
x1 = cx1 - r; x2 = cx1 + r;
y1 = cy1 - r; y2 = cy1 + r;
 
cx2 = _cairo_fixed_to_double (radial->c2.x);
cy2 = _cairo_fixed_to_double (radial->c2.y);
r = fabs (_cairo_fixed_to_double (radial->r2));
 
if (pattern->extend != CAIRO_EXTEND_NONE)
goto UNBOUNDED;
 
/* We need to be careful, as if the circles are not
* self-contained, then the solution is actually unbounded.
*/
D = (cx1-cx2)*(cx1-cx2) + (cy1-cy2)*(cy1-cy2);
if (D > r*r - 1e-5)
goto UNBOUNDED;
 
if (cx2 - r < x1)
x1 = cx2 - r;
if (cx2 + r > x2)
x2 = cx2 + r;
 
if (cy2 - r < y1)
y1 = cy2 - r;
if (cy2 + r > y2)
y2 = cy2 + r;
}
break;
 
case CAIRO_PATTERN_TYPE_LINEAR:
{
const cairo_linear_pattern_t *linear =
(const cairo_linear_pattern_t *) pattern;
 
if (pattern->extend != CAIRO_EXTEND_NONE)
goto UNBOUNDED;
 
if (linear->p1.x == linear->p2.x && linear->p1.y == linear->p2.y)
goto EMPTY;
 
if (pattern->matrix.xy != 0. || pattern->matrix.yx != 0.)
goto UNBOUNDED;
 
if (linear->p1.x == linear->p2.x) {
x1 = -HUGE_VAL;
x2 = HUGE_VAL;
y1 = _cairo_fixed_to_double (MIN (linear->p1.y, linear->p2.y));
y2 = _cairo_fixed_to_double (MAX (linear->p1.y, linear->p2.y));
} else if (linear->p1.y == linear->p2.y) {
x1 = _cairo_fixed_to_double (MIN (linear->p1.x, linear->p2.x));
x2 = _cairo_fixed_to_double (MAX (linear->p1.x, linear->p2.x));
y1 = -HUGE_VAL;
y2 = HUGE_VAL;
} else {
goto UNBOUNDED;
}
}
break;
 
default:
ASSERT_NOT_REACHED;
}
 
if (_cairo_matrix_is_translation (&pattern->matrix)) {
x1 -= pattern->matrix.x0; x2 -= pattern->matrix.x0;
y1 -= pattern->matrix.y0; y2 -= pattern->matrix.y0;
} else {
cairo_matrix_t imatrix;
 
imatrix = pattern->matrix;
status = cairo_matrix_invert (&imatrix);
/* cairo_pattern_set_matrix ensures the matrix is invertible */
assert (status == CAIRO_STATUS_SUCCESS);
 
_cairo_matrix_transform_bounding_box (&imatrix,
&x1, &y1, &x2, &y2,
NULL);
}
 
x1 = floor (x1);
if (x1 < CAIRO_RECT_INT_MIN)
x1 = CAIRO_RECT_INT_MIN;
y1 = floor (y1);
if (y1 < CAIRO_RECT_INT_MIN)
y1 = CAIRO_RECT_INT_MIN;
 
x2 = ceil (x2);
if (x2 > CAIRO_RECT_INT_MAX)
x2 = CAIRO_RECT_INT_MAX;
y2 = ceil (y2);
if (y2 > CAIRO_RECT_INT_MAX)
y2 = CAIRO_RECT_INT_MAX;
 
extents->x = x1; extents->width = x2 - x1;
extents->y = y1; extents->height = y2 - y1;
return;
 
UNBOUNDED:
/* unbounded patterns -> 'infinite' extents */
_cairo_unbounded_rectangle_init (extents);
return;
 
EMPTY:
extents->x = extents->y = 0;
extents->width = extents->height = 0;
return;
}
 
 
static unsigned long
_cairo_solid_pattern_hash (unsigned long hash,
const cairo_pattern_t *pattern)
{
const cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *) pattern;
 
hash = _cairo_hash_bytes (hash, &solid->color, sizeof (solid->color));
 
return hash;
}
 
static unsigned long
_cairo_gradient_color_stops_hash (unsigned long hash,
const cairo_gradient_pattern_t *gradient)
{
unsigned int n;
 
hash = _cairo_hash_bytes (hash,
&gradient->n_stops,
sizeof (gradient->n_stops));
 
for (n = 0; n < gradient->n_stops; n++) {
hash = _cairo_hash_bytes (hash,
&gradient->stops[n].offset,
sizeof (double));
hash = _cairo_hash_bytes (hash,
&gradient->stops[n].color,
sizeof (cairo_color_t));
}
 
return hash;
}
 
unsigned long
_cairo_linear_pattern_hash (unsigned long hash,
const cairo_linear_pattern_t *linear)
{
hash = _cairo_hash_bytes (hash, &linear->p1, sizeof (linear->p1));
hash = _cairo_hash_bytes (hash, &linear->p2, sizeof (linear->p2));
 
return _cairo_gradient_color_stops_hash (hash, &linear->base);
}
 
unsigned long
_cairo_radial_pattern_hash (unsigned long hash,
const cairo_radial_pattern_t *radial)
{
hash = _cairo_hash_bytes (hash, &radial->c1, sizeof (radial->c1));
hash = _cairo_hash_bytes (hash, &radial->r1, sizeof (radial->r1));
hash = _cairo_hash_bytes (hash, &radial->c2, sizeof (radial->c2));
hash = _cairo_hash_bytes (hash, &radial->r2, sizeof (radial->r2));
 
return _cairo_gradient_color_stops_hash (hash, &radial->base);
}
 
static unsigned long
_cairo_surface_pattern_hash (unsigned long hash,
const cairo_pattern_t *pattern)
{
const cairo_surface_pattern_t *surface = (cairo_surface_pattern_t *) pattern;
 
hash ^= surface->surface->unique_id;
 
return hash;
}
 
unsigned long
_cairo_pattern_hash (const cairo_pattern_t *pattern)
{
unsigned long hash = _CAIRO_HASH_INIT_VALUE;
 
if (pattern->status)
return 0;
 
hash = _cairo_hash_bytes (hash, &pattern->type, sizeof (pattern->type));
if (pattern->type != CAIRO_PATTERN_TYPE_SOLID) {
hash = _cairo_hash_bytes (hash,
&pattern->matrix, sizeof (pattern->matrix));
hash = _cairo_hash_bytes (hash,
&pattern->filter, sizeof (pattern->filter));
hash = _cairo_hash_bytes (hash,
&pattern->extend, sizeof (pattern->extend));
hash = _cairo_hash_bytes (hash,
&pattern->has_component_alpha,
sizeof (pattern->has_component_alpha));
}
 
switch (pattern->type) {
case CAIRO_PATTERN_TYPE_SOLID:
return _cairo_solid_pattern_hash (hash, pattern);
case CAIRO_PATTERN_TYPE_LINEAR:
return _cairo_linear_pattern_hash (hash, (cairo_linear_pattern_t *) pattern);
case CAIRO_PATTERN_TYPE_RADIAL:
return _cairo_radial_pattern_hash (hash, (cairo_radial_pattern_t *) pattern);
case CAIRO_PATTERN_TYPE_SURFACE:
return _cairo_surface_pattern_hash (hash, pattern);
default:
ASSERT_NOT_REACHED;
return FALSE;
}
}
 
static unsigned long
_cairo_gradient_pattern_color_stops_size (const cairo_pattern_t *pattern)
{
cairo_gradient_pattern_t *gradient = (cairo_gradient_pattern_t *) pattern;
 
return gradient->n_stops * (sizeof (double) + sizeof (cairo_color_t));
}
 
unsigned long
_cairo_pattern_size (const cairo_pattern_t *pattern)
{
if (pattern->status)
return 0;
 
/* XXX */
switch (pattern->type) {
case CAIRO_PATTERN_TYPE_SOLID:
return sizeof (cairo_solid_pattern_t);
break;
case CAIRO_PATTERN_TYPE_SURFACE:
return sizeof (cairo_surface_pattern_t);
break;
case CAIRO_PATTERN_TYPE_LINEAR:
return sizeof (cairo_linear_pattern_t) +
_cairo_gradient_pattern_color_stops_size (pattern);
break;
case CAIRO_PATTERN_TYPE_RADIAL:
return sizeof (cairo_radial_pattern_t) +
_cairo_gradient_pattern_color_stops_size (pattern);
default:
ASSERT_NOT_REACHED;
return 0;
}
}
 
 
static cairo_bool_t
_cairo_solid_pattern_equal (const cairo_pattern_t *A,
const cairo_pattern_t *B)
{
const cairo_solid_pattern_t *a = (cairo_solid_pattern_t *) A;
const cairo_solid_pattern_t *b = (cairo_solid_pattern_t *) B;
 
return _cairo_color_equal (&a->color, &b->color);
}
 
static cairo_bool_t
_cairo_gradient_color_stops_equal (const cairo_gradient_pattern_t *a,
const cairo_gradient_pattern_t *b)
{
unsigned int n;
 
if (a->n_stops != b->n_stops)
return FALSE;
 
for (n = 0; n < a->n_stops; n++) {
if (a->stops[n].offset != b->stops[n].offset)
return FALSE;
if (! _cairo_color_stop_equal (&a->stops[n].color, &b->stops[n].color))
return FALSE;
}
 
return TRUE;
}
 
cairo_bool_t
_cairo_linear_pattern_equal (const cairo_linear_pattern_t *a,
const cairo_linear_pattern_t *b)
{
if (a->p1.x != b->p1.x)
return FALSE;
 
if (a->p1.y != b->p1.y)
return FALSE;
 
if (a->p2.x != b->p2.x)
return FALSE;
 
if (a->p2.y != b->p2.y)
return FALSE;
 
return _cairo_gradient_color_stops_equal (&a->base, &b->base);
}
 
cairo_bool_t
_cairo_radial_pattern_equal (const cairo_radial_pattern_t *a,
const cairo_radial_pattern_t *b)
{
if (a->c1.x != b->c1.x)
return FALSE;
 
if (a->c1.y != b->c1.y)
return FALSE;
 
if (a->r1 != b->r1)
return FALSE;
 
if (a->c2.x != b->c2.x)
return FALSE;
 
if (a->c2.y != b->c2.y)
return FALSE;
 
if (a->r2 != b->r2)
return FALSE;
 
return _cairo_gradient_color_stops_equal (&a->base, &b->base);
}
 
static cairo_bool_t
_cairo_surface_pattern_equal (const cairo_pattern_t *A,
const cairo_pattern_t *B)
{
const cairo_surface_pattern_t *a = (cairo_surface_pattern_t *) A;
const cairo_surface_pattern_t *b = (cairo_surface_pattern_t *) B;
 
return a->surface->unique_id == b->surface->unique_id;
}
 
cairo_bool_t
_cairo_pattern_equal (const cairo_pattern_t *a, const cairo_pattern_t *b)
{
if (a->status || b->status)
return FALSE;
 
if (a == b)
return TRUE;
 
if (a->type != b->type)
return FALSE;
 
if (a->has_component_alpha != b->has_component_alpha)
return FALSE;
 
if (a->type != CAIRO_PATTERN_TYPE_SOLID) {
if (memcmp (&a->matrix, &b->matrix, sizeof (cairo_matrix_t)))
return FALSE;
 
if (a->filter != b->filter)
return FALSE;
 
if (a->extend != b->extend)
return FALSE;
}
 
switch (a->type) {
case CAIRO_PATTERN_TYPE_SOLID:
return _cairo_solid_pattern_equal (a, b);
case CAIRO_PATTERN_TYPE_LINEAR:
return _cairo_linear_pattern_equal ((cairo_linear_pattern_t *) a,
(cairo_linear_pattern_t *) b);
case CAIRO_PATTERN_TYPE_RADIAL:
return _cairo_radial_pattern_equal ((cairo_radial_pattern_t *) a,
(cairo_radial_pattern_t *) b);
case CAIRO_PATTERN_TYPE_SURFACE:
return _cairo_surface_pattern_equal (a, b);
default:
ASSERT_NOT_REACHED;
return FALSE;
}
}
 
/**
* cairo_pattern_get_rgba
* @pattern: a #cairo_pattern_t
* @red: return value for red component of color, or %NULL
* @green: return value for green component of color, or %NULL
* @blue: return value for blue component of color, or %NULL
* @alpha: return value for alpha component of color, or %NULL
*
* Gets the solid color for a solid color pattern.
*
* Return value: %CAIRO_STATUS_SUCCESS, or
* %CAIRO_STATUS_PATTERN_TYPE_MISMATCH if the pattern is not a solid
* color pattern.
*
* Since: 1.4
**/
cairo_status_t
cairo_pattern_get_rgba (cairo_pattern_t *pattern,
double *red, double *green,
double *blue, double *alpha)
{
cairo_solid_pattern_t *solid = (cairo_solid_pattern_t*) pattern;
double r0, g0, b0, a0;
 
if (pattern->status)
return pattern->status;
 
if (pattern->type != CAIRO_PATTERN_TYPE_SOLID)
return _cairo_error (CAIRO_STATUS_PATTERN_TYPE_MISMATCH);
 
_cairo_color_get_rgba (&solid->color, &r0, &g0, &b0, &a0);
 
if (red)
*red = r0;
if (green)
*green = g0;
if (blue)
*blue = b0;
if (alpha)
*alpha = a0;
 
return CAIRO_STATUS_SUCCESS;
}
 
/**
* cairo_pattern_get_surface
* @pattern: a #cairo_pattern_t
* @surface: return value for surface of pattern, or %NULL
*
* Gets the surface of a surface pattern. The reference returned in
* @surface is owned by the pattern; the caller should call
* cairo_surface_reference() if the surface is to be retained.
*
* Return value: %CAIRO_STATUS_SUCCESS, or
* %CAIRO_STATUS_PATTERN_TYPE_MISMATCH if the pattern is not a surface
* pattern.
*
* Since: 1.4
**/
cairo_status_t
cairo_pattern_get_surface (cairo_pattern_t *pattern,
cairo_surface_t **surface)
{
cairo_surface_pattern_t *spat = (cairo_surface_pattern_t*) pattern;
 
if (pattern->status)
return pattern->status;
 
if (pattern->type != CAIRO_PATTERN_TYPE_SURFACE)
return _cairo_error (CAIRO_STATUS_PATTERN_TYPE_MISMATCH);
 
if (surface)
*surface = spat->surface;
 
return CAIRO_STATUS_SUCCESS;
}
 
/**
* cairo_pattern_get_color_stop_rgba
* @pattern: a #cairo_pattern_t
* @index: index of the stop to return data for
* @offset: return value for the offset of the stop, or %NULL
* @red: return value for red component of color, or %NULL
* @green: return value for green component of color, or %NULL
* @blue: return value for blue component of color, or %NULL
* @alpha: return value for alpha component of color, or %NULL
*
* Gets the color and offset information at the given @index for a
* gradient pattern. Values of @index are 0 to 1 less than the number
* returned by cairo_pattern_get_color_stop_count().
*
* Return value: %CAIRO_STATUS_SUCCESS, or %CAIRO_STATUS_INVALID_INDEX
* if @index is not valid for the given pattern. If the pattern is
* not a gradient pattern, %CAIRO_STATUS_PATTERN_TYPE_MISMATCH is
* returned.
*
* Since: 1.4
**/
cairo_status_t
cairo_pattern_get_color_stop_rgba (cairo_pattern_t *pattern,
int index, double *offset,
double *red, double *green,
double *blue, double *alpha)
{
cairo_gradient_pattern_t *gradient = (cairo_gradient_pattern_t*) pattern;
 
if (pattern->status)
return pattern->status;
 
if (pattern->type != CAIRO_PATTERN_TYPE_LINEAR &&
pattern->type != CAIRO_PATTERN_TYPE_RADIAL)
return _cairo_error (CAIRO_STATUS_PATTERN_TYPE_MISMATCH);
 
if (index < 0 || (unsigned int) index >= gradient->n_stops)
return _cairo_error (CAIRO_STATUS_INVALID_INDEX);
 
if (offset)
*offset = gradient->stops[index].offset;
if (red)
*red = gradient->stops[index].color.red;
if (green)
*green = gradient->stops[index].color.green;
if (blue)
*blue = gradient->stops[index].color.blue;
if (alpha)
*alpha = gradient->stops[index].color.alpha;
 
return CAIRO_STATUS_SUCCESS;
}
 
/**
* cairo_pattern_get_color_stop_count
* @pattern: a #cairo_pattern_t
* @count: return value for the number of color stops, or %NULL
*
* Gets the number of color stops specified in the given gradient
* pattern.
*
* Return value: %CAIRO_STATUS_SUCCESS, or
* %CAIRO_STATUS_PATTERN_TYPE_MISMATCH if @pattern is not a gradient
* pattern.
*
* Since: 1.4
*/
cairo_status_t
cairo_pattern_get_color_stop_count (cairo_pattern_t *pattern,
int *count)
{
cairo_gradient_pattern_t *gradient = (cairo_gradient_pattern_t*) pattern;
 
if (pattern->status)
return pattern->status;
 
if (pattern->type != CAIRO_PATTERN_TYPE_LINEAR &&
pattern->type != CAIRO_PATTERN_TYPE_RADIAL)
return _cairo_error (CAIRO_STATUS_PATTERN_TYPE_MISMATCH);
 
if (count)
*count = gradient->n_stops;
 
return CAIRO_STATUS_SUCCESS;
}
 
/**
* cairo_pattern_get_linear_points
* @pattern: a #cairo_pattern_t
* @x0: return value for the x coordinate of the first point, or %NULL
* @y0: return value for the y coordinate of the first point, or %NULL
* @x1: return value for the x coordinate of the second point, or %NULL
* @y1: return value for the y coordinate of the second point, or %NULL
*
* Gets the gradient endpoints for a linear gradient.
*
* Return value: %CAIRO_STATUS_SUCCESS, or
* %CAIRO_STATUS_PATTERN_TYPE_MISMATCH if @pattern is not a linear
* gradient pattern.
*
* Since: 1.4
**/
cairo_status_t
cairo_pattern_get_linear_points (cairo_pattern_t *pattern,
double *x0, double *y0,
double *x1, double *y1)
{
cairo_linear_pattern_t *linear = (cairo_linear_pattern_t*) pattern;
 
if (pattern->status)
return pattern->status;
 
if (pattern->type != CAIRO_PATTERN_TYPE_LINEAR)
return _cairo_error (CAIRO_STATUS_PATTERN_TYPE_MISMATCH);
 
if (x0)
*x0 = _cairo_fixed_to_double (linear->p1.x);
if (y0)
*y0 = _cairo_fixed_to_double (linear->p1.y);
if (x1)
*x1 = _cairo_fixed_to_double (linear->p2.x);
if (y1)
*y1 = _cairo_fixed_to_double (linear->p2.y);
 
return CAIRO_STATUS_SUCCESS;
}
 
/**
* cairo_pattern_get_radial_circles
* @pattern: a #cairo_pattern_t
* @x0: return value for the x coordinate of the center of the first circle, or %NULL
* @y0: return value for the y coordinate of the center of the first circle, or %NULL
* @r0: return value for the radius of the first circle, or %NULL
* @x1: return value for the x coordinate of the center of the second circle, or %NULL
* @y1: return value for the y coordinate of the center of the second circle, or %NULL
* @r1: return value for the radius of the second circle, or %NULL
*
* Gets the gradient endpoint circles for a radial gradient, each
* specified as a center coordinate and a radius.
*
* Return value: %CAIRO_STATUS_SUCCESS, or
* %CAIRO_STATUS_PATTERN_TYPE_MISMATCH if @pattern is not a radial
* gradient pattern.
*
* Since: 1.4
**/
cairo_status_t
cairo_pattern_get_radial_circles (cairo_pattern_t *pattern,
double *x0, double *y0, double *r0,
double *x1, double *y1, double *r1)
{
cairo_radial_pattern_t *radial = (cairo_radial_pattern_t*) pattern;
 
if (pattern->status)
return pattern->status;
 
if (pattern->type != CAIRO_PATTERN_TYPE_RADIAL)
return _cairo_error (CAIRO_STATUS_PATTERN_TYPE_MISMATCH);
 
if (x0)
*x0 = _cairo_fixed_to_double (radial->c1.x);
if (y0)
*y0 = _cairo_fixed_to_double (radial->c1.y);
if (r0)
*r0 = _cairo_fixed_to_double (radial->r1);
if (x1)
*x1 = _cairo_fixed_to_double (radial->c2.x);
if (y1)
*y1 = _cairo_fixed_to_double (radial->c2.y);
if (r1)
*r1 = _cairo_fixed_to_double (radial->r2);
 
return CAIRO_STATUS_SUCCESS;
}
 
void
_cairo_pattern_reset_static_data (void)
{
#if HAS_FREED_POOL
int i;
 
for (i = 0; i < ARRAY_LENGTH (freed_pattern_pool); i++)
_freed_pool_reset (&freed_pattern_pool[i]);
#endif
 
_cairo_pattern_reset_solid_surface_cache ();
}
/programs/develop/libraries/cairo/src/cairo-pdf-operators-private.h
0,0 → 1,171
/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2004 Red Hat, Inc
* Copyright © 2006 Red Hat, Inc
* Copyright © 2007 Adrian Johnson
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Kristian Høgsberg <krh@redhat.com>
* Carl Worth <cworth@cworth.org>
* Adrian Johnson <ajohnson@redneon.com>
*/
 
#ifndef CAIRO_PDF_OPERATORS_H
#define CAIRO_PDF_OPERATORS_H
 
#include "cairo-compiler-private.h"
#include "cairo-types-private.h"
 
/* The glyph buffer size is based on the expected maximum glyphs in a
* line so that an entire line can be emitted in as one string. If the
* glyphs in a line exceeds this size the only downside is the slight
* overhead of emitting two strings.
*/
#define PDF_GLYPH_BUFFER_SIZE 200
 
typedef cairo_status_t (*cairo_pdf_operators_use_font_subset_t) (unsigned int font_id,
unsigned int subset_id,
void *closure);
 
typedef struct _cairo_pdf_glyph {
unsigned int glyph_index;
double x_position;
double x_advance;
} cairo_pdf_glyph_t;
 
typedef struct _cairo_pdf_operators {
cairo_output_stream_t *stream;
cairo_matrix_t cairo_to_pdf;
cairo_scaled_font_subsets_t *font_subsets;
cairo_pdf_operators_use_font_subset_t use_font_subset;
void *use_font_subset_closure;
cairo_bool_t use_actual_text;
cairo_bool_t in_text_object; /* inside BT/ET pair */
 
/* PDF text state */
cairo_bool_t is_new_text_object; /* text object started but matrix and font not yet selected */
unsigned int font_id;
unsigned int subset_id;
cairo_matrix_t text_matrix; /* PDF text matrix (Tlm in the PDF reference) */
cairo_matrix_t cairo_to_pdftext; /* translate cairo coords to PDF text space */
cairo_matrix_t font_matrix_inverse;
double cur_x; /* Current position in PDF text space (Tm in the PDF reference) */
double cur_y;
int hex_width;
int num_glyphs;
double glyph_buf_x_pos;
cairo_pdf_glyph_t glyphs[PDF_GLYPH_BUFFER_SIZE];
 
/* PDF line style */
cairo_bool_t has_line_style;
double line_width;
cairo_line_cap_t line_cap;
cairo_line_join_t line_join;
double miter_limit;
cairo_bool_t has_dashes;
} cairo_pdf_operators_t;
 
cairo_private void
_cairo_pdf_operators_init (cairo_pdf_operators_t *pdf_operators,
cairo_output_stream_t *stream,
cairo_matrix_t *cairo_to_pdf,
cairo_scaled_font_subsets_t *font_subsets);
 
cairo_private cairo_status_t
_cairo_pdf_operators_fini (cairo_pdf_operators_t *pdf_operators);
 
cairo_private void
_cairo_pdf_operators_set_font_subsets_callback (cairo_pdf_operators_t *pdf_operators,
cairo_pdf_operators_use_font_subset_t use_font_subset,
void *closure);
 
cairo_private void
_cairo_pdf_operators_set_stream (cairo_pdf_operators_t *pdf_operators,
cairo_output_stream_t *stream);
 
 
cairo_private void
_cairo_pdf_operators_set_cairo_to_pdf_matrix (cairo_pdf_operators_t *pdf_operators,
cairo_matrix_t *cairo_to_pdf);
 
cairo_private void
_cairo_pdf_operators_enable_actual_text (cairo_pdf_operators_t *pdf_operators,
cairo_bool_t enable);
 
cairo_private cairo_status_t
_cairo_pdf_operators_flush (cairo_pdf_operators_t *pdf_operators);
 
cairo_private void
_cairo_pdf_operators_reset (cairo_pdf_operators_t *pdf_operators);
 
cairo_private cairo_int_status_t
_cairo_pdf_operators_clip (cairo_pdf_operators_t *pdf_operators,
cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule);
 
cairo_private cairo_int_status_t
_cairo_pdf_operators_emit_stroke_style (cairo_pdf_operators_t *pdf_operators,
const cairo_stroke_style_t *style,
double scale);
 
cairo_private cairo_int_status_t
_cairo_pdf_operators_stroke (cairo_pdf_operators_t *pdf_operators,
cairo_path_fixed_t *path,
const cairo_stroke_style_t *style,
const cairo_matrix_t *ctm,
const cairo_matrix_t *ctm_inverse);
 
cairo_private cairo_int_status_t
_cairo_pdf_operators_fill (cairo_pdf_operators_t *pdf_operators,
cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule);
 
cairo_private cairo_int_status_t
_cairo_pdf_operators_fill_stroke (cairo_pdf_operators_t *pdf_operators,
cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
const cairo_stroke_style_t *style,
const cairo_matrix_t *ctm,
const cairo_matrix_t *ctm_inverse);
 
cairo_private cairo_int_status_t
_cairo_pdf_operators_show_text_glyphs (cairo_pdf_operators_t *pdf_operators,
const char *utf8,
int utf8_len,
cairo_glyph_t *glyphs,
int num_glyphs,
const cairo_text_cluster_t *clusters,
int num_clusters,
cairo_text_cluster_flags_t cluster_flags,
cairo_scaled_font_t *scaled_font);
 
#endif /* CAIRO_PDF_OPERATORS_H */
/programs/develop/libraries/cairo/src/cairo-pdf-surface-private.h
0,0 → 1,196
/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2004 Red Hat, Inc
* Copyright © 2006 Red Hat, Inc
* Copyright © 2007, 2008 Adrian Johnson
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Kristian Høgsberg <krh@redhat.com>
* Carl Worth <cworth@cworth.org>
* Adrian Johnson <ajohnson@redneon.com>
*/
 
#ifndef CAIRO_PDF_SURFACE_PRIVATE_H
#define CAIRO_PDF_SURFACE_PRIVATE_H
 
#include "cairo-pdf.h"
 
#include "cairo-surface-private.h"
#include "cairo-surface-clipper-private.h"
#include "cairo-pdf-operators-private.h"
#include "cairo-path-fixed-private.h"
 
typedef struct _cairo_pdf_resource {
unsigned int id;
} cairo_pdf_resource_t;
 
#define CAIRO_NUM_OPERATORS (CAIRO_OPERATOR_HSL_LUMINOSITY + 1)
 
typedef struct _cairo_pdf_group_resources {
cairo_bool_t operators[CAIRO_NUM_OPERATORS];
cairo_array_t alphas;
cairo_array_t smasks;
cairo_array_t patterns;
cairo_array_t xobjects;
cairo_array_t fonts;
} cairo_pdf_group_resources_t;
 
typedef struct _cairo_pdf_source_surface_entry {
cairo_hash_entry_t base;
unsigned int id;
cairo_bool_t interpolate;
cairo_pdf_resource_t surface_res;
int width;
int height;
} cairo_pdf_source_surface_entry_t;
 
typedef struct _cairo_pdf_source_surface {
cairo_surface_t *surface;
cairo_pdf_source_surface_entry_t *hash_entry;
} cairo_pdf_source_surface_t;
 
typedef struct _cairo_pdf_pattern {
double width;
double height;
cairo_rectangle_int_t extents;
cairo_pattern_t *pattern;
cairo_pdf_resource_t pattern_res;
cairo_pdf_resource_t gstate_res;
} cairo_pdf_pattern_t;
 
typedef enum _cairo_pdf_operation {
PDF_PAINT,
PDF_MASK,
PDF_FILL,
PDF_STROKE,
PDF_SHOW_GLYPHS
} cairo_pdf_operation_t;
 
typedef struct _cairo_pdf_smask_group {
double width;
double height;
cairo_pdf_resource_t group_res;
cairo_pdf_operation_t operation;
cairo_pattern_t *source;
cairo_pdf_resource_t source_res;
cairo_pattern_t *mask;
cairo_path_fixed_t path;
cairo_fill_rule_t fill_rule;
cairo_stroke_style_t style;
cairo_matrix_t ctm;
cairo_matrix_t ctm_inverse;
char *utf8;
int utf8_len;
cairo_glyph_t *glyphs;
int num_glyphs;
cairo_text_cluster_t *clusters;
int num_clusters;
cairo_bool_t cluster_flags;
cairo_scaled_font_t *scaled_font;
} cairo_pdf_smask_group_t;
 
typedef struct _cairo_pdf_surface cairo_pdf_surface_t;
 
struct _cairo_pdf_surface {
cairo_surface_t base;
 
/* Prefer the name "output" here to avoid confusion over the
* structure within a PDF document known as a "stream". */
cairo_output_stream_t *output;
 
double width;
double height;
cairo_matrix_t cairo_to_pdf;
 
cairo_array_t objects;
cairo_array_t pages;
cairo_array_t rgb_linear_functions;
cairo_array_t alpha_linear_functions;
cairo_array_t page_patterns;
cairo_array_t page_surfaces;
cairo_hash_table_t *all_surfaces;
cairo_array_t smask_groups;
cairo_array_t knockout_group;
 
cairo_scaled_font_subsets_t *font_subsets;
cairo_array_t fonts;
 
cairo_pdf_resource_t next_available_resource;
cairo_pdf_resource_t pages_resource;
 
cairo_pdf_version_t pdf_version;
cairo_bool_t compress_content;
 
cairo_pdf_resource_t content;
cairo_pdf_resource_t content_resources;
cairo_pdf_group_resources_t resources;
cairo_bool_t has_fallback_images;
cairo_bool_t header_emitted;
 
struct {
cairo_bool_t active;
cairo_pdf_resource_t self;
cairo_pdf_resource_t length;
long start_offset;
cairo_bool_t compressed;
cairo_output_stream_t *old_output;
} pdf_stream;
 
struct {
cairo_bool_t active;
cairo_output_stream_t *stream;
cairo_output_stream_t *mem_stream;
cairo_output_stream_t *old_output;
cairo_pdf_resource_t resource;
cairo_bool_t is_knockout;
} group_stream;
 
cairo_surface_clipper_t clipper;
 
cairo_pdf_operators_t pdf_operators;
cairo_paginated_mode_t paginated_mode;
cairo_bool_t select_pattern_gstate_saved;
 
cairo_bool_t force_fallbacks;
 
cairo_operator_t current_operator;
cairo_bool_t current_pattern_is_solid_color;
cairo_bool_t current_color_is_stroke;
double current_color_red;
double current_color_green;
double current_color_blue;
double current_color_alpha;
 
cairo_surface_t *paginated_surface;
};
 
#endif /* CAIRO_PDF_SURFACE_PRIVATE_H */
/programs/develop/libraries/cairo/src/cairo-pdf.h
0,0 → 1,94
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2002 University of Southern California
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
*/
 
#ifndef CAIRO_PDF_H
#define CAIRO_PDF_H
 
#include "cairo.h"
 
#if CAIRO_HAS_PDF_SURFACE
 
CAIRO_BEGIN_DECLS
 
/**
* cairo_pdf_version_t:
* @CAIRO_PDF_VERSION_1_4: The version 1.4 of the PDF specification.
* @CAIRO_PDF_VERSION_1_5: The version 1.5 of the PDF specification.
*
* #cairo_pdf_version_t is used to describe the version number of the PDF
* specification that a generated PDF file will conform to.
*
* Since 1.10
*/
typedef enum _cairo_pdf_version {
CAIRO_PDF_VERSION_1_4,
CAIRO_PDF_VERSION_1_5
} cairo_pdf_version_t;
 
cairo_public cairo_surface_t *
cairo_pdf_surface_create (const char *filename,
double width_in_points,
double height_in_points);
 
cairo_public cairo_surface_t *
cairo_pdf_surface_create_for_stream (cairo_write_func_t write_func,
void *closure,
double width_in_points,
double height_in_points);
 
cairo_public void
cairo_pdf_surface_restrict_to_version (cairo_surface_t *surface,
cairo_pdf_version_t version);
 
cairo_public void
cairo_pdf_get_versions (cairo_pdf_version_t const **versions,
int *num_versions);
 
cairo_public const char *
cairo_pdf_version_to_string (cairo_pdf_version_t version);
 
cairo_public void
cairo_pdf_surface_set_size (cairo_surface_t *surface,
double width_in_points,
double height_in_points);
 
CAIRO_END_DECLS
 
#else /* CAIRO_HAS_PDF_SURFACE */
# error Cairo was not compiled with support for the pdf backend
#endif /* CAIRO_HAS_PDF_SURFACE */
 
#endif /* CAIRO_PDF_H */
/programs/develop/libraries/cairo/src/cairo-pen.c
0,0 → 1,398
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2002 University of Southern California
* Copyright © 2008 Chris Wilson
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
* Chris Wilson <chris@chris-wilson.co.uk>
*/
 
#include "cairoint.h"
 
#include "cairo-error-private.h"
#include "cairo-slope-private.h"
 
static int
_cairo_pen_vertices_needed (double tolerance,
double radius,
const cairo_matrix_t *matrix);
 
static void
_cairo_pen_compute_slopes (cairo_pen_t *pen);
 
cairo_status_t
_cairo_pen_init (cairo_pen_t *pen,
double radius,
double tolerance,
const cairo_matrix_t *ctm)
{
int i;
int reflect;
 
if (CAIRO_INJECT_FAULT ())
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
VG (VALGRIND_MAKE_MEM_UNDEFINED (pen, sizeof (cairo_pen_t)));
 
pen->radius = radius;
pen->tolerance = tolerance;
 
reflect = _cairo_matrix_compute_determinant (ctm) < 0.;
 
pen->num_vertices = _cairo_pen_vertices_needed (tolerance,
radius,
ctm);
 
if (pen->num_vertices > ARRAY_LENGTH (pen->vertices_embedded)) {
pen->vertices = _cairo_malloc_ab (pen->num_vertices,
sizeof (cairo_pen_vertex_t));
if (unlikely (pen->vertices == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
} else {
pen->vertices = pen->vertices_embedded;
}
 
/*
* Compute pen coordinates. To generate the right ellipse, compute points around
* a circle in user space and transform them to device space. To get a consistent
* orientation in device space, flip the pen if the transformation matrix
* is reflecting
*/
for (i=0; i < pen->num_vertices; i++) {
double theta = 2 * M_PI * i / (double) pen->num_vertices;
double dx = radius * cos (reflect ? -theta : theta);
double dy = radius * sin (reflect ? -theta : theta);
cairo_pen_vertex_t *v = &pen->vertices[i];
cairo_matrix_transform_distance (ctm, &dx, &dy);
v->point.x = _cairo_fixed_from_double (dx);
v->point.y = _cairo_fixed_from_double (dy);
}
 
_cairo_pen_compute_slopes (pen);
 
return CAIRO_STATUS_SUCCESS;
}
 
void
_cairo_pen_fini (cairo_pen_t *pen)
{
if (pen->vertices != pen->vertices_embedded)
free (pen->vertices);
 
 
VG (VALGRIND_MAKE_MEM_NOACCESS (pen, sizeof (cairo_pen_t)));
}
 
cairo_status_t
_cairo_pen_init_copy (cairo_pen_t *pen, const cairo_pen_t *other)
{
VG (VALGRIND_MAKE_MEM_UNDEFINED (pen, sizeof (cairo_pen_t)));
 
*pen = *other;
 
if (CAIRO_INJECT_FAULT ())
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
pen->vertices = pen->vertices_embedded;
if (pen->num_vertices) {
if (pen->num_vertices > ARRAY_LENGTH (pen->vertices_embedded)) {
pen->vertices = _cairo_malloc_ab (pen->num_vertices,
sizeof (cairo_pen_vertex_t));
if (unlikely (pen->vertices == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
 
memcpy (pen->vertices, other->vertices,
pen->num_vertices * sizeof (cairo_pen_vertex_t));
}
 
return CAIRO_STATUS_SUCCESS;
}
 
cairo_status_t
_cairo_pen_add_points (cairo_pen_t *pen, cairo_point_t *point, int num_points)
{
cairo_status_t status;
int num_vertices;
int i;
 
if (CAIRO_INJECT_FAULT ())
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
num_vertices = pen->num_vertices + num_points;
if (num_vertices > ARRAY_LENGTH (pen->vertices_embedded) ||
pen->vertices != pen->vertices_embedded)
{
cairo_pen_vertex_t *vertices;
 
if (pen->vertices == pen->vertices_embedded) {
vertices = _cairo_malloc_ab (num_vertices,
sizeof (cairo_pen_vertex_t));
if (unlikely (vertices == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
memcpy (vertices, pen->vertices,
pen->num_vertices * sizeof (cairo_pen_vertex_t));
} else {
vertices = _cairo_realloc_ab (pen->vertices,
num_vertices,
sizeof (cairo_pen_vertex_t));
if (unlikely (vertices == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
 
pen->vertices = vertices;
}
 
pen->num_vertices = num_vertices;
 
/* initialize new vertices */
for (i=0; i < num_points; i++)
pen->vertices[pen->num_vertices-num_points+i].point = point[i];
 
status = _cairo_hull_compute (pen->vertices, &pen->num_vertices);
if (unlikely (status))
return status;
 
_cairo_pen_compute_slopes (pen);
 
return CAIRO_STATUS_SUCCESS;
}
 
/*
The circular pen in user space is transformed into an ellipse in
device space.
 
We construct the pen by computing points along the circumference
using equally spaced angles.
 
We show that this approximation to the ellipse has maximum error at the
major axis of the ellipse.
 
Set
 
M = major axis length
m = minor axis length
 
Align 'M' along the X axis and 'm' along the Y axis and draw
an ellipse parameterized by angle 't':
 
x = M cos t y = m sin t
 
Perturb t by ± d and compute two new points (x+,y+), (x-,y-).
The distance from the average of these two points to (x,y) represents
the maximum error in approximating the ellipse with a polygon formed
from vertices 2∆ radians apart.
 
x+ = M cos (t+∆) y+ = m sin (t+∆)
x- = M cos (t-∆) y- = m sin (t-∆)
 
Now compute the approximation error, E:
 
Ex = (x - (x+ + x-) / 2)
Ex = (M cos(t) - (Mcos(t+∆) + Mcos(t-∆))/2)
= M (cos(t) - (cos(t)cos(∆) + sin(t)sin(∆) +
cos(t)cos(∆) - sin(t)sin(∆))/2)
= M(cos(t) - cos(t)cos(∆))
= M cos(t) (1 - cos(∆))
 
Ey = y - (y+ - y-) / 2
= m sin (t) - (m sin(t+∆) + m sin(t-∆)) / 2
= m (sin(t) - (sin(t)cos(∆) + cos(t)sin(∆) +
sin(t)cos(∆) - cos(t)sin(∆))/2)
= m (sin(t) - sin(t)cos(∆))
= m sin(t) (1 - cos(∆))
 
E² = Ex² + Ey²
= (M cos(t) (1 - cos (∆)))² + (m sin(t) (1-cos(∆)))²
= (1 - cos(∆))² (M² cos²(t) + m² sin²(t))
= (1 - cos(∆))² ((m² + M² - m²) cos² (t) + m² sin²(t))
= (1 - cos(∆))² (M² - m²) cos² (t) + (1 - cos(∆))² m²
 
Find the extremum by differentiation wrt t and setting that to zero
 
∂(E²)/∂(t) = (1-cos(∆))² (M² - m²) (-2 cos(t) sin(t))
 
0 = 2 cos (t) sin (t)
0 = sin (2t)
t = nπ
 
Which is to say that the maximum and minimum errors occur on the
axes of the ellipse at 0 and π radians:
 
E²(0) = (1-cos(∆))² (M² - m²) + (1-cos(∆))² m²
= (1-cos(∆))² M²
E²(π) = (1-cos(∆))² m²
 
maximum error = M (1-cos(∆))
minimum error = m (1-cos(∆))
 
We must make maximum error ≤ tolerance, so compute the ∆ needed:
 
tolerance = M (1-cos(∆))
tolerance / M = 1 - cos (∆)
cos(∆) = 1 - tolerance/M
∆ = acos (1 - tolerance / M);
 
Remembering that ∆ is half of our angle between vertices,
the number of vertices is then
 
vertices = ceil(2π/2∆).
= ceil(π/∆).
 
Note that this also equation works for M == m (a circle) as it
doesn't matter where on the circle the error is computed.
*/
 
static int
_cairo_pen_vertices_needed (double tolerance,
double radius,
const cairo_matrix_t *matrix)
{
/*
* the pen is a circle that gets transformed to an ellipse by matrix.
* compute major axis length for a pen with the specified radius.
* we don't need the minor axis length.
*/
 
double major_axis = _cairo_matrix_transformed_circle_major_axis (matrix,
radius);
 
/*
* compute number of vertices needed
*/
int num_vertices;
 
/* Where tolerance / M is > 1, we use 4 points */
if (tolerance >= major_axis) {
num_vertices = 4;
} else {
double delta = acos (1 - tolerance / major_axis);
num_vertices = ceil (M_PI / delta);
 
/* number of vertices must be even */
if (num_vertices % 2)
num_vertices++;
 
/* And we must always have at least 4 vertices. */
if (num_vertices < 4)
num_vertices = 4;
}
 
return num_vertices;
}
 
static void
_cairo_pen_compute_slopes (cairo_pen_t *pen)
{
int i, i_prev;
cairo_pen_vertex_t *prev, *v, *next;
 
for (i=0, i_prev = pen->num_vertices - 1;
i < pen->num_vertices;
i_prev = i++) {
prev = &pen->vertices[i_prev];
v = &pen->vertices[i];
next = &pen->vertices[(i + 1) % pen->num_vertices];
 
_cairo_slope_init (&v->slope_cw, &prev->point, &v->point);
_cairo_slope_init (&v->slope_ccw, &v->point, &next->point);
}
}
/*
* Find active pen vertex for clockwise edge of stroke at the given slope.
*
* The strictness of the inequalities here is delicate. The issue is
* that the slope_ccw member of one pen vertex will be equivalent to
* the slope_cw member of the next pen vertex in a counterclockwise
* order. However, for this function, we care strongly about which
* vertex is returned.
*
* [I think the "care strongly" above has to do with ensuring that the
* pen's "extra points" from the spline's initial and final slopes are
* properly found when beginning the spline stroking.]
*/
int
_cairo_pen_find_active_cw_vertex_index (const cairo_pen_t *pen,
const cairo_slope_t *slope)
{
int i;
 
for (i=0; i < pen->num_vertices; i++) {
if ((_cairo_slope_compare (slope, &pen->vertices[i].slope_ccw) < 0) &&
(_cairo_slope_compare (slope, &pen->vertices[i].slope_cw) >= 0))
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 first pen vertex as the appropriate clockwise vertex.
*/
if (i == pen->num_vertices)
i = 0;
 
return i;
}
 
/* Find active pen vertex for counterclockwise edge of stroke at the given slope.
*
* Note: See the comments for _cairo_pen_find_active_cw_vertex_index
* for some details about the strictness of the inequalities here.
*/
int
_cairo_pen_find_active_ccw_vertex_index (const cairo_pen_t *pen,
const cairo_slope_t *slope)
{
cairo_slope_t slope_reverse;
int i;
 
slope_reverse = *slope;
slope_reverse.dx = -slope_reverse.dx;
slope_reverse.dy = -slope_reverse.dy;
 
for (i=pen->num_vertices-1; i >= 0; i--) {
if ((_cairo_slope_compare (&pen->vertices[i].slope_ccw, &slope_reverse) >= 0) &&
(_cairo_slope_compare (&pen->vertices[i].slope_cw, &slope_reverse) < 0))
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;
 
return i;
}
/programs/develop/libraries/cairo/src/cairo-polygon.c
0,0 → 1,495
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2002 University of Southern California
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
*/
 
#include "cairoint.h"
 
#include "cairo-error-private.h"
#include "cairo-slope-private.h"
 
void
_cairo_polygon_init (cairo_polygon_t *polygon)
{
VG (VALGRIND_MAKE_MEM_UNDEFINED (polygon, sizeof (cairo_polygon_t)));
 
polygon->status = CAIRO_STATUS_SUCCESS;
 
polygon->num_edges = 0;
 
polygon->edges = polygon->edges_embedded;
polygon->edges_size = ARRAY_LENGTH (polygon->edges_embedded);
 
polygon->has_current_point = FALSE;
polygon->has_current_edge = FALSE;
polygon->num_limits = 0;
 
polygon->extents.p1.x = polygon->extents.p1.y = INT32_MAX;
polygon->extents.p2.x = polygon->extents.p2.y = INT32_MIN;
}
 
void
_cairo_polygon_limit (cairo_polygon_t *polygon,
const cairo_box_t *limits,
int num_limits)
{
int n;
 
polygon->limits = limits;
polygon->num_limits = num_limits;
 
if (polygon->num_limits) {
polygon->limit = limits[0];
for (n = 1; n < num_limits; n++) {
if (limits[n].p1.x < polygon->limit.p1.x)
polygon->limit.p1.x = limits[n].p1.x;
 
if (limits[n].p1.y < polygon->limit.p1.y)
polygon->limit.p1.y = limits[n].p1.y;
 
if (limits[n].p2.x > polygon->limit.p2.x)
polygon->limit.p2.x = limits[n].p2.x;
 
if (limits[n].p2.y > polygon->limit.p2.y)
polygon->limit.p2.y = limits[n].p2.y;
}
}
}
 
void
_cairo_polygon_fini (cairo_polygon_t *polygon)
{
if (polygon->edges != polygon->edges_embedded)
free (polygon->edges);
 
VG (VALGRIND_MAKE_MEM_NOACCESS (polygon, sizeof (cairo_polygon_t)));
}
 
/* make room for at least one more edge */
static cairo_bool_t
_cairo_polygon_grow (cairo_polygon_t *polygon)
{
cairo_edge_t *new_edges;
int old_size = polygon->edges_size;
int new_size = 4 * old_size;
 
if (CAIRO_INJECT_FAULT ()) {
polygon->status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
return FALSE;
}
 
if (polygon->edges == polygon->edges_embedded) {
new_edges = _cairo_malloc_ab (new_size, sizeof (cairo_edge_t));
if (new_edges != NULL)
memcpy (new_edges, polygon->edges, old_size * sizeof (cairo_edge_t));
} else {
new_edges = _cairo_realloc_ab (polygon->edges,
new_size, sizeof (cairo_edge_t));
}
 
if (unlikely (new_edges == NULL)) {
polygon->status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
return FALSE;
}
 
polygon->edges = new_edges;
polygon->edges_size = new_size;
 
return TRUE;
}
 
static void
_add_edge (cairo_polygon_t *polygon,
const cairo_point_t *p1,
const cairo_point_t *p2,
int top, int bottom,
int dir)
{
cairo_edge_t *edge;
 
assert (top < bottom);
 
if (unlikely (polygon->num_edges == polygon->edges_size)) {
if (! _cairo_polygon_grow (polygon))
return;
}
 
edge = &polygon->edges[polygon->num_edges++];
edge->line.p1 = *p1;
edge->line.p2 = *p2;
edge->top = top;
edge->bottom = bottom;
edge->dir = dir;
 
if (top < polygon->extents.p1.y)
polygon->extents.p1.y = top;
if (bottom > polygon->extents.p2.y)
polygon->extents.p2.y = bottom;
 
if (p1->x < polygon->extents.p1.x || p1->x > polygon->extents.p2.x) {
cairo_fixed_t x = p1->x;
if (top != p1->y)
x = _cairo_edge_compute_intersection_x_for_y (p1, p2, top);
if (x < polygon->extents.p1.x)
polygon->extents.p1.x = x;
if (x > polygon->extents.p2.x)
polygon->extents.p2.x = x;
}
 
if (p2->x < polygon->extents.p1.x || p2->x > polygon->extents.p2.x) {
cairo_fixed_t x = p2->x;
if (bottom != p2->y)
x = _cairo_edge_compute_intersection_x_for_y (p1, p2, bottom);
if (x < polygon->extents.p1.x)
polygon->extents.p1.x = x;
if (x > polygon->extents.p2.x)
polygon->extents.p2.x = x;
}
}
 
static void
_add_clipped_edge (cairo_polygon_t *polygon,
const cairo_point_t *p1,
const cairo_point_t *p2,
const int top, const int bottom,
const int dir)
{
cairo_point_t p[2];
int top_y, bot_y;
int n;
 
for (n = 0; n < polygon->num_limits; n++) {
const cairo_box_t *limits = &polygon->limits[n];
 
if (top >= limits->p2.y)
continue;
if (bottom <= limits->p1.y)
continue;
 
if (p1->x >= limits->p1.x && p2->x >= limits->p1.x &&
p1->x <= limits->p2.x && p2->x <= limits->p2.x)
{
top_y = top;
if (top_y < limits->p1.y)
top_y = limits->p1.y;
 
bot_y = bottom;
if (bot_y > limits->p2.y)
bot_y = limits->p2.y;
 
_add_edge (polygon, p1, p2, top_y, bot_y, dir);
}
else if (p1->x <= limits->p1.x && p2->x <= limits->p1.x)
{
p[0].x = limits->p1.x;
p[0].y = limits->p1.y;
top_y = top;
if (top_y < p[0].y)
top_y = p[0].y;
 
p[1].x = limits->p1.x;
p[1].y = limits->p2.y;
bot_y = bottom;
if (bot_y > p[1].y)
bot_y = p[1].y;
 
_add_edge (polygon, &p[0], &p[1], top_y, bot_y, dir);
}
else if (p1->x >= limits->p2.x && p2->x >= limits->p2.x)
{
p[0].x = limits->p2.x;
p[0].y = limits->p1.y;
top_y = top;
if (top_y < p[0].y)
top_y = p[0].y;
 
p[1].x = limits->p2.x;
p[1].y = limits->p2.y;
bot_y = bottom;
if (bot_y > p[1].y)
bot_y = p[1].y;
 
_add_edge (polygon, &p[0], &p[1], top_y, bot_y, dir);
}
else
{
int left_y, right_y;
int p1_y, p2_y;
 
left_y = _cairo_edge_compute_intersection_y_for_x (p1, p2,
limits->p1.x);
right_y = _cairo_edge_compute_intersection_y_for_x (p1, p2,
limits->p2.x);
 
if (left_y == right_y) /* horizontal within bounds */
continue;
 
p1_y = top;
p2_y = bottom;
 
if (left_y < right_y) {
if (p1->x < limits->p1.x && left_y > limits->p1.y) {
p[0].x = limits->p1.x;
p[0].y = limits->p1.y;
top_y = p1_y;
if (top_y < p[0].y)
top_y = p[0].y;
 
p[1].x = limits->p1.x;
p[1].y = limits->p2.y;
bot_y = left_y;
if (bot_y > p[1].y)
bot_y = p[1].y;
 
if (bot_y > top_y)
_add_edge (polygon, &p[0], &p[1], top_y, bot_y, dir);
p1_y = bot_y;
}
 
if (p2->x > limits->p2.x && right_y < limits->p2.y) {
p[0].x = limits->p2.x;
p[0].y = limits->p1.y;
top_y = right_y;
if (top_y < p[0].y)
top_y = p[0].y;
 
p[1].x = limits->p2.x;
p[1].y = limits->p2.y;
bot_y = p2_y;
if (bot_y > p[1].y)
bot_y = p[1].y;
 
if (bot_y > top_y)
_add_edge (polygon, &p[0], &p[1], top_y, bot_y, dir);
p2_y = top_y;
}
} else {
if (p1->x > limits->p2.x && right_y > limits->p1.y) {
p[0].x = limits->p2.x;
p[0].y = limits->p1.y;
top_y = p1_y;
if (top_y < p[0].y)
top_y = p[0].y;
 
p[1].x = limits->p2.x;
p[1].y = limits->p2.y;
bot_y = right_y;
if (bot_y > p[1].y)
bot_y = p[1].y;
 
if (bot_y > top_y)
_add_edge (polygon, &p[0], &p[1], top_y, bot_y, dir);
p1_y = bot_y;
}
 
if (p2->x < limits->p1.x && left_y < limits->p2.y) {
p[0].x = limits->p1.x;
p[0].y = limits->p1.y;
top_y = left_y;
if (top_y < p[0].y)
top_y = p[0].y;
 
p[1].x = limits->p1.x;
p[1].y = limits->p2.y;
bot_y = p2_y;
if (bot_y > p[1].y)
bot_y = p[1].y;
 
if (bot_y > top_y)
_add_edge (polygon, &p[0], &p[1], top_y, bot_y, dir);
p2_y = top_y;
}
}
 
if (p1_y < limits->p1.y)
p1_y = limits->p1.y;
if (p2_y > limits->p2.y)
p2_y = limits->p2.y;
if (p2_y > p1_y)
_add_edge (polygon, p1, p2, p1_y, p2_y, dir);
}
}
}
 
static void
_cairo_polygon_add_edge (cairo_polygon_t *polygon,
const cairo_point_t *p1,
const cairo_point_t *p2)
{
int dir;
 
/* drop horizontal edges */
if (p1->y == p2->y)
return;
 
if (p1->y < p2->y) {
dir = 1;
} else {
const cairo_point_t *t;
t = p1, p1 = p2, p2 = t;
dir = -1;
}
 
if (polygon->num_limits) {
if (p2->y <= polygon->limit.p1.y)
return;
 
if (p1->y >= polygon->limit.p2.y)
return;
 
_add_clipped_edge (polygon, p1, p2, p1->y, p2->y, dir);
} else
_add_edge (polygon, p1, p2, p1->y, p2->y, dir);
}
 
cairo_status_t
_cairo_polygon_add_external_edge (void *polygon,
const cairo_point_t *p1,
const cairo_point_t *p2)
{
_cairo_polygon_add_edge (polygon, p1, p2);
return _cairo_polygon_status (polygon);
}
 
cairo_status_t
_cairo_polygon_add_line (cairo_polygon_t *polygon,
const cairo_line_t *line,
int top, int bottom,
int dir)
{
/* drop horizontal edges */
if (line->p1.y == line->p2.y)
return CAIRO_STATUS_SUCCESS;
 
if (bottom <= top)
return CAIRO_STATUS_SUCCESS;
 
if (polygon->num_limits) {
if (line->p2.y <= polygon->limit.p1.y)
return CAIRO_STATUS_SUCCESS;
 
if (line->p1.y >= polygon->limit.p2.y)
return CAIRO_STATUS_SUCCESS;
 
_add_clipped_edge (polygon, &line->p1, &line->p2, top, bottom, dir);
} else
_add_edge (polygon, &line->p1, &line->p2, top, bottom, dir);
 
return polygon->status;
}
 
/* flattened path operations */
 
cairo_status_t
_cairo_polygon_move_to (cairo_polygon_t *polygon,
const cairo_point_t *point)
{
if (polygon->has_current_edge) {
_cairo_polygon_add_edge (polygon,
&polygon->last_point,
&polygon->current_point);
polygon->has_current_edge = FALSE;
}
 
if (! polygon->has_current_point) {
polygon->first_point = *point;
polygon->has_current_point = TRUE;
}
 
polygon->current_point = *point;
return polygon->status;
}
 
cairo_status_t
_cairo_polygon_line_to (cairo_polygon_t *polygon,
const cairo_point_t *point)
{
/* squash collinear edges */
if (polygon->has_current_edge) {
if (polygon->current_point.x != point->x ||
polygon->current_point.y != point->y)
{
cairo_slope_t this;
 
_cairo_slope_init (&this, &polygon->current_point, point);
if (_cairo_slope_equal (&polygon->current_edge, &this)) {
polygon->current_point = *point;
return CAIRO_STATUS_SUCCESS;
}
 
_cairo_polygon_add_edge (polygon,
&polygon->last_point,
&polygon->current_point);
 
polygon->last_point = polygon->current_point;
polygon->current_edge = this;
}
} else if (polygon->has_current_point) {
if (polygon->current_point.x != point->x ||
polygon->current_point.y != point->y)
{
polygon->last_point = polygon->current_point;
_cairo_slope_init (&polygon->current_edge,
&polygon->last_point,
point);
polygon->has_current_edge = TRUE;
}
} else {
polygon->first_point = *point;
polygon->has_current_point = TRUE;
}
 
polygon->current_point = *point;
return polygon->status;
}
 
cairo_status_t
_cairo_polygon_close (cairo_polygon_t *polygon)
{
cairo_status_t status;
 
if (polygon->has_current_point) {
status = _cairo_polygon_line_to (polygon, &polygon->first_point);
polygon->has_current_point = FALSE;
}
 
if (polygon->has_current_edge) {
_cairo_polygon_add_edge (polygon,
&polygon->last_point,
&polygon->current_point);
polygon->has_current_edge = FALSE;
}
 
return polygon->status;
}
/programs/develop/libraries/cairo/src/cairo-private.h
0,0 → 1,57
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2005 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
* Carl D. Worth <cworth@redhat.com>
*/
 
#ifndef CAIRO_PRIVATE_H
#define CAIRO_PRIVATE_H
 
#include "cairo-reference-count-private.h"
#include "cairo-gstate-private.h"
#include "cairo-path-fixed-private.h"
 
struct _cairo {
cairo_reference_count_t ref_count;
 
cairo_status_t status;
 
cairo_user_data_array_t user_data;
 
cairo_gstate_t *gstate;
cairo_gstate_t gstate_tail[2];
cairo_gstate_t *gstate_freelist;
 
cairo_path_fixed_t path[1];
};
 
#endif /* CAIRO_PRIVATE_H */
/programs/develop/libraries/cairo/src/cairo-ps-surface-private.h
0,0 → 1,109
/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2003 University of Southern California
* Copyright © 2005 Red Hat, Inc
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
* Kristian Høgsberg <krh@redhat.com>
* Keith Packard <keithp@keithp.com>
*/
 
#ifndef CAIRO_PS_SURFACE_PRIVATE_H
#define CAIRO_PS_SURFACE_PRIVATE_H
 
#include "cairo-ps.h"
 
#include "cairo-surface-private.h"
#include "cairo-surface-clipper-private.h"
#include "cairo-pdf-operators-private.h"
 
#include <time.h>
 
typedef struct cairo_ps_surface {
cairo_surface_t base;
 
/* Here final_stream corresponds to the stream/file passed to
* cairo_ps_surface_create surface is built. Meanwhile stream is a
* temporary stream in which the file output is built, (so that
* the header can be built and inserted into the target stream
* before the contents of the temporary stream are copied). */
cairo_output_stream_t *final_stream;
 
FILE *tmpfile;
cairo_output_stream_t *stream;
 
cairo_bool_t eps;
cairo_content_t content;
double width;
double height;
cairo_rectangle_int_t page_bbox;
int bbox_x1, bbox_y1, bbox_x2, bbox_y2;
cairo_matrix_t cairo_to_ps;
 
/* XXX These 3 are used as temporary storage whilst emitting patterns */
cairo_image_surface_t *image;
cairo_image_surface_t *acquired_image;
void *image_extra;
 
cairo_bool_t use_string_datasource;
 
cairo_bool_t current_pattern_is_solid_color;
cairo_color_t current_color;
 
int num_pages;
 
cairo_paginated_mode_t paginated_mode;
 
cairo_bool_t force_fallbacks;
cairo_bool_t has_creation_date;
time_t creation_date;
 
cairo_scaled_font_subsets_t *font_subsets;
 
cairo_list_t document_media;
cairo_array_t dsc_header_comments;
cairo_array_t dsc_setup_comments;
cairo_array_t dsc_page_setup_comments;
 
cairo_array_t *dsc_comment_target;
 
cairo_ps_level_t ps_level;
cairo_ps_level_t ps_level_used;
 
cairo_surface_clipper_t clipper;
 
cairo_pdf_operators_t pdf_operators;
cairo_surface_t *paginated_surface;
} cairo_ps_surface_t;
 
#endif /* CAIRO_PS_SURFACE_PRIVATE_H */
/programs/develop/libraries/cairo/src/cairo-ps.h
0,0 → 1,114
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2002 University of Southern California
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
*/
 
#ifndef CAIRO_PS_H
#define CAIRO_PS_H
 
#include "cairo.h"
 
#if CAIRO_HAS_PS_SURFACE
 
#include <stdio.h>
 
CAIRO_BEGIN_DECLS
 
/* 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_ps_surface_create (const char *filename,
double width_in_points,
double height_in_points);
 
cairo_public cairo_surface_t *
cairo_ps_surface_create_for_stream (cairo_write_func_t write_func,
void *closure,
double width_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_ps_surface_set_size (cairo_surface_t *surface,
double width_in_points,
double height_in_points);
 
cairo_public void
cairo_ps_surface_dsc_comment (cairo_surface_t *surface,
const char *comment);
 
cairo_public void
cairo_ps_surface_dsc_begin_setup (cairo_surface_t *surface);
 
cairo_public void
cairo_ps_surface_dsc_begin_page_setup (cairo_surface_t *surface);
 
CAIRO_END_DECLS
 
#else /* CAIRO_HAS_PS_SURFACE */
# error Cairo was not compiled with support for the ps backend
#endif /* CAIRO_HAS_PS_SURFACE */
 
#endif /* CAIRO_PS_H */
/programs/develop/libraries/cairo/src/cairo-qt.h
0,0 → 1,85
/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2008 Mozilla Corporation
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Mozilla Corporation.
*
* Contributor(s):
* Vladimir Vukicevic <vladimir@mozilla.com>
*/
 
#ifndef CAIRO_QT_H
#define CAIRO_QT_H
 
#include "cairo.h"
 
#if CAIRO_HAS_QT_SURFACE
 
#include <QtGui/QImage>
#include <QtGui/QPainter>
 
CAIRO_BEGIN_DECLS
 
cairo_public cairo_surface_t *
cairo_qt_surface_create (QPainter *painter);
 
cairo_public cairo_surface_t *
cairo_qt_surface_create_with_qimage (cairo_format_t format,
int width,
int height);
 
cairo_public cairo_surface_t *
cairo_qt_surface_create_with_qpixmap (cairo_content_t content,
int width,
int height);
 
cairo_public QPainter *
cairo_qt_surface_get_qpainter (cairo_surface_t *surface);
 
/* XXX needs hooking to generic surface layer, my vote is for
cairo_public cairo_surface_t *
cairo_surface_map_image (cairo_surface_t *surface);
cairo_public void
cairo_surface_unmap_image (cairo_surface_t *surface, cairo_surface_t *image);
*/
cairo_public cairo_surface_t *
cairo_qt_surface_get_image (cairo_surface_t *surface);
 
cairo_public QImage *
cairo_qt_surface_get_qimage (cairo_surface_t *surface);
 
CAIRO_END_DECLS
 
#else /* CAIRO_HAS_QT_SURFACE */
 
# error Cairo was not compiled with support for the Qt backend
 
#endif /* CAIRO_HAS_QT_SURFACE */
 
#endif /* CAIRO_QT_H */
/programs/develop/libraries/cairo/src/cairo-quartz-image.h
0,0 → 1,59
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2008 Mozilla Corporation
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Mozilla Foundation.
*
* Contributor(s):
* Vladimir Vukicevic <vladimir@mozilla.com>
*/
 
#ifndef CAIRO_QUARTZ_IMAGE_H
#define CAIRO_QUARTZ_IMAGE_H
 
#include "cairo.h"
 
#if CAIRO_HAS_QUARTZ_IMAGE_SURFACE
 
#include <Carbon/Carbon.h>
 
CAIRO_BEGIN_DECLS
 
cairo_public cairo_surface_t *
cairo_quartz_image_surface_create (cairo_surface_t *image_surface);
 
cairo_public cairo_surface_t *
cairo_quartz_image_surface_get_image (cairo_surface_t *surface);
 
CAIRO_END_DECLS
 
#else /* CAIRO_HAS_QUARTZ_IMAGE_SURFACE */
# error Cairo was not compiled with support for the quartz-image backend
#endif /* CAIRO_HAS_QUARTZ_IMAGE_SURFACE */
 
#endif /* CAIRO_QUARTZ_IMAGE_H */
/programs/develop/libraries/cairo/src/cairo-quartz-private.h
0,0 → 1,112
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2004 Calum Robinson
* Copyright (C) 2006,2007 Mozilla Corporation
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Calum Robinson
*
* Contributor(s):
* Calum Robinson <calumr@mac.com>
* Vladimir Vukicevic <vladimir@mozilla.com>
*/
 
#ifndef CAIRO_QUARTZ_PRIVATE_H
#define CAIRO_QUARTZ_PRIVATE_H
 
#include "cairoint.h"
 
#if CAIRO_HAS_QUARTZ_SURFACE
#include "cairo-quartz.h"
#include "cairo-surface-clipper-private.h"
 
#ifdef CGFLOAT_DEFINED
typedef CGFloat cairo_quartz_float_t;
#else
typedef float cairo_quartz_float_t;
#endif
 
typedef struct cairo_quartz_surface {
cairo_surface_t base;
 
CGContextRef cgContext;
CGAffineTransform cgContextBaseCTM;
 
void *imageData;
cairo_surface_t *imageSurfaceEquiv;
 
cairo_surface_clipper_t clipper;
cairo_rectangle_int_t extents;
 
/* These are stored while drawing operations are in place, set up
* by quartz_setup_source() and quartz_finish_source()
*/
CGAffineTransform sourceTransform;
 
CGImageRef sourceImage;
cairo_surface_t *sourceImageSurface;
CGRect sourceImageRect;
 
CGShadingRef sourceShading;
CGPatternRef sourcePattern;
 
CGInterpolationQuality oldInterpolationQuality;
} cairo_quartz_surface_t;
 
typedef struct cairo_quartz_image_surface {
cairo_surface_t base;
 
cairo_rectangle_int_t extents;
 
CGImageRef image;
cairo_image_surface_t *imageSurface;
} cairo_quartz_image_surface_t;
 
cairo_bool_t
_cairo_quartz_verify_surface_size(int width, int height);
 
CGImageRef
_cairo_quartz_create_cgimage (cairo_format_t format,
unsigned int width,
unsigned int height,
unsigned int stride,
void *data,
cairo_bool_t interpolate,
CGColorSpaceRef colorSpaceOverride,
CGDataProviderReleaseDataCallback releaseCallback,
void *releaseInfo);
 
CGFontRef
_cairo_quartz_scaled_font_get_cg_font_ref (cairo_scaled_font_t *sfont);
 
#else
 
# error Cairo was not compiled with support for the quartz backend
 
#endif /* CAIRO_HAS_QUARTZ_SURFACE */
 
#endif /* CAIRO_QUARTZ_PRIVATE_H */
/programs/develop/libraries/cairo/src/cairo-quartz.h
0,0 → 1,84
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2006, 2007 Mozilla Corporation
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Mozilla Foundation.
*
* Contributor(s):
* Vladimir Vukicevic <vladimir@mozilla.com>
*/
 
#ifndef CAIRO_QUARTZ_H
#define CAIRO_QUARTZ_H
 
#include "cairo.h"
 
#if CAIRO_HAS_QUARTZ_SURFACE
 
#include <ApplicationServices/ApplicationServices.h>
 
CAIRO_BEGIN_DECLS
 
cairo_public cairo_surface_t *
cairo_quartz_surface_create (cairo_format_t format,
unsigned int width,
unsigned int height);
 
cairo_public cairo_surface_t *
cairo_quartz_surface_create_for_cg_context (CGContextRef cgContext,
unsigned int width,
unsigned int height);
 
cairo_public CGContextRef
cairo_quartz_surface_get_cg_context (cairo_surface_t *surface);
 
#if CAIRO_HAS_QUARTZ_FONT
 
/*
* Quartz font support
*/
 
cairo_public cairo_font_face_t *
cairo_quartz_font_face_create_for_cgfont (CGFontRef font);
 
#ifndef __LP64__
cairo_public cairo_font_face_t *
cairo_quartz_font_face_create_for_atsu_font_id (ATSUFontID font_id);
#endif
 
#endif /* CAIRO_HAS_QUARTZ_FONT */
 
CAIRO_END_DECLS
 
#else
 
# error Cairo was not compiled with support for the quartz backend
 
#endif /* CAIRO_HAS_QUARTZ_SURFACE */
 
#endif /* CAIRO_QUARTZ_H */
/programs/develop/libraries/cairo/src/cairo-recording-surface-private.h
0,0 → 1,171
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2005 Red Hat, Inc
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
* Kristian Høgsberg <krh@redhat.com>
* Adrian Johnson <ajohnson@redneon.com>
*/
 
#ifndef CAIRO_RECORDING_SURFACE_H
#define CAIRO_RECORDING_SURFACE_H
 
#include "cairoint.h"
#include "cairo-path-fixed-private.h"
#include "cairo-clip-private.h"
 
typedef enum {
/* The 5 basic drawing operations. */
CAIRO_COMMAND_PAINT,
CAIRO_COMMAND_MASK,
CAIRO_COMMAND_STROKE,
CAIRO_COMMAND_FILL,
CAIRO_COMMAND_SHOW_TEXT_GLYPHS,
} cairo_command_type_t;
 
typedef enum {
CAIRO_RECORDING_REGION_ALL,
CAIRO_RECORDING_REGION_NATIVE,
CAIRO_RECORDING_REGION_IMAGE_FALLBACK
} cairo_recording_region_type_t;
 
typedef struct _cairo_command_header {
cairo_command_type_t type;
cairo_recording_region_type_t region;
cairo_operator_t op;
cairo_clip_t clip;
} cairo_command_header_t;
 
typedef struct _cairo_command_paint {
cairo_command_header_t header;
cairo_pattern_union_t source;
} cairo_command_paint_t;
 
typedef struct _cairo_command_mask {
cairo_command_header_t header;
cairo_pattern_union_t source;
cairo_pattern_union_t mask;
} cairo_command_mask_t;
 
typedef struct _cairo_command_stroke {
cairo_command_header_t header;
cairo_pattern_union_t source;
cairo_path_fixed_t path;
cairo_stroke_style_t style;
cairo_matrix_t ctm;
cairo_matrix_t ctm_inverse;
double tolerance;
cairo_antialias_t antialias;
} cairo_command_stroke_t;
 
typedef struct _cairo_command_fill {
cairo_command_header_t header;
cairo_pattern_union_t source;
cairo_path_fixed_t path;
cairo_fill_rule_t fill_rule;
double tolerance;
cairo_antialias_t antialias;
} cairo_command_fill_t;
 
typedef struct _cairo_command_show_text_glyphs {
cairo_command_header_t header;
cairo_pattern_union_t source;
char *utf8;
int utf8_len;
cairo_glyph_t *glyphs;
unsigned int num_glyphs;
cairo_text_cluster_t *clusters;
int num_clusters;
cairo_text_cluster_flags_t cluster_flags;
cairo_scaled_font_t *scaled_font;
} cairo_command_show_text_glyphs_t;
 
typedef union _cairo_command {
cairo_command_header_t header;
 
cairo_command_paint_t paint;
cairo_command_mask_t mask;
cairo_command_stroke_t stroke;
cairo_command_fill_t fill;
cairo_command_show_text_glyphs_t show_text_glyphs;
} cairo_command_t;
 
typedef struct _cairo_recording_surface {
cairo_surface_t base;
 
cairo_content_t content;
 
/* A recording-surface is logically unbounded, but when used as a
* source we need to render it to an image, so we need a size at
* which to create that image. */
cairo_rectangle_t extents_pixels;
cairo_rectangle_int_t extents;
cairo_bool_t unbounded;
 
cairo_clip_t clip;
 
cairo_array_t commands;
 
int replay_start_idx;
} cairo_recording_surface_t;
 
slim_hidden_proto (cairo_recording_surface_create);
 
cairo_private cairo_int_status_t
_cairo_recording_surface_get_path (cairo_surface_t *surface,
cairo_path_fixed_t *path);
 
cairo_private cairo_status_t
_cairo_recording_surface_replay (cairo_surface_t *surface,
cairo_surface_t *target);
 
 
cairo_private cairo_status_t
_cairo_recording_surface_replay_analyze_recording_pattern (cairo_surface_t *surface,
cairo_surface_t *target);
 
cairo_private cairo_status_t
_cairo_recording_surface_replay_and_create_regions (cairo_surface_t *surface,
cairo_surface_t *target);
cairo_private cairo_status_t
_cairo_recording_surface_replay_region (cairo_surface_t *surface,
const cairo_rectangle_int_t *surface_extents,
cairo_surface_t *target,
cairo_recording_region_type_t region);
 
cairo_private cairo_status_t
_cairo_recording_surface_get_bbox (cairo_recording_surface_t *recording,
cairo_box_t *bbox,
const cairo_matrix_t *transform);
 
cairo_private cairo_bool_t
_cairo_surface_is_recording (const cairo_surface_t *surface);
 
#endif /* CAIRO_RECORDING_SURFACE_H */
/programs/develop/libraries/cairo/src/cairo-recording-surface.c
0,0 → 1,1134
/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2005 Red Hat, Inc
* Copyright © 2007 Adrian Johnson
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
* Kristian Høgsberg <krh@redhat.com>
* Carl Worth <cworth@cworth.org>
* Adrian Johnson <ajohnson@redneon.com>
*/
 
/**
* SECTION:cairo-recording
* @Title: Recording Surfaces
* @Short_Description: Records all drawing operations
* @See_Also: #cairo_surface_t
*
* A recording surface is a surface that records all drawing operations at
* the highest level of the surface backend interface, (that is, the
* level of paint, mask, stroke, fill, and show_text_glyphs). The recording
* surface can then be "replayed" against any target surface by using it
* as a source surface.
*
* If you want to replay a surface so that the results in target will be
* identical to the results that would have been obtained if the original
* operations applied to the recording surface had instead been applied to the
* target surface, you can use code like this:
* <informalexample><programlisting>
* cairo_t *cr;
*
* cr = cairo_create (target);
* cairo_set_source_surface (cr, recording_surface, 0.0, 0.0);
* cairo_paint (cr);
* cairo_destroy (cr);
* </programlisting></informalexample>
*
* A recording surface is logically unbounded, i.e. it has no implicit constraint
* on the size of the drawing surface. However, in practice this is rarely
* useful as you wish to replay against a particular target surface with
* known bounds. For this case, it is more efficient to specify the target
* extents to the recording surface upon creation.
*
* The recording phase of the recording surface is careful to snapshot all
* necessary objects (paths, patterns, etc.), in order to achieve
* accurate replay. The efficiency of the recording surface could be
* improved by improving the implementation of snapshot for the
* various objects. For example, it would be nice to have a
* copy-on-write implementation for _cairo_surface_snapshot.
*/
 
#include "cairoint.h"
#include "cairo-analysis-surface-private.h"
#include "cairo-clip-private.h"
#include "cairo-error-private.h"
#include "cairo-recording-surface-private.h"
#include "cairo-surface-wrapper-private.h"
 
typedef enum {
CAIRO_RECORDING_REPLAY,
CAIRO_RECORDING_CREATE_REGIONS
} cairo_recording_replay_type_t;
 
static const cairo_surface_backend_t cairo_recording_surface_backend;
 
/**
* CAIRO_HAS_RECORDING_SURFACE:
*
* Defined if the recording surface backend is available.
* The recording surface backend is always built in.
* This macro was added for completeness in cairo 1.10.
*
* Since: 1.10
*/
 
/* Currently all recording surfaces do have a size which should be passed
* in as the maximum size of any target surface against which the
* recording-surface will ever be replayed.
*
* XXX: The naming of "pixels" in the size here is a misnomer. It's
* actually a size in whatever device-space units are desired (again,
* according to the intended replay target).
*/
 
/**
* cairo_recording_surface_create:
* @content: the content of the recording surface
* @extents: the extents to record in pixels, can be %NULL to record
* unbounded operations.
*
* Creates a recording-surface which can be used to record all drawing operations
* at the highest level (that is, the level of paint, mask, stroke, fill
* and show_text_glyphs). The recording surface can then be "replayed" against
* any target surface by using it as a source to drawing operations.
*
* The recording phase of the recording surface is careful to snapshot all
* necessary objects (paths, patterns, etc.), in order to achieve
* accurate replay.
*
* Return value: a pointer to the newly created surface. The caller
* owns the surface and should call cairo_surface_destroy() when done
* with it.
*
* Since: 1.10
**/
cairo_surface_t *
cairo_recording_surface_create (cairo_content_t content,
const cairo_rectangle_t *extents)
{
cairo_recording_surface_t *recording_surface;
cairo_status_t status;
 
recording_surface = malloc (sizeof (cairo_recording_surface_t));
if (unlikely (recording_surface == NULL))
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
 
_cairo_surface_init (&recording_surface->base,
&cairo_recording_surface_backend,
NULL, /* device */
content);
 
recording_surface->content = content;
 
recording_surface->unbounded = TRUE;
_cairo_clip_init (&recording_surface->clip);
 
/* unbounded -> 'infinite' extents */
if (extents != NULL) {
recording_surface->extents_pixels = *extents;
 
/* XXX check for overflow */
recording_surface->extents.x = floor (extents->x);
recording_surface->extents.y = floor (extents->y);
recording_surface->extents.width = ceil (extents->x + extents->width) - recording_surface->extents.x;
recording_surface->extents.height = ceil (extents->y + extents->height) - recording_surface->extents.y;
 
status = _cairo_clip_rectangle (&recording_surface->clip,
&recording_surface->extents);
if (unlikely (status)) {
free (recording_surface);
return _cairo_surface_create_in_error (status);
}
 
recording_surface->unbounded = FALSE;
}
 
_cairo_array_init (&recording_surface->commands, sizeof (cairo_command_t *));
 
recording_surface->replay_start_idx = 0;
recording_surface->base.is_clear = TRUE;
 
return &recording_surface->base;
}
slim_hidden_def (cairo_recording_surface_create);
 
static cairo_surface_t *
_cairo_recording_surface_create_similar (void *abstract_surface,
cairo_content_t content,
int width,
int height)
{
cairo_rectangle_t extents;
extents.x = extents.y = 0;
extents.width = width;
extents.height = height;
return cairo_recording_surface_create (content, &extents);
}
 
static cairo_status_t
_cairo_recording_surface_finish (void *abstract_surface)
{
cairo_recording_surface_t *recording_surface = abstract_surface;
cairo_command_t **elements;
int i, num_elements;
 
num_elements = recording_surface->commands.num_elements;
elements = _cairo_array_index (&recording_surface->commands, 0);
for (i = 0; i < num_elements; i++) {
cairo_command_t *command = elements[i];
 
switch (command->header.type) {
case CAIRO_COMMAND_PAINT:
_cairo_pattern_fini (&command->paint.source.base);
break;
 
case CAIRO_COMMAND_MASK:
_cairo_pattern_fini (&command->mask.source.base);
_cairo_pattern_fini (&command->mask.mask.base);
break;
 
case CAIRO_COMMAND_STROKE:
_cairo_pattern_fini (&command->stroke.source.base);
_cairo_path_fixed_fini (&command->stroke.path);
_cairo_stroke_style_fini (&command->stroke.style);
break;
 
case CAIRO_COMMAND_FILL:
_cairo_pattern_fini (&command->fill.source.base);
_cairo_path_fixed_fini (&command->fill.path);
break;
 
case CAIRO_COMMAND_SHOW_TEXT_GLYPHS:
_cairo_pattern_fini (&command->show_text_glyphs.source.base);
free (command->show_text_glyphs.utf8);
free (command->show_text_glyphs.glyphs);
free (command->show_text_glyphs.clusters);
cairo_scaled_font_destroy (command->show_text_glyphs.scaled_font);
break;
 
default:
ASSERT_NOT_REACHED;
}
 
_cairo_clip_fini (&command->header.clip);
free (command);
}
 
_cairo_array_fini (&recording_surface->commands);
_cairo_clip_fini (&recording_surface->clip);
 
return CAIRO_STATUS_SUCCESS;
}
 
static cairo_status_t
_cairo_recording_surface_acquire_source_image (void *abstract_surface,
cairo_image_surface_t **image_out,
void **image_extra)
{
cairo_status_t status;
cairo_recording_surface_t *surface = abstract_surface;
cairo_surface_t *image;
 
image = _cairo_surface_has_snapshot (&surface->base,
&_cairo_image_surface_backend);
if (image != NULL) {
*image_out = (cairo_image_surface_t *) cairo_surface_reference (image);
*image_extra = NULL;
return CAIRO_STATUS_SUCCESS;
}
 
image = _cairo_image_surface_create_with_content (surface->content,
surface->extents.width,
surface->extents.height);
if (unlikely (image->status))
return image->status;
 
cairo_surface_set_device_offset (image,
-surface->extents.x,
-surface->extents.y);
 
status = _cairo_recording_surface_replay (&surface->base, image);
if (unlikely (status)) {
cairo_surface_destroy (image);
return status;
}
 
_cairo_surface_attach_snapshot (&surface->base, image, NULL);
 
*image_out = (cairo_image_surface_t *) image;
*image_extra = NULL;
return CAIRO_STATUS_SUCCESS;
}
 
static void
_cairo_recording_surface_release_source_image (void *abstract_surface,
cairo_image_surface_t *image,
void *image_extra)
{
cairo_surface_destroy (&image->base);
}
 
static cairo_status_t
_command_init (cairo_recording_surface_t *recording_surface,
cairo_command_header_t *command,
cairo_command_type_t type,
cairo_operator_t op,
cairo_clip_t *clip)
{
cairo_status_t status = CAIRO_STATUS_SUCCESS;
 
command->type = type;
command->op = op;
command->region = CAIRO_RECORDING_REGION_ALL;
_cairo_clip_init_copy (&command->clip, clip);
if (recording_surface->clip.path != NULL)
status = _cairo_clip_apply_clip (&command->clip, &recording_surface->clip);
 
return status;
}
 
static cairo_int_status_t
_cairo_recording_surface_paint (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_clip_t *clip)
{
cairo_status_t status;
cairo_recording_surface_t *recording_surface = abstract_surface;
cairo_command_paint_t *command;
 
command = malloc (sizeof (cairo_command_paint_t));
if (unlikely (command == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
status = _command_init (recording_surface,
&command->header, CAIRO_COMMAND_PAINT, op, clip);
if (unlikely (status))
goto CLEANUP_COMMAND;
 
status = _cairo_pattern_init_snapshot (&command->source.base, source);
if (unlikely (status))
goto CLEANUP_COMMAND;
 
status = _cairo_array_append (&recording_surface->commands, &command);
if (unlikely (status))
goto CLEANUP_SOURCE;
 
/* An optimisation that takes care to not replay what was done
* before surface is cleared. We don't erase recorded commands
* since we may have earlier snapshots of this surface. */
if (op == CAIRO_OPERATOR_CLEAR && clip == NULL)
recording_surface->replay_start_idx = recording_surface->commands.num_elements;
 
return CAIRO_STATUS_SUCCESS;
 
CLEANUP_SOURCE:
_cairo_pattern_fini (&command->source.base);
CLEANUP_COMMAND:
_cairo_clip_fini (&command->header.clip);
free (command);
return status;
}
 
static cairo_int_status_t
_cairo_recording_surface_mask (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_pattern_t *mask,
cairo_clip_t *clip)
{
cairo_status_t status;
cairo_recording_surface_t *recording_surface = abstract_surface;
cairo_command_mask_t *command;
 
command = malloc (sizeof (cairo_command_mask_t));
if (unlikely (command == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
status = _command_init (recording_surface,
&command->header, CAIRO_COMMAND_MASK, op, clip);
if (unlikely (status))
goto CLEANUP_COMMAND;
 
status = _cairo_pattern_init_snapshot (&command->source.base, source);
if (unlikely (status))
goto CLEANUP_COMMAND;
 
status = _cairo_pattern_init_snapshot (&command->mask.base, mask);
if (unlikely (status))
goto CLEANUP_SOURCE;
 
status = _cairo_array_append (&recording_surface->commands, &command);
if (unlikely (status))
goto CLEANUP_MASK;
 
return CAIRO_STATUS_SUCCESS;
 
CLEANUP_MASK:
_cairo_pattern_fini (&command->mask.base);
CLEANUP_SOURCE:
_cairo_pattern_fini (&command->source.base);
CLEANUP_COMMAND:
_cairo_clip_fini (&command->header.clip);
free (command);
return status;
}
 
static cairo_int_status_t
_cairo_recording_surface_stroke (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_path_fixed_t *path,
const cairo_stroke_style_t *style,
const cairo_matrix_t *ctm,
const cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
cairo_clip_t *clip)
{
cairo_status_t status;
cairo_recording_surface_t *recording_surface = abstract_surface;
cairo_command_stroke_t *command;
 
command = malloc (sizeof (cairo_command_stroke_t));
if (unlikely (command == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
status = _command_init (recording_surface,
&command->header, CAIRO_COMMAND_STROKE, op, clip);
if (unlikely (status))
goto CLEANUP_COMMAND;
 
status = _cairo_pattern_init_snapshot (&command->source.base, source);
if (unlikely (status))
goto CLEANUP_COMMAND;
 
status = _cairo_path_fixed_init_copy (&command->path, path);
if (unlikely (status))
goto CLEANUP_SOURCE;
 
status = _cairo_stroke_style_init_copy (&command->style, style);
if (unlikely (status))
goto CLEANUP_PATH;
 
command->ctm = *ctm;
command->ctm_inverse = *ctm_inverse;
command->tolerance = tolerance;
command->antialias = antialias;
 
status = _cairo_array_append (&recording_surface->commands, &command);
if (unlikely (status))
goto CLEANUP_STYLE;
 
return CAIRO_STATUS_SUCCESS;
 
CLEANUP_STYLE:
_cairo_stroke_style_fini (&command->style);
CLEANUP_PATH:
_cairo_path_fixed_fini (&command->path);
CLEANUP_SOURCE:
_cairo_pattern_fini (&command->source.base);
CLEANUP_COMMAND:
_cairo_clip_fini (&command->header.clip);
free (command);
return status;
}
 
static cairo_int_status_t
_cairo_recording_surface_fill (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias,
cairo_clip_t *clip)
{
cairo_status_t status;
cairo_recording_surface_t *recording_surface = abstract_surface;
cairo_command_fill_t *command;
 
command = malloc (sizeof (cairo_command_fill_t));
if (unlikely (command == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
status =_command_init (recording_surface,
&command->header, CAIRO_COMMAND_FILL, op, clip);
if (unlikely (status))
goto CLEANUP_COMMAND;
 
status = _cairo_pattern_init_snapshot (&command->source.base, source);
if (unlikely (status))
goto CLEANUP_COMMAND;
 
status = _cairo_path_fixed_init_copy (&command->path, path);
if (unlikely (status))
goto CLEANUP_SOURCE;
 
command->fill_rule = fill_rule;
command->tolerance = tolerance;
command->antialias = antialias;
 
status = _cairo_array_append (&recording_surface->commands, &command);
if (unlikely (status))
goto CLEANUP_PATH;
 
return CAIRO_STATUS_SUCCESS;
 
CLEANUP_PATH:
_cairo_path_fixed_fini (&command->path);
CLEANUP_SOURCE:
_cairo_pattern_fini (&command->source.base);
CLEANUP_COMMAND:
_cairo_clip_fini (&command->header.clip);
free (command);
return status;
}
 
static cairo_bool_t
_cairo_recording_surface_has_show_text_glyphs (void *abstract_surface)
{
return TRUE;
}
 
static cairo_int_status_t
_cairo_recording_surface_show_text_glyphs (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const char *utf8,
int utf8_len,
cairo_glyph_t *glyphs,
int num_glyphs,
const cairo_text_cluster_t *clusters,
int num_clusters,
cairo_text_cluster_flags_t cluster_flags,
cairo_scaled_font_t *scaled_font,
cairo_clip_t *clip)
{
cairo_status_t status;
cairo_recording_surface_t *recording_surface = abstract_surface;
cairo_command_show_text_glyphs_t *command;
 
command = malloc (sizeof (cairo_command_show_text_glyphs_t));
if (unlikely (command == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
status = _command_init (recording_surface,
&command->header, CAIRO_COMMAND_SHOW_TEXT_GLYPHS,
op, clip);
if (unlikely (status))
goto CLEANUP_COMMAND;
 
status = _cairo_pattern_init_snapshot (&command->source.base, source);
if (unlikely (status))
goto CLEANUP_COMMAND;
 
command->utf8 = NULL;
command->utf8_len = utf8_len;
command->glyphs = NULL;
command->num_glyphs = num_glyphs;
command->clusters = NULL;
command->num_clusters = num_clusters;
 
if (utf8_len) {
command->utf8 = malloc (utf8_len);
if (unlikely (command->utf8 == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto CLEANUP_ARRAYS;
}
memcpy (command->utf8, utf8, utf8_len);
}
if (num_glyphs) {
command->glyphs = _cairo_malloc_ab (num_glyphs, sizeof (glyphs[0]));
if (unlikely (command->glyphs == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto CLEANUP_ARRAYS;
}
memcpy (command->glyphs, glyphs, sizeof (glyphs[0]) * num_glyphs);
}
if (num_clusters) {
command->clusters = _cairo_malloc_ab (num_clusters, sizeof (clusters[0]));
if (unlikely (command->clusters == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto CLEANUP_ARRAYS;
}
memcpy (command->clusters, clusters, sizeof (clusters[0]) * num_clusters);
}
 
command->cluster_flags = cluster_flags;
 
command->scaled_font = cairo_scaled_font_reference (scaled_font);
 
status = _cairo_array_append (&recording_surface->commands, &command);
if (unlikely (status))
goto CLEANUP_SCALED_FONT;
 
return CAIRO_STATUS_SUCCESS;
 
CLEANUP_SCALED_FONT:
cairo_scaled_font_destroy (command->scaled_font);
CLEANUP_ARRAYS:
free (command->utf8);
free (command->glyphs);
free (command->clusters);
 
_cairo_pattern_fini (&command->source.base);
CLEANUP_COMMAND:
_cairo_clip_fini (&command->header.clip);
free (command);
return status;
}
 
/**
* _cairo_recording_surface_snapshot
* @surface: a #cairo_surface_t which must be a recording surface
*
* Make an immutable copy of @surface. It is an error to call a
* surface-modifying function on the result of this function.
*
* The caller owns the return value and should call
* cairo_surface_destroy() when finished with it. This function will not
* return %NULL, but will return a nil surface instead.
*
* Return value: The snapshot surface.
**/
static cairo_surface_t *
_cairo_recording_surface_snapshot (void *abstract_other)
{
cairo_recording_surface_t *other = abstract_other;
cairo_recording_surface_t *recording_surface;
cairo_status_t status;
 
recording_surface = malloc (sizeof (cairo_recording_surface_t));
if (unlikely (recording_surface == NULL))
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
 
_cairo_surface_init (&recording_surface->base,
&cairo_recording_surface_backend,
NULL, /* device */
other->base.content);
 
recording_surface->extents_pixels = other->extents_pixels;
recording_surface->extents = other->extents;
recording_surface->unbounded = other->unbounded;
recording_surface->content = other->content;
 
_cairo_clip_init_copy (&recording_surface->clip, &other->clip);
 
/* XXX We should in theory be able to reuse the original array, but we
* need to handle reference cycles during subsurface and self-copy.
*/
recording_surface->replay_start_idx = 0;
recording_surface->base.is_clear = TRUE;
 
_cairo_array_init (&recording_surface->commands, sizeof (cairo_command_t *));
status = _cairo_recording_surface_replay (&other->base, &recording_surface->base);
if (unlikely (status)) {
cairo_surface_destroy (&recording_surface->base);
return _cairo_surface_create_in_error (status);
}
 
return &recording_surface->base;
}
 
static cairo_bool_t
_cairo_recording_surface_get_extents (void *abstract_surface,
cairo_rectangle_int_t *rectangle)
{
cairo_recording_surface_t *surface = abstract_surface;
 
if (surface->unbounded)
return FALSE;
 
*rectangle = surface->extents;
return TRUE;
}
 
/**
* _cairo_surface_is_recording:
* @surface: a #cairo_surface_t
*
* Checks if a surface is a #cairo_recording_surface_t
*
* Return value: %TRUE if the surface is a recording surface
**/
cairo_bool_t
_cairo_surface_is_recording (const cairo_surface_t *surface)
{
return surface->backend == &cairo_recording_surface_backend;
}
 
static const cairo_surface_backend_t cairo_recording_surface_backend = {
CAIRO_SURFACE_TYPE_RECORDING,
_cairo_recording_surface_create_similar,
_cairo_recording_surface_finish,
_cairo_recording_surface_acquire_source_image,
_cairo_recording_surface_release_source_image,
NULL, /* acquire_dest_image */
NULL, /* release_dest_image */
NULL, /* clone_similar */
NULL, /* composite */
NULL, /* fill_rectangles */
NULL, /* composite_trapezoids */
NULL, /* create_span_renderer */
NULL, /* check_span_renderer */
NULL, /* copy_page */
NULL, /* show_page */
_cairo_recording_surface_get_extents,
NULL, /* old_show_glyphs */
NULL, /* get_font_options */
NULL, /* flush */
NULL, /* mark_dirty_rectangle */
NULL, /* scaled_font_fini */
NULL, /* scaled_glyph_fini */
 
/* Here are the 5 basic drawing operations, (which are in some
* sense the only things that cairo_recording_surface should need to
* implement). However, we implement the more generic show_text_glyphs
* instead of show_glyphs. One or the other is eough. */
 
_cairo_recording_surface_paint,
_cairo_recording_surface_mask,
_cairo_recording_surface_stroke,
_cairo_recording_surface_fill,
NULL,
 
_cairo_recording_surface_snapshot,
 
NULL, /* is_similar */
NULL, /* fill_stroke */
NULL, /* create_solid_pattern_surface */
NULL, /* can_repaint_solid_pattern_surface */
 
_cairo_recording_surface_has_show_text_glyphs,
_cairo_recording_surface_show_text_glyphs
};
 
cairo_int_status_t
_cairo_recording_surface_get_path (cairo_surface_t *surface,
cairo_path_fixed_t *path)
{
cairo_recording_surface_t *recording_surface;
cairo_command_t **elements;
int i, num_elements;
cairo_int_status_t status;
 
if (surface->status)
return surface->status;
 
recording_surface = (cairo_recording_surface_t *) surface;
status = CAIRO_STATUS_SUCCESS;
 
num_elements = recording_surface->commands.num_elements;
elements = _cairo_array_index (&recording_surface->commands, 0);
for (i = recording_surface->replay_start_idx; i < num_elements; i++) {
cairo_command_t *command = elements[i];
 
switch (command->header.type) {
case CAIRO_COMMAND_PAINT:
case CAIRO_COMMAND_MASK:
status = CAIRO_INT_STATUS_UNSUPPORTED;
break;
 
case CAIRO_COMMAND_STROKE:
{
cairo_traps_t traps;
 
_cairo_traps_init (&traps);
 
/* XXX call cairo_stroke_to_path() when that is implemented */
status = _cairo_path_fixed_stroke_to_traps (&command->stroke.path,
&command->stroke.style,
&command->stroke.ctm,
&command->stroke.ctm_inverse,
command->stroke.tolerance,
&traps);
 
if (status == CAIRO_STATUS_SUCCESS)
status = _cairo_traps_path (&traps, path);
 
_cairo_traps_fini (&traps);
break;
}
case CAIRO_COMMAND_FILL:
{
status = _cairo_path_fixed_append (path,
&command->fill.path, CAIRO_DIRECTION_FORWARD,
0, 0);
break;
}
case CAIRO_COMMAND_SHOW_TEXT_GLYPHS:
{
status = _cairo_scaled_font_glyph_path (command->show_text_glyphs.scaled_font,
command->show_text_glyphs.glyphs,
command->show_text_glyphs.num_glyphs,
path);
break;
}
 
default:
ASSERT_NOT_REACHED;
}
 
if (unlikely (status))
break;
}
 
return _cairo_surface_set_error (surface, status);
}
 
#define _clip(c) ((c)->header.clip.path ? &(c)->header.clip : NULL)
static cairo_status_t
_cairo_recording_surface_replay_internal (cairo_surface_t *surface,
const cairo_rectangle_int_t *surface_extents,
cairo_surface_t *target,
cairo_recording_replay_type_t type,
cairo_recording_region_type_t region)
{
cairo_recording_surface_t *recording_surface;
cairo_command_t **elements;
int i, num_elements;
cairo_int_status_t status;
cairo_surface_wrapper_t wrapper;
 
if (unlikely (surface->status))
return surface->status;
 
if (unlikely (target->status))
return target->status;
 
if (unlikely (surface->finished))
return _cairo_error (CAIRO_STATUS_SURFACE_FINISHED);
 
if (surface->is_clear)
return CAIRO_STATUS_SUCCESS;
 
assert (_cairo_surface_is_recording (surface));
 
_cairo_surface_wrapper_init (&wrapper, target);
_cairo_surface_wrapper_set_extents (&wrapper, surface_extents);
 
recording_surface = (cairo_recording_surface_t *) surface;
status = CAIRO_STATUS_SUCCESS;
 
num_elements = recording_surface->commands.num_elements;
elements = _cairo_array_index (&recording_surface->commands, 0);
 
for (i = recording_surface->replay_start_idx; i < num_elements; i++) {
cairo_command_t *command = elements[i];
 
if (type == CAIRO_RECORDING_REPLAY && region != CAIRO_RECORDING_REGION_ALL) {
if (command->header.region != region)
continue;
}
 
switch (command->header.type) {
case CAIRO_COMMAND_PAINT:
status = _cairo_surface_wrapper_paint (&wrapper,
command->header.op,
&command->paint.source.base,
_clip (command));
break;
 
case CAIRO_COMMAND_MASK:
status = _cairo_surface_wrapper_mask (&wrapper,
command->header.op,
&command->mask.source.base,
&command->mask.mask.base,
_clip (command));
break;
 
case CAIRO_COMMAND_STROKE:
{
status = _cairo_surface_wrapper_stroke (&wrapper,
command->header.op,
&command->stroke.source.base,
&command->stroke.path,
&command->stroke.style,
&command->stroke.ctm,
&command->stroke.ctm_inverse,
command->stroke.tolerance,
command->stroke.antialias,
_clip (command));
break;
}
case CAIRO_COMMAND_FILL:
{
cairo_command_t *stroke_command;
 
stroke_command = NULL;
if (type != CAIRO_RECORDING_CREATE_REGIONS && i < num_elements - 1)
stroke_command = elements[i + 1];
 
if (stroke_command != NULL &&
type == CAIRO_RECORDING_REPLAY &&
region != CAIRO_RECORDING_REGION_ALL)
{
if (stroke_command->header.region != region)
stroke_command = NULL;
}
 
if (stroke_command != NULL &&
stroke_command->header.type == CAIRO_COMMAND_STROKE &&
_cairo_path_fixed_is_equal (&command->fill.path,
&stroke_command->stroke.path))
{
status = _cairo_surface_wrapper_fill_stroke (&wrapper,
command->header.op,
&command->fill.source.base,
command->fill.fill_rule,
command->fill.tolerance,
command->fill.antialias,
&command->fill.path,
stroke_command->header.op,
&stroke_command->stroke.source.base,
&stroke_command->stroke.style,
&stroke_command->stroke.ctm,
&stroke_command->stroke.ctm_inverse,
stroke_command->stroke.tolerance,
stroke_command->stroke.antialias,
_clip (command));
i++;
}
else
{
status = _cairo_surface_wrapper_fill (&wrapper,
command->header.op,
&command->fill.source.base,
&command->fill.path,
command->fill.fill_rule,
command->fill.tolerance,
command->fill.antialias,
_clip (command));
}
break;
}
case CAIRO_COMMAND_SHOW_TEXT_GLYPHS:
{
cairo_glyph_t *glyphs = command->show_text_glyphs.glyphs;
cairo_glyph_t *glyphs_copy;
int num_glyphs = command->show_text_glyphs.num_glyphs;
 
/* show_text_glyphs is special because _cairo_surface_show_text_glyphs is allowed
* to modify the glyph array that's passed in. We must always
* copy the array before handing it to the backend.
*/
glyphs_copy = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t));
if (unlikely (glyphs_copy == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
break;
}
 
memcpy (glyphs_copy, glyphs, sizeof (cairo_glyph_t) * num_glyphs);
 
status = _cairo_surface_wrapper_show_text_glyphs (&wrapper,
command->header.op,
&command->show_text_glyphs.source.base,
command->show_text_glyphs.utf8, command->show_text_glyphs.utf8_len,
glyphs_copy, num_glyphs,
command->show_text_glyphs.clusters, command->show_text_glyphs.num_clusters,
command->show_text_glyphs.cluster_flags,
command->show_text_glyphs.scaled_font,
_clip (command));
free (glyphs_copy);
break;
}
default:
ASSERT_NOT_REACHED;
}
 
if (type == CAIRO_RECORDING_CREATE_REGIONS) {
if (status == CAIRO_STATUS_SUCCESS) {
command->header.region = CAIRO_RECORDING_REGION_NATIVE;
} else if (status == CAIRO_INT_STATUS_IMAGE_FALLBACK) {
command->header.region = CAIRO_RECORDING_REGION_IMAGE_FALLBACK;
status = CAIRO_STATUS_SUCCESS;
} else {
assert (_cairo_status_is_error (status));
}
}
 
if (unlikely (status))
break;
}
 
/* free up any caches */
for (i = recording_surface->replay_start_idx; i < num_elements; i++) {
cairo_command_t *command = elements[i];
 
_cairo_clip_drop_cache (&command->header.clip);
}
 
_cairo_surface_wrapper_fini (&wrapper);
 
return _cairo_surface_set_error (surface, status);
}
 
/**
* _cairo_recording_surface_replay:
* @surface: the #cairo_recording_surface_t
* @target: a target #cairo_surface_t onto which to replay the operations
* @width_pixels: width of the surface, in pixels
* @height_pixels: height of the surface, in pixels
*
* A recording surface can be "replayed" against any target surface,
* after which the results in target will be identical to the results
* that would have been obtained if the original operations applied to
* the recording surface had instead been applied to the target surface.
**/
cairo_status_t
_cairo_recording_surface_replay (cairo_surface_t *surface,
cairo_surface_t *target)
{
return _cairo_recording_surface_replay_internal (surface, NULL,
target,
CAIRO_RECORDING_REPLAY,
CAIRO_RECORDING_REGION_ALL);
}
 
/* Replay recording to surface. When the return status of each operation is
* one of %CAIRO_STATUS_SUCCESS, %CAIRO_INT_STATUS_UNSUPPORTED, or
* %CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY the status of each operation
* will be stored in the recording surface. Any other status will abort the
* replay and return the status.
*/
cairo_status_t
_cairo_recording_surface_replay_and_create_regions (cairo_surface_t *surface,
cairo_surface_t *target)
{
return _cairo_recording_surface_replay_internal (surface, NULL,
target,
CAIRO_RECORDING_CREATE_REGIONS,
CAIRO_RECORDING_REGION_ALL);
}
 
cairo_status_t
_cairo_recording_surface_replay_region (cairo_surface_t *surface,
const cairo_rectangle_int_t *surface_extents,
cairo_surface_t *target,
cairo_recording_region_type_t region)
{
return _cairo_recording_surface_replay_internal (surface, surface_extents,
target,
CAIRO_RECORDING_REPLAY,
region);
}
 
static cairo_status_t
_recording_surface_get_ink_bbox (cairo_recording_surface_t *surface,
cairo_box_t *bbox,
const cairo_matrix_t *transform)
{
cairo_surface_t *null_surface;
cairo_surface_t *analysis_surface;
cairo_status_t status;
 
null_surface = _cairo_null_surface_create (surface->content);
analysis_surface = _cairo_analysis_surface_create (null_surface);
cairo_surface_destroy (null_surface);
 
status = analysis_surface->status;
if (unlikely (status))
return status;
 
if (transform != NULL)
_cairo_analysis_surface_set_ctm (analysis_surface, transform);
 
status = _cairo_recording_surface_replay (&surface->base, analysis_surface);
_cairo_analysis_surface_get_bounding_box (analysis_surface, bbox);
cairo_surface_destroy (analysis_surface);
 
return status;
}
 
/**
* cairo_recording_surface_ink_extents:
* @surface: a #cairo_recording_surface_t
* @x0: the x-coordinate of the top-left of the ink bounding box
* @y0: the y-coordinate of the top-left of the ink bounding box
* @width: the width of the ink bounding box
* @height: the height of the ink bounding box
*
* Measures the extents of the operations stored within the recording-surface.
* This is useful to compute the required size of an image surface (or
* equivalent) into which to replay the full sequence of drawing operations.
*
* Since: 1.10
**/
void
cairo_recording_surface_ink_extents (cairo_surface_t *surface,
double *x0,
double *y0,
double *width,
double *height)
{
cairo_status_t status;
cairo_box_t bbox;
 
memset (&bbox, 0, sizeof (bbox));
 
if (! _cairo_surface_is_recording (surface)) {
_cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
goto DONE;
}
 
status = _recording_surface_get_ink_bbox ((cairo_recording_surface_t *) surface,
&bbox,
NULL);
if (unlikely (status))
status = _cairo_surface_set_error (surface, status);
 
DONE:
if (x0)
*x0 = _cairo_fixed_to_double (bbox.p1.x);
if (y0)
*y0 = _cairo_fixed_to_double (bbox.p1.y);
if (width)
*width = _cairo_fixed_to_double (bbox.p2.x - bbox.p1.x);
if (height)
*height = _cairo_fixed_to_double (bbox.p2.y - bbox.p1.y);
}
 
cairo_status_t
_cairo_recording_surface_get_bbox (cairo_recording_surface_t *surface,
cairo_box_t *bbox,
const cairo_matrix_t *transform)
{
if (! surface->unbounded) {
_cairo_box_from_rectangle (bbox, &surface->extents);
if (transform != NULL)
_cairo_matrix_transform_bounding_box_fixed (transform, bbox, NULL);
 
return CAIRO_STATUS_SUCCESS;
}
 
return _recording_surface_get_ink_bbox (surface, bbox, transform);
}
/programs/develop/libraries/cairo/src/cairo-rectangle.c
0,0 → 1,248
/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2002 University of Southern California
* Copyright © 2005 Red Hat, Inc.
* Copyright © 2006 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
*/
 
#include "cairoint.h"
 
cairo_private void
_cairo_box_from_doubles (cairo_box_t *box,
double *x1, double *y1,
double *x2, double *y2)
{
box->p1.x = _cairo_fixed_from_double (*x1);
box->p1.y = _cairo_fixed_from_double (*y1);
box->p2.x = _cairo_fixed_from_double (*x2);
box->p2.y = _cairo_fixed_from_double (*y2);
}
 
cairo_private void
_cairo_box_to_doubles (const cairo_box_t *box,
double *x1, double *y1,
double *x2, double *y2)
{
*x1 = _cairo_fixed_to_double (box->p1.x);
*y1 = _cairo_fixed_to_double (box->p1.y);
*x2 = _cairo_fixed_to_double (box->p2.x);
*y2 = _cairo_fixed_to_double (box->p2.y);
}
 
void
_cairo_box_from_rectangle (cairo_box_t *box,
const cairo_rectangle_int_t *rect)
{
box->p1.x = _cairo_fixed_from_int (rect->x);
box->p1.y = _cairo_fixed_from_int (rect->y);
box->p2.x = _cairo_fixed_from_int (rect->x + rect->width);
box->p2.y = _cairo_fixed_from_int (rect->y + rect->height);
}
 
void
_cairo_boxes_get_extents (const cairo_box_t *boxes,
int num_boxes,
cairo_box_t *extents)
{
int n;
 
assert (num_boxes > 0);
*extents = *boxes;
 
for (n = 1; n < num_boxes; n++) {
if (boxes[n].p1.x < extents->p1.x)
extents->p1.x = boxes[n].p1.x;
if (boxes[n].p2.x > extents->p2.x)
extents->p2.x = boxes[n].p2.x;
 
if (boxes[n].p1.y < extents->p1.y)
extents->p1.y = boxes[n].p1.y;
if (boxes[n].p2.y > extents->p2.y)
extents->p2.y = boxes[n].p2.y;
}
}
 
/* XXX We currently have a confusing mix of boxes and rectangles as
* exemplified by this function. A #cairo_box_t is a rectangular area
* represented by the coordinates of the upper left and lower right
* corners, expressed in fixed point numbers. A #cairo_rectangle_int_t is
* also a rectangular area, but represented by the upper left corner
* and the width and the height, as integer numbers.
*
* This function converts a #cairo_box_t to a #cairo_rectangle_int_t by
* increasing the area to the nearest integer coordinates. We should
* standardize on #cairo_rectangle_fixed_t and #cairo_rectangle_int_t, and
* this function could be renamed to the more reasonable
* _cairo_rectangle_fixed_round.
*/
 
void
_cairo_box_round_to_rectangle (const cairo_box_t *box,
cairo_rectangle_int_t *rectangle)
{
rectangle->x = _cairo_fixed_integer_floor (box->p1.x);
rectangle->y = _cairo_fixed_integer_floor (box->p1.y);
rectangle->width = _cairo_fixed_integer_ceil (box->p2.x) - rectangle->x;
rectangle->height = _cairo_fixed_integer_ceil (box->p2.y) - rectangle->y;
}
 
cairo_bool_t
_cairo_rectangle_intersect (cairo_rectangle_int_t *dst,
const cairo_rectangle_int_t *src)
{
int x1, y1, x2, y2;
 
x1 = MAX (dst->x, src->x);
y1 = MAX (dst->y, src->y);
/* Beware the unsigned promotion, fortunately we have bits to spare
* as (CAIRO_RECT_INT_MAX - CAIRO_RECT_INT_MIN) < UINT_MAX
*/
x2 = MIN (dst->x + (int) dst->width, src->x + (int) src->width);
y2 = MIN (dst->y + (int) dst->height, src->y + (int) src->height);
 
if (x1 >= x2 || y1 >= y2) {
dst->x = 0;
dst->y = 0;
dst->width = 0;
dst->height = 0;
 
return FALSE;
} else {
dst->x = x1;
dst->y = y1;
dst->width = x2 - x1;
dst->height = y2 - y1;
 
return TRUE;
}
}
 
#define P1x (line->p1.x)
#define P1y (line->p1.y)
#define P2x (line->p2.x)
#define P2y (line->p2.y)
#define B1x (box->p1.x)
#define B1y (box->p1.y)
#define B2x (box->p2.x)
#define B2y (box->p2.y)
 
/*
* Check whether any part of line intersects box. This function essentially
* computes whether the ray starting at line->p1 in the direction of line->p2
* intersects the box before it reaches p2. Normally, this is done
* by dividing by the lengths of the line projected onto each axis. Because
* we're in fixed point, this function does a bit more work to avoid having to
* do the division -- we don't care about the actual intersection point, so
* it's of no interest to us.
*/
 
cairo_bool_t
_cairo_box_intersects_line_segment (cairo_box_t *box, cairo_line_t *line)
{
cairo_fixed_t t1=0, t2=0, t3=0, t4=0;
cairo_int64_t t1y, t2y, t3x, t4x;
 
cairo_fixed_t xlen, ylen;
 
if (_cairo_box_contains_point (box, &line->p1) ||
_cairo_box_contains_point (box, &line->p2))
return TRUE;
 
xlen = P2x - P1x;
ylen = P2y - P1y;
 
if (xlen) {
if (xlen > 0) {
t1 = B1x - P1x;
t2 = B2x - P1x;
} else {
t1 = P1x - B2x;
t2 = P1x - B1x;
xlen = - xlen;
}
 
if ((t1 < 0 || t1 > xlen) &&
(t2 < 0 || t2 > xlen))
return FALSE;
} else {
/* Fully vertical line -- check that X is in bounds */
if (P1x < B1x || P1x > B2x)
return FALSE;
}
 
if (ylen) {
if (ylen > 0) {
t3 = B1y - P1y;
t4 = B2y - P1y;
} else {
t3 = P1y - B2y;
t4 = P1y - B1y;
ylen = - ylen;
}
 
if ((t3 < 0 || t3 > ylen) &&
(t4 < 0 || t4 > ylen))
return FALSE;
} else {
/* Fully horizontal line -- check Y */
if (P1y < B1y || P1y > B2y)
return FALSE;
}
 
/* If we had a horizontal or vertical line, then it's already been checked */
if (P1x == P2x || P1y == P2y)
return TRUE;
 
/* Check overlap. Note that t1 < t2 and t3 < t4 here. */
t1y = _cairo_int32x32_64_mul (t1, ylen);
t2y = _cairo_int32x32_64_mul (t2, ylen);
t3x = _cairo_int32x32_64_mul (t3, xlen);
t4x = _cairo_int32x32_64_mul (t4, xlen);
 
if (_cairo_int64_lt(t1y, t4x) &&
_cairo_int64_lt(t3x, t2y))
return TRUE;
 
return FALSE;
}
 
cairo_bool_t
_cairo_box_contains_point (cairo_box_t *box, const cairo_point_t *point)
{
if (point->x < box->p1.x || point->x > box->p2.x ||
point->y < box->p1.y || point->y > box->p2.y)
return FALSE;
return TRUE;
}
/programs/develop/libraries/cairo/src/cairo-rectangular-scan-converter.c
0,0 → 1,723
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2009 Intel Corporation
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* Contributor(s):
* Chris Wilson <chris@chris-wilson.co.uk>
*/
 
#include "cairoint.h"
 
#include "cairo-combsort-private.h"
#include "cairo-error-private.h"
#include "cairo-freelist-private.h"
#include "cairo-list-private.h"
#include "cairo-spans-private.h"
 
#include <setjmp.h>
 
typedef struct _rectangle {
struct _rectangle *next, *prev;
cairo_fixed_t left, right;
cairo_fixed_t top, bottom;
int32_t top_y, bottom_y;
int dir;
} rectangle_t;
 
#define UNROLL3(x) x x x
 
/* the parent is always given by index/2 */
#define PQ_PARENT_INDEX(i) ((i) >> 1)
#define PQ_FIRST_ENTRY 1
 
/* left and right children are index * 2 and (index * 2) +1 respectively */
#define PQ_LEFT_CHILD_INDEX(i) ((i) << 1)
 
typedef struct _pqueue {
int size, max_size;
 
rectangle_t **elements;
rectangle_t *elements_embedded[1024];
} pqueue_t;
 
typedef struct {
rectangle_t **start;
pqueue_t stop;
rectangle_t head, tail;
rectangle_t *insert_cursor;
int32_t current_y;
int32_t xmin, xmax;
 
struct coverage {
struct cell {
struct cell *prev, *next;
int x, covered, uncovered;
} head, tail, *cursor;
unsigned int count;
cairo_freepool_t pool;
} coverage;
 
cairo_half_open_span_t spans_stack[CAIRO_STACK_ARRAY_LENGTH (cairo_half_open_span_t)];
cairo_half_open_span_t *spans;
unsigned int num_spans;
unsigned int size_spans;
 
jmp_buf jmpbuf;
} sweep_line_t;
 
static inline int
rectangle_compare_start (const rectangle_t *a,
const rectangle_t *b)
{
int cmp;
 
cmp = a->top_y - b->top_y;
if (cmp)
return cmp;
 
return a->left - b->left;
}
 
static inline int
rectangle_compare_stop (const rectangle_t *a,
const rectangle_t *b)
{
return a->bottom_y - b->bottom_y;
}
 
static inline void
pqueue_init (pqueue_t *pq)
{
pq->max_size = ARRAY_LENGTH (pq->elements_embedded);
pq->size = 0;
 
pq->elements = pq->elements_embedded;
pq->elements[PQ_FIRST_ENTRY] = NULL;
}
 
static inline void
pqueue_fini (pqueue_t *pq)
{
if (pq->elements != pq->elements_embedded)
free (pq->elements);
}
 
static cairo_bool_t
pqueue_grow (pqueue_t *pq)
{
rectangle_t **new_elements;
pq->max_size *= 2;
 
if (pq->elements == pq->elements_embedded) {
new_elements = _cairo_malloc_ab (pq->max_size,
sizeof (rectangle_t *));
if (unlikely (new_elements == NULL))
return FALSE;
 
memcpy (new_elements, pq->elements_embedded,
sizeof (pq->elements_embedded));
} else {
new_elements = _cairo_realloc_ab (pq->elements,
pq->max_size,
sizeof (rectangle_t *));
if (unlikely (new_elements == NULL))
return FALSE;
}
 
pq->elements = new_elements;
return TRUE;
}
 
static inline void
pqueue_push (sweep_line_t *sweep, rectangle_t *rectangle)
{
rectangle_t **elements;
int i, parent;
 
if (unlikely (sweep->stop.size + 1 == sweep->stop.max_size)) {
if (unlikely (! pqueue_grow (&sweep->stop)))
longjmp (sweep->jmpbuf,
_cairo_error (CAIRO_STATUS_NO_MEMORY));
}
 
elements = sweep->stop.elements;
for (i = ++sweep->stop.size;
i != PQ_FIRST_ENTRY &&
rectangle_compare_stop (rectangle,
elements[parent = PQ_PARENT_INDEX (i)]) < 0;
i = parent)
{
elements[i] = elements[parent];
}
 
elements[i] = rectangle;
}
 
static inline void
pqueue_pop (pqueue_t *pq)
{
rectangle_t **elements = pq->elements;
rectangle_t *tail;
int child, i;
 
tail = elements[pq->size--];
if (pq->size == 0) {
elements[PQ_FIRST_ENTRY] = NULL;
return;
}
 
for (i = PQ_FIRST_ENTRY;
(child = PQ_LEFT_CHILD_INDEX (i)) <= pq->size;
i = child)
{
if (child != pq->size &&
rectangle_compare_stop (elements[child+1],
elements[child]) < 0)
{
child++;
}
 
if (rectangle_compare_stop (elements[child], tail) >= 0)
break;
 
elements[i] = elements[child];
}
elements[i] = tail;
}
 
static inline rectangle_t *
peek_stop (sweep_line_t *sweep)
{
return sweep->stop.elements[PQ_FIRST_ENTRY];
}
 
CAIRO_COMBSORT_DECLARE (rectangle_sort, rectangle_t *, rectangle_compare_start)
 
static void
sweep_line_init (sweep_line_t *sweep)
{
sweep->head.left = INT_MIN;
sweep->head.next = &sweep->tail;
sweep->tail.left = INT_MAX;
sweep->tail.prev = &sweep->head;
sweep->insert_cursor = &sweep->tail;
 
_cairo_freepool_init (&sweep->coverage.pool, sizeof (struct cell));
 
sweep->spans = sweep->spans_stack;
sweep->size_spans = ARRAY_LENGTH (sweep->spans_stack);
 
sweep->coverage.head.prev = NULL;
sweep->coverage.head.x = INT_MIN;
sweep->coverage.tail.next = NULL;
sweep->coverage.tail.x = INT_MAX;
 
pqueue_init (&sweep->stop);
}
 
static void
sweep_line_fini (sweep_line_t *sweep)
{
_cairo_freepool_fini (&sweep->coverage.pool);
pqueue_fini (&sweep->stop);
 
if (sweep->spans != sweep->spans_stack)
free (sweep->spans);
}
 
static inline void
add_cell (sweep_line_t *sweep, int x, int covered, int uncovered)
{
struct cell *cell;
 
cell = sweep->coverage.cursor;
if (cell->x > x) {
do {
UNROLL3({
if (cell->prev->x < x)
break;
cell = cell->prev;
})
} while (TRUE);
} else {
if (cell->x == x)
goto found;
 
do {
UNROLL3({
cell = cell->next;
if (cell->x >= x)
break;
})
} while (TRUE);
}
 
if (x != cell->x) {
struct cell *c;
 
sweep->coverage.count++;
 
c = _cairo_freepool_alloc (&sweep->coverage.pool);
if (unlikely (c == NULL)) {
longjmp (sweep->jmpbuf,
_cairo_error (CAIRO_STATUS_NO_MEMORY));
}
 
cell->prev->next = c;
c->prev = cell->prev;
c->next = cell;
cell->prev = c;
 
c->x = x;
c->covered = 0;
c->uncovered = 0;
 
cell = c;
}
 
found:
cell->covered += covered;
cell->uncovered += uncovered;
sweep->coverage.cursor = cell;
}
 
static inline void
_active_edges_to_spans (sweep_line_t *sweep)
{
int32_t y = sweep->current_y;
rectangle_t *rectangle;
int coverage, prev_coverage;
int prev_x;
struct cell *cell;
 
sweep->num_spans = 0;
if (sweep->head.next == &sweep->tail)
return;
 
sweep->coverage.head.next = &sweep->coverage.tail;
sweep->coverage.tail.prev = &sweep->coverage.head;
sweep->coverage.cursor = &sweep->coverage.tail;
sweep->coverage.count = 0;
 
/* XXX cell coverage only changes when a rectangle appears or
* disappears. Try only modifying coverage at such times.
*/
for (rectangle = sweep->head.next;
rectangle != &sweep->tail;
rectangle = rectangle->next)
{
int height;
int frac, i;
 
if (y == rectangle->bottom_y) {
height = rectangle->bottom & CAIRO_FIXED_FRAC_MASK;
if (height == 0)
continue;
} else
height = CAIRO_FIXED_ONE;
if (y == rectangle->top_y)
height -= rectangle->top & CAIRO_FIXED_FRAC_MASK;
height *= rectangle->dir;
 
i = _cairo_fixed_integer_part (rectangle->left),
frac = _cairo_fixed_fractional_part (rectangle->left);
add_cell (sweep, i,
(CAIRO_FIXED_ONE-frac) * height,
frac * height);
 
i = _cairo_fixed_integer_part (rectangle->right),
frac = _cairo_fixed_fractional_part (rectangle->right);
add_cell (sweep, i,
-(CAIRO_FIXED_ONE-frac) * height,
-frac * height);
}
 
if (2*sweep->coverage.count >= sweep->size_spans) {
unsigned size;
 
size = sweep->size_spans;
while (size <= 2*sweep->coverage.count)
size <<= 1;
 
if (sweep->spans != sweep->spans_stack)
free (sweep->spans);
 
sweep->spans = _cairo_malloc_ab (size, sizeof (cairo_half_open_span_t));
if (unlikely (sweep->spans == NULL))
longjmp (sweep->jmpbuf, _cairo_error (CAIRO_STATUS_NO_MEMORY));
 
sweep->size_spans = size;
}
 
prev_coverage = coverage = 0;
prev_x = INT_MIN;
for (cell = sweep->coverage.head.next; cell != &sweep->coverage.tail; cell = cell->next) {
if (cell->x != prev_x && coverage != prev_coverage) {
int n = sweep->num_spans++;
sweep->spans[n].x = prev_x;
sweep->spans[n].coverage = coverage >> (CAIRO_FIXED_FRAC_BITS * 2 - 8);
sweep->spans[n].coverage -= sweep->spans[n].coverage >> 8;
prev_coverage = coverage;
}
 
coverage += cell->covered;
if (coverage != prev_coverage) {
int n = sweep->num_spans++;
sweep->spans[n].x = cell->x;
sweep->spans[n].coverage = coverage >> (CAIRO_FIXED_FRAC_BITS * 2 - 8);
sweep->spans[n].coverage -= sweep->spans[n].coverage >> 8;
prev_coverage = coverage;
}
coverage += cell->uncovered;
prev_x = cell->x + 1;
}
_cairo_freepool_reset (&sweep->coverage.pool);
 
if (sweep->num_spans) {
if (prev_x <= sweep->xmax) {
int n = sweep->num_spans++;
sweep->spans[n].x = prev_x;
sweep->spans[n].coverage = coverage;
}
 
if (coverage && prev_x < sweep->xmax) {
int n = sweep->num_spans++;
sweep->spans[n].x = sweep->xmax;
sweep->spans[n].coverage = 0;
}
}
}
 
static inline void
sweep_line_delete (sweep_line_t *sweep,
rectangle_t *rectangle)
{
if (sweep->insert_cursor == rectangle)
sweep->insert_cursor = rectangle->next;
 
rectangle->prev->next = rectangle->next;
rectangle->next->prev = rectangle->prev;
 
pqueue_pop (&sweep->stop);
}
 
static inline void
sweep_line_insert (sweep_line_t *sweep,
rectangle_t *rectangle)
{
rectangle_t *pos;
 
pos = sweep->insert_cursor;
if (pos->left != rectangle->left) {
if (pos->left > rectangle->left) {
do {
UNROLL3({
if (pos->prev->left < rectangle->left)
break;
pos = pos->prev;
})
} while (TRUE);
} else {
do {
UNROLL3({
pos = pos->next;
if (pos->left >= rectangle->left)
break;
});
} while (TRUE);
}
}
 
pos->prev->next = rectangle;
rectangle->prev = pos->prev;
rectangle->next = pos;
pos->prev = rectangle;
sweep->insert_cursor = rectangle;
 
pqueue_push (sweep, rectangle);
}
 
static void
render_rows (sweep_line_t *sweep_line,
cairo_span_renderer_t *renderer,
int height)
{
cairo_status_t status;
 
_active_edges_to_spans (sweep_line);
 
status = renderer->render_rows (renderer,
sweep_line->current_y, height,
sweep_line->spans,
sweep_line->num_spans);
if (unlikely (status))
longjmp (sweep_line->jmpbuf, status);
}
 
static cairo_status_t
generate (cairo_rectangular_scan_converter_t *self,
cairo_span_renderer_t *renderer,
rectangle_t **rectangles)
{
sweep_line_t sweep_line;
rectangle_t *start, *stop;
cairo_status_t status;
 
sweep_line_init (&sweep_line);
sweep_line.xmin = self->xmin;
sweep_line.xmax = self->xmax;
sweep_line.start = rectangles;
if ((status = setjmp (sweep_line.jmpbuf)))
goto BAIL;
 
sweep_line.current_y = self->ymin;
start = *sweep_line.start++;
do {
if (start->top_y != sweep_line.current_y) {
render_rows (&sweep_line, renderer,
start->top_y - sweep_line.current_y);
sweep_line.current_y = start->top_y;
}
 
do {
sweep_line_insert (&sweep_line, start);
start = *sweep_line.start++;
if (start == NULL)
goto end;
if (start->top_y != sweep_line.current_y)
break;
} while (TRUE);
 
render_rows (&sweep_line, renderer, 1);
 
stop = peek_stop (&sweep_line);
while (stop->bottom_y == sweep_line.current_y) {
sweep_line_delete (&sweep_line, stop);
stop = peek_stop (&sweep_line);
if (stop == NULL)
break;
}
 
sweep_line.current_y++;
 
while (stop != NULL && stop->bottom_y < start->top_y) {
if (stop->bottom_y != sweep_line.current_y) {
render_rows (&sweep_line, renderer,
stop->bottom_y - sweep_line.current_y);
sweep_line.current_y = stop->bottom_y;
}
 
render_rows (&sweep_line, renderer, 1);
 
do {
sweep_line_delete (&sweep_line, stop);
stop = peek_stop (&sweep_line);
} while (stop != NULL && stop->bottom_y == sweep_line.current_y);
 
sweep_line.current_y++;
}
} while (TRUE);
 
end:
render_rows (&sweep_line, renderer, 1);
 
stop = peek_stop (&sweep_line);
while (stop->bottom_y == sweep_line.current_y) {
sweep_line_delete (&sweep_line, stop);
stop = peek_stop (&sweep_line);
if (stop == NULL)
goto out;
}
 
sweep_line.current_y++;
 
do {
if (stop->bottom_y != sweep_line.current_y) {
render_rows (&sweep_line, renderer,
stop->bottom_y - sweep_line.current_y);
sweep_line.current_y = stop->bottom_y;
}
 
render_rows (&sweep_line, renderer, 1);
 
do {
sweep_line_delete (&sweep_line, stop);
stop = peek_stop (&sweep_line);
if (stop == NULL)
goto out;
} while (stop->bottom_y == sweep_line.current_y);
 
sweep_line.current_y++;
} while (TRUE);
 
out:
status = renderer->render_rows (renderer,
sweep_line.current_y,
self->ymax - sweep_line.current_y,
NULL, 0);
 
BAIL:
sweep_line_fini (&sweep_line);
 
return status;
}
 
static cairo_status_t
_cairo_rectangular_scan_converter_generate (void *converter,
cairo_span_renderer_t *renderer)
{
cairo_rectangular_scan_converter_t *self = converter;
rectangle_t *rectangles_stack[CAIRO_STACK_ARRAY_LENGTH (rectangle_t *)];
rectangle_t **rectangles;
struct _cairo_rectangular_scan_converter_chunk *chunk;
cairo_status_t status;
int i, j;
 
if (unlikely (self->num_rectangles == 0)) {
return renderer->render_rows (renderer,
self->ymin, self->ymax - self->ymin,
NULL, 0);
}
 
rectangles = rectangles_stack;
if (unlikely (self->num_rectangles >= ARRAY_LENGTH (rectangles_stack))) {
rectangles = _cairo_malloc_ab (self->num_rectangles + 1,
sizeof (rectangle_t *));
if (unlikely (rectangles == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
 
j = 0;
for (chunk = &self->chunks; chunk != NULL; chunk = chunk->next) {
rectangle_t *rectangle;
 
rectangle = chunk->base;
for (i = 0; i < chunk->count; i++)
rectangles[j++] = &rectangle[i];
}
rectangle_sort (rectangles, j);
rectangles[j] = NULL;
 
status = generate (self, renderer, rectangles);
 
if (rectangles != rectangles_stack)
free (rectangles);
 
return status;
}
 
static rectangle_t *
_allocate_rectangle (cairo_rectangular_scan_converter_t *self)
{
rectangle_t *rectangle;
struct _cairo_rectangular_scan_converter_chunk *chunk;
 
chunk = self->tail;
if (chunk->count == chunk->size) {
int size;
 
size = chunk->size * 2;
chunk->next = _cairo_malloc_ab_plus_c (size,
sizeof (rectangle_t),
sizeof (struct _cairo_rectangular_scan_converter_chunk));
 
if (unlikely (chunk->next == NULL))
return NULL;
 
chunk = chunk->next;
chunk->next = NULL;
chunk->count = 0;
chunk->size = size;
chunk->base = chunk + 1;
self->tail = chunk;
}
 
rectangle = chunk->base;
return rectangle + chunk->count++;
}
 
cairo_status_t
_cairo_rectangular_scan_converter_add_box (cairo_rectangular_scan_converter_t *self,
const cairo_box_t *box,
int dir)
{
rectangle_t *rectangle;
 
rectangle = _allocate_rectangle (self);
if (unlikely (rectangle == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
rectangle->left = box->p1.x;
rectangle->right = box->p2.x;
rectangle->dir = dir;
 
rectangle->top = box->p1.y;
rectangle->top_y = _cairo_fixed_integer_floor (box->p1.y);
rectangle->bottom = box->p2.y;
rectangle->bottom_y = _cairo_fixed_integer_floor (box->p2.y);
assert (rectangle->bottom_y >= rectangle->top_y);
 
self->num_rectangles++;
 
return CAIRO_STATUS_SUCCESS;
}
 
static void
_cairo_rectangular_scan_converter_destroy (void *converter)
{
cairo_rectangular_scan_converter_t *self = converter;
struct _cairo_rectangular_scan_converter_chunk *chunk, *next;
 
for (chunk = self->chunks.next; chunk != NULL; chunk = next) {
next = chunk->next;
free (chunk);
}
}
 
void
_cairo_rectangular_scan_converter_init (cairo_rectangular_scan_converter_t *self,
const cairo_rectangle_int_t *extents)
{
self->base.destroy = _cairo_rectangular_scan_converter_destroy;
self->base.add_edge = NULL;
self->base.add_polygon = NULL;
self->base.generate = _cairo_rectangular_scan_converter_generate;
 
self->xmin = extents->x;
self->xmax = extents->x + extents->width;
self->ymin = extents->y;
self->ymax = extents->y + extents->height;
 
self->chunks.base = self->buf;
self->chunks.next = NULL;
self->chunks.count = 0;
self->chunks.size = sizeof (self->buf) / sizeof (rectangle_t);
self->tail = &self->chunks;
 
self->num_rectangles = 0;
}
/programs/develop/libraries/cairo/src/cairo-reference-count-private.h
0,0 → 1,61
/* 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., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Chris Wilson <chris@chris-wilson.co.uk>
*/
 
#ifndef CAIRO_REFRENCE_COUNT_PRIVATE_H
#define CAIRO_REFRENCE_COUNT_PRIVATE_H
 
#include "cairo-atomic-private.h"
 
/* 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_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)
 
#endif
/programs/develop/libraries/cairo/src/cairo-region-private.h
0,0 → 1,71
/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2005 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
* Owen Taylor <otaylor@redhat.com>
* Vladimir Vukicevic <vladimir@pobox.com>
* Søren Sandmann <sandmann@daimi.au.dk>
*/
 
#ifndef CAIRO_REGION_PRIVATE_H
#define CAIRO_REGION_PRIVATE_H
 
#include "cairo-types-private.h"
#include "cairo-reference-count-private.h"
 
#include <pixman.h>
 
CAIRO_BEGIN_DECLS
 
struct _cairo_region {
cairo_reference_count_t ref_count;
cairo_status_t status;
 
pixman_region32_t rgn;
};
 
cairo_private cairo_region_t *
_cairo_region_create_in_error (cairo_status_t status);
 
cairo_private void
_cairo_region_init (cairo_region_t *region);
 
cairo_private void
_cairo_region_init_rectangle (cairo_region_t *region,
const cairo_rectangle_int_t *rectangle);
 
cairo_private void
_cairo_region_fini (cairo_region_t *region);
 
CAIRO_END_DECLS
 
#endif /* CAIRO_REGION_PRIVATE_H */
/programs/develop/libraries/cairo/src/cairo-region.c
0,0 → 1,905
/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2005 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
* Owen Taylor <otaylor@redhat.com>
* Vladimir Vukicevic <vladimir@pobox.com>
* Søren Sandmann <sandmann@daimi.au.dk>
*/
 
#include "cairoint.h"
 
#include "cairo-error-private.h"
#include "cairo-region-private.h"
 
/* XXX need to update pixman headers to be const as appropriate */
#define CONST_CAST (pixman_region32_t *)
 
/**
* SECTION:cairo-region
* @Title: Regions
* @Short_Description: Representing a pixel-aligned area
*
* Regions are a simple graphical data type representing an area of
* integer-aligned rectangles. They are often used on raster surfaces
* to track areas of interest, such as change or clip areas.
*/
 
static const cairo_region_t _cairo_region_nil = {
CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */
CAIRO_STATUS_NO_MEMORY, /* status */
};
 
cairo_region_t *
_cairo_region_create_in_error (cairo_status_t status)
{
switch (status) {
case CAIRO_STATUS_NO_MEMORY:
return (cairo_region_t *) &_cairo_region_nil;
 
case CAIRO_STATUS_SUCCESS:
case CAIRO_STATUS_LAST_STATUS:
ASSERT_NOT_REACHED;
/* fall-through */
case CAIRO_STATUS_SURFACE_TYPE_MISMATCH:
case CAIRO_STATUS_INVALID_STATUS:
case CAIRO_STATUS_INVALID_CONTENT:
case CAIRO_STATUS_INVALID_FORMAT:
case CAIRO_STATUS_INVALID_VISUAL:
case CAIRO_STATUS_READ_ERROR:
case CAIRO_STATUS_WRITE_ERROR:
case CAIRO_STATUS_FILE_NOT_FOUND:
case CAIRO_STATUS_TEMP_FILE_ERROR:
case CAIRO_STATUS_INVALID_STRIDE:
case CAIRO_STATUS_INVALID_SIZE:
case CAIRO_STATUS_DEVICE_TYPE_MISMATCH:
case CAIRO_STATUS_DEVICE_ERROR:
case CAIRO_STATUS_INVALID_RESTORE:
case CAIRO_STATUS_INVALID_POP_GROUP:
case CAIRO_STATUS_NO_CURRENT_POINT:
case CAIRO_STATUS_INVALID_MATRIX:
case CAIRO_STATUS_NULL_POINTER:
case CAIRO_STATUS_INVALID_STRING:
case CAIRO_STATUS_INVALID_PATH_DATA:
case CAIRO_STATUS_SURFACE_FINISHED:
case CAIRO_STATUS_PATTERN_TYPE_MISMATCH:
case CAIRO_STATUS_INVALID_DASH:
case CAIRO_STATUS_INVALID_DSC_COMMENT:
case CAIRO_STATUS_INVALID_INDEX:
case CAIRO_STATUS_CLIP_NOT_REPRESENTABLE:
case CAIRO_STATUS_FONT_TYPE_MISMATCH:
case CAIRO_STATUS_USER_FONT_IMMUTABLE:
case CAIRO_STATUS_USER_FONT_ERROR:
case CAIRO_STATUS_NEGATIVE_COUNT:
case CAIRO_STATUS_INVALID_CLUSTERS:
case CAIRO_STATUS_INVALID_SLANT:
case CAIRO_STATUS_INVALID_WEIGHT:
case CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED:
default:
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_region_t *) &_cairo_region_nil;
}
}
 
/**
* _cairo_region_set_error:
* @region: a region
* @status: a status value indicating an error
*
* Atomically sets region->status to @status and calls _cairo_error;
* Does nothing if status is %CAIRO_STATUS_SUCCESS or any of the internal
* status values.
*
* All assignments of an error status to region->status should happen
* through _cairo_region_set_error(). Note that due to the nature of
* 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
* breakpoint in _cairo_error() to generate a stack trace for when the
* user causes cairo to detect an error.
*
* Return value: the error status.
**/
static cairo_status_t
_cairo_region_set_error (cairo_region_t *region,
cairo_status_t status)
{
if (! _cairo_status_is_error (status))
return status;
 
/* Don't overwrite an existing error. This preserves the first
* error, which is the most significant. */
_cairo_status_set_error (&region->status, status);
 
return _cairo_error (status);
}
 
void
_cairo_region_init (cairo_region_t *region)
{
VG (VALGRIND_MAKE_MEM_UNDEFINED (region, sizeof (cairo_region_t)));
 
region->status = CAIRO_STATUS_SUCCESS;
CAIRO_REFERENCE_COUNT_INIT (&region->ref_count, 0);
pixman_region32_init (&region->rgn);
}
 
void
_cairo_region_init_rectangle (cairo_region_t *region,
const cairo_rectangle_int_t *rectangle)
{
VG (VALGRIND_MAKE_MEM_UNDEFINED (region, sizeof (cairo_region_t)));
 
region->status = CAIRO_STATUS_SUCCESS;
CAIRO_REFERENCE_COUNT_INIT (&region->ref_count, 0);
pixman_region32_init_rect (&region->rgn,
rectangle->x, rectangle->y,
rectangle->width, rectangle->height);
}
 
void
_cairo_region_fini (cairo_region_t *region)
{
assert (! CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&region->ref_count));
pixman_region32_fini (&region->rgn);
VG (VALGRIND_MAKE_MEM_NOACCESS (region, sizeof (cairo_region_t)));
}
 
/**
* cairo_region_create:
*
* Allocates a new empty region object.
*
* Return value: A newly allocated #cairo_region_t. Free with
* cairo_region_destroy(). This function always returns a
* valid pointer; if memory cannot be allocated, then a special
* error object is returned where all operations on the object do nothing.
* You can check for this with cairo_region_status().
*
* Since: 1.10
**/
cairo_region_t *
cairo_region_create (void)
{
cairo_region_t *region;
 
region = _cairo_malloc (sizeof (cairo_region_t));
if (region == NULL)
return (cairo_region_t *) &_cairo_region_nil;
 
region->status = CAIRO_STATUS_SUCCESS;
CAIRO_REFERENCE_COUNT_INIT (&region->ref_count, 1);
 
pixman_region32_init (&region->rgn);
 
return region;
}
slim_hidden_def (cairo_region_create);
 
/**
* cairo_region_create_rectangles:
* @rects: an array of @count rectangles
* @count: number of rectangles
*
* Allocates a new region object containing the union of all given @rects.
*
* Return value: A newly allocated #cairo_region_t. Free with
* cairo_region_destroy(). This function always returns a
* valid pointer; if memory cannot be allocated, then a special
* error object is returned where all operations on the object do nothing.
* You can check for this with cairo_region_status().
*
* Since: 1.10
**/
cairo_region_t *
cairo_region_create_rectangles (const cairo_rectangle_int_t *rects,
int count)
{
pixman_box32_t stack_pboxes[CAIRO_STACK_ARRAY_LENGTH (pixman_box32_t)];
pixman_box32_t *pboxes = stack_pboxes;
cairo_region_t *region;
int i;
 
region = _cairo_malloc (sizeof (cairo_region_t));
if (unlikely (region == NULL))
return _cairo_region_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
 
if (count > ARRAY_LENGTH (stack_pboxes)) {
pboxes = _cairo_malloc_ab (count, sizeof (pixman_box32_t));
if (unlikely (pboxes == NULL)) {
free (region);
return _cairo_region_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
}
}
 
for (i = 0; i < count; i++) {
pboxes[i].x1 = rects[i].x;
pboxes[i].y1 = rects[i].y;
pboxes[i].x2 = rects[i].x + rects[i].width;
pboxes[i].y2 = rects[i].y + rects[i].height;
}
 
i = pixman_region32_init_rects (&region->rgn, pboxes, count);
 
if (pboxes != stack_pboxes)
free (pboxes);
 
if (unlikely (i == 0)) {
free (region);
return _cairo_region_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
}
 
CAIRO_REFERENCE_COUNT_INIT (&region->ref_count, 1);
region->status = CAIRO_STATUS_SUCCESS;
return region;
}
slim_hidden_def (cairo_region_create_rectangles);
 
/**
* cairo_region_create_rectangle:
* @rectangle: a #cairo_rectangle_int_t
*
* Allocates a new region object containing @rectangle.
*
* Return value: A newly allocated #cairo_region_t. Free with
* cairo_region_destroy(). This function always returns a
* valid pointer; if memory cannot be allocated, then a special
* error object is returned where all operations on the object do nothing.
* You can check for this with cairo_region_status().
*
* Since: 1.10
**/
cairo_region_t *
cairo_region_create_rectangle (const cairo_rectangle_int_t *rectangle)
{
cairo_region_t *region;
 
region = _cairo_malloc (sizeof (cairo_region_t));
if (unlikely (region == NULL))
return (cairo_region_t *) &_cairo_region_nil;
 
region->status = CAIRO_STATUS_SUCCESS;
CAIRO_REFERENCE_COUNT_INIT (&region->ref_count, 1);
 
pixman_region32_init_rect (&region->rgn,
rectangle->x, rectangle->y,
rectangle->width, rectangle->height);
 
return region;
}
slim_hidden_def (cairo_region_create_rectangle);
 
/**
* cairo_region_copy:
* @original: a #cairo_region_t
*
* Allocates a new region object copying the area from @original.
*
* Return value: A newly allocated #cairo_region_t. Free with
* cairo_region_destroy(). This function always returns a
* valid pointer; if memory cannot be allocated, then a special
* error object is returned where all operations on the object do nothing.
* You can check for this with cairo_region_status().
*
* Since: 1.10
**/
cairo_region_t *
cairo_region_copy (const cairo_region_t *original)
{
cairo_region_t *copy;
 
if (original != NULL && original->status)
return (cairo_region_t *) &_cairo_region_nil;
 
copy = cairo_region_create ();
if (unlikely (copy->status))
return copy;
 
if (original != NULL &&
! pixman_region32_copy (&copy->rgn, CONST_CAST &original->rgn))
{
cairo_region_destroy (copy);
return (cairo_region_t *) &_cairo_region_nil;
}
 
return copy;
}
slim_hidden_def (cairo_region_copy);
 
/**
* cairo_region_reference:
* @region: a #cairo_region_t
*
* Increases the reference count on @region by one. This prevents
* @region from being destroyed until a matching call to
* cairo_region_destroy() is made.
*
* Return value: the referenced #cairo_region_t.
*
* Since: 1.10
**/
cairo_region_t *
cairo_region_reference (cairo_region_t *region)
{
if (region == NULL || CAIRO_REFERENCE_COUNT_IS_INVALID (&region->ref_count))
return NULL;
 
assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&region->ref_count));
 
_cairo_reference_count_inc (&region->ref_count);
return region;
}
slim_hidden_def (cairo_region_reference);
 
/**
* cairo_region_destroy:
* @region: a #cairo_region_t
*
* Destroys a #cairo_region_t object created with
* cairo_region_create(), cairo_region_copy(), or
* or cairo_region_create_rectangle().
*
* Since: 1.10
**/
void
cairo_region_destroy (cairo_region_t *region)
{
if (region == NULL || CAIRO_REFERENCE_COUNT_IS_INVALID (&region->ref_count))
return;
 
assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&region->ref_count));
 
if (! _cairo_reference_count_dec_and_test (&region->ref_count))
return;
 
_cairo_region_fini (region);
free (region);
}
slim_hidden_def (cairo_region_destroy);
 
/**
* cairo_region_num_rectangles:
* @region: a #cairo_region_t
*
* Returns the number of rectangles contained in @region.
*
* Return value: The number of rectangles contained in @region.
*
* Since: 1.10
**/
int
cairo_region_num_rectangles (const cairo_region_t *region)
{
if (region->status)
return 0;
 
return pixman_region32_n_rects (CONST_CAST &region->rgn);
}
slim_hidden_def (cairo_region_num_rectangles);
 
/**
* cairo_region_get_rectangle:
* @region: a #cairo_region_t
* @nth: a number indicating which rectangle should be returned
* @rectangle: return location for a #cairo_rectangle_int_t
*
* Stores the @nth rectangle from the region in @rectangle.
*
* Since: 1.10
**/
void
cairo_region_get_rectangle (const cairo_region_t *region,
int nth,
cairo_rectangle_int_t *rectangle)
{
pixman_box32_t *pbox;
 
if (region->status) {
rectangle->x = rectangle->y = 0;
rectangle->width = rectangle->height = 0;
return;
}
 
pbox = pixman_region32_rectangles (CONST_CAST &region->rgn, NULL) + nth;
 
rectangle->x = pbox->x1;
rectangle->y = pbox->y1;
rectangle->width = pbox->x2 - pbox->x1;
rectangle->height = pbox->y2 - pbox->y1;
}
slim_hidden_def (cairo_region_get_rectangle);
 
/**
* cairo_region_get_extents:
* @region: a #cairo_region_t
* @extents: rectangle into which to store the extents
*
* Gets the bounding rectangle of @region as a #cairo_rectangle_int_t
*
* Since: 1.10
**/
void
cairo_region_get_extents (const cairo_region_t *region,
cairo_rectangle_int_t *extents)
{
pixman_box32_t *pextents;
 
if (region->status) {
extents->x = extents->y = 0;
extents->width = extents->height = 0;
return;
}
 
pextents = pixman_region32_extents (CONST_CAST &region->rgn);
 
extents->x = pextents->x1;
extents->y = pextents->y1;
extents->width = pextents->x2 - pextents->x1;
extents->height = pextents->y2 - pextents->y1;
}
slim_hidden_def (cairo_region_get_extents);
 
/**
* cairo_region_status:
* @region: a #cairo_region_t
*
* Checks whether an error has previous occured for this
* region object.
*
* Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY
*
* Since: 1.10
**/
cairo_status_t
cairo_region_status (const cairo_region_t *region)
{
return region->status;
}
slim_hidden_def (cairo_region_status);
 
/**
* cairo_region_subtract:
* @dst: a #cairo_region_t
* @other: another #cairo_region_t
*
* Subtracts @other from @dst and places the result in @dst
*
* Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY
*
* Since: 1.10
**/
cairo_status_t
cairo_region_subtract (cairo_region_t *dst, const cairo_region_t *other)
{
if (dst->status)
return dst->status;
 
if (other->status)
return _cairo_region_set_error (dst, other->status);
 
if (! pixman_region32_subtract (&dst->rgn,
&dst->rgn,
CONST_CAST &other->rgn))
{
return _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY);
}
 
return CAIRO_STATUS_SUCCESS;
}
slim_hidden_def (cairo_region_subtract);
 
/**
* cairo_region_subtract_rectangle:
* @dst: a #cairo_region_t
* @rectangle: a #cairo_rectangle_int_t
*
* Subtracts @rectangle from @dst and places the result in @dst
*
* Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY
*
* Since: 1.10
**/
cairo_status_t
cairo_region_subtract_rectangle (cairo_region_t *dst,
const cairo_rectangle_int_t *rectangle)
{
cairo_status_t status = CAIRO_STATUS_SUCCESS;
pixman_region32_t region;
 
if (dst->status)
return dst->status;
 
pixman_region32_init_rect (&region,
rectangle->x, rectangle->y,
rectangle->width, rectangle->height);
 
if (! pixman_region32_subtract (&dst->rgn, &dst->rgn, &region))
status = _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY);
 
pixman_region32_fini (&region);
 
return status;
}
slim_hidden_def (cairo_region_subtract_rectangle);
 
/**
* cairo_region_intersect:
* @dst: a #cairo_region_t
* @other: another #cairo_region_t
*
* Computes the intersection of @dst with @other and places the result in @dst
*
* Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY
*
* Since: 1.10
**/
cairo_status_t
cairo_region_intersect (cairo_region_t *dst, const cairo_region_t *other)
{
if (dst->status)
return dst->status;
 
if (other->status)
return _cairo_region_set_error (dst, other->status);
 
if (! pixman_region32_intersect (&dst->rgn, &dst->rgn, CONST_CAST &other->rgn))
return _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY);
 
return CAIRO_STATUS_SUCCESS;
}
slim_hidden_def (cairo_region_intersect);
 
/**
* cairo_region_intersect_rectangle:
* @dst: a #cairo_region_t
* @rectangle: a #cairo_rectangle_int_t
*
* Computes the intersection of @dst with @rectangle and places the
* result in @dst
*
* Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY
*
* Since: 1.10
**/
cairo_status_t
cairo_region_intersect_rectangle (cairo_region_t *dst,
const cairo_rectangle_int_t *rectangle)
{
cairo_status_t status = CAIRO_STATUS_SUCCESS;
pixman_region32_t region;
 
if (dst->status)
return dst->status;
 
pixman_region32_init_rect (&region,
rectangle->x, rectangle->y,
rectangle->width, rectangle->height);
 
if (! pixman_region32_intersect (&dst->rgn, &dst->rgn, &region))
status = _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY);
 
pixman_region32_fini (&region);
 
return status;
}
slim_hidden_def (cairo_region_intersect_rectangle);
 
/**
* cairo_region_union:
* @dst: a #cairo_region_t
* @other: another #cairo_region_t
*
* Computes the union of @dst with @other and places the result in @dst
*
* Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY
*
* Since: 1.10
**/
cairo_status_t
cairo_region_union (cairo_region_t *dst,
const cairo_region_t *other)
{
if (dst->status)
return dst->status;
 
if (other->status)
return _cairo_region_set_error (dst, other->status);
 
if (! pixman_region32_union (&dst->rgn, &dst->rgn, CONST_CAST &other->rgn))
return _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY);
 
return CAIRO_STATUS_SUCCESS;
}
slim_hidden_def (cairo_region_union);
 
/**
* cairo_region_union_rectangle:
* @dst: a #cairo_region_t
* @rectangle: a #cairo_rectangle_int_t
*
* Computes the union of @dst with @rectangle and places the result in @dst.
*
* Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY
*
* Since: 1.10
**/
cairo_status_t
cairo_region_union_rectangle (cairo_region_t *dst,
const cairo_rectangle_int_t *rectangle)
{
cairo_status_t status = CAIRO_STATUS_SUCCESS;
pixman_region32_t region;
 
if (dst->status)
return dst->status;
 
pixman_region32_init_rect (&region,
rectangle->x, rectangle->y,
rectangle->width, rectangle->height);
 
if (! pixman_region32_union (&dst->rgn, &dst->rgn, &region))
status = _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY);
 
pixman_region32_fini (&region);
 
return status;
}
slim_hidden_def (cairo_region_union_rectangle);
 
/**
* cairo_region_xor:
* @dst: a #cairo_region_t
* @other: another #cairo_region_t
*
* Computes the exclusive difference of @dst with @other and places the
* result in @dst. That is, @dst will be set to contain all areas that
* are either in @dst or in @other, but not in both.
*
* Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY
*
* Since: 1.10
**/
cairo_status_t
cairo_region_xor (cairo_region_t *dst, const cairo_region_t *other)
{
cairo_status_t status = CAIRO_STATUS_SUCCESS;
pixman_region32_t tmp;
 
if (dst->status)
return dst->status;
 
if (other->status)
return _cairo_region_set_error (dst, other->status);
 
pixman_region32_init (&tmp);
 
/* XXX: get an xor function into pixman */
if (! pixman_region32_subtract (&tmp, CONST_CAST &other->rgn, &dst->rgn) ||
! pixman_region32_subtract (&dst->rgn, &dst->rgn, CONST_CAST &other->rgn) ||
! pixman_region32_union (&dst->rgn, &dst->rgn, &tmp))
status = _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY);
 
pixman_region32_fini (&tmp);
 
return status;
}
slim_hidden_def (cairo_region_xor);
 
/**
* cairo_region_xor_rectangle:
* @dst: a #cairo_region_t
* @rectangle: a #cairo_rectangle_int_t
*
* Computes the exclusive difference of @dst with @rectangle and places the
* result in @dst. That is, @dst will be set to contain all areas that are
* either in @dst or in @rectangle, but not in both.
*
* Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY
*
* Since: 1.10
**/
cairo_status_t
cairo_region_xor_rectangle (cairo_region_t *dst,
const cairo_rectangle_int_t *rectangle)
{
cairo_status_t status = CAIRO_STATUS_SUCCESS;
pixman_region32_t region, tmp;
 
if (dst->status)
return dst->status;
 
pixman_region32_init_rect (&region,
rectangle->x, rectangle->y,
rectangle->width, rectangle->height);
pixman_region32_init (&tmp);
 
/* XXX: get an xor function into pixman */
if (! pixman_region32_subtract (&tmp, &region, &dst->rgn) ||
! pixman_region32_subtract (&dst->rgn, &dst->rgn, &region) ||
! pixman_region32_union (&dst->rgn, &dst->rgn, &tmp))
status = _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY);
 
pixman_region32_fini (&tmp);
pixman_region32_fini (&region);
 
return status;
}
slim_hidden_def (cairo_region_xor_rectangle);
 
/**
* cairo_region_is_empty:
* @region: a #cairo_region_t
*
* Checks whether @region is empty.
*
* Return value: %TRUE if @region is empty, %FALSE if it isn't.
*
* Since: 1.10
**/
cairo_bool_t
cairo_region_is_empty (const cairo_region_t *region)
{
if (region->status)
return TRUE;
 
return ! pixman_region32_not_empty (CONST_CAST &region->rgn);
}
slim_hidden_def (cairo_region_is_empty);
 
/**
* cairo_region_translate:
* @region: a #cairo_region_t
* @dx: Amount to translate in the x direction
* @dy: Amount to translate in the y direction
*
* Translates @region by (@dx, @dy).
*
* Since: 1.10
**/
void
cairo_region_translate (cairo_region_t *region,
int dx, int dy)
{
if (region->status)
return;
 
pixman_region32_translate (&region->rgn, dx, dy);
}
slim_hidden_def (cairo_region_translate);
 
/**
* cairo_region_overlap_t:
* @CAIRO_REGION_OVERLAP_IN: The contents are entirely inside the region
* @CAIRO_REGION_OVERLAP_OUT: The contents are entirely outside the region
* @CAIRO_REGION_OVERLAP_PART: The contents are partially inside and
* partially outside the region.
*
* Used as the return value for cairo_region_contains_rectangle().
*/
 
/**
* cairo_region_contains_rectangle:
* @region: a #cairo_region_t
* @rectangle: a #cairo_rectangle_int_t
*
* Checks whether @rectangle is inside, outside or partially contained
* in @region
*
* Return value:
* %CAIRO_REGION_OVERLAP_IN if @rectangle is entirely inside @region,
* %CAIRO_REGION_OVERLAP_OUT if @rectangle is entirely outside @region, or
* %CAIRO_REGION_OVERLAP_PART if @rectangle is partially inside and partially outside @region.
*
* Since: 1.10
**/
cairo_region_overlap_t
cairo_region_contains_rectangle (const cairo_region_t *region,
const cairo_rectangle_int_t *rectangle)
{
pixman_box32_t pbox;
pixman_region_overlap_t poverlap;
 
if (region->status)
return CAIRO_REGION_OVERLAP_OUT;
 
pbox.x1 = rectangle->x;
pbox.y1 = rectangle->y;
pbox.x2 = rectangle->x + rectangle->width;
pbox.y2 = rectangle->y + rectangle->height;
 
poverlap = pixman_region32_contains_rectangle (CONST_CAST &region->rgn,
&pbox);
switch (poverlap) {
default:
case PIXMAN_REGION_OUT: return CAIRO_REGION_OVERLAP_OUT;
case PIXMAN_REGION_IN: return CAIRO_REGION_OVERLAP_IN;
case PIXMAN_REGION_PART: return CAIRO_REGION_OVERLAP_PART;
}
}
slim_hidden_def (cairo_region_contains_rectangle);
 
/**
* cairo_region_contains_point:
* @region: a #cairo_region_t
* @x: the x coordinate of a point
* @y: the y coordinate of a point
*
* Checks whether (@x, @y) is contained in @region.
*
* Return value: %TRUE if (@x, @y) is contained in @region, %FALSE if it is not.
*
* Since: 1.10
**/
cairo_bool_t
cairo_region_contains_point (const cairo_region_t *region,
int x, int y)
{
pixman_box32_t box;
 
if (region->status)
return FALSE;
 
return pixman_region32_contains_point (CONST_CAST &region->rgn, x, y, &box);
}
slim_hidden_def (cairo_region_contains_point);
 
/**
* cairo_region_equal:
* @a: a #cairo_region_t or %NULL
* @b: a #cairo_region_t or %NULL
*
* Compares whether region_a is equivalent to region_b. %NULL as an argument
* is equal to itself, but not to any non-%NULL region.
*
* Return value: %TRUE if both regions contained the same coverage,
* %FALSE if it is not or any region is in an error status.
*
* Since: 1.10
**/
cairo_bool_t
cairo_region_equal (const cairo_region_t *a,
const cairo_region_t *b)
{
/* error objects are never equal */
if ((a != NULL && a->status) || (b != NULL && b->status))
return FALSE;
 
if (a == b)
return TRUE;
 
if (a == NULL || b == NULL)
return FALSE;
 
return pixman_region32_equal (CONST_CAST &a->rgn, CONST_CAST &b->rgn);
}
slim_hidden_def (cairo_region_equal);
/programs/develop/libraries/cairo/src/cairo-rtree-private.h
0,0 → 1,134
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2009 Chris Wilson
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Chris Wilson.
*
* Contributor(s):
* Chris Wilson <chris@chris-wilson.co.uk>
*
*/
 
#ifndef CAIRO_RTREE_PRIVATE_H
#define CAIRO_RTREE_PRIVATE_H
 
#include "cairo-compiler-private.h"
#include "cairo-types-private.h"
 
#include "cairo-freelist-private.h"
#include "cairo-list-private.h"
 
enum {
CAIRO_RTREE_NODE_AVAILABLE,
CAIRO_RTREE_NODE_DIVIDED,
CAIRO_RTREE_NODE_OCCUPIED,
};
 
typedef struct _cairo_rtree_node {
struct _cairo_rtree_node *children[4], *parent;
void **owner;
cairo_list_t link;
uint16_t pinned;
uint16_t state;
uint16_t x, y;
uint16_t width, height;
} cairo_rtree_node_t;
 
typedef struct _cairo_rtree {
cairo_rtree_node_t root;
int min_size;
cairo_list_t pinned;
cairo_list_t available;
cairo_list_t evictable;
cairo_freepool_t node_freepool;
} cairo_rtree_t;
 
cairo_private cairo_rtree_node_t *
_cairo_rtree_node_create (cairo_rtree_t *rtree,
cairo_rtree_node_t *parent,
int x,
int y,
int width,
int height);
 
cairo_private cairo_status_t
_cairo_rtree_node_insert (cairo_rtree_t *rtree,
cairo_rtree_node_t *node,
int width,
int height,
cairo_rtree_node_t **out);
 
cairo_private void
_cairo_rtree_node_collapse (cairo_rtree_t *rtree, cairo_rtree_node_t *node);
 
cairo_private void
_cairo_rtree_node_remove (cairo_rtree_t *rtree, cairo_rtree_node_t *node);
 
cairo_private void
_cairo_rtree_node_destroy (cairo_rtree_t *rtree, cairo_rtree_node_t *node);
 
cairo_private void
_cairo_rtree_init (cairo_rtree_t *rtree,
int width,
int height,
int min_size,
int node_size);
 
cairo_private cairo_int_status_t
_cairo_rtree_insert (cairo_rtree_t *rtree,
int width,
int height,
cairo_rtree_node_t **out);
 
cairo_private cairo_int_status_t
_cairo_rtree_evict_random (cairo_rtree_t *rtree,
int width,
int height,
cairo_rtree_node_t **out);
 
static inline void *
_cairo_rtree_pin (cairo_rtree_t *rtree, cairo_rtree_node_t *node)
{
if (! node->pinned) {
cairo_list_move (&node->link, &rtree->pinned);
node->pinned = 1;
}
 
return node;
}
 
cairo_private void
_cairo_rtree_unpin (cairo_rtree_t *rtree);
 
cairo_private void
_cairo_rtree_reset (cairo_rtree_t *rtree);
 
cairo_private void
_cairo_rtree_fini (cairo_rtree_t *rtree);
 
#endif /* CAIRO_RTREE_PRIVATE_H */
/programs/develop/libraries/cairo/src/cairo-rtree.c
0,0 → 1,385
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2009 Chris Wilson
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Chris Wilson.
*
* Contributor(s):
* Chris Wilson <chris@chris-wilson.co.uk>
*
*/
 
#include "cairoint.h"
 
#include "cairo-error-private.h"
#include "cairo-rtree-private.h"
 
cairo_rtree_node_t *
_cairo_rtree_node_create (cairo_rtree_t *rtree,
cairo_rtree_node_t *parent,
int x,
int y,
int width,
int height)
{
cairo_rtree_node_t *node;
 
node = _cairo_freepool_alloc (&rtree->node_freepool);
if (node == NULL) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return NULL;
}
 
node->children[0] = NULL;
node->parent = parent;
node->owner = NULL;
node->state = CAIRO_RTREE_NODE_AVAILABLE;
node->pinned = FALSE;
node->x = x;
node->y = y;
node->width = width;
node->height = height;
 
cairo_list_add (&node->link, &rtree->available);
 
return node;
}
 
void
_cairo_rtree_node_destroy (cairo_rtree_t *rtree, cairo_rtree_node_t *node)
{
int i;
 
cairo_list_del (&node->link);
 
if (node->state == CAIRO_RTREE_NODE_OCCUPIED) {
if (node->owner != NULL)
*node->owner = NULL;
} else {
for (i = 0; i < 4 && node->children[i] != NULL; i++)
_cairo_rtree_node_destroy (rtree, node->children[i]);
}
 
_cairo_freepool_free (&rtree->node_freepool, node);
}
 
void
_cairo_rtree_node_collapse (cairo_rtree_t *rtree, cairo_rtree_node_t *node)
{
int i;
 
do {
assert (node->state == CAIRO_RTREE_NODE_DIVIDED);
 
for (i = 0; i < 4 && node->children[i] != NULL; i++)
if (node->children[i]->state != CAIRO_RTREE_NODE_AVAILABLE)
return;
 
for (i = 0; i < 4 && node->children[i] != NULL; i++)
_cairo_rtree_node_destroy (rtree, node->children[i]);
 
node->children[0] = NULL;
node->state = CAIRO_RTREE_NODE_AVAILABLE;
cairo_list_move (&node->link, &rtree->available);
} while ((node = node->parent) != NULL);
}
 
cairo_status_t
_cairo_rtree_node_insert (cairo_rtree_t *rtree,
cairo_rtree_node_t *node,
int width,
int height,
cairo_rtree_node_t **out)
{
int w, h, i;
 
assert (node->state == CAIRO_RTREE_NODE_AVAILABLE);
assert (node->pinned == FALSE);
 
if (node->width - width > rtree->min_size ||
node->height - height > rtree->min_size)
{
w = node->width - width;
h = node->height - height;
 
i = 0;
node->children[i] = _cairo_rtree_node_create (rtree, node,
node->x, node->y,
width, height);
if (unlikely (node->children[i] == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
i++;
 
if (w > rtree->min_size) {
node->children[i] = _cairo_rtree_node_create (rtree, node,
node->x + width,
node->y,
w, height);
if (unlikely (node->children[i] == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
i++;
}
 
if (h > rtree->min_size) {
node->children[i] = _cairo_rtree_node_create (rtree, node,
node->x,
node->y + height,
width, h);
if (unlikely (node->children[i] == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
i++;
 
if (w > rtree->min_size) {
node->children[i] = _cairo_rtree_node_create (rtree, node,
node->x + width,
node->y + height,
w, h);
if (unlikely (node->children[i] == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
i++;
}
}
 
if (i < 4)
node->children[i] = NULL;
 
node->state = CAIRO_RTREE_NODE_DIVIDED;
cairo_list_move (&node->link, &rtree->evictable);
node = node->children[0];
}
 
node->state = CAIRO_RTREE_NODE_OCCUPIED;
cairo_list_move (&node->link, &rtree->evictable);
*out = node;
 
return CAIRO_STATUS_SUCCESS;
}
 
void
_cairo_rtree_node_remove (cairo_rtree_t *rtree, cairo_rtree_node_t *node)
{
assert (node->state == CAIRO_RTREE_NODE_OCCUPIED);
assert (node->pinned == FALSE);
 
node->state = CAIRO_RTREE_NODE_AVAILABLE;
cairo_list_move (&node->link, &rtree->available);
 
_cairo_rtree_node_collapse (rtree, node->parent);
}
 
cairo_int_status_t
_cairo_rtree_insert (cairo_rtree_t *rtree,
int width,
int height,
cairo_rtree_node_t **out)
{
cairo_rtree_node_t *node;
 
cairo_list_foreach_entry (node, cairo_rtree_node_t,
&rtree->available, link)
{
if (node->width >= width && node->height >= height)
return _cairo_rtree_node_insert (rtree, node, width, height, out);
}
 
return CAIRO_INT_STATUS_UNSUPPORTED;
}
 
static uint32_t
hars_petruska_f54_1_random (void)
{
#define rol(x,k) ((x << k) | (x >> (32-k)))
static uint32_t x;
return x = (x ^ rol (x, 5) ^ rol (x, 24)) + 0x37798849;
#undef rol
}
 
cairo_int_status_t
_cairo_rtree_evict_random (cairo_rtree_t *rtree,
int width,
int height,
cairo_rtree_node_t **out)
{
cairo_rtree_node_t *node, *next;
int i, cnt;
 
/* propagate pinned from children to root */
cairo_list_foreach_entry_safe (node, next, cairo_rtree_node_t,
&rtree->pinned, link)
{
if (node->parent != NULL)
_cairo_rtree_pin (rtree, node->parent);
}
 
cnt = 0;
cairo_list_foreach_entry (node, cairo_rtree_node_t,
&rtree->evictable, link)
{
if (node->width >= width && node->height >= height)
cnt++;
}
 
if (cnt == 0)
return CAIRO_INT_STATUS_UNSUPPORTED;
 
cnt = hars_petruska_f54_1_random () % cnt;
cairo_list_foreach_entry (node, cairo_rtree_node_t,
&rtree->evictable, link)
{
if (node->width >= width && node->height >= height && cnt-- == 0) {
if (node->state == CAIRO_RTREE_NODE_OCCUPIED) {
if (node->owner != NULL)
*node->owner = NULL;
} else {
for (i = 0; i < 4 && node->children[i] != NULL; i++)
_cairo_rtree_node_destroy (rtree, node->children[i]);
node->children[0] = NULL;
}
 
node->state = CAIRO_RTREE_NODE_AVAILABLE;
cairo_list_move (&node->link, &rtree->available);
 
*out = node;
return CAIRO_STATUS_SUCCESS;
}
}
 
return CAIRO_INT_STATUS_UNSUPPORTED;
}
 
void
_cairo_rtree_unpin (cairo_rtree_t *rtree)
{
cairo_rtree_node_t *node, *next;
cairo_list_t can_collapse;
 
if (cairo_list_is_empty (&rtree->pinned))
return;
 
cairo_list_init (&can_collapse);
 
cairo_list_foreach_entry_safe (node, next,
cairo_rtree_node_t,
&rtree->pinned,
link)
{
node->pinned = FALSE;
if (node->state == CAIRO_RTREE_NODE_OCCUPIED && node->owner == NULL) {
cairo_bool_t all_available;
int i;
 
node->state = CAIRO_RTREE_NODE_AVAILABLE;
cairo_list_move (&node->link, &rtree->available);
 
all_available = TRUE;
node = node->parent;
for (i = 0; i < 4 && node->children[i] != NULL && all_available; i++)
all_available &= node->children[i]->state == CAIRO_RTREE_NODE_AVAILABLE;
 
if (all_available) {
cairo_list_move (&node->link, &can_collapse);
for (i = 0; i < 4 && node->children[i] != NULL; i++)
cairo_list_del (&node->children[i]->link);
}
}
else
{
cairo_list_move (&node->link, &rtree->evictable);
}
}
 
cairo_list_foreach_entry_safe (node, next,
cairo_rtree_node_t,
&can_collapse,
link)
{
_cairo_rtree_node_collapse (rtree, node);
}
}
 
void
_cairo_rtree_init (cairo_rtree_t *rtree,
int width,
int height,
int min_size,
int node_size)
{
assert (node_size >= (int) sizeof (cairo_rtree_node_t));
_cairo_freepool_init (&rtree->node_freepool, node_size);
 
cairo_list_init (&rtree->available);
cairo_list_init (&rtree->pinned);
cairo_list_init (&rtree->evictable);
 
rtree->min_size = min_size;
 
memset (&rtree->root, 0, sizeof (rtree->root));
rtree->root.width = width;
rtree->root.height = height;
rtree->root.state = CAIRO_RTREE_NODE_AVAILABLE;
cairo_list_add (&rtree->root.link, &rtree->available);
}
 
void
_cairo_rtree_reset (cairo_rtree_t *rtree)
{
int i;
 
if (rtree->root.state == CAIRO_RTREE_NODE_OCCUPIED) {
if (rtree->root.owner != NULL)
*rtree->root.owner = NULL;
} else {
for (i = 0; i < 4 && rtree->root.children[i] != NULL; i++)
_cairo_rtree_node_destroy (rtree, rtree->root.children[i]);
rtree->root.children[0] = NULL;
}
 
cairo_list_init (&rtree->available);
cairo_list_init (&rtree->evictable);
cairo_list_init (&rtree->pinned);
 
rtree->root.state = CAIRO_RTREE_NODE_AVAILABLE;
rtree->root.pinned = FALSE;
cairo_list_add (&rtree->root.link, &rtree->available);
}
 
void
_cairo_rtree_fini (cairo_rtree_t *rtree)
{
int i;
 
if (rtree->root.state == CAIRO_RTREE_NODE_OCCUPIED) {
if (rtree->root.owner != NULL)
*rtree->root.owner = NULL;
} else {
for (i = 0; i < 4 && rtree->root.children[i] != NULL; i++)
_cairo_rtree_node_destroy (rtree, rtree->root.children[i]);
}
 
_cairo_freepool_fini (&rtree->node_freepool);
}
/programs/develop/libraries/cairo/src/cairo-scaled-font-private.h
0,0 → 1,131
/* 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., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
*/
 
#ifndef CAIRO_SCALED_FONT_PRIVATE_H
#define CAIRO_SCALED_FONT_PRIVATE_H
 
#include "cairo.h"
 
#include "cairo-types-private.h"
#include "cairo-list-private.h"
#include "cairo-mutex-type-private.h"
#include "cairo-reference-count-private.h"
 
typedef struct _cairo_scaled_glyph_page cairo_scaled_glyph_page_t;
 
struct _cairo_scaled_font {
/* For most cairo objects, the rule for multiple threads is that
* the user is responsible for any locking if the same object is
* manipulated from multiple threads simultaneously.
*
* However, with the caching that cairo does for scaled fonts, a
* user can easily end up with the same cairo_scaled_font object
* being manipulated from multiple threads without the user ever
* being aware of this, (and in fact, unable to control it).
*
* So, as a special exception, the cairo implementation takes care
* of all locking needed for cairo_scaled_font_t. Most of what is
* in the scaled font is immutable, (which is what allows for the
* sharing in the first place). The things that are modified and
* the locks protecting them are as follows:
*
* 1. The reference count (scaled_font->ref_count)
*
* Modifications to the reference count are protected by the
* _cairo_scaled_font_map_mutex. This is because the reference
* count of a scaled font is intimately related with the font
* map itself, (and the magic holdovers array).
*
* 2. The cache of glyphs (scaled_font->glyphs)
* 3. The backend private data (scaled_font->surface_backend,
* scaled_font->surface_private)
*
* Modifications to these fields are protected with locks on
* scaled_font->mutex in the generic scaled_font code.
*/
 
cairo_hash_entry_t hash_entry;
 
/* useful bits for _cairo_scaled_font_nil */
cairo_status_t status;
cairo_reference_count_t ref_count;
cairo_user_data_array_t user_data;
 
cairo_font_face_t *original_font_face; /* may be NULL */
 
/* hash key members */
cairo_font_face_t *font_face; /* may be NULL */
cairo_matrix_t font_matrix; /* font space => user space */
cairo_matrix_t ctm; /* user space => device space */
cairo_font_options_t options;
 
unsigned int placeholder : 1; /* protected by fontmap mutex */
unsigned int holdover : 1;
unsigned int finished : 1;
 
/* "live" scaled_font members */
cairo_matrix_t scale; /* font space => device space */
cairo_matrix_t scale_inverse; /* device space => font space */
double max_scale; /* maximum x/y expansion of scale */
cairo_font_extents_t extents; /* user space */
cairo_font_extents_t fs_extents; /* font space */
 
/* The mutex protects modification to all subsequent fields. */
cairo_mutex_t mutex;
 
cairo_hash_table_t *glyphs;
cairo_list_t glyph_pages;
cairo_bool_t cache_frozen;
cairo_bool_t global_cache_frozen;
 
/*
* One surface backend may store data in each glyph.
* Whichever surface manages to store its pointer here
* first gets to store data in each glyph
*/
const cairo_surface_backend_t *surface_backend;
void *surface_private;
 
/* font backend managing this scaled font */
const cairo_scaled_font_backend_t *backend;
cairo_list_t link;
};
 
cairo_private void
_cairo_scaled_font_revoke_ownership (cairo_scaled_font_t *scaled_font);
 
#endif /* CAIRO_SCALED_FONT_PRIVATE_H */
/programs/develop/libraries/cairo/src/cairo-scaled-font-subsets-private.h
0,0 → 1,668
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2006 Red Hat, Inc
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
*/
 
#ifndef CAIRO_SCALED_FONT_SUBSETS_PRIVATE_H
#define CAIRO_SCALED_FONT_SUBSETS_PRIVATE_H
 
#include "cairoint.h"
 
#if CAIRO_HAS_FONT_SUBSET
 
typedef struct _cairo_scaled_font_subsets_glyph {
unsigned int font_id;
unsigned int subset_id;
unsigned int subset_glyph_index;
cairo_bool_t is_scaled;
cairo_bool_t is_composite;
double x_advance;
double y_advance;
cairo_bool_t utf8_is_mapped;
uint32_t unicode;
} cairo_scaled_font_subsets_glyph_t;
 
/**
* _cairo_scaled_font_subsets_create_scaled:
*
* Create a new #cairo_scaled_font_subsets_t object which can be used
* to create subsets of any number of #cairo_scaled_font_t
* objects. This allows the (arbitrarily large and sparse) glyph
* indices of a #cairo_scaled_font_t to be mapped to one or more font
* subsets with glyph indices packed into the range
* [0 .. max_glyphs_per_subset).
*
* Return value: a pointer to the newly creates font subsets. The
* caller owns this object and should call
* _cairo_scaled_font_subsets_destroy() when done with it.
**/
cairo_private cairo_scaled_font_subsets_t *
_cairo_scaled_font_subsets_create_scaled (void);
 
/**
* _cairo_scaled_font_subsets_create_simple:
*
* Create a new #cairo_scaled_font_subsets_t object which can be used
* to create font subsets suitable for embedding as Postscript or PDF
* simple fonts.
*
* Glyphs with an outline path available will be mapped to one font
* subset for each font face. Glyphs from bitmap fonts will mapped to
* separate font subsets for each #cairo_scaled_font_t object.
*
* The maximum number of glyphs per subset is 256. Each subset
* reserves the first glyph for the .notdef glyph.
*
* Return value: a pointer to the newly creates font subsets. The
* caller owns this object and should call
* _cairo_scaled_font_subsets_destroy() when done with it.
**/
cairo_private cairo_scaled_font_subsets_t *
_cairo_scaled_font_subsets_create_simple (void);
 
/**
* _cairo_scaled_font_subsets_create_composite:
*
* Create a new #cairo_scaled_font_subsets_t object which can be used
* to create font subsets suitable for embedding as Postscript or PDF
* composite fonts.
*
* Glyphs with an outline path available will be mapped to one font
* subset for each font face. Each unscaled subset has a maximum of
* 65536 glyphs except for Type1 fonts which have a maximum of 256 glyphs.
*
* Glyphs from bitmap fonts will mapped to separate font subsets for
* each #cairo_scaled_font_t object. Each unscaled subset has a maximum
* of 256 glyphs.
*
* Each subset reserves the first glyph for the .notdef glyph.
*
* Return value: a pointer to the newly creates font subsets. The
* caller owns this object and should call
* _cairo_scaled_font_subsets_destroy() when done with it.
**/
cairo_private cairo_scaled_font_subsets_t *
_cairo_scaled_font_subsets_create_composite (void);
 
/**
* _cairo_scaled_font_subsets_destroy:
* @font_subsets: a #cairo_scaled_font_subsets_t object to be destroyed
*
* Destroys @font_subsets and all resources associated with it.
**/
cairo_private void
_cairo_scaled_font_subsets_destroy (cairo_scaled_font_subsets_t *font_subsets);
 
/**
* _cairo_scaled_font_subsets_map_glyph:
* @font_subsets: a #cairo_scaled_font_subsets_t
* @scaled_font: the font of the glyph to be mapped
* @scaled_font_glyph_index: the index of the glyph to be mapped
* @utf8: a string of text encoded in UTF-8
* @utf8_len: length of @utf8 in bytes
* @subset_glyph_ret: return structure containing subset font and glyph id
*
* Map a glyph from a #cairo_scaled_font to a new index within a
* subset of that font. The mapping performed is from the tuple:
*
* (scaled_font, scaled_font_glyph_index)
*
* to the tuple:
*
* (font_id, subset_id, subset_glyph_index)
*
* This mapping is 1:1. If the input tuple has previously mapped, the
* the output tuple previously returned will be returned again.
*
* Otherwise, the return tuple will be constructed as follows:
*
* 1) There is a 1:1 correspondence between the input scaled_font
* value and the output font_id value. If no mapping has been
* previously performed with the scaled_font value then the
* smallest unused font_id value will be returned.
*
* 2) Within the set of output tuples of the same font_id value the
* smallest value of subset_id will be returned such that
* subset_glyph_index does not exceed max_glyphs_per_subset (as
* passed to _cairo_scaled_font_subsets_create()) and that the
* resulting tuple is unique.
*
* 3) The smallest value of subset_glyph_index is returned such that
* the resulting tuple is unique.
*
* The net result is that any #cairo_scaled_font_t will be represented
* by one or more font subsets. Each subset is effectively a tuple of
* (scaled_font, font_id, subset_id) and within each subset there
* exists a mapping of scaled_glyph_font_index to subset_glyph_index.
*
* This final description of a font subset is the same representation
* used by #cairo_scaled_font_subset_t as provided by
* _cairo_scaled_font_subsets_foreach.
*
* @utf8 and @utf8_len specify a string of unicode characters that the
* glyph @scaled_font_glyph_index maps to. If @utf8_is_mapped in
* @subset_glyph_ret is %TRUE, the font subsetting will (where index to
* unicode mapping is supported) ensure that @scaled_font_glyph_index
* maps to @utf8. If @utf8_is_mapped is %FALSE,
* @scaled_font_glyph_index has already been mapped to a different
* unicode string.
*
* The returned values in the #cairo_scaled_font_subsets_glyph_t struct are:
*
* @font_id: The font ID of the mapped glyph
* @subset_id : The subset ID of the mapped glyph within the @font_id
* @subset_glyph_index: The index of the mapped glyph within the @subset_id subset
* @is_scaled: If true, the mapped glyph is from a bitmap font, and separate font
* subset is created for each font scale used. If false, the outline of the mapped glyph
* is available. One font subset for each font face is created.
* @x_advance, @y_advance: When @is_scaled is true, @x_advance and @y_advance contain
* the x and y advance for the mapped glyph in device space.
* When @is_scaled is false, @x_advance and @y_advance contain the x and y advance for
* the the mapped glyph from an unhinted 1 point font.
* @utf8_is_mapped: If true the utf8 string provided to _cairo_scaled_font_subsets_map_glyph()
* is (or already was) the utf8 string mapped to this glyph. If false the glyph is already
* mapped to a different utf8 string.
* @unicode: the unicode character mapped to this glyph by the font backend.
*
* Return value: %CAIRO_STATUS_SUCCESS if successful, or a non-zero
* value indicating an error. Possible errors include
* %CAIRO_STATUS_NO_MEMORY.
**/
cairo_private cairo_status_t
_cairo_scaled_font_subsets_map_glyph (cairo_scaled_font_subsets_t *font_subsets,
cairo_scaled_font_t *scaled_font,
unsigned long scaled_font_glyph_index,
const char * utf8,
int utf8_len,
cairo_scaled_font_subsets_glyph_t *subset_glyph_ret);
 
typedef cairo_status_t
(*cairo_scaled_font_subset_callback_func_t) (cairo_scaled_font_subset_t *font_subset,
void *closure);
 
/**
* _cairo_scaled_font_subsets_foreach:
* @font_subsets: a #cairo_scaled_font_subsets_t
* @font_subset_callback: a function to be called for each font subset
* @closure: closure data for the callback function
*
* Iterate over each unique scaled font subset as created by calls to
* _cairo_scaled_font_subsets_map_glyph(). A subset is determined by
* unique pairs of (font_id, subset_id) as returned by
* _cairo_scaled_font_subsets_map_glyph().
*
* For each subset, @font_subset_callback will be called and will be
* provided with both a #cairo_scaled_font_subset_t object containing
* all the glyphs in the subset as well as the value of @closure.
*
* The #cairo_scaled_font_subset_t object contains the scaled_font,
* the font_id, and the subset_id corresponding to all glyphs
* belonging to the subset. In addition, it contains an array providing
* a mapping between subset glyph indices and the original scaled font
* glyph indices.
*
* The index of the array corresponds to subset_glyph_index values
* returned by _cairo_scaled_font_subsets_map_glyph() while the
* values of the array correspond to the scaled_font_glyph_index
* values passed as input to the same function.
*
* Return value: %CAIRO_STATUS_SUCCESS if successful, or a non-zero
* value indicating an error. Possible errors include
* %CAIRO_STATUS_NO_MEMORY.
**/
cairo_private cairo_status_t
_cairo_scaled_font_subsets_foreach_scaled (cairo_scaled_font_subsets_t *font_subsets,
cairo_scaled_font_subset_callback_func_t font_subset_callback,
void *closure);
 
/**
* _cairo_scaled_font_subsets_foreach_unscaled:
* @font_subsets: a #cairo_scaled_font_subsets_t
* @font_subset_callback: a function to be called for each font subset
* @closure: closure data for the callback function
*
* Iterate over each unique unscaled font subset as created by calls to
* _cairo_scaled_font_subsets_map_glyph(). A subset is determined by
* unique pairs of (font_id, subset_id) as returned by
* _cairo_scaled_font_subsets_map_glyph().
*
* For each subset, @font_subset_callback will be called and will be
* provided with both a #cairo_scaled_font_subset_t object containing
* all the glyphs in the subset as well as the value of @closure.
*
* The #cairo_scaled_font_subset_t object contains the scaled_font,
* the font_id, and the subset_id corresponding to all glyphs
* belonging to the subset. In addition, it contains an array providing
* a mapping between subset glyph indices and the original scaled font
* glyph indices.
*
* The index of the array corresponds to subset_glyph_index values
* returned by _cairo_scaled_font_subsets_map_glyph() while the
* values of the array correspond to the scaled_font_glyph_index
* values passed as input to the same function.
*
* Return value: %CAIRO_STATUS_SUCCESS if successful, or a non-zero
* value indicating an error. Possible errors include
* %CAIRO_STATUS_NO_MEMORY.
**/
cairo_private cairo_status_t
_cairo_scaled_font_subsets_foreach_unscaled (cairo_scaled_font_subsets_t *font_subsets,
cairo_scaled_font_subset_callback_func_t font_subset_callback,
void *closure);
 
/**
* _cairo_scaled_font_subsets_foreach_user:
* @font_subsets: a #cairo_scaled_font_subsets_t
* @font_subset_callback: a function to be called for each font subset
* @closure: closure data for the callback function
*
* Iterate over each unique scaled font subset as created by calls to
* _cairo_scaled_font_subsets_map_glyph(). A subset is determined by
* unique pairs of (font_id, subset_id) as returned by
* _cairo_scaled_font_subsets_map_glyph().
*
* For each subset, @font_subset_callback will be called and will be
* provided with both a #cairo_scaled_font_subset_t object containing
* all the glyphs in the subset as well as the value of @closure.
*
* The #cairo_scaled_font_subset_t object contains the scaled_font,
* the font_id, and the subset_id corresponding to all glyphs
* belonging to the subset. In addition, it contains an array providing
* a mapping between subset glyph indices and the original scaled font
* glyph indices.
*
* The index of the array corresponds to subset_glyph_index values
* returned by _cairo_scaled_font_subsets_map_glyph() while the
* values of the array correspond to the scaled_font_glyph_index
* values passed as input to the same function.
*
* Return value: %CAIRO_STATUS_SUCCESS if successful, or a non-zero
* value indicating an error. Possible errors include
* %CAIRO_STATUS_NO_MEMORY.
**/
cairo_private cairo_status_t
_cairo_scaled_font_subsets_foreach_user (cairo_scaled_font_subsets_t *font_subsets,
cairo_scaled_font_subset_callback_func_t font_subset_callback,
void *closure);
 
/**
* _cairo_scaled_font_subset_create_glyph_names:
* @font_subsets: a #cairo_scaled_font_subsets_t
*
* 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 {
char *font_name;
char *ps_name;
double *widths;
double x_min, y_min, x_max, y_max;
double ascent, descent;
char *data;
unsigned long data_length;
} cairo_cff_subset_t;
 
/**
* _cairo_cff_subset_init:
* @cff_subset: a #cairo_cff_subset_t to initialize
* @font_subset: the #cairo_scaled_font_subset_t to initialize from
*
* If possible (depending on the format of the underlying
* #cairo_scaled_font_t and the font backend in use) generate a
* cff file corresponding to @font_subset and initialize
* @cff_subset with information about the subset and the cff
* data.
*
* Return value: %CAIRO_STATUS_SUCCESS if successful,
* %CAIRO_INT_STATUS_UNSUPPORTED if the font can't be subset as a
* cff file, or an non-zero value indicating an error. Possible
* errors include %CAIRO_STATUS_NO_MEMORY.
**/
cairo_private cairo_status_t
_cairo_cff_subset_init (cairo_cff_subset_t *cff_subset,
const char *name,
cairo_scaled_font_subset_t *font_subset);
 
/**
* _cairo_cff_subset_fini:
* @cff_subset: a #cairo_cff_subset_t
*
* Free all resources associated with @cff_subset. After this
* call, @cff_subset should not be used again without a
* subsequent call to _cairo_cff_subset_init() again first.
**/
cairo_private void
_cairo_cff_subset_fini (cairo_cff_subset_t *cff_subset);
 
/**
* _cairo_cff_fallback_init:
* @cff_subset: a #cairo_cff_subset_t to initialize
* @font_subset: the #cairo_scaled_font_subset_t to initialize from
*
* If possible (depending on the format of the underlying
* #cairo_scaled_font_t and the font backend in use) generate a cff
* file corresponding to @font_subset and initialize @cff_subset
* with information about the subset and the cff data.
*
* Return value: %CAIRO_STATUS_SUCCESS if successful,
* %CAIRO_INT_STATUS_UNSUPPORTED if the font can't be subset as a
* cff file, or an non-zero value indicating an error. Possible
* errors include %CAIRO_STATUS_NO_MEMORY.
**/
cairo_private cairo_status_t
_cairo_cff_fallback_init (cairo_cff_subset_t *cff_subset,
const char *name,
cairo_scaled_font_subset_t *font_subset);
 
/**
* _cairo_cff_fallback_fini:
* @cff_subset: a #cairo_cff_subset_t
*
* Free all resources associated with @cff_subset. After this
* call, @cff_subset should not be used again without a
* subsequent call to _cairo_cff_subset_init() again first.
**/
cairo_private void
_cairo_cff_fallback_fini (cairo_cff_subset_t *cff_subset);
 
typedef struct _cairo_truetype_subset {
char *font_name;
char *ps_name;
double *widths;
double x_min, y_min, x_max, y_max;
double ascent, descent;
unsigned char *data;
unsigned long data_length;
unsigned long *string_offsets;
unsigned long num_string_offsets;
} cairo_truetype_subset_t;
 
/**
* _cairo_truetype_subset_init:
* @truetype_subset: a #cairo_truetype_subset_t to initialize
* @font_subset: the #cairo_scaled_font_subset_t to initialize from
*
* If possible (depending on the format of the underlying
* #cairo_scaled_font_t and the font backend in use) generate a
* truetype file corresponding to @font_subset and initialize
* @truetype_subset with information about the subset and the truetype
* data.
*
* Return value: %CAIRO_STATUS_SUCCESS if successful,
* %CAIRO_INT_STATUS_UNSUPPORTED if the font can't be subset as a
* truetype file, or an non-zero value indicating an error. Possible
* errors include %CAIRO_STATUS_NO_MEMORY.
**/
cairo_private cairo_status_t
_cairo_truetype_subset_init (cairo_truetype_subset_t *truetype_subset,
cairo_scaled_font_subset_t *font_subset);
 
/**
* _cairo_truetype_subset_fini:
* @truetype_subset: a #cairo_truetype_subset_t
*
* Free all resources associated with @truetype_subset. After this
* call, @truetype_subset should not be used again without a
* subsequent call to _cairo_truetype_subset_init() again first.
**/
cairo_private void
_cairo_truetype_subset_fini (cairo_truetype_subset_t *truetype_subset);
 
 
 
typedef struct _cairo_type1_subset {
char *base_font;
double *widths;
double x_min, y_min, x_max, y_max;
double ascent, descent;
char *data;
unsigned long header_length;
unsigned long data_length;
unsigned long trailer_length;
} cairo_type1_subset_t;
 
 
#if CAIRO_HAS_FT_FONT
 
/**
* _cairo_type1_subset_init:
* @type1_subset: a #cairo_type1_subset_t to initialize
* @font_subset: the #cairo_scaled_font_subset_t to initialize from
* @hex_encode: if true the encrypted portion of the font is hex encoded
*
* If possible (depending on the format of the underlying
* #cairo_scaled_font_t and the font backend in use) generate a type1
* file corresponding to @font_subset and initialize @type1_subset
* with information about the subset and the type1 data.
*
* Return value: %CAIRO_STATUS_SUCCESS if successful,
* %CAIRO_INT_STATUS_UNSUPPORTED if the font can't be subset as a type1
* file, or an non-zero value indicating an error. Possible errors
* include %CAIRO_STATUS_NO_MEMORY.
**/
cairo_private cairo_status_t
_cairo_type1_subset_init (cairo_type1_subset_t *type_subset,
const char *name,
cairo_scaled_font_subset_t *font_subset,
cairo_bool_t hex_encode);
 
/**
* _cairo_type1_subset_fini:
* @type1_subset: a #cairo_type1_subset_t
*
* Free all resources associated with @type1_subset. After this call,
* @type1_subset should not be used again without a subsequent call to
* _cairo_truetype_type1_init() again first.
**/
cairo_private void
_cairo_type1_subset_fini (cairo_type1_subset_t *subset);
 
#endif /* CAIRO_HAS_FT_FONT */
 
 
/**
* _cairo_type1_scaled_font_is_type1:
* @scaled_font: a #cairo_scaled_font_t
*
* Return %TRUE if @scaled_font is a Type 1 font, otherwise return %FALSE.
**/
cairo_private cairo_bool_t
_cairo_type1_scaled_font_is_type1 (cairo_scaled_font_t *scaled_font);
 
/**
* _cairo_type1_fallback_init_binary:
* @type1_subset: a #cairo_type1_subset_t to initialize
* @font_subset: the #cairo_scaled_font_subset_t to initialize from
*
* If possible (depending on the format of the underlying
* #cairo_scaled_font_t and the font backend in use) generate a type1
* file corresponding to @font_subset and initialize @type1_subset
* with information about the subset and the type1 data. The encrypted
* part of the font is binary encoded.
*
* Return value: %CAIRO_STATUS_SUCCESS if successful,
* %CAIRO_INT_STATUS_UNSUPPORTED if the font can't be subset as a type1
* file, or an non-zero value indicating an error. Possible errors
* include %CAIRO_STATUS_NO_MEMORY.
**/
cairo_private cairo_status_t
_cairo_type1_fallback_init_binary (cairo_type1_subset_t *type_subset,
const char *name,
cairo_scaled_font_subset_t *font_subset);
 
/**
* _cairo_type1_fallback_init_hexencode:
* @type1_subset: a #cairo_type1_subset_t to initialize
* @font_subset: the #cairo_scaled_font_subset_t to initialize from
*
* If possible (depending on the format of the underlying
* #cairo_scaled_font_t and the font backend in use) generate a type1
* file corresponding to @font_subset and initialize @type1_subset
* with information about the subset and the type1 data. The encrypted
* part of the font is hex encoded.
*
* Return value: %CAIRO_STATUS_SUCCESS if successful,
* %CAIRO_INT_STATUS_UNSUPPORTED if the font can't be subset as a type1
* file, or an non-zero value indicating an error. Possible errors
* include %CAIRO_STATUS_NO_MEMORY.
**/
cairo_private cairo_status_t
_cairo_type1_fallback_init_hex (cairo_type1_subset_t *type_subset,
const char *name,
cairo_scaled_font_subset_t *font_subset);
 
/**
* _cairo_type1_fallback_fini:
* @type1_subset: a #cairo_type1_subset_t
*
* Free all resources associated with @type1_subset. After this call,
* @type1_subset should not be used again without a subsequent call to
* _cairo_truetype_type1_init() again first.
**/
cairo_private void
_cairo_type1_fallback_fini (cairo_type1_subset_t *subset);
 
typedef struct _cairo_type2_charstrings {
int *widths;
long x_min, y_min, x_max, y_max;
long ascent, descent;
cairo_array_t charstrings;
} cairo_type2_charstrings_t;
 
/**
* _cairo_type2_charstrings_init:
* @type2_subset: a #cairo_type2_subset_t to initialize
* @font_subset: the #cairo_scaled_font_subset_t to initialize from
*
* If possible (depending on the format of the underlying
* #cairo_scaled_font_t and the font backend in use) generate type2
* charstrings to @font_subset and initialize @type2_subset
* with information about the subset.
*
* Return value: %CAIRO_STATUS_SUCCESS if successful,
* %CAIRO_INT_STATUS_UNSUPPORTED if the font can't be subset as a type2
* charstrings, or an non-zero value indicating an error. Possible errors
* include %CAIRO_STATUS_NO_MEMORY.
**/
cairo_private cairo_status_t
_cairo_type2_charstrings_init (cairo_type2_charstrings_t *charstrings,
cairo_scaled_font_subset_t *font_subset);
 
/**
* _cairo_type2_charstrings_fini:
* @subset: a #cairo_type2_charstrings_t
*
* Free all resources associated with @type2_charstring. After this call,
* @type2_charstring should not be used again without a subsequent call to
* _cairo_type2_charstring_init() again first.
**/
cairo_private void
_cairo_type2_charstrings_fini (cairo_type2_charstrings_t *charstrings);
 
/**
* _cairo_truetype_create_glyph_to_unicode_map:
* @font_subset: the #cairo_scaled_font_subset_t to initialize from
*
* If possible (depending on the format of the underlying
* #cairo_scaled_font_t and the font backend in use) assign
* the unicode character of each glyph in font_subset to
* fontsubset->to_unicode.
*
* Return value: %CAIRO_STATUS_SUCCESS if successful,
* %CAIRO_INT_STATUS_UNSUPPORTED if the unicode encoding of
* the glyphs is not available. Possible errors include
* %CAIRO_STATUS_NO_MEMORY.
**/
cairo_private cairo_int_status_t
_cairo_truetype_create_glyph_to_unicode_map (cairo_scaled_font_subset_t *font_subset);
 
/**
* _cairo_truetype_index_to_ucs4:
* @scaled_font: the #cairo_scaled_font_t
* @index: the glyph index
* @ucs4: return value for the unicode value of the glyph
*
* If possible (depending on the format of the underlying
* #cairo_scaled_font_t and the font backend in use) assign
* the unicode character of the glyph to @ucs4.
*
* If mapping glyph indices to unicode is supported but the unicode
* value of the specified glyph is not available, @ucs4 is set to -1.
*
* Return value: %CAIRO_STATUS_SUCCESS if successful,
* %CAIRO_INT_STATUS_UNSUPPORTED if mapping glyph indices to unicode
* is not supported. Possible errors include %CAIRO_STATUS_NO_MEMORY.
**/
cairo_private cairo_int_status_t
_cairo_truetype_index_to_ucs4 (cairo_scaled_font_t *scaled_font,
unsigned long index,
uint32_t *ucs4);
 
/**
* _cairo_truetype_read_font_name:
* @scaled_font: the #cairo_scaled_font_t
* @ps_name: returns the PostScript name of the font
* or %NULL if the name could not be found.
* @font_name: returns the font name or %NULL if the name could not be found.
*
* If possible (depending on the format of the underlying
* #cairo_scaled_font_t and the font backend in use) read the
* PostScript and Font names from a TrueType/OpenType font.
*
* The font name is the full name of the font eg "DejaVu Sans Bold".
* The PostScript name is a shortened name with spaces removed
* suitable for use as the font name in a PS or PDF file eg
* "DejaVuSans-Bold".
*
* Return value: %CAIRO_STATUS_SUCCESS if successful,
* %CAIRO_INT_STATUS_UNSUPPORTED if the font is not TrueType/OpenType
* or the name table is not present. Possible errors include
* %CAIRO_STATUS_NO_MEMORY.
**/
cairo_private cairo_int_status_t
_cairo_truetype_read_font_name (cairo_scaled_font_t *scaled_font,
char **ps_name,
char **font_name);
 
#endif /* CAIRO_HAS_FONT_SUBSET */
 
#endif /* CAIRO_SCALED_FONT_SUBSETS_PRIVATE_H */
/programs/develop/libraries/cairo/src/cairo-scaled-font.c
0,0 → 1,2981
/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
/*
* Copyright © 2005 Keith Packard
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Keith Packard
*
* Contributor(s):
* Keith Packard <keithp@keithp.com>
* Carl D. Worth <cworth@cworth.org>
* Graydon Hoare <graydon@redhat.com>
* Owen Taylor <otaylor@redhat.com>
* Behdad Esfahbod <behdad@behdad.org>
* Chris Wilson <chris@chris-wilson.co.uk>
*/
 
#include "cairoint.h"
#include "cairo-error-private.h"
#include "cairo-scaled-font-private.h"
 
#if _XOPEN_SOURCE >= 600 || defined (_ISOC99_SOURCE)
#define ISFINITE(x) isfinite (x)
#else
#define ISFINITE(x) ((x) * (x) >= 0.) /* check for NaNs */
#endif
 
/**
* SECTION:cairo-scaled-font
* @Title: cairo_scaled_font_t
* @Short_Description: Font face at particular size and options
* @See_Also: #cairo_font_face_t, #cairo_matrix_t, #cairo_font_options_t
*
* #cairo_scaled_font_t represents a realization of a font face at a particular
* size and transformation and a certain set of font options.
*/
 
/* Global Glyph Cache
*
* We maintain a global pool of glyphs split between all active fonts. This
* allows a heavily used individual font to cache more glyphs than we could
* manage if we used per-font glyph caches, but at the same time maintains
* fairness across all fonts and provides a cap on the maximum number of
* global glyphs.
*
* The glyphs are allocated in pages, which are capped in the global pool.
* Using pages means we can reduce the frequency at which we have to probe the
* global pool and ameliorates the memory allocation pressure.
*/
 
/* XXX: This number is arbitrary---we've never done any measurement of this. */
#define MAX_GLYPH_PAGES_CACHED 512
static cairo_cache_t cairo_scaled_glyph_page_cache;
 
#define CAIRO_SCALED_GLYPH_PAGE_SIZE 32
struct _cairo_scaled_glyph_page {
cairo_cache_entry_t cache_entry;
 
cairo_list_t link;
 
unsigned int num_glyphs;
cairo_scaled_glyph_t glyphs[CAIRO_SCALED_GLYPH_PAGE_SIZE];
};
 
/*
* Notes:
*
* To store rasterizations of glyphs, we use an image surface and the
* device offset to represent the glyph origin.
*
* A device_transform converts from device space (a conceptual space) to
* surface space. For simple cases of translation only, it's called a
* device_offset and is public API (cairo_surface_[gs]et_device_offset()).
* A possibly better name for those functions could have been
* cairo_surface_[gs]et_origin(). So, that's what they do: they set where
* the device-space origin (0,0) is in the surface. If the origin is inside
* the surface, device_offset values are positive. It may look like this:
*
* Device space:
* (-x,-y) <-- negative numbers
* +----------------+
* | . |
* | . |
* |......(0,0) <---|-- device-space origin
* | |
* | |
* +----------------+
* (width-x,height-y)
*
* Surface space:
* (0,0) <-- surface-space origin
* +---------------+
* | . |
* | . |
* |......(x,y) <--|-- device_offset
* | |
* | |
* +---------------+
* (width,height)
*
* In other words: device_offset is the coordinates of the device-space
* origin relative to the top-left of the surface.
*
* We use device offsets in a couple of places:
*
* - Public API: To let toolkits like Gtk+ give user a surface that
* only represents part of the final destination (say, the expose
* area), but has the same device space as the destination. In these
* cases device_offset is typically negative. Example:
*
* application window
* +---------------+
* | . |
* | (x,y). |
* |......+---+ |
* | | | <--|-- expose area
* | +---+ |
* +---------------+
*
* In this case, the user of cairo API can set the device_space on
* the expose area to (-x,-y) to move the device space origin to that
* of the application window, such that drawing in the expose area
* surface and painting it in the application window has the same
* effect as drawing in the application window directly. Gtk+ has
* been using this feature.
*
* - Glyph surfaces: In most font rendering systems, glyph surfaces
* have an origin at (0,0) and a bounding box that is typically
* represented as (x_bearing,y_bearing,width,height). Depending on
* which way y progresses in the system, y_bearing may typically be
* negative (for systems similar to cairo, with origin at top left),
* or be positive (in systems like PDF with origin at bottom left).
* No matter which is the case, it is important to note that
* (x_bearing,y_bearing) is the coordinates of top-left of the glyph
* relative to the glyph origin. That is, for example:
*
* Scaled-glyph space:
*
* (x_bearing,y_bearing) <-- negative numbers
* +----------------+
* | . |
* | . |
* |......(0,0) <---|-- glyph origin
* | |
* | |
* +----------------+
* (width+x_bearing,height+y_bearing)
*
* Note the similarity of the origin to the device space. That is
* exactly how we use the device_offset to represent scaled glyphs:
* to use the device-space origin as the glyph origin.
*
* Now compare the scaled-glyph space to device-space and surface-space
* and convince yourself that:
*
* (x_bearing,y_bearing) = (-x,-y) = - device_offset
*
* That's right. If you are not convinced yet, contrast the definition
* of the two:
*
* "(x_bearing,y_bearing) is the coordinates of top-left of the
* glyph relative to the glyph origin."
*
* "In other words: device_offset is the coordinates of the
* device-space origin relative to the top-left of the surface."
*
* and note that glyph origin = device-space origin.
*/
 
static void
_cairo_scaled_font_fini_internal (cairo_scaled_font_t *scaled_font);
 
static void
_cairo_scaled_glyph_fini (cairo_scaled_font_t *scaled_font,
cairo_scaled_glyph_t *scaled_glyph)
{
const cairo_surface_backend_t *surface_backend = scaled_font->surface_backend;
 
if (surface_backend != NULL && surface_backend->scaled_glyph_fini != NULL)
surface_backend->scaled_glyph_fini (scaled_glyph, scaled_font);
 
if (scaled_glyph->surface != NULL)
cairo_surface_destroy (&scaled_glyph->surface->base);
 
if (scaled_glyph->path != NULL)
_cairo_path_fixed_destroy (scaled_glyph->path);
 
if (scaled_glyph->recording_surface != NULL) {
cairo_surface_finish (scaled_glyph->recording_surface);
cairo_surface_destroy (scaled_glyph->recording_surface);
}
}
 
#define ZOMBIE 0
static const cairo_scaled_font_t _cairo_scaled_font_nil = {
{ ZOMBIE }, /* hash_entry */
CAIRO_STATUS_NO_MEMORY, /* status */
CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */
{ 0, 0, 0, NULL }, /* user_data */
NULL, /* original_font_face */
NULL, /* font_face */
{ 1., 0., 0., 1., 0, 0}, /* font_matrix */
{ 1., 0., 0., 1., 0, 0}, /* ctm */
{ CAIRO_ANTIALIAS_DEFAULT, /* options */
CAIRO_SUBPIXEL_ORDER_DEFAULT,
CAIRO_HINT_STYLE_DEFAULT,
CAIRO_HINT_METRICS_DEFAULT} ,
FALSE, /* placeholder */
FALSE, /* holdover */
TRUE, /* finished */
{ 1., 0., 0., 1., 0, 0}, /* scale */
{ 1., 0., 0., 1., 0, 0}, /* scale_inverse */
1., /* max_scale */
{ 0., 0., 0., 0., 0. }, /* extents */
{ 0., 0., 0., 0., 0. }, /* fs_extents */
CAIRO_MUTEX_NIL_INITIALIZER,/* mutex */
NULL, /* glyphs */
{ NULL, NULL }, /* pages */
FALSE, /* cache_frozen */
FALSE, /* global_cache_frozen */
NULL, /* surface_backend */
NULL, /* surface_private */
NULL /* backend */
};
 
/**
* _cairo_scaled_font_set_error:
* @scaled_font: a scaled_font
* @status: a status value indicating an error
*
* Atomically sets scaled_font->status to @status and calls _cairo_error;
* Does nothing if status is %CAIRO_STATUS_SUCCESS.
*
* All assignments of an error status to scaled_font->status should happen
* through _cairo_scaled_font_set_error(). Note that due to the nature of
* 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
* breakpoint in _cairo_error() to generate a stack trace for when the
* user causes cairo to detect an error.
*
* Return value: the error status.
**/
cairo_status_t
_cairo_scaled_font_set_error (cairo_scaled_font_t *scaled_font,
cairo_status_t status)
{
if (status == CAIRO_STATUS_SUCCESS)
return 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);
}
 
/**
* cairo_scaled_font_get_type:
* @scaled_font: a #cairo_scaled_font_t
*
* This function returns the type of the backend used to create
* a scaled font. See #cairo_font_type_t for available types.
* However, this function never returns %CAIRO_FONT_TYPE_TOY.
*
* Return value: The type of @scaled_font.
*
* Since: 1.2
**/
cairo_font_type_t
cairo_scaled_font_get_type (cairo_scaled_font_t *scaled_font)
{
if (CAIRO_REFERENCE_COUNT_IS_INVALID (&scaled_font->ref_count))
return CAIRO_FONT_TYPE_TOY;
 
return scaled_font->backend->type;
}
 
/**
* cairo_scaled_font_status:
* @scaled_font: a #cairo_scaled_font_t
*
* Checks whether an error has previously occurred for this
* scaled_font.
*
* Return value: %CAIRO_STATUS_SUCCESS or another error such as
* %CAIRO_STATUS_NO_MEMORY.
**/
cairo_status_t
cairo_scaled_font_status (cairo_scaled_font_t *scaled_font)
{
return scaled_font->status;
}
slim_hidden_def (cairo_scaled_font_status);
 
/* Here we keep a unique mapping from
* font_face/matrix/ctm/font_options => #cairo_scaled_font_t.
*
* Here are the things that we want to map:
*
* a) All otherwise referenced #cairo_scaled_font_t's
* b) Some number of not otherwise referenced #cairo_scaled_font_t's
*
* The implementation uses a hash table which covers (a)
* completely. Then, for (b) we have an array of otherwise
* unreferenced fonts (holdovers) which are expired in
* least-recently-used order.
*
* The cairo_scaled_font_create() code gets to treat this like a regular
* hash table. All of the magic for the little holdover cache is in
* cairo_scaled_font_reference() and cairo_scaled_font_destroy().
*/
 
/* This defines the size of the holdover array ... that is, the number
* of scaled fonts we keep around even when not otherwise referenced
*/
#define CAIRO_SCALED_FONT_MAX_HOLDOVERS 256
 
typedef struct _cairo_scaled_font_map {
cairo_scaled_font_t *mru_scaled_font;
cairo_hash_table_t *hash_table;
cairo_scaled_font_t *holdovers[CAIRO_SCALED_FONT_MAX_HOLDOVERS];
int num_holdovers;
} cairo_scaled_font_map_t;
 
static cairo_scaled_font_map_t *cairo_scaled_font_map;
 
static int
_cairo_scaled_font_keys_equal (const void *abstract_key_a, const void *abstract_key_b);
 
static cairo_scaled_font_map_t *
_cairo_scaled_font_map_lock (void)
{
CAIRO_MUTEX_LOCK (_cairo_scaled_font_map_mutex);
 
if (cairo_scaled_font_map == NULL) {
cairo_scaled_font_map = malloc (sizeof (cairo_scaled_font_map_t));
if (unlikely (cairo_scaled_font_map == NULL))
goto CLEANUP_MUTEX_LOCK;
 
cairo_scaled_font_map->mru_scaled_font = NULL;
cairo_scaled_font_map->hash_table =
_cairo_hash_table_create (_cairo_scaled_font_keys_equal);
 
if (unlikely (cairo_scaled_font_map->hash_table == NULL))
goto CLEANUP_SCALED_FONT_MAP;
 
cairo_scaled_font_map->num_holdovers = 0;
}
 
return cairo_scaled_font_map;
 
CLEANUP_SCALED_FONT_MAP:
free (cairo_scaled_font_map);
cairo_scaled_font_map = NULL;
CLEANUP_MUTEX_LOCK:
CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_map_mutex);
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return NULL;
}
 
static void
_cairo_scaled_font_map_unlock (void)
{
CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_map_mutex);
}
 
void
_cairo_scaled_font_map_destroy (void)
{
cairo_scaled_font_map_t *font_map;
cairo_scaled_font_t *scaled_font;
 
CAIRO_MUTEX_LOCK (_cairo_scaled_font_map_mutex);
 
font_map = cairo_scaled_font_map;
if (unlikely (font_map == NULL)) {
goto CLEANUP_MUTEX_LOCK;
}
 
scaled_font = font_map->mru_scaled_font;
if (scaled_font != NULL) {
CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_map_mutex);
cairo_scaled_font_destroy (scaled_font);
CAIRO_MUTEX_LOCK (_cairo_scaled_font_map_mutex);
}
 
/* remove scaled_fonts starting from the end so that font_map->holdovers
* is always in a consistent state when we release the mutex. */
while (font_map->num_holdovers) {
scaled_font = font_map->holdovers[font_map->num_holdovers-1];
assert (! CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&scaled_font->ref_count));
_cairo_hash_table_remove (font_map->hash_table,
&scaled_font->hash_entry);
 
font_map->num_holdovers--;
 
/* This releases the font_map lock to avoid the possibility of a
* recursive deadlock when the scaled font destroy closure gets
* called
*/
_cairo_scaled_font_fini (scaled_font);
 
free (scaled_font);
}
 
_cairo_hash_table_destroy (font_map->hash_table);
 
free (cairo_scaled_font_map);
cairo_scaled_font_map = NULL;
 
CLEANUP_MUTEX_LOCK:
CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_map_mutex);
}
static void
_cairo_scaled_glyph_page_destroy (void *closure)
{
cairo_scaled_glyph_page_t *page = closure;
cairo_scaled_font_t *scaled_font;
unsigned int n;
 
scaled_font = (cairo_scaled_font_t *) page->cache_entry.hash;
for (n = 0; n < page->num_glyphs; n++) {
_cairo_hash_table_remove (scaled_font->glyphs,
&page->glyphs[n].hash_entry);
_cairo_scaled_glyph_fini (scaled_font, &page->glyphs[n]);
}
 
cairo_list_del (&page->link);
 
free (page);
}
 
/* If a scaled font wants to unlock the font map while still being
* created (needed for user-fonts), we need to take extra care not
* ending up with multiple identical scaled fonts being created.
*
* What we do is, we create a fake identical scaled font, and mark
* it as placeholder, lock its mutex, and insert that in the fontmap
* hash table. This makes other code trying to create an identical
* scaled font to just wait and retry.
*
* The reason we have to create a fake scaled font instead of just using
* scaled_font is for lifecycle management: we need to (or rather,
* other code needs to) reference the scaled_font in the hash table.
* We can't do that on the input scaled_font as it may be freed by
* font backend upon error.
*/
 
cairo_status_t
_cairo_scaled_font_register_placeholder_and_unlock_font_map (cairo_scaled_font_t *scaled_font)
{
cairo_status_t status;
cairo_scaled_font_t *placeholder_scaled_font;
 
assert (CAIRO_MUTEX_IS_LOCKED (_cairo_scaled_font_map_mutex));
 
status = scaled_font->status;
if (unlikely (status))
return status;
 
placeholder_scaled_font = malloc (sizeof (cairo_scaled_font_t));
if (unlikely (placeholder_scaled_font == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
/* full initialization is wasteful, but who cares... */
status = _cairo_scaled_font_init (placeholder_scaled_font,
scaled_font->font_face,
&scaled_font->font_matrix,
&scaled_font->ctm,
&scaled_font->options,
NULL);
if (unlikely (status))
goto FREE_PLACEHOLDER;
 
placeholder_scaled_font->placeholder = TRUE;
 
status = _cairo_hash_table_insert (cairo_scaled_font_map->hash_table,
&placeholder_scaled_font->hash_entry);
if (unlikely (status))
goto FINI_PLACEHOLDER;
 
CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_map_mutex);
CAIRO_MUTEX_LOCK (placeholder_scaled_font->mutex);
 
return CAIRO_STATUS_SUCCESS;
 
FINI_PLACEHOLDER:
_cairo_scaled_font_fini_internal (placeholder_scaled_font);
FREE_PLACEHOLDER:
free (placeholder_scaled_font);
 
return _cairo_scaled_font_set_error (scaled_font, status);
}
 
void
_cairo_scaled_font_unregister_placeholder_and_lock_font_map (cairo_scaled_font_t *scaled_font)
{
cairo_scaled_font_t *placeholder_scaled_font;
 
CAIRO_MUTEX_LOCK (_cairo_scaled_font_map_mutex);
 
placeholder_scaled_font =
_cairo_hash_table_lookup (cairo_scaled_font_map->hash_table,
&scaled_font->hash_entry);
assert (placeholder_scaled_font != NULL);
assert (placeholder_scaled_font->placeholder);
assert (CAIRO_MUTEX_IS_LOCKED (placeholder_scaled_font->mutex));
 
_cairo_hash_table_remove (cairo_scaled_font_map->hash_table,
&placeholder_scaled_font->hash_entry);
 
CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_map_mutex);
 
CAIRO_MUTEX_UNLOCK (placeholder_scaled_font->mutex);
cairo_scaled_font_destroy (placeholder_scaled_font);
 
CAIRO_MUTEX_LOCK (_cairo_scaled_font_map_mutex);
}
 
static void
_cairo_scaled_font_placeholder_wait_for_creation_to_finish (cairo_scaled_font_t *placeholder_scaled_font)
{
/* reference the place holder so it doesn't go away */
cairo_scaled_font_reference (placeholder_scaled_font);
 
/* now unlock the fontmap mutex so creation has a chance to finish */
CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_map_mutex);
 
/* wait on placeholder mutex until we are awaken */
CAIRO_MUTEX_LOCK (placeholder_scaled_font->mutex);
 
/* ok, creation done. just clean up and back out */
CAIRO_MUTEX_UNLOCK (placeholder_scaled_font->mutex);
cairo_scaled_font_destroy (placeholder_scaled_font);
 
CAIRO_MUTEX_LOCK (_cairo_scaled_font_map_mutex);
}
 
/* Fowler / Noll / Vo (FNV) Hash (http://www.isthe.com/chongo/tech/comp/fnv/)
*
* Not necessarily better than a lot of other hashes, but should be OK, and
* well tested with binary data.
*/
 
#define FNV_32_PRIME ((uint32_t)0x01000193)
#define FNV1_32_INIT ((uint32_t)0x811c9dc5)
 
static uint32_t
_hash_matrix_fnv (const cairo_matrix_t *matrix,
uint32_t hval)
{
const uint8_t *buffer = (const uint8_t *) matrix;
int len = sizeof (cairo_matrix_t);
do {
hval *= FNV_32_PRIME;
hval ^= *buffer++;
} while (--len);
 
return hval;
}
 
static uint32_t
_hash_mix_bits (uint32_t hash)
{
hash += hash << 12;
hash ^= hash >> 7;
hash += hash << 3;
hash ^= hash >> 17;
hash += hash << 5;
return hash;
}
 
static void
_cairo_scaled_font_init_key (cairo_scaled_font_t *scaled_font,
cairo_font_face_t *font_face,
const cairo_matrix_t *font_matrix,
const cairo_matrix_t *ctm,
const cairo_font_options_t *options)
{
uint32_t hash = FNV1_32_INIT;
 
scaled_font->status = CAIRO_STATUS_SUCCESS;
scaled_font->placeholder = FALSE;
scaled_font->font_face = font_face;
scaled_font->font_matrix = *font_matrix;
scaled_font->ctm = *ctm;
/* ignore translation values in the ctm */
scaled_font->ctm.x0 = 0.;
scaled_font->ctm.y0 = 0.;
_cairo_font_options_init_copy (&scaled_font->options, options);
 
/* We do a bytewise hash on the font matrices */
hash = _hash_matrix_fnv (&scaled_font->font_matrix, hash);
hash = _hash_matrix_fnv (&scaled_font->ctm, hash);
hash = _hash_mix_bits (hash);
 
hash ^= (unsigned long) scaled_font->font_face;
hash ^= cairo_font_options_hash (&scaled_font->options);
 
/* final mixing of bits */
hash = _hash_mix_bits (hash);
 
assert (hash != ZOMBIE);
scaled_font->hash_entry.hash = hash;
}
 
static cairo_bool_t
_cairo_scaled_font_keys_equal (const void *abstract_key_a,
const void *abstract_key_b)
{
const cairo_scaled_font_t *key_a = abstract_key_a;
const cairo_scaled_font_t *key_b = abstract_key_b;
 
if (key_a->hash_entry.hash != key_b->hash_entry.hash)
return FALSE;
 
return key_a->font_face == key_b->font_face &&
memcmp ((unsigned char *)(&key_a->font_matrix.xx),
(unsigned char *)(&key_b->font_matrix.xx),
sizeof(cairo_matrix_t)) == 0 &&
memcmp ((unsigned char *)(&key_a->ctm.xx),
(unsigned char *)(&key_b->ctm.xx),
sizeof(cairo_matrix_t)) == 0 &&
cairo_font_options_equal (&key_a->options, &key_b->options);
}
 
static cairo_bool_t
_cairo_scaled_font_matches (const cairo_scaled_font_t *scaled_font,
const cairo_font_face_t *font_face,
const cairo_matrix_t *font_matrix,
const cairo_matrix_t *ctm,
const cairo_font_options_t *options)
{
return scaled_font->original_font_face == font_face &&
memcmp ((unsigned char *)(&scaled_font->font_matrix.xx),
(unsigned char *)(&font_matrix->xx),
sizeof(cairo_matrix_t)) == 0 &&
memcmp ((unsigned char *)(&scaled_font->ctm.xx),
(unsigned char *)(&ctm->xx),
sizeof(cairo_matrix_t)) == 0 &&
cairo_font_options_equal (&scaled_font->options, options);
}
 
static cairo_bool_t
_cairo_scaled_glyphs_equal (const void *abstract_a, const void *abstract_b)
{
const cairo_scaled_glyph_t *a = abstract_a;
const cairo_scaled_glyph_t *b = abstract_b;
 
return a->hash_entry.hash == b->hash_entry.hash;
}
 
/*
* Basic #cairo_scaled_font_t object management
*/
 
cairo_status_t
_cairo_scaled_font_init (cairo_scaled_font_t *scaled_font,
cairo_font_face_t *font_face,
const cairo_matrix_t *font_matrix,
const cairo_matrix_t *ctm,
const cairo_font_options_t *options,
const cairo_scaled_font_backend_t *backend)
{
cairo_status_t status;
 
status = cairo_font_options_status ((cairo_font_options_t *) options);
if (unlikely (status))
return status;
 
_cairo_scaled_font_init_key (scaled_font, font_face,
font_matrix, ctm, options);
 
cairo_matrix_multiply (&scaled_font->scale,
&scaled_font->font_matrix,
&scaled_font->ctm);
 
scaled_font->max_scale = MAX (fabs (scaled_font->scale.xx) + fabs (scaled_font->scale.xy),
fabs (scaled_font->scale.yx) + fabs (scaled_font->scale.yy));
scaled_font->scale_inverse = scaled_font->scale;
status = cairo_matrix_invert (&scaled_font->scale_inverse);
if (unlikely (status)) {
/* If the font scale matrix is rank 0, just using an all-zero inverse matrix
* makes everything work correctly. This make font size 0 work without
* producing an error.
*
* FIXME: If the scale is rank 1, we still go into error mode. But then
* again, that's what we do everywhere in cairo.
*
* Also, the check for == 0. below may be too harsh...
*/
if (_cairo_matrix_is_scale_0 (&scaled_font->scale)) {
cairo_matrix_init (&scaled_font->scale_inverse,
0, 0, 0, 0,
-scaled_font->scale.x0,
-scaled_font->scale.y0);
} else
return status;
}
 
scaled_font->glyphs = _cairo_hash_table_create (_cairo_scaled_glyphs_equal);
if (unlikely (scaled_font->glyphs == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
cairo_list_init (&scaled_font->glyph_pages);
scaled_font->cache_frozen = FALSE;
scaled_font->global_cache_frozen = FALSE;
 
scaled_font->holdover = FALSE;
scaled_font->finished = FALSE;
 
CAIRO_REFERENCE_COUNT_INIT (&scaled_font->ref_count, 1);
 
_cairo_user_data_array_init (&scaled_font->user_data);
 
cairo_font_face_reference (font_face);
scaled_font->original_font_face = NULL;
 
CAIRO_MUTEX_INIT (scaled_font->mutex);
 
scaled_font->surface_backend = NULL;
scaled_font->surface_private = NULL;
 
scaled_font->backend = backend;
cairo_list_init (&scaled_font->link);
 
return CAIRO_STATUS_SUCCESS;
}
 
void
_cairo_scaled_font_freeze_cache (cairo_scaled_font_t *scaled_font)
{
/* ensure we do not modify an error object */
assert (scaled_font->status == CAIRO_STATUS_SUCCESS);
 
CAIRO_MUTEX_LOCK (scaled_font->mutex);
scaled_font->cache_frozen = TRUE;
}
 
void
_cairo_scaled_font_thaw_cache (cairo_scaled_font_t *scaled_font)
{
scaled_font->cache_frozen = FALSE;
 
if (scaled_font->global_cache_frozen) {
CAIRO_MUTEX_LOCK (_cairo_scaled_glyph_page_cache_mutex);
_cairo_cache_thaw (&cairo_scaled_glyph_page_cache);
CAIRO_MUTEX_UNLOCK (_cairo_scaled_glyph_page_cache_mutex);
 
scaled_font->global_cache_frozen = FALSE;
}
 
CAIRO_MUTEX_UNLOCK (scaled_font->mutex);
}
 
void
_cairo_scaled_font_reset_cache (cairo_scaled_font_t *scaled_font)
{
assert (! scaled_font->cache_frozen);
 
CAIRO_MUTEX_LOCK (_cairo_scaled_glyph_page_cache_mutex);
while (! cairo_list_is_empty (&scaled_font->glyph_pages)) {
_cairo_cache_remove (&cairo_scaled_glyph_page_cache,
&cairo_list_first_entry (&scaled_font->glyph_pages,
cairo_scaled_glyph_page_t,
link)->cache_entry);
}
CAIRO_MUTEX_UNLOCK (_cairo_scaled_glyph_page_cache_mutex);
}
 
cairo_status_t
_cairo_scaled_font_set_metrics (cairo_scaled_font_t *scaled_font,
cairo_font_extents_t *fs_metrics)
{
cairo_status_t status;
double font_scale_x, font_scale_y;
 
scaled_font->fs_extents = *fs_metrics;
 
status = _cairo_matrix_compute_basis_scale_factors (&scaled_font->font_matrix,
&font_scale_x, &font_scale_y,
1);
if (unlikely (status))
return status;
 
/*
* The font responded in unscaled units, scale by the font
* matrix scale factors to get to user space
*/
 
scaled_font->extents.ascent = fs_metrics->ascent * font_scale_y;
scaled_font->extents.descent = fs_metrics->descent * font_scale_y;
scaled_font->extents.height = fs_metrics->height * font_scale_y;
scaled_font->extents.max_x_advance = fs_metrics->max_x_advance * font_scale_x;
scaled_font->extents.max_y_advance = fs_metrics->max_y_advance * font_scale_y;
 
return CAIRO_STATUS_SUCCESS;
}
 
static void
_cairo_scaled_font_fini_internal (cairo_scaled_font_t *scaled_font)
{
scaled_font->finished = TRUE;
 
_cairo_scaled_font_reset_cache (scaled_font);
_cairo_hash_table_destroy (scaled_font->glyphs);
 
cairo_font_face_destroy (scaled_font->font_face);
cairo_font_face_destroy (scaled_font->original_font_face);
 
CAIRO_MUTEX_FINI (scaled_font->mutex);
 
if (scaled_font->surface_backend != NULL &&
scaled_font->surface_backend->scaled_font_fini != NULL)
scaled_font->surface_backend->scaled_font_fini (scaled_font);
 
if (scaled_font->backend != NULL && scaled_font->backend->fini != NULL)
scaled_font->backend->fini (scaled_font);
 
_cairo_user_data_array_fini (&scaled_font->user_data);
}
 
/* XXX: allow multiple backends to share the font */
void
_cairo_scaled_font_revoke_ownership (cairo_scaled_font_t *scaled_font)
{
if (scaled_font->surface_backend == NULL)
return;
 
_cairo_scaled_font_reset_cache (scaled_font);
 
if (scaled_font->surface_backend->scaled_font_fini != NULL)
scaled_font->surface_backend->scaled_font_fini (scaled_font);
 
scaled_font->surface_backend = NULL;
scaled_font->surface_private = NULL;
}
 
void
_cairo_scaled_font_fini (cairo_scaled_font_t *scaled_font)
{
/* Release the lock to avoid the possibility of a recursive
* deadlock when the scaled font destroy closure gets called. */
CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_map_mutex);
_cairo_scaled_font_fini_internal (scaled_font);
CAIRO_MUTEX_LOCK (_cairo_scaled_font_map_mutex);
}
 
/**
* cairo_scaled_font_create:
* @font_face: a #cairo_font_face_t
* @font_matrix: font space to user space transformation matrix for the
* font. In the simplest case of a N point font, this matrix is
* just a scale by N, but it can also be used to shear the font
* or stretch it unequally along the two axes. See
* cairo_set_font_matrix().
* @ctm: user to device transformation matrix with which the font will
* be used.
* @options: options to use when getting metrics for the font and
* rendering with it.
*
* Creates a #cairo_scaled_font_t object from a font face and matrices that
* describe the size of the font and the environment in which it will
* be used.
*
* Return value: a newly created #cairo_scaled_font_t. Destroy with
* cairo_scaled_font_destroy()
**/
cairo_scaled_font_t *
cairo_scaled_font_create (cairo_font_face_t *font_face,
const cairo_matrix_t *font_matrix,
const cairo_matrix_t *ctm,
const cairo_font_options_t *options)
{
cairo_status_t status;
cairo_scaled_font_map_t *font_map;
cairo_font_face_t *original_font_face = font_face;
cairo_scaled_font_t key, *old = NULL, *scaled_font = NULL, *dead = NULL;
double det;
 
status = font_face->status;
if (unlikely (status))
return _cairo_scaled_font_create_in_error (status);
 
det = _cairo_matrix_compute_determinant (font_matrix);
if (! ISFINITE (det))
return _cairo_scaled_font_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_MATRIX));
 
det = _cairo_matrix_compute_determinant (ctm);
if (! ISFINITE (det))
return _cairo_scaled_font_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_MATRIX));
 
status = cairo_font_options_status ((cairo_font_options_t *) options);
if (unlikely (status))
return _cairo_scaled_font_create_in_error (status);
 
/* Note that degenerate ctm or font_matrix *are* allowed.
* We want to support a font size of 0. */
 
font_map = _cairo_scaled_font_map_lock ();
if (unlikely (font_map == NULL))
return _cairo_scaled_font_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
 
scaled_font = font_map->mru_scaled_font;
if (scaled_font != NULL &&
_cairo_scaled_font_matches (scaled_font,
font_face, font_matrix, ctm, options))
{
assert (scaled_font->hash_entry.hash != ZOMBIE);
assert (! scaled_font->placeholder);
 
if (likely (scaled_font->status == CAIRO_STATUS_SUCCESS)) {
/* We increment the reference count manually here, (rather
* than calling into cairo_scaled_font_reference), since we
* must modify the reference count while our lock is still
* held. */
_cairo_reference_count_inc (&scaled_font->ref_count);
_cairo_scaled_font_map_unlock ();
return scaled_font;
}
 
/* the font has been put into an error status - abandon the cache */
_cairo_hash_table_remove (font_map->hash_table,
&scaled_font->hash_entry);
scaled_font->hash_entry.hash = ZOMBIE;
dead = scaled_font;
font_map->mru_scaled_font = NULL;
 
if (font_face->backend->get_implementation != NULL) {
font_face = font_face->backend->get_implementation (font_face,
font_matrix,
ctm,
options);
if (unlikely (font_face->status)) {
_cairo_scaled_font_map_unlock ();
cairo_scaled_font_destroy (scaled_font);
return _cairo_scaled_font_create_in_error (font_face->status);
}
}
 
_cairo_scaled_font_init_key (&key, font_face,
font_matrix, ctm, options);
}
else
{
if (font_face->backend->get_implementation != NULL) {
font_face = font_face->backend->get_implementation (font_face,
font_matrix,
ctm,
options);
if (unlikely (font_face->status)) {
_cairo_scaled_font_map_unlock ();
return _cairo_scaled_font_create_in_error (font_face->status);
}
}
 
_cairo_scaled_font_init_key (&key, font_face,
font_matrix, ctm, options);
 
while ((scaled_font = _cairo_hash_table_lookup (font_map->hash_table,
&key.hash_entry)))
{
if (! scaled_font->placeholder)
break;
 
/* If the scaled font is being created (happens for user-font),
* just wait until it's done, then retry */
_cairo_scaled_font_placeholder_wait_for_creation_to_finish (scaled_font);
}
 
/* Return existing scaled_font if it exists in the hash table. */
if (scaled_font != NULL) {
/* If the original reference count is 0, then this font must have
* been found in font_map->holdovers, (which means this caching is
* actually working). So now we remove it from the holdovers
* array, unless we caught the font in the middle of destruction.
*/
if (! CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&scaled_font->ref_count)) {
if (scaled_font->holdover) {
int i;
 
for (i = 0; i < font_map->num_holdovers; i++) {
if (font_map->holdovers[i] == scaled_font) {
font_map->num_holdovers--;
memmove (&font_map->holdovers[i],
&font_map->holdovers[i+1],
(font_map->num_holdovers - i) * sizeof (cairo_scaled_font_t*));
break;
}
}
 
scaled_font->holdover = FALSE;
}
 
/* reset any error status */
scaled_font->status = CAIRO_STATUS_SUCCESS;
}
 
if (likely (scaled_font->status == CAIRO_STATUS_SUCCESS)) {
/* We increment the reference count manually here, (rather
* than calling into cairo_scaled_font_reference), since we
* must modify the reference count while our lock is still
* held. */
 
old = font_map->mru_scaled_font;
font_map->mru_scaled_font = scaled_font;
/* increment reference count for the mru cache */
_cairo_reference_count_inc (&scaled_font->ref_count);
/* and increment for the returned reference */
_cairo_reference_count_inc (&scaled_font->ref_count);
_cairo_scaled_font_map_unlock ();
 
cairo_scaled_font_destroy (old);
if (font_face != original_font_face)
cairo_font_face_destroy (font_face);
 
return scaled_font;
}
 
/* the font has been put into an error status - abandon the cache */
_cairo_hash_table_remove (font_map->hash_table,
&scaled_font->hash_entry);
scaled_font->hash_entry.hash = ZOMBIE;
}
}
 
/* Otherwise create it and insert it into the hash table. */
status = font_face->backend->scaled_font_create (font_face, font_matrix,
ctm, options, &scaled_font);
/* Did we leave the backend in an error state? */
if (unlikely (status)) {
_cairo_scaled_font_map_unlock ();
if (font_face != original_font_face)
cairo_font_face_destroy (font_face);
 
if (dead != NULL)
cairo_scaled_font_destroy (dead);
 
status = _cairo_font_face_set_error (font_face, status);
return _cairo_scaled_font_create_in_error (status);
}
/* Or did we encounter an error whilst constructing the scaled font? */
if (unlikely (scaled_font->status)) {
_cairo_scaled_font_map_unlock ();
if (font_face != original_font_face)
cairo_font_face_destroy (font_face);
 
if (dead != NULL)
cairo_scaled_font_destroy (dead);
 
return scaled_font;
}
 
/* Our caching above is defeated if the backend switches fonts on us -
* e.g. old incarnations of toy-font-face and lazily resolved
* ft-font-faces
*/
assert (scaled_font->font_face == font_face);
 
scaled_font->original_font_face =
cairo_font_face_reference (original_font_face);
 
status = _cairo_hash_table_insert (font_map->hash_table,
&scaled_font->hash_entry);
if (likely (status == CAIRO_STATUS_SUCCESS)) {
old = font_map->mru_scaled_font;
font_map->mru_scaled_font = scaled_font;
_cairo_reference_count_inc (&scaled_font->ref_count);
}
 
_cairo_scaled_font_map_unlock ();
 
cairo_scaled_font_destroy (old);
if (font_face != original_font_face)
cairo_font_face_destroy (font_face);
 
if (dead != NULL)
cairo_scaled_font_destroy (dead);
 
if (unlikely (status)) {
/* We can't call _cairo_scaled_font_destroy here since it expects
* that the font has already been successfully inserted into the
* hash table. */
_cairo_scaled_font_fini_internal (scaled_font);
free (scaled_font);
return _cairo_scaled_font_create_in_error (status);
}
 
return scaled_font;
}
slim_hidden_def (cairo_scaled_font_create);
 
static cairo_scaled_font_t *_cairo_scaled_font_nil_objects[CAIRO_STATUS_LAST_STATUS + 1];
 
/* XXX This should disappear in favour of a common pool of error objects. */
cairo_scaled_font_t *
_cairo_scaled_font_create_in_error (cairo_status_t status)
{
cairo_scaled_font_t *scaled_font;
 
assert (status != CAIRO_STATUS_SUCCESS);
 
if (status == CAIRO_STATUS_NO_MEMORY)
return (cairo_scaled_font_t *) &_cairo_scaled_font_nil;
 
CAIRO_MUTEX_LOCK (_cairo_scaled_font_error_mutex);
scaled_font = _cairo_scaled_font_nil_objects[status];
if (unlikely (scaled_font == NULL)) {
scaled_font = malloc (sizeof (cairo_scaled_font_t));
if (unlikely (scaled_font == NULL)) {
CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_error_mutex);
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_scaled_font_t *) &_cairo_scaled_font_nil;
}
 
*scaled_font = _cairo_scaled_font_nil;
scaled_font->status = status;
_cairo_scaled_font_nil_objects[status] = scaled_font;
}
CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_error_mutex);
 
return scaled_font;
}
 
void
_cairo_scaled_font_reset_static_data (void)
{
int status;
 
CAIRO_MUTEX_LOCK (_cairo_scaled_font_error_mutex);
for (status = CAIRO_STATUS_SUCCESS;
status <= CAIRO_STATUS_LAST_STATUS;
status++)
{
if (_cairo_scaled_font_nil_objects[status] != NULL) {
free (_cairo_scaled_font_nil_objects[status]);
_cairo_scaled_font_nil_objects[status] = NULL;
}
}
CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_error_mutex);
 
CAIRO_MUTEX_LOCK (_cairo_scaled_glyph_page_cache_mutex);
if (cairo_scaled_glyph_page_cache.hash_table != NULL) {
_cairo_cache_fini (&cairo_scaled_glyph_page_cache);
cairo_scaled_glyph_page_cache.hash_table = NULL;
}
CAIRO_MUTEX_UNLOCK (_cairo_scaled_glyph_page_cache_mutex);
}
 
/**
* cairo_scaled_font_reference:
* @scaled_font: a #cairo_scaled_font_t, (may be %NULL in which case
* this function does nothing)
*
* Increases the reference count on @scaled_font by one. This prevents
* @scaled_font from being destroyed until a matching call to
* cairo_scaled_font_destroy() is made.
*
* The number of references to a #cairo_scaled_font_t can be get using
* cairo_scaled_font_get_reference_count().
*
* Returns: the referenced #cairo_scaled_font_t
**/
cairo_scaled_font_t *
cairo_scaled_font_reference (cairo_scaled_font_t *scaled_font)
{
if (scaled_font == NULL ||
CAIRO_REFERENCE_COUNT_IS_INVALID (&scaled_font->ref_count))
return scaled_font;
 
assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&scaled_font->ref_count));
 
_cairo_reference_count_inc (&scaled_font->ref_count);
 
return scaled_font;
}
slim_hidden_def (cairo_scaled_font_reference);
 
/**
* cairo_scaled_font_destroy:
* @scaled_font: a #cairo_scaled_font_t
*
* Decreases the reference count on @font by one. If the result
* is zero, then @font and all associated resources are freed.
* See cairo_scaled_font_reference().
**/
void
cairo_scaled_font_destroy (cairo_scaled_font_t *scaled_font)
{
cairo_scaled_font_t *lru = NULL;
cairo_scaled_font_map_t *font_map;
 
assert (CAIRO_MUTEX_IS_UNLOCKED (_cairo_scaled_font_map_mutex));
 
if (scaled_font == NULL ||
CAIRO_REFERENCE_COUNT_IS_INVALID (&scaled_font->ref_count))
return;
 
assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&scaled_font->ref_count));
 
if (! _cairo_reference_count_dec_and_test (&scaled_font->ref_count))
return;
 
font_map = _cairo_scaled_font_map_lock ();
assert (font_map != NULL);
 
/* Another thread may have resurrected the font whilst we waited */
if (! CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&scaled_font->ref_count)) {
if (! scaled_font->placeholder &&
scaled_font->hash_entry.hash != ZOMBIE)
{
/* Another thread may have already inserted us into the holdovers */
if (scaled_font->holdover)
goto unlock;
 
/* Rather than immediately destroying this object, we put it into
* the font_map->holdovers array in case it will get used again
* soon (and is why we must hold the lock over the atomic op on
* 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) {
lru = font_map->holdovers[0];
assert (! CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&lru->ref_count));
 
_cairo_hash_table_remove (font_map->hash_table,
&lru->hash_entry);
 
font_map->num_holdovers--;
memmove (&font_map->holdovers[0],
&font_map->holdovers[1],
font_map->num_holdovers * sizeof (cairo_scaled_font_t*));
}
 
font_map->holdovers[font_map->num_holdovers++] = scaled_font;
scaled_font->holdover = TRUE;
} else
lru = scaled_font;
}
 
unlock:
_cairo_scaled_font_map_unlock ();
 
/* If we pulled an item from the holdovers array, (while the font
* map lock was held, of course), then there is no way that anyone
* else could have acquired a reference to it. So we can now
* safely call fini on it without any lock held. This is desirable
* as we never want to call into any backend function with a lock
* held. */
if (lru != NULL) {
_cairo_scaled_font_fini_internal (lru);
free (lru);
}
}
slim_hidden_def (cairo_scaled_font_destroy);
 
/**
* cairo_scaled_font_get_reference_count:
* @scaled_font: a #cairo_scaled_font_t
*
* Returns the current reference count of @scaled_font.
*
* Return value: the current reference count of @scaled_font. If the
* object is a nil object, 0 will be returned.
*
* Since: 1.4
**/
unsigned int
cairo_scaled_font_get_reference_count (cairo_scaled_font_t *scaled_font)
{
if (scaled_font == NULL ||
CAIRO_REFERENCE_COUNT_IS_INVALID (&scaled_font->ref_count))
return 0;
 
return CAIRO_REFERENCE_COUNT_GET_VALUE (&scaled_font->ref_count);
}
 
/**
* cairo_scaled_font_get_user_data:
* @scaled_font: a #cairo_scaled_font_t
* @key: the address of the #cairo_user_data_key_t the user data was
* attached to
*
* Return user data previously attached to @scaled_font using the
* specified key. If no user data has been attached with the given
* key this function returns %NULL.
*
* Return value: the user data previously attached or %NULL.
*
* Since: 1.4
**/
void *
cairo_scaled_font_get_user_data (cairo_scaled_font_t *scaled_font,
const cairo_user_data_key_t *key)
{
return _cairo_user_data_array_get_data (&scaled_font->user_data,
key);
}
slim_hidden_def (cairo_scaled_font_get_user_data);
 
/**
* cairo_scaled_font_set_user_data:
* @scaled_font: a #cairo_scaled_font_t
* @key: the address of a #cairo_user_data_key_t to attach the user data to
* @user_data: the user data to attach to the #cairo_scaled_font_t
* @destroy: a #cairo_destroy_func_t which will be called when the
* #cairo_t is destroyed or when new user data is attached using the
* same key.
*
* Attach user data to @scaled_font. To remove user data from a surface,
* call this function with the key that was used to set it and %NULL
* for @data.
*
* Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY if a
* slot could not be allocated for the user data.
*
* Since: 1.4
**/
cairo_status_t
cairo_scaled_font_set_user_data (cairo_scaled_font_t *scaled_font,
const cairo_user_data_key_t *key,
void *user_data,
cairo_destroy_func_t destroy)
{
if (CAIRO_REFERENCE_COUNT_IS_INVALID (&scaled_font->ref_count))
return scaled_font->status;
 
return _cairo_user_data_array_set_data (&scaled_font->user_data,
key, user_data, destroy);
}
slim_hidden_def (cairo_scaled_font_set_user_data);
 
/* Public font API follows. */
 
/**
* cairo_scaled_font_extents:
* @scaled_font: a #cairo_scaled_font_t
* @extents: a #cairo_font_extents_t which to store the retrieved extents.
*
* Gets the metrics for a #cairo_scaled_font_t.
**/
void
cairo_scaled_font_extents (cairo_scaled_font_t *scaled_font,
cairo_font_extents_t *extents)
{
if (scaled_font->status) {
extents->ascent = 0.0;
extents->descent = 0.0;
extents->height = 0.0;
extents->max_x_advance = 0.0;
extents->max_y_advance = 0.0;
return;
}
 
*extents = scaled_font->extents;
}
slim_hidden_def (cairo_scaled_font_extents);
 
/**
* cairo_scaled_font_text_extents:
* @scaled_font: a #cairo_scaled_font_t
* @utf8: a NUL-terminated string of text, encoded in UTF-8
* @extents: a #cairo_text_extents_t which to store the retrieved extents.
*
* Gets the extents for a string of text. The extents describe a
* user-space rectangle that encloses the "inked" portion of the text
* drawn at the origin (0,0) (as it would be drawn by cairo_show_text()
* if the cairo graphics state were set to the same font_face,
* font_matrix, ctm, and font_options as @scaled_font). Additionally,
* the x_advance and y_advance values indicate the amount by which the
* current point would be advanced by cairo_show_text().
*
* Note that whitespace characters do not directly contribute to the
* size of the rectangle (extents.width and extents.height). They do
* contribute indirectly by changing the position of non-whitespace
* characters. In particular, trailing whitespace characters are
* likely to not affect the size of the rectangle, though they will
* affect the x_advance and y_advance values.
*
* Since: 1.2
**/
void
cairo_scaled_font_text_extents (cairo_scaled_font_t *scaled_font,
const char *utf8,
cairo_text_extents_t *extents)
{
cairo_status_t status;
cairo_glyph_t *glyphs = NULL;
int num_glyphs;
 
if (scaled_font->status)
goto ZERO_EXTENTS;
 
if (utf8 == NULL)
goto ZERO_EXTENTS;
 
status = cairo_scaled_font_text_to_glyphs (scaled_font, 0., 0.,
utf8, -1,
&glyphs, &num_glyphs,
NULL, NULL,
NULL);
if (unlikely (status)) {
status = _cairo_scaled_font_set_error (scaled_font, status);
goto ZERO_EXTENTS;
}
 
cairo_scaled_font_glyph_extents (scaled_font, glyphs, num_glyphs, extents);
free (glyphs);
 
return;
 
ZERO_EXTENTS:
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;
}
 
/**
* cairo_scaled_font_glyph_extents:
* @scaled_font: a #cairo_scaled_font_t
* @glyphs: an array of glyph IDs with X and Y offsets.
* @num_glyphs: the number of glyphs in the @glyphs array
* @extents: a #cairo_text_extents_t which to store the retrieved extents.
*
* Gets the extents for an array of glyphs. The extents describe a
* user-space rectangle that encloses the "inked" portion of the
* glyphs, (as they would be drawn by cairo_show_glyphs() if the cairo
* graphics state were set to the same font_face, font_matrix, ctm,
* and font_options as @scaled_font). Additionally, the x_advance and
* y_advance values indicate the amount by which the current point
* would be advanced by cairo_show_glyphs().
*
* Note that whitespace glyphs do not contribute to the size of the
* rectangle (extents.width and extents.height).
**/
void
cairo_scaled_font_glyph_extents (cairo_scaled_font_t *scaled_font,
const cairo_glyph_t *glyphs,
int num_glyphs,
cairo_text_extents_t *extents)
{
cairo_status_t status;
int i;
double min_x = 0.0, min_y = 0.0, max_x = 0.0, max_y = 0.0;
cairo_bool_t visible = FALSE;
cairo_scaled_glyph_t *scaled_glyph = NULL;
 
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;
 
if (unlikely (scaled_font->status))
goto ZERO_EXTENTS;
 
if (num_glyphs == 0)
goto ZERO_EXTENTS;
 
if (unlikely (num_glyphs < 0)) {
_cairo_error_throw (CAIRO_STATUS_NEGATIVE_COUNT);
/* XXX Can't propagate error */
goto ZERO_EXTENTS;
}
 
if (unlikely (glyphs == NULL)) {
_cairo_error_throw (CAIRO_STATUS_NULL_POINTER);
/* XXX Can't propagate error */
goto ZERO_EXTENTS;
}
 
_cairo_scaled_font_freeze_cache (scaled_font);
 
for (i = 0; i < num_glyphs; i++) {
double left, top, right, bottom;
 
status = _cairo_scaled_glyph_lookup (scaled_font,
glyphs[i].index,
CAIRO_SCALED_GLYPH_INFO_METRICS,
&scaled_glyph);
if (unlikely (status)) {
status = _cairo_scaled_font_set_error (scaled_font, status);
goto UNLOCK;
}
 
/* "Ink" extents should skip "invisible" glyphs */
if (scaled_glyph->metrics.width == 0 || scaled_glyph->metrics.height == 0)
continue;
 
left = scaled_glyph->metrics.x_bearing + glyphs[i].x;
right = left + scaled_glyph->metrics.width;
top = scaled_glyph->metrics.y_bearing + glyphs[i].y;
bottom = top + scaled_glyph->metrics.height;
 
if (!visible) {
visible = TRUE;
min_x = left;
max_x = right;
min_y = top;
max_y = bottom;
} else {
if (left < min_x) min_x = left;
if (right > max_x) max_x = right;
if (top < min_y) min_y = top;
if (bottom > max_y) max_y = bottom;
}
}
 
if (visible) {
extents->x_bearing = min_x - glyphs[0].x;
extents->y_bearing = min_y - glyphs[0].y;
extents->width = max_x - min_x;
extents->height = max_y - min_y;
} else {
extents->x_bearing = 0.0;
extents->y_bearing = 0.0;
extents->width = 0.0;
extents->height = 0.0;
}
 
if (num_glyphs) {
double x0, y0, x1, y1;
 
x0 = glyphs[0].x;
y0 = glyphs[0].y;
 
/* scaled_glyph contains the glyph for num_glyphs - 1 already. */
x1 = glyphs[num_glyphs - 1].x + scaled_glyph->metrics.x_advance;
y1 = glyphs[num_glyphs - 1].y + scaled_glyph->metrics.y_advance;
 
extents->x_advance = x1 - x0;
extents->y_advance = y1 - y0;
} else {
extents->x_advance = 0.0;
extents->y_advance = 0.0;
}
 
UNLOCK:
_cairo_scaled_font_thaw_cache (scaled_font);
return;
 
ZERO_EXTENTS:
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;
}
slim_hidden_def (cairo_scaled_font_glyph_extents);
 
#define GLYPH_LUT_SIZE 64
static cairo_status_t
cairo_scaled_font_text_to_glyphs_internal_cached (cairo_scaled_font_t *scaled_font,
double x,
double y,
const char *utf8,
cairo_glyph_t *glyphs,
cairo_text_cluster_t **clusters,
int num_chars)
{
struct glyph_lut_elt {
unsigned long index;
double x_advance;
double y_advance;
} glyph_lut[GLYPH_LUT_SIZE];
uint32_t glyph_lut_unicode[GLYPH_LUT_SIZE];
cairo_status_t status;
const char *p;
int i;
 
for (i = 0; i < GLYPH_LUT_SIZE; i++)
glyph_lut_unicode[i] = ~0U;
 
p = utf8;
for (i = 0; i < num_chars; i++) {
int idx, num_bytes;
uint32_t unicode;
cairo_scaled_glyph_t *scaled_glyph;
struct glyph_lut_elt *glyph_slot;
 
num_bytes = _cairo_utf8_get_char_validated (p, &unicode);
p += num_bytes;
 
glyphs[i].x = x;
glyphs[i].y = y;
 
idx = unicode % ARRAY_LENGTH (glyph_lut);
glyph_slot = &glyph_lut[idx];
if (glyph_lut_unicode[idx] == unicode) {
glyphs[i].index = glyph_slot->index;
x += glyph_slot->x_advance;
y += glyph_slot->y_advance;
} else {
unsigned long g;
 
g = scaled_font->backend->ucs4_to_index (scaled_font, unicode);
status = _cairo_scaled_glyph_lookup (scaled_font,
g,
CAIRO_SCALED_GLYPH_INFO_METRICS,
&scaled_glyph);
if (unlikely (status))
return status;
 
x += scaled_glyph->metrics.x_advance;
y += scaled_glyph->metrics.y_advance;
 
glyph_lut_unicode[idx] = unicode;
glyph_slot->index = g;
glyph_slot->x_advance = scaled_glyph->metrics.x_advance;
glyph_slot->y_advance = scaled_glyph->metrics.y_advance;
 
glyphs[i].index = g;
}
 
if (clusters) {
(*clusters)[i].num_bytes = num_bytes;
(*clusters)[i].num_glyphs = 1;
}
}
 
return CAIRO_STATUS_SUCCESS;
}
 
static cairo_status_t
cairo_scaled_font_text_to_glyphs_internal_uncached (cairo_scaled_font_t *scaled_font,
double x,
double y,
const char *utf8,
cairo_glyph_t *glyphs,
cairo_text_cluster_t **clusters,
int num_chars)
{
const char *p;
int i;
 
p = utf8;
for (i = 0; i < num_chars; i++) {
unsigned long g;
int num_bytes;
uint32_t unicode;
cairo_scaled_glyph_t *scaled_glyph;
cairo_status_t status;
 
num_bytes = _cairo_utf8_get_char_validated (p, &unicode);
p += num_bytes;
 
glyphs[i].x = x;
glyphs[i].y = y;
 
g = scaled_font->backend->ucs4_to_index (scaled_font, unicode);
 
/*
* No advance needed for a single character string. So, let's speed up
* one-character strings by skipping glyph lookup.
*/
if (num_chars > 1) {
status = _cairo_scaled_glyph_lookup (scaled_font,
g,
CAIRO_SCALED_GLYPH_INFO_METRICS,
&scaled_glyph);
if (unlikely (status))
return status;
 
x += scaled_glyph->metrics.x_advance;
y += scaled_glyph->metrics.y_advance;
}
 
glyphs[i].index = g;
 
if (clusters) {
(*clusters)[i].num_bytes = num_bytes;
(*clusters)[i].num_glyphs = 1;
}
}
 
return CAIRO_STATUS_SUCCESS;
}
 
/**
* cairo_scaled_font_text_to_glyphs:
* @x: X position to place first glyph
* @y: Y position to place first glyph
* @scaled_font: a #cairo_scaled_font_t
* @utf8: a string of text encoded in UTF-8
* @utf8_len: length of @utf8 in bytes, or -1 if it is NUL-terminated
* @glyphs: pointer to array of glyphs to fill
* @num_glyphs: pointer to number of glyphs
* @clusters: pointer to array of cluster mapping information to fill, or %NULL
* @num_clusters: pointer to number of clusters, or %NULL
* @cluster_flags: pointer to location to store cluster flags corresponding to the
* output @clusters, or %NULL
*
* Converts UTF-8 text to an array of glyphs, optionally with cluster
* mapping, that can be used to render later using @scaled_font.
*
* If @glyphs initially points to a non-%NULL value, that array is used
* as a glyph buffer, and @num_glyphs should point to the number of glyph
* entries available there. If the provided glyph array is too short for
* the conversion, a new glyph array is allocated using cairo_glyph_allocate()
* and placed in @glyphs. Upon return, @num_glyphs always contains the
* number of generated glyphs. If the value @glyphs points to has changed
* after the call, the user is responsible for freeing the allocated glyph
* array using cairo_glyph_free(). This may happen even if the provided
* array was large enough.
*
* If @clusters is not %NULL, @num_clusters and @cluster_flags should not be %NULL,
* and cluster mapping will be computed.
* The semantics of how cluster array allocation works is similar to the glyph
* array. That is,
* if @clusters initially points to a non-%NULL value, that array is used
* as a cluster buffer, and @num_clusters should point to the number of cluster
* entries available there. If the provided cluster array is too short for
* the conversion, a new cluster array is allocated using cairo_text_cluster_allocate()
* and placed in @clusters. Upon return, @num_clusters always contains the
* number of generated clusters. If the value @clusters points at has changed
* after the call, the user is responsible for freeing the allocated cluster
* array using cairo_text_cluster_free(). This may happen even if the provided
* array was large enough.
*
* In the simplest case, @glyphs and @clusters can point to %NULL initially
* and a suitable array will be allocated. In code:
* <informalexample><programlisting>
* cairo_status_t status;
*
* cairo_glyph_t *glyphs = NULL;
* int num_glyphs;
* cairo_text_cluster_t *clusters = NULL;
* int num_clusters;
* cairo_text_cluster_flags_t cluster_flags;
*
* status = cairo_scaled_font_text_to_glyphs (scaled_font,
* x, y,
* utf8, utf8_len,
* &amp;glyphs, &amp;num_glyphs,
* &amp;clusters, &amp;num_clusters, &amp;cluster_flags);
*
* if (status == CAIRO_STATUS_SUCCESS) {
* cairo_show_text_glyphs (cr,
* utf8, utf8_len,
* glyphs, num_glyphs,
* clusters, num_clusters, cluster_flags);
*
* cairo_glyph_free (glyphs);
* cairo_text_cluster_free (clusters);
* }
* </programlisting></informalexample>
*
* If no cluster mapping is needed:
* <informalexample><programlisting>
* cairo_status_t status;
*
* cairo_glyph_t *glyphs = NULL;
* int num_glyphs;
*
* status = cairo_scaled_font_text_to_glyphs (scaled_font,
* x, y,
* utf8, utf8_len,
* &amp;glyphs, &amp;num_glyphs,
* NULL, NULL,
* NULL);
*
* if (status == CAIRO_STATUS_SUCCESS) {
* cairo_show_glyphs (cr, glyphs, num_glyphs);
* cairo_glyph_free (glyphs);
* }
* </programlisting></informalexample>
*
* If stack-based glyph and cluster arrays are to be used for small
* arrays:
* <informalexample><programlisting>
* cairo_status_t status;
*
* cairo_glyph_t stack_glyphs[40];
* cairo_glyph_t *glyphs = stack_glyphs;
* int num_glyphs = sizeof (stack_glyphs) / sizeof (stack_glyphs[0]);
* cairo_text_cluster_t stack_clusters[40];
* cairo_text_cluster_t *clusters = stack_clusters;
* int num_clusters = sizeof (stack_clusters) / sizeof (stack_clusters[0]);
* cairo_text_cluster_flags_t cluster_flags;
*
* status = cairo_scaled_font_text_to_glyphs (scaled_font,
* x, y,
* utf8, utf8_len,
* &amp;glyphs, &amp;num_glyphs,
* &amp;clusters, &amp;num_clusters, &amp;cluster_flags);
*
* if (status == CAIRO_STATUS_SUCCESS) {
* cairo_show_text_glyphs (cr,
* utf8, utf8_len,
* glyphs, num_glyphs,
* clusters, num_clusters, cluster_flags);
*
* if (glyphs != stack_glyphs)
* cairo_glyph_free (glyphs);
* if (clusters != stack_clusters)
* cairo_text_cluster_free (clusters);
* }
* </programlisting></informalexample>
*
* For details of how @clusters, @num_clusters, and @cluster_flags map input
* UTF-8 text to the output glyphs see cairo_show_text_glyphs().
*
* The output values can be readily passed to cairo_show_text_glyphs()
* cairo_show_glyphs(), or related functions, assuming that the exact
* same @scaled_font is used for the operation.
*
* Return value: %CAIRO_STATUS_SUCCESS upon success, or an error status
* if the input values are wrong or if conversion failed. If the input
* values are correct but the conversion failed, the error status is also
* set on @scaled_font.
*
* Since: 1.8
**/
#define CACHING_THRESHOLD 16
cairo_status_t
cairo_scaled_font_text_to_glyphs (cairo_scaled_font_t *scaled_font,
double x,
double y,
const char *utf8,
int utf8_len,
cairo_glyph_t **glyphs,
int *num_glyphs,
cairo_text_cluster_t **clusters,
int *num_clusters,
cairo_text_cluster_flags_t *cluster_flags)
{
int num_chars = 0;
cairo_status_t status;
cairo_glyph_t *orig_glyphs;
cairo_text_cluster_t *orig_clusters;
 
status = scaled_font->status;
if (unlikely (status))
return status;
 
/* A slew of sanity checks */
 
/* glyphs and num_glyphs can't be NULL */
if (glyphs == NULL ||
num_glyphs == NULL) {
status = _cairo_error (CAIRO_STATUS_NULL_POINTER);
goto BAIL;
}
 
/* Special case for NULL and -1 */
if (utf8 == NULL && utf8_len == -1)
utf8_len = 0;
 
/* No NULLs for non-NULLs! */
if ((utf8_len && utf8 == NULL) ||
(clusters && num_clusters == NULL) ||
(clusters && cluster_flags == NULL)) {
status = _cairo_error (CAIRO_STATUS_NULL_POINTER);
goto BAIL;
}
 
/* A -1 for utf8_len means NUL-terminated */
if (utf8_len == -1)
utf8_len = strlen (utf8);
 
/* A NULL *glyphs means no prealloced glyphs array */
if (glyphs && *glyphs == NULL)
*num_glyphs = 0;
 
/* A NULL *clusters means no prealloced clusters array */
if (clusters && *clusters == NULL)
*num_clusters = 0;
 
if (!clusters && num_clusters) {
num_clusters = NULL;
}
 
if (cluster_flags) {
*cluster_flags = FALSE;
}
 
if (!clusters && cluster_flags) {
cluster_flags = NULL;
}
 
/* Apart from that, no negatives */
if (utf8_len < 0 ||
*num_glyphs < 0 ||
(num_clusters && *num_clusters < 0)) {
status = _cairo_error (CAIRO_STATUS_NEGATIVE_COUNT);
goto BAIL;
}
 
if (utf8_len == 0) {
status = CAIRO_STATUS_SUCCESS;
goto BAIL;
}
 
/* validate input so backend does not have to */
status = _cairo_utf8_to_ucs4 (utf8, utf8_len, NULL, &num_chars);
if (unlikely (status))
goto BAIL;
 
_cairo_scaled_font_freeze_cache (scaled_font);
 
orig_glyphs = *glyphs;
orig_clusters = clusters ? *clusters : NULL;
 
if (scaled_font->backend->text_to_glyphs) {
status = scaled_font->backend->text_to_glyphs (scaled_font, x, y,
utf8, utf8_len,
glyphs, num_glyphs,
clusters, num_clusters,
cluster_flags);
if (status != CAIRO_INT_STATUS_UNSUPPORTED) {
if (status == CAIRO_STATUS_SUCCESS) {
/* The checks here are crude; we only should do them in
* user-font backend, but they don't hurt here. This stuff
* can be hard to get right. */
 
if (*num_glyphs < 0) {
status = _cairo_error (CAIRO_STATUS_NEGATIVE_COUNT);
goto DONE;
}
if (num_glyphs && *glyphs == NULL) {
status = _cairo_error (CAIRO_STATUS_NULL_POINTER);
goto DONE;
}
 
if (clusters) {
if (*num_clusters < 0) {
status = _cairo_error (CAIRO_STATUS_NEGATIVE_COUNT);
goto DONE;
}
if (num_clusters && *clusters == NULL) {
status = _cairo_error (CAIRO_STATUS_NULL_POINTER);
goto DONE;
}
 
/* Don't trust the backend, validate clusters! */
status =
_cairo_validate_text_clusters (utf8, utf8_len,
*glyphs, *num_glyphs,
*clusters, *num_clusters,
*cluster_flags);
}
}
 
goto DONE;
}
}
 
if (*num_glyphs < num_chars) {
*glyphs = cairo_glyph_allocate (num_chars);
if (unlikely (*glyphs == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto DONE;
}
}
*num_glyphs = num_chars;
 
if (clusters) {
if (*num_clusters < num_chars) {
*clusters = cairo_text_cluster_allocate (num_chars);
if (unlikely (*clusters == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto DONE;
}
}
*num_clusters = num_chars;
}
 
if (num_chars > CACHING_THRESHOLD)
status = cairo_scaled_font_text_to_glyphs_internal_cached (scaled_font,
x, y,
utf8,
*glyphs,
clusters,
num_chars);
else
status = cairo_scaled_font_text_to_glyphs_internal_uncached (scaled_font,
x, y,
utf8,
*glyphs,
clusters,
num_chars);
 
DONE: /* error that should be logged on scaled_font happened */
_cairo_scaled_font_thaw_cache (scaled_font);
 
if (unlikely (status)) {
*num_glyphs = 0;
if (*glyphs != orig_glyphs) {
cairo_glyph_free (*glyphs);
*glyphs = orig_glyphs;
}
 
if (clusters) {
*num_clusters = 0;
if (*clusters != orig_clusters) {
cairo_text_cluster_free (*clusters);
*clusters = orig_clusters;
}
}
}
 
return _cairo_scaled_font_set_error (scaled_font, status);
 
BAIL: /* error with input arguments */
 
if (num_glyphs)
*num_glyphs = 0;
 
if (num_clusters)
*num_clusters = 0;
 
return status;
}
slim_hidden_def (cairo_scaled_font_text_to_glyphs);
 
static inline cairo_bool_t
_range_contains_glyph (const cairo_box_t *extents,
cairo_fixed_t left,
cairo_fixed_t top,
cairo_fixed_t right,
cairo_fixed_t bottom)
{
return right > extents->p1.x &&
left < extents->p2.x &&
bottom > extents->p1.y &&
top < extents->p2.y;
}
 
/*
* Compute a device-space bounding box for the glyphs.
*/
cairo_status_t
_cairo_scaled_font_glyph_device_extents (cairo_scaled_font_t *scaled_font,
const cairo_glyph_t *glyphs,
int num_glyphs,
cairo_rectangle_int_t *extents,
cairo_bool_t *overlap_out)
{
cairo_status_t status = CAIRO_STATUS_SUCCESS;
cairo_box_t box = { { INT_MAX, INT_MAX }, { INT_MIN, INT_MIN }};
cairo_scaled_glyph_t *glyph_cache[64];
cairo_bool_t overlap = overlap_out ? FALSE : TRUE;
int i;
 
if (unlikely (scaled_font->status))
return scaled_font->status;
 
_cairo_scaled_font_freeze_cache (scaled_font);
 
memset (glyph_cache, 0, sizeof (glyph_cache));
 
for (i = 0; i < num_glyphs; i++) {
cairo_scaled_glyph_t *scaled_glyph;
cairo_fixed_t x, y, x1, y1, x2, y2;
int cache_index = glyphs[i].index % ARRAY_LENGTH (glyph_cache);
 
scaled_glyph = glyph_cache[cache_index];
if (scaled_glyph == NULL ||
_cairo_scaled_glyph_index (scaled_glyph) != glyphs[i].index)
{
status = _cairo_scaled_glyph_lookup (scaled_font,
glyphs[i].index,
CAIRO_SCALED_GLYPH_INFO_METRICS,
&scaled_glyph);
if (unlikely (status))
break;
 
glyph_cache[cache_index] = scaled_glyph;
}
 
x = _cairo_fixed_from_double (glyphs[i].x);
x1 = x + scaled_glyph->bbox.p1.x;
x2 = x + scaled_glyph->bbox.p2.x;
 
y = _cairo_fixed_from_double (glyphs[i].y);
y1 = y + scaled_glyph->bbox.p1.y;
y2 = y + scaled_glyph->bbox.p2.y;
 
if (overlap == FALSE)
overlap = _range_contains_glyph (&box, x1, y1, x2, y2);
 
if (x1 < box.p1.x) box.p1.x = x1;
if (x2 > box.p2.x) box.p2.x = x2;
if (y1 < box.p1.y) box.p1.y = y1;
if (y2 > box.p2.y) box.p2.y = y2;
}
 
_cairo_scaled_font_thaw_cache (scaled_font);
if (unlikely (status))
return _cairo_scaled_font_set_error (scaled_font, status);
 
if (box.p1.x < box.p2.x) {
_cairo_box_round_to_rectangle (&box, extents);
} else {
extents->x = extents->y = 0;
extents->width = extents->height = 0;
}
 
if (overlap_out != NULL)
*overlap_out = overlap;
 
return CAIRO_STATUS_SUCCESS;
}
 
void
_cairo_scaled_font_glyph_approximate_extents (cairo_scaled_font_t *scaled_font,
const cairo_glyph_t *glyphs,
int num_glyphs,
cairo_rectangle_int_t *extents)
{
double x0 = HUGE_VAL, x1 = -HUGE_VAL;
double y0 = HUGE_VAL, y1 = -HUGE_VAL;
int i;
 
for (i = 0; i < num_glyphs; i++) {
double g;
 
g = glyphs[i].x;
if (g < x0) x0 = g;
if (g > x1) x1 = g;
 
g = glyphs[i].y;
if (g < y0) y0 = g;
if (g > y1) y1 = g;
}
 
if (x0 <= x1 && y0 <= y1) {
extents->x = floor (x0 - scaled_font->extents.max_x_advance);
extents->width = ceil (x1 + scaled_font->extents.max_x_advance);
extents->width -= extents->x;
 
extents->y = floor (y0 - scaled_font->extents.ascent);
extents->height = ceil (y1 + scaled_font->extents.descent);
extents->height -= extents->y;
} else {
extents->x = extents->y = 0;
extents->width = extents->height = 0;
}
}
 
cairo_status_t
_cairo_scaled_font_show_glyphs (cairo_scaled_font_t *scaled_font,
cairo_operator_t op,
const cairo_pattern_t *pattern,
cairo_surface_t *surface,
int source_x,
int source_y,
int dest_x,
int dest_y,
unsigned int width,
unsigned int height,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_region_t *clip_region)
{
cairo_status_t status;
cairo_surface_t *mask = NULL;
cairo_format_t mask_format = CAIRO_FORMAT_A1; /* shut gcc up */
cairo_surface_pattern_t mask_pattern;
int i;
 
/* These operators aren't interpreted the same way by the backends;
* they are implemented in terms of other operators in cairo-gstate.c
*/
assert (op != CAIRO_OPERATOR_SOURCE && op != CAIRO_OPERATOR_CLEAR);
 
if (scaled_font->status)
return scaled_font->status;
 
if (!num_glyphs)
return CAIRO_STATUS_SUCCESS;
 
if (scaled_font->backend->show_glyphs != NULL) {
int remaining_glyphs = num_glyphs;
status = scaled_font->backend->show_glyphs (scaled_font,
op, pattern,
surface,
source_x, source_y,
dest_x, dest_y,
width, height,
glyphs, num_glyphs,
clip_region,
&remaining_glyphs);
glyphs += num_glyphs - remaining_glyphs;
num_glyphs = remaining_glyphs;
if (remaining_glyphs == 0)
status = CAIRO_STATUS_SUCCESS;
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
return _cairo_scaled_font_set_error (scaled_font, status);
}
 
/* Font display routine either does not exist or failed. */
 
_cairo_scaled_font_freeze_cache (scaled_font);
 
for (i = 0; i < num_glyphs; i++) {
int x, y;
cairo_image_surface_t *glyph_surface;
cairo_scaled_glyph_t *scaled_glyph;
 
status = _cairo_scaled_glyph_lookup (scaled_font,
glyphs[i].index,
CAIRO_SCALED_GLYPH_INFO_SURFACE,
&scaled_glyph);
 
if (unlikely (status))
goto CLEANUP_MASK;
 
glyph_surface = scaled_glyph->surface;
 
/* To start, create the mask using the format from the first
* glyph. Later we'll deal with different formats. */
if (mask == NULL) {
mask_format = glyph_surface->format;
mask = cairo_image_surface_create (mask_format, width, height);
status = mask->status;
if (unlikely (status))
goto CLEANUP_MASK;
}
 
/* If we have glyphs of different formats, we "upgrade" the mask
* to the wider of the formats. */
if (glyph_surface->format != mask_format &&
_cairo_format_bits_per_pixel (mask_format) <
_cairo_format_bits_per_pixel (glyph_surface->format) )
{
cairo_surface_t *new_mask;
 
switch (glyph_surface->format) {
case CAIRO_FORMAT_ARGB32:
case CAIRO_FORMAT_A8:
case CAIRO_FORMAT_A1:
mask_format = glyph_surface->format;
break;
case CAIRO_FORMAT_RGB16_565:
case CAIRO_FORMAT_RGB24:
case CAIRO_FORMAT_INVALID:
default:
ASSERT_NOT_REACHED;
mask_format = CAIRO_FORMAT_ARGB32;
break;
}
 
new_mask = cairo_image_surface_create (mask_format, width, height);
status = new_mask->status;
if (unlikely (status)) {
cairo_surface_destroy (new_mask);
goto CLEANUP_MASK;
}
 
_cairo_pattern_init_for_surface (&mask_pattern, mask);
/* Note that we only upgrade masks, i.e. A1 -> A8 -> ARGB32, so there is
* never any component alpha here.
*/
status = _cairo_surface_composite (CAIRO_OPERATOR_ADD,
&_cairo_pattern_white.base,
&mask_pattern.base,
new_mask,
0, 0,
0, 0,
0, 0,
width, height,
NULL);
 
_cairo_pattern_fini (&mask_pattern.base);
 
if (unlikely (status)) {
cairo_surface_destroy (new_mask);
goto CLEANUP_MASK;
}
 
cairo_surface_destroy (mask);
mask = new_mask;
}
 
if (glyph_surface->width && glyph_surface->height) {
cairo_surface_pattern_t glyph_pattern;
 
/* round glyph locations to the nearest pixel */
/* XXX: FRAGILE: We're ignoring device_transform scaling here. A bug? */
x = _cairo_lround (glyphs[i].x -
glyph_surface->base.device_transform.x0);
y = _cairo_lround (glyphs[i].y -
glyph_surface->base.device_transform.y0);
 
_cairo_pattern_init_for_surface (&glyph_pattern,
&glyph_surface->base);
if (mask_format == CAIRO_FORMAT_ARGB32)
glyph_pattern.base.has_component_alpha = TRUE;
 
status = _cairo_surface_composite (CAIRO_OPERATOR_ADD,
&_cairo_pattern_white.base,
&glyph_pattern.base,
mask,
0, 0,
0, 0,
x - dest_x, y - dest_y,
glyph_surface->width,
glyph_surface->height,
NULL);
 
_cairo_pattern_fini (&glyph_pattern.base);
 
if (unlikely (status))
goto CLEANUP_MASK;
}
}
 
_cairo_pattern_init_for_surface (&mask_pattern, mask);
if (mask_format == CAIRO_FORMAT_ARGB32)
mask_pattern.base.has_component_alpha = TRUE;
 
status = _cairo_surface_composite (op, pattern, &mask_pattern.base,
surface,
source_x, source_y,
0, 0,
dest_x, dest_y,
width, height,
clip_region);
 
_cairo_pattern_fini (&mask_pattern.base);
 
CLEANUP_MASK:
_cairo_scaled_font_thaw_cache (scaled_font);
 
if (mask != NULL)
cairo_surface_destroy (mask);
return _cairo_scaled_font_set_error (scaled_font, status);
}
 
/* Add a single-device-unit rectangle to a path. */
static cairo_status_t
_add_unit_rectangle_to_path (cairo_path_fixed_t *path,
cairo_fixed_t x,
cairo_fixed_t y)
{
cairo_status_t status;
 
status = _cairo_path_fixed_move_to (path, x, y);
if (unlikely (status))
return status;
 
status = _cairo_path_fixed_rel_line_to (path,
_cairo_fixed_from_int (1),
_cairo_fixed_from_int (0));
if (unlikely (status))
return status;
 
status = _cairo_path_fixed_rel_line_to (path,
_cairo_fixed_from_int (0),
_cairo_fixed_from_int (1));
if (unlikely (status))
return status;
 
status = _cairo_path_fixed_rel_line_to (path,
_cairo_fixed_from_int (-1),
_cairo_fixed_from_int (0));
if (unlikely (status))
return status;
 
return _cairo_path_fixed_close_path (path);
}
 
/**
* _trace_mask_to_path:
* @bitmap: An alpha mask (either %CAIRO_FORMAT_A1 or %CAIRO_FORMAT_A8)
* @path: An initialized path to hold the result
*
* Given a mask surface, (an alpha image), fill out the provided path
* so that when filled it would result in something that approximates
* the mask.
*
* Note: The current tracing code here is extremely primitive. It
* operates only on an A1 surface, (converting an A8 surface to A1 if
* necessary), and performs the tracing by drawing a little square
* around each pixel that is on in the mask. We do not pretend that
* this is a high-quality result. But we are leaving it up to someone
* who cares enough about getting a better result to implement
* something more sophisticated.
**/
static cairo_status_t
_trace_mask_to_path (cairo_image_surface_t *mask,
cairo_path_fixed_t *path,
double tx, double ty)
{
const uint8_t *row;
int rows, cols, bytes_per_row;
int x, y, bit;
double xoff, yoff;
cairo_fixed_t x0, y0;
cairo_fixed_t px, py;
cairo_status_t status;
 
mask = _cairo_image_surface_coerce_to_format (mask, CAIRO_FORMAT_A1);
status = mask->base.status;
if (unlikely (status))
return status;
 
cairo_surface_get_device_offset (&mask->base, &xoff, &yoff);
x0 = _cairo_fixed_from_double (tx - xoff);
y0 = _cairo_fixed_from_double (ty - yoff);
 
bytes_per_row = (mask->width + 7) / 8;
row = mask->data;
for (y = 0, rows = mask->height; rows--; row += mask->stride, y++) {
const uint8_t *byte_ptr = row;
x = 0;
py = _cairo_fixed_from_int (y);
for (cols = bytes_per_row; cols--; ) {
uint8_t byte = *byte_ptr++;
if (byte == 0) {
x += 8;
continue;
}
 
byte = CAIRO_BITSWAP8_IF_LITTLE_ENDIAN (byte);
for (bit = 1 << 7; bit && x < mask->width; bit >>= 1, x++) {
if (byte & bit) {
px = _cairo_fixed_from_int (x);
status = _add_unit_rectangle_to_path (path,
px + x0,
py + y0);
if (unlikely (status))
goto BAIL;
}
}
}
}
 
BAIL:
cairo_surface_destroy (&mask->base);
 
return status;
}
 
cairo_status_t
_cairo_scaled_font_glyph_path (cairo_scaled_font_t *scaled_font,
const cairo_glyph_t *glyphs,
int num_glyphs,
cairo_path_fixed_t *path)
{
cairo_status_t status;
int i;
 
status = scaled_font->status;
if (unlikely (status))
return status;
 
_cairo_scaled_font_freeze_cache (scaled_font);
for (i = 0; i < num_glyphs; i++) {
cairo_scaled_glyph_t *scaled_glyph;
 
status = _cairo_scaled_glyph_lookup (scaled_font,
glyphs[i].index,
CAIRO_SCALED_GLYPH_INFO_PATH,
&scaled_glyph);
if (status == CAIRO_STATUS_SUCCESS) {
status = _cairo_path_fixed_append (path,
scaled_glyph->path, CAIRO_DIRECTION_FORWARD,
_cairo_fixed_from_double (glyphs[i].x),
_cairo_fixed_from_double (glyphs[i].y));
 
} else if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
/* If the font is incapable of providing a path, then we'll
* have to trace our own from a surface.
*/
status = _cairo_scaled_glyph_lookup (scaled_font,
glyphs[i].index,
CAIRO_SCALED_GLYPH_INFO_SURFACE,
&scaled_glyph);
if (unlikely (status))
goto BAIL;
 
status = _trace_mask_to_path (scaled_glyph->surface, path,
glyphs[i].x, glyphs[i].y);
}
 
if (unlikely (status))
goto BAIL;
}
BAIL:
_cairo_scaled_font_thaw_cache (scaled_font);
 
return _cairo_scaled_font_set_error (scaled_font, status);
}
 
/**
* _cairo_scaled_glyph_set_metrics:
* @scaled_glyph: a #cairo_scaled_glyph_t
* @scaled_font: a #cairo_scaled_font_t
* @fs_metrics: a #cairo_text_extents_t in font space
*
* _cairo_scaled_glyph_set_metrics() stores user space metrics
* for the specified glyph given font space metrics. It is
* called by the font backend when initializing a glyph with
* %CAIRO_SCALED_GLYPH_INFO_METRICS.
**/
void
_cairo_scaled_glyph_set_metrics (cairo_scaled_glyph_t *scaled_glyph,
cairo_scaled_font_t *scaled_font,
cairo_text_extents_t *fs_metrics)
{
cairo_bool_t first = TRUE;
double hm, wm;
double min_user_x = 0.0, max_user_x = 0.0, min_user_y = 0.0, max_user_y = 0.0;
double min_device_x = 0.0, max_device_x = 0.0, min_device_y = 0.0, max_device_y = 0.0;
double device_x_advance, device_y_advance;
 
scaled_glyph->fs_metrics = *fs_metrics;
 
for (hm = 0.0; hm <= 1.0; hm += 1.0)
for (wm = 0.0; wm <= 1.0; wm += 1.0) {
double x, y;
 
/* Transform this corner to user space */
x = fs_metrics->x_bearing + fs_metrics->width * wm;
y = fs_metrics->y_bearing + fs_metrics->height * hm;
cairo_matrix_transform_point (&scaled_font->font_matrix,
&x, &y);
if (first) {
min_user_x = max_user_x = x;
min_user_y = max_user_y = y;
} else {
if (x < min_user_x) min_user_x = x;
if (x > max_user_x) max_user_x = x;
if (y < min_user_y) min_user_y = y;
if (y > max_user_y) max_user_y = y;
}
 
/* Transform this corner to device space from glyph origin */
x = fs_metrics->x_bearing + fs_metrics->width * wm;
y = fs_metrics->y_bearing + fs_metrics->height * hm;
cairo_matrix_transform_distance (&scaled_font->scale,
&x, &y);
 
if (first) {
min_device_x = max_device_x = x;
min_device_y = max_device_y = y;
} else {
if (x < min_device_x) min_device_x = x;
if (x > max_device_x) max_device_x = x;
if (y < min_device_y) min_device_y = y;
if (y > max_device_y) max_device_y = y;
}
first = FALSE;
}
scaled_glyph->metrics.x_bearing = min_user_x;
scaled_glyph->metrics.y_bearing = min_user_y;
scaled_glyph->metrics.width = max_user_x - min_user_x;
scaled_glyph->metrics.height = max_user_y - min_user_y;
 
scaled_glyph->metrics.x_advance = fs_metrics->x_advance;
scaled_glyph->metrics.y_advance = fs_metrics->y_advance;
cairo_matrix_transform_distance (&scaled_font->font_matrix,
&scaled_glyph->metrics.x_advance,
&scaled_glyph->metrics.y_advance);
 
device_x_advance = fs_metrics->x_advance;
device_y_advance = fs_metrics->y_advance;
cairo_matrix_transform_distance (&scaled_font->scale,
&device_x_advance,
&device_y_advance);
 
scaled_glyph->bbox.p1.x = _cairo_fixed_from_double (min_device_x);
scaled_glyph->bbox.p1.y = _cairo_fixed_from_double (min_device_y);
scaled_glyph->bbox.p2.x = _cairo_fixed_from_double (max_device_x);
scaled_glyph->bbox.p2.y = _cairo_fixed_from_double (max_device_y);
 
scaled_glyph->x_advance = _cairo_lround (device_x_advance);
scaled_glyph->y_advance = _cairo_lround (device_y_advance);
 
scaled_glyph->has_info |= CAIRO_SCALED_GLYPH_INFO_METRICS;
}
 
void
_cairo_scaled_glyph_set_surface (cairo_scaled_glyph_t *scaled_glyph,
cairo_scaled_font_t *scaled_font,
cairo_image_surface_t *surface)
{
if (scaled_glyph->surface != NULL)
cairo_surface_destroy (&scaled_glyph->surface->base);
 
/* sanity check the backend glyph contents */
_cairo_debug_check_image_surface_is_defined (&surface->base);
scaled_glyph->surface = surface;
 
if (surface != NULL)
scaled_glyph->has_info |= CAIRO_SCALED_GLYPH_INFO_SURFACE;
else
scaled_glyph->has_info &= ~CAIRO_SCALED_GLYPH_INFO_SURFACE;
}
 
void
_cairo_scaled_glyph_set_path (cairo_scaled_glyph_t *scaled_glyph,
cairo_scaled_font_t *scaled_font,
cairo_path_fixed_t *path)
{
if (scaled_glyph->path != NULL)
_cairo_path_fixed_destroy (scaled_glyph->path);
 
scaled_glyph->path = path;
 
if (path != NULL)
scaled_glyph->has_info |= CAIRO_SCALED_GLYPH_INFO_PATH;
else
scaled_glyph->has_info &= ~CAIRO_SCALED_GLYPH_INFO_PATH;
}
 
void
_cairo_scaled_glyph_set_recording_surface (cairo_scaled_glyph_t *scaled_glyph,
cairo_scaled_font_t *scaled_font,
cairo_surface_t *recording_surface)
{
if (scaled_glyph->recording_surface != NULL) {
cairo_surface_finish (scaled_glyph->recording_surface);
cairo_surface_destroy (scaled_glyph->recording_surface);
}
 
scaled_glyph->recording_surface = recording_surface;
 
if (recording_surface != NULL)
scaled_glyph->has_info |= CAIRO_SCALED_GLYPH_INFO_RECORDING_SURFACE;
else
scaled_glyph->has_info &= ~CAIRO_SCALED_GLYPH_INFO_RECORDING_SURFACE;
}
 
static cairo_bool_t
_cairo_scaled_glyph_page_can_remove (const void *closure)
{
const cairo_scaled_glyph_page_t *page = closure;
const cairo_scaled_font_t *scaled_font;
 
scaled_font = (cairo_scaled_font_t *) page->cache_entry.hash;
return scaled_font->cache_frozen == 0;
}
 
static cairo_status_t
_cairo_scaled_font_allocate_glyph (cairo_scaled_font_t *scaled_font,
cairo_scaled_glyph_t **scaled_glyph)
{
cairo_scaled_glyph_page_t *page;
cairo_status_t status;
 
/* only the first page in the list may contain available slots */
if (! cairo_list_is_empty (&scaled_font->glyph_pages)) {
page = cairo_list_last_entry (&scaled_font->glyph_pages,
cairo_scaled_glyph_page_t,
link);
if (page->num_glyphs < CAIRO_SCALED_GLYPH_PAGE_SIZE) {
*scaled_glyph = &page->glyphs[page->num_glyphs++];
return CAIRO_STATUS_SUCCESS;
}
}
 
page = malloc (sizeof (cairo_scaled_glyph_page_t));
if (unlikely (page == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
page->cache_entry.hash = (unsigned long) scaled_font;
page->cache_entry.size = 1; /* XXX occupancy weighting? */
page->num_glyphs = 0;
 
CAIRO_MUTEX_LOCK (_cairo_scaled_glyph_page_cache_mutex);
if (scaled_font->global_cache_frozen == FALSE) {
if (unlikely (cairo_scaled_glyph_page_cache.hash_table == NULL)) {
status = _cairo_cache_init (&cairo_scaled_glyph_page_cache,
NULL,
_cairo_scaled_glyph_page_can_remove,
_cairo_scaled_glyph_page_destroy,
MAX_GLYPH_PAGES_CACHED);
if (unlikely (status)) {
CAIRO_MUTEX_UNLOCK (_cairo_scaled_glyph_page_cache_mutex);
free (page);
return status;
}
}
 
_cairo_cache_freeze (&cairo_scaled_glyph_page_cache);
scaled_font->global_cache_frozen = TRUE;
}
 
status = _cairo_cache_insert (&cairo_scaled_glyph_page_cache,
&page->cache_entry);
CAIRO_MUTEX_UNLOCK (_cairo_scaled_glyph_page_cache_mutex);
if (unlikely (status)) {
free (page);
return status;
}
 
cairo_list_add_tail (&page->link, &scaled_font->glyph_pages);
 
*scaled_glyph = &page->glyphs[page->num_glyphs++];
return CAIRO_STATUS_SUCCESS;
}
 
static void
_cairo_scaled_font_free_last_glyph (cairo_scaled_font_t *scaled_font,
cairo_scaled_glyph_t *scaled_glyph)
{
cairo_scaled_glyph_page_t *page;
 
assert (! cairo_list_is_empty (&scaled_font->glyph_pages));
page = cairo_list_last_entry (&scaled_font->glyph_pages,
cairo_scaled_glyph_page_t,
link);
assert (scaled_glyph == &page->glyphs[page->num_glyphs-1]);
 
_cairo_scaled_glyph_fini (scaled_font, scaled_glyph);
 
if (--page->num_glyphs == 0) {
_cairo_cache_remove (&cairo_scaled_glyph_page_cache,
&page->cache_entry);
}
}
 
/**
* _cairo_scaled_glyph_lookup:
* @scaled_font: a #cairo_scaled_font_t
* @index: the glyph to create
* @info: a #cairo_scaled_glyph_info_t marking which portions of
* the glyph should be filled in.
* @scaled_glyph_ret: a #cairo_scaled_glyph_t where the glyph
* is returned.
*
* If the desired info is not available, (for example, when trying to
* get INFO_PATH with a bitmapped font), this function will return
* %CAIRO_INT_STATUS_UNSUPPORTED.
*
* Note: This function must be called with the scaled font frozen, and it must
* remain frozen for as long as the @scaled_glyph_ret is alive. (If the scaled
* font was not frozen, then there is no guarantee that the glyph would not be
* evicted before you tried to access it.) See
* _cairo_scaled_font_freeze_cache() and _cairo_scaled_font_thaw_cache().
*
* Returns: a glyph with the requested portions filled in. Glyph
* lookup is cached and glyph will be automatically freed along
* with the scaled_font so no explicit free is required.
* @info can be one or more of:
* %CAIRO_SCALED_GLYPH_INFO_METRICS - glyph metrics and bounding box
* %CAIRO_SCALED_GLYPH_INFO_SURFACE - surface holding glyph image
* %CAIRO_SCALED_GLYPH_INFO_PATH - path holding glyph outline in device space
**/
cairo_int_status_t
_cairo_scaled_glyph_lookup (cairo_scaled_font_t *scaled_font,
unsigned long index,
cairo_scaled_glyph_info_t info,
cairo_scaled_glyph_t **scaled_glyph_ret)
{
cairo_status_t status = CAIRO_STATUS_SUCCESS;
cairo_scaled_glyph_t *scaled_glyph;
cairo_scaled_glyph_info_t need_info;
 
*scaled_glyph_ret = NULL;
 
if (unlikely (scaled_font->status))
return scaled_font->status;
 
if (CAIRO_INJECT_FAULT ())
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
/*
* Check cache for glyph
*/
scaled_glyph = _cairo_hash_table_lookup (scaled_font->glyphs,
(cairo_hash_entry_t *) &index);
if (scaled_glyph == NULL) {
status = _cairo_scaled_font_allocate_glyph (scaled_font, &scaled_glyph);
if (unlikely (status))
goto err;
 
memset (scaled_glyph, 0, sizeof (cairo_scaled_glyph_t));
_cairo_scaled_glyph_set_index (scaled_glyph, index);
 
/* ask backend to initialize metrics and shape fields */
status =
scaled_font->backend->scaled_glyph_init (scaled_font,
scaled_glyph,
info | CAIRO_SCALED_GLYPH_INFO_METRICS);
if (unlikely (status)) {
_cairo_scaled_font_free_last_glyph (scaled_font, scaled_glyph);
goto err;
}
 
status = _cairo_hash_table_insert (scaled_font->glyphs,
&scaled_glyph->hash_entry);
if (unlikely (status)) {
_cairo_scaled_font_free_last_glyph (scaled_font, scaled_glyph);
goto err;
}
}
 
/*
* Check and see if the glyph, as provided,
* already has the requested data and amend it if not
*/
need_info = info & ~scaled_glyph->has_info;
if (need_info) {
status = scaled_font->backend->scaled_glyph_init (scaled_font,
scaled_glyph,
need_info);
if (unlikely (status))
goto err;
 
/* Don't trust the scaled_glyph_init() return value, the font
* backend may not even know about some of the info. For example,
* no backend other than the user-fonts knows about recording-surface
* glyph info. */
if (info & ~scaled_glyph->has_info)
return CAIRO_INT_STATUS_UNSUPPORTED;
}
 
*scaled_glyph_ret = scaled_glyph;
return CAIRO_STATUS_SUCCESS;
 
err:
/* It's not an error for the backend to not support the info we want. */
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
status = _cairo_scaled_font_set_error (scaled_font, status);
return status;
}
 
double
_cairo_scaled_font_get_max_scale (cairo_scaled_font_t *scaled_font)
{
return scaled_font->max_scale;
}
 
 
/**
* cairo_scaled_font_get_font_face:
* @scaled_font: a #cairo_scaled_font_t
*
* Gets the font face that this scaled font uses. This is the
* font face passed to cairo_scaled_font_create().
*
* Return value: The #cairo_font_face_t with which @scaled_font was
* created.
*
* Since: 1.2
**/
cairo_font_face_t *
cairo_scaled_font_get_font_face (cairo_scaled_font_t *scaled_font)
{
if (scaled_font->status)
return (cairo_font_face_t*) &_cairo_font_face_nil;
 
if (scaled_font->original_font_face != NULL)
return scaled_font->original_font_face;
 
return scaled_font->font_face;
}
slim_hidden_def (cairo_scaled_font_get_font_face);
 
/**
* cairo_scaled_font_get_font_matrix:
* @scaled_font: a #cairo_scaled_font_t
* @font_matrix: return value for the matrix
*
* Stores the font matrix with which @scaled_font was created into
* @matrix.
*
* Since: 1.2
**/
void
cairo_scaled_font_get_font_matrix (cairo_scaled_font_t *scaled_font,
cairo_matrix_t *font_matrix)
{
if (scaled_font->status) {
cairo_matrix_init_identity (font_matrix);
return;
}
 
*font_matrix = scaled_font->font_matrix;
}
slim_hidden_def (cairo_scaled_font_get_font_matrix);
 
/**
* cairo_scaled_font_get_ctm:
* @scaled_font: a #cairo_scaled_font_t
* @ctm: return value for the CTM
*
* Stores the CTM with which @scaled_font was created into @ctm.
* Note that the translation offsets (x0, y0) of the CTM are ignored
* by cairo_scaled_font_create(). So, the matrix this
* function returns always has 0,0 as x0,y0.
*
* Since: 1.2
**/
void
cairo_scaled_font_get_ctm (cairo_scaled_font_t *scaled_font,
cairo_matrix_t *ctm)
{
if (scaled_font->status) {
cairo_matrix_init_identity (ctm);
return;
}
 
*ctm = scaled_font->ctm;
}
slim_hidden_def (cairo_scaled_font_get_ctm);
 
/**
* cairo_scaled_font_get_scale_matrix:
* @scaled_font: a #cairo_scaled_font_t
* @scale_matrix: return value for the matrix
*
* Stores the scale matrix of @scaled_font into @matrix.
* The scale matrix is product of the font matrix and the ctm
* associated with the scaled font, and hence is the matrix mapping from
* font space to device space.
*
* Since: 1.8
**/
void
cairo_scaled_font_get_scale_matrix (cairo_scaled_font_t *scaled_font,
cairo_matrix_t *scale_matrix)
{
if (scaled_font->status) {
cairo_matrix_init_identity (scale_matrix);
return;
}
 
*scale_matrix = scaled_font->scale;
}
 
/**
* cairo_scaled_font_get_font_options:
* @scaled_font: a #cairo_scaled_font_t
* @options: return value for the font options
*
* Stores the font options with which @scaled_font was created into
* @options.
*
* Since: 1.2
**/
void
cairo_scaled_font_get_font_options (cairo_scaled_font_t *scaled_font,
cairo_font_options_t *options)
{
if (cairo_font_options_status (options))
return;
 
if (scaled_font->status) {
_cairo_font_options_init_default (options);
return;
}
 
_cairo_font_options_init_copy (options, &scaled_font->options);
}
slim_hidden_def (cairo_scaled_font_get_font_options);
/programs/develop/libraries/cairo/src/cairo-script.h
0,0 → 1,89
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2008 Chris Wilson
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Chris Wilson
*
* Contributor(s):
* Chris Wilson <chris@chris-wilson.co.uk>
*/
 
#ifndef CAIRO_SCRIPT_H
#define CAIRO_SCRIPT_H
 
#include "cairo.h"
 
#if CAIRO_HAS_SCRIPT_SURFACE
 
CAIRO_BEGIN_DECLS
 
typedef enum {
CAIRO_SCRIPT_MODE_BINARY,
CAIRO_SCRIPT_MODE_ASCII
} cairo_script_mode_t;
 
cairo_public cairo_device_t *
cairo_script_create (const char *filename);
 
cairo_public cairo_device_t *
cairo_script_create_for_stream (cairo_write_func_t write_func,
void *closure);
 
cairo_public void
cairo_script_write_comment (cairo_device_t *script,
const char *comment,
int len);
 
cairo_public void
cairo_script_set_mode (cairo_device_t *script,
cairo_script_mode_t mode);
 
cairo_public cairo_script_mode_t
cairo_script_get_mode (cairo_device_t *script);
 
cairo_public cairo_surface_t *
cairo_script_surface_create (cairo_device_t *script,
cairo_content_t content,
double width,
double height);
 
cairo_public cairo_surface_t *
cairo_script_surface_create_for_target (cairo_device_t *script,
cairo_surface_t *target);
 
cairo_public cairo_status_t
cairo_script_from_recording_surface (cairo_device_t *script,
cairo_surface_t *recording_surface);
 
CAIRO_END_DECLS
 
#else /*CAIRO_HAS_SCRIPT_SURFACE*/
# error Cairo was not compiled with support for the CairoScript backend
#endif /*CAIRO_HAS_SCRIPT_SURFACE*/
 
#endif /*CAIRO_SCRIPT_H*/
/programs/develop/libraries/cairo/src/cairo-skia.h
0,0 → 1,84
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2002 University of Southern California
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
*/
 
#ifndef CAIRO_SKIA_H
#define CAIRO_SKIA_H
 
#include "cairo.h"
 
#if CAIRO_HAS_SKIA_SURFACE
 
CAIRO_BEGIN_DECLS
 
cairo_public cairo_surface_t *
cairo_skia_surface_create (cairo_format_t format,
int width,
int height);
 
cairo_public cairo_surface_t *
cairo_skia_surface_create_for_data (unsigned char *data,
cairo_format_t format,
int width,
int height,
int stride);
 
cairo_public unsigned char *
cairo_skia_surface_get_data (cairo_surface_t *surface);
 
cairo_public cairo_format_t
cairo_skia_surface_get_format (cairo_surface_t *surface);
 
cairo_public int
cairo_skia_surface_get_width (cairo_surface_t *surface);
 
cairo_public int
cairo_skia_surface_get_height (cairo_surface_t *surface);
 
cairo_public int
cairo_skia_surface_get_stride (cairo_surface_t *surface);
 
cairo_public cairo_surface_t *
cairo_skia_surface_get_image (cairo_surface_t *surface);
 
CAIRO_END_DECLS
 
#else
 
# error Cairo was not compiled with support for the Skia backend
 
#endif
 
#endif
/programs/develop/libraries/cairo/src/cairo-slope-private.h
0,0 → 1,72
/* 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., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
*/
 
#ifndef _CAIRO_SLOPE_PRIVATE_H
#define _CAIRO_SLOPE_PRIVATE_H
 
#include "cairo-types-private.h"
#include "cairo-fixed-private.h"
 
static inline void
_cairo_slope_init (cairo_slope_t *slope,
const cairo_point_t *a,
const cairo_point_t *b)
{
slope->dx = b->x - a->x;
slope->dy = b->y - a->y;
}
 
static inline cairo_bool_t
_cairo_slope_equal (const cairo_slope_t *a, const cairo_slope_t *b)
{
return _cairo_int64_eq (_cairo_int32x32_64_mul (a->dy, b->dx),
_cairo_int32x32_64_mul (b->dy, a->dx));
}
 
static inline cairo_bool_t
_cairo_slope_backwards (const cairo_slope_t *a, const cairo_slope_t *b)
{
return _cairo_int64_negative (_cairo_int64_add (_cairo_int32x32_64_mul (a->dx, b->dx),
_cairo_int32x32_64_mul (a->dy, b->dy)));
}
 
cairo_private int
_cairo_slope_compare (const cairo_slope_t *a,
const cairo_slope_t *b) cairo_pure;
 
 
#endif /* _CAIRO_SLOPE_PRIVATE_H */
/programs/develop/libraries/cairo/src/cairo-slope.c
0,0 → 1,99
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2002 University of Southern California
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
*/
 
#include "cairoint.h"
 
#include "cairo-slope-private.h"
 
/* Compare two slopes. Slope angles begin at 0 in the direction of the
positive X axis and increase in the direction of the positive Y
axis.
 
This function always compares the slope vectors based on the
smaller angular difference between them, (that is based on an
angular difference that is strictly less than pi). To break ties
when comparing slope vectors with an angular difference of exactly
pi, the vector with a positive dx (or positive dy if dx's are zero)
is considered to be more positive than the other.
 
Also, all slope vectors with both dx==0 and dy==0 are considered
equal and more positive than any non-zero vector.
 
< 0 => a less positive than b
== 0 => a equal to b
> 0 => a more positive than b
*/
int
_cairo_slope_compare (const cairo_slope_t *a, const cairo_slope_t *b)
{
cairo_int64_t ady_bdx = _cairo_int32x32_64_mul (a->dy, b->dx);
cairo_int64_t bdy_adx = _cairo_int32x32_64_mul (b->dy, a->dx);
int cmp;
 
cmp = _cairo_int64_cmp (ady_bdx, bdy_adx);
if (cmp)
return cmp;
 
/* special-case zero vectors. the intended logic here is:
* zero vectors all compare equal, and more positive than any
* non-zero vector.
*/
if (a->dx == 0 && a->dy == 0 && b->dx == 0 && b->dy ==0)
return 0;
if (a->dx == 0 && a->dy == 0)
return 1;
if (b->dx == 0 && b->dy ==0)
return -1;
 
/* Finally, we're looking at two vectors that are either equal or
* that differ by exactly pi. We can identify the "differ by pi"
* case by looking for a change in sign in either dx or dy between
* a and b.
*
* And in these cases, we eliminate the ambiguity by reducing the angle
* of b by an infinitesimally small amount, (that is, 'a' will
* always be considered less than 'b').
*/
if ((a->dx ^ b->dx) < 0 || (a->dy ^ b->dy) < 0) {
if (a->dx > 0 || (a->dx == 0 && a->dy > 0))
return +1;
else
return -1;
}
 
/* Finally, for identical slopes, we obviously return 0. */
return 0;
}
/programs/develop/libraries/cairo/src/cairo-spans-private.h
0,0 → 1,189
/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
/* cairo - a vector graphics library with display and print output
*
* Copyright (c) 2008 M Joonas Pihlaja
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef CAIRO_SPANS_PRIVATE_H
#define CAIRO_SPANS_PRIVATE_H
#include "cairo-types-private.h"
#include "cairo-compiler-private.h"
 
/* Number of bits of precision used for alpha. */
#define CAIRO_SPANS_UNIT_COVERAGE_BITS 8
#define CAIRO_SPANS_UNIT_COVERAGE ((1 << CAIRO_SPANS_UNIT_COVERAGE_BITS)-1)
 
/* A structure representing an open-ended horizontal span of constant
* pixel coverage. */
typedef struct _cairo_half_open_span {
/* The inclusive x-coordinate of the start of the span. */
int x;
 
/* The pixel coverage for the pixels to the right. */
int coverage;
} cairo_half_open_span_t;
 
/* Span renderer interface. Instances of renderers are provided by
* surfaces if they want to composite spans instead of trapezoids. */
typedef struct _cairo_span_renderer cairo_span_renderer_t;
struct _cairo_span_renderer {
/* Private status variable. */
cairo_status_t status;
 
/* Called to destroy the renderer. */
cairo_destroy_func_t destroy;
 
/* Render the spans on row y of the destination by whatever compositing
* method is required. */
cairo_warn cairo_status_t
(*render_rows) (void *abstract_renderer,
int y, int height,
const cairo_half_open_span_t *coverages,
unsigned num_coverages);
 
/* Called after all rows have been rendered to perform whatever
* final rendering step is required. This function is called just
* once before the renderer is destroyed. */
cairo_status_t (*finish) (void *abstract_renderer);
};
 
/* Scan converter interface. */
typedef struct _cairo_scan_converter cairo_scan_converter_t;
struct _cairo_scan_converter {
/* Destroy this scan converter. */
cairo_destroy_func_t destroy;
 
/* Add a single edge to the converter. */
cairo_status_t (*add_edge) (void *abstract_converter,
const cairo_point_t *p1,
const cairo_point_t *p2,
int top, int bottom,
int dir);
 
/* Add a polygon (set of edges) to the converter. */
cairo_status_t (*add_polygon) (void *abstract_converter,
const cairo_polygon_t *polygon);
 
/* Generates coverage spans for rows for the added edges and calls
* the renderer function for each row. After generating spans the
* only valid thing to do with the converter is to destroy it. */
cairo_status_t (*generate) (void *abstract_converter,
cairo_span_renderer_t *renderer);
 
/* Private status. Read with _cairo_scan_converter_status(). */
cairo_status_t status;
};
 
/* Scan converter constructors. */
 
cairo_private cairo_scan_converter_t *
_cairo_tor_scan_converter_create (int xmin,
int ymin,
int xmax,
int ymax,
cairo_fill_rule_t fill_rule);
 
typedef struct _cairo_rectangular_scan_converter {
cairo_scan_converter_t base;
 
int xmin, xmax;
int ymin, ymax;
 
struct _cairo_rectangular_scan_converter_chunk {
struct _cairo_rectangular_scan_converter_chunk *next;
void *base;
int count;
int size;
} chunks, *tail;
char buf[CAIRO_STACK_BUFFER_SIZE];
int num_rectangles;
} cairo_rectangular_scan_converter_t;
 
cairo_private void
_cairo_rectangular_scan_converter_init (cairo_rectangular_scan_converter_t *self,
const cairo_rectangle_int_t *extents);
 
cairo_private cairo_status_t
_cairo_rectangular_scan_converter_add_box (cairo_rectangular_scan_converter_t *self,
const cairo_box_t *box,
int dir);
 
typedef struct _cairo_botor_scan_converter {
cairo_scan_converter_t base;
 
cairo_box_t extents;
cairo_fill_rule_t fill_rule;
 
int xmin, xmax;
 
struct _cairo_botor_scan_converter_chunk {
struct _cairo_botor_scan_converter_chunk *next;
void *base;
int count;
int size;
} chunks, *tail;
char buf[CAIRO_STACK_BUFFER_SIZE];
int num_edges;
} cairo_botor_scan_converter_t;
 
cairo_private void
_cairo_botor_scan_converter_init (cairo_botor_scan_converter_t *self,
const cairo_box_t *extents,
cairo_fill_rule_t fill_rule);
 
/* cairo-spans.c: */
 
cairo_private cairo_scan_converter_t *
_cairo_scan_converter_create_in_error (cairo_status_t error);
 
cairo_private cairo_status_t
_cairo_scan_converter_status (void *abstract_converter);
 
cairo_private cairo_status_t
_cairo_scan_converter_set_error (void *abstract_converter,
cairo_status_t error);
 
cairo_private cairo_span_renderer_t *
_cairo_span_renderer_create_in_error (cairo_status_t error);
 
cairo_private cairo_status_t
_cairo_span_renderer_status (void *abstract_renderer);
 
/* Set the renderer into an error state. This sets all the method
* pointers except ->destroy() of the renderer to no-op
* implementations that just return the error status. */
cairo_private cairo_status_t
_cairo_span_renderer_set_error (void *abstract_renderer,
cairo_status_t error);
 
cairo_private cairo_status_t
_cairo_surface_composite_polygon (cairo_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *pattern,
cairo_fill_rule_t fill_rule,
cairo_antialias_t antialias,
const cairo_composite_rectangles_t *rects,
cairo_polygon_t *polygon,
cairo_region_t *clip_region);
 
#endif /* CAIRO_SPANS_PRIVATE_H */
/programs/develop/libraries/cairo/src/cairo-spans.c
0,0 → 1,323
/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
/* cairo - a vector graphics library with display and print output
*
* Copyright (c) 2008 M Joonas Pihlaja
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#include "cairoint.h"
 
#include "cairo-composite-rectangles-private.h"
#include "cairo-fixed-private.h"
 
static cairo_scan_converter_t *
_create_scan_converter (cairo_fill_rule_t fill_rule,
cairo_antialias_t antialias,
const cairo_composite_rectangles_t *rects)
{
if (antialias == CAIRO_ANTIALIAS_NONE) {
ASSERT_NOT_REACHED;
return NULL;
}
 
return _cairo_tor_scan_converter_create (rects->bounded.x,
rects->bounded.y,
rects->bounded.x + rects->bounded.width,
rects->bounded.y + rects->bounded.height,
fill_rule);
}
 
/* XXX Add me to the compositor interface. Ok, first create the compositor
* interface, and then add this with associated fallback!
*/
cairo_status_t
_cairo_surface_composite_polygon (cairo_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *pattern,
cairo_fill_rule_t fill_rule,
cairo_antialias_t antialias,
const cairo_composite_rectangles_t *rects,
cairo_polygon_t *polygon,
cairo_region_t *clip_region)
{
cairo_span_renderer_t *renderer;
cairo_scan_converter_t *converter;
cairo_status_t status;
 
converter = _create_scan_converter (fill_rule, antialias, rects);
status = converter->add_polygon (converter, polygon);
if (unlikely (status))
goto CLEANUP_CONVERTER;
 
renderer = _cairo_surface_create_span_renderer (op, pattern, surface,
antialias, rects,
clip_region);
status = converter->generate (converter, renderer);
if (unlikely (status))
goto CLEANUP_RENDERER;
 
status = renderer->finish (renderer);
 
CLEANUP_RENDERER:
renderer->destroy (renderer);
CLEANUP_CONVERTER:
converter->destroy (converter);
return status;
}
 
static void
_cairo_nil_destroy (void *abstract)
{
(void) abstract;
}
 
static cairo_status_t
_cairo_nil_scan_converter_add_polygon (void *abstract_converter,
const cairo_polygon_t *polygon)
{
(void) abstract_converter;
(void) polygon;
return _cairo_scan_converter_status (abstract_converter);
}
 
static cairo_status_t
_cairo_nil_scan_converter_add_edge (void *abstract_converter,
const cairo_point_t *p1,
const cairo_point_t *p2,
int top, int bottom,
int dir)
{
(void) abstract_converter;
(void) p1;
(void) p2;
(void) top;
(void) bottom;
(void) dir;
return _cairo_scan_converter_status (abstract_converter);
}
 
static cairo_status_t
_cairo_nil_scan_converter_generate (void *abstract_converter,
cairo_span_renderer_t *renderer)
{
(void) abstract_converter;
(void) renderer;
return _cairo_scan_converter_status (abstract_converter);
}
 
cairo_status_t
_cairo_scan_converter_status (void *abstract_converter)
{
cairo_scan_converter_t *converter = abstract_converter;
return converter->status;
}
 
cairo_status_t
_cairo_scan_converter_set_error (void *abstract_converter,
cairo_status_t error)
{
cairo_scan_converter_t *converter = abstract_converter;
if (error == CAIRO_STATUS_SUCCESS)
ASSERT_NOT_REACHED;
if (converter->status == CAIRO_STATUS_SUCCESS) {
converter->add_polygon = _cairo_nil_scan_converter_add_polygon;
converter->add_edge = _cairo_nil_scan_converter_add_edge;
converter->generate = _cairo_nil_scan_converter_generate;
converter->status = error;
}
return converter->status;
}
 
static void
_cairo_nil_scan_converter_init (cairo_scan_converter_t *converter,
cairo_status_t status)
{
converter->destroy = _cairo_nil_destroy;
converter->status = CAIRO_STATUS_SUCCESS;
status = _cairo_scan_converter_set_error (converter, status);
}
 
cairo_scan_converter_t *
_cairo_scan_converter_create_in_error (cairo_status_t status)
{
#define RETURN_NIL {\
static cairo_scan_converter_t nil;\
_cairo_nil_scan_converter_init (&nil, status);\
return &nil;\
}
switch (status) {
case CAIRO_STATUS_SUCCESS:
case CAIRO_STATUS_LAST_STATUS:
ASSERT_NOT_REACHED;
break;
case CAIRO_STATUS_INVALID_RESTORE: RETURN_NIL;
case CAIRO_STATUS_INVALID_POP_GROUP: RETURN_NIL;
case CAIRO_STATUS_NO_CURRENT_POINT: RETURN_NIL;
case CAIRO_STATUS_INVALID_MATRIX: RETURN_NIL;
case CAIRO_STATUS_INVALID_STATUS: RETURN_NIL;
case CAIRO_STATUS_NULL_POINTER: RETURN_NIL;
case CAIRO_STATUS_INVALID_STRING: RETURN_NIL;
case CAIRO_STATUS_INVALID_PATH_DATA: RETURN_NIL;
case CAIRO_STATUS_READ_ERROR: RETURN_NIL;
case CAIRO_STATUS_WRITE_ERROR: RETURN_NIL;
case CAIRO_STATUS_SURFACE_FINISHED: RETURN_NIL;
case CAIRO_STATUS_SURFACE_TYPE_MISMATCH: RETURN_NIL;
case CAIRO_STATUS_PATTERN_TYPE_MISMATCH: RETURN_NIL;
case CAIRO_STATUS_INVALID_CONTENT: RETURN_NIL;
case CAIRO_STATUS_INVALID_FORMAT: RETURN_NIL;
case CAIRO_STATUS_INVALID_VISUAL: RETURN_NIL;
case CAIRO_STATUS_FILE_NOT_FOUND: RETURN_NIL;
case CAIRO_STATUS_INVALID_DASH: RETURN_NIL;
case CAIRO_STATUS_INVALID_DSC_COMMENT: RETURN_NIL;
case CAIRO_STATUS_INVALID_INDEX: RETURN_NIL;
case CAIRO_STATUS_CLIP_NOT_REPRESENTABLE: RETURN_NIL;
case CAIRO_STATUS_TEMP_FILE_ERROR: RETURN_NIL;
case CAIRO_STATUS_INVALID_STRIDE: RETURN_NIL;
case CAIRO_STATUS_FONT_TYPE_MISMATCH: RETURN_NIL;
case CAIRO_STATUS_USER_FONT_IMMUTABLE: RETURN_NIL;
case CAIRO_STATUS_USER_FONT_ERROR: RETURN_NIL;
case CAIRO_STATUS_NEGATIVE_COUNT: RETURN_NIL;
case CAIRO_STATUS_INVALID_CLUSTERS: RETURN_NIL;
case CAIRO_STATUS_INVALID_SLANT: RETURN_NIL;
case CAIRO_STATUS_INVALID_WEIGHT: RETURN_NIL;
case CAIRO_STATUS_NO_MEMORY: RETURN_NIL;
case CAIRO_STATUS_INVALID_SIZE: RETURN_NIL;
case CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED: RETURN_NIL;
case CAIRO_STATUS_DEVICE_TYPE_MISMATCH: RETURN_NIL;
case CAIRO_STATUS_DEVICE_ERROR: RETURN_NIL;
default:
break;
}
status = CAIRO_STATUS_NO_MEMORY;
RETURN_NIL;
#undef RETURN_NIL
}
 
static cairo_status_t
_cairo_nil_span_renderer_render_rows (
void *abstract_renderer,
int y,
int height,
const cairo_half_open_span_t *coverages,
unsigned num_coverages)
{
(void) y;
(void) height;
(void) coverages;
(void) num_coverages;
return _cairo_span_renderer_status (abstract_renderer);
}
 
static cairo_status_t
_cairo_nil_span_renderer_finish (void *abstract_renderer)
{
return _cairo_span_renderer_status (abstract_renderer);
}
 
cairo_status_t
_cairo_span_renderer_status (void *abstract_renderer)
{
cairo_span_renderer_t *renderer = abstract_renderer;
return renderer->status;
}
 
cairo_status_t
_cairo_span_renderer_set_error (
void *abstract_renderer,
cairo_status_t error)
{
cairo_span_renderer_t *renderer = abstract_renderer;
if (error == CAIRO_STATUS_SUCCESS) {
ASSERT_NOT_REACHED;
}
if (renderer->status == CAIRO_STATUS_SUCCESS) {
renderer->render_rows = _cairo_nil_span_renderer_render_rows;
renderer->finish = _cairo_nil_span_renderer_finish;
renderer->status = error;
}
return renderer->status;
}
 
static void
_cairo_nil_span_renderer_init (cairo_span_renderer_t *renderer,
cairo_status_t status)
{
renderer->destroy = _cairo_nil_destroy;
renderer->status = CAIRO_STATUS_SUCCESS;
status = _cairo_span_renderer_set_error (renderer, status);
}
 
cairo_span_renderer_t *
_cairo_span_renderer_create_in_error (cairo_status_t status)
{
#define RETURN_NIL {\
static cairo_span_renderer_t nil;\
_cairo_nil_span_renderer_init (&nil, status);\
return &nil;\
}
switch (status) {
case CAIRO_STATUS_SUCCESS:
case CAIRO_STATUS_LAST_STATUS:
ASSERT_NOT_REACHED;
break;
case CAIRO_STATUS_INVALID_RESTORE: RETURN_NIL;
case CAIRO_STATUS_INVALID_POP_GROUP: RETURN_NIL;
case CAIRO_STATUS_NO_CURRENT_POINT: RETURN_NIL;
case CAIRO_STATUS_INVALID_MATRIX: RETURN_NIL;
case CAIRO_STATUS_INVALID_STATUS: RETURN_NIL;
case CAIRO_STATUS_NULL_POINTER: RETURN_NIL;
case CAIRO_STATUS_INVALID_STRING: RETURN_NIL;
case CAIRO_STATUS_INVALID_PATH_DATA: RETURN_NIL;
case CAIRO_STATUS_READ_ERROR: RETURN_NIL;
case CAIRO_STATUS_WRITE_ERROR: RETURN_NIL;
case CAIRO_STATUS_SURFACE_FINISHED: RETURN_NIL;
case CAIRO_STATUS_SURFACE_TYPE_MISMATCH: RETURN_NIL;
case CAIRO_STATUS_PATTERN_TYPE_MISMATCH: RETURN_NIL;
case CAIRO_STATUS_INVALID_CONTENT: RETURN_NIL;
case CAIRO_STATUS_INVALID_FORMAT: RETURN_NIL;
case CAIRO_STATUS_INVALID_VISUAL: RETURN_NIL;
case CAIRO_STATUS_FILE_NOT_FOUND: RETURN_NIL;
case CAIRO_STATUS_INVALID_DASH: RETURN_NIL;
case CAIRO_STATUS_INVALID_DSC_COMMENT: RETURN_NIL;
case CAIRO_STATUS_INVALID_INDEX: RETURN_NIL;
case CAIRO_STATUS_CLIP_NOT_REPRESENTABLE: RETURN_NIL;
case CAIRO_STATUS_TEMP_FILE_ERROR: RETURN_NIL;
case CAIRO_STATUS_INVALID_STRIDE: RETURN_NIL;
case CAIRO_STATUS_FONT_TYPE_MISMATCH: RETURN_NIL;
case CAIRO_STATUS_USER_FONT_IMMUTABLE: RETURN_NIL;
case CAIRO_STATUS_USER_FONT_ERROR: RETURN_NIL;
case CAIRO_STATUS_NEGATIVE_COUNT: RETURN_NIL;
case CAIRO_STATUS_INVALID_CLUSTERS: RETURN_NIL;
case CAIRO_STATUS_INVALID_SLANT: RETURN_NIL;
case CAIRO_STATUS_INVALID_WEIGHT: RETURN_NIL;
case CAIRO_STATUS_NO_MEMORY: RETURN_NIL;
case CAIRO_STATUS_INVALID_SIZE: RETURN_NIL;
case CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED: RETURN_NIL;
case CAIRO_STATUS_DEVICE_TYPE_MISMATCH: RETURN_NIL;
case CAIRO_STATUS_DEVICE_ERROR: RETURN_NIL;
default:
break;
}
status = CAIRO_STATUS_NO_MEMORY;
RETURN_NIL;
#undef RETURN_NIL
}
/programs/develop/libraries/cairo/src/cairo-spline.c
0,0 → 1,368
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2002 University of Southern California
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
*/
 
#include "cairoint.h"
 
#include "cairo-slope-private.h"
 
cairo_bool_t
_cairo_spline_init (cairo_spline_t *spline,
cairo_spline_add_point_func_t add_point_func,
void *closure,
const cairo_point_t *a, const cairo_point_t *b,
const cairo_point_t *c, const cairo_point_t *d)
{
spline->add_point_func = add_point_func;
spline->closure = closure;
 
spline->knots.a = *a;
spline->knots.b = *b;
spline->knots.c = *c;
spline->knots.d = *d;
 
if (a->x != b->x || a->y != b->y)
_cairo_slope_init (&spline->initial_slope, &spline->knots.a, &spline->knots.b);
else if (a->x != c->x || a->y != c->y)
_cairo_slope_init (&spline->initial_slope, &spline->knots.a, &spline->knots.c);
else if (a->x != d->x || a->y != d->y)
_cairo_slope_init (&spline->initial_slope, &spline->knots.a, &spline->knots.d);
else
return FALSE;
 
if (c->x != d->x || c->y != d->y)
_cairo_slope_init (&spline->final_slope, &spline->knots.c, &spline->knots.d);
else if (b->x != d->x || b->y != d->y)
_cairo_slope_init (&spline->final_slope, &spline->knots.b, &spline->knots.d);
else
_cairo_slope_init (&spline->final_slope, &spline->knots.a, &spline->knots.d);
 
return TRUE;
}
 
static cairo_status_t
_cairo_spline_add_point (cairo_spline_t *spline, cairo_point_t *point)
{
cairo_point_t *prev;
 
prev = &spline->last_point;
if (prev->x == point->x && prev->y == point->y)
return CAIRO_STATUS_SUCCESS;
 
spline->last_point = *point;
return spline->add_point_func (spline->closure, point);
}
 
static void
_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->y = a->y + ((b->y - a->y) >> 1);
}
 
static void
_de_casteljau (cairo_spline_knots_t *s1, cairo_spline_knots_t *s2)
{
cairo_point_t ab, bc, cd;
cairo_point_t abbc, bccd;
cairo_point_t final;
 
_lerp_half (&s1->a, &s1->b, &ab);
_lerp_half (&s1->b, &s1->c, &bc);
_lerp_half (&s1->c, &s1->d, &cd);
_lerp_half (&ab, &bc, &abbc);
_lerp_half (&bc, &cd, &bccd);
_lerp_half (&abbc, &bccd, &final);
 
s2->a = final;
s2->b = bccd;
s2->c = cd;
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
_cairo_spline_error_squared (const cairo_spline_knots_t *knots)
{
double bdx, bdy, berr;
double cdx, cdy, cerr;
 
/* We are going to compute the distance (squared) between each of the the b
* and c control points and the segment a-b. The maximum of these two
* distances will be our approximation error. */
 
bdx = _cairo_fixed_to_double (knots->b.x - knots->a.x);
bdy = _cairo_fixed_to_double (knots->b.y - knots->a.y);
 
cdx = _cairo_fixed_to_double (knots->c.x - knots->a.x);
cdy = _cairo_fixed_to_double (knots->c.y - knots->a.y);
 
if (knots->a.x != knots->d.x || knots->a.y != knots->d.y) {
/* Intersection point (px):
* px = p1 + u(p2 - p1)
* (p - px) ∙ (p2 - p1) = 0
* Thus:
* u = ((p - p1) ∙ (p2 - p1)) / ∥p2 - p1∥²;
*/
 
double dx, dy, u, v;
 
dx = _cairo_fixed_to_double (knots->d.x - knots->a.x);
dy = _cairo_fixed_to_double (knots->d.y - knots->a.y);
v = dx * dx + dy * dy;
 
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 = cdx * dx + cdy * dy;
if (u <= 0) {
/* cdx -= 0;
* cdy -= 0;
*/
} else if (u >= v) {
cdx -= dx;
cdy -= dy;
} else {
cdx -= u/v * dx;
cdy -= u/v * dy;
}
}
 
berr = bdx * bdx + bdy * bdy;
cerr = cdx * cdx + cdy * cdy;
if (berr > cerr)
return berr;
else
return cerr;
}
 
static cairo_status_t
_cairo_spline_decompose_into (cairo_spline_knots_t *s1, double tolerance_squared, cairo_spline_t *result)
{
cairo_spline_knots_t s2;
cairo_status_t status;
 
if (_cairo_spline_error_squared (s1) < tolerance_squared)
return _cairo_spline_add_point (result, &s1->a);
 
_de_casteljau (s1, &s2);
 
status = _cairo_spline_decompose_into (s1, tolerance_squared, result);
if (unlikely (status))
return status;
 
return _cairo_spline_decompose_into (&s2, tolerance_squared, result);
}
 
cairo_status_t
_cairo_spline_decompose (cairo_spline_t *spline, double tolerance)
{
cairo_spline_knots_t s1;
cairo_status_t status;
 
s1 = spline->knots;
spline->last_point = s1.a;
status = _cairo_spline_decompose_into (&s1, tolerance * tolerance, spline);
if (unlikely (status))
return status;
 
return _cairo_spline_add_point (spline, &spline->knots.d);
}
 
/* Note: this function is only good for computing bounds in device space. */
cairo_status_t
_cairo_spline_bound (cairo_spline_add_point_func_t add_point_func,
void *closure,
const cairo_point_t *p0, const cairo_point_t *p1,
const cairo_point_t *p2, const cairo_point_t *p3)
{
double x0, x1, x2, x3;
double y0, y1, y2, y3;
double a, b, c;
double t[4];
int t_num = 0, i;
cairo_status_t status;
 
x0 = _cairo_fixed_to_double (p0->x);
y0 = _cairo_fixed_to_double (p0->y);
x1 = _cairo_fixed_to_double (p1->x);
y1 = _cairo_fixed_to_double (p1->y);
x2 = _cairo_fixed_to_double (p2->x);
y2 = _cairo_fixed_to_double (p2->y);
x3 = _cairo_fixed_to_double (p3->x);
y3 = _cairo_fixed_to_double (p3->y);
 
/* The spline can be written as a polynomial of the four points:
*
* (1-t)³p0 + 3t(1-t)²p1 + 3t²(1-t)p2 + t³p3
*
* for 0≤t≤1. Now, the X and Y components of the spline follow the
* same polynomial but with x and y replaced for p. To find the
* bounds of the spline, we just need to find the X and Y bounds.
* To find the bound, we take the derivative and equal it to zero,
* and solve to find the t's that give the extreme points.
*
* Here is the derivative of the curve, sorted on t:
*
* 3t²(-p0+3p1-3p2+p3) + 2t(3p0-6p1+3p2) -3p0+3p1
*
* Let:
*
* a = -p0+3p1-3p2+p3
* b = p0-2p1+p2
* c = -p0+p1
*
* Gives:
*
* a.t² + 2b.t + c = 0
*
* With:
*
* delta = b*b - a*c
*
* the extreme points are at -c/2b if a is zero, at (-b±√delta)/a if
* delta is positive, and at -b/a if delta is zero.
*/
 
#define ADD(t0) \
{ \
double _t0 = (t0); \
if (0 < _t0 && _t0 < 1) \
t[t_num++] = _t0; \
}
 
#define FIND_EXTREMES(a,b,c) \
{ \
if (a == 0) { \
if (b != 0) \
ADD (-c / (2*b)); \
} else { \
double b2 = b * b; \
double delta = b2 - a * c; \
if (delta > 0) { \
cairo_bool_t feasible; \
double _2ab = 2 * a * b; \
/* We are only interested in solutions t that satisfy 0<t<1 \
* here. We do some checks to avoid sqrt if the solutions \
* are not in that range. The checks can be derived from: \
* \
* 0 < (-b±√delta)/a < 1 \
*/ \
if (_2ab >= 0) \
feasible = delta > b2 && delta < a*a + b2 + _2ab; \
else if (-b / a >= 1) \
feasible = delta < b2 && delta > a*a + b2 + _2ab; \
else \
feasible = delta < b2 || delta < a*a + b2 + _2ab; \
\
if (unlikely (feasible)) { \
double sqrt_delta = sqrt (delta); \
ADD ((-b - sqrt_delta) / a); \
ADD ((-b + sqrt_delta) / a); \
} \
} else if (delta == 0) { \
ADD (-b / a); \
} \
} \
}
 
/* Find X extremes */
a = -x0 + 3*x1 - 3*x2 + x3;
b = x0 - 2*x1 + x2;
c = -x0 + x1;
FIND_EXTREMES (a, b, c);
 
/* Find Y extremes */
a = -y0 + 3*y1 - 3*y2 + y3;
b = y0 - 2*y1 + y2;
c = -y0 + y1;
FIND_EXTREMES (a, b, c);
 
status = add_point_func (closure, p0);
if (unlikely (status))
return status;
 
for (i = 0; i < t_num; i++) {
cairo_point_t p;
double x, y;
double t_1_0, t_0_1;
double t_2_0, t_0_2;
double t_3_0, t_2_1_3, t_1_2_3, t_0_3;
 
t_1_0 = t[i]; /* t */
t_0_1 = 1 - t_1_0; /* (1 - t) */
 
t_2_0 = t_1_0 * t_1_0; /* t * t */
t_0_2 = t_0_1 * t_0_1; /* (1 - t) * (1 - t) */
 
t_3_0 = t_2_0 * t_1_0; /* t * t * t */
t_2_1_3 = t_2_0 * t_0_1 * 3; /* t * t * (1 - t) * 3 */
t_1_2_3 = t_1_0 * t_0_2 * 3; /* t * (1 - t) * (1 - t) * 3 */
t_0_3 = t_0_1 * t_0_2; /* (1 - t) * (1 - t) * (1 - t) */
 
/* Bezier polynomial */
x = x0 * t_0_3
+ x1 * t_1_2_3
+ x2 * t_2_1_3
+ x3 * t_3_0;
y = y0 * t_0_3
+ y1 * t_1_2_3
+ y2 * t_2_1_3
+ y3 * t_3_0;
 
p.x = _cairo_fixed_from_double (x);
p.y = _cairo_fixed_from_double (y);
status = add_point_func (closure, &p);
if (unlikely (status))
return status;
}
 
return add_point_func (closure, p3);
}
/programs/develop/libraries/cairo/src/cairo-stroke-style.c
0,0 → 1,310
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2005 Red Hat, Inc
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
* Carl Worth <cworth@cworth.org>
*/
 
#include "cairoint.h"
#include "cairo-error-private.h"
 
void
_cairo_stroke_style_init (cairo_stroke_style_t *style)
{
VG (VALGRIND_MAKE_MEM_UNDEFINED (style, sizeof (cairo_stroke_style_t)));
 
style->line_width = CAIRO_GSTATE_LINE_WIDTH_DEFAULT;
style->line_cap = CAIRO_GSTATE_LINE_CAP_DEFAULT;
style->line_join = CAIRO_GSTATE_LINE_JOIN_DEFAULT;
style->miter_limit = CAIRO_GSTATE_MITER_LIMIT_DEFAULT;
 
style->dash = NULL;
style->num_dashes = 0;
style->dash_offset = 0.0;
}
 
cairo_status_t
_cairo_stroke_style_init_copy (cairo_stroke_style_t *style,
const cairo_stroke_style_t *other)
{
if (CAIRO_INJECT_FAULT ())
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
VG (VALGRIND_MAKE_MEM_UNDEFINED (style, sizeof (cairo_stroke_style_t)));
 
style->line_width = other->line_width;
style->line_cap = other->line_cap;
style->line_join = other->line_join;
style->miter_limit = other->miter_limit;
 
style->num_dashes = other->num_dashes;
 
if (other->dash == NULL) {
style->dash = NULL;
} else {
style->dash = _cairo_malloc_ab (style->num_dashes, sizeof (double));
if (unlikely (style->dash == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
memcpy (style->dash, other->dash,
style->num_dashes * sizeof (double));
}
 
style->dash_offset = other->dash_offset;
 
return CAIRO_STATUS_SUCCESS;
}
 
void
_cairo_stroke_style_fini (cairo_stroke_style_t *style)
{
if (style->dash) {
free (style->dash);
style->dash = NULL;
}
style->num_dashes = 0;
 
VG (VALGRIND_MAKE_MEM_NOACCESS (style, sizeof (cairo_stroke_style_t)));
}
 
/*
* For a stroke in the given style, compute the maximum distance
* from the path that vertices could be generated. In the case
* of rotation in the ctm, the distance will not be exact.
*/
void
_cairo_stroke_style_max_distance_from_path (const cairo_stroke_style_t *style,
const cairo_matrix_t *ctm,
double *dx, double *dy)
{
double style_expansion = 0.5;
 
if (style->line_cap == CAIRO_LINE_CAP_SQUARE)
style_expansion = M_SQRT1_2;
 
if (style->line_join == CAIRO_LINE_JOIN_MITER &&
style_expansion < M_SQRT2 * style->miter_limit)
{
style_expansion = M_SQRT2 * style->miter_limit;
}
 
style_expansion *= style->line_width;
 
*dx = style_expansion * hypot (ctm->xx, ctm->xy);
*dy = style_expansion * hypot (ctm->yy, ctm->yx);
}
 
/*
* Computes the period of a dashed stroke style.
* Returns 0 for non-dashed styles.
*/
double
_cairo_stroke_style_dash_period (const cairo_stroke_style_t *style)
{
double period;
unsigned int i;
 
period = 0.0;
for (i = 0; i < style->num_dashes; i++)
period += style->dash[i];
 
if (style->num_dashes & 1)
period *= 2.0;
 
return period;
}
 
/*
* Coefficient of the linear approximation (minimizing square difference)
* of the surface covered by round caps
*
* This can be computed in the following way:
* the area inside the circle with radius w/2 and the region -d/2 <= x <= d/2 is:
* f(w,d) = 2 * integrate (sqrt (w*w/4 - x*x), x, -d/2, d/2)
* The square difference to a generic linear approximation (c*d) in the range (0,w) would be:
* integrate ((f(w,d) - c*d)^2, d, 0, w)
* To minimize this difference it is sufficient to find a solution of the differential with
* respect to c:
* solve ( diff (integrate ((f(w,d) - c*d)^2, d, 0, w), c), c)
* Which leads to c = 9/32*pi*w
* Since we're not interested in the true area, but just in a coverage extimate,
* we always divide the real area by the line width (w).
* The same computation for square caps would be
* f(w,d) = 2 * integrate(w/2, x, -d/2, d/2)
* c = 1*w
* but in this case it would not be an approximation, since f is already linear in d.
*/
#define ROUND_MINSQ_APPROXIMATION (9*M_PI/32)
 
/*
* Computes the length of the "on" part of a dashed stroke style,
* taking into account also line caps.
* Returns 0 for non-dashed styles.
*/
double
_cairo_stroke_style_dash_stroked (const cairo_stroke_style_t *style)
{
double stroked, cap_scale;
unsigned int i;
 
switch (style->line_cap) {
default: ASSERT_NOT_REACHED;
case CAIRO_LINE_CAP_BUTT: cap_scale = 0.0; break;
case CAIRO_LINE_CAP_ROUND: cap_scale = ROUND_MINSQ_APPROXIMATION; break;
case CAIRO_LINE_CAP_SQUARE: cap_scale = 1.0; break;
}
 
stroked = 0.0;
if (style->num_dashes & 1) {
/* Each dash element is used both as on and as off. The order in which they are summed is
* irrelevant, so sum the coverage of one dash element, taken both on and off at each iteration */
for (i = 0; i < style->num_dashes; i++)
stroked += style->dash[i] + cap_scale * MIN (style->dash[i], style->line_width);
} else {
/* Even (0, 2, ...) dashes are on and simply counted for the coverage, odd dashes are off, thus
* their coverage is approximated based on the area covered by the caps of adjacent on dases. */
for (i = 0; i < style->num_dashes; i+=2)
stroked += style->dash[i] + cap_scale * MIN (style->dash[i+1], style->line_width);
}
 
return stroked;
}
 
/*
* Verifies if _cairo_stroke_style_dash_approximate should be used to generate
* an approximation of the dash pattern in the specified style, when used for
* stroking a path with the given CTM and tolerance.
* Always %FALSE for non-dashed styles.
*/
cairo_bool_t
_cairo_stroke_style_dash_can_approximate (const cairo_stroke_style_t *style,
const cairo_matrix_t *ctm,
double tolerance)
{
double period;
 
if (! style->num_dashes)
return FALSE;
 
period = _cairo_stroke_style_dash_period (style);
return _cairo_matrix_transformed_circle_major_axis (ctm, period) < tolerance;
}
 
/*
* Create a 2-dashes approximation of a dashed style, by making the "on" and "off"
* parts respect the original ratio.
*/
void
_cairo_stroke_style_dash_approximate (const cairo_stroke_style_t *style,
const cairo_matrix_t *ctm,
double tolerance,
double *dash_offset,
double *dashes,
unsigned int *num_dashes)
{
double coverage, scale, offset;
cairo_bool_t on = TRUE;
unsigned int i = 0;
 
coverage = _cairo_stroke_style_dash_stroked (style) / _cairo_stroke_style_dash_period (style);
coverage = MIN (coverage, 1.0);
scale = tolerance / _cairo_matrix_transformed_circle_major_axis (ctm, 1.0);
 
/* We stop searching for a starting point as soon as the
* offset reaches zero. Otherwise when an initial dash
* segment shrinks to zero it will be skipped over. */
offset = style->dash_offset;
while (offset > 0.0 && offset >= style->dash[i]) {
offset -= style->dash[i];
on = !on;
if (++i == style->num_dashes)
i = 0;
}
 
*num_dashes = 2;
 
/*
* We want to create a new dash pattern with the same relative coverage,
* but composed of just 2 elements with total length equal to scale.
* Based on the formula in _cairo_stroke_style_dash_stroked:
* scale * coverage = dashes[0] + cap_scale * MIN (dashes[1], line_width)
* = MIN (dashes[0] + cap_scale * (scale - dashes[0]),
* dashes[0] + cap_scale * line_width) =
* = MIN (dashes[0] * (1 - cap_scale) + cap_scale * scale,
* dashes[0] + cap_scale * line_width)
*
* Solving both cases we get:
* dashes[0] = scale * (coverage - cap_scale) / (1 - cap_scale)
* when scale - dashes[0] <= line_width
* dashes[0] = scale * coverage - cap_scale * line_width
* when scale - dashes[0] > line_width.
*
* Comparing the two cases we get:
* second > first
* second > scale * (coverage - cap_scale) / (1 - cap_scale)
* second - cap_scale * second - scale * coverage + scale * cap_scale > 0
* (scale * coverage - cap_scale * line_width) - cap_scale * second - scale * coverage + scale * cap_scale > 0
* - line_width - second + scale > 0
* scale - second > line_width
* which is the condition for the second solution to be the valid one.
* So when second > first, the second solution is the correct one (i.e.
* the solution is always MAX (first, second).
*/
switch (style->line_cap) {
default:
ASSERT_NOT_REACHED;
dashes[0] = 0.0;
break;
 
case CAIRO_LINE_CAP_BUTT:
/* Simplified formula (substituting 0 for cap_scale): */
dashes[0] = scale * coverage;
break;
 
case CAIRO_LINE_CAP_ROUND:
dashes[0] = MAX(scale * (coverage - ROUND_MINSQ_APPROXIMATION) / (1.0 - ROUND_MINSQ_APPROXIMATION),
scale * coverage - ROUND_MINSQ_APPROXIMATION * style->line_width);
break;
 
case CAIRO_LINE_CAP_SQUARE:
/*
* Special attention is needed to handle the case cap_scale == 1 (since the first solution
* is either indeterminate or -inf in this case). Since dash lengths are always >=0, using
* 0 as first solution always leads to the correct solution.
*/
dashes[0] = MAX(0.0, scale * coverage - style->line_width);
break;
}
 
dashes[1] = scale - dashes[0];
 
*dash_offset = on ? 0.0 : dashes[0];
}
/programs/develop/libraries/cairo/src/cairo-supported-features.h
0,0 → 1,28
/* Generated by configure. Do not edit. */
#ifndef CAIRO_SUPPORTED_FEATURES_H
#define CAIRO_SUPPORTED_FEATURES_H
 
/* This is a dummy header, to trick gtk-doc only */
 
#define CAIRO_HAS_XLIB_SURFACE 1
#define CAIRO_HAS_XLIB_XRENDER_SURFACE 1
#define CAIRO_HAS_XCB_SHM_FUNCTIONS 1
#define CAIRO_HAS_QUARTZ_SURFACE 1
#define CAIRO_HAS_QUARTZ_FONT 1
#define CAIRO_HAS_WIN32_SURFACE 1
#define CAIRO_HAS_WIN32_FONT 1
#define CAIRO_HAS_PNG_FUNCTIONS 1
#define CAIRO_HAS_EGL_FUNCTIONS 1
#define CAIRO_HAS_GLX_FUNCTIONS 1
#define CAIRO_HAS_WGL_FUNCTIONS 1
#define CAIRO_HAS_FT_FONT 1
#define CAIRO_HAS_FC_FONT 1
#define CAIRO_HAS_PS_SURFACE 1
#define CAIRO_HAS_PDF_SURFACE 1
#define CAIRO_HAS_SVG_SURFACE 1
#define CAIRO_HAS_IMAGE_SURFACE 1
#define CAIRO_HAS_RECORDING_SURFACE 1
#define CAIRO_HAS_USER_FONT 1
#define CAIRO_HAS_GOBJECT_FUNCTIONS 1
 
#endif
/programs/develop/libraries/cairo/src/cairo-surface-clipper-private.h
0,0 → 1,72
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2009 Chris Wilson
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Chris Wilson <chris@chris-wilson.co.u>
*/
 
#ifndef CAIRO_SURFACE_CLIPPER_PRIVATE_H
#define CAIRO_SURFACE_CLIPPER_PRIVATE_H
 
#include "cairo-types-private.h"
#include "cairo-clip-private.h"
 
CAIRO_BEGIN_DECLS
 
typedef struct _cairo_surface_clipper cairo_surface_clipper_t;
 
typedef cairo_status_t
(*cairo_surface_clipper_intersect_clip_path_func_t) (cairo_surface_clipper_t *,
cairo_path_fixed_t *,
cairo_fill_rule_t,
double,
cairo_antialias_t);
struct _cairo_surface_clipper {
cairo_clip_t clip;
cairo_bool_t is_clipped;
cairo_surface_clipper_intersect_clip_path_func_t intersect_clip_path;
};
 
cairo_private cairo_status_t
_cairo_surface_clipper_set_clip (cairo_surface_clipper_t *clipper,
cairo_clip_t *clip);
 
cairo_private void
_cairo_surface_clipper_init (cairo_surface_clipper_t *clipper,
cairo_surface_clipper_intersect_clip_path_func_t intersect);
 
cairo_private void
_cairo_surface_clipper_reset (cairo_surface_clipper_t *clipper);
 
CAIRO_END_DECLS
 
#endif /* CAIRO_SURFACE_CLIPPER_PRIVATE_H */
/programs/develop/libraries/cairo/src/cairo-surface-clipper.c
0,0 → 1,135
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2009 Chris Wilson
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
* Chris Wilson <chris@chris-wilson.co.uk>
*/
 
#include "cairoint.h"
 
#include "cairo-surface-clipper-private.h"
 
/* A collection of routines to facilitate vector surface clipping */
 
static cairo_status_t
_cairo_surface_clipper_intersect_clip_path_recursive (cairo_surface_clipper_t *clipper,
cairo_clip_path_t *clip_path)
{
cairo_status_t status;
 
if (clip_path->prev != NULL) {
status =
_cairo_surface_clipper_intersect_clip_path_recursive (clipper,
clip_path->prev);
if (unlikely (status))
return status;
}
 
return clipper->intersect_clip_path (clipper,
&clip_path->path,
clip_path->fill_rule,
clip_path->tolerance,
clip_path->antialias);
}
 
cairo_status_t
_cairo_surface_clipper_set_clip (cairo_surface_clipper_t *clipper,
cairo_clip_t *clip)
{
cairo_status_t status;
cairo_bool_t clear;
 
/* XXX as we cache a reference to the path, and compare every time,
* we may in future need to install a notification if the clip->path
* is every modified (e.g. cairo_clip_translate).
*/
 
if (clip == NULL && clipper->clip.path == NULL)
return CAIRO_STATUS_SUCCESS;
 
if (clip != NULL && clipper->clip.path != NULL &&
_cairo_clip_equal (clip, &clipper->clip))
{
return CAIRO_STATUS_SUCCESS;
}
 
/* all clipped out state should never propagate this far */
assert (clip == NULL || clip->path != NULL);
 
/* Check whether this clip is a continuation of the previous.
* If not, we have to remove the current clip and rebuild.
*/
clear = clip == NULL || clip->path->prev != clipper->clip.path;
 
_cairo_clip_reset (&clipper->clip);
_cairo_clip_init_copy (&clipper->clip, clip);
 
if (clear) {
clipper->is_clipped = FALSE;
status = clipper->intersect_clip_path (clipper, NULL, 0, 0, 0);
if (unlikely (status))
return status;
 
if (clip != NULL && clip->path != NULL) {
status =
_cairo_surface_clipper_intersect_clip_path_recursive (clipper,
clip->path);
clipper->is_clipped = TRUE;
}
} else {
cairo_clip_path_t *path = clip->path;
 
clipper->is_clipped = TRUE;
status = clipper->intersect_clip_path (clipper,
&path->path,
path->fill_rule,
path->tolerance,
path->antialias);
}
 
return status;
}
 
void
_cairo_surface_clipper_init (cairo_surface_clipper_t *clipper,
cairo_surface_clipper_intersect_clip_path_func_t func)
{
_cairo_clip_init (&clipper->clip);
clipper->is_clipped = FALSE;
clipper->intersect_clip_path = func;
}
 
void
_cairo_surface_clipper_reset (cairo_surface_clipper_t *clipper)
{
_cairo_clip_reset (&clipper->clip);
clipper->is_clipped = FALSE;
}
/programs/develop/libraries/cairo/src/cairo-surface-fallback-private.h
0,0 → 1,139
/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2002 University of Southern California
* Copyright © 2005 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
*/
 
#ifndef CAIRO_SURFACE_FALLBACK_PRIVATE_H
#define CAIRO_SURFACE_FALLBACK_PRIVATE_H
 
#include "cairoint.h"
 
cairo_private cairo_status_t
_cairo_surface_fallback_paint (cairo_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_clip_t *clip);
 
cairo_private cairo_status_t
_cairo_surface_fallback_mask (cairo_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_pattern_t *mask,
cairo_clip_t *clip);
 
cairo_private cairo_status_t
_cairo_surface_fallback_stroke (cairo_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_path_fixed_t *path,
const cairo_stroke_style_t *stroke_style,
const cairo_matrix_t *ctm,
const cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
cairo_clip_t *clip);
 
cairo_private cairo_status_t
_cairo_surface_fallback_fill (cairo_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias,
cairo_clip_t *clip);
 
cairo_private cairo_status_t
_cairo_surface_fallback_show_glyphs (cairo_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font,
cairo_clip_t *clip);
 
cairo_private cairo_surface_t *
_cairo_surface_fallback_snapshot (cairo_surface_t *surface);
 
cairo_private cairo_status_t
_cairo_surface_fallback_composite (cairo_operator_t op,
const cairo_pattern_t *src,
const cairo_pattern_t *mask,
cairo_surface_t *dst,
int src_x,
int src_y,
int mask_x,
int mask_y,
int dst_x,
int dst_y,
unsigned int width,
unsigned int height,
cairo_region_t *clip_region);
 
cairo_private cairo_status_t
_cairo_surface_fallback_fill_rectangles (cairo_surface_t *surface,
cairo_operator_t op,
const cairo_color_t *color,
cairo_rectangle_int_t *rects,
int num_rects);
 
cairo_private cairo_status_t
_cairo_surface_fallback_composite_trapezoids (cairo_operator_t op,
const cairo_pattern_t *pattern,
cairo_surface_t *dst,
cairo_antialias_t antialias,
int src_x,
int src_y,
int dst_x,
int dst_y,
unsigned int width,
unsigned int height,
cairo_trapezoid_t *traps,
int num_traps,
cairo_region_t *clip_region);
 
cairo_private cairo_status_t
_cairo_surface_fallback_clone_similar (cairo_surface_t *surface,
cairo_surface_t *src,
int src_x,
int src_y,
int width,
int height,
int *clone_offset_x,
int *clone_offset_y,
cairo_surface_t **clone_out);
 
#endif
/programs/develop/libraries/cairo/src/cairo-surface-fallback.c
0,0 → 1,1642
/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2002 University of Southern California
* Copyright © 2005 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
* Joonas Pihlaja <jpihlaja@cc.helsinki.fi>
* Chris Wilson <chris@chris-wilson.co.uk>
*/
 
#include "cairoint.h"
 
#include "cairo-boxes-private.h"
#include "cairo-clip-private.h"
#include "cairo-composite-rectangles-private.h"
#include "cairo-error-private.h"
#include "cairo-region-private.h"
#include "cairo-spans-private.h"
#include "cairo-surface-fallback-private.h"
 
typedef struct {
cairo_surface_t *dst;
cairo_rectangle_int_t extents;
cairo_image_surface_t *image;
cairo_rectangle_int_t image_rect;
void *image_extra;
} fallback_state_t;
 
/**
* _fallback_init:
*
* Acquire destination image surface needed for an image-based
* fallback.
*
* Return value: %CAIRO_INT_STATUS_NOTHING_TO_DO if the extents are not
* visible, %CAIRO_STATUS_SUCCESS if some portion is visible and all
* went well, or some error status otherwise.
**/
static cairo_int_status_t
_fallback_init (fallback_state_t *state,
cairo_surface_t *dst,
int x,
int y,
int width,
int height)
{
cairo_status_t status;
 
state->extents.x = x;
state->extents.y = y;
state->extents.width = width;
state->extents.height = height;
 
state->dst = dst;
 
status = _cairo_surface_acquire_dest_image (dst, &state->extents,
&state->image, &state->image_rect,
&state->image_extra);
if (unlikely (status))
return status;
 
 
/* XXX: This NULL value tucked away in state->image is a rather
* ugly interface. Cleaner would be to push the
* CAIRO_INT_STATUS_NOTHING_TO_DO value down into
* _cairo_surface_acquire_dest_image and its backend
* counterparts. */
assert (state->image != NULL);
 
return CAIRO_STATUS_SUCCESS;
}
 
static void
_fallback_fini (fallback_state_t *state)
{
_cairo_surface_release_dest_image (state->dst, &state->extents,
state->image, &state->image_rect,
state->image_extra);
}
 
typedef cairo_status_t
(*cairo_draw_func_t) (void *closure,
cairo_operator_t op,
const cairo_pattern_t *src,
cairo_surface_t *dst,
int dst_x,
int dst_y,
const cairo_rectangle_int_t *extents,
cairo_region_t *clip_region);
 
static cairo_status_t
_create_composite_mask_pattern (cairo_surface_pattern_t *mask_pattern,
cairo_clip_t *clip,
cairo_draw_func_t draw_func,
void *draw_closure,
cairo_surface_t *dst,
const cairo_rectangle_int_t *extents)
{
cairo_surface_t *mask;
cairo_region_t *clip_region = NULL, *fallback_region = NULL;
cairo_status_t status;
cairo_bool_t clip_surface = FALSE;
 
if (clip != NULL) {
status = _cairo_clip_get_region (clip, &clip_region);
if (unlikely (_cairo_status_is_error (status) ||
status == CAIRO_INT_STATUS_NOTHING_TO_DO))
{
return status;
}
 
clip_surface = status == CAIRO_INT_STATUS_UNSUPPORTED;
}
 
/* We need to use solid here, because to use CAIRO_OPERATOR_SOURCE with
* a mask (as called via _cairo_surface_mask) triggers assertion failures.
*/
mask = _cairo_surface_create_similar_solid (dst,
CAIRO_CONTENT_ALPHA,
extents->width,
extents->height,
CAIRO_COLOR_TRANSPARENT,
TRUE);
if (unlikely (mask->status))
return mask->status;
 
if (clip_region && (extents->x || extents->y)) {
fallback_region = cairo_region_copy (clip_region);
status = fallback_region->status;
if (unlikely (status))
goto CLEANUP_SURFACE;
 
cairo_region_translate (fallback_region,
-extents->x,
-extents->y);
clip_region = fallback_region;
}
 
status = draw_func (draw_closure, CAIRO_OPERATOR_ADD,
&_cairo_pattern_white.base, mask,
extents->x, extents->y,
extents,
clip_region);
if (unlikely (status))
goto CLEANUP_SURFACE;
 
if (clip_surface)
status = _cairo_clip_combine_with_surface (clip, mask, extents->x, extents->y);
 
_cairo_pattern_init_for_surface (mask_pattern, mask);
 
CLEANUP_SURFACE:
if (fallback_region)
cairo_region_destroy (fallback_region);
cairo_surface_destroy (mask);
 
return status;
}
 
/* Handles compositing with a clip surface when the operator allows
* us to combine the clip with the mask
*/
static cairo_status_t
_clip_and_composite_with_mask (cairo_clip_t *clip,
cairo_operator_t op,
const cairo_pattern_t *src,
cairo_draw_func_t draw_func,
void *draw_closure,
cairo_surface_t *dst,
const cairo_rectangle_int_t *extents)
{
cairo_surface_pattern_t mask_pattern;
cairo_status_t status;
 
status = _create_composite_mask_pattern (&mask_pattern,
clip,
draw_func, draw_closure,
dst, extents);
if (likely (status == CAIRO_STATUS_SUCCESS)) {
status = _cairo_surface_composite (op,
src, &mask_pattern.base, dst,
extents->x, extents->y,
0, 0,
extents->x, extents->y,
extents->width, extents->height,
NULL);
 
_cairo_pattern_fini (&mask_pattern.base);
}
 
return status;
}
 
/* Handles compositing with a clip surface when we have to do the operation
* in two pieces and combine them together.
*/
static cairo_status_t
_clip_and_composite_combine (cairo_clip_t *clip,
cairo_operator_t op,
const cairo_pattern_t *src,
cairo_draw_func_t draw_func,
void *draw_closure,
cairo_surface_t *dst,
const cairo_rectangle_int_t *extents)
{
cairo_surface_t *intermediate;
cairo_surface_pattern_t pattern;
cairo_surface_pattern_t clip_pattern;
cairo_surface_t *clip_surface;
int clip_x, clip_y;
cairo_status_t status;
 
/* We'd be better off here creating a surface identical in format
* to dst, but we have no way of getting that information. Instead
* we ask the backend to create a similar surface of identical content,
* in the belief that the backend will do something useful - like use
* an identical format. For example, the xlib backend will endeavor to
* use a compatible depth to enable core protocol routines.
*/
intermediate =
_cairo_surface_create_similar_scratch (dst, dst->content,
extents->width,
extents->height);
if (intermediate == NULL) {
intermediate =
_cairo_image_surface_create_with_content (dst->content,
extents->width,
extents->width);
}
if (unlikely (intermediate->status))
return intermediate->status;
 
/* Initialize the intermediate surface from the destination surface */
_cairo_pattern_init_for_surface (&pattern, dst);
status = _cairo_surface_composite (CAIRO_OPERATOR_SOURCE,
&pattern.base, NULL, intermediate,
extents->x, extents->y,
0, 0,
0, 0,
extents->width, extents->height,
NULL);
_cairo_pattern_fini (&pattern.base);
if (unlikely (status))
goto CLEANUP_SURFACE;
 
status = (*draw_func) (draw_closure, op,
src, intermediate,
extents->x, extents->y,
extents,
NULL);
if (unlikely (status))
goto CLEANUP_SURFACE;
 
assert (clip->path != NULL);
clip_surface = _cairo_clip_get_surface (clip, dst, &clip_x, &clip_y);
if (unlikely (clip_surface->status))
goto CLEANUP_SURFACE;
 
_cairo_pattern_init_for_surface (&clip_pattern, clip_surface);
 
/* Combine that with the clip */
status = _cairo_surface_composite (CAIRO_OPERATOR_DEST_IN,
&clip_pattern.base, NULL, intermediate,
extents->x - clip_x,
extents->y - clip_y,
0, 0,
0, 0,
extents->width, extents->height,
NULL);
if (unlikely (status))
goto CLEANUP_CLIP;
 
/* Punch the clip out of the destination */
status = _cairo_surface_composite (CAIRO_OPERATOR_DEST_OUT,
&clip_pattern.base, NULL, dst,
extents->x - clip_x,
extents->y - clip_y,
0, 0,
extents->x, extents->y,
extents->width, extents->height,
NULL);
if (unlikely (status))
goto CLEANUP_CLIP;
 
/* Now add the two results together */
_cairo_pattern_init_for_surface (&pattern, intermediate);
status = _cairo_surface_composite (CAIRO_OPERATOR_ADD,
&pattern.base, NULL, dst,
0, 0,
0, 0,
extents->x, extents->y,
extents->width, extents->height,
NULL);
_cairo_pattern_fini (&pattern.base);
 
CLEANUP_CLIP:
_cairo_pattern_fini (&clip_pattern.base);
CLEANUP_SURFACE:
cairo_surface_destroy (intermediate);
 
return status;
}
 
/* Handles compositing for %CAIRO_OPERATOR_SOURCE, which is special; it's
* defined as (src IN mask IN clip) ADD (dst OUT (mask IN clip))
*/
static cairo_status_t
_clip_and_composite_source (cairo_clip_t *clip,
const cairo_pattern_t *src,
cairo_draw_func_t draw_func,
void *draw_closure,
cairo_surface_t *dst,
const cairo_rectangle_int_t *extents)
{
cairo_surface_pattern_t mask_pattern;
cairo_region_t *clip_region = NULL;
cairo_status_t status;
 
if (clip != NULL) {
status = _cairo_clip_get_region (clip, &clip_region);
if (unlikely (_cairo_status_is_error (status) ||
status == CAIRO_INT_STATUS_NOTHING_TO_DO))
{
return status;
}
}
 
/* Create a surface that is mask IN clip */
status = _create_composite_mask_pattern (&mask_pattern,
clip,
draw_func, draw_closure,
dst, extents);
if (unlikely (status))
return status;
 
/* Compute dest' = dest OUT (mask IN clip) */
status = _cairo_surface_composite (CAIRO_OPERATOR_DEST_OUT,
&mask_pattern.base, NULL, dst,
0, 0,
0, 0,
extents->x, extents->y,
extents->width, extents->height,
clip_region);
 
if (unlikely (status))
goto CLEANUP_MASK_PATTERN;
 
/* Now compute (src IN (mask IN clip)) ADD dest' */
status = _cairo_surface_composite (CAIRO_OPERATOR_ADD,
src, &mask_pattern.base, dst,
extents->x, extents->y,
0, 0,
extents->x, extents->y,
extents->width, extents->height,
clip_region);
 
CLEANUP_MASK_PATTERN:
_cairo_pattern_fini (&mask_pattern.base);
return status;
}
 
static int
_cairo_rectangle_empty (const cairo_rectangle_int_t *rect)
{
return rect->width == 0 || rect->height == 0;
}
 
/**
* _clip_and_composite:
* @clip: a #cairo_clip_t
* @op: the operator to draw with
* @src: source pattern
* @draw_func: function that can be called to draw with the mask onto a surface.
* @draw_closure: data to pass to @draw_func.
* @dst: destination surface
* @extents: rectangle holding a bounding box for the operation; this
* rectangle will be used as the size for the temporary
* surface.
*
* When there is a surface clip, we typically need to create an intermediate
* surface. This function handles the logic of creating a temporary surface
* drawing to it, then compositing the result onto the target surface.
*
* @draw_func is to called to draw the mask; it will be called no more
* than once.
*
* Return value: %CAIRO_STATUS_SUCCESS if the drawing succeeded.
**/
static cairo_status_t
_clip_and_composite (cairo_clip_t *clip,
cairo_operator_t op,
const cairo_pattern_t *src,
cairo_draw_func_t draw_func,
void *draw_closure,
cairo_surface_t *dst,
const cairo_rectangle_int_t *extents)
{
cairo_status_t status;
 
if (_cairo_rectangle_empty (extents))
/* Nothing to do */
return CAIRO_STATUS_SUCCESS;
 
if (op == CAIRO_OPERATOR_CLEAR) {
src = &_cairo_pattern_white.base;
op = CAIRO_OPERATOR_DEST_OUT;
}
 
if (op == CAIRO_OPERATOR_SOURCE) {
status = _clip_and_composite_source (clip,
src,
draw_func, draw_closure,
dst, extents);
} else {
cairo_bool_t clip_surface = FALSE;
cairo_region_t *clip_region = NULL;
 
if (clip != NULL) {
status = _cairo_clip_get_region (clip, &clip_region);
if (unlikely (_cairo_status_is_error (status) ||
status == CAIRO_INT_STATUS_NOTHING_TO_DO))
{
return status;
}
 
clip_surface = status == CAIRO_INT_STATUS_UNSUPPORTED;
}
 
if (clip_surface) {
if (_cairo_operator_bounded_by_mask (op)) {
status = _clip_and_composite_with_mask (clip, op,
src,
draw_func, draw_closure,
dst, extents);
} else {
status = _clip_and_composite_combine (clip, op,
src,
draw_func, draw_closure,
dst, extents);
}
} else {
status = draw_func (draw_closure, op,
src, dst,
0, 0,
extents,
clip_region);
}
}
 
return status;
}
 
/* Composites a region representing a set of trapezoids.
*/
static cairo_status_t
_composite_trap_region (cairo_clip_t *clip,
const cairo_pattern_t *src,
cairo_operator_t op,
cairo_surface_t *dst,
cairo_region_t *trap_region,
const cairo_rectangle_int_t *extents)
{
cairo_status_t status;
cairo_surface_pattern_t mask_pattern;
cairo_pattern_t *mask = NULL;
int mask_x = 0, mask_y =0;
 
if (clip != NULL) {
cairo_surface_t *clip_surface = NULL;
int clip_x, clip_y;
 
clip_surface = _cairo_clip_get_surface (clip, dst, &clip_x, &clip_y);
if (unlikely (clip_surface->status))
return clip_surface->status;
 
if (op == CAIRO_OPERATOR_CLEAR) {
src = &_cairo_pattern_white.base;
op = CAIRO_OPERATOR_DEST_OUT;
}
 
_cairo_pattern_init_for_surface (&mask_pattern, clip_surface);
mask_x = extents->x - clip_x;
mask_y = extents->y - clip_y;
mask = &mask_pattern.base;
}
 
status = _cairo_surface_composite (op, src, mask, dst,
extents->x, extents->y,
mask_x, mask_y,
extents->x, extents->y,
extents->width, extents->height,
trap_region);
 
if (mask != NULL)
_cairo_pattern_fini (mask);
 
return status;
}
 
typedef struct {
cairo_traps_t *traps;
cairo_antialias_t antialias;
} cairo_composite_traps_info_t;
 
static cairo_status_t
_composite_traps_draw_func (void *closure,
cairo_operator_t op,
const cairo_pattern_t *src,
cairo_surface_t *dst,
int dst_x,
int dst_y,
const cairo_rectangle_int_t *extents,
cairo_region_t *clip_region)
{
cairo_composite_traps_info_t *info = closure;
cairo_status_t status;
cairo_region_t *extents_region = NULL;
 
if (dst_x != 0 || dst_y != 0)
_cairo_traps_translate (info->traps, - dst_x, - dst_y);
 
if (clip_region == NULL &&
!_cairo_operator_bounded_by_source (op)) {
extents_region = cairo_region_create_rectangle (extents);
if (unlikely (extents_region->status))
return extents_region->status;
cairo_region_translate (extents_region, -dst_x, -dst_y);
clip_region = extents_region;
}
 
status = _cairo_surface_composite_trapezoids (op,
src, dst, info->antialias,
extents->x, extents->y,
extents->x - dst_x, extents->y - dst_y,
extents->width, extents->height,
info->traps->traps,
info->traps->num_traps,
clip_region);
 
if (extents_region)
cairo_region_destroy (extents_region);
 
return status;
}
 
enum {
HAS_CLEAR_REGION = 0x1,
};
 
static cairo_status_t
_clip_and_composite_region (const cairo_pattern_t *src,
cairo_operator_t op,
cairo_surface_t *dst,
cairo_region_t *trap_region,
cairo_clip_t *clip,
cairo_rectangle_int_t *extents)
{
cairo_region_t clear_region;
unsigned int has_region = 0;
cairo_status_t status;
 
if (! _cairo_operator_bounded_by_mask (op) && clip == NULL) {
/* If we optimize drawing with an unbounded operator to
* _cairo_surface_fill_rectangles() or to drawing with a
* clip region, then we have an additional region to clear.
*/
_cairo_region_init_rectangle (&clear_region, extents);
status = cairo_region_subtract (&clear_region, trap_region);
if (unlikely (status))
return status;
 
if (! cairo_region_is_empty (&clear_region))
has_region |= HAS_CLEAR_REGION;
}
 
if ((src->type == CAIRO_PATTERN_TYPE_SOLID || op == CAIRO_OPERATOR_CLEAR) &&
clip == NULL)
{
const cairo_color_t *color;
 
if (op == CAIRO_OPERATOR_CLEAR)
color = CAIRO_COLOR_TRANSPARENT;
else
color = &((cairo_solid_pattern_t *)src)->color;
 
/* Solid rectangles special case */
status = _cairo_surface_fill_region (dst, op, color, trap_region);
} else {
/* For a simple rectangle, we can just use composite(), for more
* rectangles, we have to set a clip region. The cost of rasterizing
* trapezoids is pretty high for most backends currently, so it's
* worthwhile even if a region is needed.
*
* If we have a clip surface, we set it as the mask; this only works
* for bounded operators other than SOURCE; for unbounded operators,
* clip and mask cannot be interchanged. For SOURCE, the operator
* as implemented by the backends is different in its handling
* of the mask then what we want.
*
* CAIRO_INT_STATUS_UNSUPPORTED will be returned if the region has
* more than rectangle and the destination doesn't support clip
* regions. In that case, we fall through.
*/
status = _composite_trap_region (clip, src, op, dst,
trap_region, extents);
}
 
if (has_region & HAS_CLEAR_REGION) {
if (status == CAIRO_STATUS_SUCCESS) {
status = _cairo_surface_fill_region (dst,
CAIRO_OPERATOR_CLEAR,
CAIRO_COLOR_TRANSPARENT,
&clear_region);
}
_cairo_region_fini (&clear_region);
}
 
return status;
}
 
/* avoid using region code to re-validate boxes */
static cairo_status_t
_fill_rectangles (cairo_surface_t *dst,
cairo_operator_t op,
const cairo_pattern_t *src,
cairo_traps_t *traps,
cairo_clip_t *clip)
{
const cairo_color_t *color;
cairo_rectangle_int_t stack_rects[CAIRO_STACK_ARRAY_LENGTH (cairo_rectangle_int_t)];
cairo_rectangle_int_t *rects = stack_rects;
cairo_status_t status;
int i;
 
if (! traps->is_rectilinear || ! traps->maybe_region)
return CAIRO_INT_STATUS_UNSUPPORTED;
 
/* XXX: convert clip region to geometric boxes? */
if (clip != NULL)
return CAIRO_INT_STATUS_UNSUPPORTED;
 
/* XXX: fallback for the region_subtract() operation */
if (! _cairo_operator_bounded_by_mask (op))
return CAIRO_INT_STATUS_UNSUPPORTED;
 
if (! (src->type == CAIRO_PATTERN_TYPE_SOLID || op == CAIRO_OPERATOR_CLEAR))
return CAIRO_INT_STATUS_UNSUPPORTED;
 
if (traps->has_intersections) {
if (traps->is_rectangular) {
status = _cairo_bentley_ottmann_tessellate_rectangular_traps (traps, CAIRO_FILL_RULE_WINDING);
} else {
status = _cairo_bentley_ottmann_tessellate_rectilinear_traps (traps, CAIRO_FILL_RULE_WINDING);
}
if (unlikely (status))
return status;
}
 
for (i = 0; i < traps->num_traps; i++) {
if (! _cairo_fixed_is_integer (traps->traps[i].top) ||
! _cairo_fixed_is_integer (traps->traps[i].bottom) ||
! _cairo_fixed_is_integer (traps->traps[i].left.p1.x) ||
! _cairo_fixed_is_integer (traps->traps[i].right.p1.x))
{
traps->maybe_region = FALSE;
return CAIRO_INT_STATUS_UNSUPPORTED;
}
}
 
if (traps->num_traps > ARRAY_LENGTH (stack_rects)) {
rects = _cairo_malloc_ab (traps->num_traps,
sizeof (cairo_rectangle_int_t));
if (unlikely (rects == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
 
for (i = 0; i < traps->num_traps; i++) {
int x1 = _cairo_fixed_integer_part (traps->traps[i].left.p1.x);
int y1 = _cairo_fixed_integer_part (traps->traps[i].top);
int x2 = _cairo_fixed_integer_part (traps->traps[i].right.p1.x);
int y2 = _cairo_fixed_integer_part (traps->traps[i].bottom);
 
rects[i].x = x1;
rects[i].y = y1;
rects[i].width = x2 - x1;
rects[i].height = y2 - y1;
}
 
if (op == CAIRO_OPERATOR_CLEAR)
color = CAIRO_COLOR_TRANSPARENT;
else
color = &((cairo_solid_pattern_t *)src)->color;
 
status = _cairo_surface_fill_rectangles (dst, op, color, rects, i);
 
if (rects != stack_rects)
free (rects);
 
return status;
}
 
/* fast-path for very common composite of a single rectangle */
static cairo_status_t
_composite_rectangle (cairo_surface_t *dst,
cairo_operator_t op,
const cairo_pattern_t *src,
cairo_traps_t *traps,
cairo_clip_t *clip)
{
cairo_rectangle_int_t rect;
 
if (clip != NULL)
return CAIRO_INT_STATUS_UNSUPPORTED;
 
if (traps->num_traps > 1 || ! traps->is_rectilinear || ! traps->maybe_region)
return CAIRO_INT_STATUS_UNSUPPORTED;
 
if (! _cairo_fixed_is_integer (traps->traps[0].top) ||
! _cairo_fixed_is_integer (traps->traps[0].bottom) ||
! _cairo_fixed_is_integer (traps->traps[0].left.p1.x) ||
! _cairo_fixed_is_integer (traps->traps[0].right.p1.x))
{
traps->maybe_region = FALSE;
return CAIRO_INT_STATUS_UNSUPPORTED;
}
 
rect.x = _cairo_fixed_integer_part (traps->traps[0].left.p1.x);
rect.y = _cairo_fixed_integer_part (traps->traps[0].top);
rect.width = _cairo_fixed_integer_part (traps->traps[0].right.p1.x) - rect.x;
rect.height = _cairo_fixed_integer_part (traps->traps[0].bottom) - rect.y;
 
return _cairo_surface_composite (op, src, NULL, dst,
rect.x, rect.y,
0, 0,
rect.x, rect.y,
rect.width, rect.height,
NULL);
}
 
/* Warning: This call modifies the coordinates of traps */
static cairo_status_t
_clip_and_composite_trapezoids (const cairo_pattern_t *src,
cairo_operator_t op,
cairo_surface_t *dst,
cairo_traps_t *traps,
cairo_antialias_t antialias,
cairo_clip_t *clip,
cairo_rectangle_int_t *extents)
{
cairo_composite_traps_info_t traps_info;
cairo_region_t *clip_region = NULL;
cairo_bool_t clip_surface = FALSE;
cairo_status_t status;
 
if (traps->num_traps == 0 && _cairo_operator_bounded_by_mask (op))
return CAIRO_STATUS_SUCCESS;
 
if (clip != NULL) {
status = _cairo_clip_get_region (clip, &clip_region);
if (unlikely (_cairo_status_is_error (status)))
return status;
if (unlikely (status == CAIRO_INT_STATUS_NOTHING_TO_DO))
return CAIRO_STATUS_SUCCESS;
 
clip_surface = status == CAIRO_INT_STATUS_UNSUPPORTED;
}
 
/* Use a fast path if the trapezoids consist of a simple region,
* but we can only do this if we do not have a clip surface, or can
* substitute the mask with the clip.
*/
if (! clip_surface ||
(_cairo_operator_bounded_by_mask (op) && op != CAIRO_OPERATOR_SOURCE))
{
cairo_region_t *trap_region = NULL;
 
if (_cairo_operator_bounded_by_source (op)) {
status = _fill_rectangles (dst, op, src, traps, clip);
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
return status;
 
status = _composite_rectangle (dst, op, src, traps, clip);
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
return status;
}
 
status = _cairo_traps_extract_region (traps, &trap_region);
if (unlikely (_cairo_status_is_error (status)))
return status;
 
if (trap_region != NULL) {
status = cairo_region_intersect_rectangle (trap_region, extents);
if (unlikely (status)) {
cairo_region_destroy (trap_region);
return status;
}
 
if (clip_region != NULL) {
status = cairo_region_intersect (trap_region, clip_region);
if (unlikely (status)) {
cairo_region_destroy (trap_region);
return status;
}
}
 
if (_cairo_operator_bounded_by_mask (op)) {
cairo_rectangle_int_t trap_extents;
 
cairo_region_get_extents (trap_region, &trap_extents);
if (! _cairo_rectangle_intersect (extents, &trap_extents)) {
cairo_region_destroy (trap_region);
return CAIRO_STATUS_SUCCESS;
}
}
 
status = _clip_and_composite_region (src, op, dst,
trap_region,
clip_surface ? clip : NULL,
extents);
cairo_region_destroy (trap_region);
 
if (likely (status != CAIRO_INT_STATUS_UNSUPPORTED))
return status;
}
}
 
/* No fast path, exclude self-intersections and clip trapezoids. */
if (traps->has_intersections) {
if (traps->is_rectangular)
status = _cairo_bentley_ottmann_tessellate_rectangular_traps (traps, CAIRO_FILL_RULE_WINDING);
else if (traps->is_rectilinear)
status = _cairo_bentley_ottmann_tessellate_rectilinear_traps (traps, CAIRO_FILL_RULE_WINDING);
else
status = _cairo_bentley_ottmann_tessellate_traps (traps, CAIRO_FILL_RULE_WINDING);
if (unlikely (status))
return status;
}
 
/* Otherwise render the trapezoids to a mask and composite in the usual
* fashion.
*/
traps_info.traps = traps;
traps_info.antialias = antialias;
 
return _clip_and_composite (clip, op, src,
_composite_traps_draw_func,
&traps_info, dst, extents);
}
 
cairo_status_t
_cairo_surface_fallback_paint (cairo_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_clip_t *clip)
{
cairo_composite_rectangles_t extents;
cairo_rectangle_int_t rect;
cairo_clip_path_t *clip_path = clip ? clip->path : NULL;
cairo_box_t boxes_stack[32], *clip_boxes = boxes_stack;
cairo_boxes_t boxes;
int num_boxes = ARRAY_LENGTH (boxes_stack);
cairo_status_t status;
cairo_traps_t traps;
 
if (!_cairo_surface_get_extents (surface, &rect))
ASSERT_NOT_REACHED;
 
status = _cairo_composite_rectangles_init_for_paint (&extents,
rect.width,
rect.height,
op, source,
clip);
if (unlikely (status))
return status;
 
if (_cairo_clip_contains_extents (clip, &extents))
clip = NULL;
 
status = _cairo_clip_to_boxes (&clip, &extents, &clip_boxes, &num_boxes);
if (unlikely (status))
return status;
 
/* If the clip cannot be reduced to a set of boxes, we will need to
* use a clipmask. Paint is special as it is the only operation that
* does not implicitly use a mask, so we may be able to reduce this
* operation to a fill...
*/
if (clip != NULL && clip_path->prev == NULL &&
_cairo_operator_bounded_by_mask (op))
{
return _cairo_surface_fill (surface, op, source,
&clip_path->path,
clip_path->fill_rule,
clip_path->tolerance,
clip_path->antialias,
NULL);
}
 
/* meh, surface-fallback is dying anyway... */
_cairo_boxes_init_for_array (&boxes, clip_boxes, num_boxes);
status = _cairo_traps_init_boxes (&traps, &boxes);
if (unlikely (status))
goto CLEANUP_BOXES;
 
status = _clip_and_composite_trapezoids (source, op, surface,
&traps, CAIRO_ANTIALIAS_DEFAULT,
clip,
extents.is_bounded ? &extents.bounded : &extents.unbounded);
_cairo_traps_fini (&traps);
 
CLEANUP_BOXES:
if (clip_boxes != boxes_stack)
free (clip_boxes);
 
return status;
}
 
static cairo_status_t
_cairo_surface_mask_draw_func (void *closure,
cairo_operator_t op,
const cairo_pattern_t *src,
cairo_surface_t *dst,
int dst_x,
int dst_y,
const cairo_rectangle_int_t *extents,
cairo_region_t *clip_region)
{
cairo_pattern_t *mask = closure;
cairo_status_t status;
cairo_region_t *extents_region = NULL;
 
if (clip_region == NULL &&
!_cairo_operator_bounded_by_source (op)) {
extents_region = cairo_region_create_rectangle (extents);
if (unlikely (extents_region->status))
return extents_region->status;
cairo_region_translate (extents_region, -dst_x, -dst_y);
clip_region = extents_region;
}
 
if (src) {
status = _cairo_surface_composite (op,
src, mask, dst,
extents->x, extents->y,
extents->x, extents->y,
extents->x - dst_x, extents->y - dst_y,
extents->width, extents->height,
clip_region);
} else {
status = _cairo_surface_composite (op,
mask, NULL, dst,
extents->x, extents->y,
0, 0, /* unused */
extents->x - dst_x, extents->y - dst_y,
extents->width, extents->height,
clip_region);
}
 
if (extents_region)
cairo_region_destroy (extents_region);
 
return status;
}
 
cairo_status_t
_cairo_surface_fallback_mask (cairo_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_pattern_t *mask,
cairo_clip_t *clip)
{
cairo_composite_rectangles_t extents;
cairo_rectangle_int_t rect;
cairo_status_t status;
 
if (!_cairo_surface_get_extents (surface, &rect))
ASSERT_NOT_REACHED;
 
status = _cairo_composite_rectangles_init_for_mask (&extents,
rect.width, rect.height,
op, source, mask, clip);
if (unlikely (status))
return status;
 
if (_cairo_clip_contains_extents (clip, &extents))
clip = NULL;
 
if (clip != NULL && extents.is_bounded) {
status = _cairo_clip_rectangle (clip, &extents.bounded);
if (unlikely (status))
return status;
}
 
return _clip_and_composite (clip, op, source,
_cairo_surface_mask_draw_func,
(void *) mask,
surface,
extents.is_bounded ? &extents.bounded : &extents.unbounded);
}
 
cairo_status_t
_cairo_surface_fallback_stroke (cairo_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_path_fixed_t *path,
const cairo_stroke_style_t *stroke_style,
const cairo_matrix_t *ctm,
const cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
cairo_clip_t *clip)
{
cairo_polygon_t polygon;
cairo_traps_t traps;
cairo_box_t boxes_stack[32], *clip_boxes = boxes_stack;
int num_boxes = ARRAY_LENGTH (boxes_stack);
cairo_composite_rectangles_t extents;
cairo_rectangle_int_t rect;
cairo_status_t status;
 
if (!_cairo_surface_get_extents (surface, &rect))
ASSERT_NOT_REACHED;
 
status = _cairo_composite_rectangles_init_for_stroke (&extents,
rect.width,
rect.height,
op, source,
path, stroke_style, ctm,
clip);
if (unlikely (status))
return status;
 
if (_cairo_clip_contains_extents (clip, &extents))
clip = NULL;
 
status = _cairo_clip_to_boxes (&clip, &extents, &clip_boxes, &num_boxes);
if (unlikely (status))
return status;
 
_cairo_polygon_init (&polygon);
_cairo_polygon_limit (&polygon, clip_boxes, num_boxes);
 
_cairo_traps_init (&traps);
_cairo_traps_limit (&traps, clip_boxes, num_boxes);
 
if (path->is_rectilinear) {
status = _cairo_path_fixed_stroke_rectilinear_to_traps (path,
stroke_style,
ctm,
&traps);
if (likely (status == CAIRO_STATUS_SUCCESS))
goto DO_TRAPS;
 
if (_cairo_status_is_error (status))
goto CLEANUP;
}
 
status = _cairo_path_fixed_stroke_to_polygon (path,
stroke_style,
ctm, ctm_inverse,
tolerance,
&polygon);
if (unlikely (status))
goto CLEANUP;
 
if (polygon.num_edges == 0)
goto DO_TRAPS;
 
if (_cairo_operator_bounded_by_mask (op)) {
_cairo_box_round_to_rectangle (&polygon.extents, &extents.mask);
if (! _cairo_rectangle_intersect (&extents.bounded, &extents.mask))
goto CLEANUP;
}
 
/* Fall back to trapezoid fills. */
status = _cairo_bentley_ottmann_tessellate_polygon (&traps,
&polygon,
CAIRO_FILL_RULE_WINDING);
if (unlikely (status))
goto CLEANUP;
 
DO_TRAPS:
status = _clip_and_composite_trapezoids (source, op, surface,
&traps, antialias,
clip,
extents.is_bounded ? &extents.bounded : &extents.unbounded);
CLEANUP:
_cairo_traps_fini (&traps);
_cairo_polygon_fini (&polygon);
if (clip_boxes != boxes_stack)
free (clip_boxes);
 
return status;
}
 
cairo_status_t
_cairo_surface_fallback_fill (cairo_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias,
cairo_clip_t *clip)
{
cairo_polygon_t polygon;
cairo_traps_t traps;
cairo_box_t boxes_stack[32], *clip_boxes = boxes_stack;
int num_boxes = ARRAY_LENGTH (boxes_stack);
cairo_bool_t is_rectilinear;
cairo_composite_rectangles_t extents;
cairo_rectangle_int_t rect;
cairo_status_t status;
 
if (!_cairo_surface_get_extents (surface, &rect))
ASSERT_NOT_REACHED;
 
status = _cairo_composite_rectangles_init_for_fill (&extents,
rect.width,
rect.height,
op, source, path,
clip);
if (unlikely (status))
return status;
 
if (_cairo_clip_contains_extents (clip, &extents))
clip = NULL;
 
status = _cairo_clip_to_boxes (&clip, &extents, &clip_boxes, &num_boxes);
if (unlikely (status))
return status;
 
_cairo_traps_init (&traps);
_cairo_traps_limit (&traps, clip_boxes, num_boxes);
 
_cairo_polygon_init (&polygon);
_cairo_polygon_limit (&polygon, clip_boxes, num_boxes);
 
if (path->is_empty_fill)
goto DO_TRAPS;
 
is_rectilinear = _cairo_path_fixed_is_rectilinear_fill (path);
if (is_rectilinear) {
status = _cairo_path_fixed_fill_rectilinear_to_traps (path,
fill_rule,
&traps);
if (likely (status == CAIRO_STATUS_SUCCESS))
goto DO_TRAPS;
 
if (_cairo_status_is_error (status))
goto CLEANUP;
}
 
status = _cairo_path_fixed_fill_to_polygon (path, tolerance, &polygon);
if (unlikely (status))
goto CLEANUP;
 
if (polygon.num_edges == 0)
goto DO_TRAPS;
 
if (_cairo_operator_bounded_by_mask (op)) {
_cairo_box_round_to_rectangle (&polygon.extents, &extents.mask);
if (! _cairo_rectangle_intersect (&extents.bounded, &extents.mask))
goto CLEANUP;
}
 
if (is_rectilinear) {
status = _cairo_bentley_ottmann_tessellate_rectilinear_polygon (&traps,
&polygon,
fill_rule);
if (likely (status == CAIRO_STATUS_SUCCESS))
goto DO_TRAPS;
 
if (unlikely (_cairo_status_is_error (status)))
goto CLEANUP;
}
 
/* Fall back to trapezoid fills. */
status = _cairo_bentley_ottmann_tessellate_polygon (&traps,
&polygon,
fill_rule);
if (unlikely (status))
goto CLEANUP;
 
DO_TRAPS:
status = _clip_and_composite_trapezoids (source, op, surface,
&traps, antialias,
clip,
extents.is_bounded ? &extents.bounded : &extents.unbounded);
CLEANUP:
_cairo_traps_fini (&traps);
_cairo_polygon_fini (&polygon);
if (clip_boxes != boxes_stack)
free (clip_boxes);
 
return status;
}
 
typedef struct {
cairo_scaled_font_t *font;
cairo_glyph_t *glyphs;
int num_glyphs;
} cairo_show_glyphs_info_t;
 
static cairo_status_t
_cairo_surface_old_show_glyphs_draw_func (void *closure,
cairo_operator_t op,
const cairo_pattern_t *src,
cairo_surface_t *dst,
int dst_x,
int dst_y,
const cairo_rectangle_int_t *extents,
cairo_region_t *clip_region)
{
cairo_show_glyphs_info_t *glyph_info = closure;
cairo_status_t status;
cairo_region_t *extents_region = NULL;
 
if (clip_region == NULL &&
!_cairo_operator_bounded_by_source (op)) {
extents_region = cairo_region_create_rectangle (extents);
if (unlikely (extents_region->status))
return extents_region->status;
cairo_region_translate (extents_region, -dst_x, -dst_y);
clip_region = extents_region;
}
 
/* Modifying the glyph array is fine because we know that this function
* will be called only once, and we've already made a copy of the
* glyphs in the wrapper.
*/
if (dst_x != 0 || dst_y != 0) {
int i;
 
for (i = 0; i < glyph_info->num_glyphs; ++i) {
((cairo_glyph_t *) glyph_info->glyphs)[i].x -= dst_x;
((cairo_glyph_t *) glyph_info->glyphs)[i].y -= dst_y;
}
}
 
status = _cairo_surface_old_show_glyphs (glyph_info->font, op, src,
dst,
extents->x, extents->y,
extents->x - dst_x,
extents->y - dst_y,
extents->width,
extents->height,
glyph_info->glyphs,
glyph_info->num_glyphs,
clip_region);
 
if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
status = _cairo_scaled_font_show_glyphs (glyph_info->font,
op,
src, dst,
extents->x, extents->y,
extents->x - dst_x,
extents->y - dst_y,
extents->width, extents->height,
glyph_info->glyphs,
glyph_info->num_glyphs,
clip_region);
}
 
if (extents_region)
cairo_region_destroy (extents_region);
 
return status;
}
 
cairo_status_t
_cairo_surface_fallback_show_glyphs (cairo_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font,
cairo_clip_t *clip)
{
cairo_show_glyphs_info_t glyph_info;
cairo_composite_rectangles_t extents;
cairo_rectangle_int_t rect;
cairo_status_t status;
 
if (!_cairo_surface_get_extents (surface, &rect))
ASSERT_NOT_REACHED;
 
status = _cairo_composite_rectangles_init_for_glyphs (&extents,
rect.width,
rect.height,
op, source,
scaled_font,
glyphs, num_glyphs,
clip,
NULL);
if (unlikely (status))
return status;
 
if (_cairo_clip_contains_rectangle (clip, &extents.mask))
clip = NULL;
 
if (clip != NULL && extents.is_bounded) {
status = _cairo_clip_rectangle (clip, &extents.bounded);
if (unlikely (status))
return status;
}
 
glyph_info.font = scaled_font;
glyph_info.glyphs = glyphs;
glyph_info.num_glyphs = num_glyphs;
 
return _clip_and_composite (clip, op, source,
_cairo_surface_old_show_glyphs_draw_func,
&glyph_info,
surface,
extents.is_bounded ? &extents.bounded : &extents.unbounded);
}
 
cairo_surface_t *
_cairo_surface_fallback_snapshot (cairo_surface_t *surface)
{
cairo_surface_t *snapshot;
cairo_status_t status;
cairo_format_t format;
cairo_surface_pattern_t pattern;
cairo_image_surface_t *image;
void *image_extra;
 
status = _cairo_surface_acquire_source_image (surface,
&image, &image_extra);
if (unlikely (status))
return _cairo_surface_create_in_error (status);
 
format = image->format;
if (format == CAIRO_FORMAT_INVALID) {
/* Non-standard images formats can be generated when retrieving
* images from unusual xservers, for example.
*/
format = _cairo_format_from_content (image->base.content);
}
snapshot = cairo_image_surface_create (format,
image->width,
image->height);
if (cairo_surface_status (snapshot)) {
_cairo_surface_release_source_image (surface, image, image_extra);
return snapshot;
}
 
_cairo_pattern_init_for_surface (&pattern, &image->base);
status = _cairo_surface_paint (snapshot,
CAIRO_OPERATOR_SOURCE,
&pattern.base,
NULL);
_cairo_pattern_fini (&pattern.base);
_cairo_surface_release_source_image (surface, image, image_extra);
if (unlikely (status)) {
cairo_surface_destroy (snapshot);
return _cairo_surface_create_in_error (status);
}
 
return snapshot;
}
 
cairo_status_t
_cairo_surface_fallback_composite (cairo_operator_t op,
const cairo_pattern_t *src,
const cairo_pattern_t *mask,
cairo_surface_t *dst,
int src_x,
int src_y,
int mask_x,
int mask_y,
int dst_x,
int dst_y,
unsigned int width,
unsigned int height,
cairo_region_t *clip_region)
{
fallback_state_t state;
cairo_region_t *fallback_region = NULL;
cairo_status_t status;
 
status = _fallback_init (&state, dst, dst_x, dst_y, width, height);
if (unlikely (status))
return status;
 
/* We know this will never fail with the image backend; but
* instead of calling into it directly, we call
* _cairo_surface_composite so that we get the correct device
* offset handling.
*/
 
if (clip_region != NULL && (state.image_rect.x || state.image_rect.y)) {
fallback_region = cairo_region_copy (clip_region);
status = fallback_region->status;
if (unlikely (status))
goto FAIL;
 
cairo_region_translate (fallback_region,
-state.image_rect.x,
-state.image_rect.y);
clip_region = fallback_region;
}
 
status = _cairo_surface_composite (op, src, mask,
&state.image->base,
src_x, src_y, mask_x, mask_y,
dst_x - state.image_rect.x,
dst_y - state.image_rect.y,
width, height,
clip_region);
FAIL:
if (fallback_region != NULL)
cairo_region_destroy (fallback_region);
_fallback_fini (&state);
 
return status;
}
 
cairo_status_t
_cairo_surface_fallback_fill_rectangles (cairo_surface_t *surface,
cairo_operator_t op,
const cairo_color_t *color,
cairo_rectangle_int_t *rects,
int num_rects)
{
fallback_state_t state;
cairo_rectangle_int_t *offset_rects = NULL;
cairo_status_t status;
int x1, y1, x2, y2;
int i;
 
assert (surface->snapshot_of == NULL);
 
if (num_rects <= 0)
return CAIRO_STATUS_SUCCESS;
 
/* Compute the bounds of the rectangles, so that we know what area of the
* destination surface to fetch
*/
x1 = rects[0].x;
y1 = rects[0].y;
x2 = rects[0].x + rects[0].width;
y2 = rects[0].y + rects[0].height;
 
for (i = 1; i < num_rects; i++) {
if (rects[i].x < x1)
x1 = rects[i].x;
if (rects[i].y < y1)
y1 = rects[i].y;
 
if ((int) (rects[i].x + rects[i].width) > x2)
x2 = rects[i].x + rects[i].width;
if ((int) (rects[i].y + rects[i].height) > y2)
y2 = rects[i].y + rects[i].height;
}
 
status = _fallback_init (&state, surface, x1, y1, x2 - x1, y2 - y1);
if (unlikely (status))
return status;
 
/* If the fetched image isn't at 0,0, we need to offset the rectangles */
 
if (state.image_rect.x != 0 || state.image_rect.y != 0) {
offset_rects = _cairo_malloc_ab (num_rects, sizeof (cairo_rectangle_int_t));
if (unlikely (offset_rects == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto DONE;
}
 
for (i = 0; i < num_rects; i++) {
offset_rects[i].x = rects[i].x - state.image_rect.x;
offset_rects[i].y = rects[i].y - state.image_rect.y;
offset_rects[i].width = rects[i].width;
offset_rects[i].height = rects[i].height;
}
 
rects = offset_rects;
}
 
status = _cairo_surface_fill_rectangles (&state.image->base,
op, color,
rects, num_rects);
 
free (offset_rects);
 
DONE:
_fallback_fini (&state);
 
return status;
}
 
cairo_status_t
_cairo_surface_fallback_composite_trapezoids (cairo_operator_t op,
const cairo_pattern_t *pattern,
cairo_surface_t *dst,
cairo_antialias_t antialias,
int src_x,
int src_y,
int dst_x,
int dst_y,
unsigned int width,
unsigned int height,
cairo_trapezoid_t *traps,
int num_traps,
cairo_region_t *clip_region)
{
fallback_state_t state;
cairo_region_t *fallback_region = NULL;
cairo_trapezoid_t *offset_traps = NULL;
cairo_status_t status;
 
status = _fallback_init (&state, dst, dst_x, dst_y, width, height);
if (unlikely (status))
return status;
 
/* If the destination image isn't at 0,0, we need to offset the trapezoids */
 
if (state.image_rect.x != 0 || state.image_rect.y != 0) {
offset_traps = _cairo_malloc_ab (num_traps, sizeof (cairo_trapezoid_t));
if (offset_traps == NULL) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto FAIL;
}
 
_cairo_trapezoid_array_translate_and_scale (offset_traps, traps, num_traps,
- state.image_rect.x, - state.image_rect.y,
1.0, 1.0);
traps = offset_traps;
 
/* similarly we need to adjust the region */
if (clip_region != NULL) {
fallback_region = cairo_region_copy (clip_region);
status = fallback_region->status;
if (unlikely (status))
goto FAIL;
 
cairo_region_translate (fallback_region,
-state.image_rect.x,
-state.image_rect.y);
clip_region = fallback_region;
}
}
 
status = _cairo_surface_composite_trapezoids (op, pattern,
&state.image->base,
antialias,
src_x, src_y,
dst_x - state.image_rect.x,
dst_y - state.image_rect.y,
width, height,
traps, num_traps,
clip_region);
FAIL:
if (offset_traps != NULL)
free (offset_traps);
 
if (fallback_region != NULL)
cairo_region_destroy (fallback_region);
 
_fallback_fini (&state);
 
return status;
}
 
cairo_status_t
_cairo_surface_fallback_clone_similar (cairo_surface_t *surface,
cairo_surface_t *src,
int src_x,
int src_y,
int width,
int height,
int *clone_offset_x,
int *clone_offset_y,
cairo_surface_t **clone_out)
{
cairo_surface_t *new_surface;
cairo_surface_pattern_t pattern;
cairo_status_t status;
 
new_surface = _cairo_surface_create_similar_scratch (surface,
src->content,
width, height);
if (new_surface == NULL)
return CAIRO_INT_STATUS_UNSUPPORTED;
if (unlikely (new_surface->status))
return new_surface->status;
 
/* We have to copy these here, so that the coordinate spaces are correct */
new_surface->device_transform = src->device_transform;
new_surface->device_transform_inverse = src->device_transform_inverse;
 
_cairo_pattern_init_for_surface (&pattern, src);
cairo_matrix_init_translate (&pattern.base.matrix, src_x, src_y);
pattern.base.filter = CAIRO_FILTER_NEAREST;
 
status = _cairo_surface_paint (new_surface,
CAIRO_OPERATOR_SOURCE,
&pattern.base,
NULL);
_cairo_pattern_fini (&pattern.base);
 
if (unlikely (status)) {
cairo_surface_destroy (new_surface);
return status;
}
 
*clone_offset_x = src_x;
*clone_offset_y = src_y;
*clone_out = new_surface;
return CAIRO_STATUS_SUCCESS;
}
/programs/develop/libraries/cairo/src/cairo-surface-offset-private.h
0,0 → 1,95
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2002 University of Southern California
* Copyright © 2005 Red Hat, Inc.
* Copyright © 2009 Chris Wilson
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Chris Wilson <chris@chris-wilson.co.u>
*/
 
#ifndef CAIRO_SURFACE_OFFSET_PRIVATE_H
#define CAIRO_SURFACE_OFFSET_PRIVATE_H
 
#include "cairo-types-private.h"
 
CAIRO_BEGIN_DECLS
 
cairo_private cairo_status_t
_cairo_surface_offset_paint (cairo_surface_t *target,
int x, int y,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_clip_t *clip);
 
cairo_private cairo_status_t
_cairo_surface_offset_mask (cairo_surface_t *target,
int x, int y,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_pattern_t *mask,
cairo_clip_t *clip);
 
cairo_private cairo_status_t
_cairo_surface_offset_stroke (cairo_surface_t *surface,
int x, int y,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_path_fixed_t *path,
const cairo_stroke_style_t *stroke_style,
const cairo_matrix_t *ctm,
const cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
cairo_clip_t *clip);
 
cairo_private cairo_status_t
_cairo_surface_offset_fill (cairo_surface_t *surface,
int x, int y,
cairo_operator_t op,
const cairo_pattern_t*source,
cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias,
cairo_clip_t *clip);
 
cairo_private cairo_status_t
_cairo_surface_offset_glyphs (cairo_surface_t *surface,
int x, int y,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_scaled_font_t *scaled_font,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_clip_t *clip);
 
#endif /* CAIRO_SURFACE_OFFSET_PRIVATE_H */
/programs/develop/libraries/cairo/src/cairo-surface-offset.c
0,0 → 1,342
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2005 Red Hat, Inc
* Copyright © 2007 Adrian Johnson
* Copyright © 2009 Chris Wilson
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
* Chris Wilson <chris@chris-wilson.co.uk>
*/
 
#include "cairoint.h"
 
#include "cairo-error-private.h"
#include "cairo-surface-offset-private.h"
 
/* A collection of routines to facilitate drawing to an alternate surface. */
 
static void
_copy_transformed_pattern (cairo_pattern_t *pattern,
const cairo_pattern_t *original,
const cairo_matrix_t *ctm_inverse)
{
_cairo_pattern_init_static_copy (pattern, original);
 
if (! _cairo_matrix_is_identity (ctm_inverse))
_cairo_pattern_transform (pattern, ctm_inverse);
}
 
cairo_status_t
_cairo_surface_offset_paint (cairo_surface_t *target,
int x, int y,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_clip_t *clip)
{
cairo_status_t status;
cairo_clip_t clip_copy, *dev_clip = clip;
cairo_pattern_union_t source_copy;
 
if (unlikely (target->status))
return target->status;
 
if (clip && clip->all_clipped)
return CAIRO_STATUS_SUCCESS;
 
if (x | y) {
cairo_matrix_t m;
 
if (clip != NULL) {
cairo_matrix_init_translate (&m, -x, -y);
status = _cairo_clip_init_copy_transformed (&clip_copy, clip, &m);
if (unlikely (status))
goto FINISH;
 
dev_clip = &clip_copy;
}
 
cairo_matrix_init_translate (&m, x, y);
_copy_transformed_pattern (&source_copy.base, source, &m);
source = &source_copy.base;
}
 
status = _cairo_surface_paint (target, op, source, dev_clip);
 
FINISH:
if (dev_clip != clip)
_cairo_clip_reset (dev_clip);
 
return status;
}
 
cairo_status_t
_cairo_surface_offset_mask (cairo_surface_t *target,
int x, int y,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_pattern_t *mask,
cairo_clip_t *clip)
{
cairo_status_t status;
cairo_clip_t clip_copy, *dev_clip = clip;
cairo_pattern_union_t source_copy;
cairo_pattern_union_t mask_copy;
 
if (unlikely (target->status))
return target->status;
 
if (clip && clip->all_clipped)
return CAIRO_STATUS_SUCCESS;
 
if (x | y) {
cairo_matrix_t m;
 
if (clip != NULL) {
cairo_matrix_init_translate (&m, -x, -y);
status = _cairo_clip_init_copy_transformed (&clip_copy, clip, &m);
if (unlikely (status))
goto FINISH;
 
dev_clip = &clip_copy;
}
 
cairo_matrix_init_translate (&m, x, y);
_copy_transformed_pattern (&source_copy.base, source, &m);
_copy_transformed_pattern (&mask_copy.base, mask, &m);
source = &source_copy.base;
mask = &mask_copy.base;
}
 
status = _cairo_surface_mask (target, op,
source, mask,
dev_clip);
 
FINISH:
if (dev_clip != clip)
_cairo_clip_reset (dev_clip);
 
return status;
}
 
cairo_status_t
_cairo_surface_offset_stroke (cairo_surface_t *surface,
int x, int y,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_path_fixed_t *path,
const cairo_stroke_style_t*stroke_style,
const cairo_matrix_t *ctm,
const cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
cairo_clip_t *clip)
{
cairo_path_fixed_t path_copy, *dev_path = path;
cairo_clip_t clip_copy, *dev_clip = clip;
cairo_matrix_t dev_ctm = *ctm;
cairo_matrix_t dev_ctm_inverse = *ctm_inverse;
cairo_pattern_union_t source_copy;
cairo_status_t status;
 
if (unlikely (surface->status))
return surface->status;
 
if (clip && clip->all_clipped)
return CAIRO_STATUS_SUCCESS;
 
if (x | y) {
cairo_matrix_t m;
 
status = _cairo_path_fixed_init_copy (&path_copy, dev_path);
if (unlikely (status))
goto FINISH;
 
_cairo_path_fixed_translate (&path_copy,
_cairo_fixed_from_int (-x),
_cairo_fixed_from_int (-y));
dev_path = &path_copy;
 
cairo_matrix_init_translate (&m, -x, -y);
cairo_matrix_multiply (&dev_ctm, &dev_ctm, &m);
if (clip != NULL) {
status = _cairo_clip_init_copy_transformed (&clip_copy, clip, &m);
if (unlikely (status))
goto FINISH;
 
dev_clip = &clip_copy;
}
 
cairo_matrix_init_translate (&m, x, y);
_copy_transformed_pattern (&source_copy.base, source, &m);
source = &source_copy.base;
cairo_matrix_multiply (&dev_ctm_inverse, &m, &dev_ctm_inverse);
}
 
status = _cairo_surface_stroke (surface, op, source,
dev_path, stroke_style,
&dev_ctm, &dev_ctm_inverse,
tolerance, antialias,
dev_clip);
 
FINISH:
if (dev_path != path)
_cairo_path_fixed_fini (dev_path);
if (dev_clip != clip)
_cairo_clip_reset (dev_clip);
 
return status;
}
 
cairo_status_t
_cairo_surface_offset_fill (cairo_surface_t *surface,
int x, int y,
cairo_operator_t op,
const cairo_pattern_t*source,
cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias,
cairo_clip_t *clip)
{
cairo_status_t status;
cairo_path_fixed_t path_copy, *dev_path = path;
cairo_clip_t clip_copy, *dev_clip = clip;
cairo_pattern_union_t source_copy;
 
if (unlikely (surface->status))
return surface->status;
 
if (clip && clip->all_clipped)
return CAIRO_STATUS_SUCCESS;
 
if (x | y) {
cairo_matrix_t m;
 
status = _cairo_path_fixed_init_copy (&path_copy, dev_path);
if (unlikely (status))
goto FINISH;
 
_cairo_path_fixed_translate (&path_copy,
_cairo_fixed_from_int (-x),
_cairo_fixed_from_int (-y));
dev_path = &path_copy;
 
if (clip != NULL) {
cairo_matrix_init_translate (&m, -x, -y);
status = _cairo_clip_init_copy_transformed (&clip_copy, clip, &m);
if (unlikely (status))
goto FINISH;
 
dev_clip = &clip_copy;
}
 
cairo_matrix_init_translate (&m, x, y);
_copy_transformed_pattern (&source_copy.base, source, &m);
source = &source_copy.base;
}
 
status = _cairo_surface_fill (surface, op, source,
dev_path, fill_rule,
tolerance, antialias,
dev_clip);
 
FINISH:
if (dev_path != path)
_cairo_path_fixed_fini (dev_path);
if (dev_clip != clip)
_cairo_clip_reset (dev_clip);
 
return status;
}
 
cairo_status_t
_cairo_surface_offset_glyphs (cairo_surface_t *surface,
int x, int y,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_scaled_font_t *scaled_font,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_clip_t *clip)
{
cairo_status_t status;
cairo_clip_t clip_copy, *dev_clip = clip;
cairo_pattern_union_t source_copy;
cairo_glyph_t *dev_glyphs;
int i;
 
if (unlikely (surface->status))
return surface->status;
 
if (clip && clip->all_clipped)
return CAIRO_STATUS_SUCCESS;
 
dev_glyphs = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t));
if (dev_glyphs == NULL)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
memcpy (dev_glyphs, glyphs, sizeof (cairo_glyph_t) * num_glyphs);
 
if (x | y) {
cairo_matrix_t m;
 
if (clip != NULL) {
cairo_matrix_init_translate (&m, -x, -y);
status = _cairo_clip_init_copy_transformed (&clip_copy, clip, &m);
if (unlikely (status))
goto FINISH;
 
dev_clip = &clip_copy;
}
 
cairo_matrix_init_translate (&m, x, y);
_copy_transformed_pattern (&source_copy.base, source, &m);
source = &source_copy.base;
 
for (i = 0; i < num_glyphs; i++) {
dev_glyphs[i].x -= x;
dev_glyphs[i].y -= y;
}
}
 
status = _cairo_surface_show_text_glyphs (surface, op, source,
NULL, 0,
dev_glyphs, num_glyphs,
NULL, 0, 0,
scaled_font,
dev_clip);
 
FINISH:
if (dev_clip != clip)
_cairo_clip_reset (dev_clip);
free (dev_glyphs);
 
return status;
}
/programs/develop/libraries/cairo/src/cairo-surface-private.h
0,0 → 1,104
/* 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., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
*/
 
#ifndef CAIRO_SURFACE_PRIVATE_H
#define CAIRO_SURFACE_PRIVATE_H
 
#include "cairo.h"
 
#include "cairo-types-private.h"
#include "cairo-list-private.h"
#include "cairo-reference-count-private.h"
#include "cairo-clip-private.h"
 
typedef void (*cairo_surface_func_t) (cairo_surface_t *);
 
struct _cairo_surface {
const cairo_surface_backend_t *backend;
cairo_device_t *device;
 
/* We allow surfaces to override the backend->type by shoving something
* else into surface->type. This is for "wrapper" surfaces that want to
* hide their internal type from the user-level API. */
cairo_surface_type_t type;
 
cairo_content_t content;
 
cairo_reference_count_t ref_count;
cairo_status_t status;
unsigned int unique_id;
 
unsigned finished : 1;
unsigned is_clear : 1;
unsigned has_font_options : 1;
unsigned owns_device : 1;
 
cairo_user_data_array_t user_data;
cairo_user_data_array_t mime_data;
 
cairo_matrix_t device_transform;
cairo_matrix_t device_transform_inverse;
cairo_list_t device_transform_observers;
 
/* The actual resolution of the device, in dots per inch. */
double x_resolution;
double y_resolution;
 
/* The resolution that should be used when generating image-based
* fallback; generally only used by the analysis/paginated
* surfaces
*/
double x_fallback_resolution;
double y_fallback_resolution;
 
/* A "snapshot" surface is immutable. See _cairo_surface_snapshot. */
cairo_surface_t *snapshot_of;
cairo_surface_func_t snapshot_detach;
/* current snapshots of this surface*/
cairo_list_t snapshots;
/* place upon snapshot list */
cairo_list_t snapshot;
 
/*
* Surface font options, falling back to backend's default options,
* and set using _cairo_surface_set_font_options(), and propagated by
* cairo_surface_create_similar().
*/
cairo_font_options_t font_options;
};
 
#endif /* CAIRO_SURFACE_PRIVATE_H */
/programs/develop/libraries/cairo/src/cairo-surface-snapshot-private.h
0,0 → 1,48
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2009 Intel Corporation
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Intel Corporation.
*
* Contributor(s):
* Chris Wilson <chris@chris-wilson.co.uk>
*/
 
#ifndef CAIRO_SURFACE_SNAPSHOT_PRIVATE_H
#define CAIRO_SURFACE_SNAPSHOT_PRIVATE_H
 
#include "cairo-surface-private.h"
 
struct _cairo_surface_snapshot {
cairo_surface_t base;
 
cairo_surface_t *target;
cairo_surface_t *clone;
};
 
#endif /* CAIRO_SURFACE_SNAPSHOT_PRIVATE_H */
/programs/develop/libraries/cairo/src/cairo-surface-snapshot.c
0,0 → 1,255
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2002 University of Southern California
* Copyright © 2005 Red Hat, Inc.
* Copyright © 2009 Intel Corporation
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
* Chris Wilson <chris@chris-wilson.co.uk>
*/
 
#include "cairoint.h"
 
#include "cairo-error-private.h"
#include "cairo-surface-snapshot-private.h"
 
static cairo_status_t
_cairo_surface_snapshot_finish (void *abstract_surface)
{
cairo_surface_snapshot_t *surface = abstract_surface;
cairo_status_t status = CAIRO_STATUS_SUCCESS;
 
if (surface->clone != NULL) {
cairo_surface_finish (surface->clone);
status = surface->clone->status;
 
cairo_surface_destroy (surface->clone);
}
 
return status;
}
 
static cairo_status_t
_cairo_surface_snapshot_acquire_source_image (void *abstract_surface,
cairo_image_surface_t **image_out,
void **extra_out)
{
cairo_surface_snapshot_t *surface = abstract_surface;
 
return _cairo_surface_acquire_source_image (surface->target, image_out, extra_out);
}
 
static void
_cairo_surface_snapshot_release_source_image (void *abstract_surface,
cairo_image_surface_t *image,
void *extra)
{
cairo_surface_snapshot_t *surface = abstract_surface;
 
_cairo_surface_release_source_image (surface->target, image, extra);
}
 
static cairo_bool_t
_cairo_surface_snapshot_get_extents (void *abstract_surface,
cairo_rectangle_int_t *extents)
{
cairo_surface_snapshot_t *surface = abstract_surface;
 
return _cairo_surface_get_extents (surface->target, extents);
}
 
static const cairo_surface_backend_t _cairo_surface_snapshot_backend = {
CAIRO_INTERNAL_SURFACE_TYPE_SNAPSHOT,
 
NULL, /* create similar */
_cairo_surface_snapshot_finish,
 
_cairo_surface_snapshot_acquire_source_image,
_cairo_surface_snapshot_release_source_image,
NULL, NULL, /* acquire, release dest */
NULL, /* clone similar */
NULL, /* composite */
NULL, /* fill rectangles */
NULL, /* composite trapezoids */
NULL, /* create span renderer */
NULL, /* check span renderer */
NULL, /* copy_page */
NULL, /* show_page */
_cairo_surface_snapshot_get_extents,
};
 
static void
_cairo_surface_snapshot_copy_on_write (cairo_surface_t *surface)
{
cairo_surface_snapshot_t *snapshot = (cairo_surface_snapshot_t *) surface;
cairo_image_surface_t *image;
cairo_image_surface_t *clone;
void *extra;
cairo_status_t status;
 
/* We need to make an image copy of the original surface since the
* snapshot may exceed the lifetime of the original device, i.e.
* when we later need to use the snapshot the data may have already
* been lost.
*/
 
status = _cairo_surface_acquire_source_image (snapshot->target, &image, &extra);
if (unlikely (status)) {
snapshot->target = _cairo_surface_create_in_error (status);
status = _cairo_surface_set_error (surface, status);
return;
}
 
clone = (cairo_image_surface_t *)
_cairo_image_surface_create_with_pixman_format (NULL,
image->pixman_format,
image->width,
image->height,
0);
if (likely (clone->base.status == CAIRO_STATUS_SUCCESS)) {
if (clone->stride == image->stride) {
memcpy (clone->data, image->data, image->stride * image->height);
} else {
pixman_image_composite32 (PIXMAN_OP_SRC,
image->pixman_image, NULL, clone->pixman_image,
0, 0,
0, 0,
0, 0,
image->width, image->height);
}
clone->base.is_clear = FALSE;
 
snapshot->clone = &clone->base;
} else {
snapshot->clone = &clone->base;
status = _cairo_surface_set_error (surface, clone->base.status);
}
 
_cairo_surface_release_source_image (snapshot->target, image, extra);
snapshot->target = snapshot->clone;
snapshot->base.type = snapshot->target->type;
}
 
/**
* _cairo_surface_snapshot
* @surface: a #cairo_surface_t
*
* Make an immutable reference to @surface. It is an error to call a
* surface-modifying function on the result of this function. The
* resulting 'snapshot' is a lazily copied-on-write surface i.e. it
* remains a reference to the original surface until that surface is
* written to again, at which time a copy is made of the original surface
* and the snapshot then points to that instead. Multiple snapshots of the
* same unmodified surface point to the same copy.
*
* The caller owns the return value and should call
* cairo_surface_destroy() when finished with it. This function will not
* return %NULL, but will return a nil surface instead.
*
* Return value: The snapshot surface. Note that the return surface
* may not necessarily be of the same type as @surface.
**/
cairo_surface_t *
_cairo_surface_snapshot (cairo_surface_t *surface)
{
cairo_surface_snapshot_t *snapshot;
cairo_status_t status;
 
if (unlikely (surface->status))
return _cairo_surface_create_in_error (surface->status);
 
if (surface->finished)
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
 
if (surface->snapshot_of != NULL)
return cairo_surface_reference (surface);
 
if (surface->backend->snapshot != NULL) {
cairo_surface_t *snap;
 
snap = _cairo_surface_has_snapshot (surface, surface->backend);
if (snap != NULL)
return cairo_surface_reference (snap);
 
snap = surface->backend->snapshot (surface);
if (snap != NULL) {
if (unlikely (snap->status))
return snap;
 
status = _cairo_surface_copy_mime_data (snap, surface);
if (unlikely (status)) {
cairo_surface_destroy (snap);
return _cairo_surface_create_in_error (status);
}
 
snap->device_transform = surface->device_transform;
snap->device_transform_inverse = surface->device_transform_inverse;
 
_cairo_surface_attach_snapshot (surface, snap, NULL);
 
return snap;
}
}
 
snapshot = (cairo_surface_snapshot_t *)
_cairo_surface_has_snapshot (surface, &_cairo_surface_snapshot_backend);
if (snapshot != NULL)
return cairo_surface_reference (&snapshot->base);
 
snapshot = malloc (sizeof (cairo_surface_snapshot_t));
if (unlikely (snapshot == NULL))
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
 
_cairo_surface_init (&snapshot->base,
&_cairo_surface_snapshot_backend,
NULL, /* device */
surface->content);
snapshot->base.type = surface->type;
 
snapshot->target = surface;
snapshot->clone = NULL;
 
status = _cairo_surface_copy_mime_data (&snapshot->base, surface);
if (unlikely (status)) {
cairo_surface_destroy (&snapshot->base);
return _cairo_surface_create_in_error (status);
}
 
snapshot->base.device_transform = surface->device_transform;
snapshot->base.device_transform_inverse = surface->device_transform_inverse;
 
_cairo_surface_attach_snapshot (surface,
&snapshot->base,
_cairo_surface_snapshot_copy_on_write);
 
return &snapshot->base;
}
/programs/develop/libraries/cairo/src/cairo-surface-subsurface-private.h
0,0 → 1,49
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2009 Intel Corporation
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Intel Corporation.
*
* Contributor(s):
* Chris Wilson <chris@chris-wilson.co.uk>
*/
 
#ifndef CAIRO_SURFACE_SUBSURFACE_PRIVATE_H
#define CAIRO_SURFACE_SUBSURFACE_PRIVATE_H
 
#include "cairo-surface-private.h"
 
struct _cairo_surface_subsurface {
cairo_surface_t base;
 
cairo_rectangle_int_t extents;
 
cairo_surface_t *target;
};
 
#endif /* CAIRO_SURFACE_SUBSURFACE_PRIVATE_H */
/programs/develop/libraries/cairo/src/cairo-surface-subsurface.c
0,0 → 1,552
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2009 Intel Corporation
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Intel Corporation.
*
* Contributor(s):
* Chris Wilson <chris@chris-wilson.co.uk>
*/
 
#include "cairoint.h"
 
#include "cairo-error-private.h"
#include "cairo-recording-surface-private.h"
#include "cairo-surface-offset-private.h"
#include "cairo-surface-subsurface-private.h"
 
static const cairo_surface_backend_t _cairo_surface_subsurface_backend;
 
static cairo_status_t
_cairo_surface_subsurface_finish (void *abstract_surface)
{
cairo_surface_subsurface_t *surface = abstract_surface;
 
cairo_surface_destroy (surface->target);
 
return CAIRO_STATUS_SUCCESS;
}
 
static cairo_surface_t *
_cairo_surface_subsurface_create_similar (void *other,
cairo_content_t content,
int width, int height)
{
cairo_surface_subsurface_t *surface = other;
return surface->target->backend->create_similar (surface->target, content, width, height);
}
 
static cairo_int_status_t
_cairo_surface_subsurface_paint (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_clip_t *clip)
{
cairo_surface_subsurface_t *surface = abstract_surface;
cairo_rectangle_int_t rect = { 0, 0, surface->extents.width, surface->extents.height };
cairo_status_t status;
cairo_clip_t target_clip;
 
_cairo_clip_init_copy (&target_clip, clip);
status = _cairo_clip_rectangle (&target_clip, &rect);
if (unlikely (status))
goto CLEANUP;
 
status = _cairo_surface_offset_paint (surface->target,
-surface->extents.x, -surface->extents.y,
op, source, &target_clip);
CLEANUP:
_cairo_clip_fini (&target_clip);
return status;
}
 
static cairo_int_status_t
_cairo_surface_subsurface_mask (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_pattern_t *mask,
cairo_clip_t *clip)
{
cairo_surface_subsurface_t *surface = abstract_surface;
cairo_rectangle_int_t rect = { 0, 0, surface->extents.width, surface->extents.height };
cairo_status_t status;
cairo_clip_t target_clip;
 
_cairo_clip_init_copy (&target_clip, clip);
status = _cairo_clip_rectangle (&target_clip, &rect);
if (unlikely (status))
goto CLEANUP;
 
status = _cairo_surface_offset_mask (surface->target,
-surface->extents.x, -surface->extents.y,
op, source, mask, &target_clip);
CLEANUP:
_cairo_clip_fini (&target_clip);
return status;
}
 
static cairo_int_status_t
_cairo_surface_subsurface_fill (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias,
cairo_clip_t *clip)
{
cairo_surface_subsurface_t *surface = abstract_surface;
cairo_rectangle_int_t rect = { 0, 0, surface->extents.width, surface->extents.height };
cairo_status_t status;
cairo_clip_t target_clip;
 
_cairo_clip_init_copy (&target_clip, clip);
status = _cairo_clip_rectangle (&target_clip, &rect);
if (unlikely (status))
goto CLEANUP;
 
status = _cairo_surface_offset_fill (surface->target,
-surface->extents.x, -surface->extents.y,
op, source, path, fill_rule, tolerance, antialias,
&target_clip);
CLEANUP:
_cairo_clip_fini (&target_clip);
return status;
}
 
static cairo_int_status_t
_cairo_surface_subsurface_stroke (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_path_fixed_t *path,
const cairo_stroke_style_t *stroke_style,
const cairo_matrix_t *ctm,
const cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
cairo_clip_t *clip)
{
cairo_surface_subsurface_t *surface = abstract_surface;
cairo_rectangle_int_t rect = { 0, 0, surface->extents.width, surface->extents.height };
cairo_status_t status;
cairo_clip_t target_clip;
 
_cairo_clip_init_copy (&target_clip, clip);
status = _cairo_clip_rectangle (&target_clip, &rect);
if (unlikely (status))
goto CLEANUP;
 
status = _cairo_surface_offset_stroke (surface->target,
-surface->extents.x, -surface->extents.y,
op, source, path, stroke_style, ctm, ctm_inverse,
tolerance, antialias,
&target_clip);
CLEANUP:
_cairo_clip_fini (&target_clip);
return status;
}
 
static cairo_int_status_t
_cairo_surface_subsurface_glyphs (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font,
cairo_clip_t *clip,
int *remaining_glyphs)
{
cairo_surface_subsurface_t *surface = abstract_surface;
cairo_rectangle_int_t rect = { 0, 0, surface->extents.width, surface->extents.height };
cairo_status_t status;
cairo_clip_t target_clip;
 
_cairo_clip_init_copy (&target_clip, clip);
status = _cairo_clip_rectangle (&target_clip, &rect);
if (unlikely (status))
goto CLEANUP;
 
status = _cairo_surface_offset_glyphs (surface->target,
-surface->extents.x, -surface->extents.y,
op, source,
scaled_font, glyphs, num_glyphs,
&target_clip);
*remaining_glyphs = 0;
CLEANUP:
_cairo_clip_fini (&target_clip);
return status;
}
 
static cairo_status_t
_cairo_surface_subsurface_flush (void *abstract_surface)
{
cairo_surface_subsurface_t *surface = abstract_surface;
cairo_status_t status;
 
status = CAIRO_STATUS_SUCCESS;
if (surface->target->backend->flush != NULL)
status = surface->target->backend->flush (surface->target);
 
return status;
}
 
static cairo_status_t
_cairo_surface_subsurface_mark_dirty (void *abstract_surface,
int x, int y,
int width, int height)
{
cairo_surface_subsurface_t *surface = abstract_surface;
cairo_status_t status;
 
status = CAIRO_STATUS_SUCCESS;
if (surface->target->backend->mark_dirty_rectangle != NULL) {
cairo_rectangle_int_t rect, extents;
 
rect.x = x;
rect.y = y;
rect.width = width;
rect.height = height;
 
extents.x = extents.y = 0;
extents.width = surface->extents.width;
extents.height = surface->extents.height;
 
if (_cairo_rectangle_intersect (&rect, &extents)) {
status = surface->target->backend->mark_dirty_rectangle (surface->target,
rect.x + surface->extents.x,
rect.y + surface->extents.y,
rect.width, rect.height);
}
}
 
return status;
}
 
static cairo_bool_t
_cairo_surface_subsurface_get_extents (void *abstract_surface,
cairo_rectangle_int_t *extents)
{
cairo_surface_subsurface_t *surface = abstract_surface;
 
extents->x = 0;
extents->y = 0;
extents->width = surface->extents.width;
extents->height = surface->extents.height;
 
return TRUE;
}
 
static void
_cairo_surface_subsurface_get_font_options (void *abstract_surface,
cairo_font_options_t *options)
{
cairo_surface_subsurface_t *surface = abstract_surface;
 
if (surface->target->backend->get_font_options != NULL)
surface->target->backend->get_font_options (surface->target, options);
}
 
struct extra {
cairo_image_surface_t *image;
void *image_extra;
};
 
static void
cairo_surface_paint_to_target (cairo_surface_t *target,
cairo_surface_subsurface_t *subsurface)
{
cairo_t *cr;
cr = cairo_create (target);
 
cairo_set_source_surface (cr,
subsurface->target,
- subsurface->extents.x,
- subsurface->extents.y);
cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
cairo_paint (cr);
cairo_destroy (cr);
}
 
static cairo_status_t
_cairo_surface_subsurface_acquire_source_image (void *abstract_surface,
cairo_image_surface_t **image_out,
void **extra_out)
{
cairo_rectangle_int_t target_extents;
cairo_surface_subsurface_t *surface = abstract_surface;
cairo_image_surface_t *image;
cairo_status_t status;
struct extra *extra;
uint8_t *data;
cairo_bool_t ret;
 
if (surface->target->type == CAIRO_SURFACE_TYPE_RECORDING) {
cairo_recording_surface_t *meta = (cairo_recording_surface_t *) surface->target;
cairo_surface_t *snapshot;
 
snapshot = _cairo_surface_has_snapshot (&surface->base,
&_cairo_image_surface_backend);
if (snapshot != NULL) {
*image_out = (cairo_image_surface_t *) cairo_surface_reference (snapshot);
*extra_out = NULL;
return CAIRO_STATUS_SUCCESS;
}
 
if (! _cairo_surface_has_snapshot (&meta->base,
&_cairo_image_surface_backend))
{
image = (cairo_image_surface_t *)
_cairo_image_surface_create_with_content (meta->content,
surface->extents.width,
surface->extents.height);
if (unlikely (image->base.status))
return image->base.status;
 
cairo_surface_paint_to_target (&image->base, surface);
 
_cairo_surface_attach_snapshot (&surface->base, &image->base, NULL);
 
*image_out = image;
*extra_out = NULL;
return CAIRO_STATUS_SUCCESS;
}
}
 
extra = malloc (sizeof (struct extra));
if (unlikely (extra == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
status = _cairo_surface_acquire_source_image (surface->target, &extra->image, &extra->image_extra);
if (unlikely (status))
goto CLEANUP;
 
ret = _cairo_surface_get_extents (&extra->image->base, &target_extents);
assert (ret);
 
/* only copy if we need to perform sub-byte manipulation */
if (PIXMAN_FORMAT_BPP (extra->image->pixman_format) >= 8 &&
target_extents.x <= surface->extents.x &&
target_extents.y <= surface->extents.y &&
surface->extents.x + surface->extents.width <= target_extents.x + target_extents.width &&
surface->extents.y + surface->extents.height <= target_extents.y + target_extents.height) {
 
assert ((PIXMAN_FORMAT_BPP (extra->image->pixman_format) % 8) == 0);
 
data = extra->image->data + surface->extents.y * extra->image->stride;
data += PIXMAN_FORMAT_BPP (extra->image->pixman_format) / 8 * surface->extents.x;
 
image = (cairo_image_surface_t *)
_cairo_image_surface_create_with_pixman_format (data,
extra->image->pixman_format,
surface->extents.width,
surface->extents.height,
extra->image->stride);
if (unlikely ((status = image->base.status)))
goto CLEANUP_IMAGE;
 
image->base.is_clear = FALSE;
} else {
image = (cairo_image_surface_t *)
_cairo_image_surface_create_with_pixman_format (NULL,
extra->image->pixman_format,
surface->extents.width,
surface->extents.height,
0);
if (unlikely ((status = image->base.status)))
goto CLEANUP_IMAGE;
 
cairo_surface_paint_to_target (&image->base, surface);
}
 
*image_out = image;
*extra_out = extra;
return CAIRO_STATUS_SUCCESS;
 
CLEANUP_IMAGE:
_cairo_surface_release_source_image (surface->target, extra->image, extra->image_extra);
CLEANUP:
free (extra);
return status;
}
 
static void
_cairo_surface_subsurface_release_source_image (void *abstract_surface,
cairo_image_surface_t *image,
void *abstract_extra)
{
cairo_surface_subsurface_t *surface = abstract_surface;
 
if (abstract_extra != NULL) {
struct extra *extra = abstract_extra;
 
_cairo_surface_release_source_image (surface->target, extra->image, extra->image_extra);
free (extra);
}
 
cairo_surface_destroy (&image->base);
}
 
static cairo_surface_t *
_cairo_surface_subsurface_snapshot (void *abstract_surface)
{
cairo_surface_subsurface_t *surface = abstract_surface;
cairo_surface_subsurface_t *snapshot;
 
snapshot = malloc (sizeof (cairo_surface_subsurface_t));
if (unlikely (snapshot == NULL))
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
 
_cairo_surface_init (&snapshot->base,
&_cairo_surface_subsurface_backend,
NULL, /* device */
surface->target->content);
snapshot->target = _cairo_surface_snapshot (surface->target);
if (unlikely (snapshot->target->status)) {
cairo_status_t status;
 
status = snapshot->target->status;
free (snapshot);
return _cairo_surface_create_in_error (status);
}
 
snapshot->base.type = snapshot->target->type;
snapshot->extents = surface->extents;
 
return &snapshot->base;
}
 
static const cairo_surface_backend_t _cairo_surface_subsurface_backend = {
CAIRO_SURFACE_TYPE_SUBSURFACE,
_cairo_surface_subsurface_create_similar,
_cairo_surface_subsurface_finish,
 
_cairo_surface_subsurface_acquire_source_image,
_cairo_surface_subsurface_release_source_image,
NULL, NULL, /* acquire, release dest */
NULL, /* clone similar */
NULL, /* composite */
NULL, /* fill rectangles */
NULL, /* composite trapezoids */
NULL, /* create span renderer */
NULL, /* check span renderer */
NULL, /* copy_page */
NULL, /* show_page */
_cairo_surface_subsurface_get_extents,
NULL, /* old_show_glyphs */
_cairo_surface_subsurface_get_font_options,
_cairo_surface_subsurface_flush,
_cairo_surface_subsurface_mark_dirty,
NULL, /* font_fini */
NULL, /* glyph_fini */
 
_cairo_surface_subsurface_paint,
_cairo_surface_subsurface_mask,
_cairo_surface_subsurface_stroke,
_cairo_surface_subsurface_fill,
_cairo_surface_subsurface_glyphs,
 
_cairo_surface_subsurface_snapshot,
};
 
/**
* cairo_surface_create_for_rectangle:
* @target: an existing surface for which the sub-surface will point to
* @x: the x-origin of the sub-surface from the top-left of the target surface (in device-space units)
* @y: the y-origin of the sub-surface from the top-left of the target surface (in device-space units)
* @width: width of the sub-surface (in device-space units)
* @height: height of the sub-surface (in device-space units)
*
* Create a new surface that is a rectangle within the target surface.
* All operations drawn to this surface are then clipped and translated
* onto the target surface. Nothing drawn via this sub-surface outside of
* its bounds is drawn onto the target surface, making this a useful method
* for passing constrained child surfaces to library routines that draw
* directly onto the parent surface, i.e. with no further backend allocations,
* double buffering or copies.
*
* <note><para>The semantics of subsurfaces have not been finalized yet
* unless the rectangle is in full device units, is contained within
* the extents of the target surface, and the target or subsurface's
* device transforms are not changed.</para></note>
*
* Return value: a pointer to the newly allocated surface. The caller
* owns the surface and should call cairo_surface_destroy() when done
* with it.
*
* This function always returns a valid pointer, but it will return a
* pointer to a "nil" surface if @other is already in an error state
* or any other error occurs.
*
* Since: 1.10
**/
cairo_surface_t *
cairo_surface_create_for_rectangle (cairo_surface_t *target,
double x, double y,
double width, double height)
{
cairo_surface_subsurface_t *surface;
 
if (unlikely (target->status))
return _cairo_surface_create_in_error (target->status);
if (unlikely (target->finished))
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
 
surface = malloc (sizeof (cairo_surface_subsurface_t));
if (unlikely (surface == NULL))
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
 
assert (_cairo_matrix_is_translation (&target->device_transform));
x += target->device_transform.x0;
y += target->device_transform.y0;
 
_cairo_surface_init (&surface->base,
&_cairo_surface_subsurface_backend,
NULL, /* device */
target->content);
 
/* XXX forced integer alignment */
surface->extents.x = ceil (x);
surface->extents.y = ceil (y);
surface->extents.width = floor (x + width) - surface->extents.x;
surface->extents.height = floor (y + height) - surface->extents.y;
 
if (target->backend->type == CAIRO_SURFACE_TYPE_SUBSURFACE) {
/* Maintain subsurfaces as 1-depth */
cairo_surface_subsurface_t *sub = (cairo_surface_subsurface_t *) target;
surface->extents.x += sub->extents.x;
surface->extents.y += sub->extents.y;
target = sub->target;
}
 
surface->target = cairo_surface_reference (target);
 
return &surface->base;
}
/* XXX observe mark-dirty */
/programs/develop/libraries/cairo/src/cairo-surface-wrapper-private.h
0,0 → 1,168
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2002 University of Southern California
* Copyright © 2005 Red Hat, Inc.
* Copyright © 2009 Chris Wilson
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Chris Wilson <chris@chris-wilson.co.u>
*/
 
#ifndef CAIRO_SURFACE_WRAPPER_PRIVATE_H
#define CAIRO_SURFACE_WRAPPER_PRIVATE_H
 
#include "cairo-types-private.h"
 
CAIRO_BEGIN_DECLS
 
struct _cairo_surface_wrapper {
cairo_surface_t *target;
 
cairo_bool_t has_extents;
cairo_rectangle_int_t extents;
};
 
cairo_private void
_cairo_surface_wrapper_init (cairo_surface_wrapper_t *wrapper,
cairo_surface_t *target);
 
cairo_private void
_cairo_surface_wrapper_set_extents (cairo_surface_wrapper_t *wrapper,
const cairo_rectangle_int_t *extents);
 
cairo_private void
_cairo_surface_wrapper_fini (cairo_surface_wrapper_t *wrapper);
 
cairo_private cairo_status_t
_cairo_surface_wrapper_acquire_source_image (cairo_surface_wrapper_t *wrapper,
cairo_image_surface_t **image_out,
void **image_extra);
 
cairo_private void
_cairo_surface_wrapper_release_source_image (cairo_surface_wrapper_t *wrapper,
cairo_image_surface_t *image,
void *image_extra);
 
 
cairo_private cairo_status_t
_cairo_surface_wrapper_paint (cairo_surface_wrapper_t *wrapper,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_clip_t *clip);
 
cairo_private cairo_status_t
_cairo_surface_wrapper_mask (cairo_surface_wrapper_t *wrapper,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_pattern_t *mask,
cairo_clip_t *clip);
 
cairo_private cairo_status_t
_cairo_surface_wrapper_stroke (cairo_surface_wrapper_t *wrapper,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_path_fixed_t *path,
const cairo_stroke_style_t *stroke_style,
const cairo_matrix_t *ctm,
const cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
cairo_clip_t *clip);
 
cairo_private cairo_status_t
_cairo_surface_wrapper_fill_stroke (cairo_surface_wrapper_t *wrapper,
cairo_operator_t fill_op,
const cairo_pattern_t *fill_source,
cairo_fill_rule_t fill_rule,
double fill_tolerance,
cairo_antialias_t fill_antialias,
cairo_path_fixed_t *path,
cairo_operator_t stroke_op,
const cairo_pattern_t *stroke_source,
const cairo_stroke_style_t *stroke_style,
const cairo_matrix_t *stroke_ctm,
const cairo_matrix_t *stroke_ctm_inverse,
double stroke_tolerance,
cairo_antialias_t stroke_antialias,
cairo_clip_t *clip);
 
cairo_private cairo_status_t
_cairo_surface_wrapper_fill (cairo_surface_wrapper_t *wrapper,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias,
cairo_clip_t *clip);
 
cairo_private cairo_status_t
_cairo_surface_wrapper_show_text_glyphs (cairo_surface_wrapper_t *wrapper,
cairo_operator_t op,
const cairo_pattern_t *source,
const char *utf8,
int utf8_len,
cairo_glyph_t *glyphs,
int num_glyphs,
const cairo_text_cluster_t *clusters,
int num_clusters,
cairo_text_cluster_flags_t cluster_flags,
cairo_scaled_font_t *scaled_font,
cairo_clip_t *clip);
 
cairo_private cairo_surface_t *
_cairo_surface_wrapper_create_similar (cairo_surface_wrapper_t *wrapper,
cairo_content_t content,
int width,
int height);
cairo_private cairo_bool_t
_cairo_surface_wrapper_get_extents (cairo_surface_wrapper_t *wrapper,
cairo_rectangle_int_t *extents);
 
cairo_private void
_cairo_surface_wrapper_get_font_options (cairo_surface_wrapper_t *wrapper,
cairo_font_options_t *options);
 
cairo_private cairo_surface_t *
_cairo_surface_wrapper_snapshot (cairo_surface_wrapper_t *wrapper);
 
cairo_private cairo_bool_t
_cairo_surface_wrapper_has_show_text_glyphs (cairo_surface_wrapper_t *wrapper);
 
static inline cairo_bool_t
_cairo_surface_wrapper_is_active (cairo_surface_wrapper_t *wrapper)
{
return wrapper->target != (cairo_surface_t *) 0;
}
 
CAIRO_END_DECLS
 
#endif /* CAIRO_SURFACE_WRAPPER_PRIVATE_H */
/programs/develop/libraries/cairo/src/cairo-surface-wrapper.c
0,0 → 1,712
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2005 Red Hat, Inc
* Copyright © 2007 Adrian Johnson
* Copyright © 2009 Chris Wilson
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
* Chris Wilson <chris@chris-wilson.co.uk>
*/
 
#include "cairoint.h"
 
#include "cairo-error-private.h"
#include "cairo-surface-wrapper-private.h"
 
/* A collection of routines to facilitate surface wrapping */
 
static void
_copy_transformed_pattern (cairo_pattern_t *pattern,
const cairo_pattern_t *original,
const cairo_matrix_t *ctm_inverse)
{
_cairo_pattern_init_static_copy (pattern, original);
 
/* apply device_transform first so that it is transformed by ctm_inverse */
if (original->type == CAIRO_PATTERN_TYPE_SURFACE) {
cairo_surface_pattern_t *surface_pattern;
cairo_surface_t *surface;
 
surface_pattern = (cairo_surface_pattern_t *) original;
surface = surface_pattern->surface;
 
if (_cairo_surface_has_device_transform (surface))
_cairo_pattern_transform (pattern, &surface->device_transform);
}
 
if (! _cairo_matrix_is_identity (ctm_inverse))
_cairo_pattern_transform (pattern, ctm_inverse);
}
 
static inline cairo_bool_t
_cairo_surface_wrapper_needs_device_transform (cairo_surface_wrapper_t *wrapper)
{
return ! _cairo_matrix_is_identity (&wrapper->target->device_transform);
}
 
static cairo_bool_t
_cairo_surface_wrapper_needs_extents_transform (cairo_surface_wrapper_t *wrapper)
{
return wrapper->has_extents && (wrapper->extents.x | wrapper->extents.y);
}
 
cairo_status_t
_cairo_surface_wrapper_acquire_source_image (cairo_surface_wrapper_t *wrapper,
cairo_image_surface_t **image_out,
void **image_extra)
{
if (unlikely (wrapper->target->status))
return wrapper->target->status;
 
return _cairo_surface_acquire_source_image (wrapper->target,
image_out, image_extra);
}
 
void
_cairo_surface_wrapper_release_source_image (cairo_surface_wrapper_t *wrapper,
cairo_image_surface_t *image,
void *image_extra)
{
_cairo_surface_release_source_image (wrapper->target, image, image_extra);
}
 
cairo_status_t
_cairo_surface_wrapper_paint (cairo_surface_wrapper_t *wrapper,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_clip_t *clip)
{
cairo_status_t status;
cairo_clip_t clip_copy, *dev_clip = clip;
cairo_pattern_union_t source_copy;
cairo_clip_t target_clip;
 
if (unlikely (wrapper->target->status))
return wrapper->target->status;
 
if (wrapper->has_extents) {
_cairo_clip_init_copy (&target_clip, clip);
status = _cairo_clip_rectangle (&target_clip, &wrapper->extents);
if (unlikely (status))
goto FINISH;
 
dev_clip = clip = &target_clip;
}
 
if (clip && clip->all_clipped) {
status = CAIRO_STATUS_SUCCESS;
goto FINISH;
}
 
if (_cairo_surface_wrapper_needs_device_transform (wrapper) ||
_cairo_surface_wrapper_needs_extents_transform (wrapper))
{
cairo_matrix_t m;
 
cairo_matrix_init_identity (&m);
 
if (_cairo_surface_wrapper_needs_extents_transform (wrapper))
cairo_matrix_translate (&m, -wrapper->extents.x, -wrapper->extents.y);
 
if (_cairo_surface_wrapper_needs_device_transform (wrapper))
cairo_matrix_multiply (&m, &wrapper->target->device_transform, &m);
 
if (clip != NULL) {
status = _cairo_clip_init_copy_transformed (&clip_copy, clip, &m);
if (unlikely (status))
goto FINISH;
 
dev_clip = &clip_copy;
}
 
status = cairo_matrix_invert (&m);
assert (status == CAIRO_STATUS_SUCCESS);
 
_copy_transformed_pattern (&source_copy.base, source, &m);
source = &source_copy.base;
}
 
status = _cairo_surface_paint (wrapper->target, op, source, dev_clip);
 
FINISH:
if (wrapper->has_extents)
_cairo_clip_reset (&target_clip);
if (dev_clip != clip)
_cairo_clip_reset (dev_clip);
return status;
}
 
cairo_status_t
_cairo_surface_wrapper_mask (cairo_surface_wrapper_t *wrapper,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_pattern_t *mask,
cairo_clip_t *clip)
{
cairo_status_t status;
cairo_clip_t clip_copy, *dev_clip = clip;
cairo_pattern_union_t source_copy;
cairo_pattern_union_t mask_copy;
cairo_clip_t target_clip;
 
if (unlikely (wrapper->target->status))
return wrapper->target->status;
 
if (wrapper->has_extents) {
_cairo_clip_init_copy (&target_clip, clip);
status = _cairo_clip_rectangle (&target_clip, &wrapper->extents);
if (unlikely (status))
goto FINISH;
 
dev_clip = clip = &target_clip;
}
 
if (clip && clip->all_clipped) {
status = CAIRO_STATUS_SUCCESS;
goto FINISH;
}
 
if (_cairo_surface_wrapper_needs_device_transform (wrapper) ||
_cairo_surface_wrapper_needs_extents_transform (wrapper))
{
cairo_matrix_t m;
 
cairo_matrix_init_identity (&m);
 
if (_cairo_surface_wrapper_needs_extents_transform (wrapper))
cairo_matrix_translate (&m, -wrapper->extents.x, -wrapper->extents.y);
 
if (_cairo_surface_wrapper_needs_device_transform (wrapper))
cairo_matrix_multiply (&m, &wrapper->target->device_transform, &m);
 
if (clip != NULL) {
status = _cairo_clip_init_copy_transformed (&clip_copy, clip, &m);
if (unlikely (status))
goto FINISH;
 
dev_clip = &clip_copy;
}
 
status = cairo_matrix_invert (&m);
assert (status == CAIRO_STATUS_SUCCESS);
 
_copy_transformed_pattern (&source_copy.base, source, &m);
source = &source_copy.base;
 
_copy_transformed_pattern (&mask_copy.base, mask, &m);
mask = &mask_copy.base;
}
 
status = _cairo_surface_mask (wrapper->target, op, source, mask, dev_clip);
 
FINISH:
if (wrapper->has_extents)
_cairo_clip_reset (&target_clip);
if (dev_clip != clip)
_cairo_clip_reset (dev_clip);
return status;
}
 
cairo_status_t
_cairo_surface_wrapper_stroke (cairo_surface_wrapper_t *wrapper,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_path_fixed_t *path,
const cairo_stroke_style_t *stroke_style,
const cairo_matrix_t *ctm,
const cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
cairo_clip_t *clip)
{
cairo_status_t status;
cairo_path_fixed_t path_copy, *dev_path = path;
cairo_clip_t clip_copy, *dev_clip = clip;
cairo_matrix_t dev_ctm = *ctm;
cairo_matrix_t dev_ctm_inverse = *ctm_inverse;
cairo_pattern_union_t source_copy;
cairo_clip_t target_clip;
 
if (unlikely (wrapper->target->status))
return wrapper->target->status;
 
if (wrapper->has_extents) {
_cairo_clip_init_copy (&target_clip, clip);
status = _cairo_clip_rectangle (&target_clip, &wrapper->extents);
if (unlikely (status))
goto FINISH;
 
dev_clip = clip = &target_clip;
}
 
if (clip && clip->all_clipped) {
status = CAIRO_STATUS_SUCCESS;
goto FINISH;
}
 
if (_cairo_surface_wrapper_needs_device_transform (wrapper) ||
_cairo_surface_wrapper_needs_extents_transform (wrapper))
{
cairo_matrix_t m;
 
cairo_matrix_init_identity (&m);
 
if (_cairo_surface_wrapper_needs_extents_transform (wrapper))
cairo_matrix_translate (&m, -wrapper->extents.x, -wrapper->extents.y);
 
if (_cairo_surface_wrapper_needs_device_transform (wrapper))
cairo_matrix_multiply (&m, &wrapper->target->device_transform, &m);
 
status = _cairo_path_fixed_init_copy (&path_copy, dev_path);
if (unlikely (status))
goto FINISH;
 
_cairo_path_fixed_transform (&path_copy, &m);
dev_path = &path_copy;
 
if (clip != NULL) {
status = _cairo_clip_init_copy_transformed (&clip_copy, clip, &m);
if (unlikely (status))
goto FINISH;
 
dev_clip = &clip_copy;
}
 
cairo_matrix_multiply (&dev_ctm, &dev_ctm, &m);
 
status = cairo_matrix_invert (&m);
assert (status == CAIRO_STATUS_SUCCESS);
 
cairo_matrix_multiply (&dev_ctm_inverse, &m, &dev_ctm_inverse);
 
_copy_transformed_pattern (&source_copy.base, source, &m);
source = &source_copy.base;
}
else
{
if (clip != NULL) {
dev_clip = &clip_copy;
_cairo_clip_init_copy (&clip_copy, clip);
}
}
 
status = _cairo_surface_stroke (wrapper->target, op, source,
dev_path, stroke_style,
&dev_ctm, &dev_ctm_inverse,
tolerance, antialias,
dev_clip);
 
FINISH:
if (dev_path != path)
_cairo_path_fixed_fini (dev_path);
if (wrapper->has_extents)
_cairo_clip_reset (&target_clip);
if (dev_clip != clip)
_cairo_clip_reset (dev_clip);
return status;
}
 
cairo_status_t
_cairo_surface_wrapper_fill_stroke (cairo_surface_wrapper_t *wrapper,
cairo_operator_t fill_op,
const cairo_pattern_t *fill_source,
cairo_fill_rule_t fill_rule,
double fill_tolerance,
cairo_antialias_t fill_antialias,
cairo_path_fixed_t *path,
cairo_operator_t stroke_op,
const cairo_pattern_t *stroke_source,
const cairo_stroke_style_t *stroke_style,
const cairo_matrix_t *stroke_ctm,
const cairo_matrix_t *stroke_ctm_inverse,
double stroke_tolerance,
cairo_antialias_t stroke_antialias,
cairo_clip_t *clip)
{
cairo_status_t status;
cairo_path_fixed_t path_copy, *dev_path = path;
cairo_clip_t clip_copy, *dev_clip = clip;
cairo_matrix_t dev_ctm = *stroke_ctm;
cairo_matrix_t dev_ctm_inverse = *stroke_ctm_inverse;
cairo_pattern_union_t stroke_source_copy;
cairo_pattern_union_t fill_source_copy;
cairo_clip_t target_clip;
 
if (unlikely (wrapper->target->status))
return wrapper->target->status;
 
if (wrapper->has_extents) {
_cairo_clip_init_copy (&target_clip, clip);
status = _cairo_clip_rectangle (&target_clip, &wrapper->extents);
if (unlikely (status))
goto FINISH;
 
dev_clip = clip = &target_clip;
}
 
if (clip && clip->all_clipped) {
status = CAIRO_STATUS_SUCCESS;
goto FINISH;
}
 
if (_cairo_surface_wrapper_needs_device_transform (wrapper) ||
_cairo_surface_wrapper_needs_extents_transform (wrapper))
{
cairo_matrix_t m;
 
cairo_matrix_init_identity (&m);
 
if (_cairo_surface_wrapper_needs_extents_transform (wrapper))
cairo_matrix_translate (&m, -wrapper->extents.x, -wrapper->extents.y);
 
if (_cairo_surface_wrapper_needs_device_transform (wrapper))
cairo_matrix_multiply (&m, &wrapper->target->device_transform, &m);
 
status = _cairo_path_fixed_init_copy (&path_copy, dev_path);
if (unlikely (status))
goto FINISH;
 
_cairo_path_fixed_transform (&path_copy, &m);
dev_path = &path_copy;
 
if (clip != NULL) {
status = _cairo_clip_init_copy_transformed (&clip_copy, clip, &m);
if (unlikely (status))
goto FINISH;
 
dev_clip = &clip_copy;
}
 
cairo_matrix_multiply (&dev_ctm, &dev_ctm, &m);
 
status = cairo_matrix_invert (&m);
assert (status == CAIRO_STATUS_SUCCESS);
 
cairo_matrix_multiply (&dev_ctm_inverse, &m, &dev_ctm_inverse);
 
_copy_transformed_pattern (&stroke_source_copy.base, stroke_source, &m);
stroke_source = &stroke_source_copy.base;
 
_copy_transformed_pattern (&fill_source_copy.base, fill_source, &m);
fill_source = &fill_source_copy.base;
}
else
{
if (clip != NULL) {
dev_clip = &clip_copy;
_cairo_clip_init_copy (&clip_copy, clip);
}
}
 
status = _cairo_surface_fill_stroke (wrapper->target,
fill_op, fill_source, fill_rule,
fill_tolerance, fill_antialias,
dev_path,
stroke_op, stroke_source,
stroke_style,
&dev_ctm, &dev_ctm_inverse,
stroke_tolerance, stroke_antialias,
dev_clip);
 
FINISH:
if (dev_path != path)
_cairo_path_fixed_fini (dev_path);
if (wrapper->has_extents)
_cairo_clip_reset (&target_clip);
if (dev_clip != clip)
_cairo_clip_reset (dev_clip);
return status;
}
 
cairo_status_t
_cairo_surface_wrapper_fill (cairo_surface_wrapper_t *wrapper,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias,
cairo_clip_t *clip)
{
cairo_status_t status;
cairo_path_fixed_t path_copy, *dev_path = path;
cairo_clip_t clip_copy, *dev_clip = clip;
cairo_pattern_union_t source_copy;
cairo_clip_t target_clip;
 
if (unlikely (wrapper->target->status))
return wrapper->target->status;
 
if (wrapper->has_extents) {
_cairo_clip_init_copy (&target_clip, clip);
status = _cairo_clip_rectangle (&target_clip, &wrapper->extents);
if (unlikely (status))
goto FINISH;
 
dev_clip = clip = &target_clip;
}
 
if (clip && clip->all_clipped) {
status = CAIRO_STATUS_SUCCESS;
goto FINISH;
}
 
if (_cairo_surface_wrapper_needs_device_transform (wrapper) ||
_cairo_surface_wrapper_needs_extents_transform (wrapper))
{
cairo_matrix_t m;
 
cairo_matrix_init_identity (&m);
 
if (_cairo_surface_wrapper_needs_extents_transform (wrapper))
cairo_matrix_translate (&m, -wrapper->extents.x, -wrapper->extents.y);
 
if (_cairo_surface_wrapper_needs_device_transform (wrapper))
cairo_matrix_multiply (&m, &wrapper->target->device_transform, &m);
 
status = _cairo_path_fixed_init_copy (&path_copy, dev_path);
if (unlikely (status))
goto FINISH;
 
_cairo_path_fixed_transform (&path_copy, &m);
dev_path = &path_copy;
 
if (clip != NULL) {
status = _cairo_clip_init_copy_transformed (&clip_copy, clip, &m);
if (unlikely (status))
goto FINISH;
 
dev_clip = &clip_copy;
}
 
status = cairo_matrix_invert (&m);
assert (status == CAIRO_STATUS_SUCCESS);
 
_copy_transformed_pattern (&source_copy.base, source, &m);
source = &source_copy.base;
}
else
{
if (clip != NULL) {
dev_clip = &clip_copy;
_cairo_clip_init_copy (&clip_copy, clip);
}
}
 
status = _cairo_surface_fill (wrapper->target, op, source,
dev_path, fill_rule,
tolerance, antialias,
dev_clip);
 
FINISH:
if (dev_path != path)
_cairo_path_fixed_fini (dev_path);
if (wrapper->has_extents)
_cairo_clip_reset (&target_clip);
if (dev_clip != clip)
_cairo_clip_reset (dev_clip);
return status;
}
 
cairo_status_t
_cairo_surface_wrapper_show_text_glyphs (cairo_surface_wrapper_t *wrapper,
cairo_operator_t op,
const cairo_pattern_t *source,
const char *utf8,
int utf8_len,
cairo_glyph_t *glyphs,
int num_glyphs,
const cairo_text_cluster_t *clusters,
int num_clusters,
cairo_text_cluster_flags_t cluster_flags,
cairo_scaled_font_t *scaled_font,
cairo_clip_t *clip)
{
cairo_status_t status;
cairo_clip_t clip_copy, *dev_clip = clip;
cairo_glyph_t *dev_glyphs = glyphs;
cairo_pattern_union_t source_copy;
cairo_clip_t target_clip;
 
if (unlikely (wrapper->target->status))
return wrapper->target->status;
 
if (glyphs == NULL || num_glyphs == 0)
return CAIRO_STATUS_SUCCESS;
 
if (wrapper->has_extents) {
_cairo_clip_init_copy (&target_clip, clip);
status = _cairo_clip_rectangle (&target_clip, &wrapper->extents);
if (unlikely (status))
goto FINISH;
 
dev_clip = clip = &target_clip;
}
 
if (clip && clip->all_clipped) {
status = CAIRO_STATUS_SUCCESS;
goto FINISH;
}
 
if (_cairo_surface_wrapper_needs_device_transform (wrapper) ||
_cairo_surface_wrapper_needs_extents_transform (wrapper))
{
cairo_matrix_t m;
int i;
 
cairo_matrix_init_identity (&m);
 
if (_cairo_surface_wrapper_needs_extents_transform (wrapper))
cairo_matrix_translate (&m, -wrapper->extents.x, -wrapper->extents.y);
 
if (_cairo_surface_wrapper_needs_device_transform (wrapper))
cairo_matrix_multiply (&m, &wrapper->target->device_transform, &m);
 
if (clip != NULL) {
status = _cairo_clip_init_copy_transformed (&clip_copy, clip, &m);
if (unlikely (status))
goto FINISH;
 
dev_clip = &clip_copy;
}
 
dev_glyphs = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t));
if (dev_glyphs == NULL) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto FINISH;
}
 
for (i = 0; i < num_glyphs; i++) {
dev_glyphs[i] = glyphs[i];
cairo_matrix_transform_point (&m, &dev_glyphs[i].x, &dev_glyphs[i].y);
}
 
status = cairo_matrix_invert (&m);
assert (status == CAIRO_STATUS_SUCCESS);
 
_copy_transformed_pattern (&source_copy.base, source, &m);
source = &source_copy.base;
}
else
{
if (clip != NULL) {
dev_clip = &clip_copy;
_cairo_clip_init_copy (&clip_copy, clip);
}
}
 
status = _cairo_surface_show_text_glyphs (wrapper->target, op, source,
utf8, utf8_len,
dev_glyphs, num_glyphs,
clusters, num_clusters,
cluster_flags,
scaled_font,
dev_clip);
 
FINISH:
if (dev_clip != clip)
_cairo_clip_reset (dev_clip);
if (wrapper->has_extents)
_cairo_clip_reset (&target_clip);
if (dev_glyphs != glyphs)
free (dev_glyphs);
return status;
}
 
cairo_surface_t *
_cairo_surface_wrapper_create_similar (cairo_surface_wrapper_t *wrapper,
cairo_content_t content,
int width,
int height)
{
return _cairo_surface_create_similar_scratch (wrapper->target,
content, width, height);
}
 
cairo_bool_t
_cairo_surface_wrapper_get_extents (cairo_surface_wrapper_t *wrapper,
cairo_rectangle_int_t *extents)
{
if (wrapper->has_extents) {
if (_cairo_surface_get_extents (wrapper->target, extents))
_cairo_rectangle_intersect (extents, &wrapper->extents);
else
*extents = wrapper->extents;
 
return TRUE;
} else {
return _cairo_surface_get_extents (wrapper->target, extents);
}
}
 
void
_cairo_surface_wrapper_set_extents (cairo_surface_wrapper_t *wrapper,
const cairo_rectangle_int_t *extents)
{
if (extents != NULL) {
wrapper->extents = *extents;
wrapper->has_extents = TRUE;
} else {
wrapper->has_extents = FALSE;
}
}
 
void
_cairo_surface_wrapper_get_font_options (cairo_surface_wrapper_t *wrapper,
cairo_font_options_t *options)
{
cairo_surface_get_font_options (wrapper->target, options);
}
 
cairo_surface_t *
_cairo_surface_wrapper_snapshot (cairo_surface_wrapper_t *wrapper)
{
return _cairo_surface_snapshot (wrapper->target);
}
 
cairo_bool_t
_cairo_surface_wrapper_has_show_text_glyphs (cairo_surface_wrapper_t *wrapper)
{
return cairo_surface_has_show_text_glyphs (wrapper->target);
}
 
void
_cairo_surface_wrapper_init (cairo_surface_wrapper_t *wrapper,
cairo_surface_t *target)
{
wrapper->target = cairo_surface_reference (target);
wrapper->has_extents = FALSE;
}
 
void
_cairo_surface_wrapper_fini (cairo_surface_wrapper_t *wrapper)
{
cairo_surface_destroy (wrapper->target);
}
/programs/develop/libraries/cairo/src/cairo-surface.c
0,0 → 1,3184
/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2002 University of Southern California
* Copyright © 2005 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
*/
 
#include "cairoint.h"
 
#include "cairo-surface-fallback-private.h"
#include "cairo-clip-private.h"
#include "cairo-device-private.h"
#include "cairo-error-private.h"
#include "cairo-recording-surface-private.h"
#include "cairo-region-private.h"
#include "cairo-tee-surface-private.h"
 
/**
* SECTION:cairo-surface
* @Title: cairo_surface_t
* @Short_Description: Base class for surfaces
* @See_Also: #cairo_t, #cairo_pattern_t
*
* #cairo_surface_t is the abstract type representing all different drawing
* targets that cairo can render to. The actual drawings are
* performed using a cairo <firstterm>context</firstterm>.
*
* A cairo surface is created by using <firstterm>backend</firstterm>-specific
* constructors, typically of the form
* cairo_<emphasis>backend</emphasis>_surface_create().
*
* Most surface types allow accessing the surface without using Cairo
* functions. If you do this, keep in mind that it is mandatory that you call
* cairo_surface_flush() before reading from or writing to the surface and that
* you must use cairo_surface_mark_dirty() after modifying it.
* <example>
* <title>Directly modifying an image surface</title>
* <programlisting>
* void
* modify_image_surface (cairo_surface_t *surface)
* {
* unsigned char *data;
* int width, height, stride;
*
* // flush to ensure all writing to the image was done
* cairo_surface_flush (surface);
*
* // modify the image
* data = cairo_image_surface_get_data (surface);
* width = cairo_image_surface_get_width (surface);
* height = cairo_image_surface_get_height (surface);
* stride = cairo_image_surface_get_stride (surface);
* modify_image_data (data, width, height, stride);
*
* // mark the image dirty so Cairo clears its caches.
* cairo_surface_mark_dirty (surface);
* }
* </programlisting>
* </example>
* Note that for other surface types it might be necessary to acquire the
* surface's device first. See cairo_device_acquire() for a discussion of
* devices.
*/
 
#define DEFINE_NIL_SURFACE(status, name) \
const cairo_surface_t name = { \
NULL, /* backend */ \
NULL, /* device */ \
CAIRO_SURFACE_TYPE_IMAGE, /* type */ \
CAIRO_CONTENT_COLOR, /* content */ \
CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */ \
status, /* status */ \
0, /* unique id */ \
FALSE, /* finished */ \
TRUE, /* is_clear */ \
FALSE, /* has_font_options */ \
FALSE, /* owns_device */ \
{ 0, 0, 0, NULL, }, /* user_data */ \
{ 0, 0, 0, NULL, }, /* mime_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 */ \
{ NULL, NULL }, /* device_transform_observers */ \
0.0, /* x_resolution */ \
0.0, /* y_resolution */ \
0.0, /* x_fallback_resolution */ \
0.0, /* y_fallback_resolution */ \
NULL, /* snapshot_of */ \
NULL, /* snapshot_detach */ \
{ NULL, NULL }, /* snapshots */ \
{ NULL, NULL }, /* snapshot */ \
{ CAIRO_ANTIALIAS_DEFAULT, /* antialias */ \
CAIRO_SUBPIXEL_ORDER_DEFAULT, /* subpixel_order */ \
CAIRO_LCD_FILTER_DEFAULT, /* lcd_filter */ \
CAIRO_HINT_STYLE_DEFAULT, /* hint_style */ \
CAIRO_HINT_METRICS_DEFAULT /* hint_metrics */ \
} /* font_options */ \
}
 
/* XXX error object! */
 
static DEFINE_NIL_SURFACE(CAIRO_STATUS_NO_MEMORY, _cairo_surface_nil);
static DEFINE_NIL_SURFACE(CAIRO_STATUS_SURFACE_TYPE_MISMATCH, _cairo_surface_nil_surface_type_mismatch);
static DEFINE_NIL_SURFACE(CAIRO_STATUS_INVALID_STATUS, _cairo_surface_nil_invalid_status);
static DEFINE_NIL_SURFACE(CAIRO_STATUS_INVALID_CONTENT, _cairo_surface_nil_invalid_content);
static DEFINE_NIL_SURFACE(CAIRO_STATUS_INVALID_FORMAT, _cairo_surface_nil_invalid_format);
static DEFINE_NIL_SURFACE(CAIRO_STATUS_INVALID_VISUAL, _cairo_surface_nil_invalid_visual);
static DEFINE_NIL_SURFACE(CAIRO_STATUS_FILE_NOT_FOUND, _cairo_surface_nil_file_not_found);
static DEFINE_NIL_SURFACE(CAIRO_STATUS_TEMP_FILE_ERROR, _cairo_surface_nil_temp_file_error);
static DEFINE_NIL_SURFACE(CAIRO_STATUS_READ_ERROR, _cairo_surface_nil_read_error);
static DEFINE_NIL_SURFACE(CAIRO_STATUS_WRITE_ERROR, _cairo_surface_nil_write_error);
static DEFINE_NIL_SURFACE(CAIRO_STATUS_INVALID_STRIDE, _cairo_surface_nil_invalid_stride);
static DEFINE_NIL_SURFACE(CAIRO_STATUS_INVALID_SIZE, _cairo_surface_nil_invalid_size);
static DEFINE_NIL_SURFACE(CAIRO_STATUS_DEVICE_TYPE_MISMATCH, _cairo_surface_nil_device_type_mismatch);
static DEFINE_NIL_SURFACE(CAIRO_STATUS_DEVICE_ERROR, _cairo_surface_nil_device_error);
 
/**
* _cairo_surface_set_error:
* @surface: a surface
* @status: a status value indicating an error
*
* Atomically sets surface->status to @status and calls _cairo_error;
* Does nothing if status is %CAIRO_STATUS_SUCCESS or any of the internal
* status values.
*
* All assignments of an error status to surface->status should happen
* through _cairo_surface_set_error(). Note that due to the nature of
* 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
* breakpoint in _cairo_error() to generate a stack trace for when the
* user causes cairo to detect an error.
*
* Return value: the error status.
**/
cairo_status_t
_cairo_surface_set_error (cairo_surface_t *surface,
cairo_status_t status)
{
if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
status = CAIRO_STATUS_SUCCESS;
 
if (status == CAIRO_STATUS_SUCCESS || status >= CAIRO_INT_STATUS_UNSUPPORTED)
return 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);
}
 
/**
* cairo_surface_get_type:
* @surface: a #cairo_surface_t
*
* This function returns the type of the backend used to create
* a surface. See #cairo_surface_type_t for available types.
*
* Return value: The type of @surface.
*
* Since: 1.2
**/
cairo_surface_type_t
cairo_surface_get_type (cairo_surface_t *surface)
{
/* We don't use surface->backend->type here so that some of the
* special "wrapper" surfaces such as cairo_paginated_surface_t
* can override surface->type with the type of the "child"
* surface. */
return surface->type;
}
slim_hidden_def (cairo_surface_get_type);
 
/**
* cairo_surface_get_content:
* @surface: a #cairo_surface_t
*
* This function returns the content type of @surface which indicates
* whether the surface contains color and/or alpha information. See
* #cairo_content_t.
*
* Return value: The content type of @surface.
*
* Since: 1.2
**/
cairo_content_t
cairo_surface_get_content (cairo_surface_t *surface)
{
return surface->content;
}
slim_hidden_def(cairo_surface_get_content);
 
/**
* cairo_surface_status:
* @surface: a #cairo_surface_t
*
* Checks whether an error has previously occurred for this
* surface.
*
* Return value: %CAIRO_STATUS_SUCCESS, %CAIRO_STATUS_NULL_POINTER,
* %CAIRO_STATUS_NO_MEMORY, %CAIRO_STATUS_READ_ERROR,
* %CAIRO_STATUS_INVALID_CONTENT, %CAIRO_STATUS_INVALID_FORMAT, or
* %CAIRO_STATUS_INVALID_VISUAL.
**/
cairo_status_t
cairo_surface_status (cairo_surface_t *surface)
{
return surface->status;
}
slim_hidden_def (cairo_surface_status);
 
static unsigned int
_cairo_surface_allocate_unique_id (void)
{
static cairo_atomic_int_t unique_id;
 
#if CAIRO_NO_MUTEX
if (++unique_id == 0)
unique_id = 1;
return unique_id;
#else
cairo_atomic_int_t old, id;
 
do {
old = _cairo_atomic_uint_get (&unique_id);
id = old + 1;
if (id == 0)
id = 1;
} while (! _cairo_atomic_uint_cmpxchg (&unique_id, old, id));
 
return id;
#endif
}
 
/**
* cairo_surface_get_device:
* @surface: a #cairo_surface_t
*
* This function returns the device for a @surface.
* See #cairo_device_t.
*
* Return value: The device for @surface or %NULL if the surface does
* not have an associated device.
*
* Since: 1.10
**/
cairo_device_t *
cairo_surface_get_device (cairo_surface_t *surface)
{
if (unlikely (surface->status))
return _cairo_device_create_in_error (surface->status);
 
return surface->device;
}
 
static cairo_bool_t
_cairo_surface_has_snapshots (cairo_surface_t *surface)
{
return ! cairo_list_is_empty (&surface->snapshots);
}
 
static cairo_bool_t
_cairo_surface_has_mime_data (cairo_surface_t *surface)
{
return surface->mime_data.num_elements != 0;
}
 
static void
_cairo_surface_detach_mime_data (cairo_surface_t *surface)
{
if (! _cairo_surface_has_mime_data (surface))
return;
 
_cairo_user_data_array_fini (&surface->mime_data);
_cairo_user_data_array_init (&surface->mime_data);
}
 
static void
_cairo_surface_detach_snapshots (cairo_surface_t *surface)
{
while (_cairo_surface_has_snapshots (surface)) {
_cairo_surface_detach_snapshot (cairo_list_first_entry (&surface->snapshots,
cairo_surface_t,
snapshot));
}
}
 
void
_cairo_surface_detach_snapshot (cairo_surface_t *snapshot)
{
assert (snapshot->snapshot_of != NULL);
 
snapshot->snapshot_of = NULL;
cairo_list_del (&snapshot->snapshot);
 
if (snapshot->snapshot_detach != NULL)
snapshot->snapshot_detach (snapshot);
 
cairo_surface_destroy (snapshot);
}
 
void
_cairo_surface_attach_snapshot (cairo_surface_t *surface,
cairo_surface_t *snapshot,
cairo_surface_func_t detach_func)
{
assert (surface != snapshot);
assert (snapshot->snapshot_of != surface);
 
cairo_surface_reference (snapshot);
 
if (snapshot->snapshot_of != NULL)
_cairo_surface_detach_snapshot (snapshot);
 
snapshot->snapshot_of = surface;
snapshot->snapshot_detach = detach_func;
 
cairo_list_add (&snapshot->snapshot, &surface->snapshots);
 
assert (_cairo_surface_has_snapshot (surface, snapshot->backend) == snapshot);
}
 
cairo_surface_t *
_cairo_surface_has_snapshot (cairo_surface_t *surface,
const cairo_surface_backend_t *backend)
{
cairo_surface_t *snapshot;
 
cairo_list_foreach_entry (snapshot, cairo_surface_t,
&surface->snapshots, snapshot)
{
/* XXX is_similar? */
if (snapshot->backend == backend)
return snapshot;
}
 
return NULL;
}
 
static cairo_bool_t
_cairo_surface_is_writable (cairo_surface_t *surface)
{
return ! surface->finished &&
surface->snapshot_of == NULL &&
! _cairo_surface_has_snapshots (surface) &&
! _cairo_surface_has_mime_data (surface);
}
 
static void
_cairo_surface_begin_modification (cairo_surface_t *surface)
{
assert (surface->status == CAIRO_STATUS_SUCCESS);
assert (! surface->finished);
assert (surface->snapshot_of == NULL);
 
_cairo_surface_detach_snapshots (surface);
_cairo_surface_detach_mime_data (surface);
}
 
void
_cairo_surface_init (cairo_surface_t *surface,
const cairo_surface_backend_t *backend,
cairo_device_t *device,
cairo_content_t content)
{
CAIRO_MUTEX_INITIALIZE ();
 
surface->backend = backend;
surface->device = cairo_device_reference (device);
surface->content = content;
surface->type = backend->type;
 
CAIRO_REFERENCE_COUNT_INIT (&surface->ref_count, 1);
surface->status = CAIRO_STATUS_SUCCESS;
surface->unique_id = _cairo_surface_allocate_unique_id ();
surface->finished = FALSE;
surface->is_clear = FALSE;
surface->owns_device = (device != NULL);
 
_cairo_user_data_array_init (&surface->user_data);
_cairo_user_data_array_init (&surface->mime_data);
 
cairo_matrix_init_identity (&surface->device_transform);
cairo_matrix_init_identity (&surface->device_transform_inverse);
cairo_list_init (&surface->device_transform_observers);
 
surface->x_resolution = CAIRO_SURFACE_RESOLUTION_DEFAULT;
surface->y_resolution = CAIRO_SURFACE_RESOLUTION_DEFAULT;
 
surface->x_fallback_resolution = CAIRO_SURFACE_FALLBACK_RESOLUTION_DEFAULT;
surface->y_fallback_resolution = CAIRO_SURFACE_FALLBACK_RESOLUTION_DEFAULT;
 
cairo_list_init (&surface->snapshots);
surface->snapshot_of = NULL;
 
surface->has_font_options = FALSE;
}
 
static void
_cairo_surface_copy_similar_properties (cairo_surface_t *surface,
cairo_surface_t *other)
{
if (other->has_font_options || other->backend != surface->backend) {
cairo_font_options_t options;
 
cairo_surface_get_font_options (other, &options);
_cairo_surface_set_font_options (surface, &options);
}
 
cairo_surface_set_fallback_resolution (surface,
other->x_fallback_resolution,
other->y_fallback_resolution);
}
 
cairo_surface_t *
_cairo_surface_create_similar_scratch (cairo_surface_t *other,
cairo_content_t content,
int width,
int height)
{
cairo_surface_t *surface;
 
if (unlikely (other->status))
return _cairo_surface_create_in_error (other->status);
 
if (other->backend->create_similar == NULL)
return NULL;
 
surface = other->backend->create_similar (other,
content, width, height);
if (surface == NULL || surface->status)
return surface;
 
_cairo_surface_copy_similar_properties (surface, other);
 
return surface;
}
 
/**
* cairo_surface_create_similar:
* @other: an existing surface used to select the backend of the new surface
* @content: the content for the new surface
* @width: width of the new surface, (in device-space units)
* @height: height of the new surface (in device-space units)
*
* Create a new surface that is as compatible as possible with an
* existing surface. For example the new surface will have the same
* fallback resolution and font options as @other. Generally, the new
* surface will also use the same backend as @other, unless that is
* not possible for some reason. The type of the returned surface may
* be examined with cairo_surface_get_type().
*
* Initially the surface contents are all 0 (transparent if contents
* have transparency, black otherwise.)
*
* Return value: a pointer to the newly allocated surface. The caller
* owns the surface and should call cairo_surface_destroy() when done
* with it.
*
* This function always returns a valid pointer, but it will return a
* pointer to a "nil" surface if @other is already in an error state
* or any other error occurs.
**/
cairo_surface_t *
cairo_surface_create_similar (cairo_surface_t *other,
cairo_content_t content,
int width,
int height)
{
if (unlikely (other->status))
return _cairo_surface_create_in_error (other->status);
if (unlikely (other->finished))
return _cairo_surface_create_in_error (CAIRO_STATUS_SURFACE_FINISHED);
 
if (unlikely (! CAIRO_CONTENT_VALID (content)))
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_CONTENT));
 
return _cairo_surface_create_similar_solid (other,
content, width, height,
CAIRO_COLOR_TRANSPARENT,
TRUE);
}
 
cairo_surface_t *
_cairo_surface_create_similar_solid (cairo_surface_t *other,
cairo_content_t content,
int width,
int height,
const cairo_color_t *color,
cairo_bool_t allow_fallback)
{
cairo_status_t status;
cairo_surface_t *surface;
cairo_solid_pattern_t pattern;
 
surface = _cairo_surface_create_similar_scratch (other, content,
width, height);
if (surface == NULL && allow_fallback)
surface = _cairo_image_surface_create_with_content (content,
width, height);
if (surface == NULL || surface->status)
return surface;
 
_cairo_pattern_init_solid (&pattern, color);
status = _cairo_surface_paint (surface,
color == CAIRO_COLOR_TRANSPARENT ?
CAIRO_OPERATOR_CLEAR : CAIRO_OPERATOR_SOURCE,
&pattern.base, NULL);
if (unlikely (status)) {
cairo_surface_destroy (surface);
surface = _cairo_surface_create_in_error (status);
}
 
return surface;
}
 
cairo_surface_t *
_cairo_surface_create_solid_pattern_surface (cairo_surface_t *other,
const cairo_solid_pattern_t *solid_pattern)
{
if (other->backend->create_solid_pattern_surface != NULL) {
cairo_surface_t *surface;
 
surface = other->backend->create_solid_pattern_surface (other,
solid_pattern);
if (surface)
return surface;
}
 
return _cairo_surface_create_similar_solid (other,
_cairo_color_get_content (&solid_pattern->color),
1, 1,
&solid_pattern->color,
FALSE);
}
 
cairo_int_status_t
_cairo_surface_repaint_solid_pattern_surface (cairo_surface_t *other,
cairo_surface_t *solid_surface,
const cairo_solid_pattern_t *solid_pattern)
{
/* Solid pattern surface for these backends are special and not trivial
* to repaint. Skip repainting.
*
* This does not work optimally with things like analysis surface that
* are proxies. But returning UNSUPPORTED is *safe* as it only
* disables some caching.
*/
if (other->backend->create_solid_pattern_surface != NULL &&
! other->backend->can_repaint_solid_pattern_surface (solid_surface,
solid_pattern))
{
return CAIRO_INT_STATUS_UNSUPPORTED;
}
 
return _cairo_surface_paint (solid_surface,
CAIRO_OPERATOR_SOURCE,
&solid_pattern->base,
NULL);
}
 
/**
* cairo_surface_reference:
* @surface: a #cairo_surface_t
*
* Increases the reference count on @surface by one. This prevents
* @surface from being destroyed until a matching call to
* cairo_surface_destroy() is made.
*
* The number of references to a #cairo_surface_t can be get using
* cairo_surface_get_reference_count().
*
* Return value: the referenced #cairo_surface_t.
**/
cairo_surface_t *
cairo_surface_reference (cairo_surface_t *surface)
{
if (surface == NULL ||
CAIRO_REFERENCE_COUNT_IS_INVALID (&surface->ref_count))
return surface;
 
assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&surface->ref_count));
 
_cairo_reference_count_inc (&surface->ref_count);
 
return surface;
}
slim_hidden_def (cairo_surface_reference);
 
/**
* cairo_surface_destroy:
* @surface: a #cairo_surface_t
*
* Decreases the reference count on @surface by one. If the result is
* zero, then @surface and all associated resources are freed. See
* cairo_surface_reference().
**/
void
cairo_surface_destroy (cairo_surface_t *surface)
{
if (surface == NULL ||
CAIRO_REFERENCE_COUNT_IS_INVALID (&surface->ref_count))
return;
 
assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&surface->ref_count));
 
if (! _cairo_reference_count_dec_and_test (&surface->ref_count))
return;
 
assert (surface->snapshot_of == NULL);
 
if (! surface->finished)
cairo_surface_finish (surface);
 
/* paranoid check that nobody took a reference whilst finishing */
assert (! CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&surface->ref_count));
 
_cairo_user_data_array_fini (&surface->user_data);
_cairo_user_data_array_fini (&surface->mime_data);
 
if (surface->owns_device)
cairo_device_destroy (surface->device);
 
free (surface);
}
slim_hidden_def(cairo_surface_destroy);
 
/**
* cairo_surface_get_reference_count:
* @surface: a #cairo_surface_t
*
* Returns the current reference count of @surface.
*
* Return value: the current reference count of @surface. If the
* object is a nil object, 0 will be returned.
*
* Since: 1.4
**/
unsigned int
cairo_surface_get_reference_count (cairo_surface_t *surface)
{
if (surface == NULL ||
CAIRO_REFERENCE_COUNT_IS_INVALID (&surface->ref_count))
return 0;
 
return CAIRO_REFERENCE_COUNT_GET_VALUE (&surface->ref_count);
}
 
/**
* cairo_surface_finish:
* @surface: the #cairo_surface_t to finish
*
* This function finishes the surface and drops all references to
* external resources. For example, for the Xlib backend it means
* that cairo will no longer access the drawable, which can be freed.
* After calling cairo_surface_finish() the only valid operations on a
* surface are getting and setting user, referencing and
* destroying, and flushing and finishing it.
* Further drawing to the surface will not affect the
* surface but will instead trigger a %CAIRO_STATUS_SURFACE_FINISHED
* error.
*
* When the last call to cairo_surface_destroy() decreases the
* reference count to zero, cairo will call cairo_surface_finish() if
* it hasn't been called already, before freeing the resources
* associated with the surface.
**/
void
cairo_surface_finish (cairo_surface_t *surface)
{
cairo_status_t status;
 
if (surface == NULL)
return;
 
if (CAIRO_REFERENCE_COUNT_IS_INVALID (&surface->ref_count))
return;
 
if (surface->finished)
return;
 
/* update the snapshots *before* we declare the surface as finished */
_cairo_surface_detach_snapshots (surface);
if (surface->snapshot_of != NULL)
_cairo_surface_detach_snapshot (surface);
 
cairo_surface_flush (surface);
surface->finished = TRUE;
 
/* call finish even if in error mode */
if (surface->backend->finish) {
status = surface->backend->finish (surface);
if (unlikely (status))
status = _cairo_surface_set_error (surface, status);
}
}
slim_hidden_def (cairo_surface_finish);
 
/**
* _cairo_surface_release_device_reference:
* @surface: a #cairo_surface_t
*
* This function makes @surface release the reference to its device. The
* function is intended to be used for avoiding cycling references for
* surfaces that are owned by their device, for example cache surfaces.
* Note that the @surface will still assume that the device is available.
* So it is the caller's responsibility to ensure the device stays around
* until the @surface is destroyed. Just calling cairo_surface_finish() is
* not enough.
**/
void
_cairo_surface_release_device_reference (cairo_surface_t *surface)
{
assert (surface->owns_device);
 
cairo_device_destroy (surface->device);
surface->owns_device = FALSE;
}
 
/**
* cairo_surface_get_user_data:
* @surface: a #cairo_surface_t
* @key: the address of the #cairo_user_data_key_t the user data was
* attached to
*
* Return user data previously attached to @surface using the specified
* key. If no user data has been attached with the given key this
* function returns %NULL.
*
* Return value: the user data previously attached or %NULL.
**/
void *
cairo_surface_get_user_data (cairo_surface_t *surface,
const cairo_user_data_key_t *key)
{
return _cairo_user_data_array_get_data (&surface->user_data,
key);
}
 
/**
* cairo_surface_set_user_data:
* @surface: a #cairo_surface_t
* @key: the address of a #cairo_user_data_key_t to attach the user data to
* @user_data: the user data to attach to the surface
* @destroy: a #cairo_destroy_func_t which will be called when the
* surface is destroyed or when new user data is attached using the
* same key.
*
* Attach user data to @surface. To remove user data from a surface,
* call this function with the key that was used to set it and %NULL
* for @data.
*
* Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY if a
* slot could not be allocated for the user data.
**/
cairo_status_t
cairo_surface_set_user_data (cairo_surface_t *surface,
const cairo_user_data_key_t *key,
void *user_data,
cairo_destroy_func_t destroy)
{
if (CAIRO_REFERENCE_COUNT_IS_INVALID (&surface->ref_count))
return surface->status;
 
return _cairo_user_data_array_set_data (&surface->user_data,
key, user_data, destroy);
}
 
/**
* cairo_surface_get_mime_data:
* @surface: a #cairo_surface_t
* @mime_type: the mime type of the image data
* @data: the image data to attached to the surface
* @length: the length of the image data
*
* Return mime data previously attached to @surface using the
* specified mime type. If no data has been attached with the given
* mime type, @data is set %NULL.
*
* Since: 1.10
**/
void
cairo_surface_get_mime_data (cairo_surface_t *surface,
const char *mime_type,
const unsigned char **data,
unsigned long *length)
{
cairo_user_data_slot_t *slots;
int i, num_slots;
 
*data = NULL;
*length = 0;
if (unlikely (surface->status))
return;
 
/* The number of mime-types attached to a surface is usually small,
* typically zero. Therefore it is quicker to do a strcmp() against
* each key than it is to intern the string (i.e. compute a hash,
* search the hash table, and do a final strcmp).
*/
num_slots = surface->mime_data.num_elements;
slots = _cairo_array_index (&surface->mime_data, 0);
for (i = 0; i < num_slots; i++) {
if (strcmp ((char *) slots[i].key, mime_type) == 0) {
cairo_mime_data_t *mime_data = slots[i].user_data;
 
*data = mime_data->data;
*length = mime_data->length;
return;
}
}
}
slim_hidden_def (cairo_surface_get_mime_data);
 
static void
_cairo_mime_data_destroy (void *ptr)
{
cairo_mime_data_t *mime_data = ptr;
 
if (! _cairo_reference_count_dec_and_test (&mime_data->ref_count))
return;
 
if (mime_data->destroy && mime_data->closure)
mime_data->destroy (mime_data->closure);
 
free (mime_data);
}
 
/**
* CAIRO_MIME_TYPE_JP2:
*
* The Joint Photographic Experts Group (JPEG) 2000 image coding standard (ISO/IEC 15444-1).
*
* @Since: 1.10
*/
 
/**
* CAIRO_MIME_TYPE_JPEG:
*
* The Joint Photographic Experts Group (JPEG) image coding standard (ISO/IEC 10918-1).
*
* @Since: 1.10
*/
 
/**
* CAIRO_MIME_TYPE_PNG:
*
* The Portable Network Graphics image file format (ISO/IEC 15948).
*
* @Since: 1.10
*/
 
/**
* CAIRO_MIME_TYPE_URI:
*
* URI for an image file (unofficial MIME type).
*
* @Since: 1.10
*/
 
/**
* cairo_surface_set_mime_data:
* @surface: a #cairo_surface_t
* @mime_type: the MIME type of the image data
* @data: the image data to attach to the surface
* @length: the length of the image data
* @destroy: a #cairo_destroy_func_t which will be called when the
* surface is destroyed or when new image data is attached using the
* same mime type.
* @closure: the data to be passed to the @destroy notifier
*
* Attach an image in the format @mime_type to @surface. To remove
* the data from a surface, call this function with same mime type
* and %NULL for @data.
*
* The attached image (or filename) data can later be used by backends
* which support it (currently: PDF, PS, SVG and Win32 Printing
* surfaces) to emit this data instead of making a snapshot of the
* @surface. This approach tends to be faster and requires less
* memory and disk space.
*
* The recognized MIME types are the following: %CAIRO_MIME_TYPE_JPEG,
* %CAIRO_MIME_TYPE_PNG, %CAIRO_MIME_TYPE_JP2, %CAIRO_MIME_TYPE_URI.
*
* See corresponding backend surface docs for details about which MIME
* types it can handle. Caution: the associated MIME data will be
* discarded if you draw on the surface afterwards. Use this function
* with care.
*
* Since: 1.10
*
* Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY if a
* slot could not be allocated for the user data.
**/
cairo_status_t
cairo_surface_set_mime_data (cairo_surface_t *surface,
const char *mime_type,
const unsigned char *data,
unsigned long length,
cairo_destroy_func_t destroy,
void *closure)
{
cairo_status_t status;
cairo_mime_data_t *mime_data;
 
if (unlikely (surface->status))
return surface->status;
if (surface->finished)
return _cairo_surface_set_error (surface, _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
 
status = _cairo_intern_string (&mime_type, -1);
if (unlikely (status))
return _cairo_surface_set_error (surface, status);
 
if (data != NULL) {
mime_data = malloc (sizeof (cairo_mime_data_t));
if (unlikely (mime_data == NULL))
return _cairo_surface_set_error (surface, _cairo_error (CAIRO_STATUS_NO_MEMORY));
 
CAIRO_REFERENCE_COUNT_INIT (&mime_data->ref_count, 1);
 
mime_data->data = (unsigned char *) data;
mime_data->length = length;
mime_data->destroy = destroy;
mime_data->closure = closure;
} else
mime_data = NULL;
 
status = _cairo_user_data_array_set_data (&surface->mime_data,
(cairo_user_data_key_t *) mime_type,
mime_data,
_cairo_mime_data_destroy);
if (unlikely (status)) {
if (mime_data != NULL)
free (mime_data);
 
return _cairo_surface_set_error (surface, status);
}
 
return CAIRO_STATUS_SUCCESS;
}
slim_hidden_def (cairo_surface_set_mime_data);
 
static void
_cairo_mime_data_reference (const void *key, void *elt, void *closure)
{
cairo_mime_data_t *mime_data = elt;
 
_cairo_reference_count_inc (&mime_data->ref_count);
}
 
cairo_status_t
_cairo_surface_copy_mime_data (cairo_surface_t *dst,
cairo_surface_t *src)
{
cairo_status_t status;
 
if (dst->status)
return dst->status;
 
if (src->status)
return _cairo_surface_set_error (dst, src->status);
 
/* first copy the mime-data, discarding any already set on dst */
status = _cairo_user_data_array_copy (&dst->mime_data, &src->mime_data);
if (unlikely (status))
return _cairo_surface_set_error (dst, status);
 
/* now increment the reference counters for the copies */
_cairo_user_data_array_foreach (&dst->mime_data,
_cairo_mime_data_reference,
NULL);
 
return CAIRO_STATUS_SUCCESS;
}
 
/**
* _cairo_surface_set_font_options:
* @surface: a #cairo_surface_t
* @options: a #cairo_font_options_t object that contains the
* options to use for this surface instead of backend's default
* font options.
*
* Sets the default font rendering options for the surface.
* This is useful to correctly propagate default font options when
* falling back to an image surface in a backend implementation.
* This affects the options returned in cairo_surface_get_font_options().
*
* If @options is %NULL the surface options are reset to those of
* the backend default.
**/
void
_cairo_surface_set_font_options (cairo_surface_t *surface,
cairo_font_options_t *options)
{
cairo_status_t status;
 
if (surface->status)
return;
 
assert (surface->snapshot_of == NULL);
 
if (surface->finished) {
status = _cairo_surface_set_error (surface,
_cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
return;
}
 
if (options) {
surface->has_font_options = TRUE;
_cairo_font_options_init_copy (&surface->font_options, options);
} else {
surface->has_font_options = FALSE;
}
}
 
/**
* cairo_surface_get_font_options:
* @surface: a #cairo_surface_t
* @options: a #cairo_font_options_t object into which to store
* the retrieved options. All existing values are overwritten
*
* Retrieves the default font rendering options for the surface.
* This allows display surfaces to report the correct subpixel order
* for rendering on them, print surfaces to disable hinting of
* metrics and so forth. The result can then be used with
* cairo_scaled_font_create().
**/
void
cairo_surface_get_font_options (cairo_surface_t *surface,
cairo_font_options_t *options)
{
if (cairo_font_options_status (options))
return;
 
if (surface->status) {
_cairo_font_options_init_default (options);
return;
}
 
if (! surface->has_font_options) {
surface->has_font_options = TRUE;
 
_cairo_font_options_init_default (&surface->font_options);
 
if (!surface->finished && surface->backend->get_font_options) {
surface->backend->get_font_options (surface, &surface->font_options);
}
}
 
_cairo_font_options_init_copy (options, &surface->font_options);
}
slim_hidden_def (cairo_surface_get_font_options);
 
/**
* cairo_surface_flush:
* @surface: a #cairo_surface_t
*
* Do any pending drawing for the surface and also restore any
* temporary modifications cairo has made to the surface's
* state. This function must be called before switching from
* drawing on the surface with cairo to drawing on it directly
* with native APIs. If the surface doesn't support direct access,
* then this function does nothing.
**/
void
cairo_surface_flush (cairo_surface_t *surface)
{
cairo_status_t status;
 
if (surface->status)
return;
 
if (surface->finished)
return;
 
/* update the current snapshots *before* the user updates the surface */
_cairo_surface_detach_snapshots (surface);
 
if (surface->backend->flush) {
status = surface->backend->flush (surface);
if (unlikely (status))
status = _cairo_surface_set_error (surface, status);
}
}
slim_hidden_def (cairo_surface_flush);
 
/**
* cairo_surface_mark_dirty:
* @surface: a #cairo_surface_t
*
* Tells cairo that drawing has been done to surface using means other
* than cairo, and that cairo should reread any cached areas. Note
* that you must call cairo_surface_flush() before doing such drawing.
*/
void
cairo_surface_mark_dirty (cairo_surface_t *surface)
{
cairo_surface_mark_dirty_rectangle (surface, 0, 0, -1, -1);
}
slim_hidden_def (cairo_surface_mark_dirty);
 
/**
* cairo_surface_mark_dirty_rectangle:
* @surface: a #cairo_surface_t
* @x: X coordinate of dirty rectangle
* @y: Y coordinate of dirty rectangle
* @width: width of dirty rectangle
* @height: height of dirty rectangle
*
* Like cairo_surface_mark_dirty(), but drawing has been done only to
* the specified rectangle, so that cairo can retain cached contents
* for other parts of the surface.
*
* Any cached clip set on the surface will be reset by this function,
* to make sure that future cairo calls have the clip set that they
* expect.
*/
void
cairo_surface_mark_dirty_rectangle (cairo_surface_t *surface,
int x,
int y,
int width,
int height)
{
cairo_status_t status;
 
if (surface->status)
return;
 
assert (surface->snapshot_of == NULL);
 
if (surface->finished) {
status = _cairo_surface_set_error (surface, _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
return;
}
 
/* The application *should* have called cairo_surface_flush() before
* modifying the surface independently of cairo (and thus having to
* call mark_dirty()). */
assert (! _cairo_surface_has_snapshots (surface));
assert (! _cairo_surface_has_mime_data (surface));
 
surface->is_clear = FALSE;
 
if (surface->backend->mark_dirty_rectangle != NULL) {
/* XXX: FRAGILE: We're ignoring the scaling component of
* device_transform here. I don't know what the right thing to
* do would actually be if there were some scaling here, but
* we avoid this since device_transfom scaling is not exported
* publicly and mark_dirty is not used internally. */
status = surface->backend->mark_dirty_rectangle (surface,
x + surface->device_transform.x0,
y + surface->device_transform.y0,
width, height);
 
if (unlikely (status))
status = _cairo_surface_set_error (surface, status);
}
}
slim_hidden_def (cairo_surface_mark_dirty_rectangle);
 
/**
* _cairo_surface_set_device_scale:
* @surface: a #cairo_surface_t
* @sx: a scale factor in the X direction
* @sy: a scale factor in the Y direction
*
* Private function for setting an extra scale factor to affect all
* drawing to a surface. This is used, for example, when replaying a
* recording surface to an image fallback intended for an eventual
* vector-oriented backend. Since the recording surface will record
* coordinates in one backend space, but the image fallback uses a
* different backend space, (differing by the fallback resolution
* scale factors), we need a scale factor correction.
*
* Caution: Not all places we use device transform correctly handle
* both a translate and a scale. An audit would be nice.
**/
void
_cairo_surface_set_device_scale (cairo_surface_t *surface,
double sx,
double sy)
{
cairo_status_t status;
 
if (surface->status)
return;
 
assert (surface->snapshot_of == NULL);
 
if (surface->finished) {
status = _cairo_surface_set_error (surface, _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
return;
}
 
_cairo_surface_begin_modification (surface);
 
surface->device_transform.xx = sx;
surface->device_transform.yy = sy;
surface->device_transform.xy = 0.0;
surface->device_transform.yx = 0.0;
 
surface->device_transform_inverse = surface->device_transform;
status = cairo_matrix_invert (&surface->device_transform_inverse);
/* should always be invertible unless given pathological input */
assert (status == CAIRO_STATUS_SUCCESS);
 
_cairo_observers_notify (&surface->device_transform_observers, surface);
}
 
/**
* cairo_surface_set_device_offset:
* @surface: a #cairo_surface_t
* @x_offset: the offset in the X direction, in device units
* @y_offset: the offset in the Y direction, in device units
*
* Sets an offset that is added to the device coordinates determined
* by the CTM when drawing to @surface. One use case for this function
* is when we want to create a #cairo_surface_t that redirects drawing
* for a portion of an onscreen surface to an offscreen surface in a
* way that is completely invisible to the user of the cairo
* API. Setting a transformation via cairo_translate() isn't
* sufficient to do this, since functions like
* cairo_device_to_user() will expose the hidden offset.
*
* Note that the offset affects drawing to the surface as well as
* using the surface in a source pattern.
**/
void
cairo_surface_set_device_offset (cairo_surface_t *surface,
double x_offset,
double y_offset)
{
cairo_status_t status;
 
if (surface->status)
return;
 
assert (surface->snapshot_of == NULL);
 
if (surface->finished) {
status = _cairo_surface_set_error (surface, _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
return;
}
 
_cairo_surface_begin_modification (surface);
 
surface->device_transform.x0 = x_offset;
surface->device_transform.y0 = y_offset;
 
surface->device_transform_inverse = surface->device_transform;
status = cairo_matrix_invert (&surface->device_transform_inverse);
/* should always be invertible unless given pathological input */
assert (status == CAIRO_STATUS_SUCCESS);
 
_cairo_observers_notify (&surface->device_transform_observers, surface);
}
slim_hidden_def (cairo_surface_set_device_offset);
 
/**
* cairo_surface_get_device_offset:
* @surface: a #cairo_surface_t
* @x_offset: the offset in the X direction, in device units
* @y_offset: the offset in the Y direction, in device units
*
* This function returns the previous device offset set by
* cairo_surface_set_device_offset().
*
* Since: 1.2
**/
void
cairo_surface_get_device_offset (cairo_surface_t *surface,
double *x_offset,
double *y_offset)
{
if (x_offset)
*x_offset = surface->device_transform.x0;
if (y_offset)
*y_offset = surface->device_transform.y0;
}
slim_hidden_def (cairo_surface_get_device_offset);
 
/**
* cairo_surface_set_fallback_resolution:
* @surface: a #cairo_surface_t
* @x_pixels_per_inch: horizontal setting for pixels per inch
* @y_pixels_per_inch: vertical setting for pixels per inch
*
* Set the horizontal and vertical resolution for image fallbacks.
*
* When certain operations aren't supported natively by a backend,
* cairo will fallback by rendering operations to an image and then
* overlaying that image onto the output. For backends that are
* natively vector-oriented, this function can be used to set the
* resolution used for these image fallbacks, (larger values will
* result in more detailed images, but also larger file sizes).
*
* Some examples of natively vector-oriented backends are the ps, pdf,
* and svg backends.
*
* For backends that are natively raster-oriented, image fallbacks are
* still possible, but they are always performed at the native
* device resolution. So this function has no effect on those
* backends.
*
* Note: The fallback resolution only takes effect at the time of
* completing a page (with cairo_show_page() or cairo_copy_page()) so
* there is currently no way to have more than one fallback resolution
* in effect on a single page.
*
* The default fallback resoultion is 300 pixels per inch in both
* dimensions.
*
* Since: 1.2
**/
void
cairo_surface_set_fallback_resolution (cairo_surface_t *surface,
double x_pixels_per_inch,
double y_pixels_per_inch)
{
cairo_status_t status;
 
if (surface->status)
return;
 
assert (surface->snapshot_of == NULL);
 
if (surface->finished) {
status = _cairo_surface_set_error (surface, _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
return;
}
 
if (x_pixels_per_inch <= 0 || y_pixels_per_inch <= 0) {
/* XXX Could delay raising the error until we fallback, but throwing
* the error here means that we can catch the real culprit.
*/
status = _cairo_surface_set_error (surface, CAIRO_STATUS_INVALID_MATRIX);
return;
}
 
_cairo_surface_begin_modification (surface);
 
surface->x_fallback_resolution = x_pixels_per_inch;
surface->y_fallback_resolution = y_pixels_per_inch;
}
slim_hidden_def (cairo_surface_set_fallback_resolution);
 
/**
* cairo_surface_get_fallback_resolution:
* @surface: a #cairo_surface_t
* @x_pixels_per_inch: horizontal pixels per inch
* @y_pixels_per_inch: vertical pixels per inch
*
* This function returns the previous fallback resolution set by
* cairo_surface_set_fallback_resolution(), or default fallback
* resolution if never set.
*
* Since: 1.8
**/
void
cairo_surface_get_fallback_resolution (cairo_surface_t *surface,
double *x_pixels_per_inch,
double *y_pixels_per_inch)
{
if (x_pixels_per_inch)
*x_pixels_per_inch = surface->x_fallback_resolution;
if (y_pixels_per_inch)
*y_pixels_per_inch = surface->y_fallback_resolution;
}
 
cairo_bool_t
_cairo_surface_has_device_transform (cairo_surface_t *surface)
{
return ! _cairo_matrix_is_identity (&surface->device_transform);
}
 
/**
* _cairo_surface_acquire_source_image:
* @surface: a #cairo_surface_t
* @image_out: location to store a pointer to an image surface that
* has identical contents to @surface. This surface could be @surface
* itself, a surface held internal to @surface, or it could be a new
* surface with a copy of the relevant portion of @surface.
* @image_extra: location to store image specific backend data
*
* Gets an image surface to use when drawing as a fallback when drawing with
* @surface as a source. _cairo_surface_release_source_image() must be called
* when finished.
*
* Return value: %CAIRO_STATUS_SUCCESS if an image was stored in @image_out.
* %CAIRO_INT_STATUS_UNSUPPORTED if an image cannot be retrieved for the specified
* surface. Or %CAIRO_STATUS_NO_MEMORY.
**/
cairo_status_t
_cairo_surface_acquire_source_image (cairo_surface_t *surface,
cairo_image_surface_t **image_out,
void **image_extra)
{
cairo_status_t status;
 
if (surface->status)
return surface->status;
 
assert (!surface->finished);
 
if (surface->backend->acquire_source_image == NULL)
return CAIRO_INT_STATUS_UNSUPPORTED;
 
status = surface->backend->acquire_source_image (surface,
image_out, image_extra);
if (unlikely (status))
return _cairo_surface_set_error (surface, status);
 
_cairo_debug_check_image_surface_is_defined (&(*image_out)->base);
 
return CAIRO_STATUS_SUCCESS;
}
 
/**
* _cairo_surface_release_source_image:
* @surface: a #cairo_surface_t
* @image_extra: same as return from the matching _cairo_surface_acquire_source_image()
*
* Releases any resources obtained with _cairo_surface_acquire_source_image()
**/
void
_cairo_surface_release_source_image (cairo_surface_t *surface,
cairo_image_surface_t *image,
void *image_extra)
{
assert (!surface->finished);
 
if (surface->backend->release_source_image)
surface->backend->release_source_image (surface, image, image_extra);
}
 
/**
* _cairo_surface_acquire_dest_image:
* @surface: a #cairo_surface_t
* @interest_rect: area of @surface for which fallback drawing is being done.
* A value of %NULL indicates that the entire surface is desired.
* XXXX I'd like to get rid of being able to pass %NULL here (nothing seems to)
* @image_out: location to store a pointer to an image surface that includes at least
* the intersection of @interest_rect with the visible area of @surface.
* This surface could be @surface itself, a surface held internal to @surface,
* or it could be a new surface with a copy of the relevant portion of @surface.
* If a new surface is created, it should have the same channels and depth
* as @surface so that copying to and from it is exact.
* @image_rect: location to store area of the original surface occupied
* by the surface stored in @image.
* @image_extra: location to store image specific backend data
*
* Retrieves a local image for a surface for implementing a fallback drawing
* operation. After calling this function, the implementation of the fallback
* drawing operation draws the primitive to the surface stored in @image_out
* then calls _cairo_surface_release_dest_image(),
* which, if a temporary surface was created, copies the bits back to the
* main surface and frees the temporary surface.
*
* Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY.
* %CAIRO_INT_STATUS_UNSUPPORTED can be returned but this will mean that
* the backend can't draw with fallbacks. It's possible for the routine
* to store %NULL in @local_out and return %CAIRO_STATUS_SUCCESS;
* that indicates that no part of @interest_rect is visible, so no drawing
* is necessary. _cairo_surface_release_dest_image() should not be called in that
* case.
**/
cairo_status_t
_cairo_surface_acquire_dest_image (cairo_surface_t *surface,
cairo_rectangle_int_t *interest_rect,
cairo_image_surface_t **image_out,
cairo_rectangle_int_t *image_rect,
void **image_extra)
{
cairo_status_t status;
 
if (surface->status)
return surface->status;
 
assert (_cairo_surface_is_writable (surface));
 
if (surface->backend->acquire_dest_image == NULL)
return CAIRO_INT_STATUS_UNSUPPORTED;
 
status = surface->backend->acquire_dest_image (surface,
interest_rect,
image_out,
image_rect,
image_extra);
if (unlikely (status))
return _cairo_surface_set_error (surface, status);
 
_cairo_debug_check_image_surface_is_defined (&(*image_out)->base);
 
return CAIRO_STATUS_SUCCESS;
}
 
/**
* _cairo_surface_release_dest_image:
* @surface: a #cairo_surface_t
* @interest_rect: same as passed to the matching _cairo_surface_acquire_dest_image()
* @image: same as returned from the matching _cairo_surface_acquire_dest_image()
* @image_rect: same as returned from the matching _cairo_surface_acquire_dest_image()
* @image_extra: same as return from the matching _cairo_surface_acquire_dest_image()
*
* Finishes the operation started with _cairo_surface_acquire_dest_image(), by, if
* necessary, copying the image from @image back to @surface and freeing any
* resources that were allocated.
**/
void
_cairo_surface_release_dest_image (cairo_surface_t *surface,
cairo_rectangle_int_t *interest_rect,
cairo_image_surface_t *image,
cairo_rectangle_int_t *image_rect,
void *image_extra)
{
assert (_cairo_surface_is_writable (surface));
 
if (surface->backend->release_dest_image)
surface->backend->release_dest_image (surface, interest_rect,
image, image_rect, image_extra);
}
 
static cairo_status_t
_cairo_recording_surface_clone_similar (cairo_surface_t *surface,
cairo_surface_t *src,
int src_x,
int src_y,
int width,
int height,
int *clone_offset_x,
int *clone_offset_y,
cairo_surface_t **clone_out)
{
cairo_recording_surface_t *recorder = (cairo_recording_surface_t *) src;
cairo_surface_t *similar;
cairo_status_t status;
 
similar = _cairo_surface_has_snapshot (src, surface->backend);
if (similar != NULL) {
*clone_out = cairo_surface_reference (similar);
*clone_offset_x = 0;
*clone_offset_y = 0;
return CAIRO_STATUS_SUCCESS;
}
 
if (recorder->unbounded ||
width*height*8 < recorder->extents.width*recorder->extents.height)
{
similar = _cairo_surface_create_similar_solid (surface,
src->content,
width, height,
CAIRO_COLOR_TRANSPARENT,
FALSE);
if (similar == NULL)
return CAIRO_INT_STATUS_UNSUPPORTED;
if (unlikely (similar->status))
return similar->status;
 
cairo_surface_set_device_offset (similar, -src_x, -src_y);
 
status = _cairo_recording_surface_replay (src, similar);
if (unlikely (status)) {
cairo_surface_destroy (similar);
return status;
}
} else {
similar = _cairo_surface_create_similar_scratch (surface,
src->content,
recorder->extents.width,
recorder->extents.height);
if (similar == NULL)
return CAIRO_INT_STATUS_UNSUPPORTED;
if (unlikely (similar->status))
return similar->status;
 
status = _cairo_recording_surface_replay (src, similar);
if (unlikely (status)) {
cairo_surface_destroy (similar);
return status;
}
 
_cairo_surface_attach_snapshot (src, similar, NULL);
 
src_x = src_y = 0;
}
 
*clone_out = similar;
*clone_offset_x = src_x;
*clone_offset_y = src_y;
return CAIRO_STATUS_SUCCESS;
}
 
/**
* _cairo_surface_clone_similar:
* @surface: a #cairo_surface_t
* @src: the source image
* @content: target content mask
* @src_x: extent for the rectangle in src we actually care about
* @src_y: extent for the rectangle in src we actually care about
* @width: extent for the rectangle in src we actually care about
* @height: extent for the rectangle in src we actually care about
* @clone_out: location to store a surface compatible with @surface
* and with contents identical to @src. The caller must call
* cairo_surface_destroy() on the result.
*
* Creates a surface with contents identical to @src but that
* can be used efficiently with @surface. If @surface and @src are
* already compatible then it may return a new reference to @src.
*
* Return value: %CAIRO_STATUS_SUCCESS if a surface was created and stored
* in @clone_out. Otherwise %CAIRO_INT_STATUS_UNSUPPORTED or another
* error like %CAIRO_STATUS_NO_MEMORY.
**/
cairo_status_t
_cairo_surface_clone_similar (cairo_surface_t *surface,
cairo_surface_t *src,
int src_x,
int src_y,
int width,
int height,
int *clone_offset_x,
int *clone_offset_y,
cairo_surface_t **clone_out)
{
cairo_status_t status = CAIRO_INT_STATUS_UNSUPPORTED;
cairo_image_surface_t *image;
void *image_extra;
 
if (unlikely (surface->status))
return surface->status;
 
if (unlikely (surface->finished))
return _cairo_error (CAIRO_STATUS_SURFACE_FINISHED);
 
#if CAIRO_HAS_TEE_SURFACE
 
if (src->type == CAIRO_SURFACE_TYPE_TEE) {
cairo_surface_t *match;
 
match = _cairo_tee_surface_find_match (src,
surface->backend,
src->content);
if (match != NULL)
src = match;
}
 
#endif
 
if (surface->backend->clone_similar != NULL) {
status = surface->backend->clone_similar (surface, src,
src_x, src_y,
width, height,
clone_offset_x,
clone_offset_y,
clone_out);
if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
if (_cairo_surface_is_image (src))
return CAIRO_INT_STATUS_UNSUPPORTED;
 
/* First check to see if we can replay to a similar surface */
if (_cairo_surface_is_recording (src)) {
return _cairo_recording_surface_clone_similar (surface, src,
src_x, src_y,
width, height,
clone_offset_x,
clone_offset_y,
clone_out);
}
 
/* If we failed, try again with an image surface */
status = _cairo_surface_acquire_source_image (src, &image, &image_extra);
if (status == CAIRO_STATUS_SUCCESS) {
status =
surface->backend->clone_similar (surface, &image->base,
src_x, src_y,
width, height,
clone_offset_x,
clone_offset_y,
clone_out);
 
_cairo_surface_release_source_image (src, image, image_extra);
}
}
}
 
/* If we're still unsupported, hit our fallback path to get a clone */
if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
status =
_cairo_surface_fallback_clone_similar (surface, src,
src_x, src_y,
width, height,
clone_offset_x,
clone_offset_y,
clone_out);
}
 
if (unlikely (status))
return status;
 
/* Update the clone's device_transform (which the underlying surface
* backend knows nothing about) */
if (*clone_out != src) {
(*clone_out)->device_transform = src->device_transform;
(*clone_out)->device_transform_inverse = src->device_transform_inverse;
}
 
return status;
}
 
/**
* _cairo_surface_is_similar
* @surface_a: a #cairo_surface_t
* @surface_b: a #cairo_surface_t
* @content: a #cairo_content_t
*
* Find out whether the given surfaces share the same backend,
* and if so, whether they can be considered similar.
*
* The definition of "similar" depends on the backend. In
* general, it means that the surface is equivalent to one
* that would have been generated by a call to cairo_surface_create_similar().
*
* Return value: %TRUE if the surfaces are similar.
**/
cairo_bool_t
_cairo_surface_is_similar (cairo_surface_t *surface_a,
cairo_surface_t *surface_b)
{
if (surface_a->backend != surface_b->backend)
return FALSE;
 
if (surface_a->backend->is_similar != NULL)
return surface_a->backend->is_similar (surface_a, surface_b);
 
return TRUE;
}
 
cairo_status_t
_cairo_surface_composite (cairo_operator_t op,
const cairo_pattern_t *src,
const cairo_pattern_t *mask,
cairo_surface_t *dst,
int src_x,
int src_y,
int mask_x,
int mask_y,
int dst_x,
int dst_y,
unsigned int width,
unsigned int height,
cairo_region_t *clip_region)
{
cairo_int_status_t status;
 
if (unlikely (dst->status))
return dst->status;
 
assert (_cairo_surface_is_writable (dst));
 
if (mask) {
/* These operators aren't interpreted the same way by the backends;
* they are implemented in terms of other operators in cairo-gstate.c
*/
assert (op != CAIRO_OPERATOR_SOURCE && op != CAIRO_OPERATOR_CLEAR);
}
 
if (dst->backend->composite) {
status = dst->backend->composite (op,
src, mask, dst,
src_x, src_y,
mask_x, mask_y,
dst_x, dst_y,
width, height,
clip_region);
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
return _cairo_surface_set_error (dst, status);
}
 
return _cairo_surface_set_error (dst,
_cairo_surface_fallback_composite (op,
src, mask, dst,
src_x, src_y,
mask_x, mask_y,
dst_x, dst_y,
width, height,
clip_region));
}
 
/**
* _cairo_surface_fill_rectangle:
* @surface: a #cairo_surface_t
* @op: the operator to apply to the rectangle
* @color: the source color
* @x: X coordinate of rectangle, in backend coordinates
* @y: Y coordinate of rectangle, in backend coordinates
* @width: width of rectangle, in backend coordinates
* @height: height of rectangle, in backend coordinates
*
* Applies an operator to a rectangle using a solid color as the source.
* See _cairo_surface_fill_rectangles() for full details.
*
* Return value: %CAIRO_STATUS_SUCCESS or the error that occurred
**/
cairo_status_t
_cairo_surface_fill_rectangle (cairo_surface_t *surface,
cairo_operator_t op,
const cairo_color_t *color,
int x,
int y,
int width,
int height)
{
cairo_rectangle_int_t rect;
 
if (surface->status)
return surface->status;
 
assert (_cairo_surface_is_writable (surface));
 
rect.x = x;
rect.y = y;
rect.width = width;
rect.height = height;
 
return _cairo_surface_fill_rectangles (surface, op, color, &rect, 1);
}
 
/**
* _cairo_surface_fill_region:
* @surface: a #cairo_surface_t
* @op: the operator to apply to the region
* @color: the source color
* @region: the region to modify, in backend coordinates
*
* Applies an operator to a set of rectangles specified as a
* #cairo_region_t using a solid color as the source.
* See _cairo_surface_fill_rectangles() for full details.
*
* Return value: %CAIRO_STATUS_SUCCESS or the error that occurred
**/
cairo_status_t
_cairo_surface_fill_region (cairo_surface_t *surface,
cairo_operator_t op,
const cairo_color_t *color,
cairo_region_t *region)
{
int num_rects;
cairo_rectangle_int_t stack_rects[CAIRO_STACK_ARRAY_LENGTH (cairo_rectangle_int_t)];
cairo_rectangle_int_t *rects = stack_rects;
cairo_status_t status;
int i;
 
if (surface->status)
return surface->status;
 
assert (_cairo_surface_is_writable (surface));
 
num_rects = cairo_region_num_rectangles (region);
if (num_rects == 0)
return CAIRO_STATUS_SUCCESS;
 
/* catch a common reduction of _cairo_clip_combine_with_surface() */
if (op == CAIRO_OPERATOR_IN &&
_cairo_color_equal (color, CAIRO_COLOR_WHITE))
{
return CAIRO_STATUS_SUCCESS;
}
 
if (num_rects > ARRAY_LENGTH (stack_rects)) {
rects = _cairo_malloc_ab (num_rects,
sizeof (cairo_rectangle_int_t));
if (rects == NULL) {
return _cairo_surface_set_error (surface,
_cairo_error (CAIRO_STATUS_NO_MEMORY));
}
}
 
for (i = 0; i < num_rects; i++)
cairo_region_get_rectangle (region, i, &rects[i]);
 
status = _cairo_surface_fill_rectangles (surface,
op, color, rects, num_rects);
 
if (rects != stack_rects)
free (rects);
 
return _cairo_surface_set_error (surface, status);
}
 
/**
* _cairo_surface_fill_rectangles:
* @surface: a #cairo_surface_t
* @op: the operator to apply to the region
* @color: the source color
* @rects: the rectangles to modify, in backend coordinates
* @num_rects: the number of rectangles in @rects
*
* Applies an operator to a set of rectangles using a solid color
* as the source. Note that even if the operator is an unbounded operator
* such as %CAIRO_OPERATOR_IN, only the given set of rectangles
* is affected. This differs from _cairo_surface_composite_trapezoids()
* where the entire destination rectangle is cleared.
*
* Return value: %CAIRO_STATUS_SUCCESS or the error that occurred
**/
cairo_status_t
_cairo_surface_fill_rectangles (cairo_surface_t *surface,
cairo_operator_t op,
const cairo_color_t *color,
cairo_rectangle_int_t *rects,
int num_rects)
{
cairo_int_status_t status;
 
if (surface->status)
return surface->status;
 
assert (_cairo_surface_is_writable (surface));
 
if (num_rects == 0)
return CAIRO_STATUS_SUCCESS;
 
if (surface->backend->fill_rectangles) {
status = surface->backend->fill_rectangles (surface,
op, color,
rects, num_rects);
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
return _cairo_surface_set_error (surface, status);
}
 
return _cairo_surface_set_error (surface,
_cairo_surface_fallback_fill_rectangles (surface,
op, color,
rects, num_rects));
}
 
static cairo_status_t
_pattern_has_error (const cairo_pattern_t *pattern)
{
const cairo_surface_pattern_t *spattern;
 
if (unlikely (pattern->status))
return pattern->status;
 
if (pattern->type != CAIRO_PATTERN_TYPE_SURFACE)
return CAIRO_STATUS_SUCCESS;
 
spattern = (const cairo_surface_pattern_t *) pattern;
if (unlikely (spattern->surface->status))
return spattern->surface->status;
 
if (unlikely (spattern->surface->finished))
return _cairo_error (CAIRO_STATUS_SURFACE_FINISHED);
 
return CAIRO_STATUS_SUCCESS;
}
 
cairo_status_t
_cairo_surface_paint (cairo_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_clip_t *clip)
{
cairo_status_t status;
 
if (unlikely (surface->status))
return surface->status;
 
if (clip && clip->all_clipped)
return CAIRO_STATUS_SUCCESS;
 
if (op == CAIRO_OPERATOR_CLEAR && surface->is_clear)
return CAIRO_STATUS_SUCCESS;
 
if (op == CAIRO_OPERATOR_OVER &&
_cairo_pattern_is_clear (source))
{
return CAIRO_STATUS_SUCCESS;
}
 
status = _pattern_has_error (source);
if (unlikely (status))
return status;
 
_cairo_surface_begin_modification (surface);
 
if (surface->backend->paint != NULL) {
status = surface->backend->paint (surface, op, source, clip);
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
goto FINISH;
}
 
status = _cairo_surface_fallback_paint (surface, op, source, clip);
 
FINISH:
surface->is_clear = op == CAIRO_OPERATOR_CLEAR && clip == NULL;
 
return _cairo_surface_set_error (surface, status);
}
 
cairo_status_t
_cairo_surface_mask (cairo_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_pattern_t *mask,
cairo_clip_t *clip)
{
cairo_status_t status;
 
if (unlikely (surface->status))
return surface->status;
 
if (clip && clip->all_clipped)
return CAIRO_STATUS_SUCCESS;
 
if (op == CAIRO_OPERATOR_CLEAR && surface->is_clear)
return CAIRO_STATUS_SUCCESS;
 
/* If the mask is blank, this is just an expensive no-op */
if (_cairo_pattern_is_clear (mask) &&
_cairo_operator_bounded_by_mask (op))
{
return CAIRO_STATUS_SUCCESS;
}
 
if (op == CAIRO_OPERATOR_OVER &&
_cairo_pattern_is_clear (source))
{
return CAIRO_STATUS_SUCCESS;
}
 
status = _pattern_has_error (source);
if (unlikely (status))
return status;
 
status = _pattern_has_error (mask);
if (unlikely (status))
return status;
 
_cairo_surface_begin_modification (surface);
 
if (surface->backend->mask != NULL) {
status = surface->backend->mask (surface, op, source, mask, clip);
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
goto FINISH;
}
 
status = _cairo_surface_fallback_mask (surface, op, source, mask, clip);
 
FINISH:
surface->is_clear = FALSE;
 
return _cairo_surface_set_error (surface, status);
}
 
cairo_status_t
_cairo_surface_fill_stroke (cairo_surface_t *surface,
cairo_operator_t fill_op,
const cairo_pattern_t *fill_source,
cairo_fill_rule_t fill_rule,
double fill_tolerance,
cairo_antialias_t fill_antialias,
cairo_path_fixed_t *path,
cairo_operator_t stroke_op,
const cairo_pattern_t *stroke_source,
const cairo_stroke_style_t *stroke_style,
const cairo_matrix_t *stroke_ctm,
const cairo_matrix_t *stroke_ctm_inverse,
double stroke_tolerance,
cairo_antialias_t stroke_antialias,
cairo_clip_t *clip)
{
cairo_status_t status;
 
if (unlikely (surface->status))
return surface->status;
 
if (clip && clip->all_clipped)
return CAIRO_STATUS_SUCCESS;
 
if (surface->is_clear &&
fill_op == CAIRO_OPERATOR_CLEAR &&
stroke_op == CAIRO_OPERATOR_CLEAR)
{
return CAIRO_STATUS_SUCCESS;
}
 
status = _pattern_has_error (fill_source);
if (unlikely (status))
return status;
 
status = _pattern_has_error (stroke_source);
if (unlikely (status))
return status;
 
_cairo_surface_begin_modification (surface);
 
if (surface->backend->fill_stroke) {
cairo_matrix_t dev_ctm = *stroke_ctm;
cairo_matrix_t dev_ctm_inverse = *stroke_ctm_inverse;
 
status = surface->backend->fill_stroke (surface,
fill_op, fill_source, fill_rule,
fill_tolerance, fill_antialias,
path,
stroke_op, stroke_source,
stroke_style,
&dev_ctm, &dev_ctm_inverse,
stroke_tolerance, stroke_antialias,
clip);
 
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
goto FINISH;
}
 
status = _cairo_surface_fill (surface, fill_op, fill_source, path,
fill_rule, fill_tolerance, fill_antialias,
clip);
if (unlikely (status))
goto FINISH;
 
status = _cairo_surface_stroke (surface, stroke_op, stroke_source, path,
stroke_style, stroke_ctm, stroke_ctm_inverse,
stroke_tolerance, stroke_antialias,
clip);
if (unlikely (status))
goto FINISH;
 
FINISH:
surface->is_clear = FALSE;
 
return _cairo_surface_set_error (surface, status);
}
 
cairo_status_t
_cairo_surface_stroke (cairo_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_path_fixed_t *path,
const cairo_stroke_style_t *stroke_style,
const cairo_matrix_t *ctm,
const cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
cairo_clip_t *clip)
{
cairo_status_t status;
 
if (unlikely (surface->status))
return surface->status;
 
if (clip && clip->all_clipped)
return CAIRO_STATUS_SUCCESS;
 
if (op == CAIRO_OPERATOR_CLEAR && surface->is_clear)
return CAIRO_STATUS_SUCCESS;
 
if (op == CAIRO_OPERATOR_OVER &&
_cairo_pattern_is_clear (source))
{
return CAIRO_STATUS_SUCCESS;
}
 
status = _pattern_has_error (source);
if (unlikely (status))
return status;
 
_cairo_surface_begin_modification (surface);
 
if (surface->backend->stroke != NULL) {
status = surface->backend->stroke (surface, op, source,
path, stroke_style,
ctm, ctm_inverse,
tolerance, antialias,
clip);
 
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
goto FINISH;
}
 
status = _cairo_surface_fallback_stroke (surface, op, source,
path, stroke_style,
ctm, ctm_inverse,
tolerance, antialias,
clip);
 
FINISH:
surface->is_clear = FALSE;
 
return _cairo_surface_set_error (surface, status);
}
 
cairo_status_t
_cairo_surface_fill (cairo_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias,
cairo_clip_t *clip)
{
cairo_status_t status;
 
if (unlikely (surface->status))
return surface->status;
 
if (clip && clip->all_clipped)
return CAIRO_STATUS_SUCCESS;
 
if (op == CAIRO_OPERATOR_CLEAR && surface->is_clear)
return CAIRO_STATUS_SUCCESS;
 
if (op == CAIRO_OPERATOR_OVER &&
_cairo_pattern_is_clear (source))
{
return CAIRO_STATUS_SUCCESS;
}
 
status = _pattern_has_error (source);
if (unlikely (status))
return status;
 
_cairo_surface_begin_modification (surface);
 
if (surface->backend->fill != NULL) {
status = surface->backend->fill (surface, op, source,
path, fill_rule,
tolerance, antialias,
clip);
 
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
goto FINISH;
}
 
status = _cairo_surface_fallback_fill (surface, op, source,
path, fill_rule,
tolerance, antialias,
clip);
 
FINISH:
surface->is_clear = FALSE;
 
return _cairo_surface_set_error (surface, status);
}
 
cairo_status_t
_cairo_surface_composite_trapezoids (cairo_operator_t op,
const cairo_pattern_t *pattern,
cairo_surface_t *dst,
cairo_antialias_t antialias,
int src_x,
int src_y,
int dst_x,
int dst_y,
unsigned int width,
unsigned int height,
cairo_trapezoid_t *traps,
int num_traps,
cairo_region_t *clip_region)
{
cairo_int_status_t status;
 
if (dst->status)
return dst->status;
 
assert (_cairo_surface_is_writable (dst));
 
/* These operators aren't interpreted the same way by the backends;
* they are implemented in terms of other operators in cairo-gstate.c
*/
assert (op != CAIRO_OPERATOR_SOURCE && op != CAIRO_OPERATOR_CLEAR);
 
if (dst->backend->composite_trapezoids) {
status = dst->backend->composite_trapezoids (op,
pattern, dst,
antialias,
src_x, src_y,
dst_x, dst_y,
width, height,
traps, num_traps,
clip_region);
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
return _cairo_surface_set_error (dst, status);
}
 
return _cairo_surface_set_error (dst,
_cairo_surface_fallback_composite_trapezoids (op, pattern, dst,
antialias,
src_x, src_y,
dst_x, dst_y,
width, height,
traps, num_traps,
clip_region));
}
 
cairo_span_renderer_t *
_cairo_surface_create_span_renderer (cairo_operator_t op,
const cairo_pattern_t *pattern,
cairo_surface_t *dst,
cairo_antialias_t antialias,
const cairo_composite_rectangles_t *rects,
cairo_region_t *clip_region)
{
assert (dst->snapshot_of == NULL);
 
if (unlikely (dst->status))
return _cairo_span_renderer_create_in_error (dst->status);
 
if (unlikely (dst->finished))
return _cairo_span_renderer_create_in_error (CAIRO_STATUS_SURFACE_FINISHED);
 
if (dst->backend->create_span_renderer) {
return dst->backend->create_span_renderer (op,
pattern, dst,
antialias,
rects,
clip_region);
}
ASSERT_NOT_REACHED;
return _cairo_span_renderer_create_in_error (CAIRO_INT_STATUS_UNSUPPORTED);
}
 
cairo_bool_t
_cairo_surface_check_span_renderer (cairo_operator_t op,
const cairo_pattern_t *pattern,
cairo_surface_t *dst,
cairo_antialias_t antialias)
{
assert (dst->snapshot_of == NULL);
assert (dst->status == CAIRO_STATUS_SUCCESS);
assert (! dst->finished);
 
/* XXX: Currently we have no mono span renderer */
if (antialias == CAIRO_ANTIALIAS_NONE)
return FALSE;
 
if (dst->backend->check_span_renderer != NULL)
return dst->backend->check_span_renderer (op, pattern, dst, antialias);
 
return FALSE;
}
 
/**
* cairo_surface_copy_page:
* @surface: a #cairo_surface_t
*
* Emits the current page for backends that support multiple pages,
* but doesn't clear it, so that the contents of the current page will
* be retained for the next page. Use cairo_surface_show_page() if you
* want to get an empty page after the emission.
*
* There is a convenience function for this that takes a #cairo_t,
* namely cairo_copy_page().
*
* Since: 1.6
*/
void
cairo_surface_copy_page (cairo_surface_t *surface)
{
cairo_status_t status_ignored;
 
if (surface->status)
return;
 
assert (surface->snapshot_of == NULL);
 
if (surface->finished) {
status_ignored = _cairo_surface_set_error (surface,
CAIRO_STATUS_SURFACE_FINISHED);
return;
}
 
/* It's fine if some backends don't implement copy_page */
if (surface->backend->copy_page == NULL)
return;
 
status_ignored = _cairo_surface_set_error (surface,
surface->backend->copy_page (surface));
}
slim_hidden_def (cairo_surface_copy_page);
 
/**
* cairo_surface_show_page:
* @surface: a #cairo_Surface_t
*
* Emits and clears the current page for backends that support multiple
* pages. Use cairo_surface_copy_page() if you don't want to clear the page.
*
* There is a convenience function for this that takes a #cairo_t,
* namely cairo_show_page().
*
* Since: 1.6
**/
void
cairo_surface_show_page (cairo_surface_t *surface)
{
cairo_status_t status_ignored;
 
if (surface->status)
return;
 
if (surface->finished) {
status_ignored = _cairo_surface_set_error (surface,
CAIRO_STATUS_SURFACE_FINISHED);
return;
}
 
_cairo_surface_begin_modification (surface);
 
/* It's fine if some backends don't implement show_page */
if (surface->backend->show_page == NULL)
return;
 
status_ignored = _cairo_surface_set_error (surface,
surface->backend->show_page (surface));
}
slim_hidden_def (cairo_surface_show_page);
 
/**
* _cairo_surface_get_extents:
* @surface: the #cairo_surface_t to fetch extents for
*
* This function returns a bounding box for the surface. The surface
* bounds are defined as a region beyond which no rendering will
* possibly be recorded, in other words, it is the maximum extent of
* potentially usable coordinates.
*
* For vector surfaces, (PDF, PS, SVG and recording-surfaces), the surface
* might be conceived as unbounded, but we force the user to provide a
* maximum size at the time of surface_create. So get_extents uses
* that size.
*
* Note: The coordinates returned are in "backend" space rather than
* "surface" space. That is, they are relative to the true (0,0)
* origin rather than the device_transform origin. This might seem a
* bit inconsistent with other #cairo_surface_t interfaces, but all
* current callers are within the surface layer where backend space is
* desired.
*
* This behavior would have to be changed is we ever exported a public
* variant of this function.
*/
cairo_bool_t
_cairo_surface_get_extents (cairo_surface_t *surface,
cairo_rectangle_int_t *extents)
{
cairo_bool_t bounded;
 
bounded = FALSE;
if (surface->backend->get_extents != NULL)
bounded = surface->backend->get_extents (surface, extents);
 
if (! bounded)
_cairo_unbounded_rectangle_init (extents);
 
return bounded;
}
 
/**
* cairo_surface_has_show_text_glyphs:
* @surface: a #cairo_surface_t
*
* Returns whether the surface supports
* sophisticated cairo_show_text_glyphs() operations. That is,
* whether it actually uses the provided text and cluster data
* to a cairo_show_text_glyphs() call.
*
* Note: Even if this function returns %FALSE, a
* cairo_show_text_glyphs() operation targeted at @surface will
* still succeed. It just will
* act like a cairo_show_glyphs() operation. Users can use this
* function to avoid computing UTF-8 text and cluster mapping if the
* target surface does not use it.
*
* Return value: %TRUE if @surface supports
* cairo_show_text_glyphs(), %FALSE otherwise
*
* Since: 1.8
**/
cairo_bool_t
cairo_surface_has_show_text_glyphs (cairo_surface_t *surface)
{
cairo_status_t status_ignored;
 
if (surface->status)
return FALSE;
 
if (surface->finished) {
status_ignored = _cairo_surface_set_error (surface,
CAIRO_STATUS_SURFACE_FINISHED);
return FALSE;
}
 
if (surface->backend->has_show_text_glyphs)
return surface->backend->has_show_text_glyphs (surface);
else
return surface->backend->show_text_glyphs != NULL;
}
slim_hidden_def (cairo_surface_has_show_text_glyphs);
 
/* Note: the backends may modify the contents of the glyph array as long as
* they do not return %CAIRO_INT_STATUS_UNSUPPORTED. This makes it possible to
* avoid copying the array again and again, and edit it in-place.
* Backends are in fact free to use the array as a generic buffer as they
* see fit.
*
* For show_glyphs backend method, and NOT for show_text_glyphs method,
* when they do return UNSUPPORTED, they may adjust remaining_glyphs to notify
* that they have successfully rendered some of the glyphs (from the beginning
* of the array), but not all. If they don't touch remaining_glyphs, it
* defaults to all glyphs.
*
* See commits 5a9642c5746fd677aed35ce620ce90b1029b1a0c and
* 1781e6018c17909311295a9cc74b70500c6b4d0a for the rationale.
*/
cairo_status_t
_cairo_surface_show_text_glyphs (cairo_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const char *utf8,
int utf8_len,
cairo_glyph_t *glyphs,
int num_glyphs,
const cairo_text_cluster_t *clusters,
int num_clusters,
cairo_text_cluster_flags_t cluster_flags,
cairo_scaled_font_t *scaled_font,
cairo_clip_t *clip)
{
cairo_status_t status;
cairo_scaled_font_t *dev_scaled_font = scaled_font;
 
if (unlikely (surface->status))
return surface->status;
 
if (num_glyphs == 0 && utf8_len == 0)
return CAIRO_STATUS_SUCCESS;
 
if (clip && clip->all_clipped)
return CAIRO_STATUS_SUCCESS;
 
if (op == CAIRO_OPERATOR_CLEAR && surface->is_clear)
return CAIRO_STATUS_SUCCESS;
 
status = _pattern_has_error (source);
if (unlikely (status))
return status;
 
_cairo_surface_begin_modification (surface);
 
if (_cairo_surface_has_device_transform (surface) &&
! _cairo_matrix_is_integer_translation (&surface->device_transform, NULL, NULL))
{
cairo_font_options_t font_options;
cairo_matrix_t dev_ctm, font_matrix;
 
cairo_scaled_font_get_font_matrix (scaled_font, &font_matrix);
cairo_scaled_font_get_ctm (scaled_font, &dev_ctm);
cairo_matrix_multiply (&dev_ctm, &dev_ctm, &surface->device_transform);
cairo_scaled_font_get_font_options (scaled_font, &font_options);
dev_scaled_font = cairo_scaled_font_create (cairo_scaled_font_get_font_face (scaled_font),
&font_matrix,
&dev_ctm,
&font_options);
}
status = cairo_scaled_font_status (dev_scaled_font);
if (unlikely (status))
return _cairo_surface_set_error (surface, status);
 
status = CAIRO_INT_STATUS_UNSUPPORTED;
 
/* The logic here is duplicated in _cairo_analysis_surface show_glyphs and
* show_text_glyphs. Keep in synch. */
if (clusters) {
/* A real show_text_glyphs call. Try show_text_glyphs backend
* method first */
if (surface->backend->show_text_glyphs != NULL) {
status = surface->backend->show_text_glyphs (surface, op,
source,
utf8, utf8_len,
glyphs, num_glyphs,
clusters, num_clusters, cluster_flags,
dev_scaled_font,
clip);
}
if (status == CAIRO_INT_STATUS_UNSUPPORTED &&
surface->backend->show_glyphs)
{
int remaining_glyphs = num_glyphs;
status = surface->backend->show_glyphs (surface, op,
source,
glyphs, num_glyphs,
dev_scaled_font,
clip,
&remaining_glyphs);
glyphs += num_glyphs - remaining_glyphs;
num_glyphs = remaining_glyphs;
if (status == CAIRO_INT_STATUS_UNSUPPORTED && remaining_glyphs == 0)
status = CAIRO_STATUS_SUCCESS;
}
} else {
/* A mere show_glyphs call. Try show_glyphs backend method first */
if (surface->backend->show_glyphs != NULL) {
int remaining_glyphs = num_glyphs;
status = surface->backend->show_glyphs (surface, op,
source,
glyphs, num_glyphs,
dev_scaled_font,
clip,
&remaining_glyphs);
glyphs += num_glyphs - remaining_glyphs;
num_glyphs = remaining_glyphs;
if (status == CAIRO_INT_STATUS_UNSUPPORTED && remaining_glyphs == 0)
status = CAIRO_STATUS_SUCCESS;
} else if (surface->backend->show_text_glyphs != NULL) {
/* Intentionally only try show_text_glyphs method for show_glyphs
* calls if backend does not have show_glyphs. If backend has
* both methods implemented, we don't fallback from show_glyphs to
* show_text_glyphs, and hence the backend can assume in its
* show_text_glyphs call that clusters is not NULL (which also
* implies that UTF-8 is not NULL, unless the text is
* zero-length).
*/
status = surface->backend->show_text_glyphs (surface, op,
source,
utf8, utf8_len,
glyphs, num_glyphs,
clusters, num_clusters, cluster_flags,
dev_scaled_font,
clip);
}
}
 
if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
status = _cairo_surface_fallback_show_glyphs (surface, op,
source,
glyphs, num_glyphs,
dev_scaled_font,
clip);
}
 
if (dev_scaled_font != scaled_font)
cairo_scaled_font_destroy (dev_scaled_font);
 
surface->is_clear = FALSE;
 
return _cairo_surface_set_error (surface, status);
}
 
/* XXX: Previously, we had a function named _cairo_surface_show_glyphs
* with not-so-useful semantics. We've now got a
* _cairo_surface_show_text_glyphs with the proper semantics, and its
* fallback still uses this old function (which still needs to be
* cleaned up in terms of both semantics and naming). */
cairo_status_t
_cairo_surface_old_show_glyphs (cairo_scaled_font_t *scaled_font,
cairo_operator_t op,
const cairo_pattern_t *pattern,
cairo_surface_t *dst,
int source_x,
int source_y,
int dest_x,
int dest_y,
unsigned int width,
unsigned int height,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_region_t *clip_region)
{
cairo_status_t status;
 
if (dst->status)
return dst->status;
 
assert (_cairo_surface_is_writable (dst));
 
if (dst->backend->old_show_glyphs) {
status = dst->backend->old_show_glyphs (scaled_font,
op, pattern, dst,
source_x, source_y,
dest_x, dest_y,
width, height,
glyphs, num_glyphs,
clip_region);
} else
status = CAIRO_INT_STATUS_UNSUPPORTED;
 
return _cairo_surface_set_error (dst, status);
}
 
static cairo_status_t
_cairo_surface_composite_fixup_unbounded_internal (cairo_surface_t *dst,
cairo_rectangle_int_t *src_rectangle,
cairo_rectangle_int_t *mask_rectangle,
int dst_x,
int dst_y,
unsigned int width,
unsigned int height,
cairo_region_t *clip_region)
{
cairo_rectangle_int_t dst_rectangle;
cairo_region_t clear_region;
cairo_status_t status;
 
/* The area that was drawn is the area in the destination rectangle but
* not within the source or the mask.
*/
dst_rectangle.x = dst_x;
dst_rectangle.y = dst_y;
dst_rectangle.width = width;
dst_rectangle.height = height;
 
_cairo_region_init_rectangle (&clear_region, &dst_rectangle);
 
if (clip_region != NULL) {
status = cairo_region_intersect (&clear_region, clip_region);
if (unlikely (status))
goto CLEANUP_REGIONS;
}
 
if (src_rectangle != NULL) {
if (! _cairo_rectangle_intersect (&dst_rectangle, src_rectangle))
goto EMPTY;
}
 
if (mask_rectangle != NULL) {
if (! _cairo_rectangle_intersect (&dst_rectangle, mask_rectangle))
goto EMPTY;
}
 
/* Now compute the area that is in dst but not drawn */
status = cairo_region_subtract_rectangle (&clear_region, &dst_rectangle);
if (unlikely (status) || cairo_region_is_empty (&clear_region))
goto CLEANUP_REGIONS;
 
EMPTY:
status = _cairo_surface_fill_region (dst, CAIRO_OPERATOR_CLEAR,
CAIRO_COLOR_TRANSPARENT,
&clear_region);
 
CLEANUP_REGIONS:
_cairo_region_fini (&clear_region);
 
return _cairo_surface_set_error (dst, status);
}
 
/**
* _cairo_surface_composite_fixup_unbounded:
* @dst: the destination surface
* @src_attr: source surface attributes (from _cairo_pattern_acquire_surface())
* @src_width: width of source surface
* @src_height: height of source surface
* @mask_attr: mask surface attributes or %NULL if no mask
* @mask_width: width of mask surface
* @mask_height: height of mask surface
* @src_x: @src_x from _cairo_surface_composite()
* @src_y: @src_y from _cairo_surface_composite()
* @mask_x: @mask_x from _cairo_surface_composite()
* @mask_y: @mask_y from _cairo_surface_composite()
* @dst_x: @dst_x from _cairo_surface_composite()
* @dst_y: @dst_y from _cairo_surface_composite()
* @width: @width from _cairo_surface_composite()
* @height: @height_x from _cairo_surface_composite()
*
* Eeek! Too many parameters! This is a helper function to take care of fixing
* up for bugs in libpixman and RENDER where, when asked to composite an
* untransformed surface with an unbounded operator (like CLEAR or SOURCE)
* only the region inside both the source and the mask is affected.
* This function clears the region that should have been drawn but was wasn't.
**/
cairo_status_t
_cairo_surface_composite_fixup_unbounded (cairo_surface_t *dst,
cairo_surface_attributes_t *src_attr,
int src_width,
int src_height,
cairo_surface_attributes_t *mask_attr,
int mask_width,
int mask_height,
int src_x,
int src_y,
int mask_x,
int mask_y,
int dst_x,
int dst_y,
unsigned int width,
unsigned int height,
cairo_region_t *clip_region)
{
cairo_rectangle_int_t src_tmp, mask_tmp;
cairo_rectangle_int_t *src_rectangle = NULL;
cairo_rectangle_int_t *mask_rectangle = NULL;
 
if (unlikely (dst->status))
return dst->status;
 
assert (_cairo_surface_is_writable (dst));
 
/* The RENDER/libpixman operators are clipped to the bounds of the untransformed,
* non-repeating sources and masks. Other sources and masks can be ignored.
*/
if (_cairo_matrix_is_integer_translation (&src_attr->matrix, NULL, NULL) &&
src_attr->extend == CAIRO_EXTEND_NONE)
{
src_tmp.x = (dst_x - (src_x + src_attr->x_offset));
src_tmp.y = (dst_y - (src_y + src_attr->y_offset));
src_tmp.width = src_width;
src_tmp.height = src_height;
 
src_rectangle = &src_tmp;
}
 
if (mask_attr &&
_cairo_matrix_is_integer_translation (&mask_attr->matrix, NULL, NULL) &&
mask_attr->extend == CAIRO_EXTEND_NONE)
{
mask_tmp.x = (dst_x - (mask_x + mask_attr->x_offset));
mask_tmp.y = (dst_y - (mask_y + mask_attr->y_offset));
mask_tmp.width = mask_width;
mask_tmp.height = mask_height;
 
mask_rectangle = &mask_tmp;
}
 
return _cairo_surface_composite_fixup_unbounded_internal (dst, src_rectangle, mask_rectangle,
dst_x, dst_y, width, height,
clip_region);
}
 
/**
* _cairo_surface_composite_shape_fixup_unbounded:
* @dst: the destination surface
* @src_attr: source surface attributes (from _cairo_pattern_acquire_surface())
* @src_width: width of source surface
* @src_height: height of source surface
* @mask_width: width of mask surface
* @mask_height: height of mask surface
* @src_x: @src_x from _cairo_surface_composite()
* @src_y: @src_y from _cairo_surface_composite()
* @mask_x: @mask_x from _cairo_surface_composite()
* @mask_y: @mask_y from _cairo_surface_composite()
* @dst_x: @dst_x from _cairo_surface_composite()
* @dst_y: @dst_y from _cairo_surface_composite()
* @width: @width from _cairo_surface_composite()
* @height: @height_x from _cairo_surface_composite()
*
* Like _cairo_surface_composite_fixup_unbounded(), but instead of
* handling the case where we have a source pattern and a mask
* pattern, handle the case where we are compositing a source pattern
* using a mask we create ourselves, as in
* _cairo_surface_composite_glyphs() or _cairo_surface_composite_trapezoids()
**/
cairo_status_t
_cairo_surface_composite_shape_fixup_unbounded (cairo_surface_t *dst,
cairo_surface_attributes_t *src_attr,
int src_width,
int src_height,
int mask_width,
int mask_height,
int src_x,
int src_y,
int mask_x,
int mask_y,
int dst_x,
int dst_y,
unsigned int width,
unsigned int height,
cairo_region_t *clip_region)
{
cairo_rectangle_int_t src_tmp, *src= NULL;
cairo_rectangle_int_t mask;
 
if (dst->status)
return dst->status;
 
assert (_cairo_surface_is_writable (dst));
 
/* The RENDER/libpixman operators are clipped to the bounds of the untransformed,
* non-repeating sources and masks. Other sources and masks can be ignored.
*/
if (_cairo_matrix_is_integer_translation (&src_attr->matrix, NULL, NULL) &&
src_attr->extend == CAIRO_EXTEND_NONE)
{
src_tmp.x = (dst_x - (src_x + src_attr->x_offset));
src_tmp.y = (dst_y - (src_y + src_attr->y_offset));
src_tmp.width = src_width;
src_tmp.height = src_height;
 
src = &src_tmp;
}
 
mask.x = dst_x - mask_x;
mask.y = dst_y - mask_y;
mask.width = mask_width;
mask.height = mask_height;
 
return _cairo_surface_composite_fixup_unbounded_internal (dst, src, &mask,
dst_x, dst_y, width, height,
clip_region);
}
 
/**
* _cairo_surface_set_resolution
* @surface: the surface
* @x_res: x resolution, in dpi
* @y_res: y resolution, in dpi
*
* Set the actual surface resolution of @surface to the given x and y DPI.
* Mainly used for correctly computing the scale factor when fallback
* rendering needs to take place in the paginated surface.
*/
void
_cairo_surface_set_resolution (cairo_surface_t *surface,
double x_res,
double y_res)
{
if (surface->status)
return;
 
surface->x_resolution = x_res;
surface->y_resolution = y_res;
}
 
/* Generic methods for determining operation extents. */
 
static void
_rectangle_intersect_clip (cairo_rectangle_int_t *extents, cairo_clip_t *clip)
{
const cairo_rectangle_int_t *clip_extents;
cairo_bool_t is_empty;
 
clip_extents = NULL;
if (clip != NULL)
clip_extents = _cairo_clip_get_extents (clip);
 
if (clip_extents != NULL)
is_empty = _cairo_rectangle_intersect (extents, clip_extents);
}
 
static void
_cairo_surface_operation_extents (cairo_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_clip_t *clip,
cairo_rectangle_int_t *extents)
{
cairo_bool_t is_empty;
 
is_empty = _cairo_surface_get_extents (surface, extents);
 
if (_cairo_operator_bounded_by_source (op)) {
cairo_rectangle_int_t source_extents;
 
_cairo_pattern_get_extents (source, &source_extents);
is_empty = _cairo_rectangle_intersect (extents, &source_extents);
}
 
_rectangle_intersect_clip (extents, clip);
}
 
cairo_status_t
_cairo_surface_paint_extents (cairo_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_clip_t *clip,
cairo_rectangle_int_t *extents)
{
_cairo_surface_operation_extents (surface, op, source, clip, extents);
return CAIRO_STATUS_SUCCESS;
}
 
cairo_status_t
_cairo_surface_mask_extents (cairo_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_pattern_t *mask,
cairo_clip_t *clip,
cairo_rectangle_int_t *extents)
{
cairo_bool_t is_empty;
 
_cairo_surface_operation_extents (surface, op, source, clip, extents);
 
if (_cairo_operator_bounded_by_mask (op)) {
cairo_rectangle_int_t mask_extents;
 
_cairo_pattern_get_extents (mask, &mask_extents);
is_empty = _cairo_rectangle_intersect (extents, &mask_extents);
}
 
return CAIRO_STATUS_SUCCESS;
}
 
cairo_status_t
_cairo_surface_stroke_extents (cairo_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_path_fixed_t *path,
const cairo_stroke_style_t *style,
const cairo_matrix_t *ctm,
const cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
cairo_clip_t *clip,
cairo_rectangle_int_t *extents)
{
cairo_status_t status;
cairo_bool_t is_empty;
 
_cairo_surface_operation_extents (surface, op, source, clip, extents);
 
if (_cairo_operator_bounded_by_mask (op)) {
cairo_rectangle_int_t mask_extents;
 
status = _cairo_path_fixed_stroke_extents (path, style,
ctm, ctm_inverse,
tolerance,
&mask_extents);
if (unlikely (status))
return status;
 
is_empty = _cairo_rectangle_intersect (extents, &mask_extents);
}
 
return CAIRO_STATUS_SUCCESS;
}
 
cairo_status_t
_cairo_surface_fill_extents (cairo_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias,
cairo_clip_t *clip,
cairo_rectangle_int_t *extents)
{
cairo_bool_t is_empty;
 
_cairo_surface_operation_extents (surface, op, source, clip, extents);
 
if (_cairo_operator_bounded_by_mask (op)) {
cairo_rectangle_int_t mask_extents;
 
_cairo_path_fixed_fill_extents (path, fill_rule, tolerance,
&mask_extents);
is_empty = _cairo_rectangle_intersect (extents, &mask_extents);
}
 
return CAIRO_STATUS_SUCCESS;
}
 
cairo_status_t
_cairo_surface_glyphs_extents (cairo_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font,
cairo_clip_t *clip,
cairo_rectangle_int_t *extents)
{
cairo_status_t status;
cairo_bool_t is_empty;
 
_cairo_surface_operation_extents (surface, op, source, clip, extents);
 
if (_cairo_operator_bounded_by_mask (op)) {
cairo_rectangle_int_t glyph_extents;
 
status = _cairo_scaled_font_glyph_device_extents (scaled_font,
glyphs,
num_glyphs,
&glyph_extents,
NULL);
if (unlikely (status))
return status;
 
is_empty = _cairo_rectangle_intersect (extents, &glyph_extents);
}
 
return CAIRO_STATUS_SUCCESS;
}
 
cairo_surface_t *
_cairo_surface_create_in_error (cairo_status_t status)
{
switch (status) {
case CAIRO_STATUS_NO_MEMORY:
return (cairo_surface_t *) &_cairo_surface_nil;
case CAIRO_STATUS_SURFACE_TYPE_MISMATCH:
return (cairo_surface_t *) &_cairo_surface_nil_surface_type_mismatch;
case CAIRO_STATUS_INVALID_STATUS:
return (cairo_surface_t *) &_cairo_surface_nil_invalid_status;
case CAIRO_STATUS_INVALID_CONTENT:
return (cairo_surface_t *) &_cairo_surface_nil_invalid_content;
case CAIRO_STATUS_INVALID_FORMAT:
return (cairo_surface_t *) &_cairo_surface_nil_invalid_format;
case CAIRO_STATUS_INVALID_VISUAL:
return (cairo_surface_t *) &_cairo_surface_nil_invalid_visual;
case CAIRO_STATUS_READ_ERROR:
return (cairo_surface_t *) &_cairo_surface_nil_read_error;
case CAIRO_STATUS_WRITE_ERROR:
return (cairo_surface_t *) &_cairo_surface_nil_write_error;
case CAIRO_STATUS_FILE_NOT_FOUND:
return (cairo_surface_t *) &_cairo_surface_nil_file_not_found;
case CAIRO_STATUS_TEMP_FILE_ERROR:
return (cairo_surface_t *) &_cairo_surface_nil_temp_file_error;
case CAIRO_STATUS_INVALID_STRIDE:
return (cairo_surface_t *) &_cairo_surface_nil_invalid_stride;
case CAIRO_STATUS_INVALID_SIZE:
return (cairo_surface_t *) &_cairo_surface_nil_invalid_size;
case CAIRO_STATUS_DEVICE_TYPE_MISMATCH:
return (cairo_surface_t *) &_cairo_surface_nil_device_type_mismatch;
case CAIRO_STATUS_DEVICE_ERROR:
return (cairo_surface_t *) &_cairo_surface_nil_device_error;
case CAIRO_STATUS_SUCCESS:
case CAIRO_STATUS_LAST_STATUS:
ASSERT_NOT_REACHED;
/* fall-through */
case CAIRO_STATUS_INVALID_RESTORE:
case CAIRO_STATUS_INVALID_POP_GROUP:
case CAIRO_STATUS_NO_CURRENT_POINT:
case CAIRO_STATUS_INVALID_MATRIX:
case CAIRO_STATUS_NULL_POINTER:
case CAIRO_STATUS_INVALID_STRING:
case CAIRO_STATUS_INVALID_PATH_DATA:
case CAIRO_STATUS_SURFACE_FINISHED:
case CAIRO_STATUS_PATTERN_TYPE_MISMATCH:
case CAIRO_STATUS_INVALID_DASH:
case CAIRO_STATUS_INVALID_DSC_COMMENT:
case CAIRO_STATUS_INVALID_INDEX:
case CAIRO_STATUS_CLIP_NOT_REPRESENTABLE:
case CAIRO_STATUS_FONT_TYPE_MISMATCH:
case CAIRO_STATUS_USER_FONT_IMMUTABLE:
case CAIRO_STATUS_USER_FONT_ERROR:
case CAIRO_STATUS_NEGATIVE_COUNT:
case CAIRO_STATUS_INVALID_CLUSTERS:
case CAIRO_STATUS_INVALID_SLANT:
case CAIRO_STATUS_INVALID_WEIGHT:
case CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED:
default:
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_surface_t *) &_cairo_surface_nil;
}
}
 
/* LocalWords: rasterized
*/
/programs/develop/libraries/cairo/src/cairo-svg-surface-private.h
0,0 → 1,74
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2004 Red Hat, Inc
* Copyright © 2005-2006 Emmanuel Pacaud <emmanuel.pacaud@free.fr>
* Copyright © 2006 Red Hat, Inc
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Kristian Høgsberg <krh@redhat.com>
* Emmanuel Pacaud <emmanuel.pacaud@univ-poitiers.fr>
* Carl Worth <cworth@cworth.org>
*/
 
#ifndef CAIRO_SVG_SURFACE_PRIVATE_H
#define CAIRO_SVG_SURFACE_PRIVATE_H
 
#include "cairo-svg.h"
 
#include "cairo-surface-private.h"
#include "cairo-surface-clipper-private.h"
 
typedef struct cairo_svg_document cairo_svg_document_t;
 
typedef struct cairo_svg_surface {
cairo_surface_t base;
 
cairo_content_t content;
 
double width;
double height;
 
cairo_svg_document_t *document;
 
cairo_output_stream_t *xml_node;
cairo_array_t page_set;
 
cairo_surface_clipper_t clipper;
unsigned int clip_level;
unsigned int base_clip;
cairo_bool_t is_base_clip_emitted;
 
cairo_paginated_mode_t paginated_mode;
 
cairo_bool_t force_fallbacks;
} cairo_svg_surface_t;
 
#endif /* CAIRO_SVG_SURFACE_PRIVATE_H */
/programs/develop/libraries/cairo/src/cairo-svg.h
0,0 → 1,82
/* cairo - a vector graphics library with display and print output
*
* cairo-svg.h
*
* Copyright © 2005 Emmanuel Pacaud <emmanuel.pacaud@univ-poitiers.fr>
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
*/
 
#ifndef CAIRO_SVG_H
#define CAIRO_SVG_H
 
#include "cairo.h"
 
#if CAIRO_HAS_SVG_SURFACE
 
CAIRO_BEGIN_DECLS
 
/**
* cairo_svg_version_t:
* @CAIRO_SVG_VERSION_1_1: The version 1.1 of the SVG specification.
* @CAIRO_SVG_VERSION_1_2: The version 1.2 of the SVG specification.
*
* #cairo_svg_version_t is used to describe the version number of the SVG
* specification that a generated SVG file will conform to.
*/
typedef enum _cairo_svg_version {
CAIRO_SVG_VERSION_1_1,
CAIRO_SVG_VERSION_1_2
} cairo_svg_version_t;
 
cairo_public cairo_surface_t *
cairo_svg_surface_create (const char *filename,
double width_in_points,
double height_in_points);
 
cairo_public cairo_surface_t *
cairo_svg_surface_create_for_stream (cairo_write_func_t write_func,
void *closure,
double width_in_points,
double height_in_points);
 
cairo_public void
cairo_svg_surface_restrict_to_version (cairo_surface_t *surface,
cairo_svg_version_t version);
 
cairo_public void
cairo_svg_get_versions (cairo_svg_version_t const **versions,
int *num_versions);
 
cairo_public const char *
cairo_svg_version_to_string (cairo_svg_version_t version);
 
CAIRO_END_DECLS
 
#else /* CAIRO_HAS_SVG_SURFACE */
# error Cairo was not compiled with support for the svg backend
#endif /* CAIRO_HAS_SVG_SURFACE */
 
#endif /* CAIRO_SVG_H */
/programs/develop/libraries/cairo/src/cairo-tee-surface-private.h
0,0 → 1,47
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2009 Chris Wilson
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Chris Wilson <chris@chris-wilson.co.uk>
*/
 
#ifndef CAIRO_TEE_SURFACE_PRIVATE_H
#define CAIRO_TEE_SURFACE_PRIVATE_H
 
#include "cairoint.h"
 
cairo_private cairo_surface_t *
_cairo_tee_surface_find_match (void *abstract_surface,
const cairo_surface_backend_t *backend,
cairo_content_t content);
 
#endif /* CAIRO_TEE_SURFACE_PRIVATE_H */
/programs/develop/libraries/cairo/src/cairo-tee.h
0,0 → 1,66
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2009 Chris Wilson
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Chris Wilson
*
* Contributor(s):
* Chris Wilson <chris@chris-wilson.co.uk>
*/
 
#ifndef CAIRO_TEE_H
#define CAIRO_TEE_H
 
#include "cairo.h"
 
#if CAIRO_HAS_TEE_SURFACE
 
CAIRO_BEGIN_DECLS
 
cairo_public cairo_surface_t *
cairo_tee_surface_create (cairo_surface_t *master);
 
cairo_public void
cairo_tee_surface_add (cairo_surface_t *surface,
cairo_surface_t *target);
 
cairo_public void
cairo_tee_surface_remove (cairo_surface_t *surface,
cairo_surface_t *target);
 
cairo_public cairo_surface_t *
cairo_tee_surface_index (cairo_surface_t *surface,
int index);
 
CAIRO_END_DECLS
 
#else /*CAIRO_HAS_TEE_SURFACE*/
# error Cairo was not compiled with support for the TEE backend
#endif /*CAIRO_HAS_TEE_SURFACE*/
 
#endif /*CAIRO_TEE_H*/
/programs/develop/libraries/cairo/src/cairo-tor-scan-converter.c
0,0 → 1,2169
/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
/* glitter-paths - polygon scan converter
*
* Copyright (c) 2008 M Joonas Pihlaja
* Copyright (c) 2007 David Turner
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
/* This is the Glitter paths scan converter incorporated into cairo.
* The source is from commit 734c53237a867a773640bd5b64816249fa1730f8
* of
*
* http://gitweb.freedesktop.org/?p=users/joonas/glitter-paths
*/
/* Glitter-paths is a stand alone polygon rasteriser derived from
* David Turner's reimplementation of Tor Anderssons's 15x17
* supersampling rasteriser from the Apparition graphics library. The
* main new feature here is cheaply choosing per-scan line between
* doing fully analytical coverage computation for an entire row at a
* time vs. using a supersampling approach.
*
* David Turner's code can be found at
*
* http://david.freetype.org/rasterizer-shootout/raster-comparison-20070813.tar.bz2
*
* In particular this file incorporates large parts of ftgrays_tor10.h
* from raster-comparison-20070813.tar.bz2
*/
/* Overview
*
* A scan converter's basic purpose to take polygon edges and convert
* them into an RLE compressed A8 mask. This one works in two phases:
* gathering edges and generating spans.
*
* 1) As the user feeds the scan converter edges they are vertically
* clipped and bucketted into a _polygon_ data structure. The edges
* are also snapped from the user's coordinates to the subpixel grid
* coordinates used during scan conversion.
*
* user
* |
* | edges
* V
* polygon buckets
*
* 2) Generating spans works by performing a vertical sweep of pixel
* rows from top to bottom and maintaining an _active_list_ of edges
* that intersect the row. From the active list the fill rule
* determines which edges are the left and right edges of the start of
* each span, and their contribution is then accumulated into a pixel
* coverage list (_cell_list_) as coverage deltas. Once the coverage
* deltas of all edges are known we can form spans of constant pixel
* coverage by summing the deltas during a traversal of the cell list.
* At the end of a pixel row the cell list is sent to a coverage
* blitter for rendering to some target surface.
*
* The pixel coverages are computed by either supersampling the row
* and box filtering a mono rasterisation, or by computing the exact
* coverages of edges in the active list. The supersampling method is
* used whenever some edge starts or stops within the row or there are
* edge intersections in the row.
*
* polygon bucket for \
* current pixel row |
* | |
* | activate new edges | Repeat GRID_Y times if we
* V \ are supersampling this row,
* active list / or just once if we're computing
* | | analytical coverage.
* | coverage deltas |
* V |
* pixel coverage list /
* |
* V
* coverage blitter
*/
#include "cairoint.h"
#include "cairo-spans-private.h"
#include "cairo-error-private.h"
 
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
 
/*-------------------------------------------------------------------------
* cairo specific config
*/
#define I static
 
/* Prefer cairo's status type. */
#define GLITTER_HAVE_STATUS_T 1
#define GLITTER_STATUS_SUCCESS CAIRO_STATUS_SUCCESS
#define GLITTER_STATUS_NO_MEMORY CAIRO_STATUS_NO_MEMORY
typedef cairo_status_t glitter_status_t;
 
/* The input coordinate scale and the rasterisation grid scales. */
#define GLITTER_INPUT_BITS CAIRO_FIXED_FRAC_BITS
#define GRID_X_BITS CAIRO_FIXED_FRAC_BITS
#define GRID_Y 15
 
/* Set glitter up to use a cairo span renderer to do the coverage
* blitting. */
struct pool;
struct cell_list;
 
static glitter_status_t
blit_with_span_renderer(
struct cell_list *coverages,
cairo_span_renderer_t *span_renderer,
struct pool *span_pool,
int y,
int height,
int xmin,
int xmax);
 
static glitter_status_t
blit_empty_with_span_renderer (cairo_span_renderer_t *renderer, int y, int height);
 
#define GLITTER_BLIT_COVERAGES_ARGS \
cairo_span_renderer_t *span_renderer, \
struct pool *span_pool
 
#define GLITTER_BLIT_COVERAGES(cells, y, height,xmin, xmax) do { \
cairo_status_t status = blit_with_span_renderer (cells, \
span_renderer, \
span_pool, \
y, height, \
xmin, xmax); \
if (unlikely (status)) \
return status; \
} while (0)
 
#define GLITTER_BLIT_COVERAGES_EMPTY(y, height, xmin, xmax) do { \
cairo_status_t status = blit_empty_with_span_renderer (span_renderer, y, height); \
if (unlikely (status)) \
return status; \
} while (0)
 
/*-------------------------------------------------------------------------
* glitter-paths.h
*/
 
/* "Input scaled" numbers are fixed precision reals with multiplier
* 2**GLITTER_INPUT_BITS. Input coordinates are given to glitter as
* pixel scaled numbers. These get converted to the internal grid
* scaled numbers as soon as possible. Internal overflow is possible
* if GRID_X/Y inside glitter-paths.c is larger than
* 1<<GLITTER_INPUT_BITS. */
#ifndef GLITTER_INPUT_BITS
# define GLITTER_INPUT_BITS 8
#endif
#define GLITTER_INPUT_SCALE (1<<GLITTER_INPUT_BITS)
typedef int glitter_input_scaled_t;
 
#if !GLITTER_HAVE_STATUS_T
typedef enum {
GLITTER_STATUS_SUCCESS = 0,
GLITTER_STATUS_NO_MEMORY
} glitter_status_t;
#endif
 
#ifndef I
# define I /*static*/
#endif
 
/* Opaque type for scan converting. */
typedef struct glitter_scan_converter glitter_scan_converter_t;
 
/* Reset a scan converter to accept polygon edges and set the clip box
* in pixels. Allocates O(ymax-ymin) bytes of memory. The clip box
* is set to integer pixel coordinates xmin <= x < xmax, ymin <= y <
* ymax. */
I glitter_status_t
glitter_scan_converter_reset(
glitter_scan_converter_t *converter,
int xmin, int ymin,
int xmax, int ymax);
 
/* Add a new polygon edge from pixel (x1,y1) to (x2,y2) to the scan
* converter. The coordinates represent pixel positions scaled by
* 2**GLITTER_PIXEL_BITS. If this function fails then the scan
* converter should be reset or destroyed. Dir must be +1 or -1,
* with the latter reversing the orientation of the edge. */
I glitter_status_t
glitter_scan_converter_add_edge (glitter_scan_converter_t *converter,
const cairo_edge_t *edge);
 
/* Render the polygon in the scan converter to the given A8 format
* image raster. Only the pixels accessible as pixels[y*stride+x] for
* x,y inside the clip box are written to, where xmin <= x < xmax,
* ymin <= y < ymax. The image is assumed to be clear on input.
*
* If nonzero_fill is true then the interior of the polygon is
* computed with the non-zero fill rule. Otherwise the even-odd fill
* rule is used.
*
* The scan converter must be reset or destroyed after this call. */
#ifndef GLITTER_BLIT_COVERAGES_ARGS
# define GLITTER_BLIT_COVERAGES_ARGS unsigned char *raster_pixels, long raster_stride
#endif
I glitter_status_t
glitter_scan_converter_render(
glitter_scan_converter_t *converter,
int nonzero_fill,
GLITTER_BLIT_COVERAGES_ARGS);
 
/*-------------------------------------------------------------------------
* glitter-paths.c: Implementation internal types
*/
#include <stdlib.h>
#include <string.h>
#include <limits.h>
 
/* All polygon coordinates are snapped onto a subsample grid. "Grid
* scaled" numbers are fixed precision reals with multiplier GRID_X or
* GRID_Y. */
typedef int grid_scaled_t;
typedef int grid_scaled_x_t;
typedef int grid_scaled_y_t;
 
/* Default x/y scale factors.
* You can either define GRID_X/Y_BITS to get a power-of-two scale
* or define GRID_X/Y separately. */
#if !defined(GRID_X) && !defined(GRID_X_BITS)
# define GRID_X_BITS 8
#endif
#if !defined(GRID_Y) && !defined(GRID_Y_BITS)
# define GRID_Y 15
#endif
 
/* Use GRID_X/Y_BITS to define GRID_X/Y if they're available. */
#ifdef GRID_X_BITS
# define GRID_X (1 << GRID_X_BITS)
#endif
#ifdef GRID_Y_BITS
# define GRID_Y (1 << GRID_Y_BITS)
#endif
 
/* The GRID_X_TO_INT_FRAC macro splits a grid scaled coordinate into
* integer and fractional parts. The integer part is floored. */
#if defined(GRID_X_TO_INT_FRAC)
/* do nothing */
#elif defined(GRID_X_BITS)
# define GRID_X_TO_INT_FRAC(x, i, f) \
_GRID_TO_INT_FRAC_shift(x, i, f, GRID_X_BITS)
#else
# define GRID_X_TO_INT_FRAC(x, i, f) \
_GRID_TO_INT_FRAC_general(x, i, f, GRID_X)
#endif
 
#define _GRID_TO_INT_FRAC_general(t, i, f, m) do { \
(i) = (t) / (m); \
(f) = (t) % (m); \
if ((f) < 0) { \
--(i); \
(f) += (m); \
} \
} while (0)
 
#define _GRID_TO_INT_FRAC_shift(t, i, f, b) do { \
(f) = (t) & ((1 << (b)) - 1); \
(i) = (t) >> (b); \
} while (0)
 
/* A grid area is a real in [0,1] scaled by 2*GRID_X*GRID_Y. We want
* to be able to represent exactly areas of subpixel trapezoids whose
* vertices are given in grid scaled coordinates. The scale factor
* comes from needing to accurately represent the area 0.5*dx*dy of a
* triangle with base dx and height dy in grid scaled numbers. */
typedef int grid_area_t;
#define GRID_XY (2*GRID_X*GRID_Y) /* Unit area on the grid. */
 
/* GRID_AREA_TO_ALPHA(area): map [0,GRID_XY] to [0,255]. */
#if GRID_XY == 510
# define GRID_AREA_TO_ALPHA(c) (((c)+1) >> 1)
#elif GRID_XY == 255
# define GRID_AREA_TO_ALPHA(c) (c)
#elif GRID_XY == 64
# define GRID_AREA_TO_ALPHA(c) (((c) << 2) | -(((c) & 0x40) >> 6))
#elif GRID_XY == 128
# define GRID_AREA_TO_ALPHA(c) ((((c) << 1) | -((c) >> 7)) & 255)
#elif GRID_XY == 256
# define GRID_AREA_TO_ALPHA(c) (((c) | -((c) >> 8)) & 255)
#elif GRID_XY == 15
# define GRID_AREA_TO_ALPHA(c) (((c) << 4) + (c))
#elif GRID_XY == 2*256*15
# define GRID_AREA_TO_ALPHA(c) (((c) + ((c)<<4) + 256) >> 9)
#else
# define GRID_AREA_TO_ALPHA(c) (((c)*255 + GRID_XY/2) / GRID_XY)
#endif
 
#define UNROLL3(x) x x x
 
struct quorem {
int32_t quo;
int32_t rem;
};
 
/* Header for a chunk of memory in a memory pool. */
struct _pool_chunk {
/* # bytes used in this chunk. */
size_t size;
 
/* # bytes total in this chunk */
size_t capacity;
 
/* Pointer to the previous chunk or %NULL if this is the sentinel
* chunk in the pool header. */
struct _pool_chunk *prev_chunk;
 
/* Actual data starts here. Well aligned for pointers. */
};
 
/* A memory pool. This is supposed to be embedded on the stack or
* within some other structure. It may optionally be followed by an
* embedded array from which requests are fulfilled until
* malloc needs to be called to allocate a first real chunk. */
struct pool {
/* Chunk we're allocating from. */
struct _pool_chunk *current;
 
/* Free list of previously allocated chunks. All have >= default
* capacity. */
struct _pool_chunk *first_free;
 
/* The default capacity of a chunk. */
size_t default_capacity;
 
/* Header for the sentinel chunk. Directly following the pool
* struct should be some space for embedded elements from which
* the sentinel chunk allocates from. */
struct _pool_chunk sentinel[1];
};
 
/* A polygon edge. */
struct edge {
/* Next in y-bucket or active list. */
struct edge *next;
 
/* Current x coordinate while the edge is on the active
* list. Initialised to the x coordinate of the top of the
* edge. The quotient is in grid_scaled_x_t units and the
* remainder is mod dy in grid_scaled_y_t units.*/
struct quorem x;
 
/* Advance of the current x when moving down a subsample line. */
struct quorem dxdy;
 
/* Advance of the current x when moving down a full pixel
* row. Only initialised when the height of the edge is large
* enough that there's a chance the edge could be stepped by a
* full row's worth of subsample rows at a time. */
struct quorem dxdy_full;
 
/* The clipped y of the top of the edge. */
grid_scaled_y_t ytop;
 
/* y2-y1 after orienting the edge downwards. */
grid_scaled_y_t dy;
 
/* Number of subsample rows remaining to scan convert of this
* edge. */
grid_scaled_y_t height_left;
 
/* Original sign of the edge: +1 for downwards, -1 for upwards
* edges. */
int dir;
int vertical;
};
 
/* Number of subsample rows per y-bucket. Must be GRID_Y. */
#define EDGE_Y_BUCKET_HEIGHT GRID_Y
 
#define EDGE_Y_BUCKET_INDEX(y, ymin) (((y) - (ymin))/EDGE_Y_BUCKET_HEIGHT)
 
/* A collection of sorted and vertically clipped edges of the polygon.
* Edges are moved from the polygon to an active list while scan
* converting. */
struct polygon {
/* The vertical clip extents. */
grid_scaled_y_t ymin, ymax;
 
/* Array of edges all starting in the same bucket. An edge is put
* into bucket EDGE_BUCKET_INDEX(edge->ytop, polygon->ymin) when
* it is added to the polygon. */
struct edge **y_buckets;
struct edge *y_buckets_embedded[64];
 
struct {
struct pool base[1];
struct edge embedded[32];
} edge_pool;
};
 
/* A cell records the effect on pixel coverage of polygon edges
* passing through a pixel. It contains two accumulators of pixel
* coverage.
*
* Consider the effects of a polygon edge on the coverage of a pixel
* it intersects and that of the following one. The coverage of the
* following pixel is the height of the edge multiplied by the width
* of the pixel, and the coverage of the pixel itself is the area of
* the trapezoid formed by the edge and the right side of the pixel.
*
* +-----------------------+-----------------------+
* | | |
* | | |
* |_______________________|_______________________|
* | \...................|.......................|\
* | \..................|.......................| |
* | \.................|.......................| |
* | \....covered.....|.......................| |
* | \....area.......|.......................| } covered height
* | \..............|.......................| |
* |uncovered\.............|.......................| |
* | area \............|.......................| |
* |___________\...........|.......................|/
* | | |
* | | |
* | | |
* +-----------------------+-----------------------+
*
* Since the coverage of the following pixel will always be a multiple
* of the width of the pixel, we can store the height of the covered
* area instead. The coverage of the pixel itself is the total
* coverage minus the area of the uncovered area to the left of the
* edge. As it's faster to compute the uncovered area we only store
* that and subtract it from the total coverage later when forming
* spans to blit.
*
* The heights and areas are signed, with left edges of the polygon
* having positive sign and right edges having negative sign. When
* two edges intersect they swap their left/rightness so their
* contribution above and below the intersection point must be
* computed separately. */
struct cell {
struct cell *next;
int x;
grid_area_t uncovered_area;
grid_scaled_y_t covered_height;
};
 
/* A cell list represents the scan line sparsely as cells ordered by
* ascending x. It is geared towards scanning the cells in order
* using an internal cursor. */
struct cell_list {
/* Points to the left-most cell in the scan line. */
struct cell *head;
/* Sentinel node */
struct cell tail;
 
/* Cursor state for iterating through the cell list. Points to
* a pointer to the current cell: either &cell_list->head or the next
* field of the previous cell. */
struct cell **cursor;
 
/* Cells in the cell list are owned by the cell list and are
* allocated from this pool. */
struct {
struct pool base[1];
struct cell embedded[32];
} cell_pool;
};
 
struct cell_pair {
struct cell *cell1;
struct cell *cell2;
};
 
/* The active list contains edges in the current scan line ordered by
* the x-coordinate of the intercept of the edge and the scan line. */
struct active_list {
/* Leftmost edge on the current scan line. */
struct edge *head;
 
/* A lower bound on the height of the active edges is used to
* estimate how soon some active edge ends. We can't advance the
* scan conversion by a full pixel row if an edge ends somewhere
* within it. */
grid_scaled_y_t min_height;
};
 
struct glitter_scan_converter {
struct polygon polygon[1];
struct active_list active[1];
struct cell_list coverages[1];
 
/* Clip box. */
grid_scaled_x_t xmin, xmax;
grid_scaled_y_t ymin, ymax;
};
 
/* Compute the floored division a/b. Assumes / and % perform symmetric
* division. */
inline static struct quorem
floored_divrem(int a, int b)
{
struct quorem qr;
qr.quo = a/b;
qr.rem = a%b;
if ((a^b)<0 && qr.rem) {
qr.quo -= 1;
qr.rem += b;
}
return qr;
}
 
/* Compute the floored division (x*a)/b. Assumes / and % perform symmetric
* division. */
static struct quorem
floored_muldivrem(int x, int a, int b)
{
struct quorem qr;
long long xa = (long long)x*a;
qr.quo = xa/b;
qr.rem = xa%b;
if ((xa>=0) != (b>=0) && qr.rem) {
qr.quo -= 1;
qr.rem += b;
}
return qr;
}
 
static void
_pool_chunk_init(
struct _pool_chunk *p,
struct _pool_chunk *prev_chunk,
size_t capacity)
{
p->prev_chunk = prev_chunk;
p->size = 0;
p->capacity = capacity;
}
 
static struct _pool_chunk *
_pool_chunk_create(
struct _pool_chunk *prev_chunk,
size_t size)
{
struct _pool_chunk *p;
size_t size_with_head = size + sizeof(struct _pool_chunk);
if (size_with_head < size)
return NULL;
p = malloc(size_with_head);
if (p)
_pool_chunk_init(p, prev_chunk, size);
return p;
}
 
static void
pool_init(
struct pool *pool,
size_t default_capacity,
size_t embedded_capacity)
{
pool->current = pool->sentinel;
pool->first_free = NULL;
pool->default_capacity = default_capacity;
_pool_chunk_init(pool->sentinel, NULL, embedded_capacity);
}
 
static void
pool_fini(struct pool *pool)
{
struct _pool_chunk *p = pool->current;
do {
while (NULL != p) {
struct _pool_chunk *prev = p->prev_chunk;
if (p != pool->sentinel)
free(p);
p = prev;
}
p = pool->first_free;
pool->first_free = NULL;
} while (NULL != p);
pool_init(pool, 0, 0);
}
 
/* Satisfy an allocation by first allocating a new large enough chunk
* and adding it to the head of the pool's chunk list. This function
* is called as a fallback if pool_alloc() couldn't do a quick
* allocation from the current chunk in the pool. */
static void *
_pool_alloc_from_new_chunk(
struct pool *pool,
size_t size)
{
struct _pool_chunk *chunk;
void *obj;
size_t capacity;
 
/* If the allocation is smaller than the default chunk size then
* try getting a chunk off the free list. Force alloc of a new
* chunk for large requests. */
capacity = size;
chunk = NULL;
if (size < pool->default_capacity) {
capacity = pool->default_capacity;
chunk = pool->first_free;
if (chunk) {
pool->first_free = chunk->prev_chunk;
_pool_chunk_init(chunk, pool->current, chunk->capacity);
}
}
 
if (NULL == chunk) {
chunk = _pool_chunk_create (pool->current, capacity);
if (unlikely (NULL == chunk))
return NULL;
}
pool->current = chunk;
 
obj = ((unsigned char*)chunk + sizeof(*chunk) + chunk->size);
chunk->size += size;
return obj;
}
 
/* Allocate size bytes from the pool. The first allocated address
* returned from a pool is aligned to sizeof(void*). Subsequent
* addresses will maintain alignment as long as multiples of void* are
* allocated. Returns the address of a new memory area or %NULL on
* allocation failures. The pool retains ownership of the returned
* memory. */
inline static void *
pool_alloc (struct pool *pool, size_t size)
{
struct _pool_chunk *chunk = pool->current;
 
if (size <= chunk->capacity - chunk->size) {
void *obj = ((unsigned char*)chunk + sizeof(*chunk) + chunk->size);
chunk->size += size;
return obj;
} else {
return _pool_alloc_from_new_chunk(pool, size);
}
}
 
/* Relinquish all pool_alloced memory back to the pool. */
static void
pool_reset (struct pool *pool)
{
/* Transfer all used chunks to the chunk free list. */
struct _pool_chunk *chunk = pool->current;
if (chunk != pool->sentinel) {
while (chunk->prev_chunk != pool->sentinel) {
chunk = chunk->prev_chunk;
}
chunk->prev_chunk = pool->first_free;
pool->first_free = pool->current;
}
/* Reset the sentinel as the current chunk. */
pool->current = pool->sentinel;
pool->sentinel->size = 0;
}
 
/* Rewinds the cell list's cursor to the beginning. After rewinding
* we're good to cell_list_find() the cell any x coordinate. */
inline static void
cell_list_rewind (struct cell_list *cells)
{
cells->cursor = &cells->head;
}
 
/* Rewind the cell list if its cursor has been advanced past x. */
inline static void
cell_list_maybe_rewind (struct cell_list *cells, int x)
{
struct cell *tail = *cells->cursor;
if (tail->x > x)
cell_list_rewind (cells);
}
 
static void
cell_list_init(struct cell_list *cells)
{
pool_init(cells->cell_pool.base,
256*sizeof(struct cell),
sizeof(cells->cell_pool.embedded));
cells->tail.next = NULL;
cells->tail.x = INT_MAX;
cells->head = &cells->tail;
cell_list_rewind (cells);
}
 
static void
cell_list_fini(struct cell_list *cells)
{
pool_fini (cells->cell_pool.base);
}
 
/* Empty the cell list. This is called at the start of every pixel
* row. */
inline static void
cell_list_reset (struct cell_list *cells)
{
cell_list_rewind (cells);
cells->head = &cells->tail;
pool_reset (cells->cell_pool.base);
}
 
static struct cell *
cell_list_alloc (struct cell_list *cells,
struct cell **cursor,
struct cell *tail,
int x)
{
struct cell *cell;
 
cell = pool_alloc (cells->cell_pool.base, sizeof (struct cell));
if (unlikely (NULL == cell))
return NULL;
 
*cursor = cell;
cell->next = tail;
cell->x = x;
cell->uncovered_area = 0;
cell->covered_height = 0;
return cell;
}
 
/* Find a cell at the given x-coordinate. Returns %NULL if a new cell
* needed to be allocated but couldn't be. Cells must be found with
* non-decreasing x-coordinate until the cell list is rewound using
* cell_list_rewind(). Ownership of the returned cell is retained by
* the cell list. */
inline static struct cell *
cell_list_find (struct cell_list *cells, int x)
{
struct cell **cursor = cells->cursor;
struct cell *tail;
 
while (1) {
UNROLL3({
tail = *cursor;
if (tail->x >= x) {
break;
}
cursor = &tail->next;
});
}
cells->cursor = cursor;
 
if (tail->x == x)
return tail;
 
return cell_list_alloc (cells, cursor, tail, x);
}
 
/* Find two cells at x1 and x2. This is exactly equivalent
* to
*
* pair.cell1 = cell_list_find(cells, x1);
* pair.cell2 = cell_list_find(cells, x2);
*
* except with less function call overhead. */
inline static struct cell_pair
cell_list_find_pair(struct cell_list *cells, int x1, int x2)
{
struct cell_pair pair;
struct cell **cursor = cells->cursor;
struct cell *cell1;
struct cell *cell2;
struct cell *newcell;
 
/* Find first cell at x1. */
while (1) {
UNROLL3({
cell1 = *cursor;
if (cell1->x > x1)
break;
 
if (cell1->x == x1)
goto found_first;
 
cursor = &cell1->next;
});
}
 
/* New first cell at x1. */
newcell = pool_alloc (cells->cell_pool.base,
sizeof (struct cell));
if (likely (NULL != newcell)) {
*cursor = newcell;
newcell->next = cell1;
newcell->x = x1;
newcell->uncovered_area = 0;
newcell->covered_height = 0;
}
cell1 = newcell;
found_first:
 
/* Find second cell at x2. */
while (1) {
UNROLL3({
cell2 = *cursor;
if (cell2->x > x2)
break;
if (cell2->x == x2)
goto found_second;
cursor = &cell2->next;
});
}
 
/* New second cell at x2. */
newcell = pool_alloc (cells->cell_pool.base,
sizeof (struct cell));
if (likely (NULL != newcell)) {
*cursor = newcell;
newcell->next = cell2;
newcell->x = x2;
newcell->uncovered_area = 0;
newcell->covered_height = 0;
}
cell2 = newcell;
found_second:
 
cells->cursor = cursor;
pair.cell1 = cell1;
pair.cell2 = cell2;
return pair;
}
 
/* Add an unbounded subpixel span covering subpixels >= x to the
* coverage cells. */
static glitter_status_t
cell_list_add_unbounded_subspan (struct cell_list *cells,
grid_scaled_x_t x)
{
struct cell *cell;
int ix, fx;
 
GRID_X_TO_INT_FRAC(x, ix, fx);
 
cell = cell_list_find (cells, ix);
if (likely (cell != NULL)) {
cell->uncovered_area += 2*fx;
cell->covered_height++;
return GLITTER_STATUS_SUCCESS;
}
 
return GLITTER_STATUS_NO_MEMORY;
}
 
/* Add a subpixel span covering [x1, x2) to the coverage cells. */
inline static glitter_status_t
cell_list_add_subspan(
struct cell_list *cells,
grid_scaled_x_t x1,
grid_scaled_x_t x2)
{
int ix1, fx1;
int ix2, fx2;
 
GRID_X_TO_INT_FRAC(x1, ix1, fx1);
GRID_X_TO_INT_FRAC(x2, ix2, fx2);
 
if (ix1 != ix2) {
struct cell_pair p;
p = cell_list_find_pair(cells, ix1, ix2);
if (likely (p.cell1 != NULL && p.cell2 != NULL)) {
p.cell1->uncovered_area += 2*fx1;
++p.cell1->covered_height;
p.cell2->uncovered_area -= 2*fx2;
--p.cell2->covered_height;
return GLITTER_STATUS_SUCCESS;
}
} else {
struct cell *cell = cell_list_find(cells, ix1);
if (likely (cell != NULL)) {
cell->uncovered_area += 2*(fx1-fx2);
return GLITTER_STATUS_SUCCESS;
}
}
return GLITTER_STATUS_NO_MEMORY;
}
 
/* Adds the analytical coverage of an edge crossing the current pixel
* row to the coverage cells and advances the edge's x position to the
* following row.
*
* This function is only called when we know that during this pixel row:
*
* 1) The relative order of all edges on the active list doesn't
* change. In particular, no edges intersect within this row to pixel
* precision.
*
* 2) No new edges start in this row.
*
* 3) No existing edges end mid-row.
*
* This function depends on being called with all edges from the
* active list in the order they appear on the list (i.e. with
* non-decreasing x-coordinate.) */
static glitter_status_t
cell_list_render_edge(
struct cell_list *cells,
struct edge *edge,
int sign)
{
grid_scaled_y_t y1, y2, dy;
grid_scaled_x_t dx;
int ix1, ix2;
grid_scaled_x_t fx1, fx2;
 
struct quorem x1 = edge->x;
struct quorem x2 = x1;
 
if (! edge->vertical) {
x2.quo += edge->dxdy_full.quo;
x2.rem += edge->dxdy_full.rem;
if (x2.rem >= 0) {
++x2.quo;
x2.rem -= edge->dy;
}
 
edge->x = x2;
}
 
GRID_X_TO_INT_FRAC(x1.quo, ix1, fx1);
GRID_X_TO_INT_FRAC(x2.quo, ix2, fx2);
 
/* Edge is entirely within a column? */
if (ix1 == ix2) {
/* We always know that ix1 is >= the cell list cursor in this
* case due to the no-intersections precondition. */
struct cell *cell = cell_list_find(cells, ix1);
if (unlikely (NULL == cell))
return GLITTER_STATUS_NO_MEMORY;
 
cell->covered_height += sign*GRID_Y;
cell->uncovered_area += sign*(fx1 + fx2)*GRID_Y;
return GLITTER_STATUS_SUCCESS;
}
 
/* Orient the edge left-to-right. */
dx = x2.quo - x1.quo;
if (dx >= 0) {
y1 = 0;
y2 = GRID_Y;
} else {
int tmp;
tmp = ix1; ix1 = ix2; ix2 = tmp;
tmp = fx1; fx1 = fx2; fx2 = tmp;
dx = -dx;
sign = -sign;
y1 = GRID_Y;
y2 = 0;
}
dy = y2 - y1;
 
/* Add coverage for all pixels [ix1,ix2] on this row crossed
* by the edge. */
{
struct cell_pair pair;
struct quorem y = floored_divrem((GRID_X - fx1)*dy, dx);
 
/* When rendering a previous edge on the active list we may
* advance the cell list cursor past the leftmost pixel of the
* current edge even though the two edges don't intersect.
* e.g. consider two edges going down and rightwards:
*
* --\_+---\_+-----+-----+----
* \_ \_ | |
* | \_ | \_ | |
* | \_| \_| |
* | \_ \_ |
* ----+-----+-\---+-\---+----
*
* The left edge touches cells past the starting cell of the
* right edge. Fortunately such cases are rare.
*
* The rewinding is never necessary if the current edge stays
* within a single column because we've checked before calling
* this function that the active list order won't change. */
cell_list_maybe_rewind(cells, ix1);
 
pair = cell_list_find_pair(cells, ix1, ix1+1);
if (unlikely (!pair.cell1 || !pair.cell2))
return GLITTER_STATUS_NO_MEMORY;
 
pair.cell1->uncovered_area += sign*y.quo*(GRID_X + fx1);
pair.cell1->covered_height += sign*y.quo;
y.quo += y1;
 
if (ix1+1 < ix2) {
struct quorem dydx_full = floored_divrem(GRID_X*dy, dx);
struct cell *cell = pair.cell2;
 
++ix1;
do {
grid_scaled_y_t y_skip = dydx_full.quo;
y.rem += dydx_full.rem;
if (y.rem >= dx) {
++y_skip;
y.rem -= dx;
}
 
y.quo += y_skip;
 
y_skip *= sign;
cell->uncovered_area += y_skip*GRID_X;
cell->covered_height += y_skip;
 
++ix1;
cell = cell_list_find(cells, ix1);
if (unlikely (NULL == cell))
return GLITTER_STATUS_NO_MEMORY;
} while (ix1 != ix2);
 
pair.cell2 = cell;
}
pair.cell2->uncovered_area += sign*(y2 - y.quo)*fx2;
pair.cell2->covered_height += sign*(y2 - y.quo);
}
 
return GLITTER_STATUS_SUCCESS;
}
 
static void
polygon_init (struct polygon *polygon)
{
polygon->ymin = polygon->ymax = 0;
polygon->y_buckets = polygon->y_buckets_embedded;
pool_init (polygon->edge_pool.base,
8192 - sizeof (struct _pool_chunk),
sizeof (polygon->edge_pool.embedded));
}
 
static void
polygon_fini (struct polygon *polygon)
{
if (polygon->y_buckets != polygon->y_buckets_embedded)
free (polygon->y_buckets);
 
pool_fini (polygon->edge_pool.base);
}
 
/* Empties the polygon of all edges. The polygon is then prepared to
* receive new edges and clip them to the vertical range
* [ymin,ymax). */
static glitter_status_t
polygon_reset (struct polygon *polygon,
grid_scaled_y_t ymin,
grid_scaled_y_t ymax)
{
unsigned h = ymax - ymin;
unsigned num_buckets = EDGE_Y_BUCKET_INDEX(ymax + EDGE_Y_BUCKET_HEIGHT-1,
ymin);
 
pool_reset(polygon->edge_pool.base);
 
if (unlikely (h > 0x7FFFFFFFU - EDGE_Y_BUCKET_HEIGHT))
goto bail_no_mem; /* even if you could, you wouldn't want to. */
 
if (polygon->y_buckets != polygon->y_buckets_embedded)
free (polygon->y_buckets);
 
polygon->y_buckets = polygon->y_buckets_embedded;
if (num_buckets > ARRAY_LENGTH (polygon->y_buckets_embedded)) {
polygon->y_buckets = _cairo_malloc_ab (num_buckets,
sizeof (struct edge *));
if (unlikely (NULL == polygon->y_buckets))
goto bail_no_mem;
}
memset (polygon->y_buckets, 0, num_buckets * sizeof (struct edge *));
 
polygon->ymin = ymin;
polygon->ymax = ymax;
return GLITTER_STATUS_SUCCESS;
 
bail_no_mem:
polygon->ymin = 0;
polygon->ymax = 0;
return GLITTER_STATUS_NO_MEMORY;
}
 
static void
_polygon_insert_edge_into_its_y_bucket(
struct polygon *polygon,
struct edge *e)
{
unsigned ix = EDGE_Y_BUCKET_INDEX(e->ytop, polygon->ymin);
struct edge **ptail = &polygon->y_buckets[ix];
e->next = *ptail;
*ptail = e;
}
 
inline static glitter_status_t
polygon_add_edge (struct polygon *polygon,
const cairo_edge_t *edge)
{
struct edge *e;
grid_scaled_x_t dx;
grid_scaled_y_t dy;
grid_scaled_y_t ytop, ybot;
grid_scaled_y_t ymin = polygon->ymin;
grid_scaled_y_t ymax = polygon->ymax;
 
assert (edge->bottom > edge->top);
 
if (unlikely (edge->top >= ymax || edge->bottom <= ymin))
return GLITTER_STATUS_SUCCESS;
 
e = pool_alloc (polygon->edge_pool.base, sizeof (struct edge));
if (unlikely (NULL == e))
return GLITTER_STATUS_NO_MEMORY;
 
dx = edge->line.p2.x - edge->line.p1.x;
dy = edge->line.p2.y - edge->line.p1.y;
e->dy = dy;
e->dir = edge->dir;
 
ytop = edge->top >= ymin ? edge->top : ymin;
ybot = edge->bottom <= ymax ? edge->bottom : ymax;
e->ytop = ytop;
e->height_left = ybot - ytop;
 
if (dx == 0) {
e->vertical = TRUE;
e->x.quo = edge->line.p1.x;
e->x.rem = 0;
e->dxdy.quo = 0;
e->dxdy.rem = 0;
e->dxdy_full.quo = 0;
e->dxdy_full.rem = 0;
} else {
e->vertical = FALSE;
e->dxdy = floored_divrem (dx, dy);
if (ytop == edge->line.p1.y) {
e->x.quo = edge->line.p1.x;
e->x.rem = 0;
} else {
e->x = floored_muldivrem (ytop - edge->line.p1.y, dx, dy);
e->x.quo += edge->line.p1.x;
}
 
if (e->height_left >= GRID_Y) {
e->dxdy_full = floored_muldivrem (GRID_Y, dx, dy);
} else {
e->dxdy_full.quo = 0;
e->dxdy_full.rem = 0;
}
}
 
_polygon_insert_edge_into_its_y_bucket (polygon, e);
 
e->x.rem -= dy; /* Bias the remainder for faster
* edge advancement. */
return GLITTER_STATUS_SUCCESS;
}
 
static void
active_list_reset (struct active_list *active)
{
active->head = NULL;
active->min_height = 0;
}
 
static void
active_list_init(struct active_list *active)
{
active_list_reset(active);
}
 
/*
* Merge two sorted edge lists.
* Input:
* - head_a: The head of the first list.
* - head_b: The head of the second list; head_b cannot be NULL.
* Output:
* Returns the head of the merged list.
*
* Implementation notes:
* To make it fast (in particular, to reduce to an insertion sort whenever
* one of the two input lists only has a single element) we iterate through
* a list until its head becomes greater than the head of the other list,
* then we switch their roles. As soon as one of the two lists is empty, we
* just attach the other one to the current list and exit.
* Writes to memory are only needed to "switch" lists (as it also requires
* attaching to the output list the list which we will be iterating next) and
* to attach the last non-empty list.
*/
static struct edge *
merge_sorted_edges (struct edge *head_a, struct edge *head_b)
{
struct edge *head, **next;
 
head = head_a;
next = &head;
 
while (1) {
while (head_a != NULL && head_a->x.quo <= head_b->x.quo) {
next = &head_a->next;
head_a = head_a->next;
}
 
*next = head_b;
if (head_a == NULL)
return head;
 
while (head_b != NULL && head_b->x.quo <= head_a->x.quo) {
next = &head_b->next;
head_b = head_b->next;
}
 
*next = head_a;
if (head_b == NULL)
return head;
}
}
 
/*
* Sort (part of) a list.
* Input:
* - list: The list to be sorted; list cannot be NULL.
* - limit: Recursion limit.
* Output:
* - head_out: The head of the sorted list containing the first 2^(level+1) elements of the
* input list; if the input list has fewer elements, head_out be a sorted list
* containing all the elements of the input list.
* Returns the head of the list of unprocessed elements (NULL if the sorted list contains
* all the elements of the input list).
*
* Implementation notes:
* Special case single element list, unroll/inline the sorting of the first two elements.
* Some tail recursion is used since we iterate on the bottom-up solution of the problem
* (we start with a small sorted list and keep merging other lists of the same size to it).
*/
static struct edge *
sort_edges (struct edge *list,
unsigned int level,
struct edge **head_out)
{
struct edge *head_other, *remaining;
unsigned int i;
 
head_other = list->next;
 
/* Single element list -> return */
if (head_other == NULL) {
*head_out = list;
return NULL;
}
 
/* Unroll the first iteration of the following loop (halves the number of calls to merge_sorted_edges):
* - Initialize remaining to be the list containing the elements after the second in the input list.
* - Initialize *head_out to be the sorted list containing the first two element.
*/
remaining = head_other->next;
if (list->x.quo <= head_other->x.quo) {
*head_out = list;
/* list->next = head_other; */ /* The input list is already like this. */
head_other->next = NULL;
} else {
*head_out = head_other;
head_other->next = list;
list->next = NULL;
}
 
for (i = 0; i < level && remaining; i++) {
/* Extract a sorted list of the same size as *head_out
* (2^(i+1) elements) from the list of remaining elements. */
remaining = sort_edges (remaining, i, &head_other);
*head_out = merge_sorted_edges (*head_out, head_other);
}
 
/* *head_out now contains (at most) 2^(level+1) elements. */
 
return remaining;
}
 
/* Test if the edges on the active list can be safely advanced by a
* full row without intersections or any edges ending. */
inline static int
active_list_can_step_full_row (struct active_list *active)
{
const struct edge *e;
int prev_x = INT_MIN;
 
/* Recomputes the minimum height of all edges on the active
* list if we have been dropping edges. */
if (active->min_height <= 0) {
int min_height = INT_MAX;
 
e = active->head;
while (NULL != e) {
if (e->height_left < min_height)
min_height = e->height_left;
e = e->next;
}
 
active->min_height = min_height;
}
 
if (active->min_height < GRID_Y)
return 0;
 
/* Check for intersections as no edges end during the next row. */
e = active->head;
while (NULL != e) {
struct quorem x = e->x;
 
if (! e->vertical) {
x.quo += e->dxdy_full.quo;
x.rem += e->dxdy_full.rem;
if (x.rem >= 0)
++x.quo;
}
 
if (x.quo <= prev_x)
return 0;
 
prev_x = x.quo;
e = e->next;
}
 
return 1;
}
 
/* Merges edges on the given subpixel row from the polygon to the
* active_list. */
inline static void
active_list_merge_edges_from_polygon(
struct active_list *active,
grid_scaled_y_t y,
struct polygon *polygon)
{
/* Split off the edges on the current subrow and merge them into
* the active list. */
unsigned ix = EDGE_Y_BUCKET_INDEX(y, polygon->ymin);
int min_height = active->min_height;
struct edge *subrow_edges = NULL;
struct edge **ptail = &polygon->y_buckets[ix];
 
while (1) {
struct edge *tail = *ptail;
if (NULL == tail) break;
 
if (y == tail->ytop) {
*ptail = tail->next;
tail->next = subrow_edges;
subrow_edges = tail;
if (tail->height_left < min_height)
min_height = tail->height_left;
} else {
ptail = &tail->next;
}
}
if (subrow_edges) {
sort_edges (subrow_edges, UINT_MAX, &subrow_edges);
active->head = merge_sorted_edges (active->head, subrow_edges);
active->min_height = min_height;
}
}
 
/* Advance the edges on the active list by one subsample row by
* updating their x positions. Drop edges from the list that end. */
inline static void
active_list_substep_edges(
struct active_list *active)
{
struct edge **cursor = &active->head;
grid_scaled_x_t prev_x = INT_MIN;
struct edge *unsorted = NULL;
 
while (1) {
struct edge *edge;
 
UNROLL3({
edge = *cursor;
if (NULL == edge)
break;
 
if (0 != --edge->height_left) {
edge->x.quo += edge->dxdy.quo;
edge->x.rem += edge->dxdy.rem;
if (edge->x.rem >= 0) {
++edge->x.quo;
edge->x.rem -= edge->dy;
}
 
if (edge->x.quo < prev_x) {
*cursor = edge->next;
edge->next = unsorted;
unsorted = edge;
} else {
prev_x = edge->x.quo;
cursor = &edge->next;
}
 
} else {
*cursor = edge->next;
}
});
}
 
if (unsorted) {
sort_edges (unsorted, UINT_MAX, &unsorted);
active->head = merge_sorted_edges (active->head, unsorted);
}
}
 
inline static glitter_status_t
apply_nonzero_fill_rule_for_subrow (struct active_list *active,
struct cell_list *coverages)
{
struct edge *edge = active->head;
int winding = 0;
int xstart;
int xend;
int status;
 
cell_list_rewind (coverages);
 
while (NULL != edge) {
xstart = edge->x.quo;
winding = edge->dir;
while (1) {
edge = edge->next;
if (NULL == edge)
return cell_list_add_unbounded_subspan (coverages, xstart);
 
winding += edge->dir;
if (0 == winding) {
if (edge->next == NULL || edge->next->x.quo != edge->x.quo)
break;
}
}
 
xend = edge->x.quo;
status = cell_list_add_subspan (coverages, xstart, xend);
if (unlikely (status))
return status;
 
edge = edge->next;
}
 
return GLITTER_STATUS_SUCCESS;
}
 
static glitter_status_t
apply_evenodd_fill_rule_for_subrow (struct active_list *active,
struct cell_list *coverages)
{
struct edge *edge = active->head;
int xstart;
int xend;
int status;
 
cell_list_rewind (coverages);
 
while (NULL != edge) {
xstart = edge->x.quo;
 
while (1) {
edge = edge->next;
if (NULL == edge)
return cell_list_add_unbounded_subspan (coverages, xstart);
 
if (edge->next == NULL || edge->next->x.quo != edge->x.quo)
break;
 
edge = edge->next;
}
 
xend = edge->x.quo;
status = cell_list_add_subspan (coverages, xstart, xend);
if (unlikely (status))
return status;
 
edge = edge->next;
}
 
return GLITTER_STATUS_SUCCESS;
}
 
static glitter_status_t
apply_nonzero_fill_rule_and_step_edges (struct active_list *active,
struct cell_list *coverages)
{
struct edge **cursor = &active->head;
struct edge *left_edge;
int status;
 
left_edge = *cursor;
while (NULL != left_edge) {
struct edge *right_edge;
int winding = left_edge->dir;
 
left_edge->height_left -= GRID_Y;
if (left_edge->height_left)
cursor = &left_edge->next;
else
*cursor = left_edge->next;
 
while (1) {
right_edge = *cursor;
if (NULL == right_edge)
return cell_list_render_edge (coverages, left_edge, +1);
 
right_edge->height_left -= GRID_Y;
if (right_edge->height_left)
cursor = &right_edge->next;
else
*cursor = right_edge->next;
 
winding += right_edge->dir;
if (0 == winding) {
if (right_edge->next == NULL ||
right_edge->next->x.quo != right_edge->x.quo)
{
break;
}
}
 
if (! right_edge->vertical) {
right_edge->x.quo += right_edge->dxdy_full.quo;
right_edge->x.rem += right_edge->dxdy_full.rem;
if (right_edge->x.rem >= 0) {
++right_edge->x.quo;
right_edge->x.rem -= right_edge->dy;
}
}
}
 
status = cell_list_render_edge (coverages, left_edge, +1);
if (unlikely (status))
return status;
 
status = cell_list_render_edge (coverages, right_edge, -1);
if (unlikely (status))
return status;
 
left_edge = *cursor;
}
 
return GLITTER_STATUS_SUCCESS;
}
 
static glitter_status_t
apply_evenodd_fill_rule_and_step_edges (struct active_list *active,
struct cell_list *coverages)
{
struct edge **cursor = &active->head;
struct edge *left_edge;
int status;
 
left_edge = *cursor;
while (NULL != left_edge) {
struct edge *right_edge;
 
left_edge->height_left -= GRID_Y;
if (left_edge->height_left)
cursor = &left_edge->next;
else
*cursor = left_edge->next;
 
while (1) {
right_edge = *cursor;
if (NULL == right_edge)
return cell_list_render_edge (coverages, left_edge, +1);
 
right_edge->height_left -= GRID_Y;
if (right_edge->height_left)
cursor = &right_edge->next;
else
*cursor = right_edge->next;
 
if (right_edge->next == NULL ||
right_edge->next->x.quo != right_edge->x.quo)
{
break;
}
 
if (! right_edge->vertical) {
right_edge->x.quo += right_edge->dxdy_full.quo;
right_edge->x.rem += right_edge->dxdy_full.rem;
if (right_edge->x.rem >= 0) {
++right_edge->x.quo;
right_edge->x.rem -= right_edge->dy;
}
}
}
 
status = cell_list_render_edge (coverages, left_edge, +1);
if (unlikely (status))
return status;
 
status = cell_list_render_edge (coverages, right_edge, -1);
if (unlikely (status))
return status;
 
left_edge = *cursor;
}
 
return GLITTER_STATUS_SUCCESS;
}
 
/* If the user hasn't configured a coverage blitter, use a default one
* that blits spans directly to an A8 raster. */
#ifndef GLITTER_BLIT_COVERAGES
 
inline static void
blit_span(
unsigned char *row_pixels,
int x, unsigned len,
grid_area_t coverage)
{
int alpha = GRID_AREA_TO_ALPHA(coverage);
if (1 == len) {
row_pixels[x] = alpha;
}
else {
memset(row_pixels + x, alpha, len);
}
}
 
#define GLITTER_BLIT_COVERAGES(coverages, y, height, xmin, xmax) \
do { \
int __y = y; \
int __h = height; \
do { \
blit_cells(coverages, raster_pixels + (__y)*raster_stride, xmin, xmax); \
} while (--__h); \
} while (0)
 
static void
blit_cells(
struct cell_list *cells,
unsigned char *row_pixels,
int xmin, int xmax)
{
struct cell *cell = cells->head;
int prev_x = xmin;
int coverage = 0;
if (NULL == cell)
return;
 
while (NULL != cell && cell->x < xmin) {
coverage += cell->covered_height;
cell = cell->next;
}
coverage *= GRID_X*2;
 
for (; NULL != cell; cell = cell->next) {
int x = cell->x;
int area;
if (x >= xmax)
break;
if (x > prev_x && 0 != coverage) {
blit_span(row_pixels, prev_x, x - prev_x, coverage);
}
 
coverage += cell->covered_height * GRID_X*2;
area = coverage - cell->uncovered_area;
if (area) {
blit_span(row_pixels, x, 1, area);
}
prev_x = x+1;
}
 
if (0 != coverage && prev_x < xmax) {
blit_span(row_pixels, prev_x, xmax - prev_x, coverage);
}
}
#endif /* GLITTER_BLIT_COVERAGES */
 
static void
_glitter_scan_converter_init(glitter_scan_converter_t *converter)
{
polygon_init(converter->polygon);
active_list_init(converter->active);
cell_list_init(converter->coverages);
converter->xmin=0;
converter->ymin=0;
converter->xmax=0;
converter->ymax=0;
}
 
static void
_glitter_scan_converter_fini(glitter_scan_converter_t *converter)
{
polygon_fini(converter->polygon);
cell_list_fini(converter->coverages);
converter->xmin=0;
converter->ymin=0;
converter->xmax=0;
converter->ymax=0;
}
 
static grid_scaled_t
int_to_grid_scaled(int i, int scale)
{
/* Clamp to max/min representable scaled number. */
if (i >= 0) {
if (i >= INT_MAX/scale)
i = INT_MAX/scale;
}
else {
if (i <= INT_MIN/scale)
i = INT_MIN/scale;
}
return i*scale;
}
 
#define int_to_grid_scaled_x(x) int_to_grid_scaled((x), GRID_X)
#define int_to_grid_scaled_y(x) int_to_grid_scaled((x), GRID_Y)
 
I glitter_status_t
glitter_scan_converter_reset(
glitter_scan_converter_t *converter,
int xmin, int ymin,
int xmax, int ymax)
{
glitter_status_t status;
 
converter->xmin = 0; converter->xmax = 0;
converter->ymin = 0; converter->ymax = 0;
 
xmin = int_to_grid_scaled_x(xmin);
ymin = int_to_grid_scaled_y(ymin);
xmax = int_to_grid_scaled_x(xmax);
ymax = int_to_grid_scaled_y(ymax);
 
active_list_reset(converter->active);
cell_list_reset(converter->coverages);
status = polygon_reset(converter->polygon, ymin, ymax);
if (status)
return status;
 
converter->xmin = xmin;
converter->xmax = xmax;
converter->ymin = ymin;
converter->ymax = ymax;
return GLITTER_STATUS_SUCCESS;
}
 
/* INPUT_TO_GRID_X/Y (in_coord, out_grid_scaled, grid_scale)
* These macros convert an input coordinate in the client's
* device space to the rasterisation grid.
*/
/* Gah.. this bit of ugly defines INPUT_TO_GRID_X/Y so as to use
* shifts if possible, and something saneish if not.
*/
#if !defined(INPUT_TO_GRID_Y) && defined(GRID_Y_BITS) && GRID_Y_BITS <= GLITTER_INPUT_BITS
# define INPUT_TO_GRID_Y(in, out) (out) = (in) >> (GLITTER_INPUT_BITS - GRID_Y_BITS)
#else
# define INPUT_TO_GRID_Y(in, out) INPUT_TO_GRID_general(in, out, GRID_Y)
#endif
 
#if !defined(INPUT_TO_GRID_X) && defined(GRID_X_BITS) && GRID_X_BITS <= GLITTER_INPUT_BITS
# define INPUT_TO_GRID_X(in, out) (out) = (in) >> (GLITTER_INPUT_BITS - GRID_X_BITS)
#else
# define INPUT_TO_GRID_X(in, out) INPUT_TO_GRID_general(in, out, GRID_X)
#endif
 
#define INPUT_TO_GRID_general(in, out, grid_scale) do { \
long long tmp__ = (long long)(grid_scale) * (in); \
tmp__ >>= GLITTER_INPUT_BITS; \
(out) = tmp__; \
} while (0)
 
I glitter_status_t
glitter_scan_converter_add_edge (glitter_scan_converter_t *converter,
const cairo_edge_t *edge)
{
cairo_edge_t e;
 
INPUT_TO_GRID_Y (edge->top, e.top);
INPUT_TO_GRID_Y (edge->bottom, e.bottom);
if (e.top >= e.bottom)
return GLITTER_STATUS_SUCCESS;
 
/* XXX: possible overflows if GRID_X/Y > 2**GLITTER_INPUT_BITS */
INPUT_TO_GRID_Y (edge->line.p1.y, e.line.p1.y);
INPUT_TO_GRID_Y (edge->line.p2.y, e.line.p2.y);
if (e.line.p1.y == e.line.p2.y)
return GLITTER_STATUS_SUCCESS;
 
INPUT_TO_GRID_X (edge->line.p1.x, e.line.p1.x);
INPUT_TO_GRID_X (edge->line.p2.x, e.line.p2.x);
 
e.dir = edge->dir;
 
return polygon_add_edge (converter->polygon, &e);
}
 
#ifndef GLITTER_BLIT_COVERAGES_BEGIN
# define GLITTER_BLIT_COVERAGES_BEGIN
#endif
 
#ifndef GLITTER_BLIT_COVERAGES_END
# define GLITTER_BLIT_COVERAGES_END
#endif
 
#ifndef GLITTER_BLIT_COVERAGES_EMPTY
# define GLITTER_BLIT_COVERAGES_EMPTY(y0, y1, xmin, xmax)
#endif
 
static cairo_bool_t
active_list_is_vertical (struct active_list *active)
{
struct edge *e;
 
for (e = active->head; e != NULL; e = e->next) {
if (! e->vertical)
return FALSE;
}
 
return TRUE;
}
 
static void
step_edges (struct active_list *active, int count)
{
struct edge **cursor = &active->head;
struct edge *edge;
 
for (edge = *cursor; edge != NULL; edge = *cursor) {
edge->height_left -= GRID_Y * count;
if (edge->height_left)
cursor = &edge->next;
else
*cursor = edge->next;
}
}
 
I glitter_status_t
glitter_scan_converter_render(
glitter_scan_converter_t *converter,
int nonzero_fill,
GLITTER_BLIT_COVERAGES_ARGS)
{
int i, j;
int ymax_i = converter->ymax / GRID_Y;
int ymin_i = converter->ymin / GRID_Y;
int xmin_i, xmax_i;
int h = ymax_i - ymin_i;
struct polygon *polygon = converter->polygon;
struct cell_list *coverages = converter->coverages;
struct active_list *active = converter->active;
 
xmin_i = converter->xmin / GRID_X;
xmax_i = converter->xmax / GRID_X;
if (xmin_i >= xmax_i)
return GLITTER_STATUS_SUCCESS;
 
/* Let the coverage blitter initialise itself. */
GLITTER_BLIT_COVERAGES_BEGIN;
 
/* Render each pixel row. */
for (i = 0; i < h; i = j) {
int do_full_step = 0;
glitter_status_t status = 0;
 
j = i + 1;
 
/* Determine if we can ignore this row or use the full pixel
* stepper. */
if (GRID_Y == EDGE_Y_BUCKET_HEIGHT && ! polygon->y_buckets[i]) {
if (! active->head) {
for (; j < h && ! polygon->y_buckets[j]; j++)
;
GLITTER_BLIT_COVERAGES_EMPTY (i+ymin_i, j-i, xmin_i, xmax_i);
continue;
}
 
do_full_step = active_list_can_step_full_row (active);
}
 
if (do_full_step) {
/* Step by a full pixel row's worth. */
if (nonzero_fill) {
status = apply_nonzero_fill_rule_and_step_edges (active,
coverages);
} else {
status = apply_evenodd_fill_rule_and_step_edges (active,
coverages);
}
 
if (active_list_is_vertical (active)) {
while (j < h &&
polygon->y_buckets[j] == NULL &&
active->min_height >= 2*GRID_Y)
{
active->min_height -= GRID_Y;
j++;
}
if (j != i + 1)
step_edges (active, j - (i + 1));
}
} else {
grid_scaled_y_t suby;
 
/* Subsample this row. */
for (suby = 0; suby < GRID_Y; suby++) {
grid_scaled_y_t y = (i+ymin_i)*GRID_Y + suby;
 
active_list_merge_edges_from_polygon (active, y, polygon);
 
if (nonzero_fill) {
status |= apply_nonzero_fill_rule_for_subrow (active,
coverages);
} else {
status |= apply_evenodd_fill_rule_for_subrow (active,
coverages);
}
 
active_list_substep_edges(active);
}
}
 
if (unlikely (status))
return status;
 
GLITTER_BLIT_COVERAGES(coverages, i+ymin_i, j-i, xmin_i, xmax_i);
cell_list_reset (coverages);
 
if (! active->head)
active->min_height = INT_MAX;
else
active->min_height -= GRID_Y;
}
 
/* Clean up the coverage blitter. */
GLITTER_BLIT_COVERAGES_END;
 
return GLITTER_STATUS_SUCCESS;
}
 
/*-------------------------------------------------------------------------
* cairo specific implementation: the coverage blitter and
* scan converter subclass. */
 
static glitter_status_t
blit_with_span_renderer (struct cell_list *cells,
cairo_span_renderer_t *renderer,
struct pool *span_pool,
int y, int height,
int xmin, int xmax)
{
struct cell *cell = cells->head;
int prev_x = xmin;
int cover = 0;
cairo_half_open_span_t *spans;
unsigned num_spans;
 
if (cell == NULL)
return blit_empty_with_span_renderer (renderer, y, height);
 
/* Skip cells to the left of the clip region. */
while (cell != NULL && cell->x < xmin) {
cover += cell->covered_height;
cell = cell->next;
}
cover *= GRID_X*2;
 
/* Count number of cells remaining. */
{
struct cell *next = cell;
num_spans = 1;
while (next != NULL) {
next = next->next;
++num_spans;
}
num_spans = 2*num_spans;
}
 
/* Allocate enough spans for the row. */
pool_reset (span_pool);
spans = pool_alloc (span_pool, sizeof(spans[0])*num_spans);
if (unlikely (spans == NULL))
return GLITTER_STATUS_NO_MEMORY;
 
num_spans = 0;
 
/* Form the spans from the coverages and areas. */
for (; cell != NULL; cell = cell->next) {
int x = cell->x;
int area;
 
if (x >= xmax)
break;
 
if (x > prev_x) {
spans[num_spans].x = prev_x;
spans[num_spans].coverage = GRID_AREA_TO_ALPHA (cover);
++num_spans;
}
 
cover += cell->covered_height*GRID_X*2;
area = cover - cell->uncovered_area;
 
spans[num_spans].x = x;
spans[num_spans].coverage = GRID_AREA_TO_ALPHA (area);
++num_spans;
 
prev_x = x+1;
}
 
if (prev_x <= xmax) {
spans[num_spans].x = prev_x;
spans[num_spans].coverage = GRID_AREA_TO_ALPHA (cover);
++num_spans;
}
 
if (prev_x < xmax && cover) {
spans[num_spans].x = xmax;
spans[num_spans].coverage = 0;
++num_spans;
}
 
/* Dump them into the renderer. */
return renderer->render_rows (renderer, y, height, spans, num_spans);
}
 
static glitter_status_t
blit_empty_with_span_renderer (cairo_span_renderer_t *renderer, int y, int height)
{
return renderer->render_rows (renderer, y, height, NULL, 0);
}
 
struct _cairo_tor_scan_converter {
cairo_scan_converter_t base;
 
glitter_scan_converter_t converter[1];
cairo_fill_rule_t fill_rule;
 
struct {
struct pool base[1];
cairo_half_open_span_t embedded[32];
} span_pool;
};
 
typedef struct _cairo_tor_scan_converter cairo_tor_scan_converter_t;
 
static void
_cairo_tor_scan_converter_destroy (void *converter)
{
cairo_tor_scan_converter_t *self = converter;
if (self == NULL) {
return;
}
_glitter_scan_converter_fini (self->converter);
pool_fini (self->span_pool.base);
free(self);
}
 
static cairo_status_t
_cairo_tor_scan_converter_add_edge (void *converter,
const cairo_point_t *p1,
const cairo_point_t *p2,
int top, int bottom,
int dir)
{
cairo_tor_scan_converter_t *self = converter;
cairo_status_t status;
cairo_edge_t edge;
 
edge.line.p1 = *p1;
edge.line.p2 = *p2;
edge.top = top;
edge.bottom = bottom;
edge.dir = dir;
 
status = glitter_scan_converter_add_edge (self->converter, &edge);
if (unlikely (status))
return _cairo_scan_converter_set_error (self, _cairo_error (status));
 
return CAIRO_STATUS_SUCCESS;
}
 
static cairo_status_t
_cairo_tor_scan_converter_add_polygon (void *converter,
const cairo_polygon_t *polygon)
{
cairo_tor_scan_converter_t *self = converter;
cairo_status_t status;
int i;
 
for (i = 0; i < polygon->num_edges; i++) {
status = glitter_scan_converter_add_edge (self->converter,
&polygon->edges[i]);
if (unlikely (status)) {
return _cairo_scan_converter_set_error (self,
_cairo_error (status));
}
}
 
return CAIRO_STATUS_SUCCESS;
}
 
static cairo_status_t
_cairo_tor_scan_converter_generate (void *converter,
cairo_span_renderer_t *renderer)
{
cairo_tor_scan_converter_t *self = converter;
cairo_status_t status;
 
status = glitter_scan_converter_render (self->converter,
self->fill_rule == CAIRO_FILL_RULE_WINDING,
renderer,
self->span_pool.base);
if (unlikely (status))
return _cairo_scan_converter_set_error (self, _cairo_error (status));
 
return CAIRO_STATUS_SUCCESS;
}
 
cairo_scan_converter_t *
_cairo_tor_scan_converter_create (int xmin,
int ymin,
int xmax,
int ymax,
cairo_fill_rule_t fill_rule)
{
cairo_tor_scan_converter_t *self;
cairo_status_t status;
 
self = calloc (1, sizeof(struct _cairo_tor_scan_converter));
if (unlikely (self == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto bail_nomem;
}
 
self->base.destroy = _cairo_tor_scan_converter_destroy;
self->base.add_edge = _cairo_tor_scan_converter_add_edge;
self->base.add_polygon = _cairo_tor_scan_converter_add_polygon;
self->base.generate = _cairo_tor_scan_converter_generate;
 
pool_init (self->span_pool.base,
250 * sizeof(self->span_pool.embedded[0]),
sizeof(self->span_pool.embedded));
 
_glitter_scan_converter_init (self->converter);
status = glitter_scan_converter_reset (self->converter,
xmin, ymin, xmax, ymax);
if (unlikely (status))
goto bail;
 
self->fill_rule = fill_rule;
 
return &self->base;
 
bail:
self->base.destroy(&self->base);
bail_nomem:
return _cairo_scan_converter_create_in_error (status);
}
/programs/develop/libraries/cairo/src/cairo-toy-font-face.c
0,0 → 1,526
/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2002 University of Southern California
* Copyright © 2005,2008 Red Hat Inc.
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
* Graydon Hoare <graydon@redhat.com>
* Owen Taylor <otaylor@redhat.com>
* Behdad Esfahbod <behdad@behdad.org>
*/
 
#define _BSD_SOURCE /* for strdup() */
#include "cairoint.h"
#include "cairo-error-private.h"
 
 
static const cairo_font_face_t _cairo_font_face_null_pointer = {
{ 0 }, /* hash_entry */
CAIRO_STATUS_NULL_POINTER, /* status */
CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */
{ 0, 0, 0, NULL }, /* user_data */
NULL
};
 
static const cairo_font_face_t _cairo_font_face_invalid_string = {
{ 0 }, /* hash_entry */
CAIRO_STATUS_INVALID_STRING, /* status */
CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */
{ 0, 0, 0, NULL }, /* user_data */
NULL
};
 
static const cairo_font_face_t _cairo_font_face_invalid_slant = {
{ 0 }, /* hash_entry */
CAIRO_STATUS_INVALID_SLANT, /* status */
CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */
{ 0, 0, 0, NULL }, /* user_data */
NULL
};
 
static const cairo_font_face_t _cairo_font_face_invalid_weight = {
{ 0 }, /* hash_entry */
CAIRO_STATUS_INVALID_WEIGHT, /* status */
CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */
{ 0, 0, 0, NULL }, /* user_data */
NULL
};
 
 
static const cairo_font_face_backend_t _cairo_toy_font_face_backend;
 
static int
_cairo_toy_font_face_keys_equal (const void *key_a,
const void *key_b);
 
/* We maintain a hash table from family/weight/slant =>
* #cairo_font_face_t for #cairo_toy_font_t. The primary purpose of
* this mapping is to provide unique #cairo_font_face_t values so that
* our cache and mapping from #cairo_font_face_t => #cairo_scaled_font_t
* works. Once the corresponding #cairo_font_face_t objects fall out of
* downstream caches, we don't need them in this hash table anymore.
*
* Modifications to this hash table are protected by
* _cairo_toy_font_face_mutex.
*/
static cairo_hash_table_t *cairo_toy_font_face_hash_table = NULL;
 
static cairo_hash_table_t *
_cairo_toy_font_face_hash_table_lock (void)
{
CAIRO_MUTEX_LOCK (_cairo_toy_font_face_mutex);
 
if (cairo_toy_font_face_hash_table == NULL)
{
cairo_toy_font_face_hash_table =
_cairo_hash_table_create (_cairo_toy_font_face_keys_equal);
 
if (cairo_toy_font_face_hash_table == NULL) {
CAIRO_MUTEX_UNLOCK (_cairo_toy_font_face_mutex);
return NULL;
}
}
 
return cairo_toy_font_face_hash_table;
}
 
static void
_cairo_toy_font_face_hash_table_unlock (void)
{
CAIRO_MUTEX_UNLOCK (_cairo_toy_font_face_mutex);
}
 
/**
* _cairo_toy_font_face_init_key:
*
* Initialize those portions of #cairo_toy_font_face_t needed to use
* it as a hash table key, including the hash code buried away in
* font_face->base.hash_entry. No memory allocation is performed here
* so that no fini call is needed. We do this to make it easier to use
* an automatic #cairo_toy_font_face_t variable as a key.
**/
static void
_cairo_toy_font_face_init_key (cairo_toy_font_face_t *key,
const char *family,
cairo_font_slant_t slant,
cairo_font_weight_t weight)
{
unsigned long hash;
 
key->family = family;
key->owns_family = FALSE;
 
key->slant = slant;
key->weight = weight;
 
/* 1607 and 1451 are just a couple of arbitrary primes. */
hash = _cairo_hash_string (family);
hash += ((unsigned long) slant) * 1607;
hash += ((unsigned long) weight) * 1451;
 
assert (hash != 0);
key->base.hash_entry.hash = hash;
}
 
static cairo_status_t
_cairo_toy_font_face_create_impl_face (cairo_toy_font_face_t *font_face,
cairo_font_face_t **impl_font_face)
{
const cairo_font_face_backend_t * backend = CAIRO_FONT_FACE_BACKEND_DEFAULT;
cairo_int_status_t status = CAIRO_INT_STATUS_UNSUPPORTED;
 
if (unlikely (font_face->base.status))
return font_face->base.status;
 
if (backend->create_for_toy != NULL &&
0 != strncmp (font_face->family, CAIRO_USER_FONT_FAMILY_DEFAULT,
strlen (CAIRO_USER_FONT_FAMILY_DEFAULT)))
{
status = backend->create_for_toy (font_face, impl_font_face);
}
 
if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
backend = &_cairo_user_font_face_backend;
status = backend->create_for_toy (font_face, impl_font_face);
}
 
return status;
}
 
static cairo_status_t
_cairo_toy_font_face_init (cairo_toy_font_face_t *font_face,
const char *family,
cairo_font_slant_t slant,
cairo_font_weight_t weight)
{
char *family_copy;
cairo_status_t status;
 
family_copy = strdup (family);
if (unlikely (family_copy == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
_cairo_toy_font_face_init_key (font_face, family_copy, slant, weight);
font_face->owns_family = TRUE;
 
_cairo_font_face_init (&font_face->base, &_cairo_toy_font_face_backend);
 
status = _cairo_toy_font_face_create_impl_face (font_face,
&font_face->impl_face);
if (unlikely (status)) {
free (family_copy);
return status;
}
 
return CAIRO_STATUS_SUCCESS;
}
 
static void
_cairo_toy_font_face_fini (cairo_toy_font_face_t *font_face)
{
/* We assert here that we own font_face->family before casting
* away the const qualifer. */
assert (font_face->owns_family);
free ((char*) font_face->family);
 
if (font_face->impl_face)
cairo_font_face_destroy (font_face->impl_face);
}
 
static int
_cairo_toy_font_face_keys_equal (const void *key_a,
const void *key_b)
{
const cairo_toy_font_face_t *face_a = key_a;
const cairo_toy_font_face_t *face_b = key_b;
 
return (strcmp (face_a->family, face_b->family) == 0 &&
face_a->slant == face_b->slant &&
face_a->weight == face_b->weight);
}
 
/**
* cairo_toy_font_face_create:
* @family: a font family name, encoded in UTF-8
* @slant: the slant for the font
* @weight: the weight for the font
*
* Creates a font face from a triplet of family, slant, and weight.
* These font faces are used in implementation of the the #cairo_t "toy"
* font API.
*
* If @family is the zero-length string "", the platform-specific default
* family is assumed. The default family then can be queried using
* cairo_toy_font_face_get_family().
*
* The cairo_select_font_face() function uses this to create font faces.
* See that function for limitations and other details of toy font faces.
*
* Return value: a newly created #cairo_font_face_t. Free with
* cairo_font_face_destroy() when you are done using it.
*
* Since: 1.8
**/
cairo_font_face_t *
cairo_toy_font_face_create (const char *family,
cairo_font_slant_t slant,
cairo_font_weight_t weight)
{
cairo_status_t status;
cairo_toy_font_face_t key, *font_face;
cairo_hash_table_t *hash_table;
 
if (family == NULL)
return (cairo_font_face_t*) &_cairo_font_face_null_pointer;
 
/* Make sure we've got valid UTF-8 for the family */
status = _cairo_utf8_to_ucs4 (family, -1, NULL, NULL);
if (unlikely (status)) {
if (status == CAIRO_STATUS_INVALID_STRING)
return (cairo_font_face_t*) &_cairo_font_face_invalid_string;
 
return (cairo_font_face_t*) &_cairo_font_face_nil;
}
 
switch (slant) {
case CAIRO_FONT_SLANT_NORMAL:
case CAIRO_FONT_SLANT_ITALIC:
case CAIRO_FONT_SLANT_OBLIQUE:
break;
default:
return (cairo_font_face_t*) &_cairo_font_face_invalid_slant;
}
 
switch (weight) {
case CAIRO_FONT_WEIGHT_NORMAL:
case CAIRO_FONT_WEIGHT_BOLD:
break;
default:
return (cairo_font_face_t*) &_cairo_font_face_invalid_weight;
}
 
if (*family == '\0')
family = CAIRO_FONT_FAMILY_DEFAULT;
 
hash_table = _cairo_toy_font_face_hash_table_lock ();
if (unlikely (hash_table == NULL))
goto UNWIND;
 
_cairo_toy_font_face_init_key (&key, family, slant, weight);
 
/* Return existing font_face if it exists in the hash table. */
font_face = _cairo_hash_table_lookup (hash_table,
&key.base.hash_entry);
if (font_face != NULL) {
if (font_face->base.status == CAIRO_STATUS_SUCCESS) {
/* We increment the reference count here manually to avoid
double-locking. */
_cairo_reference_count_inc (&font_face->base.ref_count);
_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, &font_face->base.hash_entry);
font_face->base.hash_entry.hash = 0;
}
 
/* Otherwise create it and insert into hash table. */
font_face = malloc (sizeof (cairo_toy_font_face_t));
if (unlikely (font_face == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto UNWIND_HASH_TABLE_LOCK;
}
 
status = _cairo_toy_font_face_init (font_face, family, slant, weight);
if (unlikely (status))
goto UNWIND_FONT_FACE_MALLOC;
 
assert (font_face->base.hash_entry.hash == key.base.hash_entry.hash);
status = _cairo_hash_table_insert (hash_table, &font_face->base.hash_entry);
if (unlikely (status))
goto UNWIND_FONT_FACE_INIT;
 
_cairo_toy_font_face_hash_table_unlock ();
 
return &font_face->base;
 
UNWIND_FONT_FACE_INIT:
_cairo_toy_font_face_fini (font_face);
UNWIND_FONT_FACE_MALLOC:
free (font_face);
UNWIND_HASH_TABLE_LOCK:
_cairo_toy_font_face_hash_table_unlock ();
UNWIND:
return (cairo_font_face_t*) &_cairo_font_face_nil;
}
slim_hidden_def (cairo_toy_font_face_create);
 
static void
_cairo_toy_font_face_destroy (void *abstract_face)
{
cairo_toy_font_face_t *font_face = abstract_face;
cairo_hash_table_t *hash_table;
 
if (font_face == NULL ||
CAIRO_REFERENCE_COUNT_IS_INVALID (&font_face->base.ref_count))
return;
 
hash_table = _cairo_toy_font_face_hash_table_lock ();
/* All created objects must have been mapped in the hash table. */
assert (hash_table != NULL);
 
if (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&font_face->base.ref_count)) {
/* somebody recreated the font whilst we waited for the lock */
_cairo_toy_font_face_hash_table_unlock ();
return;
}
 
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_fini (font_face);
}
 
static cairo_status_t
_cairo_toy_font_face_scaled_font_create (void *abstract_font_face,
const cairo_matrix_t *font_matrix,
const cairo_matrix_t *ctm,
const cairo_font_options_t *options,
cairo_scaled_font_t **scaled_font)
{
cairo_toy_font_face_t *font_face = (cairo_toy_font_face_t *) abstract_font_face;
 
ASSERT_NOT_REACHED;
 
return _cairo_font_face_set_error (&font_face->base, CAIRO_STATUS_FONT_TYPE_MISMATCH);
}
 
static cairo_font_face_t *
_cairo_toy_font_face_get_implementation (void *abstract_font_face,
const cairo_matrix_t *font_matrix,
const cairo_matrix_t *ctm,
const cairo_font_options_t *options)
{
cairo_toy_font_face_t *font_face = abstract_font_face;
 
if (font_face->impl_face) {
cairo_font_face_t *impl = font_face->impl_face;
 
if (impl->backend->get_implementation != NULL) {
return impl->backend->get_implementation (impl,
font_matrix,
ctm,
options);
}
 
return cairo_font_face_reference (impl);
}
 
return abstract_font_face;
}
 
static cairo_bool_t
_cairo_font_face_is_toy (cairo_font_face_t *font_face)
{
return font_face->backend == &_cairo_toy_font_face_backend;
}
 
/**
* cairo_toy_font_face_get_family:
* @font_face: A toy font face
*
* Gets the familly name of a toy font.
*
* Return value: The family name. This string is owned by the font face
* and remains valid as long as the font face is alive (referenced).
*
* Since: 1.8
**/
const char *
cairo_toy_font_face_get_family (cairo_font_face_t *font_face)
{
cairo_toy_font_face_t *toy_font_face;
 
if (font_face->status)
return CAIRO_FONT_FAMILY_DEFAULT;
 
toy_font_face = (cairo_toy_font_face_t *) font_face;
if (! _cairo_font_face_is_toy (font_face)) {
if (_cairo_font_face_set_error (font_face, CAIRO_STATUS_FONT_TYPE_MISMATCH))
return CAIRO_FONT_FAMILY_DEFAULT;
}
assert (toy_font_face->owns_family);
return toy_font_face->family;
}
 
/**
* cairo_toy_font_face_get_slant:
* @font_face: A toy font face
*
* Gets the slant a toy font.
*
* Return value: The slant value
*
* Since: 1.8
**/
cairo_font_slant_t
cairo_toy_font_face_get_slant (cairo_font_face_t *font_face)
{
cairo_toy_font_face_t *toy_font_face;
 
if (font_face->status)
return CAIRO_FONT_SLANT_DEFAULT;
 
toy_font_face = (cairo_toy_font_face_t *) font_face;
if (! _cairo_font_face_is_toy (font_face)) {
if (_cairo_font_face_set_error (font_face, CAIRO_STATUS_FONT_TYPE_MISMATCH))
return CAIRO_FONT_SLANT_DEFAULT;
}
return toy_font_face->slant;
}
slim_hidden_def (cairo_toy_font_face_get_slant);
 
/**
* cairo_toy_font_face_get_weight:
* @font_face: A toy font face
*
* Gets the weight a toy font.
*
* Return value: The weight value
*
* Since: 1.8
**/
cairo_font_weight_t
cairo_toy_font_face_get_weight (cairo_font_face_t *font_face)
{
cairo_toy_font_face_t *toy_font_face;
 
if (font_face->status)
return CAIRO_FONT_WEIGHT_DEFAULT;
 
toy_font_face = (cairo_toy_font_face_t *) font_face;
if (! _cairo_font_face_is_toy (font_face)) {
if (_cairo_font_face_set_error (font_face, CAIRO_STATUS_FONT_TYPE_MISMATCH))
return CAIRO_FONT_WEIGHT_DEFAULT;
}
return toy_font_face->weight;
}
slim_hidden_def (cairo_toy_font_face_get_weight);
 
static const cairo_font_face_backend_t _cairo_toy_font_face_backend = {
CAIRO_FONT_TYPE_TOY,
NULL, /* create_for_toy */
_cairo_toy_font_face_destroy,
_cairo_toy_font_face_scaled_font_create,
_cairo_toy_font_face_get_implementation
};
 
void
_cairo_toy_font_face_reset_static_data (void)
{
cairo_hash_table_t *hash_table;
 
/* We manually acquire the lock rather than calling
* cairo_toy_font_face_hash_table_lock simply to avoid
* creating the table only to destroy it again. */
CAIRO_MUTEX_LOCK (_cairo_toy_font_face_mutex);
hash_table = cairo_toy_font_face_hash_table;
cairo_toy_font_face_hash_table = NULL;
CAIRO_MUTEX_UNLOCK (_cairo_toy_font_face_mutex);
 
if (hash_table != NULL)
_cairo_hash_table_destroy (hash_table);
}
/programs/develop/libraries/cairo/src/cairo-traps.c
0,0 → 1,605
/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
/*
* Copyright © 2002 Keith Packard
* Copyright © 2007 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Keith Packard
*
* Contributor(s):
* Keith R. Packard <keithp@keithp.com>
* Carl D. Worth <cworth@cworth.org>
*
* 2002-07-15: Converted from XRenderCompositeDoublePoly to #cairo_trap_t. Carl D. Worth
*/
 
#include "cairoint.h"
 
#include "cairo-boxes-private.h"
#include "cairo-error-private.h"
#include "cairo-region-private.h"
#include "cairo-slope-private.h"
 
/* private functions */
 
void
_cairo_traps_init (cairo_traps_t *traps)
{
VG (VALGRIND_MAKE_MEM_UNDEFINED (traps, sizeof (cairo_traps_t)));
 
traps->status = CAIRO_STATUS_SUCCESS;
 
traps->maybe_region = 1;
traps->is_rectilinear = 0;
traps->is_rectangular = 0;
 
traps->num_traps = 0;
 
traps->traps_size = ARRAY_LENGTH (traps->traps_embedded);
traps->traps = traps->traps_embedded;
 
traps->num_limits = 0;
traps->has_intersections = FALSE;
}
 
void
_cairo_traps_limit (cairo_traps_t *traps,
const cairo_box_t *limits,
int num_limits)
{
traps->limits = limits;
traps->num_limits = num_limits;
}
 
void
_cairo_traps_clear (cairo_traps_t *traps)
{
traps->status = CAIRO_STATUS_SUCCESS;
 
traps->maybe_region = 1;
traps->is_rectilinear = 0;
traps->is_rectangular = 0;
 
traps->num_traps = 0;
traps->has_intersections = FALSE;
}
 
void
_cairo_traps_fini (cairo_traps_t *traps)
{
if (traps->traps != traps->traps_embedded)
free (traps->traps);
 
VG (VALGRIND_MAKE_MEM_NOACCESS (traps, sizeof (cairo_traps_t)));
}
 
/* make room for at least one more trap */
static cairo_bool_t
_cairo_traps_grow (cairo_traps_t *traps)
{
cairo_trapezoid_t *new_traps;
int new_size = 4 * traps->traps_size;
 
if (CAIRO_INJECT_FAULT ()) {
traps->status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
return FALSE;
}
 
if (traps->traps == traps->traps_embedded) {
new_traps = _cairo_malloc_ab (new_size, sizeof (cairo_trapezoid_t));
if (new_traps != NULL)
memcpy (new_traps, traps->traps, sizeof (traps->traps_embedded));
} else {
new_traps = _cairo_realloc_ab (traps->traps,
new_size, sizeof (cairo_trapezoid_t));
}
 
if (unlikely (new_traps == NULL)) {
traps->status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
return FALSE;
}
 
traps->traps = new_traps;
traps->traps_size = new_size;
return TRUE;
}
 
void
_cairo_traps_add_trap (cairo_traps_t *traps,
cairo_fixed_t top, cairo_fixed_t bottom,
cairo_line_t *left, cairo_line_t *right)
{
cairo_trapezoid_t *trap;
 
if (unlikely (traps->num_traps == traps->traps_size)) {
if (unlikely (! _cairo_traps_grow (traps)))
return;
}
 
trap = &traps->traps[traps->num_traps++];
trap->top = top;
trap->bottom = bottom;
trap->left = *left;
trap->right = *right;
}
 
/**
* _cairo_traps_init_box:
* @traps: a #cairo_traps_t
* @box: an array box that will each be converted to a single trapezoid
* to store in @traps.
*
* Initializes a #cairo_traps_t to contain an array of rectangular
* trapezoids.
**/
cairo_status_t
_cairo_traps_init_boxes (cairo_traps_t *traps,
const cairo_boxes_t *boxes)
{
cairo_trapezoid_t *trap;
const struct _cairo_boxes_chunk *chunk;
 
_cairo_traps_init (traps);
 
while (traps->traps_size < boxes->num_boxes) {
if (unlikely (! _cairo_traps_grow (traps))) {
_cairo_traps_fini (traps);
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
}
 
traps->num_traps = boxes->num_boxes;
traps->is_rectilinear = TRUE;
traps->is_rectangular = TRUE;
traps->maybe_region = boxes->is_pixel_aligned;
 
trap = &traps->traps[0];
for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
const cairo_box_t *box;
int i;
 
box = chunk->base;
for (i = 0; i < chunk->count; i++) {
trap->top = box->p1.y;
trap->bottom = box->p2.y;
 
trap->left.p1 = box->p1;
trap->left.p2.x = box->p1.x;
trap->left.p2.y = box->p2.y;
 
trap->right.p1.x = box->p2.x;
trap->right.p1.y = box->p1.y;
trap->right.p2 = box->p2;
 
box++, trap++;
}
}
 
return CAIRO_STATUS_SUCCESS;
}
 
cairo_status_t
_cairo_traps_tessellate_rectangle (cairo_traps_t *traps,
const cairo_point_t *top_left,
const cairo_point_t *bottom_right)
{
cairo_line_t left;
cairo_line_t right;
cairo_fixed_t top, bottom;
 
if (top_left->y == bottom_right->y)
return CAIRO_STATUS_SUCCESS;
 
if (top_left->x == bottom_right->x)
return CAIRO_STATUS_SUCCESS;
 
left.p1.x = left.p2.x = top_left->x;
left.p1.y = right.p1.y = top_left->y;
right.p1.x = right.p2.x = bottom_right->x;
left.p2.y = right.p2.y = bottom_right->y;
 
top = top_left->y;
bottom = bottom_right->y;
 
if (traps->num_limits) {
cairo_bool_t reversed;
int n;
 
/* support counter-clockwise winding for rectangular tessellation */
reversed = top_left->x > bottom_right->x;
if (reversed) {
right.p1.x = right.p2.x = top_left->x;
left.p1.x = left.p2.x = bottom_right->x;
}
 
for (n = 0; n < traps->num_limits; n++) {
const cairo_box_t *limits = &traps->limits[n];
cairo_line_t _left, _right;
cairo_fixed_t _top, _bottom;
 
if (top >= limits->p2.y)
continue;
if (bottom <= limits->p1.y)
continue;
 
/* Trivially reject if trapezoid is entirely to the right or
* to the left of the limits. */
if (left.p1.x >= limits->p2.x)
continue;
if (right.p1.x <= limits->p1.x)
continue;
 
/* Otherwise, clip the trapezoid to the limits. */
_top = top;
if (_top < limits->p1.y)
_top = limits->p1.y;
 
_bottom = bottom;
if (_bottom > limits->p2.y)
_bottom = limits->p2.y;
 
if (_bottom <= _top)
continue;
 
_left = left;
if (_left.p1.x < limits->p1.x) {
_left.p1.x = limits->p1.x;
_left.p1.y = limits->p1.y;
_left.p2.x = limits->p1.x;
_left.p2.y = limits->p2.y;
}
 
_right = right;
if (_right.p1.x > limits->p2.x) {
_right.p1.x = limits->p2.x;
_right.p1.y = limits->p1.y;
_right.p2.x = limits->p2.x;
_right.p2.y = limits->p2.y;
}
 
if (left.p1.x >= right.p1.x)
continue;
 
if (reversed)
_cairo_traps_add_trap (traps, _top, _bottom, &_right, &_left);
else
_cairo_traps_add_trap (traps, _top, _bottom, &_left, &_right);
}
} else {
_cairo_traps_add_trap (traps, top, bottom, &left, &right);
}
 
return traps->status;
}
 
void
_cairo_traps_translate (cairo_traps_t *traps, int x, int y)
{
cairo_fixed_t xoff, yoff;
cairo_trapezoid_t *t;
int i;
 
/* Ugh. The cairo_composite/(Render) interface doesn't allow
an offset for the trapezoids. Need to manually shift all
the coordinates to align with the offset origin of the
intermediate surface. */
 
xoff = _cairo_fixed_from_int (x);
yoff = _cairo_fixed_from_int (y);
 
for (i = 0, t = traps->traps; i < traps->num_traps; i++, t++) {
t->top += yoff;
t->bottom += yoff;
t->left.p1.x += xoff;
t->left.p1.y += yoff;
t->left.p2.x += xoff;
t->left.p2.y += yoff;
t->right.p1.x += xoff;
t->right.p1.y += yoff;
t->right.p2.x += xoff;
t->right.p2.y += yoff;
}
}
 
void
_cairo_trapezoid_array_translate_and_scale (cairo_trapezoid_t *offset_traps,
cairo_trapezoid_t *src_traps,
int num_traps,
double tx, double ty,
double sx, double sy)
{
int i;
cairo_fixed_t xoff = _cairo_fixed_from_double (tx);
cairo_fixed_t yoff = _cairo_fixed_from_double (ty);
 
if (sx == 1.0 && sy == 1.0) {
for (i = 0; i < num_traps; i++) {
offset_traps[i].top = src_traps[i].top + yoff;
offset_traps[i].bottom = src_traps[i].bottom + yoff;
offset_traps[i].left.p1.x = src_traps[i].left.p1.x + xoff;
offset_traps[i].left.p1.y = src_traps[i].left.p1.y + yoff;
offset_traps[i].left.p2.x = src_traps[i].left.p2.x + xoff;
offset_traps[i].left.p2.y = src_traps[i].left.p2.y + yoff;
offset_traps[i].right.p1.x = src_traps[i].right.p1.x + xoff;
offset_traps[i].right.p1.y = src_traps[i].right.p1.y + yoff;
offset_traps[i].right.p2.x = src_traps[i].right.p2.x + xoff;
offset_traps[i].right.p2.y = src_traps[i].right.p2.y + yoff;
}
} else {
cairo_fixed_t xsc = _cairo_fixed_from_double (sx);
cairo_fixed_t ysc = _cairo_fixed_from_double (sy);
 
for (i = 0; i < num_traps; i++) {
offset_traps[i].top = _cairo_fixed_mul (src_traps[i].top + yoff, ysc);
offset_traps[i].bottom = _cairo_fixed_mul (src_traps[i].bottom + yoff, ysc);
offset_traps[i].left.p1.x = _cairo_fixed_mul (src_traps[i].left.p1.x + xoff, xsc);
offset_traps[i].left.p1.y = _cairo_fixed_mul (src_traps[i].left.p1.y + yoff, ysc);
offset_traps[i].left.p2.x = _cairo_fixed_mul (src_traps[i].left.p2.x + xoff, xsc);
offset_traps[i].left.p2.y = _cairo_fixed_mul (src_traps[i].left.p2.y + yoff, ysc);
offset_traps[i].right.p1.x = _cairo_fixed_mul (src_traps[i].right.p1.x + xoff, xsc);
offset_traps[i].right.p1.y = _cairo_fixed_mul (src_traps[i].right.p1.y + yoff, ysc);
offset_traps[i].right.p2.x = _cairo_fixed_mul (src_traps[i].right.p2.x + xoff, xsc);
offset_traps[i].right.p2.y = _cairo_fixed_mul (src_traps[i].right.p2.y + yoff, ysc);
}
}
}
 
static cairo_bool_t
_cairo_trap_contains (cairo_trapezoid_t *t, cairo_point_t *pt)
{
cairo_slope_t slope_left, slope_pt, slope_right;
 
if (t->top > pt->y)
return FALSE;
if (t->bottom < pt->y)
return FALSE;
 
_cairo_slope_init (&slope_left, &t->left.p1, &t->left.p2);
_cairo_slope_init (&slope_pt, &t->left.p1, pt);
 
if (_cairo_slope_compare (&slope_left, &slope_pt) < 0)
return FALSE;
 
_cairo_slope_init (&slope_right, &t->right.p1, &t->right.p2);
_cairo_slope_init (&slope_pt, &t->right.p1, pt);
 
if (_cairo_slope_compare (&slope_pt, &slope_right) < 0)
return FALSE;
 
return TRUE;
}
 
cairo_bool_t
_cairo_traps_contain (const cairo_traps_t *traps,
double x, double y)
{
int i;
cairo_point_t point;
 
point.x = _cairo_fixed_from_double (x);
point.y = _cairo_fixed_from_double (y);
 
for (i = 0; i < traps->num_traps; i++) {
if (_cairo_trap_contains (&traps->traps[i], &point))
return TRUE;
}
 
return FALSE;
}
 
static cairo_fixed_t
_line_compute_intersection_x_for_y (const cairo_line_t *line,
cairo_fixed_t y)
{
return _cairo_edge_compute_intersection_x_for_y (&line->p1, &line->p2, y);
}
 
void
_cairo_traps_extents (const cairo_traps_t *traps,
cairo_box_t *extents)
{
int i;
 
if (traps->num_traps == 0) {
extents->p1.x = extents->p1.y = 0;
extents->p2.x = extents->p2.y = 0;
return;
}
 
extents->p1.x = extents->p1.y = INT32_MAX;
extents->p2.x = extents->p2.y = INT32_MIN;
 
for (i = 0; i < traps->num_traps; i++) {
const cairo_trapezoid_t *trap = &traps->traps[i];
 
if (trap->top < extents->p1.y)
extents->p1.y = trap->top;
if (trap->bottom > extents->p2.y)
extents->p2.y = trap->bottom;
 
if (trap->left.p1.x < extents->p1.x) {
cairo_fixed_t x = trap->left.p1.x;
if (trap->top != trap->left.p1.y) {
x = _line_compute_intersection_x_for_y (&trap->left,
trap->top);
if (x < extents->p1.x)
extents->p1.x = x;
} else
extents->p1.x = x;
}
if (trap->left.p2.x < extents->p1.x) {
cairo_fixed_t x = trap->left.p2.x;
if (trap->bottom != trap->left.p2.y) {
x = _line_compute_intersection_x_for_y (&trap->left,
trap->bottom);
if (x < extents->p1.x)
extents->p1.x = x;
} else
extents->p1.x = x;
}
 
if (trap->right.p1.x > extents->p2.x) {
cairo_fixed_t x = trap->right.p1.x;
if (trap->top != trap->right.p1.y) {
x = _line_compute_intersection_x_for_y (&trap->right,
trap->top);
if (x > extents->p2.x)
extents->p2.x = x;
} else
extents->p2.x = x;
}
if (trap->right.p2.x > extents->p2.x) {
cairo_fixed_t x = trap->right.p2.x;
if (trap->bottom != trap->right.p2.y) {
x = _line_compute_intersection_x_for_y (&trap->right,
trap->bottom);
if (x > extents->p2.x)
extents->p2.x = x;
} else
extents->p2.x = x;
}
}
}
 
 
/**
* _cairo_traps_extract_region:
* @traps: a #cairo_traps_t
* @region: a #cairo_region_t
*
* Determines if a set of trapezoids are exactly representable as a
* cairo region. If so, the passed-in region is initialized to
* the area representing the given traps. It should be finalized
* with cairo_region_fini(). If not, %CAIRO_INT_STATUS_UNSUPPORTED
* is returned.
*
* Return value: %CAIRO_STATUS_SUCCESS, %CAIRO_INT_STATUS_UNSUPPORTED
* or %CAIRO_STATUS_NO_MEMORY
**/
cairo_int_status_t
_cairo_traps_extract_region (cairo_traps_t *traps,
cairo_region_t **region)
{
cairo_rectangle_int_t stack_rects[CAIRO_STACK_ARRAY_LENGTH (cairo_rectangle_int_t)];
cairo_rectangle_int_t *rects = stack_rects;
cairo_int_status_t status;
int i, rect_count;
 
/* we only treat this a hint... */
if (! traps->maybe_region)
return CAIRO_INT_STATUS_UNSUPPORTED;
 
for (i = 0; i < traps->num_traps; i++) {
if (traps->traps[i].left.p1.x != traps->traps[i].left.p2.x ||
traps->traps[i].right.p1.x != traps->traps[i].right.p2.x ||
! _cairo_fixed_is_integer (traps->traps[i].top) ||
! _cairo_fixed_is_integer (traps->traps[i].bottom) ||
! _cairo_fixed_is_integer (traps->traps[i].left.p1.x) ||
! _cairo_fixed_is_integer (traps->traps[i].right.p1.x))
{
traps->maybe_region = FALSE;
return CAIRO_INT_STATUS_UNSUPPORTED;
}
}
 
if (traps->num_traps > ARRAY_LENGTH (stack_rects)) {
rects = _cairo_malloc_ab (traps->num_traps, sizeof (cairo_rectangle_int_t));
 
if (unlikely (rects == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
 
rect_count = 0;
for (i = 0; i < traps->num_traps; i++) {
int x1 = _cairo_fixed_integer_part (traps->traps[i].left.p1.x);
int y1 = _cairo_fixed_integer_part (traps->traps[i].top);
int x2 = _cairo_fixed_integer_part (traps->traps[i].right.p1.x);
int y2 = _cairo_fixed_integer_part (traps->traps[i].bottom);
 
rects[rect_count].x = x1;
rects[rect_count].y = y1;
rects[rect_count].width = x2 - x1;
rects[rect_count].height = y2 - y1;
 
rect_count++;
}
 
*region = cairo_region_create_rectangles (rects, rect_count);
status = (*region)->status;
 
if (rects != stack_rects)
free (rects);
 
return status;
}
 
/* moves trap points such that they become the actual corners of the trapezoid */
static void
_sanitize_trap (cairo_trapezoid_t *t)
{
cairo_trapezoid_t s = *t;
 
#define FIX(lr, tb, p) \
if (t->lr.p.y != t->tb) { \
t->lr.p.x = s.lr.p2.x + _cairo_fixed_mul_div_floor (s.lr.p1.x - s.lr.p2.x, s.tb - s.lr.p2.y, s.lr.p1.y - s.lr.p2.y); \
t->lr.p.y = s.tb; \
}
FIX (left, top, p1);
FIX (left, bottom, p2);
FIX (right, top, p1);
FIX (right, bottom, p2);
}
 
cairo_private cairo_status_t
_cairo_traps_path (const cairo_traps_t *traps,
cairo_path_fixed_t *path)
{
int i;
 
for (i = 0; i < traps->num_traps; i++) {
cairo_status_t status;
cairo_trapezoid_t trap = traps->traps[i];
 
if (trap.top == trap.bottom)
continue;
 
_sanitize_trap (&trap);
 
status = _cairo_path_fixed_move_to (path, trap.left.p1.x, trap.top);
if (unlikely (status)) return status;
status = _cairo_path_fixed_line_to (path, trap.right.p1.x, trap.top);
if (unlikely (status)) return status;
status = _cairo_path_fixed_line_to (path, trap.right.p2.x, trap.bottom);
if (unlikely (status)) return status;
status = _cairo_path_fixed_line_to (path, trap.left.p2.x, trap.bottom);
if (unlikely (status)) return status;
status = _cairo_path_fixed_close_path (path);
if (unlikely (status)) return status;
}
 
return CAIRO_STATUS_SUCCESS;
}
/programs/develop/libraries/cairo/src/cairo-truetype-subset-private.h
0,0 → 1,199
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2006 Red Hat, Inc
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
* Kristian Høgsberg <krh@redhat.com>
* Adrian Johnson <ajohnson@redneon.com>
*/
 
#ifndef CAIRO_TRUETYPE_SUBSET_PRIVATE_H
#define CAIRO_TRUETYPE_SUBSET_PRIVATE_H
 
#include "cairoint.h"
 
#if CAIRO_HAS_FONT_SUBSET
 
/* The structs defined here should strictly follow the TrueType
* specification and not be padded. We use only 16-bit integer
* in their definition to guarantee that. The fields of type
* "FIXED" in the TT spec are broken into two *_1 and *_2 16-bit
* parts, and 64-bit members are broken into four.
*
* The test truetype-tables in the test suite makes sure that
* these tables have the right size. Please update that test
* if you add new tables/structs that should be packed.
*/
 
#define MAKE_TT_TAG(a, b, c, d) (a<<24 | b<<16 | c<<8 | d)
#define TT_TAG_CFF MAKE_TT_TAG('C','F','F',' ')
#define TT_TAG_cmap MAKE_TT_TAG('c','m','a','p')
#define TT_TAG_cvt MAKE_TT_TAG('c','v','t',' ')
#define TT_TAG_fpgm MAKE_TT_TAG('f','p','g','m')
#define TT_TAG_glyf MAKE_TT_TAG('g','l','y','f')
#define TT_TAG_head MAKE_TT_TAG('h','e','a','d')
#define TT_TAG_hhea MAKE_TT_TAG('h','h','e','a')
#define TT_TAG_hmtx MAKE_TT_TAG('h','m','t','x')
#define TT_TAG_loca MAKE_TT_TAG('l','o','c','a')
#define TT_TAG_maxp MAKE_TT_TAG('m','a','x','p')
#define TT_TAG_name MAKE_TT_TAG('n','a','m','e')
#define TT_TAG_post MAKE_TT_TAG('p','o','s','t')
#define TT_TAG_prep MAKE_TT_TAG('p','r','e','p')
 
/* All tt_* structs are big-endian */
typedef struct _tt_cmap_index {
uint16_t platform;
uint16_t encoding;
uint32_t offset;
} tt_cmap_index_t;
 
typedef struct _tt_cmap {
uint16_t version;
uint16_t num_tables;
tt_cmap_index_t index[1];
} tt_cmap_t;
 
typedef struct _segment_map {
uint16_t format;
uint16_t length;
uint16_t version;
uint16_t segCountX2;
uint16_t searchRange;
uint16_t entrySelector;
uint16_t rangeShift;
uint16_t endCount[1];
} tt_segment_map_t;
 
typedef struct _tt_head {
int16_t version_1;
int16_t version_2;
int16_t revision_1;
int16_t revision_2;
uint16_t checksum_1;
uint16_t checksum_2;
uint16_t magic_1;
uint16_t magic_2;
uint16_t flags;
uint16_t units_per_em;
int16_t created_1;
int16_t created_2;
int16_t created_3;
int16_t created_4;
int16_t modified_1;
int16_t modified_2;
int16_t modified_3;
int16_t modified_4;
int16_t x_min; /* FWORD */
int16_t y_min; /* FWORD */
int16_t x_max; /* FWORD */
int16_t y_max; /* FWORD */
uint16_t mac_style;
uint16_t lowest_rec_pppem;
int16_t font_direction_hint;
int16_t index_to_loc_format;
int16_t glyph_data_format;
} tt_head_t;
 
typedef struct _tt_hhea {
int16_t version_1;
int16_t version_2;
int16_t ascender; /* FWORD */
int16_t descender; /* FWORD */
int16_t line_gap; /* FWORD */
uint16_t advance_max_width; /* UFWORD */
int16_t min_left_side_bearing; /* FWORD */
int16_t min_right_side_bearing; /* FWORD */
int16_t x_max_extent; /* FWORD */
int16_t caret_slope_rise;
int16_t caret_slope_run;
int16_t reserved[5];
int16_t metric_data_format;
uint16_t num_hmetrics;
} tt_hhea_t;
 
typedef struct _tt_maxp {
int16_t version_1;
int16_t version_2;
uint16_t num_glyphs;
uint16_t max_points;
uint16_t max_contours;
uint16_t max_composite_points;
uint16_t max_composite_contours;
uint16_t max_zones;
uint16_t max_twilight_points;
uint16_t max_storage;
uint16_t max_function_defs;
uint16_t max_instruction_defs;
uint16_t max_stack_elements;
uint16_t max_size_of_instructions;
uint16_t max_component_elements;
uint16_t max_component_depth;
} tt_maxp_t;
 
typedef struct _tt_name_record {
uint16_t platform;
uint16_t encoding;
uint16_t language;
uint16_t name;
uint16_t length;
uint16_t offset;
} tt_name_record_t;
 
typedef struct _tt_name {
uint16_t format;
uint16_t num_records;
uint16_t strings_offset;
tt_name_record_t records[1];
} tt_name_t;
 
 
 
/* composite_glyph_t flags */
#define TT_ARG_1_AND_2_ARE_WORDS 0x0001
#define TT_WE_HAVE_A_SCALE 0x0008
#define TT_MORE_COMPONENTS 0x0020
#define TT_WE_HAVE_AN_X_AND_Y_SCALE 0x0040
#define TT_WE_HAVE_A_TWO_BY_TWO 0x0080
 
typedef struct _tt_composite_glyph {
uint16_t flags;
uint16_t index;
uint16_t args[6]; /* 1 to 6 arguments depending on value of flags */
} tt_composite_glyph_t;
 
typedef struct _tt_glyph_data {
int16_t num_contours;
int8_t data[8];
tt_composite_glyph_t glyph;
} tt_glyph_data_t;
 
#endif /* CAIRO_HAS_FONT_SUBSET */
 
#endif /* CAIRO_TRUETYPE_SUBSET_PRIVATE_H */
/programs/develop/libraries/cairo/src/cairo-type1-private.h
0,0 → 1,51
/* Cairo - a vector graphics library with display and print output
*
* Copyright © 2007 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
* Adrian Johnson <ajohnson@redneon.com>
*/
 
#ifndef CAIRO_TYPE1_PRIVATE_H
#define CAIRO_TYPE1_PRIVATE_H
 
#include "cairoint.h"
 
#if CAIRO_HAS_FONT_SUBSET
 
/* Magic constants for the type1 eexec encryption */
#define CAIRO_TYPE1_ENCRYPT_C1 ((unsigned short) 52845)
#define CAIRO_TYPE1_ENCRYPT_C2 ((unsigned short) 22719)
#define CAIRO_TYPE1_PRIVATE_DICT_KEY ((unsigned short) 55665)
#define CAIRO_TYPE1_CHARSTRING_KEY ((unsigned short) 4330)
 
#endif /* CAIRO_HAS_FONT_SUBSET */
 
#endif /* CAIRO_TYPE1_PRIVATE_H */
/programs/develop/libraries/cairo/src/cairo-type3-glyph-surface-private.h
0,0 → 1,87
/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2008 Adrian Johnson
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Adrian Johnson.
*
* Contributor(s):
* Adrian Johnson <ajohnson@redneon.com>
*/
 
#ifndef CAIRO_TYPE3_GLYPH_SURFACE_PRIVATE_H
#define CAIRO_TYPE3_GLYPH_SURFACE_PRIVATE_H
 
#include "cairoint.h"
 
#if CAIRO_HAS_FONT_SUBSET
 
#include "cairo-surface-private.h"
#include "cairo-surface-clipper-private.h"
#include "cairo-pdf-operators-private.h"
 
typedef cairo_status_t (*cairo_type3_glyph_surface_emit_image_t) (cairo_image_surface_t *image,
cairo_output_stream_t *stream);
 
typedef struct cairo_type3_glyph_surface {
cairo_surface_t base;
 
cairo_scaled_font_t *scaled_font;
cairo_output_stream_t *stream;
cairo_pdf_operators_t pdf_operators;
cairo_matrix_t cairo_to_pdf;
cairo_type3_glyph_surface_emit_image_t emit_image;
 
cairo_surface_clipper_t clipper;
} cairo_type3_glyph_surface_t;
 
cairo_private cairo_surface_t *
_cairo_type3_glyph_surface_create (cairo_scaled_font_t *scaled_font,
cairo_output_stream_t *stream,
cairo_type3_glyph_surface_emit_image_t emit_image,
cairo_scaled_font_subsets_t *font_subsets);
 
cairo_private void
_cairo_type3_glyph_surface_set_font_subsets_callback (void *abstract_surface,
cairo_pdf_operators_use_font_subset_t use_font_subset,
void *closure);
 
cairo_private cairo_status_t
_cairo_type3_glyph_surface_analyze_glyph (void *abstract_surface,
unsigned long glyph_index);
 
cairo_private cairo_status_t
_cairo_type3_glyph_surface_emit_glyph (void *abstract_surface,
cairo_output_stream_t *stream,
unsigned long glyph_index,
cairo_box_t *bbox,
double *width);
 
#endif /* CAIRO_HAS_FONT_SUBSET */
 
#endif /* CAIRO_TYPE3_GLYPH_SURFACE_PRIVATE_H */
/programs/develop/libraries/cairo/src/cairo-types-private.h
0,0 → 1,477
/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2002 University of Southern California
* Copyright © 2005 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
*/
 
#ifndef CAIRO_TYPES_PRIVATE_H
#define CAIRO_TYPES_PRIVATE_H
 
#include "cairo.h"
#include "cairo-fixed-type-private.h"
#include "cairo-list-private.h"
#include "cairo-reference-count-private.h"
 
/**
* SECTION:cairo-types
* @Title: Types
* @Short_Description: Generic data types
*
* This section lists generic data types used in the cairo API.
*/
 
typedef struct _cairo_array cairo_array_t;
typedef struct _cairo_backend cairo_backend_t;
typedef struct _cairo_boxes_t cairo_boxes_t;
typedef struct _cairo_cache cairo_cache_t;
typedef struct _cairo_composite_rectangles cairo_composite_rectangles_t;
typedef struct _cairo_clip cairo_clip_t;
typedef struct _cairo_clip_path cairo_clip_path_t;
typedef struct _cairo_color cairo_color_t;
typedef struct _cairo_color_stop cairo_color_stop_t;
typedef struct _cairo_device_backend cairo_device_backend_t;
typedef struct _cairo_font_face_backend cairo_font_face_backend_t;
typedef struct _cairo_gstate cairo_gstate_t;
typedef struct _cairo_hash_entry cairo_hash_entry_t;
typedef struct _cairo_hash_table cairo_hash_table_t;
typedef struct _cairo_image_surface cairo_image_surface_t;
typedef struct _cairo_mime_data cairo_mime_data_t;
typedef struct _cairo_observer cairo_observer_t;
typedef struct _cairo_output_stream cairo_output_stream_t;
typedef struct _cairo_paginated_surface_backend cairo_paginated_surface_backend_t;
typedef struct _cairo_path_fixed cairo_path_fixed_t;
typedef struct _cairo_rectangle_int16 cairo_glyph_size_t;
typedef struct _cairo_scaled_font_backend cairo_scaled_font_backend_t;
typedef struct _cairo_scaled_font_subsets cairo_scaled_font_subsets_t;
typedef struct _cairo_solid_pattern cairo_solid_pattern_t;
typedef struct _cairo_surface_backend cairo_surface_backend_t;
typedef struct _cairo_surface_snapshot cairo_surface_snapshot_t;
typedef struct _cairo_surface_subsurface cairo_surface_subsurface_t;
typedef struct _cairo_surface_wrapper cairo_surface_wrapper_t;
typedef struct _cairo_unscaled_font_backend cairo_unscaled_font_backend_t;
typedef struct _cairo_xlib_screen_info cairo_xlib_screen_info_t;
 
typedef cairo_array_t cairo_user_data_array_t;
 
struct _cairo_observer {
cairo_list_t link;
void (*callback) (cairo_observer_t *self, void *arg);
};
 
/**
* cairo_hash_entry_t:
*
* A #cairo_hash_entry_t contains both a key and a value for
* #cairo_hash_table_t. User-derived types for #cairo_hash_entry_t must
* be type-compatible with this structure (eg. they must have an
* unsigned long as the first parameter. The easiest way to get this
* is to use:
*
* typedef _my_entry {
* cairo_hash_entry_t base;
* ... Remainder of key and value fields here ..
* } my_entry_t;
*
* which then allows a pointer to my_entry_t to be passed to any of
* the #cairo_hash_table_t functions as follows without requiring a cast:
*
* _cairo_hash_table_insert (hash_table, &my_entry->base);
*
* IMPORTANT: The caller is reponsible for initializing
* my_entry->base.hash with a hash code derived from the key. The
* essential property of the hash code is that keys_equal must never
* return %TRUE for two keys that have different hashes. The best hash
* code will reduce the frequency of two keys with the same code for
* which keys_equal returns %FALSE.
*
* Which parts of the entry make up the "key" and which part make up
* the value are entirely up to the caller, (as determined by the
* computation going into base.hash as well as the keys_equal
* function). A few of the #cairo_hash_table_t functions accept an entry
* which will be used exclusively as a "key", (indicated by a
* parameter name of key). In these cases, the value-related fields of
* the entry need not be initialized if so desired.
**/
struct _cairo_hash_entry {
unsigned long hash;
};
 
struct _cairo_array {
unsigned int size;
unsigned int num_elements;
unsigned int element_size;
char **elements;
 
cairo_bool_t is_snapshot;
};
 
/**
* cairo_lcd_filter_t:
* @CAIRO_LCD_FILTER_DEFAULT: Use the default LCD filter for
* font backend and target device
* @CAIRO_LCD_FILTER_NONE: Do not perform LCD filtering
* @CAIRO_LCD_FILTER_INTRA_PIXEL: Intra-pixel filter
* @CAIRO_LCD_FILTER_FIR3: FIR filter with a 3x3 kernel
* @CAIRO_LCD_FILTER_FIR5: FIR filter with a 5x5 kernel
*
* The LCD filter specifies the low-pass filter applied to LCD-optimized
* bitmaps generated with an antialiasing mode of %CAIRO_ANTIALIAS_SUBPIXEL.
*
* Note: This API was temporarily made available in the public
* interface during the 1.7.x development series, but was made private
* before 1.8.
**/
typedef enum _cairo_lcd_filter {
CAIRO_LCD_FILTER_DEFAULT,
CAIRO_LCD_FILTER_NONE,
CAIRO_LCD_FILTER_INTRA_PIXEL,
CAIRO_LCD_FILTER_FIR3,
CAIRO_LCD_FILTER_FIR5
} cairo_lcd_filter_t;
 
struct _cairo_font_options {
cairo_antialias_t antialias;
cairo_subpixel_order_t subpixel_order;
cairo_lcd_filter_t lcd_filter;
cairo_hint_style_t hint_style;
cairo_hint_metrics_t hint_metrics;
};
 
/* XXX: Right now, the _cairo_color structure puts unpremultiplied
color in the doubles and premultiplied color in the shorts. Yes,
this is crazy insane, (but at least we don't export this
madness). I'm still working on a cleaner API, but in the meantime,
at least this does prevent precision loss in color when changing
alpha. */
struct _cairo_color {
double red;
double green;
double blue;
double alpha;
 
unsigned short red_short;
unsigned short green_short;
unsigned short blue_short;
unsigned short alpha_short;
};
 
struct _cairo_color_stop {
/* unpremultiplied */
double red;
double green;
double blue;
double alpha;
 
/* unpremultipled, for convenience */
uint16_t red_short;
uint16_t green_short;
uint16_t blue_short;
uint16_t alpha_short;
};
 
typedef enum _cairo_paginated_mode {
CAIRO_PAGINATED_MODE_ANALYZE, /* analyze page regions */
CAIRO_PAGINATED_MODE_RENDER, /* render page contents */
CAIRO_PAGINATED_MODE_FALLBACK /* paint fallback images */
} cairo_paginated_mode_t;
 
/* 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 100
* offset. We want to keep it fit in int8_t as the compiler may choose
* that for #cairo_status_t */
typedef enum _cairo_int_status {
CAIRO_INT_STATUS_UNSUPPORTED = 100,
CAIRO_INT_STATUS_DEGENERATE,
CAIRO_INT_STATUS_NOTHING_TO_DO,
CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY,
CAIRO_INT_STATUS_IMAGE_FALLBACK,
CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN,
 
CAIRO_INT_STATUS_LAST_STATUS
} cairo_int_status_t;
 
typedef enum _cairo_internal_surface_type {
CAIRO_INTERNAL_SURFACE_TYPE_SNAPSHOT = 0x1000,
CAIRO_INTERNAL_SURFACE_TYPE_PAGINATED,
CAIRO_INTERNAL_SURFACE_TYPE_ANALYSIS,
CAIRO_INTERNAL_SURFACE_TYPE_TEST_FALLBACK,
CAIRO_INTERNAL_SURFACE_TYPE_TEST_PAGINATED,
CAIRO_INTERNAL_SURFACE_TYPE_TEST_WRAPPING,
CAIRO_INTERNAL_SURFACE_TYPE_NULL,
CAIRO_INTERNAL_SURFACE_TYPE_TYPE3_GLYPH
} cairo_internal_surface_type_t;
 
#define CAIRO_HAS_TEST_PAGINATED_SURFACE 1
#define CAIRO_HAS_TEST_NULL_SURFACE 1
#define CAIRO_HAS_TEST_WRAPPING_SURFACE 1
 
typedef struct _cairo_slope {
cairo_fixed_t dx;
cairo_fixed_t dy;
} cairo_slope_t, cairo_distance_t;
 
typedef struct _cairo_point_double {
double x;
double y;
} cairo_point_double_t;
 
typedef struct _cairo_distance_double {
double dx;
double dy;
} cairo_distance_double_t;
 
typedef struct _cairo_line {
cairo_point_t p1;
cairo_point_t p2;
} cairo_line_t, cairo_box_t;
 
typedef struct _cairo_trapezoid {
cairo_fixed_t top, bottom;
cairo_line_t left, right;
} cairo_trapezoid_t;
 
typedef struct _cairo_point_int {
int x, y;
} cairo_point_int_t;
 
#define CAIRO_RECT_INT_MIN (INT_MIN >> CAIRO_FIXED_FRAC_BITS)
#define CAIRO_RECT_INT_MAX (INT_MAX >> CAIRO_FIXED_FRAC_BITS)
 
typedef enum _cairo_direction {
CAIRO_DIRECTION_FORWARD,
CAIRO_DIRECTION_REVERSE
} cairo_direction_t;
 
typedef struct _cairo_edge {
cairo_line_t line;
int top, bottom;
int dir;
} cairo_edge_t;
 
typedef struct _cairo_polygon {
cairo_status_t status;
 
cairo_point_t first_point;
cairo_point_t last_point;
cairo_point_t current_point;
cairo_slope_t current_edge;
cairo_bool_t has_current_point;
cairo_bool_t has_current_edge;
 
cairo_box_t extents;
cairo_box_t limit;
const cairo_box_t *limits;
int num_limits;
 
int num_edges;
int edges_size;
cairo_edge_t *edges;
cairo_edge_t edges_embedded[32];
} cairo_polygon_t;
 
typedef cairo_warn cairo_status_t
(*cairo_spline_add_point_func_t) (void *closure,
const cairo_point_t *point);
 
typedef struct _cairo_spline_knots {
cairo_point_t a, b, c, d;
} cairo_spline_knots_t;
 
typedef struct _cairo_spline {
cairo_spline_add_point_func_t add_point_func;
void *closure;
 
cairo_spline_knots_t knots;
 
cairo_slope_t initial_slope;
cairo_slope_t final_slope;
 
cairo_bool_t has_point;
cairo_point_t last_point;
} cairo_spline_t;
 
typedef struct _cairo_pen_vertex {
cairo_point_t point;
 
cairo_slope_t slope_ccw;
cairo_slope_t slope_cw;
} cairo_pen_vertex_t;
 
typedef struct _cairo_pen {
double radius;
double tolerance;
 
int num_vertices;
cairo_pen_vertex_t *vertices;
cairo_pen_vertex_t vertices_embedded[32];
} cairo_pen_t;
 
typedef struct _cairo_stroke_style {
double line_width;
cairo_line_cap_t line_cap;
cairo_line_join_t line_join;
double miter_limit;
double *dash;
unsigned int num_dashes;
double dash_offset;
} cairo_stroke_style_t;
 
typedef struct _cairo_format_masks {
int bpp;
unsigned long alpha_mask;
unsigned long red_mask;
unsigned long green_mask;
unsigned long blue_mask;
} cairo_format_masks_t;
 
typedef enum {
CAIRO_STOCK_WHITE,
CAIRO_STOCK_BLACK,
CAIRO_STOCK_TRANSPARENT,
CAIRO_STOCK_NUM_COLORS,
} cairo_stock_t;
 
typedef enum _cairo_image_transparency {
CAIRO_IMAGE_IS_OPAQUE,
CAIRO_IMAGE_HAS_BILEVEL_ALPHA,
CAIRO_IMAGE_HAS_ALPHA,
CAIRO_IMAGE_UNKNOWN
} cairo_image_transparency_t;
 
struct _cairo_mime_data {
cairo_reference_count_t ref_count;
unsigned char *data;
unsigned long length;
cairo_destroy_func_t destroy;
void *closure;
};
 
struct _cairo_pattern {
cairo_pattern_type_t type;
cairo_reference_count_t ref_count;
cairo_status_t status;
cairo_user_data_array_t user_data;
 
cairo_matrix_t matrix;
cairo_filter_t filter;
cairo_extend_t extend;
 
cairo_bool_t has_component_alpha;
};
 
struct _cairo_solid_pattern {
cairo_pattern_t base;
cairo_color_t color;
};
 
typedef struct _cairo_surface_pattern {
cairo_pattern_t base;
 
cairo_surface_t *surface;
} cairo_surface_pattern_t;
 
typedef struct _cairo_gradient_stop {
double offset;
cairo_color_stop_t color;
} cairo_gradient_stop_t;
 
typedef struct _cairo_gradient_pattern {
cairo_pattern_t base;
 
unsigned int n_stops;
unsigned int stops_size;
cairo_gradient_stop_t *stops;
cairo_gradient_stop_t stops_embedded[2];
} cairo_gradient_pattern_t;
 
typedef struct _cairo_linear_pattern {
cairo_gradient_pattern_t base;
 
cairo_point_t p1;
cairo_point_t p2;
} cairo_linear_pattern_t;
 
typedef struct _cairo_radial_pattern {
cairo_gradient_pattern_t base;
 
cairo_point_t c1;
cairo_fixed_t r1;
cairo_point_t c2;
cairo_fixed_t r2;
} cairo_radial_pattern_t;
 
typedef union {
cairo_gradient_pattern_t base;
 
cairo_linear_pattern_t linear;
cairo_radial_pattern_t radial;
} cairo_gradient_pattern_union_t;
 
typedef union {
cairo_pattern_type_t type;
cairo_pattern_t base;
 
cairo_solid_pattern_t solid;
cairo_surface_pattern_t surface;
cairo_gradient_pattern_union_t gradient;
} cairo_pattern_union_t;
 
/*
* A #cairo_unscaled_font_t is just an opaque handle we use in the
* glyph cache.
*/
typedef struct _cairo_unscaled_font {
cairo_hash_entry_t hash_entry;
cairo_reference_count_t ref_count;
const cairo_unscaled_font_backend_t *backend;
} cairo_unscaled_font_t;
 
typedef struct _cairo_scaled_glyph {
cairo_hash_entry_t hash_entry;
 
cairo_text_extents_t metrics; /* user-space metrics */
cairo_text_extents_t fs_metrics; /* font-space metrics */
cairo_box_t bbox; /* device-space bounds */
int16_t x_advance; /* device-space rounded X advance */
int16_t y_advance; /* device-space rounded Y advance */
 
unsigned int has_info;
cairo_image_surface_t *surface; /* device-space image */
cairo_path_fixed_t *path; /* device-space outline */
cairo_surface_t *recording_surface; /* device-space recording-surface */
 
void *surface_private; /* for the surface backend */
} cairo_scaled_glyph_t;
#endif /* CAIRO_TYPES_PRIVATE_H */
/programs/develop/libraries/cairo/src/cairo-unicode.c
0,0 → 1,422
/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
/* cairo - a vector graphics library with display and print output
*
* The code in this file is derived from GLib's gutf8.c and
* ultimately from libunicode. It is relicensed under the
* dual LGPL/MPL with permission of the original authors.
*
* Copyright © 1999 Tom Tromey
* Copyright © 2005 Red Hat, Inc
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Tom Tromey.
* and Red Hat, Inc.
*
* Contributor(s):
* Owen Taylor <otaylor@redhat.com>
*/
 
#include "cairoint.h"
#include "cairo-error-private.h"
 
#define UTF8_COMPUTE(Char, Mask, Len) \
if (Char < 128) \
{ \
Len = 1; \
Mask = 0x7f; \
} \
else if ((Char & 0xe0) == 0xc0) \
{ \
Len = 2; \
Mask = 0x1f; \
} \
else if ((Char & 0xf0) == 0xe0) \
{ \
Len = 3; \
Mask = 0x0f; \
} \
else if ((Char & 0xf8) == 0xf0) \
{ \
Len = 4; \
Mask = 0x07; \
} \
else if ((Char & 0xfc) == 0xf8) \
{ \
Len = 5; \
Mask = 0x03; \
} \
else if ((Char & 0xfe) == 0xfc) \
{ \
Len = 6; \
Mask = 0x01; \
} \
else \
Len = -1;
 
#define UTF8_LENGTH(Char) \
((Char) < 0x80 ? 1 : \
((Char) < 0x800 ? 2 : \
((Char) < 0x10000 ? 3 : \
((Char) < 0x200000 ? 4 : \
((Char) < 0x4000000 ? 5 : 6)))))
 
#define UTF8_GET(Result, Chars, Count, Mask, Len) \
(Result) = (Chars)[0] & (Mask); \
for ((Count) = 1; (Count) < (Len); ++(Count)) \
{ \
if (((Chars)[(Count)] & 0xc0) != 0x80) \
{ \
(Result) = -1; \
break; \
} \
(Result) <<= 6; \
(Result) |= ((Chars)[(Count)] & 0x3f); \
}
 
#define UNICODE_VALID(Char) \
((Char) < 0x110000 && \
(((Char) & 0xFFFFF800) != 0xD800) && \
((Char) < 0xFDD0 || (Char) > 0xFDEF) && \
((Char) & 0xFFFE) != 0xFFFE)
 
static const char utf8_skip_data[256] = {
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,6,6,1,1
};
 
#define UTF8_NEXT_CHAR(p) ((p) + utf8_skip_data[*(unsigned char *)(p)])
 
/* Converts a sequence of bytes encoded as UTF-8 to a Unicode character.
* If @p does not point to a valid UTF-8 encoded character, results are
* undefined.
**/
static uint32_t
_utf8_get_char (const unsigned char *p)
{
int i, mask = 0, len;
uint32_t result;
unsigned char c = (unsigned char) *p;
 
UTF8_COMPUTE (c, mask, len);
if (len == -1)
return (uint32_t)-1;
UTF8_GET (result, p, i, mask, len);
 
return result;
}
 
/* Like _utf8_get_char, but take a maximum length
* and return (uint32_t)-2 on incomplete trailing character
*/
static uint32_t
_utf8_get_char_extended (const unsigned char *p,
long max_len)
{
int i, len;
uint32_t wc = (unsigned char) *p;
 
if (wc < 0x80) {
return wc;
} else if (wc < 0xc0) {
return (uint32_t)-1;
} else if (wc < 0xe0) {
len = 2;
wc &= 0x1f;
} else if (wc < 0xf0) {
len = 3;
wc &= 0x0f;
} else if (wc < 0xf8) {
len = 4;
wc &= 0x07;
} else if (wc < 0xfc) {
len = 5;
wc &= 0x03;
} else if (wc < 0xfe) {
len = 6;
wc &= 0x01;
} else {
return (uint32_t)-1;
}
 
if (max_len >= 0 && len > max_len) {
for (i = 1; i < max_len; i++) {
if ((((unsigned char *)p)[i] & 0xc0) != 0x80)
return (uint32_t)-1;
}
return (uint32_t)-2;
}
 
for (i = 1; i < len; ++i) {
uint32_t ch = ((unsigned char *)p)[i];
 
if ((ch & 0xc0) != 0x80) {
if (ch)
return (uint32_t)-1;
else
return (uint32_t)-2;
}
 
wc <<= 6;
wc |= (ch & 0x3f);
}
 
if (UTF8_LENGTH(wc) != len)
return (uint32_t)-1;
 
return wc;
}
 
/**
* _cairo_utf8_get_char_validated:
* @p: a UTF-8 string
* @unicode: location to store one Unicode character
*
* Decodes the first character of a valid UTF-8 string, and returns
* the number of bytes consumed.
*
* Note that the string should be valid. Do not use this without
* validating the string first.
*
* Returns: the number of bytes forming the character returned.
**/
int
_cairo_utf8_get_char_validated (const char *p,
uint32_t *unicode)
{
int i, mask = 0, len;
uint32_t result;
unsigned char c = (unsigned char) *p;
 
UTF8_COMPUTE (c, mask, len);
if (len == -1) {
if (unicode)
*unicode = (uint32_t)-1;
return 1;
}
UTF8_GET (result, p, i, mask, len);
 
if (unicode)
*unicode = result;
return len;
}
 
/**
* _cairo_utf8_to_ucs4:
* @str: an UTF-8 string
* @len: length of @str in bytes, or -1 if it is nul-terminated.
* If @len is supplied and the string has an embedded nul
* byte, only the portion before the nul byte is converted.
* @result: location to store a pointer to a newly allocated UTF-32
* string (always native endian), or %NULL. Free with free(). A 0
* word will be written after the last character.
* @items_written: location to store number of 32-bit words
* written. (Not including the trailing 0)
*
* Converts a UTF-8 string to UCS-4. UCS-4 is an encoding of Unicode
* with 1 32-bit word per character. The string is validated to
* consist entirely of valid Unicode characters.
*
* Return value: %CAIRO_STATUS_SUCCESS if the entire string was
* successfully converted. %CAIRO_STATUS_INVALID_STRING if an
* invalid sequence was found.
**/
cairo_status_t
_cairo_utf8_to_ucs4 (const char *str,
int len,
uint32_t **result,
int *items_written)
{
uint32_t *str32 = NULL;
int n_chars, i;
const unsigned char *in;
const unsigned char * const ustr = (const unsigned char *) str;
 
in = ustr;
n_chars = 0;
while ((len < 0 || ustr + len - in > 0) && *in)
{
uint32_t wc = _utf8_get_char_extended (in, ustr + len - in);
if (wc & 0x80000000 || !UNICODE_VALID (wc))
return _cairo_error (CAIRO_STATUS_INVALID_STRING);
 
n_chars++;
if (n_chars == INT_MAX)
return _cairo_error (CAIRO_STATUS_INVALID_STRING);
 
in = UTF8_NEXT_CHAR (in);
}
 
if (result) {
str32 = _cairo_malloc_ab (n_chars + 1, sizeof (uint32_t));
if (!str32)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
in = ustr;
for (i=0; i < n_chars; i++) {
str32[i] = _utf8_get_char (in);
in = UTF8_NEXT_CHAR (in);
}
str32[i] = 0;
 
*result = str32;
}
 
if (items_written)
*items_written = n_chars;
 
return CAIRO_STATUS_SUCCESS;
}
 
/**
* _cairo_ucs4_to_utf8:
* @unicode: a UCS-4 character
* @utf8: buffer to write utf8 string into. Must have at least 4 bytes
* space available. Or %NULL.
*
* This space left intentionally blank.
*
* Return value: Number of bytes in the utf8 string or 0 if an invalid
* unicode character
**/
int
_cairo_ucs4_to_utf8 (uint32_t unicode,
char *utf8)
{
int bytes;
char *p;
 
if (unicode < 0x80) {
if (utf8)
*utf8 = unicode;
return 1;
} else if (unicode < 0x800) {
bytes = 2;
} else if (unicode < 0x10000) {
bytes = 3;
} else if (unicode < 0x200000) {
bytes = 4;
} else {
return 0;
}
 
if (!utf8)
return bytes;
 
p = utf8 + bytes;
while (p > utf8) {
*--p = 0x80 | (unicode & 0x3f);
unicode >>= 6;
}
*p |= 0xf0 << (4 - bytes);
 
return bytes;
}
 
#if CAIRO_HAS_UTF8_TO_UTF16
/**
* _cairo_utf8_to_utf16:
* @str: an UTF-8 string
* @len: length of @str in bytes, or -1 if it is nul-terminated.
* If @len is supplied and the string has an embedded nul
* byte, only the portion before the nul byte is converted.
* @result: location to store a pointer to a newly allocated UTF-16
* string (always native endian). Free with free(). A 0
* word will be written after the last character.
* @items_written: location to store number of 16-bit words
* written. (Not including the trailing 0)
*
* Converts a UTF-8 string to UTF-16. UTF-16 is an encoding of Unicode
* where characters are represented either as a single 16-bit word, or
* as a pair of 16-bit "surrogates". The string is validated to
* consist entirely of valid Unicode characters.
*
* Return value: %CAIRO_STATUS_SUCCESS if the entire string was
* successfully converted. %CAIRO_STATUS_INVALID_STRING if an
* an invalid sequence was found.
**/
cairo_status_t
_cairo_utf8_to_utf16 (const char *str,
int len,
uint16_t **result,
int *items_written)
{
uint16_t *str16 = NULL;
int n16, i;
const unsigned char *in;
const unsigned char * const ustr = (const unsigned char *) str;
 
in = ustr;
n16 = 0;
while ((len < 0 || ustr + len - in > 0) && *in) {
uint32_t wc = _utf8_get_char_extended (in, ustr + len - in);
if (wc & 0x80000000 || !UNICODE_VALID (wc))
return _cairo_error (CAIRO_STATUS_INVALID_STRING);
 
if (wc < 0x10000)
n16 += 1;
else
n16 += 2;
 
if (n16 == INT_MAX - 1 || n16 == INT_MAX)
return _cairo_error (CAIRO_STATUS_INVALID_STRING);
 
in = UTF8_NEXT_CHAR (in);
}
 
str16 = _cairo_malloc_ab (n16 + 1, sizeof (uint16_t));
if (!str16)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
in = ustr;
for (i = 0; i < n16;) {
uint32_t wc = _utf8_get_char (in);
 
if (wc < 0x10000) {
str16[i++] = wc;
} else {
str16[i++] = (wc - 0x10000) / 0x400 + 0xd800;
str16[i++] = (wc - 0x10000) % 0x400 + 0xdc00;
}
 
in = UTF8_NEXT_CHAR (in);
}
 
str16[i] = 0;
 
*result = str16;
if (items_written)
*items_written = n16;
 
return CAIRO_STATUS_SUCCESS;
}
#endif
/programs/develop/libraries/cairo/src/cairo-user-font-private.h
0,0 → 1,46
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2006, 2008 Red Hat, Inc
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
* Kristian Høgsberg <krh@redhat.com>
* Behdad Esfahbod <behdad@behdad.org>
*/
 
#ifndef CAIRO_USER_FONT_PRIVATE_H
#define CAIRO_USER_FONT_PRIVATE_H
 
#include "cairo.h"
#include "cairo-compiler-private.h"
 
cairo_private cairo_bool_t
_cairo_font_face_is_user (cairo_font_face_t *font_face);
 
#endif /* CAIRO_USER_FONT_PRIVATE_H */
/programs/develop/libraries/cairo/src/cairo-user-font.c
0,0 → 1,827
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2006, 2008 Red Hat, Inc
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
* Kristian Høgsberg <krh@redhat.com>
* Behdad Esfahbod <behdad@behdad.org>
*/
 
#include "cairoint.h"
#include "cairo-user-font-private.h"
#include "cairo-recording-surface-private.h"
#include "cairo-analysis-surface-private.h"
#include "cairo-error-private.h"
 
/**
* SECTION:cairo-user-fonts
* @Title:User Fonts
* @Short_Description: Font support with font data provided by the user
*
* The user-font feature allows the cairo user to provide drawings for glyphs
* in a font. This is most useful in implementing fonts in non-standard
* formats, like SVG fonts and Flash fonts, but can also be used by games and
* other application to draw "funky" fonts.
*/
 
/**
* CAIRO_HAS_USER_FONT:
*
* Defined if the user font backend is available.
* This macro can be used to conditionally compile backend-specific code.
* The user font backend is always built in versions of cairo that support
* this feature (1.8 and later).
*
* @Since: 1.8
*/
 
typedef struct _cairo_user_scaled_font_methods {
cairo_user_scaled_font_init_func_t init;
cairo_user_scaled_font_render_glyph_func_t render_glyph;
cairo_user_scaled_font_unicode_to_glyph_func_t unicode_to_glyph;
cairo_user_scaled_font_text_to_glyphs_func_t text_to_glyphs;
} cairo_user_scaled_font_methods_t;
 
typedef struct _cairo_user_font_face {
cairo_font_face_t base;
 
/* Set to true after first scaled font is created. At that point,
* the scaled_font_methods cannot change anymore. */
cairo_bool_t immutable;
 
cairo_user_scaled_font_methods_t scaled_font_methods;
} cairo_user_font_face_t;
 
typedef struct _cairo_user_scaled_font {
cairo_scaled_font_t base;
 
cairo_text_extents_t default_glyph_extents;
 
/* space to compute extents in, and factors to convert back to user space */
cairo_matrix_t extent_scale;
double extent_x_scale;
double extent_y_scale;
 
/* multiplier for metrics hinting */
double snap_x_scale;
double snap_y_scale;
 
} cairo_user_scaled_font_t;
 
/* #cairo_user_scaled_font_t */
 
static cairo_surface_t *
_cairo_user_scaled_font_create_recording_surface (const cairo_user_scaled_font_t *scaled_font)
{
cairo_content_t content;
 
content = scaled_font->base.options.antialias == CAIRO_ANTIALIAS_SUBPIXEL ?
CAIRO_CONTENT_COLOR_ALPHA :
CAIRO_CONTENT_ALPHA;
 
return cairo_recording_surface_create (content, NULL);
}
 
 
static cairo_t *
_cairo_user_scaled_font_create_recording_context (const cairo_user_scaled_font_t *scaled_font,
cairo_surface_t *recording_surface)
{
cairo_t *cr;
 
cr = cairo_create (recording_surface);
 
if (!_cairo_matrix_is_scale_0 (&scaled_font->base.scale)) {
cairo_matrix_t scale;
scale = scaled_font->base.scale;
scale.x0 = scale.y0 = 0.;
cairo_set_matrix (cr, &scale);
}
 
cairo_set_font_size (cr, 1.0);
cairo_set_font_options (cr, &scaled_font->base.options);
cairo_set_source_rgb (cr, 1., 1., 1.);
 
return cr;
}
 
static cairo_int_status_t
_cairo_user_scaled_glyph_init (void *abstract_font,
cairo_scaled_glyph_t *scaled_glyph,
cairo_scaled_glyph_info_t info)
{
cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
cairo_user_scaled_font_t *scaled_font = abstract_font;
cairo_surface_t *recording_surface = scaled_glyph->recording_surface;
 
if (!scaled_glyph->recording_surface) {
cairo_user_font_face_t *face =
(cairo_user_font_face_t *) scaled_font->base.font_face;
cairo_text_extents_t extents = scaled_font->default_glyph_extents;
cairo_t *cr;
 
if (!face->scaled_font_methods.render_glyph)
return CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED;
 
recording_surface = _cairo_user_scaled_font_create_recording_surface (scaled_font);
 
/* special case for 0 rank matrix (as in _cairo_scaled_font_init): empty surface */
if (!_cairo_matrix_is_scale_0 (&scaled_font->base.scale)) {
cr = _cairo_user_scaled_font_create_recording_context (scaled_font, recording_surface);
status = face->scaled_font_methods.render_glyph ((cairo_scaled_font_t *)scaled_font,
_cairo_scaled_glyph_index(scaled_glyph),
cr, &extents);
if (status == CAIRO_STATUS_SUCCESS)
status = cairo_status (cr);
 
cairo_destroy (cr);
 
if (unlikely (status)) {
cairo_surface_destroy (recording_surface);
return status;
}
}
 
_cairo_scaled_glyph_set_recording_surface (scaled_glyph,
&scaled_font->base,
recording_surface);
 
 
/* set metrics */
 
if (extents.width == 0.) {
cairo_box_t bbox;
double x1, y1, x2, y2;
double x_scale, y_scale;
 
/* Compute extents.x/y/width/height from recording_surface,
* in font space.
*/
status = _cairo_recording_surface_get_bbox ((cairo_recording_surface_t *) recording_surface,
&bbox,
&scaled_font->extent_scale);
if (unlikely (status))
return status;
 
_cairo_box_to_doubles (&bbox, &x1, &y1, &x2, &y2);
 
x_scale = scaled_font->extent_x_scale;
y_scale = scaled_font->extent_y_scale;
extents.x_bearing = x1 * x_scale;
extents.y_bearing = y1 * y_scale;
extents.width = (x2 - x1) * x_scale;
extents.height = (y2 - y1) * y_scale;
}
 
if (scaled_font->base.options.hint_metrics != CAIRO_HINT_METRICS_OFF) {
extents.x_advance = _cairo_lround (extents.x_advance / scaled_font->snap_x_scale) * scaled_font->snap_x_scale;
extents.y_advance = _cairo_lround (extents.y_advance / scaled_font->snap_y_scale) * scaled_font->snap_y_scale;
}
 
_cairo_scaled_glyph_set_metrics (scaled_glyph,
&scaled_font->base,
&extents);
}
 
if (info & CAIRO_SCALED_GLYPH_INFO_SURFACE) {
cairo_surface_t *surface;
cairo_format_t format;
int width, height;
 
/* TODO
* extend the glyph cache to support argb glyphs.
* need to figure out the semantics and interaction with subpixel
* rendering first.
*/
 
width = _cairo_fixed_integer_ceil (scaled_glyph->bbox.p2.x) -
_cairo_fixed_integer_floor (scaled_glyph->bbox.p1.x);
height = _cairo_fixed_integer_ceil (scaled_glyph->bbox.p2.y) -
_cairo_fixed_integer_floor (scaled_glyph->bbox.p1.y);
 
switch (scaled_font->base.options.antialias) {
default:
case CAIRO_ANTIALIAS_DEFAULT:
case CAIRO_ANTIALIAS_GRAY: format = CAIRO_FORMAT_A8; break;
case CAIRO_ANTIALIAS_NONE: format = CAIRO_FORMAT_A1; break;
case CAIRO_ANTIALIAS_SUBPIXEL: format = CAIRO_FORMAT_ARGB32; break;
}
surface = cairo_image_surface_create (format, width, height);
 
cairo_surface_set_device_offset (surface,
- _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.x),
- _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.y));
status = _cairo_recording_surface_replay (recording_surface, surface);
 
if (unlikely (status)) {
cairo_surface_destroy(surface);
return status;
}
 
_cairo_scaled_glyph_set_surface (scaled_glyph,
&scaled_font->base,
(cairo_image_surface_t *) surface);
}
 
if (info & CAIRO_SCALED_GLYPH_INFO_PATH) {
cairo_path_fixed_t *path = _cairo_path_fixed_create ();
if (!path)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
status = _cairo_recording_surface_get_path (recording_surface, path);
if (unlikely (status)) {
_cairo_path_fixed_destroy (path);
return status;
}
 
_cairo_scaled_glyph_set_path (scaled_glyph,
&scaled_font->base,
path);
}
 
return status;
}
 
static unsigned long
_cairo_user_ucs4_to_index (void *abstract_font,
uint32_t ucs4)
{
cairo_user_scaled_font_t *scaled_font = abstract_font;
cairo_user_font_face_t *face =
(cairo_user_font_face_t *) scaled_font->base.font_face;
unsigned long glyph = 0;
 
if (face->scaled_font_methods.unicode_to_glyph) {
cairo_status_t status;
 
status = face->scaled_font_methods.unicode_to_glyph (&scaled_font->base,
ucs4, &glyph);
 
if (status == CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED)
goto not_implemented;
 
if (status != CAIRO_STATUS_SUCCESS) {
status = _cairo_scaled_font_set_error (&scaled_font->base, status);
glyph = 0;
}
 
} else {
not_implemented:
glyph = ucs4;
}
 
return glyph;
}
 
static cairo_int_status_t
_cairo_user_text_to_glyphs (void *abstract_font,
double x,
double y,
const char *utf8,
int utf8_len,
cairo_glyph_t **glyphs,
int *num_glyphs,
cairo_text_cluster_t **clusters,
int *num_clusters,
cairo_text_cluster_flags_t *cluster_flags)
{
cairo_int_status_t status = CAIRO_INT_STATUS_UNSUPPORTED;
 
cairo_user_scaled_font_t *scaled_font = abstract_font;
cairo_user_font_face_t *face =
(cairo_user_font_face_t *) scaled_font->base.font_face;
 
if (face->scaled_font_methods.text_to_glyphs) {
int i;
cairo_glyph_t *orig_glyphs = *glyphs;
int orig_num_glyphs = *num_glyphs;
 
status = face->scaled_font_methods.text_to_glyphs (&scaled_font->base,
utf8, utf8_len,
glyphs, num_glyphs,
clusters, num_clusters, cluster_flags);
 
if (status != CAIRO_STATUS_SUCCESS &&
status != CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED)
return status;
 
if (status == CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED || *num_glyphs < 0) {
if (orig_glyphs != *glyphs) {
cairo_glyph_free (*glyphs);
*glyphs = orig_glyphs;
}
*num_glyphs = orig_num_glyphs;
return CAIRO_INT_STATUS_UNSUPPORTED;
}
 
/* Convert from font space to user space and add x,y */
for (i = 0; i < *num_glyphs; i++) {
double gx = (*glyphs)[i].x;
double gy = (*glyphs)[i].y;
 
cairo_matrix_transform_point (&scaled_font->base.font_matrix,
&gx, &gy);
 
(*glyphs)[i].x = gx + x;
(*glyphs)[i].y = gy + y;
}
}
 
return status;
}
 
static cairo_status_t
_cairo_user_font_face_scaled_font_create (void *abstract_face,
const cairo_matrix_t *font_matrix,
const cairo_matrix_t *ctm,
const cairo_font_options_t *options,
cairo_scaled_font_t **scaled_font);
 
static cairo_status_t
_cairo_user_font_face_create_for_toy (cairo_toy_font_face_t *toy_face,
cairo_font_face_t **font_face)
{
return _cairo_font_face_twin_create_for_toy (toy_face, font_face);
}
 
static const cairo_scaled_font_backend_t _cairo_user_scaled_font_backend = {
CAIRO_FONT_TYPE_USER,
NULL, /* scaled_font_fini */
_cairo_user_scaled_glyph_init,
_cairo_user_text_to_glyphs,
_cairo_user_ucs4_to_index,
NULL, /* show_glyphs */
NULL, /* load_truetype_table */
NULL /* index_to_ucs4 */
};
 
/* #cairo_user_font_face_t */
 
static cairo_status_t
_cairo_user_font_face_scaled_font_create (void *abstract_face,
const cairo_matrix_t *font_matrix,
const cairo_matrix_t *ctm,
const cairo_font_options_t *options,
cairo_scaled_font_t **scaled_font)
{
cairo_status_t status = CAIRO_STATUS_SUCCESS;
cairo_user_font_face_t *font_face = abstract_face;
cairo_user_scaled_font_t *user_scaled_font = NULL;
cairo_font_extents_t font_extents = {1., 0., 1., 1., 0.};
 
font_face->immutable = TRUE;
 
user_scaled_font = malloc (sizeof (cairo_user_scaled_font_t));
if (unlikely (user_scaled_font == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
status = _cairo_scaled_font_init (&user_scaled_font->base,
&font_face->base,
font_matrix, ctm, options,
&_cairo_user_scaled_font_backend);
 
if (unlikely (status)) {
free (user_scaled_font);
return status;
}
 
/* XXX metrics hinting? */
 
/* compute a normalized version of font scale matrix to compute
* extents in. This is to minimize error caused by the cairo_fixed_t
* representation. */
{
double fixed_scale, x_scale, y_scale;
 
user_scaled_font->extent_scale = user_scaled_font->base.scale_inverse;
status = _cairo_matrix_compute_basis_scale_factors (&user_scaled_font->extent_scale,
&x_scale, &y_scale,
1);
if (status == CAIRO_STATUS_SUCCESS) {
 
if (x_scale == 0) x_scale = 1.;
if (y_scale == 0) y_scale = 1.;
 
user_scaled_font->snap_x_scale = x_scale;
user_scaled_font->snap_y_scale = y_scale;
 
/* since glyphs are pretty much 1.0x1.0, we can reduce error by
* scaling to a larger square. say, 1024.x1024. */
fixed_scale = 1024.;
x_scale /= fixed_scale;
y_scale /= fixed_scale;
 
cairo_matrix_scale (&user_scaled_font->extent_scale, 1. / x_scale, 1. / y_scale);
 
user_scaled_font->extent_x_scale = x_scale;
user_scaled_font->extent_y_scale = y_scale;
}
}
 
if (status == CAIRO_STATUS_SUCCESS &&
font_face->scaled_font_methods.init != NULL)
{
/* Lock the scaled_font mutex such that user doesn't accidentally try
* to use it just yet. */
CAIRO_MUTEX_LOCK (user_scaled_font->base.mutex);
 
/* Give away fontmap lock such that user-font can use other fonts */
status = _cairo_scaled_font_register_placeholder_and_unlock_font_map (&user_scaled_font->base);
if (status == CAIRO_STATUS_SUCCESS) {
cairo_surface_t *recording_surface;
cairo_t *cr;
 
recording_surface = _cairo_user_scaled_font_create_recording_surface (user_scaled_font);
cr = _cairo_user_scaled_font_create_recording_context (user_scaled_font, recording_surface);
cairo_surface_destroy (recording_surface);
 
status = font_face->scaled_font_methods.init (&user_scaled_font->base,
cr,
&font_extents);
 
if (status == CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED)
status = CAIRO_STATUS_SUCCESS;
 
if (status == CAIRO_STATUS_SUCCESS)
status = cairo_status (cr);
 
cairo_destroy (cr);
 
_cairo_scaled_font_unregister_placeholder_and_lock_font_map (&user_scaled_font->base);
}
 
CAIRO_MUTEX_UNLOCK (user_scaled_font->base.mutex);
}
 
if (status == CAIRO_STATUS_SUCCESS)
status = _cairo_scaled_font_set_metrics (&user_scaled_font->base, &font_extents);
 
if (status != CAIRO_STATUS_SUCCESS) {
_cairo_scaled_font_fini (&user_scaled_font->base);
free (user_scaled_font);
} else {
user_scaled_font->default_glyph_extents.x_bearing = 0.;
user_scaled_font->default_glyph_extents.y_bearing = -font_extents.ascent;
user_scaled_font->default_glyph_extents.width = 0.;
user_scaled_font->default_glyph_extents.height = font_extents.ascent + font_extents.descent;
user_scaled_font->default_glyph_extents.x_advance = font_extents.max_x_advance;
user_scaled_font->default_glyph_extents.y_advance = 0.;
 
*scaled_font = &user_scaled_font->base;
}
 
return status;
}
 
const cairo_font_face_backend_t _cairo_user_font_face_backend = {
CAIRO_FONT_TYPE_USER,
_cairo_user_font_face_create_for_toy,
NULL, /* destroy */
_cairo_user_font_face_scaled_font_create
};
 
 
cairo_bool_t
_cairo_font_face_is_user (cairo_font_face_t *font_face)
{
return font_face->backend == &_cairo_user_font_face_backend;
}
 
/* Implement the public interface */
 
/**
* cairo_user_font_face_create:
*
* Creates a new user font-face.
*
* Use the setter functions to associate callbacks with the returned
* user font. The only mandatory callback is render_glyph.
*
* After the font-face is created, the user can attach arbitrary data
* (the actual font data) to it using cairo_font_face_set_user_data()
* and access it from the user-font callbacks by using
* cairo_scaled_font_get_font_face() followed by
* cairo_font_face_get_user_data().
*
* Return value: a newly created #cairo_font_face_t. Free with
* cairo_font_face_destroy() when you are done using it.
*
* Since: 1.8
**/
cairo_font_face_t *
cairo_user_font_face_create (void)
{
cairo_user_font_face_t *font_face;
 
font_face = malloc (sizeof (cairo_user_font_face_t));
if (!font_face) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_font_face_t *)&_cairo_font_face_nil;
}
 
_cairo_font_face_init (&font_face->base, &_cairo_user_font_face_backend);
 
font_face->immutable = FALSE;
memset (&font_face->scaled_font_methods, 0, sizeof (font_face->scaled_font_methods));
 
return &font_face->base;
}
slim_hidden_def(cairo_user_font_face_create);
 
/* User-font method setters */
 
 
/**
* cairo_user_font_face_set_init_func:
* @font_face: A user font face
* @init_func: The init callback, or %NULL
*
* Sets the scaled-font initialization function of a user-font.
* See #cairo_user_scaled_font_init_func_t for details of how the callback
* works.
*
* The font-face should not be immutable or a %CAIRO_STATUS_USER_FONT_IMMUTABLE
* error will occur. A user font-face is immutable as soon as a scaled-font
* is created from it.
*
* Since: 1.8
**/
void
cairo_user_font_face_set_init_func (cairo_font_face_t *font_face,
cairo_user_scaled_font_init_func_t init_func)
{
cairo_user_font_face_t *user_font_face;
 
if (font_face->status)
return;
 
if (! _cairo_font_face_is_user (font_face)) {
if (_cairo_font_face_set_error (font_face, CAIRO_STATUS_FONT_TYPE_MISMATCH))
return;
}
 
user_font_face = (cairo_user_font_face_t *) font_face;
if (user_font_face->immutable) {
if (_cairo_font_face_set_error (font_face, CAIRO_STATUS_USER_FONT_IMMUTABLE))
return;
}
user_font_face->scaled_font_methods.init = init_func;
}
slim_hidden_def(cairo_user_font_face_set_init_func);
 
/**
* cairo_user_font_face_set_render_glyph_func:
* @font_face: A user font face
* @render_glyph_func: The render_glyph callback, or %NULL
*
* Sets the glyph rendering function of a user-font.
* See #cairo_user_scaled_font_render_glyph_func_t for details of how the callback
* works.
*
* The font-face should not be immutable or a %CAIRO_STATUS_USER_FONT_IMMUTABLE
* error will occur. A user font-face is immutable as soon as a scaled-font
* is created from it.
*
* The render_glyph callback is the only mandatory callback of a user-font.
* If the callback is %NULL and a glyph is tried to be rendered using
* @font_face, a %CAIRO_STATUS_USER_FONT_ERROR will occur.
*
* Since: 1.8
**/
void
cairo_user_font_face_set_render_glyph_func (cairo_font_face_t *font_face,
cairo_user_scaled_font_render_glyph_func_t render_glyph_func)
{
cairo_user_font_face_t *user_font_face;
 
if (font_face->status)
return;
 
if (! _cairo_font_face_is_user (font_face)) {
if (_cairo_font_face_set_error (font_face, CAIRO_STATUS_FONT_TYPE_MISMATCH))
return;
}
 
user_font_face = (cairo_user_font_face_t *) font_face;
if (user_font_face->immutable) {
if (_cairo_font_face_set_error (font_face, CAIRO_STATUS_USER_FONT_IMMUTABLE))
return;
}
user_font_face->scaled_font_methods.render_glyph = render_glyph_func;
}
slim_hidden_def(cairo_user_font_face_set_render_glyph_func);
 
/**
* cairo_user_font_face_set_text_to_glyphs_func:
* @font_face: A user font face
* @text_to_glyphs_func: The text_to_glyphs callback, or %NULL
*
* Sets th text-to-glyphs conversion function of a user-font.
* See #cairo_user_scaled_font_text_to_glyphs_func_t for details of how the callback
* works.
*
* The font-face should not be immutable or a %CAIRO_STATUS_USER_FONT_IMMUTABLE
* error will occur. A user font-face is immutable as soon as a scaled-font
* is created from it.
*
* Since: 1.8
**/
void
cairo_user_font_face_set_text_to_glyphs_func (cairo_font_face_t *font_face,
cairo_user_scaled_font_text_to_glyphs_func_t text_to_glyphs_func)
{
cairo_user_font_face_t *user_font_face;
 
if (font_face->status)
return;
 
if (! _cairo_font_face_is_user (font_face)) {
if (_cairo_font_face_set_error (font_face, CAIRO_STATUS_FONT_TYPE_MISMATCH))
return;
}
 
user_font_face = (cairo_user_font_face_t *) font_face;
if (user_font_face->immutable) {
if (_cairo_font_face_set_error (font_face, CAIRO_STATUS_USER_FONT_IMMUTABLE))
return;
}
user_font_face->scaled_font_methods.text_to_glyphs = text_to_glyphs_func;
}
 
/**
* cairo_user_font_face_set_unicode_to_glyph_func:
* @font_face: A user font face
* @unicode_to_glyph_func: The unicode_to_glyph callback, or %NULL
*
* Sets the unicode-to-glyph conversion function of a user-font.
* See #cairo_user_scaled_font_unicode_to_glyph_func_t for details of how the callback
* works.
*
* The font-face should not be immutable or a %CAIRO_STATUS_USER_FONT_IMMUTABLE
* error will occur. A user font-face is immutable as soon as a scaled-font
* is created from it.
*
* Since: 1.8
**/
void
cairo_user_font_face_set_unicode_to_glyph_func (cairo_font_face_t *font_face,
cairo_user_scaled_font_unicode_to_glyph_func_t unicode_to_glyph_func)
{
cairo_user_font_face_t *user_font_face;
if (font_face->status)
return;
 
if (! _cairo_font_face_is_user (font_face)) {
if (_cairo_font_face_set_error (font_face, CAIRO_STATUS_FONT_TYPE_MISMATCH))
return;
}
 
user_font_face = (cairo_user_font_face_t *) font_face;
if (user_font_face->immutable) {
if (_cairo_font_face_set_error (font_face, CAIRO_STATUS_USER_FONT_IMMUTABLE))
return;
}
user_font_face->scaled_font_methods.unicode_to_glyph = unicode_to_glyph_func;
}
slim_hidden_def(cairo_user_font_face_set_unicode_to_glyph_func);
 
/* User-font method getters */
 
/**
* cairo_user_font_face_get_init_func:
* @font_face: A user font face
*
* Gets the scaled-font initialization function of a user-font.
*
* Return value: The init callback of @font_face
* or %NULL if none set or an error has occurred.
*
* Since: 1.8
**/
cairo_user_scaled_font_init_func_t
cairo_user_font_face_get_init_func (cairo_font_face_t *font_face)
{
cairo_user_font_face_t *user_font_face;
 
if (font_face->status)
return NULL;
 
if (! _cairo_font_face_is_user (font_face)) {
if (_cairo_font_face_set_error (font_face, CAIRO_STATUS_FONT_TYPE_MISMATCH))
return NULL;
}
 
user_font_face = (cairo_user_font_face_t *) font_face;
return user_font_face->scaled_font_methods.init;
}
 
/**
* cairo_user_font_face_get_render_glyph_func:
* @font_face: A user font face
*
* Gets the glyph rendering function of a user-font.
*
* Return value: The render_glyph callback of @font_face
* or %NULL if none set or an error has occurred.
*
* Since: 1.8
**/
cairo_user_scaled_font_render_glyph_func_t
cairo_user_font_face_get_render_glyph_func (cairo_font_face_t *font_face)
{
cairo_user_font_face_t *user_font_face;
 
if (font_face->status)
return NULL;
 
if (! _cairo_font_face_is_user (font_face)) {
if (_cairo_font_face_set_error (font_face, CAIRO_STATUS_FONT_TYPE_MISMATCH))
return NULL;
}
 
user_font_face = (cairo_user_font_face_t *) font_face;
return user_font_face->scaled_font_methods.render_glyph;
}
 
/**
* cairo_user_font_face_get_text_to_glyphs_func:
* @font_face: A user font face
*
* Gets the text-to-glyphs conversion function of a user-font.
*
* Return value: The text_to_glyphs callback of @font_face
* or %NULL if none set or an error occurred.
*
* Since: 1.8
**/
cairo_user_scaled_font_text_to_glyphs_func_t
cairo_user_font_face_get_text_to_glyphs_func (cairo_font_face_t *font_face)
{
cairo_user_font_face_t *user_font_face;
 
if (font_face->status)
return NULL;
 
if (! _cairo_font_face_is_user (font_face)) {
if (_cairo_font_face_set_error (font_face, CAIRO_STATUS_FONT_TYPE_MISMATCH))
return NULL;
}
 
user_font_face = (cairo_user_font_face_t *) font_face;
return user_font_face->scaled_font_methods.text_to_glyphs;
}
 
/**
* cairo_user_font_face_get_unicode_to_glyph_func:
* @font_face: A user font face
*
* Gets the unicode-to-glyph conversion function of a user-font.
*
* Return value: The unicode_to_glyph callback of @font_face
* or %NULL if none set or an error occurred.
*
* Since: 1.8
**/
cairo_user_scaled_font_unicode_to_glyph_func_t
cairo_user_font_face_get_unicode_to_glyph_func (cairo_font_face_t *font_face)
{
cairo_user_font_face_t *user_font_face;
 
if (font_face->status)
return NULL;
 
if (! _cairo_font_face_is_user (font_face)) {
if (_cairo_font_face_set_error (font_face, CAIRO_STATUS_FONT_TYPE_MISMATCH))
return NULL;
}
 
user_font_face = (cairo_user_font_face_t *) font_face;
return user_font_face->scaled_font_methods.unicode_to_glyph;
}
/programs/develop/libraries/cairo/src/cairo-version.c
0,0 → 1,244
/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
/* 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., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
*/
 
#define CAIRO_VERSION_H 1
 
#include "cairoint.h"
 
/* get the "real" version info instead of dummy cairo-version.h */
#undef CAIRO_VERSION_H
#include "../cairo-version.h"
 
/**
* SECTION:cairo-version
* @Title: Version Information
* @Short_Description: Compile-time and run-time version checks.
*
* Cairo has a three-part version number scheme. In this scheme, we use
* even vs. odd numbers to distinguish fixed points in the software
* vs. in-progress development, (such as from git instead of a tar file,
* or as a "snapshot" tar file as opposed to a "release" tar file).
*
* <informalexample><programlisting>
* _____ Major. Always 1, until we invent a new scheme.
* / ___ Minor. Even/Odd = Release/Snapshot (tar files) or Branch/Head (git)
* | / _ Micro. Even/Odd = Tar-file/git
* | | /
* 1.0.0
* </programlisting></informalexample>
*
* Here are a few examples of versions that one might see.
* <informalexample><programlisting>
* Releases
* --------
* 1.0.0 - A major release
* 1.0.2 - A subsequent maintenance release
* 1.2.0 - Another major release
*
* Snapshots
* ---------
* 1.1.2 - A snapshot (working toward the 1.2.0 release)
*
* In-progress development (eg. from git)
* --------------------------------------
* 1.0.1 - Development on a maintenance branch (toward 1.0.2 release)
* 1.1.1 - Development on head (toward 1.1.2 snapshot and 1.2.0 release)
* </programlisting></informalexample>
* </para>
* <refsect2>
* <title>Compatibility</title>
* <para>
* The API/ABI compatibility guarantees for various versions are as
* follows. First, let's assume some cairo-using application code that is
* successfully using the API/ABI "from" one version of cairo. Then let's
* ask the question whether this same code can be moved "to" the API/ABI
* of another version of cairo.
*
* Moving from a release to any later version (release, snapshot,
* development) is always guaranteed to provide compatibility.
*
* Moving from a snapshot to any later version is not guaranteed to
* provide compatibility, since snapshots may introduce new API that ends
* up being removed before the next release.
*
* Moving from an in-development version (odd micro component) to any
* later version is not guaranteed to provide compatibility. In fact,
* there's not even a guarantee that the code will even continue to work
* with the same in-development version number. This is because these
* numbers don't correspond to any fixed state of the software, but
* rather the many states between snapshots and releases.
* </para>
* </refsect2>
* <refsect2>
* <title>Examining the version</title>
* <para>
* Cairo provides the ability to examine the version at either
* compile-time or run-time and in both a human-readable form as well as
* an encoded form suitable for direct comparison. Cairo also provides the
* macro CAIRO_VERSION_ENCODE() to perform the encoding.
*
* <informalexample><programlisting>
* Compile-time
* ------------
* CAIRO_VERSION_STRING Human-readable
* CAIRO_VERSION Encoded, suitable for comparison
*
* Run-time
* --------
* cairo_version_string() Human-readable
* cairo_version() Encoded, suitable for comparison
* </programlisting></informalexample>
*
* For example, checking that the cairo version is greater than or equal
* to 1.0.0 could be achieved at compile-time or run-time as follows:
*
* <informalexample><programlisting>
* ##if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 0, 0)
* printf ("Compiling with suitable cairo version: %s\n", %CAIRO_VERSION_STRING);
* ##endif
*
* if (cairo_version() >= CAIRO_VERSION_ENCODE(1, 0, 0))
* printf ("Running with suitable cairo version: %s\n", cairo_version_string ());
* </programlisting></informalexample>
* </para>
* </refsect2>
*/
 
/**
* CAIRO_VERSION:
*
* The version of cairo available at compile-time, encoded using
* CAIRO_VERSION_ENCODE().
*/
 
/**
* CAIRO_VERSION_MAJOR:
*
* The major component of the version of cairo available at compile-time.
*/
 
/**
* CAIRO_VERSION_MINOR:
*
* The minor component of the version of cairo available at compile-time.
*/
 
/**
* CAIRO_VERSION_MICRO:
*
* The micro component of the version of cairo available at compile-time.
*/
 
/**
* CAIRO_VERSION_STRING:
*
* A human-readable string literal containing the version of cairo available
* at compile-time, in the form of "X.Y.Z".
*/
 
/**
* CAIRO_VERSION_ENCODE:
* @major: the major component of the version number
* @minor: the minor component of the version number
* @micro: the micro component of the version number
*
* This macro encodes the given cairo version into an integer. The numbers
* returned by %CAIRO_VERSION and cairo_version() are encoded using this macro.
* Two encoded version numbers can be compared as integers. The encoding ensures
* that later versions compare greater than earlier versions.
*
* @Returns: the encoded version.
*/
 
/**
* CAIRO_VERSION_STRINGIZE:
* @major: the major component of the version number
* @minor: the minor component of the version number
* @micro: the micro component of the version number
*
* This macro encodes the given cairo version into an string. The numbers
* returned by %CAIRO_VERSION_STRING and cairo_version_string() are encoded using this macro.
* The parameters to this macro must expand to numerical literals.
*
* @Returns: a string literal containing the version.
*
* @Since: 1.8
*/
 
/**
* cairo_version:
*
* Returns the version of the cairo library encoded in a single
* integer as per %CAIRO_VERSION_ENCODE. The encoding ensures that
* later versions compare greater than earlier versions.
*
* A run-time comparison to check that cairo's version is greater than
* or equal to version X.Y.Z could be performed as follows:
*
* <informalexample><programlisting>
* if (cairo_version() >= CAIRO_VERSION_ENCODE(X,Y,Z)) {...}
* </programlisting></informalexample>
*
* See also cairo_version_string() as well as the compile-time
* equivalents %CAIRO_VERSION and %CAIRO_VERSION_STRING.
*
* Return value: the encoded version.
**/
int
cairo_version (void)
{
return CAIRO_VERSION;
}
 
/**
* cairo_version_string:
*
* Returns the version of the cairo library as a human-readable string
* of the form "X.Y.Z".
*
* See also cairo_version() as well as the compile-time equivalents
* %CAIRO_VERSION_STRING and %CAIRO_VERSION.
*
* Return value: a string containing the version.
**/
const char*
cairo_version_string (void)
{
return CAIRO_VERSION_STRING;
}
slim_hidden_def (cairo_version_string);
/programs/develop/libraries/cairo/src/cairo-version.h
0,0 → 1,14
/* This is a dummy file.
* The actual version info is in toplevel cairo-version.h.
* The purpose of this file is to make most of the source files NOT depend
* on the real cairo-version.h, and as a result, changing library version
* would not cause a complete rebuild of all object files (just a relink).
* This is useful when bisecting. */
#ifndef CAIRO_VERSION_H
#define CAIRO_VERSION_H
 
#define CAIRO_VERSION_MAJOR USE_cairo_version_OR_cairo_version_string_INSTEAD
#define CAIRO_VERSION_MINOR USE_cairo_version_OR_cairo_version_string_INSTEAD
#define CAIRO_VERSION_MICRO USE_cairo_version_OR_cairo_version_string_INSTEAD
 
#endif
/programs/develop/libraries/cairo/src/cairo-vg.h
0,0 → 1,103
/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2007 * Mozilla Corporation
* Copyright © 2009 Chris Wilson
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Mozilla Corporation.
*
* Contributor(s):
* Vladimir Vukicevic <vladimir@mozilla.com>
* Chris Wilson <chris@chris-wilson.co.uk>
*/
 
#ifndef CAIRO_VG_H
#define CAIRO_VG_H
 
#include "cairo.h"
 
#if CAIRO_HAS_VG_SURFACE
 
#include <VG/openvg.h>
 
CAIRO_BEGIN_DECLS
 
typedef struct _cairo_vg_context cairo_vg_context_t;
 
#if CAIRO_HAS_GLX_FUNCTIONS
typedef struct __GLXcontextRec *GLXContext;
typedef struct _XDisplay Display;
 
cairo_public cairo_vg_context_t *
cairo_vg_context_create_for_glx (Display *dpy,
GLXContext ctx);
#endif
 
#if CAIRO_HAS_EGL_FUNCTIONS
#include <EGL/egl.h>
 
cairo_public cairo_vg_context_t *
cairo_vg_context_create_for_egl (EGLDisplay egl_display,
EGLContext egl_context);
#endif
 
cairo_public cairo_status_t
cairo_vg_context_status (cairo_vg_context_t *context);
 
cairo_public void
cairo_vg_context_destroy (cairo_vg_context_t *context);
 
cairo_public cairo_surface_t *
cairo_vg_surface_create (cairo_vg_context_t *context,
cairo_content_t content, int width, int height);
 
cairo_public cairo_surface_t *
cairo_vg_surface_create_for_image (cairo_vg_context_t *context,
VGImage image,
VGImageFormat format,
int width, int height);
 
cairo_public VGImage
cairo_vg_surface_get_image (cairo_surface_t *abstract_surface);
 
cairo_public VGImageFormat
cairo_vg_surface_get_format (cairo_surface_t *abstract_surface);
 
cairo_public int
cairo_vg_surface_get_height (cairo_surface_t *abstract_surface);
 
cairo_public int
cairo_vg_surface_get_width (cairo_surface_t *abstract_surface);
 
CAIRO_END_DECLS
 
#else /* CAIRO_HAS_VG_SURFACE*/
# error Cairo was not compiled with support for the OpenVG backend
#endif /* CAIRO_HAS_VG_SURFACE*/
 
#endif /* CAIRO_VG_H */
/programs/develop/libraries/cairo/src/cairo-wideint-private.h
0,0 → 1,320
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2004 Keith Packard
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Keith Packard
*
* Contributor(s):
* Keith R. Packard <keithp@keithp.com>
*
*/
 
#ifndef CAIRO_WIDEINT_H
#define CAIRO_WIDEINT_H
 
#include "cairo-wideint-type-private.h"
 
#include "cairo-compiler-private.h"
 
/*
* 64-bit datatypes. Two separate implementations, one using
* built-in 64-bit signed/unsigned types another implemented
* as a pair of 32-bit ints
*/
 
#define I cairo_private cairo_const
 
#if !HAVE_UINT64_T
 
cairo_uquorem64_t I
_cairo_uint64_divrem (cairo_uint64_t num, cairo_uint64_t den);
 
cairo_uint64_t I _cairo_uint32_to_uint64 (uint32_t i);
#define _cairo_uint64_to_uint32(a) ((a).lo)
cairo_uint64_t I _cairo_uint64_add (cairo_uint64_t a, cairo_uint64_t b);
cairo_uint64_t I _cairo_uint64_sub (cairo_uint64_t a, cairo_uint64_t b);
cairo_uint64_t I _cairo_uint64_mul (cairo_uint64_t a, cairo_uint64_t b);
cairo_uint64_t I _cairo_uint32x32_64_mul (uint32_t a, uint32_t b);
cairo_uint64_t I _cairo_uint64_lsl (cairo_uint64_t a, int shift);
cairo_uint64_t I _cairo_uint64_rsl (cairo_uint64_t a, int shift);
cairo_uint64_t I _cairo_uint64_rsa (cairo_uint64_t a, int shift);
int I _cairo_uint64_lt (cairo_uint64_t a, cairo_uint64_t b);
int I _cairo_uint64_cmp (cairo_uint64_t a, cairo_uint64_t b);
int I _cairo_uint64_eq (cairo_uint64_t a, cairo_uint64_t b);
cairo_uint64_t I _cairo_uint64_negate (cairo_uint64_t a);
#define _cairo_uint64_is_zero(a) ((a).hi == 0 && (a).lo == 0)
#define _cairo_uint64_negative(a) (((int32_t) ((a).hi)) < 0)
cairo_uint64_t I _cairo_uint64_not (cairo_uint64_t a);
 
#define _cairo_uint64_to_int64(i) (i)
#define _cairo_int64_to_uint64(i) (i)
 
cairo_int64_t I _cairo_int32_to_int64(int32_t i);
#define _cairo_int64_to_int32(a) ((int32_t) _cairo_uint64_to_uint32(a))
#define _cairo_int64_add(a,b) _cairo_uint64_add (a,b)
#define _cairo_int64_sub(a,b) _cairo_uint64_sub (a,b)
#define _cairo_int64_mul(a,b) _cairo_uint64_mul (a,b)
cairo_int64_t I _cairo_int32x32_64_mul (int32_t a, int32_t b);
int I _cairo_int64_lt (cairo_int64_t a, cairo_int64_t b);
int I _cairo_int64_cmp (cairo_int64_t a, cairo_int64_t b);
#define _cairo_int64_is_zero(a) _cairo_uint64_is_zero (a)
#define _cairo_int64_eq(a,b) _cairo_uint64_eq (a,b)
#define _cairo_int64_lsl(a,b) _cairo_uint64_lsl (a,b)
#define _cairo_int64_rsl(a,b) _cairo_uint64_rsl (a,b)
#define _cairo_int64_rsa(a,b) _cairo_uint64_rsa (a,b)
#define _cairo_int64_negate(a) _cairo_uint64_negate(a)
#define _cairo_int64_negative(a) (((int32_t) ((a).hi)) < 0)
#define _cairo_int64_not(a) _cairo_uint64_not(a)
 
#else
 
static inline cairo_uquorem64_t
_cairo_uint64_divrem (cairo_uint64_t num, cairo_uint64_t den)
{
cairo_uquorem64_t qr;
 
qr.quo = num / den;
qr.rem = num % den;
return qr;
}
 
#define _cairo_uint32_to_uint64(i) ((uint64_t) (i))
#define _cairo_uint64_to_uint32(i) ((uint32_t) (i))
#define _cairo_uint64_add(a,b) ((a) + (b))
#define _cairo_uint64_sub(a,b) ((a) - (b))
#define _cairo_uint64_mul(a,b) ((a) * (b))
#define _cairo_uint32x32_64_mul(a,b) ((uint64_t) (a) * (b))
#define _cairo_uint64_lsl(a,b) ((a) << (b))
#define _cairo_uint64_rsl(a,b) ((uint64_t) (a) >> (b))
#define _cairo_uint64_rsa(a,b) ((uint64_t) ((int64_t) (a) >> (b)))
#define _cairo_uint64_lt(a,b) ((a) < (b))
#define _cairo_uint64_cmp(a,b) ((a) == (b) ? 0 : (a) < (b) ? -1 : 1)
#define _cairo_uint64_is_zero(a) ((a) == 0)
#define _cairo_uint64_eq(a,b) ((a) == (b))
#define _cairo_uint64_negate(a) ((uint64_t) -((int64_t) (a)))
#define _cairo_uint64_negative(a) ((int64_t) (a) < 0)
#define _cairo_uint64_not(a) (~(a))
 
#define _cairo_uint64_to_int64(i) ((int64_t) (i))
#define _cairo_int64_to_uint64(i) ((uint64_t) (i))
 
#define _cairo_int32_to_int64(i) ((int64_t) (i))
#define _cairo_int64_to_int32(i) ((int32_t) (i))
#define _cairo_int64_add(a,b) ((a) + (b))
#define _cairo_int64_sub(a,b) ((a) - (b))
#define _cairo_int64_mul(a,b) ((a) * (b))
#define _cairo_int32x32_64_mul(a,b) ((int64_t) (a) * (b))
#define _cairo_int64_lt(a,b) ((a) < (b))
#define _cairo_int64_cmp(a,b) ((a) == (b) ? 0 : (a) < (b) ? -1 : 1)
#define _cairo_int64_is_zero(a) ((a) == 0)
#define _cairo_int64_eq(a,b) ((a) == (b))
#define _cairo_int64_lsl(a,b) ((a) << (b))
#define _cairo_int64_rsl(a,b) ((int64_t) ((uint64_t) (a) >> (b)))
#define _cairo_int64_rsa(a,b) ((int64_t) (a) >> (b))
#define _cairo_int64_negate(a) (-(a))
#define _cairo_int64_negative(a) ((a) < 0)
#define _cairo_int64_not(a) (~(a))
 
#endif
 
/*
* 64-bit comparisions derived from lt or eq
*/
#define _cairo_uint64_le(a,b) (!_cairo_uint64_gt(a,b))
#define _cairo_uint64_ne(a,b) (!_cairo_uint64_eq(a,b))
#define _cairo_uint64_ge(a,b) (!_cairo_uint64_lt(a,b))
#define _cairo_uint64_gt(a,b) _cairo_uint64_lt(b,a)
 
#define _cairo_int64_le(a,b) (!_cairo_int64_gt(a,b))
#define _cairo_int64_ne(a,b) (!_cairo_int64_eq(a,b))
#define _cairo_int64_ge(a,b) (!_cairo_int64_lt(a,b))
#define _cairo_int64_gt(a,b) _cairo_int64_lt(b,a)
 
/*
* As the C implementation always computes both, create
* a function which returns both for the 'native' type as well
*/
 
static inline cairo_quorem64_t
_cairo_int64_divrem (cairo_int64_t num, cairo_int64_t den)
{
int num_neg = _cairo_int64_negative (num);
int den_neg = _cairo_int64_negative (den);
cairo_uquorem64_t uqr;
cairo_quorem64_t qr;
 
if (num_neg)
num = _cairo_int64_negate (num);
if (den_neg)
den = _cairo_int64_negate (den);
uqr = _cairo_uint64_divrem (num, den);
if (num_neg)
qr.rem = _cairo_int64_negate (uqr.rem);
else
qr.rem = uqr.rem;
if (num_neg != den_neg)
qr.quo = (cairo_int64_t) _cairo_int64_negate (uqr.quo);
else
qr.quo = (cairo_int64_t) uqr.quo;
return qr;
}
 
static inline int32_t
_cairo_int64_32_div (cairo_int64_t num, int32_t den)
{
#if !HAVE_UINT64_T
return _cairo_int64_to_int32
(_cairo_int64_divrem (num, _cairo_int32_to_int64 (den)).quo);
#else
return num / den;
#endif
}
 
/*
* 128-bit datatypes. Again, provide two implementations in
* case the machine has a native 128-bit datatype. GCC supports int128_t
* on ia64
*/
 
#if !HAVE_UINT128_T
 
cairo_uint128_t I _cairo_uint32_to_uint128 (uint32_t i);
cairo_uint128_t I _cairo_uint64_to_uint128 (cairo_uint64_t i);
#define _cairo_uint128_to_uint64(a) ((a).lo)
#define _cairo_uint128_to_uint32(a) _cairo_uint64_to_uint32(_cairo_uint128_to_uint64(a))
cairo_uint128_t I _cairo_uint128_add (cairo_uint128_t a, cairo_uint128_t b);
cairo_uint128_t I _cairo_uint128_sub (cairo_uint128_t a, cairo_uint128_t b);
cairo_uint128_t I _cairo_uint128_mul (cairo_uint128_t a, cairo_uint128_t b);
cairo_uint128_t I _cairo_uint64x64_128_mul (cairo_uint64_t a, cairo_uint64_t b);
cairo_uint128_t I _cairo_uint128_lsl (cairo_uint128_t a, int shift);
cairo_uint128_t I _cairo_uint128_rsl (cairo_uint128_t a, int shift);
cairo_uint128_t I _cairo_uint128_rsa (cairo_uint128_t a, int shift);
int I _cairo_uint128_lt (cairo_uint128_t a, cairo_uint128_t b);
int I _cairo_uint128_cmp (cairo_uint128_t a, cairo_uint128_t b);
int I _cairo_uint128_eq (cairo_uint128_t a, cairo_uint128_t b);
#define _cairo_uint128_is_zero(a) (_cairo_uint64_is_zero ((a).hi) && _cairo_uint64_is_zero ((a).lo))
cairo_uint128_t I _cairo_uint128_negate (cairo_uint128_t a);
#define _cairo_uint128_negative(a) (_cairo_uint64_negative(a.hi))
cairo_uint128_t I _cairo_uint128_not (cairo_uint128_t a);
 
#define _cairo_uint128_to_int128(i) (i)
#define _cairo_int128_to_uint128(i) (i)
 
cairo_int128_t I _cairo_int32_to_int128 (int32_t i);
cairo_int128_t I _cairo_int64_to_int128 (cairo_int64_t i);
#define _cairo_int128_to_int64(a) ((cairo_int64_t) (a).lo)
#define _cairo_int128_to_int32(a) _cairo_int64_to_int32(_cairo_int128_to_int64(a))
#define _cairo_int128_add(a,b) _cairo_uint128_add(a,b)
#define _cairo_int128_sub(a,b) _cairo_uint128_sub(a,b)
#define _cairo_int128_mul(a,b) _cairo_uint128_mul(a,b)
cairo_int128_t I _cairo_int64x64_128_mul (cairo_int64_t a, cairo_int64_t b);
#define _cairo_int64x32_128_mul(a, b) _cairo_int64x64_128_mul(a, _cairo_int32_to_int64(b))
#define _cairo_int128_lsl(a,b) _cairo_uint128_lsl(a,b)
#define _cairo_int128_rsl(a,b) _cairo_uint128_rsl(a,b)
#define _cairo_int128_rsa(a,b) _cairo_uint128_rsa(a,b)
int I _cairo_int128_lt (cairo_int128_t a, cairo_int128_t b);
int I _cairo_int128_cmp (cairo_int128_t a, cairo_int128_t b);
#define _cairo_int128_is_zero(a) _cairo_uint128_is_zero (a)
#define _cairo_int128_eq(a,b) _cairo_uint128_eq (a,b)
#define _cairo_int128_negate(a) _cairo_uint128_negate(a)
#define _cairo_int128_negative(a) (_cairo_uint128_negative(a))
#define _cairo_int128_not(a) _cairo_uint128_not(a)
 
#else /* !HAVE_UINT128_T */
 
#define _cairo_uint32_to_uint128(i) ((uint128_t) (i))
#define _cairo_uint64_to_uint128(i) ((uint128_t) (i))
#define _cairo_uint128_to_uint64(i) ((uint64_t) (i))
#define _cairo_uint128_to_uint32(i) ((uint32_t) (i))
#define _cairo_uint128_add(a,b) ((a) + (b))
#define _cairo_uint128_sub(a,b) ((a) - (b))
#define _cairo_uint128_mul(a,b) ((a) * (b))
#define _cairo_uint64x64_128_mul(a,b) ((uint128_t) (a) * (b))
#define _cairo_uint128_lsl(a,b) ((a) << (b))
#define _cairo_uint128_rsl(a,b) ((uint128_t) (a) >> (b))
#define _cairo_uint128_rsa(a,b) ((uint128_t) ((int128_t) (a) >> (b)))
#define _cairo_uint128_lt(a,b) ((a) < (b))
#define _cairo_uint128_cmp(a,b) ((a) == (b) ? 0 : (a) < (b) ? -1 : 1)
#define _cairo_uint128_is_zero(a) ((a) == 0)
#define _cairo_uint128_eq(a,b) ((a) == (b))
#define _cairo_uint128_negate(a) ((uint128_t) -((int128_t) (a)))
#define _cairo_uint128_negative(a) ((int128_t) (a) < 0)
#define _cairo_uint128_not(a) (~(a))
 
#define _cairo_uint128_to_int128(i) ((int128_t) (i))
#define _cairo_int128_to_uint128(i) ((uint128_t) (i))
 
#define _cairo_int32_to_int128(i) ((int128_t) (i))
#define _cairo_int64_to_int128(i) ((int128_t) (i))
#define _cairo_int128_to_int64(i) ((int64_t) (i))
#define _cairo_int128_to_int32(i) ((int32_t) (i))
#define _cairo_int128_add(a,b) ((a) + (b))
#define _cairo_int128_sub(a,b) ((a) - (b))
#define _cairo_int128_mul(a,b) ((a) * (b))
#define _cairo_int64x64_128_mul(a,b) ((int128_t) (a) * (b))
#define _cairo_int64x32_128_mul(a, b) _cairo_int64x64_128_mul(a, _cairo_int32_to_int64(b))
#define _cairo_int128_lt(a,b) ((a) < (b))
#define _cairo_int128_cmp(a,b) ((a) == (b) ? 0 : (a) < (b) ? -1 : 1)
#define _cairo_int128_is_zero(a) ((a) == 0)
#define _cairo_int128_eq(a,b) ((a) == (b))
#define _cairo_int128_lsl(a,b) ((a) << (b))
#define _cairo_int128_rsl(a,b) ((int128_t) ((uint128_t) (a) >> (b)))
#define _cairo_int128_rsa(a,b) ((int128_t) (a) >> (b))
#define _cairo_int128_negate(a) (-(a))
#define _cairo_int128_negative(a) ((a) < 0)
#define _cairo_int128_not(a) (~(a))
 
#endif /* HAVE_UINT128_T */
 
cairo_uquorem128_t I
_cairo_uint128_divrem (cairo_uint128_t num, cairo_uint128_t den);
 
cairo_quorem128_t I
_cairo_int128_divrem (cairo_int128_t num, cairo_int128_t den);
 
cairo_uquorem64_t I
_cairo_uint_96by64_32x64_divrem (cairo_uint128_t num,
cairo_uint64_t den);
 
cairo_quorem64_t I
_cairo_int_96by64_32x64_divrem (cairo_int128_t num,
cairo_int64_t den);
 
#define _cairo_uint128_le(a,b) (!_cairo_uint128_gt(a,b))
#define _cairo_uint128_ne(a,b) (!_cairo_uint128_eq(a,b))
#define _cairo_uint128_ge(a,b) (!_cairo_uint128_lt(a,b))
#define _cairo_uint128_gt(a,b) _cairo_uint128_lt(b,a)
 
#define _cairo_int128_le(a,b) (!_cairo_int128_gt(a,b))
#define _cairo_int128_ne(a,b) (!_cairo_int128_eq(a,b))
#define _cairo_int128_ge(a,b) (!_cairo_int128_lt(a,b))
#define _cairo_int128_gt(a,b) _cairo_int128_lt(b,a)
 
#undef I
 
#endif /* CAIRO_WIDEINT_H */
/programs/develop/libraries/cairo/src/cairo-wideint-type-private.h
0,0 → 1,155
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2004 Keith Packard
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Keith Packard
*
* Contributor(s):
* Keith R. Packard <keithp@keithp.com>
*
*/
 
#ifndef CAIRO_WIDEINT_TYPE_H
#define CAIRO_WIDEINT_TYPE_H
 
#include "cairo.h"
 
#if HAVE_CONFIG_H
#include "config.h"
#endif
 
#if HAVE_STDINT_H
# include <stdint.h>
#elif HAVE_INTTYPES_H
# include <inttypes.h>
#elif HAVE_SYS_INT_TYPES_H
# include <sys/int_types.h>
#elif defined(_MSC_VER)
typedef __int8 int8_t;
typedef unsigned __int8 uint8_t;
typedef __int16 int16_t;
typedef unsigned __int16 uint16_t;
typedef __int32 int32_t;
typedef unsigned __int32 uint32_t;
typedef __int64 int64_t;
typedef unsigned __int64 uint64_t;
# ifndef HAVE_UINT64_T
# define HAVE_UINT64_T 1
# endif
#else
#error Cannot find definitions for fixed-width integral types (uint8_t, uint32_t, etc.)
#endif
 
#ifndef INT16_MIN
# define INT16_MIN (-32767-1)
#endif
#ifndef INT16_MAX
# define INT16_MAX (32767)
#endif
#ifndef UINT16_MAX
# define UINT16_MAX (65535)
#endif
#ifndef INT32_MIN
# define INT32_MIN (-2147483647-1)
#endif
#ifndef INT32_MAX
# define INT32_MAX (2147483647)
#endif
 
#if HAVE_BYTESWAP_H
# include <byteswap.h>
#endif
#ifndef bswap_16
# define bswap_16(p) \
(((((uint16_t)(p)) & 0x00ff) << 8) | \
(((uint16_t)(p)) >> 8));
#endif
#ifndef bswap_32
# define bswap_32(p) \
(((((uint32_t)(p)) & 0x000000ff) << 24) | \
((((uint32_t)(p)) & 0x0000ff00) << 8) | \
((((uint32_t)(p)) & 0x00ff0000) >> 8) | \
((((uint32_t)(p))) >> 24));
#endif
 
 
#if !HAVE_UINT64_T
 
typedef struct _cairo_uint64 {
uint32_t lo, hi;
} cairo_uint64_t, cairo_int64_t;
 
#else
 
typedef uint64_t cairo_uint64_t;
typedef int64_t cairo_int64_t;
 
#endif
 
typedef struct _cairo_uquorem64 {
cairo_uint64_t quo;
cairo_uint64_t rem;
} cairo_uquorem64_t;
 
typedef struct _cairo_quorem64 {
cairo_int64_t quo;
cairo_int64_t rem;
} cairo_quorem64_t;
 
/* gcc has a non-standard name. */
#if HAVE___UINT128_T && !HAVE_UINT128_T
typedef __uint128_t uint128_t;
typedef __int128_t int128_t;
#define HAVE_UINT128_T 1
#endif
 
#if !HAVE_UINT128_T
 
typedef struct cairo_uint128 {
cairo_uint64_t lo, hi;
} cairo_uint128_t, cairo_int128_t;
 
#else
 
typedef uint128_t cairo_uint128_t;
typedef int128_t cairo_int128_t;
 
#endif
 
typedef struct _cairo_uquorem128 {
cairo_uint128_t quo;
cairo_uint128_t rem;
} cairo_uquorem128_t;
 
typedef struct _cairo_quorem128 {
cairo_int128_t quo;
cairo_int128_t rem;
} cairo_quorem128_t;
 
 
#endif /* CAIRO_WIDEINT_H */
/programs/develop/libraries/cairo/src/cairo-wideint.c
0,0 → 1,819
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2004 Keith Packard
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Keith Packard
*
* Contributor(s):
* Keith R. Packard <keithp@keithp.com>
*/
 
#include "cairoint.h"
 
#if HAVE_UINT64_T
 
#define uint64_lo32(i) ((i) & 0xffffffff)
#define uint64_hi32(i) ((i) >> 32)
#define uint64_lo(i) ((i) & 0xffffffff)
#define uint64_hi(i) ((i) >> 32)
#define uint64_shift32(i) ((i) << 32)
#define uint64_carry32 (((uint64_t) 1) << 32)
 
#define _cairo_uint32s_to_uint64(h,l) ((uint64_t) (h) << 32 | (l))
 
#else
 
#define uint64_lo32(i) ((i).lo)
#define uint64_hi32(i) ((i).hi)
 
static cairo_uint64_t
uint64_lo (cairo_uint64_t i)
{
cairo_uint64_t s;
 
s.lo = i.lo;
s.hi = 0;
return s;
}
 
static cairo_uint64_t
uint64_hi (cairo_uint64_t i)
{
cairo_uint64_t s;
 
s.lo = i.hi;
s.hi = 0;
return s;
}
 
static cairo_uint64_t
uint64_shift32 (cairo_uint64_t i)
{
cairo_uint64_t s;
 
s.lo = 0;
s.hi = i.lo;
return s;
}
 
static const cairo_uint64_t uint64_carry32 = { 0, 1 };
 
cairo_uint64_t
_cairo_uint32_to_uint64 (uint32_t i)
{
cairo_uint64_t q;
 
q.lo = i;
q.hi = 0;
return q;
}
 
cairo_int64_t
_cairo_int32_to_int64 (int32_t i)
{
cairo_uint64_t q;
 
q.lo = i;
q.hi = i < 0 ? -1 : 0;
return q;
}
 
static cairo_uint64_t
_cairo_uint32s_to_uint64 (uint32_t h, uint32_t l)
{
cairo_uint64_t q;
 
q.lo = l;
q.hi = h;
return q;
}
 
cairo_uint64_t
_cairo_uint64_add (cairo_uint64_t a, cairo_uint64_t b)
{
cairo_uint64_t s;
 
s.hi = a.hi + b.hi;
s.lo = a.lo + b.lo;
if (s.lo < a.lo)
s.hi++;
return s;
}
 
cairo_uint64_t
_cairo_uint64_sub (cairo_uint64_t a, cairo_uint64_t b)
{
cairo_uint64_t s;
 
s.hi = a.hi - b.hi;
s.lo = a.lo - b.lo;
if (s.lo > a.lo)
s.hi--;
return s;
}
 
#define uint32_lo(i) ((i) & 0xffff)
#define uint32_hi(i) ((i) >> 16)
#define uint32_carry16 ((1) << 16)
 
cairo_uint64_t
_cairo_uint32x32_64_mul (uint32_t a, uint32_t b)
{
cairo_uint64_t s;
 
uint16_t ah, al, bh, bl;
uint32_t r0, r1, r2, r3;
 
al = uint32_lo (a);
ah = uint32_hi (a);
bl = uint32_lo (b);
bh = uint32_hi (b);
 
r0 = (uint32_t) al * bl;
r1 = (uint32_t) al * bh;
r2 = (uint32_t) ah * bl;
r3 = (uint32_t) ah * bh;
 
r1 += uint32_hi(r0); /* no carry possible */
r1 += r2; /* but this can carry */
if (r1 < r2) /* check */
r3 += uint32_carry16;
 
s.hi = r3 + uint32_hi(r1);
s.lo = (uint32_lo (r1) << 16) + uint32_lo (r0);
return s;
}
 
cairo_int64_t
_cairo_int32x32_64_mul (int32_t a, int32_t b)
{
cairo_int64_t s;
s = _cairo_uint32x32_64_mul ((uint32_t) a, (uint32_t) b);
if (a < 0)
s.hi -= b;
if (b < 0)
s.hi -= a;
return s;
}
 
cairo_uint64_t
_cairo_uint64_mul (cairo_uint64_t a, cairo_uint64_t b)
{
cairo_uint64_t s;
 
s = _cairo_uint32x32_64_mul (a.lo, b.lo);
s.hi += a.lo * b.hi + a.hi * b.lo;
return s;
}
 
cairo_uint64_t
_cairo_uint64_lsl (cairo_uint64_t a, int shift)
{
if (shift >= 32)
{
a.hi = a.lo;
a.lo = 0;
shift -= 32;
}
if (shift)
{
a.hi = a.hi << shift | a.lo >> (32 - shift);
a.lo = a.lo << shift;
}
return a;
}
 
cairo_uint64_t
_cairo_uint64_rsl (cairo_uint64_t a, int shift)
{
if (shift >= 32)
{
a.lo = a.hi;
a.hi = 0;
shift -= 32;
}
if (shift)
{
a.lo = a.lo >> shift | a.hi << (32 - shift);
a.hi = a.hi >> shift;
}
return a;
}
 
#define _cairo_uint32_rsa(a,n) ((uint32_t) (((int32_t) (a)) >> (n)))
 
cairo_int64_t
_cairo_uint64_rsa (cairo_int64_t a, int shift)
{
if (shift >= 32)
{
a.lo = a.hi;
a.hi = _cairo_uint32_rsa (a.hi, 31);
shift -= 32;
}
if (shift)
{
a.lo = a.lo >> shift | a.hi << (32 - shift);
a.hi = _cairo_uint32_rsa (a.hi, shift);
}
return a;
}
 
int
_cairo_uint64_lt (cairo_uint64_t a, cairo_uint64_t b)
{
return (a.hi < b.hi ||
(a.hi == b.hi && a.lo < b.lo));
}
 
int
_cairo_uint64_eq (cairo_uint64_t a, cairo_uint64_t b)
{
return a.hi == b.hi && a.lo == b.lo;
}
 
int
_cairo_int64_lt (cairo_int64_t a, cairo_int64_t b)
{
if (_cairo_int64_negative (a) && !_cairo_int64_negative (b))
return 1;
if (!_cairo_int64_negative (a) && _cairo_int64_negative (b))
return 0;
return _cairo_uint64_lt (a, b);
}
 
int
_cairo_uint64_cmp (cairo_uint64_t a, cairo_uint64_t b)
{
if (a.hi < b.hi)
return -1;
else if (a.hi > b.hi)
return 1;
else if (a.lo < b.lo)
return -1;
else if (a.lo > b.lo)
return 1;
else
return 0;
}
 
int
_cairo_int64_cmp (cairo_int64_t a, cairo_int64_t b)
{
if (_cairo_int64_negative (a) && !_cairo_int64_negative (b))
return -1;
if (!_cairo_int64_negative (a) && _cairo_int64_negative (b))
return 1;
 
return _cairo_uint64_cmp (a, b);
}
 
cairo_uint64_t
_cairo_uint64_not (cairo_uint64_t a)
{
a.lo = ~a.lo;
a.hi = ~a.hi;
return a;
}
 
cairo_uint64_t
_cairo_uint64_negate (cairo_uint64_t a)
{
a.lo = ~a.lo;
a.hi = ~a.hi;
if (++a.lo == 0)
++a.hi;
return a;
}
 
/*
* Simple bit-at-a-time divide.
*/
cairo_uquorem64_t
_cairo_uint64_divrem (cairo_uint64_t num, cairo_uint64_t den)
{
cairo_uquorem64_t qr;
cairo_uint64_t bit;
cairo_uint64_t quo;
 
bit = _cairo_uint32_to_uint64 (1);
 
/* normalize to make den >= num, but not overflow */
while (_cairo_uint64_lt (den, num) && (den.hi & 0x80000000) == 0)
{
bit = _cairo_uint64_lsl (bit, 1);
den = _cairo_uint64_lsl (den, 1);
}
quo = _cairo_uint32_to_uint64 (0);
 
/* generate quotient, one bit at a time */
while (bit.hi | bit.lo)
{
if (_cairo_uint64_le (den, num))
{
num = _cairo_uint64_sub (num, den);
quo = _cairo_uint64_add (quo, bit);
}
bit = _cairo_uint64_rsl (bit, 1);
den = _cairo_uint64_rsl (den, 1);
}
qr.quo = quo;
qr.rem = num;
return qr;
}
 
#endif /* !HAVE_UINT64_T */
 
#if HAVE_UINT128_T
cairo_uquorem128_t
_cairo_uint128_divrem (cairo_uint128_t num, cairo_uint128_t den)
{
cairo_uquorem128_t qr;
 
qr.quo = num / den;
qr.rem = num % den;
return qr;
}
 
#else
 
cairo_uint128_t
_cairo_uint32_to_uint128 (uint32_t i)
{
cairo_uint128_t q;
 
q.lo = _cairo_uint32_to_uint64 (i);
q.hi = _cairo_uint32_to_uint64 (0);
return q;
}
 
cairo_int128_t
_cairo_int32_to_int128 (int32_t i)
{
cairo_int128_t q;
 
q.lo = _cairo_int32_to_int64 (i);
q.hi = _cairo_int32_to_int64 (i < 0 ? -1 : 0);
return q;
}
 
cairo_uint128_t
_cairo_uint64_to_uint128 (cairo_uint64_t i)
{
cairo_uint128_t q;
 
q.lo = i;
q.hi = _cairo_uint32_to_uint64 (0);
return q;
}
 
cairo_int128_t
_cairo_int64_to_int128 (cairo_int64_t i)
{
cairo_int128_t q;
 
q.lo = i;
q.hi = _cairo_int32_to_int64 (_cairo_int64_negative(i) ? -1 : 0);
return q;
}
 
cairo_uint128_t
_cairo_uint128_add (cairo_uint128_t a, cairo_uint128_t b)
{
cairo_uint128_t s;
 
s.hi = _cairo_uint64_add (a.hi, b.hi);
s.lo = _cairo_uint64_add (a.lo, b.lo);
if (_cairo_uint64_lt (s.lo, a.lo))
s.hi = _cairo_uint64_add (s.hi, _cairo_uint32_to_uint64 (1));
return s;
}
 
cairo_uint128_t
_cairo_uint128_sub (cairo_uint128_t a, cairo_uint128_t b)
{
cairo_uint128_t s;
 
s.hi = _cairo_uint64_sub (a.hi, b.hi);
s.lo = _cairo_uint64_sub (a.lo, b.lo);
if (_cairo_uint64_gt (s.lo, a.lo))
s.hi = _cairo_uint64_sub (s.hi, _cairo_uint32_to_uint64(1));
return s;
}
 
cairo_uint128_t
_cairo_uint64x64_128_mul (cairo_uint64_t a, cairo_uint64_t b)
{
cairo_uint128_t s;
uint32_t ah, al, bh, bl;
cairo_uint64_t r0, r1, r2, r3;
 
al = uint64_lo32 (a);
ah = uint64_hi32 (a);
bl = uint64_lo32 (b);
bh = uint64_hi32 (b);
 
r0 = _cairo_uint32x32_64_mul (al, bl);
r1 = _cairo_uint32x32_64_mul (al, bh);
r2 = _cairo_uint32x32_64_mul (ah, bl);
r3 = _cairo_uint32x32_64_mul (ah, bh);
 
r1 = _cairo_uint64_add (r1, uint64_hi (r0)); /* no carry possible */
r1 = _cairo_uint64_add (r1, r2); /* but this can carry */
if (_cairo_uint64_lt (r1, r2)) /* check */
r3 = _cairo_uint64_add (r3, uint64_carry32);
 
s.hi = _cairo_uint64_add (r3, uint64_hi(r1));
s.lo = _cairo_uint64_add (uint64_shift32 (r1),
uint64_lo (r0));
return s;
}
 
cairo_int128_t
_cairo_int64x64_128_mul (cairo_int64_t a, cairo_int64_t b)
{
cairo_int128_t s;
s = _cairo_uint64x64_128_mul (_cairo_int64_to_uint64(a),
_cairo_int64_to_uint64(b));
if (_cairo_int64_negative (a))
s.hi = _cairo_uint64_sub (s.hi,
_cairo_int64_to_uint64 (b));
if (_cairo_int64_negative (b))
s.hi = _cairo_uint64_sub (s.hi,
_cairo_int64_to_uint64 (a));
return s;
}
 
cairo_uint128_t
_cairo_uint128_mul (cairo_uint128_t a, cairo_uint128_t b)
{
cairo_uint128_t s;
 
s = _cairo_uint64x64_128_mul (a.lo, b.lo);
s.hi = _cairo_uint64_add (s.hi,
_cairo_uint64_mul (a.lo, b.hi));
s.hi = _cairo_uint64_add (s.hi,
_cairo_uint64_mul (a.hi, b.lo));
return s;
}
 
cairo_uint128_t
_cairo_uint128_lsl (cairo_uint128_t a, int shift)
{
if (shift >= 64)
{
a.hi = a.lo;
a.lo = _cairo_uint32_to_uint64 (0);
shift -= 64;
}
if (shift)
{
a.hi = _cairo_uint64_add (_cairo_uint64_lsl (a.hi, shift),
_cairo_uint64_rsl (a.lo, (64 - shift)));
a.lo = _cairo_uint64_lsl (a.lo, shift);
}
return a;
}
 
cairo_uint128_t
_cairo_uint128_rsl (cairo_uint128_t a, int shift)
{
if (shift >= 64)
{
a.lo = a.hi;
a.hi = _cairo_uint32_to_uint64 (0);
shift -= 64;
}
if (shift)
{
a.lo = _cairo_uint64_add (_cairo_uint64_rsl (a.lo, shift),
_cairo_uint64_lsl (a.hi, (64 - shift)));
a.hi = _cairo_uint64_rsl (a.hi, shift);
}
return a;
}
 
cairo_uint128_t
_cairo_uint128_rsa (cairo_int128_t a, int shift)
{
if (shift >= 64)
{
a.lo = a.hi;
a.hi = _cairo_uint64_rsa (a.hi, 64-1);
shift -= 64;
}
if (shift)
{
a.lo = _cairo_uint64_add (_cairo_uint64_rsl (a.lo, shift),
_cairo_uint64_lsl (a.hi, (64 - shift)));
a.hi = _cairo_uint64_rsa (a.hi, shift);
}
return a;
}
 
int
_cairo_uint128_lt (cairo_uint128_t a, cairo_uint128_t b)
{
return (_cairo_uint64_lt (a.hi, b.hi) ||
(_cairo_uint64_eq (a.hi, b.hi) &&
_cairo_uint64_lt (a.lo, b.lo)));
}
 
int
_cairo_int128_lt (cairo_int128_t a, cairo_int128_t b)
{
if (_cairo_int128_negative (a) && !_cairo_int128_negative (b))
return 1;
if (!_cairo_int128_negative (a) && _cairo_int128_negative (b))
return 0;
return _cairo_uint128_lt (a, b);
}
 
int
_cairo_uint128_cmp (cairo_uint128_t a, cairo_uint128_t b)
{
int cmp;
 
cmp = _cairo_uint64_cmp (a.hi, b.hi);
if (cmp)
return cmp;
return _cairo_uint64_cmp (a.lo, b.lo);
}
 
int
_cairo_int128_cmp (cairo_int128_t a, cairo_int128_t b)
{
if (_cairo_int128_negative (a) && !_cairo_int128_negative (b))
return -1;
if (!_cairo_int128_negative (a) && _cairo_int128_negative (b))
return 1;
 
return _cairo_uint128_cmp (a, b);
}
 
int
_cairo_uint128_eq (cairo_uint128_t a, cairo_uint128_t b)
{
return (_cairo_uint64_eq (a.hi, b.hi) &&
_cairo_uint64_eq (a.lo, b.lo));
}
 
#if HAVE_UINT64_T
#define _cairo_msbset64(q) (q & ((uint64_t) 1 << 63))
#else
#define _cairo_msbset64(q) (q.hi & ((uint32_t) 1 << 31))
#endif
 
cairo_uquorem128_t
_cairo_uint128_divrem (cairo_uint128_t num, cairo_uint128_t den)
{
cairo_uquorem128_t qr;
cairo_uint128_t bit;
cairo_uint128_t quo;
 
bit = _cairo_uint32_to_uint128 (1);
 
/* normalize to make den >= num, but not overflow */
while (_cairo_uint128_lt (den, num) && !_cairo_msbset64(den.hi))
{
bit = _cairo_uint128_lsl (bit, 1);
den = _cairo_uint128_lsl (den, 1);
}
quo = _cairo_uint32_to_uint128 (0);
 
/* generate quotient, one bit at a time */
while (_cairo_uint128_ne (bit, _cairo_uint32_to_uint128(0)))
{
if (_cairo_uint128_le (den, num))
{
num = _cairo_uint128_sub (num, den);
quo = _cairo_uint128_add (quo, bit);
}
bit = _cairo_uint128_rsl (bit, 1);
den = _cairo_uint128_rsl (den, 1);
}
qr.quo = quo;
qr.rem = num;
return qr;
}
 
cairo_int128_t
_cairo_int128_negate (cairo_int128_t a)
{
a.lo = _cairo_uint64_not (a.lo);
a.hi = _cairo_uint64_not (a.hi);
return _cairo_uint128_add (a, _cairo_uint32_to_uint128 (1));
}
 
cairo_int128_t
_cairo_int128_not (cairo_int128_t a)
{
a.lo = _cairo_uint64_not (a.lo);
a.hi = _cairo_uint64_not (a.hi);
return a;
}
 
#endif /* !HAVE_UINT128_T */
 
cairo_quorem128_t
_cairo_int128_divrem (cairo_int128_t num, cairo_int128_t den)
{
int num_neg = _cairo_int128_negative (num);
int den_neg = _cairo_int128_negative (den);
cairo_uquorem128_t uqr;
cairo_quorem128_t qr;
 
if (num_neg)
num = _cairo_int128_negate (num);
if (den_neg)
den = _cairo_int128_negate (den);
uqr = _cairo_uint128_divrem (num, den);
if (num_neg)
qr.rem = _cairo_int128_negate (uqr.rem);
else
qr.rem = uqr.rem;
if (num_neg != den_neg)
qr.quo = _cairo_int128_negate (uqr.quo);
else
qr.quo = uqr.quo;
return qr;
}
 
/**
* _cairo_uint_96by64_32x64_divrem:
*
* Compute a 32 bit quotient and 64 bit remainder of a 96 bit unsigned
* dividend and 64 bit divisor. If the quotient doesn't fit into 32
* bits then the returned remainder is equal to the divisor, and the
* quotient is the largest representable 64 bit integer. It is an
* error to call this function with the high 32 bits of @num being
* non-zero. */
cairo_uquorem64_t
_cairo_uint_96by64_32x64_divrem (cairo_uint128_t num,
cairo_uint64_t den)
{
cairo_uquorem64_t result;
cairo_uint64_t B = _cairo_uint32s_to_uint64 (1, 0);
 
/* These are the high 64 bits of the *96* bit numerator. We're
* going to represent the numerator as xB + y, where x is a 64,
* and y is a 32 bit number. */
cairo_uint64_t x = _cairo_uint128_to_uint64 (_cairo_uint128_rsl(num, 32));
 
/* Initialise the result to indicate overflow. */
result.quo = _cairo_uint32s_to_uint64 (-1U, -1U);
result.rem = den;
 
/* Don't bother if the quotient is going to overflow. */
if (_cairo_uint64_ge (x, den)) {
return /* overflow */ result;
}
 
if (_cairo_uint64_lt (x, B)) {
/* When the final quotient is known to fit in 32 bits, then
* num < 2^64 if and only if den < 2^32. */
return _cairo_uint64_divrem (_cairo_uint128_to_uint64 (num), den);
}
else {
/* Denominator is >= 2^32. the numerator is >= 2^64, and the
* division won't overflow: need two divrems. Write the
* numerator and denominator as
*
* num = xB + y x : 64 bits, y : 32 bits
* den = uB + v u, v : 32 bits
*/
uint32_t y = _cairo_uint128_to_uint32 (num);
uint32_t u = uint64_hi32 (den);
uint32_t v = _cairo_uint64_to_uint32 (den);
 
/* Compute a lower bound approximate quotient of num/den
* from x/(u+1). Then we have
*
* x = q(u+1) + r ; q : 32 bits, r <= u : 32 bits.
*
* xB + y = q(u+1)B + (rB+y)
* = q(uB + B + v - v) + (rB+y)
* = q(uB + v) + qB - qv + (rB+y)
* = q(uB + v) + q(B-v) + (rB+y)
*
* The true quotient of num/den then is q plus the
* contribution of q(B-v) + (rB+y). The main contribution
* comes from the term q(B-v), with the term (rB+y) only
* contributing at most one part.
*
* The term q(B-v) must fit into 64 bits, since q fits into 32
* bits on account of being a lower bound to the true
* quotient, and as B-v <= 2^32, we may safely use a single
* 64/64 bit division to find its contribution. */
 
cairo_uquorem64_t quorem;
cairo_uint64_t remainder; /* will contain final remainder */
uint32_t quotient; /* will contain final quotient. */
uint32_t q;
uint32_t r;
 
/* Approximate quotient by dividing the high 64 bits of num by
* u+1. Watch out for overflow of u+1. */
if (u+1) {
quorem = _cairo_uint64_divrem (x, _cairo_uint32_to_uint64 (u+1));
q = _cairo_uint64_to_uint32 (quorem.quo);
r = _cairo_uint64_to_uint32 (quorem.rem);
}
else {
q = uint64_hi32 (x);
r = _cairo_uint64_to_uint32 (x);
}
quotient = q;
 
/* Add the main term's contribution to quotient. Note B-v =
* -v as an uint32 (unless v = 0) */
if (v)
quorem = _cairo_uint64_divrem (_cairo_uint32x32_64_mul (q, -v), den);
else
quorem = _cairo_uint64_divrem (_cairo_uint32s_to_uint64 (q, 0), den);
quotient += _cairo_uint64_to_uint32 (quorem.quo);
 
/* Add the contribution of the subterm and start computing the
* true remainder. */
remainder = _cairo_uint32s_to_uint64 (r, y);
if (_cairo_uint64_ge (remainder, den)) {
remainder = _cairo_uint64_sub (remainder, den);
quotient++;
}
 
/* Add the contribution of the main term's remainder. The
* funky test here checks that remainder + main_rem >= den,
* taking into account overflow of the addition. */
remainder = _cairo_uint64_add (remainder, quorem.rem);
if (_cairo_uint64_ge (remainder, den) ||
_cairo_uint64_lt (remainder, quorem.rem))
{
remainder = _cairo_uint64_sub (remainder, den);
quotient++;
}
 
result.quo = _cairo_uint32_to_uint64 (quotient);
result.rem = remainder;
}
return result;
}
 
cairo_quorem64_t
_cairo_int_96by64_32x64_divrem (cairo_int128_t num, cairo_int64_t den)
{
int num_neg = _cairo_int128_negative (num);
int den_neg = _cairo_int64_negative (den);
cairo_uint64_t nonneg_den;
cairo_uquorem64_t uqr;
cairo_quorem64_t qr;
 
if (num_neg)
num = _cairo_int128_negate (num);
if (den_neg)
nonneg_den = _cairo_int64_negate (den);
else
nonneg_den = den;
 
uqr = _cairo_uint_96by64_32x64_divrem (num, nonneg_den);
if (_cairo_uint64_eq (uqr.rem, nonneg_den)) {
/* bail on overflow. */
qr.quo = _cairo_uint32s_to_uint64 (0x7FFFFFFF, -1U);
qr.rem = den;
return qr;
}
 
if (num_neg)
qr.rem = _cairo_int64_negate (uqr.rem);
else
qr.rem = uqr.rem;
if (num_neg != den_neg)
qr.quo = _cairo_int64_negate (uqr.quo);
else
qr.quo = uqr.quo;
return qr;
}
/programs/develop/libraries/cairo/src/cairo-win32-private.h
0,0 → 1,213
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2005 Red Hat, Inc
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
* Owen Taylor <otaylor@redhat.com>
*/
 
#ifndef CAIRO_WIN32_PRIVATE_H
#define CAIRO_WIN32_PRIVATE_H
 
#include "cairo-win32.h"
#include "cairoint.h"
#include "cairo-surface-clipper-private.h"
 
#ifndef SHADEBLENDCAPS
#define SHADEBLENDCAPS 120
#endif
#ifndef SB_NONE
#define SB_NONE 0
#endif
 
#define WIN32_FONT_LOGICAL_SCALE 32
 
typedef struct _cairo_win32_surface {
cairo_surface_t base;
 
cairo_format_t format;
 
HDC dc;
 
/* We create off-screen surfaces as DIBs or DDBs, based on what we created
* originally*/
HBITMAP bitmap;
cairo_bool_t is_dib;
 
/* Used to save the initial 1x1 monochrome bitmap for the DC to
* select back into the DC before deleting the DC and our
* bitmap. For Windows XP, this doesn't seem to be necessary
* ... we can just delete the DC and that automatically unselects
* out bitmap. But it's standard practice so apparently is needed
* on some versions of Windows.
*/
HBITMAP saved_dc_bitmap;
 
cairo_surface_t *image;
 
cairo_rectangle_int_t extents;
 
/* Initial clip bits
* We need these kept around so that we maintain
* whatever clip was set on the original DC at creation
* time when cairo is asked to reset the surface clip.
*/
cairo_rectangle_int_t clip_rect;
HRGN initial_clip_rgn;
cairo_bool_t had_simple_clip;
cairo_region_t *clip_region;
 
/* For path clipping to the printing-surface */
cairo_surface_clipper_t clipper;
 
/* Surface DC flags */
uint32_t flags;
 
/* printing surface bits */
cairo_paginated_mode_t paginated_mode;
cairo_content_t content;
cairo_bool_t path_empty;
cairo_bool_t has_ctm;
cairo_matrix_t ctm;
cairo_bool_t has_gdi_ctm;
cairo_matrix_t gdi_ctm;
HBRUSH brush, old_brush;
cairo_scaled_font_subsets_t *font_subsets;
} cairo_win32_surface_t;
 
/* Surface DC flag values */
enum {
/* If this is a surface created for printing or not */
CAIRO_WIN32_SURFACE_FOR_PRINTING = (1<<0),
 
/* Whether the DC is a display DC or not */
CAIRO_WIN32_SURFACE_IS_DISPLAY = (1<<1),
 
/* Whether we can use BitBlt with this surface */
CAIRO_WIN32_SURFACE_CAN_BITBLT = (1<<2),
 
/* Whether we can use AlphaBlend with this surface */
CAIRO_WIN32_SURFACE_CAN_ALPHABLEND = (1<<3),
 
/* Whether we can use StretchBlt with this surface */
CAIRO_WIN32_SURFACE_CAN_STRETCHBLT = (1<<4),
 
/* Whether we can use StretchDIBits with this surface */
CAIRO_WIN32_SURFACE_CAN_STRETCHDIB = (1<<5),
 
/* Whether we can use GradientFill rectangles with this surface */
CAIRO_WIN32_SURFACE_CAN_RECT_GRADIENT = (1<<6),
 
/* Whether we can use the CHECKJPEGFORMAT escape function */
CAIRO_WIN32_SURFACE_CAN_CHECK_JPEG = (1<<7),
 
/* Whether we can use the CHECKJPEGFORMAT escape function */
CAIRO_WIN32_SURFACE_CAN_CHECK_PNG = (1<<8),
};
 
cairo_status_t
_cairo_win32_print_gdi_error (const char *context);
 
cairo_bool_t
_cairo_surface_is_win32 (cairo_surface_t *surface);
 
cairo_bool_t
_cairo_surface_is_win32_printing (cairo_surface_t *surface);
 
cairo_status_t
_cairo_win32_surface_finish (void *abstract_surface);
 
cairo_bool_t
_cairo_win32_surface_get_extents (void *abstract_surface,
cairo_rectangle_int_t *rectangle);
 
uint32_t
_cairo_win32_flags_for_dc (HDC dc);
 
cairo_status_t
_cairo_win32_surface_set_clip_region (void *abstract_surface,
cairo_region_t *region);
 
cairo_int_status_t
_cairo_win32_surface_show_glyphs (void *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font,
cairo_clip_t *clip,
int *remaining_glyphs);
 
cairo_surface_t *
_cairo_win32_surface_create_similar (void *abstract_src,
cairo_content_t content,
int width,
int height);
 
cairo_status_t
_cairo_win32_surface_clone_similar (void *abstract_surface,
cairo_surface_t *src,
cairo_content_t content,
int src_x,
int src_y,
int width,
int height,
int *clone_offset_x,
int *clone_offset_y,
cairo_surface_t **clone_out);
 
static inline void
_cairo_matrix_to_win32_xform (const cairo_matrix_t *m,
XFORM *xform)
{
xform->eM11 = (FLOAT) m->xx;
xform->eM21 = (FLOAT) m->xy;
xform->eM12 = (FLOAT) m->yx;
xform->eM22 = (FLOAT) m->yy;
xform->eDx = (FLOAT) m->x0;
xform->eDy = (FLOAT) m->y0;
}
 
cairo_int_status_t
_cairo_win32_save_initial_clip (HDC dc, cairo_win32_surface_t *surface);
 
cairo_int_status_t
_cairo_win32_restore_initial_clip (cairo_win32_surface_t *surface);
 
void
_cairo_win32_debug_dump_hrgn (HRGN rgn, char *header);
 
cairo_bool_t
_cairo_win32_scaled_font_is_type1 (cairo_scaled_font_t *scaled_font);
 
cairo_bool_t
_cairo_win32_scaled_font_is_bitmap (cairo_scaled_font_t *scaled_font);
 
#endif /* CAIRO_WIN32_PRIVATE_H */
/programs/develop/libraries/cairo/src/cairo-win32.h
0,0 → 1,112
/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2005 Red Hat, Inc
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
* Owen Taylor <otaylor@redhat.com>
*/
 
#ifndef _CAIRO_WIN32_H_
#define _CAIRO_WIN32_H_
 
#include "cairo.h"
 
#if CAIRO_HAS_WIN32_SURFACE
 
#include <windows.h>
 
CAIRO_BEGIN_DECLS
 
cairo_public cairo_surface_t *
cairo_win32_surface_create (HDC hdc);
 
cairo_public cairo_surface_t *
cairo_win32_printing_surface_create (HDC hdc);
 
cairo_public cairo_surface_t *
cairo_win32_surface_create_with_ddb (HDC hdc,
cairo_format_t format,
int width,
int height);
 
cairo_public cairo_surface_t *
cairo_win32_surface_create_with_dib (cairo_format_t format,
int width,
int height);
 
cairo_public HDC
cairo_win32_surface_get_dc (cairo_surface_t *surface);
 
cairo_public cairo_surface_t *
cairo_win32_surface_get_image (cairo_surface_t *surface);
 
#if CAIRO_HAS_WIN32_FONT
 
/*
* Win32 font support
*/
 
cairo_public cairo_font_face_t *
cairo_win32_font_face_create_for_logfontw (LOGFONTW *logfont);
 
cairo_public cairo_font_face_t *
cairo_win32_font_face_create_for_hfont (HFONT font);
 
cairo_public cairo_font_face_t *
cairo_win32_font_face_create_for_logfontw_hfont (LOGFONTW *logfont, HFONT font);
 
cairo_public cairo_status_t
cairo_win32_scaled_font_select_font (cairo_scaled_font_t *scaled_font,
HDC hdc);
 
cairo_public void
cairo_win32_scaled_font_done_font (cairo_scaled_font_t *scaled_font);
 
cairo_public double
cairo_win32_scaled_font_get_metrics_factor (cairo_scaled_font_t *scaled_font);
 
cairo_public void
cairo_win32_scaled_font_get_logical_to_device (cairo_scaled_font_t *scaled_font,
cairo_matrix_t *logical_to_device);
 
cairo_public void
cairo_win32_scaled_font_get_device_to_logical (cairo_scaled_font_t *scaled_font,
cairo_matrix_t *device_to_logical);
 
#endif /* CAIRO_HAS_WIN32_FONT */
 
CAIRO_END_DECLS
 
#else /* CAIRO_HAS_WIN32_SURFACE */
# error Cairo was not compiled with support for the win32 backend
#endif /* CAIRO_HAS_WIN32_SURFACE */
 
#endif /* _CAIRO_WIN32_H_ */
/programs/develop/libraries/cairo/src/cairo-xcb-private.h
0,0 → 1,786
/* Cairo - a vector graphics library with display and print output
*
* Copyright © 2005 Red Hat, Inc.
* Copyright © 2009 Intel Corporation
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributors(s):
* Chris Wilson <chris@chris-wilson.co.uk>
*/
 
#ifndef CAIRO_XCB_PRIVATE_H
#define CAIRO_XCB_PRIVATE_H
 
#include "cairo-xcb.h"
 
#include "cairo-cache-private.h"
#include "cairo-compiler-private.h"
#include "cairo-device-private.h"
#include "cairo-error-private.h"
#include "cairo-freelist-private.h"
#include "cairo-list-private.h"
#include "cairo-mutex-private.h"
#include "cairo-reference-count-private.h"
#include "cairo-spans-private.h"
#include "cairo-surface-private.h"
 
#include <xcb/xcb.h>
#include <xcb/render.h>
#include <xcb/xcbext.h>
#include <pixman.h>
 
typedef struct _cairo_xcb_connection cairo_xcb_connection_t;
typedef struct _cairo_xcb_font cairo_xcb_font_t;
typedef struct _cairo_xcb_screen cairo_xcb_screen_t;
typedef struct _cairo_xcb_surface cairo_xcb_surface_t;
typedef struct _cairo_xcb_shm_mem_pool cairo_xcb_shm_mem_pool_t;
typedef struct _cairo_xcb_shm_info cairo_xcb_shm_info_t;
 
struct _cairo_xcb_shm_info {
cairo_xcb_connection_t *connection;
uint32_t shm;
uint32_t offset;
uint64_t seqno;
void *mem;
cairo_xcb_shm_mem_pool_t *pool;
};
 
struct _cairo_xcb_surface {
cairo_surface_t base;
cairo_surface_t *fallback;
 
cairo_xcb_connection_t *connection;
cairo_xcb_screen_t *screen;
 
cairo_surface_t *drm;
cairo_bool_t marked_dirty;
 
xcb_drawable_t drawable;
cairo_bool_t owns_pixmap;
int use_pixmap;
 
cairo_bool_t deferred_clear;
 
int width;
int height;
int depth;
 
unsigned int flags;
xcb_render_picture_t picture;
xcb_render_pictformat_t xrender_format;
pixman_format_code_t pixman_format;
 
cairo_list_t link;
};
 
#if CAIRO_HAS_XLIB_XCB_FUNCTIONS
typedef struct _cairo_xlib_xcb_surface {
cairo_surface_t base;
 
cairo_xcb_surface_t *xcb;
 
/* original settings for query */
void *display;
void *screen;
void *visual;
void *format;
} cairo_xlib_xcb_surface_t;
#endif
 
 
enum {
GLYPHSET_INDEX_ARGB32,
GLYPHSET_INDEX_A8,
GLYPHSET_INDEX_A1,
NUM_GLYPHSETS
};
 
typedef struct _cairo_xcb_font_glyphset_free_glyphs {
xcb_render_glyphset_t glyphset;
int glyph_count;
xcb_render_glyph_t glyph_indices[128];
} cairo_xcb_font_glyphset_free_glyphs_t;
 
typedef struct _cairo_xcb_font_glyphset_info {
xcb_render_glyphset_t glyphset;
cairo_format_t format;
xcb_render_pictformat_t xrender_format;
cairo_xcb_font_glyphset_free_glyphs_t *pending_free_glyphs;
} cairo_xcb_font_glyphset_info_t;
 
struct _cairo_xcb_font {
cairo_scaled_font_t *scaled_font;
cairo_xcb_connection_t *connection;
cairo_xcb_font_glyphset_info_t glyphset_info[NUM_GLYPHSETS];
cairo_list_t link;
};
 
struct _cairo_xcb_screen {
cairo_xcb_connection_t *connection;
 
xcb_screen_t *xcb_screen;
cairo_device_t *device;
 
xcb_gcontext_t gc[4];
int gc_depths; /* 4 x uint8_t */
 
cairo_surface_t *stock_colors[CAIRO_STOCK_NUM_COLORS];
struct {
cairo_surface_t *picture;
cairo_color_t color;
} solid_cache[16];
int solid_cache_size;
 
cairo_cache_t surface_pattern_cache;
cairo_cache_t linear_pattern_cache;
cairo_cache_t radial_pattern_cache;
cairo_freelist_t pattern_cache_entry_freelist;
 
cairo_list_t link;
cairo_list_t surfaces;
};
 
struct _cairo_xcb_connection {
cairo_device_t device;
 
xcb_connection_t *xcb_connection;
cairo_bool_t has_socket;
 
xcb_render_pictformat_t standard_formats[5];
cairo_hash_table_t *xrender_formats;
cairo_hash_table_t *visual_to_xrender_format;
 
unsigned int maximum_request_length;
unsigned int flags;
 
const xcb_setup_t *root;
const xcb_query_extension_reply_t *render;
const xcb_query_extension_reply_t *shm;
const xcb_query_extension_reply_t *dri2;
uint64_t seqno;
 
cairo_list_t free_xids;
cairo_freepool_t xid_pool;
 
cairo_mutex_t shm_mutex;
cairo_list_t shm_pools;
cairo_freepool_t shm_info_freelist;
 
cairo_mutex_t screens_mutex;
cairo_list_t screens;
 
cairo_list_t fonts;
 
cairo_list_t link;
};
 
enum {
CAIRO_XCB_HAS_RENDER = 0x0001,
CAIRO_XCB_RENDER_HAS_FILL_RECTANGLES = 0x0002,
CAIRO_XCB_RENDER_HAS_COMPOSITE = 0x0004,
CAIRO_XCB_RENDER_HAS_COMPOSITE_TRAPEZOIDS = 0x0008,
CAIRO_XCB_RENDER_HAS_COMPOSITE_SPANS = 0x0010,
CAIRO_XCB_RENDER_HAS_COMPOSITE_GLYPHS = 0x0020,
CAIRO_XCB_RENDER_HAS_PICTURE_TRANSFORM = 0x0040,
CAIRO_XCB_RENDER_HAS_FILTERS = 0x0080,
CAIRO_XCB_RENDER_HAS_PDF_OPERATORS = 0x0100,
CAIRO_XCB_RENDER_HAS_EXTENDED_REPEAT = 0x0200,
CAIRO_XCB_RENDER_HAS_GRADIENTS = 0x0400,
 
CAIRO_XCB_HAS_CAIRO = 0x10000,
 
CAIRO_XCB_HAS_DRI2 = 0x40000000,
CAIRO_XCB_HAS_SHM = 0x80000000
};
 
#define CAIRO_XCB_SHM_SMALL_IMAGE 8192
 
cairo_private extern const cairo_surface_backend_t _cairo_xcb_surface_backend;
 
cairo_private cairo_xcb_connection_t *
_cairo_xcb_connection_get (xcb_connection_t *connection);
 
static inline cairo_xcb_connection_t *
_cairo_xcb_connection_reference (cairo_xcb_connection_t *connection)
{
return (cairo_xcb_connection_t *) cairo_device_reference (&connection->device);
}
 
cairo_private xcb_render_pictformat_t
_cairo_xcb_connection_get_xrender_format (cairo_xcb_connection_t *connection,
pixman_format_code_t pixman_format);
 
cairo_private xcb_render_pictformat_t
_cairo_xcb_connection_get_xrender_format_for_visual (cairo_xcb_connection_t *connection,
const xcb_visualid_t visual);
 
static inline cairo_status_t cairo_warn
_cairo_xcb_connection_acquire (cairo_xcb_connection_t *connection)
{
return cairo_device_acquire (&connection->device);
}
 
cairo_private cairo_status_t
_cairo_xcb_connection_take_socket (cairo_xcb_connection_t *connection);
 
cairo_private uint32_t
_cairo_xcb_connection_get_xid (cairo_xcb_connection_t *connection);
 
cairo_private void
_cairo_xcb_connection_put_xid (cairo_xcb_connection_t *connection,
uint32_t xid);
 
static inline void
_cairo_xcb_connection_release (cairo_xcb_connection_t *connection)
{
cairo_device_release (&connection->device);
}
 
static inline void
_cairo_xcb_connection_destroy (cairo_xcb_connection_t *connection)
{
cairo_device_destroy (&connection->device);
}
 
cairo_private cairo_int_status_t
_cairo_xcb_connection_allocate_shm_info (cairo_xcb_connection_t *display,
size_t size,
cairo_xcb_shm_info_t **shm_info_out);
 
cairo_private void
_cairo_xcb_shm_info_destroy (cairo_xcb_shm_info_t *shm_info);
 
cairo_private void
_cairo_xcb_connection_shm_mem_pools_fini (cairo_xcb_connection_t *connection);
 
cairo_private void
_cairo_xcb_font_finish (cairo_xcb_font_t *font);
 
cairo_private cairo_xcb_screen_t *
_cairo_xcb_screen_get (xcb_connection_t *connection,
xcb_screen_t *screen);
 
cairo_private void
_cairo_xcb_screen_finish (cairo_xcb_screen_t *screen);
 
cairo_private xcb_gcontext_t
_cairo_xcb_screen_get_gc (cairo_xcb_screen_t *screen,
xcb_drawable_t drawable,
int depth);
 
cairo_private void
_cairo_xcb_screen_put_gc (cairo_xcb_screen_t *screen, int depth, xcb_gcontext_t gc);
 
cairo_private cairo_status_t
_cairo_xcb_screen_store_surface_picture (cairo_xcb_screen_t *screen,
cairo_surface_t *picture,
unsigned int size);
cairo_private void
_cairo_xcb_screen_remove_surface_picture (cairo_xcb_screen_t *screen,
cairo_surface_t *picture);
 
cairo_private cairo_status_t
_cairo_xcb_screen_store_linear_picture (cairo_xcb_screen_t *screen,
const cairo_linear_pattern_t *linear,
cairo_surface_t *picture);
 
cairo_private cairo_surface_t *
_cairo_xcb_screen_lookup_linear_picture (cairo_xcb_screen_t *screen,
const cairo_linear_pattern_t *linear);
 
cairo_private cairo_status_t
_cairo_xcb_screen_store_radial_picture (cairo_xcb_screen_t *screen,
const cairo_radial_pattern_t *radial,
cairo_surface_t *picture);
 
cairo_private cairo_surface_t *
_cairo_xcb_screen_lookup_radial_picture (cairo_xcb_screen_t *screen,
const cairo_radial_pattern_t *radial);
 
cairo_private cairo_surface_t *
_cairo_xcb_surface_create_similar_image (cairo_xcb_surface_t *other,
cairo_content_t content,
int width, int height);
 
cairo_private cairo_surface_t *
_cairo_xcb_surface_create_similar (void *abstract_other,
cairo_content_t content,
int width,
int height);
 
cairo_private cairo_surface_t *
_cairo_xcb_surface_create_internal (cairo_xcb_screen_t *screen,
xcb_drawable_t drawable,
cairo_bool_t owns_pixmap,
pixman_format_code_t pixman_format,
xcb_render_pictformat_t xrender_format,
int width,
int height);
 
cairo_private cairo_int_status_t
_cairo_xcb_surface_cairo_paint (cairo_xcb_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_clip_t *clip);
 
cairo_private cairo_int_status_t
_cairo_xcb_surface_cairo_mask (cairo_xcb_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_pattern_t *mask,
cairo_clip_t *clip);
 
cairo_private cairo_int_status_t
_cairo_xcb_surface_cairo_stroke (cairo_xcb_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_path_fixed_t *path,
const cairo_stroke_style_t *style,
const cairo_matrix_t *ctm,
const cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
cairo_clip_t *clip);
 
cairo_private cairo_int_status_t
_cairo_xcb_surface_cairo_fill (cairo_xcb_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias,
cairo_clip_t *clip);
 
cairo_private cairo_int_status_t
_cairo_xcb_surface_cairo_glyphs (cairo_xcb_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_scaled_font_t *scaled_font,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_clip_t *clip);
 
cairo_private cairo_int_status_t
_cairo_xcb_surface_render_paint (cairo_xcb_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_clip_t *clip);
 
cairo_private cairo_int_status_t
_cairo_xcb_surface_render_mask (cairo_xcb_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_pattern_t *mask,
cairo_clip_t *clip);
 
cairo_private cairo_int_status_t
_cairo_xcb_surface_render_stroke (cairo_xcb_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_path_fixed_t *path,
const cairo_stroke_style_t *style,
const cairo_matrix_t *ctm,
const cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
cairo_clip_t *clip);
 
cairo_private cairo_int_status_t
_cairo_xcb_surface_render_fill (cairo_xcb_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias,
cairo_clip_t *clip);
 
cairo_private cairo_int_status_t
_cairo_xcb_surface_render_glyphs (cairo_xcb_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_scaled_font_t *scaled_font,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_clip_t *clip);
cairo_private void
_cairo_xcb_surface_scaled_font_fini (cairo_scaled_font_t *scaled_font);
 
cairo_private void
_cairo_xcb_surface_scaled_glyph_fini (cairo_scaled_glyph_t *scaled_glyph,
cairo_scaled_font_t *scaled_font);
 
cairo_private cairo_status_t
_cairo_xcb_surface_clear (cairo_xcb_surface_t *dst);
 
cairo_private cairo_status_t
_cairo_xcb_surface_core_copy_boxes (cairo_xcb_surface_t *dst,
const cairo_pattern_t *src_pattern,
const cairo_rectangle_int_t *extents,
const cairo_boxes_t *boxes);
 
cairo_private cairo_status_t
_cairo_xcb_surface_core_fill_boxes (cairo_xcb_surface_t *dst,
const cairo_color_t *color,
cairo_boxes_t *boxes);
 
static inline void
_cairo_xcb_connection_write (cairo_xcb_connection_t *connection,
struct iovec *vec,
int count)
{
if (unlikely (connection->device.status))
return;
 
connection->seqno++;
if (unlikely (! xcb_writev (connection->xcb_connection, vec, count, 1)))
connection->device.status = _cairo_error (CAIRO_STATUS_WRITE_ERROR);
}
 
cairo_private xcb_pixmap_t
_cairo_xcb_connection_create_pixmap (cairo_xcb_connection_t *connection,
uint8_t depth,
xcb_drawable_t drawable,
uint16_t width,
uint16_t height);
 
cairo_private void
_cairo_xcb_connection_free_pixmap (cairo_xcb_connection_t *connection,
xcb_pixmap_t pixmap);
 
cairo_private xcb_gcontext_t
_cairo_xcb_connection_create_gc (cairo_xcb_connection_t *connection,
xcb_drawable_t drawable,
uint32_t value_mask,
uint32_t *values);
 
cairo_private void
_cairo_xcb_connection_free_gc (cairo_xcb_connection_t *connection,
xcb_gcontext_t gc);
 
cairo_private void
_cairo_xcb_connection_change_gc (cairo_xcb_connection_t *connection,
xcb_gcontext_t gc,
uint32_t value_mask,
uint32_t *values);
 
cairo_private void
_cairo_xcb_connection_copy_area (cairo_xcb_connection_t *connection,
xcb_drawable_t src,
xcb_drawable_t dst,
xcb_gcontext_t gc,
int16_t src_x,
int16_t src_y,
int16_t dst_x,
int16_t dst_y,
uint16_t width,
uint16_t height);
 
cairo_private void
_cairo_xcb_connection_put_image (cairo_xcb_connection_t *connection,
xcb_drawable_t dst,
xcb_gcontext_t gc,
uint16_t width,
uint16_t height,
int16_t dst_x,
int16_t dst_y,
uint8_t depth,
uint32_t length,
void *data);
 
cairo_private void
_cairo_xcb_connection_put_subimage (cairo_xcb_connection_t *connection,
xcb_drawable_t dst,
xcb_gcontext_t gc,
int16_t src_x,
int16_t src_y,
uint16_t width,
uint16_t height,
uint16_t cpp,
uint16_t stride,
int16_t dst_x,
int16_t dst_y,
uint8_t depth,
void *data);
 
cairo_private cairo_status_t
_cairo_xcb_connection_get_image (cairo_xcb_connection_t *connection,
xcb_drawable_t src,
int16_t src_x,
int16_t src_y,
uint16_t width,
uint16_t height,
xcb_get_image_reply_t **reply);
 
cairo_private void
_cairo_xcb_connection_poly_fill_rectangle (cairo_xcb_connection_t *connection,
xcb_drawable_t dst,
xcb_gcontext_t gc,
uint32_t num_rectangles,
xcb_rectangle_t *rectangles);
 
#if CAIRO_HAS_XCB_SHM_FUNCTIONS
cairo_private uint32_t
_cairo_xcb_connection_shm_attach (cairo_xcb_connection_t *connection,
uint32_t id,
cairo_bool_t readonly);
 
cairo_private uint64_t
_cairo_xcb_connection_shm_put_image (cairo_xcb_connection_t *connection,
xcb_drawable_t dst,
xcb_gcontext_t gc,
uint16_t total_width,
uint16_t total_height,
int16_t src_x,
int16_t src_y,
uint16_t width,
uint16_t height,
int16_t dst_x,
int16_t dst_y,
uint8_t depth,
uint32_t shm,
uint32_t offset);
 
cairo_private cairo_status_t
_cairo_xcb_connection_shm_get_image (cairo_xcb_connection_t *connection,
xcb_drawable_t src,
int16_t src_x,
int16_t src_y,
uint16_t width,
uint16_t height,
uint32_t shmseg,
uint32_t offset);
 
cairo_private void
_cairo_xcb_connection_shm_detach (cairo_xcb_connection_t *connection,
uint32_t segment);
#else
static inline uint64_t
_cairo_xcb_connection_shm_put_image (cairo_xcb_connection_t *connection,
xcb_drawable_t dst,
xcb_gcontext_t gc,
uint16_t total_width,
uint16_t total_height,
int16_t src_x,
int16_t src_y,
uint16_t width,
uint16_t height,
int16_t dst_x,
int16_t dst_y,
uint8_t depth,
uint32_t shm,
uint32_t offset)
{
return 0;
}
#endif
 
cairo_private void
_cairo_xcb_connection_render_spans (cairo_xcb_connection_t *connection,
xcb_render_picture_t dst,
int op,
xcb_render_picture_t src,
int16_t src_x, int16_t src_y,
int16_t dst_x, int16_t dst_y,
int16_t width, int16_t height,
unsigned int length,
uint16_t *spans);
cairo_private void
_cairo_xcb_connection_render_create_picture (cairo_xcb_connection_t *connection,
xcb_render_picture_t picture,
xcb_drawable_t drawable,
xcb_render_pictformat_t format,
uint32_t value_mask,
uint32_t *value_list);
 
cairo_private void
_cairo_xcb_connection_render_change_picture (cairo_xcb_connection_t *connection,
xcb_render_picture_t picture,
uint32_t value_mask,
uint32_t *value_list);
 
cairo_private void
_cairo_xcb_connection_render_set_picture_clip_rectangles (cairo_xcb_connection_t *connection,
xcb_render_picture_t picture,
int16_t clip_x_origin,
int16_t clip_y_origin,
uint32_t rectangles_len,
xcb_rectangle_t *rectangles);
 
cairo_private void
_cairo_xcb_connection_render_free_picture (cairo_xcb_connection_t *connection,
xcb_render_picture_t picture);
 
cairo_private void
_cairo_xcb_connection_render_composite (cairo_xcb_connection_t *connection,
uint8_t op,
xcb_render_picture_t src,
xcb_render_picture_t mask,
xcb_render_picture_t dst,
int16_t src_x,
int16_t src_y,
int16_t mask_x,
int16_t mask_y,
int16_t dst_x,
int16_t dst_y,
uint16_t width,
uint16_t height);
 
cairo_private void
_cairo_xcb_connection_render_trapezoids (cairo_xcb_connection_t *connection,
uint8_t op,
xcb_render_picture_t src,
xcb_render_picture_t dst,
xcb_render_pictformat_t mask_format,
int16_t src_x,
int16_t src_y,
uint32_t traps_len,
xcb_render_trapezoid_t *traps);
 
cairo_private void
_cairo_xcb_connection_render_create_glyph_set (cairo_xcb_connection_t *connection,
xcb_render_glyphset_t id,
xcb_render_pictformat_t format);
 
cairo_private void
_cairo_xcb_connection_render_free_glyph_set (cairo_xcb_connection_t *connection,
xcb_render_glyphset_t glyphset);
 
cairo_private void
_cairo_xcb_connection_render_add_glyphs (cairo_xcb_connection_t *connection,
xcb_render_glyphset_t glyphset,
uint32_t num_glyphs,
uint32_t *glyphs_id,
xcb_render_glyphinfo_t *glyphs,
uint32_t data_len,
uint8_t *data);
 
cairo_private void
_cairo_xcb_connection_render_free_glyphs (cairo_xcb_connection_t *connection,
xcb_render_glyphset_t glyphset,
uint32_t num_glyphs,
xcb_render_glyph_t *glyphs);
 
cairo_private void
_cairo_xcb_connection_render_composite_glyphs_8 (cairo_xcb_connection_t *connection,
uint8_t op,
xcb_render_picture_t src,
xcb_render_picture_t dst,
xcb_render_pictformat_t mask_format,
xcb_render_glyphset_t glyphset,
int16_t src_x,
int16_t src_y,
uint32_t glyphcmds_len,
uint8_t *glyphcmds);
 
cairo_private void
_cairo_xcb_connection_render_composite_glyphs_16 (cairo_xcb_connection_t *connection,
uint8_t op,
xcb_render_picture_t src,
xcb_render_picture_t dst,
xcb_render_pictformat_t mask_format,
xcb_render_glyphset_t glyphset,
int16_t src_x,
int16_t src_y,
uint32_t glyphcmds_len,
uint8_t *glyphcmds);
 
cairo_private void
_cairo_xcb_connection_render_composite_glyphs_32 (cairo_xcb_connection_t *connection,
uint8_t op,
xcb_render_picture_t src,
xcb_render_picture_t dst,
xcb_render_pictformat_t mask_format,
xcb_render_glyphset_t glyphset,
int16_t src_x,
int16_t src_y,
uint32_t glyphcmds_len,
uint8_t *glyphcmds);
 
cairo_private void
_cairo_xcb_connection_render_fill_rectangles (cairo_xcb_connection_t *connection,
uint8_t op,
xcb_render_picture_t dst,
xcb_render_color_t color,
uint32_t num_rects,
xcb_rectangle_t *rects);
 
cairo_private void
_cairo_xcb_connection_render_set_picture_transform (cairo_xcb_connection_t *connection,
xcb_render_picture_t picture,
xcb_render_transform_t *transform);
 
cairo_private void
_cairo_xcb_connection_render_set_picture_filter (cairo_xcb_connection_t *connection,
xcb_render_picture_t picture,
uint16_t filter_len,
char *filter);
 
cairo_private void
_cairo_xcb_connection_render_create_solid_fill (cairo_xcb_connection_t *connection,
xcb_render_picture_t picture,
xcb_render_color_t color);
 
cairo_private void
_cairo_xcb_connection_render_create_linear_gradient (cairo_xcb_connection_t *connection,
xcb_render_picture_t picture,
xcb_render_pointfix_t p1,
xcb_render_pointfix_t p2,
uint32_t num_stops,
xcb_render_fixed_t *stops,
xcb_render_color_t *colors);
 
cairo_private void
_cairo_xcb_connection_render_create_radial_gradient (cairo_xcb_connection_t *connection,
xcb_render_picture_t picture,
xcb_render_pointfix_t inner,
xcb_render_pointfix_t outer,
xcb_render_fixed_t inner_radius,
xcb_render_fixed_t outer_radius,
uint32_t num_stops,
xcb_render_fixed_t *stops,
xcb_render_color_t *colors);
 
cairo_private void
_cairo_xcb_connection_render_create_conical_gradient (cairo_xcb_connection_t *c,
xcb_render_picture_t picture,
xcb_render_pointfix_t center,
xcb_render_fixed_t angle,
uint32_t num_stops,
xcb_render_fixed_t *stops,
xcb_render_color_t *colors);
#if CAIRO_HAS_XLIB_XCB_FUNCTIONS
slim_hidden_proto (cairo_xcb_surface_create);
slim_hidden_proto (cairo_xcb_surface_create_for_bitmap);
slim_hidden_proto (cairo_xcb_surface_create_with_xrender_format);
slim_hidden_proto (cairo_xcb_surface_set_size);
#endif
 
#endif /* CAIRO_XCB_PRIVATE_H */
/programs/develop/libraries/cairo/src/cairo-xcb.h
0,0 → 1,96
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2002 University of Southern California
* Copyright © 2009 Intel Corporation
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
* Chris Wilson <chris@chris-wilson.co.uk>
*/
 
#ifndef CAIRO_XCB_H
#define CAIRO_XCB_H
 
#include "cairo.h"
 
#if CAIRO_HAS_XCB_SURFACE
 
#include <xcb/xcb.h>
#include <xcb/render.h>
 
CAIRO_BEGIN_DECLS
 
cairo_public cairo_surface_t *
cairo_xcb_surface_create (xcb_connection_t *connection,
xcb_drawable_t drawable,
xcb_visualtype_t *visual,
int width,
int height);
 
cairo_public cairo_surface_t *
cairo_xcb_surface_create_for_bitmap (xcb_connection_t *connection,
xcb_screen_t *screen,
xcb_pixmap_t bitmap,
int width,
int height);
 
cairo_public cairo_surface_t *
cairo_xcb_surface_create_with_xrender_format (xcb_connection_t *connection,
xcb_screen_t *screen,
xcb_drawable_t drawable,
xcb_render_pictforminfo_t *format,
int width,
int height);
 
cairo_public void
cairo_xcb_surface_set_size (cairo_surface_t *surface,
int width,
int height);
 
/* debug interface */
 
cairo_public void
cairo_xcb_device_debug_cap_xshm_version (cairo_device_t *device,
int major_version,
int minor_version);
 
cairo_public void
cairo_xcb_device_debug_cap_xrender_version (cairo_device_t *device,
int major_version,
int minor_version);
 
CAIRO_END_DECLS
 
#else /* CAIRO_HAS_XCB_SURFACE */
# error Cairo was not compiled with support for the xcb backend
#endif /* CAIRO_HAS_XCB_SURFACE */
 
#endif /* CAIRO_XCB_H */
/programs/develop/libraries/cairo/src/cairo-xlib-private.h
0,0 → 1,200
/* Cairo - a vector graphics library with display and print output
*
* Copyright © 2005 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributors(s):
* Chris Wilson <chris@chris-wilson.co.uk>
* Karl Tomlinson <karlt+@karlt.net>, Mozilla Corporation
*/
 
#ifndef CAIRO_XLIB_PRIVATE_H
#define CAIRO_XLIB_PRIVATE_H
 
#include "cairo-xlib.h"
#include "cairo-xlib-xrender-private.h"
 
#include "cairo-compiler-private.h"
#include "cairo-device-private.h"
#include "cairo-freelist-type-private.h"
#include "cairo-list-private.h"
#include "cairo-reference-count-private.h"
#include "cairo-types-private.h"
 
typedef struct _cairo_xlib_display cairo_xlib_display_t;
typedef struct _cairo_xlib_screen cairo_xlib_screen_t;
 
typedef struct _cairo_xlib_hook cairo_xlib_hook_t;
typedef struct _cairo_xlib_job cairo_xlib_job_t;
typedef void (*cairo_xlib_notify_func) (Display *, void *);
typedef void (*cairo_xlib_notify_resource_func) (Display *, XID);
 
struct _cairo_xlib_hook {
cairo_xlib_hook_t *prev, *next; /* private */
void (*func) (cairo_xlib_display_t *display, void *data);
};
 
/* size of color cube */
#define CUBE_SIZE 6
/* size of gray ramp */
#define RAMP_SIZE 16
 
struct _cairo_xlib_display {
cairo_device_t base;
 
cairo_xlib_display_t *next;
 
Display *display;
cairo_list_t screens;
 
int render_major;
int render_minor;
XRenderPictFormat *cached_xrender_formats[CAIRO_FORMAT_RGB16_565 + 1];
 
cairo_xlib_job_t *workqueue;
cairo_freelist_t wq_freelist;
 
cairo_xlib_hook_t *close_display_hooks;
unsigned int buggy_gradients :1;
unsigned int buggy_pad_reflect :1;
unsigned int buggy_repeat :1;
unsigned int closed :1;
};
 
typedef struct _cairo_xlib_visual_info {
cairo_list_t link;
VisualID visualid;
struct { uint8_t a, r, g, b; } colors[256];
uint8_t cube_to_pseudocolor[CUBE_SIZE][CUBE_SIZE][CUBE_SIZE];
uint8_t field8_to_cube[256];
int8_t dither8_to_cube[256];
uint8_t gray8_to_pseudocolor[256];
} cairo_xlib_visual_info_t;
 
struct _cairo_xlib_screen {
cairo_list_t link;
 
cairo_device_t *device;
Screen *screen;
 
cairo_bool_t has_font_options;
cairo_font_options_t font_options;
 
GC gc[4];
cairo_atomic_int_t gc_depths; /* 4 x uint8_t */
 
cairo_list_t visuals;
};
 
cairo_private cairo_device_t *
_cairo_xlib_device_create (Display *display);
 
cairo_private cairo_xlib_screen_t *
_cairo_xlib_display_get_screen (cairo_xlib_display_t *display,
Screen *screen);
 
cairo_private void
_cairo_xlib_add_close_display_hook (cairo_xlib_display_t *display, cairo_xlib_hook_t *hook);
 
cairo_private void
_cairo_xlib_remove_close_display_hook (cairo_xlib_display_t *display, cairo_xlib_hook_t *hook);
 
cairo_private cairo_status_t
_cairo_xlib_display_queue_work (cairo_xlib_display_t *display,
cairo_xlib_notify_func notify,
void *data,
void (*destroy)(void *));
cairo_private cairo_status_t
_cairo_xlib_display_queue_resource (cairo_xlib_display_t *display,
cairo_xlib_notify_resource_func notify,
XID resource);
cairo_private cairo_status_t
_cairo_xlib_display_acquire (cairo_device_t *device,
cairo_xlib_display_t **display);
 
cairo_private void
_cairo_xlib_display_get_xrender_version (cairo_xlib_display_t *display,
int *major, int *minor);
 
cairo_private cairo_bool_t
_cairo_xlib_display_has_repeat (cairo_device_t *device);
 
cairo_private cairo_bool_t
_cairo_xlib_display_has_reflect (cairo_device_t *device);
 
cairo_private cairo_bool_t
_cairo_xlib_display_has_gradients (cairo_device_t *device);
 
cairo_private XRenderPictFormat *
_cairo_xlib_display_get_xrender_format (cairo_xlib_display_t *display,
cairo_format_t format);
 
cairo_private cairo_status_t
_cairo_xlib_screen_get (Display *dpy,
Screen *screen,
cairo_xlib_screen_t **out);
 
cairo_private void
_cairo_xlib_screen_destroy (cairo_xlib_screen_t *info);
 
cairo_private void
_cairo_xlib_screen_close_display (cairo_xlib_display_t *display,
cairo_xlib_screen_t *info);
 
cairo_private GC
_cairo_xlib_screen_get_gc (cairo_xlib_display_t *display,
cairo_xlib_screen_t *info,
int depth,
Drawable drawable);
 
cairo_private void
_cairo_xlib_screen_put_gc (cairo_xlib_display_t *display,
cairo_xlib_screen_t *info,
int depth,
GC gc);
 
cairo_private cairo_font_options_t *
_cairo_xlib_screen_get_font_options (cairo_xlib_screen_t *info);
 
cairo_private cairo_status_t
_cairo_xlib_screen_get_visual_info (cairo_xlib_display_t *display,
cairo_xlib_screen_t *info,
Visual *visual,
cairo_xlib_visual_info_t **out);
 
cairo_private cairo_status_t
_cairo_xlib_visual_info_create (Display *dpy,
int screen,
VisualID visualid,
cairo_xlib_visual_info_t **out);
 
cairo_private void
_cairo_xlib_visual_info_destroy (cairo_xlib_visual_info_t *info);
 
#endif /* CAIRO_XLIB_PRIVATE_H */
/programs/develop/libraries/cairo/src/cairo-xlib-surface-private.h
0,0 → 1,112
/* Cairo - a vector graphics library with display and print output
*
* Copyright © 2005 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*/
 
#ifndef CAIRO_XLIB_SURFACE_PRIVATE_H
#define CAIRO_XLIB_SURFACE_PRIVATE_H
 
#include "cairo-xlib.h"
#include "cairo-xlib-private.h"
#include "cairo-xlib-xrender-private.h"
 
#include "cairo-surface-private.h"
 
typedef struct _cairo_xlib_surface cairo_xlib_surface_t;
 
struct _cairo_xlib_surface {
cairo_surface_t base;
 
cairo_xlib_screen_t *screen;
cairo_xlib_hook_t close_display_hook;
 
Drawable drawable;
cairo_bool_t owns_pixmap;
Visual *visual;
 
int use_pixmap;
 
int render_major;
int render_minor;
 
/* TRUE if the server has a bug with repeating pictures
*
* https://bugs.freedesktop.org/show_bug.cgi?id=3566
*
* We can't test for this because it depends on whether the
* picture is in video memory or not.
*
* We also use this variable as a guard against a second
* independent bug with transformed repeating pictures:
*
* http://lists.freedesktop.org/archives/cairo/2004-September/001839.html
*
* Both are fixed in xorg >= 6.9 and hopefully in > 6.8.2, so
* we can reuse the test for now.
*/
unsigned int buggy_gradients : 1;
unsigned int buggy_pad_reflect : 1;
unsigned int buggy_repeat : 1;
#define CAIRO_XLIB_SURFACE_HAS_BUGGY_GRADIENTS 1
#define CAIRO_XLIB_SURFACE_HAS_BUGGY_PAD_REFLECT 1
#define CAIRO_XLIB_SURFACE_HAS_BUGGY_REPEAT 1
 
int width;
int height;
int depth;
 
Picture dst_picture, src_picture;
 
unsigned int clip_dirty;
XRectangle embedded_clip_rects[8];
XRectangle *clip_rects;
int num_clip_rects;
cairo_region_t *clip_region;
 
XRenderPictFormat *xrender_format;
cairo_filter_t filter;
cairo_extend_t extend;
cairo_bool_t has_component_alpha;
int precision;
XTransform xtransform;
 
uint32_t a_mask;
uint32_t r_mask;
uint32_t g_mask;
uint32_t b_mask;
};
 
enum {
CAIRO_XLIB_SURFACE_CLIP_DIRTY_GC = 0x01,
CAIRO_XLIB_SURFACE_CLIP_DIRTY_PICTURE = 0x02,
CAIRO_XLIB_SURFACE_CLIP_DIRTY_ALL = 0x03
};
 
#endif /* CAIRO_XLIB_SURFACE_PRIVATE_H */
/programs/develop/libraries/cairo/src/cairo-xlib-xrender-private.h
0,0 → 1,1164
/* Cairo - a vector graphics library with display and print output
*
* Copyright © 2007 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*/
 
#ifndef CAIRO_XLIB_XRENDER_PRIVATE_H
#define CAIRO_XLIB_XRENDER_PRIVATE_H
 
#include "cairo-features.h"
#include "cairo-compiler-private.h"
 
#include <X11/Xlib.h>
 
/* These prototypes are used when defining interfaces missing from the
* render headers. As it happens, it is the case that all libxrender
* functions take a pointer as first argument. */
 
__attribute__((__unused__)) static void _void_consume (void *p, ...) { }
__attribute__((__unused__)) static void * _voidp_consume (void *p, ...) { return (void *)0; }
__attribute__((__unused__)) static int _int_consume (void *p, ...) { return 0; }
__attribute__((__unused__)) static void _void_consume_free (Display *p, XID n) { }
 
 
#if CAIRO_HAS_XLIB_XRENDER_SURFACE
 
#include "cairo-xlib-xrender.h"
 
#include <X11/extensions/Xrender.h>
#include <X11/extensions/renderproto.h>
 
/* We require Render >= 0.6. The following defines were only added in
* 0.10. Make sure they are defined.
*/
 
/* Filters included in 0.10 */
#ifndef FilterConvolution
#define FilterConvolution "convolution"
#endif
 
/* Extended repeat attributes included in 0.10 */
#ifndef RepeatNone
#define RepeatNone 0
#define RepeatNormal 1
#define RepeatPad 2
#define RepeatReflect 3
#endif
 
 
#ifndef PictOptBlendMinimum
/*
* Operators only available in version 0.11
*/
#define PictOpBlendMinimum 0x30
#define PictOpMultiply 0x30
#define PictOpScreen 0x31
#define PictOpOverlay 0x32
#define PictOpDarken 0x33
#define PictOpLighten 0x34
#define PictOpColorDodge 0x35
#define PictOpColorBurn 0x36
#define PictOpHardLight 0x37
#define PictOpSoftLight 0x38
#define PictOpDifference 0x39
#define PictOpExclusion 0x3a
#define PictOpHSLHue 0x3b
#define PictOpHSLSaturation 0x3c
#define PictOpHSLColor 0x3d
#define PictOpHSLLuminosity 0x3e
#define PictOpBlendMaximum 0x3e
#endif
 
/* There doesn't appear to be a simple #define that we can conditionalize
* on. Instead, use the version; gradients were introdiced in 0.10. */
#if RENDER_MAJOR == 0 && RENDER_MINOR < 10
#define XRenderCreateLinearGradient _int_consume
#define XRenderCreateRadialGradient _int_consume
#define XRenderCreateConicalGradient _int_consume
typedef struct _XCircle {
XFixed x;
XFixed y;
XFixed radius;
} XCircle;
typedef struct _XLinearGradient {
XPointFixed p1;
XPointFixed p2;
} XLinearGradient;
 
typedef struct _XRadialGradient {
XCircle inner;
XCircle outer;
} XRadialGradient;
 
typedef struct _XConicalGradient {
XPointFixed center;
XFixed angle; /* in degrees */
} XConicalGradient;
#endif
 
 
#else /* !CAIRO_HAS_XLIB_XRENDER_SURFACE */
 
/* Provide dummy symbols and macros to get it compile and take the fallback
* route, just like as if Xrender is not available in the server at run-time. */
 
 
/* Functions */
 
#define XRenderQueryExtension _int_consume
#define XRenderQueryVersion _int_consume
#define XRenderQueryFormats _int_consume
#define XRenderQuerySubpixelOrder _int_consume
#define XRenderSetSubpixelOrder _int_consume
#define XRenderFindVisualFormat _voidp_consume
#define XRenderFindFormat _voidp_consume
#define XRenderFindStandardFormat _voidp_consume
#define XRenderQueryPictIndexValues _voidp_consume
#define XRenderCreatePicture _int_consume
#define XRenderChangePicture _void_consume
#define XRenderSetPictureClipRectangles _void_consume
#define XRenderSetPictureClipRegion _void_consume
#define XRenderSetPictureTransform _void_consume
#define XRenderFreePicture _void_consume_free
#define XRenderComposite _void_consume
#define XRenderCreateGlyphSet _int_consume
#define XRenderReferenceGlyphSet _int_consume
#define XRenderFreeGlyphSet _void_consume_free
#define XRenderAddGlyphs _void_consume
#define XRenderFreeGlyphs _void_consume
#define XRenderCompositeString8 _void_consume
#define XRenderCompositeString16 _void_consume
#define XRenderCompositeString32 _void_consume
#define XRenderCompositeText8 (cairo_xrender_composite_text_func_t) _void_consume
#define XRenderCompositeText16 _void_consume
#define XRenderCompositeText32 _void_consume
#define XRenderFillRectangle _void_consume
#define XRenderFillRectangles _void_consume
#define XRenderCompositeTrapezoids _void_consume
#define XRenderCompositeTriangles _void_consume
#define XRenderCompositeTriStrip _void_consume
#define XRenderCompositeTriFan _void_consume
#define XRenderCompositeDoublePoly _void_consume
#define XRenderParseColor _int_consume
#define XRenderCreateCursor _int_consume
#define XRenderQueryFilters _voidp_consume
#define XRenderSetPictureFilter _void_consume
#define XRenderCreateAnimCursor _int_consume
#define XRenderAddTraps _void_consume
#define XRenderCreateSolidFill _int_consume
#define XRenderCreateLinearGradient _int_consume
#define XRenderCreateRadialGradient _int_consume
#define XRenderCreateConicalGradient _int_consume
 
#define cairo_xlib_surface_create_with_xrender_format _voidp_consume
 
 
 
/* The rest of this file is copied from various Xrender header files, with
* the following copyright/license information:
*
* Copyright © 2000 SuSE, Inc.
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation, and that the name of SuSE not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. SuSE makes no representations about the
* suitability of this software for any purpose. It is provided "as is"
* without express or implied warranty.
*
* SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE
* BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Author: Keith Packard, SuSE, Inc.
*/
 
 
/* Copied from X11/extensions/render.h */
 
typedef unsigned long Glyph;
typedef unsigned long GlyphSet;
typedef unsigned long Picture;
typedef unsigned long PictFormat;
 
#define BadPictFormat 0
#define BadPicture 1
#define BadPictOp 2
#define BadGlyphSet 3
#define BadGlyph 4
#define RenderNumberErrors (BadGlyph+1)
 
#define PictTypeIndexed 0
#define PictTypeDirect 1
 
#define PictOpMinimum 0
#define PictOpClear 0
#define PictOpSrc 1
#define PictOpDst 2
#define PictOpOver 3
#define PictOpOverReverse 4
#define PictOpIn 5
#define PictOpInReverse 6
#define PictOpOut 7
#define PictOpOutReverse 8
#define PictOpAtop 9
#define PictOpAtopReverse 10
#define PictOpXor 11
#define PictOpAdd 12
#define PictOpSaturate 13
#define PictOpMaximum 13
 
/*
* Operators only available in version 0.2
*/
#define PictOpDisjointMinimum 0x10
#define PictOpDisjointClear 0x10
#define PictOpDisjointSrc 0x11
#define PictOpDisjointDst 0x12
#define PictOpDisjointOver 0x13
#define PictOpDisjointOverReverse 0x14
#define PictOpDisjointIn 0x15
#define PictOpDisjointInReverse 0x16
#define PictOpDisjointOut 0x17
#define PictOpDisjointOutReverse 0x18
#define PictOpDisjointAtop 0x19
#define PictOpDisjointAtopReverse 0x1a
#define PictOpDisjointXor 0x1b
#define PictOpDisjointMaximum 0x1b
 
#define PictOpConjointMinimum 0x20
#define PictOpConjointClear 0x20
#define PictOpConjointSrc 0x21
#define PictOpConjointDst 0x22
#define PictOpConjointOver 0x23
#define PictOpConjointOverReverse 0x24
#define PictOpConjointIn 0x25
#define PictOpConjointInReverse 0x26
#define PictOpConjointOut 0x27
#define PictOpConjointOutReverse 0x28
#define PictOpConjointAtop 0x29
#define PictOpConjointAtopReverse 0x2a
#define PictOpConjointXor 0x2b
#define PictOpConjointMaximum 0x2b
 
/*
* Operators only available in version 0.11
*/
#define PictOpBlendMinimum 0x30
#define PictOpMultiply 0x30
#define PictOpScreen 0x31
#define PictOpOverlay 0x32
#define PictOpDarken 0x33
#define PictOpLighten 0x34
#define PictOpColorDodge 0x35
#define PictOpColorBurn 0x36
#define PictOpHardLight 0x37
#define PictOpSoftLight 0x38
#define PictOpDifference 0x39
#define PictOpExclusion 0x3a
#define PictOpHSLHue 0x3b
#define PictOpHSLSaturation 0x3c
#define PictOpHSLColor 0x3d
#define PictOpHSLLuminosity 0x3e
#define PictOpBlendMaximum 0x3e
 
#define PolyEdgeSharp 0
#define PolyEdgeSmooth 1
 
#define PolyModePrecise 0
#define PolyModeImprecise 1
 
#define CPRepeat (1 << 0)
#define CPAlphaMap (1 << 1)
#define CPAlphaXOrigin (1 << 2)
#define CPAlphaYOrigin (1 << 3)
#define CPClipXOrigin (1 << 4)
#define CPClipYOrigin (1 << 5)
#define CPClipMask (1 << 6)
#define CPGraphicsExposure (1 << 7)
#define CPSubwindowMode (1 << 8)
#define CPPolyEdge (1 << 9)
#define CPPolyMode (1 << 10)
#define CPDither (1 << 11)
#define CPComponentAlpha (1 << 12)
#define CPLastBit 12
 
/* Filters included in 0.6 */
#define FilterNearest "nearest"
#define FilterBilinear "bilinear"
/* Filters included in 0.10 */
#define FilterConvolution "convolution"
 
#define FilterFast "fast"
#define FilterGood "good"
#define FilterBest "best"
 
#define FilterAliasNone -1
 
/* Subpixel orders included in 0.6 */
#define SubPixelUnknown 0
#define SubPixelHorizontalRGB 1
#define SubPixelHorizontalBGR 2
#define SubPixelVerticalRGB 3
#define SubPixelVerticalBGR 4
#define SubPixelNone 5
 
/* Extended repeat attributes included in 0.10 */
#define RepeatNone 0
#define RepeatNormal 1
#define RepeatPad 2
#define RepeatReflect 3
 
 
 
/* Copied from X11/extensions/Xrender.h */
 
typedef struct {
short red;
short redMask;
short green;
short greenMask;
short blue;
short blueMask;
short alpha;
short alphaMask;
} XRenderDirectFormat;
 
typedef struct {
PictFormat id;
int type;
int depth;
XRenderDirectFormat direct;
Colormap colormap;
} XRenderPictFormat;
 
#define PictFormatID (1 << 0)
#define PictFormatType (1 << 1)
#define PictFormatDepth (1 << 2)
#define PictFormatRed (1 << 3)
#define PictFormatRedMask (1 << 4)
#define PictFormatGreen (1 << 5)
#define PictFormatGreenMask (1 << 6)
#define PictFormatBlue (1 << 7)
#define PictFormatBlueMask (1 << 8)
#define PictFormatAlpha (1 << 9)
#define PictFormatAlphaMask (1 << 10)
#define PictFormatColormap (1 << 11)
 
typedef struct _XRenderPictureAttributes {
int repeat;
Picture alpha_map;
int alpha_x_origin;
int alpha_y_origin;
int clip_x_origin;
int clip_y_origin;
Pixmap clip_mask;
Bool graphics_exposures;
int subwindow_mode;
int poly_edge;
int poly_mode;
Atom dither;
Bool component_alpha;
} XRenderPictureAttributes;
 
typedef struct {
unsigned short red;
unsigned short green;
unsigned short blue;
unsigned short alpha;
} XRenderColor;
 
typedef struct _XGlyphInfo {
unsigned short width;
unsigned short height;
short x;
short y;
short xOff;
short yOff;
} XGlyphInfo;
 
typedef struct _XGlyphElt8 {
GlyphSet glyphset;
_Xconst char *chars;
int nchars;
int xOff;
int yOff;
} XGlyphElt8;
 
typedef struct _XGlyphElt16 {
GlyphSet glyphset;
_Xconst unsigned short *chars;
int nchars;
int xOff;
int yOff;
} XGlyphElt16;
 
typedef struct _XGlyphElt32 {
GlyphSet glyphset;
_Xconst unsigned int *chars;
int nchars;
int xOff;
int yOff;
} XGlyphElt32;
 
typedef double XDouble;
 
typedef struct _XPointDouble {
XDouble x, y;
} XPointDouble;
 
#define XDoubleToFixed(f) ((XFixed) ((f) * 65536))
#define XFixedToDouble(f) (((XDouble) (f)) / 65536)
 
typedef int XFixed;
 
typedef struct _XPointFixed {
XFixed x, y;
} XPointFixed;
 
typedef struct _XLineFixed {
XPointFixed p1, p2;
} XLineFixed;
 
typedef struct _XTriangle {
XPointFixed p1, p2, p3;
} XTriangle;
 
typedef struct _XCircle {
XFixed x;
XFixed y;
XFixed radius;
} XCircle;
 
typedef struct _XTrapezoid {
XFixed top, bottom;
XLineFixed left, right;
} XTrapezoid;
 
typedef struct _XTransform {
XFixed matrix[3][3];
} XTransform;
 
typedef struct _XFilters {
int nfilter;
char **filter;
int nalias;
short *alias;
} XFilters;
 
typedef struct _XIndexValue {
unsigned long pixel;
unsigned short red, green, blue, alpha;
} XIndexValue;
 
typedef struct _XAnimCursor {
Cursor cursor;
unsigned long delay;
} XAnimCursor;
 
typedef struct _XSpanFix {
XFixed left, right, y;
} XSpanFix;
 
typedef struct _XTrap {
XSpanFix top, bottom;
} XTrap;
 
typedef struct _XLinearGradient {
XPointFixed p1;
XPointFixed p2;
} XLinearGradient;
 
typedef struct _XRadialGradient {
XCircle inner;
XCircle outer;
} XRadialGradient;
 
typedef struct _XConicalGradient {
XPointFixed center;
XFixed angle; /* in degrees */
} XConicalGradient;
 
#define PictStandardARGB32 0
#define PictStandardRGB24 1
#define PictStandardA8 2
#define PictStandardA4 3
#define PictStandardA1 4
#define PictStandardNUM 5
 
 
 
/* Copied from X11/extensions/renderproto.h */
 
#include <X11/Xmd.h>
 
#define Window CARD32
#define Drawable CARD32
#define Font CARD32
#define Pixmap CARD32
#define Cursor CARD32
#define Colormap CARD32
#define GContext CARD32
#define Atom CARD32
#define VisualID CARD32
#define Time CARD32
#define KeyCode CARD8
#define KeySym CARD32
 
#define Picture CARD32
#define PictFormat CARD32
#define Fixed INT32
#define Glyphset CARD32
#define Glyph CARD32
 
/*
* data structures
*/
 
typedef struct {
CARD16 red B16;
CARD16 redMask B16;
CARD16 green B16;
CARD16 greenMask B16;
CARD16 blue B16;
CARD16 blueMask B16;
CARD16 alpha B16;
CARD16 alphaMask B16;
} xDirectFormat;
 
#define sz_xDirectFormat 16
 
typedef struct {
PictFormat id B32;
CARD8 type;
CARD8 depth;
CARD16 pad1 B16;
xDirectFormat direct;
Colormap colormap;
} xPictFormInfo;
 
#define sz_xPictFormInfo 28
 
typedef struct {
VisualID visual;
PictFormat format;
} xPictVisual;
 
#define sz_xPictVisual 8
 
typedef struct {
CARD8 depth;
CARD8 pad1;
CARD16 nPictVisuals B16;
CARD32 pad2 B32;
} xPictDepth;
 
#define sz_xPictDepth 8
 
typedef struct {
CARD32 nDepth B32;
PictFormat fallback B32;
} xPictScreen;
 
#define sz_xPictScreen 8
 
typedef struct {
CARD32 pixel B32;
CARD16 red B16;
CARD16 green B16;
CARD16 blue B16;
CARD16 alpha B16;
} xIndexValue;
 
#define sz_xIndexValue 12
 
typedef struct {
CARD16 red B16;
CARD16 green B16;
CARD16 blue B16;
CARD16 alpha B16;
} xRenderColor;
 
#define sz_xRenderColor 8
 
typedef struct {
Fixed x B32;
Fixed y B32;
} xPointFixed;
 
#define sz_xPointFixed 8
 
typedef struct {
xPointFixed p1;
xPointFixed p2;
} xLineFixed;
 
#define sz_xLineFixed 16
 
typedef struct {
xPointFixed p1, p2, p3;
} xTriangle;
 
#define sz_xTriangle 24
 
typedef struct {
Fixed top B32;
Fixed bottom B32;
xLineFixed left;
xLineFixed right;
} xTrapezoid;
 
#define sz_xTrapezoid 40
 
typedef struct {
CARD16 width B16;
CARD16 height B16;
INT16 x B16;
INT16 y B16;
INT16 xOff B16;
INT16 yOff B16;
} xGlyphInfo;
 
#define sz_xGlyphInfo 12
 
typedef struct {
CARD8 len;
CARD8 pad1;
CARD16 pad2;
INT16 deltax;
INT16 deltay;
} xGlyphElt;
 
#define sz_xGlyphElt 8
 
typedef struct {
Fixed l, r, y;
} xSpanFix;
 
#define sz_xSpanFix 12
 
typedef struct {
xSpanFix top, bot;
} xTrap;
 
#define sz_xTrap 24
 
/*
* requests and replies
*/
typedef struct {
CARD8 reqType;
CARD8 renderReqType;
CARD16 length B16;
CARD32 majorVersion B32;
CARD32 minorVersion B32;
} xRenderQueryVersionReq;
 
#define sz_xRenderQueryVersionReq 12
 
typedef struct {
BYTE type; /* X_Reply */
BYTE pad1;
CARD16 sequenceNumber B16;
CARD32 length B32;
CARD32 majorVersion B32;
CARD32 minorVersion B32;
CARD32 pad2 B32;
CARD32 pad3 B32;
CARD32 pad4 B32;
CARD32 pad5 B32;
} xRenderQueryVersionReply;
 
#define sz_xRenderQueryVersionReply 32
 
typedef struct {
CARD8 reqType;
CARD8 renderReqType;
CARD16 length B16;
} xRenderQueryPictFormatsReq;
 
#define sz_xRenderQueryPictFormatsReq 4
 
typedef struct {
BYTE type; /* X_Reply */
BYTE pad1;
CARD16 sequenceNumber B16;
CARD32 length B32;
CARD32 numFormats B32;
CARD32 numScreens B32;
CARD32 numDepths B32;
CARD32 numVisuals B32;
CARD32 numSubpixel B32; /* Version 0.6 */
CARD32 pad5 B32;
} xRenderQueryPictFormatsReply;
 
#define sz_xRenderQueryPictFormatsReply 32
 
typedef struct {
CARD8 reqType;
CARD8 renderReqType;
CARD16 length B16;
PictFormat format B32;
} xRenderQueryPictIndexValuesReq;
 
#define sz_xRenderQueryPictIndexValuesReq 8
 
typedef struct {
BYTE type; /* X_Reply */
BYTE pad1;
CARD16 sequenceNumber B16;
CARD32 length B32;
CARD32 numIndexValues;
CARD32 pad2 B32;
CARD32 pad3 B32;
CARD32 pad4 B32;
CARD32 pad5 B32;
CARD32 pad6 B32;
} xRenderQueryPictIndexValuesReply;
 
#define sz_xRenderQueryPictIndexValuesReply 32
 
typedef struct {
CARD8 reqType;
CARD8 renderReqType;
CARD16 length B16;
Picture pid B32;
Drawable drawable B32;
PictFormat format B32;
CARD32 mask B32;
} xRenderCreatePictureReq;
 
#define sz_xRenderCreatePictureReq 20
 
typedef struct {
CARD8 reqType;
CARD8 renderReqType;
CARD16 length B16;
Picture picture B32;
CARD32 mask B32;
} xRenderChangePictureReq;
 
#define sz_xRenderChangePictureReq 12
 
typedef struct {
CARD8 reqType;
CARD8 renderReqType;
CARD16 length B16;
Picture picture B32;
INT16 xOrigin B16;
INT16 yOrigin B16;
} xRenderSetPictureClipRectanglesReq;
 
#define sz_xRenderSetPictureClipRectanglesReq 12
 
typedef struct {
CARD8 reqType;
CARD8 renderReqType;
CARD16 length B16;
Picture picture B32;
} xRenderFreePictureReq;
 
#define sz_xRenderFreePictureReq 8
 
typedef struct {
CARD8 reqType;
CARD8 renderReqType;
CARD16 length B16;
CARD8 op;
CARD8 pad1;
CARD16 pad2 B16;
Picture src B32;
Picture mask B32;
Picture dst B32;
INT16 xSrc B16;
INT16 ySrc B16;
INT16 xMask B16;
INT16 yMask B16;
INT16 xDst B16;
INT16 yDst B16;
CARD16 width B16;
CARD16 height B16;
} xRenderCompositeReq;
 
#define sz_xRenderCompositeReq 36
 
typedef struct {
CARD8 reqType;
CARD8 renderReqType;
CARD16 length B16;
Picture src B32;
Picture dst B32;
CARD32 colorScale B32;
CARD32 alphaScale B32;
INT16 xSrc B16;
INT16 ySrc B16;
INT16 xDst B16;
INT16 yDst B16;
CARD16 width B16;
CARD16 height B16;
} xRenderScaleReq;
 
#define sz_xRenderScaleReq 32
 
typedef struct {
CARD8 reqType;
CARD8 renderReqType;
CARD16 length B16;
CARD8 op;
CARD8 pad1;
CARD16 pad2 B16;
Picture src B32;
Picture dst B32;
PictFormat maskFormat B32;
INT16 xSrc B16;
INT16 ySrc B16;
} xRenderTrapezoidsReq;
 
#define sz_xRenderTrapezoidsReq 24
 
typedef struct {
CARD8 reqType;
CARD8 renderReqType;
CARD16 length B16;
CARD8 op;
CARD8 pad1;
CARD16 pad2 B16;
Picture src B32;
Picture dst B32;
PictFormat maskFormat B32;
INT16 xSrc B16;
INT16 ySrc B16;
} xRenderTrianglesReq;
 
#define sz_xRenderTrianglesReq 24
 
typedef struct {
CARD8 reqType;
CARD8 renderReqType;
CARD16 length B16;
CARD8 op;
CARD8 pad1;
CARD16 pad2 B16;
Picture src B32;
Picture dst B32;
PictFormat maskFormat B32;
INT16 xSrc B16;
INT16 ySrc B16;
} xRenderTriStripReq;
 
#define sz_xRenderTriStripReq 24
 
typedef struct {
CARD8 reqType;
CARD8 renderReqType;
CARD16 length B16;
CARD8 op;
CARD8 pad1;
CARD16 pad2 B16;
Picture src B32;
Picture dst B32;
PictFormat maskFormat B32;
INT16 xSrc B16;
INT16 ySrc B16;
} xRenderTriFanReq;
 
#define sz_xRenderTriFanReq 24
 
typedef struct {
CARD8 reqType;
CARD8 renderReqType;
CARD16 length B16;
Glyphset gsid B32;
PictFormat format B32;
} xRenderCreateGlyphSetReq;
 
#define sz_xRenderCreateGlyphSetReq 12
 
typedef struct {
CARD8 reqType;
CARD8 renderReqType;
CARD16 length B16;
Glyphset gsid B32;
Glyphset existing B32;
} xRenderReferenceGlyphSetReq;
 
#define sz_xRenderReferenceGlyphSetReq 24
 
typedef struct {
CARD8 reqType;
CARD8 renderReqType;
CARD16 length B16;
Glyphset glyphset B32;
} xRenderFreeGlyphSetReq;
 
#define sz_xRenderFreeGlyphSetReq 8
 
typedef struct {
CARD8 reqType;
CARD8 renderReqType;
CARD16 length B16;
Glyphset glyphset B32;
CARD32 nglyphs;
} xRenderAddGlyphsReq;
 
#define sz_xRenderAddGlyphsReq 12
 
typedef struct {
CARD8 reqType;
CARD8 renderReqType;
CARD16 length B16;
Glyphset glyphset B32;
} xRenderFreeGlyphsReq;
 
#define sz_xRenderFreeGlyphsReq 8
 
typedef struct {
CARD8 reqType;
CARD8 renderReqType;
CARD16 length B16;
CARD8 op;
CARD8 pad1;
CARD16 pad2 B16;
Picture src B32;
Picture dst B32;
PictFormat maskFormat B32;
Glyphset glyphset B32;
INT16 xSrc B16;
INT16 ySrc B16;
} xRenderCompositeGlyphsReq, xRenderCompositeGlyphs8Req,
xRenderCompositeGlyphs16Req, xRenderCompositeGlyphs32Req;
 
#define sz_xRenderCompositeGlyphs8Req 28
#define sz_xRenderCompositeGlyphs16Req 28
#define sz_xRenderCompositeGlyphs32Req 28
 
/* 0.1 and higher */
 
typedef struct {
CARD8 reqType;
CARD8 renderReqType;
CARD16 length B16;
CARD8 op;
CARD8 pad1;
CARD16 pad2 B16;
Picture dst B32;
xRenderColor color;
} xRenderFillRectanglesReq;
 
#define sz_xRenderFillRectanglesReq 20
 
/* 0.5 and higher */
 
typedef struct {
CARD8 reqType;
CARD8 renderReqType;
CARD16 length B16;
Cursor cid B32;
Picture src B32;
CARD16 x B16;
CARD16 y B16;
} xRenderCreateCursorReq;
 
#define sz_xRenderCreateCursorReq 16
 
/* 0.6 and higher */
 
/*
* This can't use an array because 32-bit values may be in bitfields
*/
typedef struct {
Fixed matrix11 B32;
Fixed matrix12 B32;
Fixed matrix13 B32;
Fixed matrix21 B32;
Fixed matrix22 B32;
Fixed matrix23 B32;
Fixed matrix31 B32;
Fixed matrix32 B32;
Fixed matrix33 B32;
} xRenderTransform;
 
#define sz_xRenderTransform 36
 
typedef struct {
CARD8 reqType;
CARD8 renderReqType;
CARD16 length B16;
Picture picture B32;
xRenderTransform transform;
} xRenderSetPictureTransformReq;
 
#define sz_xRenderSetPictureTransformReq 44
 
typedef struct {
CARD8 reqType;
CARD8 renderReqType;
CARD16 length B16;
Drawable drawable B32;
} xRenderQueryFiltersReq;
 
#define sz_xRenderQueryFiltersReq 8
 
typedef struct {
BYTE type; /* X_Reply */
BYTE pad1;
CARD16 sequenceNumber B16;
CARD32 length B32;
CARD32 numAliases B32; /* LISTofCARD16 */
CARD32 numFilters B32; /* LISTofSTRING8 */
CARD32 pad2 B32;
CARD32 pad3 B32;
CARD32 pad4 B32;
CARD32 pad5 B32;
} xRenderQueryFiltersReply;
 
#define sz_xRenderQueryFiltersReply 32
 
typedef struct {
CARD8 reqType;
CARD8 renderReqType;
CARD16 length B16;
Picture picture B32;
CARD16 nbytes B16; /* number of bytes in name */
CARD16 pad B16;
} xRenderSetPictureFilterReq;
 
#define sz_xRenderSetPictureFilterReq 12
 
/* 0.8 and higher */
 
typedef struct {
Cursor cursor B32;
CARD32 delay B32;
} xAnimCursorElt;
 
#define sz_xAnimCursorElt 8
 
typedef struct {
CARD8 reqType;
CARD8 renderReqType;
CARD16 length B16;
Cursor cid B32;
} xRenderCreateAnimCursorReq;
 
#define sz_xRenderCreateAnimCursorReq 8
 
/* 0.9 and higher */
 
typedef struct {
CARD8 reqType;
CARD8 renderReqType;
CARD16 length B16;
Picture picture;
INT16 xOff B16;
INT16 yOff B16;
} xRenderAddTrapsReq;
 
#define sz_xRenderAddTrapsReq 12
 
/* 0.10 and higher */
 
typedef struct {
CARD8 reqType;
CARD8 renderReqType;
CARD16 length B16;
Picture pid B32;
xRenderColor color;
} xRenderCreateSolidFillReq;
 
#define sz_xRenderCreateSolidFillReq 16
 
typedef struct {
CARD8 reqType;
CARD8 renderReqType;
CARD16 length B16;
Picture pid B32;
xPointFixed p1;
xPointFixed p2;
CARD32 nStops;
} xRenderCreateLinearGradientReq;
 
#define sz_xRenderCreateLinearGradientReq 28
 
typedef struct {
CARD8 reqType;
CARD8 renderReqType;
CARD16 length B16;
Picture pid B32;
xPointFixed inner;
xPointFixed outer;
Fixed inner_radius;
Fixed outer_radius;
CARD32 nStops;
} xRenderCreateRadialGradientReq;
 
#define sz_xRenderCreateRadialGradientReq 36
 
typedef struct {
CARD8 reqType;
CARD8 renderReqType;
CARD16 length B16;
Picture pid B32;
xPointFixed center;
Fixed angle; /* in degrees */
CARD32 nStops;
} xRenderCreateConicalGradientReq;
 
#define sz_xRenderCreateConicalGradientReq 24
 
#undef Window
#undef Drawable
#undef Font
#undef Pixmap
#undef Cursor
#undef Colormap
#undef GContext
#undef Atom
#undef VisualID
#undef Time
#undef KeyCode
#undef KeySym
 
#undef Picture
#undef PictFormat
#undef Fixed
#undef Glyphset
#undef Glyph
 
 
#endif /* CAIRO_HAS_XLIB_XRENDER_SURFACE */
 
#endif /* CAIRO_XLIB_XRENDER_PRIVATE_H */
/programs/develop/libraries/cairo/src/cairo-xlib-xrender.h
0,0 → 1,66
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2002 University of Southern California
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
*/
 
#ifndef CAIRO_XLIB_XRENDER_H
#define CAIRO_XLIB_XRENDER_H
 
#include "cairo.h"
 
#if CAIRO_HAS_XLIB_XRENDER_SURFACE
 
#include <X11/Xlib.h>
#include <X11/extensions/Xrender.h>
 
CAIRO_BEGIN_DECLS
 
cairo_public cairo_surface_t *
cairo_xlib_surface_create_with_xrender_format (Display *dpy,
Drawable drawable,
Screen *screen,
XRenderPictFormat *format,
int width,
int height);
 
cairo_public XRenderPictFormat *
cairo_xlib_surface_get_xrender_format (cairo_surface_t *surface);
 
CAIRO_END_DECLS
 
#else /* CAIRO_HAS_XLIB_XRENDER_SURFACE */
# error Cairo was not compiled with support for the xlib XRender backend
#endif /* CAIRO_HAS_XLIB_XRENDER_SURFACE */
 
#endif /* CAIRO_XLIB_XRENDER_H */
/programs/develop/libraries/cairo/src/cairo-xlib.h
0,0 → 1,100
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2002 University of Southern California
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
*/
 
#ifndef CAIRO_XLIB_H
#define CAIRO_XLIB_H
 
#include "cairo.h"
 
#if CAIRO_HAS_XLIB_SURFACE
 
#include <X11/Xlib.h>
 
CAIRO_BEGIN_DECLS
 
cairo_public cairo_surface_t *
cairo_xlib_surface_create (Display *dpy,
Drawable drawable,
Visual *visual,
int width,
int height);
 
cairo_public cairo_surface_t *
cairo_xlib_surface_create_for_bitmap (Display *dpy,
Pixmap bitmap,
Screen *screen,
int width,
int height);
 
cairo_public void
cairo_xlib_surface_set_size (cairo_surface_t *surface,
int width,
int height);
 
cairo_public void
cairo_xlib_surface_set_drawable (cairo_surface_t *surface,
Drawable drawable,
int width,
int height);
 
cairo_public Display *
cairo_xlib_surface_get_display (cairo_surface_t *surface);
 
cairo_public Drawable
cairo_xlib_surface_get_drawable (cairo_surface_t *surface);
 
cairo_public Screen *
cairo_xlib_surface_get_screen (cairo_surface_t *surface);
 
cairo_public Visual *
cairo_xlib_surface_get_visual (cairo_surface_t *surface);
 
cairo_public int
cairo_xlib_surface_get_depth (cairo_surface_t *surface);
 
cairo_public int
cairo_xlib_surface_get_width (cairo_surface_t *surface);
 
cairo_public int
cairo_xlib_surface_get_height (cairo_surface_t *surface);
 
CAIRO_END_DECLS
 
#else /* CAIRO_HAS_XLIB_SURFACE */
# error Cairo was not compiled with support for the xlib backend
#endif /* CAIRO_HAS_XLIB_SURFACE */
 
#endif /* CAIRO_XLIB_H */
/programs/develop/libraries/cairo/src/cairo-xml.h
0,0 → 1,67
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2009 Chris Wilson
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Chris Wilson
*
* Contributor(s):
* Chris Wilson <chris@chris-wilson.co.uk>
*/
 
#ifndef CAIRO_XML_H
#define CAIRO_XML_H
 
#include "cairo.h"
 
#if CAIRO_HAS_XML_SURFACE
 
CAIRO_BEGIN_DECLS
 
cairo_public cairo_device_t *
cairo_xml_create (const char *filename);
 
cairo_public cairo_device_t *
cairo_xml_create_for_stream (cairo_write_func_t write_func,
void *closure);
 
cairo_public cairo_surface_t *
cairo_xml_surface_create (cairo_device_t *xml,
cairo_content_t content,
double width, double height);
 
cairo_public cairo_status_t
cairo_xml_for_recording_surface (cairo_device_t *xml,
cairo_surface_t *surface);
 
CAIRO_END_DECLS
 
#else /*CAIRO_HAS_XML_SURFACE*/
# error Cairo was not compiled with support for the XML backend
#endif /*CAIRO_HAS_XML_SURFACE*/
 
#endif /*CAIRO_XML_H*/
/programs/develop/libraries/cairo/src/cairo.c
0,0 → 1,4173
/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
/* 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., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
*/
 
#include "cairoint.h"
#include "cairo-private.h"
 
#include "cairo-arc-private.h"
#include "cairo-error-private.h"
#include "cairo-path-private.h"
 
/**
* SECTION:cairo
* @Title: cairo_t
* @Short_Description: The cairo drawing context
* @See_Also: #cairo_surface_t
*
* #cairo_t is the main object used when drawing with cairo. To
* draw with cairo, you create a #cairo_t, set the target surface,
* and drawing options for the #cairo_t, create shapes with
* functions like cairo_move_to() and cairo_line_to(), and then
* draw shapes with cairo_stroke() or cairo_fill().
*
* #cairo_t<!-- -->'s can be pushed to a stack via cairo_save().
* They may then safely be changed, without loosing the current state.
* Use cairo_restore() to restore to the saved state.
*/
 
/**
* SECTION:cairo-text
* @Title: text
* @Short_Description: Rendering text and glyphs
* @See_Also: #cairo_font_face_t, #cairo_scaled_font_t, cairo_text_path(),
* cairo_glyph_path()
*
* The functions with <emphasis>text</emphasis> in their name form cairo's
* <firstterm>toy</firstterm> text API. The toy API takes UTF-8 encoded
* text and is limited in its functionality to rendering simple
* left-to-right text with no advanced features. That means for example
* that most complex scripts like Hebrew, Arabic, and Indic scripts are
* out of question. No kerning or correct positioning of diacritical marks
* either. The font selection is pretty limited too and doesn't handle the
* case that the selected font does not cover the characters in the text.
* This set of functions are really that, a toy text API, for testing and
* demonstration purposes. Any serious application should avoid them.
*
* The functions with <emphasis>glyphs</emphasis> in their name form cairo's
* <firstterm>low-level</firstterm> text API. The low-level API relies on
* the user to convert text to a set of glyph indexes and positions. This
* is a very hard problem and is best handled by external libraries, like
* the pangocairo that is part of the Pango text layout and rendering library.
* Pango is available from <ulink
* url="http://www.pango.org/">http://www.pango.org/</ulink>.
*/
 
/**
* SECTION:cairo-transforms
* @Title: Transformations
* @Short_Description: Manipulating the current transformation matrix
* @See_Also: #cairo_matrix_t
*
* The current transformation matrix, <firstterm>ctm</firstterm>, is a
* two-dimensional affine transformation that maps all coordinates and other
* drawing instruments from the <firstterm>user space</firstterm> into the
* surface's canonical coordinate system, also known as the <firstterm>device
* space</firstterm>.
*/
 
#define CAIRO_TOLERANCE_MINIMUM _cairo_fixed_to_double(1)
 
#if !defined(INFINITY)
#define INFINITY HUGE_VAL
#endif
 
static const cairo_t _cairo_nil = {
CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */
CAIRO_STATUS_NO_MEMORY, /* status */
{ 0, 0, 0, NULL }, /* user_data */
NULL, /* gstate */
{{ 0 }, { 0 }}, /* gstate_tail */
NULL, /* gstate_freelist */
{{ /* path */
{ 0, 0 }, /* last_move_point */
{ 0, 0 }, /* current point */
FALSE, /* has_current_point */
FALSE, /* has_last_move_point */
FALSE, /* has_curve_to */
FALSE, /* is_box */
FALSE, /* maybe_fill_region */
TRUE, /* is_empty_fill */
{ {0, 0}, {0, 0}}, /* extents */
{{{NULL,NULL}}} /* link */
}}
};
 
static const cairo_t _cairo_nil__null_pointer = {
CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */
CAIRO_STATUS_NULL_POINTER, /* status */
{ 0, 0, 0, NULL }, /* user_data */
NULL, /* gstate */
{{ 0 }, { 0 }}, /* gstate_tail */
NULL, /* gstate_freelist */
{{ /* path */
{ 0, 0 }, /* last_move_point */
{ 0, 0 }, /* current point */
FALSE, /* has_current_point */
FALSE, /* has_last_move_point */
FALSE, /* has_curve_to */
FALSE, /* is_box */
FALSE, /* maybe_fill_region */
TRUE, /* is_empty_fill */
{ {0, 0}, {0, 0}}, /* extents */
{{{NULL,NULL}}} /* link */
}}
};
#include <assert.h>
 
/**
* _cairo_error:
* @status: a status value indicating an error, (eg. not
* %CAIRO_STATUS_SUCCESS)
*
* Checks that status is an error status, but does nothing else.
*
* All assignments of an error status to any user-visible object
* within the cairo application should result in a call to
* _cairo_error().
*
* 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
* user causes cairo to detect an error.
*
* Return value: the error status.
**/
cairo_status_t
_cairo_error (cairo_status_t status)
{
CAIRO_ENSURE_UNIQUE;
assert (_cairo_status_is_error (status));
 
return status;
}
 
/**
* _cairo_set_error:
* @cr: a cairo context
* @status: a status value indicating an error
*
* Atomically sets cr->status to @status and calls _cairo_error;
* Does nothing if status is %CAIRO_STATUS_SUCCESS.
*
* All assignments of an error status to cr->status should happen
* through _cairo_set_error(). Note that due to the nature of 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
* breakpoint in _cairo_error() to generate a stack trace for when the
* user causes cairo to detect an error.
**/
static void
_cairo_set_error (cairo_t *cr, cairo_status_t status)
{
/* Don't overwrite an existing error. This preserves the first
* error, which is the most significant. */
_cairo_status_set_error (&cr->status, _cairo_error (status));
}
 
/* We keep a small stash of contexts to reduce malloc pressure */
#define CAIRO_STASH_SIZE 4
#if CAIRO_NO_MUTEX
static struct {
cairo_t pool[CAIRO_STASH_SIZE];
int occupied;
} _context_stash;
 
static cairo_t *
_context_get (void)
{
int avail;
 
avail = ffs (~_context_stash.occupied) - 1;
if (avail >= CAIRO_STASH_SIZE)
return malloc (sizeof (cairo_t));
 
_context_stash.occupied |= 1 << avail;
return &_context_stash.pool[avail];
}
 
static void
_context_put (cairo_t *cr)
{
if (cr < &_context_stash.pool[0] ||
cr >= &_context_stash.pool[CAIRO_STASH_SIZE])
{
free (cr);
return;
}
 
_context_stash.occupied &= ~(1 << (cr - &_context_stash.pool[0]));
}
#elif HAS_ATOMIC_OPS
static struct {
cairo_t pool[CAIRO_STASH_SIZE];
cairo_atomic_int_t occupied;
} _context_stash;
 
static cairo_t *
_context_get (void)
{
cairo_atomic_int_t avail, old, new;
 
do {
old = _cairo_atomic_int_get (&_context_stash.occupied);
avail = ffs (~old) - 1;
if (avail >= CAIRO_STASH_SIZE)
return malloc (sizeof (cairo_t));
 
new = old | (1 << avail);
} while (! _cairo_atomic_int_cmpxchg (&_context_stash.occupied, old, new));
 
return &_context_stash.pool[avail];
}
 
static void
_context_put (cairo_t *cr)
{
cairo_atomic_int_t old, new, avail;
 
if (cr < &_context_stash.pool[0] ||
cr >= &_context_stash.pool[CAIRO_STASH_SIZE])
{
free (cr);
return;
}
 
avail = ~(1 << (cr - &_context_stash.pool[0]));
do {
old = _cairo_atomic_int_get (&_context_stash.occupied);
new = old & avail;
} while (! _cairo_atomic_int_cmpxchg (&_context_stash.occupied, old, new));
}
#else
#define _context_get() malloc (sizeof (cairo_t))
#define _context_put(cr) free (cr)
#endif
 
/* XXX This should disappear in favour of a common pool of error objects. */
static cairo_t *_cairo_nil__objects[CAIRO_STATUS_LAST_STATUS + 1];
 
static cairo_t *
_cairo_create_in_error (cairo_status_t status)
{
cairo_t *cr;
 
assert (status != CAIRO_STATUS_SUCCESS);
 
/* special case OOM in order to avoid another allocation */
switch ((int) status) {
case CAIRO_STATUS_NO_MEMORY:
return (cairo_t *) &_cairo_nil;
case CAIRO_STATUS_NULL_POINTER:
return (cairo_t *) &_cairo_nil__null_pointer;
}
 
CAIRO_MUTEX_LOCK (_cairo_error_mutex);
cr = _cairo_nil__objects[status];
if (cr == NULL) {
cr = malloc (sizeof (cairo_t));
if (unlikely (cr == NULL)) {
CAIRO_MUTEX_UNLOCK (_cairo_error_mutex);
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_t *) &_cairo_nil;
}
 
*cr = _cairo_nil;
cr->status = status;
_cairo_nil__objects[status] = cr;
}
CAIRO_MUTEX_UNLOCK (_cairo_error_mutex);
 
return cr;
}
 
void
_cairo_reset_static_data (void)
{
int status;
 
CAIRO_MUTEX_LOCK (_cairo_error_mutex);
for (status = CAIRO_STATUS_SUCCESS;
status <= CAIRO_STATUS_LAST_STATUS;
status++)
{
if (_cairo_nil__objects[status] != NULL) {
free (_cairo_nil__objects[status]);
_cairo_nil__objects[status] = NULL;
}
}
CAIRO_MUTEX_UNLOCK (_cairo_error_mutex);
}
 
/**
* cairo_create:
* @target: target surface for the context
*
* Creates a new #cairo_t with all graphics state parameters set to
* default values and with @target as a target surface. The target
* surface should be constructed with a backend-specific function such
* as cairo_image_surface_create() (or any other
* cairo_<emphasis>backend</emphasis>_surface_create() variant).
*
* This function references @target, so you can immediately
* call cairo_surface_destroy() on it if you don't need to
* maintain a separate reference to it.
*
* Return value: a newly allocated #cairo_t with a reference
* count of 1. The initial reference count should be released
* with cairo_destroy() when you are done using the #cairo_t.
* This function never returns %NULL. If memory cannot be
* allocated, a special #cairo_t object will be returned on
* which cairo_status() returns %CAIRO_STATUS_NO_MEMORY.
* You can use this object normally, but no drawing will
* be done.
**/
cairo_t *
cairo_create (cairo_surface_t *target)
{
cairo_t *cr;
cairo_status_t status;
 
if (unlikely (target == NULL))
return _cairo_create_in_error (_cairo_error (CAIRO_STATUS_NULL_POINTER));
if (unlikely (target->status))
return _cairo_create_in_error (target->status);
 
cr = _context_get ();
if (unlikely (cr == NULL))
return _cairo_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
 
CAIRO_REFERENCE_COUNT_INIT (&cr->ref_count, 1);
 
cr->status = CAIRO_STATUS_SUCCESS;
 
_cairo_user_data_array_init (&cr->user_data);
_cairo_path_fixed_init (cr->path);
 
cr->gstate = &cr->gstate_tail[0];
cr->gstate_freelist = &cr->gstate_tail[1];
cr->gstate_tail[1].next = NULL;
 
status = _cairo_gstate_init (cr->gstate, target);
if (unlikely (status)) {
_context_put (cr);
cr = _cairo_create_in_error (status);
}
 
return cr;
}
slim_hidden_def (cairo_create);
 
/**
* cairo_reference:
* @cr: a #cairo_t
*
* Increases the reference count on @cr by one. This prevents
* @cr from being destroyed until a matching call to cairo_destroy()
* is made.
*
* The number of references to a #cairo_t can be get using
* cairo_get_reference_count().
*
* Return value: the referenced #cairo_t.
**/
cairo_t *
cairo_reference (cairo_t *cr)
{
if (cr == NULL || CAIRO_REFERENCE_COUNT_IS_INVALID (&cr->ref_count))
return cr;
 
assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&cr->ref_count));
 
_cairo_reference_count_inc (&cr->ref_count);
 
return cr;
}
 
/**
* cairo_destroy:
* @cr: a #cairo_t
*
* Decreases the reference count on @cr by one. If the result
* is zero, then @cr and all associated resources are freed.
* See cairo_reference().
**/
void
cairo_destroy (cairo_t *cr)
{
if (cr == NULL || CAIRO_REFERENCE_COUNT_IS_INVALID (&cr->ref_count))
return;
 
assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&cr->ref_count));
 
if (! _cairo_reference_count_dec_and_test (&cr->ref_count))
return;
 
while (cr->gstate != &cr->gstate_tail[0]) {
if (_cairo_gstate_restore (&cr->gstate, &cr->gstate_freelist))
break;
}
 
_cairo_gstate_fini (cr->gstate);
cr->gstate_freelist = cr->gstate_freelist->next; /* skip over tail[1] */
while (cr->gstate_freelist != NULL) {
cairo_gstate_t *gstate = cr->gstate_freelist;
cr->gstate_freelist = gstate->next;
free (gstate);
}
 
_cairo_path_fixed_fini (cr->path);
 
_cairo_user_data_array_fini (&cr->user_data);
 
/* mark the context as invalid to protect against misuse */
cr->status = CAIRO_STATUS_NULL_POINTER;
 
_context_put (cr);
}
slim_hidden_def (cairo_destroy);
 
/**
* cairo_get_user_data:
* @cr: a #cairo_t
* @key: the address of the #cairo_user_data_key_t the user data was
* attached to
*
* Return user data previously attached to @cr using the specified
* key. If no user data has been attached with the given key this
* function returns %NULL.
*
* Return value: the user data previously attached or %NULL.
*
* Since: 1.4
**/
void *
cairo_get_user_data (cairo_t *cr,
const cairo_user_data_key_t *key)
{
return _cairo_user_data_array_get_data (&cr->user_data,
key);
}
 
/**
* cairo_set_user_data:
* @cr: a #cairo_t
* @key: the address of a #cairo_user_data_key_t to attach the user data to
* @user_data: the user data to attach to the #cairo_t
* @destroy: a #cairo_destroy_func_t which will be called when the
* #cairo_t is destroyed or when new user data is attached using the
* same key.
*
* Attach user data to @cr. To remove user data from a surface,
* call this function with the key that was used to set it and %NULL
* for @data.
*
* Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY if a
* slot could not be allocated for the user data.
*
* Since: 1.4
**/
cairo_status_t
cairo_set_user_data (cairo_t *cr,
const cairo_user_data_key_t *key,
void *user_data,
cairo_destroy_func_t destroy)
{
if (CAIRO_REFERENCE_COUNT_IS_INVALID (&cr->ref_count))
return cr->status;
 
return _cairo_user_data_array_set_data (&cr->user_data,
key, user_data, destroy);
}
 
/**
* cairo_get_reference_count:
* @cr: a #cairo_t
*
* Returns the current reference count of @cr.
*
* Return value: the current reference count of @cr. If the
* object is a nil object, 0 will be returned.
*
* Since: 1.4
**/
unsigned int
cairo_get_reference_count (cairo_t *cr)
{
if (cr == NULL || CAIRO_REFERENCE_COUNT_IS_INVALID (&cr->ref_count))
return 0;
 
return CAIRO_REFERENCE_COUNT_GET_VALUE (&cr->ref_count);
}
 
/**
* cairo_save:
* @cr: a #cairo_t
*
* Makes a copy of the current state of @cr and saves it
* on an internal stack of saved states for @cr. When
* cairo_restore() is called, @cr will be restored to
* the saved state. Multiple calls to cairo_save() and
* cairo_restore() can be nested; each call to cairo_restore()
* restores the state from the matching paired cairo_save().
*
* It isn't necessary to clear all saved states before
* a #cairo_t is freed. If the reference count of a #cairo_t
* drops to zero in response to a call to cairo_destroy(),
* any saved states will be freed along with the #cairo_t.
**/
void
cairo_save (cairo_t *cr)
{
cairo_status_t status;
 
if (unlikely (cr->status))
return;
 
status = _cairo_gstate_save (&cr->gstate, &cr->gstate_freelist);
if (unlikely (status))
_cairo_set_error (cr, status);
}
slim_hidden_def(cairo_save);
 
/**
* cairo_restore:
* @cr: a #cairo_t
*
* Restores @cr to the state saved by a preceding call to
* cairo_save() and removes that state from the stack of
* saved states.
**/
void
cairo_restore (cairo_t *cr)
{
cairo_status_t status;
 
if (unlikely (cr->status))
return;
 
status = _cairo_gstate_restore (&cr->gstate, &cr->gstate_freelist);
if (unlikely (status))
_cairo_set_error (cr, status);
}
slim_hidden_def(cairo_restore);
 
/**
* cairo_push_group:
* @cr: a cairo context
*
* Temporarily redirects drawing to an intermediate surface known as a
* group. The redirection lasts until the group is completed by a call
* to cairo_pop_group() or cairo_pop_group_to_source(). These calls
* provide the result of any drawing to the group as a pattern,
* (either as an explicit object, or set as the source pattern).
*
* This group functionality can be convenient for performing
* intermediate compositing. One common use of a group is to render
* objects as opaque within the group, (so that they occlude each
* other), and then blend the result with translucence onto the
* destination.
*
* Groups can be nested arbitrarily deep by making balanced calls to
* cairo_push_group()/cairo_pop_group(). Each call pushes/pops the new
* target group onto/from a stack.
*
* The cairo_push_group() function calls cairo_save() so that any
* changes to the graphics state will not be visible outside the
* group, (the pop_group functions call cairo_restore()).
*
* By default the intermediate group will have a content type of
* %CAIRO_CONTENT_COLOR_ALPHA. Other content types can be chosen for
* the group by using cairo_push_group_with_content() instead.
*
* As an example, here is how one might fill and stroke a path with
* translucence, but without any portion of the fill being visible
* under the stroke:
*
* <informalexample><programlisting>
* cairo_push_group (cr);
* cairo_set_source (cr, fill_pattern);
* cairo_fill_preserve (cr);
* cairo_set_source (cr, stroke_pattern);
* cairo_stroke (cr);
* cairo_pop_group_to_source (cr);
* cairo_paint_with_alpha (cr, alpha);
* </programlisting></informalexample>
*
* Since: 1.2
*/
void
cairo_push_group (cairo_t *cr)
{
cairo_push_group_with_content (cr, CAIRO_CONTENT_COLOR_ALPHA);
}
 
/**
* cairo_push_group_with_content:
* @cr: a cairo context
* @content: a #cairo_content_t indicating the type of group that
* will be created
*
* Temporarily redirects drawing to an intermediate surface known as a
* group. The redirection lasts until the group is completed by a call
* to cairo_pop_group() or cairo_pop_group_to_source(). These calls
* provide the result of any drawing to the group as a pattern,
* (either as an explicit object, or set as the source pattern).
*
* The group will have a content type of @content. The ability to
* control this content type is the only distinction between this
* function and cairo_push_group() which you should see for a more
* detailed description of group rendering.
*
* Since: 1.2
*/
void
cairo_push_group_with_content (cairo_t *cr, cairo_content_t content)
{
cairo_surface_t *group_surface;
cairo_clip_t *clip;
cairo_status_t status;
 
if (unlikely (cr->status))
return;
 
clip = _cairo_gstate_get_clip (cr->gstate);
if (clip->all_clipped) {
group_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 0, 0);
status = group_surface->status;
if (unlikely (status))
goto bail;
} else {
cairo_surface_t *parent_surface;
const cairo_rectangle_int_t *clip_extents;
cairo_rectangle_int_t extents;
cairo_matrix_t matrix;
cairo_bool_t is_empty;
 
parent_surface = _cairo_gstate_get_target (cr->gstate);
 
/* Get the extents that we'll use in creating our new group surface */
is_empty = _cairo_surface_get_extents (parent_surface, &extents);
clip_extents = _cairo_clip_get_extents (_cairo_gstate_get_clip (cr->gstate));
if (clip_extents != NULL)
is_empty = _cairo_rectangle_intersect (&extents, clip_extents);
 
group_surface = _cairo_surface_create_similar_solid (parent_surface,
content,
extents.width,
extents.height,
CAIRO_COLOR_TRANSPARENT,
TRUE);
status = group_surface->status;
if (unlikely (status))
goto bail;
 
/* Set device offsets on the new surface so that logically it appears at
* the same location on the parent surface -- when we pop_group this,
* the source pattern will get fixed up for the appropriate target surface
* device offsets, so we want to set our own surface offsets from /that/,
* and not from the device origin. */
cairo_surface_set_device_offset (group_surface,
parent_surface->device_transform.x0 - extents.x,
parent_surface->device_transform.y0 - extents.y);
 
/* If we have a current path, we need to adjust it to compensate for
* the device offset just applied. */
cairo_matrix_init_translate (&matrix, -extents.x, -extents.y);
_cairo_path_fixed_transform (cr->path, &matrix);
}
 
/* create a new gstate for the redirect */
cairo_save (cr);
if (unlikely (cr->status))
goto bail;
 
status = _cairo_gstate_redirect_target (cr->gstate, group_surface);
 
bail:
cairo_surface_destroy (group_surface);
if (unlikely (status))
_cairo_set_error (cr, status);
}
slim_hidden_def(cairo_push_group_with_content);
 
/**
* cairo_pop_group:
* @cr: a cairo context
*
* Terminates the redirection begun by a call to cairo_push_group() or
* cairo_push_group_with_content() and returns a new pattern
* containing the results of all drawing operations performed to the
* group.
*
* The cairo_pop_group() function calls cairo_restore(), (balancing a
* call to cairo_save() by the push_group function), so that any
* changes to the graphics state will not be visible outside the
* group.
*
* Return value: a newly created (surface) pattern containing the
* results of all drawing operations performed to the group. The
* caller owns the returned object and should call
* cairo_pattern_destroy() when finished with it.
*
* Since: 1.2
**/
cairo_pattern_t *
cairo_pop_group (cairo_t *cr)
{
cairo_surface_t *group_surface, *parent_target;
cairo_pattern_t *group_pattern;
cairo_matrix_t group_matrix, device_transform_matrix;
cairo_status_t status;
 
if (unlikely (cr->status))
return _cairo_pattern_create_in_error (cr->status);
 
/* Grab the active surfaces */
group_surface = _cairo_gstate_get_target (cr->gstate);
parent_target = _cairo_gstate_get_parent_target (cr->gstate);
 
/* Verify that we are at the right nesting level */
if (parent_target == NULL) {
_cairo_set_error (cr, CAIRO_STATUS_INVALID_POP_GROUP);
return _cairo_pattern_create_in_error (CAIRO_STATUS_INVALID_POP_GROUP);
}
 
/* We need to save group_surface before we restore; we don't need
* to reference parent_target and original_target, since the
* gstate will still hold refs to them once we restore. */
group_surface = cairo_surface_reference (group_surface);
 
cairo_restore (cr);
 
if (unlikely (cr->status)) {
group_pattern = _cairo_pattern_create_in_error (cr->status);
goto done;
}
 
group_pattern = cairo_pattern_create_for_surface (group_surface);
status = group_pattern->status;
if (unlikely (status)) {
_cairo_set_error (cr, status);
goto done;
}
 
_cairo_gstate_get_matrix (cr->gstate, &group_matrix);
/* Transform by group_matrix centered around device_transform so that when
* we call _cairo_gstate_copy_transformed_pattern the result is a pattern
* with a matrix equivalent to the device_transform of group_surface. */
if (_cairo_surface_has_device_transform (group_surface)) {
cairo_pattern_set_matrix (group_pattern, &group_surface->device_transform);
_cairo_pattern_transform (group_pattern, &group_matrix);
_cairo_pattern_transform (group_pattern, &group_surface->device_transform_inverse);
} else {
cairo_pattern_set_matrix (group_pattern, &group_matrix);
}
 
/* If we have a current path, we need to adjust it to compensate for
* the device offset just removed. */
cairo_matrix_multiply (&device_transform_matrix,
&_cairo_gstate_get_target (cr->gstate)->device_transform,
&group_surface->device_transform_inverse);
_cairo_path_fixed_transform (cr->path, &device_transform_matrix);
 
done:
cairo_surface_destroy (group_surface);
 
return group_pattern;
}
slim_hidden_def(cairo_pop_group);
 
/**
* cairo_pop_group_to_source:
* @cr: a cairo context
*
* Terminates the redirection begun by a call to cairo_push_group() or
* cairo_push_group_with_content() and installs the resulting pattern
* as the source pattern in the given cairo context.
*
* The behavior of this function is equivalent to the sequence of
* operations:
*
* <informalexample><programlisting>
* #cairo_pattern_t *group = cairo_pop_group (cr);
* cairo_set_source (cr, group);
* cairo_pattern_destroy (group);
* </programlisting></informalexample>
*
* but is more convenient as their is no need for a variable to store
* the short-lived pointer to the pattern.
*
* The cairo_pop_group() function calls cairo_restore(), (balancing a
* call to cairo_save() by the push_group function), so that any
* changes to the graphics state will not be visible outside the
* group.
*
* Since: 1.2
**/
void
cairo_pop_group_to_source (cairo_t *cr)
{
cairo_pattern_t *group_pattern;
 
group_pattern = cairo_pop_group (cr);
cairo_set_source (cr, group_pattern);
cairo_pattern_destroy (group_pattern);
}
 
/**
* cairo_set_operator:
* @cr: a #cairo_t
* @op: a compositing operator, specified as a #cairo_operator_t
*
* Sets the compositing operator to be used for all drawing
* operations. See #cairo_operator_t for details on the semantics of
* each available compositing operator.
*
* The default operator is %CAIRO_OPERATOR_OVER.
**/
void
cairo_set_operator (cairo_t *cr, cairo_operator_t op)
{
cairo_status_t status;
 
if (unlikely (cr->status))
return;
 
status = _cairo_gstate_set_operator (cr->gstate, op);
if (unlikely (status))
_cairo_set_error (cr, status);
}
slim_hidden_def (cairo_set_operator);
 
 
static cairo_bool_t
_current_source_matches_solid (cairo_t *cr,
double red,
double green,
double blue,
double alpha)
{
const cairo_pattern_t *current;
cairo_color_t color;
 
current = cr->gstate->source;
if (current->type != CAIRO_PATTERN_TYPE_SOLID)
return FALSE;
 
red = _cairo_restrict_value (red, 0.0, 1.0);
green = _cairo_restrict_value (green, 0.0, 1.0);
blue = _cairo_restrict_value (blue, 0.0, 1.0);
alpha = _cairo_restrict_value (alpha, 0.0, 1.0);
 
_cairo_color_init_rgba (&color, red, green, blue, alpha);
return _cairo_color_equal (&color,
&((cairo_solid_pattern_t *) current)->color);
}
/**
* cairo_set_source_rgb
* @cr: a cairo context
* @red: red component of color
* @green: green component of color
* @blue: blue component of color
*
* Sets the source pattern within @cr to an opaque color. This opaque
* color will then be used for any subsequent drawing operation until
* a new source pattern is set.
*
* The color components are floating point numbers in the range 0 to
* 1. If the values passed in are outside that range, they will be
* clamped.
*
* The default source pattern is opaque black, (that is, it is
* equivalent to cairo_set_source_rgb(cr, 0.0, 0.0, 0.0)).
**/
void
cairo_set_source_rgb (cairo_t *cr, double red, double green, double blue)
{
cairo_pattern_t *pattern;
 
if (unlikely (cr->status))
return;
 
if (_current_source_matches_solid (cr, red, green, blue, 1.))
return;
 
/* push the current pattern to the freed lists */
cairo_set_source (cr, (cairo_pattern_t *) &_cairo_pattern_black);
 
pattern = cairo_pattern_create_rgb (red, green, blue);
cairo_set_source (cr, pattern);
cairo_pattern_destroy (pattern);
}
slim_hidden_def (cairo_set_source_rgb);
 
/**
* cairo_set_source_rgba:
* @cr: a cairo context
* @red: red component of color
* @green: green component of color
* @blue: blue component of color
* @alpha: alpha component of color
*
* Sets the source pattern within @cr to a translucent color. This
* color will then be used for any subsequent drawing operation until
* a new source pattern is set.
*
* The color and alpha components are floating point numbers in the
* range 0 to 1. If the values passed in are outside that range, they
* will be clamped.
*
* The default source pattern is opaque black, (that is, it is
* equivalent to cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 1.0)).
**/
void
cairo_set_source_rgba (cairo_t *cr,
double red, double green, double blue,
double alpha)
{
cairo_pattern_t *pattern;
 
if (unlikely (cr->status))
return;
 
if (_current_source_matches_solid (cr, red, green, blue, alpha))
return;
 
/* push the current pattern to the freed lists */
cairo_set_source (cr, (cairo_pattern_t *) &_cairo_pattern_black);
 
pattern = cairo_pattern_create_rgba (red, green, blue, alpha);
cairo_set_source (cr, pattern);
cairo_pattern_destroy (pattern);
}
 
/**
* cairo_set_source_surface:
* @cr: a cairo context
* @surface: a surface to be used to set the source pattern
* @x: User-space X coordinate for surface origin
* @y: User-space Y coordinate for surface origin
*
* This is a convenience function for creating a pattern from @surface
* and setting it as the source in @cr with cairo_set_source().
*
* The @x and @y parameters give the user-space coordinate at which
* the surface origin should appear. (The surface origin is its
* upper-left corner before any transformation has been applied.) The
* @x and @y parameters are negated and then set as translation values
* in the pattern matrix.
*
* Other than the initial translation pattern matrix, as described
* above, all other pattern attributes, (such as its extend mode), are
* set to the default values as in cairo_pattern_create_for_surface().
* The resulting pattern can be queried with cairo_get_source() so
* that these attributes can be modified if desired, (eg. to create a
* repeating pattern with cairo_pattern_set_extend()).
**/
void
cairo_set_source_surface (cairo_t *cr,
cairo_surface_t *surface,
double x,
double y)
{
cairo_pattern_t *pattern;
cairo_matrix_t matrix;
 
if (unlikely (cr->status))
return;
 
/* push the current pattern to the freed lists */
cairo_set_source (cr, (cairo_pattern_t *) &_cairo_pattern_black);
 
pattern = cairo_pattern_create_for_surface (surface);
 
cairo_matrix_init_translate (&matrix, -x, -y);
cairo_pattern_set_matrix (pattern, &matrix);
 
cairo_set_source (cr, pattern);
cairo_pattern_destroy (pattern);
}
slim_hidden_def (cairo_set_source_surface);
 
/**
* cairo_set_source
* @cr: a cairo context
* @source: a #cairo_pattern_t to be used as the source for
* subsequent drawing operations.
*
* Sets the source pattern within @cr to @source. This pattern
* will then be used for any subsequent drawing operation until a new
* source pattern is set.
*
* Note: The pattern's transformation matrix will be locked to the
* user space in effect at the time of cairo_set_source(). This means
* that further modifications of the current transformation matrix
* will not affect the source pattern. See cairo_pattern_set_matrix().
*
* The default source pattern is a solid pattern that is opaque black,
* (that is, it is equivalent to cairo_set_source_rgb(cr, 0.0, 0.0,
* 0.0)).
**/
void
cairo_set_source (cairo_t *cr, cairo_pattern_t *source)
{
cairo_status_t status;
 
if (unlikely (cr->status))
return;
 
if (source == NULL) {
_cairo_set_error (cr, CAIRO_STATUS_NULL_POINTER);
return;
}
 
if (source->status) {
_cairo_set_error (cr, source->status);
return;
}
 
status = _cairo_gstate_set_source (cr->gstate, source);
if (unlikely (status))
_cairo_set_error (cr, status);
}
slim_hidden_def (cairo_set_source);
 
/**
* cairo_get_source:
* @cr: a cairo context
*
* Gets the current source pattern for @cr.
*
* Return value: the current source pattern. This object is owned by
* cairo. To keep a reference to it, you must call
* cairo_pattern_reference().
**/
cairo_pattern_t *
cairo_get_source (cairo_t *cr)
{
if (unlikely (cr->status))
return _cairo_pattern_create_in_error (cr->status);
 
return _cairo_gstate_get_source (cr->gstate);
}
 
/**
* cairo_set_tolerance:
* @cr: a #cairo_t
* @tolerance: the tolerance, in device units (typically pixels)
*
* Sets the tolerance used when converting paths into trapezoids.
* Curved segments of the path will be subdivided until the maximum
* deviation between the original path and the polygonal approximation
* is less than @tolerance. The default value is 0.1. A larger
* value will give better performance, a smaller value, better
* appearance. (Reducing the value from the default value of 0.1
* is unlikely to improve appearance significantly.) The accuracy of paths
* within Cairo is limited by the precision of its internal arithmetic, and
* the prescribed @tolerance is restricted to the smallest
* representable internal value.
**/
void
cairo_set_tolerance (cairo_t *cr, double tolerance)
{
cairo_status_t status;
 
if (unlikely (cr->status))
return;
 
if (tolerance < CAIRO_TOLERANCE_MINIMUM)
tolerance = CAIRO_TOLERANCE_MINIMUM;
 
status = _cairo_gstate_set_tolerance (cr->gstate, tolerance);
if (unlikely (status))
_cairo_set_error (cr, status);
}
slim_hidden_def (cairo_set_tolerance);
 
/**
* cairo_set_antialias:
* @cr: a #cairo_t
* @antialias: the new antialiasing mode
*
* Set the antialiasing mode of the rasterizer used for drawing shapes.
* This value is a hint, and a particular backend may or may not support
* a particular value. At the current time, no backend supports
* %CAIRO_ANTIALIAS_SUBPIXEL when drawing shapes.
*
* Note that this option does not affect text rendering, instead see
* cairo_font_options_set_antialias().
**/
void
cairo_set_antialias (cairo_t *cr, cairo_antialias_t antialias)
{
cairo_status_t status;
 
if (unlikely (cr->status))
return;
 
status = _cairo_gstate_set_antialias (cr->gstate, antialias);
if (unlikely (status))
_cairo_set_error (cr, status);
}
 
/**
* cairo_set_fill_rule:
* @cr: a #cairo_t
* @fill_rule: a fill rule, specified as a #cairo_fill_rule_t
*
* Set the current fill rule within the cairo context. The fill rule
* is used to determine which regions are inside or outside a complex
* (potentially self-intersecting) path. The current fill rule affects
* both cairo_fill() and cairo_clip(). See #cairo_fill_rule_t for details
* on the semantics of each available fill rule.
*
* The default fill rule is %CAIRO_FILL_RULE_WINDING.
**/
void
cairo_set_fill_rule (cairo_t *cr, cairo_fill_rule_t fill_rule)
{
cairo_status_t status;
 
if (unlikely (cr->status))
return;
 
status = _cairo_gstate_set_fill_rule (cr->gstate, fill_rule);
if (unlikely (status))
_cairo_set_error (cr, status);
}
 
/**
* cairo_set_line_width:
* @cr: a #cairo_t
* @width: a line width
*
* Sets the current line width within the cairo context. The line
* width value specifies the diameter of a pen that is circular in
* user space, (though device-space pen may be an ellipse in general
* due to scaling/shear/rotation of the CTM).
*
* Note: When the description above refers to user space and CTM it
* refers to the user space and CTM in effect at the time of the
* stroking operation, not the user space and CTM in effect at the
* time of the call to cairo_set_line_width(). The simplest usage
* makes both of these spaces identical. That is, if there is no
* change to the CTM between a call to cairo_set_line_width() and the
* stroking operation, then one can just pass user-space values to
* cairo_set_line_width() and ignore this note.
*
* As with the other stroke parameters, the current line width is
* examined by cairo_stroke(), cairo_stroke_extents(), and
* cairo_stroke_to_path(), but does not have any effect during path
* construction.
*
* The default line width value is 2.0.
**/
void
cairo_set_line_width (cairo_t *cr, double width)
{
cairo_status_t status;
 
if (unlikely (cr->status))
return;
 
if (width < 0.)
width = 0.;
 
status = _cairo_gstate_set_line_width (cr->gstate, width);
if (unlikely (status))
_cairo_set_error (cr, status);
}
slim_hidden_def (cairo_set_line_width);
 
/**
* cairo_set_line_cap:
* @cr: a cairo context
* @line_cap: a line cap style
*
* Sets the current line cap style within the cairo context. See
* #cairo_line_cap_t for details about how the available line cap
* styles are drawn.
*
* As with the other stroke parameters, the current line cap style is
* examined by cairo_stroke(), cairo_stroke_extents(), and
* cairo_stroke_to_path(), but does not have any effect during path
* construction.
*
* The default line cap style is %CAIRO_LINE_CAP_BUTT.
**/
void
cairo_set_line_cap (cairo_t *cr, cairo_line_cap_t line_cap)
{
cairo_status_t status;
 
if (unlikely (cr->status))
return;
 
status = _cairo_gstate_set_line_cap (cr->gstate, line_cap);
if (unlikely (status))
_cairo_set_error (cr, status);
}
slim_hidden_def (cairo_set_line_cap);
 
/**
* cairo_set_line_join:
* @cr: a cairo context
* @line_join: a line join style
*
* Sets the current line join style within the cairo context. See
* #cairo_line_join_t for details about how the available line join
* styles are drawn.
*
* As with the other stroke parameters, the current line join style is
* examined by cairo_stroke(), cairo_stroke_extents(), and
* cairo_stroke_to_path(), but does not have any effect during path
* construction.
*
* The default line join style is %CAIRO_LINE_JOIN_MITER.
**/
void
cairo_set_line_join (cairo_t *cr, cairo_line_join_t line_join)
{
cairo_status_t status;
 
if (unlikely (cr->status))
return;
 
status = _cairo_gstate_set_line_join (cr->gstate, line_join);
if (unlikely (status))
_cairo_set_error (cr, status);
}
slim_hidden_def (cairo_set_line_join);
 
/**
* cairo_set_dash:
* @cr: a cairo context
* @dashes: an array specifying alternate lengths of on and off stroke portions
* @num_dashes: the length of the dashes array
* @offset: an offset into the dash pattern at which the stroke should start
*
* Sets the dash pattern to be used by cairo_stroke(). A dash pattern
* is specified by @dashes, an array of positive values. Each value
* provides the length of alternate "on" and "off" portions of the
* stroke. The @offset specifies an offset into the pattern at which
* the stroke begins.
*
* Each "on" segment will have caps applied as if the segment were a
* separate sub-path. In particular, it is valid to use an "on" length
* of 0.0 with %CAIRO_LINE_CAP_ROUND or %CAIRO_LINE_CAP_SQUARE in order
* to distributed dots or squares along a path.
*
* Note: The length values are in user-space units as evaluated at the
* time of stroking. This is not necessarily the same as the user
* space at the time of cairo_set_dash().
*
* If @num_dashes is 0 dashing is disabled.
*
* If @num_dashes is 1 a symmetric pattern is assumed with alternating
* on and off portions of the size specified by the single value in
* @dashes.
*
* If any value in @dashes is negative, or if all values are 0, then
* @cr will be put into an error state with a status of
* %CAIRO_STATUS_INVALID_DASH.
**/
void
cairo_set_dash (cairo_t *cr,
const double *dashes,
int num_dashes,
double offset)
{
cairo_status_t status;
 
if (unlikely (cr->status))
return;
 
status = _cairo_gstate_set_dash (cr->gstate,
dashes, num_dashes, offset);
if (unlikely (status))
_cairo_set_error (cr, status);
}
 
/**
* cairo_get_dash_count:
* @cr: a #cairo_t
*
* This function returns the length of the dash array in @cr (0 if dashing
* is not currently in effect).
*
* See also cairo_set_dash() and cairo_get_dash().
*
* Return value: the length of the dash array, or 0 if no dash array set.
*
* Since: 1.4
*/
int
cairo_get_dash_count (cairo_t *cr)
{
int num_dashes;
 
if (unlikely (cr->status))
return 0;
 
_cairo_gstate_get_dash (cr->gstate, NULL, &num_dashes, NULL);
 
return num_dashes;
}
 
/**
* cairo_get_dash:
* @cr: a #cairo_t
* @dashes: return value for the dash array, or %NULL
* @offset: return value for the current dash offset, or %NULL
*
* Gets the current dash array. If not %NULL, @dashes should be big
* enough to hold at least the number of values returned by
* cairo_get_dash_count().
*
* Since: 1.4
**/
void
cairo_get_dash (cairo_t *cr,
double *dashes,
double *offset)
{
if (unlikely (cr->status))
return;
 
_cairo_gstate_get_dash (cr->gstate, dashes, NULL, offset);
}
 
/**
* cairo_set_miter_limit:
* @cr: a cairo context
* @limit: miter limit to set
*
* Sets the current miter limit within the cairo context.
*
* If the current line join style is set to %CAIRO_LINE_JOIN_MITER
* (see cairo_set_line_join()), the miter limit is used to determine
* whether the lines should be joined with a bevel instead of a miter.
* Cairo divides the length of the miter by the line width.
* If the result is greater than the miter limit, the style is
* converted to a bevel.
*
* As with the other stroke parameters, the current line miter limit is
* examined by cairo_stroke(), cairo_stroke_extents(), and
* cairo_stroke_to_path(), but does not have any effect during path
* construction.
*
* The default miter limit value is 10.0, which will convert joins
* with interior angles less than 11 degrees to bevels instead of
* miters. For reference, a miter limit of 2.0 makes the miter cutoff
* at 60 degrees, and a miter limit of 1.414 makes the cutoff at 90
* degrees.
*
* A miter limit for a desired angle can be computed as: miter limit =
* 1/sin(angle/2)
**/
void
cairo_set_miter_limit (cairo_t *cr, double limit)
{
cairo_status_t status;
 
if (unlikely (cr->status))
return;
 
status = _cairo_gstate_set_miter_limit (cr->gstate, limit);
if (unlikely (status))
_cairo_set_error (cr, status);
}
 
/**
* cairo_translate:
* @cr: a cairo context
* @tx: amount to translate in the X direction
* @ty: amount to translate in the Y direction
*
* Modifies the current transformation matrix (CTM) by translating the
* user-space origin by (@tx, @ty). This offset is interpreted as a
* user-space coordinate according to the CTM in place before the new
* call to cairo_translate(). In other words, the translation of the
* user-space origin takes place after any existing transformation.
**/
void
cairo_translate (cairo_t *cr, double tx, double ty)
{
cairo_status_t status;
 
if (unlikely (cr->status))
return;
 
status = _cairo_gstate_translate (cr->gstate, tx, ty);
if (unlikely (status))
_cairo_set_error (cr, status);
}
slim_hidden_def (cairo_translate);
 
/**
* cairo_scale:
* @cr: a cairo context
* @sx: scale factor for the X dimension
* @sy: scale factor for the Y dimension
*
* Modifies the current transformation matrix (CTM) by scaling the X
* and Y user-space axes by @sx and @sy respectively. The scaling of
* the axes takes place after any existing transformation of user
* space.
**/
void
cairo_scale (cairo_t *cr, double sx, double sy)
{
cairo_status_t status;
 
if (unlikely (cr->status))
return;
 
status = _cairo_gstate_scale (cr->gstate, sx, sy);
if (unlikely (status))
_cairo_set_error (cr, status);
}
slim_hidden_def (cairo_scale);
 
/**
* cairo_rotate:
* @cr: a cairo context
* @angle: angle (in radians) by which the user-space axes will be
* rotated
*
* Modifies the current transformation matrix (CTM) by rotating the
* user-space axes by @angle radians. The rotation of the axes takes
* places after any existing transformation of user space. The
* rotation direction for positive angles is from the positive X axis
* toward the positive Y axis.
**/
void
cairo_rotate (cairo_t *cr, double angle)
{
cairo_status_t status;
 
if (unlikely (cr->status))
return;
 
status = _cairo_gstate_rotate (cr->gstate, angle);
if (unlikely (status))
_cairo_set_error (cr, status);
}
 
/**
* cairo_transform:
* @cr: a cairo context
* @matrix: a transformation to be applied to the user-space axes
*
* Modifies the current transformation matrix (CTM) by applying
* @matrix as an additional transformation. The new transformation of
* user space takes place after any existing transformation.
**/
void
cairo_transform (cairo_t *cr,
const cairo_matrix_t *matrix)
{
cairo_status_t status;
 
if (unlikely (cr->status))
return;
 
status = _cairo_gstate_transform (cr->gstate, matrix);
if (unlikely (status))
_cairo_set_error (cr, status);
}
slim_hidden_def (cairo_transform);
 
/**
* cairo_set_matrix:
* @cr: a cairo context
* @matrix: a transformation matrix from user space to device space
*
* Modifies the current transformation matrix (CTM) by setting it
* equal to @matrix.
**/
void
cairo_set_matrix (cairo_t *cr,
const cairo_matrix_t *matrix)
{
cairo_status_t status;
 
if (unlikely (cr->status))
return;
 
status = _cairo_gstate_set_matrix (cr->gstate, matrix);
if (unlikely (status))
_cairo_set_error (cr, status);
}
slim_hidden_def (cairo_set_matrix);
 
/**
* cairo_identity_matrix:
* @cr: a cairo context
*
* Resets the current transformation matrix (CTM) by setting it equal
* to the identity matrix. That is, the user-space and device-space
* axes will be aligned and one user-space unit will transform to one
* device-space unit.
**/
void
cairo_identity_matrix (cairo_t *cr)
{
if (unlikely (cr->status))
return;
 
_cairo_gstate_identity_matrix (cr->gstate);
}
 
/**
* cairo_user_to_device:
* @cr: a cairo context
* @x: X value of coordinate (in/out parameter)
* @y: Y value of coordinate (in/out parameter)
*
* Transform a coordinate from user space to device space by
* multiplying the given point by the current transformation matrix
* (CTM).
**/
void
cairo_user_to_device (cairo_t *cr, double *x, double *y)
{
if (unlikely (cr->status))
return;
 
_cairo_gstate_user_to_device (cr->gstate, x, y);
}
slim_hidden_def (cairo_user_to_device);
 
/**
* cairo_user_to_device_distance:
* @cr: a cairo context
* @dx: X component of a distance vector (in/out parameter)
* @dy: Y component of a distance vector (in/out parameter)
*
* Transform a distance vector from user space to device space. This
* function is similar to cairo_user_to_device() except that the
* translation components of the CTM will be ignored when transforming
* (@dx,@dy).
**/
void
cairo_user_to_device_distance (cairo_t *cr, double *dx, double *dy)
{
if (unlikely (cr->status))
return;
 
_cairo_gstate_user_to_device_distance (cr->gstate, dx, dy);
}
slim_hidden_def (cairo_user_to_device_distance);
 
/**
* cairo_device_to_user:
* @cr: a cairo
* @x: X value of coordinate (in/out parameter)
* @y: Y value of coordinate (in/out parameter)
*
* Transform a coordinate from device space to user space by
* multiplying the given point by the inverse of the current
* transformation matrix (CTM).
**/
void
cairo_device_to_user (cairo_t *cr, double *x, double *y)
{
if (unlikely (cr->status))
return;
 
_cairo_gstate_device_to_user (cr->gstate, x, y);
}
 
/**
* cairo_device_to_user_distance:
* @cr: a cairo context
* @dx: X component of a distance vector (in/out parameter)
* @dy: Y component of a distance vector (in/out parameter)
*
* Transform a distance vector from device space to user space. This
* function is similar to cairo_device_to_user() except that the
* translation components of the inverse CTM will be ignored when
* transforming (@dx,@dy).
**/
void
cairo_device_to_user_distance (cairo_t *cr, double *dx, double *dy)
{
if (unlikely (cr->status))
return;
 
_cairo_gstate_device_to_user_distance (cr->gstate, dx, dy);
}
 
/**
* cairo_new_path:
* @cr: a cairo context
*
* Clears the current path. After this call there will be no path and
* no current point.
**/
void
cairo_new_path (cairo_t *cr)
{
if (unlikely (cr->status))
return;
 
_cairo_path_fixed_fini (cr->path);
_cairo_path_fixed_init (cr->path);
}
slim_hidden_def(cairo_new_path);
 
/**
* cairo_move_to:
* @cr: a cairo context
* @x: the X coordinate of the new position
* @y: the Y coordinate of the new position
*
* Begin a new sub-path. After this call the current point will be (@x,
* @y).
**/
void
cairo_move_to (cairo_t *cr, double x, double y)
{
cairo_status_t status;
cairo_fixed_t x_fixed, y_fixed;
 
if (unlikely (cr->status))
return;
 
_cairo_gstate_user_to_backend (cr->gstate, &x, &y);
x_fixed = _cairo_fixed_from_double (x);
y_fixed = _cairo_fixed_from_double (y);
 
status = _cairo_path_fixed_move_to (cr->path, x_fixed, y_fixed);
if (unlikely (status))
_cairo_set_error (cr, status);
}
slim_hidden_def(cairo_move_to);
 
/**
* cairo_new_sub_path:
* @cr: a cairo context
*
* Begin a new sub-path. Note that the existing path is not
* affected. After this call there will be no current point.
*
* In many cases, this call is not needed since new sub-paths are
* frequently started with cairo_move_to().
*
* A call to cairo_new_sub_path() is particularly useful when
* beginning a new sub-path with one of the cairo_arc() calls. This
* makes things easier as it is no longer necessary to manually
* compute the arc's initial coordinates for a call to
* cairo_move_to().
*
* Since: 1.2
**/
void
cairo_new_sub_path (cairo_t *cr)
{
if (unlikely (cr->status))
return;
 
_cairo_path_fixed_new_sub_path (cr->path);
}
 
/**
* cairo_line_to:
* @cr: a cairo context
* @x: the X coordinate of the end of the new line
* @y: the Y coordinate of the end of the new line
*
* Adds a line to the path from the current point to position (@x, @y)
* in user-space coordinates. After this call the current point
* will be (@x, @y).
*
* If there is no current point before the call to cairo_line_to()
* this function will behave as cairo_move_to(@cr, @x, @y).
**/
void
cairo_line_to (cairo_t *cr, double x, double y)
{
cairo_status_t status;
cairo_fixed_t x_fixed, y_fixed;
 
if (unlikely (cr->status))
return;
 
_cairo_gstate_user_to_backend (cr->gstate, &x, &y);
x_fixed = _cairo_fixed_from_double (x);
y_fixed = _cairo_fixed_from_double (y);
 
status = _cairo_path_fixed_line_to (cr->path, x_fixed, y_fixed);
if (unlikely (status))
_cairo_set_error (cr, status);
}
slim_hidden_def (cairo_line_to);
 
/**
* cairo_curve_to:
* @cr: a cairo context
* @x1: the X coordinate of the first control point
* @y1: the Y coordinate of the first control point
* @x2: the X coordinate of the second control point
* @y2: the Y coordinate of the second control point
* @x3: the X coordinate of the end of the curve
* @y3: the Y coordinate of the end of the curve
*
* Adds a cubic Bézier spline to the path from the current point to
* position (@x3, @y3) in user-space coordinates, using (@x1, @y1) and
* (@x2, @y2) as the control points. After this call the current point
* will be (@x3, @y3).
*
* If there is no current point before the call to cairo_curve_to()
* this function will behave as if preceded by a call to
* cairo_move_to(@cr, @x1, @y1).
**/
void
cairo_curve_to (cairo_t *cr,
double x1, double y1,
double x2, double y2,
double x3, double y3)
{
cairo_status_t status;
cairo_fixed_t x1_fixed, y1_fixed;
cairo_fixed_t x2_fixed, y2_fixed;
cairo_fixed_t x3_fixed, y3_fixed;
 
if (unlikely (cr->status))
return;
 
_cairo_gstate_user_to_backend (cr->gstate, &x1, &y1);
_cairo_gstate_user_to_backend (cr->gstate, &x2, &y2);
_cairo_gstate_user_to_backend (cr->gstate, &x3, &y3);
 
x1_fixed = _cairo_fixed_from_double (x1);
y1_fixed = _cairo_fixed_from_double (y1);
 
x2_fixed = _cairo_fixed_from_double (x2);
y2_fixed = _cairo_fixed_from_double (y2);
 
x3_fixed = _cairo_fixed_from_double (x3);
y3_fixed = _cairo_fixed_from_double (y3);
 
status = _cairo_path_fixed_curve_to (cr->path,
x1_fixed, y1_fixed,
x2_fixed, y2_fixed,
x3_fixed, y3_fixed);
if (unlikely (status))
_cairo_set_error (cr, status);
}
slim_hidden_def (cairo_curve_to);
 
/**
* cairo_arc:
* @cr: a cairo context
* @xc: X position of the center of the arc
* @yc: Y position of the center of the arc
* @radius: the radius of the arc
* @angle1: the start angle, in radians
* @angle2: the end angle, in radians
*
* Adds a circular arc of the given @radius to the current path. The
* arc is centered at (@xc, @yc), begins at @angle1 and proceeds in
* the direction of increasing angles to end at @angle2. If @angle2 is
* less than @angle1 it will be progressively increased by 2*M_PI
* until it is greater than @angle1.
*
* 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
* 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
* of the positive X axis (in user space). An angle of %M_PI/2.0 radians
* (90 degrees) is in the direction of the positive Y axis (in
* user space). Angles increase in the direction from the positive X
* axis toward the positive Y axis. So with the default transformation
* matrix, angles increase in a clockwise direction.
*
* (To convert from degrees to radians, use <literal>degrees * (M_PI /
* 180.)</literal>.)
*
* This function gives the arc in the direction of increasing angles;
* see cairo_arc_negative() to get the arc in the direction of
* decreasing angles.
*
* The arc is circular in user space. To achieve an elliptical arc,
* you can scale the current transformation matrix by different
* amounts in the X and Y directions. For example, to draw an ellipse
* in the box given by @x, @y, @width, @height:
*
* <informalexample><programlisting>
* cairo_save (cr);
* cairo_translate (cr, x + width / 2., y + height / 2.);
* cairo_scale (cr, width / 2., height / 2.);
* cairo_arc (cr, 0., 0., 1., 0., 2 * M_PI);
* cairo_restore (cr);
* </programlisting></informalexample>
**/
void
cairo_arc (cairo_t *cr,
double xc, double yc,
double radius,
double angle1, double angle2)
{
if (unlikely (cr->status))
return;
 
/* Do nothing, successfully, if radius is <= 0 */
if (radius <= 0.0) {
cairo_line_to (cr, xc, yc); /* might become a move_to */
cairo_line_to (cr, xc, yc);
return;
}
 
while (angle2 < angle1)
angle2 += 2 * M_PI;
 
cairo_line_to (cr,
xc + radius * cos (angle1),
yc + radius * sin (angle1));
 
_cairo_arc_path (cr, xc, yc, radius,
angle1, angle2);
}
 
/**
* cairo_arc_negative:
* @cr: a cairo context
* @xc: X position of the center of the arc
* @yc: Y position of the center of the arc
* @radius: the radius of the arc
* @angle1: the start angle, in radians
* @angle2: the end angle, in radians
*
* Adds a circular arc of the given @radius to the current path. The
* arc is centered at (@xc, @yc), begins at @angle1 and proceeds in
* the direction of decreasing angles to end at @angle2. If @angle2 is
* greater than @angle1 it will be progressively decreased by 2*M_PI
* until it is less than @angle1.
*
* See cairo_arc() for more details. This function differs only in the
* direction of the arc between the two angles.
**/
void
cairo_arc_negative (cairo_t *cr,
double xc, double yc,
double radius,
double angle1, double angle2)
{
if (unlikely (cr->status))
return;
 
/* Do nothing, successfully, if radius is <= 0 */
if (radius <= 0.0)
return;
 
while (angle2 > angle1)
angle2 -= 2 * M_PI;
 
cairo_line_to (cr,
xc + radius * cos (angle1),
yc + radius * sin (angle1));
 
_cairo_arc_path_negative (cr, xc, yc, radius,
angle1, angle2);
}
 
/* XXX: NYI
void
cairo_arc_to (cairo_t *cr,
double x1, double y1,
double x2, double y2,
double radius)
{
cairo_status_t status;
 
if (unlikely (cr->status))
return;
 
status = _cairo_gstate_arc_to (cr->gstate,
x1, y1,
x2, y2,
radius);
if (unlikely (status))
_cairo_set_error (cr, status);
}
*/
 
/**
* cairo_rel_move_to:
* @cr: a cairo context
* @dx: the X offset
* @dy: the Y offset
*
* Begin a new sub-path. After this call the current point will offset
* by (@x, @y).
*
* Given a current point of (x, y), cairo_rel_move_to(@cr, @dx, @dy)
* is logically equivalent to cairo_move_to(@cr, x + @dx, y + @dy).
*
* It is an error to call this function with no current point. Doing
* so will cause @cr to shutdown with a status of
* %CAIRO_STATUS_NO_CURRENT_POINT.
**/
void
cairo_rel_move_to (cairo_t *cr, double dx, double dy)
{
cairo_fixed_t dx_fixed, dy_fixed;
cairo_status_t status;
 
if (unlikely (cr->status))
return;
 
_cairo_gstate_user_to_device_distance (cr->gstate, &dx, &dy);
 
dx_fixed = _cairo_fixed_from_double (dx);
dy_fixed = _cairo_fixed_from_double (dy);
 
status = _cairo_path_fixed_rel_move_to (cr->path, dx_fixed, dy_fixed);
if (unlikely (status))
_cairo_set_error (cr, status);
}
 
/**
* cairo_rel_line_to:
* @cr: a cairo context
* @dx: the X offset to the end of the new line
* @dy: the Y offset to the end of the new line
*
* Relative-coordinate version of cairo_line_to(). Adds a line to the
* path from the current point to a point that is offset from the
* current point by (@dx, @dy) in user space. After this call the
* current point will be offset by (@dx, @dy).
*
* Given a current point of (x, y), cairo_rel_line_to(@cr, @dx, @dy)
* is logically equivalent to cairo_line_to(@cr, x + @dx, y + @dy).
*
* It is an error to call this function with no current point. Doing
* so will cause @cr to shutdown with a status of
* %CAIRO_STATUS_NO_CURRENT_POINT.
**/
void
cairo_rel_line_to (cairo_t *cr, double dx, double dy)
{
cairo_fixed_t dx_fixed, dy_fixed;
cairo_status_t status;
 
if (unlikely (cr->status))
return;
 
_cairo_gstate_user_to_device_distance (cr->gstate, &dx, &dy);
 
dx_fixed = _cairo_fixed_from_double (dx);
dy_fixed = _cairo_fixed_from_double (dy);
 
status = _cairo_path_fixed_rel_line_to (cr->path, dx_fixed, dy_fixed);
if (unlikely (status))
_cairo_set_error (cr, status);
}
slim_hidden_def(cairo_rel_line_to);
 
/**
* cairo_rel_curve_to:
* @cr: a cairo context
* @dx1: the X offset to the first control point
* @dy1: the Y offset to the first control point
* @dx2: the X offset to the second control point
* @dy2: the Y offset to the second control point
* @dx3: the X offset to the end of the curve
* @dy3: the Y offset to the end of the curve
*
* Relative-coordinate version of cairo_curve_to(). All offsets are
* relative to the current point. Adds a cubic Bézier spline to the
* path from the current point to a point offset from the current
* point by (@dx3, @dy3), using points offset by (@dx1, @dy1) and
* (@dx2, @dy2) as the control points. After this call the current
* point will be offset by (@dx3, @dy3).
*
* Given a current point of (x, y), cairo_rel_curve_to(@cr, @dx1,
* @dy1, @dx2, @dy2, @dx3, @dy3) is logically equivalent to
* cairo_curve_to(@cr, x+@dx1, y+@dy1, x+@dx2, y+@dy2, x+@dx3, y+@dy3).
*
* It is an error to call this function with no current point. Doing
* so will cause @cr to shutdown with a status of
* %CAIRO_STATUS_NO_CURRENT_POINT.
**/
void
cairo_rel_curve_to (cairo_t *cr,
double dx1, double dy1,
double dx2, double dy2,
double dx3, double dy3)
{
cairo_fixed_t dx1_fixed, dy1_fixed;
cairo_fixed_t dx2_fixed, dy2_fixed;
cairo_fixed_t dx3_fixed, dy3_fixed;
cairo_status_t status;
 
if (unlikely (cr->status))
return;
 
_cairo_gstate_user_to_device_distance (cr->gstate, &dx1, &dy1);
_cairo_gstate_user_to_device_distance (cr->gstate, &dx2, &dy2);
_cairo_gstate_user_to_device_distance (cr->gstate, &dx3, &dy3);
 
dx1_fixed = _cairo_fixed_from_double (dx1);
dy1_fixed = _cairo_fixed_from_double (dy1);
 
dx2_fixed = _cairo_fixed_from_double (dx2);
dy2_fixed = _cairo_fixed_from_double (dy2);
 
dx3_fixed = _cairo_fixed_from_double (dx3);
dy3_fixed = _cairo_fixed_from_double (dy3);
 
status = _cairo_path_fixed_rel_curve_to (cr->path,
dx1_fixed, dy1_fixed,
dx2_fixed, dy2_fixed,
dx3_fixed, dy3_fixed);
if (unlikely (status))
_cairo_set_error (cr, status);
}
 
/**
* cairo_rectangle:
* @cr: a cairo context
* @x: the X coordinate of the top left corner of the rectangle
* @y: the Y coordinate to the top left corner of the rectangle
* @width: the width of the rectangle
* @height: the height of the rectangle
*
* Adds a closed sub-path rectangle of the given size to the current
* path at position (@x, @y) in user-space coordinates.
*
* This function is logically equivalent to:
* <informalexample><programlisting>
* cairo_move_to (cr, x, y);
* cairo_rel_line_to (cr, width, 0);
* cairo_rel_line_to (cr, 0, height);
* cairo_rel_line_to (cr, -width, 0);
* cairo_close_path (cr);
* </programlisting></informalexample>
**/
void
cairo_rectangle (cairo_t *cr,
double x, double y,
double width, double height)
{
if (unlikely (cr->status))
return;
 
cairo_move_to (cr, x, y);
cairo_rel_line_to (cr, width, 0);
cairo_rel_line_to (cr, 0, height);
cairo_rel_line_to (cr, -width, 0);
cairo_close_path (cr);
}
 
#if 0
/* XXX: NYI */
void
cairo_stroke_to_path (cairo_t *cr)
{
cairo_status_t status;
 
if (unlikely (cr->status))
return;
 
/* The code in _cairo_recording_surface_get_path has a poorman's stroke_to_path */
 
status = _cairo_gstate_stroke_path (cr->gstate);
if (unlikely (status))
_cairo_set_error (cr, status);
}
#endif
 
/**
* cairo_close_path:
* @cr: a cairo context
*
* Adds a line segment to the path from the current point to the
* beginning of the current sub-path, (the most recent point passed to
* cairo_move_to()), and closes this sub-path. After this call the
* current point will be at the joined endpoint of the sub-path.
*
* The behavior of cairo_close_path() is distinct from simply calling
* cairo_line_to() with the equivalent coordinate in the case of
* stroking. When a closed sub-path is stroked, there are no caps on
* the ends of the sub-path. Instead, there is a line join connecting
* the final and initial segments of the sub-path.
*
* If there is no current point before the call to cairo_close_path(),
* this function will have no effect.
*
* Note: As of cairo version 1.2.4 any call to cairo_close_path() will
* place an explicit MOVE_TO element into the path immediately after
* the CLOSE_PATH element, (which can be seen in cairo_copy_path() for
* example). This can simplify path processing in some cases as it may
* not be necessary to save the "last move_to point" during processing
* as the MOVE_TO immediately after the CLOSE_PATH will provide that
* point.
**/
void
cairo_close_path (cairo_t *cr)
{
cairo_status_t status;
 
if (unlikely (cr->status))
return;
 
status = _cairo_path_fixed_close_path (cr->path);
if (unlikely (status))
_cairo_set_error (cr, status);
}
slim_hidden_def(cairo_close_path);
 
/**
* cairo_path_extents:
* @cr: a cairo context
* @x1: left of the resulting extents
* @y1: top of the resulting extents
* @x2: right of the resulting extents
* @y2: bottom of the resulting extents
*
* Computes a bounding box in user-space coordinates covering the
* points on the current path. If the current path is empty, returns
* an empty rectangle ((0,0), (0,0)). Stroke parameters, fill rule,
* surface dimensions and clipping are not taken into account.
*
* Contrast with cairo_fill_extents() and cairo_stroke_extents() which
* return the extents of only the area that would be "inked" by
* the corresponding drawing operations.
*
* The result of cairo_path_extents() is defined as equivalent to the
* limit of cairo_stroke_extents() with %CAIRO_LINE_CAP_ROUND as the
* line width approaches 0.0, (but never reaching the empty-rectangle
* returned by cairo_stroke_extents() for a line width of 0.0).
*
* Specifically, this means that zero-area sub-paths such as
* cairo_move_to();cairo_line_to() segments, (even degenerate cases
* where the coordinates to both calls are identical), will be
* considered as contributing to the extents. However, a lone
* cairo_move_to() will not contribute to the results of
* cairo_path_extents().
*
* Since: 1.6
**/
void
cairo_path_extents (cairo_t *cr,
double *x1, double *y1, double *x2, double *y2)
{
if (unlikely (cr->status)) {
if (x1)
*x1 = 0.0;
if (y1)
*y1 = 0.0;
if (x2)
*x2 = 0.0;
if (y2)
*y2 = 0.0;
 
return;
}
 
_cairo_gstate_path_extents (cr->gstate,
cr->path,
x1, y1, x2, y2);
}
 
/**
* cairo_paint:
* @cr: a cairo context
*
* A drawing operator that paints the current source everywhere within
* the current clip region.
**/
void
cairo_paint (cairo_t *cr)
{
cairo_status_t status;
 
if (unlikely (cr->status))
return;
 
status = _cairo_gstate_paint (cr->gstate);
if (unlikely (status))
_cairo_set_error (cr, status);
}
slim_hidden_def (cairo_paint);
 
/**
* cairo_paint_with_alpha:
* @cr: a cairo context
* @alpha: alpha value, between 0 (transparent) and 1 (opaque)
*
* A drawing operator that paints the current source everywhere within
* the current clip region using a mask of constant alpha value
* @alpha. The effect is similar to cairo_paint(), but the drawing
* is faded out using the alpha value.
**/
void
cairo_paint_with_alpha (cairo_t *cr,
double alpha)
{
cairo_status_t status;
cairo_color_t color;
cairo_solid_pattern_t pattern;
 
if (unlikely (cr->status))
return;
 
if (CAIRO_ALPHA_IS_OPAQUE (alpha)) {
cairo_paint (cr);
return;
}
 
if (CAIRO_ALPHA_IS_ZERO (alpha) &&
_cairo_operator_bounded_by_mask (cr->gstate->op)) {
return;
}
 
_cairo_color_init_rgba (&color, 0., 0., 0., alpha);
_cairo_pattern_init_solid (&pattern, &color);
 
status = _cairo_gstate_mask (cr->gstate, &pattern.base);
if (unlikely (status))
_cairo_set_error (cr, status);
 
_cairo_pattern_fini (&pattern.base);
}
 
/**
* cairo_mask:
* @cr: a cairo context
* @pattern: a #cairo_pattern_t
*
* A drawing operator that paints the current source
* using the alpha channel of @pattern as a mask. (Opaque
* areas of @pattern are painted with the source, transparent
* areas are not painted.)
*/
void
cairo_mask (cairo_t *cr,
cairo_pattern_t *pattern)
{
cairo_status_t status;
 
if (unlikely (cr->status))
return;
 
if (pattern == NULL) {
_cairo_set_error (cr, CAIRO_STATUS_NULL_POINTER);
return;
}
 
if (pattern->status) {
_cairo_set_error (cr, pattern->status);
return;
}
 
status = _cairo_gstate_mask (cr->gstate, pattern);
if (unlikely (status))
_cairo_set_error (cr, status);
}
slim_hidden_def (cairo_mask);
 
/**
* cairo_mask_surface:
* @cr: a cairo context
* @surface: a #cairo_surface_t
* @surface_x: X coordinate at which to place the origin of @surface
* @surface_y: Y coordinate at which to place the origin of @surface
*
* A drawing operator that paints the current source
* using the alpha channel of @surface as a mask. (Opaque
* areas of @surface are painted with the source, transparent
* areas are not painted.)
*/
void
cairo_mask_surface (cairo_t *cr,
cairo_surface_t *surface,
double surface_x,
double surface_y)
{
cairo_pattern_t *pattern;
cairo_matrix_t matrix;
 
if (unlikely (cr->status))
return;
 
pattern = cairo_pattern_create_for_surface (surface);
 
cairo_matrix_init_translate (&matrix, - surface_x, - surface_y);
cairo_pattern_set_matrix (pattern, &matrix);
 
cairo_mask (cr, pattern);
 
cairo_pattern_destroy (pattern);
}
 
/**
* cairo_stroke:
* @cr: a cairo context
*
* A drawing operator that strokes the current path according to the
* current line width, line join, line cap, and dash settings. After
* cairo_stroke(), the current path will be cleared from the cairo
* context. See cairo_set_line_width(), cairo_set_line_join(),
* cairo_set_line_cap(), cairo_set_dash(), and
* cairo_stroke_preserve().
*
* Note: Degenerate segments and sub-paths are treated specially and
* provide a useful result. These can result in two different
* situations:
*
* 1. Zero-length "on" segments set in cairo_set_dash(). If the cap
* style is %CAIRO_LINE_CAP_ROUND or %CAIRO_LINE_CAP_SQUARE then these
* segments will be drawn as circular dots or squares respectively. In
* the case of %CAIRO_LINE_CAP_SQUARE, the orientation of the squares
* is determined by the direction of the underlying path.
*
* 2. A sub-path created by cairo_move_to() followed by either a
* cairo_close_path() or one or more calls to cairo_line_to() to the
* same coordinate as the cairo_move_to(). If the cap style is
* %CAIRO_LINE_CAP_ROUND then these sub-paths will be drawn as circular
* dots. Note that in the case of %CAIRO_LINE_CAP_SQUARE a degenerate
* sub-path will not be drawn at all, (since the correct orientation
* is indeterminate).
*
* In no case will a cap style of %CAIRO_LINE_CAP_BUTT cause anything
* to be drawn in the case of either degenerate segments or sub-paths.
**/
void
cairo_stroke (cairo_t *cr)
{
cairo_stroke_preserve (cr);
 
cairo_new_path (cr);
}
slim_hidden_def(cairo_stroke);
 
/**
* cairo_stroke_preserve:
* @cr: a cairo context
*
* A drawing operator that strokes the current path according to the
* current line width, line join, line cap, and dash settings. Unlike
* cairo_stroke(), cairo_stroke_preserve() preserves the path within the
* cairo context.
*
* See cairo_set_line_width(), cairo_set_line_join(),
* cairo_set_line_cap(), cairo_set_dash(), and
* cairo_stroke_preserve().
**/
void
cairo_stroke_preserve (cairo_t *cr)
{
cairo_status_t status;
 
if (unlikely (cr->status))
return;
 
status = _cairo_gstate_stroke (cr->gstate, cr->path);
if (unlikely (status))
_cairo_set_error (cr, status);
}
slim_hidden_def(cairo_stroke_preserve);
 
/**
* cairo_fill:
* @cr: a cairo context
*
* A drawing operator that fills the current path according to the
* current fill rule, (each sub-path is implicitly closed before being
* filled). After cairo_fill(), the current path will be cleared from
* the cairo context. See cairo_set_fill_rule() and
* cairo_fill_preserve().
**/
void
cairo_fill (cairo_t *cr)
{
cairo_fill_preserve (cr);
 
cairo_new_path (cr);
}
 
/**
* cairo_fill_preserve:
* @cr: a cairo context
*
* A drawing operator that fills the current path according to the
* current fill rule, (each sub-path is implicitly closed before being
* filled). Unlike cairo_fill(), cairo_fill_preserve() preserves the
* path within the cairo context.
*
* See cairo_set_fill_rule() and cairo_fill().
**/
void
cairo_fill_preserve (cairo_t *cr)
{
cairo_status_t status;
 
if (unlikely (cr->status))
return;
 
status = _cairo_gstate_fill (cr->gstate, cr->path);
if (unlikely (status))
_cairo_set_error (cr, status);
}
slim_hidden_def(cairo_fill_preserve);
 
/**
* cairo_copy_page:
* @cr: a cairo context
*
* Emits the current page for backends that support multiple pages, but
* doesn't clear it, so, the contents of the current page will be retained
* for the next page too. Use cairo_show_page() if you want to get an
* empty page after the emission.
*
* This is a convenience function that simply calls
* cairo_surface_copy_page() on @cr's target.
**/
void
cairo_copy_page (cairo_t *cr)
{
cairo_status_t status;
 
if (unlikely (cr->status))
return;
 
status = _cairo_gstate_copy_page (cr->gstate);
if (unlikely (status))
_cairo_set_error (cr, status);
}
 
/**
* cairo_show_page:
* @cr: a cairo context
*
* Emits and clears the current page for backends that support multiple
* pages. Use cairo_copy_page() if you don't want to clear the page.
*
* This is a convenience function that simply calls
* cairo_surface_show_page() on @cr's target.
**/
void
cairo_show_page (cairo_t *cr)
{
cairo_status_t status;
 
if (unlikely (cr->status))
return;
 
status = _cairo_gstate_show_page (cr->gstate);
if (unlikely (status))
_cairo_set_error (cr, status);
}
 
/**
* cairo_in_stroke:
* @cr: a cairo context
* @x: X coordinate of the point to test
* @y: Y coordinate of the point to test
*
* Tests whether the given point is inside the area that would be
* affected by a cairo_stroke() operation given the current path and
* stroking parameters. Surface dimensions and clipping are not taken
* into account.
*
* See cairo_stroke(), cairo_set_line_width(), cairo_set_line_join(),
* cairo_set_line_cap(), cairo_set_dash(), and
* cairo_stroke_preserve().
*
* Return value: A non-zero value if the point is inside, or zero if
* outside.
**/
cairo_bool_t
cairo_in_stroke (cairo_t *cr, double x, double y)
{
cairo_status_t status;
cairo_bool_t inside = FALSE;
 
if (unlikely (cr->status))
return FALSE;
 
status = _cairo_gstate_in_stroke (cr->gstate,
cr->path,
x, y, &inside);
if (unlikely (status))
_cairo_set_error (cr, status);
 
return inside;
}
 
/**
* cairo_in_fill:
* @cr: a cairo context
* @x: X coordinate of the point to test
* @y: Y coordinate of the point to test
*
* Tests whether the given point is inside the area that would be
* affected by a cairo_fill() operation given the current path and
* filling parameters. Surface dimensions and clipping are not taken
* into account.
*
* See cairo_fill(), cairo_set_fill_rule() and cairo_fill_preserve().
*
* Return value: A non-zero value if the point is inside, or zero if
* outside.
**/
cairo_bool_t
cairo_in_fill (cairo_t *cr, double x, double y)
{
if (unlikely (cr->status))
return FALSE;
 
return _cairo_gstate_in_fill (cr->gstate, cr->path, x, y);
}
 
/**
* cairo_stroke_extents:
* @cr: a cairo context
* @x1: left of the resulting extents
* @y1: top of the resulting extents
* @x2: right of the resulting extents
* @y2: bottom of the resulting extents
*
* Computes a bounding box in user coordinates covering the area that
* would be affected, (the "inked" area), by a cairo_stroke()
* operation given the current path and stroke parameters.
* If the current path is empty, returns an empty rectangle ((0,0), (0,0)).
* Surface dimensions and clipping are not taken into account.
*
* Note that if the line width is set to exactly zero, then
* cairo_stroke_extents() will return an empty rectangle. Contrast with
* cairo_path_extents() which can be used to compute the non-empty
* bounds as the line width approaches zero.
*
* Note that cairo_stroke_extents() must necessarily do more work to
* compute the precise inked areas in light of the stroke parameters,
* so cairo_path_extents() may be more desirable for sake of
* performance if non-inked path extents are desired.
*
* See cairo_stroke(), cairo_set_line_width(), cairo_set_line_join(),
* cairo_set_line_cap(), cairo_set_dash(), and
* cairo_stroke_preserve().
**/
void
cairo_stroke_extents (cairo_t *cr,
double *x1, double *y1, double *x2, double *y2)
{
cairo_status_t status;
 
if (unlikely (cr->status)) {
if (x1)
*x1 = 0.0;
if (y1)
*y1 = 0.0;
if (x2)
*x2 = 0.0;
if (y2)
*y2 = 0.0;
 
return;
}
 
status = _cairo_gstate_stroke_extents (cr->gstate,
cr->path,
x1, y1, x2, y2);
if (unlikely (status))
_cairo_set_error (cr, status);
}
 
/**
* cairo_fill_extents:
* @cr: a cairo context
* @x1: left of the resulting extents
* @y1: top of the resulting extents
* @x2: right of the resulting extents
* @y2: bottom of the resulting extents
*
* Computes a bounding box in user coordinates covering the area that
* would be affected, (the "inked" area), by a cairo_fill() operation
* given the current path and fill parameters. If the current path is
* empty, returns an empty rectangle ((0,0), (0,0)). Surface
* dimensions and clipping are not taken into account.
*
* Contrast with cairo_path_extents(), which is similar, but returns
* non-zero extents for some paths with no inked area, (such as a
* simple line segment).
*
* Note that cairo_fill_extents() must necessarily do more work to
* compute the precise inked areas in light of the fill rule, so
* cairo_path_extents() may be more desirable for sake of performance
* if the non-inked path extents are desired.
*
* See cairo_fill(), cairo_set_fill_rule() and cairo_fill_preserve().
**/
void
cairo_fill_extents (cairo_t *cr,
double *x1, double *y1, double *x2, double *y2)
{
cairo_status_t status;
 
if (unlikely (cr->status)) {
if (x1)
*x1 = 0.0;
if (y1)
*y1 = 0.0;
if (x2)
*x2 = 0.0;
if (y2)
*y2 = 0.0;
 
return;
}
 
status = _cairo_gstate_fill_extents (cr->gstate,
cr->path,
x1, y1, x2, y2);
if (unlikely (status))
_cairo_set_error (cr, status);
}
 
/**
* cairo_clip:
* @cr: a cairo context
*
* Establishes a new clip region by intersecting the current clip
* region with the current path as it would be filled by cairo_fill()
* and according to the current fill rule (see cairo_set_fill_rule()).
*
* After cairo_clip(), the current path will be cleared from the cairo
* context.
*
* The current clip region affects all drawing operations by
* effectively masking out any changes to the surface that are outside
* the current clip region.
*
* Calling cairo_clip() can only make the clip region smaller, never
* larger. But the current clip is part of the graphics state, so a
* temporary restriction of the clip region can be achieved by
* calling cairo_clip() within a cairo_save()/cairo_restore()
* pair. The only other means of increasing the size of the clip
* region is cairo_reset_clip().
**/
void
cairo_clip (cairo_t *cr)
{
cairo_clip_preserve (cr);
 
cairo_new_path (cr);
}
 
/**
* cairo_clip_preserve:
* @cr: a cairo context
*
* Establishes a new clip region by intersecting the current clip
* region with the current path as it would be filled by cairo_fill()
* and according to the current fill rule (see cairo_set_fill_rule()).
*
* Unlike cairo_clip(), cairo_clip_preserve() preserves the path within
* the cairo context.
*
* The current clip region affects all drawing operations by
* effectively masking out any changes to the surface that are outside
* the current clip region.
*
* Calling cairo_clip_preserve() can only make the clip region smaller, never
* larger. But the current clip is part of the graphics state, so a
* temporary restriction of the clip region can be achieved by
* calling cairo_clip_preserve() within a cairo_save()/cairo_restore()
* pair. The only other means of increasing the size of the clip
* region is cairo_reset_clip().
**/
void
cairo_clip_preserve (cairo_t *cr)
{
cairo_status_t status;
 
if (unlikely (cr->status))
return;
 
status = _cairo_gstate_clip (cr->gstate, cr->path);
if (unlikely (status))
_cairo_set_error (cr, status);
}
slim_hidden_def(cairo_clip_preserve);
 
/**
* cairo_reset_clip:
* @cr: a cairo context
*
* Reset the current clip region to its original, unrestricted
* state. That is, set the clip region to an infinitely large shape
* containing the target surface. Equivalently, if infinity is too
* hard to grasp, one can imagine the clip region being reset to the
* exact bounds of the target surface.
*
* Note that code meant to be reusable should not call
* cairo_reset_clip() as it will cause results unexpected by
* higher-level code which calls cairo_clip(). Consider using
* cairo_save() and cairo_restore() around cairo_clip() as a more
* robust means of temporarily restricting the clip region.
**/
void
cairo_reset_clip (cairo_t *cr)
{
cairo_status_t status;
 
if (unlikely (cr->status))
return;
 
status = _cairo_gstate_reset_clip (cr->gstate);
if (unlikely (status))
_cairo_set_error (cr, status);
}
 
/**
* cairo_clip_extents:
* @cr: a cairo context
* @x1: left of the resulting extents
* @y1: top of the resulting extents
* @x2: right of the resulting extents
* @y2: bottom of the resulting extents
*
* Computes a bounding box in user coordinates covering the area inside the
* current clip.
*
* Since: 1.4
**/
void
cairo_clip_extents (cairo_t *cr,
double *x1, double *y1,
double *x2, double *y2)
{
if (unlikely (cr->status)) {
if (x1)
*x1 = 0.0;
if (y1)
*y1 = 0.0;
if (x2)
*x2 = 0.0;
if (y2)
*y2 = 0.0;
 
return;
}
 
if (! _cairo_gstate_clip_extents (cr->gstate, x1, y1, x2, y2)) {
*x1 = -INFINITY;
*y1 = -INFINITY;
*x2 = +INFINITY;
*y2 = +INFINITY;
}
}
 
/**
* cairo_in_clip:
* @cr: a cairo context
* @x: X coordinate of the point to test
* @y: Y coordinate of the point to test
*
* Tests whether the given point is inside the area that would be
* visible through the current clip, i.e. the area that would be filled by
* a cairo_paint() operation.
*
* See cairo_clip(), and cairo_clip_preserve().
*
* Return value: A non-zero value if the point is inside, or zero if
* outside.
*
* Since: 1.10
**/
cairo_bool_t
cairo_in_clip (cairo_t *cr, double x, double y)
{
if (unlikely (cr->status))
return FALSE;
 
return _cairo_gstate_in_clip (cr->gstate, x, y);
}
 
static cairo_rectangle_list_t *
_cairo_rectangle_list_create_in_error (cairo_status_t status)
{
cairo_rectangle_list_t *list;
 
if (status == CAIRO_STATUS_NO_MEMORY)
return (cairo_rectangle_list_t*) &_cairo_rectangles_nil;
 
list = malloc (sizeof (cairo_rectangle_list_t));
if (unlikely (list == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
return (cairo_rectangle_list_t*) &_cairo_rectangles_nil;
}
 
list->status = status;
list->rectangles = NULL;
list->num_rectangles = 0;
return list;
}
 
/**
* cairo_copy_clip_rectangle_list:
* @cr: a cairo context
*
* Gets the current clip region as a list of rectangles in user coordinates.
* Never returns %NULL.
*
* The status in the list may be %CAIRO_STATUS_CLIP_NOT_REPRESENTABLE to
* indicate that the clip region cannot be represented as a list of
* user-space rectangles. The status may have other values to indicate
* other errors.
*
* Returns: the current clip region as a list of rectangles in user coordinates,
* which should be destroyed using cairo_rectangle_list_destroy().
*
* Since: 1.4
**/
cairo_rectangle_list_t *
cairo_copy_clip_rectangle_list (cairo_t *cr)
{
if (unlikely (cr->status))
return _cairo_rectangle_list_create_in_error (cr->status);
 
return _cairo_gstate_copy_clip_rectangle_list (cr->gstate);
}
 
/**
* cairo_select_font_face:
* @cr: a #cairo_t
* @family: a font family name, encoded in UTF-8
* @slant: the slant for the font
* @weight: the weight for the font
*
* Note: The cairo_select_font_face() function call is part of what
* the cairo designers call the "toy" text API. It is convenient for
* short demos and simple programs, but it is not expected to be
* adequate for serious text-using applications.
*
* Selects a family and style of font from a simplified description as
* a family name, slant and weight. Cairo provides no operation to
* list available family names on the system (this is a "toy",
* remember), but the standard CSS2 generic family names, ("serif",
* "sans-serif", "cursive", "fantasy", "monospace"), are likely to
* work as expected.
*
* If @family starts with the string "@cairo:", or if no native font
* backends are compiled in, cairo will use an internal font family.
* The internal font family recognizes many modifiers in the @family
* string, most notably, it recognizes the string "monospace". That is,
* the family name "@cairo:monospace" will use the monospace version of
* the internal font family.
*
* For "real" font selection, see the font-backend-specific
* font_face_create functions for the font backend you are using. (For
* example, if you are using the freetype-based cairo-ft font backend,
* see cairo_ft_font_face_create_for_ft_face() or
* cairo_ft_font_face_create_for_pattern().) The resulting font face
* could then be used with cairo_scaled_font_create() and
* cairo_set_scaled_font().
*
* Similarly, when using the "real" font support, you can call
* directly into the underlying font system, (such as fontconfig or
* freetype), for operations such as listing available fonts, etc.
*
* It is expected that most applications will need to use a more
* comprehensive font handling and text layout library, (for example,
* pango), in conjunction with cairo.
*
* If text is drawn without a call to cairo_select_font_face(), (nor
* cairo_set_font_face() nor cairo_set_scaled_font()), the default
* family is platform-specific, but is essentially "sans-serif".
* Default slant is %CAIRO_FONT_SLANT_NORMAL, and default weight is
* %CAIRO_FONT_WEIGHT_NORMAL.
*
* This function is equivalent to a call to cairo_toy_font_face_create()
* followed by cairo_set_font_face().
**/
void
cairo_select_font_face (cairo_t *cr,
const char *family,
cairo_font_slant_t slant,
cairo_font_weight_t weight)
{
cairo_status_t status;
 
if (unlikely (cr->status))
return;
 
status = _cairo_gstate_select_font_face (cr->gstate, family, slant, weight);
if (unlikely (status))
_cairo_set_error (cr, status);
}
 
/**
* cairo_font_extents:
* @cr: a #cairo_t
* @extents: a #cairo_font_extents_t object into which the results
* will be stored.
*
* Gets the font extents for the currently selected font.
**/
void
cairo_font_extents (cairo_t *cr,
cairo_font_extents_t *extents)
{
cairo_status_t status;
 
extents->ascent = 0.0;
extents->descent = 0.0;
extents->height = 0.0;
extents->max_x_advance = 0.0;
extents->max_y_advance = 0.0;
 
if (unlikely (cr->status))
return;
 
status = _cairo_gstate_get_font_extents (cr->gstate, extents);
if (unlikely (status))
_cairo_set_error (cr, status);
}
 
/**
* cairo_set_font_face:
* @cr: a #cairo_t
* @font_face: a #cairo_font_face_t, or %NULL to restore to the default font
*
* Replaces the current #cairo_font_face_t object in the #cairo_t with
* @font_face. The replaced font face in the #cairo_t will be
* destroyed if there are no other references to it.
**/
void
cairo_set_font_face (cairo_t *cr,
cairo_font_face_t *font_face)
{
cairo_status_t status;
 
if (unlikely (cr->status))
return;
 
status = _cairo_gstate_set_font_face (cr->gstate, font_face);
if (unlikely (status))
_cairo_set_error (cr, status);
}
 
/**
* cairo_get_font_face:
* @cr: a #cairo_t
*
* Gets the current font face for a #cairo_t.
*
* Return value: the current font face. This object is owned by
* cairo. To keep a reference to it, you must call
* cairo_font_face_reference().
*
* This function never returns %NULL. If memory cannot be allocated, a
* special "nil" #cairo_font_face_t object will be returned on which
* cairo_font_face_status() returns %CAIRO_STATUS_NO_MEMORY. Using
* this nil object will cause its error state to propagate to other
* objects it is passed to, (for example, calling
* cairo_set_font_face() with a nil font will trigger an error that
* will shutdown the #cairo_t object).
**/
cairo_font_face_t *
cairo_get_font_face (cairo_t *cr)
{
cairo_status_t status;
cairo_font_face_t *font_face;
 
if (unlikely (cr->status))
return (cairo_font_face_t*) &_cairo_font_face_nil;
 
status = _cairo_gstate_get_font_face (cr->gstate, &font_face);
if (unlikely (status)) {
_cairo_set_error (cr, status);
return (cairo_font_face_t*) &_cairo_font_face_nil;
}
 
return font_face;
}
 
/**
* cairo_set_font_size:
* @cr: a #cairo_t
* @size: the new font size, in user space units
*
* Sets the current font matrix to a scale by a factor of @size, replacing
* any font matrix previously set with cairo_set_font_size() or
* cairo_set_font_matrix(). This results in a font size of @size user space
* units. (More precisely, this matrix will result in the font's
* em-square being a @size by @size square in user space.)
*
* If text is drawn without a call to cairo_set_font_size(), (nor
* cairo_set_font_matrix() nor cairo_set_scaled_font()), the default
* font size is 10.0.
**/
void
cairo_set_font_size (cairo_t *cr, double size)
{
cairo_status_t status;
 
if (unlikely (cr->status))
return;
 
status = _cairo_gstate_set_font_size (cr->gstate, size);
if (unlikely (status))
_cairo_set_error (cr, status);
}
slim_hidden_def (cairo_set_font_size);
 
/**
* cairo_set_font_matrix
* @cr: a #cairo_t
* @matrix: a #cairo_matrix_t describing a transform to be applied to
* the current font.
*
* Sets the current font matrix to @matrix. The font matrix gives a
* transformation from the design space of the font (in this space,
* the em-square is 1 unit by 1 unit) to user space. Normally, a
* simple scale is used (see cairo_set_font_size()), but a more
* complex font matrix can be used to shear the font
* or stretch it unequally along the two axes
**/
void
cairo_set_font_matrix (cairo_t *cr,
const cairo_matrix_t *matrix)
{
cairo_status_t status;
 
if (unlikely (cr->status))
return;
 
status = _cairo_gstate_set_font_matrix (cr->gstate, matrix);
if (unlikely (status))
_cairo_set_error (cr, status);
}
 
/**
* cairo_get_font_matrix
* @cr: a #cairo_t
* @matrix: return value for the matrix
*
* Stores the current font matrix into @matrix. See
* cairo_set_font_matrix().
**/
void
cairo_get_font_matrix (cairo_t *cr, cairo_matrix_t *matrix)
{
if (unlikely (cr->status)) {
cairo_matrix_init_identity (matrix);
return;
}
 
_cairo_gstate_get_font_matrix (cr->gstate, matrix);
}
 
/**
* cairo_set_font_options:
* @cr: a #cairo_t
* @options: font options to use
*
* Sets a set of custom font rendering options for the #cairo_t.
* Rendering options are derived by merging these options with the
* options derived from underlying surface; if the value in @options
* has a default value (like %CAIRO_ANTIALIAS_DEFAULT), then the value
* from the surface is used.
**/
void
cairo_set_font_options (cairo_t *cr,
const cairo_font_options_t *options)
{
cairo_status_t status;
 
if (unlikely (cr->status))
return;
 
status = cairo_font_options_status ((cairo_font_options_t *) options);
if (unlikely (status)) {
_cairo_set_error (cr, status);
return;
}
 
_cairo_gstate_set_font_options (cr->gstate, options);
}
slim_hidden_def (cairo_set_font_options);
 
/**
* cairo_get_font_options:
* @cr: a #cairo_t
* @options: a #cairo_font_options_t object into which to store
* the retrieved options. All existing values are overwritten
*
* Retrieves font rendering options set via #cairo_set_font_options.
* Note that the returned options do not include any options derived
* from the underlying surface; they are literally the options
* passed to cairo_set_font_options().
**/
void
cairo_get_font_options (cairo_t *cr,
cairo_font_options_t *options)
{
/* check that we aren't trying to overwrite the nil object */
if (cairo_font_options_status (options))
return;
 
if (unlikely (cr->status)) {
_cairo_font_options_init_default (options);
return;
}
 
_cairo_gstate_get_font_options (cr->gstate, options);
}
 
/**
* cairo_set_scaled_font:
* @cr: a #cairo_t
* @scaled_font: a #cairo_scaled_font_t
*
* Replaces the current font face, font matrix, and font options in
* the #cairo_t with those of the #cairo_scaled_font_t. Except for
* some translation, the current CTM of the #cairo_t should be the
* same as that of the #cairo_scaled_font_t, which can be accessed
* using cairo_scaled_font_get_ctm().
*
* Since: 1.2
**/
void
cairo_set_scaled_font (cairo_t *cr,
const cairo_scaled_font_t *scaled_font)
{
cairo_status_t status;
cairo_bool_t was_previous;
 
if (unlikely (cr->status))
return;
 
if (scaled_font == NULL) {
status = _cairo_error (CAIRO_STATUS_NULL_POINTER);
goto BAIL;
}
 
status = scaled_font->status;
if (unlikely (status))
goto BAIL;
 
if (scaled_font == cr->gstate->scaled_font)
return;
 
was_previous = scaled_font == cr->gstate->previous_scaled_font;
 
status = _cairo_gstate_set_font_face (cr->gstate, scaled_font->font_face);
if (unlikely (status))
goto BAIL;
 
status = _cairo_gstate_set_font_matrix (cr->gstate, &scaled_font->font_matrix);
if (unlikely (status))
goto BAIL;
 
_cairo_gstate_set_font_options (cr->gstate, &scaled_font->options);
 
if (was_previous)
cr->gstate->scaled_font = cairo_scaled_font_reference ((cairo_scaled_font_t *) scaled_font);
 
return;
 
BAIL:
_cairo_set_error (cr, status);
}
 
/**
* cairo_get_scaled_font:
* @cr: a #cairo_t
*
* Gets the current scaled font for a #cairo_t.
*
* Return value: the current scaled font. This object is owned by
* cairo. To keep a reference to it, you must call
* cairo_scaled_font_reference().
*
* This function never returns %NULL. If memory cannot be allocated, a
* special "nil" #cairo_scaled_font_t object will be returned on which
* cairo_scaled_font_status() returns %CAIRO_STATUS_NO_MEMORY. Using
* this nil object will cause its error state to propagate to other
* objects it is passed to, (for example, calling
* cairo_set_scaled_font() with a nil font will trigger an error that
* will shutdown the #cairo_t object).
*
* Since: 1.4
**/
cairo_scaled_font_t *
cairo_get_scaled_font (cairo_t *cr)
{
cairo_status_t status;
cairo_scaled_font_t *scaled_font;
 
if (unlikely (cr->status))
return _cairo_scaled_font_create_in_error (cr->status);
 
status = _cairo_gstate_get_scaled_font (cr->gstate, &scaled_font);
if (unlikely (status)) {
_cairo_set_error (cr, status);
return _cairo_scaled_font_create_in_error (status);
}
 
return scaled_font;
}
 
/**
* cairo_text_extents:
* @cr: a #cairo_t
* @utf8: a NUL-terminated string of text encoded in UTF-8, or %NULL
* @extents: a #cairo_text_extents_t object into which the results
* will be stored
*
* Gets the extents for a string of text. The extents describe a
* user-space rectangle that encloses the "inked" portion of the text,
* (as it would be drawn by cairo_show_text()). Additionally, the
* x_advance and y_advance values indicate the amount by which the
* current point would be advanced by cairo_show_text().
*
* Note that whitespace characters do not directly contribute to the
* size of the rectangle (extents.width and extents.height). They do
* contribute indirectly by changing the position of non-whitespace
* characters. In particular, trailing whitespace characters are
* likely to not affect the size of the rectangle, though they will
* affect the x_advance and y_advance values.
**/
void
cairo_text_extents (cairo_t *cr,
const char *utf8,
cairo_text_extents_t *extents)
{
cairo_status_t status;
cairo_glyph_t *glyphs = NULL;
int num_glyphs;
double x, y;
 
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;
 
if (unlikely (cr->status))
return;
 
if (utf8 == NULL)
return;
 
cairo_get_current_point (cr, &x, &y);
 
status = _cairo_gstate_text_to_glyphs (cr->gstate,
x, y,
utf8, strlen (utf8),
&glyphs, &num_glyphs,
NULL, NULL,
NULL);
 
if (status == CAIRO_STATUS_SUCCESS)
status = _cairo_gstate_glyph_extents (cr->gstate,
glyphs, num_glyphs,
extents);
cairo_glyph_free (glyphs);
 
if (unlikely (status))
_cairo_set_error (cr, status);
}
 
/**
* cairo_glyph_extents:
* @cr: a #cairo_t
* @glyphs: an array of #cairo_glyph_t objects
* @num_glyphs: the number of elements in @glyphs
* @extents: a #cairo_text_extents_t object into which the results
* will be stored
*
* Gets the extents for an array of glyphs. The extents describe a
* user-space rectangle that encloses the "inked" portion of the
* glyphs, (as they would be drawn by cairo_show_glyphs()).
* Additionally, the x_advance and y_advance values indicate the
* amount by which the current point would be advanced by
* cairo_show_glyphs().
*
* Note that whitespace glyphs do not contribute to the size of the
* rectangle (extents.width and extents.height).
**/
void
cairo_glyph_extents (cairo_t *cr,
const cairo_glyph_t *glyphs,
int num_glyphs,
cairo_text_extents_t *extents)
{
cairo_status_t 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;
 
if (unlikely (cr->status))
return;
 
if (num_glyphs == 0)
return;
 
if (num_glyphs < 0) {
_cairo_set_error (cr, CAIRO_STATUS_NEGATIVE_COUNT);
return;
}
 
if (glyphs == NULL) {
_cairo_set_error (cr, CAIRO_STATUS_NULL_POINTER);
return;
}
 
status = _cairo_gstate_glyph_extents (cr->gstate, glyphs, num_glyphs,
extents);
if (unlikely (status))
_cairo_set_error (cr, status);
}
 
/**
* cairo_show_text:
* @cr: a cairo context
* @utf8: a NUL-terminated string of text encoded in UTF-8, or %NULL
*
* A drawing operator that generates the shape from a string of UTF-8
* characters, rendered according to the current font_face, font_size
* (font_matrix), and font_options.
*
* This function first computes a set of glyphs for the string of
* text. The first glyph is placed so that its origin is at the
* current point. The origin of each subsequent glyph is offset from
* that of the previous glyph by the advance values of the previous
* glyph.
*
* After this call the current point is moved to the origin of where
* the next glyph would be placed in this same progression. That is,
* the current point will be at the origin of the final glyph offset
* by its advance values. This allows for easy display of a single
* logical string with multiple calls to cairo_show_text().
*
* Note: The cairo_show_text() function call is part of what the cairo
* designers call the "toy" text API. It is convenient for short demos
* and simple programs, but it is not expected to be adequate for
* serious text-using applications. See cairo_show_glyphs() for the
* "real" text display API in cairo.
**/
void
cairo_show_text (cairo_t *cr, const char *utf8)
{
cairo_text_extents_t extents;
cairo_status_t status;
cairo_glyph_t *glyphs, *last_glyph;
cairo_text_cluster_t *clusters;
int utf8_len, num_glyphs, num_clusters;
cairo_text_cluster_flags_t cluster_flags;
double x, y;
cairo_bool_t has_show_text_glyphs;
cairo_glyph_t stack_glyphs[CAIRO_STACK_ARRAY_LENGTH (cairo_glyph_t)];
cairo_text_cluster_t stack_clusters[CAIRO_STACK_ARRAY_LENGTH (cairo_text_cluster_t)];
 
if (unlikely (cr->status))
return;
 
if (utf8 == NULL)
return;
 
cairo_get_current_point (cr, &x, &y);
 
utf8_len = strlen (utf8);
 
has_show_text_glyphs =
cairo_surface_has_show_text_glyphs (cairo_get_target (cr));
 
glyphs = stack_glyphs;
num_glyphs = ARRAY_LENGTH (stack_glyphs);
 
if (has_show_text_glyphs) {
clusters = stack_clusters;
num_clusters = ARRAY_LENGTH (stack_clusters);
} else {
clusters = NULL;
num_clusters = 0;
}
 
status = _cairo_gstate_text_to_glyphs (cr->gstate,
x, y,
utf8, utf8_len,
&glyphs, &num_glyphs,
has_show_text_glyphs ? &clusters : NULL, &num_clusters,
&cluster_flags);
if (unlikely (status))
goto BAIL;
 
if (num_glyphs == 0)
return;
 
status = _cairo_gstate_show_text_glyphs (cr->gstate,
utf8, utf8_len,
glyphs, num_glyphs,
clusters, num_clusters,
cluster_flags);
if (unlikely (status))
goto BAIL;
 
last_glyph = &glyphs[num_glyphs - 1];
status = _cairo_gstate_glyph_extents (cr->gstate,
last_glyph, 1,
&extents);
if (unlikely (status))
goto BAIL;
 
x = last_glyph->x + extents.x_advance;
y = last_glyph->y + extents.y_advance;
cairo_move_to (cr, x, y);
 
BAIL:
if (glyphs != stack_glyphs)
cairo_glyph_free (glyphs);
if (clusters != stack_clusters)
cairo_text_cluster_free (clusters);
 
if (unlikely (status))
_cairo_set_error (cr, status);
}
 
/**
* cairo_show_glyphs:
* @cr: a cairo context
* @glyphs: array of glyphs to show
* @num_glyphs: number of glyphs to show
*
* A drawing operator that generates the shape from an array of glyphs,
* rendered according to the current font face, font size
* (font matrix), and font options.
**/
void
cairo_show_glyphs (cairo_t *cr, const cairo_glyph_t *glyphs, int num_glyphs)
{
cairo_status_t status;
 
if (unlikely (cr->status))
return;
 
if (num_glyphs == 0)
return;
 
if (num_glyphs < 0) {
_cairo_set_error (cr, CAIRO_STATUS_NEGATIVE_COUNT);
return;
}
 
if (glyphs == NULL) {
_cairo_set_error (cr, CAIRO_STATUS_NULL_POINTER);
return;
}
 
status = _cairo_gstate_show_text_glyphs (cr->gstate,
NULL, 0,
glyphs, num_glyphs,
NULL, 0,
FALSE);
if (unlikely (status))
_cairo_set_error (cr, status);
}
 
/**
* cairo_show_text_glyphs:
* @cr: a cairo context
* @utf8: a string of text encoded in UTF-8
* @utf8_len: length of @utf8 in bytes, or -1 if it is NUL-terminated
* @glyphs: array of glyphs to show
* @num_glyphs: number of glyphs to show
* @clusters: array of cluster mapping information
* @num_clusters: number of clusters in the mapping
* @cluster_flags: cluster mapping flags
*
* This operation has rendering effects similar to cairo_show_glyphs()
* but, if the target surface supports it, uses the provided text and
* cluster mapping to embed the text for the glyphs shown in the output.
* If the target does not support the extended attributes, this function
* acts like the basic cairo_show_glyphs() as if it had been passed
* @glyphs and @num_glyphs.
*
* The mapping between @utf8 and @glyphs is provided by an array of
* <firstterm>clusters</firstterm>. Each cluster covers a number of
* text bytes and glyphs, and neighboring clusters cover neighboring
* areas of @utf8 and @glyphs. The clusters should collectively cover @utf8
* and @glyphs in entirety.
*
* The first cluster always covers bytes from the beginning of @utf8.
* If @cluster_flags do not have the %CAIRO_TEXT_CLUSTER_FLAG_BACKWARD
* set, the first cluster also covers the beginning
* of @glyphs, otherwise it covers the end of the @glyphs array and
* following clusters move backward.
*
* See #cairo_text_cluster_t for constraints on valid clusters.
*
* Since: 1.8
**/
void
cairo_show_text_glyphs (cairo_t *cr,
const char *utf8,
int utf8_len,
const cairo_glyph_t *glyphs,
int num_glyphs,
const cairo_text_cluster_t *clusters,
int num_clusters,
cairo_text_cluster_flags_t cluster_flags)
{
cairo_status_t status;
 
if (unlikely (cr->status))
return;
 
/* A slew of sanity checks */
 
/* Special case for NULL and -1 */
if (utf8 == NULL && utf8_len == -1)
utf8_len = 0;
 
/* No NULLs for non-zeros */
if ((num_glyphs && glyphs == NULL) ||
(utf8_len && utf8 == NULL) ||
(num_clusters && clusters == NULL)) {
_cairo_set_error (cr, CAIRO_STATUS_NULL_POINTER);
return;
}
 
/* A -1 for utf8_len means NUL-terminated */
if (utf8_len == -1)
utf8_len = strlen (utf8);
 
/* Apart from that, no negatives */
if (num_glyphs < 0 || utf8_len < 0 || num_clusters < 0) {
_cairo_set_error (cr, CAIRO_STATUS_NEGATIVE_COUNT);
return;
}
 
/* Make sure clusters cover the entire glyphs and utf8 arrays,
* and that cluster boundaries are UTF-8 boundaries. */
status = _cairo_validate_text_clusters (utf8, utf8_len,
glyphs, num_glyphs,
clusters, num_clusters, cluster_flags);
if (status == CAIRO_STATUS_INVALID_CLUSTERS) {
/* Either got invalid UTF-8 text, or cluster mapping is bad.
* Differentiate those. */
 
cairo_status_t status2;
 
status2 = _cairo_utf8_to_ucs4 (utf8, utf8_len, NULL, NULL);
if (status2)
status = status2;
 
_cairo_set_error (cr, status);
return;
}
 
if (num_glyphs == 0 && utf8_len == 0)
return;
 
status = _cairo_gstate_show_text_glyphs (cr->gstate,
utf8, utf8_len,
glyphs, num_glyphs,
clusters, num_clusters, cluster_flags);
if (unlikely (status))
_cairo_set_error (cr, status);
}
 
/**
* cairo_text_path:
* @cr: a cairo context
* @utf8: a NUL-terminated string of text encoded in UTF-8, or %NULL
*
* Adds closed paths for text to the current path. The generated
* path if filled, achieves an effect similar to that of
* cairo_show_text().
*
* Text conversion and positioning is done similar to cairo_show_text().
*
* Like cairo_show_text(), After this call the current point is
* moved to the origin of where the next glyph would be placed in
* this same progression. That is, the current point will be at
* the origin of the final glyph offset by its advance values.
* This allows for chaining multiple calls to to cairo_text_path()
* without having to set current point in between.
*
* Note: The cairo_text_path() function call is part of what the cairo
* designers call the "toy" text API. It is convenient for short demos
* and simple programs, but it is not expected to be adequate for
* serious text-using applications. See cairo_glyph_path() for the
* "real" text path API in cairo.
**/
void
cairo_text_path (cairo_t *cr, const char *utf8)
{
cairo_status_t status;
cairo_text_extents_t extents;
cairo_glyph_t stack_glyphs[CAIRO_STACK_ARRAY_LENGTH (cairo_glyph_t)];
cairo_glyph_t *glyphs, *last_glyph;
int num_glyphs;
double x, y;
 
if (unlikely (cr->status))
return;
 
if (utf8 == NULL)
return;
 
cairo_get_current_point (cr, &x, &y);
 
glyphs = stack_glyphs;
num_glyphs = ARRAY_LENGTH (stack_glyphs);
 
status = _cairo_gstate_text_to_glyphs (cr->gstate,
x, y,
utf8, strlen (utf8),
&glyphs, &num_glyphs,
NULL, NULL,
NULL);
 
if (unlikely (status))
goto BAIL;
 
if (num_glyphs == 0)
return;
 
status = _cairo_gstate_glyph_path (cr->gstate,
glyphs, num_glyphs,
cr->path);
 
if (unlikely (status))
goto BAIL;
 
last_glyph = &glyphs[num_glyphs - 1];
status = _cairo_gstate_glyph_extents (cr->gstate,
last_glyph, 1,
&extents);
 
if (unlikely (status))
goto BAIL;
 
x = last_glyph->x + extents.x_advance;
y = last_glyph->y + extents.y_advance;
cairo_move_to (cr, x, y);
 
BAIL:
if (glyphs != stack_glyphs)
cairo_glyph_free (glyphs);
 
if (unlikely (status))
_cairo_set_error (cr, status);
}
 
/**
* cairo_glyph_path:
* @cr: a cairo context
* @glyphs: array of glyphs to show
* @num_glyphs: number of glyphs to show
*
* Adds closed paths for the glyphs to the current path. The generated
* path if filled, achieves an effect similar to that of
* cairo_show_glyphs().
**/
void
cairo_glyph_path (cairo_t *cr, const cairo_glyph_t *glyphs, int num_glyphs)
{
cairo_status_t status;
 
if (unlikely (cr->status))
return;
 
if (num_glyphs == 0)
return;
 
if (num_glyphs < 0) {
_cairo_set_error (cr, CAIRO_STATUS_NEGATIVE_COUNT);
return;
}
 
if (glyphs == NULL) {
_cairo_set_error (cr, CAIRO_STATUS_NULL_POINTER);
return;
}
 
status = _cairo_gstate_glyph_path (cr->gstate,
glyphs, num_glyphs,
cr->path);
if (unlikely (status))
_cairo_set_error (cr, status);
}
 
/**
* cairo_get_operator:
* @cr: a cairo context
*
* Gets the current compositing operator for a cairo context.
*
* Return value: the current compositing operator.
**/
cairo_operator_t
cairo_get_operator (cairo_t *cr)
{
if (unlikely (cr->status))
return CAIRO_GSTATE_OPERATOR_DEFAULT;
 
return _cairo_gstate_get_operator (cr->gstate);
}
 
/**
* cairo_get_tolerance:
* @cr: a cairo context
*
* Gets the current tolerance value, as set by cairo_set_tolerance().
*
* Return value: the current tolerance value.
**/
double
cairo_get_tolerance (cairo_t *cr)
{
if (unlikely (cr->status))
return CAIRO_GSTATE_TOLERANCE_DEFAULT;
 
return _cairo_gstate_get_tolerance (cr->gstate);
}
slim_hidden_def (cairo_get_tolerance);
 
/**
* cairo_get_antialias:
* @cr: a cairo context
*
* Gets the current shape antialiasing mode, as set by cairo_set_shape_antialias().
*
* Return value: the current shape antialiasing mode.
**/
cairo_antialias_t
cairo_get_antialias (cairo_t *cr)
{
if (unlikely (cr->status))
return CAIRO_ANTIALIAS_DEFAULT;
 
return _cairo_gstate_get_antialias (cr->gstate);
}
 
/**
* cairo_has_current_point:
* @cr: a cairo context
*
* Returns whether a current point is defined on the current path.
* See cairo_get_current_point() for details on the current point.
*
* Return value: whether a current point is defined.
*
* Since: 1.6
**/
cairo_bool_t
cairo_has_current_point (cairo_t *cr)
{
if (unlikely (cr->status))
return FALSE;
 
return cr->path->has_current_point;
}
 
/**
* cairo_get_current_point:
* @cr: a cairo context
* @x: return value for X coordinate of the current point
* @y: return value for Y coordinate of the current point
*
* Gets the current point of the current path, which is
* conceptually the final point reached by the path so far.
*
* The current point is returned in the user-space coordinate
* system. If there is no defined current point or if @cr is in an
* error status, @x and @y will both be set to 0.0. It is possible to
* check this in advance with cairo_has_current_point().
*
* Most path construction functions alter the current point. See the
* following for details on how they affect the current point:
* cairo_new_path(), cairo_new_sub_path(),
* cairo_append_path(), cairo_close_path(),
* cairo_move_to(), cairo_line_to(), cairo_curve_to(),
* cairo_rel_move_to(), cairo_rel_line_to(), cairo_rel_curve_to(),
* cairo_arc(), cairo_arc_negative(), cairo_rectangle(),
* cairo_text_path(), cairo_glyph_path(), cairo_stroke_to_path().
*
* Some functions use and alter the current point but do not
* otherwise change current path:
* cairo_show_text().
*
* Some functions unset the current path and as a result, current point:
* cairo_fill(), cairo_stroke().
**/
void
cairo_get_current_point (cairo_t *cr, double *x_ret, double *y_ret)
{
cairo_fixed_t x_fixed, y_fixed;
double x, y;
 
if (cr->status == CAIRO_STATUS_SUCCESS &&
_cairo_path_fixed_get_current_point (cr->path, &x_fixed, &y_fixed))
{
x = _cairo_fixed_to_double (x_fixed);
y = _cairo_fixed_to_double (y_fixed);
_cairo_gstate_backend_to_user (cr->gstate, &x, &y);
}
else
{
x = 0.0;
y = 0.0;
}
 
if (x_ret)
*x_ret = x;
if (y_ret)
*y_ret = y;
}
slim_hidden_def(cairo_get_current_point);
 
/**
* cairo_get_fill_rule:
* @cr: a cairo context
*
* Gets the current fill rule, as set by cairo_set_fill_rule().
*
* Return value: the current fill rule.
**/
cairo_fill_rule_t
cairo_get_fill_rule (cairo_t *cr)
{
if (unlikely (cr->status))
return CAIRO_GSTATE_FILL_RULE_DEFAULT;
 
return _cairo_gstate_get_fill_rule (cr->gstate);
}
 
/**
* cairo_get_line_width:
* @cr: a cairo context
*
* This function returns the current line width value exactly as set by
* cairo_set_line_width(). Note that the value is unchanged even if
* the CTM has changed between the calls to cairo_set_line_width() and
* cairo_get_line_width().
*
* Return value: the current line width.
**/
double
cairo_get_line_width (cairo_t *cr)
{
if (unlikely (cr->status))
return CAIRO_GSTATE_LINE_WIDTH_DEFAULT;
 
return _cairo_gstate_get_line_width (cr->gstate);
}
slim_hidden_def (cairo_get_line_width);
 
/**
* cairo_get_line_cap:
* @cr: a cairo context
*
* Gets the current line cap style, as set by cairo_set_line_cap().
*
* Return value: the current line cap style.
**/
cairo_line_cap_t
cairo_get_line_cap (cairo_t *cr)
{
if (unlikely (cr->status))
return CAIRO_GSTATE_LINE_CAP_DEFAULT;
 
return _cairo_gstate_get_line_cap (cr->gstate);
}
 
/**
* cairo_get_line_join:
* @cr: a cairo context
*
* Gets the current line join style, as set by cairo_set_line_join().
*
* Return value: the current line join style.
**/
cairo_line_join_t
cairo_get_line_join (cairo_t *cr)
{
if (unlikely (cr->status))
return CAIRO_GSTATE_LINE_JOIN_DEFAULT;
 
return _cairo_gstate_get_line_join (cr->gstate);
}
 
/**
* cairo_get_miter_limit:
* @cr: a cairo context
*
* Gets the current miter limit, as set by cairo_set_miter_limit().
*
* Return value: the current miter limit.
**/
double
cairo_get_miter_limit (cairo_t *cr)
{
if (unlikely (cr->status))
return CAIRO_GSTATE_MITER_LIMIT_DEFAULT;
 
return _cairo_gstate_get_miter_limit (cr->gstate);
}
 
/**
* cairo_get_matrix:
* @cr: a cairo context
* @matrix: return value for the matrix
*
* Stores the current transformation matrix (CTM) into @matrix.
**/
void
cairo_get_matrix (cairo_t *cr, cairo_matrix_t *matrix)
{
if (unlikely (cr->status)) {
cairo_matrix_init_identity (matrix);
return;
}
 
_cairo_gstate_get_matrix (cr->gstate, matrix);
}
slim_hidden_def (cairo_get_matrix);
 
/**
* cairo_get_target:
* @cr: a cairo context
*
* Gets the target surface for the cairo context as passed to
* cairo_create().
*
* This function will always return a valid pointer, but the result
* can be a "nil" surface if @cr is already in an error state,
* (ie. cairo_status() <literal>!=</literal> %CAIRO_STATUS_SUCCESS).
* A nil surface is indicated by cairo_surface_status()
* <literal>!=</literal> %CAIRO_STATUS_SUCCESS.
*
* Return value: the target surface. This object is owned by cairo. To
* keep a reference to it, you must call cairo_surface_reference().
**/
cairo_surface_t *
cairo_get_target (cairo_t *cr)
{
if (unlikely (cr->status))
return _cairo_surface_create_in_error (cr->status);
 
return _cairo_gstate_get_original_target (cr->gstate);
}
slim_hidden_def (cairo_get_target);
 
/**
* cairo_get_group_target:
* @cr: a cairo context
*
* Gets the current destination surface for the context. This is either
* the original target surface as passed to cairo_create() or the target
* surface for the current group as started by the most recent call to
* cairo_push_group() or cairo_push_group_with_content().
*
* This function will always return a valid pointer, but the result
* can be a "nil" surface if @cr is already in an error state,
* (ie. cairo_status() <literal>!=</literal> %CAIRO_STATUS_SUCCESS).
* A nil surface is indicated by cairo_surface_status()
* <literal>!=</literal> %CAIRO_STATUS_SUCCESS.
*
* Return value: the target surface. This object is owned by cairo. To
* keep a reference to it, you must call cairo_surface_reference().
*
* Since: 1.2
**/
cairo_surface_t *
cairo_get_group_target (cairo_t *cr)
{
if (unlikely (cr->status))
return _cairo_surface_create_in_error (cr->status);
 
return _cairo_gstate_get_target (cr->gstate);
}
 
/**
* cairo_copy_path:
* @cr: a cairo context
*
* Creates a copy of the current path and returns it to the user as a
* #cairo_path_t. See #cairo_path_data_t for hints on how to iterate
* over the returned data structure.
*
* This function will always return a valid pointer, but the result
* will have no data (<literal>data==%NULL</literal> and
* <literal>num_data==0</literal>), if either of the following
* conditions hold:
*
* <orderedlist>
* <listitem>If there is insufficient memory to copy the path. In this
* case <literal>path->status</literal> will be set to
* %CAIRO_STATUS_NO_MEMORY.</listitem>
* <listitem>If @cr is already in an error state. In this case
* <literal>path->status</literal> will contain the same status that
* would be returned by cairo_status().</listitem>
* </orderedlist>
*
* Return value: the copy of the current path. The caller owns the
* returned object and should call cairo_path_destroy() when finished
* with it.
**/
cairo_path_t *
cairo_copy_path (cairo_t *cr)
{
if (unlikely (cr->status))
return _cairo_path_create_in_error (cr->status);
 
return _cairo_path_create (cr->path, cr->gstate);
}
 
/**
* cairo_copy_path_flat:
* @cr: a cairo context
*
* Gets a flattened copy of the current path and returns it to the
* user as a #cairo_path_t. See #cairo_path_data_t for hints on
* how to iterate over the returned data structure.
*
* This function is like cairo_copy_path() except that any curves
* in the path will be approximated with piecewise-linear
* approximations, (accurate to within the current tolerance
* value). That is, the result is guaranteed to not have any elements
* of type %CAIRO_PATH_CURVE_TO which will instead be replaced by a
* series of %CAIRO_PATH_LINE_TO elements.
*
* This function will always return a valid pointer, but the result
* will have no data (<literal>data==%NULL</literal> and
* <literal>num_data==0</literal>), if either of the following
* conditions hold:
*
* <orderedlist>
* <listitem>If there is insufficient memory to copy the path. In this
* case <literal>path->status</literal> will be set to
* %CAIRO_STATUS_NO_MEMORY.</listitem>
* <listitem>If @cr is already in an error state. In this case
* <literal>path->status</literal> will contain the same status that
* would be returned by cairo_status().</listitem>
* </orderedlist>
*
* Return value: the copy of the current path. The caller owns the
* returned object and should call cairo_path_destroy() when finished
* with it.
**/
cairo_path_t *
cairo_copy_path_flat (cairo_t *cr)
{
if (unlikely (cr->status))
return _cairo_path_create_in_error (cr->status);
 
return _cairo_path_create_flat (cr->path, cr->gstate);
}
 
/**
* cairo_append_path:
* @cr: a cairo context
* @path: path to be appended
*
* Append the @path onto the current path. The @path may be either the
* return value from one of cairo_copy_path() or
* cairo_copy_path_flat() or it may be constructed manually. See
* #cairo_path_t for details on how the path data structure should be
* initialized, and note that <literal>path->status</literal> must be
* initialized to %CAIRO_STATUS_SUCCESS.
**/
void
cairo_append_path (cairo_t *cr,
const cairo_path_t *path)
{
cairo_status_t status;
 
if (unlikely (cr->status))
return;
 
if (path == NULL) {
_cairo_set_error (cr, CAIRO_STATUS_NULL_POINTER);
return;
}
 
if (path->status) {
if (path->status > CAIRO_STATUS_SUCCESS &&
path->status <= CAIRO_STATUS_LAST_STATUS)
_cairo_set_error (cr, path->status);
else
_cairo_set_error (cr, CAIRO_STATUS_INVALID_STATUS);
return;
}
 
if (path->num_data == 0)
return;
 
if (path->data == NULL) {
_cairo_set_error (cr, CAIRO_STATUS_NULL_POINTER);
return;
}
 
status = _cairo_path_append_to_context (path, cr);
if (unlikely (status))
_cairo_set_error (cr, status);
}
 
/**
* cairo_status:
* @cr: a cairo context
*
* Checks whether an error has previously occurred for this context.
*
* Returns: the current status of this context, see #cairo_status_t
**/
cairo_status_t
cairo_status (cairo_t *cr)
{
return cr->status;
}
slim_hidden_def (cairo_status);
/programs/develop/libraries/cairo/src/cairo.h
0,0 → 1,2684
/* 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., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
*/
 
#ifndef CAIRO_H
#define CAIRO_H
 
#include "cairo-version.h"
#include "cairo-features.h"
#include "cairo-deprecated.h"
 
#ifdef __cplusplus
# define CAIRO_BEGIN_DECLS extern "C" {
# define CAIRO_END_DECLS }
#else
# define CAIRO_BEGIN_DECLS
# define CAIRO_END_DECLS
#endif
 
#ifndef cairo_public
# if defined (_MSC_VER) && ! defined (CAIRO_WIN32_STATIC_BUILD)
# define cairo_public __declspec(dllimport)
# else
# define cairo_public
# endif
#endif
 
CAIRO_BEGIN_DECLS
 
#define CAIRO_VERSION_ENCODE(major, minor, micro) ( \
((major) * 10000) \
+ ((minor) * 100) \
+ ((micro) * 1))
 
#define CAIRO_VERSION CAIRO_VERSION_ENCODE( \
CAIRO_VERSION_MAJOR, \
CAIRO_VERSION_MINOR, \
CAIRO_VERSION_MICRO)
 
 
#define CAIRO_VERSION_STRINGIZE_(major, minor, micro) \
#major"."#minor"."#micro
#define CAIRO_VERSION_STRINGIZE(major, minor, micro) \
CAIRO_VERSION_STRINGIZE_(major, minor, micro)
 
#define CAIRO_VERSION_STRING CAIRO_VERSION_STRINGIZE( \
CAIRO_VERSION_MAJOR, \
CAIRO_VERSION_MINOR, \
CAIRO_VERSION_MICRO)
 
 
cairo_public int
cairo_version (void);
 
cairo_public const char*
cairo_version_string (void);
 
/**
* cairo_bool_t:
*
* #cairo_bool_t is used for boolean values. Returns of type
* #cairo_bool_t will always be either 0 or 1, but testing against
* these values explicitly is not encouraged; just use the
* value as a boolean condition.
*
* <informalexample><programlisting>
* if (cairo_in_stroke (cr, x, y)) {
* /<!-- -->* do something *<!-- -->/
* }
* </programlisting></informalexample>
**/
typedef int cairo_bool_t;
 
/**
* cairo_t:
*
* A #cairo_t contains the current state of the rendering device,
* including coordinates of yet to be drawn shapes.
*
* Cairo contexts, as #cairo_t objects are named, are central to
* cairo and all drawing with cairo is always done to a #cairo_t
* object.
*
* Memory management of #cairo_t is done with
* cairo_reference() and cairo_destroy().
**/
typedef struct _cairo cairo_t;
 
/**
* cairo_surface_t:
*
* A #cairo_surface_t represents an image, either as the destination
* of a drawing operation or as source when drawing onto another
* surface. To draw to a #cairo_surface_t, create a cairo context
* with the surface as the target, using cairo_create().
*
* There are different subtypes of #cairo_surface_t for
* different drawing backends; for example, cairo_image_surface_create()
* creates a bitmap image in memory.
* The type of a surface can be queried with cairo_surface_get_type().
*
* The initial contents of a surface after creation depend upon the manner
* of its creation. If cairo creates the surface and backing storage for
* the user, it will be initially cleared; for example,
* cairo_image_surface_create() and cairo_surface_create_similar().
* Alternatively, if the user passes in a reference to some backing storage
* and asks cairo to wrap that in a #cairo_surface_t, then the contents are
* not modified; for example, cairo_image_surface_create_for_data() and
* cairo_xlib_surface_create().
*
* Memory management of #cairo_surface_t is done with
* cairo_surface_reference() and cairo_surface_destroy().
**/
typedef struct _cairo_surface cairo_surface_t;
 
/**
* cairo_device_t:
*
* A #cairo_device_t represents the driver interface for drawing
* operations to a #cairo_surface_t. There are different subtypes of
* #cairo_device_t for different drawing backends; for example,
* cairo_xcb_device_create() creates a device that wraps the connection
* to an X Windows System using the XCB library.
*
* The type of a device can be queried with cairo_device_get_type().
*
* Memory management of #cairo_device_t is done with
* cairo_device_reference() and cairo_device_destroy().
*
* Since: 1.10
**/
typedef struct _cairo_device cairo_device_t;
 
/**
* cairo_matrix_t:
* @xx: xx component of the affine transformation
* @yx: yx component of the affine transformation
* @xy: xy component of the affine transformation
* @yy: yy component of the affine transformation
* @x0: X translation component of the affine transformation
* @y0: Y translation component of the affine transformation
*
* A #cairo_matrix_t holds an affine transformation, such as a scale,
* rotation, shear, or a combination of those. The transformation of
* a point (x, y) is given by:
* <programlisting>
* x_new = xx * x + xy * y + x0;
* y_new = yx * x + yy * y + y0;
* </programlisting>
**/
typedef struct _cairo_matrix {
double xx; double yx;
double xy; double yy;
double x0; double y0;
} cairo_matrix_t;
 
/**
* cairo_pattern_t:
*
* A #cairo_pattern_t represents a source when drawing onto a
* surface. There are different subtypes of #cairo_pattern_t,
* for different types of sources; for example,
* cairo_pattern_create_rgb() creates a pattern for a solid
* opaque color.
*
* Other than various cairo_pattern_create_<emphasis>type</emphasis>()
* functions, some of the pattern types can be implicitly created
* using various cairo_set_source_<emphasis>type</emphasis>() functions;
* for example cairo_set_source_rgb().
*
* The type of a pattern can be queried with cairo_pattern_get_type().
*
* Memory management of #cairo_pattern_t is done with
* cairo_pattern_reference() and cairo_pattern_destroy().
**/
typedef struct _cairo_pattern cairo_pattern_t;
 
/**
* cairo_destroy_func_t:
* @data: The data element being destroyed.
*
* #cairo_destroy_func_t the type of function which is called when a
* data element is destroyed. It is passed the pointer to the data
* element and should free any memory and resources allocated for it.
**/
typedef void (*cairo_destroy_func_t) (void *data);
 
/**
* cairo_user_data_key_t:
* @unused: not used; ignore.
*
* #cairo_user_data_key_t is used for attaching user data to cairo
* data structures. The actual contents of the struct is never used,
* and there is no need to initialize the object; only the unique
* address of a #cairo_data_key_t object is used. Typically, you
* would just use the address of a static #cairo_data_key_t object.
**/
typedef struct _cairo_user_data_key {
int unused;
} cairo_user_data_key_t;
 
/**
* cairo_status_t:
* @CAIRO_STATUS_SUCCESS: no error has occurred
* @CAIRO_STATUS_NO_MEMORY: out of memory
* @CAIRO_STATUS_INVALID_RESTORE: cairo_restore() called without matching cairo_save()
* @CAIRO_STATUS_INVALID_POP_GROUP: no saved group to pop, i.e. cairo_pop_group() without matching cairo_push_group()
* @CAIRO_STATUS_NO_CURRENT_POINT: no current point defined
* @CAIRO_STATUS_INVALID_MATRIX: invalid matrix (not invertible)
* @CAIRO_STATUS_INVALID_STATUS: invalid value for an input #cairo_status_t
* @CAIRO_STATUS_NULL_POINTER: %NULL pointer
* @CAIRO_STATUS_INVALID_STRING: input string not valid UTF-8
* @CAIRO_STATUS_INVALID_PATH_DATA: input path data not valid
* @CAIRO_STATUS_READ_ERROR: error while reading from input stream
* @CAIRO_STATUS_WRITE_ERROR: error while writing to output stream
* @CAIRO_STATUS_SURFACE_FINISHED: target surface has been finished
* @CAIRO_STATUS_SURFACE_TYPE_MISMATCH: the surface type is not appropriate for the operation
* @CAIRO_STATUS_PATTERN_TYPE_MISMATCH: the pattern type is not appropriate for the operation
* @CAIRO_STATUS_INVALID_CONTENT: invalid value for an input #cairo_content_t
* @CAIRO_STATUS_INVALID_FORMAT: invalid value for an input #cairo_format_t
* @CAIRO_STATUS_INVALID_VISUAL: invalid value for an input Visual*
* @CAIRO_STATUS_FILE_NOT_FOUND: file not found
* @CAIRO_STATUS_INVALID_DASH: invalid value for a dash setting
* @CAIRO_STATUS_INVALID_DSC_COMMENT: invalid value for a DSC comment (Since 1.2)
* @CAIRO_STATUS_INVALID_INDEX: invalid index passed to getter (Since 1.4)
* @CAIRO_STATUS_CLIP_NOT_REPRESENTABLE: clip region not representable in desired format (Since 1.4)
* @CAIRO_STATUS_TEMP_FILE_ERROR: error creating or writing to a temporary file (Since 1.6)
* @CAIRO_STATUS_INVALID_STRIDE: invalid value for stride (Since 1.6)
* @CAIRO_STATUS_FONT_TYPE_MISMATCH: the font type is not appropriate for the operation (Since 1.8)
* @CAIRO_STATUS_USER_FONT_IMMUTABLE: the user-font is immutable (Since 1.8)
* @CAIRO_STATUS_USER_FONT_ERROR: error occurred in a user-font callback function (Since 1.8)
* @CAIRO_STATUS_NEGATIVE_COUNT: negative number used where it is not allowed (Since 1.8)
* @CAIRO_STATUS_INVALID_CLUSTERS: input clusters do not represent the accompanying text and glyph array (Since 1.8)
* @CAIRO_STATUS_INVALID_SLANT: invalid value for an input #cairo_font_slant_t (Since 1.8)
* @CAIRO_STATUS_INVALID_WEIGHT: invalid value for an input #cairo_font_weight_t (Since 1.8)
* @CAIRO_STATUS_INVALID_SIZE: invalid value (typically too big) for the size of the input (surface, pattern, etc.) (Since 1.10)
* @CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED: user-font method not implemented (Since 1.10)
* @CAIRO_STATUS_DEVICE_TYPE_MISMATCH: the device type is not appropriate for the operation (Since 1.10)
* @CAIRO_STATUS_DEVICE_ERROR: an operation to the device caused an unspecified error (Since 1.10)
* @CAIRO_STATUS_LAST_STATUS: this is a special value indicating the number of
* status values defined in this enumeration. When using this value, note
* that the version of cairo at run-time may have additional status values
* defined than the value of this symbol at compile-time. (Since 1.10)
*
* #cairo_status_t is used to indicate errors that can occur when
* using Cairo. In some cases it is returned directly by functions.
* but when using #cairo_t, the last error, if any, is stored in
* the context and can be retrieved with cairo_status().
*
* New entries may be added in future versions. Use cairo_status_to_string()
* to get a human-readable representation of an error message.
**/
typedef enum _cairo_status {
CAIRO_STATUS_SUCCESS = 0,
 
CAIRO_STATUS_NO_MEMORY,
CAIRO_STATUS_INVALID_RESTORE,
CAIRO_STATUS_INVALID_POP_GROUP,
CAIRO_STATUS_NO_CURRENT_POINT,
CAIRO_STATUS_INVALID_MATRIX,
CAIRO_STATUS_INVALID_STATUS,
CAIRO_STATUS_NULL_POINTER,
CAIRO_STATUS_INVALID_STRING,
CAIRO_STATUS_INVALID_PATH_DATA,
CAIRO_STATUS_READ_ERROR,
CAIRO_STATUS_WRITE_ERROR,
CAIRO_STATUS_SURFACE_FINISHED,
CAIRO_STATUS_SURFACE_TYPE_MISMATCH,
CAIRO_STATUS_PATTERN_TYPE_MISMATCH,
CAIRO_STATUS_INVALID_CONTENT,
CAIRO_STATUS_INVALID_FORMAT,
CAIRO_STATUS_INVALID_VISUAL,
CAIRO_STATUS_FILE_NOT_FOUND,
CAIRO_STATUS_INVALID_DASH,
CAIRO_STATUS_INVALID_DSC_COMMENT,
CAIRO_STATUS_INVALID_INDEX,
CAIRO_STATUS_CLIP_NOT_REPRESENTABLE,
CAIRO_STATUS_TEMP_FILE_ERROR,
CAIRO_STATUS_INVALID_STRIDE,
CAIRO_STATUS_FONT_TYPE_MISMATCH,
CAIRO_STATUS_USER_FONT_IMMUTABLE,
CAIRO_STATUS_USER_FONT_ERROR,
CAIRO_STATUS_NEGATIVE_COUNT,
CAIRO_STATUS_INVALID_CLUSTERS,
CAIRO_STATUS_INVALID_SLANT,
CAIRO_STATUS_INVALID_WEIGHT,
CAIRO_STATUS_INVALID_SIZE,
CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED,
CAIRO_STATUS_DEVICE_TYPE_MISMATCH,
CAIRO_STATUS_DEVICE_ERROR,
 
CAIRO_STATUS_LAST_STATUS
} cairo_status_t;
 
/**
* cairo_content_t:
* @CAIRO_CONTENT_COLOR: The surface will hold color content only.
* @CAIRO_CONTENT_ALPHA: The surface will hold alpha content only.
* @CAIRO_CONTENT_COLOR_ALPHA: The surface will hold color and alpha content.
*
* #cairo_content_t is used to describe the content that a surface will
* contain, whether color information, alpha information (translucence
* vs. opacity), or both.
*
* Note: The large values here are designed to keep #cairo_content_t
* values distinct from #cairo_format_t values so that the
* implementation can detect the error if users confuse the two types.
**/
typedef enum _cairo_content {
CAIRO_CONTENT_COLOR = 0x1000,
CAIRO_CONTENT_ALPHA = 0x2000,
CAIRO_CONTENT_COLOR_ALPHA = 0x3000
} cairo_content_t;
 
/**
* cairo_write_func_t:
* @closure: the output closure
* @data: the buffer containing the data to write
* @length: the amount of data to write
*
* #cairo_write_func_t is the type of function which is called when a
* backend needs to write data to an output stream. It is passed the
* closure which was specified by the user at the time the write
* function was registered, the data to write and the length of the
* data in bytes. The write function should return
* %CAIRO_STATUS_SUCCESS if all the data was successfully written,
* %CAIRO_STATUS_WRITE_ERROR otherwise.
*
* Returns: the status code of the write operation
**/
typedef cairo_status_t (*cairo_write_func_t) (void *closure,
const unsigned char *data,
unsigned int length);
 
/**
* cairo_read_func_t:
* @closure: the input closure
* @data: the buffer into which to read the data
* @length: the amount of data to read
*
* #cairo_read_func_t is the type of function which is called when a
* backend needs to read data from an input stream. It is passed the
* closure which was specified by the user at the time the read
* function was registered, the buffer to read the data into and the
* length of the data in bytes. The read function should return
* %CAIRO_STATUS_SUCCESS if all the data was successfully read,
* %CAIRO_STATUS_READ_ERROR otherwise.
*
* Returns: the status code of the read operation
**/
typedef cairo_status_t (*cairo_read_func_t) (void *closure,
unsigned char *data,
unsigned int length);
 
/* Functions for manipulating state objects */
cairo_public cairo_t *
cairo_create (cairo_surface_t *target);
 
cairo_public cairo_t *
cairo_reference (cairo_t *cr);
 
cairo_public void
cairo_destroy (cairo_t *cr);
 
cairo_public unsigned int
cairo_get_reference_count (cairo_t *cr);
 
cairo_public void *
cairo_get_user_data (cairo_t *cr,
const cairo_user_data_key_t *key);
 
cairo_public cairo_status_t
cairo_set_user_data (cairo_t *cr,
const cairo_user_data_key_t *key,
void *user_data,
cairo_destroy_func_t destroy);
 
cairo_public void
cairo_save (cairo_t *cr);
 
cairo_public void
cairo_restore (cairo_t *cr);
 
cairo_public void
cairo_push_group (cairo_t *cr);
 
cairo_public void
cairo_push_group_with_content (cairo_t *cr, cairo_content_t content);
 
cairo_public cairo_pattern_t *
cairo_pop_group (cairo_t *cr);
 
cairo_public void
cairo_pop_group_to_source (cairo_t *cr);
 
/* Modify state */
 
/**
* cairo_operator_t:
* @CAIRO_OPERATOR_CLEAR: clear destination layer (bounded)
* @CAIRO_OPERATOR_SOURCE: replace destination layer (bounded)
* @CAIRO_OPERATOR_OVER: draw source layer on top of destination layer
* (bounded)
* @CAIRO_OPERATOR_IN: draw source where there was destination content
* (unbounded)
* @CAIRO_OPERATOR_OUT: draw source where there was no destination
* content (unbounded)
* @CAIRO_OPERATOR_ATOP: draw source on top of destination content and
* only there
* @CAIRO_OPERATOR_DEST: ignore the source
* @CAIRO_OPERATOR_DEST_OVER: draw destination on top of source
* @CAIRO_OPERATOR_DEST_IN: leave destination only where there was
* source content (unbounded)
* @CAIRO_OPERATOR_DEST_OUT: leave destination only where there was no
* source content
* @CAIRO_OPERATOR_DEST_ATOP: leave destination on top of source content
* and only there (unbounded)
* @CAIRO_OPERATOR_XOR: source and destination are shown where there is only
* one of them
* @CAIRO_OPERATOR_ADD: source and destination layers are accumulated
* @CAIRO_OPERATOR_SATURATE: like over, but assuming source and dest are
* disjoint geometries
* @CAIRO_OPERATOR_MULTIPLY: source and destination layers are multiplied.
* This causes the result to be at least as dark as the darker inputs.
* @CAIRO_OPERATOR_SCREEN: source and destination are complemented and
* multiplied. This causes the result to be at least as light as the lighter
* inputs.
* @CAIRO_OPERATOR_OVERLAY: multiplies or screens, depending on the
* lightness of the destination color.
* @CAIRO_OPERATOR_DARKEN: replaces the destination with the source if it
* is darker, otherwise keeps the source.
* @CAIRO_OPERATOR_LIGHTEN: replaces the destination with the source if it
* is lighter, otherwise keeps the source.
* @CAIRO_OPERATOR_COLOR_DODGE: brightens the destination color to reflect
* the source color.
* @CAIRO_OPERATOR_COLOR_BURN: darkens the destination color to reflect
* the source color.
* @CAIRO_OPERATOR_HARD_LIGHT: Multiplies or screens, dependant on source
* color.
* @CAIRO_OPERATOR_SOFT_LIGHT: Darkens or lightens, dependant on source
* color.
* @CAIRO_OPERATOR_DIFFERENCE: Takes the difference of the source and
* destination color.
* @CAIRO_OPERATOR_EXCLUSION: Produces an effect similar to difference, but
* with lower contrast.
* @CAIRO_OPERATOR_HSL_HUE: Creates a color with the hue of the source
* and the saturation and luminosity of the target.
* @CAIRO_OPERATOR_HSL_SATURATION: Creates a color with the saturation
* of the source and the hue and luminosity of the target. Painting with
* this mode onto a gray area prduces no change.
* @CAIRO_OPERATOR_HSL_COLOR: Creates a color with the hue and saturation
* of the source and the luminosity of the target. This preserves the gray
* levels of the target and is useful for coloring monochrome images or
* tinting color images.
* @CAIRO_OPERATOR_HSL_LUMINOSITY: Creates a color with the luminosity of
* the source and the hue and saturation of the target. This produces an
* inverse effect to @CAIRO_OPERATOR_HSL_COLOR.
*
* #cairo_operator_t is used to set the compositing operator for all cairo
* drawing operations.
*
* The default operator is %CAIRO_OPERATOR_OVER.
*
* The operators marked as <firstterm>unbounded</firstterm> modify their
* destination even outside of the mask layer (that is, their effect is not
* bound by the mask layer). However, their effect can still be limited by
* way of clipping.
*
* To keep things simple, the operator descriptions here
* document the behavior for when both source and destination are either fully
* transparent or fully opaque. The actual implementation works for
* translucent layers too.
* For a more detailed explanation of the effects of each operator, including
* the mathematical definitions, see
* <ulink url="http://cairographics.org/operators/">http://cairographics.org/operators/</ulink>.
**/
typedef enum _cairo_operator {
CAIRO_OPERATOR_CLEAR,
 
CAIRO_OPERATOR_SOURCE,
CAIRO_OPERATOR_OVER,
CAIRO_OPERATOR_IN,
CAIRO_OPERATOR_OUT,
CAIRO_OPERATOR_ATOP,
 
CAIRO_OPERATOR_DEST,
CAIRO_OPERATOR_DEST_OVER,
CAIRO_OPERATOR_DEST_IN,
CAIRO_OPERATOR_DEST_OUT,
CAIRO_OPERATOR_DEST_ATOP,
 
CAIRO_OPERATOR_XOR,
CAIRO_OPERATOR_ADD,
CAIRO_OPERATOR_SATURATE,
 
CAIRO_OPERATOR_MULTIPLY,
CAIRO_OPERATOR_SCREEN,
CAIRO_OPERATOR_OVERLAY,
CAIRO_OPERATOR_DARKEN,
CAIRO_OPERATOR_LIGHTEN,
CAIRO_OPERATOR_COLOR_DODGE,
CAIRO_OPERATOR_COLOR_BURN,
CAIRO_OPERATOR_HARD_LIGHT,
CAIRO_OPERATOR_SOFT_LIGHT,
CAIRO_OPERATOR_DIFFERENCE,
CAIRO_OPERATOR_EXCLUSION,
CAIRO_OPERATOR_HSL_HUE,
CAIRO_OPERATOR_HSL_SATURATION,
CAIRO_OPERATOR_HSL_COLOR,
CAIRO_OPERATOR_HSL_LUMINOSITY
} cairo_operator_t;
 
cairo_public void
cairo_set_operator (cairo_t *cr, cairo_operator_t op);
 
cairo_public void
cairo_set_source (cairo_t *cr, cairo_pattern_t *source);
 
cairo_public void
cairo_set_source_rgb (cairo_t *cr, double red, double green, double blue);
 
cairo_public void
cairo_set_source_rgba (cairo_t *cr,
double red, double green, double blue,
double alpha);
 
cairo_public void
cairo_set_source_surface (cairo_t *cr,
cairo_surface_t *surface,
double x,
double y);
 
cairo_public void
cairo_set_tolerance (cairo_t *cr, double tolerance);
 
/**
* cairo_antialias_t:
* @CAIRO_ANTIALIAS_DEFAULT: Use the default antialiasing for
* the subsystem and target device
* @CAIRO_ANTIALIAS_NONE: Use a bilevel alpha mask
* @CAIRO_ANTIALIAS_GRAY: Perform single-color antialiasing (using
* shades of gray for black text on a white background, for example).
* @CAIRO_ANTIALIAS_SUBPIXEL: Perform antialiasing by taking
* advantage of the order of subpixel elements on devices
* such as LCD panels
*
* Specifies the type of antialiasing to do when rendering text or shapes.
**/
typedef enum _cairo_antialias {
CAIRO_ANTIALIAS_DEFAULT,
CAIRO_ANTIALIAS_NONE,
CAIRO_ANTIALIAS_GRAY,
CAIRO_ANTIALIAS_SUBPIXEL
} cairo_antialias_t;
 
cairo_public void
cairo_set_antialias (cairo_t *cr, cairo_antialias_t antialias);
 
/**
* cairo_fill_rule_t:
* @CAIRO_FILL_RULE_WINDING: If the path crosses the ray from
* left-to-right, counts +1. If the path crosses the ray
* from right to left, counts -1. (Left and right are determined
* from the perspective of looking along the ray from the starting
* point.) If the total count is non-zero, the point will be filled.
* @CAIRO_FILL_RULE_EVEN_ODD: Counts the total number of
* intersections, without regard to the orientation of the contour. If
* the total number of intersections is odd, the point will be
* filled.
*
* #cairo_fill_rule_t is used to select how paths are filled. For both
* fill rules, whether or not a point is included in the fill is
* determined by taking a ray from that point to infinity and looking
* at intersections with the path. The ray can be in any direction,
* as long as it doesn't pass through the end point of a segment
* or have a tricky intersection such as intersecting tangent to the path.
* (Note that filling is not actually implemented in this way. This
* is just a description of the rule that is applied.)
*
* The default fill rule is %CAIRO_FILL_RULE_WINDING.
*
* New entries may be added in future versions.
**/
typedef enum _cairo_fill_rule {
CAIRO_FILL_RULE_WINDING,
CAIRO_FILL_RULE_EVEN_ODD
} cairo_fill_rule_t;
 
cairo_public void
cairo_set_fill_rule (cairo_t *cr, cairo_fill_rule_t fill_rule);
 
cairo_public void
cairo_set_line_width (cairo_t *cr, double width);
 
/**
* cairo_line_cap_t:
* @CAIRO_LINE_CAP_BUTT: start(stop) the line exactly at the start(end) point
* @CAIRO_LINE_CAP_ROUND: use a round ending, the center of the circle is the end point
* @CAIRO_LINE_CAP_SQUARE: use squared ending, the center of the square is the end point
*
* Specifies how to render the endpoints of the path when stroking.
*
* The default line cap style is %CAIRO_LINE_CAP_BUTT.
**/
typedef enum _cairo_line_cap {
CAIRO_LINE_CAP_BUTT,
CAIRO_LINE_CAP_ROUND,
CAIRO_LINE_CAP_SQUARE
} cairo_line_cap_t;
 
cairo_public void
cairo_set_line_cap (cairo_t *cr, cairo_line_cap_t line_cap);
 
/**
* cairo_line_join_t:
* @CAIRO_LINE_JOIN_MITER: use a sharp (angled) corner, see
* cairo_set_miter_limit()
* @CAIRO_LINE_JOIN_ROUND: use a rounded join, the center of the circle is the
* joint point
* @CAIRO_LINE_JOIN_BEVEL: use a cut-off join, the join is cut off at half
* the line width from the joint point
*
* Specifies how to render the junction of two lines when stroking.
*
* The default line join style is %CAIRO_LINE_JOIN_MITER.
**/
typedef enum _cairo_line_join {
CAIRO_LINE_JOIN_MITER,
CAIRO_LINE_JOIN_ROUND,
CAIRO_LINE_JOIN_BEVEL
} cairo_line_join_t;
 
cairo_public void
cairo_set_line_join (cairo_t *cr, cairo_line_join_t line_join);
 
cairo_public void
cairo_set_dash (cairo_t *cr,
const double *dashes,
int num_dashes,
double offset);
 
cairo_public void
cairo_set_miter_limit (cairo_t *cr, double limit);
 
cairo_public void
cairo_translate (cairo_t *cr, double tx, double ty);
 
cairo_public void
cairo_scale (cairo_t *cr, double sx, double sy);
 
cairo_public void
cairo_rotate (cairo_t *cr, double angle);
 
cairo_public void
cairo_transform (cairo_t *cr,
const cairo_matrix_t *matrix);
 
cairo_public void
cairo_set_matrix (cairo_t *cr,
const cairo_matrix_t *matrix);
 
cairo_public void
cairo_identity_matrix (cairo_t *cr);
 
cairo_public void
cairo_user_to_device (cairo_t *cr, double *x, double *y);
 
cairo_public void
cairo_user_to_device_distance (cairo_t *cr, double *dx, double *dy);
 
cairo_public void
cairo_device_to_user (cairo_t *cr, double *x, double *y);
 
cairo_public void
cairo_device_to_user_distance (cairo_t *cr, double *dx, double *dy);
 
/* Path creation functions */
cairo_public void
cairo_new_path (cairo_t *cr);
 
cairo_public void
cairo_move_to (cairo_t *cr, double x, double y);
 
cairo_public void
cairo_new_sub_path (cairo_t *cr);
 
cairo_public void
cairo_line_to (cairo_t *cr, double x, double y);
 
cairo_public void
cairo_curve_to (cairo_t *cr,
double x1, double y1,
double x2, double y2,
double x3, double y3);
 
cairo_public void
cairo_arc (cairo_t *cr,
double xc, double yc,
double radius,
double angle1, double angle2);
 
cairo_public void
cairo_arc_negative (cairo_t *cr,
double xc, double yc,
double radius,
double angle1, double angle2);
 
/* XXX: NYI
cairo_public void
cairo_arc_to (cairo_t *cr,
double x1, double y1,
double x2, double y2,
double radius);
*/
 
cairo_public void
cairo_rel_move_to (cairo_t *cr, double dx, double dy);
 
cairo_public void
cairo_rel_line_to (cairo_t *cr, double dx, double dy);
 
cairo_public void
cairo_rel_curve_to (cairo_t *cr,
double dx1, double dy1,
double dx2, double dy2,
double dx3, double dy3);
 
cairo_public void
cairo_rectangle (cairo_t *cr,
double x, double y,
double width, double height);
 
/* XXX: NYI
cairo_public void
cairo_stroke_to_path (cairo_t *cr);
*/
 
cairo_public void
cairo_close_path (cairo_t *cr);
 
cairo_public void
cairo_path_extents (cairo_t *cr,
double *x1, double *y1,
double *x2, double *y2);
 
/* Painting functions */
cairo_public void
cairo_paint (cairo_t *cr);
 
cairo_public void
cairo_paint_with_alpha (cairo_t *cr,
double alpha);
 
cairo_public void
cairo_mask (cairo_t *cr,
cairo_pattern_t *pattern);
 
cairo_public void
cairo_mask_surface (cairo_t *cr,
cairo_surface_t *surface,
double surface_x,
double surface_y);
 
cairo_public void
cairo_stroke (cairo_t *cr);
 
cairo_public void
cairo_stroke_preserve (cairo_t *cr);
 
cairo_public void
cairo_fill (cairo_t *cr);
 
cairo_public void
cairo_fill_preserve (cairo_t *cr);
 
cairo_public void
cairo_copy_page (cairo_t *cr);
 
cairo_public void
cairo_show_page (cairo_t *cr);
 
/* Insideness testing */
cairo_public cairo_bool_t
cairo_in_stroke (cairo_t *cr, double x, double y);
 
cairo_public cairo_bool_t
cairo_in_fill (cairo_t *cr, double x, double y);
 
cairo_public cairo_bool_t
cairo_in_clip (cairo_t *cr, double x, double y);
 
/* Rectangular extents */
cairo_public void
cairo_stroke_extents (cairo_t *cr,
double *x1, double *y1,
double *x2, double *y2);
 
cairo_public void
cairo_fill_extents (cairo_t *cr,
double *x1, double *y1,
double *x2, double *y2);
 
/* Clipping */
cairo_public void
cairo_reset_clip (cairo_t *cr);
 
cairo_public void
cairo_clip (cairo_t *cr);
 
cairo_public void
cairo_clip_preserve (cairo_t *cr);
 
cairo_public void
cairo_clip_extents (cairo_t *cr,
double *x1, double *y1,
double *x2, double *y2);
 
/**
* cairo_rectangle_t:
* @x: X coordinate of the left side of the rectangle
* @y: Y coordinate of the the top side of the rectangle
* @width: width of the rectangle
* @height: height of the rectangle
*
* A data structure for holding a rectangle.
*
* Since: 1.4
**/
typedef struct _cairo_rectangle {
double x, y, width, height;
} cairo_rectangle_t;
 
/**
* cairo_rectangle_list_t:
* @status: Error status of the rectangle list
* @rectangles: Array containing the rectangles
* @num_rectangles: Number of rectangles in this list
*
* A data structure for holding a dynamically allocated
* array of rectangles.
*
* Since: 1.4
**/
typedef struct _cairo_rectangle_list {
cairo_status_t status;
cairo_rectangle_t *rectangles;
int num_rectangles;
} cairo_rectangle_list_t;
 
cairo_public cairo_rectangle_list_t *
cairo_copy_clip_rectangle_list (cairo_t *cr);
 
cairo_public void
cairo_rectangle_list_destroy (cairo_rectangle_list_t *rectangle_list);
 
/* Font/Text functions */
 
/**
* cairo_scaled_font_t:
*
* A #cairo_scaled_font_t is a font scaled to a particular size and device
* resolution. A #cairo_scaled_font_t is most useful for low-level font
* usage where a library or application wants to cache a reference
* to a scaled font to speed up the computation of metrics.
*
* There are various types of scaled fonts, depending on the
* <firstterm>font backend</firstterm> they use. The type of a
* scaled font can be queried using cairo_scaled_font_get_type().
*
* Memory management of #cairo_scaled_font_t is done with
* cairo_scaled_font_reference() and cairo_scaled_font_destroy().
**/
typedef struct _cairo_scaled_font cairo_scaled_font_t;
 
/**
* cairo_font_face_t:
*
* A #cairo_font_face_t specifies all aspects of a font other
* than the size or font matrix (a font matrix is used to distort
* a font by sheering it or scaling it unequally in the two
* directions) . A font face can be set on a #cairo_t by using
* cairo_set_font_face(); the size and font matrix are set with
* cairo_set_font_size() and cairo_set_font_matrix().
*
* There are various types of font faces, depending on the
* <firstterm>font backend</firstterm> they use. The type of a
* font face can be queried using cairo_font_face_get_type().
*
* Memory management of #cairo_font_face_t is done with
* cairo_font_face_reference() and cairo_font_face_destroy().
**/
typedef struct _cairo_font_face cairo_font_face_t;
 
/**
* cairo_glyph_t:
* @index: glyph index in the font. The exact interpretation of the
* glyph index depends on the font technology being used.
* @x: the offset in the X direction between the origin used for
* drawing or measuring the string and the origin of this glyph.
* @y: the offset in the Y direction between the origin used for
* drawing or measuring the string and the origin of this glyph.
*
* The #cairo_glyph_t structure holds information about a single glyph
* when drawing or measuring text. A font is (in simple terms) a
* collection of shapes used to draw text. A glyph is one of these
* shapes. There can be multiple glyphs for a single character
* (alternates to be used in different contexts, for example), or a
* glyph can be a <firstterm>ligature</firstterm> of multiple
* characters. Cairo doesn't expose any way of converting input text
* into glyphs, so in order to use the Cairo interfaces that take
* arrays of glyphs, you must directly access the appropriate
* underlying font system.
*
* Note that the offsets given by @x and @y are not cumulative. When
* drawing or measuring text, each glyph is individually positioned
* with respect to the overall origin
**/
typedef struct {
unsigned long index;
double x;
double y;
} cairo_glyph_t;
 
cairo_public cairo_glyph_t *
cairo_glyph_allocate (int num_glyphs);
 
cairo_public void
cairo_glyph_free (cairo_glyph_t *glyphs);
 
/**
* cairo_text_cluster_t:
* @num_bytes: the number of bytes of UTF-8 text covered by cluster
* @num_glyphs: the number of glyphs covered by cluster
*
* The #cairo_text_cluster_t structure holds information about a single
* <firstterm>text cluster</firstterm>. A text cluster is a minimal
* mapping of some glyphs corresponding to some UTF-8 text.
*
* For a cluster to be valid, both @num_bytes and @num_glyphs should
* be non-negative, and at least one should be non-zero.
* Note that clusters with zero glyphs are not as well supported as
* normal clusters. For example, PDF rendering applications typically
* ignore those clusters when PDF text is being selected.
*
* See cairo_show_text_glyphs() for how clusters are used in advanced
* text operations.
*
* Since: 1.8
**/
typedef struct {
int num_bytes;
int num_glyphs;
} cairo_text_cluster_t;
 
cairo_public cairo_text_cluster_t *
cairo_text_cluster_allocate (int num_clusters);
 
cairo_public void
cairo_text_cluster_free (cairo_text_cluster_t *clusters);
 
/**
* cairo_text_cluster_flags_t:
* @CAIRO_TEXT_CLUSTER_FLAG_BACKWARD: The clusters in the cluster array
* map to glyphs in the glyph array from end to start.
*
* Specifies properties of a text cluster mapping.
*
* Since: 1.8
**/
typedef enum _cairo_text_cluster_flags {
CAIRO_TEXT_CLUSTER_FLAG_BACKWARD = 0x00000001
} cairo_text_cluster_flags_t;
 
/**
* cairo_text_extents_t:
* @x_bearing: the horizontal distance from the origin to the
* leftmost part of the glyphs as drawn. Positive if the
* glyphs lie entirely to the right of the origin.
* @y_bearing: the vertical distance from the origin to the
* topmost part of the glyphs as drawn. Positive only if the
* glyphs lie completely below the origin; will usually be
* negative.
* @width: width of the glyphs as drawn
* @height: height of the glyphs as drawn
* @x_advance:distance to advance in the X direction
* after drawing these glyphs
* @y_advance: distance to advance in the Y direction
* after drawing these glyphs. Will typically be zero except
* for vertical text layout as found in East-Asian languages.
*
* The #cairo_text_extents_t structure stores the extents of a single
* glyph or a string of glyphs in user-space coordinates. Because text
* extents are in user-space coordinates, they are mostly, but not
* entirely, independent of the current transformation matrix. If you call
* <literal>cairo_scale(cr, 2.0, 2.0)</literal>, text will
* be drawn twice as big, but the reported text extents will not be
* doubled. They will change slightly due to hinting (so you can't
* assume that metrics are independent of the transformation matrix),
* but otherwise will remain unchanged.
**/
typedef struct {
double x_bearing;
double y_bearing;
double width;
double height;
double x_advance;
double y_advance;
} cairo_text_extents_t;
 
/**
* cairo_font_extents_t:
* @ascent: the distance that the font extends above the baseline.
* Note that this is not always exactly equal to the maximum
* of the extents of all the glyphs in the font, but rather
* is picked to express the font designer's intent as to
* how the font should align with elements above it.
* @descent: the distance that the font extends below the baseline.
* This value is positive for typical fonts that include
* portions below the baseline. Note that this is not always
* exactly equal to the maximum of the extents of all the
* glyphs in the font, but rather is picked to express the
* font designer's intent as to how the the font should
* align with elements below it.
* @height: the recommended vertical distance between baselines when
* setting consecutive lines of text with the font. This
* is greater than @ascent+@descent by a
* quantity known as the <firstterm>line spacing</firstterm>
* or <firstterm>external leading</firstterm>. When space
* is at a premium, most fonts can be set with only
* a distance of @ascent+@descent between lines.
* @max_x_advance: the maximum distance in the X direction that
* the the origin is advanced for any glyph in the font.
* @max_y_advance: the maximum distance in the Y direction that
* the the origin is advanced for any glyph in the font.
* this will be zero for normal fonts used for horizontal
* writing. (The scripts of East Asia are sometimes written
* vertically.)
*
* The #cairo_font_extents_t structure stores metric information for
* a font. Values are given in the current user-space coordinate
* system.
*
* Because font metrics are in user-space coordinates, they are
* mostly, but not entirely, independent of the current transformation
* matrix. If you call <literal>cairo_scale(cr, 2.0, 2.0)</literal>,
* text will be drawn twice as big, but the reported text extents will
* not be doubled. They will change slightly due to hinting (so you
* can't assume that metrics are independent of the transformation
* matrix), but otherwise will remain unchanged.
**/
typedef struct {
double ascent;
double descent;
double height;
double max_x_advance;
double max_y_advance;
} cairo_font_extents_t;
 
/**
* cairo_font_slant_t:
* @CAIRO_FONT_SLANT_NORMAL: Upright font style
* @CAIRO_FONT_SLANT_ITALIC: Italic font style
* @CAIRO_FONT_SLANT_OBLIQUE: Oblique font style
*
* Specifies variants of a font face based on their slant.
**/
typedef enum _cairo_font_slant {
CAIRO_FONT_SLANT_NORMAL,
CAIRO_FONT_SLANT_ITALIC,
CAIRO_FONT_SLANT_OBLIQUE
} cairo_font_slant_t;
 
/**
* cairo_font_weight_t:
* @CAIRO_FONT_WEIGHT_NORMAL: Normal font weight
* @CAIRO_FONT_WEIGHT_BOLD: Bold font weight
*
* Specifies variants of a font face based on their weight.
**/
typedef enum _cairo_font_weight {
CAIRO_FONT_WEIGHT_NORMAL,
CAIRO_FONT_WEIGHT_BOLD
} cairo_font_weight_t;
 
/**
* cairo_subpixel_order_t:
* @CAIRO_SUBPIXEL_ORDER_DEFAULT: Use the default subpixel order for
* for the target device
* @CAIRO_SUBPIXEL_ORDER_RGB: Subpixel elements are arranged horizontally
* with red at the left
* @CAIRO_SUBPIXEL_ORDER_BGR: Subpixel elements are arranged horizontally
* with blue at the left
* @CAIRO_SUBPIXEL_ORDER_VRGB: Subpixel elements are arranged vertically
* with red at the top
* @CAIRO_SUBPIXEL_ORDER_VBGR: Subpixel elements are arranged vertically
* with blue at the top
*
* The subpixel order specifies the order of color elements within
* each pixel on the display device when rendering with an
* antialiasing mode of %CAIRO_ANTIALIAS_SUBPIXEL.
**/
typedef enum _cairo_subpixel_order {
CAIRO_SUBPIXEL_ORDER_DEFAULT,
CAIRO_SUBPIXEL_ORDER_RGB,
CAIRO_SUBPIXEL_ORDER_BGR,
CAIRO_SUBPIXEL_ORDER_VRGB,
CAIRO_SUBPIXEL_ORDER_VBGR
} cairo_subpixel_order_t;
 
/**
* cairo_hint_style_t:
* @CAIRO_HINT_STYLE_DEFAULT: Use the default hint style for
* font backend and target device
* @CAIRO_HINT_STYLE_NONE: Do not hint outlines
* @CAIRO_HINT_STYLE_SLIGHT: Hint outlines slightly to improve
* contrast while retaining good fidelity to the original
* shapes.
* @CAIRO_HINT_STYLE_MEDIUM: Hint outlines with medium strength
* giving a compromise between fidelity to the original shapes
* and contrast
* @CAIRO_HINT_STYLE_FULL: Hint outlines to maximize contrast
*
* Specifies the type of hinting to do on font outlines. Hinting
* is the process of fitting outlines to the pixel grid in order
* to improve the appearance of the result. Since hinting outlines
* involves distorting them, it also reduces the faithfulness
* to the original outline shapes. Not all of the outline hinting
* styles are supported by all font backends.
*
* New entries may be added in future versions.
**/
typedef enum _cairo_hint_style {
CAIRO_HINT_STYLE_DEFAULT,
CAIRO_HINT_STYLE_NONE,
CAIRO_HINT_STYLE_SLIGHT,
CAIRO_HINT_STYLE_MEDIUM,
CAIRO_HINT_STYLE_FULL
} cairo_hint_style_t;
 
/**
* cairo_hint_metrics_t:
* @CAIRO_HINT_METRICS_DEFAULT: Hint metrics in the default
* manner for the font backend and target device
* @CAIRO_HINT_METRICS_OFF: Do not hint font metrics
* @CAIRO_HINT_METRICS_ON: Hint font metrics
*
* Specifies whether to hint font metrics; hinting font metrics
* means quantizing them so that they are integer values in
* device space. Doing this improves the consistency of
* letter and line spacing, however it also means that text
* will be laid out differently at different zoom factors.
**/
typedef enum _cairo_hint_metrics {
CAIRO_HINT_METRICS_DEFAULT,
CAIRO_HINT_METRICS_OFF,
CAIRO_HINT_METRICS_ON
} cairo_hint_metrics_t;
 
/**
* cairo_font_options_t:
*
* An opaque structure holding all options that are used when
* rendering fonts.
*
* Individual features of a #cairo_font_options_t can be set or
* accessed using functions named
* cairo_font_options_set_<emphasis>feature_name</emphasis> and
* cairo_font_options_get_<emphasis>feature_name</emphasis>, like
* cairo_font_options_set_antialias() and
* cairo_font_options_get_antialias().
*
* New features may be added to a #cairo_font_options_t in the
* future. For this reason, cairo_font_options_copy(),
* cairo_font_options_equal(), cairo_font_options_merge(), and
* cairo_font_options_hash() should be used to copy, check
* for equality, merge, or compute a hash value of
* #cairo_font_options_t objects.
**/
typedef struct _cairo_font_options cairo_font_options_t;
 
cairo_public cairo_font_options_t *
cairo_font_options_create (void);
 
cairo_public cairo_font_options_t *
cairo_font_options_copy (const cairo_font_options_t *original);
 
cairo_public void
cairo_font_options_destroy (cairo_font_options_t *options);
 
cairo_public cairo_status_t
cairo_font_options_status (cairo_font_options_t *options);
 
cairo_public void
cairo_font_options_merge (cairo_font_options_t *options,
const cairo_font_options_t *other);
cairo_public cairo_bool_t
cairo_font_options_equal (const cairo_font_options_t *options,
const cairo_font_options_t *other);
 
cairo_public unsigned long
cairo_font_options_hash (const cairo_font_options_t *options);
 
cairo_public void
cairo_font_options_set_antialias (cairo_font_options_t *options,
cairo_antialias_t antialias);
cairo_public cairo_antialias_t
cairo_font_options_get_antialias (const cairo_font_options_t *options);
 
cairo_public void
cairo_font_options_set_subpixel_order (cairo_font_options_t *options,
cairo_subpixel_order_t subpixel_order);
cairo_public cairo_subpixel_order_t
cairo_font_options_get_subpixel_order (const cairo_font_options_t *options);
 
cairo_public void
cairo_font_options_set_hint_style (cairo_font_options_t *options,
cairo_hint_style_t hint_style);
cairo_public cairo_hint_style_t
cairo_font_options_get_hint_style (const cairo_font_options_t *options);
 
cairo_public void
cairo_font_options_set_hint_metrics (cairo_font_options_t *options,
cairo_hint_metrics_t hint_metrics);
cairo_public cairo_hint_metrics_t
cairo_font_options_get_hint_metrics (const cairo_font_options_t *options);
 
/* This interface is for dealing with text as text, not caring about the
font object inside the the cairo_t. */
 
cairo_public void
cairo_select_font_face (cairo_t *cr,
const char *family,
cairo_font_slant_t slant,
cairo_font_weight_t weight);
 
cairo_public void
cairo_set_font_size (cairo_t *cr, double size);
 
cairo_public void
cairo_set_font_matrix (cairo_t *cr,
const cairo_matrix_t *matrix);
 
cairo_public void
cairo_get_font_matrix (cairo_t *cr,
cairo_matrix_t *matrix);
 
cairo_public void
cairo_set_font_options (cairo_t *cr,
const cairo_font_options_t *options);
 
cairo_public void
cairo_get_font_options (cairo_t *cr,
cairo_font_options_t *options);
 
cairo_public void
cairo_set_font_face (cairo_t *cr, cairo_font_face_t *font_face);
 
cairo_public cairo_font_face_t *
cairo_get_font_face (cairo_t *cr);
 
cairo_public void
cairo_set_scaled_font (cairo_t *cr,
const cairo_scaled_font_t *scaled_font);
 
cairo_public cairo_scaled_font_t *
cairo_get_scaled_font (cairo_t *cr);
 
cairo_public void
cairo_show_text (cairo_t *cr, const char *utf8);
 
cairo_public void
cairo_show_glyphs (cairo_t *cr, const cairo_glyph_t *glyphs, int num_glyphs);
 
cairo_public void
cairo_show_text_glyphs (cairo_t *cr,
const char *utf8,
int utf8_len,
const cairo_glyph_t *glyphs,
int num_glyphs,
const cairo_text_cluster_t *clusters,
int num_clusters,
cairo_text_cluster_flags_t cluster_flags);
 
cairo_public void
cairo_text_path (cairo_t *cr, const char *utf8);
 
cairo_public void
cairo_glyph_path (cairo_t *cr, const cairo_glyph_t *glyphs, int num_glyphs);
 
cairo_public void
cairo_text_extents (cairo_t *cr,
const char *utf8,
cairo_text_extents_t *extents);
 
cairo_public void
cairo_glyph_extents (cairo_t *cr,
const cairo_glyph_t *glyphs,
int num_glyphs,
cairo_text_extents_t *extents);
 
cairo_public void
cairo_font_extents (cairo_t *cr,
cairo_font_extents_t *extents);
 
/* Generic identifier for a font style */
 
cairo_public cairo_font_face_t *
cairo_font_face_reference (cairo_font_face_t *font_face);
 
cairo_public void
cairo_font_face_destroy (cairo_font_face_t *font_face);
 
cairo_public unsigned int
cairo_font_face_get_reference_count (cairo_font_face_t *font_face);
 
cairo_public cairo_status_t
cairo_font_face_status (cairo_font_face_t *font_face);
 
 
/**
* cairo_font_type_t:
* @CAIRO_FONT_TYPE_TOY: The font was created using cairo's toy font api
* @CAIRO_FONT_TYPE_FT: The font is of type FreeType
* @CAIRO_FONT_TYPE_WIN32: The font is of type Win32
* @CAIRO_FONT_TYPE_QUARTZ: The font is of type Quartz (Since: 1.6)
* @CAIRO_FONT_TYPE_USER: The font was create using cairo's user font api (Since: 1.8)
*
* #cairo_font_type_t is used to describe the type of a given font
* face or scaled font. The font types are also known as "font
* backends" within cairo.
*
* The type of a font face is determined by the function used to
* create it, which will generally be of the form
* cairo_<emphasis>type</emphasis>_font_face_create(). The font face type can be queried
* with cairo_font_face_get_type()
*
* The various #cairo_font_face_t functions can be used with a font face
* of any type.
*
* The type of a scaled font is determined by the type of the font
* face passed to cairo_scaled_font_create(). The scaled font type can
* be queried with cairo_scaled_font_get_type()
*
* The various #cairo_scaled_font_t functions can be used with scaled
* fonts of any type, but some font backends also provide
* type-specific functions that must only be called with a scaled font
* of the appropriate type. These functions have names that begin with
* cairo_<emphasis>type</emphasis>_scaled_font() such as cairo_ft_scaled_font_lock_face().
*
* The behavior of calling a type-specific function with a scaled font
* of the wrong type is undefined.
*
* New entries may be added in future versions.
*
* Since: 1.2
**/
typedef enum _cairo_font_type {
CAIRO_FONT_TYPE_TOY,
CAIRO_FONT_TYPE_FT,
CAIRO_FONT_TYPE_WIN32,
CAIRO_FONT_TYPE_QUARTZ,
CAIRO_FONT_TYPE_USER
} cairo_font_type_t;
 
cairo_public cairo_font_type_t
cairo_font_face_get_type (cairo_font_face_t *font_face);
 
cairo_public void *
cairo_font_face_get_user_data (cairo_font_face_t *font_face,
const cairo_user_data_key_t *key);
 
cairo_public cairo_status_t
cairo_font_face_set_user_data (cairo_font_face_t *font_face,
const cairo_user_data_key_t *key,
void *user_data,
cairo_destroy_func_t destroy);
 
/* Portable interface to general font features. */
 
cairo_public cairo_scaled_font_t *
cairo_scaled_font_create (cairo_font_face_t *font_face,
const cairo_matrix_t *font_matrix,
const cairo_matrix_t *ctm,
const cairo_font_options_t *options);
 
cairo_public cairo_scaled_font_t *
cairo_scaled_font_reference (cairo_scaled_font_t *scaled_font);
 
cairo_public void
cairo_scaled_font_destroy (cairo_scaled_font_t *scaled_font);
 
cairo_public unsigned int
cairo_scaled_font_get_reference_count (cairo_scaled_font_t *scaled_font);
 
cairo_public cairo_status_t
cairo_scaled_font_status (cairo_scaled_font_t *scaled_font);
 
cairo_public cairo_font_type_t
cairo_scaled_font_get_type (cairo_scaled_font_t *scaled_font);
 
cairo_public void *
cairo_scaled_font_get_user_data (cairo_scaled_font_t *scaled_font,
const cairo_user_data_key_t *key);
 
cairo_public cairo_status_t
cairo_scaled_font_set_user_data (cairo_scaled_font_t *scaled_font,
const cairo_user_data_key_t *key,
void *user_data,
cairo_destroy_func_t destroy);
 
cairo_public void
cairo_scaled_font_extents (cairo_scaled_font_t *scaled_font,
cairo_font_extents_t *extents);
 
cairo_public void
cairo_scaled_font_text_extents (cairo_scaled_font_t *scaled_font,
const char *utf8,
cairo_text_extents_t *extents);
 
cairo_public void
cairo_scaled_font_glyph_extents (cairo_scaled_font_t *scaled_font,
const cairo_glyph_t *glyphs,
int num_glyphs,
cairo_text_extents_t *extents);
 
cairo_public cairo_status_t
cairo_scaled_font_text_to_glyphs (cairo_scaled_font_t *scaled_font,
double x,
double y,
const char *utf8,
int utf8_len,
cairo_glyph_t **glyphs,
int *num_glyphs,
cairo_text_cluster_t **clusters,
int *num_clusters,
cairo_text_cluster_flags_t *cluster_flags);
 
cairo_public cairo_font_face_t *
cairo_scaled_font_get_font_face (cairo_scaled_font_t *scaled_font);
 
cairo_public void
cairo_scaled_font_get_font_matrix (cairo_scaled_font_t *scaled_font,
cairo_matrix_t *font_matrix);
 
cairo_public void
cairo_scaled_font_get_ctm (cairo_scaled_font_t *scaled_font,
cairo_matrix_t *ctm);
 
cairo_public void
cairo_scaled_font_get_scale_matrix (cairo_scaled_font_t *scaled_font,
cairo_matrix_t *scale_matrix);
 
cairo_public void
cairo_scaled_font_get_font_options (cairo_scaled_font_t *scaled_font,
cairo_font_options_t *options);
 
 
/* Toy fonts */
 
cairo_public cairo_font_face_t *
cairo_toy_font_face_create (const char *family,
cairo_font_slant_t slant,
cairo_font_weight_t weight);
 
cairo_public const char *
cairo_toy_font_face_get_family (cairo_font_face_t *font_face);
 
cairo_public cairo_font_slant_t
cairo_toy_font_face_get_slant (cairo_font_face_t *font_face);
 
cairo_public cairo_font_weight_t
cairo_toy_font_face_get_weight (cairo_font_face_t *font_face);
 
 
/* User fonts */
 
cairo_public cairo_font_face_t *
cairo_user_font_face_create (void);
 
/* User-font method signatures */
 
/**
* cairo_user_scaled_font_init_func_t:
* @scaled_font: the scaled-font being created
* @cr: a cairo context, in font space
* @extents: font extents to fill in, in font space
*
* #cairo_user_scaled_font_init_func_t is the type of function which is
* called when a scaled-font needs to be created for a user font-face.
*
* The cairo context @cr is not used by the caller, but is prepared in font
* space, similar to what the cairo contexts passed to the render_glyph
* method will look like. The callback can use this context for extents
* computation for example. After the callback is called, @cr is checked
* for any error status.
*
* The @extents argument is where the user font sets the font extents for
* @scaled_font. It is in font space, which means that for most cases its
* ascent and descent members should add to 1.0. @extents is preset to
* hold a value of 1.0 for ascent, height, and max_x_advance, and 0.0 for
* descent and max_y_advance members.
*
* The callback is optional. If not set, default font extents as described
* in the previous paragraph will be used.
*
* Note that @scaled_font is not fully initialized at this
* point and trying to use it for text operations in the callback will result
* in deadlock.
*
* Returns: %CAIRO_STATUS_SUCCESS upon success, or an error status on error.
*
* Since: 1.8
**/
typedef cairo_status_t (*cairo_user_scaled_font_init_func_t) (cairo_scaled_font_t *scaled_font,
cairo_t *cr,
cairo_font_extents_t *extents);
 
/**
* cairo_user_scaled_font_render_glyph_func_t:
* @scaled_font: user scaled-font
* @glyph: glyph code to render
* @cr: cairo context to draw to, in font space
* @extents: glyph extents to fill in, in font space
*
* #cairo_user_scaled_font_render_glyph_func_t is the type of function which
* is called when a user scaled-font needs to render a glyph.
*
* The callback is mandatory, and expected to draw the glyph with code @glyph to
* the cairo context @cr. @cr is prepared such that the glyph drawing is done in
* font space. That is, the matrix set on @cr is the scale matrix of @scaled_font,
* The @extents argument is where the user font sets the font extents for
* @scaled_font. However, if user prefers to draw in user space, they can
* achieve that by changing the matrix on @cr. All cairo rendering operations
* to @cr are permitted, however, the result is undefined if any source other
* than the default source on @cr is used. That means, glyph bitmaps should
* be rendered using cairo_mask() instead of cairo_paint().
*
* Other non-default settings on @cr include a font size of 1.0 (given that
* it is set up to be in font space), and font options corresponding to
* @scaled_font.
*
* The @extents argument is preset to have <literal>x_bearing</literal>,
* <literal>width</literal>, and <literal>y_advance</literal> of zero,
* <literal>y_bearing</literal> set to <literal>-font_extents.ascent</literal>,
* <literal>height</literal> to <literal>font_extents.ascent+font_extents.descent</literal>,
* and <literal>x_advance</literal> to <literal>font_extents.max_x_advance</literal>.
* The only field user needs to set in majority of cases is
* <literal>x_advance</literal>.
* If the <literal>width</literal> field is zero upon the callback returning
* (which is its preset value), the glyph extents are automatically computed
* based on the drawings done to @cr. This is in most cases exactly what the
* desired behavior is. However, if for any reason the callback sets the
* extents, it must be ink extents, and include the extents of all drawing
* done to @cr in the callback.
*
* Returns: %CAIRO_STATUS_SUCCESS upon success, or
* %CAIRO_STATUS_USER_FONT_ERROR or any other error status on error.
*
* Since: 1.8
**/
typedef cairo_status_t (*cairo_user_scaled_font_render_glyph_func_t) (cairo_scaled_font_t *scaled_font,
unsigned long glyph,
cairo_t *cr,
cairo_text_extents_t *extents);
 
/**
* cairo_user_scaled_font_text_to_glyphs_func_t:
* @scaled_font: the scaled-font being created
* @utf8: a string of text encoded in UTF-8
* @utf8_len: length of @utf8 in bytes
* @glyphs: pointer to array of glyphs to fill, in font space
* @num_glyphs: pointer to number of glyphs
* @clusters: pointer to array of cluster mapping information to fill, or %NULL
* @num_clusters: pointer to number of clusters
* @cluster_flags: pointer to location to store cluster flags corresponding to the
* output @clusters
*
* #cairo_user_scaled_font_text_to_glyphs_func_t is the type of function which
* is called to convert input text to an array of glyphs. This is used by the
* cairo_show_text() operation.
*
* Using this callback the user-font has full control on glyphs and their
* positions. That means, it allows for features like ligatures and kerning,
* as well as complex <firstterm>shaping</firstterm> required for scripts like
* Arabic and Indic.
*
* The @num_glyphs argument is preset to the number of glyph entries available
* in the @glyphs buffer. If the @glyphs buffer is %NULL, the value of
* @num_glyphs will be zero. If the provided glyph array is too short for
* the conversion (or for convenience), a new glyph array may be allocated
* using cairo_glyph_allocate() and placed in @glyphs. Upon return,
* @num_glyphs should contain the number of generated glyphs. If the value
* @glyphs points at has changed after the call, the caller will free the
* allocated glyph array using cairo_glyph_free().
* The callback should populate the glyph indices and positions (in font space)
* assuming that the text is to be shown at the origin.
*
* If @clusters is not %NULL, @num_clusters and @cluster_flags are also
* non-%NULL, and cluster mapping should be computed. The semantics of how
* cluster array allocation works is similar to the glyph array. That is,
* if @clusters initially points to a non-%NULL value, that array may be used
* as a cluster buffer, and @num_clusters points to the number of cluster
* entries available there. If the provided cluster array is too short for
* the conversion (or for convenience), a new cluster array may be allocated
* using cairo_text_cluster_allocate() and placed in @clusters. Upon return,
* @num_clusters should contain the number of generated clusters.
* If the value @clusters points at has changed after the call, the caller
* will free the allocated cluster array using cairo_text_cluster_free().
*
* The callback is optional. If @num_glyphs is negative upon
* the callback returning or if the return value
* is %CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED, the unicode_to_glyph callback
* is tried. See #cairo_user_scaled_font_unicode_to_glyph_func_t.
*
* Note: While cairo does not impose any limitation on glyph indices,
* some applications may assume that a glyph index fits in a 16-bit
* unsigned integer. As such, it is advised that user-fonts keep their
* glyphs in the 0 to 65535 range. Furthermore, some applications may
* assume that glyph 0 is a special glyph-not-found glyph. User-fonts
* are advised to use glyph 0 for such purposes and do not use that
* glyph value for other purposes.
*
* Returns: %CAIRO_STATUS_SUCCESS upon success,
* %CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED if fallback options should be tried,
* or %CAIRO_STATUS_USER_FONT_ERROR or any other error status on error.
*
* Since: 1.8
**/
typedef cairo_status_t (*cairo_user_scaled_font_text_to_glyphs_func_t) (cairo_scaled_font_t *scaled_font,
const char *utf8,
int utf8_len,
cairo_glyph_t **glyphs,
int *num_glyphs,
cairo_text_cluster_t **clusters,
int *num_clusters,
cairo_text_cluster_flags_t *cluster_flags);
 
/**
* cairo_user_scaled_font_unicode_to_glyph_func_t:
* @scaled_font: the scaled-font being created
* @unicode: input unicode character code-point
* @glyph_index: output glyph index
*
* #cairo_user_scaled_font_unicode_to_glyph_func_t is the type of function which
* is called to convert an input Unicode character to a single glyph.
* This is used by the cairo_show_text() operation.
*
* This callback is used to provide the same functionality as the
* text_to_glyphs callback does (see #cairo_user_scaled_font_text_to_glyphs_func_t)
* but has much less control on the output,
* in exchange for increased ease of use. The inherent assumption to using
* this callback is that each character maps to one glyph, and that the
* mapping is context independent. It also assumes that glyphs are positioned
* according to their advance width. These mean no ligatures, kerning, or
* complex scripts can be implemented using this callback.
*
* The callback is optional, and only used if text_to_glyphs callback is not
* set or fails to return glyphs. If this callback is not set or if it returns
* %CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED, an identity mapping from Unicode
* code-points to glyph indices is assumed.
*
* Note: While cairo does not impose any limitation on glyph indices,
* some applications may assume that a glyph index fits in a 16-bit
* unsigned integer. As such, it is advised that user-fonts keep their
* glyphs in the 0 to 65535 range. Furthermore, some applications may
* assume that glyph 0 is a special glyph-not-found glyph. User-fonts
* are advised to use glyph 0 for such purposes and do not use that
* glyph value for other purposes.
*
* Returns: %CAIRO_STATUS_SUCCESS upon success,
* %CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED if fallback options should be tried,
* or %CAIRO_STATUS_USER_FONT_ERROR or any other error status on error.
*
* Since: 1.8
**/
typedef cairo_status_t (*cairo_user_scaled_font_unicode_to_glyph_func_t) (cairo_scaled_font_t *scaled_font,
unsigned long unicode,
unsigned long *glyph_index);
 
/* User-font method setters */
 
cairo_public void
cairo_user_font_face_set_init_func (cairo_font_face_t *font_face,
cairo_user_scaled_font_init_func_t init_func);
 
cairo_public void
cairo_user_font_face_set_render_glyph_func (cairo_font_face_t *font_face,
cairo_user_scaled_font_render_glyph_func_t render_glyph_func);
 
cairo_public void
cairo_user_font_face_set_text_to_glyphs_func (cairo_font_face_t *font_face,
cairo_user_scaled_font_text_to_glyphs_func_t text_to_glyphs_func);
 
cairo_public void
cairo_user_font_face_set_unicode_to_glyph_func (cairo_font_face_t *font_face,
cairo_user_scaled_font_unicode_to_glyph_func_t unicode_to_glyph_func);
 
/* User-font method getters */
 
cairo_public cairo_user_scaled_font_init_func_t
cairo_user_font_face_get_init_func (cairo_font_face_t *font_face);
 
cairo_public cairo_user_scaled_font_render_glyph_func_t
cairo_user_font_face_get_render_glyph_func (cairo_font_face_t *font_face);
 
cairo_public cairo_user_scaled_font_text_to_glyphs_func_t
cairo_user_font_face_get_text_to_glyphs_func (cairo_font_face_t *font_face);
 
cairo_public cairo_user_scaled_font_unicode_to_glyph_func_t
cairo_user_font_face_get_unicode_to_glyph_func (cairo_font_face_t *font_face);
 
 
/* Query functions */
 
cairo_public cairo_operator_t
cairo_get_operator (cairo_t *cr);
 
cairo_public cairo_pattern_t *
cairo_get_source (cairo_t *cr);
 
cairo_public double
cairo_get_tolerance (cairo_t *cr);
 
cairo_public cairo_antialias_t
cairo_get_antialias (cairo_t *cr);
 
cairo_public cairo_bool_t
cairo_has_current_point (cairo_t *cr);
 
cairo_public void
cairo_get_current_point (cairo_t *cr, double *x, double *y);
 
cairo_public cairo_fill_rule_t
cairo_get_fill_rule (cairo_t *cr);
 
cairo_public double
cairo_get_line_width (cairo_t *cr);
 
cairo_public cairo_line_cap_t
cairo_get_line_cap (cairo_t *cr);
 
cairo_public cairo_line_join_t
cairo_get_line_join (cairo_t *cr);
 
cairo_public double
cairo_get_miter_limit (cairo_t *cr);
 
cairo_public int
cairo_get_dash_count (cairo_t *cr);
 
cairo_public void
cairo_get_dash (cairo_t *cr, double *dashes, double *offset);
 
cairo_public void
cairo_get_matrix (cairo_t *cr, cairo_matrix_t *matrix);
 
cairo_public cairo_surface_t *
cairo_get_target (cairo_t *cr);
 
cairo_public cairo_surface_t *
cairo_get_group_target (cairo_t *cr);
 
/**
* cairo_path_data_type_t:
* @CAIRO_PATH_MOVE_TO: A move-to operation
* @CAIRO_PATH_LINE_TO: A line-to operation
* @CAIRO_PATH_CURVE_TO: A curve-to operation
* @CAIRO_PATH_CLOSE_PATH: A close-path operation
*
* #cairo_path_data_t is used to describe the type of one portion
* of a path when represented as a #cairo_path_t.
* See #cairo_path_data_t for details.
**/
typedef enum _cairo_path_data_type {
CAIRO_PATH_MOVE_TO,
CAIRO_PATH_LINE_TO,
CAIRO_PATH_CURVE_TO,
CAIRO_PATH_CLOSE_PATH
} cairo_path_data_type_t;
 
/**
* cairo_path_data_t:
*
* #cairo_path_data_t is used to represent the path data inside a
* #cairo_path_t.
*
* The data structure is designed to try to balance the demands of
* efficiency and ease-of-use. A path is represented as an array of
* #cairo_path_data_t, which is a union of headers and points.
*
* Each portion of the path is represented by one or more elements in
* the array, (one header followed by 0 or more points). The length
* value of the header is the number of array elements for the current
* portion including the header, (ie. length == 1 + # of points), and
* where the number of points for each element type is as follows:
*
* <programlisting>
* %CAIRO_PATH_MOVE_TO: 1 point
* %CAIRO_PATH_LINE_TO: 1 point
* %CAIRO_PATH_CURVE_TO: 3 points
* %CAIRO_PATH_CLOSE_PATH: 0 points
* </programlisting>
*
* The semantics and ordering of the coordinate values are consistent
* with cairo_move_to(), cairo_line_to(), cairo_curve_to(), and
* cairo_close_path().
*
* Here is sample code for iterating through a #cairo_path_t:
*
* <informalexample><programlisting>
* int i;
* cairo_path_t *path;
* cairo_path_data_t *data;
* &nbsp;
* path = cairo_copy_path (cr);
* &nbsp;
* for (i=0; i < path->num_data; i += path->data[i].header.length) {
* data = &amp;path->data[i];
* switch (data->header.type) {
* case CAIRO_PATH_MOVE_TO:
* do_move_to_things (data[1].point.x, data[1].point.y);
* break;
* case CAIRO_PATH_LINE_TO:
* do_line_to_things (data[1].point.x, data[1].point.y);
* break;
* case CAIRO_PATH_CURVE_TO:
* do_curve_to_things (data[1].point.x, data[1].point.y,
* data[2].point.x, data[2].point.y,
* data[3].point.x, data[3].point.y);
* break;
* case CAIRO_PATH_CLOSE_PATH:
* do_close_path_things ();
* break;
* }
* }
* cairo_path_destroy (path);
* </programlisting></informalexample>
*
* As of cairo 1.4, cairo does not mind if there are more elements in
* a portion of the path than needed. Such elements can be used by
* users of the cairo API to hold extra values in the path data
* structure. For this reason, it is recommended that applications
* always use <literal>data->header.length</literal> to
* iterate over the path data, instead of hardcoding the number of
* elements for each element type.
**/
typedef union _cairo_path_data_t cairo_path_data_t;
union _cairo_path_data_t {
struct {
cairo_path_data_type_t type;
int length;
} header;
struct {
double x, y;
} point;
};
 
/**
* cairo_path_t:
* @status: the current error status
* @data: the elements in the path
* @num_data: the number of elements in the data array
*
* A data structure for holding a path. This data structure serves as
* the return value for cairo_copy_path() and
* cairo_copy_path_flat() as well the input value for
* cairo_append_path().
*
* See #cairo_path_data_t for hints on how to iterate over the
* actual data within the path.
*
* The num_data member gives the number of elements in the data
* array. This number is larger than the number of independent path
* portions (defined in #cairo_path_data_type_t), since the data
* includes both headers and coordinates for each portion.
**/
typedef struct cairo_path {
cairo_status_t status;
cairo_path_data_t *data;
int num_data;
} cairo_path_t;
 
cairo_public cairo_path_t *
cairo_copy_path (cairo_t *cr);
 
cairo_public cairo_path_t *
cairo_copy_path_flat (cairo_t *cr);
 
cairo_public void
cairo_append_path (cairo_t *cr,
const cairo_path_t *path);
 
cairo_public void
cairo_path_destroy (cairo_path_t *path);
 
/* Error status queries */
 
cairo_public cairo_status_t
cairo_status (cairo_t *cr);
 
cairo_public const char *
cairo_status_to_string (cairo_status_t status);
 
/* Backend device manipulation */
 
cairo_public cairo_device_t *
cairo_device_reference (cairo_device_t *device);
 
/**
* cairo_device_type_t:
* @CAIRO_DEVICE_TYPE_DRM: The surface is of type Direct Render Manager
* @CAIRO_DEVICE_TYPE_GL: The surface is of type OpenGL
* @CAIRO_DEVICE_TYPE_SCRIPT: The surface is of type script
* @CAIRO_DEVICE_TYPE_XCB: The surface is of type xcb
* @CAIRO_DEVICE_TYPE_XLIB: The surface is of type xlib
* @CAIRO_DEVICE_TYPE_XML: The surface is of type XML
* cairo_surface_create_for_rectangle()
*
* #cairo_device_type_t is used to describe the type of a given
* device. The devices types are also known as "backends" within cairo.
*
* The device type can be queried with cairo_device_get_type()
*
* The various #cairo_device_t functions can be used with surfaces of
* any type, but some backends also provide type-specific functions
* that must only be called with a device of the appropriate
* type. These functions have names that begin with
* cairo_<emphasis>type</emphasis>_device<!-- --> such as cairo_xcb_device_debug_set_render_version().
*
* The behavior of calling a type-specific function with a surface of
* the wrong type is undefined.
*
* New entries may be added in future versions.
*
* Since: 1.10
**/
typedef enum _cairo_device_type {
CAIRO_DEVICE_TYPE_DRM,
CAIRO_DEVICE_TYPE_GL,
CAIRO_DEVICE_TYPE_SCRIPT,
CAIRO_DEVICE_TYPE_XCB,
CAIRO_DEVICE_TYPE_XLIB,
CAIRO_DEVICE_TYPE_XML
} cairo_device_type_t;
 
cairo_public cairo_device_type_t
cairo_device_get_type (cairo_device_t *device);
 
cairo_public cairo_status_t
cairo_device_status (cairo_device_t *device);
 
cairo_public cairo_status_t
cairo_device_acquire (cairo_device_t *device);
 
cairo_public void
cairo_device_release (cairo_device_t *device);
 
cairo_public void
cairo_device_flush (cairo_device_t *device);
 
cairo_public void
cairo_device_finish (cairo_device_t *device);
 
cairo_public void
cairo_device_destroy (cairo_device_t *device);
 
cairo_public unsigned int
cairo_device_get_reference_count (cairo_device_t *device);
 
cairo_public void *
cairo_device_get_user_data (cairo_device_t *device,
const cairo_user_data_key_t *key);
 
cairo_public cairo_status_t
cairo_device_set_user_data (cairo_device_t *device,
const cairo_user_data_key_t *key,
void *user_data,
cairo_destroy_func_t destroy);
 
 
/* Surface manipulation */
 
cairo_public cairo_surface_t *
cairo_surface_create_similar (cairo_surface_t *other,
cairo_content_t content,
int width,
int height);
 
cairo_public cairo_surface_t *
cairo_surface_create_for_rectangle (cairo_surface_t *target,
double x,
double y,
double width,
double height);
 
cairo_public cairo_surface_t *
cairo_surface_reference (cairo_surface_t *surface);
 
cairo_public void
cairo_surface_finish (cairo_surface_t *surface);
 
cairo_public void
cairo_surface_destroy (cairo_surface_t *surface);
 
cairo_public cairo_device_t *
cairo_surface_get_device (cairo_surface_t *surface);
 
cairo_public unsigned int
cairo_surface_get_reference_count (cairo_surface_t *surface);
 
cairo_public cairo_status_t
cairo_surface_status (cairo_surface_t *surface);
 
/**
* cairo_surface_type_t:
* @CAIRO_SURFACE_TYPE_IMAGE: The surface is of type image
* @CAIRO_SURFACE_TYPE_PDF: The surface is of type pdf
* @CAIRO_SURFACE_TYPE_PS: The surface is of type ps
* @CAIRO_SURFACE_TYPE_XLIB: The surface is of type xlib
* @CAIRO_SURFACE_TYPE_XCB: The surface is of type xcb
* @CAIRO_SURFACE_TYPE_GLITZ: The surface is of type glitz
* @CAIRO_SURFACE_TYPE_QUARTZ: The surface is of type quartz
* @CAIRO_SURFACE_TYPE_WIN32: The surface is of type win32
* @CAIRO_SURFACE_TYPE_BEOS: The surface is of type beos
* @CAIRO_SURFACE_TYPE_DIRECTFB: The surface is of type directfb
* @CAIRO_SURFACE_TYPE_SVG: The surface is of type svg
* @CAIRO_SURFACE_TYPE_OS2: The surface is of type os2
* @CAIRO_SURFACE_TYPE_WIN32_PRINTING: The surface is a win32 printing surface
* @CAIRO_SURFACE_TYPE_QUARTZ_IMAGE: The surface is of type quartz_image
* @CAIRO_SURFACE_TYPE_SCRIPT: The surface is of type script, since 1.10
* @CAIRO_SURFACE_TYPE_QT: The surface is of type Qt, since 1.10
* @CAIRO_SURFACE_TYPE_RECORDING: The surface is of type recording, since 1.10
* @CAIRO_SURFACE_TYPE_VG: The surface is a OpenVG surface, since 1.10
* @CAIRO_SURFACE_TYPE_GL: The surface is of type OpenGL, since 1.10
* @CAIRO_SURFACE_TYPE_DRM: The surface is of type Direct Render Manager, since 1.10
* @CAIRO_SURFACE_TYPE_TEE: The surface is of type 'tee' (a multiplexing surface), since 1.10
* @CAIRO_SURFACE_TYPE_XML: The surface is of type XML (for debugging), since 1.10
* @CAIRO_SURFACE_TYPE_SKIA: The surface is of type Skia, since 1.10
* @CAIRO_SURFACE_TYPE_SUBSURFACE: The surface is a subsurface created with
* cairo_surface_create_for_rectangle(), since 1.10
*
* #cairo_surface_type_t is used to describe the type of a given
* surface. The surface types are also known as "backends" or "surface
* backends" within cairo.
*
* The type of a surface is determined by the function used to create
* it, which will generally be of the form cairo_<emphasis>type</emphasis>_surface_create(),
* (though see cairo_surface_create_similar() as well).
*
* The surface type can be queried with cairo_surface_get_type()
*
* The various #cairo_surface_t functions can be used with surfaces of
* any type, but some backends also provide type-specific functions
* that must only be called with a surface of the appropriate
* type. These functions have names that begin with
* cairo_<emphasis>type</emphasis>_surface<!-- --> such as cairo_image_surface_get_width().
*
* The behavior of calling a type-specific function with a surface of
* the wrong type is undefined.
*
* New entries may be added in future versions.
*
* Since: 1.2
**/
typedef enum _cairo_surface_type {
CAIRO_SURFACE_TYPE_IMAGE,
CAIRO_SURFACE_TYPE_PDF,
CAIRO_SURFACE_TYPE_PS,
CAIRO_SURFACE_TYPE_XLIB,
CAIRO_SURFACE_TYPE_XCB,
CAIRO_SURFACE_TYPE_GLITZ,
CAIRO_SURFACE_TYPE_QUARTZ,
CAIRO_SURFACE_TYPE_WIN32,
CAIRO_SURFACE_TYPE_BEOS,
CAIRO_SURFACE_TYPE_DIRECTFB,
CAIRO_SURFACE_TYPE_SVG,
CAIRO_SURFACE_TYPE_OS2,
CAIRO_SURFACE_TYPE_WIN32_PRINTING,
CAIRO_SURFACE_TYPE_QUARTZ_IMAGE,
CAIRO_SURFACE_TYPE_SCRIPT,
CAIRO_SURFACE_TYPE_QT,
CAIRO_SURFACE_TYPE_RECORDING,
CAIRO_SURFACE_TYPE_VG,
CAIRO_SURFACE_TYPE_GL,
CAIRO_SURFACE_TYPE_DRM,
CAIRO_SURFACE_TYPE_TEE,
CAIRO_SURFACE_TYPE_XML,
CAIRO_SURFACE_TYPE_SKIA,
CAIRO_SURFACE_TYPE_SUBSURFACE
} cairo_surface_type_t;
 
cairo_public cairo_surface_type_t
cairo_surface_get_type (cairo_surface_t *surface);
 
cairo_public cairo_content_t
cairo_surface_get_content (cairo_surface_t *surface);
 
#if CAIRO_HAS_PNG_FUNCTIONS
 
cairo_public cairo_status_t
cairo_surface_write_to_png (cairo_surface_t *surface,
const char *filename);
 
cairo_public cairo_status_t
cairo_surface_write_to_png_stream (cairo_surface_t *surface,
cairo_write_func_t write_func,
void *closure);
 
#endif
 
cairo_public void *
cairo_surface_get_user_data (cairo_surface_t *surface,
const cairo_user_data_key_t *key);
 
cairo_public cairo_status_t
cairo_surface_set_user_data (cairo_surface_t *surface,
const cairo_user_data_key_t *key,
void *user_data,
cairo_destroy_func_t destroy);
 
#define CAIRO_MIME_TYPE_JPEG "image/jpeg"
#define CAIRO_MIME_TYPE_PNG "image/png"
#define CAIRO_MIME_TYPE_JP2 "image/jp2"
#define CAIRO_MIME_TYPE_URI "text/x-uri"
 
cairo_public void
cairo_surface_get_mime_data (cairo_surface_t *surface,
const char *mime_type,
const unsigned char **data,
unsigned long *length);
 
cairo_public cairo_status_t
cairo_surface_set_mime_data (cairo_surface_t *surface,
const char *mime_type,
const unsigned char *data,
unsigned long length,
cairo_destroy_func_t destroy,
void *closure);
 
cairo_public void
cairo_surface_get_font_options (cairo_surface_t *surface,
cairo_font_options_t *options);
 
cairo_public void
cairo_surface_flush (cairo_surface_t *surface);
 
cairo_public void
cairo_surface_mark_dirty (cairo_surface_t *surface);
 
cairo_public void
cairo_surface_mark_dirty_rectangle (cairo_surface_t *surface,
int x,
int y,
int width,
int height);
 
cairo_public void
cairo_surface_set_device_offset (cairo_surface_t *surface,
double x_offset,
double y_offset);
 
cairo_public void
cairo_surface_get_device_offset (cairo_surface_t *surface,
double *x_offset,
double *y_offset);
 
cairo_public void
cairo_surface_set_fallback_resolution (cairo_surface_t *surface,
double x_pixels_per_inch,
double y_pixels_per_inch);
 
cairo_public void
cairo_surface_get_fallback_resolution (cairo_surface_t *surface,
double *x_pixels_per_inch,
double *y_pixels_per_inch);
 
cairo_public void
cairo_surface_copy_page (cairo_surface_t *surface);
 
cairo_public void
cairo_surface_show_page (cairo_surface_t *surface);
 
cairo_public cairo_bool_t
cairo_surface_has_show_text_glyphs (cairo_surface_t *surface);
 
/* Image-surface functions */
 
/**
* cairo_format_t:
* @CAIRO_FORMAT_INVALID: no such format exists or is supported.
* @CAIRO_FORMAT_ARGB32: each pixel is a 32-bit quantity, with
* alpha in the upper 8 bits, then red, then green, then blue.
* The 32-bit quantities are stored native-endian. Pre-multiplied
* alpha is used. (That is, 50% transparent red is 0x80800000,
* not 0x80ff0000.)
* @CAIRO_FORMAT_RGB24: each pixel is a 32-bit quantity, with
* the upper 8 bits unused. Red, Green, and Blue are stored
* in the remaining 24 bits in that order.
* @CAIRO_FORMAT_A8: each pixel is a 8-bit quantity holding
* an alpha value.
* @CAIRO_FORMAT_A1: each pixel is a 1-bit quantity holding
* an alpha value. Pixels are packed together into 32-bit
* quantities. The ordering of the bits matches the
* endianess of the platform. On a big-endian machine, the
* first pixel is in the uppermost bit, on a little-endian
* machine the first pixel is in the least-significant bit.
* @CAIRO_FORMAT_RGB16_565: each pixel is a 16-bit quantity
* with red in the upper 5 bits, then green in the middle
* 6 bits, and blue in the lower 5 bits.
*
* #cairo_format_t is used to identify the memory format of
* image data.
*
* New entries may be added in future versions.
**/
typedef enum _cairo_format {
CAIRO_FORMAT_INVALID = -1,
CAIRO_FORMAT_ARGB32 = 0,
CAIRO_FORMAT_RGB24 = 1,
CAIRO_FORMAT_A8 = 2,
CAIRO_FORMAT_A1 = 3,
CAIRO_FORMAT_RGB16_565 = 4
} cairo_format_t;
 
cairo_public cairo_surface_t *
cairo_image_surface_create (cairo_format_t format,
int width,
int height);
 
cairo_public int
cairo_format_stride_for_width (cairo_format_t format,
int width);
 
cairo_public cairo_surface_t *
cairo_image_surface_create_for_data (unsigned char *data,
cairo_format_t format,
int width,
int height,
int stride);
 
cairo_public unsigned char *
cairo_image_surface_get_data (cairo_surface_t *surface);
 
cairo_public cairo_format_t
cairo_image_surface_get_format (cairo_surface_t *surface);
 
cairo_public int
cairo_image_surface_get_width (cairo_surface_t *surface);
 
cairo_public int
cairo_image_surface_get_height (cairo_surface_t *surface);
 
cairo_public int
cairo_image_surface_get_stride (cairo_surface_t *surface);
 
#if CAIRO_HAS_PNG_FUNCTIONS
 
cairo_public cairo_surface_t *
cairo_image_surface_create_from_png (const char *filename);
 
cairo_public cairo_surface_t *
cairo_image_surface_create_from_png_stream (cairo_read_func_t read_func,
void *closure);
 
#endif
 
/* Recording-surface functions */
 
cairo_public cairo_surface_t *
cairo_recording_surface_create (cairo_content_t content,
const cairo_rectangle_t *extents);
 
cairo_public void
cairo_recording_surface_ink_extents (cairo_surface_t *surface,
double *x0,
double *y0,
double *width,
double *height);
 
/* Pattern creation functions */
 
cairo_public cairo_pattern_t *
cairo_pattern_create_rgb (double red, double green, double blue);
 
cairo_public cairo_pattern_t *
cairo_pattern_create_rgba (double red, double green, double blue,
double alpha);
 
cairo_public cairo_pattern_t *
cairo_pattern_create_for_surface (cairo_surface_t *surface);
 
cairo_public cairo_pattern_t *
cairo_pattern_create_linear (double x0, double y0,
double x1, double y1);
 
cairo_public cairo_pattern_t *
cairo_pattern_create_radial (double cx0, double cy0, double radius0,
double cx1, double cy1, double radius1);
 
cairo_public cairo_pattern_t *
cairo_pattern_reference (cairo_pattern_t *pattern);
 
cairo_public void
cairo_pattern_destroy (cairo_pattern_t *pattern);
 
cairo_public unsigned int
cairo_pattern_get_reference_count (cairo_pattern_t *pattern);
 
cairo_public cairo_status_t
cairo_pattern_status (cairo_pattern_t *pattern);
 
cairo_public void *
cairo_pattern_get_user_data (cairo_pattern_t *pattern,
const cairo_user_data_key_t *key);
 
cairo_public cairo_status_t
cairo_pattern_set_user_data (cairo_pattern_t *pattern,
const cairo_user_data_key_t *key,
void *user_data,
cairo_destroy_func_t destroy);
 
/**
* cairo_pattern_type_t:
* @CAIRO_PATTERN_TYPE_SOLID: The pattern is a solid (uniform)
* color. It may be opaque or translucent.
* @CAIRO_PATTERN_TYPE_SURFACE: The pattern is a based on a surface (an image).
* @CAIRO_PATTERN_TYPE_LINEAR: The pattern is a linear gradient.
* @CAIRO_PATTERN_TYPE_RADIAL: The pattern is a radial gradient.
*
* #cairo_pattern_type_t is used to describe the type of a given pattern.
*
* The type of a pattern is determined by the function used to create
* it. The cairo_pattern_create_rgb() and cairo_pattern_create_rgba()
* functions create SOLID patterns. The remaining
* cairo_pattern_create<!-- --> functions map to pattern types in obvious
* ways.
*
* The pattern type can be queried with cairo_pattern_get_type()
*
* Most #cairo_pattern_t functions can be called with a pattern of any
* type, (though trying to change the extend or filter for a solid
* pattern will have no effect). A notable exception is
* cairo_pattern_add_color_stop_rgb() and
* cairo_pattern_add_color_stop_rgba() which must only be called with
* gradient patterns (either LINEAR or RADIAL). Otherwise the pattern
* will be shutdown and put into an error state.
*
* New entries may be added in future versions.
*
* Since: 1.2
**/
typedef enum _cairo_pattern_type {
CAIRO_PATTERN_TYPE_SOLID,
CAIRO_PATTERN_TYPE_SURFACE,
CAIRO_PATTERN_TYPE_LINEAR,
CAIRO_PATTERN_TYPE_RADIAL
} cairo_pattern_type_t;
 
cairo_public cairo_pattern_type_t
cairo_pattern_get_type (cairo_pattern_t *pattern);
 
cairo_public void
cairo_pattern_add_color_stop_rgb (cairo_pattern_t *pattern,
double offset,
double red, double green, double blue);
 
cairo_public void
cairo_pattern_add_color_stop_rgba (cairo_pattern_t *pattern,
double offset,
double red, double green, double blue,
double alpha);
 
cairo_public void
cairo_pattern_set_matrix (cairo_pattern_t *pattern,
const cairo_matrix_t *matrix);
 
cairo_public void
cairo_pattern_get_matrix (cairo_pattern_t *pattern,
cairo_matrix_t *matrix);
 
/**
* cairo_extend_t:
* @CAIRO_EXTEND_NONE: pixels outside of the source pattern
* are fully transparent
* @CAIRO_EXTEND_REPEAT: the pattern is tiled by repeating
* @CAIRO_EXTEND_REFLECT: the pattern is tiled by reflecting
* at the edges (Implemented for surface patterns since 1.6)
* @CAIRO_EXTEND_PAD: pixels outside of the pattern copy
* the closest pixel from the source (Since 1.2; but only
* implemented for surface patterns since 1.6)
*
* #cairo_extend_t is used to describe how pattern color/alpha will be
* determined for areas "outside" the pattern's natural area, (for
* example, outside the surface bounds or outside the gradient
* geometry).
*
* The default extend mode is %CAIRO_EXTEND_NONE for surface patterns
* and %CAIRO_EXTEND_PAD for gradient patterns.
*
* New entries may be added in future versions.
**/
typedef enum _cairo_extend {
CAIRO_EXTEND_NONE,
CAIRO_EXTEND_REPEAT,
CAIRO_EXTEND_REFLECT,
CAIRO_EXTEND_PAD
} cairo_extend_t;
 
cairo_public void
cairo_pattern_set_extend (cairo_pattern_t *pattern, cairo_extend_t extend);
 
cairo_public cairo_extend_t
cairo_pattern_get_extend (cairo_pattern_t *pattern);
 
/**
* cairo_filter_t:
* @CAIRO_FILTER_FAST: A high-performance filter, with quality similar
* to %CAIRO_FILTER_NEAREST
* @CAIRO_FILTER_GOOD: A reasonable-performance filter, with quality
* similar to %CAIRO_FILTER_BILINEAR
* @CAIRO_FILTER_BEST: The highest-quality available, performance may
* not be suitable for interactive use.
* @CAIRO_FILTER_NEAREST: Nearest-neighbor filtering
* @CAIRO_FILTER_BILINEAR: Linear interpolation in two dimensions
* @CAIRO_FILTER_GAUSSIAN: This filter value is currently
* unimplemented, and should not be used in current code.
*
* #cairo_filter_t is used to indicate what filtering should be
* applied when reading pixel values from patterns. See
* cairo_pattern_set_source() for indicating the desired filter to be
* used with a particular pattern.
*/
typedef enum _cairo_filter {
CAIRO_FILTER_FAST,
CAIRO_FILTER_GOOD,
CAIRO_FILTER_BEST,
CAIRO_FILTER_NEAREST,
CAIRO_FILTER_BILINEAR,
CAIRO_FILTER_GAUSSIAN
} cairo_filter_t;
 
cairo_public void
cairo_pattern_set_filter (cairo_pattern_t *pattern, cairo_filter_t filter);
 
cairo_public cairo_filter_t
cairo_pattern_get_filter (cairo_pattern_t *pattern);
 
cairo_public cairo_status_t
cairo_pattern_get_rgba (cairo_pattern_t *pattern,
double *red, double *green,
double *blue, double *alpha);
 
cairo_public cairo_status_t
cairo_pattern_get_surface (cairo_pattern_t *pattern,
cairo_surface_t **surface);
 
 
cairo_public cairo_status_t
cairo_pattern_get_color_stop_rgba (cairo_pattern_t *pattern,
int index, double *offset,
double *red, double *green,
double *blue, double *alpha);
 
cairo_public cairo_status_t
cairo_pattern_get_color_stop_count (cairo_pattern_t *pattern,
int *count);
 
cairo_public cairo_status_t
cairo_pattern_get_linear_points (cairo_pattern_t *pattern,
double *x0, double *y0,
double *x1, double *y1);
 
cairo_public cairo_status_t
cairo_pattern_get_radial_circles (cairo_pattern_t *pattern,
double *x0, double *y0, double *r0,
double *x1, double *y1, double *r1);
 
/* Matrix functions */
 
cairo_public void
cairo_matrix_init (cairo_matrix_t *matrix,
double xx, double yx,
double xy, double yy,
double x0, double y0);
 
cairo_public void
cairo_matrix_init_identity (cairo_matrix_t *matrix);
 
cairo_public void
cairo_matrix_init_translate (cairo_matrix_t *matrix,
double tx, double ty);
 
cairo_public void
cairo_matrix_init_scale (cairo_matrix_t *matrix,
double sx, double sy);
 
cairo_public void
cairo_matrix_init_rotate (cairo_matrix_t *matrix,
double radians);
 
cairo_public void
cairo_matrix_translate (cairo_matrix_t *matrix, double tx, double ty);
 
cairo_public void
cairo_matrix_scale (cairo_matrix_t *matrix, double sx, double sy);
 
cairo_public void
cairo_matrix_rotate (cairo_matrix_t *matrix, double radians);
 
cairo_public cairo_status_t
cairo_matrix_invert (cairo_matrix_t *matrix);
 
cairo_public void
cairo_matrix_multiply (cairo_matrix_t *result,
const cairo_matrix_t *a,
const cairo_matrix_t *b);
 
cairo_public void
cairo_matrix_transform_distance (const cairo_matrix_t *matrix,
double *dx, double *dy);
 
cairo_public void
cairo_matrix_transform_point (const cairo_matrix_t *matrix,
double *x, double *y);
 
/* Region functions */
 
/**
* cairo_region_t:
*
* A #cairo_region_t represents a set of integer-aligned rectangles.
*
* It allows set-theoretical operations like cairo_region_union() and
* cairo_region_intersect() to be performed on them.
*
* Memory management of #cairo_region_t is done with
* cairo_region_reference() and cairo_region_destroy().
*
* Since: 1.10
**/
typedef struct _cairo_region cairo_region_t;
 
/**
* cairo_rectangle_int_t:
* @x: X coordinate of the left side of the rectangle
* @y: Y coordinate of the the top side of the rectangle
* @width: width of the rectangle
* @height: height of the rectangle
*
* A data structure for holding a rectangle with integer coordinates.
*
* Since: 1.10
**/
 
typedef struct _cairo_rectangle_int {
int x, y;
int width, height;
} cairo_rectangle_int_t;
 
typedef enum _cairo_region_overlap {
CAIRO_REGION_OVERLAP_IN, /* completely inside region */
CAIRO_REGION_OVERLAP_OUT, /* completely outside region */
CAIRO_REGION_OVERLAP_PART /* partly inside region */
} cairo_region_overlap_t;
 
cairo_public cairo_region_t *
cairo_region_create (void);
 
cairo_public cairo_region_t *
cairo_region_create_rectangle (const cairo_rectangle_int_t *rectangle);
 
cairo_public cairo_region_t *
cairo_region_create_rectangles (const cairo_rectangle_int_t *rects,
int count);
 
cairo_public cairo_region_t *
cairo_region_copy (const cairo_region_t *original);
 
cairo_public cairo_region_t *
cairo_region_reference (cairo_region_t *region);
 
cairo_public void
cairo_region_destroy (cairo_region_t *region);
 
cairo_public cairo_bool_t
cairo_region_equal (const cairo_region_t *a, const cairo_region_t *b);
 
cairo_public cairo_status_t
cairo_region_status (const cairo_region_t *region);
 
cairo_public void
cairo_region_get_extents (const cairo_region_t *region,
cairo_rectangle_int_t *extents);
 
cairo_public int
cairo_region_num_rectangles (const cairo_region_t *region);
 
cairo_public void
cairo_region_get_rectangle (const cairo_region_t *region,
int nth,
cairo_rectangle_int_t *rectangle);
 
cairo_public cairo_bool_t
cairo_region_is_empty (const cairo_region_t *region);
 
cairo_public cairo_region_overlap_t
cairo_region_contains_rectangle (const cairo_region_t *region,
const cairo_rectangle_int_t *rectangle);
 
cairo_public cairo_bool_t
cairo_region_contains_point (const cairo_region_t *region, int x, int y);
 
cairo_public void
cairo_region_translate (cairo_region_t *region, int dx, int dy);
 
cairo_public cairo_status_t
cairo_region_subtract (cairo_region_t *dst, const cairo_region_t *other);
 
cairo_public cairo_status_t
cairo_region_subtract_rectangle (cairo_region_t *dst,
const cairo_rectangle_int_t *rectangle);
 
cairo_public cairo_status_t
cairo_region_intersect (cairo_region_t *dst, const cairo_region_t *other);
 
cairo_public cairo_status_t
cairo_region_intersect_rectangle (cairo_region_t *dst,
const cairo_rectangle_int_t *rectangle);
 
cairo_public cairo_status_t
cairo_region_union (cairo_region_t *dst, const cairo_region_t *other);
 
cairo_public cairo_status_t
cairo_region_union_rectangle (cairo_region_t *dst,
const cairo_rectangle_int_t *rectangle);
 
cairo_public cairo_status_t
cairo_region_xor (cairo_region_t *dst, const cairo_region_t *other);
 
cairo_public cairo_status_t
cairo_region_xor_rectangle (cairo_region_t *dst,
const cairo_rectangle_int_t *rectangle);
 
/* Functions to be used while debugging (not intended for use in production code) */
cairo_public void
cairo_debug_reset_static_data (void);
 
 
CAIRO_END_DECLS
 
#endif /* CAIRO_H */
/programs/develop/libraries/cairo/src/cairoint.h
0,0 → 1,2546
/* 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., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
*/
 
/*
* These definitions are solely for use by the implementation of cairo
* and constitute no kind of standard. If you need any of these
* functions, please drop me a note. Either the library needs new
* functionality, or there's a way to do what you need using the
* existing published interfaces. cworth@cworth.org
*/
 
#ifndef _CAIROINT_H_
#define _CAIROINT_H_
 
#if HAVE_CONFIG_H
#include "config.h"
#endif
 
#ifdef _MSC_VER
#define cairo_public __declspec(dllexport)
#endif
 
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <stddef.h>
 
#ifdef _MSC_VER
#define _USE_MATH_DEFINES
#endif
#include <math.h>
#include <limits.h>
#include <stdio.h>
 
#include "cairo.h"
#include <pixman.h>
 
#include "cairo-compiler-private.h"
 
#if CAIRO_HAS_PS_SURFACE || \
CAIRO_HAS_PDF_SURFACE || \
CAIRO_HAS_SVG_SURFACE || \
CAIRO_HAS_WIN32_SURFACE
#define CAIRO_HAS_FONT_SUBSET 1
#endif
 
#if CAIRO_HAS_PS_SURFACE || CAIRO_HAS_PDF_SURFACE || CAIRO_HAS_FONT_SUBSET
#define CAIRO_HAS_PDF_OPERATORS 1
#endif
 
CAIRO_BEGIN_DECLS
 
#if _WIN32 && !_WIN32_WCE /* Permissions on WinCE? No worries! */
cairo_private FILE *
_cairo_win32_tmpfile (void);
#define tmpfile() _cairo_win32_tmpfile()
#endif
 
#undef MIN
#define MIN(a, b) ((a) < (b) ? (a) : (b))
 
#undef MAX
#define MAX(a, b) ((a) > (b) ? (a) : (b))
 
#ifndef FALSE
#define FALSE 0
#endif
 
#ifndef TRUE
#define TRUE 1
#endif
 
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
 
#ifndef M_SQRT2
#define M_SQRT2 1.41421356237309504880
#endif
 
#ifndef M_SQRT1_2
#define M_SQRT1_2 0.707106781186547524400844362104849039
#endif
 
#undef ARRAY_LENGTH
#define ARRAY_LENGTH(__array) ((int) (sizeof (__array) / sizeof (__array[0])))
 
#undef STRINGIFY
#undef STRINGIFY_ARG
#define STRINGIFY(macro_or_string) STRINGIFY_ARG (macro_or_string)
#define STRINGIFY_ARG(contents) #contents
 
#if defined (__GNUC__)
#define cairo_container_of(ptr, type, member) ({ \
const __typeof__ (((type *) 0)->member) *mptr__ = (ptr); \
(type *) ((char *) mptr__ - offsetof (type, member)); \
})
#else
#define cairo_container_of(ptr, type, member) \
((type *)((char *) (ptr) - (char *) &((type *)0)->member))
#endif
 
 
#define ASSERT_NOT_REACHED \
do { \
assert (!"reached"); \
} while (0)
#define COMPILE_TIME_ASSERT1(condition, line) \
typedef int compile_time_assertion_at_line_##line##_failed [(condition)?1:-1]
#define COMPILE_TIME_ASSERT0(condition, line) COMPILE_TIME_ASSERT1(condition, line)
#define COMPILE_TIME_ASSERT(condition) COMPILE_TIME_ASSERT0(condition, __LINE__)
 
#define CAIRO_ALPHA_IS_CLEAR(alpha) ((alpha) <= ((double)0x00ff / (double)0xffff))
#define CAIRO_ALPHA_SHORT_IS_CLEAR(alpha) ((alpha) <= 0x00ff)
 
#define CAIRO_ALPHA_IS_OPAQUE(alpha) ((alpha) >= ((double)0xff00 / (double)0xffff))
#define CAIRO_ALPHA_SHORT_IS_OPAQUE(alpha) ((alpha) >= 0xff00)
#define CAIRO_ALPHA_IS_ZERO(alpha) ((alpha) <= 0.0)
 
#define CAIRO_COLOR_IS_CLEAR(color) CAIRO_ALPHA_SHORT_IS_CLEAR ((color)->alpha_short)
#define CAIRO_COLOR_IS_OPAQUE(color) CAIRO_ALPHA_SHORT_IS_OPAQUE ((color)->alpha_short)
 
/* Reverse the bits in a byte with 7 operations (no 64-bit):
* Devised by Sean Anderson, July 13, 2001.
* Source: http://graphics.stanford.edu/~seander/bithacks.html#ReverseByteWith32Bits
*/
#define CAIRO_BITSWAP8(c) ((((c) * 0x0802LU & 0x22110LU) | ((c) * 0x8020LU & 0x88440LU)) * 0x10101LU >> 16)
 
/* Return the number of 1 bits in mask.
*
* GCC 3.4 supports a "population count" builtin, which on many targets is
* implemented with a single instruction. There is a fallback definition
* in libgcc in case a target does not have one, which should be just as
* good as the open-coded solution below, (which is "HACKMEM 169").
*/
static inline int cairo_const
_cairo_popcount (uint32_t mask)
{
#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
return __builtin_popcount (mask);
#else
register int y;
 
y = (mask >> 1) &033333333333;
y = mask - y - ((y >>1) & 033333333333);
return (((y + (y >> 3)) & 030707070707) % 077);
#endif
}
 
#ifdef WORDS_BIGENDIAN
#define CAIRO_BITSWAP8_IF_LITTLE_ENDIAN(c) (c)
#else
#define CAIRO_BITSWAP8_IF_LITTLE_ENDIAN(c) CAIRO_BITSWAP8(c)
#endif
 
#ifdef WORDS_BIGENDIAN
 
#define cpu_to_be16(v) (v)
#define be16_to_cpu(v) (v)
#define cpu_to_be32(v) (v)
#define be32_to_cpu(v) (v)
 
#else
 
static inline uint16_t cairo_const
cpu_to_be16(uint16_t v)
{
return (v << 8) | (v >> 8);
}
 
static inline uint16_t cairo_const
be16_to_cpu(uint16_t v)
{
return cpu_to_be16 (v);
}
 
static inline uint32_t cairo_const
cpu_to_be32(uint32_t v)
{
return (cpu_to_be16 (v) << 16) | cpu_to_be16 (v >> 16);
}
 
static inline uint32_t cairo_const
be32_to_cpu(uint32_t v)
{
return cpu_to_be32 (v);
}
 
#endif
 
 
/* The glibc versions of ispace() and isdigit() are slow in UTF-8 locales.
*/
 
static inline int cairo_const
_cairo_isspace (int c)
{
return (c == 0x20 || (c >= 0x09 && c <= 0x0d));
}
 
static inline int cairo_const
_cairo_isdigit (int c)
{
return (c >= '0' && c <= '9');
}
 
#include "cairo-types-private.h"
#include "cairo-cache-private.h"
#include "cairo-reference-count-private.h"
#include "cairo-spans-private.h"
 
cairo_private void
_cairo_box_from_doubles (cairo_box_t *box,
double *x1, double *y1,
double *x2, double *y2);
 
cairo_private void
_cairo_box_to_doubles (const cairo_box_t *box,
double *x1, double *y1,
double *x2, double *y2);
 
cairo_private void
_cairo_box_from_rectangle (cairo_box_t *box,
const cairo_rectangle_int_t *rectangle);
 
cairo_private void
_cairo_box_round_to_rectangle (const cairo_box_t *box,
cairo_rectangle_int_t *rectangle);
 
cairo_private void
_cairo_boxes_get_extents (const cairo_box_t *boxes,
int num_boxes,
cairo_box_t *extents);
 
static inline void
_cairo_unbounded_rectangle_init (cairo_rectangle_int_t *rect)
{
rect->x = CAIRO_RECT_INT_MIN;
rect->y = CAIRO_RECT_INT_MIN;
rect->width = CAIRO_RECT_INT_MAX - CAIRO_RECT_INT_MIN;
rect->height = CAIRO_RECT_INT_MAX - CAIRO_RECT_INT_MIN;
}
 
cairo_private cairo_bool_t
_cairo_rectangle_intersect (cairo_rectangle_int_t *dst,
const cairo_rectangle_int_t *src);
 
cairo_private cairo_bool_t
_cairo_box_intersects_line_segment (cairo_box_t *box,
cairo_line_t *line) cairo_pure;
 
cairo_private cairo_bool_t
_cairo_box_contains_point (cairo_box_t *box,
const cairo_point_t *point) cairo_pure;
 
/* cairo-array.c structures and functions */
 
cairo_private void
_cairo_array_init (cairo_array_t *array, int element_size);
 
cairo_private void
_cairo_array_init_snapshot (cairo_array_t *array,
const cairo_array_t *other);
 
cairo_private void
_cairo_array_fini (cairo_array_t *array);
 
cairo_private cairo_status_t
_cairo_array_grow_by (cairo_array_t *array, unsigned int additional);
 
cairo_private void
_cairo_array_truncate (cairo_array_t *array, unsigned int num_elements);
 
cairo_private cairo_status_t
_cairo_array_append (cairo_array_t *array, const void *element);
 
cairo_private cairo_status_t
_cairo_array_append_multiple (cairo_array_t *array,
const void *elements,
int num_elements);
 
cairo_private cairo_status_t
_cairo_array_allocate (cairo_array_t *array,
unsigned int num_elements,
void **elements);
 
cairo_private void *
_cairo_array_index (cairo_array_t *array, unsigned int index);
 
cairo_private void
_cairo_array_copy_element (cairo_array_t *array, int index, void *dst);
 
cairo_private int
_cairo_array_num_elements (cairo_array_t *array);
 
cairo_private int
_cairo_array_size (cairo_array_t *array);
 
typedef struct {
const cairo_user_data_key_t *key;
void *user_data;
cairo_destroy_func_t destroy;
} cairo_user_data_slot_t;
 
cairo_private void
_cairo_user_data_array_init (cairo_user_data_array_t *array);
 
cairo_private void
_cairo_user_data_array_fini (cairo_user_data_array_t *array);
 
cairo_private void *
_cairo_user_data_array_get_data (cairo_user_data_array_t *array,
const cairo_user_data_key_t *key);
 
cairo_private cairo_status_t
_cairo_user_data_array_set_data (cairo_user_data_array_t *array,
const cairo_user_data_key_t *key,
void *user_data,
cairo_destroy_func_t destroy);
 
cairo_private cairo_status_t
_cairo_user_data_array_copy (cairo_user_data_array_t *dst,
cairo_user_data_array_t *src);
 
cairo_private void
_cairo_user_data_array_foreach (cairo_user_data_array_t *array,
void (*func) (const void *key,
void *elt,
void *closure),
void *closure);
 
#define _CAIRO_HASH_INIT_VALUE 5381
 
cairo_private unsigned long
_cairo_hash_string (const char *c);
 
cairo_private unsigned long
_cairo_hash_bytes (unsigned long hash,
const void *bytes,
unsigned int length);
 
#define _cairo_scaled_glyph_index(g) ((g)->hash_entry.hash)
#define _cairo_scaled_glyph_set_index(g, i) ((g)->hash_entry.hash = (i))
 
#include "cairo-scaled-font-private.h"
 
struct _cairo_font_face {
/* hash_entry must be first */
cairo_hash_entry_t hash_entry;
cairo_status_t status;
cairo_reference_count_t ref_count;
cairo_user_data_array_t user_data;
const cairo_font_face_backend_t *backend;
};
 
cairo_private void
_cairo_reset_static_data (void);
 
cairo_private void
_cairo_toy_font_face_reset_static_data (void);
 
cairo_private void
_cairo_ft_font_reset_static_data (void);
 
/* the font backend interface */
 
struct _cairo_unscaled_font_backend {
void (*destroy) (void *unscaled_font);
};
 
/* #cairo_toy_font_face_t - simple family/slant/weight font faces used for
* the built-in font API
*/
 
typedef struct _cairo_toy_font_face {
cairo_font_face_t base;
const char *family;
cairo_bool_t owns_family;
cairo_font_slant_t slant;
cairo_font_weight_t weight;
 
cairo_font_face_t *impl_face; /* The non-toy font face this actually uses */
} cairo_toy_font_face_t;
 
typedef enum _cairo_scaled_glyph_info {
CAIRO_SCALED_GLYPH_INFO_METRICS = (1 << 0),
CAIRO_SCALED_GLYPH_INFO_SURFACE = (1 << 1),
CAIRO_SCALED_GLYPH_INFO_PATH = (1 << 2),
CAIRO_SCALED_GLYPH_INFO_RECORDING_SURFACE = (1 << 3)
} cairo_scaled_glyph_info_t;
 
typedef struct _cairo_scaled_font_subset {
cairo_scaled_font_t *scaled_font;
unsigned int font_id;
unsigned int subset_id;
 
/* Index of glyphs array is subset_glyph_index.
* Value of glyphs array is scaled_font_glyph_index.
*/
unsigned long *glyphs;
unsigned long *to_unicode;
char **utf8;
char **glyph_names;
unsigned int num_glyphs;
cairo_bool_t is_composite;
cairo_bool_t is_scaled;
} cairo_scaled_font_subset_t;
 
struct _cairo_scaled_font_backend {
cairo_font_type_t type;
 
void
(*fini) (void *scaled_font);
 
cairo_warn cairo_int_status_t
(*scaled_glyph_init) (void *scaled_font,
cairo_scaled_glyph_t *scaled_glyph,
cairo_scaled_glyph_info_t info);
 
/* A backend only needs to implement this or ucs4_to_index(), not
* both. This allows the backend to do something more sophisticated
* then just converting characters one by one.
*/
cairo_warn cairo_int_status_t
(*text_to_glyphs) (void *scaled_font,
double x,
double y,
const char *utf8,
int utf8_len,
cairo_glyph_t **glyphs,
int *num_glyphs,
cairo_text_cluster_t **clusters,
int *num_clusters,
cairo_text_cluster_flags_t *cluster_flags);
 
unsigned long
(*ucs4_to_index) (void *scaled_font,
uint32_t ucs4);
cairo_warn cairo_int_status_t
(*show_glyphs) (void *scaled_font,
cairo_operator_t op,
const cairo_pattern_t *pattern,
cairo_surface_t *surface,
int source_x,
int source_y,
int dest_x,
int dest_y,
unsigned int width,
unsigned int height,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_region_t *clip_region,
int *remaining_glyphs);
 
cairo_warn cairo_int_status_t
(*load_truetype_table)(void *scaled_font,
unsigned long tag,
long offset,
unsigned char *buffer,
unsigned long *length);
 
/* ucs4 is set to -1 if the unicode character could not be found
* for the glyph */
cairo_warn cairo_int_status_t
(*index_to_ucs4)(void *scaled_font,
unsigned long index,
uint32_t *ucs4);
};
 
struct _cairo_font_face_backend {
cairo_font_type_t type;
 
cairo_warn cairo_status_t
(*create_for_toy) (cairo_toy_font_face_t *toy_face,
cairo_font_face_t **font_face);
 
/* The destroy() function is allowed to resurrect the font face
* by re-referencing. This is needed for the FreeType backend.
*/
void
(*destroy) (void *font_face);
 
cairo_warn cairo_status_t
(*scaled_font_create) (void *font_face,
const cairo_matrix_t *font_matrix,
const cairo_matrix_t *ctm,
const cairo_font_options_t *options,
cairo_scaled_font_t **scaled_font);
 
cairo_font_face_t *
(*get_implementation) (void *font_face,
const cairo_matrix_t *font_matrix,
const cairo_matrix_t *ctm,
const cairo_font_options_t *options);
};
 
extern const cairo_private struct _cairo_font_face_backend _cairo_user_font_face_backend;
 
/* concrete font backends */
#if CAIRO_HAS_FT_FONT
 
extern const cairo_private struct _cairo_font_face_backend _cairo_ft_font_face_backend;
 
#endif
 
#if CAIRO_HAS_WIN32_FONT
 
extern const cairo_private struct _cairo_font_face_backend _cairo_win32_font_face_backend;
 
#endif
 
#if CAIRO_HAS_QUARTZ_FONT
 
extern const cairo_private struct _cairo_font_face_backend _cairo_quartz_font_face_backend;
 
#endif
 
struct _cairo_surface_backend {
cairo_surface_type_t type;
 
cairo_surface_t *
(*create_similar) (void *surface,
cairo_content_t content,
int width,
int height);
 
cairo_warn cairo_status_t
(*finish) (void *surface);
 
cairo_warn cairo_status_t
(*acquire_source_image) (void *abstract_surface,
cairo_image_surface_t **image_out,
void **image_extra);
 
void
(*release_source_image) (void *abstract_surface,
cairo_image_surface_t *image,
void *image_extra);
 
cairo_warn cairo_status_t
(*acquire_dest_image) (void *abstract_surface,
cairo_rectangle_int_t *interest_rect,
cairo_image_surface_t **image_out,
cairo_rectangle_int_t *image_rect,
void **image_extra);
 
void
(*release_dest_image) (void *abstract_surface,
cairo_rectangle_int_t *interest_rect,
cairo_image_surface_t *image,
cairo_rectangle_int_t *image_rect,
void *image_extra);
 
/* Create a new surface (@clone_out) with the following
* characteristics:
*
* 1. It is as compatible as possible with @surface (in terms of
* efficiency)
*
* 2. It has the same contents as @src within the given rectangle.
*
* 3. The offset of the similar surface with respect to the original
* surface is returned in the clone_offset vector.
* - if you clone the entire surface, this vector is zero.
* - if you clone (src_x, src_y)x(w, h) the vector is (src_x, src_y);
*/
cairo_warn cairo_status_t
(*clone_similar) (void *surface,
cairo_surface_t *src,
int src_x,
int src_y,
int width,
int height,
int *clone_offset_x,
int *clone_offset_y,
cairo_surface_t **clone_out);
 
/* XXX remove to a separate cairo_surface_compositor_t */
/* XXX: dst should be the first argument for consistency */
cairo_warn cairo_int_status_t
(*composite) (cairo_operator_t op,
const cairo_pattern_t *src,
const cairo_pattern_t *mask,
void *dst,
int src_x,
int src_y,
int mask_x,
int mask_y,
int dst_x,
int dst_y,
unsigned int width,
unsigned int height,
cairo_region_t *clip_region);
 
cairo_warn cairo_int_status_t
(*fill_rectangles) (void *surface,
cairo_operator_t op,
const cairo_color_t *color,
cairo_rectangle_int_t *rects,
int num_rects);
 
/* XXX: dst should be the first argument for consistency */
cairo_warn cairo_int_status_t
(*composite_trapezoids) (cairo_operator_t op,
const cairo_pattern_t *pattern,
void *dst,
cairo_antialias_t antialias,
int src_x,
int src_y,
int dst_x,
int dst_y,
unsigned int width,
unsigned int height,
cairo_trapezoid_t *traps,
int num_traps,
cairo_region_t *region);
 
cairo_warn cairo_span_renderer_t *
(*create_span_renderer) (cairo_operator_t op,
const cairo_pattern_t *pattern,
void *dst,
cairo_antialias_t antialias,
const cairo_composite_rectangles_t *rects,
cairo_region_t *clip_region);
 
cairo_warn cairo_bool_t
(*check_span_renderer) (cairo_operator_t op,
const cairo_pattern_t *pattern,
void *dst,
cairo_antialias_t antialias);
 
cairo_warn cairo_int_status_t
(*copy_page) (void *surface);
 
cairo_warn cairo_int_status_t
(*show_page) (void *surface);
 
/* Get the extents of the current surface. For many surface types
* this will be as simple as { x=0, y=0, width=surface->width,
* height=surface->height}.
*
* If this function is not implemented, or if it returns
* FALSE the surface is considered to be
* boundless and infinite bounds are used for it.
*/
cairo_warn cairo_bool_t
(*get_extents) (void *surface,
cairo_rectangle_int_t *extents);
 
/*
* This is an optional entry to let the surface manage its own glyph
* resources. If null, render against this surface, using image
* surfaces as glyphs.
*/
cairo_warn cairo_int_status_t
(*old_show_glyphs) (cairo_scaled_font_t *font,
cairo_operator_t op,
const cairo_pattern_t *pattern,
void *surface,
int source_x,
int source_y,
int dest_x,
int dest_y,
unsigned int width,
unsigned int height,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_region_t *clip_region);
 
void
(*get_font_options) (void *surface,
cairo_font_options_t *options);
 
cairo_warn cairo_status_t
(*flush) (void *surface);
 
cairo_warn cairo_status_t
(*mark_dirty_rectangle) (void *surface,
int x,
int y,
int width,
int height);
 
void
(*scaled_font_fini) (cairo_scaled_font_t *scaled_font);
 
void
(*scaled_glyph_fini) (cairo_scaled_glyph_t *scaled_glyph,
cairo_scaled_font_t *scaled_font);
 
/* OK, I'm starting over somewhat by defining the 5 top-level
* drawing operators for the surface backend here with consistent
* naming and argument-order conventions. */
cairo_warn cairo_int_status_t
(*paint) (void *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_clip_t *clip);
 
cairo_warn cairo_int_status_t
(*mask) (void *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_pattern_t *mask,
cairo_clip_t *clip);
 
cairo_warn cairo_int_status_t
(*stroke) (void *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_path_fixed_t *path,
const cairo_stroke_style_t *style,
const cairo_matrix_t *ctm,
const cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
cairo_clip_t *clip);
 
cairo_warn cairo_int_status_t
(*fill) (void *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias,
cairo_clip_t *clip);
 
cairo_warn cairo_int_status_t
(*show_glyphs) (void *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font,
cairo_clip_t *clip,
int *remaining_glyphs);
 
cairo_surface_t *
(*snapshot) (void *surface);
 
cairo_bool_t
(*is_similar) (void *surface_a,
void *surface_b);
 
cairo_warn cairo_int_status_t
(*fill_stroke) (void *surface,
cairo_operator_t fill_op,
const cairo_pattern_t *fill_source,
cairo_fill_rule_t fill_rule,
double fill_tolerance,
cairo_antialias_t fill_antialias,
cairo_path_fixed_t *path,
cairo_operator_t stroke_op,
const cairo_pattern_t *stroke_source,
const cairo_stroke_style_t *stroke_style,
const cairo_matrix_t *stroke_ctm,
const cairo_matrix_t *stroke_ctm_inverse,
double stroke_tolerance,
cairo_antialias_t stroke_antialias,
cairo_clip_t *clip);
 
cairo_surface_t *
(*create_solid_pattern_surface)
(void *surface,
const cairo_solid_pattern_t *solid_pattern);
 
cairo_bool_t
(*can_repaint_solid_pattern_surface)
(void *surface,
const cairo_solid_pattern_t *solid_pattern);
 
cairo_bool_t
(*has_show_text_glyphs) (void *surface);
 
cairo_warn cairo_int_status_t
(*show_text_glyphs) (void *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const char *utf8,
int utf8_len,
cairo_glyph_t *glyphs,
int num_glyphs,
const cairo_text_cluster_t *clusters,
int num_clusters,
cairo_text_cluster_flags_t cluster_flags,
cairo_scaled_font_t *scaled_font,
cairo_clip_t *clip);
};
 
#include "cairo-surface-private.h"
 
struct _cairo_image_surface {
cairo_surface_t base;
 
pixman_format_code_t pixman_format;
cairo_format_t format;
unsigned char *data;
 
int width;
int height;
int stride;
int depth;
 
pixman_image_t *pixman_image;
 
unsigned owns_data : 1;
unsigned transparency : 2;
};
 
extern const cairo_private cairo_surface_backend_t _cairo_image_surface_backend;
 
#define CAIRO_EXTEND_SURFACE_DEFAULT CAIRO_EXTEND_NONE
#define CAIRO_EXTEND_GRADIENT_DEFAULT CAIRO_EXTEND_PAD
#define CAIRO_FILTER_DEFAULT CAIRO_FILTER_GOOD
 
extern const cairo_private cairo_solid_pattern_t _cairo_pattern_clear;
extern const cairo_private cairo_solid_pattern_t _cairo_pattern_black;
extern const cairo_private cairo_solid_pattern_t _cairo_pattern_white;
 
typedef struct _cairo_surface_attributes {
cairo_matrix_t matrix;
cairo_extend_t extend;
cairo_filter_t filter;
cairo_bool_t has_component_alpha;
int x_offset;
int y_offset;
void *extra;
} cairo_surface_attributes_t;
 
typedef struct _cairo_traps {
cairo_status_t status;
 
const cairo_box_t *limits;
int num_limits;
 
unsigned int maybe_region : 1; /* hint: 0 implies that it cannot be */
unsigned int has_intersections : 1;
unsigned int is_rectilinear : 1;
unsigned int is_rectangular : 1;
 
int num_traps;
int traps_size;
cairo_trapezoid_t *traps;
cairo_trapezoid_t traps_embedded[16];
} cairo_traps_t;
 
#define CAIRO_FONT_SLANT_DEFAULT CAIRO_FONT_SLANT_NORMAL
#define CAIRO_FONT_WEIGHT_DEFAULT CAIRO_FONT_WEIGHT_NORMAL
 
#define CAIRO_WIN32_FONT_FAMILY_DEFAULT "Arial"
#define CAIRO_QUARTZ_FONT_FAMILY_DEFAULT "Helvetica"
#define CAIRO_FT_FONT_FAMILY_DEFAULT ""
#define CAIRO_USER_FONT_FAMILY_DEFAULT "@cairo:"
 
#if CAIRO_HAS_WIN32_FONT
 
#define CAIRO_FONT_FAMILY_DEFAULT CAIRO_WIN32_FONT_FAMILY_DEFAULT
#define CAIRO_FONT_FACE_BACKEND_DEFAULT &_cairo_win32_font_face_backend
 
#elif CAIRO_HAS_QUARTZ_FONT
 
#define CAIRO_FONT_FAMILY_DEFAULT CAIRO_QUARTZ_FONT_FAMILY_DEFAULT
#define CAIRO_FONT_FACE_BACKEND_DEFAULT &_cairo_quartz_font_face_backend
 
#elif CAIRO_HAS_FT_FONT
 
#define CAIRO_FONT_FAMILY_DEFAULT CAIRO_FT_FONT_FAMILY_DEFAULT
#define CAIRO_FONT_FACE_BACKEND_DEFAULT &_cairo_ft_font_face_backend
 
#else
 
#define CAIRO_FONT_FAMILY_DEFAULT CAIRO_FT_FONT_FAMILY_DEFAULT
#define CAIRO_FONT_FACE_BACKEND_DEFAULT &_cairo_user_font_face_backend
 
#endif
 
#define CAIRO_GSTATE_OPERATOR_DEFAULT CAIRO_OPERATOR_OVER
#define CAIRO_GSTATE_TOLERANCE_DEFAULT 0.1
#define CAIRO_GSTATE_FILL_RULE_DEFAULT CAIRO_FILL_RULE_WINDING
#define CAIRO_GSTATE_LINE_WIDTH_DEFAULT 2.0
#define CAIRO_GSTATE_LINE_CAP_DEFAULT CAIRO_LINE_CAP_BUTT
#define CAIRO_GSTATE_LINE_JOIN_DEFAULT CAIRO_LINE_JOIN_MITER
#define CAIRO_GSTATE_MITER_LIMIT_DEFAULT 10.0
#define CAIRO_GSTATE_DEFAULT_FONT_SIZE 10.0
 
#define CAIRO_SURFACE_RESOLUTION_DEFAULT 72.0
#define CAIRO_SURFACE_FALLBACK_RESOLUTION_DEFAULT 300.0
 
typedef struct _cairo_stroke_face {
cairo_point_t ccw;
cairo_point_t point;
cairo_point_t cw;
cairo_slope_t dev_vector;
cairo_point_double_t usr_vector;
} cairo_stroke_face_t;
 
/* cairo.c */
 
static inline double cairo_const
_cairo_restrict_value (double value, double min, double max)
{
if (value < min)
return min;
else if (value > max)
return max;
else
return value;
}
 
/* C99 round() rounds to the nearest integral value with halfway cases rounded
* away from 0. _cairo_round rounds halfway cases toward negative infinity.
* This matches the rounding behaviour of _cairo_lround. */
static inline double cairo_const
_cairo_round (double r)
{
return floor (r + .5);
}
 
#if DISABLE_SOME_FLOATING_POINT
cairo_private int
_cairo_lround (double d) cairo_const;
#else
#define _cairo_lround lround
#endif
 
cairo_private uint16_t
_cairo_half_from_float (float f) cairo_const;
 
cairo_private cairo_bool_t
_cairo_operator_bounded_by_mask (cairo_operator_t op) cairo_const;
 
cairo_private cairo_bool_t
_cairo_operator_bounded_by_source (cairo_operator_t op) cairo_const;
 
enum {
CAIRO_OPERATOR_BOUND_BY_MASK = 1 << 1,
CAIRO_OPERATOR_BOUND_BY_SOURCE = 1 << 2,
};
 
cairo_private uint32_t
_cairo_operator_bounded_by_either (cairo_operator_t op) cairo_const;
/* cairo-color.c */
cairo_private const cairo_color_t *
_cairo_stock_color (cairo_stock_t stock) cairo_pure;
 
#define CAIRO_COLOR_WHITE _cairo_stock_color (CAIRO_STOCK_WHITE)
#define CAIRO_COLOR_BLACK _cairo_stock_color (CAIRO_STOCK_BLACK)
#define CAIRO_COLOR_TRANSPARENT _cairo_stock_color (CAIRO_STOCK_TRANSPARENT)
 
cairo_private uint16_t
_cairo_color_double_to_short (double d) cairo_const;
 
cairo_private void
_cairo_color_init (cairo_color_t *color);
 
cairo_private void
_cairo_color_init_rgb (cairo_color_t *color,
double red, double green, double blue);
 
cairo_private void
_cairo_color_init_rgba (cairo_color_t *color,
double red, double green, double blue,
double alpha);
 
cairo_private void
_cairo_color_multiply_alpha (cairo_color_t *color,
double alpha);
 
cairo_private void
_cairo_color_get_rgba (cairo_color_t *color,
double *red,
double *green,
double *blue,
double *alpha);
 
cairo_private void
_cairo_color_get_rgba_premultiplied (cairo_color_t *color,
double *red,
double *green,
double *blue,
double *alpha);
 
cairo_private cairo_bool_t
_cairo_color_equal (const cairo_color_t *color_a,
const cairo_color_t *color_b) cairo_pure;
 
cairo_private cairo_bool_t
_cairo_color_stop_equal (const cairo_color_stop_t *color_a,
const cairo_color_stop_t *color_b) cairo_pure;
 
cairo_private cairo_content_t
_cairo_color_get_content (const cairo_color_t *color) cairo_pure;
 
/* cairo-font-face.c */
 
extern const cairo_private cairo_font_face_t _cairo_font_face_nil;
 
cairo_private void
_cairo_font_face_init (cairo_font_face_t *font_face,
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 void
_cairo_unscaled_font_init (cairo_unscaled_font_t *font,
const cairo_unscaled_font_backend_t *backend);
 
cairo_private_no_warn cairo_unscaled_font_t *
_cairo_unscaled_font_reference (cairo_unscaled_font_t *font);
 
cairo_private void
_cairo_unscaled_font_destroy (cairo_unscaled_font_t *font);
 
/* cairo-font-face-twin.c */
 
cairo_private cairo_font_face_t *
_cairo_font_face_twin_create_fallback (void);
 
cairo_private cairo_status_t
_cairo_font_face_twin_create_for_toy (cairo_toy_font_face_t *toy_face,
cairo_font_face_t **font_face);
 
/* cairo-font-face-twin-data.c */
 
extern const cairo_private int8_t _cairo_twin_outlines[];
extern const cairo_private uint16_t _cairo_twin_charmap[128];
 
/* cairo-font-options.c */
 
cairo_private void
_cairo_font_options_init_default (cairo_font_options_t *options);
 
cairo_private void
_cairo_font_options_init_copy (cairo_font_options_t *options,
const cairo_font_options_t *other);
 
cairo_private void
_cairo_font_options_set_lcd_filter (cairo_font_options_t *options,
cairo_lcd_filter_t lcd_filter);
 
cairo_private cairo_lcd_filter_t
_cairo_font_options_get_lcd_filter (const cairo_font_options_t *options);
 
/* cairo-hull.c */
cairo_private cairo_status_t
_cairo_hull_compute (cairo_pen_vertex_t *vertices, int *num_vertices);
 
/* cairo-lzw.c */
cairo_private unsigned char *
_cairo_lzw_compress (unsigned char *data, unsigned long *size_in_out);
 
/* cairo-misc.c */
cairo_private cairo_status_t
_cairo_validate_text_clusters (const char *utf8,
int utf8_len,
const cairo_glyph_t *glyphs,
int num_glyphs,
const cairo_text_cluster_t *clusters,
int num_clusters,
cairo_text_cluster_flags_t cluster_flags);
 
cairo_private cairo_status_t
_cairo_intern_string (const char **str_inout, int len);
 
cairo_private void
_cairo_intern_string_reset_static_data (void);
 
/* cairo-path-fixed.c */
cairo_private cairo_path_fixed_t *
_cairo_path_fixed_create (void);
 
cairo_private void
_cairo_path_fixed_init (cairo_path_fixed_t *path);
 
cairo_private cairo_status_t
_cairo_path_fixed_init_copy (cairo_path_fixed_t *path,
const cairo_path_fixed_t *other);
 
cairo_private cairo_bool_t
_cairo_path_fixed_is_equal (const cairo_path_fixed_t *path,
const cairo_path_fixed_t *other);
 
cairo_private void
_cairo_path_fixed_fini (cairo_path_fixed_t *path);
 
cairo_private void
_cairo_path_fixed_destroy (cairo_path_fixed_t *path);
 
cairo_private cairo_status_t
_cairo_path_fixed_move_to (cairo_path_fixed_t *path,
cairo_fixed_t x,
cairo_fixed_t y);
 
cairo_private void
_cairo_path_fixed_new_sub_path (cairo_path_fixed_t *path);
 
cairo_private cairo_status_t
_cairo_path_fixed_rel_move_to (cairo_path_fixed_t *path,
cairo_fixed_t dx,
cairo_fixed_t dy);
 
cairo_private cairo_status_t
_cairo_path_fixed_line_to (cairo_path_fixed_t *path,
cairo_fixed_t x,
cairo_fixed_t y);
 
cairo_private cairo_status_t
_cairo_path_fixed_rel_line_to (cairo_path_fixed_t *path,
cairo_fixed_t dx,
cairo_fixed_t dy);
 
cairo_private cairo_status_t
_cairo_path_fixed_curve_to (cairo_path_fixed_t *path,
cairo_fixed_t x0, cairo_fixed_t y0,
cairo_fixed_t x1, cairo_fixed_t y1,
cairo_fixed_t x2, cairo_fixed_t y2);
 
cairo_private cairo_status_t
_cairo_path_fixed_rel_curve_to (cairo_path_fixed_t *path,
cairo_fixed_t dx0, cairo_fixed_t dy0,
cairo_fixed_t dx1, cairo_fixed_t dy1,
cairo_fixed_t dx2, cairo_fixed_t dy2);
 
cairo_private cairo_status_t
_cairo_path_fixed_close_path (cairo_path_fixed_t *path);
 
cairo_private cairo_bool_t
_cairo_path_fixed_get_current_point (cairo_path_fixed_t *path,
cairo_fixed_t *x,
cairo_fixed_t *y);
 
typedef cairo_status_t
(cairo_path_fixed_move_to_func_t) (void *closure,
const cairo_point_t *point);
 
typedef cairo_status_t
(cairo_path_fixed_line_to_func_t) (void *closure,
const cairo_point_t *point);
 
typedef cairo_status_t
(cairo_path_fixed_curve_to_func_t) (void *closure,
const cairo_point_t *p0,
const cairo_point_t *p1,
const cairo_point_t *p2);
 
typedef cairo_status_t
(cairo_path_fixed_close_path_func_t) (void *closure);
 
cairo_private cairo_status_t
_cairo_path_fixed_interpret (const cairo_path_fixed_t *path,
cairo_direction_t dir,
cairo_path_fixed_move_to_func_t *move_to,
cairo_path_fixed_line_to_func_t *line_to,
cairo_path_fixed_curve_to_func_t *curve_to,
cairo_path_fixed_close_path_func_t *close_path,
void *closure);
 
cairo_private cairo_status_t
_cairo_path_fixed_interpret_flat (const cairo_path_fixed_t *path,
cairo_direction_t dir,
cairo_path_fixed_move_to_func_t *move_to,
cairo_path_fixed_line_to_func_t *line_to,
cairo_path_fixed_close_path_func_t *close_path,
void *closure,
double tolerance);
 
cairo_private cairo_bool_t
_cairo_path_fixed_extents (const cairo_path_fixed_t *path,
cairo_box_t *box);
 
cairo_private void
_cairo_path_fixed_approximate_clip_extents (const cairo_path_fixed_t *path,
cairo_rectangle_int_t *extents);
 
cairo_private void
_cairo_path_fixed_approximate_fill_extents (const cairo_path_fixed_t *path,
cairo_rectangle_int_t *extents);
 
cairo_private void
_cairo_path_fixed_fill_extents (const cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_rectangle_int_t *extents);
 
cairo_private void
_cairo_path_fixed_approximate_stroke_extents (const cairo_path_fixed_t *path,
const cairo_stroke_style_t *style,
const cairo_matrix_t *ctm,
cairo_rectangle_int_t *extents);
 
cairo_private cairo_status_t
_cairo_path_fixed_stroke_extents (const cairo_path_fixed_t *path,
const cairo_stroke_style_t *style,
const cairo_matrix_t *ctm,
const cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_rectangle_int_t *extents);
 
cairo_private void
_cairo_path_fixed_transform (cairo_path_fixed_t *path,
const cairo_matrix_t *matrix);
 
cairo_private cairo_bool_t
_cairo_path_fixed_is_box (const cairo_path_fixed_t *path,
cairo_box_t *box);
 
cairo_private cairo_bool_t
_cairo_path_fixed_is_rectangle (const cairo_path_fixed_t *path,
cairo_box_t *box);
 
/* cairo-path-in-fill.c */
cairo_private cairo_bool_t
_cairo_path_fixed_in_fill (const cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
double x,
double y);
 
/* cairo-path-fill.c */
cairo_private cairo_status_t
_cairo_path_fixed_fill_to_polygon (const cairo_path_fixed_t *path,
double tolerance,
cairo_polygon_t *polygon);
 
cairo_private cairo_int_status_t
_cairo_path_fixed_fill_rectilinear_to_traps (const cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
cairo_traps_t *traps);
 
cairo_private cairo_status_t
_cairo_path_fixed_fill_rectilinear_to_boxes (const cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
cairo_boxes_t *boxes);
 
cairo_private cairo_region_t *
_cairo_path_fixed_fill_rectilinear_to_region (const cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
const cairo_rectangle_int_t *extents);
 
cairo_private cairo_status_t
_cairo_path_fixed_fill_to_traps (const cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_traps_t *traps);
 
/* cairo-path-stroke.c */
cairo_private cairo_status_t
_cairo_path_fixed_stroke_to_polygon (const cairo_path_fixed_t *path,
const cairo_stroke_style_t *stroke_style,
const cairo_matrix_t *ctm,
const cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_polygon_t *polygon);
 
cairo_private cairo_int_status_t
_cairo_path_fixed_stroke_rectilinear_to_traps (const cairo_path_fixed_t *path,
const cairo_stroke_style_t *stroke_style,
const cairo_matrix_t *ctm,
cairo_traps_t *traps);
 
cairo_private cairo_int_status_t
_cairo_path_fixed_stroke_rectilinear_to_boxes (const cairo_path_fixed_t *path,
const cairo_stroke_style_t *stroke_style,
const cairo_matrix_t *ctm,
cairo_boxes_t *boxes);
 
cairo_private cairo_status_t
_cairo_path_fixed_stroke_to_traps (const cairo_path_fixed_t *path,
const cairo_stroke_style_t *stroke_style,
const cairo_matrix_t *ctm,
const cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_traps_t *traps);
 
cairo_private cairo_status_t
_cairo_path_fixed_stroke_to_shaper (cairo_path_fixed_t *path,
const cairo_stroke_style_t *stroke_style,
const cairo_matrix_t *ctm,
const cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_status_t (*add_triangle) (void *closure,
const cairo_point_t triangle[3]),
cairo_status_t (*add_triangle_fan) (void *closure,
const cairo_point_t *midpt,
const cairo_point_t *points,
int npoints),
cairo_status_t (*add_quad) (void *closure,
const cairo_point_t quad[4]),
void *closure);
 
/* cairo-scaled-font.c */
 
cairo_private void
_cairo_scaled_font_freeze_cache (cairo_scaled_font_t *scaled_font);
 
cairo_private void
_cairo_scaled_font_thaw_cache (cairo_scaled_font_t *scaled_font);
 
cairo_private void
_cairo_scaled_font_reset_cache (cairo_scaled_font_t *scaled_font);
 
cairo_private cairo_status_t
_cairo_scaled_font_set_error (cairo_scaled_font_t *scaled_font,
cairo_status_t status);
 
cairo_private cairo_scaled_font_t *
_cairo_scaled_font_create_in_error (cairo_status_t status);
 
cairo_private void
_cairo_scaled_font_reset_static_data (void);
 
cairo_private cairo_status_t
_cairo_scaled_font_register_placeholder_and_unlock_font_map (cairo_scaled_font_t *scaled_font);
 
cairo_private void
_cairo_scaled_font_unregister_placeholder_and_lock_font_map (cairo_scaled_font_t *scaled_font);
 
cairo_private cairo_status_t
_cairo_scaled_font_init (cairo_scaled_font_t *scaled_font,
cairo_font_face_t *font_face,
const cairo_matrix_t *font_matrix,
const cairo_matrix_t *ctm,
const cairo_font_options_t *options,
const cairo_scaled_font_backend_t *backend);
 
cairo_private cairo_status_t
_cairo_scaled_font_set_metrics (cairo_scaled_font_t *scaled_font,
cairo_font_extents_t *fs_metrics);
 
/* This should only be called on an error path by a scaled_font constructor */
cairo_private void
_cairo_scaled_font_fini (cairo_scaled_font_t *scaled_font);
 
cairo_private cairo_status_t
_cairo_scaled_font_font_extents (cairo_scaled_font_t *scaled_font,
cairo_font_extents_t *extents);
 
cairo_private cairo_status_t
_cairo_scaled_font_glyph_device_extents (cairo_scaled_font_t *scaled_font,
const cairo_glyph_t *glyphs,
int num_glyphs,
cairo_rectangle_int_t *extents,
cairo_bool_t *overlap);
 
cairo_private void
_cairo_scaled_font_glyph_approximate_extents (cairo_scaled_font_t *scaled_font,
const cairo_glyph_t *glyphs,
int num_glyphs,
cairo_rectangle_int_t *extents);
 
cairo_private cairo_status_t
_cairo_scaled_font_show_glyphs (cairo_scaled_font_t *scaled_font,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_surface_t *surface,
int source_x,
int source_y,
int dest_x,
int dest_y,
unsigned int width,
unsigned int height,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_region_t *clip_region);
 
cairo_private cairo_status_t
_cairo_scaled_font_glyph_path (cairo_scaled_font_t *scaled_font,
const cairo_glyph_t *glyphs,
int num_glyphs,
cairo_path_fixed_t *path);
 
cairo_private void
_cairo_scaled_glyph_set_metrics (cairo_scaled_glyph_t *scaled_glyph,
cairo_scaled_font_t *scaled_font,
cairo_text_extents_t *fs_metrics);
 
cairo_private void
_cairo_scaled_glyph_set_surface (cairo_scaled_glyph_t *scaled_glyph,
cairo_scaled_font_t *scaled_font,
cairo_image_surface_t *surface);
 
cairo_private void
_cairo_scaled_glyph_set_path (cairo_scaled_glyph_t *scaled_glyph,
cairo_scaled_font_t *scaled_font,
cairo_path_fixed_t *path);
 
cairo_private void
_cairo_scaled_glyph_set_recording_surface (cairo_scaled_glyph_t *scaled_glyph,
cairo_scaled_font_t *scaled_font,
cairo_surface_t *recording_surface);
 
cairo_private cairo_int_status_t
_cairo_scaled_glyph_lookup (cairo_scaled_font_t *scaled_font,
unsigned long index,
cairo_scaled_glyph_info_t info,
cairo_scaled_glyph_t **scaled_glyph_ret);
 
cairo_private double
_cairo_scaled_font_get_max_scale (cairo_scaled_font_t *scaled_font);
 
cairo_private void
_cairo_scaled_font_map_destroy (void);
 
/* cairo-stroke-style.c */
 
cairo_private void
_cairo_stroke_style_init (cairo_stroke_style_t *style);
 
cairo_private cairo_status_t
_cairo_stroke_style_init_copy (cairo_stroke_style_t *style,
const cairo_stroke_style_t *other);
 
cairo_private void
_cairo_stroke_style_fini (cairo_stroke_style_t *style);
 
cairo_private void
_cairo_stroke_style_max_distance_from_path (const cairo_stroke_style_t *style,
const cairo_matrix_t *ctm,
double *dx, double *dy);
 
cairo_private double
_cairo_stroke_style_dash_period (const cairo_stroke_style_t *style);
 
cairo_private double
_cairo_stroke_style_dash_stroked (const cairo_stroke_style_t *style);
 
cairo_private cairo_bool_t
_cairo_stroke_style_dash_can_approximate (const cairo_stroke_style_t *style,
const cairo_matrix_t *ctm,
double tolerance);
 
cairo_private void
_cairo_stroke_style_dash_approximate (const cairo_stroke_style_t *style,
const cairo_matrix_t *ctm,
double tolerance,
double *dash_offset,
double *dashes,
unsigned int *num_dashes);
 
 
/* cairo-surface.c */
 
cairo_private cairo_surface_t *
_cairo_surface_create_in_error (cairo_status_t status);
 
cairo_private cairo_status_t
_cairo_surface_copy_mime_data (cairo_surface_t *dst,
cairo_surface_t *src);
 
cairo_private cairo_status_t
_cairo_surface_set_error (cairo_surface_t *surface,
cairo_status_t status);
 
cairo_private void
_cairo_surface_set_resolution (cairo_surface_t *surface,
double x_res,
double y_res);
 
cairo_private cairo_surface_t *
_cairo_surface_create_similar_scratch (cairo_surface_t *other,
cairo_content_t content,
int width,
int height);
 
cairo_private cairo_surface_t *
_cairo_surface_create_similar_solid (cairo_surface_t *other,
cairo_content_t content,
int width,
int height,
const cairo_color_t *color,
cairo_bool_t allow_fallback);
 
cairo_private cairo_surface_t *
_cairo_surface_create_solid_pattern_surface (cairo_surface_t *other,
const cairo_solid_pattern_t *solid_pattern);
 
cairo_private cairo_int_status_t
_cairo_surface_repaint_solid_pattern_surface (cairo_surface_t *other,
cairo_surface_t *solid_surface,
const cairo_solid_pattern_t *solid_pattern);
 
cairo_private void
_cairo_surface_init (cairo_surface_t *surface,
const cairo_surface_backend_t *backend,
cairo_device_t *device,
cairo_content_t content);
 
cairo_private void
_cairo_surface_set_font_options (cairo_surface_t *surface,
cairo_font_options_t *options);
 
cairo_private cairo_status_t
_cairo_surface_composite (cairo_operator_t op,
const cairo_pattern_t *src,
const cairo_pattern_t *mask,
cairo_surface_t *dst,
int src_x,
int src_y,
int mask_x,
int mask_y,
int dst_x,
int dst_y,
unsigned int width,
unsigned int height,
cairo_region_t *clip_region);
 
cairo_private cairo_status_t
_cairo_surface_fill_rectangle (cairo_surface_t *surface,
cairo_operator_t op,
const cairo_color_t *color,
int x,
int y,
int width,
int height);
 
cairo_private cairo_status_t
_cairo_surface_fill_region (cairo_surface_t *surface,
cairo_operator_t op,
const cairo_color_t *color,
cairo_region_t *region);
 
cairo_private cairo_status_t
_cairo_surface_fill_rectangles (cairo_surface_t *surface,
cairo_operator_t op,
const cairo_color_t *color,
cairo_rectangle_int_t *rects,
int num_rects);
 
cairo_private cairo_status_t
_cairo_surface_paint (cairo_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_clip_t *clip);
 
cairo_private cairo_status_t
_cairo_surface_mask (cairo_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_pattern_t *mask,
cairo_clip_t *clip);
 
cairo_private cairo_status_t
_cairo_surface_fill_stroke (cairo_surface_t *surface,
cairo_operator_t fill_op,
const cairo_pattern_t *fill_source,
cairo_fill_rule_t fill_rule,
double fill_tolerance,
cairo_antialias_t fill_antialias,
cairo_path_fixed_t *path,
cairo_operator_t stroke_op,
const cairo_pattern_t *stroke_source,
const cairo_stroke_style_t *stroke_style,
const cairo_matrix_t *stroke_ctm,
const cairo_matrix_t *stroke_ctm_inverse,
double stroke_tolerance,
cairo_antialias_t stroke_antialias,
cairo_clip_t *clip);
 
cairo_private cairo_status_t
_cairo_surface_stroke (cairo_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_path_fixed_t *path,
const cairo_stroke_style_t *style,
const cairo_matrix_t *ctm,
const cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
cairo_clip_t *clip);
 
cairo_private cairo_status_t
_cairo_surface_fill (cairo_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias,
cairo_clip_t *clip);
 
cairo_private cairo_status_t
_cairo_surface_show_text_glyphs (cairo_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const char *utf8,
int utf8_len,
cairo_glyph_t *glyphs,
int num_glyphs,
const cairo_text_cluster_t *clusters,
int num_clusters,
cairo_text_cluster_flags_t cluster_flags,
cairo_scaled_font_t *scaled_font,
cairo_clip_t *clip);
 
cairo_private cairo_status_t
_cairo_surface_paint_extents (cairo_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_clip_t *clip,
cairo_rectangle_int_t *extents);
 
cairo_private cairo_status_t
_cairo_surface_mask_extents (cairo_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_pattern_t *mask,
cairo_clip_t *clip,
cairo_rectangle_int_t *extents);
 
cairo_private cairo_status_t
_cairo_surface_stroke_extents (cairo_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_path_fixed_t *path,
const cairo_stroke_style_t *style,
const cairo_matrix_t *ctm,
const cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
cairo_clip_t *clip,
cairo_rectangle_int_t *extents);
 
cairo_private cairo_status_t
_cairo_surface_fill_extents (cairo_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias,
cairo_clip_t *clip,
cairo_rectangle_int_t *extents);
 
cairo_private cairo_status_t
_cairo_surface_glyphs_extents (cairo_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font,
cairo_clip_t *clip,
cairo_rectangle_int_t *extents);
 
cairo_private cairo_status_t
_cairo_surface_composite_trapezoids (cairo_operator_t op,
const cairo_pattern_t *pattern,
cairo_surface_t *dst,
cairo_antialias_t antialias,
int src_x,
int src_y,
int dst_x,
int dst_y,
unsigned int width,
unsigned int height,
cairo_trapezoid_t *traps,
int ntraps,
cairo_region_t *clip_region);
 
cairo_private cairo_span_renderer_t *
_cairo_surface_create_span_renderer (cairo_operator_t op,
const cairo_pattern_t *pattern,
cairo_surface_t *dst,
cairo_antialias_t antialias,
const cairo_composite_rectangles_t *rects,
cairo_region_t *clip_region);
 
cairo_private cairo_bool_t
_cairo_surface_check_span_renderer (cairo_operator_t op,
const cairo_pattern_t *pattern,
cairo_surface_t *dst,
cairo_antialias_t antialias);
 
cairo_private cairo_status_t
_cairo_surface_acquire_source_image (cairo_surface_t *surface,
cairo_image_surface_t **image_out,
void **image_extra);
 
cairo_private void
_cairo_surface_release_source_image (cairo_surface_t *surface,
cairo_image_surface_t *image,
void *image_extra);
 
cairo_private cairo_status_t
_cairo_surface_acquire_dest_image (cairo_surface_t *surface,
cairo_rectangle_int_t *interest_rect,
cairo_image_surface_t **image_out,
cairo_rectangle_int_t *image_rect,
void **image_extra);
 
cairo_private void
_cairo_surface_release_dest_image (cairo_surface_t *surface,
cairo_rectangle_int_t *interest_rect,
cairo_image_surface_t *image,
cairo_rectangle_int_t *image_rect,
void *image_extra);
 
cairo_private cairo_status_t
_cairo_surface_clone_similar (cairo_surface_t *surface,
cairo_surface_t *src,
int src_x,
int src_y,
int width,
int height,
int *clone_offset_x,
int *clone_offset_y,
cairo_surface_t **clone_out);
 
cairo_private cairo_surface_t *
_cairo_surface_snapshot (cairo_surface_t *surface);
 
cairo_private void
_cairo_surface_attach_snapshot (cairo_surface_t *surface,
cairo_surface_t *snapshot,
cairo_surface_func_t detach_func);
 
cairo_private cairo_surface_t *
_cairo_surface_has_snapshot (cairo_surface_t *surface,
const cairo_surface_backend_t *backend);
 
cairo_private void
_cairo_surface_detach_snapshot (cairo_surface_t *snapshot);
 
cairo_private cairo_bool_t
_cairo_surface_is_similar (cairo_surface_t *surface_a,
cairo_surface_t *surface_b);
 
cairo_private cairo_bool_t
_cairo_surface_get_extents (cairo_surface_t *surface,
cairo_rectangle_int_t *extents);
 
cairo_private cairo_status_t
_cairo_surface_old_show_glyphs (cairo_scaled_font_t *scaled_font,
cairo_operator_t op,
const cairo_pattern_t *pattern,
cairo_surface_t *surface,
int source_x,
int source_y,
int dest_x,
int dest_y,
unsigned int width,
unsigned int height,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_region_t *clip_region);
 
cairo_private cairo_status_t
_cairo_surface_composite_fixup_unbounded (cairo_surface_t *dst,
cairo_surface_attributes_t *src_attr,
int src_width,
int src_height,
cairo_surface_attributes_t *mask_attr,
int mask_width,
int mask_height,
int src_x,
int src_y,
int mask_x,
int mask_y,
int dst_x,
int dst_y,
unsigned int width,
unsigned int height,
cairo_region_t *clip_region);
 
cairo_private cairo_status_t
_cairo_surface_composite_shape_fixup_unbounded (cairo_surface_t *dst,
cairo_surface_attributes_t *src_attr,
int src_width,
int src_height,
int mask_width,
int mask_height,
int src_x,
int src_y,
int mask_x,
int mask_y,
int dst_x,
int dst_y,
unsigned int width,
unsigned int height,
cairo_region_t *clip_region);
 
cairo_private cairo_bool_t
_cairo_surface_is_opaque (const cairo_surface_t *surface);
 
cairo_private void
_cairo_surface_set_device_scale (cairo_surface_t *surface,
double sx,
double sy);
 
cairo_private cairo_bool_t
_cairo_surface_has_device_transform (cairo_surface_t *surface) cairo_pure;
 
cairo_private void
_cairo_surface_release_device_reference (cairo_surface_t *surface);
 
/* cairo-image-surface.c */
 
/* XXX: In cairo 1.2.0 we added a new %CAIRO_FORMAT_RGB16_565 but
* neglected to adjust this macro. The net effect is that it's
* impossible to externally create an image surface with this
* format. This is perhaps a good thing since we also neglected to fix
* up things like cairo_surface_write_to_png() for the new format
* (-Wswitch-enum will tell you where). Is it obvious that format was
* added in haste?
*
* The reason for the new format was to allow the xlib backend to be
* used on X servers with a 565 visual. So the new format did its job
* for that, even without being considered "valid" for the sake of
* things like cairo_image_surface_create().
*
* Since 1.2.0 we ran into the same situtation with X servers with BGR
* visuals. This time we invented #cairo_internal_format_t instead,
* (see it for more discussion).
*
* The punchline is that %CAIRO_FORMAT_VALID must not conside any
* internal format to be valid. Also we need to decide if the
* RGB16_565 should be moved to instead be an internal format. If so,
* this macro need not change for it. (We probably will need to leave
* an RGB16_565 value in the header files for the sake of code that
* might have that value in it.)
*
* If we do decide to start fully supporting RGB16_565 as an external
* format, then %CAIRO_FORMAT_VALID needs to be adjusted to include
* it. But that should not happen before all necessary code is fixed
* to support it (at least cairo_surface_write_to_png() and a few spots
* in cairo-xlib-surface.c--again see -Wswitch-enum).
*/
#define CAIRO_FORMAT_VALID(format) ((format) >= CAIRO_FORMAT_ARGB32 && \
(format) <= CAIRO_FORMAT_RGB16_565)
 
/* pixman-required stride alignment in bytes. */
#define CAIRO_STRIDE_ALIGNMENT (sizeof (uint32_t))
#define CAIRO_STRIDE_FOR_WIDTH_BPP(w,bpp) \
((((bpp)*(w)+7)/8 + CAIRO_STRIDE_ALIGNMENT-1) & -CAIRO_STRIDE_ALIGNMENT)
 
#define CAIRO_CONTENT_VALID(content) ((content) && \
(((content) & ~(CAIRO_CONTENT_COLOR | \
CAIRO_CONTENT_ALPHA | \
CAIRO_CONTENT_COLOR_ALPHA))\
== 0))
 
cairo_private int
_cairo_format_bits_per_pixel (cairo_format_t format) cairo_const;
 
cairo_private cairo_format_t
_cairo_format_from_content (cairo_content_t content) cairo_const;
 
cairo_private cairo_format_t
_cairo_format_from_pixman_format (pixman_format_code_t pixman_format);
 
cairo_private cairo_content_t
_cairo_content_from_format (cairo_format_t format) cairo_const;
 
cairo_private cairo_content_t
_cairo_content_from_pixman_format (pixman_format_code_t pixman_format);
 
cairo_private cairo_surface_t *
_cairo_image_surface_create_for_pixman_image (pixman_image_t *pixman_image,
pixman_format_code_t pixman_format);
 
cairo_private pixman_format_code_t
_cairo_format_to_pixman_format_code (cairo_format_t format);
 
cairo_private cairo_bool_t
_pixman_format_from_masks (cairo_format_masks_t *masks,
pixman_format_code_t *format_ret);
 
cairo_private cairo_bool_t
_pixman_format_to_masks (pixman_format_code_t pixman_format,
cairo_format_masks_t *masks);
 
cairo_private void
_cairo_image_reset_static_data (void);
 
cairo_private cairo_surface_t *
_cairo_image_surface_create_with_pixman_format (unsigned char *data,
pixman_format_code_t pixman_format,
int width,
int height,
int stride);
 
cairo_private cairo_surface_t *
_cairo_image_surface_create_with_content (cairo_content_t content,
int width,
int height);
 
cairo_private void
_cairo_image_surface_assume_ownership_of_data (cairo_image_surface_t *surface);
 
cairo_private cairo_image_surface_t *
_cairo_image_surface_coerce (cairo_image_surface_t *surface);
 
cairo_private cairo_image_surface_t *
_cairo_image_surface_coerce_to_format (cairo_image_surface_t *surface,
cairo_format_t format);
 
cairo_private void
_cairo_image_surface_span_render_row (int y,
const cairo_half_open_span_t *spans,
unsigned num_spans,
uint8_t *data,
uint32_t stride);
 
cairo_private cairo_image_transparency_t
_cairo_image_analyze_transparency (cairo_image_surface_t *image);
 
cairo_private cairo_bool_t
_cairo_surface_is_image (const cairo_surface_t *surface) cairo_pure;
 
cairo_private cairo_bool_t
_cairo_surface_is_recording (const cairo_surface_t *surface) cairo_pure;
 
/* cairo-pen.c */
cairo_private cairo_status_t
_cairo_pen_init (cairo_pen_t *pen,
double radius,
double tolerance,
const cairo_matrix_t *ctm);
 
cairo_private void
_cairo_pen_init_empty (cairo_pen_t *pen);
 
cairo_private cairo_status_t
_cairo_pen_init_copy (cairo_pen_t *pen, const cairo_pen_t *other);
 
cairo_private void
_cairo_pen_fini (cairo_pen_t *pen);
 
cairo_private cairo_status_t
_cairo_pen_add_points (cairo_pen_t *pen, cairo_point_t *point, int num_points);
 
cairo_private cairo_status_t
_cairo_pen_add_points_for_slopes (cairo_pen_t *pen,
cairo_point_t *a,
cairo_point_t *b,
cairo_point_t *c,
cairo_point_t *d);
 
cairo_private int
_cairo_pen_find_active_cw_vertex_index (const cairo_pen_t *pen,
const cairo_slope_t *slope);
 
cairo_private int
_cairo_pen_find_active_ccw_vertex_index (const cairo_pen_t *pen,
const cairo_slope_t *slope);
 
/* cairo-polygon.c */
cairo_private void
_cairo_polygon_init (cairo_polygon_t *polygon);
 
cairo_private void
_cairo_polygon_limit (cairo_polygon_t *polygon,
const cairo_box_t *boxes,
int num_boxes);
 
cairo_private void
_cairo_polygon_fini (cairo_polygon_t *polygon);
 
cairo_private cairo_status_t
_cairo_polygon_add_line (cairo_polygon_t *polygon,
const cairo_line_t *line,
int top, int bottom,
int dir);
 
cairo_private cairo_status_t
_cairo_polygon_add_external_edge (void *polygon,
const cairo_point_t *p1,
const cairo_point_t *p2);
 
cairo_private cairo_status_t
_cairo_polygon_move_to (cairo_polygon_t *polygon,
const cairo_point_t *point);
 
cairo_private cairo_status_t
_cairo_polygon_line_to (cairo_polygon_t *polygon,
const cairo_point_t *point);
 
cairo_private cairo_status_t
_cairo_polygon_close (cairo_polygon_t *polygon);
 
#define _cairo_polygon_status(P) ((cairo_polygon_t *) (P))->status
 
/* cairo-spline.c */
cairo_private cairo_bool_t
_cairo_spline_init (cairo_spline_t *spline,
cairo_spline_add_point_func_t add_point_func,
void *closure,
const cairo_point_t *a, const cairo_point_t *b,
const cairo_point_t *c, const cairo_point_t *d);
 
cairo_private cairo_status_t
_cairo_spline_decompose (cairo_spline_t *spline, double tolerance);
 
cairo_private cairo_status_t
_cairo_spline_bound (cairo_spline_add_point_func_t add_point_func,
void *closure,
const cairo_point_t *p0, const cairo_point_t *p1,
const cairo_point_t *p2, const cairo_point_t *p3);
 
/* cairo-matrix.c */
cairo_private void
_cairo_matrix_get_affine (const cairo_matrix_t *matrix,
double *xx, double *yx,
double *xy, double *yy,
double *x0, double *y0);
 
cairo_private void
_cairo_matrix_transform_bounding_box (const cairo_matrix_t *matrix,
double *x1, double *y1,
double *x2, double *y2,
cairo_bool_t *is_tight);
 
cairo_private void
_cairo_matrix_transform_bounding_box_fixed (const cairo_matrix_t *matrix,
cairo_box_t *bbox,
cairo_bool_t *is_tight);
 
cairo_private cairo_bool_t
_cairo_matrix_is_invertible (const cairo_matrix_t *matrix) cairo_pure;
 
cairo_private cairo_bool_t
_cairo_matrix_is_scale_0 (const cairo_matrix_t *matrix) cairo_pure;
 
cairo_private double
_cairo_matrix_compute_determinant (const cairo_matrix_t *matrix) cairo_pure;
 
cairo_private cairo_status_t
_cairo_matrix_compute_basis_scale_factors (const cairo_matrix_t *matrix,
double *sx, double *sy, int x_major);
 
cairo_private cairo_bool_t
_cairo_matrix_is_identity (const cairo_matrix_t *matrix) cairo_pure;
 
cairo_private cairo_bool_t
_cairo_matrix_is_translation (const cairo_matrix_t *matrix) cairo_pure;
 
cairo_private cairo_bool_t
_cairo_matrix_is_integer_translation(const cairo_matrix_t *matrix,
int *itx, int *ity);
 
cairo_private cairo_bool_t
_cairo_matrix_has_unity_scale (const cairo_matrix_t *matrix);
 
cairo_private cairo_bool_t
_cairo_matrix_is_pixel_exact (const cairo_matrix_t *matrix) cairo_pure;
 
cairo_private double
_cairo_matrix_transformed_circle_major_axis (const cairo_matrix_t *matrix,
double radius) cairo_pure;
 
cairo_private void
_cairo_matrix_to_pixman_matrix (const cairo_matrix_t *matrix,
pixman_transform_t *pixman_transform,
double xc,
double yc);
 
/* cairo-traps.c */
cairo_private void
_cairo_traps_init (cairo_traps_t *traps);
 
cairo_private void
_cairo_traps_limit (cairo_traps_t *traps,
const cairo_box_t *boxes,
int num_boxes);
 
cairo_private cairo_status_t
_cairo_traps_init_boxes (cairo_traps_t *traps,
const cairo_boxes_t *boxes);
 
cairo_private void
_cairo_traps_clear (cairo_traps_t *traps);
 
cairo_private void
_cairo_traps_fini (cairo_traps_t *traps);
 
#define _cairo_traps_status(T) (T)->status
 
cairo_private void
_cairo_traps_translate (cairo_traps_t *traps, int x, int y);
 
cairo_private cairo_status_t
_cairo_traps_tessellate_rectangle (cairo_traps_t *traps,
const cairo_point_t *top_left,
const cairo_point_t *bottom_right);
 
cairo_private void
_cairo_traps_add_trap (cairo_traps_t *traps,
cairo_fixed_t top, cairo_fixed_t bottom,
cairo_line_t *left, cairo_line_t *right);
 
cairo_private cairo_status_t
_cairo_bentley_ottmann_tessellate_rectilinear_polygon (cairo_traps_t *traps,
const cairo_polygon_t *polygon,
cairo_fill_rule_t fill_rule);
 
cairo_private cairo_status_t
_cairo_bentley_ottmann_tessellate_polygon (cairo_traps_t *traps,
const cairo_polygon_t *polygon,
cairo_fill_rule_t fill_rule);
 
cairo_private cairo_status_t
_cairo_bentley_ottmann_tessellate_traps (cairo_traps_t *traps,
cairo_fill_rule_t fill_rule);
 
cairo_private cairo_status_t
_cairo_bentley_ottmann_tessellate_rectangular_traps (cairo_traps_t *traps,
cairo_fill_rule_t fill_rule);
 
cairo_private cairo_status_t
_cairo_bentley_ottmann_tessellate_boxes (const cairo_boxes_t *in,
cairo_fill_rule_t fill_rule,
cairo_boxes_t *out);
 
cairo_private cairo_status_t
_cairo_bentley_ottmann_tessellate_rectilinear_traps (cairo_traps_t *traps,
cairo_fill_rule_t fill_rule);
 
cairo_private cairo_status_t
_cairo_bentley_ottmann_tessellate_rectilinear_polygon_to_boxes (const cairo_polygon_t *polygon,
cairo_fill_rule_t fill_rule,
cairo_boxes_t *boxes);
 
cairo_private int
_cairo_traps_contain (const cairo_traps_t *traps,
double x, double y);
 
cairo_private void
_cairo_traps_extents (const cairo_traps_t *traps,
cairo_box_t *extents);
 
cairo_private cairo_int_status_t
_cairo_traps_extract_region (cairo_traps_t *traps,
cairo_region_t **region);
 
cairo_private cairo_status_t
_cairo_traps_path (const cairo_traps_t *traps,
cairo_path_fixed_t *path);
 
cairo_private void
_cairo_trapezoid_array_translate_and_scale (cairo_trapezoid_t *offset_traps,
cairo_trapezoid_t *src_traps,
int num_traps,
double tx, double ty,
double sx, double sy);
 
/* cairo-pattern.c */
 
cairo_private cairo_pattern_t *
_cairo_pattern_create_in_error (cairo_status_t status);
 
cairo_private cairo_status_t
_cairo_pattern_create_copy (cairo_pattern_t **pattern,
const cairo_pattern_t *other);
 
cairo_private cairo_status_t
_cairo_pattern_init_copy (cairo_pattern_t *pattern,
const cairo_pattern_t *other);
 
cairo_private void
_cairo_pattern_init_static_copy (cairo_pattern_t *pattern,
const cairo_pattern_t *other);
 
cairo_private cairo_status_t
_cairo_pattern_init_snapshot (cairo_pattern_t *pattern,
const cairo_pattern_t *other);
 
cairo_private void
_cairo_pattern_init_solid (cairo_solid_pattern_t *pattern,
const cairo_color_t *color);
 
cairo_private void
_cairo_pattern_init_for_surface (cairo_surface_pattern_t *pattern,
cairo_surface_t *surface);
 
cairo_private void
_cairo_pattern_init_linear (cairo_linear_pattern_t *pattern,
double x0, double y0, double x1, double y1);
 
cairo_private void
_cairo_pattern_init_radial (cairo_radial_pattern_t *pattern,
double cx0, double cy0, double radius0,
double cx1, double cy1, double radius1);
 
cairo_private void
_cairo_pattern_fini (cairo_pattern_t *pattern);
 
cairo_private cairo_pattern_t *
_cairo_pattern_create_solid (const cairo_color_t *color);
 
cairo_private void
_cairo_pattern_transform (cairo_pattern_t *pattern,
const cairo_matrix_t *ctm_inverse);
 
cairo_private cairo_bool_t
_cairo_gradient_pattern_is_solid (const cairo_gradient_pattern_t *gradient,
const cairo_rectangle_int_t *extents,
cairo_color_t *color);
 
cairo_private cairo_bool_t
_cairo_pattern_is_opaque_solid (const cairo_pattern_t *pattern);
 
cairo_private cairo_bool_t
_cairo_pattern_is_opaque (const cairo_pattern_t *pattern,
const cairo_rectangle_int_t *extents);
 
cairo_private cairo_bool_t
_cairo_pattern_is_clear (const cairo_pattern_t *pattern);
 
cairo_private_no_warn cairo_filter_t
_cairo_pattern_analyze_filter (const cairo_pattern_t *pattern,
double *pad_out);
 
enum {
CAIRO_PATTERN_ACQUIRE_NONE = 0x0,
CAIRO_PATTERN_ACQUIRE_NO_REFLECT = 0x1
};
cairo_private cairo_int_status_t
_cairo_pattern_acquire_surface (const cairo_pattern_t *pattern,
cairo_surface_t *dst,
int x,
int y,
unsigned int width,
unsigned int height,
unsigned int flags,
cairo_surface_t **surface_out,
cairo_surface_attributes_t *attributes);
 
cairo_private void
_cairo_pattern_release_surface (const cairo_pattern_t *pattern,
cairo_surface_t *surface,
cairo_surface_attributes_t *attributes);
 
cairo_private cairo_int_status_t
_cairo_pattern_acquire_surfaces (const cairo_pattern_t *src,
const cairo_pattern_t *mask,
cairo_surface_t *dst,
int src_x,
int src_y,
int mask_x,
int mask_y,
unsigned int width,
unsigned int height,
unsigned int flags,
cairo_surface_t **src_out,
cairo_surface_t **mask_out,
cairo_surface_attributes_t *src_attributes,
cairo_surface_attributes_t *mask_attributes);
 
cairo_private void
_cairo_pattern_get_extents (const cairo_pattern_t *pattern,
cairo_rectangle_int_t *extents);
 
cairo_private unsigned long
_cairo_pattern_hash (const cairo_pattern_t *pattern);
 
cairo_private unsigned long
_cairo_linear_pattern_hash (unsigned long hash,
const cairo_linear_pattern_t *linear);
 
cairo_private unsigned long
_cairo_radial_pattern_hash (unsigned long hash,
const cairo_radial_pattern_t *radial);
 
cairo_private cairo_bool_t
_cairo_linear_pattern_equal (const cairo_linear_pattern_t *a,
const cairo_linear_pattern_t *b);
 
cairo_private unsigned long
_cairo_pattern_size (const cairo_pattern_t *pattern);
 
cairo_private cairo_bool_t
_cairo_radial_pattern_equal (const cairo_radial_pattern_t *a,
const cairo_radial_pattern_t *b);
 
cairo_private cairo_bool_t
_cairo_pattern_equal (const cairo_pattern_t *a,
const cairo_pattern_t *b);
 
cairo_private void
_cairo_pattern_reset_static_data (void);
 
#if CAIRO_HAS_DRM_SURFACE
 
cairo_private void
_cairo_drm_device_reset_static_data (void);
 
#endif
 
cairo_private void
_cairo_clip_reset_static_data (void);
 
/* cairo-unicode.c */
 
cairo_private int
_cairo_utf8_get_char_validated (const char *p,
uint32_t *unicode);
 
cairo_private cairo_status_t
_cairo_utf8_to_ucs4 (const char *str,
int len,
uint32_t **result,
int *items_written);
 
cairo_private int
_cairo_ucs4_to_utf8 (uint32_t unicode,
char *utf8);
 
#if CAIRO_HAS_WIN32_FONT || CAIRO_HAS_QUARTZ_FONT || CAIRO_HAS_PDF_OPERATORS
# define CAIRO_HAS_UTF8_TO_UTF16 1
#endif
#if CAIRO_HAS_UTF8_TO_UTF16
cairo_private cairo_status_t
_cairo_utf8_to_utf16 (const char *str,
int len,
uint16_t **result,
int *items_written);
#endif
 
/* cairo-observer.c */
 
cairo_private void
_cairo_observers_notify (cairo_list_t *observers, void *arg);
 
/* Avoid unnecessary PLT entries. */
slim_hidden_proto (cairo_clip_preserve);
slim_hidden_proto (cairo_close_path);
slim_hidden_proto (cairo_create);
slim_hidden_proto (cairo_curve_to);
slim_hidden_proto (cairo_destroy);
slim_hidden_proto (cairo_fill_preserve);
slim_hidden_proto (cairo_font_face_destroy);
slim_hidden_proto (cairo_font_face_get_user_data);
slim_hidden_proto_no_warn (cairo_font_face_reference);
slim_hidden_proto (cairo_font_face_set_user_data);
slim_hidden_proto (cairo_font_options_equal);
slim_hidden_proto (cairo_font_options_hash);
slim_hidden_proto (cairo_font_options_merge);
slim_hidden_proto (cairo_font_options_set_antialias);
slim_hidden_proto (cairo_font_options_set_hint_metrics);
slim_hidden_proto (cairo_font_options_set_hint_style);
slim_hidden_proto (cairo_font_options_set_subpixel_order);
slim_hidden_proto (cairo_font_options_status);
slim_hidden_proto (cairo_format_stride_for_width);
slim_hidden_proto (cairo_get_current_point);
slim_hidden_proto (cairo_get_line_width);
slim_hidden_proto (cairo_get_matrix);
slim_hidden_proto (cairo_get_target);
slim_hidden_proto (cairo_get_tolerance);
slim_hidden_proto (cairo_glyph_allocate);
slim_hidden_proto (cairo_glyph_free);
slim_hidden_proto (cairo_image_surface_create);
slim_hidden_proto (cairo_image_surface_create_for_data);
slim_hidden_proto (cairo_image_surface_get_data);
slim_hidden_proto (cairo_image_surface_get_format);
slim_hidden_proto (cairo_image_surface_get_height);
slim_hidden_proto (cairo_image_surface_get_stride);
slim_hidden_proto (cairo_image_surface_get_width);
slim_hidden_proto (cairo_line_to);
slim_hidden_proto (cairo_mask);
slim_hidden_proto (cairo_matrix_init);
slim_hidden_proto (cairo_matrix_init_identity);
slim_hidden_proto (cairo_matrix_init_rotate);
slim_hidden_proto (cairo_matrix_init_scale);
slim_hidden_proto (cairo_matrix_init_translate);
slim_hidden_proto (cairo_matrix_invert);
slim_hidden_proto (cairo_matrix_multiply);
slim_hidden_proto (cairo_matrix_scale);
slim_hidden_proto (cairo_matrix_transform_distance);
slim_hidden_proto (cairo_matrix_transform_point);
slim_hidden_proto (cairo_matrix_translate);
slim_hidden_proto (cairo_move_to);
slim_hidden_proto (cairo_new_path);
slim_hidden_proto (cairo_paint);
slim_hidden_proto (cairo_pattern_create_for_surface);
slim_hidden_proto (cairo_pattern_create_rgb);
slim_hidden_proto (cairo_pattern_create_rgba);
slim_hidden_proto (cairo_pattern_destroy);
slim_hidden_proto (cairo_pattern_get_extend);
slim_hidden_proto_no_warn (cairo_pattern_reference);
slim_hidden_proto (cairo_pattern_set_matrix);
slim_hidden_proto (cairo_pop_group);
slim_hidden_proto (cairo_push_group_with_content);
slim_hidden_proto (cairo_rel_line_to);
slim_hidden_proto (cairo_restore);
slim_hidden_proto (cairo_save);
slim_hidden_proto (cairo_scale);
slim_hidden_proto (cairo_scaled_font_create);
slim_hidden_proto (cairo_scaled_font_destroy);
slim_hidden_proto (cairo_scaled_font_extents);
slim_hidden_proto (cairo_scaled_font_get_ctm);
slim_hidden_proto (cairo_scaled_font_get_font_face);
slim_hidden_proto (cairo_scaled_font_get_font_matrix);
slim_hidden_proto (cairo_scaled_font_get_font_options);
slim_hidden_proto (cairo_scaled_font_glyph_extents);
slim_hidden_proto_no_warn (cairo_scaled_font_reference);
slim_hidden_proto (cairo_scaled_font_status);
slim_hidden_proto (cairo_scaled_font_get_user_data);
slim_hidden_proto (cairo_scaled_font_set_user_data);
slim_hidden_proto (cairo_scaled_font_text_to_glyphs);
slim_hidden_proto (cairo_set_font_options);
slim_hidden_proto (cairo_set_font_size);
slim_hidden_proto (cairo_set_line_cap);
slim_hidden_proto (cairo_set_line_join);
slim_hidden_proto (cairo_set_line_width);
slim_hidden_proto (cairo_set_matrix);
slim_hidden_proto (cairo_set_operator);
slim_hidden_proto (cairo_set_source);
slim_hidden_proto (cairo_set_source_rgb);
slim_hidden_proto (cairo_set_source_surface);
slim_hidden_proto (cairo_set_tolerance);
slim_hidden_proto (cairo_status);
slim_hidden_proto (cairo_stroke);
slim_hidden_proto (cairo_stroke_preserve);
slim_hidden_proto (cairo_surface_copy_page);
slim_hidden_proto (cairo_surface_destroy);
slim_hidden_proto (cairo_surface_finish);
slim_hidden_proto (cairo_surface_flush);
slim_hidden_proto (cairo_surface_get_content);
slim_hidden_proto (cairo_surface_get_device_offset);
slim_hidden_proto (cairo_surface_get_font_options);
slim_hidden_proto (cairo_surface_get_mime_data);
slim_hidden_proto (cairo_surface_get_type);
slim_hidden_proto (cairo_surface_has_show_text_glyphs);
slim_hidden_proto (cairo_surface_mark_dirty);
slim_hidden_proto (cairo_surface_mark_dirty_rectangle);
slim_hidden_proto_no_warn (cairo_surface_reference);
slim_hidden_proto (cairo_surface_set_device_offset);
slim_hidden_proto (cairo_surface_set_fallback_resolution);
slim_hidden_proto (cairo_surface_set_mime_data);
slim_hidden_proto (cairo_surface_show_page);
slim_hidden_proto (cairo_surface_status);
slim_hidden_proto (cairo_text_cluster_allocate);
slim_hidden_proto (cairo_text_cluster_free);
slim_hidden_proto (cairo_toy_font_face_create);
slim_hidden_proto (cairo_toy_font_face_get_slant);
slim_hidden_proto (cairo_toy_font_face_get_weight);
slim_hidden_proto (cairo_translate);
slim_hidden_proto (cairo_transform);
slim_hidden_proto (cairo_user_font_face_create);
slim_hidden_proto (cairo_user_font_face_set_init_func);
slim_hidden_proto (cairo_user_font_face_set_render_glyph_func);
slim_hidden_proto (cairo_user_font_face_set_unicode_to_glyph_func);
slim_hidden_proto (cairo_user_to_device);
slim_hidden_proto (cairo_user_to_device_distance);
slim_hidden_proto (cairo_version_string);
slim_hidden_proto (cairo_region_create);
slim_hidden_proto (cairo_region_create_rectangle);
slim_hidden_proto (cairo_region_create_rectangles);
slim_hidden_proto (cairo_region_copy);
slim_hidden_proto (cairo_region_reference);
slim_hidden_proto (cairo_region_destroy);
slim_hidden_proto (cairo_region_equal);
slim_hidden_proto (cairo_region_status);
slim_hidden_proto (cairo_region_get_extents);
slim_hidden_proto (cairo_region_num_rectangles);
slim_hidden_proto (cairo_region_get_rectangle);
slim_hidden_proto (cairo_region_is_empty);
slim_hidden_proto (cairo_region_contains_rectangle);
slim_hidden_proto (cairo_region_contains_point);
slim_hidden_proto (cairo_region_translate);
slim_hidden_proto (cairo_region_subtract);
slim_hidden_proto (cairo_region_subtract_rectangle);
slim_hidden_proto (cairo_region_intersect);
slim_hidden_proto (cairo_region_intersect_rectangle);
slim_hidden_proto (cairo_region_union);
slim_hidden_proto (cairo_region_union_rectangle);
slim_hidden_proto (cairo_region_xor);
slim_hidden_proto (cairo_region_xor_rectangle);
 
#if CAIRO_HAS_PNG_FUNCTIONS
 
slim_hidden_proto (cairo_surface_write_to_png_stream);
 
#endif
 
cairo_private_no_warn cairo_filter_t
_cairo_pattern_analyze_filter (const cairo_pattern_t *pattern,
double *pad_out);
 
CAIRO_END_DECLS
 
#include "cairo-mutex-private.h"
#include "cairo-fixed-private.h"
#include "cairo-wideint-private.h"
#include "cairo-malloc-private.h"
#include "cairo-hash-private.h"
 
#if HAVE_VALGRIND
#include <memcheck.h>
 
#define VG(x) x
 
cairo_private void
_cairo_debug_check_image_surface_is_defined (const cairo_surface_t *surface);
 
#else
 
#define VG(x)
#define _cairo_debug_check_image_surface_is_defined(X)
 
#endif
 
cairo_private void
_cairo_debug_print_path (FILE *stream, cairo_path_fixed_t *path);
 
cairo_private void
_cairo_debug_print_clip (FILE *stream, cairo_clip_t *clip);
 
#endif
/programs/develop/libraries/cairo/src/test-fallback-surface.h
0,0 → 1,50
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2005 Red Hat, Inc
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
* Carl Worth <cworth@cworth.org>
*/
 
#ifndef TEST_FALLBACK_SURFACE_H
#define TEST_FALLBACK_SURFACE_H
 
#include "cairo.h"
 
CAIRO_BEGIN_DECLS
 
cairo_surface_t *
_cairo_test_fallback_surface_create (cairo_content_t content,
int width,
int height);
 
CAIRO_END_DECLS
 
#endif /* TEST_FALLBACK_SURFACE_H */
/programs/develop/libraries/cairo/src/test-fallback16-surface.h
0,0 → 1,52
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2005 Red Hat, Inc
* Copyright © 2009 Chris Wilson
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
* Carl Worth <cworth@cworth.org>
* Chris Wilson <chris@chris-wilson.co.uk>
*/
 
#ifndef TEST_FALLBACK16_SURFACE_H
#define TEST_FALLBACK16_SURFACE_H
 
#include "cairo.h"
 
CAIRO_BEGIN_DECLS
 
cairo_surface_t *
_cairo_test_fallback16_surface_create (cairo_content_t content,
int width,
int height);
 
CAIRO_END_DECLS
 
#endif /* TEST_FALLBACK16_SURFACE_H */
/programs/develop/libraries/cairo/src/test-null-surface.h
0,0 → 1,46
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2009 Chris Wilson
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* Contributor(s):
* Chris Wilson <chris@chris-wilson.co.uk>
*/
 
#ifndef TEST_NULL_SURFACE_H
#define TEST_NULL_SURFACE_H
 
#include "cairo.h"
 
CAIRO_BEGIN_DECLS
 
cairo_public cairo_surface_t *
_cairo_test_null_surface_create (cairo_content_t content);
 
CAIRO_END_DECLS
 
#endif /* TEST_NULL_SURFACE_H */
/programs/develop/libraries/cairo/src/test-paginated-surface.h
0,0 → 1,48
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2005 Red Hat, Inc
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
* Carl Worth <cworth@cworth.org>
*/
 
#ifndef TEST_PAGINATED_SURFACE_H
#define TEST_PAGINATED_SURFACE_H
 
#include "cairo.h"
 
CAIRO_BEGIN_DECLS
 
cairo_surface_t *
_cairo_test_paginated_surface_create (cairo_surface_t *target);
 
CAIRO_END_DECLS
 
#endif /* TEST_PAGINATED_SURFACE_H */
/programs/develop/libraries/cairo/src/test-wrapping-surface.h
0,0 → 1,51
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2005 Red Hat, Inc
* Copyright © 2009 Chris Wilson
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
* Carl Worth <cworth@cworth.org>
* Chris Wilson <chris@chris-wilson.co.uk>
*/
 
#ifndef TEST_WRAPPING_SURFACE_H
#define TEST_WRAPPING_SURFACE_H
 
#include "cairo.h"
 
CAIRO_BEGIN_DECLS
 
cairo_surface_t *
_cairo_test_wrapping_surface_create (cairo_surface_t *target);
 
CAIRO_END_DECLS
 
#endif /* TEST_WRAPPING_SURFACE_H */
 
/programs/develop/libraries/cairo/src
Property changes:
Added: tsvn:logminsize
+5
\ No newline at end of property
/programs/develop/libraries/cairo
Property changes:
Added: tsvn:logminsize
+5
\ No newline at end of property
/programs/develop/libraries/pixman/Makefile
7,7 → 7,7
 
DEFINES = -DHAVE_CONFIG_H -DPACKAGE -DPIXMAN_NO_TLS -DUSE_MMX
 
INCLUDES = -I../pixman -I../newlib/include -I../newlib/include/sys
INCLUDES = -I../pixman -I../newlib/include
 
SOURCES = \
pixman-image.c \
/programs/develop/libraries/pixman/README
0,0 → 1,22
pixman is a library that provides low-level pixel manipulation
features such as image compositing and trapezoid rasterization.
 
All questions regarding this software should be directed to the pixman
mailing list:
 
http://lists.freedesktop.org/mailman/listinfo/pixman
 
Please send patches and bug reports either to the mailing list above,
or file them at the freedesktop bug tracker:
 
https://bugs.freedesktop.org/enter_bug.cgi?product=pixman
 
The master development code repository can be found at:
 
git://anongit.freedesktop.org/git/pixman
 
http://gitweb.freedesktop.org/?p=pixman;a=summary
 
For more information on the git code manager, see:
 
http://wiki.x.org/wiki/GitPage
/programs/develop/libraries/pixman/config.h
0,0 → 1,144
/* config.h. Generated from config.h.in by configure. */
/* config.h.in. Generated from configure.ac by autoheader. */
 
/* Define if building universal (internal helper macro) */
/* #undef AC_APPLE_UNIVERSAL_BUILD */
 
/* Whether we have alarm() */
/* #undef HAVE_ALARM */
 
/* Define to 1 if you have the <dlfcn.h> header file. */
/* #undef HAVE_DLFCN_H */
 
/* Define to 1 if you have the `getisax' function. */
/* #undef HAVE_GETISAX */
 
/* Whether we have getpagesize() */
#define HAVE_GETPAGESIZE 1
 
/* Whether we have gettimeofday() */
#define HAVE_GETTIMEOFDAY 1
 
/* Define to 1 if you have the <inttypes.h> header file. */
#define HAVE_INTTYPES_H 1
 
/* Define to 1 if you have the `pixman-1' library (-lpixman-1). */
/* #undef HAVE_LIBPIXMAN_1 */
 
/* Define to 1 if you have the <memory.h> header file. */
#define HAVE_MEMORY_H 1
 
/* Whether we have mprotect() */
#define HAVE_MPROTECT 1
 
/* Whether we have posix_memalign() */
/* #undef HAVE_POSIX_MEMALIGN */
 
/* Whether pthread_setspecific() is supported */
/* #undef HAVE_PTHREAD_SETSPECIFIC */
 
/* Whether we have sigaction() */
/* #undef HAVE_SIGACTION */
 
/* Define to 1 if you have the <stdint.h> header file. */
#define HAVE_STDINT_H 1
 
/* Define to 1 if you have the <stdlib.h> header file. */
#define HAVE_STDLIB_H 1
 
/* Define to 1 if you have the <strings.h> header file. */
#define HAVE_STRINGS_H 1
 
/* Define to 1 if you have the <string.h> header file. */
#define HAVE_STRING_H 1
 
/* Define to 1 if we have <sys/mman.h> */
/* #undef HAVE_SYS_MMAN_H */
 
/* Define to 1 if you have the <sys/stat.h> header file. */
#define HAVE_SYS_STAT_H 1
 
/* Define to 1 if you have the <sys/types.h> header file. */
#define HAVE_SYS_TYPES_H 1
 
/* Define to 1 if you have the <unistd.h> header file. */
#define HAVE_UNISTD_H 1
 
/* Define to the sub-directory in which libtool stores uninstalled libraries.
*/
#define LT_OBJDIR ".libs/"
 
/* Name of package */
#define PACKAGE "pixman"
 
/* Define to the address where bug reports for this package should be sent. */
#define PACKAGE_BUGREPORT ""pixman@lists.freedesktop.org""
 
/* Define to the full name of this package. */
#define PACKAGE_NAME "pixman"
 
/* Define to the full name and version of this package. */
#define PACKAGE_STRING "pixman 0.20.2"
 
/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME "pixman"
 
/* Define to the home page for this package. */
#define PACKAGE_URL ""
 
/* Define to the version of this package. */
#define PACKAGE_VERSION "0.20.2"
 
/* enable TIMER_BEGIN/TIMER_END macros */
/* #undef PIXMAN_TIMERS */
 
/* The size of `long', as computed by sizeof. */
#define SIZEOF_LONG 4
 
/* Define to 1 if you have the ANSI C header files. */
#define STDC_HEADERS 1
 
/* Whether the tool chain supports __thread */
#define TOOLCHAIN_SUPPORTS__THREAD /**/
 
/* use ARM NEON assembly optimizations */
/* #undef USE_ARM_NEON */
 
/* use ARM SIMD assembly optimizations */
/* #undef USE_ARM_SIMD */
 
/* use GNU-style inline assembler */
#define USE_GCC_INLINE_ASM 1
 
/* use MMX compiler intrinsics */
#define USE_MMX 1
 
/* use OpenMP in the test suite */
#define USE_OPENMP 1
 
/* use SSE2 compiler intrinsics */
#define USE_SSE2 1
 
/* use VMX compiler intrinsics */
/* #undef USE_VMX */
 
/* Version number of package */
#define VERSION "0.20.2"
 
/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
significant byte first (like Motorola and SPARC, unlike Intel). */
#if defined AC_APPLE_UNIVERSAL_BUILD
# if defined __BIG_ENDIAN__
# define WORDS_BIGENDIAN 1
# endif
#else
# ifndef WORDS_BIGENDIAN
/* # undef WORDS_BIGENDIAN */
# endif
#endif
 
/* Define to `__inline__' or `__inline' if that's what the C compiler
calls it, or to nothing if 'inline' is not supported under any name. */
#ifndef __cplusplus
/* #undef inline */
#endif