/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, ®ion); |
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, ®ion->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, ®ion); |
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, ®ion); |
} |
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 (&matrix, 0.5, 0.5); |
* cairo_pattern_set_matrix (pattern, &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 (®ion->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 (®ion->ref_count, 0); |
pixman_region32_init (®ion->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 (®ion->ref_count, 0); |
pixman_region32_init_rect (®ion->rgn, |
rectangle->x, rectangle->y, |
rectangle->width, rectangle->height); |
} |
void |
_cairo_region_fini (cairo_region_t *region) |
{ |
assert (! CAIRO_REFERENCE_COUNT_HAS_REFERENCE (®ion->ref_count)); |
pixman_region32_fini (®ion->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 (®ion->ref_count, 1); |
pixman_region32_init (®ion->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 (®ion->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 (®ion->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 (®ion->ref_count, 1); |
pixman_region32_init_rect (®ion->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 (©->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 (®ion->ref_count)) |
return NULL; |
assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (®ion->ref_count)); |
_cairo_reference_count_inc (®ion->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 (®ion->ref_count)) |
return; |
assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (®ion->ref_count)); |
if (! _cairo_reference_count_dec_and_test (®ion->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 ®ion->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 ®ion->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 ®ion->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 (®ion, |
rectangle->x, rectangle->y, |
rectangle->width, rectangle->height); |
if (! pixman_region32_subtract (&dst->rgn, &dst->rgn, ®ion)) |
status = _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY); |
pixman_region32_fini (®ion); |
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 (®ion, |
rectangle->x, rectangle->y, |
rectangle->width, rectangle->height); |
if (! pixman_region32_intersect (&dst->rgn, &dst->rgn, ®ion)) |
status = _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY); |
pixman_region32_fini (®ion); |
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 (®ion, |
rectangle->x, rectangle->y, |
rectangle->width, rectangle->height); |
if (! pixman_region32_union (&dst->rgn, &dst->rgn, ®ion)) |
status = _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY); |
pixman_region32_fini (®ion); |
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 (®ion, |
rectangle->x, rectangle->y, |
rectangle->width, rectangle->height); |
pixman_region32_init (&tmp); |
/* XXX: get an xor function into pixman */ |
if (! pixman_region32_subtract (&tmp, ®ion, &dst->rgn) || |
! pixman_region32_subtract (&dst->rgn, &dst->rgn, ®ion) || |
! 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 (®ion); |
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 ®ion->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 (®ion->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 ®ion->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 ®ion->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, |
* &glyphs, &num_glyphs, |
* &clusters, &num_clusters, &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, |
* &glyphs, &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, |
* &glyphs, &num_glyphs, |
* &clusters, &num_clusters, &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; |
* |
* path = cairo_copy_path (cr); |
* |
* for (i=0; i < path->num_data; i += path->data[i].header.length) { |
* data = &path->data[i]; |
* switch (data->header.type) { |
* case CAIRO_PATH_MOVE_TO: |
* 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 |