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
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)