summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSteve Chaplin <stevech1097@yahoo.com.au>2010-05-31 19:33:29 +0800
committerSteve Chaplin <stevech1097@yahoo.com.au>2010-05-31 19:33:29 +0800
commit59415110e1811019d49562fd06ad75d9182b9b77 (patch)
treee161a51c2995eef4b20fedf049c1bbb157837a60
downloadpycairo-59415110e1811019d49562fd06ad75d9182b9b77.tar.gz
Create the initial pycairo for Python 3.x git repo, using the py2cairo 1.8.10
files. Remove autotools and setup.py files. Upgrade LGPL license to version 3, remove MPL license.
-rw-r--r--.gitignore4
-rw-r--r--AUTHORS11
-rw-r--r--COPYING674
-rw-r--r--COPYING.LESSER165
-rw-r--r--INSTALL11
-rw-r--r--NEWS0
-rw-r--r--README40
-rw-r--r--RELEASING89
-rw-r--r--doc/.gitignore6
-rw-r--r--doc/README89
-rwxr-xr-xdoc/conf.py187
-rw-r--r--doc/faq.rst41
-rw-r--r--doc/index.rst19
-rw-r--r--doc/overview.rst31
-rw-r--r--doc/pycairo_c_api.rst118
-rw-r--r--doc/reference/constants.rst525
-rw-r--r--doc/reference/context.rst1485
-rw-r--r--doc/reference/exceptions.rst18
-rw-r--r--doc/reference/index.rst19
-rw-r--r--doc/reference/matrix.rst181
-rw-r--r--doc/reference/paths.rst23
-rw-r--r--doc/reference/patterns.rst286
-rw-r--r--doc/reference/surfaces.rst719
-rw-r--r--doc/reference/text.rst279
-rw-r--r--examples/.gitignore5
-rwxr-xr-xexamples/cairo_snippets/c_to_python.py35
-rw-r--r--examples/cairo_snippets/snippets/.gitignore5
-rwxr-xr-xexamples/cairo_snippets/snippets/__init__.py12
-rwxr-xr-xexamples/cairo_snippets/snippets/arc.py21
-rwxr-xr-xexamples/cairo_snippets/snippets/arc_negative.py22
-rwxr-xr-xexamples/cairo_snippets/snippets/clip.py13
-rwxr-xr-xexamples/cairo_snippets/snippets/clip_image.py13
-rwxr-xr-xexamples/cairo_snippets/snippets/curve_rectangle.py53
-rwxr-xr-xexamples/cairo_snippets/snippets/curve_to.py17
-rwxr-xr-xexamples/cairo_snippets/snippets/ellipse.py33
-rwxr-xr-xexamples/cairo_snippets/snippets/fill_and_stroke.py12
-rwxr-xr-xexamples/cairo_snippets/snippets/fill_and_stroke2.py18
-rwxr-xr-xexamples/cairo_snippets/snippets/glyph_path.py21
-rwxr-xr-xexamples/cairo_snippets/snippets/gradient.py16
-rwxr-xr-xexamples/cairo_snippets/snippets/gradient_mask.py12
-rwxr-xr-xexamples/cairo_snippets/snippets/group.py16
-rwxr-xr-xexamples/cairo_snippets/snippets/image.py14
-rwxr-xr-xexamples/cairo_snippets/snippets/imagepattern.py23
-rwxr-xr-xexamples/cairo_snippets/snippets/path.py7
-rwxr-xr-xexamples/cairo_snippets/snippets/set_line_cap.py19
-rwxr-xr-xexamples/cairo_snippets/snippets/set_line_join.py21
-rwxr-xr-xexamples/cairo_snippets/snippets/show_glyphs.py15
-rwxr-xr-xexamples/cairo_snippets/snippets/text.py22
-rwxr-xr-xexamples/cairo_snippets/snippets/text_align_center.py26
-rwxr-xr-xexamples/cairo_snippets/snippets/text_extents.py27
-rwxr-xr-xexamples/cairo_snippets/snippets_gtk.py140
-rwxr-xr-xexamples/cairo_snippets/snippets_pdf.py56
-rwxr-xr-xexamples/cairo_snippets/snippets_png.py52
-rwxr-xr-xexamples/cairo_snippets/snippets_ps.py56
-rwxr-xr-xexamples/cairo_snippets/snippets_svg.py53
-rwxr-xr-xexamples/gradient.py33
-rwxr-xr-xexamples/gtk/cairo-demo.py121
-rwxr-xr-xexamples/gtk/cairo-knockout.py128
-rwxr-xr-xexamples/gtk/hangman.py257
-rwxr-xr-xexamples/gtk/lsystem.py123
-rwxr-xr-xexamples/gtk/png_view.py35
-rwxr-xr-xexamples/gtk/text.py41
-rwxr-xr-xexamples/hering.py55
-rwxr-xr-xexamples/spiral.py36
-rwxr-xr-xexamples/warpedtext.py85
-rw-r--r--py3cairo-uninstalled.pc.in8
-rw-r--r--py3cairo.pc.in8
-rw-r--r--src/.gitignore2
-rwxr-xr-xsrc/__init__.py18
-rw-r--r--src/cairomodule.c496
-rw-r--r--src/context.c1433
-rw-r--r--src/font.c598
-rw-r--r--src/matrix.c332
-rw-r--r--src/path.c316
-rw-r--r--src/pattern.c585
-rw-r--r--src/private.h160
-rw-r--r--src/py3cairo.h206
-rw-r--r--src/surface.c1424
-rw-r--r--src/wscript32
-rw-r--r--test/.gitignore3
-rw-r--r--test/README13
-rw-r--r--test/api_test.py86
-rw-r--r--test/examples_test.py29
-rwxr-xr-xtest/isurface_create_for_data1.py32
-rwxr-xr-xtest/isurface_create_for_data2.py30
-rwxr-xr-xtest/isurface_create_from_png.py56
-rwxr-xr-xtest/isurface_get_data.py50
-rwxr-xr-xtest/pygame-test1.py65
-rwxr-xr-xtest/pygame-test2.py49
-rwxr-xr-xtest/surface_create_for_stream.py81
-rwxr-xr-xtest/surface_write_to_png.py73
-rw-r--r--wscript72
92 files changed, 13046 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..ef7b764
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,4 @@
+#
+*~
+.lock-wscript
+.waf*
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..30f0383
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,11 @@
+Original Author
+---------------
+James Henstridge <james@daa.com.au>
+
+Maintainer
+----------
+Steve Chaplin <stevech1097 # yahoo.com.au>
+
+Contributors
+------------
+Maarten Breddels
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..94a9ed0
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,674 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ <program> Copyright (C) <year> <name of author>
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+ The GNU General Public License does not permit incorporating your program
+into proprietary programs. If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License. But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
diff --git a/COPYING.LESSER b/COPYING.LESSER
new file mode 100644
index 0000000..65c5ca8
--- /dev/null
+++ b/COPYING.LESSER
@@ -0,0 +1,165 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+
+ This version of the GNU Lesser General Public License incorporates
+the terms and conditions of version 3 of the GNU General Public
+License, supplemented by the additional permissions listed below.
+
+ 0. Additional Definitions.
+
+ As used herein, "this License" refers to version 3 of the GNU Lesser
+General Public License, and the "GNU GPL" refers to version 3 of the GNU
+General Public License.
+
+ "The Library" refers to a covered work governed by this License,
+other than an Application or a Combined Work as defined below.
+
+ An "Application" is any work that makes use of an interface provided
+by the Library, but which is not otherwise based on the Library.
+Defining a subclass of a class defined by the Library is deemed a mode
+of using an interface provided by the Library.
+
+ A "Combined Work" is a work produced by combining or linking an
+Application with the Library. The particular version of the Library
+with which the Combined Work was made is also called the "Linked
+Version".
+
+ The "Minimal Corresponding Source" for a Combined Work means the
+Corresponding Source for the Combined Work, excluding any source code
+for portions of the Combined Work that, considered in isolation, are
+based on the Application, and not on the Linked Version.
+
+ The "Corresponding Application Code" for a Combined Work means the
+object code and/or source code for the Application, including any data
+and utility programs needed for reproducing the Combined Work from the
+Application, but excluding the System Libraries of the Combined Work.
+
+ 1. Exception to Section 3 of the GNU GPL.
+
+ You may convey a covered work under sections 3 and 4 of this License
+without being bound by section 3 of the GNU GPL.
+
+ 2. Conveying Modified Versions.
+
+ If you modify a copy of the Library, and, in your modifications, a
+facility refers to a function or data to be supplied by an Application
+that uses the facility (other than as an argument passed when the
+facility is invoked), then you may convey a copy of the modified
+version:
+
+ a) under this License, provided that you make a good faith effort to
+ ensure that, in the event an Application does not supply the
+ function or data, the facility still operates, and performs
+ whatever part of its purpose remains meaningful, or
+
+ b) under the GNU GPL, with none of the additional permissions of
+ this License applicable to that copy.
+
+ 3. Object Code Incorporating Material from Library Header Files.
+
+ The object code form of an Application may incorporate material from
+a header file that is part of the Library. You may convey such object
+code under terms of your choice, provided that, if the incorporated
+material is not limited to numerical parameters, data structure
+layouts and accessors, or small macros, inline functions and templates
+(ten or fewer lines in length), you do both of the following:
+
+ a) Give prominent notice with each copy of the object code that the
+ Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the object code with a copy of the GNU GPL and this license
+ document.
+
+ 4. Combined Works.
+
+ You may convey a Combined Work under terms of your choice that,
+taken together, effectively do not restrict modification of the
+portions of the Library contained in the Combined Work and reverse
+engineering for debugging such modifications, if you also do each of
+the following:
+
+ a) Give prominent notice with each copy of the Combined Work that
+ the Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the Combined Work with a copy of the GNU GPL and this license
+ document.
+
+ c) For a Combined Work that displays copyright notices during
+ execution, include the copyright notice for the Library among
+ these notices, as well as a reference directing the user to the
+ copies of the GNU GPL and this license document.
+
+ d) Do one of the following:
+
+ 0) Convey the Minimal Corresponding Source under the terms of this
+ License, and the Corresponding Application Code in a form
+ suitable for, and under terms that permit, the user to
+ recombine or relink the Application with a modified version of
+ the Linked Version to produce a modified Combined Work, in the
+ manner specified by section 6 of the GNU GPL for conveying
+ Corresponding Source.
+
+ 1) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (a) uses at run time
+ a copy of the Library already present on the user's computer
+ system, and (b) will operate properly with a modified version
+ of the Library that is interface-compatible with the Linked
+ Version.
+
+ e) Provide Installation Information, but only if you would otherwise
+ be required to provide such information under section 6 of the
+ GNU GPL, and only to the extent that such information is
+ necessary to install and execute a modified version of the
+ Combined Work produced by recombining or relinking the
+ Application with a modified version of the Linked Version. (If
+ you use option 4d0, the Installation Information must accompany
+ the Minimal Corresponding Source and Corresponding Application
+ Code. If you use option 4d1, you must provide the Installation
+ Information in the manner specified by section 6 of the GNU GPL
+ for conveying Corresponding Source.)
+
+ 5. Combined Libraries.
+
+ You may place library facilities that are a work based on the
+Library side by side in a single library together with other library
+facilities that are not Applications and are not covered by this
+License, and convey such a combined library under terms of your
+choice, if you do both of the following:
+
+ a) Accompany the combined library with a copy of the same work based
+ on the Library, uncombined with any other library facilities,
+ conveyed under the terms of this License.
+
+ b) Give prominent notice with the combined library that part of it
+ is a work based on the Library, and explaining where to find the
+ accompanying uncombined form of the same work.
+
+ 6. Revised Versions of the GNU Lesser General Public License.
+
+ The Free Software Foundation may publish revised and/or new versions
+of the GNU Lesser General Public License from time to time. Such new
+versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Library as you received it specifies that a certain numbered version
+of the GNU Lesser General Public License "or any later version"
+applies to it, you have the option of following the terms and
+conditions either of that published version or of any later version
+published by the Free Software Foundation. If the Library as you
+received it does not specify a version number of the GNU Lesser
+General Public License, you may choose any version of the GNU Lesser
+General Public License ever published by the Free Software Foundation.
+
+ If the Library as you received it specifies that a proxy can decide
+whether future versions of the GNU Lesser General Public License shall
+apply, that proxy's public statement of acceptance of any version is
+permanent authorization for you to choose that version for the
+Library.
diff --git a/INSTALL b/INSTALL
new file mode 100644
index 0000000..724f1cb
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,11 @@
+Install Procedure
+-----------------
+$ ./waf --help # shows available waf options
+$ ./waf configure # use '--prefix=PREFIX' if needed
+$ ./waf build
+$ ./waf install
+
+
+Testing
+-------
+See test/README
diff --git a/NEWS b/NEWS
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/NEWS
diff --git a/README b/README
new file mode 100644
index 0000000..1e7eda6
--- /dev/null
+++ b/README
@@ -0,0 +1,40 @@
+Pycairo - Python 3.x bindings for cairo
+http://www.cairographics.org/pycairo
+
+Dependencies
+------------
+ cairo >= 1.8.10
+ Python >= 3.1
+
+Compiling
+---------
+See the INSTALL document for build instructions.
+
+Documentation
+-------------
+The 'doc' directory contains reStructuredText files which are used by Sphinx
+to generate html (and other format) documentation.
+
+License
+-------
+Pycairo is free software and is available to be redistributed and/or modified
+under the terms of the GNU Lesser General Public License version 3 (LGPLv3).
+
+Contact
+-------
+Mailing List:
+If you have some ideas for how cairo or Pycairo could be improved, please feel
+free to send a message to cairo@cairographics.org
+ http://cairographics.org/cgi-bin/mailman/listinfo/cairo
+
+Bugzilla:
+If you find a bug in Pycairo, please go to
+ https://bugs.freedesktop.org/enter_bug.cgi?product=pycairo
+and submit a bugreport.
+
+IMPORTANT: make sure you state which version of cairo, pycairo, and Python you
+are using when you report a problem or bug.
+
+>>> import cairo
+>>> cairo.cairo_version_string() # shows the cairo version
+>>> cairo.version # shows the pycairo version
diff --git a/RELEASING b/RELEASING
new file mode 100644
index 0000000..84cfb0f
--- /dev/null
+++ b/RELEASING
@@ -0,0 +1,89 @@
+Here are the steps to follow to create a new pycairo release:
+
+1) Fill out an entry in the NEWS file
+Sift through the information in 'git log' since the last release. Summarize
+major changes briefly in a style similar to other entries in NEWS.
+
+2) Increment pycairo and cairo version numbers in:
+ configure.ac
+ doc/conf.py
+ README
+ setup.py
+ wscript
+
+Increment pycairo_major/minor/micro_version in configure.ac
+Increase the cairo_required_version - to an even numbered version.
+Increment pycairo_major/minor version to match the cairo major/minor version
+that pycairo requires (and increment the micro version if necessary for any
+subsequent pycairo updates).
+
+3) Run "make distcheck" and verify that it gives no warnings or errors and
+ ends with a message of the form:
+
+ ===============================================
+ pycairo-X.Y.Z archives ready for distribution:
+ pycairo-X.Y.Z.tar.gz
+ ===============================================
+
+Install from the tar.gz archive, run tests and examples.
+
+4) Commit the changes to NEWS, configure.ac etc
+It's especially important to mention the new version number in the git commit
+comment.
+Add a '=== Pycairo x.x.x ===' header.
+
+$ git tag X.Y.Z
+ push the changes to the freedesktop server.
+$ git push origin master
+
+5) Edit Makefile.am and select either 'snapshot' or 'release'.
+ Run "make release-publish" which will perform the following steps for you:
+
+* Check that the version number ends with an even micro component
+* Check that no release exists with the current version
+* Verify that make distcheck completes successfully
+* Generate the final tar file
+* Generate an md5sum file
+* scp both files to appear on http://cairographics.org/releases
+* Place local copies of the files in the releases directory
+* Create a LATEST-package-version file (after deleting any old one)
+* Provide some text for the release announcement (see below).
+
+6) Verify that the tar file arrived at the website.
+ Check tar file has read permissions for all.
+ Update the pycairo webpage to reference the new release.
+ Update http://cheeseshop.python.org entry for pycairo.
+
+7) Edit:
+ configure.ac
+ setup.py
+ wscript
+ to increment pycairo_version_micro to the next larger (odd) number.
+$ git push origin master
+
+8) Send a message to cairo-announce@cairographics.org
+ and CC python-announce-list@python.org
+ to announce the new release using the text provided from
+ "make release-publish".
+
+
+Generating documentation archives
+---------------------------------
+$ cd doc/
+$ vi conf.py # update the version and release numbers
+$ make clean
+$ make html
+$ cd .build/
+$ mv html pycairo-x.x.x-docs-html
+$ tar cjf /tmp/pycairo-x.x.x-docs-html.tar.bz2 pycairo-x.x.x-docs-html
+$ zip -r /tmp/pycairo-x.x.x-docs-html.zip pycairo-x.x.x-docs-html
+$ chmod a+r /tmp/pycairo*
+
+untar docs in /tmp and check that they have correct version number and view
+OK.
+copy file to the 'releases' directory on cairo website:
+ scp pycairo-x.x.x-docs-html.tar.bz2 cairographics.org:/srv/cairo.freedesktop.org/www/releases
+
+cd doc
+ html_docs_create.sh
+ html_docs_upload.sh
diff --git a/doc/.gitignore b/doc/.gitignore
new file mode 100644
index 0000000..0e3f32a
--- /dev/null
+++ b/doc/.gitignore
@@ -0,0 +1,6 @@
+.build
+.static
+.templates
+html_docs_create.sh
+html_docs_upload.sh
+
diff --git a/doc/README b/doc/README
new file mode 100644
index 0000000..4bf7671
--- /dev/null
+++ b/doc/README
@@ -0,0 +1,89 @@
+Pycairo Documentation README
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This directory contains the reStructuredText (reST) sources to the Pycairo
+documentation.
+
+Options for accessing pycairo documentation:
+1. Read the documentation online at http://cairographics.org/documentation/pycairo/
+
+2. Download the latest 'pycairo-x.x.x-docs-html.tar.gz' prebuilt documents
+from http://www.cairographics.org/releases/. Uncompress the docs and point
+your browser at the index.html file.
+
+3. Build the documentation yourself - the hardest option, see details below.
+
+
+Building the docs
+=================
+You need to install Python 2.4 or higher; the toolset used to build the docs are
+written in Python. The toolset used to build the documentation is called
+*Sphinx*, it is not included in this tree, but maintained separately in the
+Python Subversion repository. Also needed are Jinja, a templating engine
+(included in Sphinx as a Subversion external), and optionally Pygments, a code
+highlighter.
+
+
+Using make
+----------
+ make html
+
+Available make targets are:
+
+ * "html", which builds standalone HTML files for offline viewing.
+
+ * "htmlhelp", which builds HTML files and a HTML Help project file usable to
+ convert them into a single Compiled HTML (.chm) file -- these are popular
+ under Microsoft Windows, but very handy on every platform.
+
+ To create the CHM file, you need to run the Microsoft HTML Help Workshop
+ over the generated project (.hhp) file.
+
+ * "latex", which builds LaTeX source files that can be run with "pdflatex"
+ to produce PDF documents.
+
+ * "text", which builds a plain text file for each source file.
+
+ * "linkcheck", which checks all external references to see whether they are
+ broken, redirected or malformed, and outputs this information to stdout
+ as well as a plain-text (.txt) file.
+
+ * "changes", which builds an overview over all versionadded/versionchanged/
+ deprecated items in the current version. This is meant as a help for the
+ writer of the "What's New" document.
+
+ * "pydoc-topics", which builds a Python module containing a dictionary
+ with plain text documentation for the labels defined in
+ `tools/sphinxext/pyspecific.py` -- pydoc needs these to show topic
+ and keyword help.
+
+A "make update" updates the Subversion checkouts in `tools/`.
+
+
+Without make
+------------
+
+You'll need to checkout the Sphinx package to the `tools/` directory::
+
+ svn co http://svn.python.org/projects/doctools/trunk/sphinx tools/sphinx
+
+Then, you need to install Docutils 0.4 (the SVN snapshot won't work), either
+by checking it out via ::
+
+ svn co http://svn.python.org/projects/external/docutils-0.4/docutils tools/docutils
+
+or by installing it from http://docutils.sf.net/.
+
+You can optionally also install Pygments, either as a checkout via ::
+
+ svn co http://svn.python.org/projects/external/Pygments-0.9/pygments tools/pygments
+
+or from PyPI at http://pypi.python.org/pypi/Pygments.
+
+
+Then, make an output directory, e.g. under `build/`, and run ::
+
+ python tools/sphinx-build.py -b<builder> . build/<outputdirectory>
+
+where `<builder>` is one of html, web or htmlhelp (for explanations see the make
+targets above).
diff --git a/doc/conf.py b/doc/conf.py
new file mode 100755
index 0000000..d6ccba9
--- /dev/null
+++ b/doc/conf.py
@@ -0,0 +1,187 @@
+# -*- coding: utf-8 -*-
+#
+# pycairo documentation build configuration file, created by
+# sphinx-quickstart on Tue Nov 25 23:21:00 2008.
+#
+# This file is execfile()d with the current directory set to its containing dir.
+#
+# The contents of this file are pickled, so don't put values in the namespace
+# that aren't pickleable (module imports are okay, they're removed automatically).
+#
+# All configuration values have a default; values that are commented out
+# serve to show the default.
+
+import sys, os
+
+# If your extensions are in another directory, add it here. If the directory
+# is relative to the documentation root, use os.path.abspath to make it
+# absolute, like shown here.
+#sys.path.append(os.path.abspath('.'))
+
+# General configuration
+# ---------------------
+
+# Add any Sphinx extension module names here, as strings. They can be extensions
+# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
+extensions = []
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['.templates']
+
+# The suffix of source filenames.
+source_suffix = '.rst'
+
+# The encoding of source files.
+#source_encoding = 'utf-8'
+
+# The master toctree document.
+master_doc = 'index'
+
+# General information about the project.
+project = u'pycairo'
+copyright = u'2008, Steve Chaplin'
+
+# The version info for the project you're documenting, acts as replacement for
+# |version| and |release|, also used in various other places throughout the
+# built documents.
+#
+# The short X.Y version.
+version = '1.8'
+# The full version, including alpha/beta/rc tags.
+release = '1.8.10'
+
+# The language for content autogenerated by Sphinx. Refer to documentation
+# for a list of supported languages.
+#language = None
+
+# There are two options for replacing |today|: either, you set today to some
+# non-false value, then it is used:
+#today = ''
+# Else, today_fmt is used as the format for a strftime call.
+#today_fmt = '%B %d, %Y'
+
+# List of documents that shouldn't be included in the build.
+#unused_docs = []
+
+# List of directories, relative to source directory, that shouldn't be searched
+# for source files.
+exclude_trees = ['.build']
+
+# The reST default role (used for this markup: `text`) to use for all documents.
+#default_role = None
+
+# If true, '()' will be appended to :func: etc. cross-reference text.
+#add_function_parentheses = True
+
+# If true, the current module name will be prepended to all description
+# unit titles (such as .. function::).
+#add_module_names = True
+
+# If true, sectionauthor and moduleauthor directives will be shown in the
+# output. They are ignored by default.
+#show_authors = False
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'sphinx'
+
+
+# Options for HTML output
+# -----------------------
+
+# The style sheet to use for HTML and HTML Help pages. A file of that name
+# must exist either in Sphinx' static/ path, or in one of the custom paths
+# given in html_static_path.
+html_style = 'default.css'
+
+# The name for this set of Sphinx documents. If None, it defaults to
+# "<project> v<release> documentation".
+#html_title = None
+
+# A shorter title for the navigation bar. Default is the same as html_title.
+#html_short_title = None
+
+# The name of an image file (relative to this directory) to place at the top
+# of the sidebar.
+#html_logo = None
+
+# The name of an image file (within the static path) to use as favicon of the
+# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
+# pixels large.
+#html_favicon = None
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = ['.static']
+
+# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
+# using the given strftime format.
+#html_last_updated_fmt = '%b %d, %Y'
+
+# If true, SmartyPants will be used to convert quotes and dashes to
+# typographically correct entities.
+#html_use_smartypants = True
+
+# Custom sidebar templates, maps document names to template names.
+#html_sidebars = {}
+
+# Additional templates that should be rendered to pages, maps page names to
+# template names.
+#html_additional_pages = {}
+
+# If false, no module index is generated.
+#html_use_modindex = True
+
+# If false, no index is generated.
+#html_use_index = True
+
+# If true, the index is split into individual pages for each letter.
+#html_split_index = False
+
+# If true, the reST sources are included in the HTML build as _sources/<name>.
+#html_copy_source = True
+
+# If true, an OpenSearch description file will be output, and all pages will
+# contain a <link> tag referring to it. The value of this option must be the
+# base URL from which the finished HTML is served.
+#html_use_opensearch = ''
+
+# If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml").
+#html_file_suffix = ''
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'pycairodoc'
+
+
+# Options for LaTeX output
+# ------------------------
+
+# The paper size ('letter' or 'a4').
+#latex_paper_size = 'letter'
+
+# The font size ('10pt', '11pt' or '12pt').
+#latex_font_size = '10pt'
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title, author, document class [howto/manual]).
+latex_documents = [
+ ('index', 'pycairo.tex', ur'pycairo Documentation',
+ ur'Steve Chaplin', 'manual'),
+]
+
+# The name of an image file (relative to this directory) to place at the top of
+# the title page.
+#latex_logo = None
+
+# For "manual" documents, if this is true, then toplevel headings are parts,
+# not chapters.
+#latex_use_parts = False
+
+# Additional stuff for the LaTeX preamble.
+#latex_preamble = ''
+
+# Documents to append as an appendix to all manuals.
+#latex_appendices = []
+
+# If false, no module index is generated.
+#latex_use_modindex = True
diff --git a/doc/faq.rst b/doc/faq.rst
new file mode 100644
index 0000000..2cd986d
--- /dev/null
+++ b/doc/faq.rst
@@ -0,0 +1,41 @@
+***
+FAQ
+***
+
+.. currentmodule:: cairo
+
+
+Pycairo FAQ - Frequently Asked Questions
+========================================
+
+Q: Can I subclass pycairo classes?
+
+A: Cairo, the C library, is not an object oriented library, so a Python
+binding can never be a truly object oriented interface to cairo. One way to
+write the Python bindings for cairo would be as a single long list of module
+functions - this would be the most accurate representation of the underlying C
+library. Pycairo (and most other cairo language bindings?) instead chose to
+implement the bindings using Context, Surface, Pattern, etc classes. An
+advantage is that the classes organise cairo into groups of similar functions.
+A disadvantage is that creates an illusion that cairo is object oriented
+library, and people are then tempted to create subclasses to override cairo
+methods. When in fact there are no methods to override, just cairo functions
+which can't be overridden.
+
+The cairo documentation Appendix A "Creating a language binding for cairo"
+section "Memory Management" describes why deriving from a Surface creates
+problems and is best avoided.
+
+cairo.Context can be subclassed.
+All other pycairo subclasses cannot be subclassed.
+
+
+Q: How do I use pycairo with numpy?
+
+A: See test/isurface_create_for_data2.py
+
+
+Q: How do I use pycairo with pygame?
+
+A: See test/pygame-test1.py
+ test/pygame-test2.py
diff --git a/doc/index.rst b/doc/index.rst
new file mode 100644
index 0000000..df9f5ae
--- /dev/null
+++ b/doc/index.rst
@@ -0,0 +1,19 @@
+Pycairo Documentation
+=====================
+
+.. module:: cairo
+
+.. toctree::
+ :maxdepth: 1
+
+ overview
+ reference/index
+ faq
+ pycairo_c_api
+
+
+Indices and tables
+==================
+
+* :ref:`genindex`
+* :ref:`search`
diff --git a/doc/overview.rst b/doc/overview.rst
new file mode 100644
index 0000000..e862335
--- /dev/null
+++ b/doc/overview.rst
@@ -0,0 +1,31 @@
+********
+Overview
+********
+
+.. currentmodule:: cairo
+
+Pycairo is a Python binding for the cairo graphics library.
+
+The Pycairo bindings are designed to match the cairo C API as closely as
+possible, and to deviate only in cases which are clearly better implemented in
+a more 'Pythonic' way.
+
+Features of the Pycairo bindings:
+
+* Provides an object oriented interface to cairo, using Python 2.2 new style classes.
+* Pycairo_Check_Status() is called to check the status of cairo operations, and raise exceptions as appropriate.
+* Provides a C API that can be used by other Python extensions.
+
+The C cairo functions cairo_reference(), cairo_destroy(),
+cairo_surface_reference(), cairo_surface_destroy() (and their equivalents for
+surfaces and patterns) are not made public by the pycairo bindings. This is
+because pycairo handles cairo object construction and destruction.
+
+To use the pycairo library::
+
+ import cairo
+
+See :ref:`Reference <reference_index>` for further details.
+
+For examples of pycairo code see the 'examples' directory that comes with the
+pycairo distribution.
diff --git a/doc/pycairo_c_api.rst b/doc/pycairo_c_api.rst
new file mode 100644
index 0000000..bf0e9e4
--- /dev/null
+++ b/doc/pycairo_c_api.rst
@@ -0,0 +1,118 @@
+.. highlightlang:: c
+
+
+*************
+Pycairo C API
+*************
+
+.. currentmodule:: cairo
+
+This manual documents the API used by C and C++ programmers who want to write
+extension modules that use pycairo.
+
+
+.. _api-includes:
+
+To access the Pycairo C API
+===========================
+Edit the client module file to add the following lines::
+
+ /* All function, type and macro definitions needed to use the Pycairo/C API
+ * are included in your code by the following line
+ */
+ #include "Pycairo.h"
+
+ /* define a variable for the C API */
+ static Pycairo_CAPI_t *Pycairo_CAPI;
+
+ /* import pycairo - add to the init<module> function */
+ Pycairo_IMPORT;
+
+
+Pycairo Objects
+===============
+Objects::
+
+ PycairoContext
+ PycairoFontFace
+ PycairoToyFontFace
+ PycairoFontOptions
+ PycairoMatrix
+ PycairoPath
+ PycairoPattern
+ PycairoSolidPattern
+ PycairoSurfacePattern
+ PycairoGradient
+ PycairoLinearGradient
+ PycairoRadialGradient
+ PycairoScaledFont
+ PycairoSurface
+ PycairoImageSurface
+ PycairoPDFSurface
+ PycairoPSSurface
+ PycairoSVGSurface
+ PycairoWin32Surface
+ PycairoXCBSurface
+ PycairoXlibSurface
+
+
+Pycairo Types
+=============
+Types::
+
+ PyTypeObject *Context_Type;
+ PyTypeObject *FontFace_Type;
+ PyTypeObject *ToyFontFace_Type;
+ PyTypeObject *FontOptions_Type;
+ PyTypeObject *Matrix_Type;
+ PyTypeObject *Path_Type;
+ PyTypeObject *Pattern_Type;
+ PyTypeObject *SolidPattern_Type;
+ PyTypeObject *SurfacePattern_Type;
+ PyTypeObject *Gradient_Type;
+ PyTypeObject *LinearGradient_Type;
+ PyTypeObject *RadialGradient_Type;
+ PyTypeObject *ScaledFont_Type;
+ PyTypeObject *Surface_Type;
+ PyTypeObject *ImageSurface_Type;
+ PyTypeObject *PDFSurface_Type;
+ PyTypeObject *PSSurface_Type;
+ PyTypeObject *SVGSurface_Type;
+ PyTypeObject *Win32Surface_Type;
+ PyTypeObject *XCBSurface_Type;
+ PyTypeObject *XlibSurface_Type;
+
+
+Functions
+=========
+
+.. cfunction:: cairo_t * PycairoContext_GET(obj)
+
+ get the C cairo_t \* object out of the PycairoContext \*obj
+
+
+.. cfunction:: PyObject * PycairoContext_FromContext(cairo_t *ctx, PyTypeObject *type, PyObject *base)
+
+
+.. cfunction:: PyObject * PycairoFontFace_FromFontFace(cairo_font_face_t *font_face)
+
+
+.. cfunction:: PyObject * PycairoFontOptions_FromFontOptions(cairo_font_options_t *font_options)
+
+
+.. cfunction:: PyObject * PycairoMatrix_FromMatrix(const cairo_matrix_t *matrix)
+
+
+.. cfunction:: PyObject * PycairoPath_FromPath(cairo_path_t *path)
+
+
+.. cfunction:: PyObject * PycairoPattern_FromPattern(cairo_pattern_t *pattern, PyObject *base)
+
+
+.. cfunction:: PyObject * PycairoScaledFont_FromScaledFont(cairo_scaled_font_t *scaled_font)
+
+
+.. cfunction:: PyObject * PycairoSurface_FromSurface(cairo_surface_t *surface, PyObject *base)
+
+
+.. cfunction:: int PycairoCheck_Status(cairo_status_t status)
diff --git a/doc/reference/constants.rst b/doc/reference/constants.rst
new file mode 100644
index 0000000..18454d6
--- /dev/null
+++ b/doc/reference/constants.rst
@@ -0,0 +1,525 @@
+.. _constants:
+
+******************************
+Module Functions and Constants
+******************************
+
+.. currentmodule:: cairo
+
+
+Module Functions
+================
+
+.. function:: cairo_version()
+
+ :returns: the encoded version
+ :rtype: int
+
+ Returns the version of the underlying C cairo library, encoded in a single
+ integer.
+
+.. function:: cairo_version_string()
+
+ :returns: the encoded version
+ :rtype: str
+
+ Returns the version of the underlying C cairo library as a human-readable
+ string of the form "X.Y.Z".
+
+
+Module Constants
+================
+
+.. data:: version
+
+ the pycairo version, as a string
+
+.. data:: version_info
+
+ the pycairo version, as a tuple
+
+
+.. _constants_HAS:
+
+cairo.HAS
+---------
+.. data:: HAS_ATSUI_FONT
+ HAS_FT_FONT
+ HAS_GLITZ_SURFACE
+ HAS_IMAGE_SURFACE
+ HAS_PDF_SURFACE
+ HAS_PNG_FUNCTIONS
+ HAS_PS_SURFACE
+ HAS_SVG_SURFACE
+ HAS_USER_FONT
+ HAS_QUARTZ_SURFACE
+ HAS_WIN32_FONT
+ HAS_WIN32_SURFACE
+ HAS_XCB_SURFACE
+ HAS_XLIB_SURFACE
+
+ 1 if the feature is present in the underlying C cairo library,
+ 0 otherwise
+
+
+.. _constants_ANTIALIAS:
+
+cairo.ANTIALIAS
+---------------
+ANTIALIAS specifies the type of antialiasing to do when rendering text or
+shapes.
+
+.. data:: ANTIALIAS_DEFAULT
+
+ Use the default antialiasing for the subsystem and target device
+
+.. data:: ANTIALIAS_NONE
+
+ Use a bilevel alpha mask
+
+.. data:: ANTIALIAS_GRAY
+
+ Perform single-color antialiasing (using shades of gray for black text on a
+ white background, for example).
+
+.. data:: ANTIALIAS_SUBPIXEL
+
+ Perform antialiasing by taking advantage of the order of subpixel elements
+ on devices such as LCD panels.
+
+
+.. _constants_CONTENT:
+
+cairo.CONTENT
+-------------
+These constants are used to describe the content that a :class:`Surface` will
+contain, whether color information, alpha information (translucence
+vs. opacity), or both.
+
+.. data:: CONTENT_COLOR
+
+ The surface will hold color content only.
+
+.. data:: CONTENT_ALPHA
+
+ The surface will hold alpha content only.
+
+.. data:: CONTENT_COLOR_ALPHA
+
+ The surface will hold color and alpha content.
+
+
+.. _constants_EXTEND:
+
+cairo.EXTEND
+------------
+These constants are used to describe how :class:`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 *EXTEND_NONE* for :class:`SurfacePattern` and
+*EXTEND_PAD* for :class:`Gradient` patterns.
+
+.. data:: EXTEND_NONE
+
+ pixels outside of the source pattern are fully transparent
+
+.. data:: EXTEND_REPEAT
+
+ the pattern is tiled by repeating
+
+.. data:: EXTEND_REFLECT
+
+ the pattern is tiled by reflecting at the edges (Implemented for surface
+ patterns since 1.6)
+
+.. data:: 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)
+
+New entries may be added in future versions.
+
+
+.. _constants_FILL_RULE:
+
+cairo.FILL_RULE
+---------------
+These constants are 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 *FILL_RULE_WINDING*.
+
+.. data:: 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.
+
+.. data:: 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.
+
+New entries may be added in future versions.
+
+
+.. _constants_FILTER:
+
+cairo.FILTER
+------------
+These constants are used to indicate what filtering should be applied when
+reading pixel values from patterns. See :meth:`SurfacePattern.set_filter` for
+indicating the desired filter to be used with a particular pattern.
+
+.. data:: FILTER_FAST
+
+ A high-performance filter, with quality similar *FILTER_NEAREST*
+
+.. data:: FILTER_GOOD
+
+ A reasonable-performance filter, with quality similar to *FILTER_BILINEAR*
+
+.. data:: FILTER_BEST
+
+ The highest-quality available, performance may not be suitable for
+ interactive use.
+
+.. data:: FILTER_NEAREST
+
+ Nearest-neighbor filtering
+
+.. data:: FILTER_BILINEAR
+
+ Linear interpolation in two dimensions
+
+.. data:: FILTER_GAUSSIAN
+
+ This filter value is currently unimplemented, and should not be used in
+ current code.
+
+
+.. _constants_FONT_SLANT:
+
+cairo.FONT_SLANT
+----------------
+These constants specify variants of a :class:`FontFace` based on their slant.
+
+.. data:: FONT_SLANT_NORMAL
+
+ Upright font style
+
+.. data:: FONT_SLANT_ITALIC
+
+ Italic font style
+
+.. data:: FONT_SLANT_OBLIQUE
+
+ Oblique font style
+
+
+.. _constants_FONT_WEIGHT:
+
+cairo.FONT_WEIGHT
+-----------------
+These constants specify variants of a :class:`FontFace` based on their weight.
+
+.. data:: FONT_WEIGHT_NORMAL
+
+ Normal font weight
+
+.. data:: FONT_WEIGHT_BOLD
+
+ Bold font weight
+
+
+.. _constants_FORMAT:
+
+cairo.FORMAT
+------------
+These constants are used to identify the memory format of
+:class:`ImageSurface` data.
+
+.. data:: 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.)
+
+.. data:: 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.
+
+.. data:: FORMAT_A8
+
+ each pixel is a 8-bit quantity holding an alpha value.
+
+.. data:: 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.
+
+New entries may be added in future versions.
+
+
+.. _constants_HINT_METRICS:
+
+cairo.HINT_METRICS
+------------------
+These constants specify 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.
+
+.. data:: HINT_METRICS_DEFAULT
+
+ Hint metrics in the default manner for the font backend and target device
+
+.. data:: HINT_METRICS_OFF
+
+ Do not hint font metrics
+
+.. data:: HINT_METRICS_ON
+
+ Hint font metrics
+
+
+.. _constants_HINT_STYLE:
+
+cairo.HINT_STYLE
+----------------
+These constants specify 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.
+
+.. data:: HINT_STYLE_DEFAULT
+
+ Use the default hint style for font backend and target device
+
+.. data:: HINT_STYLE_NONE
+
+ Do not hint outlines
+
+.. data:: HINT_STYLE_SLIGHT
+
+ Hint outlines slightly to improve contrast while retaining good fidelity to
+ the original shapes.
+
+.. data:: HINT_STYLE_MEDIUM
+
+ Hint outlines with medium strength giving a compromise between fidelity to
+ the original shapes and contrast
+
+.. data:: HINT_STYLE_FULL
+
+ Hint outlines to maximize contrast
+
+New entries may be added in future versions.
+
+
+.. _constants_LINE_CAP:
+
+cairo.LINE_CAP
+--------------
+These constants specify how to render the endpoints of the path when stroking.
+
+The default line cap style is *LINE_CAP_BUTT*
+
+.. data:: LINE_CAP_BUTT
+
+ start(stop) the line exactly at the start(end) point
+
+.. data:: LINE_CAP_ROUND
+
+ use a round ending, the center of the circle is the end point
+
+.. data:: LINE_CAP_SQUARE
+
+ use squared ending, the center of the square is the end point
+
+
+.. _constants_LINE_JOIN:
+
+cairo.LINE_JOIN
+---------------
+These constants specify how to render the junction of two lines when stroking.
+
+The default line join style is *LINE_JOIN_MITER*
+
+.. data:: LINE_JOIN_MITER
+
+ use a sharp (angled) corner, see :meth:`Context.set_miter_limit`
+
+.. data:: LINE_JOIN_ROUND
+
+ use a rounded join, the center of the circle is the joint point
+
+.. data:: LINE_JOIN_BEVEL
+
+ use a cut-off join, the join is cut off at half the line width from the
+ joint point
+
+
+.. _constants_OPERATOR:
+
+cairo.OPERATOR
+--------------
+These constants are used to set the compositing operator for all cairo drawing
+operations.
+
+The default operator is *OPERATOR_OVER*.
+
+The operators marked as *unbounded* 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 http://cairographics.org/operators.
+
+.. data:: OPERATOR_CLEAR
+
+ clear destination layer (bounded)
+
+.. data:: OPERATOR_SOURCE
+
+ replace destination layer (bounded)
+
+.. data:: OPERATOR_OVER
+
+ draw source layer on top of destination layer (bounded)
+
+.. data:: OPERATOR_IN
+
+ draw source where there was destination content (unbounded)
+
+.. data:: OPERATOR_OUT
+
+ draw source where there was no destination content (unbounded)
+
+.. data:: OPERATOR_ATOP
+
+ draw source on top of destination content and only there
+
+.. data:: OPERATOR_DEST
+
+ ignore the source
+
+.. data:: OPERATOR_DEST_OVER
+
+ draw destination on top of source
+
+.. data:: OPERATOR_DEST_IN
+
+ leave destination only where there was source content (unbounded)
+
+.. data:: OPERATOR_DEST_OUT
+
+ leave destination only where there was no source content
+
+.. data:: OPERATOR_DEST_ATOP
+
+ leave destination on top of source content and only there (unbounded)
+
+.. data:: OPERATOR_XOR
+
+ source and destination are shown where there is only one of them
+
+.. data:: OPERATOR_ADD
+
+ source and destination layers are accumulated
+
+.. data:: OPERATOR_SATURATE
+
+ like over, but assuming source and dest are disjoint geometries
+
+
+.. _constants_PATH:
+
+cairo.PATH
+----------
+These constants are used to describe the type of one portion of a path when
+represented as a :class:`Path`.
+
+.. See #cairo_path_data_t for details.
+
+.. data:: PATH_MOVE_TO
+
+ A move-to operation
+
+.. data:: PATH_LINE_TO
+
+ A line-to operation
+
+.. data:: PATH_CURVE_TO
+
+ A curve-to operation
+
+.. data:: PATH_CLOSE_PATH
+
+ A close-path operation
+
+
+.. _constants_PS_LEVEL:
+
+cairo.PS_LEVEL
+--------------
+These constants are used to describe the language level of the PostScript
+Language Reference that a generated PostScript file will conform to. Note:
+the constants are only defined when cairo has been compiled with PS support
+enabled.
+
+.. data:: PS_LEVEL_2
+
+ The language level 2 of the PostScript specification.
+
+.. data:: PS_LEVEL_3
+
+ The language level 3 of the PostScript specification.
+
+
+.. _constants_SUBPIXEL_ORDER:
+
+cairo.SUBPIXEL_ORDER
+--------------------
+The subpixel order specifies the order of color elements within each pixel on
+the display device when rendering with an antialiasing mode of
+:data:`ANTIALIAS_SUBPIXEL`.
+
+.. data:: SUBPIXEL_ORDER_DEFAULT
+
+ Use the default subpixel order for for the target device
+
+.. data:: SUBPIXEL_ORDER_RGB
+
+ Subpixel elements are arranged horizontally with red at the left
+
+.. data:: SUBPIXEL_ORDER_BGR
+
+ Subpixel elements are arranged horizontally with blue at the left
+
+.. data:: SUBPIXEL_ORDER_VRGB
+
+ Subpixel elements are arranged vertically with red at the top
+
+.. data:: SUBPIXEL_ORDER_VBGR
+
+ Subpixel elements are arranged vertically with blue at the top
+
diff --git a/doc/reference/context.rst b/doc/reference/context.rst
new file mode 100644
index 0000000..277bd16
--- /dev/null
+++ b/doc/reference/context.rst
@@ -0,0 +1,1485 @@
+.. _context:
+
+*************
+Cairo Context
+*************
+
+.. currentmodule:: cairo
+
+.. comment block
+ example reST:
+ (add back '..' where required at column 0)
+ . class:: module.C[(signature)]
+ .. classmethod:: name(signature)
+ .. staticmethod:: name(signature)
+ .. method:: method(signature)
+
+ :param p1: xxx
+ :type p1: int
+ :param p2: xxx
+ :type p2: str
+ :returns: xxx
+ :rtype: list of strings
+ :raises: xxx
+
+ .. versionadded:: 1.6
+ links:
+ :data:`cairo.ANTIALIAS_SUBPIXEL`
+ :class:`Context`
+ :exc:`cairo.Error`
+ :meth:`.copy_page`
+ :meth:`Context.copy_page`
+ :ref:`LINE_CAP <constants_LINE_CAP>`
+
+
+class Context()
+===============
+
+*Context* is the main object used when drawing with cairo. To draw with cairo,
+you create a *Context*, set the target surface, and drawing options for the
+*Context*, create shapes with functions like :meth:`Context.move_to` and
+:meth:`Context.line_to`, and then draw shapes with :meth:`Context.stroke` or
+:meth:`Context.fill`.
+
+*Contexts* can be pushed to a stack via :meth:`Context.save`. They may then
+safely be changed, without loosing the current state. Use
+:meth:`Context.restore` to restore to the saved state.
+
+.. class:: Context(target)
+
+ :param target: target :class:`Surface` for the context
+ :returns: a newly allocated *Context*
+ :raises: *MemoryError* in case of no memory
+
+ Creates a new *Context* 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 :class:`ImageSurface`
+ (or any other cairo backend surface create variant).
+
+ .. method:: append_path(path)
+
+ :param path: :class:`Path` to be appended
+
+ Append the *path* onto the current path. The *path* may be either the
+ return value from one of :meth:`Context.copy_path` or
+ :meth:`Context.copy_path_flat` or it may be constructed manually (in C).
+
+ .. method:: arc(xc, yc, radius, angle1, angle2)
+
+ :param xc: X position of the center of the arc
+ :type xc: float
+ :param yc: Y position of the center of the arc
+ :type yc: float
+ :param radius: the radius of the arc
+ :type radius: float
+ :param angle1: the start angle, in radians
+ :type angle1: float
+ :param angle2: the end angle, in radians
+ :type angle2: float
+
+ 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*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
+ :meth:`Context.new_sub_path` before calling :meth:`Context.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 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 ``degrees * (math.pi / 180)``.
+
+ This function gives the arc in the direction of increasing angles; see
+ :meth:`Context.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*::
+
+ ctx.save()
+ ctx.translate(x + width / 2., y + height / 2.)
+ ctx.scale(width / 2., height / 2.)
+ ctx.arc(0., 0., 1., 0., 2 * math.pi)
+ ctx.restore()
+
+
+ .. method:: arc_negative(xc, yc, radius, angle1, angle2)
+
+ :param xc: X position of the center of the arc
+ :type xc: float
+ :param yc: Y position of the center of the arc
+ :type yc: float
+ :param radius: the radius of the arc
+ :type radius: float
+ :param angle1: the start angle, in radians
+ :type angle1: float
+ :param angle2: the end angle, in radians
+ :type angle2: float
+
+ 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*PI until
+ it is less than *angle1*.
+
+ See :meth:`Context.arc` for more details. This function differs only in
+ the direction of the arc between the two angles.
+
+ .. method:: clip()
+
+ Establishes a new clip region by intersecting the current clip region
+ with the current path as it would be filled by :meth:`Context.fill` and
+ according to the current :ref:`FILL RULE <constants_FILL_RULE>` (see
+ :meth:`Context.set_fill_rule`).
+
+ After :meth:`.clip`, the current path will be cleared from the
+ :class:`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 :meth:`.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
+ :meth:`.clip` within a :meth:`Context.save`/:meth:`Context.restore`
+ pair. The only other means of increasing the size of the clip region is
+ :meth:`Context.reset_clip`.
+
+ .. method:: clip_extents()
+
+ :returns: (x1, y1, x2, y2)
+ :rtype: (float, float, float, float)
+
+ * *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.
+
+ .. versionadded:: 1.4
+
+ .. method:: clip_preserve()
+
+ Establishes a new clip region by intersecting the current clip region
+ with the current path as it would be filled by :meth:`Context.fill` and
+ according to the current :ref:`FILL RULE <constants_FILL_RULE>` (see
+ :meth:`Context.set_fill_rule`).
+
+ Unlike :meth:`Context.clip`, :meth:`.clip_preserve` preserves the path
+ within the :class:`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 :meth:`.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
+ :meth:`.clip_preserve` within a
+ :meth:`Context.save`/:meth:`Context.restore` pair. The only other means
+ of increasing the size of the clip region is :meth:`Context.reset_clip`.
+
+ .. method:: close_path()
+
+ 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
+ :meth:`Context.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 :meth:`.close_path` is distinct from simply calling
+ :meth:`Context.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 :meth:`.close_path`,
+ this function will have no effect.
+
+ Note: As of cairo version 1.2.4 any call to :meth:`.close_path` will
+ place an explicit MOVE_TO element into the path immediately after the
+ CLOSE_PATH element, (which can be seen in :meth:`Context.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.
+
+ .. method:: copy_clip_rectangle_list()
+
+ :returns: the current clip region as a list of rectangles in user
+ coordinates
+ :rtype: list of 4-tuples of float
+
+ (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. - not implemented in pycairo)
+
+ .. versionadded:: 1.4
+
+ .. method:: copy_page()
+
+ 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 :meth:`Context.show_page` if you want to get
+ an empty page after the emission.
+
+ This is a convenience function that simply calls
+ :meth:`Surface.copy_page` on *Context's* target.
+
+ .. method:: copy_path()
+
+ :returns: :class:`Path`
+ :raises: *MemoryError* in case of no memory
+
+ Creates a copy of the current path and returns it to the user as a
+ :class:`Path`.
+
+ .. method:: copy_path_flat()
+
+ :returns: :class:`Path`
+ :raises: *MemoryError* in case of no memory
+
+ Gets a flattened copy of the current path and returns it to the
+ user as a :class:`Path`.
+
+ This function is like :meth:`Context.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.
+
+ .. method:: curve_to(x1, y1, x2, y2, x3, y3)
+
+ :param x1: the X coordinate of the first control point
+ :type x1: float
+ :param y1: the Y coordinate of the first control point
+ :type y1: float
+ :param x2: the X coordinate of the second control point
+ :type x2: float
+ :param y2: the Y coordinate of the second control point
+ :type y2: float
+ :param x3: the X coordinate of the end of the curve
+ :type x3: float
+ :param y3: the Y coordinate of the end of the curve
+ :type y3: float
+
+ 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 :meth:`.curve_to`
+ this function will behave as if preceded by a call to
+ ``ctx.move_to(x1, y1)``.
+
+ .. method:: device_to_user(x, y)
+
+ :param x: X value of coordinate
+ :type x: float
+ :param y: Y value of coordinate
+ :type y: float
+ :returns: (x, y)
+ :rtype: (float, float)
+
+ Transform a coordinate from device space to user space by multiplying
+ the given point by the inverse of the current transformation matrix
+ (CTM).
+
+ .. method:: device_to_user_distance(dx, dy)
+
+ :param dx: X component of a distance vector
+ :type dx: float
+ :param dy: Y component of a distance vector
+ :type dy: float
+ :returns: (dx, dy)
+ :rtype: (float, float)
+
+ Transform a distance vector from device space to user space. This
+ function is similar to :meth:`Context.device_to_user` except that the
+ translation components of the inverse CTM will be ignored when
+ transforming *(dx,dy)*.
+
+ .. method:: fill()
+
+ A drawing operator that fills the current path according to the current
+ :ref:`FILL RULE <constants_FILL_RULE>`, (each sub-path is implicitly
+ closed before being filled). After :meth:`.fill`, the current path will
+ be cleared from the :class:`Context`. See :meth:`Context.set_fill_rule`
+ and :meth:`Context.fill_preserve`.
+
+ .. method:: fill_extents()
+
+ :returns: (x1, y1, x2, y2)
+ :rtype: (float, float, float, float)
+
+ * *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 :meth:`Context.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 :meth:`Context.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 :meth:`.fill_extents` must necessarily do more work to compute
+ the precise inked areas in light of the fill rule, so
+ :meth:`Context.path_extents` may be more desirable for sake of
+ performance if the non-inked path extents are desired.
+
+ See :meth:`Context.fill`, :meth:`Context.set_fill_rule` and
+ :meth:`Context.fill_preserve`.
+
+ .. method:: fill_preserve()
+
+ A drawing operator that fills the current path according to the current
+ :ref:`FILL RULE <constants_FILL_RULE>`, (each sub-path is implicitly
+ closed before being filled). Unlike :meth:`Context.fill`,
+ :meth:`.fill_preserve` preserves the path within the :class:`Context`.
+
+ See :meth:`Context.set_fill_rule` and :meth:`Context.fill`.
+
+ .. method:: font_extents()
+
+ :returns: (ascent, descent, height, max_x_advance, max_y_advance)
+ :rtype: (float, float, float, float, float)
+
+ Gets the font extents for the currently selected font.
+
+ .. method:: get_antialias()
+
+ :returns: the current :ref:`ANTIALIAS <constants_ANTIALIAS>` mode,
+ as set by :meth:`Context.set_antialias`.
+
+ .. method:: get_current_point()
+
+ :returns: (x, y)
+ :rtype: (float, float)
+
+ * *x*: X coordinate of the current point
+ * *y*: 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 :class:`Context` is in an error
+ status, *x* and *y* will both be set to 0.0. It is possible to check this
+ in advance with :meth:`Context.has_current_point`.
+
+ Most path construction functions alter the current point. See the
+ following for details on how they affect the current point:
+ :meth:`Context.new_path`, :meth:`Context.new_sub_path`,
+ :meth:`Context.append_path`, :meth:`Context.close_path`,
+ :meth:`Context.move_to`, :meth:`Context.line_to`,
+ :meth:`Context.curve_to`, :meth:`Context.rel_move_to`,
+ :meth:`Context.rel_line_to`, :meth:`Context.rel_curve_to`,
+ :meth:`Context.arc`, :meth:`Context.arc_negative`,
+ :meth:`Context.rectangle`, :meth:`Context.text_path`,
+ :meth:`Context.glyph_path`, :meth:`Context.stroke_to_path`.
+
+ Some functions use and alter the current point but do not otherwise
+ change current path:
+ :meth:`Context.show_text`.
+
+ Some functions unset the current path and as a result, current point:
+ :meth:`Context.fill`, :meth:`Context.stroke`.
+
+ .. method:: get_dash()
+
+ :returns: (dashes, offset)
+ :rtype: (tuple, float)
+
+ * *dashes*: return value for the dash array
+ * *offset*: return value for the current dash offset
+
+ Gets the current dash array.
+
+ .. versionadded:: 1.4
+
+ .. method:: get_dash_count()
+
+ :returns: the length of the dash array, or 0 if no dash array set.
+ :rtype: int
+
+ See also :meth:`Context.set_dash` and :meth:`Context.get_dash`.
+
+ .. versionadded:: 1.4
+
+ .. method:: get_fill_rule()
+
+ :returns: the current :ref:`FILL RULE <constants_FILL_RULE>`, as
+ set by :meth:`Context.set_fill_rule`.
+
+ .. method:: get_font_face()
+
+ :returns: the current :class:`FontFace` for the :class:`Context`.
+
+ .. method:: get_font_matrix()
+
+ :returns: the current :class:`Matrix` for the :class:`Context`.
+
+ See :meth:`Context.set_font_matrix`.
+
+ .. method:: get_font_options()
+
+ :returns: the current :class:`FontOptions` for the :class:`Context`.
+
+ Retrieves font rendering options set via
+ :meth:`Context.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 :meth:`Context.set_font_options`.
+
+ .. method:: get_group_target()
+
+ :returns: the target :class:`Surface`.
+
+ Gets the current destination :class:`Surface` for the
+ :class:`Context`. This is either the original target surface as passed
+ to :class:`Context` or the target surface for the current group as
+ started by the most recent call to :meth:`Context.push_group` or
+ :meth:`Context.push_group_with_content`.
+
+ .. versionadded:: 1.2
+
+ .. method:: get_line_cap()
+
+ :returns: the current :ref:`LINE_CAP <constants_LINE_CAP>` style, as
+ set by :meth:`Context.set_line_cap`.
+
+ .. method:: get_line_join()
+
+ :returns: the current :ref:`LINE_JOIN <constants_LINE_JOIN>` style, as
+ set by :meth:`Context.set_line_join`.
+
+ .. method:: get_line_width()
+
+ :returns: the current line width
+ :rtype: float
+
+ This function returns the current line width value exactly as set by
+ :meth:`Context.set_line_width`. Note that the value is unchanged even if
+ the CTM has changed between the calls to :meth:`Context.set_line_width`
+ and :meth:`.get_line_width`.
+
+ .. method:: get_matrix()
+
+ :returns: the current transformation :class:`Matrix` (CTM)
+
+ .. method:: get_miter_limit()
+
+ :returns: the current miter limit, as set by
+ :meth:`Context.set_miter_limit`.
+ :rtype: float
+
+ .. method:: get_operator()
+
+ :returns: the current compositing :ref:`OPERATOR <constants_OPERATOR>`
+ for a :class:`Context`.
+
+ .. method:: get_scaled_font()
+
+ :returns: the current :class:`ScaledFont` for a :class:`Context`.
+
+ .. versionadded:: 1.4
+
+ .. method:: get_source()
+
+ :returns: the current source :class:`Pattern` for a :class:`Context`.
+
+ .. method:: get_target()
+
+ :returns: the target :class:`Surface` for the :class:`Context`
+
+ .. method:: get_tolerance()
+
+ :returns: the current tolerance value, as set by
+ :meth:`Context.set_tolerance`
+ :rtype: float
+
+ .. method:: glyph_extents(glyphs, [num_glyphs])
+
+ :param glyphs: glyphs
+ :type glyphs: a sequence of (int, float, float)
+ :param num_glyphs: number of glyphs to measure, defaults to using all
+ :type num_glyphs: int
+ :returns: x_bearing, y_bearing, width, height, x_advance, y_advance
+ :rtype: 6-tuple of float
+
+ 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 :meth:`Context.show_glyphs`). Additionally,
+ the x_advance and y_advance values indicate the amount by which the
+ current point would be advanced by :meth:`Context.show_glyphs`.
+
+ Note that whitespace glyphs do not contribute to the size of the
+ rectangle (extents.width and extents.height).
+
+ .. method:: glyph_path(glyphs[, num_glyphs])
+
+ :param glyphs: glyphs to show
+ :type glyphs: a sequence of (int, float, float)
+ :param num_glyphs: number of glyphs to show, defaults to showing all
+ :type num_glyphs: int
+
+ Adds closed paths for the glyphs to the current path. The generated path
+ if filled, achieves an effect similar to that of
+ :meth:`Context.show_glyphs`.
+
+ .. method:: has_current_point()
+
+ returns: True iff a current point is defined on the current path.
+ See :meth:`Context.get_current_point` for details on the current point.
+
+ .. versionadded:: 1.6
+
+ .. method:: identity_matrix()
+
+ Resets the current transformation :class:`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.
+
+ .. method:: in_fill(x, y)
+
+ :param x: X coordinate of the point to test
+ :type x: float
+ :param y: Y coordinate of the point to test
+ :type y: float
+ :returns: True iff the point is inside the area that would be affected
+ by a :meth:`Context.fill` operation given the current path and filling
+ parameters. Surface dimensions and clipping are not taken into account.
+
+ See :meth:`Context.fill`, :meth:`Context.set_fill_rule` and
+ :meth:`Context.fill_preserve`.
+
+ .. method:: in_stroke(x, y)
+
+ :param x: X coordinate of the point to test
+ :type x: float
+ :param y: Y coordinate of the point to test
+ :type y: float
+
+ :returns: True iff the point is inside the area that would be affected
+ by a :meth:`Context.stroke` operation given the current path and
+ stroking parameters. Surface dimensions and clipping are not taken
+ into account.
+
+ See :meth:`Context.stroke`, :meth:`Context.set_line_width`,
+ :meth:`Context.set_line_join`, :meth:`Context.set_line_cap`,
+ :meth:`Context.set_dash`, and :meth:`Context.stroke_preserve`.
+
+ .. method:: line_to(x, y)
+
+ :param x: the X coordinate of the end of the new line
+ :type x: float
+ :param y: the Y coordinate of the end of the new line
+ :type y: float
+
+ 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 :meth:`.line_to`
+ this function will behave as ``ctx.move_to(x, y)``.
+
+ .. method:: mask(pattern)
+
+ :param pattern: a :class:`Pattern`
+
+ 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.)
+
+ .. method:: mask_surface(surface, x=0.0, y=0.0)
+
+ :param surface: a :class:`Surface`
+ :param x: X coordinate at which to place the origin of *surface*
+ :type x: float
+ :param y: Y coordinate at which to place the origin of *surface*
+ :type y: float
+
+ 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.)
+
+ .. method:: move_to(x, y)
+
+ :param x: the X coordinate of the new position
+ :type x: float
+ :param y: the Y coordinate of the new position
+ :type y: float
+
+ Begin a new sub-path. After this call the current point will be *(x,
+ y)*.
+
+ .. method:: new_path()
+
+ Clears the current path. After this call there will be no path and no
+ current point.
+
+ .. method:: new_sub_path()
+
+ 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 :meth:`Context.move_to`.
+
+ A call to :meth:`.new_sub_path` is particularly useful when beginning a
+ new sub-path with one of the :meth:`Context.arc` calls. This makes
+ things easier as it is no longer necessary to manually compute the arc's
+ initial coordinates for a call to :meth:`Context.move_to`.
+
+ .. versionadded:: 1.6
+
+ .. method:: paint()
+
+ A drawing operator that paints the current source everywhere within the
+ current clip region.
+
+ .. method:: paint_with_alpha(alpha)
+
+ :param alpha: alpha value, between 0 (transparent) and 1 (opaque)
+ :type alpha: float
+
+ 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 :meth:`Context.paint`, but the drawing is faded out
+ using the alpha value.
+
+ .. method:: path_extents()
+
+ :returns: (x1, y1, x2, y2)
+ :rtype: (float, float, float, float)
+
+ * *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 :meth:`Context.fill_extents` and
+ :meth:`Context.stroke_extents` which return the extents of only the area
+ that would be "inked" by the corresponding drawing operations.
+
+ The result of :meth:`.path_extents` is defined as equivalent to the
+ limit of :meth:`Context.stroke_extents` with cairo.LINE_CAP_ROUND as the
+ line width approaches 0.0, (but never reaching the empty-rectangle
+ returned by :meth:`Context.stroke_extents` for a line width of 0.0).
+
+ Specifically, this means that zero-area sub-paths such as
+ :meth:`Context.move_to`; :meth:`Context.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
+ :meth:`Context.move_to` will not contribute to the results of
+ :meth:`Context.path_extents`.
+
+ .. versionadded:: 1.6
+
+ .. method:: pop_group()
+
+ :returns: a newly created :class:`SurfacePattern` containing the results
+ of all drawing operations performed to the group.
+
+ Terminates the redirection begun by a call to :meth:`Context.push_group`
+ or :meth:`Context.push_group_with_content` and returns a new pattern
+ containing the results of all drawing operations performed to the group.
+
+ The :meth:`.pop_group` function calls :meth:`Context.restore`,
+ (balancing a call to :meth:`Context.save` by the
+ :meth:`Context.push_group` function), so that any changes to the graphics
+ state will not be visible outside the group.
+
+ .. versionadded:: 1.2
+
+ .. method:: pop_group_to_source()
+
+ Terminates the redirection begun by a call to :meth:`Context.push_group`
+ or :meth:`Context.push_group_with_content` and installs the resulting
+ pattern as the source :class:`Pattern` in the given :class:`Context`.
+
+ The behavior of this function is equivalent to the sequence of
+ operations::
+
+ group = cairo_pop_group()
+ ctx.set_source(group)
+
+ but is more convenient as their is no need for a variable to store
+ the short-lived pointer to the pattern.
+
+ The :meth:`Context.pop_group` function calls :meth:`Context.restore`,
+ (balancing a call to :meth:`Context.save` by the
+ :meth:`Context.push_group` function), so that any changes to the graphics
+ state will not be visible outside the group.
+
+ .. versionadded:: 1.2
+
+ .. method:: push_group()
+
+ Temporarily redirects drawing to an intermediate surface known as a
+ group. The redirection lasts until the group is completed by a call to
+ :meth:`Context.pop_group` or :meth:`Context.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
+ :meth:`Context.push_group`/:meth:`Context.pop_group`. Each call
+ pushes/pops the new target group onto/from a stack.
+
+ The :meth:`.push_group` function calls :meth:`Context.save` so that any
+ changes to the graphics state will not be visible outside the group,
+ (the pop_group functions call :meth:`Context.restore`).
+
+ By default the intermediate group will have a :ref:`CONTENT
+ <constants_CONTENT>` type of cairo.CONTENT_COLOR_ALPHA. Other content
+ types can be chosen for the group by using
+ :meth:`Context.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::
+
+ ctx.push_group()
+ ctx.set_source(fill_pattern)
+ ctx.fill_preserve()
+ ctx.set_source(stroke_pattern)
+ ctx.stroke()
+ ctx.pop_group_to_source()
+ ctx.paint_with_alpha(alpha)
+
+ .. versionadded:: 1.2
+
+ .. method:: push_group_with_content(content)
+
+ :param content: a :ref:`CONTENT <constants_CONTENT>` 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
+ :meth:`Context.pop_group` or :meth:`Context.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
+ :meth:`Context.push_group` which you should see for a more detailed
+ description of group rendering.
+
+ .. versionadded:: 1.2
+
+ .. method:: rectangle(x, y, width, height)
+
+ :param x: the X coordinate of the top left corner of the rectangle
+ :type x: float
+ :param y: the Y coordinate to the top left corner of the rectangle
+ :type y: float
+ :param width: the width of the rectangle
+ :type width: float
+ :param height: the height of the rectangle
+ :type height: float
+
+ 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::
+
+ ctx.move_to(x, y)
+ ctx.rel_line_to(width, 0)
+ ctx.rel_line_to(0, height)
+ ctx.rel_line_to(-width, 0)
+ ctx.close_path()
+
+ .. method:: rel_curve_to(dx1, dy1, dx2, dy2, dx3, dy4)
+
+ :param dx1: the X offset to the first control point
+ :type dx1: float
+ :param dy1: the Y offset to the first control point
+ :type dy1: float
+ :param dx2: the X offset to the second control point
+ :type dx2: float
+ :param dy2: the Y offset to the second control point
+ :type dy2: float
+ :param dx3: the X offset to the end of the curve
+ :type dx3: float
+ :param dy3: the Y offset to the end of the curve
+ :type dy3: float
+ :raises: :exc:`cairo.Error` if called with no current point.
+
+ Relative-coordinate version of :meth:`Context.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), ``ctx.rel_curve_to(dx1, dy1, dx2, dy2,
+ dx3, dy3)`` is logically equivalent to ``ctx.curve_to(x+dx1, y+dy1,
+ x+dx2, y+dy2, x+dx3, y+dy3)``.
+
+ .. method:: rel_line_to(dx, dy)
+
+ :param dx: the X offset to the end of the new line
+ :type dx: float
+ :param dy: the Y offset to the end of the new line
+ :type dy: float
+ :raises: :exc:`cairo.Error` if called with no current point.
+
+ Relative-coordinate version of :meth:`Context.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), ``ctx.rel_line_to(dx, dy)`` is logically
+ equivalent to ``ctx.line_to(x + dx, y + dy)``.
+
+ .. method:: rel_move_to(dx, dy)
+
+ :param dx: the X offset
+ :type dx: float
+ :param dy: the Y offset
+ :type dy: float
+ :raises: :exc:`cairo.Error` if called with no current point.
+
+ Begin a new sub-path. After this call the current point will offset by
+ *(dx, dy)*.
+
+ Given a current point of (x, y), ``ctx.rel_move_to(dx, dy)`` is logically
+ equivalent to ``ctx.(x + dx, y + dy)``.
+
+ .. method:: reset_clip()
+
+ 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 :meth:`.reset_clip`
+ as it will cause results unexpected by higher-level code which calls
+ :meth:`.clip`. Consider using :meth:`.save` and :meth:`.restore` around
+ :meth:`.clip` as a more robust means of temporarily restricting the clip
+ region.
+
+ .. method:: restore()
+
+ Restores :class:`Context` to the state saved by a preceding call to
+ :meth:`.save` and removes that state from the stack of saved states.
+
+ .. method:: rotate(angle)
+
+ :param angle: angle (in radians) by which the user-space axes will be
+ rotated
+ :type angle: float
+
+ 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.
+
+ .. method:: save()
+
+ Makes a copy of the current state of :class:`Context` and saves it on an
+ internal stack of saved states. When :meth:`.restore` is called,
+ :class:`Context` will be restored to the saved state. Multiple calls to
+ :meth:`.save` and :meth:`.restore` can be nested; each call to
+ :meth:`.restore` restores the state from the matching paired
+ :meth:`.save`.
+
+ .. method:: scale(sx, sy)
+
+ :param sx: scale factor for the X dimension
+ :type sx: float
+ :param sy: scale factor for the Y dimension
+ :type sy: float
+
+ 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.
+
+ .. method:: select_font_face(family[, slant[, weight]])
+
+ :param family: a font family name
+ :type family: str or unicode
+ :param slant: the :ref:`FONT_SLANT <constants_FONT_SLANT>` of the font,
+ defaults to :data:`cairo.FONT_SLANT_NORMAL`.
+ :param weight: the :ref:`FONT_WEIGHT <constants_FONT_WEIGHT>` of the
+ font, defaults to :data:`cairo.FONT_WEIGHT_NORMAL`.
+
+ Note: The :meth:`.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.
+
+ 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 :meth:`.select_font_face`, (nor
+ :meth:`.set_font_face` nor :meth:`.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 :class:`ToyFontFace`
+ followed by :meth:`.set_font_face`.
+
+ .. method:: set_antialias(antialias)
+
+ :param antialias: the new :ref:`ANTIALIAS <constants_ANTIALIAS>` 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
+ :data:`cairo.ANTIALIAS_SUBPIXEL` when drawing shapes.
+
+ Note that this option does not affect text rendering, instead see
+ :meth:`FontOptions.set_antialias`.
+
+ .. method:: set_dash(dashes, [offset=0])
+
+ :param dashes: a sequence specifying alternate lengths of on and off
+ stroke portions.
+ :type dashes: sequence of float
+ :param offset: an offset into the dash pattern at which the stroke
+ should start, defaults to 0.
+ :type offset: int
+ :raises: :exc:`cairo.Error` if any value in *dashes* is negative, or if
+ all values are 0.
+
+ Sets the dash pattern to be used by :meth:`.stroke`. A dash pattern is
+ specified by *dashes* - a sequence 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 :data:`cairo.LINE_CAP_ROUND` or :data:`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 :meth:`.set_dash`.
+
+ If the number of dashes is 0 dashing is disabled.
+
+ If the number of dashes is 1 a symmetric pattern is assumed with
+ alternating on and off portions of the size specified by the single
+ value in *dashes*.
+
+ .. method:: set_fill_rule(fill_rule)
+
+ :param fill_rule: a :ref:`FILL RULE <constants_FILL_RULE>` to set the
+ 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
+ :meth:`.fill` and :meth:`.clip`.
+
+ The default fill rule is :data:`cairo.FILL_RULE_WINDING`.
+
+ .. method:: set_font_face(font_face)
+
+ :param font_face: a :class:`FontFace`, or None to restore to the
+ default :class:`FontFace`
+
+ Replaces the current :class:`FontFace` object in the :class:`Context`
+ with *font_face*.
+
+ .. method:: set_font_matrix(matrix)
+
+ :param matrix: a :class:`Matrix` 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 :meth:`.set_font_size`), but a more complex font matrix can
+ be used to shear the font or stretch it unequally along the two axes
+
+ .. method:: set_font_options(options)
+
+ :param options: :class:`FontOptions` to use
+
+ Sets a set of custom font rendering options for the :class:`Context`.
+ 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 :data:`cairo.ANTIALIAS_DEFAULT`), then the value from the
+ surface is used.
+
+ .. method:: set_font_size(size)
+
+ :param size: the new font size, in user space units
+ :type size: float
+
+ Sets the current font matrix to a scale by a factor of *size*, replacing
+ any font matrix previously set with :meth:`.set_font_size` or
+ :meth:`.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 :meth:`.set_font_size`, (nor
+ :meth:`.set_font_matrix` nor :meth:`.set_scaled_font`), the default font
+ size is 10.0.
+
+ .. method:: set_line_cap(line_cap)
+
+ :param line_cap: a :ref:`LINE_CAP <constants_LINE_CAP>` style
+
+ Sets the current line cap style within the :class:`Context`.
+
+ As with the other stroke parameters, the current line cap style is
+ examined by :meth:`.stroke`, :meth:`.stroke_extents`, and
+ :meth:`.stroke_to_path`, but does not have any effect during path
+ construction.
+
+ The default line cap style is :data:`cairo.LINE_CAP_BUTT`.
+
+ .. method:: set_line_join(line_join)
+
+ :param line_join: a :ref:`LINE_JOIN <constants_LINE_JOIN>` style
+
+ Sets the current line join style within the :class:`Context`.
+
+ As with the other stroke parameters, the current line join style is
+ examined by :meth:`.stroke`, :meth:`.stroke_extents`, and
+ :meth:`.stroke_to_path`, but does not have any effect during path
+ construction.
+
+ The default line join style is :data:`cairo.LINE_JOIN_MITER`.
+
+ .. method:: set_line_width(width)
+
+ :param width: a line width
+ :type width: float
+
+ Sets the current line width within the :class:`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 :meth:`.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 :meth:`.set_line_width` and the stroking operation, then one can
+ just pass user-space values to :meth:`.set_line_width` and ignore this
+ note.
+
+ As with the other stroke parameters, the current line width is examined
+ by :meth:`.stroke`, :meth:`.stroke_extents`, and
+ :meth:`.stroke_to_path`, but does not have any effect during path
+ construction.
+
+ The default line width value is 2.0.
+
+ .. method:: set_matrix(matrix)
+
+ :param matrix: a transformation :class:`Matrix` from user space to
+ device space.
+
+ Modifies the current transformation matrix (CTM) by setting it equal to
+ *matrix*.
+
+ .. method:: set_miter_limit(limit)
+
+ :param limit: miter limit to set
+ :type width: float
+
+ Sets the current miter limit within the :class:`Context`.
+
+ If the current line join style is set to :data:`cairo.LINE_JOIN_MITER`
+ (see :meth:`.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 :meth:`.stroke`, :meth:`.stroke_extents`, and
+ :meth:`.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/math.sin(angle/2)
+
+ .. method:: set_operator(op)
+
+ :param op: the compositing :ref:`OPERATOR <constants_OPERATOR>` to set
+ for use in all drawing operations.
+
+ The default operator is :data:`cairo.OPERATOR_OVER`.
+
+ .. method:: set_scaled_font(scaled_font)
+
+ :param scaled_font: a :class:`ScaledFont`
+
+ Replaces the current font face, font matrix, and font options in the
+ :class:`Context` with those of the :class:`ScaledFont`. Except for some
+ translation, the current CTM of the :class:`Context` should be the same
+ as that of the :class:`ScaledFont`, which can be accessed using
+ :meth:`ScaledFont.get_ctm`.
+
+ .. versionadded:: 1.2
+
+ .. method:: set_source(source)
+
+ :param source: a :class:`Pattern` to be used as the source for
+ subsequent drawing operations.
+
+ Sets the source pattern within :class:`Context` 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 :meth:`.set_source`. This means that
+ further modifications of the current transformation matrix will not
+ affect the source pattern. See :meth:`Pattern.set_matrix`.
+
+ The default source pattern is a solid pattern that is opaque black,
+ (that is, it is equivalent to ``set_source_rgb(0.0, 0.0, 0.0)``.
+
+ .. method:: set_source_rgb(red, green, blue)
+
+ :param red: red component of color
+ :type red: float
+ :param green: green component of color
+ :type green: float
+ :param blue: blue component of color
+ :type blue: float
+
+ Sets the source pattern within :class:`Context` 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 ``set_source_rgb(0.0, 0.0, 0.0)``.
+
+ .. method:: set_source_rgba(red, green, blue[, alpha=1.0])
+
+ :param red: red component of color
+ :type red: float
+ :param green: green component of color
+ :type green: float
+ :param blue: blue component of color
+ :type blue: float
+ :param alpha: alpha component of color
+ :type alpha: float
+
+ Sets the source pattern within :class:`Context` 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 ``set_source_rgba(0.0, 0.0, 0.0, 1.0)``.
+
+ .. method:: set_source_surface(surface[, x=0.0[, y=0.0]])
+
+ :param surface: a :class:`Surface` to be used to set the source pattern
+ :param x: User-space X coordinate for surface origin
+ :type x: float
+ :param y: User-space Y coordinate for surface origin
+ :type y: float
+
+ This is a convenience function for creating a pattern from a
+ :class:`Surface` and setting it as the source in :class:`Context` with
+ :meth:`.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*
+ patterns 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 :class:`SurfacePattern`. The resulting pattern can
+ be queried with :meth:`.get_source` so that these attributes can be
+ modified if desired, (eg. to create a repeating pattern with
+ :meth:`.Pattern.set_extend`).
+
+ .. method:: set_tolerance(tolerance)
+
+ :param tolerance: the tolerance, in device units (typically pixels)
+ :type tolerance: float
+
+ 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.
+
+ .. method:: show_glyphs(glyphs[, num_glyphs])
+
+ :param glyphs: glyphs to show
+ :type glyphs: a sequence of (int, float, float)
+ :param num_glyphs: number of glyphs to show, defaults to showing all
+ glyphs
+ :type num_glyphs: int
+
+ 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.
+
+ .. method:: show_page()
+
+ Emits and clears the current page for backends that support multiple
+ pages. Use :meth:`.copy_page` if you don't want to clear the page.
+
+ This is a convenience function that simply calls
+ ``ctx.get_target() . show_page()``
+
+ .. method:: show_text(text)
+
+ :param text: text
+ :type text: str or unicode
+
+ A drawing operator that generates the shape from a string of text,
+ 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 :meth:`.show_text`.
+
+ Note: The :meth:`.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 :meth:`.show_glyphs` for the
+ "real" text display API in cairo.
+
+ .. method:: stroke()
+
+ A drawing operator that strokes the current path according to the
+ current line width, line join, line cap, and dash settings. After
+ :meth:`.stroke`, the current path will be cleared from the cairo
+ context. See :meth:`.set_line_width`, :meth:`.set_line_join`,
+ :meth:`.set_line_cap`, :meth:`.set_dash`, and :meth:`.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 :meth:`.set_dash`. If the cap
+ style is :data:`cairo.LINE_CAP_ROUND` or :data:`cairo.LINE_CAP_SQUARE`
+ then these segments will be drawn as circular dots or squares
+ respectively. In the case of :data:`cairo.LINE_CAP_SQUARE`, the
+ orientation of the squares is determined by the direction of the
+ underlying path.
+
+ 2. A sub-path created by :meth:`.move_to` followed by either a
+ :meth:`.close_path` or one or more calls to :meth:`.line_to` to the same
+ coordinate as the :meth:`.move_to`. If the cap style is
+ :data:`cairo.LINE_CAP_ROUND` then these sub-paths will be drawn as
+ circular dots. Note that in the case of :data:`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 :data:`cairo.LINE_CAP_BUTT` cause anything
+ to be drawn in the case of either degenerate segments or sub-paths.
+
+ .. method:: stroke_extents()
+
+ :returns: (x1, y1, x2, y2)
+ :rtype: (float, float, float, float)
+
+ * *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 :meth:`.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
+ :meth:`.stroke_extents` will return an empty rectangle. Contrast with
+ :meth:`.path_extents` which can be used to compute the non-empty bounds
+ as the line width approaches zero.
+
+ Note that :meth:`.stroke_extents` must necessarily do more work to
+ compute the precise inked areas in light of the stroke parameters, so
+ :meth:`.path_extents` may be more desirable for sake of performance if
+ non-inked path extents are desired.
+
+ See :meth:`.stroke`, :meth:`.set_line_width`, :meth:`.set_line_join`,
+ :meth:`.set_line_cap`, :meth:`.set_dash`, and :meth:`.stroke_preserve`.
+
+ .. method:: stroke_preserve()
+
+ A drawing operator that strokes the current path according to the
+ current line width, line join, line cap, and dash settings. Unlike
+ :meth:`.stroke`, :meth:`.stroke_preserve` preserves the path within the
+ cairo context.
+
+ See :meth:`.set_line_width`, :meth:`.set_line_join`,
+ :meth:`.set_line_cap`, :meth:`.set_dash`, and :meth:`.stroke_preserve`.
+
+ .. method:: text_extents(text)
+
+ :param text: text to get extents for
+ :type text: string or unicode
+ :returns: x_bearing, y_bearing, width, height, x_advance, y_advance
+ :rtype: 6-tuple of float
+
+ 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 :meth:`Context.show_text`). Additionally, the x_advance and
+ y_advance values indicate the amount by which the current point would be
+ advanced by :meth:`Context.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.
+
+ .. method:: text_path(text)
+
+ :param text: text
+ :type text: string or unicode
+
+ Adds closed paths for text to the current path. The generated path if
+ filled, achieves an effect similar to that of :meth:`Context.show_text`.
+
+ Text conversion and positioning is done similar to
+ :meth:`Context.show_text`.
+
+ Like :meth:`Context.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 :meth:`Context.text_path` without having to set
+ current point in between.
+
+ Note: The :meth:`.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 :meth:`Context.glyph_path` for the "real"
+ text path API in cairo.
+
+ .. method:: transform(matrix)
+
+ :param matrix: a transformation :class:`Matrix` 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.
+
+ .. method:: translate(tx, ty)
+
+ :param tx: amount to translate in the X direction
+ :type tx: float
+ :param ty: amount to translate in the Y direction
+ :type ty: float
+
+ 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 :meth:`.translate`. In other words, the translation of the user-space
+ origin takes place after any existing transformation.
+
+ .. method:: user_to_device(x, y)
+
+ :param x: X value of coordinate
+ :type x: float
+ :param y: Y value of coordinate
+ :type y: float
+ :returns: (x, y)
+ :rtype: (float, float)
+
+ * *x*: X value of coordinate
+ * *y*: Y value of coordinate
+
+ Transform a coordinate from user space to device space by multiplying
+ the given point by the current transformation matrix (CTM).
+
+ .. method:: user_to_device_distance(dx, dy)
+
+ :param dx: X value of a distance vector
+ :type dx: float
+ :param dy: Y value of a distance vector
+ :type dy: float
+ :returns: (dx, dy)
+ :rtype: (float, float)
+
+ * *dx*: X value of a distance vector
+ * *dy*: Y value of a distance vector
+
+ Transform a distance vector from user space to device space. This
+ function is similar to :meth:`Context.user_to_device` except that the
+ translation components of the CTM will be ignored when transforming
+ *(dx,dy)*.
diff --git a/doc/reference/exceptions.rst b/doc/reference/exceptions.rst
new file mode 100644
index 0000000..ce1bfa2
--- /dev/null
+++ b/doc/reference/exceptions.rst
@@ -0,0 +1,18 @@
+.. _exceptions:
+
+**********
+Exceptions
+**********
+
+.. currentmodule:: cairo
+
+When a cairo function or method call fails an exception is raised. I/O errors
+raise IOError, memory errors raise MemoryError, and all other errors raise
+cairo.Error.
+
+cairo.Error()
+=============
+
+.. exception:: cairo.Error
+
+ This exception is raised when a cairo object returns an error status.
diff --git a/doc/reference/index.rst b/doc/reference/index.rst
new file mode 100644
index 0000000..2b1b9ac
--- /dev/null
+++ b/doc/reference/index.rst
@@ -0,0 +1,19 @@
+.. _reference_index:
+
+*********
+Reference
+*********
+
+.. currentmodule:: cairo
+
+.. toctree::
+ :maxdepth: 2
+
+ constants
+ context
+ exceptions
+ matrix
+ paths
+ patterns
+ surfaces
+ text
diff --git a/doc/reference/matrix.rst b/doc/reference/matrix.rst
new file mode 100644
index 0000000..cb3ec3e
--- /dev/null
+++ b/doc/reference/matrix.rst
@@ -0,0 +1,181 @@
+.. _matrix:
+
+******
+Matrix
+******
+
+.. currentmodule:: cairo
+
+
+class Matrix()
+==============
+
+*Matrix* is used throughout cairo to convert between different coordinate
+spaces. A *Matrix* holds an affine transformation, such as a scale, rotation,
+shear, or a combination of these. The transformation of a point (x,y) is
+given by::
+
+ x_new = xx * x + xy * y + x0
+ y_new = yx * x + yy * y + y0
+
+The current transformation matrix of a :class:`Context`, represented as a
+*Matrix*, defines the transformation from user-space coordinates to device-space
+coordinates.
+
+Some standard Python operators can be used with matrices:
+
+To read the values from a *Matrix*::
+
+ xx, yx, xy, yy, x0, y0 = matrix
+
+To multiply two matrices::
+
+ matrix3 = matrix1.multiply(matrix2)
+ # or equivalently
+ matrix3 = matrix1 * matrix2
+
+To compare two matrices::
+
+ matrix1 == matrix2
+ matrix1 != matrix2
+
+For more information on matrix transformation see http://www.cairographics.org/matrix_transform
+
+
+.. class:: Matrix(xx = 1.0, yx = 0.0, xy = 0.0, yy = 1.0, x0 = 0.0, y0 = 0.0)
+
+ :param xx: xx component of the affine transformation
+ :type xx: float
+ :param yx: yx component of the affine transformation
+ :type yx: float
+ :param xy: xy component of the affine transformation
+ :type xy: float
+ :param yy: yy component of the affine transformation
+ :type yy: float
+ :param x0: X translation component of the affine transformation
+ :type x0: float
+ :param y0: Y translation component of the affine transformation
+ :type y0: float
+
+ Create a new *Matrix* with the affine transformation given by *xx, yx, xy,
+ yy, x0, y0*. The transformation is given by::
+
+ x_new = xx * x + xy * y + x0
+ y_new = yx * x + yy * y + y0
+
+ To create a new identity matrix::
+
+ matrix = cairo.Matrix()
+
+ To create a matrix with a transformation which translates by tx and ty in the X and Y dimensions, respectively::
+
+ matrix = cairo.Matrix(x0=tx, y0=ty)
+
+ To create a matrix with a transformation that scales by sx and sy in the X and Y dimensions, respectively::
+
+ matrix = cairo.Matrix(xx=sy, yy=sy)
+
+
+ .. classmethod:: init_rotate(radians)
+
+ :param 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.
+ :type radians: float
+ :returns: a new *Matrix* set to a transformation that rotates by *radians*.
+
+
+ .. method:: invert()
+
+ :returns: If *Matrix* has an inverse, modifies *Matrix* to be the
+ inverse matrix and returns *None*
+ :raises: :exc:`cairo.Error` if the *Matrix* as no inverse
+
+ Changes *Matrix* to be the inverse of it's original value. Not all
+ transformation matrices have inverses; if the matrix collapses points
+ together (it is *degenerate*), then it has no inverse and this function
+ will fail.
+
+
+ .. method:: multiply(matrix2)
+
+ :param matrix2: a second matrix
+ :type matrix2: cairo.Matrix
+ :returns: a new *Matrix*
+
+ Multiplies the affine transformations in *Matrix* and *matrix2*
+ together. The effect of the resulting transformation is to first apply
+ the transformation in *Matrix* to the coordinates and then apply the
+ transformation in *matrix2* to the coordinates.
+
+ It is allowable for result to be identical to either *Matrix* or *matrix2*.
+
+
+ .. method:: rotate(radians)
+
+ :param 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.
+ :type radians: float
+
+ Initialize *Matrix* to a transformation that rotates by *radians*.
+
+ .. method:: scale(sx, sy)
+
+ :param sx: scale factor in the X direction
+ :type sx: float
+ :param sy: scale factor in the Y direction
+ :type sy: float
+
+ 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.
+
+ .. method:: transform_distance(dx, dy)
+
+ :param dx: X component of a distance vector.
+ :type dx: float
+ :param dy: Y component of a distance vector.
+ :type dy: float
+ :returns: the transformed distance vector (dx,dy)
+ :rtype: (float, float)
+
+ Transforms the distance vector *(dx,dy)* by *Matrix*. This is similar to
+ :meth:`.transform_point` except that the translation components of
+ the transformation are ignored. The calculation of the returned vector
+ is as follows::
+
+ dx2 = dx1 * a + dy1 * c
+ dy2 = dx1 * b + dy1 * d
+
+ 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*.
+
+
+ .. method:: transform_point(x, y)
+
+ :param x: X position.
+ :type x: float
+ :param y: Y position.
+ :type y: float
+ :returns: the transformed point (x,y)
+ :rtype: (float, float)
+
+ Transforms the point *(x, y)* by *Matrix*.
+
+ .. method:: translate(tx, ty)
+
+ :param tx: amount to translate in the X direction
+ :type tx: float
+ :param ty: amount to translate in the Y direction
+ :type ty: float
+
+ Applies a transformation 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.
diff --git a/doc/reference/paths.rst b/doc/reference/paths.rst
new file mode 100644
index 0000000..ebaac59
--- /dev/null
+++ b/doc/reference/paths.rst
@@ -0,0 +1,23 @@
+.. _paths:
+
+*****
+Paths
+*****
+
+.. currentmodule:: cairo
+
+class Path()
+============
+
+.. class:: Path()
+
+ *Path* cannot be instantiated directly, it is created by calling
+ :meth:`Context.copy_path` and :meth:`Context.copy_path_flat`.
+
+ str(path) lists the path elements.
+
+ See :ref:`PATH attributes <constants_PATH>`
+
+ Path is an iterator.
+
+ See examples/warpedtext.py for example usage.
diff --git a/doc/reference/patterns.rst b/doc/reference/patterns.rst
new file mode 100644
index 0000000..9fab1d2
--- /dev/null
+++ b/doc/reference/patterns.rst
@@ -0,0 +1,286 @@
+.. _patterns:
+
+********
+Patterns
+********
+
+.. currentmodule:: cairo
+
+
+Patterns are 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 *PatternType* constructors
+listed below, or implicitly through *Context.set_source_<type>()* methods.
+
+
+class Pattern()
+===============
+
+*Pattern* is the abstract base class from which all the other pattern classes
+derive. It cannot be instantiated directly.
+
+.. class:: Pattern()
+
+ .. method:: get_extend()
+
+ :returns: the current extend strategy used for drawing the *Pattern*.
+ :rtype: int
+
+ Gets the current extend mode for the *Pattern*. See
+ :ref:`EXTEND attributes <constants_EXTEND>`
+ for details on the semantics of each extend strategy.
+
+ .. method:: get_matrix()
+
+ :returns: a new :class:`Matrix` which stores a copy of the *Pattern's* transformation matrix
+
+ .. method:: set_extend(extend)
+
+ :param extend: an :ref:`EXTEND <constants_EXTEND>` 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*.
+
+ The default extend mode is :data:`cairo.EXTEND_NONE` for
+ :class:`SurfacePattern` and :data:`cairo.EXTEND_PAD` for
+ :class:`Gradient` Patterns.
+
+ .. method:: set_matrix(matrix)
+
+ :param matrix: a :class:`Matrix`
+
+ 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::
+
+ matrix = cairo.Matrix(xx=0.5,yy=0.5)
+ pattern.set_matrix(matrix)
+
+ 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
+ :class:`Context.set_source`.
+
+
+class SolidPattern(:class:`Pattern`)
+====================================
+
+.. class:: SolidPattern(red, green, blue, alpha=1.0)
+
+ :param red: red component of the color
+ :type red: float
+ :param green: green component of the color
+ :type green: float
+ :param blue: blue component of the color
+ :type blue: float
+ :param alpha: alpha component of the color
+ :type alpha: float
+ :returns: a new *SolidPattern*
+ :raises: *MemoryError* in case of no memory
+
+ Creates a new *SolidPattern* 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.
+
+
+ .. method:: get_rgba()
+
+ :returns: (red, green, blue, alpha) a tuple of float
+
+ Gets the solid color for a *SolidPattern*.
+
+ .. versionadded:: 1.4
+
+
+class SurfacePattern(:class:`Pattern`)
+======================================
+
+.. class:: SurfacePattern(surface)
+
+ :param surface: a cairo :class:`Surface`
+ :returns: a newly created *SurfacePattern* for the given surface.
+ :raises: *MemoryError* in case of no memory.
+
+ .. method:: get_filter()
+
+ :returns: the current :ref:`FILTER <constants_filter>` used for
+ resizing the *SurfacePattern*.
+
+ .. method:: get_surface()
+
+ :returns: the :class:`Surface` of the *SurfacePattern*.
+
+ .. versionadded:: 1.4
+
+ .. method:: set_filter(filter)
+
+ :param filter: a :ref:`FILTER <constants_filter>` describing the filter
+ to use for resizing the *Pattern*
+
+ Note that you might want to control filtering even when you do not have
+ an explicit *Pattern* object, (for example when using
+ :meth:`Context.set_source_surface`). In these cases, it is convenient to use
+ :meth:`Context.get_source` to get access to the pattern that cairo creates
+ implicitly. For example::
+
+ context.set_source_surface(image, x, y)
+ surfacepattern.set_filter(context.get_source(), cairo.FILTER_NEAREST)
+
+
+class Gradient(:class:`Pattern`)
+================================
+
+*Gradient* is an abstract base class from which other *Pattern* classes
+derive. It cannot be instantiated directly.
+
+.. class:: Gradient()
+
+ .. method:: add_color_stop_rgb(offset, red, green, blue)
+
+ :param offset: an offset in the range [0.0 .. 1.0]
+ :type offset: float
+ :param red: red component of color
+ :type red: float
+ :param green: green component of color
+ :type green: float
+ :param blue: blue component of color
+ :type blue: float
+
+ Adds an opaque color stop to a *Gradient* pattern. The offset specifies
+ the location along the gradient's control vector. For example, a
+ *LinearGradient's* control vector is from (x0,y0) to (x1,y1) while a
+ *RadialGradient'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 :meth:`Context.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.
+
+ .. method:: add_color_stop_rgba(offset, red, green, blue, alpha)
+
+ :param offset: an offset in the range [0.0 .. 1.0]
+ :type offset: float
+ :param red: red component of color
+ :type red: float
+ :param green: green component of color
+ :type green: float
+ :param blue: blue component of color
+ :type blue: float
+ :param alpha: alpha component of color
+ :type alpha: float
+
+ Adds an opaque color stop to a *Gradient* pattern. The offset specifies
+ the location along the gradient's control vector. For example, a
+ *LinearGradient's* control vector is from (x0,y0) to (x1,y1) while a
+ *RadialGradient'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 :meth:`Context.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.
+
+
+class LinearGradient(:class:`Gradient`)
+=======================================
+.. class:: LinearGradient(x0, y0, x1, y1)
+
+ :param x0: x coordinate of the start point
+ :type x0: float
+ :param y0: y coordinate of the start point
+ :type y0: float
+ :param x1: x coordinate of the end point
+ :type x1: float
+ :param y1: y coordinate of the end point
+ :type y1: float
+ :returns: a new *LinearGradient*
+ :raises: *MemoryError* in case of no memory
+
+ Create a new *LinearGradient* along the line defined by (x0, y0) and (x1,
+ y1). Before using the *Gradient* pattern, a number of color stops should
+ be defined using :meth:`Gradient.add_color_stop_rgb` or
+ :meth:`Gradient.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 :meth:`Pattern.set_matrix`
+
+ .. method:: get_linear_points()
+
+ :returns: (x0, y0, x1, y1) - a tuple of float
+
+ * x0: return value for the x coordinate of the first point
+ * y0: return value for the y coordinate of the first point
+ * x1: return value for the x coordinate of the second point
+ * y1: return value for the y coordinate of the second point
+
+ Gets the gradient endpoints for a *LinearGradient*.
+
+ .. versionadded:: 1.4
+
+
+class RadialGradient(:class:`Gradient`)
+=======================================
+.. class:: RadialGradient(cx0, cy0, radius0, cx1, cy1, radius1)
+
+ :param cx0: x coordinate for the center of the start circle
+ :type cx0: float
+ :param cy0: y coordinate for the center of the start circle
+ :type cy0: float
+ :param radius0: radius of the start circle
+ :type radius0: float
+ :param cx1: x coordinate for the center of the end circle
+ :type cx1: float
+ :param cy1: y coordinate for the center of the end circle
+ :type cy1: float
+ :param radius1: radius of the end circle
+ :type radius1: float
+ :returns: the newly created *RadialGradient*
+ :raises: *MemoryError* in case of no memory
+
+ Creates a new *RadialGradient* pattern 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
+ :meth:`Gradient.add_color_stop_rgb` or :meth:`Gradient.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 :meth:`Pattern.set_matrix`.
+
+ .. method:: get_radial_circles()
+
+ :returns: (x0, y0, r0, x1, y1, r1) - a tuple of float
+
+ * x0: return value for the x coordinate of the center of the first circle
+ * y0: return value for the y coordinate of the center of the first circle
+ * r0: return value for the radius of the first circle
+ * x1: return value for the x coordinate of the center of the second circle
+ * y1: return value for the y coordinate of the center of the second circle
+ * r1: return value for the radius of the second circle
+
+ Gets the *Gradient* endpoint circles for a *RadialGradient*, each
+ specified as a center coordinate and a radius.
+
+ .. versionadded:: 1.4
diff --git a/doc/reference/surfaces.rst b/doc/reference/surfaces.rst
new file mode 100644
index 0000000..261fc1e
--- /dev/null
+++ b/doc/reference/surfaces.rst
@@ -0,0 +1,719 @@
+.. _surfaces:
+
+********
+Surfaces
+********
+
+.. currentmodule:: cairo
+
+.. comment block
+ example reST:
+ (add back '..' where required at column 0)
+ . class:: module.C[(signature)]
+ .. classmethod:: name(signature)
+ .. staticmethod:: name(signature)
+ .. method:: method(signature)
+
+ :param p1: xxx
+ :type p1: int
+ :param p2: xxx
+ :type p2: str
+ :returns: xxx
+ :rtype: list of strings
+ :raises: xxx
+
+ .. versionadded:: 1.6
+ links:
+ :data:`cairo.ANTIALIAS_SUBPIXEL`
+ :class:`Context`
+ :exc:`cairo.Error`
+ :meth:`.copy_page`
+ :meth:`Context.copy_page`
+ :ref:`LINE_CAP <constants_LINE_CAP>`
+
+ ``ctx.rel_move_to(dx, dy)`` # code snippet
+
+
+cairo.Surface is the abstract type representing all different drawing targets
+that cairo can render to. The actual drawings are performed using a
+:class:`Context`.
+
+A cairo.Surface is created by using backend-specific constructors
+of the form cairo.<XXX>Surface().
+
+class Surface()
+===============
+
+.. class:: Surface()
+
+ *Surface* is the abstract base class from which all the other surface
+ classes derive. It cannot be instantiated directly.
+
+ .. method:: copy_page()
+
+ 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 :meth:`.show_page` if you want to get an
+ empty page after the emission.
+
+ :meth:`Context.copy_page` is a convenience function for this.
+
+ .. versionadded:: 1.6
+
+ .. method:: create_similar(content, width, height)
+
+ :param content: the :ref:`CONTENT <constants_CONTENT>` for the new
+ surface
+ :param width: width of the new surface, (in device-space units)
+ :type width: int
+ :param height: height of the new surface (in device-space units)
+ :type width: int
+
+ :returns: a newly allocated *Surface*.
+
+ Create a *Surface* that is as compatible as possible with the existing
+ surface. For example the new surface will have the same fallback
+ resolution and :class:`FontOptions`. Generally, the new surface will
+ also use the same backend, unless that is not possible for some
+ reason.
+
+ Initially the surface contents are all 0 (transparent if contents have
+ transparency, black otherwise.)
+
+ .. method:: finish()
+
+ This method 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 finish()
+ the only valid operations on a *Surface* are flushing and finishing it.
+ Further drawing to the surface will not affect the surface but will
+ instead trigger a :exc:`cairo.Error` exception.
+
+ .. method:: flush()
+
+ Do any pending drawing for the *Surface* and also restore any temporary
+ modification's cairo has made to the *Surface's* state. This method
+ 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.
+
+ .. method:: get_content()
+
+ :returns: The :ref:`CONTENT <constants_CONTENT>` type of *Surface*,
+ which indicates whether the *Surface* contains color and/or alpha
+ information.
+
+ .. versionadded:: 1.2
+
+ .. method:: get_device_offset()
+
+ :returns: (x_offset, y_offset) a tuple of float
+
+ * x_offset: the offset in the X direction, in device units
+ * y_offset: the offset in the Y direction, in device units
+
+ This method returns the previous device offset set by
+ :meth:`.set_device_offset`.
+
+ .. versionadded:: 1.2
+
+ .. method:: get_fallback_resolution()
+
+ :returns: (x_pixels_per_inch, y_pixels_per_inch) a tuple of float
+
+ * x_pixels_per_inch: horizontal pixels per inch
+ * y_pixels_per_inch: vertical pixels per inch
+
+ This method returns the previous fallback resolution set by
+ :meth:`.set_fallback_resolution`, or default fallback resolution if
+ never set.
+
+ .. versionadded:: 1.8
+
+ .. method:: get_font_options()
+
+ :returns: a :class:`FontOptions`
+
+ 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 :class:`ScaledFont`.
+
+ .. method:: mark_dirty()
+
+ 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 :meth:`.flush` before doing such drawing.
+
+ .. method:: mark_dirty_rectangle(x, y, width, height)
+
+ :param x: X coordinate of dirty rectangle
+ :type x: int
+ :param y: Y coordinate of dirty rectangle
+ :type y: int
+ :param width: width of dirty rectangle
+ :type width: int
+ :param height: height of dirty rectangle
+ :type height: int
+
+ Like :meth:`.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.
+
+ .. method:: set_device_offset(x_offset, y_offset)
+
+ :param x_offset: the offset in the X direction, in device units
+ :type x_offset: float
+ :param y_offset: the offset in the Y direction, in device units
+ :type y_offset: float
+
+ 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 *Surface* 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
+ :meth:`Context.translate` isn't sufficient to do this, since functions
+ like :meth:`Context.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.
+
+ .. method:: set_fallback_resolution(x_pixels_per_inch, y_pixels_per_inch)
+
+ :param x_pixels_per_inch: horizontal setting for pixels per inch
+ :type x_pixels_per_inch: float
+ :param y_pixels_per_inch: vertical setting for pixels per inch
+ :type y_pixels_per_inch: float
+
+ 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 :meth:`Context.show_page` or
+ :meth:`Context.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.
+
+ .. versionadded:: 1.2
+
+ .. method:: show_page()
+
+ Emits and clears the current page for backends that support multiple
+ pages. Use :meth:`.copy_page` if you don't want to clear the page.
+
+ There is a convenience function for this that takes a
+ :meth:`Context.show_page`.
+
+ .. versionadded:: 1.6
+
+ .. method:: write_to_png(fobj)
+
+ :param fobj: the file to write to
+ :type fobj: str, file or file-like object
+ :raises: *MemoryError* if memory could not be allocated for the operation
+
+ *IOError* if an I/O error occurs while attempting to write the file
+
+ Writes the contents of *Surface* to *fobj* as a PNG image.
+
+
+class ImageSurface(:class:`Surface`)
+====================================
+
+A *cairo.ImageSurface* provides the ability to render to memory buffers either
+allocated by cairo or by the calling code. The supported image formats are
+those defined in :ref:`FORMAT attributes <constants_FORMAT>`.
+
+.. class:: ImageSurface(format, width, height)
+
+ :param format: :ref:`FORMAT <constants_FORMAT>` of pixels in the surface to create
+ :param width: width of the surface, in pixels
+ :param height: height of the surface, in pixels
+ :returns: a new *ImageSurface*
+ :raises: *MemoryError* in case of no memory
+
+ Creates an *ImageSurface* 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).
+
+ .. classmethod:: create_for_data(data, format, width, height[, stride])
+
+ :param data: a writable Python buffer object
+ :param format: the :ref:`FORMAT <constants_FORMAT>` of pixels in the
+ buffer
+ :param width: the width of the image to be stored in the buffer
+ :param height: the height of the image to be stored in the buffer
+ :param stride: the number of bytes between the start of rows in the
+ buffer as allocated. If not given the value from
+ ``format_stride_for_width(format, width)`` is used.
+ :returns: a new *ImageSurface*
+ :raises: *MemoryError* in case of no memory.
+
+ :exc:`cairo.Error` in case of invalid *stride* value.
+
+ Creates an *ImageSurface* for the provided pixel data. The initial
+ contents of buffer 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
+ :meth:`.format_stride_for_width` with the desired format and maximum
+ image width value, and use the resulting stride value to allocate the
+ data and to create the *ImageSurface*. See
+ :meth:`.format_stride_for_width` for example code.
+
+ .. classmethod:: create_from_png(fobj)
+
+ :param fobj: a filename, file, or file-like object of the PNG to load.
+ :returns: a new *ImageSurface* initialized the contents to the given
+ PNG file.
+
+ .. staticmethod:: format_stride_for_width(format, width)
+
+ :param format: a cairo :ref:`FORMAT <constants_FORMAT>` value
+ :param width: the desired width of an *ImageSurface* to be created.
+ :returns: the appropriate stride to use given the desired format and
+ width, or -1 if either the format is invalid or the width too large.
+ :rtype: int
+
+ This method 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::
+
+ stride = cairo.ImageSurface.format_stride_for_width (format, width)
+ surface = cairo.ImageSurface.create_for_data (data, format, width, height, stride)
+
+ .. versionadded:: 1.6
+
+ .. method:: get_data()
+
+ :returns: a Python buffer object for the data of the *ImageSurface*, for direct inspection or modification.
+
+ .. versionadded:: 1.2
+
+ .. method:: get_format()
+
+ :returns: the :ref:`FORMAT <constants_FORMAT>` of the *ImageSurface*.
+
+ .. versionadded:: 1.2
+
+ .. method:: get_height()
+
+ :returns: the height of the *ImageSurface* in pixels.
+
+ .. method:: get_stride()
+
+ :returns: the stride of the *ImageSurface* in bytes. The stride is the distance in bytes from the beginning of one row of the image data to the beginning of the next row.
+
+ .. method:: get_width()
+
+ :returns: the width of the *ImageSurface* in pixels.
+
+
+class PDFSurface(:class:`Surface`)
+==================================
+
+The PDFSurface is used to render cairo graphics to Adobe PDF files and is a
+multi-page vector surface backend.
+
+.. class:: PDFSurface(fobj, width_in_points, height_in_points)
+
+ :param fobj: a filename or writable file object. None may be used to specify no output. This will generate a *PDFSurface* that may be queried and used as a source, without generating a temporary file.
+ :type fobj: None, str, file or file-like object
+ :param width_in_points: width of the surface, in points
+ (1 point == 1/72.0 inch)
+ :type width_in_points: float
+ :param height_in_points: height of the surface, in points
+ (1 point == 1/72.0 inch)
+ :type height_in_points: float
+ :returns: a new *PDFSurface* of the specified size in points to be written
+ to *fobj*.
+ :raises: *MemoryError* in case of no memory
+
+ .. versionadded:: 1.2
+
+ .. method:: set_size()
+
+ :param width_in_points: new surface width, in points
+ (1 point == 1/72.0 inch)
+ :type width_in_points: float
+ :param height_in_points: new surface height, in points
+ (1 point == 1/72.0 inch)
+ :type height_in_points: float
+
+ Changes the size of a *PDFSurface* for the current (and subsequent) pages.
+
+ This function should only be called before any drawing operations have
+ been performed on the current page. The simplest way to do this is to
+ call this function immediately after creating the surface or immediately
+ after completing a page with either :meth:`Context.show_page` or
+ :meth:`Context.copy_page`.
+
+ .. versionadded:: 1.2
+
+
+class PSSurface(:class:`Surface`)
+=================================
+
+The *PSSurface* is used to render cairo graphics to Adobe PostScript files and
+is a multi-page vector surface backend.
+
+.. class:: PSSurface(fobj, width_in_points, height_in_points)
+
+ :param fobj: a filename or writable file object. None may be used to specify no output. This will generate a *PSSurface* that may be queried and used as a source, without generating a temporary file.
+ :type fobj: None, str, file or file-like object
+ :param width_in_points: width of the surface, in points
+ (1 point == 1/72.0 inch)
+ :type width_in_points: float
+ :param height_in_points: height of the surface, in points
+ (1 point == 1/72.0 inch)
+ :type height_in_points: float
+ :returns: a new *PDFSurface* of the specified size in points to be written
+ to *fobj*.
+ :raises: *MemoryError* in case of no memory
+
+ Note that the size of individual pages of the PostScript output can
+ vary. See :meth:`.set_size`.
+
+ .. method:: dsc_begin_page_setup()
+
+ This method indicates that subsequent calls to
+ :meth:`.dsc_comment` should direct comments to the PageSetup
+ section of the PostScript output.
+
+ This method call is only needed for the first page of a surface. It
+ should be called after any call to :meth:`.dsc_begin_setup` and
+ before any drawing is performed to the surface.
+
+ See :meth:`.dsc_comment` for more details.
+
+ .. versionadded:: 1.2
+
+ .. method:: dsc_begin_setup()
+
+ This function indicates that subsequent calls to :meth:`.dsc_comment`
+ should direct comments to the Setup section of the PostScript output.
+
+ This function should be called at most once per surface, and must be
+ called before any call to :meth:`.dsc_begin_page_setup` and before any
+ drawing is performed to the surface.
+
+ See :meth:`.dsc_comment` for more details.
+
+ .. versionadded:: 1.2
+
+ .. method:: dsc_comment(comment)
+
+ :param comment: a comment string to be emitted into the PostScript output
+ :type comment: str
+
+ Emit a comment into the PostScript output for the given surface.
+
+ The comment is expected to conform to the PostScript Language
+ Document Structuring Conventions (DSC). Please see that manual for
+ details on the available comments and their meanings. In
+ particular, the %%IncludeFeature comment allows a
+ device-independent means of controlling printer device features. So
+ the PostScript Printer Description Files Specification will also be
+ a useful reference.
+
+ The comment string must begin with a percent character (%) and the
+ total length of the string (including any initial percent
+ characters) must not exceed 255 characters. Violating either of
+ these conditions will place *PSSurface* into an error state. But
+ beyond these two conditions, this function will not enforce
+ conformance of the comment with any particular specification.
+
+ The comment string should not have a trailing newline.
+
+ The DSC specifies different sections in which particular comments
+ can appear. This function provides for comments to be emitted
+ within three sections: the header, the Setup section, and the
+ PageSetup section. Comments appearing in the first two sections
+ apply to the entire document while comments in the BeginPageSetup
+ section apply only to a single page.
+
+ For comments to appear in the header section, this function should
+ be called after the surface is created, but before a call to
+ :meth:`.dsc_begin_setup`.
+
+ For comments to appear in the Setup section, this function should be
+ called after a call to :meth:`.dsc_begin_setup` but before a call to
+ :meth:`.dsc_begin_page_setup`.
+
+ For comments to appear in the PageSetup section, this function should be
+ called after a call to :meth:`.dsc_begin_page_setup`.
+
+ Note that it is only necessary to call :meth:`.dsc_begin_page_setup` for
+ the first page of any surface. After a call to :meth:`Context.show_page`
+ or :meth:`Context.copy_page` comments are unambiguously directed to the
+ PageSetup section of the current page. But it doesn't hurt to call this
+ function at the beginning of every page as that consistency may make the
+ calling code simpler.
+
+ As a final note, cairo automatically generates several comments on
+ its own. As such, applications must not manually generate any of
+ the following comments:
+
+ Header section: %!PS-Adobe-3.0, %Creator, %CreationDate, %Pages,
+ %BoundingBox, %DocumentData, %LanguageLevel, %EndComments.
+
+ Setup section: %BeginSetup, %EndSetup
+
+ PageSetup section: %BeginPageSetup, %PageBoundingBox,
+ %EndPageSetup.
+
+ Other sections: %BeginProlog, %EndProlog, %Page, %Trailer, %EOF
+
+ Here is an example sequence showing how this function might be used::
+
+ surface = PSSurface (filename, width, height)
+ ...
+ surface.dsc_comment (surface, "%%Title: My excellent document")
+ surface.dsc_comment (surface, "%%Copyright: Copyright (C) 2006 Cairo Lover")
+ ...
+ surface.dsc_begin_setup (surface)
+ surface.dsc_comment (surface, "%%IncludeFeature: *MediaColor White")
+ ...
+ surface.dsc_begin_page_setup (surface)
+ surface.dsc_comment (surface, "%%IncludeFeature: *PageSize A3")
+ surface.dsc_comment (surface, "%%IncludeFeature: *InputSlot LargeCapacity")
+ surface.dsc_comment (surface, "%%IncludeFeature: *MediaType Glossy")
+ surface.dsc_comment (surface, "%%IncludeFeature: *MediaColor Blue")
+ ... draw to first page here ..
+ ctx.show_page (cr)
+ ...
+ surface.dsc_comment (surface, "%%IncludeFeature: PageSize A5");
+ ...
+
+ .. versionadded:: 1.2
+
+ .. method:: get_eps()
+
+ :returns: True iff the *PSSurface* will output Encapsulated PostScript.
+
+ .. versionadded:: 1.6
+
+ .. staticmethod:: ps_level_to_string(level)
+
+ :param level: a :ref:`PS_LEVEL <constants_PS_LEVEL>`
+ :returns: the string associated to given level.
+ :rtype: str
+ :raises: :exc:`cairo.Error` if *level* isn't valid.
+
+ Get the string representation of the given *level*. See
+ :meth:`.ps_get_levels` for a way to get the list of valid level
+ ids.
+
+ .. versionadded:: 1.6
+
+ .. method:: restrict_to_level(level)
+
+ :param level: a :ref:`PS_LEVEL <constants_PS_LEVEL>`
+
+ Restricts the generated PostSript file to *level*. See
+ :meth:`.ps_get_levels` for a list of available level values that
+ can be used here.
+
+ This function should only be called before any drawing operations have
+ been performed on the given surface. The simplest way to do this is to
+ call this function immediately after creating the surface.
+
+ .. versionadded:: 1.6
+
+ .. method:: set_eps(eps)
+
+ :param eps: True to output EPS format PostScript
+ :type eps: bool
+
+ If *eps* is True, the PostScript surface will output Encapsulated
+ PostScript.
+
+ This function should only be called before any drawing operations have
+ been performed on the current page. The simplest way to do this is to
+ call this function immediately after creating the surface. An
+ Encapsulated PostScript file should never contain more than one page.
+
+ .. versionadded:: 1.6
+
+ .. method:: set_size(width_in_points, height_in_points)
+
+ :param width_in_points: new surface width, in points (1 point == 1/72.0 inch)
+ :param height_in_points: new surface height, in points (1 point == 1/72.0 inch)
+ :type width_in_points: float
+ :type height_in_points: float
+
+ Changes the size of a PostScript surface for the current (and
+ subsequent) pages.
+
+ This function should only be called before any drawing operations
+ have been performed on the current page. The simplest way to do
+ this is to call this function immediately after creating the
+ surface or immediately after completing a page with either
+ :meth:`Context.show_page` or :meth:`Context.copy_page`.
+
+ .. versionadded:: 1.2
+
+
+class SVGSurface(:class:`Surface`)
+==================================
+
+The *SVGSurface* is used to render cairo graphics to SVG files and is a
+multi-page vector surface backend
+
+.. class:: SVGSurface(fobj, width_in_points, height_in_points)
+
+ :param fobj: a filename or writable file object. None may be used to specify no output. This will generate a *SVGSurface* that may be queried and used as a source, without generating a temporary file.
+ :type fobj: None, str, file or file-like object
+ :param width_in_points: width of the surface, in points (1 point == 1/72.0 inch)
+ :type width_in_points: float
+ :param height_in_points: height of the surface, in points (1 point == 1/72.0 inch)
+ :type height_in_points: float
+ :returns: a new *SVGSurface* of the specified size in points to be written to *fobj*.
+ :raises: *MemoryError* in case of no memory
+
+
+ .. method:: get_versions
+
+ Not implemented in pycairo (yet)
+
+ .. method:: restrict_to_version
+
+ Not implemented in pycairo (yet)
+
+ .. method:: version_to_string
+
+ Not implemented in pycairo (yet)
+
+
+class Win32Surface(:class:`Surface`)
+====================================
+
+The Microsoft Windows surface is used to render cairo graphics to Microsoft
+Windows windows, bitmaps, and printing device contexts.
+
+.. class:: Win32Surface(hdc)
+
+ :param hdc: the DC to create a surface for
+ :type hdc: int
+ :returns: the newly created surface
+
+ Creates a cairo surface that targets the given DC. The DC will be queried
+ for its initial clip extents, and this will be used as the size of the
+ cairo surface. The resulting surface will always be of format
+ cairo.FORMAT_RGB24, see :ref:`FORMAT attributes <constants_FORMAT>`.
+
+
+
+class Win32PrintingSurface(:class:`Surface`)
+============================================
+
+The Win32PrintingSurface is a multi-page vector surface type.
+
+.. class:: Win32PrintingSurface(hdc)
+
+ :param hdc: the DC to create a surface for
+ :type hdc: int
+ :returns: the newly created surface
+
+ Creates a cairo surface that targets the given DC. The DC will be queried
+ for its initial clip extents, and this will be used as the size of the
+ cairo surface. The DC should be a printing DC; antialiasing will be
+ ignored, and GDI will be used as much as possible to draw to the surface.
+
+ The returned surface will be wrapped using the paginated surface to provide
+ correct complex rendering behaviour; :meth:`.show_page` and associated
+ methods must be used for correct output.
+
+
+class XCBSurface(:class:`Surface`)
+==================================
+
+The XCB surface is used to render cairo graphics to X Window System windows
+and pixmaps using the XCB library.
+
+Note that the XCB surface automatically takes advantage of the X render
+extension if it is available.
+
+.. class:: XCBSurface
+
+ :param connection: an XCB connection
+ :param drawable: a X drawable
+ :param visualtype: a X visualtype
+ :param width: The surface width
+ :param height: The surface height
+
+ Creates a cairo surface that targets the given drawable (pixmap or window).
+
+ .. note:: This methods works using xpyb.
+
+ .. method:: set_size(width, height)
+
+ :param width: The width of the surface
+ :param height: The height of the surface
+
+ Informs cairo of the new size of the X Drawable underlying the surface. For a surface created
+ for a Window (rather than a Pixmap), this function must be called each time the size of the
+ window changes. (For a subwindow, you are normally resizing the window yourself, but for a
+ toplevel window, it is necessary to listen for ConfigureNotify events.)
+
+ A Pixmap can never change size, so it is never necessary to call this function on a surface
+ created for a Pixmap.
+
+
+class XlibSurface(:class:`Surface`)
+===================================
+
+The XLib surface is used to render cairo graphics to X Window System windows
+and pixmaps using the XLib library.
+
+Note that the XLib surface automatically takes advantage of X render extension
+if it is available.
+
+.. class:: XlibSurface
+
+ .. note:: *XlibSurface* cannot be instantiated directly because Python
+ interaction with Xlib would require open source Python bindings to Xlib
+ which provided a C API.
+ However, an *XlibSurface* instance can be returned from a function call
+ when using pygtk http://www.pygtk.org/.
+
+ .. method:: get_depth()
+
+ :returns: the number of bits used to represent each pixel value.
+
+ .. versionadded:: 1.2
+
+ .. method:: get_height()
+
+ :returns: the height of the X Drawable underlying the surface in pixels.
+
+ .. versionadded:: 1.2
+
+ .. method:: get_width()
+
+ :returns: the width of the X Drawable underlying the surface in pixels.
+
+ .. versionadded:: 1.2
diff --git a/doc/reference/text.rst b/doc/reference/text.rst
new file mode 100644
index 0000000..b0a261f
--- /dev/null
+++ b/doc/reference/text.rst
@@ -0,0 +1,279 @@
+.. _text:
+
+****
+Text
+****
+
+.. currentmodule:: cairo
+
+Cairo has two sets of text rendering capabilities:
+
+* The functions with text in their name form cairo's toy 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 glyphs in their name form cairo's low-level 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 http://www.pango.org/.
+
+
+
+class FontFace()
+================
+
+A *cairo.FontFace* 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 *FontFace* can be set on a
+:class:`Context` by using :meth:`Context.set_font_face` the size and font
+matrix are set with :meth:`Context.set_font_size` and
+:meth:`Context.set_font_matrix`.
+
+There are various types of *FontFace*, depending on the font backend they
+use.
+
+.. class:: FontFace()
+
+ .. note:: This class cannot be instantiated directly, it is returned by
+ :meth:`Context.get_font_face`.
+
+
+
+class FreeTypeFontFace(:class:`FontFace`)
+=========================================
+
+FreeType Fonts - Font support for FreeType.
+
+The FreeType font backend is primarily used to render text on GNU/Linux
+systems, but can be used on other platforms too.
+
+ .. note:: FreeType Fonts are not implemented in pycairo because there is no open source Python bindings to FreeType (and fontconfig) that provides a C API. This a possible project idea for anyone interested in adding FreeType support to pycairo.
+
+
+class ToyFontFace(:class:`FontFace`)
+====================================
+
+The *cairo.ToyFontFace* class can be used instead of :meth:`Context.select_font_face` to create a toy font independently of a context.
+
+.. class:: ToyFontFace(family[, slant[, weight]])
+
+ :param family: a font family name
+ :type family: str or unicode
+ :param slant: the :ref:`FONT_SLANT <constants_FONT_SLANT>` of the font,
+ defaults to :data:`cairo.FONT_SLANT_NORMAL`.
+ :param weight: the :ref:`FONT_WEIGHT <constants_FONT_WEIGHT>` of the font,
+ defaults to :data:`cairo.FONT_WEIGHT_NORMAL`.
+ :returns: a new *ToyFontFace*
+
+ Creates a *ToyFontFace* from a triplet of family, slant, and weight. These
+ font faces are used in implementation of the the "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
+ :meth:`.get_family`.
+
+ The :meth:`Context.select_font_face` method uses this to create font
+ faces. See that function for limitations of toy font faces.
+
+ .. versionadded:: 1.8.4
+
+ .. method:: get_family()
+
+ :returns: the family name of a toy font
+ :rtype: str
+
+ .. versionadded:: 1.8.4
+
+ .. method:: get_slant()
+
+ :returns: the :ref:`FONT_SLANT <constants_FONT_SLANT>` value
+
+ .. versionadded:: 1.8.4
+
+ .. method:: get_weight()
+
+ :returns: the :ref:`FONT_WEIGHT <constants_FONT_WEIGHT>` value
+
+ .. versionadded:: 1.8.4
+
+
+class UserFontFace(:class:`FontFace`)
+=====================================
+
+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.
+
+ .. note:: UserFontFace support has not (yet) been added to pycairo. If you
+ need this feature in pycairo register your interest by sending a message
+ to the cairo mailing list, or by opening a pycairo bug report.
+
+
+class ScaledFont()
+==================
+
+A *ScaledFont* is a font scaled to a particular size and device resolution. A
+*ScaledFont* 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 font backend they
+use.
+
+.. class:: ScaledFont(font_face, font_matrix, ctm, options)
+
+ :param font_face: a :class:`FontFace` instance
+ :param font_matrix: font space to user space transformation :class:`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 :meth:`Context.set_font_matrix`.
+ :param ctm: user to device transformation :class:`Matrix` with which the
+ font will be used.
+ :param options: a :class:`FontOptions` instance to use when getting metrics
+ for the font and rendering with it.
+
+ Creates a *ScaledFont* object from a *FontFace* and matrices that describe
+ the size of the font and the environment in which it will be used.
+
+ .. method:: extents()
+
+ :returns: (ascent, descent, height, max_x_advance, max_y_advance), a tuple of float values.
+
+ Gets the metrics for a *ScaledFont*.
+
+ .. method:: get_ctm()
+
+ Not implemented in pycairo (yet)
+
+ .. method:: get_font_face()
+
+ :returns: the :class:`FontFace` that this *ScaledFont* was created for.
+
+ .. versionadded:: 1.2
+
+ .. method:: get_font_matrix()
+
+ Not implemented in pycairo (yet)
+
+ .. method:: get_font_options()
+
+ Not implemented in pycairo (yet)
+
+ .. method:: get_scale_matrix()
+
+ :returns: the scale :class:`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.
+
+ .. versionadded:: 1.8
+
+
+ .. method:: glyph_extents()
+
+ Not implemented in pycairo (yet)
+
+
+ .. method:: text_extents(text)
+
+ :param text: text
+ :type text: str or unicode
+ :returns: (x_bearing, y_bearing, width, height, x_advance, y_advance)
+ :rtype: 6-tuple of float
+
+ 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 :meth:`Context.show_text` if the
+ cairo graphics state were set to the same font_face, font_matrix, ctm,
+ and font_options as *ScaledFont*). Additionally, the x_advance and
+ y_advance values indicate the amount by which the current point would be
+ advanced by :meth:`Context.show_text`.
+
+ Note that whitespace characters do not directly contribute to the size
+ of the rectangle (width and 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.
+
+ .. versionadded:: 1.2
+
+ .. method:: text_to_glyphs()
+
+ Not implemented in pycairo (yet)
+
+
+
+class FontOptions()
+===================
+
+An opaque structure holding all options that are used when rendering fonts.
+
+Individual features of a *FontOptions* can be set or accessed using functions
+named *FontOptions.set_<feature_name>* and
+*FontOptions.get_<feature_name>*, like :meth:`FontOptions.set_antialias`
+and :meth:`FontOptions.get_antialias`.
+
+New features may be added to a *FontOptions* in the future. For this reason,
+:meth:`FontOptions.copy()`, :meth:`FontOptions.equal()`,
+:meth:`FontOptions.merge()`, and :meth:`FontOptions.hash()` should be used to
+copy, check for equality, merge, or compute a hash value of FontOptions
+objects.
+
+.. class:: FontOptions()
+
+ :returns: a newly allocated *FontOptions*.
+
+ Allocates a new *FontOptions* object with all options initialized to default values.
+
+ .. method:: get_antialias()
+
+ :returns: the :ref:`ANTIALIAS <constants_ANTIALIAS>` mode for the *FontOptions* object
+
+ .. method:: get_hint_metrics()
+
+ :returns: the :ref:`HINT METRICS <constants_HINT_METRICS>` mode for the *FontOptions* object
+
+ .. method:: get_hint_style()
+
+ :returns: the :ref:`HINT STYLE <constants_HINT_STYLE>` for the *FontOptions* object
+
+ .. method:: get_subpixel_order()
+
+ :returns: the :ref:`SUBPIXEL_ORDER <constants_SUBPIXEL_ORDER>` for the *FontOptions* object
+
+ .. method:: set_antialias(antialias)
+
+ :param antialias: the :ref:`ANTIALIAS <constants_ANTIALIAS>` mode
+
+ This specifies the type of antialiasing to do when rendering text.
+
+ .. method:: set_hint_metrics(hint_metrics)
+
+ :param hint_metrics: the :ref:`HINT METRICS <constants_HINT_METRICS>` mode
+
+ This controls whether metrics are quantized to integer values in device
+ units.
+
+ .. method:: set_hint_style(hint_style)
+
+ :param hint_style: the :ref:`HINT STYLE <constants_HINT_STYLE>`
+
+ This controls whether to fit font outlines to the pixel grid, and if so,
+ whether to optimize for fidelity or contrast.
+
+ .. method:: set_subpixel_order(subpixel_order)
+
+ :param subpixel_order: the :ref:`SUBPIXEL_ORDER <constants_SUBPIXEL_ORDER>`
+
+ The subpixel order specifies the order of color elements within each
+ pixel on the display device when rendering with an antialiasing mode of
+ :data:`cairo.ANTIALIAS_SUBPIXEL`.
diff --git a/examples/.gitignore b/examples/.gitignore
new file mode 100644
index 0000000..377bac3
--- /dev/null
+++ b/examples/.gitignore
@@ -0,0 +1,5 @@
+*.pdf
+*.pyc
+*.pyo
+*.png
+*.ps
diff --git a/examples/cairo_snippets/c_to_python.py b/examples/cairo_snippets/c_to_python.py
new file mode 100755
index 0000000..43dcc68
--- /dev/null
+++ b/examples/cairo_snippets/c_to_python.py
@@ -0,0 +1,35 @@
+#!/usr/bin/env python
+"""
+translate C <snippet>.cairo to Python <snippet>.py
+
+; -> ''
+cairo_ -> cr.
+'(cr, ' -> ( but not snippet_normalize (cr, width, height)
+(cr) -> ()
+/* -> #/*
+CAIRO_ -> cairo.
+"""
+
+import sys
+
+
+if len(sys.argv) != 2 or not sys.argv[1].endswith('.cairo'):
+ raise SystemExit('usage: c_to_python.py <file>.cairo')
+
+filename_in = sys.argv[1]
+filename_out = filename_in.replace('.cairo', '.py')
+
+file_in = file(filename_in)
+file_out = file(filename_out, 'w')
+
+for line in file_in:
+ line = line.replace(';', '') # should be ';' and whitespace to EOL only -> \n
+ if not line.startswith('snippet_'):
+ line = line.replace('cairo_', 'cr.')
+ line = line.replace('(cr, ', '(')
+ line = line.replace('(cr)', '()')
+ line = line.replace('/*', '#/*')
+ line = line.replace(' ', '')
+ line = line.replace('CAIRO_', 'cairo.')
+
+ file_out.write (line)
diff --git a/examples/cairo_snippets/snippets/.gitignore b/examples/cairo_snippets/snippets/.gitignore
new file mode 100644
index 0000000..6be9629
--- /dev/null
+++ b/examples/cairo_snippets/snippets/.gitignore
@@ -0,0 +1,5 @@
+*.pdf
+*.png
+*.ps
+*.pyc
+*.svg
diff --git a/examples/cairo_snippets/snippets/__init__.py b/examples/cairo_snippets/snippets/__init__.py
new file mode 100755
index 0000000..70b4813
--- /dev/null
+++ b/examples/cairo_snippets/snippets/__init__.py
@@ -0,0 +1,12 @@
+# snippet list generation
+import os
+
+# list of snippet files
+snip_list = [x[:-3] for x in os.listdir (os.path.dirname (__file__))
+ if not x.startswith('_') and x.endswith('.py')]
+snip_list.sort()
+
+# function used by some or all snippets
+def snippet_normalize (ctx, width, height):
+ ctx.scale (width, height)
+ ctx.set_line_width (0.04)
diff --git a/examples/cairo_snippets/snippets/arc.py b/examples/cairo_snippets/snippets/arc.py
new file mode 100755
index 0000000..b4e6e5d
--- /dev/null
+++ b/examples/cairo_snippets/snippets/arc.py
@@ -0,0 +1,21 @@
+xc = 0.5
+yc = 0.5
+radius = 0.4
+angle1 = 45.0 * (M_PI/180.0) #/* angles are specified */
+angle2 = 180.0 * (M_PI/180.0) #/* in radians */
+
+snippet_normalize (cr, width, height)
+
+cr.arc (xc, yc, radius, angle1, angle2)
+cr.stroke ()
+
+#/* draw helping lines */
+cr.set_source_rgba (1,0.2,0.2,0.6)
+cr.arc (xc, yc, 0.05, 0, 2*M_PI)
+cr.fill ()
+cr.set_line_width (0.03)
+cr.arc (xc, yc, radius, angle1, angle1)
+cr.line_to (xc, yc)
+cr.arc (xc, yc, radius, angle2, angle2)
+cr.line_to (xc, yc)
+cr.stroke ()
diff --git a/examples/cairo_snippets/snippets/arc_negative.py b/examples/cairo_snippets/snippets/arc_negative.py
new file mode 100755
index 0000000..ca6a85d
--- /dev/null
+++ b/examples/cairo_snippets/snippets/arc_negative.py
@@ -0,0 +1,22 @@
+xc = 0.5
+yc = 0.5
+radius = 0.4
+angle1 = 45.0 * (M_PI/180.0) #/* angles are specified */
+angle2 = 180.0 * (M_PI/180.0) #/* in radians */
+
+snippet_normalize (cr, width, height)
+
+cr.arc_negative (xc, yc, radius, angle1, angle2)
+cr.stroke ()
+
+#/* draw helping lines */
+cr.set_source_rgba (1,0.2,0.2,0.6)
+cr.arc (xc, yc, 0.05, 0, 2*M_PI)
+cr.fill ()
+cr.set_line_width (0.03)
+cr.arc (xc, yc, radius, angle1, angle1)
+cr.line_to (xc, yc)
+cr.arc (xc, yc, radius, angle2, angle2)
+cr.line_to (xc, yc)
+cr.stroke ()
+#cr.stroke (10)
diff --git a/examples/cairo_snippets/snippets/clip.py b/examples/cairo_snippets/snippets/clip.py
new file mode 100755
index 0000000..8456235
--- /dev/null
+++ b/examples/cairo_snippets/snippets/clip.py
@@ -0,0 +1,13 @@
+snippet_normalize (cr, width, height)
+
+cr.arc (0.5, 0.5, 0.3, 0, 2 * M_PI)
+cr.clip ()
+
+cr.rectangle (0, 0, 1, 1)
+cr.fill ()
+cr.set_source_rgb (0, 1, 0)
+cr.move_to (0, 0)
+cr.line_to (1, 1)
+cr.move_to (1, 0)
+cr.line_to (0, 1)
+cr.stroke ()
diff --git a/examples/cairo_snippets/snippets/clip_image.py b/examples/cairo_snippets/snippets/clip_image.py
new file mode 100755
index 0000000..39a84ab
--- /dev/null
+++ b/examples/cairo_snippets/snippets/clip_image.py
@@ -0,0 +1,13 @@
+snippet_normalize (cr, width, height)
+
+cr.arc (0.5, 0.5, 0.3, 0, 2*M_PI)
+cr.clip ()
+
+image = cairo.ImageSurface.create_from_png ("data/romedalen.png")
+w = image.get_width()
+h = image.get_height()
+
+cr.scale (1.0/w, 1.0/h)
+
+cr.set_source_surface (image, 0, 0)
+cr.paint ()
diff --git a/examples/cairo_snippets/snippets/curve_rectangle.py b/examples/cairo_snippets/snippets/curve_rectangle.py
new file mode 100755
index 0000000..3fb3c4a
--- /dev/null
+++ b/examples/cairo_snippets/snippets/curve_rectangle.py
@@ -0,0 +1,53 @@
+#/* a custom shape, that could be wrapped in a function */
+x0 = 0.1 #/*< parameters like cairo_rectangle */
+y0 = 0.1
+rect_width = 0.8
+rect_height = 0.8
+radius = 0.4 #/*< and an approximate curvature radius */
+
+snippet_normalize (cr, width, height)
+
+x1=x0+rect_width
+y1=y0+rect_height
+#if (!rect_width || !rect_height)
+# return
+if rect_width/2<radius:
+ if rect_height/2<radius:
+ cr.move_to (x0, (y0 + y1)/2)
+ cr.curve_to (x0 ,y0, x0, y0, (x0 + x1)/2, y0)
+ cr.curve_to (x1, y0, x1, y0, x1, (y0 + y1)/2)
+ cr.curve_to (x1, y1, x1, y1, (x1 + x0)/2, y1)
+ cr.curve_to (x0, y1, x0, y1, x0, (y0 + y1)/2)
+ else:
+ cr.move_to (x0, y0 + radius)
+ cr.curve_to (x0 ,y0, x0, y0, (x0 + x1)/2, y0)
+ cr.curve_to (x1, y0, x1, y0, x1, y0 + radius)
+ cr.line_to (x1 , y1 - radius)
+ cr.curve_to (x1, y1, x1, y1, (x1 + x0)/2, y1)
+ cr.curve_to (x0, y1, x0, y1, x0, y1- radius)
+
+else:
+ if rect_height/2<radius:
+ cr.move_to (x0, (y0 + y1)/2)
+ cr.curve_to (x0 , y0, x0 , y0, x0 + radius, y0)
+ cr.line_to (x1 - radius, y0)
+ cr.curve_to (x1, y0, x1, y0, x1, (y0 + y1)/2)
+ cr.curve_to (x1, y1, x1, y1, x1 - radius, y1)
+ cr.line_to (x0 + radius, y1)
+ cr.curve_to (x0, y1, x0, y1, x0, (y0 + y1)/2)
+ else:
+ cr.move_to (x0, y0 + radius)
+ cr.curve_to (x0 , y0, x0 , y0, x0 + radius, y0)
+ cr.line_to (x1 - radius, y0)
+ cr.curve_to (x1, y0, x1, y0, x1, y0 + radius)
+ cr.line_to (x1 , y1 - radius)
+ cr.curve_to (x1, y1, x1, y1, x1 - radius, y1)
+ cr.line_to (x0 + radius, y1)
+ cr.curve_to (x0, y1, x0, y1, x0, y1- radius)
+
+cr.close_path ()
+
+cr.set_source_rgb (0.5,0.5,1)
+cr.fill_preserve ()
+cr.set_source_rgba (0.5,0,0,0.5)
+cr.stroke ()
diff --git a/examples/cairo_snippets/snippets/curve_to.py b/examples/cairo_snippets/snippets/curve_to.py
new file mode 100755
index 0000000..59e3b00
--- /dev/null
+++ b/examples/cairo_snippets/snippets/curve_to.py
@@ -0,0 +1,17 @@
+x, y = 0.1, 0.5
+x1, y1 = 0.4, 0.9
+x2, y2 = 0.6, 0.1
+x3, y3 = 0.9, 0.5
+
+snippet_normalize (cr, width, height)
+
+cr.move_to (x, y)
+cr.curve_to (x1, y1, x2, y2, x3, y3)
+
+cr.stroke ()
+
+cr.set_source_rgba (1,0.2,0.2,0.6)
+cr.set_line_width (0.03)
+cr.move_to (x,y); cr.line_to (x1,y1)
+cr.move_to (x2,y2); cr.line_to (x3,y3)
+cr.stroke ()
diff --git a/examples/cairo_snippets/snippets/ellipse.py b/examples/cairo_snippets/snippets/ellipse.py
new file mode 100755
index 0000000..9afd4f2
--- /dev/null
+++ b/examples/cairo_snippets/snippets/ellipse.py
@@ -0,0 +1,33 @@
+snippet_normalize(cr, width, height)
+
+def path_ellipse(cr, x, y, width, height, angle=0):
+ """
+ x - center x
+ y - center y
+ width - width of ellipse (in x direction when angle=0)
+ height - height of ellipse (in y direction when angle=0)
+ angle - angle in radians to rotate, clockwise
+ """
+ cr.save()
+ cr.translate(x, y)
+ cr.rotate(angle)
+ cr.scale(width / 2.0, height / 2.0)
+ cr.arc(0.0, 0.0, 1.0, 0.0, 2.0 * M_PI)
+ cr.restore()
+
+
+path_ellipse(cr, 0.5, 0.5, 1.0, 0.3, M_PI/4.0)
+
+# fill
+cr.set_source_rgba(1,0,0,1)
+cr.fill_preserve()
+
+# stroke
+# reset identity matrix so line_width is a constant
+# width in device-space, not user-space
+cr.save()
+cr.identity_matrix()
+cr.set_source_rgba(0,0,0,1)
+cr.set_line_width(3)
+cr.stroke()
+cr.restore()
diff --git a/examples/cairo_snippets/snippets/fill_and_stroke.py b/examples/cairo_snippets/snippets/fill_and_stroke.py
new file mode 100755
index 0000000..6d66192
--- /dev/null
+++ b/examples/cairo_snippets/snippets/fill_and_stroke.py
@@ -0,0 +1,12 @@
+snippet_normalize (cr, width, height)
+
+cr.move_to (0.5, 0.1)
+cr.line_to (0.9, 0.9)
+cr.rel_line_to (-0.4, 0.0)
+cr.curve_to (0.2, 0.9, 0.2, 0.5, 0.5, 0.5)
+cr.close_path()
+
+cr.set_source_rgb (0, 0, 1)
+cr.fill_preserve ()
+cr.set_source_rgb (0, 0, 0)
+cr.stroke ()
diff --git a/examples/cairo_snippets/snippets/fill_and_stroke2.py b/examples/cairo_snippets/snippets/fill_and_stroke2.py
new file mode 100755
index 0000000..c520630
--- /dev/null
+++ b/examples/cairo_snippets/snippets/fill_and_stroke2.py
@@ -0,0 +1,18 @@
+snippet_normalize (cr, width, height)
+
+cr.move_to (0.5, 0.1)
+cr.line_to (0.9, 0.9)
+cr.rel_line_to (-0.4, 0.0)
+cr.curve_to (0.2, 0.9, 0.2, 0.5, 0.5, 0.5)
+cr.close_path ()
+
+cr.move_to (0.25, 0.1)
+cr.rel_line_to (0.2, 0.2)
+cr.rel_line_to (-0.2, 0.2)
+cr.rel_line_to (-0.2, -0.2)
+cr.close_path ()
+
+cr.set_source_rgb (0, 0, 1)
+cr.fill_preserve ()
+cr.set_source_rgb (0, 0, 0)
+cr.stroke ()
diff --git a/examples/cairo_snippets/snippets/glyph_path.py b/examples/cairo_snippets/snippets/glyph_path.py
new file mode 100755
index 0000000..2b73193
--- /dev/null
+++ b/examples/cairo_snippets/snippets/glyph_path.py
@@ -0,0 +1,21 @@
+snippet_normalize (cr, width, height)
+
+cr.select_font_face ("Sans", cairo.FONT_SLANT_NORMAL,
+ cairo.FONT_WEIGHT_NORMAL)
+# draw 0.16 glyphs in 0.20 squares, at (0.02, 0.04) from left corner
+cr.set_font_size (0.16)
+
+glyphs = []
+index = 20
+for y in range(5):
+ for x in range(5):
+ glyphs.append ((index, x/5.0 + 0.02, y/5.0 + 0.16))
+ index += 1
+
+cr.glyph_path (glyphs)
+cr.set_source_rgb (0.5,0.5,1.0)
+cr.fill_preserve ()
+cr.set_source_rgb (0,0,0)
+cr.set_line_width (0.005)
+cr.stroke ()
+
diff --git a/examples/cairo_snippets/snippets/gradient.py b/examples/cairo_snippets/snippets/gradient.py
new file mode 100755
index 0000000..22f0658
--- /dev/null
+++ b/examples/cairo_snippets/snippets/gradient.py
@@ -0,0 +1,16 @@
+snippet_normalize (cr, width, height)
+
+pat = cairo.LinearGradient (0.0, 0.0, 0.0, 1.0)
+pat.add_color_stop_rgba (1, 0, 0, 0, 1)
+pat.add_color_stop_rgba (0, 1, 1, 1, 1)
+cr.rectangle (0,0,1,1)
+cr.set_source (pat)
+cr.fill ()
+
+pat = cairo.RadialGradient (0.45, 0.4, 0.1,
+ 0.4, 0.4, 0.5)
+pat.add_color_stop_rgba (0, 1, 1, 1, 1)
+pat.add_color_stop_rgba (1, 0, 0, 0, 1)
+cr.set_source (pat)
+cr.arc (0.5, 0.5, 0.3, 0, 2 * M_PI)
+cr.fill ()
diff --git a/examples/cairo_snippets/snippets/gradient_mask.py b/examples/cairo_snippets/snippets/gradient_mask.py
new file mode 100755
index 0000000..4a0eba4
--- /dev/null
+++ b/examples/cairo_snippets/snippets/gradient_mask.py
@@ -0,0 +1,12 @@
+snippet_normalize (cr, width, height)
+
+pattern = cairo.LinearGradient (0, 0, 1, 1)
+pattern.add_color_stop_rgb (0, 0, 0.3, 0.8)
+pattern.add_color_stop_rgb (1, 0, 0.8, 0.3)
+
+mask = cairo.RadialGradient (0.5, 0.5, 0.25, 0.5, 0.5, 0.5)
+mask.add_color_stop_rgba (0, 0, 0, 0, 1)
+mask.add_color_stop_rgba (0.5, 0, 0, 0, 0)
+
+cr.set_source (pattern)
+cr.mask (mask)
diff --git a/examples/cairo_snippets/snippets/group.py b/examples/cairo_snippets/snippets/group.py
new file mode 100755
index 0000000..a787f4d
--- /dev/null
+++ b/examples/cairo_snippets/snippets/group.py
@@ -0,0 +1,16 @@
+# demo/test for group functions
+snippet_normalize (cr, width, height)
+
+cr.rectangle (0.1, 0.1, 0.6, 0.6)
+cr.set_line_width (0.03)
+cr.set_source_rgb (0.8, 0.8, 0.8)
+cr.fill()
+
+cr.push_group()
+cr.rectangle (0.3, 0.3, 0.6, 0.6)
+cr.set_source (cairo.SolidPattern (1, 0, 0))
+cr.fill_preserve()
+cr.set_source (cairo.SolidPattern (0, 0, 0))
+cr.stroke ()
+cr.pop_group_to_source()
+cr.paint_with_alpha (0.5)
diff --git a/examples/cairo_snippets/snippets/image.py b/examples/cairo_snippets/snippets/image.py
new file mode 100755
index 0000000..ccadc4f
--- /dev/null
+++ b/examples/cairo_snippets/snippets/image.py
@@ -0,0 +1,14 @@
+snippet_normalize (cr, width, height)
+
+image = cairo.ImageSurface.create_from_png ("data/romedalen.png")
+w = image.get_width()
+h = image.get_height()
+
+cr.translate (0.5, 0.5)
+cr.rotate (45* M_PI/180)
+cr.scale (1.0/w, 1.0/h)
+cr.translate (-0.5*w, -0.5*h)
+
+cr.set_source_surface (image, 0, 0)
+cr.paint ()
+
diff --git a/examples/cairo_snippets/snippets/imagepattern.py b/examples/cairo_snippets/snippets/imagepattern.py
new file mode 100755
index 0000000..5d07c07
--- /dev/null
+++ b/examples/cairo_snippets/snippets/imagepattern.py
@@ -0,0 +1,23 @@
+import math
+
+snippet_normalize (cr, width, height)
+
+image = cairo.ImageSurface.create_from_png ("data/romedalen.png")
+w = image.get_width()
+h = image.get_height()
+
+pattern = cairo.SurfacePattern (image)
+pattern.set_extend (cairo.EXTEND_REPEAT)
+
+cr.translate (0.5, 0.5)
+cr.rotate (M_PI / 4)
+cr.scale (1 / math.sqrt (2), 1 / math.sqrt (2))
+cr.translate (- 0.5, - 0.5)
+
+matrix = cairo.Matrix(xx=w * 5, yy=h * 5)
+pattern.set_matrix (matrix)
+
+cr.set_source (pattern)
+
+cr.rectangle (0, 0, 1.0, 1.0)
+cr.fill ()
diff --git a/examples/cairo_snippets/snippets/path.py b/examples/cairo_snippets/snippets/path.py
new file mode 100755
index 0000000..cce8aec
--- /dev/null
+++ b/examples/cairo_snippets/snippets/path.py
@@ -0,0 +1,7 @@
+snippet_normalize (cr, width, height)
+cr.move_to (0.5, 0.1)
+cr.line_to (0.9, 0.9)
+cr.rel_line_to (-0.4, 0.0)
+cr.curve_to (0.2, 0.9, 0.2, 0.5, 0.5, 0.5)
+
+cr.stroke ()
diff --git a/examples/cairo_snippets/snippets/set_line_cap.py b/examples/cairo_snippets/snippets/set_line_cap.py
new file mode 100755
index 0000000..6de1fae
--- /dev/null
+++ b/examples/cairo_snippets/snippets/set_line_cap.py
@@ -0,0 +1,19 @@
+snippet_normalize (cr, width, height)
+cr.set_line_width (0.12)
+cr.set_line_cap (cairo.LINE_CAP_BUTT) #/* default */
+cr.move_to (0.25, 0.2); cr.line_to (0.25, 0.8)
+cr.stroke ()
+cr.set_line_cap (cairo.LINE_CAP_ROUND)
+cr.move_to (0.5, 0.2); cr.line_to (0.5, 0.8)
+cr.stroke ()
+cr.set_line_cap (cairo.LINE_CAP_SQUARE)
+cr.move_to (0.75, 0.2); cr.line_to (0.75, 0.8)
+cr.stroke ()
+
+#/* draw helping lines */
+cr.set_source_rgb (1,0.2,0.2)
+cr.set_line_width (0.01)
+cr.move_to (0.25, 0.2); cr.line_to (0.25, 0.8)
+cr.move_to (0.5, 0.2); cr.line_to (0.5, 0.8)
+cr.move_to (0.75, 0.2); cr.line_to (0.75, 0.8)
+cr.stroke ()
diff --git a/examples/cairo_snippets/snippets/set_line_join.py b/examples/cairo_snippets/snippets/set_line_join.py
new file mode 100755
index 0000000..b2e1919
--- /dev/null
+++ b/examples/cairo_snippets/snippets/set_line_join.py
@@ -0,0 +1,21 @@
+snippet_normalize (cr, width, height)
+cr.set_line_width (0.16)
+cr.move_to (0.3, 0.33)
+cr.rel_line_to (0.2, -0.2)
+cr.rel_line_to (0.2, 0.2)
+cr.set_line_join (cairo.LINE_JOIN_MITER) #/* default */
+cr.stroke ()
+
+cr.move_to (0.3, 0.63)
+cr.rel_line_to (0.2, -0.2)
+cr.rel_line_to (0.2, 0.2)
+cr.set_line_join (cairo.LINE_JOIN_BEVEL)
+cr.stroke ()
+
+cr.move_to (0.3, 0.93)
+cr.rel_line_to (0.2, -0.2)
+cr.rel_line_to (0.2, 0.2)
+cr.set_line_join (cairo.LINE_JOIN_ROUND)
+cr.stroke ()
+
+
diff --git a/examples/cairo_snippets/snippets/show_glyphs.py b/examples/cairo_snippets/snippets/show_glyphs.py
new file mode 100755
index 0000000..a41cf61
--- /dev/null
+++ b/examples/cairo_snippets/snippets/show_glyphs.py
@@ -0,0 +1,15 @@
+snippet_normalize (cr, width, height)
+
+cr.select_font_face ("Sans", cairo.FONT_SLANT_NORMAL,
+ cairo.FONT_WEIGHT_NORMAL)
+# draw 0.08 glyphs in 0.10 squares, at (0.01, 0.02) from left corner
+cr.set_font_size (0.08)
+
+glyphs = []
+index = 0
+for y in range(10):
+ for x in range(10):
+ glyphs.append ((index, x/10.0 + 0.01, y/10.0 + 0.08))
+ index += 1
+
+cr.show_glyphs (glyphs)
diff --git a/examples/cairo_snippets/snippets/text.py b/examples/cairo_snippets/snippets/text.py
new file mode 100755
index 0000000..1ba80e6
--- /dev/null
+++ b/examples/cairo_snippets/snippets/text.py
@@ -0,0 +1,22 @@
+snippet_normalize (cr, width, height)
+cr.select_font_face ("Sans", cairo.FONT_SLANT_NORMAL,
+ cairo.FONT_WEIGHT_BOLD)
+cr.set_font_size (0.35)
+
+cr.move_to (0.04, 0.53)
+cr.show_text ("Hello")
+
+cr.move_to (0.27, 0.65)
+cr.text_path ("void")
+cr.set_source_rgb (0.5,0.5,1)
+cr.fill_preserve ()
+cr.set_source_rgb (0,0,0)
+cr.set_line_width (0.01)
+cr.stroke ()
+
+#/* draw helping lines */
+cr.set_source_rgba (1,0.2,0.2, 0.6)
+cr.arc (0.04, 0.53, 0.02, 0, 2*M_PI)
+cr.arc (0.27, 0.65, 0.02, 0, 2*M_PI)
+cr.fill ()
+
diff --git a/examples/cairo_snippets/snippets/text_align_center.py b/examples/cairo_snippets/snippets/text_align_center.py
new file mode 100755
index 0000000..4bc3124
--- /dev/null
+++ b/examples/cairo_snippets/snippets/text_align_center.py
@@ -0,0 +1,26 @@
+utf8 = "cairo"
+
+snippet_normalize (cr, width, height)
+
+cr.select_font_face ("Sans",
+ cairo.FONT_SLANT_NORMAL,
+ cairo.FONT_WEIGHT_NORMAL)
+
+cr.set_font_size (0.2)
+x_bearing, y_bearing, width, height, x_advance, y_advance = cr.text_extents (utf8)
+x = 0.5-(width/2 + x_bearing)
+y = 0.5-(height/2 + y_bearing)
+
+cr.move_to (x, y)
+cr.show_text (utf8)
+
+#/* draw helping lines */
+cr.set_source_rgba (1,0.2,0.2,0.6)
+cr.arc (x, y, 0.05, 0, 2*M_PI)
+cr.fill ()
+cr.move_to (0.5, 0)
+cr.rel_line_to (0, 1)
+cr.move_to (0, 0.5)
+cr.rel_line_to (1, 0)
+cr.stroke ()
+
diff --git a/examples/cairo_snippets/snippets/text_extents.py b/examples/cairo_snippets/snippets/text_extents.py
new file mode 100755
index 0000000..890fb88
--- /dev/null
+++ b/examples/cairo_snippets/snippets/text_extents.py
@@ -0,0 +1,27 @@
+utf8 = "cairo"
+
+snippet_normalize (cr, width, height)
+
+cr.select_font_face ("Sans",
+ cairo.FONT_SLANT_NORMAL,
+ cairo.FONT_WEIGHT_NORMAL)
+
+cr.set_font_size (0.4)
+x_bearing, y_bearing, width, height, x_advance, y_advance = cr.text_extents (utf8)
+
+x=0.1
+y=0.6
+
+cr.move_to (x,y)
+cr.show_text (utf8)
+
+#/* draw helping lines */
+cr.set_source_rgba (1,0.2,0.2,0.6)
+cr.arc (x, y, 0.05, 0, 2*M_PI)
+cr.fill ()
+cr.move_to (x,y)
+cr.rel_line_to (0, -height)
+cr.rel_line_to (width, 0)
+cr.rel_line_to (x_bearing, -y_bearing)
+cr.stroke ()
+
diff --git a/examples/cairo_snippets/snippets_gtk.py b/examples/cairo_snippets/snippets_gtk.py
new file mode 100755
index 0000000..c7796ea
--- /dev/null
+++ b/examples/cairo_snippets/snippets_gtk.py
@@ -0,0 +1,140 @@
+#!/usr/bin/env python
+"""Python version of cairo-demo/cairo_snippets/cairo_snippets_gtk.c
+"""
+from __future__ import division
+from math import pi as M_PI # used by many snippets
+import os.path
+import sys
+
+import cairo
+import gtk
+import pango
+
+from snippets import snip_list, snippet_normalize
+
+
+Width, Height = 400, 400
+
+snippets_path = os.path.join(os.path.dirname(__file__), 'snippets')
+
+
+def gdkcolor_to_rgb (gdkcolor):
+ return gdkcolor.red/65535, gdkcolor.green/65535, gdkcolor.blue/65535
+
+
+class Window (gtk.Window):
+ """Composite widget"""
+ def __init__ (self, title=None, type=gtk.WINDOW_TOPLEVEL):
+ gtk.Window.__init__ (self, type)
+ self.set_default_size (Width, Height)
+
+ self.da = gtk.DrawingArea()
+ self.da.connect('expose-event', self.da_expose_event)
+
+ def put_in_frame (widget):
+ frame = gtk.Frame (label=None)
+ frame.set_property ('shadow_type', gtk.SHADOW_IN)
+ frame.add (widget)
+ return frame
+
+ vpaned = gtk.VPaned()
+ self.add (vpaned)
+
+ sv = self.create_text_view()
+ vpaned.pack1 (put_in_frame (sv), True, True)
+ sv.set_size_request (Width, int(Height/2))
+
+ hpaned = gtk.HPaned()
+ vpaned.pack2 (hpaned, True, False)
+
+ sl = self.create_snippet_list()
+ hpaned.pack1 (put_in_frame (sl), True, True)
+
+ hpaned.pack2 (put_in_frame (self.da), True, True)
+ self.da.set_size_request (int(Width/2), int(Height/2))
+
+ # set focus to snippet list
+ sl.get_child().grab_focus()
+
+
+ def da_expose_event (self, da, event, data=None):
+ x, y, width, height = da.allocation
+
+ cr = da.window.cairo_create()
+
+ try:
+ exec (self.snippet_str, globals(), locals())
+ except:
+ exc_type, exc_value = sys.exc_info()[:2]
+ print >> sys.stderr, exc_type, exc_value
+
+ return True
+
+
+ def create_text_view (self):
+ sw = gtk.ScrolledWindow()
+ sw.set_property ('shadow-type', gtk.SHADOW_IN)
+ sw.set_policy (hscrollbar_policy=gtk.POLICY_AUTOMATIC,
+ vscrollbar_policy=gtk.POLICY_AUTOMATIC)
+
+ text_view = gtk.TextView()
+ sw.add (text_view)
+ # set a fixed width font, so any tabs line up
+ text_view.modify_font(pango.FontDescription ("Fixed"))
+
+ self.text_buffer = text_view.get_buffer()
+
+ return sw
+
+
+ def cb_selection_changed (self, tselection, data=None):
+ model, iter = tselection.get_selected()
+ if iter:
+ filename = model[iter][0] + '.py'
+ try:
+ path = os.path.join(snippets_path, filename)
+ file_obj = open(path, 'r')
+ self.snippet_str = file_obj.read()
+ file_obj.close()
+ self.text_buffer.set_text(self.snippet_str)
+ except IOError, exc:
+ print "%s: %s" % (exc.filename, exc.strerror)
+
+ self._draw_pixmap = True
+ self.da.queue_draw()
+
+
+ def create_snippet_list (self):
+ sw = gtk.ScrolledWindow()
+ sw.set_property ('shadow-type', gtk.SHADOW_IN)
+ sw.set_policy (hscrollbar_policy=gtk.POLICY_NEVER,
+ vscrollbar_policy=gtk.POLICY_AUTOMATIC)
+
+ model = gtk.ListStore (str,)
+ for row in snip_list:
+ model.append (row=(row,))
+
+ tree_view = gtk.TreeView (model)
+ sw.add (tree_view)
+ tree_view.set_property ('headers-visible', False)
+ tree_view.set_property ('search-column', 0)
+ tree_view.set_property ('rules-hint', False)
+
+ tselection = tree_view.get_selection()
+ tselection.connect ("changed", self.cb_selection_changed)
+ tselection.set_mode (gtk.SELECTION_BROWSE)
+
+ cr = gtk.CellRendererText()
+ tvc = gtk.TreeViewColumn (None, cr, text=0)
+ tree_view.append_column (tvc)
+
+ tselection.select_path(0,) # select first item
+
+ return sw
+
+
+if __name__ == '__main__':
+ app = Window ()
+ app.connect('destroy', gtk.main_quit)
+ app.show_all()
+ gtk.main()
diff --git a/examples/cairo_snippets/snippets_pdf.py b/examples/cairo_snippets/snippets_pdf.py
new file mode 100755
index 0000000..0606804
--- /dev/null
+++ b/examples/cairo_snippets/snippets_pdf.py
@@ -0,0 +1,56 @@
+#!/usr/bin/env python
+"""Python version of cairo-demo/cairo_snippets/cairo_snippets_pdf.c
+create a file for each example rather than one large file for all examples
+"""
+
+from __future__ import division
+from math import pi as M_PI # used by many snippets
+import sys
+
+import cairo
+if not cairo.HAS_PDF_SURFACE:
+ raise SystemExit ('cairo was not compiled with PDF support')
+
+from snippets import snip_list, snippet_normalize
+
+
+width_in_inches, height_in_inches = 2, 2
+width_in_points, height_in_points = width_in_inches * 72, height_in_inches * 72
+width, height = width_in_points, height_in_points # used by snippet_normalize()
+
+
+def do_snippet (snippet):
+ if verbose_mode:
+ print 'processing %s' % snippet,
+
+ filename = 'snippets/%s.pdf' % snippet
+ surface = cairo.PDFSurface (filename, width_in_points, height_in_points)
+ cr = cairo.Context (surface)
+
+ cr.save()
+ try:
+ execfile ('snippets/%s.py' % snippet, globals(), locals())
+ except:
+ exc_type, exc_value = sys.exc_info()[:2]
+ print >> sys.stderr, exc_type, exc_value
+ else:
+ cr.restore()
+ cr.show_page()
+ surface.finish()
+
+ if verbose_mode:
+ print
+
+if __name__ == '__main__':
+ verbose_mode = True
+ if len(sys.argv) > 1 and sys.argv[1] == '-s':
+ verbose_mode = False
+ del sys.argv[1]
+
+ if len(sys.argv) > 1: # do specified snippets
+ snippet_list = sys.argv[1:]
+ else: # do all snippets
+ snippet_list = snip_list
+
+ for s in snippet_list:
+ do_snippet (s)
diff --git a/examples/cairo_snippets/snippets_png.py b/examples/cairo_snippets/snippets_png.py
new file mode 100755
index 0000000..5341979
--- /dev/null
+++ b/examples/cairo_snippets/snippets_png.py
@@ -0,0 +1,52 @@
+#!/usr/bin/env python
+"""Python version of cairo-demo/cairo_snippets/cairo_snippets_png.c
+"""
+
+from __future__ import division
+from math import pi as M_PI # used by many snippets
+import sys
+
+import cairo
+if not (cairo.HAS_IMAGE_SURFACE and cairo.HAS_PNG_FUNCTIONS):
+ raise SystemExit ('cairo was not compiled with ImageSurface and PNG support')
+
+from snippets import snip_list, snippet_normalize
+
+
+width, height = 256, 256 # used by snippet_normalize()
+
+
+def do_snippet (snippet):
+ if verbose_mode:
+ print 'processing %s' % snippet,
+
+ surface = cairo.ImageSurface (cairo.FORMAT_ARGB32, width, height)
+ cr = cairo.Context (surface)
+
+ cr.save()
+ try:
+ execfile ('snippets/%s.py' % snippet, globals(), locals())
+ except:
+# exc_type, exc_value = sys.exc_info()[:2]
+# print >> sys.stderr, exc_type, exc_value
+ raise
+ else:
+ cr.restore()
+ surface.write_to_png ('snippets/%s.png' % snippet)
+
+ if verbose_mode:
+ print
+
+if __name__ == '__main__':
+ verbose_mode = True
+ if len(sys.argv) > 1 and sys.argv[1] == '-s':
+ verbose_mode = False
+ del sys.argv[1]
+
+ if len(sys.argv) > 1: # do specified snippets
+ snippet_list = sys.argv[1:]
+ else: # do all snippets
+ snippet_list = snip_list
+
+ for s in snippet_list:
+ do_snippet (s)
diff --git a/examples/cairo_snippets/snippets_ps.py b/examples/cairo_snippets/snippets_ps.py
new file mode 100755
index 0000000..364402a
--- /dev/null
+++ b/examples/cairo_snippets/snippets_ps.py
@@ -0,0 +1,56 @@
+#!/usr/bin/env python
+"""Python version of cairo-demo/cairo_snippets/cairo_snippets_ps.c
+create a file for each example rather than one large file for all examples
+"""
+
+from __future__ import division
+from math import pi as M_PI # used by many snippets
+import sys
+
+import cairo
+if not cairo.HAS_PS_SURFACE:
+ raise SystemExit ('cairo was not compiled with PS support')
+
+from snippets import snip_list, snippet_normalize
+
+
+width_in_inches, height_in_inches = 2, 2
+width_in_points, height_in_points = width_in_inches * 72, height_in_inches * 72
+width, height = width_in_points, height_in_points # used by snippet_normalize()
+
+
+def do_snippet (snippet):
+ if verbose_mode:
+ print 'processing %s' % snippet,
+
+ filename = 'snippets/%s.ps' % snippet
+ surface = cairo.PSSurface (filename, width_in_points, height_in_points)
+ cr = cairo.Context (surface)
+
+ cr.save()
+ try:
+ execfile ('snippets/%s.py' % snippet, globals(), locals())
+ except:
+ exc_type, exc_value = sys.exc_info()[:2]
+ print >> sys.stderr, exc_type, exc_value
+ else:
+ cr.restore()
+ cr.show_page()
+ surface.finish()
+
+ if verbose_mode:
+ print
+
+if __name__ == '__main__':
+ verbose_mode = True
+ if len(sys.argv) > 1 and sys.argv[1] == '-s':
+ verbose_mode = False
+ del sys.argv[1]
+
+ if len(sys.argv) > 1: # do specified snippets
+ snippet_list = sys.argv[1:]
+ else: # do all snippets
+ snippet_list = snip_list
+
+ for s in snippet_list:
+ do_snippet (s)
diff --git a/examples/cairo_snippets/snippets_svg.py b/examples/cairo_snippets/snippets_svg.py
new file mode 100755
index 0000000..3620ee7
--- /dev/null
+++ b/examples/cairo_snippets/snippets_svg.py
@@ -0,0 +1,53 @@
+#!/usr/bin/env python
+
+from __future__ import division
+from math import pi as M_PI # used by many snippets
+import sys
+
+import cairo
+if not cairo.HAS_SVG_SURFACE:
+ raise SystemExit ('cairo was not compiled with SVG support')
+
+from snippets import snip_list, snippet_normalize
+
+
+width_in_inches, height_in_inches = 2, 2
+width_in_points, height_in_points = width_in_inches * 72, height_in_inches * 72
+width, height = width_in_points, height_in_points # used by snippet_normalize()
+
+
+def do_snippet (snippet):
+ if verbose_mode:
+ print 'processing %s' % snippet,
+
+ filename = 'snippets/%s.svg' % snippet
+ surface = cairo.SVGSurface (filename, width_in_points, height_in_points)
+ cr = cairo.Context (surface)
+
+ cr.save()
+ try:
+ execfile ('snippets/%s.py' % snippet, globals(), locals())
+ except:
+ exc_type, exc_value = sys.exc_info()[:2]
+ print >> sys.stderr, exc_type, exc_value
+ else:
+ cr.restore()
+ cr.show_page()
+ surface.finish()
+
+ if verbose_mode:
+ print
+
+if __name__ == '__main__':
+ verbose_mode = True
+ if len(sys.argv) > 1 and sys.argv[1] == '-s':
+ verbose_mode = False
+ del sys.argv[1]
+
+ if len(sys.argv) > 1: # do specified snippets
+ snippet_list = sys.argv[1:]
+ else: # do all snippets
+ snippet_list = snip_list
+
+ for s in snippet_list:
+ do_snippet (s)
diff --git a/examples/gradient.py b/examples/gradient.py
new file mode 100755
index 0000000..9ebbf76
--- /dev/null
+++ b/examples/gradient.py
@@ -0,0 +1,33 @@
+#!/usr/bin/env python
+"""/cairo-demo/cairo_snippets/gradient.cairo translated to Python
+"""
+
+import math
+import cairo
+
+WIDTH, HEIGHT = 256, 256
+
+surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, WIDTH, HEIGHT)
+ctx = cairo.Context(surface)
+
+ctx.scale (WIDTH/1.0, HEIGHT/1.0)
+
+pat = cairo.LinearGradient (0.0, 0.0, 0.0, 1.0)
+pat.add_color_stop_rgba (1, 0, 0, 0, 1)
+pat.add_color_stop_rgba (0, 1, 1, 1, 1)
+
+ctx.rectangle (0,0,1,1)
+ctx.set_source (pat)
+ctx.fill ()
+
+pat = cairo.RadialGradient (0.45, 0.4, 0.1,
+ 0.4, 0.4, 0.5)
+pat.add_color_stop_rgba (0, 1, 1, 1, 1)
+pat.add_color_stop_rgba (1, 0, 0, 0, 1)
+
+ctx.set_source (pat)
+ctx.arc (0.5, 0.5, 0.3, 0, 2 * math.pi)
+ctx.fill ()
+
+surface.write_to_png('gradient.png')
+#surface.write_to_png(10)
diff --git a/examples/gtk/cairo-demo.py b/examples/gtk/cairo-demo.py
new file mode 100755
index 0000000..76795ce
--- /dev/null
+++ b/examples/gtk/cairo-demo.py
@@ -0,0 +1,121 @@
+#!/usr/bin/env python
+"""Based on cairo-demo/X11/cairo-demo.c
+"""
+import cairo
+import gtk
+
+SIZE = 30
+
+def triangle(ctx):
+ ctx.move_to(SIZE, 0)
+ ctx.rel_line_to(SIZE, 2*SIZE)
+ ctx.rel_line_to(-2*SIZE, 0)
+ ctx.close_path()
+
+def square(ctx):
+ ctx.move_to(0, 0)
+ ctx.rel_line_to(2*SIZE, 0)
+ ctx.rel_line_to(0, 2*SIZE)
+ ctx.rel_line_to(-2*SIZE, 0)
+ ctx.close_path()
+
+def bowtie(ctx):
+ ctx.move_to(0, 0)
+ ctx.rel_line_to(2*SIZE, 2*SIZE)
+ ctx.rel_line_to(-2*SIZE, 0)
+ ctx.rel_line_to(2*SIZE, -2*SIZE)
+ ctx.close_path()
+
+def inf(ctx):
+ ctx.move_to(0, SIZE)
+ ctx.rel_curve_to(0,SIZE, SIZE,SIZE, 2*SIZE,0)
+ ctx.rel_curve_to(SIZE,-SIZE, 2*SIZE,-SIZE, 2*SIZE,0)
+ ctx.rel_curve_to(0,SIZE, -SIZE,SIZE, -2*SIZE,0)
+ ctx.rel_curve_to(-SIZE,-SIZE, -2*SIZE,-SIZE, -2*SIZE,0)
+ ctx.close_path()
+
+def draw_shapes(ctx, x, y, fill):
+ ctx.save()
+
+ ctx.new_path()
+ ctx.translate(x+SIZE, y+SIZE)
+ bowtie(ctx)
+ if fill:
+ ctx.fill()
+ else:
+ ctx.stroke()
+
+ ctx.new_path()
+ ctx.translate(3*SIZE, 0)
+ square(ctx)
+ if fill:
+ ctx.fill()
+ else:
+ ctx.stroke()
+
+ ctx.new_path()
+ ctx.translate(3*SIZE, 0)
+ triangle(ctx)
+ if fill:
+ ctx.fill()
+ else:
+ ctx.stroke()
+
+ ctx.new_path()
+ ctx.translate(3*SIZE, 0)
+ inf(ctx)
+ if fill:
+ ctx.fill()
+ else:
+ ctx.stroke()
+
+ ctx.restore()
+
+def fill_shapes(ctx, x, y):
+ draw_shapes(ctx, x, y, True)
+
+def stroke_shapes(ctx, x, y):
+ draw_shapes(ctx, x, y, False)
+
+def expose (da, event):
+ ctx = da.window.cairo_create()
+
+ ctx.set_source_rgb(0, 0, 0)
+
+ ctx.set_line_width(SIZE / 4)
+ ctx.set_tolerance(0.1)
+
+ ctx.set_line_join(cairo.LINE_JOIN_ROUND)
+ ctx.set_dash([SIZE/4.0, SIZE/4.0], 0)
+ stroke_shapes(ctx, 0, 0)
+
+ ctx.set_dash([], 0)
+ stroke_shapes(ctx, 0, 3*SIZE)
+
+ ctx.set_line_join(cairo.LINE_JOIN_BEVEL)
+ stroke_shapes(ctx, 0, 6*SIZE)
+
+ ctx.set_line_join(cairo.LINE_JOIN_MITER)
+ stroke_shapes(ctx, 0, 9*SIZE)
+
+ fill_shapes(ctx, 0, 12*SIZE)
+
+ ctx.set_line_join(cairo.LINE_JOIN_BEVEL)
+ fill_shapes(ctx, 0, 15*SIZE)
+ ctx.set_source_rgb(1,0,0)
+ stroke_shapes(ctx, 0, 15*SIZE)
+
+def main():
+ win = gtk.Window()
+ win.connect('destroy', gtk.main_quit)
+ win.set_default_size(450, 550)
+
+ drawingarea = gtk.DrawingArea()
+ win.add(drawingarea)
+ drawingarea.connect('expose_event', expose)
+
+ win.show_all()
+ gtk.main()
+
+if __name__ == '__main__':
+ main()
diff --git a/examples/gtk/cairo-knockout.py b/examples/gtk/cairo-knockout.py
new file mode 100755
index 0000000..e8c2c90
--- /dev/null
+++ b/examples/gtk/cairo-knockout.py
@@ -0,0 +1,128 @@
+#!/usr/bin/env python
+"""Based on gtk+/test/testcairo.c
+"""
+
+from __future__ import division
+import math
+import sys
+
+import cairo
+import gtk
+
+
+def oval_path(ctx, xc, yc, xr, yr):
+ ctx.save()
+
+ ctx.translate (xc, yc)
+ ctx.scale (1.0, yr / xr)
+ ctx.move_to (xr, 0.0)
+ ctx.arc (0, 0, xr, 0, 2 * math.pi)
+ ctx.close_path ()
+
+ ctx.restore()
+
+def fill_checks(ctx, x, y, width, height):
+ CHECK_SIZE = 32
+
+ ctx.rectangle (x, y, width, height)
+ ctx.set_source_rgb (0.4, 0.4, 0.4)
+ ctx.fill ()
+
+ # Only works for CHECK_SIZE a power of 2
+ for j in range (x & -CHECK_SIZE, height, CHECK_SIZE):
+ for i in range (y & -CHECK_SIZE, width, CHECK_SIZE):
+ if ((i / CHECK_SIZE + j / CHECK_SIZE) % 2 == 0):
+ ctx.rectangle (i, j, CHECK_SIZE, CHECK_SIZE)
+
+ ctx.set_source_rgb (0.7, 0.7, 0.7)
+ ctx.fill ()
+
+def draw_3circles(ctx, xc, yc, radius, alpha):
+ subradius = radius * (2 / 3. - 0.1)
+
+ ctx.set_source_rgba(1, 0, 0, alpha)
+ oval_path(ctx,
+ xc + radius / 3. * math.cos(math.pi * 0.5),
+ yc - radius / 3. * math.sin(math.pi * 0.5),
+ subradius, subradius)
+ ctx.fill()
+
+ ctx.set_source_rgba(0, 1, 0, alpha)
+ oval_path(ctx,
+ xc + radius / 3. * math.cos(math.pi * (0.5 + 2/.3)),
+ yc - radius / 3. * math.sin(math.pi * (0.5 + 2/.3)),
+ subradius, subradius)
+ ctx.fill()
+
+ ctx.set_source_rgba(0, 0, 1, alpha)
+ oval_path(ctx,
+ xc + radius / 3. * math.cos(math.pi * (0.5 + 4/.3)),
+ yc - radius / 3. * math.sin(math.pi * (0.5 + 4/.3)),
+ subradius, subradius)
+ ctx.fill()
+
+def draw (ctx, width, height):
+ radius = 0.5 * min(width, height) - 10
+ xc = width / 2.
+ yc = height / 2.
+
+ target = ctx.get_target()
+ overlay = target.create_similar(cairo.CONTENT_COLOR_ALPHA, width, height)
+ punch = target.create_similar(cairo.CONTENT_ALPHA, width, height)
+ circles = target.create_similar(cairo.CONTENT_COLOR_ALPHA, width, height)
+
+ fill_checks(ctx, 0, 0, width, height)
+
+ # Draw a black circle on the overlay
+ overlay_cr = cairo.Context (overlay)
+ overlay_cr.set_source_rgb (0, 0, 0)
+ oval_path (overlay_cr, xc, yc, radius, radius)
+ overlay_cr.fill()
+
+ # Draw 3 circles to the punch surface, then cut
+ # that out of the main circle in the overlay
+ punch_cr = cairo.Context (punch)
+ draw_3circles (punch_cr, xc, yc, radius, 1.0)
+
+ overlay_cr.set_operator (cairo.OPERATOR_DEST_OUT)
+ overlay_cr.set_source_surface (punch, 0, 0)
+ overlay_cr.paint()
+
+ # Now draw the 3 circles in a subgroup again
+ # at half intensity, and use OperatorAdd to join up
+ # without seams.
+ circles_cr = cairo.Context (circles)
+
+ circles_cr.set_operator (cairo.OPERATOR_OVER)
+ draw_3circles (circles_cr, xc, yc, radius, 0.5)
+
+ overlay_cr.set_operator (cairo.OPERATOR_ADD)
+ overlay_cr.set_source_surface (circles, 0, 0)
+ overlay_cr.paint()
+
+ ctx.set_source_surface (overlay, 0, 0)
+ ctx.paint()
+
+def expose(drawingarea, event):
+ ctx = drawingarea.window.cairo_create()
+
+ _, _, width, height = drawingarea.allocation
+ draw (ctx, width, height)
+
+ return False
+
+def main():
+ win = gtk.Window()
+ win.connect('destroy', gtk.main_quit)
+ win.set_title('Knockout Groups')
+ win.set_default_size(400, 400)
+
+ drawingarea = gtk.DrawingArea()
+ win.add(drawingarea)
+ drawingarea.connect('expose_event', expose)
+
+ win.show_all()
+ gtk.main()
+
+if __name__ == '__main__':
+ main()
diff --git a/examples/gtk/hangman.py b/examples/gtk/hangman.py
new file mode 100755
index 0000000..8aa16ce
--- /dev/null
+++ b/examples/gtk/hangman.py
@@ -0,0 +1,257 @@
+#!/usr/bin/env python
+# -*- coding: iso8859-1 -*-
+#
+# Copyright © 2004 Kevin Worth
+#
+# 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 Kevin Worth not
+# be used in advertising or publicity pertaining to distribution of
+# the software without specific, written prior permission. Kevin Worth
+# California makes no representations about the suitability of this
+# software for any purpose. It is provided "as is" without express or
+# implied warranty.
+#
+# KEVIN WORTH DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+# INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+# NO EVENT SHALL KEVIN WORTH 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: Kevin Worth <kevin@theworths.org>
+
+from math import pi
+from random import randint
+
+import cairo
+import gtk
+
+letters_guessed = ""
+letters_guessed_right = ""
+letters_guessed_wrong = ""
+
+body_parts = 6
+words = ['cairo', 'graphics', 'pencil', 'keyboard', 'science', 'ricochet', 'flood', 'president', 'sanity']
+
+idxRandom = randint(0, len(words) -1)
+word_chosen = words[idxRandom]
+
+#print "The secret word is " + word_chosen
+
+def guess_letter(widget, event):
+ global letters_guessed, letters_guessed_right, letters_guessed_wrong
+ if event.string in letters_guessed:
+ print "What?!?! You already guessed '" + event.string + "'!"
+ else:
+ letters_guessed += event.string
+ if word_chosen.lower().find(event.string) != -1:
+ letters_guessed_right += event.string
+ else:
+ letters_guessed_wrong += event.string
+ widget.queue_draw()
+
+def expose_event(widget, event):
+ _, _, width, height = widget.allocation
+
+ if width < height:
+ size = width
+ else:
+ size = height
+
+ pixmap = gtk.gdk.Pixmap (widget.window, width, height)
+ ctx = pixmap.cairo_create()
+
+ # set the background
+ ctx.set_source_rgb(0.7,0.7,0.7)
+ ctx.set_operator (cairo.OPERATOR_SOURCE)
+ ctx.paint()
+
+ ctx.translate ((width - size) / 2, (height - size) / 2)
+ ctx.scale(size / 150.0, size / 160.0)
+
+ def man_hung():
+ return len(letters_guessed_wrong) == body_parts
+
+ ctx.set_font_size(10)
+ ctx.set_source_rgb(0,0,0)
+ for idxLetter in range(len(word_chosen)):
+ #print "Examining letter: " + word_chosen[idxLetter]
+ if word_chosen[idxLetter].lower() in letters_guessed_right or man_hung():
+ if idxLetter == 0:
+ ctx.move_to(0, 150)
+ ctx.show_text(word_chosen[idxLetter].upper())
+ else:
+ ctx.move_to(idxLetter * 15, 150)
+ ctx.show_text(word_chosen[idxLetter].lower())
+ else:
+ ctx.move_to(idxLetter * 15, 150)
+ ctx.show_text('_')
+
+ # Draw Letters Guessed
+
+ ctx.move_to(0, 160)
+ ctx.set_source_rgb(0, 0, 0)
+ ctx.show_text(letters_guessed)
+
+ # Draw noose
+
+ ctx.move_to(100, 12.5)
+ ctx.line_to(100, 5)
+ ctx.line_to(130, 5)
+ ctx.line_to(130, 100)
+ ctx.set_source_rgb(0, 0, 0)
+ ctx.stroke()
+
+ # Draw base fill color
+
+ ctx.move_to(130, 100)
+ ctx.line_to(130, 140)
+ ctx.line_to(40, 140)
+ ctx.line_to(40, 130)
+ ctx.line_to(50, 130)
+ ctx.line_to(50, 122)
+ ctx.line_to(60, 122)
+ ctx.line_to(60, 114)
+ ctx.line_to(70, 114)
+ ctx.line_to(70, 106)
+ ctx.line_to(130, 106)
+ ctx.set_source_rgb(.4, .2, .1)
+ ctx.fill()
+
+ # Draw base outline color
+
+ ctx.move_to(130, 100)
+ ctx.line_to(130, 140)
+ ctx.line_to(40, 140)
+
+ # Draw 1st(lowest) stair
+
+ ctx.line_to(40, 130)
+ ctx.line_to(50, 130)
+ ctx.line_to(130, 130)
+ ctx.set_source_rgb(0, 0, 0)
+ ctx.stroke()
+
+ # Draw 2nd stair
+
+ ctx.move_to(50, 130)
+ ctx.line_to(50, 121)
+ ctx.line_to(60, 121)
+ ctx.line_to(130, 121)
+ ctx.stroke()
+
+ # Draw 3rd stair
+
+ ctx.move_to(60, 121)
+ ctx.line_to(60, 113)
+ ctx.line_to(70, 113)
+ ctx.line_to(130, 113)
+ ctx.stroke()
+
+ # Draw 4th(top) stair
+
+ ctx.move_to(70, 113)
+ ctx.line_to(70, 105)
+ ctx.line_to(130, 105)
+ ctx.stroke()
+
+ # Draw Head
+
+ if len(letters_guessed_wrong) > 0:
+ ctx.move_to(107.5, 20)
+ ctx.arc(100, 20, 7.5, 0, 2*pi)
+ ctx.set_line_width(1)
+ ctx.stroke()
+
+ # Draw Eye 1
+
+ ctx.move_to(104, 17)
+ ctx.arc(103, 17, 1, 0, 2*pi)
+ ctx.move_to(103.1, 17)
+ ctx.arc(103, 17, .1, 0, 2*pi)
+
+ # Draw Eye 2
+
+ ctx.move_to(98, 17)
+ ctx.arc(97, 17, 1, 0, 2*pi)
+ ctx.move_to(97.1, 17)
+ ctx.arc(97, 17, .1, 0, 2*pi)
+
+ # Draw Nose
+
+ ctx.move_to(100.5, 19)
+ ctx.line_to(99.5, 21)
+ ctx.line_to(100.5, 21)
+
+ # Draw Mouth
+
+ if len(letters_guessed_wrong) < 6:
+ ctx.move_to(97, 23)
+ ctx.curve_to(97, 23, 100, 27.5, 103, 23)
+ ctx.set_line_width(.5)
+ ctx.stroke()
+ else:
+ ctx.move_to(100.5, 24)
+ ctx.arc(100, 24, .5, 0, 2*pi)
+ ctx.set_line_width(.5)
+ ctx.stroke()
+
+ ctx.set_source_rgb(0, 0, 0)
+ ctx.set_line_width(1)
+
+ # Draw Body
+
+ if len(letters_guessed_wrong) > 1:
+ ctx.move_to(100, 27.5)
+ ctx.line_to(100, 70)
+ ctx.stroke()
+
+ # Draw Arm 1
+
+ if len(letters_guessed_wrong) > 2:
+ ctx.move_to(100, 35)
+ ctx.line_to(110, 50)
+ ctx.stroke()
+
+ # Draw Arm 2
+
+ if len(letters_guessed_wrong) > 3:
+ ctx.move_to(100, 35)
+ ctx.line_to(90, 50)
+ ctx.stroke()
+
+ # Draw Leg 1
+
+ if len(letters_guessed_wrong) > 4:
+ ctx.move_to(100, 70)
+ ctx.line_to(112, 95)
+ ctx.stroke()
+
+ # Draw Leg 2
+
+ if len(letters_guessed_wrong) > 5:
+ ctx.move_to(100, 70)
+ ctx.line_to(88, 95)
+ ctx.stroke()
+
+ # draw pixmap to gdk.window
+ gc = gtk.gdk.GC(widget.window)
+ widget.window.draw_drawable(gc, pixmap, 0,0, 0,0, -1,-1)
+
+
+win = gtk.Window()
+win.connect('destroy', gtk.main_quit)
+win.connect('key_press_event', guess_letter)
+win.set_title('Kevin\'s cairo demo')
+
+drawingarea = gtk.DrawingArea()
+win.add(drawingarea)
+drawingarea.connect('expose_event', expose_event)
+drawingarea.set_size_request(300,320)
+
+win.show_all()
+gtk.main()
diff --git a/examples/gtk/lsystem.py b/examples/gtk/lsystem.py
new file mode 100755
index 0000000..e08c8dc
--- /dev/null
+++ b/examples/gtk/lsystem.py
@@ -0,0 +1,123 @@
+#!/usr/bin/env python
+
+import cairo
+import gtk
+
+# Copyright 2003 Jesse Andrews (jdandr2@uky.edu) under GPL
+
+
+class lindenmayer:
+ def __init__( self ):
+ self.str = ''
+ self.prod = {'[':'[','f':'f',']':']','+':'+','-':'-'}
+ self.SIZE = 10
+ self.THETA = 90
+
+ def addProd( self, let, pro ):
+ self.prod[let]=pro
+
+ def iterate( self, qty=1 ):
+ for i in xrange(qty):
+ self.str = ''.join([ self.prod[l] for l in self.str])
+ print 'Done iterating'
+
+ def expose( self, drawingarea, event ):
+ drawable = drawingarea.window
+ x, y, width, height = drawingarea.allocation
+
+ ctx = drawable.cairo_create()
+ ctx.set_source_rgb(0, 0, 0)
+
+ ctx.set_line_width(self.SIZE / 4)
+ ctx.set_tolerance(0.1)
+ ctx.set_line_join(cairo.LINE_JOIN_BEVEL)
+
+ ctx.new_path()
+ ctx.move_to(100,100)
+
+ for c in self.str:
+ if c == 'f': line(ctx, self.SIZE )
+ if c == '+': rotate( ctx, +self.THETA )
+ if c == '-': rotate( ctx, -self.THETA )
+ if c == '[': ctx.save()
+ if c == ']': ctx.restore()
+
+ ctx.stroke()
+
+def line(ctx, len):
+ ctx.rel_line_to( 0, len )
+
+def rotate(ctx, deg):
+ ctx.rotate( 2*3.141592653589793*deg/360.0 )
+
+def lin_setup():
+ cls = lindenmayer()
+ ################# SETUP LSYSTEM HERE ################
+
+ ### Generic stuff ###
+
+ cls.str = 'f' # the starting string
+
+ cls.SIZE = 5 # length of a line
+
+ ##############################################
+ ##############################################
+ #### Uncomment the one you want to use... ####
+ #### only one at a time right now! ####
+ ##############################################
+ ##############################################
+
+ ###### Kock Square Curve #######
+ cls.addProd('f','f-f+f+f-f')
+ cls.THETA = 90
+
+ ###### Kock Snowflake ######
+
+# cls.addProd('f','f-f++f-f')
+# cls.THETA = 60
+
+ ######## Peano Curve ########
+# cls.addProd('x', 'xfyfx+f+yfxfy-f-xfyfx')
+# cls.addProd('y', 'yfxfy-f-xfyfx+f+yfxfy')
+# cls.addProd('f', 'f')
+# cls.THETA = 90
+# cls.str = 'y'
+
+ ###### the plant ######
+ ## doesn't seem to work ... .save & .restore messed up ##
+
+# cls.addProd( 'f','f[+f]f[-f]f' )
+# cls.THETA = 25
+
+ ####### the tree #########
+ ## doesn't seem to work ... .save & .restore messed up ##
+
+# cls.addProd( 'f', 'ff+[+f-f-f]-[-f+f+f]' )
+# cls.THETA = 22
+
+
+ ### times to iterate string rewriting ###
+ #this grows QUICKLY, so start only inc by 1 each run!
+ cls.iterate(4)
+
+ ################ DONE SETUP ###############
+ return cls
+
+def main():
+ win = gtk.Window()
+ win.connect('destroy', lambda x: gtk.main_quit())
+ win.set_title('cairo Lindenmayer System')
+ win.set_default_size(600, 600)
+
+ cls = lin_setup()
+
+ drawingarea = gtk.DrawingArea()
+ win.add(drawingarea)
+ drawingarea.connect('expose_event', cls.expose)
+
+ win.show_all()
+ gtk.main()
+
+if __name__ == '__main__':
+ main()
+
diff --git a/examples/gtk/png_view.py b/examples/gtk/png_view.py
new file mode 100755
index 0000000..1100c75
--- /dev/null
+++ b/examples/gtk/png_view.py
@@ -0,0 +1,35 @@
+#!/usr/bin/env python
+"""Display a png file
+"""
+
+import sys
+
+import cairo
+import gtk
+
+
+def expose_event(widget, event, surface):
+ ctx = widget.window.cairo_create()
+ ctx.set_source_surface(surface, 0,0)
+ ctx.paint()
+
+
+if len(sys.argv) != 2:
+ raise SystemExit('usage: png_view.py png_file')
+
+filename = sys.argv[1]
+
+surface = cairo.ImageSurface.create_from_png(filename)
+Width = surface.get_width()
+Height = surface.get_height()
+
+win = gtk.Window()
+win.connect('destroy', gtk.main_quit)
+
+drawingarea = gtk.DrawingArea()
+win.add(drawingarea)
+drawingarea.connect('expose_event', expose_event, surface)
+drawingarea.set_size_request(Width,Height)
+
+win.show_all()
+gtk.main()
diff --git a/examples/gtk/text.py b/examples/gtk/text.py
new file mode 100755
index 0000000..2bef98b
--- /dev/null
+++ b/examples/gtk/text.py
@@ -0,0 +1,41 @@
+#!/usr/bin/env python
+
+import cairo
+import gtk
+
+
+def expose_event(widget, event):
+ ctx = widget.window.cairo_create()
+
+ ctx.set_line_width(6)
+ ctx.set_tolerance(.1)
+
+ ctx.select_font_face('sans-serif')
+ ctx.set_font_size(48)
+ (x, y, width, height, dx, dy) = ctx.text_extents('Hello World')
+
+ ctx.translate (100, 100)
+
+ ctx.new_path()
+ ctx.move_to(x-10,y-10)
+ ctx.rel_line_to(width + 20, 0)
+ ctx.rel_line_to(0, height + 20)
+ ctx.rel_line_to(-(width + 20), 0)
+ ctx.close_path()
+ ctx.set_source_rgb(0,0,1)
+ ctx.stroke()
+
+ ctx.move_to(0, 0)
+ ctx.set_source_rgb(0,0,0)
+ ctx.show_text('Hello World')
+
+win = gtk.Window()
+win.connect('destroy', gtk.main_quit)
+
+drawingarea = gtk.DrawingArea()
+win.add(drawingarea)
+drawingarea.connect('expose_event', expose_event)
+drawingarea.set_size_request(400,150)
+
+win.show_all()
+gtk.main()
diff --git a/examples/hering.py b/examples/hering.py
new file mode 100755
index 0000000..e400e15
--- /dev/null
+++ b/examples/hering.py
@@ -0,0 +1,55 @@
+#!/usr/bin/env python
+"""cairo/cairo-demo/png/hering.c translated into Python
+"""
+
+import math
+
+import cairo
+
+WIDTH = 300
+HEIGHT = 600
+
+def draw_hering (ctx, width, height):
+ LINES= 32
+ MAX_THETA = .80 * math.pi * 2
+ THETA_INC = 2.0 * MAX_THETA / (LINES-1)
+
+ ctx.set_source_rgb (0, 0, 0)
+ ctx.set_line_width (2.0)
+
+ ctx.save()
+
+ ctx.translate (width / 2, height / 2)
+ ctx.rotate (MAX_THETA)
+
+ for i in range (LINES):
+ ctx.move_to (-2 * width, 0)
+ ctx.line_to (2 * width, 0)
+ ctx.stroke()
+
+ ctx.rotate (- THETA_INC)
+
+ ctx.restore()
+
+ ctx.set_line_width (6)
+ ctx.set_source_rgb (1, 0, 0)
+
+ ctx.move_to (width / 4.0, 0)
+ ctx.rel_line_to (0, height)
+ ctx.stroke()
+
+ ctx.move_to (3 * width / 4.0, 0)
+ ctx.rel_line_to (0, height)
+ ctx.stroke()
+
+
+surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, WIDTH, HEIGHT)
+ctx = cairo.Context(surface)
+
+ctx.set_source_rgb (1, 1, 1)
+ctx.set_operator (cairo.OPERATOR_SOURCE)
+ctx.paint()
+
+draw_hering (ctx, WIDTH, HEIGHT)
+
+surface.write_to_png('hering.png')
diff --git a/examples/spiral.py b/examples/spiral.py
new file mode 100755
index 0000000..7be9af2
--- /dev/null
+++ b/examples/spiral.py
@@ -0,0 +1,36 @@
+#!/usr/bin/env python
+"""cairo/cairo-demo/png/spiral.c translated into Python
+"""
+
+import cairo
+
+WIDTH, HEIGHT = 600, 600
+
+def draw_spiral (ctx, width, height):
+ wd = .02 * width
+ hd = .02 * height
+
+ width -= 2
+ height -= 2
+
+ ctx.move_to (width + 1, 1-hd)
+ for i in range(9):
+ ctx.rel_line_to (0, height - hd * (2 * i - 1))
+ ctx.rel_line_to (- (width - wd * (2 *i)), 0)
+ ctx.rel_line_to (0, - (height - hd * (2*i)))
+ ctx.rel_line_to (width - wd * (2 * i + 1), 0)
+
+ ctx.set_source_rgb (0, 0, 1)
+ ctx.stroke()
+
+
+surface = cairo.ImageSurface (cairo.FORMAT_ARGB32, WIDTH, HEIGHT)
+ctx = cairo.Context(surface)
+
+ctx.set_source_rgb (1, 1, 1)
+ctx.set_operator (cairo.OPERATOR_SOURCE)
+ctx.paint()
+
+draw_spiral (ctx, WIDTH, HEIGHT)
+
+surface.write_to_png('spiral.png')
diff --git a/examples/warpedtext.py b/examples/warpedtext.py
new file mode 100755
index 0000000..cd83ee7
--- /dev/null
+++ b/examples/warpedtext.py
@@ -0,0 +1,85 @@
+#!/usr/bin/env python
+
+import cairo
+import math
+
+def warpPath(ctx, function):
+ first = True
+
+ for type, points in ctx.copy_path():
+ if type == cairo.PATH_MOVE_TO:
+ if first:
+ ctx.new_path()
+ first = False
+ x, y = function(*points)
+ ctx.move_to(x, y)
+
+ elif type == cairo.PATH_LINE_TO:
+ x, y = function(*points)
+ ctx.line_to(x, y)
+
+ elif type == cairo.PATH_CURVE_TO:
+ x1, y1, x2, y2, x3, y3 = points
+ x1, y1 = function(x1, y1)
+ x2, y2 = function(x2, y2)
+ x3, y3 = function(x3, y3)
+ ctx.curve_to(x1, y1, x2, y2, x3, y3)
+
+ elif type == cairo.PATH_CLOSE_PATH:
+ ctx.close_path()
+
+def spiral(x, y):
+ theta0 = -math.pi * 3 / 4
+ theta = x / Width * math.pi * 2 + theta0
+ radius = y + 200 - x/7
+ xnew = radius*math.cos(theta)
+ ynew = radius*math.sin(-theta)
+ return xnew + Width/2, ynew + Height/2
+
+def curl(x, y):
+ xn = x - Textwidth/2
+ #yn = y - Textheight/2
+ xnew = xn
+ ynew = y + xn ** 3 / ((Textwidth/2)**3) * 70
+ return xnew + Width/2, ynew + Height*2/5
+
+
+Width, Height = 512, 512
+surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, Width, Height)
+ctx = cairo.Context(surface)
+solidpattern = ctx.get_source()
+
+# background
+pat = cairo.LinearGradient (0.0, 0.0, 0, Height)
+pat.add_color_stop_rgba (1, 0, 0, 0, 1)
+pat.add_color_stop_rgba (0, 1, 1, 1, 1)
+
+ctx.rectangle (0,0,Width,Height)
+ctx.set_source (pat)
+ctx.fill ()
+
+# foreground
+ctx.set_source (solidpattern)
+ctx.set_source_rgb (1,1,1)
+
+ctx.select_font_face("Sans")
+ctx.set_font_size(80)
+
+# spiral text
+ctx.new_path()
+ctx.move_to(0, 0)
+ctx.text_path("pycairo - " + "spam " * 5)
+warpPath(ctx, spiral)
+ctx.fill()
+
+# curly text
+ctx.new_path()
+ctx.move_to(0, 0)
+ctx.set_source_rgb(0.3, 0.3, 0.3)
+text = "I am curly :)"
+ctx.text_path(text)
+Textwidth, Textheight = ctx.text_extents(text)[2:4]
+warpPath(ctx, curl)
+ctx.fill()
+
+surface.write_to_png("warpedtext.png")
diff --git a/py3cairo-uninstalled.pc.in b/py3cairo-uninstalled.pc.in
new file mode 100644
index 0000000..dbe9a39
--- /dev/null
+++ b/py3cairo-uninstalled.pc.in
@@ -0,0 +1,8 @@
+prefix=@prefix@
+
+Name: Pycairo
+Description: Python bindings for cairo
+Version: @VERSION@
+Requires: cairo
+Cflags: -I@includedir@/pycairo
+Libs:
diff --git a/py3cairo.pc.in b/py3cairo.pc.in
new file mode 100644
index 0000000..dbe9a39
--- /dev/null
+++ b/py3cairo.pc.in
@@ -0,0 +1,8 @@
+prefix=@prefix@
+
+Name: Pycairo
+Description: Python bindings for cairo
+Version: @VERSION@
+Requires: cairo
+Cflags: -I@includedir@/pycairo
+Libs:
diff --git a/src/.gitignore b/src/.gitignore
new file mode 100644
index 0000000..52e4e61
--- /dev/null
+++ b/src/.gitignore
@@ -0,0 +1,2 @@
+*.pyc
+*.pyo
diff --git a/src/__init__.py b/src/__init__.py
new file mode 100755
index 0000000..85e07e2
--- /dev/null
+++ b/src/__init__.py
@@ -0,0 +1,18 @@
+'''
+Copyright © 2003,2010 James Henstridge, Steven Chaplin
+
+This file is part of pycairo.
+
+Pycairo is free software: you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License version 3 as published
+by the Free Software Foundation.
+
+Pycairo is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with pycairo. If not, see <http://www.gnu.org/licenses/>.
+'''
+from _cairo import *
diff --git a/src/cairomodule.c b/src/cairomodule.c
new file mode 100644
index 0000000..02da659
--- /dev/null
+++ b/src/cairomodule.c
@@ -0,0 +1,496 @@
+/* -*- mode: C; c-basic-offset: 2 -*-
+ *
+ * Copyright © 2003,2010 James Henstridge, Steven Chaplin
+ *
+ * This file is part of pycairo.
+ *
+ * Pycairo is free software: you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License version 3 as published
+ * by the Free Software Foundation.
+ *
+ * Pycairo is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with pycairo. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define PY_SSIZE_T_CLEAN
+#include <Python.h>
+
+#include "config.h"
+#include "private.h"
+
+/* to read CAIRO_PS_LEVEL_* constants */
+#ifdef CAIRO_HAS_PS_SURFACE
+# include <cairo-ps.h>
+#endif
+
+/* for XCB api */
+#if defined(CAIRO_HAS_XCB_SURFACE) && defined(HAVE_XPYB)
+xpyb_CAPI_t *xpyb_CAPI;
+PyObject *xpybVISUALTYPE_type;
+#endif
+
+/* A module specific exception */
+PyObject *CairoError = NULL;
+
+int
+Pycairo_Check_Status (cairo_status_t status) {
+ if (PyErr_Occurred() != NULL)
+ return 1;
+
+ switch (status) {
+ case CAIRO_STATUS_SUCCESS:
+ return 0;
+ /* if appropriate - translate the status string into Python,
+ * else - use cairo_status_to_string()
+ */
+ case CAIRO_STATUS_NO_MEMORY:
+ PyErr_NoMemory();
+ break;
+ case CAIRO_STATUS_READ_ERROR:
+ case CAIRO_STATUS_WRITE_ERROR:
+ PyErr_SetString(PyExc_IOError, cairo_status_to_string (status));
+ break;
+ case CAIRO_STATUS_INVALID_RESTORE:
+ PyErr_SetString(CairoError, "Context.restore without matching "
+ "Context.save");
+ break;
+ case CAIRO_STATUS_INVALID_POP_GROUP:
+ PyErr_SetString(CairoError, "Context.pop_group without matching "
+ "Context.push_group");
+ break;
+ default:
+ PyErr_SetString(CairoError, cairo_status_to_string (status));
+ }
+ return 1;
+}
+
+
+/* C API. Clients get at this via Pycairo_IMPORT, defined in pycairo.h.
+ */
+static Pycairo_CAPI_t CAPI = {
+ &PycairoContext_Type,
+ PycairoContext_FromContext,
+
+ &PycairoFontFace_Type,
+ &PycairoToyFontFace_Type,
+ PycairoFontFace_FromFontFace,
+
+ &PycairoFontOptions_Type,
+ PycairoFontOptions_FromFontOptions,
+
+ &PycairoMatrix_Type,
+ PycairoMatrix_FromMatrix,
+
+ &PycairoPath_Type,
+ PycairoPath_FromPath,
+
+ &PycairoPattern_Type,
+ &PycairoSolidPattern_Type,
+ &PycairoSurfacePattern_Type,
+ &PycairoGradient_Type,
+ &PycairoLinearGradient_Type,
+ &PycairoRadialGradient_Type,
+ PycairoPattern_FromPattern,
+
+ &PycairoScaledFont_Type,
+ PycairoScaledFont_FromScaledFont,
+
+ &PycairoSurface_Type,
+#ifdef CAIRO_HAS_IMAGE_SURFACE
+ &PycairoImageSurface_Type,
+#else
+ 0,
+#endif
+#ifdef CAIRO_HAS_PDF_SURFACE
+ &PycairoPDFSurface_Type,
+#else
+ 0,
+#endif
+#ifdef CAIRO_HAS_PS_SURFACE
+ &PycairoPSSurface_Type,
+#else
+ 0,
+#endif
+#ifdef CAIRO_HAS_SVG_SURFACE
+ &PycairoSVGSurface_Type,
+#else
+ 0,
+#endif
+#ifdef CAIRO_HAS_WIN32_SURFACE
+ &PycairoWin32Surface_Type,
+ &PycairoWin32PrintingSurface_Type,
+#else
+ 0,
+ 0,
+#endif
+#ifdef CAIRO_HAS_XCB_SURFACE
+ &PycairoXCBSurface_Type,
+#else
+ 0,
+#endif
+#ifdef CAIRO_HAS_XLIB_SURFACE
+ &PycairoXlibSurface_Type,
+#else
+ 0,
+#endif
+ PycairoSurface_FromSurface,
+
+ Pycairo_Check_Status,
+};
+
+static PyObject *
+pycairo_cairo_version (PyObject *self) {
+ return PyInt_FromLong (cairo_version());
+}
+
+static PyObject *
+pycairo_cairo_version_string (PyObject *self) {
+ return PyString_FromString (cairo_version_string());
+}
+
+static PyMethodDef cairo_functions[] = {
+ {"cairo_version", (PyCFunction)pycairo_cairo_version, METH_NOARGS},
+ {"cairo_version_string", (PyCFunction)pycairo_cairo_version_string,
+ METH_NOARGS},
+ {NULL, NULL, 0, NULL},
+};
+
+
+DL_EXPORT(void)
+init_cairo(void)
+{
+ PyObject *m;
+
+ if (PyType_Ready(&PycairoContext_Type) < 0)
+ return;
+ if (PyType_Ready(&PycairoFontFace_Type) < 0)
+ return;
+ if (PyType_Ready(&PycairoToyFontFace_Type) < 0)
+ return;
+ if (PyType_Ready(&PycairoFontOptions_Type) < 0)
+ return;
+ if (PyType_Ready(&PycairoMatrix_Type) < 0)
+ return;
+ if (PyType_Ready(&PycairoPath_Type) < 0)
+ return;
+ PycairoPathiter_Type.tp_iter=&PyObject_SelfIter;
+ if (PyType_Ready(&PycairoPathiter_Type) < 0)
+ return;
+
+ if (PyType_Ready(&PycairoPattern_Type) < 0)
+ return;
+ if (PyType_Ready(&PycairoSolidPattern_Type) < 0)
+ return;
+ if (PyType_Ready(&PycairoSurfacePattern_Type) < 0)
+ return;
+ if (PyType_Ready(&PycairoGradient_Type) < 0)
+ return;
+ if (PyType_Ready(&PycairoLinearGradient_Type) < 0)
+ return;
+ if (PyType_Ready(&PycairoRadialGradient_Type) < 0)
+ return;
+
+ if (PyType_Ready(&PycairoScaledFont_Type) < 0)
+ return;
+
+ if (PyType_Ready(&PycairoSurface_Type) < 0)
+ return;
+#ifdef CAIRO_HAS_IMAGE_SURFACE
+ if (PyType_Ready(&PycairoImageSurface_Type) < 0)
+ return;
+#endif
+#ifdef CAIRO_HAS_PDF_SURFACE
+ if (PyType_Ready(&PycairoPDFSurface_Type) < 0)
+ return;
+#endif
+#ifdef CAIRO_HAS_PS_SURFACE
+ if (PyType_Ready(&PycairoPSSurface_Type) < 0)
+ return;
+#endif
+#ifdef CAIRO_HAS_SVG_SURFACE
+ if (PyType_Ready(&PycairoSVGSurface_Type) < 0)
+ return;
+#endif
+#ifdef CAIRO_HAS_WIN32_SURFACE
+ if (PyType_Ready(&PycairoWin32Surface_Type) < 0)
+ return;
+ if (PyType_Ready(&PycairoWin32PrintingSurface_Type) < 0)
+ return;
+#endif
+#ifdef CAIRO_HAS_XCB_SURFACE
+ if (PyType_Ready(&PycairoXCBSurface_Type) < 0)
+ return;
+#endif
+#ifdef CAIRO_HAS_XLIB_SURFACE
+ if (PyType_Ready(&PycairoXlibSurface_Type) < 0)
+ return;
+#endif
+
+ m = Py_InitModule("cairo._cairo", cairo_functions);
+
+ PyModule_AddStringConstant(m, "version", VERSION);
+ PyModule_AddObject(m, "version_info",
+ Py_BuildValue("(iii)",
+ PYCAIRO_VERSION_MAJOR,
+ PYCAIRO_VERSION_MINOR,
+ PYCAIRO_VERSION_MICRO
+ ));
+
+ Py_INCREF(&PycairoContext_Type);
+ PyModule_AddObject(m, "Context", (PyObject *)&PycairoContext_Type);
+ Py_INCREF(&PycairoFontFace_Type);
+ PyModule_AddObject(m, "FontFace",(PyObject *)&PycairoFontFace_Type);
+ Py_INCREF(&PycairoToyFontFace_Type);
+ PyModule_AddObject(m, "ToyFontFace",(PyObject *)&PycairoToyFontFace_Type);
+ Py_INCREF(&PycairoFontOptions_Type);
+ PyModule_AddObject(m, "FontOptions",(PyObject *)&PycairoFontOptions_Type);
+ Py_INCREF(&PycairoMatrix_Type);
+ PyModule_AddObject(m, "Matrix", (PyObject *)&PycairoMatrix_Type);
+ Py_INCREF(&PycairoPath_Type);
+ /* Don't add Path object since it is not accessed directly as 'cairo.Path'
+ * PyModule_AddObject(m, "Path", (PyObject *)&PycairoPath_Type);
+ */
+ Py_INCREF(&PycairoPattern_Type);
+ PyModule_AddObject(m, "Pattern", (PyObject *)&PycairoPattern_Type);
+ Py_INCREF(&PycairoSolidPattern_Type);
+ PyModule_AddObject(m, "SolidPattern",
+ (PyObject *)&PycairoSolidPattern_Type);
+ Py_INCREF(&PycairoSurfacePattern_Type);
+ PyModule_AddObject(m, "SurfacePattern",
+ (PyObject *)&PycairoSurfacePattern_Type);
+ Py_INCREF(&PycairoGradient_Type);
+ PyModule_AddObject(m, "Gradient", (PyObject *)&PycairoGradient_Type);
+ Py_INCREF(&PycairoLinearGradient_Type);
+ PyModule_AddObject(m, "LinearGradient",
+ (PyObject *)&PycairoLinearGradient_Type);
+ Py_INCREF(&PycairoRadialGradient_Type);
+ PyModule_AddObject(m, "RadialGradient",
+ (PyObject *)&PycairoRadialGradient_Type);
+
+ Py_INCREF(&PycairoScaledFont_Type);
+ PyModule_AddObject(m, "ScaledFont", (PyObject *)&PycairoScaledFont_Type);
+
+ Py_INCREF(&PycairoSurface_Type);
+ PyModule_AddObject(m, "Surface", (PyObject *)&PycairoSurface_Type);
+
+#ifdef CAIRO_HAS_IMAGE_SURFACE
+ Py_INCREF(&PycairoImageSurface_Type);
+ PyModule_AddObject(m, "ImageSurface",
+ (PyObject *)&PycairoImageSurface_Type);
+#endif
+
+#ifdef CAIRO_HAS_PDF_SURFACE
+ Py_INCREF(&PycairoPDFSurface_Type);
+ PyModule_AddObject(m, "PDFSurface", (PyObject *)&PycairoPDFSurface_Type);
+#endif
+
+#ifdef CAIRO_HAS_PS_SURFACE
+ Py_INCREF(&PycairoPSSurface_Type);
+ PyModule_AddObject(m, "PSSurface", (PyObject *)&PycairoPSSurface_Type);
+#endif
+
+#ifdef CAIRO_HAS_SVG_SURFACE
+ Py_INCREF(&PycairoSVGSurface_Type);
+ PyModule_AddObject(m, "SVGSurface", (PyObject *)&PycairoSVGSurface_Type);
+#endif
+
+#ifdef CAIRO_HAS_WIN32_SURFACE
+ Py_INCREF(&PycairoWin32Surface_Type);
+ PyModule_AddObject(m, "Win32Surface",
+ (PyObject *)&PycairoWin32Surface_Type);
+ Py_INCREF(&PycairoWin32PrintingSurface_Type);
+ PyModule_AddObject(m, "Win32PrintingSurface",
+ (PyObject *)&PycairoWin32PrintingSurface_Type);
+#endif
+
+#ifdef CAIRO_HAS_XCB_SURFACE
+ Py_INCREF(&PycairoXCBSurface_Type);
+ PyModule_AddObject(m, "XCBSurface",
+ (PyObject *)&PycairoXCBSurface_Type);
+#endif
+
+#ifdef CAIRO_HAS_XLIB_SURFACE
+ Py_INCREF(&PycairoXlibSurface_Type);
+ PyModule_AddObject(m, "XlibSurface",
+ (PyObject *)&PycairoXlibSurface_Type);
+#endif
+
+ PyModule_AddObject(m, "CAPI", PyCObject_FromVoidPtr(&CAPI, NULL));
+
+ /* Add 'cairo.Error' to the module */
+ if (CairoError == NULL) {
+ CairoError = PyErr_NewException("cairo.Error", NULL, NULL);
+ if (CairoError == NULL)
+ return;
+ }
+ Py_INCREF(CairoError);
+ if (PyModule_AddObject(m, "Error", CairoError) < 0)
+ return;
+
+ /* constants */
+#if CAIRO_HAS_ATSUI_FONT
+ PyModule_AddIntConstant(m, "HAS_ATSUI_FONT", 1);
+#else
+ PyModule_AddIntConstant(m, "HAS_ATSUI_FONT", 0);
+#endif
+#if CAIRO_HAS_FT_FONT
+ PyModule_AddIntConstant(m, "HAS_FT_FONT", 1);
+#else
+ PyModule_AddIntConstant(m, "HAS_FT_FONT", 0);
+#endif
+#if CAIRO_HAS_GLITZ_SURFACE
+ PyModule_AddIntConstant(m, "HAS_GLITZ_SURFACE", 1);
+#else
+ PyModule_AddIntConstant(m, "HAS_GLITZ_SURFACE", 0);
+#endif
+#if CAIRO_HAS_IMAGE_SURFACE
+ PyModule_AddIntConstant(m, "HAS_IMAGE_SURFACE", 1);
+#else
+ PyModule_AddIntConstant(m, "HAS_IMAGE_SURFACE", 0);
+#endif
+#if CAIRO_HAS_PDF_SURFACE
+ PyModule_AddIntConstant(m, "HAS_PDF_SURFACE", 1);
+#else
+ PyModule_AddIntConstant(m, "HAS_PDF_SURFACE", 0);
+#endif
+#if CAIRO_HAS_PNG_FUNCTIONS
+ PyModule_AddIntConstant(m, "HAS_PNG_FUNCTIONS", 1);
+#else
+ PyModule_AddIntConstant(m, "HAS_PNG_FUNCTIONS", 0);
+#endif
+#if CAIRO_HAS_PS_SURFACE
+ PyModule_AddIntConstant(m, "HAS_PS_SURFACE", 1);
+#else
+ PyModule_AddIntConstant(m, "HAS_PS_SURFACE", 0);
+#endif
+#if CAIRO_HAS_SVG_SURFACE
+ PyModule_AddIntConstant(m, "HAS_SVG_SURFACE", 1);
+#else
+ PyModule_AddIntConstant(m, "HAS_SVG_SURFACE", 0);
+#endif
+#if CAIRO_HAS_USER_FONT
+ PyModule_AddIntConstant(m, "HAS_USER_FONT", 1);
+#else
+ PyModule_AddIntConstant(m, "HAS_USER_FONT", 0);
+#endif
+#if CAIRO_HAS_QUARTZ_SURFACE
+ PyModule_AddIntConstant(m, "HAS_QUARTZ_SURFACE", 1);
+#else
+ PyModule_AddIntConstant(m, "HAS_QUARTZ_SURFACE", 0);
+#endif
+#if CAIRO_HAS_WIN32_FONT
+ PyModule_AddIntConstant(m, "HAS_WIN32_FONT", 1);
+#else
+ PyModule_AddIntConstant(m, "HAS_WIN32_FONT", 0);
+#endif
+#if CAIRO_HAS_WIN32_SURFACE
+ PyModule_AddIntConstant(m, "HAS_WIN32_SURFACE", 1);
+#else
+ PyModule_AddIntConstant(m, "HAS_WIN32_SURFACE", 0);
+#endif
+#if CAIRO_HAS_XCB_SURFACE
+ PyModule_AddIntConstant(m, "HAS_XCB_SURFACE", 1);
+#else
+ PyModule_AddIntConstant(m, "HAS_XCB_SURFACE", 0);
+#endif
+#if CAIRO_HAS_XLIB_SURFACE
+ PyModule_AddIntConstant(m, "HAS_XLIB_SURFACE", 1);
+#else
+ PyModule_AddIntConstant(m, "HAS_XLIB_SURFACE", 0);
+#endif
+
+#define CONSTANT(x) PyModule_AddIntConstant(m, #x, CAIRO_##x)
+ CONSTANT(ANTIALIAS_DEFAULT);
+ CONSTANT(ANTIALIAS_NONE);
+ CONSTANT(ANTIALIAS_GRAY);
+ CONSTANT(ANTIALIAS_SUBPIXEL);
+
+ CONSTANT(CONTENT_COLOR);
+ CONSTANT(CONTENT_ALPHA);
+ CONSTANT(CONTENT_COLOR_ALPHA);
+
+ CONSTANT(EXTEND_NONE);
+ CONSTANT(EXTEND_REPEAT);
+ CONSTANT(EXTEND_REFLECT);
+ CONSTANT(EXTEND_PAD);
+
+ CONSTANT(FILL_RULE_WINDING);
+ CONSTANT(FILL_RULE_EVEN_ODD);
+
+ CONSTANT(FILTER_FAST);
+ CONSTANT(FILTER_GOOD);
+ CONSTANT(FILTER_BEST);
+ CONSTANT(FILTER_NEAREST);
+ CONSTANT(FILTER_BILINEAR);
+ CONSTANT(FILTER_GAUSSIAN);
+
+ CONSTANT(FONT_WEIGHT_NORMAL);
+ CONSTANT(FONT_WEIGHT_BOLD);
+
+ CONSTANT(FONT_SLANT_NORMAL);
+ CONSTANT(FONT_SLANT_ITALIC);
+ CONSTANT(FONT_SLANT_OBLIQUE);
+
+ CONSTANT(FORMAT_ARGB32);
+ CONSTANT(FORMAT_RGB24);
+ CONSTANT(FORMAT_A8);
+ CONSTANT(FORMAT_A1);
+
+ CONSTANT(HINT_METRICS_DEFAULT);
+ CONSTANT(HINT_METRICS_OFF);
+ CONSTANT(HINT_METRICS_ON);
+
+ CONSTANT(HINT_STYLE_DEFAULT);
+ CONSTANT(HINT_STYLE_NONE);
+ CONSTANT(HINT_STYLE_SLIGHT);
+ CONSTANT(HINT_STYLE_MEDIUM);
+ CONSTANT(HINT_STYLE_FULL);
+
+ CONSTANT(LINE_CAP_BUTT);
+ CONSTANT(LINE_CAP_ROUND);
+ CONSTANT(LINE_CAP_SQUARE);
+
+ CONSTANT(LINE_JOIN_MITER);
+ CONSTANT(LINE_JOIN_ROUND);
+ CONSTANT(LINE_JOIN_BEVEL);
+
+ CONSTANT(OPERATOR_CLEAR);
+
+ CONSTANT(OPERATOR_SOURCE);
+ CONSTANT(OPERATOR_OVER);
+ CONSTANT(OPERATOR_IN);
+ CONSTANT(OPERATOR_OUT);
+ CONSTANT(OPERATOR_ATOP);
+
+ CONSTANT(OPERATOR_DEST);
+ CONSTANT(OPERATOR_DEST_OVER);
+ CONSTANT(OPERATOR_DEST_IN);
+ CONSTANT(OPERATOR_DEST_OUT);
+ CONSTANT(OPERATOR_DEST_ATOP);
+
+ CONSTANT(OPERATOR_XOR);
+ CONSTANT(OPERATOR_ADD);
+ CONSTANT(OPERATOR_SATURATE);
+
+ CONSTANT(PATH_MOVE_TO);
+ CONSTANT(PATH_LINE_TO);
+ CONSTANT(PATH_CURVE_TO);
+ CONSTANT(PATH_CLOSE_PATH);
+
+#ifdef CAIRO_HAS_PS_SURFACE
+ CONSTANT(PS_LEVEL_2);
+ CONSTANT(PS_LEVEL_3);
+#endif
+
+ CONSTANT(SUBPIXEL_ORDER_DEFAULT);
+ CONSTANT(SUBPIXEL_ORDER_RGB);
+ CONSTANT(SUBPIXEL_ORDER_BGR);
+ CONSTANT(SUBPIXEL_ORDER_VRGB);
+ CONSTANT(SUBPIXEL_ORDER_VBGR);
+#undef CONSTANT
+}
diff --git a/src/context.c b/src/context.c
new file mode 100644
index 0000000..cf56f5d
--- /dev/null
+++ b/src/context.c
@@ -0,0 +1,1433 @@
+/* -*- mode: C; c-basic-offset: 2 -*-
+ *
+ * Copyright © 2003,2010 James Henstridge, Steven Chaplin
+ *
+ * This file is part of pycairo.
+ *
+ * Pycairo is free software: you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License version 3 as published
+ * by the Free Software Foundation.
+ *
+ * Pycairo is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with pycairo. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define PY_SSIZE_T_CLEAN
+#include <Python.h>
+
+#include "config.h"
+#include "private.h"
+
+
+/* PycairoContext_FromContext
+ * Create a new PycairoContext from a cairo_t
+ * ctx - a cairo_t to 'wrap' into a Python object.
+ * It is unreferenced if the PycairoContext creation fails, or if
+ * the cairo_t has an error status.
+ * type - a pointer to the type to instantiate.
+ * It can be &PycairoContext_Type, or a PycairoContext_Type subtype.
+ * (cairo.Context or a cairo.Context subclass)
+ * base - the base object used to create the context, or NULL.
+ * it is referenced to keep it alive while the cairo_t is being used
+ * Return value: New reference or NULL on failure
+ */
+PyObject *
+PycairoContext_FromContext(cairo_t *ctx, PyTypeObject *type, PyObject *base) {
+ PyObject *o;
+
+ assert (ctx != NULL);
+
+ if (Pycairo_Check_Status (cairo_status (ctx))) {
+ cairo_destroy (ctx);
+ return NULL;
+ }
+
+ o = PycairoContext_Type.tp_alloc (type, 0);
+ if (o) {
+ ((PycairoContext *)o)->ctx = ctx;
+ Py_XINCREF(base);
+ ((PycairoContext *)o)->base = base;
+ } else {
+ cairo_destroy (ctx);
+ }
+ return o;
+}
+
+static void
+pycairo_dealloc(PycairoContext *o) {
+ if (o->ctx) {
+ cairo_destroy(o->ctx);
+ o->ctx = NULL;
+ }
+ Py_CLEAR(o->base);
+
+ o->ob_type->tp_free((PyObject *)o);
+}
+
+static PyObject *
+pycairo_new (PyTypeObject *type, PyObject *args, PyObject *kwds) {
+ PycairoSurface *s;
+ if (!PyArg_ParseTuple(args, "O!:Context.__new__",
+ &PycairoSurface_Type, &s))
+ return NULL;
+ return PycairoContext_FromContext (cairo_create (s->surface), type, NULL);
+}
+
+static PyObject *
+pycairo_append_path (PycairoContext *o, PyObject *args) {
+ PycairoPath *p;
+
+ if (!PyArg_ParseTuple(args, "O!:Context.append_path",
+ &PycairoPath_Type, &p))
+ return NULL;
+
+ Py_BEGIN_ALLOW_THREADS;
+ cairo_append_path (o->ctx, p->path);
+ Py_END_ALLOW_THREADS;
+ RETURN_NULL_IF_CAIRO_CONTEXT_ERROR(o->ctx);
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+pycairo_arc (PycairoContext *o, PyObject *args) {
+ double xc, yc, radius, angle1, angle2;
+
+ if (!PyArg_ParseTuple (args, "ddddd:Context.arc",
+ &xc, &yc, &radius, &angle1, &angle2))
+ return NULL;
+
+ cairo_arc (o->ctx, xc, yc, radius, angle1, angle2);
+ RETURN_NULL_IF_CAIRO_CONTEXT_ERROR(o->ctx);
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+pycairo_arc_negative (PycairoContext *o, PyObject *args) {
+ double xc, yc, radius, angle1, angle2;
+
+ if (!PyArg_ParseTuple (args, "ddddd:Context.arc_negative",
+ &xc, &yc, &radius, &angle1, &angle2))
+ return NULL;
+
+ cairo_arc_negative (o->ctx, xc, yc, radius, angle1, angle2);
+ RETURN_NULL_IF_CAIRO_CONTEXT_ERROR(o->ctx);
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+pycairo_clip (PycairoContext *o) {
+ Py_BEGIN_ALLOW_THREADS;
+ cairo_clip (o->ctx);
+ Py_END_ALLOW_THREADS;
+ RETURN_NULL_IF_CAIRO_CONTEXT_ERROR(o->ctx);
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+pycairo_clip_extents (PycairoContext *o) {
+ double x1, y1, x2, y2;
+ cairo_clip_extents (o->ctx, &x1, &y1, &x2, &y2);
+ RETURN_NULL_IF_CAIRO_CONTEXT_ERROR(o->ctx);
+ return Py_BuildValue("(dddd)", x1, y1, x2, y2);
+}
+
+static PyObject *
+pycairo_clip_preserve (PycairoContext *o) {
+ Py_BEGIN_ALLOW_THREADS;
+ cairo_clip_preserve (o->ctx);
+ Py_END_ALLOW_THREADS;
+ RETURN_NULL_IF_CAIRO_CONTEXT_ERROR(o->ctx);
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+pycairo_close_path (PycairoContext *o) {
+ Py_BEGIN_ALLOW_THREADS;
+ cairo_close_path (o->ctx);
+ Py_END_ALLOW_THREADS;
+ RETURN_NULL_IF_CAIRO_CONTEXT_ERROR(o->ctx);
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+pycairo_copy_clip_rectangle_list (PycairoContext *o) {
+ int i;
+ PyObject *rv = NULL;
+ cairo_rectangle_t *r;
+ cairo_rectangle_list_t *rlist = cairo_copy_clip_rectangle_list (o->ctx);
+ if (rlist->status != CAIRO_STATUS_SUCCESS) {
+ Pycairo_Check_Status (rlist->status);
+ goto exit;
+ }
+
+ rv = PyTuple_New(rlist->num_rectangles);
+ if (rv == NULL)
+ goto exit;
+
+ for (i = 0, r = rlist->rectangles; i < rlist->num_rectangles; i++, r++) {
+ PyObject *py_rect = Py_BuildValue("(dddd)", r->x, r->y,
+ r->width, r->height);
+ if (py_rect == NULL) {
+ Py_CLEAR(rv);
+ goto exit;
+ }
+ PyTuple_SET_ITEM (rv, i, py_rect);
+ }
+ exit:
+ cairo_rectangle_list_destroy(rlist);
+ return rv;
+}
+
+static PyObject *
+pycairo_copy_page (PycairoContext *o) {
+ Py_BEGIN_ALLOW_THREADS;
+ cairo_copy_page (o->ctx);
+ Py_END_ALLOW_THREADS;
+ RETURN_NULL_IF_CAIRO_CONTEXT_ERROR(o->ctx);
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+pycairo_copy_path (PycairoContext *o) {
+ cairo_path_t *cp;
+ Py_BEGIN_ALLOW_THREADS;
+ cp = cairo_copy_path (o->ctx);
+ Py_END_ALLOW_THREADS;
+ return PycairoPath_FromPath (cp);
+}
+
+static PyObject *
+pycairo_copy_path_flat (PycairoContext *o) {
+ cairo_path_t *cp;
+ Py_BEGIN_ALLOW_THREADS;
+ cp = cairo_copy_path_flat (o->ctx);
+ Py_END_ALLOW_THREADS;
+ return PycairoPath_FromPath (cp);
+}
+
+static PyObject *
+pycairo_curve_to (PycairoContext *o, PyObject *args) {
+ double x1, y1, x2, y2, x3, y3;
+
+ if (!PyArg_ParseTuple (args, "dddddd:Context.curve_to",
+ &x1, &y1, &x2, &y2, &x3, &y3))
+ return NULL;
+
+ cairo_curve_to (o->ctx, x1, y1, x2, y2, x3, y3);
+ RETURN_NULL_IF_CAIRO_CONTEXT_ERROR(o->ctx);
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+pycairo_device_to_user(PycairoContext *o, PyObject *args) {
+ double x, y;
+
+ if (!PyArg_ParseTuple(args, "dd:Context.device_to_user", &x, &y))
+ return NULL;
+
+ cairo_device_to_user(o->ctx, &x, &y);
+ RETURN_NULL_IF_CAIRO_CONTEXT_ERROR(o->ctx);
+ return Py_BuildValue("(dd)", x, y);
+}
+
+static PyObject *
+pycairo_device_to_user_distance (PycairoContext *o, PyObject *args) {
+ double dx, dy;
+
+ if (!PyArg_ParseTuple (args, "dd:Context.device_to_user_distance",
+ &dx, &dy))
+ return NULL;
+
+ cairo_device_to_user_distance (o->ctx, &dx, &dy);
+ RETURN_NULL_IF_CAIRO_CONTEXT_ERROR(o->ctx);
+ return Py_BuildValue("(dd)", dx, dy);
+}
+
+static PyObject *
+pycairo_fill (PycairoContext *o) {
+ Py_BEGIN_ALLOW_THREADS;
+ cairo_fill (o->ctx);
+ Py_END_ALLOW_THREADS;
+ RETURN_NULL_IF_CAIRO_CONTEXT_ERROR(o->ctx);
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+pycairo_fill_extents (PycairoContext *o) {
+ double x1, y1, x2, y2;
+ cairo_fill_extents (o->ctx, &x1, &y1, &x2, &y2);
+ RETURN_NULL_IF_CAIRO_CONTEXT_ERROR(o->ctx);
+ return Py_BuildValue("(dddd)", x1, y1, x2, y2);
+}
+
+static PyObject *
+pycairo_fill_preserve (PycairoContext *o) {
+ Py_BEGIN_ALLOW_THREADS;
+ cairo_fill_preserve (o->ctx);
+ Py_END_ALLOW_THREADS;
+ RETURN_NULL_IF_CAIRO_CONTEXT_ERROR(o->ctx);
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+pycairo_font_extents (PycairoContext *o) {
+ cairo_font_extents_t e;
+
+ cairo_font_extents (o->ctx, &e);
+ RETURN_NULL_IF_CAIRO_CONTEXT_ERROR(o->ctx);
+ return Py_BuildValue("(ddddd)", e.ascent, e.descent, e.height,
+ e.max_x_advance, e.max_y_advance);
+}
+
+static PyObject *
+pycairo_get_antialias (PycairoContext *o) {
+ return PyInt_FromLong (cairo_get_antialias (o->ctx));
+}
+
+static PyObject *
+pycairo_get_current_point (PycairoContext *o) {
+ double x, y;
+ cairo_get_current_point (o->ctx, &x, &y);
+ return Py_BuildValue("(dd)", x, y);
+}
+
+static PyObject *
+pycairo_get_dash (PycairoContext *o) {
+ double *dashes = NULL, offset;
+ int count, i;
+ PyObject *py_dashes = NULL, *rv = NULL;
+
+ count = cairo_get_dash_count (o->ctx);
+ dashes = PyMem_Malloc (count * sizeof(double));
+ if (dashes == NULL)
+ return PyErr_NoMemory();
+
+ cairo_get_dash (o->ctx, dashes, &offset);
+ py_dashes = PyTuple_New(count);
+ if (py_dashes == NULL)
+ goto exit;
+
+ for (i = 0; i < count; i++) {
+ PyObject *dash = PyFloat_FromDouble(dashes[i]);
+ if (dash == NULL)
+ goto exit;
+ PyTuple_SET_ITEM (py_dashes, i, dash);
+ }
+ rv = Py_BuildValue("(Od)", py_dashes, offset);
+
+ exit:
+ PyMem_Free (dashes);
+ Py_XDECREF(py_dashes);
+ return rv;
+}
+
+static PyObject *
+pycairo_get_dash_count (PycairoContext *o) {
+ return PyInt_FromLong (cairo_get_dash_count (o->ctx));
+}
+
+static PyObject *
+pycairo_get_fill_rule (PycairoContext *o) {
+ return PyInt_FromLong(cairo_get_fill_rule (o->ctx));
+}
+
+static PyObject *
+pycairo_get_font_face (PycairoContext *o) {
+ return PycairoFontFace_FromFontFace (
+ cairo_font_face_reference (cairo_get_font_face (o->ctx)));
+}
+
+static PyObject *
+pycairo_get_font_matrix (PycairoContext *o) {
+ cairo_matrix_t matrix;
+ cairo_get_font_matrix (o->ctx, &matrix);
+ return PycairoMatrix_FromMatrix (&matrix);
+}
+
+static PyObject *
+pycairo_get_font_options (PycairoContext *o) {
+ cairo_font_options_t *options = cairo_font_options_create();
+ cairo_get_font_options (o->ctx, options);
+ /* there is no reference fn */
+ return PycairoFontOptions_FromFontOptions (options);
+}
+
+static PyObject *
+pycairo_get_group_target (PycairoContext *o) {
+ cairo_surface_t *surface = cairo_get_group_target (o->ctx);
+ if (surface != NULL)
+ return PycairoSurface_FromSurface (cairo_surface_reference (surface),
+ NULL);
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+pycairo_get_line_cap (PycairoContext *o) {
+ return PyInt_FromLong(cairo_get_line_cap (o->ctx));
+}
+
+static PyObject *
+pycairo_get_line_join (PycairoContext *o) {
+ return PyInt_FromLong(cairo_get_line_join (o->ctx));
+}
+
+static PyObject *
+pycairo_get_line_width (PycairoContext *o) {
+ return PyFloat_FromDouble(cairo_get_line_width (o->ctx));
+}
+
+static PyObject *
+pycairo_get_matrix (PycairoContext *o) {
+ cairo_matrix_t matrix;
+ cairo_get_matrix (o->ctx, &matrix);
+ return PycairoMatrix_FromMatrix (&matrix);
+}
+
+static PyObject *
+pycairo_get_miter_limit (PycairoContext *o) {
+ return PyFloat_FromDouble (cairo_get_miter_limit (o->ctx));
+}
+
+static PyObject *
+pycairo_get_operator (PycairoContext *o) {
+ return PyInt_FromLong (cairo_get_operator (o->ctx));
+}
+
+static PyObject *
+pycairo_get_scaled_font (PycairoContext *o) {
+ return PycairoScaledFont_FromScaledFont (
+ cairo_scaled_font_reference (cairo_get_scaled_font (o->ctx)));
+}
+
+static PyObject *
+pycairo_get_source (PycairoContext *o) {
+ return PycairoPattern_FromPattern (
+ cairo_pattern_reference (cairo_get_source (o->ctx)), NULL);
+}
+
+static PyObject *
+pycairo_get_target (PycairoContext *o) {
+ return PycairoSurface_FromSurface (
+ cairo_surface_reference (cairo_get_target (o->ctx)),
+ NULL);
+}
+
+static PyObject *
+pycairo_get_tolerance (PycairoContext *o) {
+ return PyFloat_FromDouble (cairo_get_tolerance (o->ctx));
+}
+
+/* read a Python sequence of (i,x,y) sequences
+ * return cairo_glyph_t *
+ * num_glyphs
+ * must call PyMem_Free(glyphs) when finished using the glyphs
+ */
+static cairo_glyph_t *
+_PyGlyphs_AsGlyphs (PyObject *py_object, int *num_glyphs)
+{
+ int length, i;
+ cairo_glyph_t *glyphs = NULL, *glyph;
+ PyObject *py_glyphs, *py_seq = NULL;
+
+ py_glyphs = PySequence_Fast (py_object, "glyphs must be a sequence");
+ if (py_glyphs == NULL)
+ return NULL;
+
+ length = PySequence_Fast_GET_SIZE(py_glyphs);
+ if (*num_glyphs < 0 || *num_glyphs > length)
+ *num_glyphs = length;
+
+ glyphs = PyMem_Malloc (*num_glyphs * sizeof(cairo_glyph_t));
+ if (glyphs == NULL) {
+ PyErr_NoMemory();
+ goto error;
+ }
+ for (i = 0, glyph = glyphs; i < *num_glyphs; i++, glyph++) {
+ PyObject *py_item = PySequence_Fast_GET_ITEM(py_glyphs, i);
+ py_seq = PySequence_Fast (py_item, "glyph items must be a sequence");
+ if (py_seq == NULL)
+ goto error;
+ if (PySequence_Fast_GET_SIZE(py_seq) != 3) {
+ PyErr_SetString(PyExc_ValueError,
+ "each glyph item must be an (i,x,y) sequence");
+ goto error;
+ }
+ glyph->index = PyInt_AsLong(PySequence_Fast_GET_ITEM(py_seq, 0));
+ glyph->x = PyFloat_AsDouble(PySequence_Fast_GET_ITEM(py_seq, 1));
+ glyph->y = PyFloat_AsDouble(PySequence_Fast_GET_ITEM(py_seq, 2));
+ if (PyErr_Occurred())
+ goto error;
+ Py_DECREF(py_seq);
+ }
+ Py_DECREF(py_glyphs);
+ return glyphs;
+ error:
+ Py_DECREF(py_glyphs);
+ Py_XDECREF(py_seq);
+ PyMem_Free(glyphs);
+ return NULL;
+}
+
+static PyObject *
+pycairo_glyph_extents (PycairoContext *o, PyObject *args) {
+ int num_glyphs = -1;
+ cairo_glyph_t *glyphs;
+ cairo_text_extents_t extents;
+ PyObject *py_object;
+
+ if (!PyArg_ParseTuple (args, "O|i:Context.glyph_extents",
+ &py_object, &num_glyphs))
+ return NULL;
+
+ glyphs = _PyGlyphs_AsGlyphs (py_object, &num_glyphs);
+ if (glyphs == NULL)
+ return NULL;
+ cairo_glyph_extents (o->ctx, glyphs, num_glyphs, &extents);
+ PyMem_Free (glyphs);
+ RETURN_NULL_IF_CAIRO_CONTEXT_ERROR(o->ctx);
+ return Py_BuildValue("(dddddd)", extents.x_bearing, extents.y_bearing,
+ extents.width, extents.height, extents.x_advance,
+ extents.y_advance);
+}
+
+static PyObject *
+pycairo_glyph_path (PycairoContext *o, PyObject *args) {
+ int num_glyphs = -1;
+ cairo_glyph_t *glyphs;
+ PyObject *py_object;
+
+ if (!PyArg_ParseTuple (args, "O|i:Context.glyph_path",
+ &py_object, &num_glyphs))
+ return NULL;
+
+ glyphs = _PyGlyphs_AsGlyphs (py_object, &num_glyphs);
+ if (glyphs == NULL)
+ return NULL;
+ cairo_glyph_path (o->ctx, glyphs, num_glyphs);
+ PyMem_Free (glyphs);
+ RETURN_NULL_IF_CAIRO_CONTEXT_ERROR(o->ctx);
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+pycairo_has_current_point (PycairoContext *o) {
+ PyObject *b = cairo_has_current_point (o->ctx) ? Py_True : Py_False;
+ RETURN_NULL_IF_CAIRO_CONTEXT_ERROR(o->ctx);
+ Py_INCREF(b);
+ return b;
+}
+
+static PyObject *
+pycairo_identity_matrix (PycairoContext *o) {
+ cairo_identity_matrix (o->ctx);
+ RETURN_NULL_IF_CAIRO_CONTEXT_ERROR(o->ctx);
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+pycairo_in_fill (PycairoContext *o, PyObject *args) {
+ double x, y;
+ PyObject *result;
+
+ if (!PyArg_ParseTuple (args, "dd:Context.in_fill", &x, &y))
+ return NULL;
+
+ result = cairo_in_fill (o->ctx, x, y) ? Py_True : Py_False;
+ RETURN_NULL_IF_CAIRO_CONTEXT_ERROR(o->ctx);
+ Py_INCREF(result);
+ return result;
+}
+
+static PyObject *
+pycairo_in_stroke (PycairoContext *o, PyObject *args) {
+ double x, y;
+ PyObject *result;
+
+ if (!PyArg_ParseTuple (args, "dd:Context.in_stroke", &x, &y))
+ return NULL;
+
+ result = cairo_in_stroke (o->ctx, x, y) ? Py_True : Py_False;
+ RETURN_NULL_IF_CAIRO_CONTEXT_ERROR(o->ctx);
+ Py_INCREF(result);
+ return result;
+}
+
+static PyObject *
+pycairo_line_to (PycairoContext *o, PyObject *args) {
+ double x, y;
+
+ if (!PyArg_ParseTuple (args, "dd:Context.line_to", &x, &y))
+ return NULL;
+
+ cairo_line_to (o->ctx, x, y);
+ RETURN_NULL_IF_CAIRO_CONTEXT_ERROR(o->ctx);
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+pycairo_mask (PycairoContext *o, PyObject *args) {
+ PycairoPattern *p;
+
+ if (!PyArg_ParseTuple(args, "O!:Context.mask", &PycairoPattern_Type, &p))
+ return NULL;
+
+ Py_BEGIN_ALLOW_THREADS;
+ cairo_mask (o->ctx, p->pattern);
+ Py_END_ALLOW_THREADS;
+ RETURN_NULL_IF_CAIRO_CONTEXT_ERROR(o->ctx);
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+pycairo_mask_surface (PycairoContext *o, PyObject *args) {
+ PycairoSurface *s;
+ double surface_x = 0.0, surface_y = 0.0;
+
+ if (!PyArg_ParseTuple (args, "O!|dd:Context.mask_surface",
+ &PycairoSurface_Type, &s, &surface_x, &surface_y))
+ return NULL;
+
+ Py_BEGIN_ALLOW_THREADS;
+ cairo_mask_surface (o->ctx, s->surface, surface_x, surface_y);
+ Py_END_ALLOW_THREADS;
+ RETURN_NULL_IF_CAIRO_CONTEXT_ERROR(o->ctx);
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+pycairo_move_to (PycairoContext *o, PyObject *args) {
+ double x, y;
+
+ if (!PyArg_ParseTuple (args, "dd:Context.move_to", &x, &y))
+ return NULL;
+
+ cairo_move_to (o->ctx, x, y);
+ RETURN_NULL_IF_CAIRO_CONTEXT_ERROR(o->ctx);
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+pycairo_new_path (PycairoContext *o) {
+ cairo_new_path (o->ctx);
+ RETURN_NULL_IF_CAIRO_CONTEXT_ERROR(o->ctx);
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+pycairo_new_sub_path (PycairoContext *o) {
+ cairo_new_sub_path (o->ctx);
+ RETURN_NULL_IF_CAIRO_CONTEXT_ERROR(o->ctx);
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+pycairo_paint (PycairoContext *o) {
+ Py_BEGIN_ALLOW_THREADS;
+ cairo_paint (o->ctx);
+ Py_END_ALLOW_THREADS;
+ RETURN_NULL_IF_CAIRO_CONTEXT_ERROR(o->ctx);
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+pycairo_paint_with_alpha (PycairoContext *o, PyObject *args) {
+ double alpha;
+
+ if (!PyArg_ParseTuple (args, "d:Context.paint_with_alpha", &alpha))
+ return NULL;
+
+ Py_BEGIN_ALLOW_THREADS;
+ cairo_paint_with_alpha (o->ctx, alpha);
+ Py_END_ALLOW_THREADS;
+ RETURN_NULL_IF_CAIRO_CONTEXT_ERROR(o->ctx);
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+pycairo_path_extents (PycairoContext *o) {
+ double x1, y1, x2, y2;
+ cairo_path_extents (o->ctx, &x1, &y1, &x2, &y2);
+ RETURN_NULL_IF_CAIRO_CONTEXT_ERROR(o->ctx);
+ return Py_BuildValue("(dddd)", x1, y1, x2, y2);
+}
+
+static PyObject *
+pycairo_pop_group (PycairoContext *o) {
+ return PycairoPattern_FromPattern (cairo_pop_group (o->ctx), NULL);
+}
+
+static PyObject *
+pycairo_pop_group_to_source (PycairoContext *o) {
+ cairo_pop_group_to_source (o->ctx);
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+pycairo_push_group (PycairoContext *o) {
+ cairo_push_group (o->ctx);
+ RETURN_NULL_IF_CAIRO_CONTEXT_ERROR(o->ctx);
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+pycairo_push_group_with_content (PycairoContext *o, PyObject *args) {
+ cairo_content_t content;
+
+ if (!PyArg_ParseTuple(args, "i:Context.push_group_with_content",
+ &content))
+ return NULL;
+ cairo_push_group_with_content (o->ctx, content);
+ RETURN_NULL_IF_CAIRO_CONTEXT_ERROR(o->ctx);
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+pycairo_rectangle (PycairoContext *o, PyObject *args) {
+ double x, y, width, height;
+
+ if (!PyArg_ParseTuple (args, "dddd:Context.rectangle",
+ &x, &y, &width, &height))
+ return NULL;
+
+ cairo_rectangle (o->ctx, x, y, width, height);
+ RETURN_NULL_IF_CAIRO_CONTEXT_ERROR(o->ctx);
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+pycairo_rel_curve_to (PycairoContext *o, PyObject *args) {
+ double dx1, dy1, dx2, dy2, dx3, dy3;
+
+ if (!PyArg_ParseTuple (args, "dddddd:Context.rel_curve_to",
+ &dx1, &dy1, &dx2, &dy2, &dx3, &dy3))
+ return NULL;
+
+ cairo_rel_curve_to (o->ctx, dx1, dy1, dx2, dy2, dx3, dy3);
+ RETURN_NULL_IF_CAIRO_CONTEXT_ERROR(o->ctx);
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+pycairo_rel_line_to (PycairoContext *o, PyObject *args) {
+ double dx, dy;
+
+ if (!PyArg_ParseTuple (args, "dd:Context.rel_line_to", &dx, &dy))
+ return NULL;
+
+ cairo_rel_line_to (o->ctx, dx, dy);
+ RETURN_NULL_IF_CAIRO_CONTEXT_ERROR(o->ctx);
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+pycairo_rel_move_to (PycairoContext *o, PyObject *args) {
+ double dx, dy;
+
+ if (!PyArg_ParseTuple (args, "dd:Context.rel_move_to", &dx, &dy))
+ return NULL;
+
+ cairo_rel_move_to (o->ctx, dx, dy);
+ RETURN_NULL_IF_CAIRO_CONTEXT_ERROR(o->ctx);
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+pycairo_reset_clip (PycairoContext *o) {
+ cairo_reset_clip (o->ctx);
+ RETURN_NULL_IF_CAIRO_CONTEXT_ERROR(o->ctx);
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+pycairo_restore (PycairoContext *o) {
+ cairo_restore (o->ctx);
+ RETURN_NULL_IF_CAIRO_CONTEXT_ERROR(o->ctx);
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+pycairo_rotate (PycairoContext *o, PyObject *args) {
+ double angle;
+
+ if (!PyArg_ParseTuple(args, "d:Context.rotate", &angle))
+ return NULL;
+
+ cairo_rotate (o->ctx, angle);
+ RETURN_NULL_IF_CAIRO_CONTEXT_ERROR(o->ctx);
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+pycairo_save (PycairoContext *o) {
+ cairo_save (o->ctx);
+ RETURN_NULL_IF_CAIRO_CONTEXT_ERROR(o->ctx);
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+pycairo_scale (PycairoContext *o, PyObject *args) {
+ double sx, sy;
+
+ if (!PyArg_ParseTuple (args, "dd:Context.scale", &sx, &sy))
+ return NULL;
+
+ cairo_scale (o->ctx, sx, sy);
+ RETURN_NULL_IF_CAIRO_CONTEXT_ERROR(o->ctx);
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+pycairo_select_font_face (PycairoContext *o, PyObject *args) {
+ PyObject *obj;
+ PyObject *pyUTF8 = NULL;
+ const char *utf8family = NULL;
+ cairo_font_slant_t slant = CAIRO_FONT_SLANT_NORMAL;
+ cairo_font_weight_t weight = CAIRO_FONT_WEIGHT_NORMAL;
+
+ if (!PyArg_ParseTuple(args, "O!|ii:Context.select_font_face",
+ &PyBaseString_Type, &obj, &slant, &weight))
+ return NULL;
+
+ /* accept str and unicode family, auto convert to utf8 as required */
+ if (PyString_Check(obj)) {
+ /* A plain ASCII string is also a valid UTF-8 string */
+ utf8family = PyString_AS_STRING(obj);
+ } else if (PyUnicode_Check(obj)) {
+ pyUTF8 = PyUnicode_AsUTF8String(obj);
+ if (pyUTF8 != NULL) {
+ utf8family = PyString_AS_STRING(pyUTF8);
+ }
+ } else {
+ PyErr_SetString(PyExc_TypeError,
+ "Context.select_font_face: family must be str or unicode");
+ }
+ if (utf8family == NULL)
+ return NULL;
+
+ cairo_select_font_face (o->ctx, utf8family, slant, weight);
+ Py_XDECREF(pyUTF8);
+ RETURN_NULL_IF_CAIRO_CONTEXT_ERROR(o->ctx);
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+pycairo_set_antialias (PycairoContext *o, PyObject *args) {
+ cairo_antialias_t antialias = CAIRO_ANTIALIAS_DEFAULT;
+
+ if (!PyArg_ParseTuple(args, "|i:Context.set_antialias", &antialias))
+ return NULL;
+
+ cairo_set_antialias (o->ctx, antialias);
+ RETURN_NULL_IF_CAIRO_CONTEXT_ERROR(o->ctx);
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+pycairo_set_dash (PycairoContext *o, PyObject *args) {
+ double *dashes, offset = 0;
+ int num_dashes, i;
+ PyObject *py_dashes;
+
+ if (!PyArg_ParseTuple (args, "O|d:Context.set_dash", &py_dashes, &offset))
+ return NULL;
+
+ py_dashes = PySequence_Fast (py_dashes,
+ "first argument must be a sequence");
+ if (py_dashes == NULL)
+ return NULL;
+
+ num_dashes = PySequence_Fast_GET_SIZE(py_dashes);
+ dashes = PyMem_Malloc (num_dashes * sizeof(double));
+ if (dashes == NULL) {
+ Py_DECREF(py_dashes);
+ return PyErr_NoMemory();
+ }
+
+ for (i = 0; i < num_dashes; i++) {
+ dashes[i] = PyFloat_AsDouble(PySequence_Fast_GET_ITEM(py_dashes, i));
+ if (PyErr_Occurred()) {
+ PyMem_Free (dashes);
+ Py_DECREF(py_dashes);
+ return NULL;
+ }
+ }
+ cairo_set_dash (o->ctx, dashes, num_dashes, offset);
+ PyMem_Free (dashes);
+ Py_DECREF(py_dashes);
+ RETURN_NULL_IF_CAIRO_CONTEXT_ERROR(o->ctx);
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+pycairo_set_fill_rule (PycairoContext *o, PyObject *args) {
+ cairo_fill_rule_t fill_rule;
+
+ if (!PyArg_ParseTuple (args, "i:Context.set_fill_rule", &fill_rule))
+ return NULL;
+
+ cairo_set_fill_rule (o->ctx, fill_rule);
+ RETURN_NULL_IF_CAIRO_CONTEXT_ERROR(o->ctx);
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+pycairo_set_font_face (PycairoContext *o, PyObject *obj) {
+ if (PyObject_TypeCheck(obj, &PycairoFontFace_Type))
+ cairo_set_font_face (o->ctx, ((PycairoFontFace *)obj)->font_face);
+ else if (obj == Py_None)
+ cairo_set_font_face (o->ctx, NULL);
+ else {
+ PyErr_SetString(PyExc_TypeError,
+ "Context.set_font_face() argument must be "
+ "cairo.FontFace or None");
+ return NULL;
+ }
+ RETURN_NULL_IF_CAIRO_CONTEXT_ERROR(o->ctx);
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+pycairo_set_font_matrix (PycairoContext *o, PyObject *args) {
+ PycairoMatrix *matrix;
+
+ if (!PyArg_ParseTuple (args, "O!:Context.set_font_matrix",
+ &PycairoMatrix_Type, &matrix))
+ return NULL;
+
+ cairo_set_font_matrix (o->ctx, &matrix->matrix);
+ RETURN_NULL_IF_CAIRO_CONTEXT_ERROR(o->ctx);
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+pycairo_set_font_options (PycairoContext *o, PyObject *args) {
+ PycairoFontOptions *options;
+
+ if (!PyArg_ParseTuple (args, "O!:Context.set_font_options",
+ &PycairoFontOptions_Type, &options))
+ return NULL;
+
+ cairo_set_font_options (o->ctx, options->font_options);
+ RETURN_NULL_IF_CAIRO_CONTEXT_ERROR(o->ctx);
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+pycairo_set_font_size (PycairoContext *o, PyObject *args) {
+ double size;
+
+ if (!PyArg_ParseTuple (args, "d:Context.set_font_size", &size))
+ return NULL;
+
+ cairo_set_font_size (o->ctx, size);
+ RETURN_NULL_IF_CAIRO_CONTEXT_ERROR(o->ctx);
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+pycairo_set_line_cap (PycairoContext *o, PyObject *args) {
+ cairo_line_cap_t line_cap;
+
+ if (!PyArg_ParseTuple (args, "i:Context.set_line_cap", &line_cap))
+ return NULL;
+
+ cairo_set_line_cap (o->ctx, line_cap);
+ RETURN_NULL_IF_CAIRO_CONTEXT_ERROR(o->ctx);
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+pycairo_set_line_join (PycairoContext *o, PyObject *args) {
+ cairo_line_join_t line_join;
+
+ if (!PyArg_ParseTuple (args, "i:Context.set_line_join", &line_join))
+ return NULL;
+
+ cairo_set_line_join (o->ctx, line_join);
+ RETURN_NULL_IF_CAIRO_CONTEXT_ERROR(o->ctx);
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+pycairo_set_line_width (PycairoContext *o, PyObject *args) {
+ double width;
+
+ if (!PyArg_ParseTuple (args, "d:Context.set_line_width", &width))
+ return NULL;
+
+ cairo_set_line_width (o->ctx, width);
+ RETURN_NULL_IF_CAIRO_CONTEXT_ERROR(o->ctx);
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+pycairo_set_matrix (PycairoContext *o, PyObject *args) {
+ PycairoMatrix *matrix;
+
+ if (!PyArg_ParseTuple (args, "O!:Context.set_matrix",
+ &PycairoMatrix_Type, &matrix))
+ return NULL;
+
+ cairo_set_matrix (o->ctx, &matrix->matrix);
+ RETURN_NULL_IF_CAIRO_CONTEXT_ERROR(o->ctx);
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+pycairo_set_miter_limit (PycairoContext *o, PyObject *args) {
+ double limit;
+
+ if (!PyArg_ParseTuple (args, "d:Context.set_miter_limit", &limit))
+ return NULL;
+
+ cairo_set_miter_limit (o->ctx, limit);
+ RETURN_NULL_IF_CAIRO_CONTEXT_ERROR(o->ctx);
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+pycairo_set_operator(PycairoContext *o, PyObject *args) {
+ cairo_operator_t op;
+
+ if (!PyArg_ParseTuple(args, "i:Context.set_operator", &op))
+ return NULL;
+
+ cairo_set_operator(o->ctx, op);
+ RETURN_NULL_IF_CAIRO_CONTEXT_ERROR(o->ctx);
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+pycairo_set_scaled_font(PycairoContext *o, PyObject *args) {
+ PycairoScaledFont *f;
+ if (!PyArg_ParseTuple( args, "O!:Context.set_scaled_font",
+ &PycairoScaledFont_Type, &f))
+ return NULL;
+
+ cairo_set_scaled_font(o->ctx, f->scaled_font);
+ RETURN_NULL_IF_CAIRO_CONTEXT_ERROR(o->ctx);
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+pycairo_set_source (PycairoContext *o, PyObject *args) {
+ PycairoPattern *p;
+
+ if (!PyArg_ParseTuple( args, "O!:Context.set_source",
+ &PycairoPattern_Type, &p))
+ return NULL;
+
+ cairo_set_source (o->ctx, p->pattern);
+ RETURN_NULL_IF_CAIRO_CONTEXT_ERROR(o->ctx);
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+pycairo_set_source_rgb (PycairoContext *o, PyObject *args) {
+ double red, green, blue;
+
+ if (!PyArg_ParseTuple (args, "ddd:Context.set_source_rgb",
+ &red, &green, &blue))
+ return NULL;
+
+ cairo_set_source_rgb (o->ctx, red, green, blue);
+ RETURN_NULL_IF_CAIRO_CONTEXT_ERROR(o->ctx);
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+pycairo_set_source_rgba (PycairoContext *o, PyObject *args) {
+ double red, green, blue;
+ double alpha = 1.0;
+
+ if (!PyArg_ParseTuple (args, "ddd|d:Context.set_source_rgba",
+ &red, &green, &blue, &alpha))
+ return NULL;
+
+ cairo_set_source_rgba (o->ctx, red, green, blue, alpha);
+ RETURN_NULL_IF_CAIRO_CONTEXT_ERROR(o->ctx);
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+pycairo_set_source_surface (PycairoContext *o, PyObject *args) {
+ PycairoSurface *surface;
+ double x = 0.0, y = 0.0;
+
+ if (!PyArg_ParseTuple (args, "O!|dd:Context.set_source_surface",
+ &PycairoSurface_Type, &surface, &x, &y))
+ return NULL;
+
+ cairo_set_source_surface (o->ctx, surface->surface, x, y);
+ RETURN_NULL_IF_CAIRO_CONTEXT_ERROR(o->ctx);
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+pycairo_set_tolerance (PycairoContext *o, PyObject *args) {
+ double tolerance;
+ if (!PyArg_ParseTuple (args, "d:Context.set_tolerance", &tolerance))
+ return NULL;
+ cairo_set_tolerance (o->ctx, tolerance);
+ RETURN_NULL_IF_CAIRO_CONTEXT_ERROR(o->ctx);
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+pycairo_show_glyphs (PycairoContext *o, PyObject *args) {
+ int num_glyphs = -1;
+ cairo_glyph_t *glyphs;
+ PyObject *py_object;
+
+ if (!PyArg_ParseTuple (args, "O|i:Context.show_glyphs",
+ &py_object, &num_glyphs))
+ return NULL;
+
+ glyphs = _PyGlyphs_AsGlyphs (py_object, &num_glyphs);
+ if (glyphs == NULL)
+ return NULL;
+ Py_BEGIN_ALLOW_THREADS;
+ cairo_show_glyphs (o->ctx, glyphs, num_glyphs);
+ Py_END_ALLOW_THREADS;
+ PyMem_Free (glyphs);
+ RETURN_NULL_IF_CAIRO_CONTEXT_ERROR(o->ctx);
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+pycairo_show_page (PycairoContext *o) {
+ Py_BEGIN_ALLOW_THREADS;
+ cairo_show_page (o->ctx);
+ Py_END_ALLOW_THREADS;
+ RETURN_NULL_IF_CAIRO_CONTEXT_ERROR(o->ctx);
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+pycairo_show_text (PycairoContext *o, PyObject *obj) {
+ PyObject *pyUTF8 = NULL;
+ const char *utf8 = NULL;
+
+ /* accept str and unicode text, auto convert to utf8 as required */
+ if (PyString_Check(obj)) {
+ /* A plain ASCII string is also a valid UTF-8 string */
+ utf8 = PyString_AS_STRING(obj);
+ } else if (PyUnicode_Check(obj)) {
+ pyUTF8 = PyUnicode_AsUTF8String(obj);
+ if (pyUTF8 != NULL) {
+ utf8 = PyString_AS_STRING(pyUTF8);
+ }
+ } else {
+ PyErr_SetString(PyExc_TypeError,
+ "Context.show_text: text must be str or unicode");
+ }
+ if (utf8 == NULL)
+ return NULL;
+
+ Py_BEGIN_ALLOW_THREADS;
+ cairo_show_text (o->ctx, utf8);
+ Py_END_ALLOW_THREADS;
+ Py_XDECREF(pyUTF8);
+ RETURN_NULL_IF_CAIRO_CONTEXT_ERROR(o->ctx);
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+pycairo_stroke (PycairoContext *o) {
+ Py_BEGIN_ALLOW_THREADS;
+ cairo_stroke (o->ctx);
+ Py_END_ALLOW_THREADS;
+ RETURN_NULL_IF_CAIRO_CONTEXT_ERROR(o->ctx);
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+pycairo_stroke_extents (PycairoContext *o) {
+ double x1, y1, x2, y2;
+ cairo_stroke_extents (o->ctx, &x1, &y1, &x2, &y2);
+ RETURN_NULL_IF_CAIRO_CONTEXT_ERROR(o->ctx);
+ return Py_BuildValue("(dddd)", x1, y1, x2, y2);
+}
+
+static PyObject *
+pycairo_stroke_preserve (PycairoContext *o) {
+ Py_BEGIN_ALLOW_THREADS;
+ cairo_stroke_preserve (o->ctx);
+ Py_END_ALLOW_THREADS;
+ RETURN_NULL_IF_CAIRO_CONTEXT_ERROR(o->ctx);
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+pycairo_text_extents (PycairoContext *o, PyObject *obj) {
+ cairo_text_extents_t extents;
+ PyObject *pyUTF8 = NULL;
+ const char *utf8 = NULL;
+
+ /* accept str and unicode text, auto convert to utf8 as required */
+ if (PyString_Check(obj)) {
+ /* A plain ASCII string is also a valid UTF-8 string */
+ utf8 = PyString_AS_STRING(obj);
+ } else if (PyUnicode_Check(obj)) {
+ pyUTF8 = PyUnicode_AsUTF8String(obj);
+ if (pyUTF8 != NULL) {
+ utf8 = PyString_AS_STRING(pyUTF8);
+ }
+ } else {
+ PyErr_SetString(PyExc_TypeError,
+ "Context.text_extents: text must be str or unicode");
+ }
+ if (utf8 == NULL)
+ return NULL;
+
+ cairo_text_extents (o->ctx, utf8, &extents);
+ Py_XDECREF(pyUTF8);
+ RETURN_NULL_IF_CAIRO_CONTEXT_ERROR(o->ctx);
+ return Py_BuildValue("(dddddd)", extents.x_bearing, extents.y_bearing,
+ extents.width, extents.height, extents.x_advance,
+ extents.y_advance);
+}
+
+static PyObject *
+pycairo_text_path (PycairoContext *o, PyObject *obj) {
+ PyObject *pyUTF8 = NULL;
+ const char *utf8 = NULL;
+
+ /* accept str and unicode text, auto convert to utf8 as required */
+ if (PyString_Check(obj)) {
+ /* A plain ASCII string is also a valid UTF-8 string */
+ utf8 = PyString_AS_STRING(obj);
+ } else if (PyUnicode_Check(obj)) {
+ pyUTF8 = PyUnicode_AsUTF8String(obj);
+ if (pyUTF8 != NULL) {
+ utf8 = PyString_AS_STRING(pyUTF8);
+ }
+ } else {
+ PyErr_SetString(PyExc_TypeError,
+ "Context.text_path: text must be str or unicode");
+ }
+ if (utf8 == NULL)
+ return NULL;
+
+ cairo_text_path (o->ctx, utf8);
+ Py_XDECREF(pyUTF8);
+ RETURN_NULL_IF_CAIRO_CONTEXT_ERROR(o->ctx);
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+pycairo_transform (PycairoContext *o, PyObject *args) {
+ PycairoMatrix *matrix;
+
+ if (!PyArg_ParseTuple (args, "O!:Context.transform",
+ &PycairoMatrix_Type, &matrix))
+ return NULL;
+
+ cairo_transform (o->ctx, &matrix->matrix);
+ RETURN_NULL_IF_CAIRO_CONTEXT_ERROR(o->ctx);
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+pycairo_translate (PycairoContext *o, PyObject *args) {
+ double tx, ty;
+
+ if (!PyArg_ParseTuple (args, "dd:Context.translate", &tx, &ty))
+ return NULL;
+
+ cairo_translate (o->ctx, tx, ty);
+ RETURN_NULL_IF_CAIRO_CONTEXT_ERROR(o->ctx);
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+pycairo_user_to_device (PycairoContext *o, PyObject *args) {
+ double x, y;
+
+ if (!PyArg_ParseTuple (args, "dd:Context.user_to_device", &x, &y))
+ return NULL;
+
+ cairo_user_to_device (o->ctx, &x, &y);
+ RETURN_NULL_IF_CAIRO_CONTEXT_ERROR(o->ctx);
+ return Py_BuildValue("(dd)", x, y);
+}
+
+static PyObject *
+pycairo_user_to_device_distance (PycairoContext *o, PyObject *args) {
+ double dx, dy;
+
+ if (!PyArg_ParseTuple (args, "dd:Context.user_to_device_distance",
+ &dx, &dy))
+ return NULL;
+
+ cairo_user_to_device_distance (o->ctx, &dx, &dy);
+ RETURN_NULL_IF_CAIRO_CONTEXT_ERROR(o->ctx);
+ return Py_BuildValue("(dd)", dx, dy);
+}
+
+
+static PyMethodDef pycairo_methods[] = {
+ /* methods never exposed in a language binding:
+ * cairo_destroy()
+ * cairo_reference()
+ * cairo_rectangle_list_destroy()
+ *
+ * cairo_status()
+ * cairo_status_string()
+ * - not needed since Pycairo calls Pycairo_Check_Status() to check
+ * for errors and raise exceptions
+ */
+ {"append_path", (PyCFunction)pycairo_append_path, METH_VARARGS},
+ {"arc", (PyCFunction)pycairo_arc, METH_VARARGS},
+ {"arc_negative", (PyCFunction)pycairo_arc_negative, METH_VARARGS},
+ {"clip", (PyCFunction)pycairo_clip, METH_NOARGS},
+ {"clip_extents", (PyCFunction)pycairo_clip_extents, METH_NOARGS},
+ {"clip_preserve", (PyCFunction)pycairo_clip_preserve, METH_NOARGS},
+ {"close_path", (PyCFunction)pycairo_close_path, METH_NOARGS},
+ {"copy_clip_rectangle_list", (PyCFunction)pycairo_copy_clip_rectangle_list,
+ METH_NOARGS},
+ {"copy_page", (PyCFunction)pycairo_copy_page, METH_NOARGS},
+ {"copy_path", (PyCFunction)pycairo_copy_path, METH_NOARGS},
+ {"copy_path_flat", (PyCFunction)pycairo_copy_path_flat, METH_NOARGS},
+ {"curve_to", (PyCFunction)pycairo_curve_to, METH_VARARGS},
+ {"device_to_user", (PyCFunction)pycairo_device_to_user, METH_VARARGS},
+ {"device_to_user_distance", (PyCFunction)pycairo_device_to_user_distance,
+ METH_VARARGS},
+ {"fill", (PyCFunction)pycairo_fill, METH_NOARGS},
+ {"fill_extents", (PyCFunction)pycairo_fill_extents, METH_NOARGS},
+ {"fill_preserve", (PyCFunction)pycairo_fill_preserve, METH_NOARGS},
+ {"font_extents", (PyCFunction)pycairo_font_extents, METH_NOARGS},
+ {"get_antialias", (PyCFunction)pycairo_get_antialias, METH_NOARGS},
+ {"get_current_point",(PyCFunction)pycairo_get_current_point,METH_NOARGS},
+ {"get_dash", (PyCFunction)pycairo_get_dash, METH_NOARGS},
+ {"get_dash_count", (PyCFunction)pycairo_get_dash_count, METH_NOARGS},
+ {"get_fill_rule", (PyCFunction)pycairo_get_fill_rule, METH_NOARGS},
+ {"get_font_face", (PyCFunction)pycairo_get_font_face, METH_NOARGS},
+ {"get_font_matrix", (PyCFunction)pycairo_get_font_matrix, METH_NOARGS},
+ {"get_font_options",(PyCFunction)pycairo_get_font_options, METH_NOARGS},
+ {"get_group_target",(PyCFunction)pycairo_get_group_target, METH_NOARGS},
+ {"get_line_cap", (PyCFunction)pycairo_get_line_cap, METH_NOARGS},
+ {"get_line_join", (PyCFunction)pycairo_get_line_join, METH_NOARGS},
+ {"get_line_width", (PyCFunction)pycairo_get_line_width, METH_NOARGS},
+ {"get_matrix", (PyCFunction)pycairo_get_matrix, METH_NOARGS},
+ {"get_miter_limit", (PyCFunction)pycairo_get_miter_limit, METH_NOARGS},
+ {"get_operator", (PyCFunction)pycairo_get_operator, METH_NOARGS},
+ {"get_scaled_font", (PyCFunction)pycairo_get_scaled_font, METH_NOARGS},
+ {"get_source", (PyCFunction)pycairo_get_source, METH_NOARGS},
+ {"get_target", (PyCFunction)pycairo_get_target, METH_NOARGS},
+ {"get_tolerance", (PyCFunction)pycairo_get_tolerance, METH_NOARGS},
+ {"glyph_extents", (PyCFunction)pycairo_glyph_extents, METH_VARARGS},
+ {"glyph_path", (PyCFunction)pycairo_glyph_path, METH_VARARGS},
+ {"has_current_point",(PyCFunction)pycairo_has_current_point, METH_NOARGS},
+ {"identity_matrix", (PyCFunction)pycairo_identity_matrix, METH_NOARGS},
+ {"in_fill", (PyCFunction)pycairo_in_fill, METH_VARARGS},
+ {"in_stroke", (PyCFunction)pycairo_in_stroke, METH_VARARGS},
+ {"line_to", (PyCFunction)pycairo_line_to, METH_VARARGS},
+ {"mask", (PyCFunction)pycairo_mask, METH_VARARGS},
+ {"mask_surface", (PyCFunction)pycairo_mask_surface, METH_VARARGS},
+ {"move_to", (PyCFunction)pycairo_move_to, METH_VARARGS},
+ {"new_path", (PyCFunction)pycairo_new_path, METH_NOARGS},
+ {"new_sub_path", (PyCFunction)pycairo_new_sub_path, METH_NOARGS},
+ {"paint", (PyCFunction)pycairo_paint, METH_NOARGS},
+ {"paint_with_alpha",(PyCFunction)pycairo_paint_with_alpha, METH_VARARGS},
+ {"path_extents", (PyCFunction)pycairo_path_extents, METH_NOARGS},
+ {"pop_group", (PyCFunction)pycairo_pop_group, METH_NOARGS},
+ {"pop_group_to_source", (PyCFunction)pycairo_pop_group_to_source,
+ METH_NOARGS},
+ {"push_group", (PyCFunction)pycairo_push_group, METH_NOARGS},
+ {"push_group_with_content", (PyCFunction)pycairo_push_group_with_content,
+ METH_VARARGS},
+ {"rectangle", (PyCFunction)pycairo_rectangle, METH_VARARGS},
+ {"rel_curve_to", (PyCFunction)pycairo_rel_curve_to, METH_VARARGS},
+ {"rel_line_to", (PyCFunction)pycairo_rel_line_to, METH_VARARGS},
+ {"rel_move_to", (PyCFunction)pycairo_rel_move_to, METH_VARARGS},
+ {"reset_clip", (PyCFunction)pycairo_reset_clip, METH_NOARGS},
+ {"restore", (PyCFunction)pycairo_restore, METH_NOARGS},
+ {"rotate", (PyCFunction)pycairo_rotate, METH_VARARGS},
+ {"save", (PyCFunction)pycairo_save, METH_NOARGS},
+ {"scale", (PyCFunction)pycairo_scale, METH_VARARGS},
+ {"select_font_face",(PyCFunction)pycairo_select_font_face, METH_VARARGS},
+ {"set_antialias", (PyCFunction)pycairo_set_antialias, METH_VARARGS},
+ {"set_dash", (PyCFunction)pycairo_set_dash, METH_VARARGS},
+ {"set_fill_rule", (PyCFunction)pycairo_set_fill_rule, METH_VARARGS},
+ {"set_font_face", (PyCFunction)pycairo_set_font_face, METH_O},
+ {"set_font_matrix", (PyCFunction)pycairo_set_font_matrix, METH_VARARGS},
+ {"set_font_options",(PyCFunction)pycairo_set_font_options, METH_VARARGS},
+ {"set_font_size", (PyCFunction)pycairo_set_font_size, METH_VARARGS},
+ {"set_line_cap", (PyCFunction)pycairo_set_line_cap, METH_VARARGS},
+ {"set_line_join", (PyCFunction)pycairo_set_line_join, METH_VARARGS},
+ {"set_line_width", (PyCFunction)pycairo_set_line_width, METH_VARARGS},
+ {"set_matrix", (PyCFunction)pycairo_set_matrix, METH_VARARGS},
+ {"set_miter_limit", (PyCFunction)pycairo_set_miter_limit, METH_VARARGS},
+ {"set_operator", (PyCFunction)pycairo_set_operator, METH_VARARGS},
+ {"set_scaled_font", (PyCFunction)pycairo_set_scaled_font, METH_VARARGS},
+ {"set_source", (PyCFunction)pycairo_set_source, METH_VARARGS},
+ {"set_source_rgb", (PyCFunction)pycairo_set_source_rgb, METH_VARARGS},
+ {"set_source_rgba", (PyCFunction)pycairo_set_source_rgba, METH_VARARGS},
+ {"set_source_surface",(PyCFunction)pycairo_set_source_surface, METH_VARARGS},
+ {"set_tolerance", (PyCFunction)pycairo_set_tolerance, METH_VARARGS},
+ {"show_glyphs", (PyCFunction)pycairo_show_glyphs, METH_VARARGS},
+ {"show_page", (PyCFunction)pycairo_show_page, METH_NOARGS},
+ {"show_text", (PyCFunction)pycairo_show_text, METH_O},
+ {"stroke", (PyCFunction)pycairo_stroke, METH_NOARGS},
+ {"stroke_extents", (PyCFunction)pycairo_stroke_extents, METH_NOARGS},
+ {"stroke_preserve", (PyCFunction)pycairo_stroke_preserve, METH_NOARGS},
+ {"text_extents", (PyCFunction)pycairo_text_extents, METH_O},
+ {"text_path", (PyCFunction)pycairo_text_path, METH_O},
+ {"transform", (PyCFunction)pycairo_transform, METH_VARARGS},
+ {"translate", (PyCFunction)pycairo_translate, METH_VARARGS},
+ {"user_to_device", (PyCFunction)pycairo_user_to_device, METH_VARARGS},
+ {"user_to_device_distance",(PyCFunction)pycairo_user_to_device_distance,
+ METH_VARARGS},
+ {NULL, NULL, 0, NULL},
+};
+
+PyTypeObject PycairoContext_Type = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /* ob_size */
+ "cairo.Context", /* tp_name */
+ sizeof(PycairoContext), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)pycairo_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,/* tp_flags */
+ 0, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ pycairo_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ (newfunc)pycairo_new, /* tp_new */
+ 0, /* tp_free */
+ 0, /* tp_is_gc */
+ 0, /* tp_bases */
+};
diff --git a/src/font.c b/src/font.c
new file mode 100644
index 0000000..4377aeb
--- /dev/null
+++ b/src/font.c
@@ -0,0 +1,598 @@
+/* -*- mode: C; c-basic-offset: 2 -*-
+ *
+ * Copyright © 2003,2010 James Henstridge, Steven Chaplin
+ *
+ * This file is part of pycairo.
+ *
+ * Pycairo is free software: you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License version 3 as published
+ * by the Free Software Foundation.
+ *
+ * Pycairo is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with pycairo. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define PY_SSIZE_T_CLEAN
+#include <Python.h>
+
+#include "config.h"
+#include "private.h"
+
+
+/* class cairo.FontFace --------------------------------------------------- */
+
+/* PycairoFontFace_FromFontFace
+ * Create a new PycairoFontFace from a cairo_font_face_t
+ * font_face - a cairo_font_face_t to 'wrap' into a Python object.
+ * it is unreferenced if the PycairoFontFace creation fails
+ * Return value: New reference or NULL on failure
+ */
+PyObject *
+PycairoFontFace_FromFontFace (cairo_font_face_t *font_face) {
+ PyTypeObject *type = NULL;
+ PyObject *o;
+
+ assert (font_face != NULL);
+
+ if (Pycairo_Check_Status (cairo_font_face_status (font_face))) {
+ cairo_font_face_destroy (font_face);
+ return NULL;
+ }
+
+ switch (cairo_font_face_get_type (font_face)) {
+ case CAIRO_FONT_TYPE_TOY:
+ type = &PycairoToyFontFace_Type;
+ break;
+ default:
+ type = &PycairoFontFace_Type;
+ break;
+ }
+ o = type->tp_alloc (type, 0);
+ if (o == NULL)
+ cairo_font_face_destroy (font_face);
+ else
+ ((PycairoFontFace *)o)->font_face = font_face;
+ return o;
+}
+
+static void
+font_face_dealloc (PycairoFontFace *o) {
+ if (o->font_face) {
+ cairo_font_face_destroy (o->font_face);
+ o->font_face = NULL;
+ }
+ o->ob_type->tp_free((PyObject *) o);
+}
+
+static PyObject *
+font_face_new (PyTypeObject *type, PyObject *args, PyObject *kwds) {
+ PyErr_SetString (PyExc_TypeError, "The FontFace type cannot be "
+ "instantiated directly, use Context.get_font_face()");
+ return NULL;
+}
+
+/*
+static PyMethodDef font_face_methods[] = {
+ * methods never exposed in a language binding:
+ * cairo_font_face_destroy()
+ * cairo_font_face_get_user_data()
+ * cairo_font_face_get_type()
+ * cairo_font_face_reference()
+ * cairo_font_face_set_user_data(),
+ {NULL, NULL, 0, NULL},
+};
+*/
+
+PyTypeObject PycairoFontFace_Type = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /* ob_size */
+ "cairo.FontFace", /* tp_name */
+ sizeof(PycairoFontFace), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)font_face_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT, /* tp_flags */
+ 0, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ (newfunc)font_face_new, /* tp_new */
+ 0, /* tp_free */
+ 0, /* tp_is_gc */
+ 0, /* tp_bases */
+};
+
+
+/* class cairo.ToyFontFace ------------------------------------------------- */
+
+static PyObject *
+toy_font_face_new (PyTypeObject *type, PyObject *args, PyObject *kwds) {
+ PyObject *obj;
+ PyObject *pyUTF8 = NULL;
+ const char *utf8family = NULL;
+ cairo_font_slant_t slant = CAIRO_FONT_SLANT_NORMAL;
+ cairo_font_weight_t weight = CAIRO_FONT_WEIGHT_NORMAL;
+
+ if (!PyArg_ParseTuple(args, "O!|ii:ToyFontFace.__new__",
+ &PyBaseString_Type, &obj, &slant, &weight))
+ return NULL;
+
+ /* accept str and unicode family, auto convert to utf8 as required */
+ if (PyString_Check(obj)) {
+ /* A plain ASCII string is also a valid UTF-8 string */
+ utf8family = PyString_AS_STRING(obj);
+ } else if (PyUnicode_Check(obj)) {
+ pyUTF8 = PyUnicode_AsUTF8String(obj);
+ if (pyUTF8 != NULL) {
+ utf8family = PyString_AS_STRING(pyUTF8);
+ }
+ } else {
+ PyErr_SetString(PyExc_TypeError,
+ "ToyFontFace.__new__: family must be str or unicode");
+ }
+ if (utf8family == NULL)
+ return NULL;
+
+ PyObject *o = PycairoFontFace_FromFontFace (
+ cairo_toy_font_face_create (utf8family, slant, weight));
+ Py_XDECREF(pyUTF8);
+ return o;
+}
+
+static PyObject *
+toy_font_get_family (PycairoToyFontFace *o) {
+ return PyString_FromString (cairo_toy_font_face_get_family (o->font_face));
+}
+
+static PyObject *
+toy_font_get_slant (PycairoToyFontFace *o) {
+ return PyInt_FromLong (cairo_toy_font_face_get_slant (o->font_face));
+}
+
+static PyObject *
+toy_font_get_weight (PycairoToyFontFace *o) {
+ return PyInt_FromLong (cairo_toy_font_face_get_weight (o->font_face));
+}
+
+static PyMethodDef toy_font_face_methods[] = {
+ {"get_family", (PyCFunction)toy_font_get_family, METH_NOARGS},
+ {"get_slant", (PyCFunction)toy_font_get_slant, METH_NOARGS},
+ {"get_weight", (PyCFunction)toy_font_get_weight, METH_NOARGS},
+ {NULL, NULL, 0, NULL},
+};
+
+
+PyTypeObject PycairoToyFontFace_Type = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /* ob_size */
+ "cairo.ToyFontFace", /* tp_name */
+ sizeof(PycairoToyFontFace), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT, /* tp_flags */
+ 0, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ toy_font_face_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &PycairoFontFace_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ (newfunc)toy_font_face_new, /* tp_new */
+ 0, /* tp_free */
+ 0, /* tp_is_gc */
+ 0, /* tp_bases */
+};
+
+
+/* class cairo.ScaledFont ------------------------------------------------- */
+
+/* PycairoScaledFont_FromScaledFont
+ * Create a new PycairoScaledFont from a cairo_scaled_font_t
+ * scaled_font - a cairo_scaled_font_t to 'wrap' into a Python object.
+ * it is unreferenced if the PycairoScaledFont creation fails
+ * Return value: New reference or NULL on failure
+ */
+PyObject *
+PycairoScaledFont_FromScaledFont (cairo_scaled_font_t *scaled_font) {
+ PyObject *o;
+
+ assert (scaled_font != NULL);
+
+ if (Pycairo_Check_Status (cairo_scaled_font_status (scaled_font))) {
+ cairo_scaled_font_destroy (scaled_font);
+ return NULL;
+ }
+
+ o = PycairoScaledFont_Type.tp_alloc (&PycairoScaledFont_Type, 0);
+ if (o == NULL)
+ cairo_scaled_font_destroy (scaled_font);
+ else
+ ((PycairoScaledFont *)o)->scaled_font = scaled_font;
+ return o;
+}
+
+static void
+scaled_font_dealloc(PycairoScaledFont *o) {
+ if (o->scaled_font) {
+ cairo_scaled_font_destroy (o->scaled_font);
+ o->scaled_font = NULL;
+ }
+ o->ob_type->tp_free((PyObject *) o);
+}
+
+static PyObject *
+scaled_font_new (PyTypeObject *type, PyObject *args, PyObject *kwds) {
+ PycairoFontFace *ff;
+ PycairoFontOptions *fo;
+ PycairoMatrix *mx1, *mx2;
+
+ if (!PyArg_ParseTuple(args, "O!O!O!O!:ScaledFont.__new__",
+ &PycairoFontFace_Type, &ff,
+ &PycairoMatrix_Type, &mx1,
+ &PycairoMatrix_Type, &mx2,
+ &PycairoFontOptions_Type, &fo))
+ return NULL;
+ return PycairoScaledFont_FromScaledFont (
+ cairo_scaled_font_create (ff->font_face, &mx1->matrix,
+ &mx2->matrix, fo->font_options));
+}
+
+static PyObject *
+scaled_font_extents (PycairoScaledFont *o) {
+ cairo_font_extents_t e;
+
+ cairo_scaled_font_extents (o->scaled_font, &e);
+ RETURN_NULL_IF_CAIRO_SCALED_FONT_ERROR(o->scaled_font);
+ return Py_BuildValue ("(ddddd)", e.ascent, e.descent, e.height,
+ e.max_x_advance, e.max_y_advance);
+}
+
+static PyObject *
+scaled_font_get_font_face (PycairoScaledFont *o) {
+ return PycairoFontFace_FromFontFace (
+ cairo_font_face_reference (
+ cairo_scaled_font_get_font_face (o->scaled_font)));
+}
+
+static PyObject *
+scaled_font_get_scale_matrix (PycairoScaledFont *o) {
+ cairo_matrix_t matrix;
+ cairo_scaled_font_get_scale_matrix (o->scaled_font, &matrix);
+ return PycairoMatrix_FromMatrix (&matrix);
+}
+
+static PyObject *
+scaled_font_text_extents (PycairoScaledFont *o, PyObject *obj) {
+ cairo_text_extents_t extents;
+ PyObject *pyUTF8 = NULL;
+ const char *utf8 = NULL;
+
+ /* accept str and unicode text, auto convert to utf8 as required */
+ if (PyString_Check(obj)) {
+ /* A plain ASCII string is also a valid UTF-8 string */
+ utf8 = PyString_AS_STRING(obj);
+ } else if (PyUnicode_Check(obj)) {
+ pyUTF8 = PyUnicode_AsUTF8String(obj);
+ if (pyUTF8 != NULL) {
+ utf8 = PyString_AS_STRING(pyUTF8);
+ }
+ } else {
+ PyErr_SetString(PyExc_TypeError,
+ "ScaledFont.text_extents: text must be str or unicode");
+ }
+ if (utf8 == NULL)
+ return NULL;
+
+ cairo_scaled_font_text_extents (o->scaled_font, utf8, &extents);
+ Py_XDECREF(pyUTF8);
+ RETURN_NULL_IF_CAIRO_SCALED_FONT_ERROR(o->scaled_font);
+ return Py_BuildValue("(dddddd)", extents.x_bearing, extents.y_bearing,
+ extents.width, extents.height, extents.x_advance,
+ extents.y_advance);
+}
+
+static PyMethodDef scaled_font_methods[] = {
+ /* methods never exposed in a language binding:
+ * cairo_scaled_font_destroy()
+ * cairo_scaled_font_get_type()
+ * cairo_scaled_font_reference()
+ *
+ * TODO if requested:
+ * cairo_scaled_font_get_ctm
+ * cairo_scaled_font_get_font_matrix
+ * cairo_scaled_font_get_font_options
+ * cairo_scaled_font_glyph_extents
+ * cairo_scaled_font_text_to_glyphs
+ */
+ {"extents", (PyCFunction)scaled_font_extents, METH_NOARGS},
+ {"get_font_face", (PyCFunction)scaled_font_get_font_face, METH_NOARGS},
+ {"get_scale_matrix", (PyCFunction)scaled_font_get_scale_matrix, METH_VARARGS},
+ {"text_extents", (PyCFunction)scaled_font_text_extents, METH_O},
+ {NULL, NULL, 0, NULL},
+};
+
+
+PyTypeObject PycairoScaledFont_Type = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /* ob_size */
+ "cairo.ScaledFont", /* tp_name */
+ sizeof(PycairoScaledFont), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)scaled_font_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT, /* tp_flags */
+ 0, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ scaled_font_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ (newfunc)scaled_font_new, /* tp_new */
+ 0, /* tp_free */
+ 0, /* tp_is_gc */
+ 0, /* tp_bases */
+};
+
+
+/* class cairo.FontOptions ------------------------------------------------ */
+
+/* PycairoFontOptions_FromFontOptions
+ * Create a new PycairoFontOptions from a cairo_font_options_t
+ * font_options - a cairo_font_options_t to 'wrap' into a Python object.
+ * it is unreferenced if the PycairoFontOptions creation fails
+ * Return value: New reference or NULL on failure
+ */
+PyObject *
+PycairoFontOptions_FromFontOptions (cairo_font_options_t *font_options) {
+ PyObject *o;
+
+ assert (font_options != NULL);
+
+ if (Pycairo_Check_Status (cairo_font_options_status (font_options))) {
+ cairo_font_options_destroy (font_options);
+ return NULL;
+ }
+
+ o = PycairoFontOptions_Type.tp_alloc (&PycairoFontOptions_Type, 0);
+ if (o == NULL)
+ cairo_font_options_destroy (font_options);
+ else
+ ((PycairoFontOptions *)o)->font_options = font_options;
+ return o;
+}
+
+static void
+font_options_dealloc(PycairoFontOptions *o) {
+ if (o->font_options) {
+ cairo_font_options_destroy (o->font_options);
+ o->font_options = NULL;
+ }
+ o->ob_type->tp_free((PyObject *) o);
+}
+
+static PyObject *
+font_options_new (PyTypeObject *type, PyObject *args, PyObject *kwds) {
+ return PycairoFontOptions_FromFontOptions (cairo_font_options_create());
+}
+
+static PyObject *
+font_options_get_antialias (PycairoFontOptions *o) {
+ return PyInt_FromLong (cairo_font_options_get_antialias (o->font_options));
+}
+
+static PyObject *
+font_options_get_hint_metrics (PycairoFontOptions *o) {
+ return PyInt_FromLong (cairo_font_options_get_hint_metrics
+ (o->font_options));
+}
+
+static PyObject *
+font_options_get_hint_style (PycairoFontOptions *o) {
+ return PyInt_FromLong (cairo_font_options_get_hint_style
+ (o->font_options));
+}
+
+static PyObject *
+font_options_get_subpixel_order (PycairoFontOptions *o) {
+ return PyInt_FromLong (cairo_font_options_get_subpixel_order
+ (o->font_options));
+}
+
+static PyObject *
+font_options_set_antialias (PycairoFontOptions *o, PyObject *args) {
+ cairo_antialias_t aa = CAIRO_ANTIALIAS_DEFAULT;
+
+ if (!PyArg_ParseTuple(args, "|i:FontOptions.set_antialias", &aa))
+ return NULL;
+
+ cairo_font_options_set_antialias (o->font_options, aa);
+ RETURN_NULL_IF_CAIRO_FONT_OPTIONS_ERROR(o->font_options);
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+font_options_set_hint_metrics (PycairoFontOptions *o, PyObject *args) {
+ cairo_hint_metrics_t hm = CAIRO_HINT_METRICS_DEFAULT;
+
+ if (!PyArg_ParseTuple(args, "|i:FontOptions.set_hint_metrics", &hm))
+ return NULL;
+
+ cairo_font_options_set_hint_metrics (o->font_options, hm);
+ RETURN_NULL_IF_CAIRO_FONT_OPTIONS_ERROR(o->font_options);
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+font_options_set_hint_style (PycairoFontOptions *o, PyObject *args) {
+ cairo_hint_style_t hs = CAIRO_HINT_STYLE_DEFAULT;
+
+ if (!PyArg_ParseTuple(args, "|i:FontOptions.set_hint_style", &hs))
+ return NULL;
+
+ cairo_font_options_set_hint_style (o->font_options, hs);
+ RETURN_NULL_IF_CAIRO_FONT_OPTIONS_ERROR(o->font_options);
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+font_options_set_subpixel_order (PycairoFontOptions *o, PyObject *args) {
+ cairo_subpixel_order_t so = CAIRO_SUBPIXEL_ORDER_DEFAULT;
+
+ if (!PyArg_ParseTuple(args, "|i:FontOptions.set_subpixel_order", &so))
+ return NULL;
+
+ cairo_font_options_set_subpixel_order (o->font_options, so);
+ RETURN_NULL_IF_CAIRO_FONT_OPTIONS_ERROR(o->font_options);
+ Py_RETURN_NONE;
+}
+
+
+static PyMethodDef font_options_methods[] = {
+ /* methods never exposed in a language binding:
+ * cairo_font_options_destroy()
+ * cairo_font_options_reference()
+ */
+ /* TODO: */
+ /* copy */
+ /* hash */
+ /* merge */
+ /* equal (richcmp?) */
+ {"get_antialias", (PyCFunction)font_options_get_antialias, METH_NOARGS},
+ {"get_hint_metrics", (PyCFunction)font_options_get_hint_metrics,
+ METH_NOARGS},
+ {"get_hint_style", (PyCFunction)font_options_get_hint_style, METH_NOARGS},
+ {"get_subpixel_order",(PyCFunction)font_options_get_subpixel_order,
+ METH_NOARGS},
+ {"set_antialias", (PyCFunction)font_options_set_antialias, METH_VARARGS},
+ {"set_hint_metrics", (PyCFunction)font_options_set_hint_metrics,
+ METH_VARARGS},
+ {"set_hint_style", (PyCFunction)font_options_set_hint_style, METH_VARARGS},
+ {"set_subpixel_order",(PyCFunction)font_options_set_subpixel_order,
+ METH_VARARGS},
+ {NULL, NULL, 0, NULL},
+};
+
+
+PyTypeObject PycairoFontOptions_Type = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /* ob_size */
+ "cairo.FontOptions", /* tp_name */
+ sizeof(PycairoFontOptions), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)font_options_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT, /* tp_flags */
+ 0, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ font_options_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ (newfunc)font_options_new, /* tp_new */
+ 0, /* tp_free */
+ 0, /* tp_is_gc */
+ 0, /* tp_bases */
+};
diff --git a/src/matrix.c b/src/matrix.c
new file mode 100644
index 0000000..98ccd9f
--- /dev/null
+++ b/src/matrix.c
@@ -0,0 +1,332 @@
+/* -*- mode: C; c-basic-offset: 2 -*-
+ *
+ * Copyright © 2003,2010 James Henstridge, Steven Chaplin
+ *
+ * This file is part of pycairo.
+ *
+ * Pycairo is free software: you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License version 3 as published
+ * by the Free Software Foundation.
+ *
+ * Pycairo is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with pycairo. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define PY_SSIZE_T_CLEAN
+#include <Python.h>
+
+#include "config.h"
+#include "private.h"
+
+
+/* PycairoMatrix_FromMatrix
+ * Create a new PycairoMatrix from a cairo_matrix_t
+ * matrix - a cairo_matrix_t to 'wrap' into a Python object.
+ * the cairo_matrix_t values are copied.
+ * Return value: New reference or NULL on failure
+ */
+PyObject *
+PycairoMatrix_FromMatrix (const cairo_matrix_t *matrix) {
+ assert (matrix != NULL);
+ PyObject *o = PycairoMatrix_Type.tp_alloc (&PycairoMatrix_Type, 0);
+ if (o != NULL)
+ ((PycairoMatrix *)o)->matrix = *matrix; // copy struct
+ return o;
+}
+
+static void
+matrix_dealloc (PycairoMatrix *o) {
+ o->ob_type->tp_free((PyObject *)o);
+}
+
+static PyObject *
+matrix_new (PyTypeObject *type, PyObject *args, PyObject *kwds) {
+ static char *kwlist[] = { "xx", "yx", "xy", "yy", "x0", "y0", NULL };
+ double xx = 1.0, yx = 0.0, xy = 0.0, yy = 1.0, x0 = 0.0, y0 = 0.0;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds,
+ "|dddddd:Matrix.__init__", kwlist,
+ &xx, &yx, &xy, &yy, &x0, &y0))
+ return NULL;
+
+ cairo_matrix_t mx;
+ cairo_matrix_init (&mx, xx, yx, xy, yy, x0, y0);
+ return PycairoMatrix_FromMatrix (&mx);
+}
+
+static PyObject *
+matrix_init_rotate (PyTypeObject *type, PyObject *args) {
+ cairo_matrix_t matrix;
+ double radians;
+
+ if (!PyArg_ParseTuple(args, "d:Matrix.init_rotate", &radians))
+ return NULL;
+
+ cairo_matrix_init_rotate (&matrix, radians);
+ return PycairoMatrix_FromMatrix (&matrix);
+}
+
+static PyObject *
+matrix_invert (PycairoMatrix *o) {
+ if (Pycairo_Check_Status (cairo_matrix_invert (&o->matrix)))
+ return NULL;
+ Py_RETURN_NONE;
+}
+
+/* cairo_matrix_multiply */
+static PyObject *
+matrix_multiply (PycairoMatrix *o, PyObject *args) {
+ PycairoMatrix *mx2;
+
+ if (!PyArg_ParseTuple(args, "O!:Matrix.multiply",
+ &PycairoMatrix_Type, &mx2))
+ return NULL;
+
+ cairo_matrix_t result;
+ cairo_matrix_multiply (&result, &o->matrix, &mx2->matrix);
+ return PycairoMatrix_FromMatrix (&result);
+}
+
+/* standard matrix multiply, for use by '*' operator */
+static PyObject *
+matrix_operator_multiply (PycairoMatrix *o, PycairoMatrix *o2) {
+ cairo_matrix_t result;
+ cairo_matrix_multiply (&result, &o->matrix, &o2->matrix);
+ return PycairoMatrix_FromMatrix (&result);
+}
+
+static PyObject *
+matrix_repr (PycairoMatrix *o) {
+ char buf[256];
+
+ PyOS_snprintf(buf, sizeof(buf), "cairo.Matrix(%g, %g, %g, %g, %g, %g)",
+ o->matrix.xx, o->matrix.yx,
+ o->matrix.xy, o->matrix.yy,
+ o->matrix.x0, o->matrix.y0);
+ return PyString_FromString(buf);
+}
+
+static PyObject *
+matrix_richcmp (PycairoMatrix *m1, PycairoMatrix *m2, int op) {
+ int equal;
+ PyObject *ret;
+ cairo_matrix_t *mx1 = &m1->matrix;
+ cairo_matrix_t *mx2 = &m2->matrix;
+
+ if (!PyObject_TypeCheck(m2, &PycairoMatrix_Type) ||
+ !(op == Py_EQ || op == Py_NE)) {
+ Py_INCREF(Py_NotImplemented);
+ return Py_NotImplemented;
+ }
+
+ equal = mx1->xx == mx2->xx && mx1->yx == mx2->yx &&
+ mx1->xy == mx2->xy && mx1->yy == mx2->yy &&
+ mx1->x0 == mx2->x0 && mx1->y0 == mx2->y0;
+
+ if (op == Py_EQ)
+ ret = equal ? Py_True : Py_False;
+ else
+ ret = equal ? Py_False : Py_True;
+ Py_INCREF(ret);
+ return ret;
+}
+
+static PyObject *
+matrix_rotate (PycairoMatrix *o, PyObject *args) {
+ double radians;
+
+ if (!PyArg_ParseTuple(args, "d:Matrix.rotate", &radians))
+ return NULL;
+
+ cairo_matrix_rotate (&o->matrix, radians);
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+matrix_scale (PycairoMatrix *o, PyObject *args) {
+ double sx, sy;
+
+ if (!PyArg_ParseTuple(args, "dd:Matrix.scale", &sx, &sy))
+ return NULL;
+
+ cairo_matrix_scale (&o->matrix, sx, sy);
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+matrix_transform_distance (PycairoMatrix *o, PyObject *args) {
+ double dx, dy;
+
+ if (!PyArg_ParseTuple(args, "dd:Matrix.transform_distance", &dx, &dy))
+ return NULL;
+
+ cairo_matrix_transform_distance (&o->matrix, &dx, &dy);
+ return Py_BuildValue("(dd)", dx, dy);
+}
+
+static PyObject *
+matrix_transform_point (PycairoMatrix *o, PyObject *args) {
+ double x, y;
+
+ if (!PyArg_ParseTuple(args, "dd:Matrix.transform_point", &x, &y))
+ return NULL;
+
+ cairo_matrix_transform_point (&o->matrix, &x, &y);
+ return Py_BuildValue("(dd)", x, y);
+}
+
+static PyObject *
+matrix_translate (PycairoMatrix *o, PyObject *args) {
+ double tx, ty;
+
+ if (!PyArg_ParseTuple(args, "dd:Matrix.translate", &tx, &ty))
+ return NULL;
+
+ cairo_matrix_translate (&o->matrix, tx, ty);
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+matrix_item (PycairoMatrix *o, Py_ssize_t i) {
+ switch (i) {
+ case 0:
+ return Py_BuildValue("d", o->matrix.xx);
+ case 1:
+ return Py_BuildValue("d", o->matrix.yx);
+ case 2:
+ return Py_BuildValue("d", o->matrix.xy);
+ case 3:
+ return Py_BuildValue("d", o->matrix.yy);
+ case 4:
+ return Py_BuildValue("d", o->matrix.x0);
+ case 5:
+ return Py_BuildValue("d", o->matrix.y0);
+ default:
+ PyErr_SetString(PyExc_IndexError, "Matrix index out of range");
+ return NULL;
+ }
+}
+
+static PyNumberMethods matrix_as_number = {
+ (binaryfunc)0, /*nb_add*/
+ (binaryfunc)0, /*nb_subtract*/
+ (binaryfunc)matrix_operator_multiply, /*nb_multiply*/
+ (binaryfunc)0, /*nb_divide*/
+ (binaryfunc)0, /*nb_remainder*/
+ (binaryfunc)0, /*nb_divmod*/
+ (ternaryfunc)0, /*nb_power*/
+ (unaryfunc)0, /*nb_negative*/
+ (unaryfunc)0, /*nb_positive*/
+ (unaryfunc)0, /*nb_absolute*/
+ (inquiry)0, /*nb_nonzero*/
+ (unaryfunc)0, /*nb_invert*/
+ (binaryfunc)0, /*nb_lshift*/
+ (binaryfunc)0, /*nb_rshift*/
+ (binaryfunc)0, /*nb_and*/
+ (binaryfunc)0, /*nb_xor*/
+ (binaryfunc)0, /*nb_or*/
+ (coercion)0, /*nb_coerce*/
+ (unaryfunc)0, /*nb_int*/
+ (unaryfunc)0, /*nb_long*/
+ (unaryfunc)0, /*nb_float*/
+ (unaryfunc)0, /*nb_oct*/
+ (unaryfunc)0, /*nb_hex*/
+ 0, /*nb_inplace_add*/
+ 0, /*nb_inplace_subtract*/
+ 0, /*nb_inplace_multiply*/
+ 0, /*nb_inplace_divide*/
+ 0, /*nb_inplace_remainder*/
+ 0, /*nb_inplace_power*/
+ 0, /*nb_inplace_lshift*/
+ 0, /*nb_inplace_rshift*/
+ 0, /*nb_inplace_and*/
+ 0, /*nb_inplace_xor*/
+ 0, /*nb_inplace_or*/
+ (binaryfunc)0, /* nb_floor_divide */
+ 0, /* nb_true_divide */
+ 0, /* nb_inplace_floor_divide */
+ 0, /* nb_inplace_true_divide */
+ (unaryfunc)0, /* nb_index */
+};
+
+static PySequenceMethods matrix_as_sequence = {
+ 0, /* sq_length */
+ 0, /* sq_concat */
+ 0, /* sq_repeat */
+ (ssizeargfunc)matrix_item, /* sq_item */
+ 0, /* sq_slice */
+ 0, /* sq_ass_item */
+ 0, /* sq_ass_slice */
+ 0, /* sq_contains */
+};
+
+static PyMethodDef matrix_methods[] = {
+ /* Do not need to wrap all cairo_matrix_init_*() functions
+ * C API Matrix constructors Python equivalents
+ * cairo_matrix_init() cairo.Matrix(xx,yx,xy,yy,x0,y0)
+ * cairo_matrix_init_rotate() cairo.Matrix.init_rotate(radians)
+
+ * cairo_matrix_init_identity() cairo.Matrix()
+ * cairo_matrix_init_translate() cairo.Matrix(x0=x0,y0=y0)
+ * cairo_matrix_init_scale() cairo.Matrix(xx=xx,yy=yy)
+ */
+ {"init_rotate", (PyCFunction)matrix_init_rotate, METH_VARARGS | METH_CLASS },
+ {"invert", (PyCFunction)matrix_invert, METH_NOARGS },
+ {"multiply", (PyCFunction)matrix_multiply, METH_VARARGS },
+ {"rotate", (PyCFunction)matrix_rotate, METH_VARARGS },
+ {"scale", (PyCFunction)matrix_scale, METH_VARARGS },
+ {"transform_distance",(PyCFunction)matrix_transform_distance, METH_VARARGS },
+ {"transform_point", (PyCFunction)matrix_transform_point, METH_VARARGS },
+ {"translate", (PyCFunction)matrix_translate, METH_VARARGS },
+ {NULL, NULL, 0, NULL},
+};
+
+PyTypeObject PycairoMatrix_Type = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /* ob_size */
+ "cairo.Matrix", /* tp_name */
+ sizeof(PycairoMatrix), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)matrix_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ (reprfunc)matrix_repr, /* tp_repr */
+ &matrix_as_number, /* tp_as_number */
+ &matrix_as_sequence, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT, /* tp_flags */
+ NULL, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ (richcmpfunc)matrix_richcmp, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ matrix_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ (newfunc)matrix_new, /* tp_new */
+ 0, /* tp_free */
+ 0, /* tp_is_gc */
+ 0, /* tp_bases */
+};
diff --git a/src/path.c b/src/path.c
new file mode 100644
index 0000000..394f25c
--- /dev/null
+++ b/src/path.c
@@ -0,0 +1,316 @@
+/* -*- mode: C; c-basic-offset: 2 -*-
+ *
+ * Copyright © 2005,2010 Steve Chaplin
+ *
+ * This file is part of pycairo.
+ *
+ * Pycairo is free software: you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License version 3 as published
+ * by the Free Software Foundation.
+ *
+ * Pycairo is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with pycairo. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define PY_SSIZE_T_CLEAN
+#include <Python.h>
+
+#include "config.h"
+#include "private.h"
+
+
+/* PycairoPath iterator object
+ * modelled on Python-2.4/Objects/rangeobject.c and tupleobject.c
+ */
+
+/* PycairoPath_FromPath
+ * Create a new PycairoPath from a cairo_path_t
+ * path - a cairo_path_t to 'wrap' into a Python object.
+ * path is unreferenced if the PycairoPath creation fails, or if path
+ * is in an error status.
+ * Return value: New reference or NULL on failure
+ */
+PyObject *
+PycairoPath_FromPath (cairo_path_t *path) {
+ PyObject *o;
+
+ assert (path != NULL);
+
+ if (Pycairo_Check_Status (path->status)) {
+ cairo_path_destroy (path);
+ return NULL;
+ }
+
+ o = PycairoPath_Type.tp_alloc (&PycairoPath_Type, 0);
+ if (o)
+ ((PycairoPath *)o)->path = path;
+ else
+ cairo_path_destroy (path);
+ return o;
+}
+
+static void
+path_dealloc(PycairoPath *p) {
+#ifdef DEBUG
+ printf("path_dealloc start\n");
+#endif
+ if (p->path) {
+ cairo_path_destroy(p->path);
+ p->path = NULL;
+ }
+ p->ob_type->tp_free((PyObject *)p);
+#ifdef DEBUG
+ printf("path_dealloc end\n");
+#endif
+}
+
+static PyObject *
+path_new(PyTypeObject *type, PyObject *args, PyObject *kwds) {
+ return type->tp_alloc(type, 0);
+ /* initializes memory to zeros */
+}
+
+static int
+path_init(PycairoPath *p, PyObject *args, PyObject *kwds) {
+ PyErr_SetString(PyExc_TypeError, "The Path type cannot be instantiated, "
+ "use Context.copy_path()");
+ return -1;
+}
+
+static PyObject *
+path_str(PycairoPath *p) {
+ PyObject *s, *pieces = NULL, *result = NULL;
+ cairo_path_t *path = p->path;
+ cairo_path_data_t *data;
+ int i, ret;
+ char buf[80];
+
+ pieces = PyList_New(0);
+ if (pieces == NULL)
+ goto Done;
+
+ /* loop reading elements */
+ 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:
+ PyOS_snprintf(buf, sizeof(buf), "move_to %f %f",
+ data[1].point.x, data[1].point.y);
+ s = PyString_FromString(buf);
+ if (!s)
+ goto Done;
+ ret = PyList_Append(pieces, s);
+ Py_DECREF(s);
+ if (ret < 0)
+ goto Done;
+ break;
+
+ case CAIRO_PATH_LINE_TO:
+ PyOS_snprintf(buf, sizeof(buf), "line_to %f %f",
+ data[1].point.x, data[1].point.y);
+ s = PyString_FromString(buf);
+ if (!s)
+ goto Done;
+ ret = PyList_Append(pieces, s);
+ Py_DECREF(s);
+ if (ret < 0)
+ goto Done;
+ break;
+
+ case CAIRO_PATH_CURVE_TO:
+ PyOS_snprintf(buf, sizeof(buf), "curve_to %f %f %f %f %f %f",
+ data[1].point.x, data[1].point.y,
+ data[2].point.x, data[2].point.y,
+ data[3].point.x, data[3].point.y);
+ s = PyString_FromString(buf);
+ if (!s)
+ goto Done;
+ ret = PyList_Append(pieces, s);
+ Py_DECREF(s);
+ if (ret < 0)
+ goto Done;
+ break;
+
+ case CAIRO_PATH_CLOSE_PATH:
+ s = PyString_FromString("close path");
+ if (!s)
+ goto Done;
+ ret = PyList_Append(pieces, s);
+ Py_DECREF(s);
+ if (ret < 0)
+ goto Done;
+ break;
+ }
+ }
+ /* result = "\n".join(pieces) */
+ s = PyString_FromString("\n");
+ if (s == NULL)
+ goto Done;
+ result = _PyString_Join(s, pieces);
+ Py_DECREF(s);
+
+Done:
+ Py_XDECREF(pieces);
+ return result;
+}
+
+static PyObject * path_iter(PyObject *seq); /* forward declaration */
+
+
+PyTypeObject PycairoPath_Type = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /* ob_size */
+ "cairo.Path", /* tp_name */
+ sizeof(PycairoPath), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)path_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ (reprfunc)path_str, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT, /* tp_flags */
+ 0, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ (getiterfunc)path_iter, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)path_init, /* tp_init */
+ 0, /* tp_alloc */
+ (newfunc)path_new, /* tp_new */
+};
+
+/*********************** PycairoPath Iterator **************************/
+
+typedef struct {
+ PyObject_HEAD
+ int index; /* position within PycairoPath */
+ PycairoPath *pypath; /* Set to NULL when iterator is exhausted */
+} PycairoPathiter;
+
+PyTypeObject PycairoPathiter_Type;
+
+
+static void
+pathiter_dealloc(PycairoPathiter *it) {
+ Py_XDECREF(it->pypath);
+ PyObject_Del(it);
+}
+
+static PyObject *
+path_iter(PyObject *pypath) {
+ PycairoPathiter *it;
+
+ if (!PyObject_TypeCheck (pypath, &PycairoPath_Type)) {
+ PyErr_BadInternalCall();
+ return NULL;
+ }
+ it = PyObject_New(PycairoPathiter, &PycairoPathiter_Type);
+ if (it == NULL)
+ return NULL;
+
+ it->index = 0;
+ Py_INCREF(pypath);
+ it->pypath = (PycairoPath *)pypath;
+ return (PyObject *) it;
+}
+
+static PyObject *
+pathiter_next(PycairoPathiter *it) {
+ PycairoPath *pypath;
+ cairo_path_t *path;
+
+ assert(it != NULL);
+ pypath = it->pypath;
+ if (pypath == NULL)
+ return NULL;
+ assert (PyObject_TypeCheck (pypath, &PycairoPath_Type));
+ path = pypath->path;
+
+ /* return the next path element, advance index */
+ if (it->index < path->num_data) {
+ cairo_path_data_t *data = &path->data[it->index];
+ int type = data->header.type;
+
+ it->index += data[0].header.length;
+
+ switch (type) {
+ case CAIRO_PATH_MOVE_TO:
+ case CAIRO_PATH_LINE_TO:
+ return Py_BuildValue("(i(dd))", type,
+ data[1].point.x, data[1].point.y);
+ case CAIRO_PATH_CURVE_TO:
+ return Py_BuildValue("(i(dddddd))", type,
+ data[1].point.x, data[1].point.y,
+ data[2].point.x, data[2].point.y,
+ data[3].point.x, data[3].point.y);
+ case CAIRO_PATH_CLOSE_PATH:
+ return Py_BuildValue("i()", type);
+ default:
+ PyErr_SetString(PyExc_RuntimeError, "unknown CAIRO_PATH type");
+ return NULL;
+ }
+ }
+
+ /* iterator has no remaining items */
+ Py_DECREF(pypath);
+ it->pypath = NULL;
+ return NULL;
+}
+
+PyTypeObject PycairoPathiter_Type = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /* ob_size */
+ "cairo.Pathiter", /* tp_name */
+ sizeof(PycairoPathiter), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)pathiter_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT, /* tp_flags */
+ 0, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* PyObject_SelfIter, */ /* tp_iter */
+ (iternextfunc)pathiter_next, /* tp_iternext */
+ 0, /* tp_methods */
+};
diff --git a/src/pattern.c b/src/pattern.c
new file mode 100644
index 0000000..0676114
--- /dev/null
+++ b/src/pattern.c
@@ -0,0 +1,585 @@
+/* -*- mode: C; c-basic-offset: 2 -*-
+ *
+ * Copyright © 2004-2006,2010 Steve Chaplin
+ *
+ * This file is part of pycairo.
+ *
+ * Pycairo is free software: you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License version 3 as published
+ * by the Free Software Foundation.
+ *
+ * Pycairo is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with pycairo. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define PY_SSIZE_T_CLEAN
+#include <Python.h>
+
+#include "config.h"
+#include "private.h"
+
+
+/* Class Pattern ---------------------------------------------------------- */
+
+/* PycairoPattern_FromPattern
+ * Create a new
+ * PycairoSolidPattern,
+ * PycairoSurfacePattern,
+ * PycairoLinearGradient, or
+ * PycairoRadialGradient from a cairo_pattern_t.
+ * pattern - a cairo_pattern_t to 'wrap' into a Python object.
+ * It is unreferenced if the PycairoPattern creation fails, or if the
+ * pattern has an error status.
+ * base - the base object used to create the pattern, or NULL.
+ * It is referenced to keep it alive while the cairo_pattern_t is being used.
+ * For PycairoSurfacePattern base should be the PycairoSurface, for other
+ # patterns it should be NULL.
+ * Return value: New reference or NULL on failure
+ */
+PyObject *
+PycairoPattern_FromPattern (cairo_pattern_t *pattern, PyObject *base) {
+ PyTypeObject *type = NULL;
+ PyObject *o;
+
+ assert (pattern != NULL);
+
+ if (Pycairo_Check_Status (cairo_pattern_status (pattern))) {
+ cairo_pattern_destroy (pattern);
+ return NULL;
+ }
+
+ switch (cairo_pattern_get_type (pattern)) {
+ case CAIRO_PATTERN_TYPE_SOLID:
+ type = &PycairoSolidPattern_Type;
+ break;
+ case CAIRO_PATTERN_TYPE_SURFACE:
+ type = &PycairoSurfacePattern_Type;
+ break;
+ case CAIRO_PATTERN_TYPE_LINEAR:
+ type = &PycairoLinearGradient_Type;
+ break;
+ case CAIRO_PATTERN_TYPE_RADIAL:
+ type = &PycairoRadialGradient_Type;
+ break;
+ default:
+ type = &PycairoPattern_Type;
+ break;
+ }
+
+ o = type->tp_alloc(type, 0);
+ if (o == NULL) {
+ cairo_pattern_destroy (pattern);
+ } else {
+ ((PycairoPattern *)o)->pattern = pattern;
+ Py_XINCREF(base);
+ ((PycairoPattern *)o)->base = base;
+ }
+ return o;
+}
+
+static void
+pattern_dealloc (PycairoPattern *o) {
+ if (o->pattern) {
+ cairo_pattern_destroy (o->pattern);
+ o->pattern = NULL;
+ }
+ Py_CLEAR(o->base);
+
+ o->ob_type->tp_free((PyObject *)o);
+}
+
+static PyObject *
+pattern_new (PyTypeObject *type, PyObject *args, PyObject *kwds) {
+ PyErr_SetString(PyExc_TypeError,
+ "The Pattern type cannot be instantiated");
+ return NULL;
+}
+
+static PyObject *
+pattern_get_extend (PycairoPattern *o) {
+ return PyInt_FromLong (cairo_pattern_get_extend (o->pattern));
+}
+
+static PyObject *
+pattern_get_matrix (PycairoPattern *o) {
+ cairo_matrix_t matrix;
+ cairo_pattern_get_matrix (o->pattern, &matrix);
+ return PycairoMatrix_FromMatrix (&matrix);
+}
+
+static PyObject *
+pattern_set_extend (PycairoPattern *o, PyObject *args) {
+ int extend;
+
+ if (!PyArg_ParseTuple(args, "i:Pattern.set_extend", &extend))
+ return NULL;
+
+ cairo_pattern_set_extend (o->pattern, extend);
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+pattern_set_matrix (PycairoPattern *o, PyObject *args) {
+ PycairoMatrix *m;
+
+ if (!PyArg_ParseTuple (args, "O!:Pattern.set_matrix",
+ &PycairoMatrix_Type, &m))
+ return NULL;
+
+ cairo_pattern_set_matrix (o->pattern, &m->matrix);
+ Py_RETURN_NONE;
+}
+
+static PyMethodDef pattern_methods[] = {
+ /* methods never exposed in a language binding:
+ * cairo_pattern_destroy()
+ * cairo_pattern_get_type()
+ * cairo_pattern_reference()
+ *
+ * cairo_pattern_status()
+ * - not needed since Pycairo handles status checking
+ */
+ {"get_extend", (PyCFunction)pattern_get_extend, METH_NOARGS },
+ {"get_matrix", (PyCFunction)pattern_get_matrix, METH_NOARGS },
+ {"set_extend", (PyCFunction)pattern_set_extend, METH_VARARGS },
+ {"set_matrix", (PyCFunction)pattern_set_matrix, METH_VARARGS },
+ {NULL, NULL, 0, NULL},
+};
+
+PyTypeObject PycairoPattern_Type = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /* ob_size */
+ "cairo.Pattern", /* tp_name */
+ sizeof(PycairoPattern), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)pattern_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,/* tp_flags */
+ 0, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ pattern_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ (newfunc)pattern_new, /* tp_new */
+ 0, /* tp_free */
+ 0, /* tp_is_gc */
+ 0, /* tp_bases */
+};
+
+
+/* Class SolidPattern ----------------------------------------------------- */
+
+static PyObject *
+solid_pattern_new (PyTypeObject *type, PyObject *args, PyObject *kwds) {
+ double r, g, b, a = 1.0;
+ if (!PyArg_ParseTuple (args, "ddd|d:SolidPattern.__new__", &r, &g, &b, &a))
+ return NULL;
+ return PycairoPattern_FromPattern (cairo_pattern_create_rgba (r, g, b, a),
+ NULL);
+}
+
+static PyObject *
+solid_pattern_get_rgba (PycairoSolidPattern *o) {
+ double red, green, blue, alpha;
+ cairo_pattern_get_rgba (o->pattern, &red, &green, &blue, &alpha);
+ return Py_BuildValue("(dddd)", red, green, blue, alpha);
+}
+
+static PyMethodDef solid_pattern_methods[] = {
+ {"get_rgba", (PyCFunction)solid_pattern_get_rgba, METH_NOARGS },
+ {NULL, NULL, 0, NULL},
+};
+
+PyTypeObject PycairoSolidPattern_Type = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /* ob_size */
+ "cairo.SolidPattern", /* tp_name */
+ sizeof(PycairoSolidPattern), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT, /* tp_flags */
+ 0, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ solid_pattern_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &PycairoPattern_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ (newfunc)solid_pattern_new, /* tp_new */
+ 0, /* tp_free */
+ 0, /* tp_is_gc */
+ 0, /* tp_bases */
+};
+
+/* Class SurfacePattern --------------------------------------------------- */
+
+static PyObject *
+surface_pattern_new (PyTypeObject *type, PyObject *args, PyObject *kwds) {
+ PycairoSurface *s;
+ if (!PyArg_ParseTuple (args, "O!:SurfacePattern.__new__",
+ &PycairoSurface_Type, &s))
+ return NULL;
+ return PycairoPattern_FromPattern (
+ cairo_pattern_create_for_surface (s->surface), (PyObject *)s);
+}
+
+static PyObject *
+surface_pattern_get_filter (PycairoSurfacePattern *o) {
+ return PyInt_FromLong (cairo_pattern_get_filter (o->pattern));
+}
+
+static PyObject *
+surface_pattern_get_surface (PycairoSurfacePattern *o) {
+ /*
+ cairo_surface_t *surface;
+ cairo_pattern_get_surface (o->pattern, &surface);
+ return PycairoSurface_FromSurface (
+ cairo_surface_reference (surface), NULL);
+ */
+ /* return the surface used to create the pattern */
+ return Py_BuildValue("O", o->base);
+}
+
+static PyObject *
+surface_pattern_set_filter (PycairoSurfacePattern *o, PyObject *args) {
+ int filter;
+
+ if (!PyArg_ParseTuple (args, "i:SurfacePattern.set_filter", &filter))
+ return NULL;
+
+ cairo_pattern_set_filter (o->pattern, filter);
+ Py_RETURN_NONE;
+}
+
+static PyMethodDef surface_pattern_methods[] = {
+ {"get_filter", (PyCFunction)surface_pattern_get_filter, METH_NOARGS },
+ {"get_surface", (PyCFunction)surface_pattern_get_surface, METH_NOARGS },
+ {"set_filter", (PyCFunction)surface_pattern_set_filter, METH_VARARGS },
+ {NULL, NULL, 0, NULL},
+};
+
+PyTypeObject PycairoSurfacePattern_Type = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /* ob_size */
+ "cairo.SurfacePattern", /* tp_name */
+ sizeof(PycairoSurfacePattern), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT, /* tp_flags */
+ 0, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ surface_pattern_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &PycairoPattern_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ (newfunc)surface_pattern_new, /* tp_new */
+ 0, /* tp_free */
+ 0, /* tp_is_gc */
+ 0, /* tp_bases */
+};
+
+/* Class Gradient --------------------------------------------------------- */
+
+static PyObject *
+gradient_new (PyTypeObject *type, PyObject *args, PyObject *kwds) {
+ PyErr_SetString(PyExc_TypeError,
+ "The Gradient type cannot be instantiated");
+ return NULL;
+}
+
+static PyObject *
+gradient_add_color_stop_rgb (PycairoGradient *o, PyObject *args) {
+ double offset, red, green, blue;
+ if (!PyArg_ParseTuple(args, "dddd:Gradient.add_color_stop_rgb",
+ &offset, &red, &green, &blue))
+ return NULL;
+ cairo_pattern_add_color_stop_rgb (o->pattern, offset, red, green, blue);
+ RETURN_NULL_IF_CAIRO_PATTERN_ERROR(o->pattern);
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+gradient_add_color_stop_rgba (PycairoGradient *o, PyObject *args) {
+ double offset, red, green, blue, alpha;
+ if (!PyArg_ParseTuple(args, "ddddd:Gradient.add_color_stop_rgba",
+ &offset, &red, &green, &blue, &alpha))
+ return NULL;
+ cairo_pattern_add_color_stop_rgba (o->pattern, offset, red,
+ green, blue, alpha);
+ RETURN_NULL_IF_CAIRO_PATTERN_ERROR(o->pattern);
+ Py_RETURN_NONE;
+}
+
+static PyMethodDef gradient_methods[] = {
+ {"add_color_stop_rgb",(PyCFunction)gradient_add_color_stop_rgb,
+ METH_VARARGS },
+ {"add_color_stop_rgba",(PyCFunction)gradient_add_color_stop_rgba,
+ METH_VARARGS },
+ {NULL, NULL, 0, NULL},
+};
+
+PyTypeObject PycairoGradient_Type = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /* ob_size */
+ "cairo.Gradient", /* tp_name */
+ sizeof(PycairoGradient), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,/* tp_flags */
+ 0, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ gradient_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &PycairoPattern_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ (newfunc)gradient_new, /* tp_new */
+ 0, /* tp_free */
+ 0, /* tp_is_gc */
+ 0, /* tp_bases */
+};
+
+/* Class LinearGradient --------------------------------------------------- */
+
+static PyObject *
+linear_gradient_new (PyTypeObject *type, PyObject *args, PyObject *kwds) {
+ double x0, y0, x1, y1;
+ if (!PyArg_ParseTuple(args, "dddd:LinearGradient.__new__",
+ &x0, &y0, &x1, &y1))
+ return NULL;
+ return PycairoPattern_FromPattern (
+ cairo_pattern_create_linear (x0, y0, x1, y1), NULL);
+}
+
+static PyObject *
+linear_gradient_get_linear_points (PycairoLinearGradient *o) {
+ double x0, y0, x1, y1;
+ cairo_pattern_get_linear_points (o->pattern, &x0, &y0, &x1, &y1);
+ return Py_BuildValue("(dddd)", x0, y0, x1, y1);
+}
+
+static PyMethodDef linear_gradient_methods[] = {
+ {"get_linear_points", (PyCFunction)linear_gradient_get_linear_points,
+ METH_NOARGS },
+ {NULL, NULL, 0, NULL},
+};
+
+PyTypeObject PycairoLinearGradient_Type = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /* ob_size */
+ "cairo.LinearGradient", /* tp_name */
+ sizeof(PycairoLinearGradient), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT, /* tp_flags */
+ 0, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ linear_gradient_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &PycairoGradient_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ (newfunc)linear_gradient_new, /* tp_new */
+ 0, /* tp_free */
+ 0, /* tp_is_gc */
+ 0, /* tp_bases */
+};
+
+/* Class RadialGradient --------------------------------------------------- */
+
+static PyObject *
+radial_gradient_new (PyTypeObject *type, PyObject *args, PyObject *kwds) {
+ double cx0, cy0, radius0, cx1, cy1, radius1;
+ if (!PyArg_ParseTuple(args, "dddddd:RadialGradient.__new__",
+ &cx0, &cy0, &radius0, &cx1, &cy1, &radius1))
+ return NULL;
+ return PycairoPattern_FromPattern (
+ cairo_pattern_create_radial (cx0, cy0, radius0, cx1, cy1, radius1),
+ NULL);
+}
+
+static PyObject *
+radial_gradient_get_radial_circles (PycairoRadialGradient *o) {
+ double x0, y0, r0, x1, y1, r1;
+ cairo_pattern_get_radial_circles (o->pattern, &x0, &y0, &r0,
+ &x1, &y1, &r1);
+ return Py_BuildValue("(dddddd)", x0, y0, r0, x1, y1, r1);
+}
+
+static PyMethodDef radial_gradient_methods[] = {
+ {"get_radial_circles", (PyCFunction)radial_gradient_get_radial_circles,
+ METH_NOARGS },
+ {NULL, NULL, 0, NULL},
+};
+
+PyTypeObject PycairoRadialGradient_Type = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /* ob_size */
+ "cairo.RadialGradient", /* tp_name */
+ sizeof(PycairoRadialGradient), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT, /* tp_flags */
+ 0, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ radial_gradient_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &PycairoGradient_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ (newfunc)radial_gradient_new, /* tp_new */
+ 0, /* tp_free */
+ 0, /* tp_is_gc */
+ 0, /* tp_bases */
+};
diff --git a/src/private.h b/src/private.h
new file mode 100644
index 0000000..ba59daf
--- /dev/null
+++ b/src/private.h
@@ -0,0 +1,160 @@
+/* -*- mode: C; c-basic-offset: 2 -*-
+ *
+ * Copyright © 2003,2010 James Henstridge, Steven Chaplin
+ *
+ * This file is part of pycairo.
+ *
+ * Pycairo is free software: you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License version 3 as published
+ * by the Free Software Foundation.
+ *
+ * Pycairo is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with pycairo. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _PYCAIRO_PRIVATE_H_
+#define _PYCAIRO_PRIVATE_H_
+
+#ifdef _PYCAIRO_H_
+# error "don't include pycairo.h and pycairo-private.h together"
+#endif
+
+#define _INSIDE_PYCAIRO_
+#include <Python.h>
+
+#include "py3cairo.h"
+
+
+extern PyObject *CairoError;
+
+extern PyTypeObject PycairoContext_Type;
+PyObject *PycairoContext_FromContext (cairo_t *ctx, PyTypeObject *type,
+ PyObject *base);
+
+extern PyTypeObject PycairoFontFace_Type;
+extern PyTypeObject PycairoToyFontFace_Type;
+PyObject *PycairoFontFace_FromFontFace (cairo_font_face_t *font_face);
+
+extern PyTypeObject PycairoFontOptions_Type;
+PyObject *PycairoFontOptions_FromFontOptions (
+ cairo_font_options_t *font_options);
+
+extern PyTypeObject PycairoMatrix_Type;
+PyObject *PycairoMatrix_FromMatrix (const cairo_matrix_t *matrix);
+
+extern PyTypeObject PycairoPath_Type;
+PyObject *PycairoPath_FromPath (cairo_path_t *path);
+
+extern PyTypeObject PycairoPathiter_Type;
+
+extern PyTypeObject PycairoPattern_Type;
+extern PyTypeObject PycairoSolidPattern_Type;
+extern PyTypeObject PycairoSurfacePattern_Type;
+extern PyTypeObject PycairoGradient_Type;
+extern PyTypeObject PycairoLinearGradient_Type;
+extern PyTypeObject PycairoRadialGradient_Type;
+PyObject *PycairoPattern_FromPattern (cairo_pattern_t *pattern,
+ PyObject *base);
+
+extern PyTypeObject PycairoScaledFont_Type;
+PyObject *PycairoScaledFont_FromScaledFont (cairo_scaled_font_t *scaled_font);
+
+extern PyTypeObject PycairoSurface_Type;
+extern PyTypeObject PycairoImageSurface_Type;
+
+#if CAIRO_HAS_PDF_SURFACE
+extern PyTypeObject PycairoPDFSurface_Type;
+#endif
+
+#if CAIRO_HAS_PS_SURFACE
+extern PyTypeObject PycairoPSSurface_Type;
+#endif
+
+#if CAIRO_HAS_SVG_SURFACE
+extern PyTypeObject PycairoSVGSurface_Type;
+#endif
+
+#if CAIRO_HAS_WIN32_SURFACE
+extern PyTypeObject PycairoWin32Surface_Type;
+extern PyTypeObject PycairoWin32PrintingSurface_Type;
+#endif
+
+#if CAIRO_HAS_XCB_SURFACE
+extern PyTypeObject PycairoXCBSurface_Type;
+#ifdef HAVE_XPYB
+# include <xpyb.h>
+extern xpyb_CAPI_t *xpyb_CAPI;
+extern PyObject *xpybVISUALTYPE_type;
+#endif
+#endif
+
+#if CAIRO_HAS_XLIB_SURFACE
+extern PyTypeObject PycairoXlibSurface_Type;
+#endif
+
+PyObject *PycairoSurface_FromSurface (cairo_surface_t *surface,
+ PyObject *base);
+
+int Pycairo_Check_Status (cairo_status_t status);
+
+/* error checking macros */
+#define RETURN_NULL_IF_CAIRO_ERROR(status) \
+ do { \
+ if (status != CAIRO_STATUS_SUCCESS) { \
+ Pycairo_Check_Status (status); \
+ return NULL; \
+ } \
+ } while (0)
+
+#define RETURN_NULL_IF_CAIRO_CONTEXT_ERROR(ctx) \
+ do { \
+ cairo_status_t status = cairo_status (ctx); \
+ if (status != CAIRO_STATUS_SUCCESS) { \
+ Pycairo_Check_Status (status); \
+ return NULL; \
+ } \
+ } while (0)
+
+#define RETURN_NULL_IF_CAIRO_PATTERN_ERROR(pattern) \
+ do { \
+ cairo_status_t status = cairo_pattern_status (pattern); \
+ if (status != CAIRO_STATUS_SUCCESS) { \
+ Pycairo_Check_Status (status); \
+ return NULL; \
+ } \
+ } while (0)
+
+#define RETURN_NULL_IF_CAIRO_SURFACE_ERROR(surface) \
+ do { \
+ cairo_status_t status = cairo_surface_status (surface); \
+ if (status != CAIRO_STATUS_SUCCESS) { \
+ Pycairo_Check_Status (status); \
+ return NULL; \
+ } \
+ } while (0)
+
+#define RETURN_NULL_IF_CAIRO_SCALED_FONT_ERROR(sc_font) \
+ do { \
+ cairo_status_t status = cairo_scaled_font_status (sc_font); \
+ if (status != CAIRO_STATUS_SUCCESS) { \
+ Pycairo_Check_Status (status); \
+ return NULL; \
+ } \
+ } while (0)
+
+#define RETURN_NULL_IF_CAIRO_FONT_OPTIONS_ERROR(fo) \
+ do { \
+ cairo_status_t status = cairo_font_options_status (fo); \
+ if (status != CAIRO_STATUS_SUCCESS) { \
+ Pycairo_Check_Status (status); \
+ return NULL; \
+ } \
+ } while (0)
+
+
+#endif /* _PYCAIRO_PRIVATE_H_ */
diff --git a/src/py3cairo.h b/src/py3cairo.h
new file mode 100644
index 0000000..35b4240
--- /dev/null
+++ b/src/py3cairo.h
@@ -0,0 +1,206 @@
+/* -*- mode: C; c-basic-offset: 2 -*-
+ *
+ * Copyright © 2003,2010 James Henstridge, Steven Chaplin
+ *
+ * This file is part of pycairo.
+ *
+ * Pycairo is free software: you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License version 3 as published
+ * by the Free Software Foundation.
+ *
+ * Pycairo is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with pycairo. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _PYCAIRO_H_
+#define _PYCAIRO_H_
+
+#include <Python.h>
+
+#include <cairo.h>
+
+
+typedef struct {
+ PyObject_HEAD
+ cairo_t *ctx;
+ PyObject *base; /* base object used to create context, or NULL */
+} PycairoContext;
+
+typedef struct {
+ PyObject_HEAD
+ cairo_font_face_t *font_face;
+} PycairoFontFace;
+
+#define PycairoToyFontFace PycairoFontFace
+
+typedef struct {
+ PyObject_HEAD
+ cairo_font_options_t *font_options;
+} PycairoFontOptions;
+
+typedef struct {
+ PyObject_HEAD
+ cairo_matrix_t matrix;
+} PycairoMatrix;
+
+typedef struct {
+ PyObject_HEAD
+ cairo_path_t *path;
+} PycairoPath;
+
+typedef struct {
+ PyObject_HEAD
+ cairo_pattern_t *pattern;
+ PyObject *base; /* base object used to create pattern, or NULL */
+} PycairoPattern;
+
+#define PycairoSolidPattern PycairoPattern
+#define PycairoSurfacePattern PycairoPattern
+#define PycairoGradient PycairoPattern
+#define PycairoLinearGradient PycairoPattern
+#define PycairoRadialGradient PycairoPattern
+
+typedef struct {
+ PyObject_HEAD
+ cairo_scaled_font_t *scaled_font;
+} PycairoScaledFont;
+
+typedef struct {
+ PyObject_HEAD
+ cairo_surface_t *surface;
+ PyObject *base; /* base object used to create surface, or NULL */
+} PycairoSurface;
+
+#define PycairoImageSurface PycairoSurface
+#define PycairoPDFSurface PycairoSurface
+#define PycairoPSSurface PycairoSurface
+#define PycairoSVGSurface PycairoSurface
+#define PycairoWin32Surface PycairoSurface
+#define PycairoWin32PrintingSurface PycairoSurface
+#define PycairoXCBSurface PycairoSurface
+#define PycairoXlibSurface PycairoSurface
+
+/* get C object out of the Python wrapper */
+#define PycairoContext_GET(obj) (((PycairoContext *)(obj))->ctx)
+
+/* Define structure for C API. */
+typedef struct {
+ /* (type object, constructor) pairs */
+ PyTypeObject *Context_Type;
+ PyObject *(*Context_FromContext)(cairo_t *ctx, PyTypeObject *type,
+ PyObject *base);
+ PyTypeObject *FontFace_Type;
+ PyTypeObject *ToyFontFace_Type;
+ PyObject *(*FontFace_FromFontFace)(cairo_font_face_t *font_face);
+ PyTypeObject *FontOptions_Type;
+ PyObject *(*FontOptions_FromFontOptions)(
+ cairo_font_options_t *font_options);
+ PyTypeObject *Matrix_Type;
+ PyObject *(*Matrix_FromMatrix)(const cairo_matrix_t *matrix);
+ PyTypeObject *Path_Type;
+ PyObject *(*Path_FromPath)(cairo_path_t *path);
+
+ PyTypeObject *Pattern_Type;
+ PyTypeObject *SolidPattern_Type;
+ PyTypeObject *SurfacePattern_Type;
+ PyTypeObject *Gradient_Type;
+ PyTypeObject *LinearGradient_Type;
+ PyTypeObject *RadialGradient_Type;
+ PyObject *(*Pattern_FromPattern)(cairo_pattern_t *pattern, PyObject *base);
+
+ PyTypeObject *ScaledFont_Type;
+ PyObject *(*ScaledFont_FromScaledFont)(cairo_scaled_font_t *scaled_font);
+
+ PyTypeObject *Surface_Type;
+ PyTypeObject *ImageSurface_Type;
+ PyTypeObject *PDFSurface_Type;
+ PyTypeObject *PSSurface_Type;
+ PyTypeObject *SVGSurface_Type;
+ PyTypeObject *Win32Surface_Type;
+ PyTypeObject *Win32PrintingSurface_Type;
+ PyTypeObject *XCBSurface_Type;
+ PyTypeObject *XlibSurface_Type;
+ PyObject *(*Surface_FromSurface)(cairo_surface_t *surface, PyObject *base);
+
+ /* misc functions */
+ int (*Check_Status)(cairo_status_t status);
+} Pycairo_CAPI_t;
+
+
+#ifndef _INSIDE_PYCAIRO_
+
+/* Macros for accessing the C API */
+#define PycairoContext_Type *(Pycairo_CAPI->Context_Type)
+#define PycairoContext_FromContext (Pycairo_CAPI->Context_FromContext)
+#define PycairoFontFace_Type *(Pycairo_CAPI->FontFace_Type)
+#define PycairoToyFontFace_Type *(Pycairo_CAPI->ToyFontFace_Type)
+#define PycairoFontFace_FromFontFace (Pycairo_CAPI->FontFace_FromFontFace)
+#define PycairoFontOptions_Type *(Pycairo_CAPI->FontOptions_Type)
+#define PycairoFontOptions_FromFontOptions \
+ (Pycairo_CAPI->FontOptions_FromFontOptions)
+#define PycairoMatrix_Type *(Pycairo_CAPI->Matrix_Type)
+#define PycairoMatrix_FromMatrix (Pycairo_CAPI->Matrix_FromMatrix)
+#define PycairoPath_Type *(Pycairo_CAPI->Path_Type)
+#define PycairoPath_FromPath (Pycairo_CAPI->Path_FromPath)
+
+#define PycairoPattern_Type *(Pycairo_CAPI->Pattern_Type)
+#define PycairoSolidPattern_Type *(Pycairo_CAPI->SolidPattern_Type)
+#define PycairoSurfacePattern_Type *(Pycairo_CAPI->SurfacePattern_Type)
+#define PycairoGradient_Type *(Pycairo_CAPI->Gradient_Type)
+#define PycairoLinearGradient_Type *(Pycairo_CAPI->LinearGradient_Type)
+#define PycairoRadialGradient_Type *(Pycairo_CAPI->RadialGradient_Type)
+#define PycairoPattern_FromPattern (Pycairo_CAPI->Pattern_FromPattern)
+
+#define PycairoScaledFont_Type *(Pycairo_CAPI->ScaledFont_Type)
+#define PycairoScaledFont_FromScaledFont \
+ (Pycairo_CAPI->ScaledFont_FromScaledFont)
+
+#define PycairoSurface_Type *(Pycairo_CAPI->Surface_Type)
+#define PycairoImageSurface_Type *(Pycairo_CAPI->ImageSurface_Type)
+
+#if CAIRO_HAS_PDF_SURFACE
+#define PycairoPDFSurface_Type *(Pycairo_CAPI->PDFSurface_Type)
+#endif
+
+#if CAIRO_HAS_PS_SURFACE
+#define PycairoPSSurface_Type *(Pycairo_CAPI->PSSurface_Type)
+#endif
+
+#if CAIRO_HAS_SVG_SURFACE
+#define PycairoSVGSurface_Type *(Pycairo_CAPI->SVGSurface_Type)
+#endif
+
+#if CAIRO_HAS_WIN32_SURFACE
+#define PycairoWin32Surface_Type *(Pycairo_CAPI->Win32Surface_Type)
+#define PycairoWin32PrintingSurface_Type *(Pycairo_CAPI->Win32PrintingSurface_Type)
+#endif
+
+#if CAIRO_HAS_XCB_SURFACE
+#define PycairoXCBSurface_Type *(Pycairo_CAPI->XCBSurface_Type)
+#endif
+
+#if CAIRO_HAS_XLIB_SURFACE
+#define PycairoXlibSurface_Type *(Pycairo_CAPI->XlibSurface_Type)
+#endif
+
+#define PycairoSurface_FromSurface (Pycairo_CAPI->Surface_FromSurface)
+
+#define Pycairo_Check_Status (Pycairo_CAPI->Check_Status)
+
+
+/* To access the Pycairo C API, edit the client module file to:
+ * 1) Add the following line to define a global variable for the C API
+ * static Pycairo_CAPI_t *Pycairo_CAPI;
+ * 2) Add 'Pycairo_IMPORT;' to the init<module> function
+ */
+#define Pycairo_IMPORT \
+ Pycairo_CAPI = (Pycairo_CAPI_t*) PyCObject_Import("cairo", "CAPI")
+
+#endif /* ifndef _INSIDE_PYCAIRO_ */
+
+#endif /* ifndef _PYCAIRO_H_ */
diff --git a/src/surface.c b/src/surface.c
new file mode 100644
index 0000000..2e19f14
--- /dev/null
+++ b/src/surface.c
@@ -0,0 +1,1424 @@
+/* -*- mode: C; c-basic-offset: 2 -*-
+ *
+ * Copyright © 2003,2010 James Henstridge, Steven Chaplin
+ *
+ * This file is part of pycairo.
+ *
+ * Pycairo is free software: you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License version 3 as published
+ * by the Free Software Foundation.
+ *
+ * Pycairo is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with pycairo. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define PY_SSIZE_T_CLEAN
+#include <Python.h>
+
+#include "config.h"
+#include "private.h"
+
+
+/* Class Surface ---------------------------------------------------------- */
+
+/* PycairoSurface_FromSurface
+ * Create a new
+ * PycairoImageSurface,
+ * PycairoPDFSurface,
+ * PycairoPSSurface,
+ * PycairoSVGSurface,
+ * PycairoWin32Surface,
+ * PycairoWin32PrintingSurface,
+ * PycairoXCBSurface, or
+ * PycairoXlibSurface
+ * from a cairo_surface_t.
+ * surface - a cairo_surface_t to 'wrap' into a Python object.
+ * It is unreferenced if the PycairoSurface creation fails, or if the
+ * cairo_surface_t has an error status.
+ * base - the base object used to create the surface, or NULL.
+ * It is referenced to keep it alive while the cairo_surface_t is being used.
+ * Return value: New reference or NULL on failure
+ */
+PyObject *
+PycairoSurface_FromSurface (cairo_surface_t *surface, PyObject *base) {
+ PyTypeObject *type = NULL;
+ PyObject *o;
+
+ assert (surface != NULL);
+
+ if (Pycairo_Check_Status (cairo_surface_status (surface))) {
+ cairo_surface_destroy (surface);
+ return NULL;
+ }
+
+ switch (cairo_surface_get_type (surface)) {
+#if CAIRO_HAS_IMAGE_SURFACE
+ case CAIRO_SURFACE_TYPE_IMAGE:
+ type = &PycairoImageSurface_Type;
+ break;
+#endif
+#if CAIRO_HAS_PDF_SURFACE
+ case CAIRO_SURFACE_TYPE_PDF:
+ type = &PycairoPDFSurface_Type;
+ break;
+#endif
+#if CAIRO_HAS_PS_SURFACE
+ case CAIRO_SURFACE_TYPE_PS:
+ type = &PycairoPSSurface_Type;
+ break;
+#endif
+#if CAIRO_HAS_SVG_SURFACE
+ case CAIRO_SURFACE_TYPE_SVG:
+ type = &PycairoSVGSurface_Type;
+ break;
+#endif
+#if CAIRO_HAS_WIN32_SURFACE
+ case CAIRO_SURFACE_TYPE_WIN32:
+ type = &PycairoWin32Surface_Type;
+ break;
+ case CAIRO_SURFACE_TYPE_WIN32_PRINTING:
+ type = &PycairoWin32PrintingSurface_Type;
+ break;
+#endif
+#if CAIRO_HAS_XCB_SURFACE
+ case CAIRO_SURFACE_TYPE_XCB:
+ type = &PycairoXCBSurface_Type;
+ break;
+#endif
+#if CAIRO_HAS_XLIB_SURFACE
+ case CAIRO_SURFACE_TYPE_XLIB:
+ type = &PycairoXlibSurface_Type;
+ break;
+#endif
+ default:
+ type = &PycairoSurface_Type;
+ break;
+ }
+ o = type->tp_alloc (type, 0);
+ if (o == NULL) {
+ cairo_surface_destroy (surface);
+ } else {
+ ((PycairoSurface *)o)->surface = surface;
+ Py_XINCREF(base);
+ ((PycairoSurface *)o)->base = base;
+ }
+ return o;
+}
+
+/* for use with
+ * cairo_surface_write_to_png_stream()
+ * cairo_pdf/ps/svg_surface_create_for_stream()
+ */
+static cairo_status_t
+_write_func (void *closure, const unsigned char *data, unsigned int length) {
+ PyGILState_STATE gstate = PyGILState_Ensure();
+ PyObject *res = PyObject_CallMethod ((PyObject *)closure, "write", "(s#)",
+ data, (Py_ssize_t)length);
+ if (res == NULL) {
+ /* an exception has occurred, it will be picked up later by
+ * Pycairo_Check_Status()
+ */
+ PyGILState_Release(gstate);
+ return CAIRO_STATUS_WRITE_ERROR;
+ }
+ Py_DECREF(res);
+ PyGILState_Release(gstate);
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static void
+surface_dealloc (PycairoSurface *o) {
+ if (o->surface) {
+ cairo_surface_destroy(o->surface);
+ o->surface = NULL;
+ }
+ Py_CLEAR(o->base);
+
+ o->ob_type->tp_free((PyObject *)o);
+}
+
+static PyObject *
+surface_new (PyTypeObject *type, PyObject *args, PyObject *kwds) {
+ PyErr_SetString(PyExc_TypeError,
+ "The Surface type cannot be instantiated");
+ return NULL;
+}
+
+static PyObject *
+surface_copy_page (PycairoSurface *o) {
+ Py_BEGIN_ALLOW_THREADS;
+ cairo_surface_copy_page (o->surface);
+ Py_END_ALLOW_THREADS;
+ RETURN_NULL_IF_CAIRO_SURFACE_ERROR(o->surface);
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+surface_create_similar (PycairoSurface *o, PyObject *args) {
+ cairo_content_t content;
+ int width, height;
+
+ if (!PyArg_ParseTuple (args, "iii:Surface.create_similar",
+ &content, &width, &height))
+ return NULL;
+ return PycairoSurface_FromSurface (
+ cairo_surface_create_similar (o->surface, content, width, height),
+ NULL);
+}
+
+static PyObject *
+surface_finish (PycairoSurface *o) {
+ cairo_surface_finish (o->surface);
+ Py_CLEAR(o->base);
+ RETURN_NULL_IF_CAIRO_SURFACE_ERROR(o->surface);
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+surface_flush (PycairoSurface *o) {
+ Py_BEGIN_ALLOW_THREADS;
+ cairo_surface_flush (o->surface);
+ Py_END_ALLOW_THREADS;
+ RETURN_NULL_IF_CAIRO_SURFACE_ERROR(o->surface);
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+surface_get_content (PycairoSurface *o) {
+ return PyInt_FromLong (cairo_surface_get_content (o->surface));
+}
+
+static PyObject *
+surface_get_device_offset (PycairoSurface *o) {
+ double x_offset, y_offset;
+ cairo_surface_get_device_offset (o->surface, &x_offset, &y_offset);
+ return Py_BuildValue("(dd)", x_offset, y_offset);
+}
+
+static PyObject *
+surface_get_fallback_resolution (PycairoSurface *o) {
+ double x_ppi, y_ppi;
+ cairo_surface_get_fallback_resolution (o->surface, &x_ppi, &y_ppi);
+ return Py_BuildValue("(dd)", x_ppi, y_ppi);
+}
+
+static PyObject *
+surface_get_font_options (PycairoSurface *o) {
+ cairo_font_options_t *options = cairo_font_options_create();
+
+ cairo_surface_get_font_options (o->surface, options);
+ /* there is no reference fn */
+ return PycairoFontOptions_FromFontOptions (options);
+}
+
+static PyObject *
+surface_mark_dirty (PycairoSurface *o) {
+ cairo_surface_mark_dirty (o->surface);
+ RETURN_NULL_IF_CAIRO_SURFACE_ERROR(o->surface);
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+surface_mark_dirty_rectangle (PycairoSurface *o, PyObject *args) {
+ int x, y, width, height;
+
+ if (!PyArg_ParseTuple(args, "iiii:Surface.mark_dirty_rectangle",
+ &x, &y, &width, &height))
+ return NULL;
+
+ cairo_surface_mark_dirty_rectangle (o->surface, x, y, width, height);
+ RETURN_NULL_IF_CAIRO_SURFACE_ERROR(o->surface);
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+surface_set_device_offset (PycairoSurface *o, PyObject *args) {
+ double x_offset, y_offset;
+
+ if (!PyArg_ParseTuple (args, "dd:Surface.set_device_offset",
+ &x_offset, &y_offset))
+ return NULL;
+
+ cairo_surface_set_device_offset (o->surface, x_offset, y_offset);
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+surface_set_fallback_resolution (PycairoSurface *o, PyObject *args) {
+ double x_ppi, y_ppi;
+
+ if (!PyArg_ParseTuple(args, "dd:Surface.set_fallback_resolution",
+ &x_ppi, &y_ppi))
+ return NULL;
+ cairo_surface_set_fallback_resolution (o->surface, x_ppi, y_ppi);
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+surface_show_page (PycairoSurface *o) {
+ Py_BEGIN_ALLOW_THREADS;
+ cairo_surface_show_page (o->surface);
+ Py_END_ALLOW_THREADS;
+ RETURN_NULL_IF_CAIRO_SURFACE_ERROR(o->surface);
+ Py_RETURN_NONE;
+}
+
+#ifdef CAIRO_HAS_PNG_FUNCTIONS
+/* METH_O */
+static PyObject *
+surface_write_to_png (PycairoSurface *o, PyObject *file) {
+ cairo_status_t status;
+
+ if (PyObject_TypeCheck (file, &PyString_Type)) {
+ /* string (filename) argument */
+ Py_BEGIN_ALLOW_THREADS;
+ status = cairo_surface_write_to_png (o->surface,
+ PyString_AsString(file));
+ Py_END_ALLOW_THREADS;
+
+ } else { /* file or file-like object argument */
+ PyObject* writer = PyObject_GetAttrString (file, "write");
+ if (writer == NULL || !PyCallable_Check (writer)) {
+ Py_XDECREF(writer);
+ PyErr_SetString(PyExc_TypeError,
+"Surface.write_to_png takes one argument which must be a filename (str), file "
+"object, or a file-like object which has a \"write\" method (like StringIO)");
+ return NULL;
+ }
+ Py_DECREF(writer);
+ Py_BEGIN_ALLOW_THREADS;
+ status = cairo_surface_write_to_png_stream (o->surface, _write_func,
+ file);
+ Py_END_ALLOW_THREADS;
+ }
+ RETURN_NULL_IF_CAIRO_ERROR(status);
+ Py_RETURN_NONE;
+}
+#endif /* CAIRO_HAS_PNG_FUNCTIONS */
+
+
+static PyMethodDef surface_methods[] = {
+ /* methods never exposed in a language binding:
+ * cairo_surface_destroy()
+ * cairo_surface_get_type()
+ * cairo_surface_get_user_data()
+ * cairo_surface_reference()
+ * cairo_surface_set_user_data()
+ */
+ {"copy_page", (PyCFunction)surface_copy_page, METH_NOARGS},
+ {"create_similar", (PyCFunction)surface_create_similar, METH_VARARGS},
+ {"finish", (PyCFunction)surface_finish, METH_NOARGS},
+ {"flush", (PyCFunction)surface_flush, METH_NOARGS},
+ {"get_content", (PyCFunction)surface_get_content, METH_NOARGS},
+ {"get_device_offset",(PyCFunction)surface_get_device_offset,METH_NOARGS},
+ {"get_fallback_resolution",(PyCFunction)surface_get_fallback_resolution,
+ METH_NOARGS},
+ {"get_font_options",(PyCFunction)surface_get_font_options, METH_NOARGS},
+ {"mark_dirty", (PyCFunction)surface_mark_dirty, METH_NOARGS},
+ {"mark_dirty_rectangle", (PyCFunction)surface_mark_dirty_rectangle,
+ METH_VARARGS},
+ {"set_device_offset",(PyCFunction)surface_set_device_offset,METH_VARARGS},
+ {"set_fallback_resolution",(PyCFunction)surface_set_fallback_resolution,
+ METH_VARARGS},
+ {"show_page", (PyCFunction)surface_show_page, METH_NOARGS},
+#ifdef CAIRO_HAS_PNG_FUNCTIONS
+ {"write_to_png", (PyCFunction)surface_write_to_png, METH_O },
+#endif
+ {NULL, NULL, 0, NULL},
+};
+
+
+PyTypeObject PycairoSurface_Type = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /* ob_size */
+ "cairo.Surface", /* tp_name */
+ sizeof(PycairoSurface), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)surface_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,/* tp_flags */
+ 0, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ surface_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ (newfunc)surface_new, /* tp_new */
+ 0, /* tp_free */
+ 0, /* tp_is_gc */
+ 0, /* tp_bases */
+};
+
+
+/* Class ImageSurface(Surface) -------------------------------------------- */
+#ifdef CAIRO_HAS_IMAGE_SURFACE
+
+static PyObject *
+image_surface_new (PyTypeObject *type, PyObject *args, PyObject *kwds) {
+ cairo_format_t format;
+ int width, height;
+
+ if (!PyArg_ParseTuple (args, "iii:ImageSurface.__new__",
+ &format, &width, &height))
+ return NULL;
+ return PycairoSurface_FromSurface (
+ cairo_image_surface_create (format, width, height),
+ NULL);
+}
+
+static PyObject *
+image_surface_create_for_data (PyTypeObject *type, PyObject *args) {
+ cairo_surface_t *surface;
+ cairo_format_t format;
+ unsigned char *buffer;
+ int width, height, stride = -1, res;
+ Py_ssize_t buffer_len;
+ PyObject *obj;
+
+ if (!PyArg_ParseTuple(args, "Oiii|i:Surface.create_for_data",
+ &obj, &format, &width, &height, &stride))
+ return NULL;
+
+ res = PyObject_AsWriteBuffer (obj, (void **)&buffer, &buffer_len);
+ if (res == -1)
+ return NULL;
+
+ if (width <= 0) {
+ PyErr_SetString(PyExc_ValueError, "width must be positive");
+ return NULL;
+ }
+ if (height <= 0) {
+ PyErr_SetString(PyExc_ValueError, "height must be positive");
+ return NULL;
+ }
+ /* if stride is missing, calculate it from width */
+ if (stride < 0) {
+ stride = cairo_format_stride_for_width (format, width);
+ if (stride == -1){
+ PyErr_SetString(CairoError,
+ "format is invalid or the width too large");
+ return NULL;
+ }
+ }
+ if (height * stride > buffer_len) {
+ PyErr_SetString(PyExc_TypeError, "buffer is not long enough");
+ return NULL;
+ }
+ Py_BEGIN_ALLOW_THREADS;
+ surface = cairo_image_surface_create_for_data (buffer, format, width,
+ height, stride);
+ Py_END_ALLOW_THREADS;
+ return PycairoSurface_FromSurface(surface, obj);
+}
+
+
+#ifdef CAIRO_HAS_PNG_FUNCTIONS
+static cairo_status_t
+_read_func (void *closure, unsigned char *data, unsigned int length) {
+ char *buffer;
+ Py_ssize_t str_length;
+ cairo_status_t status = CAIRO_STATUS_READ_ERROR;
+ PyGILState_STATE gstate = PyGILState_Ensure();
+ PyObject *pystr = PyObject_CallMethod ((PyObject *)closure, "read", "(i)",
+ length);
+ if (pystr == NULL) {
+ /* an exception has occurred, it will be picked up later by
+ * Pycairo_Check_Status()
+ */
+ goto end;
+ }
+ int ret = PyString_AsStringAndSize(pystr, &buffer, &str_length);
+ if (ret == -1 || str_length < length) {
+ goto end;
+ }
+ /* don't use strncpy() since png data may contain NUL bytes */
+ memcpy (data, buffer, str_length);
+ status = CAIRO_STATUS_SUCCESS;
+ end:
+ Py_XDECREF(pystr);
+ PyGILState_Release(gstate);
+ return status;
+}
+
+/* METH_O | METH_CLASS */
+static PyObject *
+image_surface_create_from_png (PyTypeObject *type, PyObject *file) {
+ PyObject* reader;
+ cairo_surface_t *is;
+
+ if (PyObject_TypeCheck (file, &PyBaseString_Type)) {
+ Py_BEGIN_ALLOW_THREADS;
+ is = cairo_image_surface_create_from_png (PyString_AsString(file));
+ Py_END_ALLOW_THREADS;
+ return PycairoSurface_FromSurface (is, NULL);
+ }
+
+ /* file or file-like object argument */
+ reader = PyObject_GetAttrString (file, "read");
+ if (reader == NULL || !PyCallable_Check (reader)) {
+ Py_XDECREF(reader);
+ PyErr_SetString(PyExc_TypeError,
+"ImageSurface.create_from_png argument must be a filename (str), file object, "
+"or an object that has a \"read\" method (like StringIO)");
+ return NULL;
+ }
+ Py_DECREF(reader);
+
+ Py_BEGIN_ALLOW_THREADS;
+ is = cairo_image_surface_create_from_png_stream (_read_func, file);
+ Py_END_ALLOW_THREADS;
+ return PycairoSurface_FromSurface (is, NULL);
+}
+#endif /* CAIRO_HAS_PNG_FUNCTIONS */
+
+/* METH_STATIC */
+static PyObject *
+image_surface_format_stride_for_width (PyObject *self, PyObject *args) {
+ cairo_format_t format;
+ int width;
+ if (!PyArg_ParseTuple(args, "ii:format_stride_for_width", &format, &width))
+ return NULL;
+ return PyInt_FromLong (cairo_format_stride_for_width (format, width));
+}
+
+static PyObject *
+image_surface_get_data (PycairoImageSurface *o) {
+ return PyBuffer_FromReadWriteObject((PyObject *)o, 0, Py_END_OF_BUFFER);
+}
+
+static PyObject *
+image_surface_get_format (PycairoImageSurface *o) {
+ return PyInt_FromLong (cairo_image_surface_get_format (o->surface));
+}
+
+static PyObject *
+image_surface_get_height (PycairoImageSurface *o) {
+ return PyInt_FromLong (cairo_image_surface_get_height (o->surface));
+}
+
+static PyObject *
+image_surface_get_stride (PycairoImageSurface *o) {
+ return PyInt_FromLong (cairo_image_surface_get_stride (o->surface));
+}
+
+static PyObject *
+image_surface_get_width (PycairoImageSurface *o) {
+ return PyInt_FromLong (cairo_image_surface_get_width (o->surface));
+}
+
+
+/* Buffer interface functions, used by ImageSurface.get_data() */
+static int
+image_surface_buffer_getreadbuf (PycairoImageSurface *o, int segment,
+ const void **ptr) {
+ cairo_surface_t *surface = o->surface;
+ int height, stride;
+
+ if (segment != 0) {
+ PyErr_SetString(PyExc_SystemError,
+ "accessing non-existent ImageSurface segment");
+ return -1;
+ }
+ height = cairo_image_surface_get_height (surface);
+ stride = cairo_image_surface_get_stride (surface);
+ *ptr = (void *) cairo_image_surface_get_data (surface);
+ return height * stride;
+}
+
+static int
+image_surface_buffer_getwritebuf (PycairoImageSurface *o, int segment,
+ const void **ptr) {
+ cairo_surface_t *surface = o->surface;
+ int height, stride;
+
+ if (segment != 0) {
+ PyErr_SetString(PyExc_SystemError,
+ "accessing non-existent ImageSurface segment");
+ return -1;
+ }
+ height = cairo_image_surface_get_height (surface);
+ stride = cairo_image_surface_get_stride (surface);
+ *ptr = (void *) cairo_image_surface_get_data (surface);
+ return height * stride;
+}
+
+static int
+image_surface_buffer_getsegcount (PycairoImageSurface *o, int *lenp) {
+ if (lenp) {
+ /* report the sum of the sizes (in bytes) of all segments */
+ cairo_surface_t *surface = o->surface;
+ int height = cairo_image_surface_get_height (surface);
+ int stride = cairo_image_surface_get_stride (surface);
+ *lenp = height * stride;
+ }
+ return 1; /* surface data is all in one segment */
+}
+
+/* See Python C API Manual 10.7 */
+static PyBufferProcs image_surface_as_buffer = {
+ (readbufferproc) image_surface_buffer_getreadbuf,
+ (writebufferproc)image_surface_buffer_getwritebuf,
+ (segcountproc) image_surface_buffer_getsegcount,
+ (charbufferproc) NULL,
+};
+
+static PyMethodDef image_surface_methods[] = {
+ {"create_for_data",(PyCFunction)image_surface_create_for_data,
+ METH_VARARGS | METH_CLASS},
+#ifdef CAIRO_HAS_PNG_FUNCTIONS
+ {"create_from_png", (PyCFunction)image_surface_create_from_png,
+ METH_O | METH_CLASS},
+#endif
+ {"format_stride_for_width",
+ (PyCFunction)image_surface_format_stride_for_width,
+ METH_VARARGS | METH_STATIC},
+ {"get_data", (PyCFunction)image_surface_get_data, METH_NOARGS},
+ {"get_format", (PyCFunction)image_surface_get_format, METH_NOARGS},
+ {"get_height", (PyCFunction)image_surface_get_height, METH_NOARGS},
+ {"get_stride", (PyCFunction)image_surface_get_stride, METH_NOARGS},
+ {"get_width", (PyCFunction)image_surface_get_width, METH_NOARGS},
+ {NULL, NULL, 0, NULL},
+};
+
+
+PyTypeObject PycairoImageSurface_Type = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /* ob_size */
+ "cairo.ImageSurface", /* tp_name */
+ sizeof(PycairoImageSurface), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ &image_surface_as_buffer, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT, /* tp_flags */
+ 0, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ image_surface_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &PycairoSurface_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ (newfunc)image_surface_new, /* tp_new */
+ 0, /* tp_free */
+ 0, /* tp_is_gc */
+ 0, /* tp_bases */
+};
+#endif /* CAIRO_HAS_IMAGE_SURFACE */
+
+
+/* Class PDFSurface(Surface) ---------------------------------------------- */
+#ifdef CAIRO_HAS_PDF_SURFACE
+#include <cairo-pdf.h>
+
+static PyObject *
+pdf_surface_new (PyTypeObject *type, PyObject *args, PyObject *kwds) {
+ double width_in_points, height_in_points;
+ PyObject *file, *writer;
+ cairo_surface_t *sfc;
+
+ if (!PyArg_ParseTuple(args, "Odd:PDFSurface.__new__",
+ &file, &width_in_points, &height_in_points))
+ return NULL;
+
+ if (file == Py_None) {
+ Py_BEGIN_ALLOW_THREADS;
+ sfc = cairo_pdf_surface_create (NULL,
+ width_in_points, height_in_points);
+ Py_END_ALLOW_THREADS;
+ return PycairoSurface_FromSurface (sfc, NULL);
+ }else if (PyObject_TypeCheck (file, &PyBaseString_Type)) {
+ /* string (filename) argument */
+ Py_BEGIN_ALLOW_THREADS;
+ sfc = cairo_pdf_surface_create (PyString_AsString(file),
+ width_in_points, height_in_points);
+ Py_END_ALLOW_THREADS;
+ return PycairoSurface_FromSurface (sfc, NULL);
+ }
+ /* file or file-like object argument */
+ writer = PyObject_GetAttrString (file, "write");
+ if (writer == NULL || !PyCallable_Check (writer)) {
+ Py_XDECREF(writer);
+ PyErr_SetString(PyExc_TypeError,
+"PDFSurface argument 1 must be\n"
+" None, or\n"
+" a filename (str), or\n"
+" a file object, or\n"
+" an object that has a \"write\" method (like StringIO)."
+ );
+ return NULL;
+ }
+ Py_DECREF(writer);
+
+ Py_BEGIN_ALLOW_THREADS;
+ sfc = cairo_pdf_surface_create_for_stream (_write_func, file,
+ width_in_points, height_in_points);
+ Py_END_ALLOW_THREADS;
+ return PycairoSurface_FromSurface (sfc, file);
+}
+
+static PyObject *
+pdf_surface_set_size (PycairoPDFSurface *o, PyObject *args) {
+ double width_in_points, height_in_points;
+
+ if (!PyArg_ParseTuple(args, "dd:PDFSurface.set_size", &width_in_points,
+ &height_in_points))
+ return NULL;
+ cairo_pdf_surface_set_size (o->surface, width_in_points,
+ height_in_points);
+ Py_RETURN_NONE;
+}
+
+static PyMethodDef pdf_surface_methods[] = {
+ {"set_size", (PyCFunction)pdf_surface_set_size, METH_VARARGS },
+ {NULL, NULL, 0, NULL},
+};
+
+PyTypeObject PycairoPDFSurface_Type = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /* ob_size */
+ "cairo.PDFSurface", /* tp_name */
+ sizeof(PycairoPDFSurface), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT, /* tp_flags */
+ 0, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ pdf_surface_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &PycairoSurface_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ (newfunc)pdf_surface_new, /* tp_new */
+ 0, /* tp_free */
+ 0, /* tp_is_gc */
+ 0, /* tp_bases */
+};
+#endif /* CAIRO_HAS_PDF_SURFACE */
+
+
+/* Class PSSurface(Surface) ----------------------------------------------- */
+#ifdef CAIRO_HAS_PS_SURFACE
+#include <cairo-ps.h>
+
+static PyObject *
+ps_surface_new (PyTypeObject *type, PyObject *args, PyObject *kwds) {
+ double width_in_points, height_in_points;
+ PyObject *file, *writer;
+ cairo_surface_t *sfc;
+
+ if (!PyArg_ParseTuple(args, "Odd:PSSurface.__new__",
+ &file, &width_in_points, &height_in_points))
+ return NULL;
+
+ if (file == Py_None) {
+ Py_BEGIN_ALLOW_THREADS;
+ sfc = cairo_ps_surface_create (NULL,
+ width_in_points, height_in_points);
+ Py_END_ALLOW_THREADS;
+ return PycairoSurface_FromSurface (sfc, NULL);
+ }else if (PyObject_TypeCheck (file, &PyBaseString_Type)) {
+ /* string (filename) argument */
+ Py_BEGIN_ALLOW_THREADS;
+ sfc = cairo_ps_surface_create (PyString_AsString(file),
+ width_in_points, height_in_points);
+ Py_END_ALLOW_THREADS;
+ return PycairoSurface_FromSurface (sfc, NULL);
+ }
+ /* else: file or file-like object argument */
+ writer = PyObject_GetAttrString (file, "write");
+ if (writer == NULL || !PyCallable_Check (writer)) {
+ Py_XDECREF(writer);
+ PyErr_SetString(PyExc_TypeError,
+"PSSurface argument 1 must be\n"
+" None, or\n"
+" a filename (str), or\n"
+" a file object, or\n"
+" an object that has a \"write\" method (like StringIO)."
+ );
+ return NULL;
+ }
+ Py_DECREF(writer);
+
+ Py_BEGIN_ALLOW_THREADS;
+ sfc = cairo_ps_surface_create_for_stream (_write_func, file,
+ width_in_points, height_in_points);
+ Py_END_ALLOW_THREADS;
+ return PycairoSurface_FromSurface (sfc, file);
+}
+
+static PyObject *
+ps_surface_dsc_begin_page_setup (PycairoPSSurface *o) {
+ cairo_ps_surface_dsc_begin_page_setup (o->surface);
+ RETURN_NULL_IF_CAIRO_SURFACE_ERROR(o->surface);
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+ps_surface_dsc_begin_setup (PycairoPSSurface *o) {
+ cairo_ps_surface_dsc_begin_setup (o->surface);
+ RETURN_NULL_IF_CAIRO_SURFACE_ERROR(o->surface);
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+ps_surface_dsc_comment (PycairoPSSurface *o, PyObject *args) {
+ const char *comment;
+ if (!PyArg_ParseTuple(args, "s:PSSurface.dsc_comment", &comment))
+ return NULL;
+ cairo_ps_surface_dsc_comment (o->surface, comment);
+ RETURN_NULL_IF_CAIRO_SURFACE_ERROR(o->surface);
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+ps_surface_get_eps (PycairoPSSurface *o) {
+ PyObject *eps = cairo_ps_surface_get_eps (o->surface) ? Py_True : Py_False;
+ RETURN_NULL_IF_CAIRO_SURFACE_ERROR(o->surface);
+ Py_INCREF(eps);
+ return eps;
+}
+
+/* METH_STATIC */
+static PyObject *
+ps_surface_ps_level_to_string (PyObject *self, PyObject *args) {
+ int level;
+ if (!PyArg_ParseTuple(args, "i:ps_level_to_string", &level))
+ return NULL;
+ const char *s = cairo_ps_level_to_string (level);
+ if (s == NULL){
+ PyErr_SetString(CairoError, "ps_level_to_string: "
+ "invalid level argument");
+ return NULL;
+ }
+ return PyString_FromString(s);
+}
+
+static PyObject *
+ps_surface_restrict_to_level (PycairoPSSurface *o, PyObject *args) {
+ int level;
+
+ if (!PyArg_ParseTuple(args, "i:PSSurface.restrict_to_level", &level))
+ return NULL;
+ cairo_ps_surface_restrict_to_level (o->surface, level);
+ RETURN_NULL_IF_CAIRO_SURFACE_ERROR(o->surface);
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+ps_surface_set_eps (PycairoPSSurface *o, PyObject *args) {
+ PyObject *py_eps;
+ if (!PyArg_ParseTuple(args, "O!:PSSurface.set_eps",
+ &PyBool_Type, &py_eps))
+ return NULL;
+ cairo_ps_surface_set_eps (o->surface, (py_eps == Py_True));
+ RETURN_NULL_IF_CAIRO_SURFACE_ERROR(o->surface);
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+ps_surface_set_size (PycairoPSSurface *o, PyObject *args) {
+ double width_in_points, height_in_points;
+
+ if (!PyArg_ParseTuple(args, "dd:PSSurface.set_size",
+ &width_in_points, &height_in_points))
+ return NULL;
+ cairo_ps_surface_set_size (o->surface, width_in_points, height_in_points);
+ Py_RETURN_NONE;
+}
+
+static PyMethodDef ps_surface_methods[] = {
+ {"dsc_begin_page_setup",
+ (PyCFunction)ps_surface_dsc_begin_page_setup, METH_NOARGS },
+ {"dsc_begin_setup", (PyCFunction)ps_surface_dsc_begin_setup, METH_NOARGS },
+ {"dsc_comment", (PyCFunction)ps_surface_dsc_comment, METH_VARARGS },
+ {"get_eps", (PyCFunction)ps_surface_get_eps, METH_NOARGS },
+ /* ps_get_levels - not implemented yet*/
+ {"ps_level_to_string", (PyCFunction)ps_surface_ps_level_to_string,
+ METH_VARARGS | METH_STATIC},
+ {"restrict_to_level", (PyCFunction)ps_surface_restrict_to_level,
+ METH_VARARGS },
+ {"set_eps", (PyCFunction)ps_surface_set_eps, METH_VARARGS },
+ {"set_size", (PyCFunction)ps_surface_set_size, METH_VARARGS },
+ {NULL, NULL, 0, NULL},
+};
+
+PyTypeObject PycairoPSSurface_Type = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /* ob_size */
+ "cairo.PSSurface", /* tp_name */
+ sizeof(PycairoPSSurface), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT, /* tp_flags */
+ 0, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ ps_surface_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &PycairoSurface_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ (newfunc)ps_surface_new, /* tp_new */
+ 0, /* tp_free */
+ 0, /* tp_is_gc */
+ 0, /* tp_bases */
+};
+#endif /* CAIRO_HAS_PS_SURFACE */
+
+
+/* Class SVGSurface(Surface) ----------------------------------------------- */
+#ifdef CAIRO_HAS_SVG_SURFACE
+#include <cairo-svg.h>
+
+static PyObject *
+svg_surface_new (PyTypeObject *type, PyObject *args, PyObject *kwds) {
+ double width_in_points, height_in_points;
+ PyObject *file, *writer;
+ cairo_surface_t *sfc;
+
+ if (!PyArg_ParseTuple(args, "Odd:SVGSurface.__new__",
+ &file, &width_in_points, &height_in_points))
+ return NULL;
+
+ if (file == Py_None) {
+ Py_BEGIN_ALLOW_THREADS;
+ sfc = cairo_svg_surface_create (NULL,
+ width_in_points, height_in_points);
+ Py_END_ALLOW_THREADS;
+ return PycairoSurface_FromSurface (sfc, NULL);
+ }else if (PyObject_TypeCheck (file, &PyBaseString_Type)) {
+ /* string (filename) argument */
+ Py_BEGIN_ALLOW_THREADS;
+ sfc = cairo_svg_surface_create (PyString_AsString(file),
+ width_in_points, height_in_points);
+ Py_END_ALLOW_THREADS;
+ return PycairoSurface_FromSurface (sfc, NULL);
+ }
+ /* else: file or file-like object argument */
+ writer = PyObject_GetAttrString (file, "write");
+ if (writer == NULL || !PyCallable_Check (writer)) {
+ Py_XDECREF(writer);
+ PyErr_SetString(PyExc_TypeError,
+"SVGSurface argument 1 must be\n"
+" None, or\n"
+" a filename (str), or\n"
+" a file object, or\n"
+" an object that has a \"write\" method (like StringIO)."
+ );
+ return NULL;
+ }
+ Py_DECREF(writer);
+
+ Py_BEGIN_ALLOW_THREADS;
+ sfc = cairo_svg_surface_create_for_stream (_write_func, file,
+ width_in_points, height_in_points);
+ Py_END_ALLOW_THREADS;
+ return PycairoSurface_FromSurface (sfc, file);
+}
+
+static PyMethodDef svg_surface_methods[] = {
+ /* TODO
+ * cairo_svg_surface_restrict_to_version
+ * cairo_svg_get_versions
+ * cairo_svg_version_to_string
+ */
+ {NULL, NULL, 0, NULL},
+};
+
+PyTypeObject PycairoSVGSurface_Type = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /* ob_size */
+ "cairo.SVGSurface", /* tp_name */
+ sizeof(PycairoSVGSurface), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT, /* tp_flags */
+ 0, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ svg_surface_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &PycairoSurface_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ (newfunc)svg_surface_new, /* tp_new */
+ 0, /* tp_free */
+ 0, /* tp_is_gc */
+ 0, /* tp_bases */
+};
+#endif /* CAIRO_HAS_SVG_SURFACE */
+
+
+#if CAIRO_HAS_WIN32_SURFACE
+#include <cairo-win32.h>
+
+/* Class Win32Surface(Surface) -------------------------------------------- */
+static PyObject *
+win32_surface_new (PyTypeObject *type, PyObject *args, PyObject *kwds) {
+ int hdc;
+
+ if (!PyArg_ParseTuple(args, "i:Win32Surface.__new__", &hdc))
+ return NULL;
+ return PycairoSurface_FromSurface (
+ cairo_win32_surface_create ((HDC)hdc), NULL);
+}
+
+static PyMethodDef win32_surface_methods[] = {
+ {NULL, NULL, 0, NULL},
+};
+
+PyTypeObject PycairoWin32Surface_Type = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /* ob_size */
+ "cairo.Win32Surface", /* tp_name */
+ sizeof(PycairoWin32Surface), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT, /* tp_flags */
+ 0, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ win32_surface_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &PycairoSurface_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ (newfunc)win32_surface_new, /* tp_new */
+ 0, /* tp_free */
+ 0, /* tp_is_gc */
+ 0, /* tp_bases */
+};
+
+
+/* Class Win32PrintingSurface(Surface) ------------------------------------ */
+static PyObject *
+win32_printing_surface_new (PyTypeObject *type, PyObject *args,
+ PyObject *kwds) {
+ int hdc;
+
+ if (!PyArg_ParseTuple(args, "i:Win32PrintingSurface.__new__", &hdc))
+ return NULL;
+ return PycairoSurface_FromSurface (
+ cairo_win32_printing_surface_create ((HDC)hdc), NULL);
+}
+
+static PyMethodDef win32_printing_surface_methods[] = {
+ {NULL, NULL, 0, NULL},
+};
+
+PyTypeObject PycairoWin32PrintingSurface_Type = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /* ob_size */
+ "cairo.Win32PrintingSurface", /* tp_name */
+ sizeof(PycairoWin32PrintingSurface), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT, /* tp_flags */
+ 0, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ win32_printing_surface_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &PycairoSurface_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ (newfunc)win32_printing_surface_new,/* tp_new */
+ 0, /* tp_free */
+ 0, /* tp_is_gc */
+ 0, /* tp_bases */
+};
+#endif /* CAIRO_HAS_WIN32_SURFACE */
+
+
+/* Class XCBSurface(Surface) --------------------------------------------- */
+#ifdef CAIRO_HAS_XCB_SURFACE
+#include <cairo-xcb.h>
+
+#ifdef HAVE_XPYB
+/** Convert a Python object from xpyb to a C struct matching libxcb type.
+ * The object must be referenced if you want to keep returned data away from
+ * garbage collection.
+ * @param obj The object to convert.
+ * @param len The size of the object read by Python.
+ * @return A pointer to that data.
+ */
+const void *
+xpyb2struct(PyObject *obj, Py_ssize_t *len)
+{
+ const void *data;
+
+ if (PyObject_AsReadBuffer(obj, &data, len) < 0)
+ return NULL;
+
+ return data;
+}
+
+static int
+have_xpyb(void)
+{
+ static int have_xpyb = -1;
+ if(have_xpyb == -1) {
+ /* Get type from xpyb */
+ xpyb_IMPORT;
+ /* Some types are not defined in the CAPI */
+ PyObject *xpyb_module = PyImport_ImportModule("xcb.xproto");
+ if (xpyb_module) {
+ PyObject *dict = PyModule_GetDict(xpyb_module);
+ xpybVISUALTYPE_type = PyDict_GetItemString(dict, "VISUALTYPE");
+ Py_DECREF(xpyb_module);
+ have_xpyb = 1;
+ }
+ else
+ have_xpyb = 0;
+ }
+ return have_xpyb;
+}
+
+#endif
+
+static PyObject *
+xcb_surface_new (PyTypeObject *type, PyObject *args, PyObject *kwds) {
+#ifdef HAVE_XPYB
+ int width, height;
+ xcb_drawable_t drawable;
+ PyObject *visual;
+ xpybConn *conn;
+
+ if(!have_xpyb())
+ return NULL;
+
+ if (!PyArg_ParseTuple(args, "O!IO!ii:XCBSurface.__new__",
+ xpyb_CAPI->xpybConn_type, &conn,
+ &drawable,
+ xpybVISUALTYPE_type, &visual,
+ &width, &height))
+ return NULL;
+
+ /* Convert Python object VISUALTYPE to a xcb_visualtype_t */
+ Py_ssize_t length;
+ xcb_visualtype_t *visualtype = (xcb_visualtype_t *) xpyb2struct(visual, &length);
+
+ if (length < sizeof(xcb_visualtype_t))
+ return NULL;
+
+ return PycairoSurface_FromSurface (
+ cairo_xcb_surface_create (conn->conn, drawable, visualtype,
+ width, height), NULL);
+#else
+ PyErr_SetString(PyExc_TypeError,
+ "pycairo was not compiled with xpyb support");
+ return NULL;
+#endif
+}
+
+#ifdef HAVE_XPYB
+static PyObject *
+xcb_surface_set_size (PycairoXCBSurface *o, PyObject *args) {
+ int width, height;
+
+ if (!PyArg_ParseTuple(args, "ii:XCBSurface.set_size", &width, &height))
+ return NULL;
+ cairo_xcb_surface_set_size (o->surface, width, height);
+ Py_RETURN_NONE;
+}
+#endif
+
+static PyMethodDef xcb_surface_methods[] = {
+#ifdef HAVE_XPYB
+ {"set_size", (PyCFunction)xcb_surface_set_size, METH_VARARGS },
+#endif
+ {NULL, NULL, 0, NULL},
+};
+
+PyTypeObject PycairoXCBSurface_Type = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /* ob_size */
+ "cairo.XCBSurface", /* tp_name */
+ sizeof(PycairoXCBSurface), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT, /* tp_flags */
+ 0, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ xcb_surface_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &PycairoSurface_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ (newfunc)xcb_surface_new, /* tp_new */
+ 0, /* tp_free */
+ 0, /* tp_is_gc */
+ 0, /* tp_bases */
+};
+#endif /* CAIRO_HAS_XCB_SURFACE */
+
+
+/* Class XlibSurface(Surface) --------------------------------------------- */
+#ifdef CAIRO_HAS_XLIB_SURFACE
+#include <cairo-xlib.h>
+
+static PyObject *
+xlib_surface_new (PyTypeObject *type, PyObject *args, PyObject *kwds) {
+ PyErr_SetString(PyExc_TypeError,
+ "The XlibSurface type cannot be directly instantiated");
+ return NULL;
+}
+
+static PyObject *
+xlib_surface_get_depth (PycairoXlibSurface *o) {
+ return PyInt_FromLong (cairo_xlib_surface_get_depth (o->surface));
+}
+
+static PyObject *
+xlib_surface_get_height (PycairoXlibSurface *o) {
+ return PyInt_FromLong (cairo_xlib_surface_get_height (o->surface));
+}
+
+static PyObject *
+xlib_surface_get_width (PycairoXlibSurface *o) {
+ return PyInt_FromLong (cairo_xlib_surface_get_width (o->surface));
+}
+
+static PyMethodDef xlib_surface_methods[] = {
+ {"get_depth", (PyCFunction)xlib_surface_get_depth, METH_NOARGS },
+ {"get_height",(PyCFunction)xlib_surface_get_height, METH_NOARGS },
+ {"get_width", (PyCFunction)xlib_surface_get_width, METH_NOARGS },
+ {NULL, NULL, 0, NULL},
+};
+
+PyTypeObject PycairoXlibSurface_Type = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /* ob_size */
+ "cairo.XlibSurface", /* tp_name */
+ sizeof(PycairoXlibSurface), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT, /* tp_flags */
+ 0, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ xlib_surface_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &PycairoSurface_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ (newfunc)xlib_surface_new, /* tp_new */
+ 0, /* tp_free */
+ 0, /* tp_is_gc */
+ 0, /* tp_bases */
+};
+#endif /* CAIRO_HAS_XLIB_SURFACE */
diff --git a/src/wscript b/src/wscript
new file mode 100644
index 0000000..41b89c7
--- /dev/null
+++ b/src/wscript
@@ -0,0 +1,32 @@
+# -*- python -*-
+
+import os
+
+
+d = 'src'
+
+def build(bld):
+ print(' %s/build' %d)
+
+ # .py files
+ bld.new_task_gen(
+ features = 'py',
+ source = '__init__.py',
+ install_path = '${PYTHONDIR}/cairo',
+ )
+
+ # C extension module
+ bld.new_task_gen(
+ features = 'cc cshlib pyext',
+ source = 'cairomodule.c context.c font.c path.c pattern.c matrix.c surface.c',
+ target = '_cairo',
+ includes = '.',
+ uselib = 'CAIRO',
+ install_path = '${PYTHONDIR}/cairo',
+ )
+
+ # C API
+ bld.install_files(os.path.join(bld.env['PREFIX'], 'include', 'pycairo'),
+ 'py3cairo.h')
+
+ # how to strip binaries ?
diff --git a/test/.gitignore b/test/.gitignore
new file mode 100644
index 0000000..8bc8786
--- /dev/null
+++ b/test/.gitignore
@@ -0,0 +1,3 @@
+*.png
+*.pyc
+*.pyo
diff --git a/test/README b/test/README
new file mode 100644
index 0000000..15a9b7d
--- /dev/null
+++ b/test/README
@@ -0,0 +1,13 @@
+pycairo tests
+-------------
+
+The main test files are the '*_test.py' files.
+They use py.test from pylib.
+http://codespeak.net/py/dist/
+
+$ cd test
+$ py.test
+
+The other files are tests that were used to test/develop specific
+functions. They usually require you run the test and then visually examine the
+output.
diff --git a/test/api_test.py b/test/api_test.py
new file mode 100644
index 0000000..c83bf99
--- /dev/null
+++ b/test/api_test.py
@@ -0,0 +1,86 @@
+'''test pycairo API
+- can be expanded later as required.
+- is not able to test the quality of images created. We assume cairo itself
+ tests for this.
+'''
+import tempfile as tfi
+
+import cairo
+import py.test as test
+
+
+def test_context():
+ if cairo.HAS_IMAGE_SURFACE:
+ f, w, h = cairo.FORMAT_ARGB32, 100, 100
+ s = cairo.ImageSurface(f, w, h)
+ ctx = cairo.Context(s)
+ ctx.set_source_rgb(1.0, 1.0, 1.0)
+ ctx.set_operator(cairo.OPERATOR_SOURCE)
+ ctx.paint()
+
+
+def test_matrix():
+ m = cairo.Matrix()
+ m.rotate(10)
+ m.scale(1.5, 2.5)
+ m.translate(10, 20)
+
+
+def test_path():
+ # AttributeError: 'module' object has no attribute 'Path'
+ test.raises(AttributeError, "p = cairo.Path()")
+ # see examples/warpedtext.py
+
+
+def test_pattern():
+ # TypeError: The Pattern type cannot be instantiated
+ test.raises(TypeError, "p = cairo.Pattern()")
+
+ r,g,b,a = 0.1, 0.2, 0.3, 0.4
+ p = cairo.SolidPattern(r,g,b,a)
+ assert p.get_rgba() == (r,g,b,a)
+
+ # SurfacePattern
+
+ # TypeError: The Gradient type cannot be instantiated
+ test.raises(TypeError, "p = cairo.Gradient()")
+
+ x0,y0,x1,y1 = 0.0, 0.0, 0.0, 1.0
+ p = cairo.LinearGradient(x0,y0,x1,y1)
+ assert p.get_linear_points() == (x0,y0,x1,y1)
+ p.add_color_stop_rgba(1, 0, 0, 0, 1)
+ p.add_color_stop_rgba(0, 1, 1, 1, 1)
+
+ cx0, cy0, radius0, cx1, cy1, radius1 = 1.0, 1.0, 1.0, 2.0, 2.0, 1.0
+ p = cairo.RadialGradient(cx0, cy0, radius0, cx1, cy1, radius1)
+ assert p.get_radial_circles() == (cx0, cy0, radius0, cx1, cy1, radius1)
+ p.add_color_stop_rgba(0, 1, 1, 1, 1)
+ p.add_color_stop_rgba(1, 0, 0, 0, 1)
+
+
+def test_surface():
+ # TypeError: The Surface type cannot be instantiated
+ test.raises(TypeError, "s = cairo.Surface()")
+
+ if cairo.HAS_IMAGE_SURFACE:
+ f, w, h = cairo.FORMAT_ARGB32, 100, 100
+ s = cairo.ImageSurface(f, w, h)
+ assert s.get_format() == f
+ assert s.get_width() == w
+ assert s.get_height() == h
+
+ if cairo.HAS_PDF_SURFACE:
+ f, w, h = tfi.TemporaryFile(mode='w+b'), 100, 100
+ s = cairo.PDFSurface(f, w, h)
+
+ if cairo.HAS_PS_SURFACE:
+ f, w, h = tfi.TemporaryFile(mode='w+b'), 100, 100
+ s = cairo.PSSurface(f, w, h)
+
+ if cairo.HAS_SVG_SURFACE:
+ f, w, h = tfi.TemporaryFile(mode='w+b'), 100, 100
+ s = cairo.SVGSurface(f, w, h)
+
+
+def test_text():
+ pass
diff --git a/test/examples_test.py b/test/examples_test.py
new file mode 100644
index 0000000..57e58c4
--- /dev/null
+++ b/test/examples_test.py
@@ -0,0 +1,29 @@
+'''test by running example scripts
+'''
+import os
+import os.path
+import subprocess
+
+import cairo
+#import py.test as test
+
+
+def test_snippets():
+ '''Run all snippets in png,pdf,ps,svg mode and check they exit successfully.
+ This will create *.{pdf,png,ps,svg} output files in
+ examples/cairo_snippets/snippets/
+ '''
+ def doSnippets(name):
+ retcode = subprocess.call('python %s -s' % name, shell=True)
+ assert retcode == 0, 'Error: retcode == {0}'.format(retcode)
+
+ os.chdir(os.path.join(os.path.dirname(__file__), '..', 'examples',
+ 'cairo_snippets'))
+ if cairo.HAS_PDF_SURFACE:
+ doSnippets('snippets_pdf.py')
+ if cairo.HAS_IMAGE_SURFACE and cairo.HAS_PNG_FUNCTIONS:
+ doSnippets('snippets_png.py')
+ if cairo.HAS_PS_SURFACE:
+ doSnippets('snippets_ps.py')
+ if cairo.HAS_SVG_SURFACE:
+ doSnippets('snippets_svg.py')
diff --git a/test/isurface_create_for_data1.py b/test/isurface_create_for_data1.py
new file mode 100755
index 0000000..867fde4
--- /dev/null
+++ b/test/isurface_create_for_data1.py
@@ -0,0 +1,32 @@
+#!/usr/bin/env python
+"""test cairo.ImageSurface.create_for_data() with a Python array
+"""
+
+import array
+import tempfile
+
+import cairo
+
+if not (cairo.HAS_IMAGE_SURFACE and cairo.HAS_PNG_FUNCTIONS):
+ raise SystemExit ('cairo was not compiled with ImageSurface and PNG support')
+
+h, fileName = tempfile.mkstemp(prefix='pycairo_', suffix='.png')
+width, height = 255, 255
+data = array.array('B', [0] * width * height * 4)
+
+for y in range(height):
+ for x in range(width):
+ offset = (x + (y * width)) * 4
+ alpha = y
+
+ # cairo.FORMAT_ARGB32 uses pre-multiplied alpha
+ data[offset+0] = int(x * alpha/255.0) # B
+ data[offset+1] = int(y * alpha/255.0) # G
+ data[offset+2] = 0 # R
+ data[offset+3] = alpha # A
+
+surface = cairo.ImageSurface.create_for_data(data, cairo.FORMAT_ARGB32,
+ width, height)
+ctx = cairo.Context(surface)
+surface.write_to_png(fileName)
+print "see %s output file" % fileName
diff --git a/test/isurface_create_for_data2.py b/test/isurface_create_for_data2.py
new file mode 100755
index 0000000..c4f290b
--- /dev/null
+++ b/test/isurface_create_for_data2.py
@@ -0,0 +1,30 @@
+#!/usr/bin/env python
+"""test cairo.ImageSurface.create_for_data() with a numpy array
+"""
+import tempfile
+
+import cairo
+import numpy
+
+if not (cairo.HAS_IMAGE_SURFACE and cairo.HAS_PNG_FUNCTIONS):
+ raise SystemExit ('cairo was not compiled with ImageSurface and PNG support')
+
+h, fileName = tempfile.mkstemp(prefix='pycairo_', suffix='.png')
+width, height = 255, 255
+data = numpy.ndarray (shape=(height,width,4), dtype=numpy.uint8)
+
+for x in range(width):
+ for y in range(height):
+ alpha = y
+
+ # cairo.FORMAT_ARGB32 uses pre-multiplied alpha
+ data[y][x][0] = int(x * alpha/255.0) # B
+ data[y][x][1] = int(y * alpha/255.0) # G
+ data[y][x][2] = 0 # R
+ data[y][x][3] = alpha # A
+
+surface = cairo.ImageSurface.create_for_data (data, cairo.FORMAT_ARGB32,
+ width, height)
+ctx = cairo.Context(surface)
+surface.write_to_png(fileName)
+print "see %s output file" % fileName
diff --git a/test/isurface_create_from_png.py b/test/isurface_create_from_png.py
new file mode 100755
index 0000000..129016d
--- /dev/null
+++ b/test/isurface_create_from_png.py
@@ -0,0 +1,56 @@
+#!/usr/bin/env python
+'''test cairo.ImageSurface.create_from_png() and
+ cairo.Surface.write_to_png()
+'''
+
+import os
+import tempfile
+
+import cairo
+
+if not (cairo.HAS_IMAGE_SURFACE and cairo.HAS_PNG_FUNCTIONS):
+ raise SystemExit ('cairo was not compiled with ImageSurface and PNG support')
+
+inFileName = os.path.join(os.path.dirname(__file__), '..', 'examples',
+ 'cairo_snippets', 'data', 'romedalen.png')
+surface = cairo.ImageSurface.create_from_png(inFileName)
+
+# write to filename
+_, outFileName = tempfile.mkstemp(prefix='pycairo_', suffix='.png')
+surface.write_to_png(outFileName)
+print "see %s output file" % outFileName
+
+# write to file object
+h, outFileName = tempfile.mkstemp(prefix='pycairo_', suffix='.png')
+os.close(h)
+f=file(outFileName, "w")
+surface.write_to_png(f)
+f.close()
+print "see %s output file" % outFileName
+
+# write to object that has a "write" method
+import StringIO
+_, outFileName = tempfile.mkstemp(prefix='pycairo_', suffix='.png')
+buf = StringIO.StringIO()
+surface.write_to_png(buf)
+png_string = buf.getvalue()
+buf.close()
+f=file(outFileName, "w")
+f.write(png_string)
+f.close()
+print "see %s output file" % outFileName
+
+# write to object that has a "write" method
+_, outFileName = tempfile.mkstemp(prefix='pycairo_', suffix='.png')
+import cStringIO
+buf = cStringIO.StringIO()
+surface.write_to_png(buf)
+png_string = buf.getvalue()
+buf.close()
+f=file(outFileName, "w")
+f.write(png_string)
+f.close()
+print "see %s output file" % outFileName
+
+# error test - to check the error message, should raise TypeError
+#surface.write_to_png(101)
diff --git a/test/isurface_get_data.py b/test/isurface_get_data.py
new file mode 100755
index 0000000..f2662d4
--- /dev/null
+++ b/test/isurface_get_data.py
@@ -0,0 +1,50 @@
+#!/usr/bin/env python
+"""
+Test ImageSurface.get_data()
+"""
+import tempfile
+
+import cairo
+import numpy
+
+if not (cairo.HAS_IMAGE_SURFACE and cairo.HAS_PNG_FUNCTIONS):
+ raise SystemExit ('cairo was not compiled with ImageSurface and PNG support')
+
+w, h = 128, 128
+
+surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, w, h)
+ctx = cairo.Context(surface)
+
+ctx.set_source_rgb(1, 1, 1) # white
+ctx.set_operator(cairo.OPERATOR_SOURCE)
+ctx.paint()
+
+# Draw out the triangle using absolute coordinates
+ctx.move_to(w/2, h/3)
+ctx.line_to(2*w/3, 2*h/3)
+ctx.rel_line_to(-1*w/3, 0)
+ctx.close_path()
+
+ctx.set_source_rgb(0, 0, 0) # black
+ctx.set_line_width(15)
+ctx.stroke()
+_, outFileName = tempfile.mkstemp(prefix='pycairo_', suffix='.png')
+surface.write_to_png(outFileName)
+print "see %s output file" % outFileName
+
+# modify surface using numpy
+buf = surface.get_data()
+# alternative which should work (?) but reports
+# TypeError: buffer is read-only
+# - is a Python bug?
+#buf = buffer (surface1)
+
+a = numpy.ndarray(shape=(w,h,4), dtype=numpy.uint8, buffer=buf)
+
+# draw a vertical line
+a[:,40,0] = 255 # byte 0 is blue on little-endian systems
+a[:,40,1] = 0
+a[:,40,2] = 0
+_, outFileName = tempfile.mkstemp(prefix='pycairo_', suffix='.png')
+surface.write_to_png(outFileName)
+print "see %s output file" % outFileName
diff --git a/test/pygame-test1.py b/test/pygame-test1.py
new file mode 100755
index 0000000..bd96b88
--- /dev/null
+++ b/test/pygame-test1.py
@@ -0,0 +1,65 @@
+#!/usr/bin/env python
+"""demonstrate pycairo and pygame
+method1: use pycairo and pygame directly
+"""
+
+import array
+import math
+import sys
+
+import cairo
+import pygame
+
+def draw(surface):
+ x,y, radius = (250,250, 200)
+ ctx = cairo.Context(surface)
+ ctx.set_line_width(15)
+ ctx.arc(x, y, radius, 0, 2.0 * math.pi)
+ ctx.set_source_rgb(0.8, 0.8, 0.8)
+ ctx.fill_preserve()
+ ctx.set_source_rgb(1, 1, 1)
+ ctx.stroke()
+
+def input(events):
+ for event in events:
+ if event.type == pygame.QUIT:
+ sys.exit(0)
+ else:
+ print event
+
+
+Width, Height = 512, 512
+surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, Width, Height)
+
+pygame.init()
+window = pygame.display.set_mode( (Width,Height) )
+screen = pygame.display.get_surface()
+
+draw(surface)
+
+#Create PyGame surface from Cairo Surface
+buf = surface.get_data()
+image = pygame.image.frombuffer(buf,(Width,Height),"ARGB",)
+#Tranfer to Screen
+screen.blit(image, (0,0))
+pygame.display.flip()
+
+while True:
+ input(pygame.event.get())
+
+
+"""
+with pycairo 1.4.12 and pygame 1.7.1 you get the error message:
+
+Traceback (most recent call last):
+ File "./pygame-test1.py", line 42, in <module>
+ image = pygame.image.frombuffer(buf,(Width,Height),"ARGB",)
+TypeError: char buffer type not available
+
+This is because with
+ buf = surface.get_data()
+pycairo provides a binary image buffer,
+whereas with
+ image = pygame.image.frombuffer(buf,(Width,Height),"ARGB",)
+pygame is expecting a text-based character buffer!
+"""
diff --git a/test/pygame-test2.py b/test/pygame-test2.py
new file mode 100755
index 0000000..bec32de
--- /dev/null
+++ b/test/pygame-test2.py
@@ -0,0 +1,49 @@
+#!/usr/bin/env python
+"""demonstrate pycairo and pygame
+method1: use an intermediate Python array object
+"""
+
+import array
+import math
+import sys
+
+import cairo
+import pygame
+
+def draw(surface):
+ x,y, radius = (250,250, 200)
+ ctx = cairo.Context(surface)
+ ctx.set_line_width(15)
+ ctx.arc(x, y, radius, 0, 2.0 * math.pi)
+ ctx.set_source_rgb(0.8, 0.8, 0.8)
+ ctx.fill_preserve()
+ ctx.set_source_rgb(1, 1, 1)
+ ctx.stroke()
+
+def input(events):
+ for event in events:
+ if event.type == pygame.QUIT:
+ sys.exit(0)
+ else:
+ print event
+
+
+Width, Height = 512, 512
+data = array.array('c', chr(0) * Width * Height * 4)
+stride = Width * 4
+surface = cairo.ImageSurface.create_for_data(data, cairo.FORMAT_ARGB32,Width, Height, stride)
+
+pygame.init()
+window = pygame.display.set_mode( (Width,Height) )
+screen = pygame.display.get_surface()
+
+draw(surface)
+
+#Create PyGame surface from Cairo Surface
+image = pygame.image.frombuffer(data.tostring(),(Width,Height),"ARGB",)
+#Tranfer to Screen
+screen.blit(image, (0,0))
+pygame.display.flip()
+
+while True:
+ input(pygame.event.get())
diff --git a/test/surface_create_for_stream.py b/test/surface_create_for_stream.py
new file mode 100755
index 0000000..61997e0
--- /dev/null
+++ b/test/surface_create_for_stream.py
@@ -0,0 +1,81 @@
+#!/usr/bin/env python
+"""
+Test PDF/PS/SVG constructors (using streams)
+"""
+
+import cStringIO
+import gc
+import math
+import sys
+import StringIO
+
+import cairo
+
+
+class C(object):
+ """a file-like object (for testing), it simulates sys.stdout
+ """
+ def __init__ (self):
+ self.closed = False
+
+ def write(self, s):
+ """just echo to stdout, without newlines"""
+ if self.closed:
+ raise ValueError ("I/O operation on closed file")
+ sys.stdout.write(s)
+
+ def close(self):
+ self.closed = True
+
+
+# a selection of possible args to surface.write_to_png()
+#fo = '/tmp/f.ps'
+fo = file('/tmp/f.svg', 'w')
+#fo = StringIO.StringIO()
+#fo = cStringIO.StringIO()
+#fo = sys.stdout
+#fo = C()
+
+#fo.close() # this should cause: ValueError: I/O operation on closed file
+
+WIDTH, HEIGHT = 256, 256
+
+#surface = cairo.PDFSurface(fo, WIDTH, HEIGHT)
+#surface = cairo.PSSurface(fo, WIDTH, HEIGHT)
+surface = cairo.SVGSurface(fo, WIDTH, HEIGHT)
+
+#sys.stdout.write ('1\n'); sys.stdout.flush()
+ctx = cairo.Context(surface)
+
+#del fo # test that 'fo' is referenced to keep it alive
+#gc.collect()
+
+#fo.close() # this should cause: ValueError: I/O operation on closed file
+
+ctx.scale(WIDTH/1.0, HEIGHT/1.0)
+
+pat = cairo.LinearGradient(0.0, 0.0, 0.0, 1.0)
+pat.add_color_stop_rgba(1, 0, 0, 0, 1)
+pat.add_color_stop_rgba(0, 1, 1, 1, 1)
+
+ctx.rectangle(0,0,1,1)
+ctx.set_source(pat)
+ctx.fill()
+
+pat = cairo.RadialGradient(0.45, 0.4, 0.1,
+ 0.4, 0.4, 0.5)
+pat.add_color_stop_rgba(0, 1, 1, 1, 1)
+pat.add_color_stop_rgba(1, 0, 0, 0, 1)
+
+ctx.set_source(pat)
+ctx.arc(0.5, 0.5, 0.3, 0, 2 * math.pi)
+ctx.fill()
+
+ctx.show_page()
+surface.finish()
+
+# for testing StringIO: get data and write to file
+#string = fo.getvalue()
+#f2 = file('/tmp/f.ps', 'w')
+#f2.write(string)
+#f2.close()
diff --git a/test/surface_write_to_png.py b/test/surface_write_to_png.py
new file mode 100755
index 0000000..61674f4
--- /dev/null
+++ b/test/surface_write_to_png.py
@@ -0,0 +1,73 @@
+#!/usr/bin/env python
+"""
+Test Surface.write_to_png()
+"""
+
+import cStringIO
+import math
+import sys
+import StringIO
+
+import cairo
+
+
+if not (cairo.HAS_IMAGE_SURFACE and cairo.HAS_PNG_FUNCTIONS):
+ raise SystemExit ('cairo was not compiled with ImageSurface and PNG support')
+
+
+class C(object):
+ """a file-like object (for testing), it simulates sys.stdout
+ """
+ def __init__(self):
+ self.closed = False
+
+ def write(self, s):
+ """just echo to stdout, without newlines"""
+ if self.closed:
+ raise ValueError("I/O operation on closed file")
+ sys.stdout.write(s)
+
+ def close(self):
+ self.closed = True
+
+
+WIDTH, HEIGHT = 256, 256
+
+surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, WIDTH, HEIGHT)
+ctx = cairo.Context(surface)
+
+ctx.scale(WIDTH/1.0, HEIGHT/1.0)
+
+pat = cairo.LinearGradient(0.0, 0.0, 0.0, 1.0)
+pat.add_color_stop_rgba(1, 0, 0, 0, 1)
+pat.add_color_stop_rgba(0, 1, 1, 1, 1)
+
+ctx.rectangle(0,0,1,1)
+ctx.set_source(pat)
+ctx.fill()
+
+pat = cairo.RadialGradient(0.45, 0.4, 0.1,
+ 0.4, 0.4, 0.5)
+pat.add_color_stop_rgba(0, 1, 1, 1, 1)
+pat.add_color_stop_rgba(1, 0, 0, 0, 1)
+
+ctx.set_source(pat)
+ctx.arc(0.5, 0.5, 0.3, 0, 2 * math.pi)
+ctx.fill()
+
+# a selection of possible args to surface.write_to_png()
+#fo = '/tmp/f.png'
+fo = file('/tmp/f.png', 'w')
+#fo = StringIO.StringIO()
+#fo = cStringIO.StringIO()
+#fo = sys.stdout
+#fo = C()
+
+#fo.close() # this should cause: ValueError: I/O operation on closed file
+surface.write_to_png(fo)
+
+# for testing StringIO: get data and write to file
+#string = fo.getvalue()
+#f2 = file('/tmp/f.png', 'w')
+#f2.write(string)
+#f2.close()
diff --git a/wscript b/wscript
new file mode 100644
index 0000000..a98e7ee
--- /dev/null
+++ b/wscript
@@ -0,0 +1,72 @@
+# -*- python -*-
+
+import os
+
+APPNAME='pycairo'
+VERSION='1.8.10'
+cairo_version_required = '1.8.10'
+srcdir = '.'
+blddir = '../%s-build' % APPNAME
+
+d = srcdir
+
+
+def set_options(opt):
+ print(' %s/set_options' %d)
+ opt.tool_options('compiler_cc')
+ opt.tool_options('python') # options for disabling pyc or pyo compilation
+
+
+def init():
+ print(' %s/init' %d)
+
+
+def configure(conf):
+ print(' %s/configure' %d)
+
+ env = conf.env
+ conf.check_tool('misc')
+ conf.check_tool('compiler_cc')
+ conf.check_tool('python')
+ conf.check_python_version((2,6,0))
+ conf.check_python_headers()
+ conf.check_cfg(package='cairo', atleast_version=cairo_version_required,
+ args='--cflags --libs')
+
+ # add gcc options
+ if env['CC_NAME'] == 'gcc':
+ for opt in ('-std=c99', '-Wall'):
+ if opt not in env['CCFLAGS']:
+ env.append_value('CCFLAGS', opt)
+
+ version = [int(s) for s in VERSION.split('.')]
+ conf.define('VERSION', VERSION)
+ conf.define('PYCAIRO_VERSION_MAJOR', version[0])
+ conf.define('PYCAIRO_VERSION_MINOR', version[1])
+ conf.define('PYCAIRO_VERSION_MICRO', version[2])
+
+ conf.write_config_header('src/config.h')
+
+
+def build(bld):
+ print(' %s/build' %d)
+ bld.add_subdirs('src')
+
+ # generate and install the .pc file
+ obj = bld.new_task_gen('subst')
+ obj.source = 'py3cairo.pc.in'
+ obj.target = 'py3cairo.pc'
+ obj.dict = {
+ 'VERSION' : VERSION,
+ 'prefix' : bld.env['PREFIX'],
+ 'includedir': os.path.join(bld.env['PREFIX'], 'include'),
+ }
+ obj.install_path = os.path.join(bld.env['PREFIX'], 'lib', 'pkgconfig')
+
+
+def dist(): # create archives of project
+ print(' %s/dist' %d)
+
+
+def shutdown():
+ print(' %s/shutdown' %d)