diff options
author | Carl Worth <cworth@cworth.org> | 2006-02-13 16:46:37 -0800 |
---|---|---|
committer | Carl Worth <cworth@cworth.org> | 2006-02-13 16:46:37 -0800 |
commit | db163fcc882251188e0ce63d0b9606cb59664da0 (patch) | |
tree | cc99e4040f31575d7b0a1769b49f7b6ee75d12be | |
parent | d7edfcacd918cb8d78a5694348fa21d77f17f6fa (diff) | |
parent | 327dc6f2ae304aa0536123bf8224a53290f72c29 (diff) |
Remove pixman and revert tessellation bug from SNAPSHOT_0_2_0SNAPSHOT_0_2_0
99 files changed, 12467 insertions, 4209 deletions
@@ -13,6 +13,7 @@ config.sub configure libtool ltmain.sh +releases stamp-h stamp-h1 stamp-h.in @@ -1,4 +1,5 @@ Olivier Andrieu <oliv__a@users.sourceforge.net> PNG backend +Peter Dennis Bartok <peter@novonyx.com> Bug fix for clipping Dave Beckett <dave.beckett@bristol.ac.uk> Track rename of libpixman, build fixes Andrew Chant <andrew.chant@utoronto.ca> Adding const where needed John Ellson <ellson@research.att.com> First font/glyph extents functions @@ -13,6 +14,7 @@ David Reveman <davidr@freedesktop.org> New pattern API, OpenGL backend Jamey Sharp <jamey@minilop.net> Surface/font backend virtualization, XCB backend Bill Spitzak <spitzak@d2.com> Build fix to find Xrender.h without xrender.pc Sasha Vasko <sasha@aftercode.net> Build fix to compile without xlib backend +Vladimir Vukicevic <vladimir@pobox.com> Bug fix for clipping Carl Worth <cworth@isi.edu> Original library, support for paths, images Richard D. Worth <richard@theworths.org> Build fixes for cygwin @@ -81,3 +81,14 @@ libpixman, (nor in glitz?). -- font-size="0" in an SVG file does very bad things. + +-- + +move_to_show_surface (see cairo/test): + + * 2004-10-25 Carl Worth <cworth@cworth.org> + * + * It looks like cairo_show_surface has no effect if it follows a + * call to cairo_move_to to any coordinate other than 0,0. A little + * bit of poking around suggests this isn't a regression, (at least + * not since the last pixman snapshot). @@ -1,510 +1,17 @@ +Cairo is free software. - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 +Every source file in the implementation of cairo is available to be +redistributed and/or modified under the terms of either the GNU Lesser +General Public License (LPGL) version 2.1 or the Mozilla Public +License (MPL) version 1.1. Some files are available under more +liberal terms, but we believe that in all cases, each file may be used +under either the LGPL or the MPL. - Copyright (C) 1991, 1999 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - -[This is the first released version of the Lesser GPL. It also counts - as the successor of the GNU Library Public License, version 2, hence - the version number 2.1.] - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Lesser General Public License, applies to some -specially designated software packages--typically libraries--of the -Free Software Foundation and other authors who decide to use it. You -can use it too, but we suggest you first think carefully about whether -this license or the ordinary General Public License is the better -strategy to use in any particular case, based on the explanations -below. - - When we speak of free software, we are referring to freedom of use, -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 this service if you wish); that you receive source code or can get -it if you want it; that you can change the software and use pieces of -it in new free programs; and that you are informed that you can do -these things. - - To protect your rights, we need to make restrictions that forbid -distributors to deny you these rights or to ask you to surrender these -rights. These restrictions translate to certain responsibilities for -you if you distribute copies of the library or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link other code with the library, you must provide -complete object files to the recipients, so that they can relink them -with the library after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - We protect your rights with a two-step method: (1) we copyright the -library, and (2) we offer you this license, which gives you legal -permission to copy, distribute and/or modify the library. - - To protect each distributor, we want to make it very clear that -there is no warranty for the free library. Also, if the library is -modified by someone else and passed on, the recipients should know -that what they have is not the original version, so that the original -author's reputation will not be affected by problems that might be -introduced by others. - - Finally, software patents pose a constant threat to the existence of -any free program. We wish to make sure that a company cannot -effectively restrict the users of a free program by obtaining a -restrictive license from a patent holder. Therefore, we insist that -any patent license obtained for a version of the library must be -consistent with the full freedom of use specified in this license. - - Most GNU software, including some libraries, is covered by the -ordinary GNU General Public License. This license, the GNU Lesser -General Public License, applies to certain designated libraries, and -is quite different from the ordinary General Public License. We use -this license for certain libraries in order to permit linking those -libraries into non-free programs. - - When a program is linked with a library, whether statically or using -a shared library, the combination of the two is legally speaking a -combined work, a derivative of the original library. The ordinary -General Public License therefore permits such linking only if the -entire combination fits its criteria of freedom. The Lesser General -Public License permits more lax criteria for linking other code with -the library. - - We call this license the "Lesser" General Public License because it -does Less to protect the user's freedom than the ordinary General -Public License. It also provides other free software developers Less -of an advantage over competing non-free programs. These disadvantages -are the reason we use the ordinary General Public License for many -libraries. However, the Lesser license provides advantages in certain -special circumstances. - - For example, on rare occasions, there may be a special need to -encourage the widest possible use of a certain library, so that it -becomes a de-facto standard. To achieve this, non-free programs must -be allowed to use the library. A more frequent case is that a free -library does the same job as widely used non-free libraries. In this -case, there is little to gain by limiting the free library to free -software only, so we use the Lesser General Public License. - - In other cases, permission to use a particular library in non-free -programs enables a greater number of people to use a large body of -free software. For example, permission to use the GNU C Library in -non-free programs enables many more people to use the whole GNU -operating system, as well as its variant, the GNU/Linux operating -system. - - Although the Lesser General Public License is Less protective of the -users' freedom, it does ensure that the user of a program that is -linked with the Library has the freedom and the wherewithal to run -that program using a modified version of the Library. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, whereas the latter must -be combined with the library in order to run. - - GNU LESSER GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library or other -program which contains a notice placed by the copyright holder or -other authorized party saying it may be distributed under the terms of -this Lesser General Public License (also called "this License"). -Each licensee is addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, complete source code means -all the source code for all modules it contains, plus any associated -interface definition files, plus the scripts used to control -compilation and installation of the library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete source code as you receive it, in any medium, provided that -you conspicuously and appropriately publish on each copy an -appropriate copyright notice and disclaimer of warranty; keep intact -all the notices that refer to this License and to the absence of any -warranty; and distribute a copy of this License along with the -Library. - - You may charge a fee for the physical act of transferring a copy, -and you may at your option offer warranty protection in exchange for a -fee. - - 2. You may modify your copy or copies of the Library or any portion -of it, thus forming a work based on the Library, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Library, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote -it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you accompany -it with the complete corresponding machine-readable source code, which -must be distributed under the terms of Sections 1 and 2 above on a -medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy -from a designated place, then offering equivalent access to copy the -source code from the same place satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also combine or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (1) uses at run time a - copy of the library already present on the user's computer system, - rather than copying library functions into the executable, and (2) - will operate properly with a modified version of the library, if - the user installs one, as long as the modified version is - interface-compatible with the version that the work was made with. - - c) Accompany the work with a written offer, valid for at least - three years, to give the same user the materials specified in - Subsection 6a, above, for a charge no more than the cost of - performing this distribution. - - d) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - e) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the materials to be distributed need not include anything that is -normally distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies -the executable. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. 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 not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library is void, and will automatically terminate your -rights under this License. However, parties who have received copies, -or rights, from you under this License will not have their licenses -terminated so long as such parties remain in full compliance. - - 9. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -subject to these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties with -this License. - - 11. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -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 -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply, and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library under this License -may add an explicit geographical distribution limitation excluding those -countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 13. The Free Software Foundation may publish revised and/or new -versions of the 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 -specifies a version number of this License which applies to it and -"any later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -write to the author to ask for permission. For software which is -copyrighted by the Free Software Foundation, write to the Free -Software Foundation; we sometimes make exceptions for this. Our -decision will be guided by the two goals of preserving the free status -of all derivatives of our free software and of promoting the sharing -and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "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 -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE LIBRARY 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 -LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF -SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Libraries - - If you develop a new library, and you want it to be of the greatest -possible use to the public, we recommend making it free software that -everyone can redistribute and change. You can do so by permitting -redistribution under these terms (or, alternatively, under the terms -of the ordinary General Public License). - - To apply these terms, attach the following notices to the library. -It is safest to attach them to the start of each source file to most -effectively convey 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 library's name and a brief idea of what it does.> - Copyright (C) <year> <name of author> - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library 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 this library; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -Also add information on how to contact you by electronic and paper mail. - -You should also get your employer (if you work as a programmer) or -your school, if any, to sign a "copyright disclaimer" for the library, -if necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - library `Frob' (a library for tweaking knobs) written by James - Random Hacker. - - <signature of Ty Coon>, 1 April 1990 - Ty Coon, President of Vice - -That's all there is to it! +See the following files in this directory for the precise terms and +conditions of either license: + COPYING-LGPL-2.1 + COPYING-MPL-1.1 +Please see each file in the implementation for Copyright and licensing +information. diff --git a/COPYING-LGPL-2.1 b/COPYING-LGPL-2.1 new file mode 100644 index 00000000..b124cf58 --- /dev/null +++ b/COPYING-LGPL-2.1 @@ -0,0 +1,510 @@ + + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations +below. + + When we speak of free software, we are referring to freedom of use, +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 this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it +becomes a de-facto standard. To achieve this, non-free programs must +be allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control +compilation and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at least + three years, to give the same user the materials specified in + Subsection 6a, above, for a charge no more than the cost of + performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. 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 not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +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 +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply, and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License +may add an explicit geographical distribution limitation excluding those +countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the 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 +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "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 +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY 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 +LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms +of the ordinary General Public License). + + To apply these terms, attach the following notices to the library. +It is safest to attach them to the start of each source file to most +effectively convey 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 library's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or +your school, if any, to sign a "copyright disclaimer" for the library, +if necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James + Random Hacker. + + <signature of Ty Coon>, 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/COPYING-MPL-1.1 b/COPYING-MPL-1.1 new file mode 100644 index 00000000..7714141d --- /dev/null +++ b/COPYING-MPL-1.1 @@ -0,0 +1,470 @@ + MOZILLA PUBLIC LICENSE + Version 1.1 + + --------------- + +1. Definitions. + + 1.0.1. "Commercial Use" means distribution or otherwise making the + Covered Code available to a third party. + + 1.1. "Contributor" means each entity that creates or contributes to + the creation of Modifications. + + 1.2. "Contributor Version" means the combination of the Original + Code, prior Modifications used by a Contributor, and the Modifications + made by that particular Contributor. + + 1.3. "Covered Code" means the Original Code or Modifications or the + combination of the Original Code and Modifications, in each case + including portions thereof. + + 1.4. "Electronic Distribution Mechanism" means a mechanism generally + accepted in the software development community for the electronic + transfer of data. + + 1.5. "Executable" means Covered Code in any form other than Source + Code. + + 1.6. "Initial Developer" means the individual or entity identified + as the Initial Developer in the Source Code notice required by Exhibit + A. + + 1.7. "Larger Work" means a work which combines Covered Code or + portions thereof with code not governed by the terms of this License. + + 1.8. "License" means this document. + + 1.8.1. "Licensable" means having the right to grant, to the maximum + extent possible, whether at the time of the initial grant or + subsequently acquired, any and all of the rights conveyed herein. + + 1.9. "Modifications" means any addition to or deletion from the + substance or structure of either the Original Code or any previous + Modifications. When Covered Code is released as a series of files, a + Modification is: + A. Any addition to or deletion from the contents of a file + containing Original Code or previous Modifications. + + B. Any new file that contains any part of the Original Code or + previous Modifications. + + 1.10. "Original Code" means Source Code of computer software code + which is described in the Source Code notice required by Exhibit A as + Original Code, and which, at the time of its release under this + License is not already Covered Code governed by this License. + + 1.10.1. "Patent Claims" means any patent claim(s), now owned or + hereafter acquired, including without limitation, method, process, + and apparatus claims, in any patent Licensable by grantor. + + 1.11. "Source Code" means the preferred form of the Covered Code for + making modifications to it, including all modules it contains, plus + any associated interface definition files, scripts used to control + compilation and installation of an Executable, or source code + differential comparisons against either the Original Code or another + well known, available Covered Code of the Contributor's choice. The + Source Code can be in a compressed or archival form, provided the + appropriate decompression or de-archiving software is widely available + for no charge. + + 1.12. "You" (or "Your") means an individual or a legal entity + exercising rights under, and complying with all of the terms of, this + License or a future version of this License issued under Section 6.1. + For legal entities, "You" includes any entity which controls, is + controlled by, or is under common control with You. For purposes of + this definition, "control" means (a) the power, direct or indirect, + to cause the direction or management of such entity, whether by + contract or otherwise, or (b) ownership of more than fifty percent + (50%) of the outstanding shares or beneficial ownership of such + entity. + +2. Source Code License. + + 2.1. The Initial Developer Grant. + The Initial Developer hereby grants You a world-wide, royalty-free, + non-exclusive license, subject to third party intellectual property + claims: + (a) under intellectual property rights (other than patent or + trademark) Licensable by Initial Developer to use, reproduce, + modify, display, perform, sublicense and distribute the Original + Code (or portions thereof) with or without Modifications, and/or + as part of a Larger Work; and + + (b) under Patents Claims infringed by the making, using or + selling of Original Code, to make, have made, use, practice, + sell, and offer for sale, and/or otherwise dispose of the + Original Code (or portions thereof). + + (c) the licenses granted in this Section 2.1(a) and (b) are + effective on the date Initial Developer first distributes + Original Code under the terms of this License. + + (d) Notwithstanding Section 2.1(b) above, no patent license is + granted: 1) for code that You delete from the Original Code; 2) + separate from the Original Code; or 3) for infringements caused + by: i) the modification of the Original Code or ii) the + combination of the Original Code with other software or devices. + + 2.2. Contributor Grant. + Subject to third party intellectual property claims, each Contributor + hereby grants You a world-wide, royalty-free, non-exclusive license + + (a) under intellectual property rights (other than patent or + trademark) Licensable by Contributor, to use, reproduce, modify, + display, perform, sublicense and distribute the Modifications + created by such Contributor (or portions thereof) either on an + unmodified basis, with other Modifications, as Covered Code + and/or as part of a Larger Work; and + + (b) under Patent Claims infringed by the making, using, or + selling of Modifications made by that Contributor either alone + and/or in combination with its Contributor Version (or portions + of such combination), to make, use, sell, offer for sale, have + made, and/or otherwise dispose of: 1) Modifications made by that + Contributor (or portions thereof); and 2) the combination of + Modifications made by that Contributor with its Contributor + Version (or portions of such combination). + + (c) the licenses granted in Sections 2.2(a) and 2.2(b) are + effective on the date Contributor first makes Commercial Use of + the Covered Code. + + (d) Notwithstanding Section 2.2(b) above, no patent license is + granted: 1) for any code that Contributor has deleted from the + Contributor Version; 2) separate from the Contributor Version; + 3) for infringements caused by: i) third party modifications of + Contributor Version or ii) the combination of Modifications made + by that Contributor with other software (except as part of the + Contributor Version) or other devices; or 4) under Patent Claims + infringed by Covered Code in the absence of Modifications made by + that Contributor. + +3. Distribution Obligations. + + 3.1. Application of License. + The Modifications which You create or to which You contribute are + governed by the terms of this License, including without limitation + Section 2.2. The Source Code version of Covered Code may be + distributed only under the terms of this License or a future version + of this License released under Section 6.1, and You must include a + copy of this License with every copy of the Source Code You + distribute. You may not offer or impose any terms on any Source Code + version that alters or restricts the applicable version of this + License or the recipients' rights hereunder. However, You may include + an additional document offering the additional rights described in + Section 3.5. + + 3.2. Availability of Source Code. + Any Modification which You create or to which You contribute must be + made available in Source Code form under the terms of this License + either on the same media as an Executable version or via an accepted + Electronic Distribution Mechanism to anyone to whom you made an + Executable version available; and if made available via Electronic + Distribution Mechanism, must remain available for at least twelve (12) + months after the date it initially became available, or at least six + (6) months after a subsequent version of that particular Modification + has been made available to such recipients. You are responsible for + ensuring that the Source Code version remains available even if the + Electronic Distribution Mechanism is maintained by a third party. + + 3.3. Description of Modifications. + You must cause all Covered Code to which You contribute to contain a + file documenting the changes You made to create that Covered Code and + the date of any change. You must include a prominent statement that + the Modification is derived, directly or indirectly, from Original + Code provided by the Initial Developer and including the name of the + Initial Developer in (a) the Source Code, and (b) in any notice in an + Executable version or related documentation in which You describe the + origin or ownership of the Covered Code. + + 3.4. Intellectual Property Matters + (a) Third Party Claims. + If Contributor has knowledge that a license under a third party's + intellectual property rights is required to exercise the rights + granted by such Contributor under Sections 2.1 or 2.2, + Contributor must include a text file with the Source Code + distribution titled "LEGAL" which describes the claim and the + party making the claim in sufficient detail that a recipient will + know whom to contact. If Contributor obtains such knowledge after + the Modification is made available as described in Section 3.2, + Contributor shall promptly modify the LEGAL file in all copies + Contributor makes available thereafter and shall take other steps + (such as notifying appropriate mailing lists or newsgroups) + reasonably calculated to inform those who received the Covered + Code that new knowledge has been obtained. + + (b) Contributor APIs. + If Contributor's Modifications include an application programming + interface and Contributor has knowledge of patent licenses which + are reasonably necessary to implement that API, Contributor must + also include this information in the LEGAL file. + + (c) Representations. + Contributor represents that, except as disclosed pursuant to + Section 3.4(a) above, Contributor believes that Contributor's + Modifications are Contributor's original creation(s) and/or + Contributor has sufficient rights to grant the rights conveyed by + this License. + + 3.5. Required Notices. + You must duplicate the notice in Exhibit A in each file of the Source + Code. If it is not possible to put such notice in a particular Source + Code file due to its structure, then You must include such notice in a + location (such as a relevant directory) where a user would be likely + to look for such a notice. If You created one or more Modification(s) + You may add your name as a Contributor to the notice described in + Exhibit A. You must also duplicate this License in any documentation + for the Source Code where You describe recipients' rights or ownership + rights relating to Covered Code. You may choose to offer, and to + charge a fee for, warranty, support, indemnity or liability + obligations to one or more recipients of Covered Code. However, You + may do so only on Your own behalf, and not on behalf of the Initial + Developer or any Contributor. You must make it absolutely clear than + any such warranty, support, indemnity or liability obligation is + offered by You alone, and You hereby agree to indemnify the Initial + Developer and every Contributor for any liability incurred by the + Initial Developer or such Contributor as a result of warranty, + support, indemnity or liability terms You offer. + + 3.6. Distribution of Executable Versions. + You may distribute Covered Code in Executable form only if the + requirements of Section 3.1-3.5 have been met for that Covered Code, + and if You include a notice stating that the Source Code version of + the Covered Code is available under the terms of this License, + including a description of how and where You have fulfilled the + obligations of Section 3.2. The notice must be conspicuously included + in any notice in an Executable version, related documentation or + collateral in which You describe recipients' rights relating to the + Covered Code. You may distribute the Executable version of Covered + Code or ownership rights under a license of Your choice, which may + contain terms different from this License, provided that You are in + compliance with the terms of this License and that the license for the + Executable version does not attempt to limit or alter the recipient's + rights in the Source Code version from the rights set forth in this + License. If You distribute the Executable version under a different + license You must make it absolutely clear that any terms which differ + from this License are offered by You alone, not by the Initial + Developer or any Contributor. You hereby agree to indemnify the + Initial Developer and every Contributor for any liability incurred by + the Initial Developer or such Contributor as a result of any such + terms You offer. + + 3.7. Larger Works. + You may create a Larger Work by combining Covered Code with other code + not governed by the terms of this License and distribute the Larger + Work as a single product. In such a case, You must make sure the + requirements of this License are fulfilled for the Covered Code. + +4. Inability to Comply Due to Statute or Regulation. + + If it is impossible for You to comply with any of the terms of this + License with respect to some or all of the Covered Code due to + statute, judicial order, or regulation then You must: (a) comply with + the terms of this License to the maximum extent possible; and (b) + describe the limitations and the code they affect. Such description + must be included in the LEGAL file described in Section 3.4 and must + be included with all distributions of the Source Code. Except to the + extent prohibited by statute or regulation, such description must be + sufficiently detailed for a recipient of ordinary skill to be able to + understand it. + +5. Application of this License. + + This License applies to code to which the Initial Developer has + attached the notice in Exhibit A and to related Covered Code. + +6. Versions of the License. + + 6.1. New Versions. + Netscape Communications Corporation ("Netscape") may publish revised + and/or new versions of the License from time to time. Each version + will be given a distinguishing version number. + + 6.2. Effect of New Versions. + Once Covered Code has been published under a particular version of the + License, You may always continue to use it under the terms of that + version. You may also choose to use such Covered Code under the terms + of any subsequent version of the License published by Netscape. No one + other than Netscape has the right to modify the terms applicable to + Covered Code created under this License. + + 6.3. Derivative Works. + If You create or use a modified version of this License (which you may + only do in order to apply it to code which is not already Covered Code + governed by this License), You must (a) rename Your license so that + the phrases "Mozilla", "MOZILLAPL", "MOZPL", "Netscape", + "MPL", "NPL" or any confusingly similar phrase do not appear in your + license (except to note that your license differs from this License) + and (b) otherwise make it clear that Your version of the license + contains terms which differ from the Mozilla Public License and + Netscape Public License. (Filling in the name of the Initial + Developer, Original Code or Contributor in the notice described in + Exhibit A shall not of themselves be deemed to be modifications of + this License.) + +7. DISCLAIMER OF WARRANTY. + + COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + WITHOUT LIMITATION, WARRANTIES THAT THE COVERED CODE IS FREE OF + DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING. + THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED CODE + IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, + YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE + COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER + OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF + ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER. + +8. TERMINATION. + + 8.1. This License and the rights granted hereunder will terminate + automatically if You fail to comply with terms herein and fail to cure + such breach within 30 days of becoming aware of the breach. All + sublicenses to the Covered Code which are properly granted shall + survive any termination of this License. Provisions which, by their + nature, must remain in effect beyond the termination of this License + shall survive. + + 8.2. If You initiate litigation by asserting a patent infringement + claim (excluding declatory judgment actions) against Initial Developer + or a Contributor (the Initial Developer or Contributor against whom + You file such action is referred to as "Participant") alleging that: + + (a) such Participant's Contributor Version directly or indirectly + infringes any patent, then any and all rights granted by such + Participant to You under Sections 2.1 and/or 2.2 of this License + shall, upon 60 days notice from Participant terminate prospectively, + unless if within 60 days after receipt of notice You either: (i) + agree in writing to pay Participant a mutually agreeable reasonable + royalty for Your past and future use of Modifications made by such + Participant, or (ii) withdraw Your litigation claim with respect to + the Contributor Version against such Participant. If within 60 days + of notice, a reasonable royalty and payment arrangement are not + mutually agreed upon in writing by the parties or the litigation claim + is not withdrawn, the rights granted by Participant to You under + Sections 2.1 and/or 2.2 automatically terminate at the expiration of + the 60 day notice period specified above. + + (b) any software, hardware, or device, other than such Participant's + Contributor Version, directly or indirectly infringes any patent, then + any rights granted to You by such Participant under Sections 2.1(b) + and 2.2(b) are revoked effective as of the date You first made, used, + sold, distributed, or had made, Modifications made by that + Participant. + + 8.3. If You assert a patent infringement claim against Participant + alleging that such Participant's Contributor Version directly or + indirectly infringes any patent where such claim is resolved (such as + by license or settlement) prior to the initiation of patent + infringement litigation, then the reasonable value of the licenses + granted by such Participant under Sections 2.1 or 2.2 shall be taken + into account in determining the amount or value of any payment or + license. + + 8.4. In the event of termination under Sections 8.1 or 8.2 above, + all end user license agreements (excluding distributors and resellers) + which have been validly granted by You or any distributor hereunder + prior to termination shall survive termination. + +9. LIMITATION OF LIABILITY. + + UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT + (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE INITIAL + DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED CODE, + OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR + ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY + CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL, + WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER + COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN + INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF + LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY + RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW + PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE + EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO + THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU. + +10. U.S. GOVERNMENT END USERS. + + The Covered Code is a "commercial item," as that term is defined in + 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial computer + software" and "commercial computer software documentation," as such + terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48 + C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995), + all U.S. Government End Users acquire Covered Code with only those + rights set forth herein. + +11. MISCELLANEOUS. + + This License represents the complete agreement concerning subject + matter hereof. If any provision of this License is held to be + unenforceable, such provision shall be reformed only to the extent + necessary to make it enforceable. This License shall be governed by + California law provisions (except to the extent applicable law, if + any, provides otherwise), excluding its conflict-of-law provisions. + With respect to disputes in which at least one party is a citizen of, + or an entity chartered or registered to do business in the United + States of America, any litigation relating to this License shall be + subject to the jurisdiction of the Federal Courts of the Northern + District of California, with venue lying in Santa Clara County, + California, with the losing party responsible for costs, including + without limitation, court costs and reasonable attorneys' fees and + expenses. The application of the United Nations Convention on + Contracts for the International Sale of Goods is expressly excluded. + Any law or regulation which provides that the language of a contract + shall be construed against the drafter shall not apply to this + License. + +12. RESPONSIBILITY FOR CLAIMS. + + As between Initial Developer and the Contributors, each party is + responsible for claims and damages arising, directly or indirectly, + out of its utilization of rights under this License and You agree to + work with Initial Developer and Contributors to distribute such + responsibility on an equitable basis. Nothing herein is intended or + shall be deemed to constitute any admission of liability. + +13. MULTIPLE-LICENSED CODE. + + Initial Developer may designate portions of the Covered Code as + "Multiple-Licensed". "Multiple-Licensed" means that the Initial + Developer permits you to utilize portions of the Covered Code under + Your choice of the NPL or the alternative licenses, if any, specified + by the Initial Developer in the file described in Exhibit A. + +EXHIBIT A -Mozilla Public License. + + ``The contents of this file are subject to the Mozilla Public License + Version 1.1 (the "License"); you may not use this file except in + compliance with the License. You may obtain a copy of the License at + http://www.mozilla.org/MPL/ + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + License for the specific language governing rights and limitations + under the License. + + The Original Code is ______________________________________. + + The Initial Developer of the Original Code is ________________________. + Portions created by ______________________ are Copyright (C) ______ + _______________________. All Rights Reserved. + + Contributor(s): ______________________________________. + + Alternatively, the contents of this file may be used under the terms + of the _____ license (the "[___] License"), in which case the + provisions of [______] License are applicable instead of those + above. If you wish to allow use of your version of this file only + under the terms of the [____] License and not to allow others to use + your version of this file under the MPL, indicate your decision by + deleting the provisions above and replace them with the notice and + other provisions required by the [___] License. If you do not delete + the provisions above, a recipient may use your version of this file + under either the MPL or the [___] License." + + [NOTE: The text of this Exhibit A may differ slightly from the text of + the notices in the Source Code files of the Original Code. You should + use the text of this Exhibit A rather than the text found in the + Original Code Source Code for Your Modifications.] + @@ -1,3 +1,443 @@ +2004-10-27 Carl Worth <cworth@cworth.org> + + * configure.in: Increment CAIRO_VERSION to 0.2.0. + + * NEWS: Add notes for snapshot 0.2.0. + Add note on reverted tessellation regression bugs. + + * RELEASING: Update release instructions for new release-publish + target. + + * Makefile.am: Add release-check and release-publish targets + copied from libpixman. + + * test/Makefile.am (AM_LDFLAGS): Fix to always link tests against + locally built library, not installed version. + + * test/fill_rule.c: Add new test for cairo_set_fill_rule. Also + demonstrate some of the current tessellation bugs with the version + of the code that is in CVS. + +2004-10-26 Carl Worth <cworth@cworth.org> + + * test/cairo_test.c (cairo_test): Find reference images in + ${srcdir} so that make distcheck will work. + + * test/Makefile.am (cairo_test_lib): Add header files so that make + distcheck is happy. + (INCLUDES): Add -D_GNU_SOURCE for asprintf. Someone motivated may + want to find a more portable approach. + (EXTRA_DIST): Add reference images for the sake of make distcheck. + + * configure.in: Shell doesn't like whitespace around assignment + operator. + + * test/README: Add paragraph on new features. + + * test/.cvsignore: + * test/Makefile.am: + * test/README: + * test/cairo_test.c: + * test/cairo_test.h: + * test/line_width-ref.png: + * test/line_width.c: + * test/move_to_show_surface-ref.png: + * test/move_to_show_surface.c: + * test/read_png.c: + * test/read_png.h: + * test/write_png.c: + * test/write_png.h: + * test/xmalloc.c: + * test/xmalloc.h: Add initial regression test suite. + + * configure.in: Don't AC_SUBST a dozen different FOO_CFLAGS and + FOO_LIBS. Instead, incrementally build up just CAIRO_CFLAGS and + CAIRO_LIBS. + + * cairo.pc.in (Libs): Don't list flags that should get picked up + via dependency information through Requires. + + * BUGS (font-size): Add description of move_to_show_surface. + +2004-10-21 Carl Worth <cworth@cworth.org> + + * src/cairo_png_surface.c: + * src/cairo.c: + * src/cairo.h: + * src/cairo_cache.c: + * src/cairo_color.c: + * src/cairo_fixed.c: + * src/cairo_font.c: + * src/cairo_ft_font.c: + * src/cairo_glitz_surface.c: + * src/cairo_gstate.c: + * src/cairo_hull.c: + * src/cairo_image_surface.c: + * src/cairo_matrix.c: + * src/cairo_path.c: + * src/cairo_path_bounds.c: + * src/cairo_path_fill.c: + * src/cairo_path_stroke.c: + * src/cairo_pattern.c: + * src/cairo_pen.c: + * src/cairo_png_surface.c: + * src/cairo_polygon.c: + * src/cairo_ps_surface.c: + * src/cairo_slope.c: + * src/cairo_spline.c: + * src/cairo_surface.c: + * src/cairo_traps.c: + * src/cairo_xcb_surface.c: + * src/cairo_xlib_surface.c: + * src/cairoint.h: Convert all files to utf-8. Add copyright + information to cairo_png_surface.c. + + * src/cairo_hull.c (_cairo_hull_vertex_compare): Fix comparison so + that it results in a stable sort. This should fix some rendering + bugs due to broken pens. + + * TODO: Add items on custom caps and getting access to hidden + image data + + * Makefile.am (EXTRA_DIST): Add COPYING-LGPL-2.1 and + COPYING-MPL-1.1 to the distribution. + +2004-10-13 Carl Worth <cworth@cworth.org> + + * autogen.sh: automake 1.4 seems to be sufficient. Don't require + 1.6. + +2004-10-12 Keith Packard <keithp@keithp.com> + + * src/cairo_traps.c: (_cairo_traps_init), (_cairo_traps_add_trap), + (_cairo_traps_extents): + * src/cairoint.h: + Compute extents of cairo_traps_t on the fly using approximate + method which is correct given the way cairo generates trapezoids. + + * src/cairo_xlib_surface.c: (_cairo_xlib_surface_create_similar): + Avoid zero-dimensioned pixmaps + +2004-10-12 Carl Worth <cworth@cworth.org> + + * src/cairo_pen.c: Fix a few typos in pen vertex math description. + +2004-10-12 Keith Packard <keithp@keithp.com> + + reviewed by: Carl Worth <cworth@cworth.org> + + * src/cairo_pen.c: (_cairo_pen_init), (_cairo_pen_vertices_needed): + Adapt function from Walter Brisken to compute pen ellipse major + axis length and use that to compute the required number of pen + vertices. + +2004-10-07 Graydon Hoare <graydon@redhat.com> + + * src/Makefile.am (libcairo_la_SOURCES): Add cairo_cache.c + + * src/cairo.c + (cairo_text_extents) + (cairo_show_text) + (cairo_text_path): Rewrite using temporary glyph arrays + + * src/cairo_cache.c: New file. + + * src/cairo_font.c (_cairo_glyph_cache_create) + (_cairo_glyph_cache_destroy) + (_cairo_glyph_cache_reference) + (_cairo_glyph_cache_pop_last) + (_cairo_glyph_surface_init) + (_cairo_font_lookup_glyph): Remove old glyph cache code. + (_cairo_font_scale) + (_cairo_font_transform): Remove font-transforming code. + (_cairo_font_text_extents) + (_cairo_font_text_bbox) + (_cairo_font_show_text) + (_cairo_font_text_path): Remove text-API code. + (_cairo_font_cache_key_t): New structure type. + (_font_cache_hash) + (_font_cache_keys_equal) + (_font_cache_create_entry) + (_font_cache_destroy_entry) + (_font_cache_destroy_cache): New font cache code. + (_global_font_cache) + (_lock_global_font_cache) + (_unlock_global_font_cache) + (_get_global_font_cache): New global font cache. + (_cairo_font_text_to_glyphs) + (_cairo_glyph_cache_hash) + (_cairo_glyph_cache_keys_equal) + (_image_glyph_cache_create_entry) + (_image_glyph_cache_destroy_entry) + (_image_glyph_cache_destroy_cache): New glyph cache code. + (_global_image_glyph_cache) + (_cairo_lock_global_image_glyph_cache) + (_cairo_unlock_global_image_glyph_cache) + (_cairo_get_global_image_glyph_cache): New global glyph cache. + (_cairo_font_cache_backend): New structure. + (_cairo_image_cache_backend): Likewise. + (_cairo_font_create): Reimplement in terms of font cache. + (_cairo_font_init): Remove matrix and glyph cache related code. + (_cairo_font_copy): Likewise. + (_cairo_font_show_glyphs): Delegate to surface when possible. + (_cairo_font_glyph_extents) + (_cairo_font_glyph_bbox) + (_cairo_font_glyph_path) + (_cairo_font_font_extents) + (_cairo_font_show_glyphs): Rename to as cairo_unscaled_font_XXX, + and add scale parameter. + + * src/cairo_ft_font.c + (ft_cache_t) + (ft_font_val_t) + (cairo_ft_cache_key_t) + (cairo_ft_cache_entry_t): New structure types. + (_create_from_face) + (_reference_font_val) + (_destroy_font_val) + (_create_from_library_and_pattern): New functions. + (_ft_font_cache_hash) + (_ft_font_cache_keys_equal) + (_ft_font_cache_create_entry) + (_ft_font_cache_destroy_entry) + (_ft_font_cache_destroy_cache): New ft font cache code. + (_global_ft_cache) + (_lock_global_ft_cache) + (_unlock_global_ft_cache) + (_get_global_ft_cache): New global ft font cache. + (_ft_font_cache_backend): New structure. + (_cairo_ft_font_create): Rewrite to use cache. + (_cairo_ft_font_destroy): Likewise. + (_cairo_ft_font_copy): Remove. + (_install_font_matrix): Rename as _install_font_scale. + (_utf8_to_glyphs): Rename as _cairo_ft_font_text_to_glyphs. + (_cairo_ft_font_text_to_glyphs): Use cache for metrics. + (_cairo_ft_font_extents): Accept size, use scaled metrics. + (_cairo_ft_font_glyph_extents) + (_cairo_ft_font_glyph_bbox) + (_cairo_ft_font_show_glyphs) + (_cairo_ft_font_glyph_path): Modify to use size, cache. + (_cairo_ft_font_text_extents) + (_cairo_ft_font_text_bbox) + (_cairo_ft_font_show_text) + (_cairo_ft_font_text_path): Remove text-API code. + (cairo_ft_font_create) + (cairo_ft_font_create_for_ft_face) + (cairo_ft_font_face) + (cairo_ft_font_pattern): Rewrite using ft_font_val_t. + + * src/cairo_gstate.c (cairo_gstate_init_copy): Just reference font. + (_cairo_gstate_fini): Finalize font matrix. + (_cairo_gstate_default_matrix): Initialize font matrix. + (_cairo_gstate_clip): Re-enable clipping rectangle. + (_cairo_gstate_select_font) + (_cairo_gstate_set_font): Set font matrix to identity. + (_cairo_gstate_scale_font): Scale font matrix, not font. + (_cairo_gstate_transform_font): Transform font matrix, not font. + (_cairo_gstate_set_font_transform): Install as font matrix, not in font. + (_build_font_scale): New helper function. + (_cairo_gstate_text_to_glyphs): New function. + (_cairo_gstate_current_font_extents) + (_cairo_gstate_glyph_extents) + (_cairo_gstate_show_glyphs) + (_cairo_gstate_glyph_path): Rewrite using font matrix and size. + (_cairo_gstate_text_path + (_cairo_gstate_text_extents) + (_cairo_gstate_show_text): Remove text-API code. + + * src/cairo_xlib_surface.c + (_cairo_xlib_surface_set_clip_region): Minor bug fix. + (_cairo_xlib_surface_show_glyphs): New function. + (_cairo_xlib_surface_backend): Add reference to new function. + (glyphset_cache_t) + (glyphset_cache_entry_t): New structure types. + (_next_xlib_glyph): New helper function. + (_xlib_glyphset_cache_create_value) + (_xlib_glyphset_cache_destroy_cache) + (_xlib_glyphset_cache_destroy_value) + (_xlib_glyphset_cache_backend): New glyphset cache code. + (_xlib_glyphset_caches) + (_lock_xlib_glyphset_caches) + (_unlock_xlib_glyphset_caches) + (_get_glyphset_cache): New global glyphset cache. + + * src/cairo_glitz_surface.c (cairo_glitz_surface_backend): + Add NULL entry for show_glyphs. + + * src/cairo_image_surface.c (cairo_image_surface_backend): + Add NULL entry for show_glyphs. + + * src/cairo_ps_surface.c (cairo_ps_surface_backend): + Add NULL entry for show_glyphs. + + * src/cairo_png_surface.c (cairo_png_surface_backend): + Add NULL entry for show_glyphs. + + * src/cairo_xcb_surface.c (cairo_xcb_surface_backend): + Add NULL entry for show_glyphs. + + * src/cairoint.h (cairo_cache_backend_t): New structure type. + (cairo_cache_entry_base_t) + (cairo_cache_arrangement_t) + (cairo_cache_t): New structure types. + (_cairo_cache_init) + (_cairo_cache_reference) + (_cairo_cache_destroy) + (_cairo_cache_lookup) + (_cairo_hash_string): New cache functions. + (CAIRO_IMAGE_GLYPH_CACHE_MEMORY_DEFAULT) + (CAIRO_XLIB_GLYPH_CACHE_MEMORY_DEFAULT) + (CAIRO_FONT_CACHE_NUM_FONTS_DEFAULT) + (CAIRO_FT_CACHE_NUM_FONTS_DEFAULT): New constants. + (cairo_font_scale_t) + (cairo_glyph_cache_key_t) + (cairo_image_glyph_cache_entry_t): New structure types. + (_cairo_lock_global_image_glyph_cache) + (_cairo_unlock_global_image_glyph_cache) + (_cairo_get_global_image_glyph_cache) + (_cairo_glyph_cache_hash) + (_cairo_glyph_cache_keys_equal): New functions for glyph caches. + (cairo_font_backend_t): Remove text-API calls, add scale params, + remove copy call. + (cairo_surface_backend_t): Add show_glyphs entry. + (cairo_glyph_surface_t) + (cairo_glyph_surface_node_t): Remove old glyph cache structures. + (cairo_unscaled_font_t): New structure type. + (cairo_font): Remove glyph cache member, add pointer to unscaled. + (cairo_gstate): Add font_matrix member, change to hold unscaled. + (_cairo_gstate_set_font_transform) + (_cairo_gstate_current_font_transform) + (_cairo_gstate_text_to_glyphs): New functions. + (_cairo_gstate_text_path + (_cairo_gstate_text_extents) + (_cairo_gstate_show_text) + (_cairo_font_text_extents) + (_cairo_font_text_bbox) + (_cairo_font_show_text) + (_cairo_font_text_path): Remove text-API code. + (_cairo_font_glyph_extents) + (_cairo_font_glyph_bbox) + (_cairo_font_glyph_path) + (_cairo_font_font_extents) + (_cairo_font_show_glyphs): Add scale parameter. + +2004-10-04 David Reveman <c99drn@cs.umu.se> + + * configure.in: Require version 0.2.3 of glitz. + + * src/cairo_glitz_surface.c: Do not use VBOs and PBOs for immediate + mode drawing. + +2004-09-30 Jamey Sharp <jamey@minilop.net> + + * src/cairo_xcb_surface.c: + Update for minor XCB API change. + +2004-09-20 David Reveman <c99drn@cs.umu.se> + + * src/cairo_glitz_surface.c (_cairo_glitz_surface_create_similar): + Make sure that only offscreen formats are picked. + (_cairo_glitz_surface_create_similar): Only try to find offscreen + multi-sample format if offscreen multi-sampling is supported. + (_cairo_glitz_surface_create_similar): If we can't find a drawable + format try to pick a non-drawable format. + (_cairo_glitz_surface_composite): Mask clone should be in + CAIRO_FORMAT_A8 format. + +2004-09-15 David Reveman <c99drn@cs.umu.se> + + * src/cairo_glitz_surface.c (_cairo_glitz_surface_set_image): Do + the scanline order conversion in cairo. + (_cairo_glitz_surface_create_pattern): Pre-multiply gradient colors. + (_cairo_glitz_surface_create_similar): Find similar formats + correctly. + +2004-09-12 David Reveman <c99drn@cs.umu.se> + + * src/cairo_glitz_surface.c (_cairo_glitz_surface_create_pattern): + Pickup repeat setting when cloning surface. + (_cairo_glitz_surface_create_pattern): cairo_surface_set_repeat + likes to get a cairo_surface_t pointer not a cairo_glitz_surface_t + pointer. + (_cairo_glitz_surface_set_image): Get pixel masks from pixman image + format. + +2004-09-11 Carl Worth <stacyworth@pippin.local> + + * autogen.sh: Require automake 1.6 rather than 1.7 since it seems + to work just fine. + +2004-09-11 David Reveman <c99drn@cs.umu.se> + + * configure.in: Require version 0.2.2 of glitz. + + * src/cairo_glitz_surface.c (_cairo_glitz_surface_create_pattern): + 0.5 should no longer be added to gradient stop coordinates. + + * src/cairo.h: CAIRO_HAS_GL_SURFACE -> CAIRO_HAS_GLITZ_SURFACE. + cairo_set_target_gl -> cairo_set_target_glitz. + cairo_gl_surface_create -> cairo_glitz_surface_create. + + * src/cairo-features.h.in: GL_SURFACE_FEATURE -> GLITZ_SURFACE_FEATURE. + + * src/Makefile.am: CAIRO_HAS_GL_SURFACE -> CAIRO_HAS_GLITZ_SURFACE, + libcairo_gl_sources -> libcairo_glitz_sources, cairo_gl_surface.c -> + cairo_glitz_surface.c, GL_CFLAGS -> GLITZ_CFLAGS and + GL_LIBS -> GLITZ_LIBS. + + * cairo.pc.in (Requires): GL_REQUIRES -> GLITZ_REQUIRES. + + * configure.in: Replaced the gl backend with the new glitz backend. + Cairo now requires version 0.2.1 of glitz. + +2004-09-04 Carl Worth <cworth@brudder.east.isi.edu> + + * COPYING: + * COPYING-MPL-1.1: + * COPYING-LGPL-2.1: + * src/cairo-features.h.in: + * src/cairo.c: + * src/cairo.h: + * src/cairo_color.c: + * src/cairo_fixed.c: + * src/cairo_font.c: + * src/cairo_gstate.c: + * src/cairo_hull.c: + * src/cairo_image_surface.c: + * src/cairo_matrix.c: + * src/cairo_path.c: + * src/cairo_path_bounds.c: + * src/cairo_path_fill.c: + * src/cairo_path_stroke.c: + * src/cairo_pen.c: + * src/cairo_polygon.c: + * src/cairo_ps_surface.c: + * src/cairo_slope.c: + * src/cairo_spline.c: + * src/cairo_surface.c: + * src/cairo_xcb_surface.c: + * src/cairo_xlib_surface.c: + * src/cairoint.h: Add the MPL as a new license option, in addition + to the LGPL. + +2004-08-14 Carl Worth <cworth@isi.edu> + + * src/cairo_image_surface.c + (_cairo_image_surface_set_clip_region): Make a copy of the region + since pixman is currently taking ownership of it (ugh). Thanks to + Vladimir Vukicevic <vladimir@pobox.com> and Peter Dennis Bartok + <peter@novonyx.com>. + + * autogen.sh (LANG): Explicitly set LANG=C to fix the awk + string->number conversion for user with locales that don't match + ASCII digit conventions. + +2004-08-03 Carl Worth <cworth@isi.edu> + + * src/cairo_gstate.c (extract_transformed_rectangle): Temporarily + disable rectangle-based clipping optimization as it's not working + (see cairo_snippets/xxx_clip_rectangle for a test case). + 2004-08-02 Carl Worth <cworth@isi.edu> * COPYING: @@ -24,6 +464,8 @@ * src/cairo_xcb_surface.c: * src/cairo_xlib_surface.c: * src/cairoint.h: Change from MIT license to LGPL. + Fix to explicitly refer to GNU Lesser Public License 2.1 rather + than the Library Public License version 2 or "any later version" * src/cairo_pattern.c: * src/cairo_gl_surface.c: Fix copyright attributions mistakenly diff --git a/Makefile.am b/Makefile.am index 297ec9de..6dfc4ab3 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,8 +1,50 @@ -SUBDIRS = src +SUBDIRS = src test EXTRA_DIST = \ COPYING \ + COPYING-LGPL-2.1 \ + COPYING-MPL-1.1 \ cairo.pc.in pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = cairo.pc + +# Some custom targets to make it easier to release things. +# Use either: +# make release-check +# or make release-publish + +RELEASE_UPLOAD_DIR = cairographics.org:/home/www/cairo/snapshots +RELEASE_URL_BASE = http://cairographics.org/snapshots +RELEASE_ANNOUNCE_LIST = cairo-announce@cairographics.org + +tar_file = $(PACKAGE)-$(VERSION).tar.gz +md5_file = $(tar_file).md5 + +$(md5_file): $(tar_file) + md5sum $^ > $@ + +release-remove-old: + rm -f $(tar_file) $(md5_file) + +release-check: release-remove-old distcheck $(md5_file) + +release-publish: release-check + mkdir -p releases + scp $(tar_file) $(md5_file) $(RELEASE_UPLOAD_DIR) + mv $(tar_file) $(md5_file) releases + @echo "" + @echo "Please send an announcement to $(RELEASE_ANNOUNCE_LIST)" + @echo "including the following:" + @echo "" + @echo "Subject: $(PACKAGE) snapshot $(VERSION) now available" + @echo "" + @echo "A new $(PACKAGE) snapshot $(VERSION) is now available from:" + @echo "" + @echo " $(RELEASE_URL_BASE)/$(tar_file)" + @echo " $(RELEASE_URL_BASE)/$(md5_file)" + @echo -n " " + @cat releases/$(md5_file) + @echo "" + @echo "Also, please include the new entries from the NEWS file." + @@ -1,8 +1,83 @@ -Glyph caching -------------- -Internal caching of glyphs provides a major improvement to -text rendering performance, especially for Xlib and OpenGL -backends. +Snapshot 0.2.0 (2004-10-27 Carl Worth <cworth@cworth.org>) +=========================================================== +New license: LGPL/MPL +--------------------- +The most significant news with this release is that the license of +cairo has changed. It is now dual-licensed under the LGPL and the +MPL. For details see the COPYING file as well as COPYING-LGPL-2.1 and +COPYING-MPL-1.1. + +I express my thanks to everyone involved in the license change process +for their patience and support! + +New font and glyph internals +---------------------------- +Graydon Hoare has put a tremendous amount of work into new internals +for handling fonts and glyphs, including caches where appropriate. +This work has no impact on the user-level API, but should result in +great performance improvements for applications using text. + +New test suite +-------------- +This snapshot of cairo includes a (small) test suite in +cairo/test. The tests can be run with "make check". The test suite was +designed to make it very easy to add new tests, and we hope to see +many contributions here. As you find bugs, please try adding a minimal +test case to the suite, and submit it with the bug report to the +cairo@cairographics.org mailing list. This will make it much easier +for us to track progress in fixing bugs. + +New name for glitz backend +-------------------------- +The gl backend has now been renamed to the glitz backend. This means +that the following names have changed: + + CAIRO_HAS_GL_SURFACE -> CAIRO_HAS_GLITZ_SURFACE + cairo_set_target_gl -> cairo_set_target_glitz + cairo_gl_surface_create -> cairo_glitz_surface_create + +This change obviously breaks backwards compatibility for applications +using the old gl backend. + +Up-to-date with latest glitz snapshots +-------------------------------------- +This snapshot of cairo is now up to date with the latest glitz +snapshot, (currently 0.2.3). We know that the latest cairo and glitz +snapshots have been incompatible for a very long time. We've finally +fixed that now and we're determined to not let that happen again. + +Revert some tessellation regression bugs +---------------------------------------- +People that have been seeing some tessellation bugs, (eg. leaked +fills), in the CVS version of cairo may have better luck with this +release. A change since the last snapshot was identified to trigger +some of these bugs and was reverted before making the snapshot. The +behavior should be the same as the previous (0.1.23) snapshot. + +Miscellaneous changes +--------------------- +Changed CAIRO_FILTER_DEFAULT to CAIRO_FILTER_BEST to make gradients +easier. + +Track XCB API change regarding iterators. + +Various bug fixes +----------------- +Fix calculation of required number of vertices for pen. + +Fix to avoid zero-dimensioned pixmaps. + +Fix broken sort of pen vertices. + +Fix bug when cairo_show_text called with a NULL string. + +Fix clipping bugs. + +Fix bug in computing image length with XCB. + +Fix infinite loop bug in cairo_arc. + +Fix memory management interactions with libpixman. Snapshot 0.1.23 (2004-05-11 Carl Worth <cworth@isi.edu>) ======================================================== @@ -170,7 +245,7 @@ the heavy lifting with this renaming effort. Conditional compilation of backends ----------------------------------- -Cairo now allows optional beckends to be disabled at compile time. The +Cairo now allows optional backends to be disabled at compile time. The following options may now be passed to the configure script: --disable-xlib @@ -2,44 +2,52 @@ So far, cairo hasn't reached an initial release. But we can still form good habits now by practicing the release process with the current snapshots. -10 easy steps to creating a new cairo snapshot -============================================== +A new snapshot is needed whenever significant new features or bug +fixes are committed. Here are the steps to follow: -1) Commit code with a significant new feature or backwards - incompatibility. +1) Ensure that there are no local, uncommitted modifications. The best + thing to do here may be to begin with a fresh checkout from CVS: - Either of these events triggers the need for a new snapshot. - Users of cairo snapshots need to be able to specify snapshot - version numbers in order to get access to a specific set of - features. + cvs -d cairographics.org:/cvs/cairo co cairo -2) Increment CAIRO_VERSION in configure.in + But it's probably good enough if "cvs -q update -Ad" generates no + output. - Right now, in its pre-release form, we are incrementing - CAIRO_VERSION for each snapshot but we are not changing the - libtool shared library version information. Until now, we've - only incremented the sub-minor version. We'll invent rules for - incrementing major and minor numbers when the time is right. - -3) Verify that the code passes "make distcheck" +2) Verify that the code passes "make distcheck" Running "make distcheck" should result in no warnings or errors and end with a message of the form: - ============================================= + ================================================ cairo-X.Y.Z.tar.gz is ready for distribution - ============================================= + ================================================ (But the tar file isn't actually ready yet, as we still have some more steps to follow). -4) Fill out an entry in the NEWS file +3) Fill out an entry in the NEWS file Sift through the information in ChangeLog since the last snapshot. Summarize major changes briefly in a style similar to other entries in NEWS. Take special care to note any incompatible changes in the API. These should be easy to find - by looking for cairo.h in the ChangeLog. + by looking for cairo.h in the ChangeLog. Additionally, the + output following command should be examined using the previous + snapshot tag: + + cvs diff -r SNAPSHOT_X_Y_Z src/cairo.h + +4) Increment CAIRO_VERSION in configure.in + + Right now, in its pre-release form, we are incrementing + CAIRO_VERSION for each snapshot but we are not changing + the libtool shared library version information. Increment the + subminor version for bug fixes and backwards-compatible + additions to the API. Increment the minor number (and reset + the subminor) for backward-incompatible changes to the API + (including removals). Leave the major number at 0 until we are + ready for the first 1.0 release, (at which point these rules + will change). 5) Commit the changes to NEWS and configure.in @@ -47,27 +55,20 @@ snapshots. other commit. It's especially important to mention the new version number in the ChangeLog. -6) Run "make distcheck" to generate the final tar file including the - changes to NEWS and ChangeLog. - -7) Copy the resulting tar file to the cairo snapshots distribution - directory: +6) Run "make release-publish" which will perform the following steps + for you: - scp cairo-X.Y.Z-tar.gz cairographics.org:/home/www/cairo/snapshots + * Verify that make distcheck completes successfully + * Generate the final tar file with the correct version number + * Generate an md5sum file + * scp both files to cairographics.org:/home/www/cairo/snapshots + * Place local copies of both files in the releases directory + * Provide some text for the release announcement -8) Tag the entire source tree with a tag of the form SNAPSHOT_X_Y_Z: +7) Tag the entire source tree with a tag of the form SNAPSHOT_X_Y_Z: cvs tag SNAPSHOT_X_Y_Z -9) Send a message to cairo-announce@cairographics.org to announce the - new snapshot. - - The message should provide the URL for the snapshot: - - http://cairographics.org/snapshots/cairo-X.Y.Z.tar.gz - - and should also include the relevant section from the NEWS - file. +8) Send a message to cairo-announce@cairographics.org to announce the + new snapshot using the text provided by the previous step. -10) Sit back and relax in confidence, or alternately, brace yourself - for a flood of new bug reports. @@ -58,10 +58,19 @@ functions: cairo_mark_dirty * Re-implement the trapezoid rasterization algorithm according to the -new "specification". + new "specification". * Stroking closed, degenerate paths should still draw caps. Round -caps are easy; square should probably draw an axis aligned square. + caps are easy; square should probably draw an axis-aligned square. + +* It would be nice if the user had a mechanism to reliably draw custom + caps. One approach here would be to provide the coordinates of the + butt cap faces so that the user can append seamless caps to the + current path. We may also need to provide the coordinates of the + faces of every dash as well. + +* We need a way to get at the image data after something + like cairo_surface_create_similar with the image backend. * Verification, profiling, optimization. @@ -1,6 +1,5 @@ #!/bin/sh # Run this to generate all the initial makefiles, etc. - set -e PACKAGE=cairo @@ -15,11 +14,14 @@ AUTOCONF=${AUTOCONF-autoconf} # automake 1.8 requires autoconf 2.58 # automake 1.7 requires autoconf 2.54 -automake_min_vers=1.7 +# I don't know what automake 1.4 wants, but the following seems to work... +automake_min_vers=1.4 aclocal_min_vers=$automake_min_vers autoconf_min_vers=2.54 libtoolize_min_vers=1.4 +# The awk-based string->number conversion we use needs a C locale to work as expected. +LANG=C ARGV0=$0 diff --git a/cairo.pc.in b/cairo.pc.in index c67dc05c..339d576b 100644 --- a/cairo.pc.in +++ b/cairo.pc.in @@ -7,7 +7,7 @@ Name: cairo Description: Multi-platform 2D graphics library Version: @VERSION@ -Requires: fontconfig libpixman @XRENDER_REQUIRES@ @PNG_REQUIRES@ @GL_REQUIRES@ -Libs: -L${libdir} -lcairo -lm @XRENDER_LIBS@ @PS_LIBS@ @FREETYPE_LIBS@ +Requires: fontconfig libpixman @XRENDER_REQUIRES@ @PNG_REQUIRES@ @GLITZ_REQUIRES@ +Libs: -L${libdir} -lcairo -lm Cflags: -I${includedir} @FREETYPE_CFLAGS@ diff --git a/configure.in b/configure.in index 5ab37391..b17c9100 100644 --- a/configure.in +++ b/configure.in @@ -3,7 +3,7 @@ AC_INIT(src/cairo.h) dnl =========================================================================== # Package version number, (as distinct from shared library version) -CAIRO_VERSION=0.1.23 +CAIRO_VERSION=0.2.0 # libtool shared library version @@ -60,9 +60,10 @@ else AM_CONDITIONAL(CAIRO_HAS_XLIB_SURFACE, true) fi +CAIRO_CFLAGS="$CAIRO_CFLAGS $XRENDER_CFLAGS" +CAIRO_LIBS="$CAIRO_LIBS $XRENDER_LIBS" + AC_SUBST(XLIB_SURFACE_FEATURE) -AC_SUBST(XRENDER_CFLAGS) -AC_SUBST(XRENDER_LIBS) AC_SUBST(XRENDER_REQUIRES) dnl =========================================================================== @@ -84,9 +85,10 @@ else AM_CONDITIONAL(CAIRO_HAS_XCB_SURFACE, true) fi +CAIRO_CFLAGS="$CAIRO_CFLAGS $XCB_CFLAGS" +CAIRO_LIBS="$CAIRO_LIBS $XCB_LIBS" + AC_SUBST(XCB_SURFACE_FEATURE) -AC_SUBST(XCB_CFLAGS) -AC_SUBST(XCB_LIBS) dnl =========================================================================== @@ -103,6 +105,8 @@ else AM_CONDITIONAL(CAIRO_HAS_PS_SURFACE, true) fi +CAIRO_LIBS="$CAIRO_LIBS $PS_LIBS" + AC_SUBST(PS_SURFACE_FEATURE) AC_SUBST(PS_LIBS) @@ -129,35 +133,37 @@ else AM_CONDITIONAL(CAIRO_HAS_PNG_SURFACE, true) fi +CAIRO_CFLAGS="$CAIRO_CFLAGS $PNG_CFLAGS" +CAIRO_LIBS="$CAIRO_LIBS $PNG_LIBS" + AC_SUBST(PNG_SURFACE_FEATURE) -AC_SUBST(PNG_CFLAGS) -AC_SUBST(PNG_LIBS) AC_SUBST(PNG_REQUIRES) dnl =========================================================================== -AC_ARG_ENABLE(gl, - [ --disable-gl Disable cairo's OpenGL backend], - [use_gl=$enableval], [use_gl=yes]) +AC_ARG_ENABLE(glitz, + [ --disable-glitz Disable cairo's glitz backend], + [use_glitz=$enableval], [use_glitz=yes]) -if test "x$use_gl" = "xyes"; then - PKG_CHECK_MODULES(GL, glitz >= 0.1.5, [ - GL_REQUIRES=glitz - use_gl=yes], [use_gl="no (requires glitz http://freedesktop.org/software/glitz)"]) +if test "x$use_glitz" = "xyes"; then + PKG_CHECK_MODULES(GLITZ, glitz >= 0.2.3, [ + GLITZ_REQUIRES=glitz + use_glitz=yes], [use_glitz="no (requires glitz http://freedesktop.org/software/glitz)"]) fi -if test "x$use_gl" != "xyes"; then - GL_SURFACE_FEATURE=CAIRO_HAS_NO_GL_SURFACE - AM_CONDITIONAL(CAIRO_HAS_GL_SURFACE, false) +if test "x$use_glitz" != "xyes"; then + GLITZ_SURFACE_FEATURE=CAIRO_HAS_NO_GLITZ_SURFACE + AM_CONDITIONAL(CAIRO_HAS_GLITZ_SURFACE, false) else - GL_SURFACE_FEATURE=CAIRO_HAS_GL_SURFACE - AM_CONDITIONAL(CAIRO_HAS_GL_SURFACE, true) + GLITZ_SURFACE_FEATURE=CAIRO_HAS_GLITZ_SURFACE + AM_CONDITIONAL(CAIRO_HAS_GLITZ_SURFACE, true) fi -AC_SUBST(GL_LIBS) -AC_SUBST(GL_CFLAGS) -AC_SUBST(GL_SURFACE_FEATURE) -AC_SUBST(GL_REQUIRES) +CAIRO_CFLAGS="$CAIRO_CFLAGS $GLITZ_CFLAGS" +CAIRO_LIBS="$CAIRO_LIBS $GLITZ_LIBS" + +AC_SUBST(GLITZ_SURFACE_FEATURE) +AC_SUBST(GLITZ_REQUIRES) dnl =========================================================================== @@ -176,7 +182,12 @@ AC_SUBST(SANITY_CHECKING_FEATURE) dnl =========================================================================== PKG_CHECK_MODULES(FONTCONFIG, fontconfig) -PKG_CHECK_MODULES(CAIRO, libpixman >= 0.1.1) +CAIRO_CFLAGS="$CAIRO_CFLAGS $FONTCONFIG_CFLAGS" +CAIRO_LIBS="$CAIRO_LIBS $FONTCONFIG_LIBS" + +PKG_CHECK_MODULES(PIXMAN, libpixman >= 0.1.1) +CAIRO_CFLAGS="$CAIRO_CFLAGS $PIXMAN_CFLAGS" +CAIRO_LIBS="$CAIRO_LIBS $PIXMAN_LIBS" # Test for freetype2 separate from pkg-config since at least up to # 2003-06-07, there was no freetype2.pc in the release. @@ -218,13 +229,9 @@ FREETYPE_LIBS=`$FREETYPE_CONFIG --libs` AC_SUBST(FREETYPE_CFLAGS) AC_SUBST(FREETYPE_LIBS) - CAIRO_CFLAGS="$CAIRO_CFLAGS $FREETYPE_CFLAGS" CAIRO_LIBS="$CAIRO_LIBS $FREETYPE_LIBS" -AC_SUBST(CAIRO_CFLAGS) -AC_SUBST(CAIRO_LIBS) - dnl =========================================================================== dnl Checks for precise integer types @@ -239,7 +246,12 @@ if test "x$GCC" = "xyes"; then -Wmissing-prototypes -Wmissing-declarations \ -Wnested-externs -fno-strict-aliasing" fi -AC_SUBST(WARN_CFLAGS) + +CAIRO_CFLAGS="$CAIRO_CFLAGS $WARN_CFLAGS" +CAIRO_LIBS="$CAIRO_LIBS -lm" + +AC_SUBST(CAIRO_CFLAGS) +AC_SUBST(CAIRO_LIBS) dnl =========================================================================== @@ -248,6 +260,7 @@ cairo.pc Makefile src/Makefile src/cairo-features.h +test/Makefile ]) dnl =========================================================================== @@ -258,6 +271,6 @@ echo " Xlib: $use_xlib" echo " XCB: $use_xcb" echo " PostScript: $use_ps" echo " PNG: $use_png" -echo " OpenGL: $use_gl" +echo " glitz: $use_glitz" echo "" diff --git a/src/Makefile.am b/src/Makefile.am index 38a30ade..8343cb1c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -17,8 +17,8 @@ if CAIRO_HAS_XCB_SURFACE libcairo_xcb_sources = cairo_xcb_surface.c endif -if CAIRO_HAS_GL_SURFACE -libcairo_gl_sources = cairo_gl_surface.c +if CAIRO_HAS_GLITZ_SURFACE +libcairo_glitz_sources = cairo_glitz_surface.c endif # These names match automake style variable definition conventions so @@ -31,6 +31,7 @@ XRENDER_LIBS=@XRENDER_LIBS@ libcairo_la_SOURCES = \ cairo.c \ cairo.h \ + cairo_cache.c \ cairo_color.c \ cairo_fixed.c \ cairo_font.c \ @@ -56,11 +57,11 @@ libcairo_la_SOURCES = \ $(libcairo_png_sources) \ $(libcairo_xlib_sources)\ $(libcairo_xcb_sources) \ - $(libcairo_gl_sources) \ + $(libcairo_glitz_sources)\ cairoint.h libcairo_la_LDFLAGS = -version-info @VERSION_INFO@ -no-undefined -INCLUDES = -I$(srcdir) $(WARN_CFLAGS) $(CAIRO_CFLAGS) $(FONTCONFIG_CFLAGS) $(XRENDER_CFLAGS) $(XCB_CFLAGS) $(PNG_CFLAGS) $(GL_CFLAGS) +INCLUDES = -I$(srcdir) $(CAIRO_CFLAGS) -libcairo_la_LIBADD = $(CAIRO_LIBS) $(FONTCONFIG_LIBS) $(XRENDER_LIBS) $(XCB_LIBS) $(PS_LIBS) $(PNG_LIBS) $(GL_LIBS) -lm +libcairo_la_LIBADD = $(CAIRO_LIBS) -lm diff --git a/src/cairo-cache.c b/src/cairo-cache.c new file mode 100644 index 00000000..a33d69a0 --- /dev/null +++ b/src/cairo-cache.c @@ -0,0 +1,454 @@ +/* cairo - a vector graphics library with display and print output + * + * This file is Copyright © 2004 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Contributor(s): + * Keith Packard + * Graydon Hoare <graydon@redhat.com> + */ + +#include "cairoint.h" + +/* + * This structure, and accompanying table, is borrowed/modified from the + * file xserver/render/glyph.c in the freedesktop.org x server, with + * permission (and suggested modification of doubling sizes) by Keith + * Packard. + */ + +static cairo_cache_arrangement_t cache_arrangements [] = { + { 16, 43, 41 }, + { 32, 73, 71 }, + { 64, 151, 149 }, + { 128, 283, 281 }, + { 256, 571, 569 }, + { 512, 1153, 1151 }, + { 1024, 2269, 2267 }, + { 2048, 4519, 4517 }, + { 4096, 9013, 9011 }, + { 8192, 18043, 18041 }, + { 16384, 36109, 36107 }, + { 32768, 72091, 72089 }, + { 65536, 144409, 144407 }, + { 131072, 288361, 288359 }, + { 262144, 576883, 576881 }, + { 524288, 1153459, 1153457 }, + { 1048576, 2307163, 2307161 }, + { 2097152, 4613893, 4613891 }, + { 4194304, 9227641, 9227639 }, + { 8388608, 18455029, 18455027 }, + { 16777216, 36911011, 36911009 }, + { 33554432, 73819861, 73819859 }, + { 67108864, 147639589, 147639587 }, + { 134217728, 295279081, 295279079 }, + { 268435456, 590559793, 590559791 } +}; + +#define N_CACHE_SIZES (sizeof(cache_arrangements)/sizeof(cache_arrangements[0])) + +/* + * Entries 'e' are poiners, in one of 3 states: + * + * e == NULL: The entry has never had anything put in it + * e != DEAD_ENTRY: The entry has an active value in it currently + * e == DEAD_ENTRY: The entry *had* a value in it at some point, but the + * entry has been killed. Lookups requesting free space can + * reuse these entries; lookups requesting a precise match + * should neither return these entries nor stop searching when + * seeing these entries. + * + * We expect keys will not be destroyed frequently, so our table does not + * contain any explicit shrinking code nor any chain-coalescing code for + * entries randomly deleted by memory pressure (except during rehashing, of + * course). These assumptions are potentially bad, but they make the + * implementation straightforward. + * + * Revisit later if evidence appears that we're using excessive memory from + * a mostly-dead table. + * + * Generally you do not need to worry about freeing cache entries; the + * cache will expire entries randomly as it experiences memory pressure. + * There is currently no explicit entry-removing call, though one can be + * added easily. + * + * This table is open-addressed with double hashing. Each table size is a + * prime chosen to be a little more than double the high water mark for a + * given arrangement, so the tables should remain < 50% full. The table + * size makes for the "first" hash modulus; a second prime (2 less than the + * first prime) serves as the "second" hash modulus, which is co-prime and + * thus guarantees a complete permutation of table indices. + * + */ + +#define DEAD_ENTRY ((cairo_cache_entry_base_t *) 1) +#define NULL_ENTRY_P(cache, i) ((cache)->entries[i] == NULL) +#define DEAD_ENTRY_P(cache, i) ((cache)->entries[i] == DEAD_ENTRY) +#define LIVE_ENTRY_P(cache, i) \ + (!((NULL_ENTRY_P((cache),(i))) || (DEAD_ENTRY_P((cache),(i))))) + +#ifdef CAIRO_DO_SANITY_CHECKING +#include <assert.h> +static void +_cache_sane_state (cairo_cache_t *cache) +{ + assert (cache != NULL); + assert (cache->entries != NULL); + assert (cache->backend != NULL); + assert (cache->arrangement != NULL); + assert (cache->refcount > 0); + assert (cache->used_memory <= cache->max_memory); + assert (cache->live_entries <= cache->arrangement->size); +} +#else +#define _cache_sane_state(c) +#define assert(x) +#endif + +static void +_entry_destroy (cairo_cache_t *cache, unsigned long i) +{ + _cache_sane_state (cache); + + if (LIVE_ENTRY_P(cache, i)) + { + cairo_cache_entry_base_t *entry = cache->entries[i]; + assert(cache->live_entries > 0); + assert(cache->used_memory > entry->memory); + + cache->live_entries--; + cache->used_memory -= entry->memory; + cache->backend->destroy_entry (cache, entry); + cache->entries[i] = DEAD_ENTRY; + } +} + +static cairo_cache_entry_base_t ** +_cache_lookup (cairo_cache_t *cache, + void *key, + int (*predicate)(void*,void*,void*)) +{ + + cairo_cache_entry_base_t **probe; + unsigned long hash; + unsigned long table_size, i, idx, step; + + _cache_sane_state (cache); + assert (key != NULL); + + table_size = cache->arrangement->size; + hash = cache->backend->hash (cache, key); + idx = hash % table_size; + step = 0; + + for (i = 0; i < table_size; ++i) + { +#ifdef CAIRO_MEASURE_CACHE_PERFORMANCE + cache->probes++; +#endif + assert(idx < table_size); + probe = cache->entries + idx; + + /* + * There are two lookup modes: searching for a free slot and searching + * for an exact entry. + */ + + if (predicate != NULL) + { + /* We are looking up an exact entry. */ + if (*probe != NULL + && *probe != DEAD_ENTRY + && (*probe)->hashcode == hash + && predicate (cache, key, *probe)) + return probe; + } + else + { + /* We are just looking for a free slot. */ + if (*probe == NULL + || *probe == DEAD_ENTRY) + return probe; + } + + if (step == 0) { + step = hash % cache->arrangement->rehash; + if (step == 0) + step = 1; + } + + idx += step; + if (idx >= table_size) + idx -= table_size; + } + + /* + * The table should not have permitted you to get here if you were just + * looking for a free slot: there should have been room. + */ + assert(predicate != NULL); + return NULL; +} + +static cairo_cache_entry_base_t ** +_find_available_entry_for (cairo_cache_t *cache, + void *key) +{ + return _cache_lookup (cache, key, NULL); +} + +static cairo_cache_entry_base_t ** +_find_exact_live_entry_for (cairo_cache_t *cache, + void *key) +{ + return _cache_lookup (cache, key, cache->backend->keys_equal); +} + + +static cairo_cache_arrangement_t * +_find_cache_arrangement (unsigned long proposed_size) +{ + unsigned long idx; + + for (idx = 0; idx < N_CACHE_SIZES; ++idx) + if (cache_arrangements[idx].high_water_mark >= proposed_size) + return &cache_arrangements[idx]; + return NULL; +} + +static cairo_status_t +_resize_cache (cairo_cache_t *cache, unsigned long proposed_size) +{ + cairo_cache_t tmp; + cairo_cache_entry_base_t **e; + unsigned long new_size, i; + + tmp = *cache; + tmp.arrangement = _find_cache_arrangement (proposed_size); + assert(tmp.arrangement != NULL); + if (tmp.arrangement == cache->arrangement) + return CAIRO_STATUS_SUCCESS; + + new_size = tmp.arrangement->size; + tmp.entries = calloc (new_size, sizeof (cairo_cache_entry_base_t *)); + if (tmp.entries == NULL) + return CAIRO_STATUS_NO_MEMORY; + + for (i = 0; i < cache->arrangement->size; ++i) { + if (LIVE_ENTRY_P(cache, i)) { + e = _find_available_entry_for (&tmp, cache->entries[i]); + assert (e != NULL); + *e = cache->entries[i]; + } + } + free (cache->entries); + cache->entries = tmp.entries; + cache->arrangement = tmp.arrangement; + return CAIRO_STATUS_SUCCESS; +} + + +#ifdef CAIRO_MEASURE_CACHE_PERFORMANCE +static double +_load_factor (cairo_cache_t *cache) +{ + return ((double) cache->live_entries) + / ((double) cache->arrangement->size); +} +#endif + +static unsigned long +_random_live_entry (cairo_cache_t *cache) +{ + unsigned long idx; + assert(cache != NULL); + do { + idx = rand () % cache->arrangement->size; + } while (! LIVE_ENTRY_P(cache, idx)); + return idx; +} + + +/* public API follows */ + +cairo_status_t +_cairo_cache_init (cairo_cache_t *cache, + const cairo_cache_backend_t *backend, + unsigned long max_memory) +{ + assert(backend != NULL); + + if (cache != NULL){ + cache->arrangement = &cache_arrangements[0]; + cache->refcount = 1; + cache->max_memory = max_memory; + cache->used_memory = 0; + cache->live_entries = 0; + +#ifdef CAIRO_MEASURE_CACHE_PERFORMANCE + cache->hits = 0; + cache->misses = 0; + cache->probes = 0; +#endif + + cache->backend = backend; + cache->entries = calloc (sizeof(cairo_cache_entry_base_t *), + cache->arrangement->size); + if (cache->entries == NULL) + return CAIRO_STATUS_NO_MEMORY; + } + _cache_sane_state (cache); + return CAIRO_STATUS_SUCCESS; +} + +void +_cairo_cache_reference (cairo_cache_t *cache) +{ + _cache_sane_state (cache); + cache->refcount++; +} + +void +_cairo_cache_destroy (cairo_cache_t *cache) +{ + unsigned long i; + if (cache != NULL) { + + _cache_sane_state (cache); + + if (cache->refcount-- > 0) + return; + + for (i = 0; i < cache->arrangement->size; ++i) { + _entry_destroy (cache, i); + } + + free (cache->entries); + cache->entries = NULL; + cache->backend->destroy_cache (cache); + } +} + +cairo_status_t +_cairo_cache_lookup (cairo_cache_t *cache, + void *key, + void **entry_return) +{ + + unsigned long idx; + cairo_status_t status = CAIRO_STATUS_SUCCESS; + cairo_cache_entry_base_t **slot = NULL, *new_entry; + + _cache_sane_state (cache); + +#ifdef CAIRO_MEASURE_CACHE_PERFORMANCE + if ((cache->hits + cache->misses) % 0xffff == 0) + printf("cache %p stats: size %ld, live %ld, load %.2f\n" + " mem %ld/%ld, hit %ld, miss %ld\n" + " probe %ld, %.2f probe/access\n", + cache, + cache->arrangement->size, + cache->live_entries, + _load_factor (cache), + cache->used_memory, + cache->max_memory, + cache->hits, + cache->misses, + cache->probes, + ((double) cache->probes) + / ((double) (cache->hits + + cache->misses + 1))); +#endif + + /* See if we have an entry in the table already. */ + slot = _find_exact_live_entry_for (cache, key); + if (slot != NULL) { +#ifdef CAIRO_MEASURE_CACHE_PERFORMANCE + cache->hits++; +#endif + *entry_return = *slot; + return status; + } + +#ifdef CAIRO_MEASURE_CACHE_PERFORMANCE + cache->misses++; +#endif + + /* Build the new entry. */ + status = cache->backend->create_entry (cache, key, + entry_return); + if (status != CAIRO_STATUS_SUCCESS) + return status; + + new_entry = (cairo_cache_entry_base_t *) (*entry_return); + + /* Store the hash value in case the backend forgot. */ + new_entry->hashcode = cache->backend->hash (cache, key); + + /* Make some entries die if we're under memory pressure. */ + while (cache->live_entries > 0 && + ((cache->max_memory - cache->used_memory) < new_entry->memory)) { + idx = _random_live_entry (cache); + assert (idx < cache->arrangement->size); + _entry_destroy (cache, idx); + } + + assert(cache->max_memory >= (cache->used_memory + new_entry->memory)); + + /* Make room in the table for a new slot. */ + status = _resize_cache (cache, cache->live_entries + 1); + if (status != CAIRO_STATUS_SUCCESS) { + cache->backend->destroy_entry (cache, new_entry); + *entry_return = NULL; + return status; + } + + slot = _find_available_entry_for (cache, key); + assert(slot != NULL); + + /* Store entry in slot and increment statistics. */ + *slot = new_entry; + cache->live_entries++; + cache->used_memory += new_entry->memory; + + _cache_sane_state (cache); + + return status; +} + +unsigned long +_cairo_hash_string (const char *c) +{ + /* This is the djb2 hash. */ + unsigned long hash = 5381; + while (*c) + hash = ((hash << 5) + hash) + *c++; + return hash; +} + diff --git a/src/cairo-color.c b/src/cairo-color.c index 837a9a52..2fe793ac 100644 --- a/src/cairo-color.c +++ b/src/cairo-color.c @@ -1,22 +1,37 @@ /* cairo - a vector graphics library with display and print output * - * Copyright © 2002 University of Southern California + * Copyright © 2002 University of Southern California * * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. * - * This library 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 - * Library General Public License for more details. + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ * - * Author: Carl D. Worth <cworth@isi.edu> + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth <cworth@isi.edu> */ #include "cairoint.h" diff --git a/src/cairo-features.h.in b/src/cairo-features.h.in index 21d16749..632ad8d7 100644 --- a/src/cairo-features.h.in +++ b/src/cairo-features.h.in @@ -3,20 +3,35 @@ * Copyright © 2003 University of Southern California * * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. * - * This library 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 - * Library General Public License for more details. + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ * - * Author: Carl D. Worth <cworth@isi.edu> + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl Worth <cworth@east.isi.edu> */ #ifndef _CAIRO_CONFIG_H_ @@ -30,7 +45,7 @@ #define @XCB_SURFACE_FEATURE@ -#define @GL_SURFACE_FEATURE@ +#define @GLITZ_SURFACE_FEATURE@ #define @SANITY_CHECKING_FEATURE@ diff --git a/src/cairo-fixed.c b/src/cairo-fixed.c index 7dd1a07e..32368d7f 100644 --- a/src/cairo-fixed.c +++ b/src/cairo-fixed.c @@ -1,22 +1,37 @@ /* cairo - a vector graphics library with display and print output * - * Copyright © 2003 University of Southern California + * Copyright © 2003 University of Southern California * * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. * - * This library 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 - * Library General Public License for more details. + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ * - * Author: Carl D. Worth <cworth@isi.edu> + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth <cworth@isi.edu> */ #include "cairoint.h" diff --git a/src/cairo-font.c b/src/cairo-font.c index af397172..5ad9f041 100644 --- a/src/cairo-font.c +++ b/src/cairo-font.c @@ -1,40 +1,95 @@ /* cairo - a vector graphics library with display and print output * - * Copyright © 2002 University of Southern California + * Copyright © 2002 University of Southern California * * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. * - * This library 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 - * Library General Public License for more details. + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ * - * Author: Carl D. Worth <cworth@isi.edu> + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth <cworth@isi.edu> */ #include "cairoint.h" -static cairo_glyph_cache_t * -_cairo_glyph_cache_create (void); -static void -_cairo_glyph_cache_destroy (cairo_glyph_cache_t *glyph_cache); +/* First we implement a global font cache for named fonts. */ + +typedef struct { + cairo_cache_entry_base_t base; + const char *family; + cairo_font_slant_t slant; + cairo_font_weight_t weight; +} cairo_font_cache_key_t; + +typedef struct { + cairo_font_cache_key_t key; + cairo_unscaled_font_t *unscaled; +} cairo_font_cache_entry_t; + +static unsigned long +_font_cache_hash (void *cache, void *key) +{ + cairo_font_cache_key_t *in; + in = (cairo_font_cache_key_t *) key; + unsigned long hash; + + /* 1607 and 1451 are just a couple random primes. */ + hash = _cairo_hash_string (in->family); + hash += ((unsigned long) in->slant) * 1607; + hash += ((unsigned long) in->weight) * 1451; + return hash; +} -static void -_cairo_glyph_cache_reference (cairo_glyph_cache_t *glyph_cache); -cairo_font_t * -_cairo_font_create (const char *family, - cairo_font_slant_t slant, - cairo_font_weight_t weight) +static int +_font_cache_keys_equal (void *cache, + void *k1, + void *k2) { + cairo_font_cache_key_t *a, *b; + a = (cairo_font_cache_key_t *) k1; + b = (cairo_font_cache_key_t *) k2; + + return (strcmp (a->family, b->family) == 0) + && (a->weight == b->weight) + && (a->slant == b->slant); +} + + +static cairo_status_t +_font_cache_create_entry (void *cache, + void *key, + void **return_value) +{ + cairo_font_cache_key_t *k; + cairo_font_cache_entry_t *entry; + k = (cairo_font_cache_key_t *) key; + const struct cairo_font_backend *backend = CAIRO_FONT_BACKEND_DEFAULT; /* XXX: The current freetype backend may return NULL, (for example @@ -43,365 +98,428 @@ _cairo_font_create (const char *family, * like to build in some sort fo font here, (even a really lame, * ugly one if necessary). */ - return backend->create (family, slant, weight); + entry = malloc (sizeof (cairo_font_cache_entry_t)); + if (entry == NULL) + goto FAIL; + + entry->key.slant = k->slant; + entry->key.weight = k->weight; + entry->key.family = strdup(k->family); + if (entry->key.family == NULL) + goto FREE_ENTRY; + + entry->unscaled = backend->create (k->family, k->slant, k->weight); + if (entry->unscaled == NULL) + goto FREE_FAMILY; + + /* Not sure how to measure backend font mem; use a simple count for now.*/ + entry->key.base.memory = 1; + *return_value = entry; + return CAIRO_STATUS_SUCCESS; + + FREE_FAMILY: + free ((void *) entry->key.family); + + FREE_ENTRY: + free (entry); + + FAIL: + return CAIRO_STATUS_NO_MEMORY; } -cairo_status_t -_cairo_font_init (cairo_font_t *font, - const struct cairo_font_backend *backend) +static void +_font_cache_destroy_entry (void *cache, + void *entry) { - cairo_matrix_set_identity (&font->matrix); - font->refcount = 1; - font->backend = backend; - font->glyph_cache = _cairo_glyph_cache_create (); - if (font->glyph_cache == NULL) - return CAIRO_STATUS_NO_MEMORY; + cairo_font_cache_entry_t *e; - return CAIRO_STATUS_SUCCESS; + e = (cairo_font_cache_entry_t *) entry; + _cairo_unscaled_font_destroy (e->unscaled); + free ((void *) e->key.family); + free (e); } -cairo_font_t * -_cairo_font_copy (cairo_font_t *font) +static void +_font_cache_destroy_cache (void *cache) { - cairo_font_t *newfont = NULL; - char *tmp = NULL; + free (cache); +} - if (font == NULL || font->backend->copy == NULL) - return NULL; - - newfont = font->backend->copy (font); - if (newfont == NULL) { - free (tmp); - return NULL; - } +const struct cairo_cache_backend cairo_font_cache_backend = { + _font_cache_hash, + _font_cache_keys_equal, + _font_cache_create_entry, + _font_cache_destroy_entry, + _font_cache_destroy_cache +}; - newfont->refcount = 1; - cairo_matrix_copy(&newfont->matrix, &font->matrix); - newfont->backend = font->backend; - if (newfont->glyph_cache) - _cairo_glyph_cache_destroy (newfont->glyph_cache); - - newfont->glyph_cache = font->glyph_cache; - _cairo_glyph_cache_reference (font->glyph_cache); - - return newfont; +static void +_lock_global_font_cache (void) +{ + /* FIXME: implement locking. */ } -cairo_status_t -_cairo_font_scale (cairo_font_t *font, double scale) +static void +_unlock_global_font_cache (void) { - return cairo_matrix_scale (&font->matrix, scale, scale); + /* FIXME: implement locking. */ } -cairo_status_t -_cairo_font_transform (cairo_font_t *font, cairo_matrix_t *matrix) +static cairo_cache_t * +_global_font_cache = NULL; + +static cairo_cache_t * +_get_global_font_cache (void) { - return cairo_matrix_multiply (&font->matrix, matrix, &font->matrix); + if (_global_font_cache == NULL) { + _global_font_cache = malloc (sizeof (cairo_cache_t)); + + if (_global_font_cache == NULL) + goto FAIL; + + if (_cairo_cache_init (_global_font_cache, + &cairo_font_cache_backend, + CAIRO_FONT_CACHE_NUM_FONTS_DEFAULT)) + goto FAIL; + } + + return _global_font_cache; + + FAIL: + if (_global_font_cache) + free (_global_font_cache); + _global_font_cache = NULL; + return NULL; } -cairo_status_t -_cairo_font_text_extents (cairo_font_t *font, - const unsigned char *utf8, - cairo_text_extents_t *extents) +/* Now the internal "unscaled + scale" font API */ + +cairo_unscaled_font_t * +_cairo_unscaled_font_create (const char *family, + cairo_font_slant_t slant, + cairo_font_weight_t weight) { - return font->backend->text_extents(font, utf8, extents); + cairo_cache_t * cache; + cairo_font_cache_key_t key; + cairo_font_cache_entry_t *font; + cairo_status_t status; + + _lock_global_font_cache (); + cache = _get_global_font_cache (); + if (cache == NULL) { + _unlock_global_font_cache (); + return NULL; + } + + key.family = family; + key.slant = slant; + key.weight = weight; + + status = _cairo_cache_lookup (cache, &key, (void **) &font); + if (status) { + _unlock_global_font_cache (); + return NULL; + } + + _cairo_unscaled_font_reference (font->unscaled); + _unlock_global_font_cache (); + return font->unscaled; } -cairo_status_t -_cairo_font_glyph_extents (cairo_font_t *font, - cairo_glyph_t *glyphs, - int num_glyphs, - cairo_text_extents_t *extents) +void +_cairo_font_init (cairo_font_t *scaled, + cairo_font_scale_t *scale, + cairo_unscaled_font_t *unscaled) { - return font->backend->glyph_extents(font, glyphs, num_glyphs, extents); + scaled->scale = *scale; + scaled->unscaled = unscaled; + scaled->refcount = 1; } cairo_status_t -_cairo_font_text_bbox (cairo_font_t *font, - cairo_surface_t *surface, - double x, - double y, - const unsigned char *utf8, - cairo_box_t *bbox) +_cairo_unscaled_font_init (cairo_unscaled_font_t *font, + const struct cairo_font_backend *backend) { - return font->backend->text_bbox (font, surface, x, y, utf8, bbox); + font->refcount = 1; + font->backend = backend; + return CAIRO_STATUS_SUCCESS; } + cairo_status_t -_cairo_font_glyph_bbox (cairo_font_t *font, - cairo_surface_t *surface, - cairo_glyph_t *glyphs, - int num_glyphs, - cairo_box_t *bbox) +_cairo_unscaled_font_text_to_glyphs (cairo_unscaled_font_t *font, + cairo_font_scale_t *scale, + const unsigned char *utf8, + cairo_glyph_t **glyphs, + int *num_glyphs) { - return font->backend->glyph_bbox (font, surface, glyphs, num_glyphs, bbox); + return font->backend->text_to_glyphs (font, scale, utf8, glyphs, num_glyphs); } cairo_status_t -_cairo_font_show_text (cairo_font_t *font, - cairo_operator_t operator, - cairo_surface_t *source, - cairo_surface_t *surface, - int source_x, - int source_y, - double x, - double y, - const unsigned char *utf8) +_cairo_unscaled_font_glyph_extents (cairo_unscaled_font_t *font, + cairo_font_scale_t *scale, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_text_extents_t *extents) { - return font->backend->show_text(font, operator, source, - surface, source_x, source_y, x, y, utf8); + return font->backend->glyph_extents(font, scale, glyphs, num_glyphs, extents); } + cairo_status_t -_cairo_font_show_glyphs (cairo_font_t *font, - cairo_operator_t operator, - cairo_surface_t *source, - cairo_surface_t *surface, - int source_x, - int source_y, - cairo_glyph_t *glyphs, - int num_glyphs) +_cairo_unscaled_font_glyph_bbox (cairo_unscaled_font_t *font, + cairo_font_scale_t *scale, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_box_t *bbox) { - return font->backend->show_glyphs(font, operator, source, - surface, source_x, source_y, - glyphs, num_glyphs); + return font->backend->glyph_bbox (font, scale, glyphs, num_glyphs, bbox); } cairo_status_t -_cairo_font_text_path (cairo_font_t *font, - double x, - double y, - const unsigned char *utf8, - cairo_path_t *path) +_cairo_unscaled_font_show_glyphs (cairo_unscaled_font_t *font, + cairo_font_scale_t *scale, + cairo_operator_t operator, + cairo_surface_t *source, + cairo_surface_t *surface, + int source_x, + int source_y, + cairo_glyph_t *glyphs, + int num_glyphs) { - return font->backend->text_path(font, x, y, utf8, path); + cairo_status_t status; + if (surface->backend->show_glyphs != NULL) { + status = surface->backend->show_glyphs (font, scale, operator, source, + surface, source_x, source_y, + glyphs, num_glyphs); + if (status == CAIRO_STATUS_SUCCESS) + return status; + } + + /* Surface display routine either does not exist or failed. */ + return font->backend->show_glyphs (font, scale, operator, source, + surface, source_x, source_y, + glyphs, num_glyphs); } cairo_status_t -_cairo_font_glyph_path (cairo_font_t *font, - cairo_glyph_t *glyphs, - int num_glyphs, - cairo_path_t *path) +_cairo_unscaled_font_glyph_path (cairo_unscaled_font_t *font, + cairo_font_scale_t *scale, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_path_t *path) { - return font->backend->glyph_path(font, glyphs, num_glyphs, path); + return font->backend->glyph_path (font, scale, glyphs, num_glyphs, path); } cairo_status_t -_cairo_font_font_extents (cairo_font_t *font, - cairo_font_extents_t *extents) +_cairo_unscaled_font_font_extents (cairo_unscaled_font_t *font, + cairo_font_scale_t *scale, + cairo_font_extents_t *extents) { - return font->backend->font_extents(font, extents); + return font->backend->font_extents(font, scale, extents); } -static void -_cairo_glyph_cache_pop_last (cairo_glyph_cache_t *glyph_cache) +void +_cairo_unscaled_font_reference (cairo_unscaled_font_t *font) { - if (glyph_cache->last) { - cairo_glyph_surface_node_t *remove = glyph_cache->last; - - cairo_surface_destroy (remove->s.surface); - glyph_cache->last = remove->prev; - if (glyph_cache->last) - glyph_cache->last->next = NULL; + font->refcount++; +} - free (remove); - glyph_cache->n_nodes--; - } +void +_cairo_unscaled_font_destroy (cairo_unscaled_font_t *font) +{ + if (--(font->refcount) > 0) + return; + + if (font->backend) + font->backend->destroy (font); } -static cairo_glyph_cache_t * -_cairo_glyph_cache_create (void) -{ - cairo_glyph_cache_t *glyph_cache; - - glyph_cache = malloc (sizeof (cairo_glyph_cache_t)); - if (glyph_cache == NULL) - return NULL; - - glyph_cache->n_nodes = 0; - glyph_cache->first = NULL; - glyph_cache->last = NULL; - glyph_cache->cache_size = CAIRO_FONT_CACHE_SIZE_DEFAULT; - glyph_cache->ref_count = 1; - return glyph_cache; + +/* Public font API follows. */ + +void +cairo_font_reference (cairo_font_t *font) +{ + font->refcount++; } -static void -_cairo_glyph_cache_reference (cairo_glyph_cache_t *glyph_cache) +void +cairo_font_destroy (cairo_font_t *font) { - if (glyph_cache == NULL) + if (--(font->refcount) > 0) return; - glyph_cache->ref_count++; + if (font->unscaled) + _cairo_unscaled_font_destroy (font->unscaled); + + free (font); } -static void -_cairo_glyph_cache_destroy (cairo_glyph_cache_t *glyph_cache) +void +cairo_font_set_transform (cairo_font_t *font, + cairo_matrix_t *matrix) { - if (glyph_cache == NULL) - return; + double dummy; + cairo_matrix_get_affine (matrix, + &font->scale.matrix[0][0], + &font->scale.matrix[0][1], + &font->scale.matrix[1][0], + &font->scale.matrix[1][1], + &dummy, &dummy); +} + +void +cairo_font_current_transform (cairo_font_t *font, + cairo_matrix_t *matrix) +{ + cairo_matrix_set_affine (matrix, + font->scale.matrix[0][0], + font->scale.matrix[0][1], + font->scale.matrix[1][0], + font->scale.matrix[1][1], + 0, 0); +} - glyph_cache->ref_count--; - if (glyph_cache->ref_count) - return; - while (glyph_cache->last) - _cairo_glyph_cache_pop_last (glyph_cache); +/* Now we implement functions to access a default global image & metrics + * cache. + */ - free (glyph_cache); +unsigned long +_cairo_glyph_cache_hash (void *cache, void *key) +{ + cairo_glyph_cache_key_t *in; + in = (cairo_glyph_cache_key_t *) key; + return + ((unsigned long) in->unscaled) + ^ ((unsigned long) in->scale.matrix[0][0]) + ^ ((unsigned long) in->scale.matrix[0][1]) + ^ ((unsigned long) in->scale.matrix[1][0]) + ^ ((unsigned long) in->scale.matrix[1][1]) + ^ in->index; } -static void -_cairo_glyph_surface_init (cairo_font_t *font, - cairo_surface_t *surface, - const cairo_glyph_t *glyph, - cairo_glyph_surface_t *glyph_surface) +int +_cairo_glyph_cache_keys_equal (void *cache, + void *k1, + void *k2) { - cairo_surface_t *image; - - glyph_surface->surface = NULL; - glyph_surface->index = glyph->index; - glyph_surface->matrix[0][0] = font->matrix.m[0][0]; - glyph_surface->matrix[0][1] = font->matrix.m[0][1]; - glyph_surface->matrix[1][0] = font->matrix.m[1][0]; - glyph_surface->matrix[1][1] = font->matrix.m[1][1]; - - image = font->backend->create_glyph (font, glyph, &glyph_surface->size); - if (image == NULL) - return; - - if (surface->backend != image->backend) { - cairo_status_t status; - - glyph_surface->surface = - _cairo_surface_create_similar_scratch (surface, - CAIRO_FORMAT_A8, 0, - glyph_surface->size.width, - glyph_surface->size.height); - if (glyph_surface->surface == NULL) { - glyph_surface->surface = image; - return; - } - - status = _cairo_surface_set_image (glyph_surface->surface, - (cairo_image_surface_t *) image); - if (status) { - cairo_surface_destroy (glyph_surface->surface); - glyph_surface->surface = NULL; - } - cairo_surface_destroy (image); - } else - glyph_surface->surface = image; + cairo_glyph_cache_key_t *a, *b; + a = (cairo_glyph_cache_key_t *) k1; + b = (cairo_glyph_cache_key_t *) k2; + return (a->index == b->index) + && (a->unscaled == b->unscaled) + && (a->scale.matrix[0][0] == b->scale.matrix[0][0]) + && (a->scale.matrix[0][1] == b->scale.matrix[0][1]) + && (a->scale.matrix[1][0] == b->scale.matrix[1][0]) + && (a->scale.matrix[1][1] == b->scale.matrix[1][1]); } -cairo_surface_t * -_cairo_font_lookup_glyph (cairo_font_t *font, - cairo_surface_t *surface, - const cairo_glyph_t *glyph, - cairo_glyph_size_t *return_size) + +static cairo_status_t +_image_glyph_cache_create_entry (void *cache, + void *key, + void **return_value) { - cairo_glyph_surface_t glyph_surface; - cairo_glyph_cache_t *cache = font->glyph_cache; - cairo_glyph_surface_node_t *node; - - for (node = cache->first; node != NULL; node = node->next) { - cairo_glyph_surface_t *s = &node->s; - - if ((s->surface == NULL || s->surface->backend == surface->backend) && - s->index == glyph->index && - s->matrix[0][0] == font->matrix.m[0][0] && - s->matrix[0][1] == font->matrix.m[0][1] && - s->matrix[1][0] == font->matrix.m[1][0] && - s->matrix[1][1] == font->matrix.m[1][1]) { - - /* move node first in cache */ - if (node->prev) { - if (node->next == NULL) { - cache->last = node->prev; - node->prev->next = NULL; - } else { - node->prev->next = node->next; - node->next->prev = node->prev; - } - - node->prev = NULL; - node->next = cache->first; - cache->first = node; - if (node->next) - node->next->prev = node; - else - cache->last = node; - } - - cairo_surface_reference (s->surface); - *return_size = s->size; - - return s->surface; - } - } - - _cairo_glyph_surface_init (font, surface, glyph, &glyph_surface); + cairo_glyph_cache_key_t *k = (cairo_glyph_cache_key_t *) key; + cairo_image_glyph_cache_entry_t *im; + cairo_status_t status; - *return_size = glyph_surface.size; - - if (cache->cache_size > 0) { - if (cache->n_nodes == cache->cache_size) - _cairo_glyph_cache_pop_last (cache); - - node = malloc (sizeof (cairo_glyph_surface_node_t)); - if (node) { - cairo_surface_reference (glyph_surface.surface); - - /* insert node first in cache */ - node->s = glyph_surface; - node->prev = NULL; - node->next = cache->first; - cache->first = node; - if (node->next) - node->next->prev = node; - else - cache->last = node; - - cache->n_nodes++; - } + im = calloc (1, sizeof (cairo_image_glyph_cache_entry_t)); + if (im == NULL) + return CAIRO_STATUS_NO_MEMORY; + + im->key = *k; + status = im->key.unscaled->backend->create_glyph (im); + + if (status != CAIRO_STATUS_SUCCESS) { + free (im); + return status; } - - return glyph_surface.surface; + + _cairo_unscaled_font_reference (im->key.unscaled); + + im->key.base.memory = + sizeof (cairo_image_glyph_cache_entry_t) + + (im->image ? + sizeof (cairo_image_surface_t) + + 28 * sizeof (int) /* rough guess at size of pixman image structure */ + + (im->image->height * im->image->stride) : 0); + + *return_value = im; + + return CAIRO_STATUS_SUCCESS; } -/* public font interface follows */ -void -cairo_font_reference (cairo_font_t *font) +static void +_image_glyph_cache_destroy_entry (void *cache, + void *value) { - font->refcount++; + cairo_image_glyph_cache_entry_t *im; + + im = (cairo_image_glyph_cache_entry_t *) value; + _cairo_unscaled_font_destroy (im->key.unscaled); + cairo_surface_destroy (&(im->image->base)); + free (im); } -void -cairo_font_destroy (cairo_font_t *font) +static void +_image_glyph_cache_destroy_cache (void *cache) { - if (--(font->refcount) > 0) - return; + free (cache); +} - _cairo_glyph_cache_destroy (font->glyph_cache); +const cairo_cache_backend_t cairo_image_cache_backend = { + _cairo_glyph_cache_hash, + _cairo_glyph_cache_keys_equal, + _image_glyph_cache_create_entry, + _image_glyph_cache_destroy_entry, + _image_glyph_cache_destroy_cache +}; - if (font->backend->destroy) - font->backend->destroy (font); -} void -cairo_font_set_transform (cairo_font_t *font, - cairo_matrix_t *matrix) +_cairo_lock_global_image_glyph_cache() { - cairo_matrix_copy (&(font->matrix), matrix); + /* FIXME: implement locking. */ } void -cairo_font_current_transform (cairo_font_t *font, - cairo_matrix_t *matrix) +_cairo_unlock_global_image_glyph_cache() { - cairo_matrix_copy (matrix, &(font->matrix)); + /* FIXME: implement locking. */ +} + +static cairo_cache_t * +_global_image_glyph_cache = NULL; + +cairo_cache_t * +_cairo_get_global_image_glyph_cache () +{ + if (_global_image_glyph_cache == NULL) { + _global_image_glyph_cache = malloc (sizeof (cairo_cache_t)); + + if (_global_image_glyph_cache == NULL) + goto FAIL; + + if (_cairo_cache_init (_global_image_glyph_cache, + &cairo_image_cache_backend, + CAIRO_IMAGE_GLYPH_CACHE_MEMORY_DEFAULT)) + goto FAIL; + } + + return _global_image_glyph_cache; + + FAIL: + if (_global_image_glyph_cache) + free (_global_image_glyph_cache); + _global_image_glyph_cache = NULL; + return NULL; } diff --git a/src/cairo-ft-font.c b/src/cairo-ft-font.c index 5b0a7f64..f757db09 100644 --- a/src/cairo-ft-font.c +++ b/src/cairo-ft-font.c @@ -1,5 +1,5 @@ /* - * Copyright © 2003 Red Hat Inc. + * Copyright © 2003 Red Hat Inc. * * Permission to use, copy, modify, distribute, and sell this software and * its documentation for any purpose is hereby granted without fee, @@ -31,116 +31,294 @@ #include FT_OUTLINE_H #include FT_IMAGE_H -typedef struct { - cairo_font_t base; +#define DOUBLE_TO_26_6(d) ((FT_F26Dot6)((d) * 64.0)) +#define DOUBLE_FROM_26_6(t) ((double)(t) / 64.0) +#define DOUBLE_TO_16_16(d) ((FT_Fixed)((d) * 65536.0)) +#define DOUBLE_FROM_16_16(t) ((double)(t) / 65536.0) - FT_Library ft_library; - int owns_ft_library; +/* + * First we make a private, sharable implementation object which can be + * stored both in a private cache and in public font objects (including + * those connected to fonts we don't own) + */ + +typedef struct { + int refcount; FT_Face face; int owns_face; - FcPattern *pattern; -} cairo_ft_font_t; +} ft_font_val_t; -#define DOUBLE_TO_26_6(d) ((FT_F26Dot6)((d) * 64.0)) -#define DOUBLE_FROM_26_6(t) ((double)(t) / 64.0) -#define DOUBLE_TO_16_16(d) ((FT_Fixed)((d) * 65536.0)) -#define DOUBLE_FROM_16_16(t) ((double)(t) / 65536.0) +static ft_font_val_t * +_create_from_face (FT_Face face, int owns_face) +{ + ft_font_val_t *tmp = malloc (sizeof(ft_font_val_t)); + if (tmp) { + tmp->refcount = 1; + tmp->face = face; + tmp->owns_face = owns_face; + FT_Set_Char_Size (face, + DOUBLE_TO_26_6 (1.0), + DOUBLE_TO_26_6 (1.0), + 0, 0); + } + return tmp; +} -/* implement the platform-specific interface */ +static void +_reference_font_val (ft_font_val_t *f) +{ + f->refcount++; +} -cairo_font_t * -cairo_ft_font_create (FT_Library ft_library, FcPattern *pattern) +static void +_destroy_font_val (ft_font_val_t *f) { - cairo_ft_font_t *f = NULL; + if (--(f->refcount) > 0) + return; + + if (f->owns_face) + FT_Done_Face (f->face); + + free (f); +} + +static ft_font_val_t * +_create_from_library_and_pattern (FT_Library ft_library, FcPattern *pattern) +{ + ft_font_val_t *f = NULL; char *filename = NULL; - FT_Face face = NULL; int owns_face = 0; + FT_Face face = NULL; FcPattern *resolved = NULL; FcResult result = FcResultMatch; - + + if (pattern == NULL) + goto FAIL; + FcConfigSubstitute (0, pattern, FcMatchPattern); FcDefaultSubstitute (pattern); resolved = FcFontMatch (0, pattern, &result); + if (!resolved) + goto FAIL; + if (result != FcResultMatch) - { - if (resolved) - FcPatternDestroy (resolved); - return NULL; - } + goto FREE_RESOLVED; /* If the pattern has an FT_Face object, use that. */ if (FcPatternGetFTFace (resolved, FC_FT_FACE, 0, &face) != FcResultMatch || face == NULL) { - /* otherwise it had better have a filename */ - int open_res = 0; - owns_face = 1; result = FcPatternGetString (resolved, FC_FILE, 0, (FcChar8 **)(&filename)); if (result == FcResultMatch) - open_res = FT_New_Face (ft_library, filename, 0, &face); + if (FT_New_Face (ft_library, filename, 0, &face)) + goto FREE_RESOLVED; if (face == NULL) - return NULL; + goto FREE_RESOLVED; + + owns_face = 1; } - f = (cairo_ft_font_t *) cairo_ft_font_create_for_ft_face (face); - if (f != NULL) - f->pattern = FcPatternDuplicate (resolved); + f = _create_from_face (face, owns_face); + + FcPatternDestroy (resolved); + return f; + + FREE_RESOLVED: + if (resolved) + FcPatternDestroy (resolved); + + FAIL: + return NULL; +} - f->ft_library = ft_library; - f->owns_ft_library = 0; - f->owns_face = owns_face; +/* + * We then make the user-exposed structure out of one of these impls, such + * that it is reasonably cheap to copy and/or destroy. Unfortunately this + * duplicates a certain amount of the caching machinery in the font cache, + * but that's unavoidable as we also provide an FcPattern resolution API, + * which is not part of cairo's generic font finding system. + */ - FcPatternDestroy (resolved); - return (cairo_font_t *) f; +typedef struct { + cairo_unscaled_font_t base; + FcPattern *pattern; + ft_font_val_t *val; +} cairo_ft_font_t; + +/* + * We then make a key and entry type which are compatible with the generic + * cache system. This cache serves to share single ft_font_val_t instances + * between fonts (or between font lifecycles). + */ + +typedef struct { + cairo_cache_entry_base_t base; + FcPattern *pattern; +} cairo_ft_cache_key_t; + +typedef struct { + cairo_ft_cache_key_t key; + ft_font_val_t *val; +} cairo_ft_cache_entry_t; + +/* + * Then we create a cache which maps FcPattern keys to the refcounted + * ft_font_val_t values. + */ + +typedef struct { + cairo_cache_t base; + FT_Library lib; +} ft_cache_t; + + +static unsigned long +_ft_font_cache_hash (void *cache, void *key) +{ + cairo_ft_cache_key_t *in; + in = (cairo_ft_cache_key_t *) key; + return FcPatternHash (in->pattern); } -FT_Face -cairo_ft_font_face (cairo_font_t *abstract_font) +static int +_ft_font_cache_keys_equal (void *cache, + void *k1, + void *k2) { - cairo_ft_font_t *font = (cairo_ft_font_t *) abstract_font; + cairo_ft_cache_key_t *a; + cairo_ft_cache_key_t *b; + a = (cairo_ft_cache_key_t *) k1; + b = (cairo_ft_cache_key_t *) k2; + + return FcPatternEqual (a->pattern, b->pattern); +} - if (font == NULL) - return NULL; - return font->face; +static cairo_status_t +_ft_font_cache_create_entry (void *cache, + void *key, + void **return_entry) +{ + ft_cache_t *ftcache = (ft_cache_t *) cache; + cairo_ft_cache_key_t *k = (cairo_ft_cache_key_t *) key; + cairo_ft_cache_entry_t *entry; + + entry = malloc (sizeof (cairo_ft_cache_entry_t)); + if (entry == NULL) + return CAIRO_STATUS_NO_MEMORY; + + entry->key.pattern = FcPatternDuplicate (k->pattern); + if (!entry->key.pattern) { + free (entry); + return CAIRO_STATUS_NO_MEMORY; + } + + entry->val = _create_from_library_and_pattern (ftcache->lib, entry->key.pattern); + entry->key.base.memory = 1; + + *return_entry = entry; + + return CAIRO_STATUS_SUCCESS; } -FcPattern * -cairo_ft_font_pattern (cairo_font_t *abstract_font) +static void +_ft_font_cache_destroy_entry (void *cache, + void *entry) +{ + cairo_ft_cache_entry_t *e = (cairo_ft_cache_entry_t *) entry; + FcPatternDestroy (e->key.pattern); + _destroy_font_val (e->val); + free (e); +} + +static void +_ft_font_cache_destroy_cache (void *cache) { - cairo_ft_font_t *font = (cairo_ft_font_t *) abstract_font; + ft_cache_t *fc = (ft_cache_t *) cache; + FT_Done_FreeType (fc->lib); + free (fc); +} - if (font == NULL) - return NULL; +const struct cairo_cache_backend _ft_font_cache_backend = { + _ft_font_cache_hash, + _ft_font_cache_keys_equal, + _ft_font_cache_create_entry, + _ft_font_cache_destroy_entry, + _ft_font_cache_destroy_cache +}; - return font->pattern; + +static ft_cache_t *_global_ft_cache = NULL; + +static void +_lock_global_ft_cache (void) +{ + /* FIXME: Perform locking here. */ +} + +static void +_unlock_global_ft_cache (void) +{ + /* FIXME: Perform locking here. */ +} + +static cairo_cache_t * +_get_global_ft_cache (void) +{ + if (_global_ft_cache == NULL) + { + _global_ft_cache = malloc (sizeof(ft_cache_t)); + if (!_global_ft_cache) + goto FAIL; + + if (_cairo_cache_init (&_global_ft_cache->base, + &_ft_font_cache_backend, + CAIRO_FT_CACHE_NUM_FONTS_DEFAULT)) + goto FAIL; + + if (FT_Init_FreeType (&_global_ft_cache->lib)) + goto FAIL; + } + return &_global_ft_cache->base; + + FAIL: + if (_global_ft_cache) + free (_global_ft_cache); + _global_ft_cache = NULL; + return NULL; } /* implement the backend interface */ -static cairo_font_t * +const struct cairo_font_backend cairo_ft_font_backend; + +static cairo_unscaled_font_t * _cairo_ft_font_create (const char *family, cairo_font_slant_t slant, cairo_font_weight_t weight) { - cairo_ft_font_t *ft_font = NULL; - cairo_font_t *font = NULL; - FcPattern * pat = NULL; + cairo_status_t status; + cairo_ft_font_t *font = NULL; int fcslant; int fcweight; - FT_Library ft_library; - FT_Error error; + cairo_cache_t *cache; + cairo_ft_cache_entry_t *entry; + cairo_ft_cache_key_t key; - pat = FcPatternCreate (); - if (pat == NULL) - return NULL; + key.pattern = FcPatternCreate (); + if (key.pattern == NULL) + goto FAIL; + + font = malloc (sizeof (cairo_ft_font_t)); + if (font == NULL) + goto FREE_PATTERN; switch (weight) { @@ -167,52 +345,44 @@ _cairo_ft_font_create (const char *family, break; } - FcPatternAddString (pat, FC_FAMILY, family); - FcPatternAddInteger (pat, FC_SLANT, fcslant); - FcPatternAddInteger (pat, FC_WEIGHT, fcweight); + FcPatternAddString (key.pattern, FC_FAMILY, family); + FcPatternAddInteger (key.pattern, FC_SLANT, fcslant); + FcPatternAddInteger (key.pattern, FC_WEIGHT, fcweight); - error = FT_Init_FreeType (&ft_library); - if (error) { - FcPatternDestroy (pat); - return NULL; - } + if (_cairo_unscaled_font_init (&font->base, &cairo_ft_font_backend)) + goto FREE_PATTERN; - font = cairo_ft_font_create (ft_library, pat); - if (font == NULL) - return NULL; + _lock_global_ft_cache (); + cache = _get_global_ft_cache (); + if (cache == NULL) { + _unlock_global_ft_cache (); + goto FREE_PATTERN; + } - ft_font = (cairo_ft_font_t *) font; + status = _cairo_cache_lookup (cache, &key, (void **) &entry); + _unlock_global_ft_cache (); - ft_font->owns_ft_library = 1; + if (status) + goto FREE_PATTERN; - FT_Set_Char_Size (ft_font->face, - DOUBLE_TO_26_6 (1.0), - DOUBLE_TO_26_6 (1.0), - 0, 0); - - FcPatternDestroy (pat); - return font; -} + font->pattern = FcPatternDuplicate (entry->key.pattern); + if (font->pattern == NULL) + goto FREE_PATTERN; -static cairo_font_t * -_cairo_ft_font_copy (void *abstract_font) -{ - cairo_ft_font_t * font_new = NULL; - cairo_ft_font_t * font = abstract_font; - - if (font->base.backend != &cairo_ft_font_backend) - return NULL; + font->val = entry->val; + _reference_font_val (font->val); + + return &font->base; - font_new = (cairo_ft_font_t *) cairo_ft_font_create_for_ft_face (font->face); - if (font_new == NULL) - return NULL; + FREE_PATTERN: + FcPatternDestroy (key.pattern); - if (font_new != NULL && font->pattern != NULL) - font_new->pattern = FcPatternDuplicate (font->pattern); + FAIL: + return NULL; - return (cairo_font_t *) font_new; } + static void _cairo_ft_font_destroy (void *abstract_font) { @@ -220,15 +390,11 @@ _cairo_ft_font_destroy (void *abstract_font) if (font == NULL) return; - - if (font->face != NULL && font->owns_face) - FT_Done_Face (font->face); if (font->pattern != NULL) FcPatternDestroy (font->pattern); - if (font->ft_library && font->owns_ft_library) - FT_Done_FreeType (font->ft_library); + _destroy_font_val (font->val); free (font); } @@ -268,7 +434,7 @@ _utf8_to_ucs4 (char const *utf8, } static void -_install_font_matrix(cairo_matrix_t *matrix, FT_Face face) +_install_font_scale (cairo_font_scale_t *sc, FT_Face face) { cairo_matrix_t normalized; double scale_x, scale_y; @@ -276,16 +442,20 @@ _install_font_matrix(cairo_matrix_t *matrix, FT_Face face) FT_Matrix mat; /* The font matrix has x and y "scale" components which we extract and - * use as pixel scale values. These influence the way freetype chooses - * hints, as well as selecting different bitmaps in hand-rendered - * fonts. We also copy the normalized matrix to freetype's - * transformation. + * use as character scale values. These influence the way freetype + * chooses hints, as well as selecting different bitmaps in + * hand-rendered fonts. We also copy the normalized matrix to + * freetype's transformation. */ - _cairo_matrix_compute_scale_factors (matrix, &scale_x, &scale_y); - - cairo_matrix_copy (&normalized, matrix); + cairo_matrix_set_affine (&normalized, + sc->matrix[0][0], + sc->matrix[0][1], + sc->matrix[1][0], + sc->matrix[1][1], + 0, 0); + _cairo_matrix_compute_scale_factors (&normalized, &scale_x, &scale_y); cairo_matrix_scale (&normalized, 1.0 / scale_x, 1.0 / scale_y); cairo_matrix_get_affine (&normalized, &xx /* 00 */ , &yx /* 01 */, @@ -298,21 +468,28 @@ _install_font_matrix(cairo_matrix_t *matrix, FT_Face face) mat.yy = DOUBLE_TO_16_16(yy); FT_Set_Transform(face, &mat, NULL); - FT_Set_Char_Size(face, - DOUBLE_TO_26_6(scale_x), - DOUBLE_TO_26_6(scale_y), - 0, 0); + + FT_Set_Pixel_Sizes(face, + (FT_UInt) scale_x, + (FT_UInt) scale_y); } -static int -_utf8_to_glyphs (cairo_ft_font_t *font, - const unsigned char *utf8, - double x0, - double y0, - cairo_glyph_t **glyphs, - size_t *nglyphs) +static cairo_status_t +_cairo_ft_font_text_to_glyphs (void *abstract_font, + cairo_font_scale_t *sc, + const unsigned char *utf8, + cairo_glyph_t **glyphs, + int *nglyphs) { - FT_Face face = font->face; + cairo_ft_font_t *font = abstract_font; + FT_Face face = font->val->face; + cairo_glyph_cache_key_t key; + cairo_image_glyph_cache_entry_t *val; + cairo_cache_t *cache; + + key.unscaled = &font->base; + key.scale = *sc; + double x = 0., y = 0.; size_t i; FT_ULong *ucs4 = NULL; @@ -320,56 +497,70 @@ _utf8_to_glyphs (cairo_ft_font_t *font, _utf8_to_ucs4 (utf8, &ucs4, nglyphs); if (ucs4 == NULL) - return 0; + return CAIRO_STATUS_NO_MEMORY; *glyphs = (cairo_glyph_t *) malloc ((*nglyphs) * (sizeof (cairo_glyph_t))); if (*glyphs == NULL) { free (ucs4); - return 0; + return CAIRO_STATUS_NO_MEMORY; } - _install_font_matrix (&font->base.matrix, face); + _cairo_lock_global_image_glyph_cache (); + cache = _cairo_get_global_image_glyph_cache (); + if (cache == NULL) { + _cairo_unlock_global_image_glyph_cache (); + return CAIRO_STATUS_NO_MEMORY; + } for (i = 0; i < *nglyphs; i++) { (*glyphs)[i].index = FT_Get_Char_Index (face, ucs4[i]); - (*glyphs)[i].x = x0 + x; - (*glyphs)[i].y = y0 + y; - - FT_Load_Glyph (face, (*glyphs)[i].index, FT_LOAD_DEFAULT); + (*glyphs)[i].x = x; + (*glyphs)[i].y = y; - x += DOUBLE_FROM_26_6 (face->glyph->advance.x); - y -= DOUBLE_FROM_26_6 (face->glyph->advance.y); + val = NULL; + key.index = (*glyphs)[i].index; + + if (_cairo_cache_lookup (cache, &key, (void **) &val) + != CAIRO_STATUS_SUCCESS || val == NULL) + continue; + + x += val->extents.x_advance; + y -= val->extents.y_advance; } + _cairo_unlock_global_image_glyph_cache (); free (ucs4); - return 1; + return CAIRO_STATUS_SUCCESS; } + static cairo_status_t _cairo_ft_font_font_extents (void *abstract_font, + cairo_font_scale_t *sc, cairo_font_extents_t *extents) { cairo_ft_font_t *font = abstract_font; - FT_Face face = font->face; - double scale_x, scale_y; + FT_Face face = font->val->face; + FT_Size_Metrics *metrics = &face->size->metrics; - double upm = face->units_per_EM; + _install_font_scale (sc, face); - _cairo_matrix_compute_scale_factors (&font->base.matrix, &scale_x, &scale_y); + extents->ascent = DOUBLE_FROM_26_6(metrics->ascender); + extents->descent = DOUBLE_FROM_26_6(metrics->descender); + extents->height = DOUBLE_FROM_26_6(metrics->height); + extents->max_x_advance = DOUBLE_FROM_26_6(metrics->max_advance); - extents->ascent = face->ascender / upm * scale_y; - extents->descent = face->descender / upm * scale_y; - extents->height = face->height / upm * scale_y; - extents->max_x_advance = face->max_advance_width / upm * scale_x; - extents->max_y_advance = face->max_advance_height / upm * scale_y; + /* FIXME: this doesn't do vertical layout atm. */ + extents->max_y_advance = 0.0; return CAIRO_STATUS_SUCCESS; } static cairo_status_t _cairo_ft_font_glyph_extents (void *abstract_font, + cairo_font_scale_t *sc, cairo_glyph_t *glyphs, int num_glyphs, cairo_text_extents_t *extents) @@ -379,10 +570,10 @@ _cairo_ft_font_glyph_extents (void *abstract_font, cairo_point_double_t origin; cairo_point_double_t glyph_min, glyph_max; cairo_point_double_t total_min, total_max; - FT_Error error; - FT_Face face = font->face; - FT_GlyphSlot glyph = face->glyph; - FT_Glyph_Metrics *metrics = &glyph->metrics; + + cairo_image_glyph_cache_entry_t *img = NULL; + cairo_cache_t *cache; + cairo_glyph_cache_key_t key; if (num_glyphs == 0) { @@ -399,24 +590,33 @@ _cairo_ft_font_glyph_extents (void *abstract_font, origin.x = glyphs[0].x; origin.y = glyphs[0].y; - _install_font_matrix (&font->base.matrix, face); + _cairo_lock_global_image_glyph_cache (); + cache = _cairo_get_global_image_glyph_cache (); + if (cache == NULL) { + _cairo_unlock_global_image_glyph_cache (); + return CAIRO_STATUS_NO_MEMORY; + } + + key.unscaled = &font->base; + key.scale = *sc; for (i = 0; i < num_glyphs; i++) { - error = FT_Load_Glyph (face, glyphs[i].index, FT_LOAD_DEFAULT); - /* XXX: What to do in this error case? */ - if (error) + img = NULL; + key.index = glyphs[i].index; + if (_cairo_cache_lookup (cache, &key, (void **) &img) + != CAIRO_STATUS_SUCCESS || img == NULL) continue; - + /* XXX: Need to add code here to check the font's FcPattern for FC_VERTICAL_LAYOUT and if set get vertBearingX/Y instead. This will require that cairo_ft_font_create_for_ft_face accept an FcPattern. */ - glyph_min.x = glyphs[i].x + DOUBLE_FROM_26_6 (metrics->horiBearingX); - glyph_min.y = glyphs[i].y - DOUBLE_FROM_26_6 (metrics->horiBearingY); - glyph_max.x = glyph_min.x + DOUBLE_FROM_26_6 (metrics->width); - glyph_max.y = glyph_min.y + DOUBLE_FROM_26_6 (metrics->height); + glyph_min.x = glyphs[i].x + img->extents.x_bearing; + glyph_min.y = glyphs[i].y - img->extents.y_bearing; + glyph_max.x = glyph_min.x + img->extents.width; + glyph_max.y = glyph_min.y + img->extents.height; if (i==0) { total_min = glyph_min; @@ -433,12 +633,13 @@ _cairo_ft_font_glyph_extents (void *abstract_font, total_max.y = glyph_max.y; } } + _cairo_unlock_global_image_glyph_cache (); extents->x_bearing = total_min.x - origin.x; extents->y_bearing = total_min.y - origin.y; extents->width = total_max.x - total_min.x; extents->height = total_max.y - total_min.y; - extents->x_advance = glyphs[i-1].x + DOUBLE_FROM_26_6 (metrics->horiAdvance) - origin.x; + extents->x_advance = glyphs[i-1].x + (img == NULL ? 0 : img->extents.x_advance) - origin.x; extents->y_advance = glyphs[i-1].y + 0 - origin.y; return CAIRO_STATUS_SUCCESS; @@ -446,34 +647,16 @@ _cairo_ft_font_glyph_extents (void *abstract_font, static cairo_status_t -_cairo_ft_font_text_extents (void *abstract_font, - const unsigned char *utf8, - cairo_text_extents_t *extents) -{ - cairo_ft_font_t *font = abstract_font; - cairo_glyph_t *glyphs; - size_t nglyphs; - cairo_status_t status = CAIRO_STATUS_SUCCESS; - - if (_utf8_to_glyphs (font, utf8, 0, 0, &glyphs, &nglyphs)) - { - status = _cairo_ft_font_glyph_extents (font, glyphs, nglyphs, - extents); - free (glyphs); - } - return status; -} - -static cairo_status_t -_cairo_ft_font_glyph_bbox (void *abstract_font, - cairo_surface_t *surface, - const cairo_glyph_t *glyphs, - int num_glyphs, - cairo_box_t *bbox) +_cairo_ft_font_glyph_bbox (void *abstract_font, + cairo_font_scale_t *sc, + const cairo_glyph_t *glyphs, + int num_glyphs, + cairo_box_t *bbox) { + cairo_image_glyph_cache_entry_t *img; + cairo_cache_t *cache; + cairo_glyph_cache_key_t key; cairo_ft_font_t *font = abstract_font; - cairo_surface_t *mask = NULL; - cairo_glyph_size_t size; cairo_fixed_t x1, y1, x2, y2; int i; @@ -481,22 +664,33 @@ _cairo_ft_font_glyph_bbox (void *abstract_font, bbox->p1.x = bbox->p1.y = CAIRO_MAXSHORT << 16; bbox->p2.x = bbox->p2.y = CAIRO_MINSHORT << 16; - if (font == NULL - || surface == NULL - || glyphs == NULL) + _cairo_lock_global_image_glyph_cache (); + cache = _cairo_get_global_image_glyph_cache(); + + if (cache == NULL + || font == NULL + || glyphs == NULL) { + _cairo_unlock_global_image_glyph_cache (); return CAIRO_STATUS_NO_MEMORY; + } + + key.unscaled = &font->base; + key.scale = *sc; for (i = 0; i < num_glyphs; i++) { - mask = _cairo_font_lookup_glyph (&font->base, surface, - &glyphs[i], &size); - if (mask == NULL) + + img = NULL; + key.index = glyphs[i].index; + + if (_cairo_cache_lookup (cache, &key, (void **) &img) + != CAIRO_STATUS_SUCCESS || img == NULL) continue; - x1 = _cairo_fixed_from_double (glyphs[i].x + size.x); - y1 = _cairo_fixed_from_double (glyphs[i].y - size.y); - x2 = x1 + _cairo_fixed_from_double (size.width); - y2 = y1 + _cairo_fixed_from_double (size.height); + x1 = _cairo_fixed_from_double (glyphs[i].x + img->size.x); + y1 = _cairo_fixed_from_double (glyphs[i].y - img->size.y); + x2 = x1 + _cairo_fixed_from_double (img->size.width); + y2 = y1 + _cairo_fixed_from_double (img->size.height); if (x1 < bbox->p1.x) bbox->p1.x = x1; @@ -509,117 +703,82 @@ _cairo_ft_font_glyph_bbox (void *abstract_font, if (y2 > bbox->p2.y) bbox->p2.y = y2; - - if (mask) - cairo_surface_destroy (mask); } + _cairo_unlock_global_image_glyph_cache (); return CAIRO_STATUS_SUCCESS; } -static cairo_status_t -_cairo_ft_font_text_bbox (void *abstract_font, - cairo_surface_t *surface, - double x0, - double y0, - const unsigned char *utf8, - cairo_box_t *bbox) -{ - cairo_ft_font_t *font = abstract_font; - cairo_glyph_t *glyphs; - size_t num_glyphs; - - if (_utf8_to_glyphs (font, utf8, x0, y0, &glyphs, &num_glyphs)) - { - cairo_status_t res; - res = _cairo_ft_font_glyph_bbox (font, surface, - glyphs, num_glyphs, bbox); - free (glyphs); - return res; - } - else - return CAIRO_STATUS_NO_MEMORY; -} static cairo_status_t -_cairo_ft_font_show_glyphs (void *abstract_font, - cairo_operator_t operator, - cairo_surface_t *source, - cairo_surface_t *surface, - int source_x, - int source_y, - const cairo_glyph_t *glyphs, - int num_glyphs) +_cairo_ft_font_show_glyphs (void *abstract_font, + cairo_font_scale_t *sc, + cairo_operator_t operator, + cairo_surface_t *source, + cairo_surface_t *surface, + int source_x, + int source_y, + const cairo_glyph_t *glyphs, + int num_glyphs) { + cairo_image_glyph_cache_entry_t *img; + cairo_cache_t *cache; + cairo_glyph_cache_key_t key; cairo_ft_font_t *font = abstract_font; cairo_status_t status; - cairo_surface_t *mask = NULL; - cairo_glyph_size_t size; double x, y; int i; - if (font == NULL + _cairo_lock_global_image_glyph_cache (); + cache = _cairo_get_global_image_glyph_cache(); + + if (cache == NULL + || font == NULL || source == NULL || surface == NULL - || glyphs == NULL) + || glyphs == NULL) { + _cairo_unlock_global_image_glyph_cache (); return CAIRO_STATUS_NO_MEMORY; + } + + key.unscaled = &font->base; + key.scale = *sc; for (i = 0; i < num_glyphs; i++) { - mask = _cairo_font_lookup_glyph (&font->base, surface, - &glyphs[i], &size); - if (mask == NULL) + img = NULL; + key.index = glyphs[i].index; + + if (_cairo_cache_lookup (cache, &key, (void **) &img) + != CAIRO_STATUS_SUCCESS + || img == NULL + || img->image == NULL) continue; x = glyphs[i].x; y = glyphs[i].y; - status = _cairo_surface_composite (operator, source, mask, surface, - source_x + x + size.x, - source_y + y - size.y, + status = _cairo_surface_composite (operator, source, + &(img->image->base), + surface, + source_x + x + img->size.x, + source_y + y - img->size.y, 0, 0, - x + size.x, - y - size.y, - (double) size.width, - (double) size.height); - - cairo_surface_destroy (mask); + x + img->size.x, + y - img->size.y, + (double) img->size.width, + (double) img->size.height); - if (status) + if (status) { + _cairo_unlock_global_image_glyph_cache (); return status; + } } + _cairo_unlock_global_image_glyph_cache (); return CAIRO_STATUS_SUCCESS; } -static cairo_status_t -_cairo_ft_font_show_text (void *abstract_font, - cairo_operator_t operator, - cairo_surface_t *source, - cairo_surface_t *surface, - int source_x, - int source_y, - double x0, - double y0, - const unsigned char *utf8) -{ - cairo_ft_font_t *font = abstract_font; - cairo_glyph_t *glyphs; - size_t num_glyphs; - - if (_utf8_to_glyphs (font, utf8, x0, y0, &glyphs, &num_glyphs)) - { - cairo_status_t res; - res = _cairo_ft_font_show_glyphs (font, operator, - source, surface, - source_x, source_y, - glyphs, num_glyphs); - free (glyphs); - return res; - } - else - return CAIRO_STATUS_NO_MEMORY; -} static int _move_to (FT_Vector *to, void *closure) @@ -699,10 +858,11 @@ _cubic_to (FT_Vector *control1, FT_Vector *control2, FT_Vector *to, void *closur } static cairo_status_t -_cairo_ft_font_glyph_path (void *abstract_font, - cairo_glyph_t *glyphs, - int num_glyphs, - cairo_path_t *path) +_cairo_ft_font_glyph_path (void *abstract_font, + cairo_font_scale_t *sc, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_path_t *path) { int i; cairo_ft_font_t *font = abstract_font; @@ -717,8 +877,9 @@ _cairo_ft_font_glyph_path (void *abstract_font, 0, /* delta */ }; - glyph = font->face->glyph; - _install_font_matrix (&font->base.matrix, font->face); + glyph = font->val->face->glyph; + + _install_font_scale (sc, font->val->face); for (i = 0; i < num_glyphs; i++) { @@ -727,7 +888,7 @@ _cairo_ft_font_glyph_path (void *abstract_font, 0, DOUBLE_TO_16_16 (-1.0), }; - error = FT_Load_Glyph (font->face, glyphs[i].index, FT_LOAD_DEFAULT); + error = FT_Load_Glyph (font->val->face, glyphs[i].index, FT_LOAD_DEFAULT); /* XXX: What to do in this error case? */ if (error) continue; @@ -747,130 +908,218 @@ _cairo_ft_font_glyph_path (void *abstract_font, return CAIRO_STATUS_SUCCESS; } -static cairo_status_t -_cairo_ft_font_text_path (void *abstract_font, - double x, - double y, - const unsigned char *utf8, - cairo_path_t *path) -{ - cairo_ft_font_t *font = abstract_font; - cairo_glyph_t *glyphs; - size_t nglyphs; - - if (_utf8_to_glyphs (font, utf8, x, y, &glyphs, &nglyphs)) - { - cairo_status_t res; - res = _cairo_ft_font_glyph_path (font, glyphs, nglyphs, path); - free (glyphs); - return res; - } - else - return CAIRO_STATUS_NO_MEMORY; -} - -cairo_font_t * -cairo_ft_font_create_for_ft_face (FT_Face face) -{ - cairo_ft_font_t *f = NULL; - - f = malloc (sizeof (cairo_ft_font_t)); - if (f == NULL) - return NULL; - memset (f, 0, sizeof (cairo_ft_font_t)); - - _cairo_font_init (&f->base, - &cairo_ft_font_backend); - - f->ft_library = NULL; - f->owns_ft_library = 0; - - f->face = face; - f->owns_face = 0; - return (cairo_font_t *) f; -} - -static cairo_surface_t * -_cairo_ft_font_create_glyph (void *abstract_font, - const cairo_glyph_t *glyph, - cairo_glyph_size_t *return_size) +static cairo_status_t +_cairo_ft_font_create_glyph(cairo_image_glyph_cache_entry_t *val) { - cairo_ft_font_t *font = abstract_font; - cairo_image_surface_t *image; + cairo_ft_font_t *font = (cairo_ft_font_t *)val->key.unscaled; FT_GlyphSlot glyphslot; unsigned int width, height, stride; FT_Outline *outline; FT_BBox cbox; FT_Bitmap bitmap; - - glyphslot = font->face->glyph; - _install_font_matrix (&font->base.matrix, font->face); + FT_Glyph_Metrics *metrics; - FT_Load_Glyph (font->face, glyph->index, FT_LOAD_DEFAULT); + glyphslot = font->val->face->glyph; + metrics = &glyphslot->metrics; - outline = &glyphslot->outline; + _install_font_scale (&val->key.scale, font->val->face); + + if (FT_Load_Glyph (font->val->face, val->key.index, FT_LOAD_DEFAULT) != 0) + return CAIRO_STATUS_NO_MEMORY; + + val->extents.x_bearing = DOUBLE_FROM_26_6 (metrics->horiBearingX); + val->extents.y_bearing = DOUBLE_FROM_26_6 (metrics->horiBearingY); + val->extents.width = DOUBLE_FROM_26_6 (metrics->width); + val->extents.height = DOUBLE_FROM_26_6 (metrics->height); + val->extents.x_advance = DOUBLE_FROM_26_6 (font->val->face->glyph->advance.x); + val->extents.y_advance = DOUBLE_FROM_26_6 (font->val->face->glyph->advance.y); + outline = &glyphslot->outline; + FT_Outline_Get_CBox (outline, &cbox); cbox.xMin &= -64; cbox.yMin &= -64; cbox.xMax = (cbox.xMax + 63) & -64; cbox.yMax = (cbox.yMax + 63) & -64; - + width = (unsigned int) ((cbox.xMax - cbox.xMin) >> 6); height = (unsigned int) ((cbox.yMax - cbox.yMin) >> 6); stride = (width + 3) & -4; - bitmap.pixel_mode = ft_pixel_mode_grays; - bitmap.num_grays = 256; - bitmap.width = width; - bitmap.rows = height; - bitmap.pitch = stride; - if (width * height == 0) - return NULL; - - bitmap.buffer = malloc (stride * height); - if (bitmap.buffer == NULL) - return NULL; - - memset (bitmap.buffer, 0x0, stride * height); + val->image = NULL; + else + { - FT_Outline_Translate (outline, -cbox.xMin, -cbox.yMin); - FT_Outline_Get_Bitmap (glyphslot->library, outline, &bitmap); - - image = (cairo_image_surface_t *) + bitmap.pixel_mode = ft_pixel_mode_grays; + bitmap.num_grays = 256; + bitmap.width = width; + bitmap.rows = height; + bitmap.pitch = stride; + bitmap.buffer = calloc (1, stride * height); + + if (bitmap.buffer == NULL) { + return CAIRO_STATUS_NO_MEMORY; + }; + + FT_Outline_Translate (outline, -cbox.xMin, -cbox.yMin); + + if (FT_Outline_Get_Bitmap (glyphslot->library, outline, &bitmap) != 0) { + free (bitmap.buffer); + return CAIRO_STATUS_NO_MEMORY; + } + + val->image = (cairo_image_surface_t *) cairo_image_surface_create_for_data ((char *) bitmap.buffer, CAIRO_FORMAT_A8, width, height, stride); - if (image == NULL) { - free (bitmap.buffer); - return NULL; + if (val->image == NULL) { + free (bitmap.buffer); + return CAIRO_STATUS_NO_MEMORY; + } + + _cairo_image_surface_assume_ownership_of_data (val->image); } - - _cairo_image_surface_assume_ownership_of_data (image); - - return_size->width = (unsigned short) width; - return_size->height = (unsigned short) height; - return_size->x = (short) (cbox.xMin >> 6); - return_size->y = (short) (cbox.yMax >> 6); - return &image->base; + val->size.width = (unsigned short) width; + val->size.height = (unsigned short) height; + val->size.x = (short) (cbox.xMin >> 6); + val->size.y = (short) (cbox.yMax >> 6); + + return CAIRO_STATUS_SUCCESS; } const struct cairo_font_backend cairo_ft_font_backend = { _cairo_ft_font_create, - _cairo_ft_font_copy, _cairo_ft_font_destroy, _cairo_ft_font_font_extents, - _cairo_ft_font_text_extents, + _cairo_ft_font_text_to_glyphs, _cairo_ft_font_glyph_extents, - _cairo_ft_font_text_bbox, _cairo_ft_font_glyph_bbox, - _cairo_ft_font_show_text, _cairo_ft_font_show_glyphs, - _cairo_ft_font_text_path, _cairo_ft_font_glyph_path, _cairo_ft_font_create_glyph }; + + +/* implement the platform-specific interface */ + +cairo_font_t * +cairo_ft_font_create (FT_Library ft_library, FcPattern *pattern) +{ + cairo_font_scale_t scale; + cairo_font_t *scaled; + cairo_ft_font_t *f = NULL; + ft_font_val_t *v = NULL; + FcPattern *dup; + + scale.matrix[0][0] = 1.; + scale.matrix[0][1] = 0.; + scale.matrix[1][0] = 0.; + scale.matrix[1][1] = 1.; + + scaled = malloc (sizeof (cairo_font_t)); + if (scaled == NULL) + goto FAIL; + + dup = FcPatternDuplicate(pattern); + if (dup == NULL) + goto FREE_SCALED; + + v = _create_from_library_and_pattern (ft_library, pattern); + if (v == NULL) + goto FREE_PATTERN; + + f = malloc (sizeof(cairo_ft_font_t)); + if (f == NULL) + goto FREE_VAL; + + if (_cairo_unscaled_font_init (&f->base, &cairo_ft_font_backend)) + goto FREE_VAL; + + f->pattern = dup; + f->val = v; + + _cairo_font_init (scaled, &scale, &f->base); + + return scaled; + + FREE_VAL: + _destroy_font_val (v); + + FREE_PATTERN: + FcPatternDestroy (dup); + + FREE_SCALED: + free (scaled); + + FAIL: + return NULL; +} + +cairo_font_t * +cairo_ft_font_create_for_ft_face (FT_Face face) +{ + cairo_font_scale_t scale; + cairo_font_t *scaled; + cairo_ft_font_t *f = NULL; + ft_font_val_t *v = NULL; + + scale.matrix[0][0] = 1.; + scale.matrix[0][1] = 0.; + scale.matrix[1][0] = 0.; + scale.matrix[1][1] = 1.; + + scaled = malloc (sizeof (cairo_font_t)); + if (scaled == NULL) + goto FAIL; + + v = _create_from_face (face, 0); + if (v == NULL) + goto FREE_SCALED; + + f = malloc (sizeof(cairo_ft_font_t)); + if (f == NULL) + goto FREE_VAL; + + _cairo_unscaled_font_init (&f->base, &cairo_ft_font_backend); + f->pattern = NULL; + f->val = v; + + _cairo_font_init (scaled, &scale, &f->base); + + return scaled; + + FREE_VAL: + _destroy_font_val (v); + + FREE_SCALED: + free (scaled); + + FAIL: + return NULL; +} + +FT_Face +cairo_ft_font_face (cairo_font_t *abstract_font) +{ + cairo_ft_font_t *font = (cairo_ft_font_t *) abstract_font->unscaled; + + if (font == NULL || font->val == NULL) + return NULL; + + return font->val->face; +} + +FcPattern * +cairo_ft_font_pattern (cairo_font_t *abstract_font) +{ + cairo_ft_font_t *font = (cairo_ft_font_t *) abstract_font->unscaled; + + if (font == NULL) + return NULL; + + return font->pattern; +} diff --git a/src/cairo-glitz-surface.c b/src/cairo-glitz-surface.c new file mode 100644 index 00000000..21e88920 --- /dev/null +++ b/src/cairo-glitz-surface.c @@ -0,0 +1,930 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2004 David Reveman + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of David + * Reveman not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. David Reveman makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * DAVID REVEMAN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL DAVID REVEMAN BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: David Reveman <c99drn@cs.umu.se> + */ + +#include "cairoint.h" + +#define GLITZ_FIXED_TO_FLOAT(f) \ + (((glitz_float_t) (f)) / 65536) + +#define GLITZ_FIXED_LINE_X_TO_FLOAT(line, v) \ + (((glitz_float_t) \ + ((line).p1.x + (cairo_fixed_16_16_t) \ + (((cairo_fixed_32_32_t) ((v) - (line).p1.y) * \ + ((line).p2.x - (line).p1.x)) / \ + ((line).p2.y - (line).p1.y)))) / 65536) + +#define GLITZ_FIXED_LINE_X_CEIL_TO_FLOAT(line, v) \ + (((glitz_float_t) \ + ((line).p1.x + (cairo_fixed_16_16_t) \ + (((((line).p2.y - (line).p1.y) - 1) + \ + ((cairo_fixed_32_32_t) ((v) - (line).p1.y) * \ + ((line).p2.x - (line).p1.x))) / \ + ((line).p2.y - (line).p1.y)))) / 65536) + +void +cairo_set_target_glitz (cairo_t *cr, glitz_surface_t *surface) +{ + cairo_surface_t *crsurface; + + if (cr->status && cr->status != CAIRO_STATUS_NO_TARGET_SURFACE) + return; + + glitz_surface_reference (surface); + + crsurface = cairo_glitz_surface_create (surface); + if (crsurface == NULL) { + cr->status = CAIRO_STATUS_NO_MEMORY; + return; + } + + cairo_set_target_surface (cr, crsurface); + + cairo_surface_destroy (crsurface); +} + +typedef struct cairo_glitz_surface { + cairo_surface_t base; + + unsigned long features; + glitz_surface_t *surface; + glitz_format_t *format; + + cairo_pattern_t pattern; + cairo_box_t pattern_box; +} cairo_glitz_surface_t; + +static void +_cairo_glitz_surface_destroy (void *abstract_surface) +{ + cairo_glitz_surface_t *surface = abstract_surface; + + glitz_surface_destroy (surface->surface); + + _cairo_pattern_fini (&surface->pattern); + + free (surface); +} + +static double +_cairo_glitz_surface_pixels_per_inch (void *abstract_surface) +{ + return 96.0; +} + +static cairo_image_surface_t * +_cairo_glitz_surface_get_image (void *abstract_surface) +{ + cairo_glitz_surface_t *surface = abstract_surface; + cairo_image_surface_t *image; + char *pixels; + int width, height; + cairo_format_masks_t format; + glitz_buffer_t *buffer; + glitz_pixel_format_t pf; + + if (surface->pattern.type != CAIRO_PATTERN_SURFACE) { + cairo_box_t box; + + box.p1.x = box.p1.y = 0; + box.p2.x = surface->pattern_box.p2.x; + box.p2.y = surface->pattern_box.p2.y; + + return _cairo_pattern_get_image (&surface->pattern, &box); + } + + + width = glitz_surface_get_width (surface->surface); + height = glitz_surface_get_height (surface->surface); + + if (surface->format->red_size > 0) { + format.bpp = 32; + + if (surface->format->alpha_size > 0) + format.alpha_mask = 0xff000000; + else + format.alpha_mask = 0x0; + + format.red_mask = 0xff0000; + format.green_mask = 0xff00; + format.blue_mask = 0xff; + } else { + format.bpp = 8; + format.blue_mask = format.green_mask = format.red_mask = 0x0; + format.alpha_mask = 0xff; + } + + pf.masks.bpp = format.bpp; + pf.masks.alpha_mask = format.alpha_mask; + pf.masks.red_mask = format.red_mask; + pf.masks.green_mask = format.green_mask; + pf.masks.blue_mask = format.blue_mask; + pf.xoffset = 0; + pf.skip_lines = 0; + pf.bytes_per_line = (((width * format.bpp) / 8) + 3) & -4; + pf.scanline_order = GLITZ_PIXEL_SCANLINE_ORDER_TOP_DOWN; + + pixels = malloc (height * pf.bytes_per_line); + if (!pixels) + return NULL; + + buffer = glitz_buffer_create_for_data (pixels); + if (!buffer) { + free (pixels); + return NULL; + } + + glitz_get_pixels (surface->surface, + 0, 0, + width, height, + &pf, + buffer); + + glitz_buffer_destroy (buffer); + + image = (cairo_image_surface_t *) + _cairo_image_surface_create_with_masks (pixels, + &format, + width, height, + pf.bytes_per_line); + + _cairo_image_surface_assume_ownership_of_data (image); + + _cairo_image_surface_set_repeat (image, surface->base.repeat); + _cairo_image_surface_set_matrix (image, &(surface->base.matrix)); + + return image; +} + +static cairo_status_t +_cairo_glitz_surface_set_image (void *abstract_surface, + cairo_image_surface_t *image) +{ + cairo_glitz_surface_t *surface = abstract_surface; + glitz_buffer_t *buffer; + glitz_pixel_format_t pf; + pixman_format_t *format; + int am, rm, gm, bm; + + format = pixman_image_get_format (image->pixman_image); + if (format == NULL) + return CAIRO_STATUS_NO_MEMORY; + + pixman_format_get_masks (format, &pf.masks.bpp, &am, &rm, &gm, &bm); + + pf.masks.alpha_mask = am; + pf.masks.red_mask = rm; + pf.masks.green_mask = gm; + pf.masks.blue_mask = bm; + pf.xoffset = 0; + pf.skip_lines = 0; + pf.bytes_per_line = image->stride; + pf.scanline_order = GLITZ_PIXEL_SCANLINE_ORDER_TOP_DOWN; + + buffer = glitz_buffer_create_for_data (image->data); + if (!buffer) + return CAIRO_STATUS_NO_MEMORY; + + glitz_set_pixels (surface->surface, + 0, 0, + image->width, image->height, + &pf, + buffer); + + glitz_buffer_destroy (buffer); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_glitz_surface_set_matrix (void *abstract_surface, + cairo_matrix_t *matrix) +{ + cairo_glitz_surface_t *surface = abstract_surface; + glitz_transform_t transform; + + transform.matrix[0][0] = _cairo_fixed_from_double (matrix->m[0][0]); + transform.matrix[0][1] = _cairo_fixed_from_double (matrix->m[1][0]); + transform.matrix[0][2] = _cairo_fixed_from_double (matrix->m[2][0]); + + transform.matrix[1][0] = _cairo_fixed_from_double (matrix->m[0][1]); + transform.matrix[1][1] = _cairo_fixed_from_double (matrix->m[1][1]); + transform.matrix[1][2] = _cairo_fixed_from_double (matrix->m[2][1]); + + transform.matrix[2][0] = 0; + transform.matrix[2][1] = 0; + transform.matrix[2][2] = 1 << 16; + + glitz_surface_set_transform (surface->surface, &transform); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_glitz_surface_set_filter (void *abstract_surface, cairo_filter_t filter) +{ + cairo_glitz_surface_t *surface = abstract_surface; + glitz_filter_t glitz_filter; + + switch (filter) { + case CAIRO_FILTER_FAST: + case CAIRO_FILTER_NEAREST: + glitz_filter = GLITZ_FILTER_NEAREST; + break; + case CAIRO_FILTER_GOOD: + case CAIRO_FILTER_BEST: + case CAIRO_FILTER_BILINEAR: + default: + glitz_filter = GLITZ_FILTER_BILINEAR; + break; + } + + glitz_surface_set_filter (surface->surface, glitz_filter, NULL, 0); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_glitz_surface_set_repeat (void *abstract_surface, int repeat) +{ + cairo_glitz_surface_t *surface = abstract_surface; + + glitz_surface_set_fill (surface->surface, + (repeat)? GLITZ_FILL_REPEAT: + GLITZ_FILL_TRANSPARENT); + + return CAIRO_STATUS_SUCCESS; +} + +static glitz_operator_t +_glitz_operator (cairo_operator_t op) +{ + switch (op) { + case CAIRO_OPERATOR_CLEAR: + return GLITZ_OPERATOR_CLEAR; + case CAIRO_OPERATOR_SRC: + return GLITZ_OPERATOR_SRC; + case CAIRO_OPERATOR_DST: + return GLITZ_OPERATOR_DST; + case CAIRO_OPERATOR_OVER_REVERSE: + return GLITZ_OPERATOR_OVER_REVERSE; + case CAIRO_OPERATOR_IN: + return GLITZ_OPERATOR_IN; + case CAIRO_OPERATOR_IN_REVERSE: + return GLITZ_OPERATOR_IN_REVERSE; + case CAIRO_OPERATOR_OUT: + return GLITZ_OPERATOR_OUT; + case CAIRO_OPERATOR_OUT_REVERSE: + return GLITZ_OPERATOR_OUT_REVERSE; + case CAIRO_OPERATOR_ATOP: + return GLITZ_OPERATOR_ATOP; + case CAIRO_OPERATOR_ATOP_REVERSE: + return GLITZ_OPERATOR_ATOP_REVERSE; + case CAIRO_OPERATOR_XOR: + return GLITZ_OPERATOR_XOR; + case CAIRO_OPERATOR_ADD: + return GLITZ_OPERATOR_ADD; + case CAIRO_OPERATOR_SATURATE: + return GLITZ_OPERATOR_SATURATE; + case CAIRO_OPERATOR_OVER: + default: + return GLITZ_OPERATOR_OVER; + } +} + +static glitz_surface_t * +_glitz_surface_create_solid (glitz_surface_t *other, + glitz_format_name_t format_name, + glitz_color_t *color) +{ + glitz_surface_t *surface; + glitz_format_t *format; + + format = glitz_surface_find_similar_standard_format (other, format_name); + if (format == NULL) + return NULL; + + surface = glitz_surface_create_similar (other, format, 1, 1); + if (surface == NULL) + return NULL; + + glitz_set_rectangle (surface, color, 0, 0, 1, 1); + + glitz_surface_set_fill (surface, GLITZ_FILL_REPEAT); + + return surface; +} + +static cairo_surface_t * +_cairo_glitz_surface_create_similar (void *abstract_src, + cairo_format_t format, + int drawable, + int width, + int height) +{ + cairo_glitz_surface_t *src = abstract_src; + glitz_surface_t *surface; + cairo_surface_t *crsurface; + glitz_format_t *glitz_format; + glitz_format_t templ; + unsigned long mask; + + templ.read.offscreen = 1; + mask = GLITZ_FORMAT_READ_OFFSCREEN_MASK; + + if (drawable) { + templ.draw.offscreen = 1; + if (src->features & GLITZ_FEATURE_OFFSCREEN_MULTISAMPLE_MASK) { + templ.multisample.samples = src->format->multisample.samples; + mask |= GLITZ_FORMAT_MULTISAMPLE_SAMPLES_MASK; + } + } else + templ.draw.offscreen = 0; + + mask |= GLITZ_FORMAT_DRAW_OFFSCREEN_MASK; + + switch (format) { + case CAIRO_FORMAT_A1: + case CAIRO_FORMAT_A8: + templ.alpha_size = 8; + mask |= GLITZ_FORMAT_ALPHA_SIZE_MASK; + break; + case CAIRO_FORMAT_RGB24: + templ.red_size = 8; + mask |= GLITZ_FORMAT_RED_SIZE_MASK; + break; + case CAIRO_FORMAT_ARGB32: + default: + templ.alpha_size = templ.red_size = 8; + mask |= GLITZ_FORMAT_ALPHA_SIZE_MASK; + mask |= GLITZ_FORMAT_RED_SIZE_MASK; + break; + } + + glitz_format = + glitz_surface_find_similar_format (src->surface, mask, &templ, 0); + if (glitz_format == NULL) { + mask &= ~GLITZ_FORMAT_DRAW_OFFSCREEN_MASK; + glitz_format = + glitz_surface_find_similar_format (src->surface, mask, &templ, 0); + if (glitz_format == NULL) + return NULL; + } + + surface = glitz_surface_create_similar (src->surface, glitz_format, + width, height); + if (surface == NULL) + return NULL; + + crsurface = cairo_glitz_surface_create (surface); + if (crsurface == NULL) + glitz_surface_destroy (surface); + + return crsurface; +} + +static cairo_glitz_surface_t * +_cairo_glitz_surface_clone_similar (cairo_glitz_surface_t *templ, + cairo_surface_t *src, + cairo_format_t format) +{ + cairo_glitz_surface_t *clone; + cairo_image_surface_t *src_image; + + src_image = _cairo_surface_get_image (src); + + clone = (cairo_glitz_surface_t *) + _cairo_glitz_surface_create_similar (templ, format, 0, + src_image->width, + src_image->height); + if (clone == NULL) + return NULL; + + _cairo_glitz_surface_set_filter (clone, cairo_surface_get_filter (src)); + + _cairo_glitz_surface_set_image (clone, src_image); + + _cairo_glitz_surface_set_matrix (clone, &(src_image->base.matrix)); + + cairo_surface_destroy (&src_image->base); + + return clone; +} + +static cairo_int_status_t +_glitz_composite (glitz_operator_t op, + glitz_surface_t *src, + glitz_surface_t *mask, + glitz_surface_t *dst, + int src_x, + int src_y, + int mask_x, + int mask_y, + int dst_x, + int dst_y, + int width, + int height, + glitz_buffer_t *geometry, + glitz_geometry_format_t *format) +{ + if (glitz_surface_get_status (dst)) + return CAIRO_STATUS_NO_TARGET_SURFACE; + + glitz_set_geometry (dst, + 0, 0, + format, geometry); + + glitz_composite (op, + src, + mask, + dst, + src_x, src_y, + mask_x, mask_y, + dst_x, dst_y, + width, height); + + glitz_set_geometry (dst, 0, 0, NULL, NULL); + + if (glitz_surface_get_status (dst) == GLITZ_STATUS_NOT_SUPPORTED) + return CAIRO_INT_STATUS_UNSUPPORTED; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_glitz_surface_composite (cairo_operator_t op, + cairo_surface_t *generic_src, + cairo_surface_t *generic_mask, + void *abstract_dst, + int src_x, + int src_y, + int mask_x, + int mask_y, + int dst_x, + int dst_y, + unsigned int width, + unsigned int height) +{ + cairo_glitz_surface_t *dst = abstract_dst; + cairo_glitz_surface_t *src = (cairo_glitz_surface_t *) generic_src; + cairo_glitz_surface_t *mask = (cairo_glitz_surface_t *) generic_mask; + cairo_glitz_surface_t *src_clone = NULL; + cairo_glitz_surface_t *mask_clone = NULL; + cairo_int_status_t status; + + if (generic_src->backend != dst->base.backend) { + src_clone = _cairo_glitz_surface_clone_similar (dst, generic_src, + CAIRO_FORMAT_ARGB32); + if (!src_clone) + return CAIRO_INT_STATUS_UNSUPPORTED; + + src = src_clone; + } + + if (generic_mask && (generic_mask->backend != dst->base.backend)) { + mask_clone = _cairo_glitz_surface_clone_similar (dst, generic_mask, + CAIRO_FORMAT_A8); + if (!mask_clone) + return CAIRO_INT_STATUS_UNSUPPORTED; + + mask = mask_clone; + } + + status = _glitz_composite (_glitz_operator (op), + src->surface, + (mask)? mask->surface: NULL, + dst->surface, + src_x, src_y, + mask_x, mask_y, + dst_x, dst_y, + width, height, + NULL, NULL); + + if (src_clone) + cairo_surface_destroy (&src_clone->base); + + if (mask_clone) + cairo_surface_destroy (&mask_clone->base); + + return status; +} + +static cairo_int_status_t +_cairo_glitz_surface_fill_rectangles (void *abstract_dst, + cairo_operator_t op, + const cairo_color_t *color, + cairo_rectangle_t *rects, + int n_rects) +{ + cairo_glitz_surface_t *dst = abstract_dst; + glitz_color_t glitz_color; + + glitz_color.red = color->red_short; + glitz_color.green = color->green_short; + glitz_color.blue = color->blue_short; + glitz_color.alpha = color->alpha_short; + + if (op != CAIRO_OPERATOR_SRC) { + glitz_surface_t *solid; + glitz_float_t *vertices; + glitz_buffer_t *buffer; + glitz_geometry_format_t gf; + cairo_int_status_t status; + int width, height; + void *data; + + gf.mode = GLITZ_GEOMETRY_MODE_DIRECT; + gf.edge_hint = GLITZ_GEOMETRY_EDGE_HINT_SHARP; + gf.primitive = GLITZ_GEOMETRY_PRIMITIVE_QUADS; + gf.type = GLITZ_DATA_TYPE_FLOAT; + gf.first = 0; + gf.count = n_rects * 4; + + data = malloc (n_rects * 8 * sizeof (glitz_float_t)); + if (!data) + return CAIRO_STATUS_NO_MEMORY; + + buffer = glitz_buffer_create_for_data (data); + if (buffer == NULL) { + free (data); + return CAIRO_STATUS_NO_MEMORY; + } + + width = height = 0; + vertices = glitz_buffer_map (buffer, GLITZ_BUFFER_ACCESS_WRITE_ONLY); + for (; n_rects; rects++, n_rects--) { + *vertices++ = (glitz_float_t) rects->x; + *vertices++ = (glitz_float_t) rects->y; + *vertices++ = (glitz_float_t) (rects->x + rects->width); + *vertices++ = (glitz_float_t) rects->y; + *vertices++ = (glitz_float_t) (rects->x + rects->width); + *vertices++ = (glitz_float_t) (rects->y + rects->height); + *vertices++ = (glitz_float_t) rects->x; + *vertices++ = (glitz_float_t) (rects->y + rects->height); + + if ((rects->x + rects->width) > width) + width = rects->x + rects->width; + + if ((rects->y + rects->height) > height) + height = rects->y + rects->height; + } + glitz_buffer_unmap (buffer); + + solid = _glitz_surface_create_solid (dst->surface, + GLITZ_STANDARD_ARGB32, + &glitz_color); + if (solid == NULL) + return CAIRO_STATUS_NO_MEMORY; + + status = _glitz_composite (_glitz_operator (op), + solid, + NULL, + dst->surface, + 0, 0, + 0, 0, + 0, 0, + width, height, + buffer, &gf); + + glitz_surface_destroy (solid); + glitz_buffer_destroy (buffer); + free (data); + + return status; + } else + glitz_set_rectangles (dst->surface, &glitz_color, + (glitz_rectangle_t *) rects, n_rects); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_glitz_surface_composite_trapezoids (cairo_operator_t op, + cairo_surface_t *generic_src, + void *abstract_dst, + int x_src, + int y_src, + cairo_trapezoid_t *traps, + int n_traps) +{ + cairo_glitz_surface_t *dst = abstract_dst; + cairo_glitz_surface_t *src = (cairo_glitz_surface_t *) generic_src; + glitz_surface_t *mask = NULL; + glitz_float_t *vertices; + glitz_buffer_t *buffer; + glitz_geometry_format_t gf; + cairo_int_status_t status; + int x_dst, y_dst, x_rel, y_rel, width, height; + void *data; + + if (generic_src->backend != dst->base.backend) + return CAIRO_INT_STATUS_UNSUPPORTED; + + gf.mode = GLITZ_GEOMETRY_MODE_DIRECT; + gf.edge_hint = GLITZ_GEOMETRY_EDGE_HINT_GOOD_SMOOTH; + gf.primitive = GLITZ_GEOMETRY_PRIMITIVE_QUADS; + gf.type = GLITZ_DATA_TYPE_FLOAT; + gf.first = 0; + gf.count = n_traps * 4; + + data = malloc (n_traps * 8 * sizeof (glitz_float_t)); + if (!data) + return CAIRO_STATUS_NO_MEMORY; + + buffer = glitz_buffer_create_for_data (data); + if (buffer == NULL) { + free (data); + return CAIRO_STATUS_NO_MEMORY; + } + + x_dst = traps[0].left.p1.x >> 16; + y_dst = traps[0].left.p1.y >> 16; + + vertices = glitz_buffer_map (buffer, GLITZ_BUFFER_ACCESS_WRITE_ONLY); + for (; n_traps; traps++, n_traps--) { + glitz_float_t top, bottom; + + top = GLITZ_FIXED_TO_FLOAT (traps->top); + bottom = GLITZ_FIXED_TO_FLOAT (traps->bottom); + + *vertices++ = GLITZ_FIXED_LINE_X_TO_FLOAT (traps->left, traps->top); + *vertices++ = top; + *vertices++ = + GLITZ_FIXED_LINE_X_CEIL_TO_FLOAT (traps->right, traps->top); + *vertices++ = top; + *vertices++ = + GLITZ_FIXED_LINE_X_CEIL_TO_FLOAT (traps->right, traps->bottom); + *vertices++ = bottom; + *vertices++ = GLITZ_FIXED_LINE_X_TO_FLOAT (traps->left, traps->bottom); + *vertices++ = bottom; + } + glitz_buffer_unmap (buffer); + + if ((src->pattern.type == CAIRO_PATTERN_SURFACE) && + (src->pattern.color.alpha != 1.0)) { + glitz_color_t color; + + color.red = color.green = color.blue = 0; + color.alpha = src->pattern.color.alpha_short; + + mask = _glitz_surface_create_solid (dst->surface, + GLITZ_STANDARD_A8, + &color); + } + + x_rel = (src->pattern_box.p1.x >> 16) + x_src - x_dst; + y_rel = (src->pattern_box.p1.y >> 16) + y_src - y_dst; + + x_dst = src->pattern_box.p1.x >> 16; + y_dst = src->pattern_box.p1.y >> 16; + + width = ((src->pattern_box.p2.x + 65535) >> 16) - + (src->pattern_box.p1.x >> 16); + height = ((src->pattern_box.p2.y + 65535) >> 16) - + (src->pattern_box.p1.y >> 16); + + status = _glitz_composite (_glitz_operator (op), + src->surface, + mask, + dst->surface, + x_rel, y_rel, + 0, 0, + x_dst, y_dst, + width, height, + buffer, &gf); + + if (mask) + glitz_surface_destroy (mask); + + glitz_buffer_destroy (buffer); + free (data); + + return status; +} + +static cairo_int_status_t +_cairo_glitz_surface_copy_page (void *abstract_surface) +{ + return CAIRO_INT_STATUS_UNSUPPORTED; +} + +static cairo_int_status_t +_cairo_glitz_surface_show_page (void *abstract_surface) +{ + return CAIRO_INT_STATUS_UNSUPPORTED; +} + +static cairo_int_status_t +_cairo_glitz_surface_create_pattern (void *abstract_dst, + cairo_pattern_t *pattern, + cairo_box_t *box) +{ + cairo_glitz_surface_t *dst = abstract_dst; + cairo_surface_t *generic_src = NULL; + cairo_image_surface_t *image = NULL; + cairo_glitz_surface_t *src; + + switch (pattern->type) { + case CAIRO_PATTERN_SOLID: + generic_src = + _cairo_surface_create_similar_solid (abstract_dst, + CAIRO_FORMAT_ARGB32, + 1, 1, + &pattern->color); + if (generic_src) + cairo_surface_set_repeat (generic_src, 1); + break; + case CAIRO_PATTERN_RADIAL: + /* glitz doesn't support inner and outer circle with different + center points. */ + if (pattern->u.radial.center0.x != pattern->u.radial.center1.x || + pattern->u.radial.center0.y != pattern->u.radial.center1.y) + break; + /* fall-through */ + case CAIRO_PATTERN_LINEAR: { + glitz_fixed16_16_t *params; + int i, n_params; + + if (!(dst->features & GLITZ_FEATURE_FRAGMENT_PROGRAM_MASK)) + break; + + if (pattern->filter != CAIRO_FILTER_BILINEAR) + break; + + n_params = pattern->n_stops * 3 + 4; + + params = malloc (sizeof (glitz_fixed16_16_t) * n_params); + if (params == NULL) + return CAIRO_STATUS_NO_MEMORY; + + generic_src = + _cairo_glitz_surface_create_similar (abstract_dst, + CAIRO_FORMAT_ARGB32, 0, + pattern->n_stops, 1); + if (generic_src == NULL) { + free (params); + return CAIRO_STATUS_NO_MEMORY; + } + + src = (cairo_glitz_surface_t *) generic_src; + + for (i = 0; i < pattern->n_stops; i++) { + glitz_color_t color; + + color.alpha = pattern->stops[i].color_char[3]; + color.red = pattern->stops[i].color_char[0] * color.alpha; + color.green = pattern->stops[i].color_char[1] * color.alpha; + color.blue = pattern->stops[i].color_char[2] * color.alpha; + color.alpha *= 256; + + glitz_set_rectangle (src->surface, &color, i, 0, 1, 1); + + params[4 + 3 * i] = pattern->stops[i].offset; + params[5 + 3 * i] = i << 16; + params[6 + 3 * i] = 0; + } + + if (pattern->type == CAIRO_PATTERN_LINEAR) { + params[0] = _cairo_fixed_from_double (pattern->u.linear.point0.x); + params[1] = _cairo_fixed_from_double (pattern->u.linear.point0.y); + params[2] = _cairo_fixed_from_double (pattern->u.linear.point1.x); + params[3] = _cairo_fixed_from_double (pattern->u.linear.point1.y); + + glitz_surface_set_filter (src->surface, + GLITZ_FILTER_LINEAR_GRADIENT, + params, n_params); + } else { + params[0] = _cairo_fixed_from_double (pattern->u.radial.center0.x); + params[1] = _cairo_fixed_from_double (pattern->u.radial.center0.y); + params[2] = _cairo_fixed_from_double (pattern->u.radial.radius0); + params[3] = _cairo_fixed_from_double (pattern->u.radial.radius1); + + glitz_surface_set_filter (src->surface, + GLITZ_FILTER_RADIAL_GRADIENT, + params, n_params); + } + + switch (pattern->extend) { + case CAIRO_EXTEND_REPEAT: + glitz_surface_set_fill (src->surface, GLITZ_FILL_REPEAT); + break; + case CAIRO_EXTEND_REFLECT: + glitz_surface_set_fill (src->surface, GLITZ_FILL_REFLECT); + break; + case CAIRO_EXTEND_NONE: + default: + glitz_surface_set_fill (src->surface, GLITZ_FILL_NEAREST); + break; + } + + cairo_surface_set_matrix (&src->base, &pattern->matrix); + + free (params); + } break; + case CAIRO_PATTERN_SURFACE: + generic_src = pattern->u.surface.surface; + cairo_surface_reference (generic_src); + break; + } + + if (generic_src == NULL) { + image = _cairo_pattern_get_image (pattern, box); + if (image == NULL) + return CAIRO_STATUS_NO_MEMORY; + + generic_src = &image->base; + } + + if (generic_src->backend != dst->base.backend) { + src = _cairo_glitz_surface_clone_similar (dst, generic_src, + CAIRO_FORMAT_ARGB32); + if (src == NULL) + return CAIRO_STATUS_NO_MEMORY; + + cairo_surface_set_repeat (&src->base, generic_src->repeat); + } else + src = (cairo_glitz_surface_t *) generic_src; + + if (image) + cairo_surface_destroy (&image->base); + + _cairo_pattern_init_copy (&src->pattern, pattern); + src->pattern_box = *box; + + pattern->source = &src->base; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_glitz_surface_set_clip_region (void *abstract_surface, + pixman_region16_t *region) +{ + return CAIRO_INT_STATUS_UNSUPPORTED; +} + +static const struct cairo_surface_backend cairo_glitz_surface_backend = { + _cairo_glitz_surface_create_similar, + _cairo_glitz_surface_destroy, + _cairo_glitz_surface_pixels_per_inch, + _cairo_glitz_surface_get_image, + _cairo_glitz_surface_set_image, + _cairo_glitz_surface_set_matrix, + _cairo_glitz_surface_set_filter, + _cairo_glitz_surface_set_repeat, + _cairo_glitz_surface_composite, + _cairo_glitz_surface_fill_rectangles, + _cairo_glitz_surface_composite_trapezoids, + _cairo_glitz_surface_copy_page, + _cairo_glitz_surface_show_page, + _cairo_glitz_surface_set_clip_region, + _cairo_glitz_surface_create_pattern, + NULL /* show_glyphs */ +}; + +cairo_surface_t * +cairo_glitz_surface_create (glitz_surface_t *surface) +{ + cairo_glitz_surface_t *crsurface; + + if (!surface) + return NULL; + + crsurface = malloc (sizeof (cairo_glitz_surface_t)); + if (crsurface == NULL) + return NULL; + + _cairo_surface_init (&crsurface->base, &cairo_glitz_surface_backend); + + crsurface->surface = surface; + crsurface->features = glitz_surface_get_features (surface); + crsurface->format = glitz_surface_get_format (surface); + + _cairo_pattern_init (&crsurface->pattern); + crsurface->pattern.type = CAIRO_PATTERN_SURFACE; + crsurface->pattern.u.surface.surface = NULL; + + return (cairo_surface_t *) crsurface; +} diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c index 563f84b4..9f9de69e 100644 --- a/src/cairo-gstate.c +++ b/src/cairo-gstate.c @@ -1,22 +1,37 @@ /* cairo - a vector graphics library with display and print output * - * Copyright © 2002 University of Southern California + * Copyright © 2002 University of Southern California * * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. * - * This library 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 - * Library General Public License for more details. + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ * - * Author: Carl D. Worth <cworth@isi.edu> + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth <cworth@isi.edu> */ #include <stdlib.h> @@ -62,9 +77,9 @@ _cairo_gstate_init (cairo_gstate_t *gstate) gstate->num_dashes = 0; gstate->dash_offset = 0.0; - gstate->font = _cairo_font_create (CAIRO_FONT_FAMILY_DEFAULT, - CAIRO_FONT_SLANT_DEFAULT, - CAIRO_FONT_WEIGHT_DEFAULT); + gstate->font = _cairo_unscaled_font_create (CAIRO_FONT_FAMILY_DEFAULT, + CAIRO_FONT_SLANT_DEFAULT, + CAIRO_FONT_WEIGHT_DEFAULT); gstate->surface = NULL; @@ -104,11 +119,8 @@ _cairo_gstate_init_copy (cairo_gstate_t *gstate, cairo_gstate_t *other) } if (other->font) { - gstate->font = _cairo_font_copy (other->font); - if (!gstate->font) { - status = CAIRO_STATUS_NO_MEMORY; - goto CLEANUP_DASHES; - } + gstate->font = other->font; + _cairo_unscaled_font_reference (gstate->font); } if (other->clip.region) @@ -134,9 +146,10 @@ _cairo_gstate_init_copy (cairo_gstate_t *gstate, cairo_gstate_t *other) CLEANUP_PATH: _cairo_path_fini (&gstate->path); + CLEANUP_FONT: - cairo_font_destroy (gstate->font); - CLEANUP_DASHES: + _cairo_unscaled_font_destroy (gstate->font); + free (gstate->dash); gstate->dash = NULL; @@ -146,7 +159,7 @@ _cairo_gstate_init_copy (cairo_gstate_t *gstate, cairo_gstate_t *other) void _cairo_gstate_fini (cairo_gstate_t *gstate) { - cairo_font_destroy (gstate->font); + _cairo_unscaled_font_destroy (gstate->font); if (gstate->surface) cairo_surface_destroy (gstate->surface); @@ -162,6 +175,8 @@ _cairo_gstate_fini (cairo_gstate_t *gstate) cairo_pattern_destroy (gstate->pattern); + _cairo_matrix_fini (&gstate->font_matrix); + _cairo_matrix_fini (&gstate->ctm); _cairo_matrix_fini (&gstate->ctm_inverse); @@ -612,6 +627,8 @@ _cairo_gstate_default_matrix (cairo_gstate_t *gstate) if (scale == 0) scale = 1; + cairo_matrix_set_identity (&gstate->font_matrix); + cairo_matrix_set_identity (&gstate->ctm); cairo_matrix_scale (&gstate->ctm, scale, scale); cairo_matrix_copy (&gstate->ctm_inverse, &gstate->ctm); @@ -1968,16 +1985,28 @@ _cairo_gstate_show_surface (cairo_gstate_t *gstate, return CAIRO_STATUS_SUCCESS; } + cairo_status_t _cairo_gstate_select_font (cairo_gstate_t *gstate, const char *family, cairo_font_slant_t slant, cairo_font_weight_t weight) { - if (gstate->font != NULL) - cairo_font_destroy (gstate->font); + cairo_unscaled_font_t *tmp; + + tmp = _cairo_unscaled_font_create (family, slant, weight); + + if (tmp == NULL) + return CAIRO_STATUS_NO_MEMORY; - gstate->font = _cairo_font_create (family, slant, weight); + if (gstate->font != tmp) + { + if (gstate->font != NULL) + _cairo_unscaled_font_destroy (gstate->font); + + cairo_matrix_set_identity (&gstate->font_matrix); + gstate->font = tmp; + } return CAIRO_STATUS_SUCCESS; } @@ -1986,212 +2015,294 @@ cairo_status_t _cairo_gstate_scale_font (cairo_gstate_t *gstate, double scale) { - return _cairo_font_scale (gstate->font, scale); + return cairo_matrix_scale (&gstate->font_matrix, scale, scale); } cairo_status_t _cairo_gstate_transform_font (cairo_gstate_t *gstate, cairo_matrix_t *matrix) { - return _cairo_font_transform (gstate->font, matrix); + cairo_matrix_t tmp; + double a, b, c, d, tx, ty; + cairo_matrix_get_affine (matrix, &a, &b, &c, &d, &tx, &ty); + cairo_matrix_set_affine (&tmp, a, b, c, d, 0, 0); + return cairo_matrix_multiply (&gstate->font_matrix, &gstate->font_matrix, &tmp); } + cairo_status_t _cairo_gstate_current_font (cairo_gstate_t *gstate, cairo_font_t **font) { - *font = gstate->font; + cairo_font_scale_t scale; + cairo_font_t *scaled; + double dummy; + + scaled = malloc (sizeof (cairo_font_t)); + if (scaled == NULL) + return CAIRO_STATUS_NO_MEMORY; + + cairo_matrix_get_affine (&gstate->font_matrix, + &scale.matrix[0][0], + &scale.matrix[0][1], + &scale.matrix[1][0], + &scale.matrix[1][1], + &dummy, &dummy); + + _cairo_font_init (scaled, &scale, gstate->font); + _cairo_unscaled_font_reference (gstate->font); + + *font = scaled; return CAIRO_STATUS_SUCCESS; } -cairo_status_t -_cairo_gstate_current_font_extents (cairo_gstate_t *gstate, - cairo_font_extents_t *extents) +void +_cairo_gstate_set_font_transform (cairo_gstate_t *gstate, + cairo_matrix_t *matrix) { - cairo_int_status_t status; - cairo_matrix_t saved_font_matrix; - - cairo_matrix_copy (&saved_font_matrix, &gstate->font->matrix); - cairo_matrix_multiply (&gstate->font->matrix, &gstate->ctm, &gstate->font->matrix); - - status = _cairo_font_font_extents (gstate->font, extents); - - cairo_matrix_copy (&gstate->font->matrix, &saved_font_matrix); + cairo_matrix_copy (&gstate->font_matrix, matrix); +} - return status; +void +_cairo_gstate_current_font_transform (cairo_gstate_t *gstate, + cairo_matrix_t *matrix) +{ + cairo_matrix_copy (matrix, &gstate->font_matrix); } +/* + * Like everything else in this file, fonts involve Too Many Coordinate Spaces; + * it is easy to get confused about what's going on. + * + * The user's view + * --------------- + * + * Users ask for things in user space. When cairo starts, a user space unit + * is about 1/96 inch, which is similar to (but importantly different from) + * the normal "point" units most users think in terms of. When a user + * selects a font, its scale is set to "one user unit". The user can then + * independently scale the user coordinate system *or* the font matrix, in + * order to adjust the rendered size of the font. + * + * If the user asks for a permanent reference to "a font", they are given a + * handle to a structure holding a scale matrix and an unscaled font. This + * effectively decouples the font from further changes to user space. Even + * if the user then "sets" the current cairo_t font to the handle they were + * passed, further changes to the cairo_t CTM will not affect externally + * held references to the font. + * + * + * The font's view + * --------------- + * + * Fonts are designed and stored (in say .ttf files) in "font space", which + * describes an "EM Square" (a design tile) and has some abstract number + * such as 1000, 1024, or 2048 units per "EM". This is basically an + * uninteresting space for us, but we need to remember that it exists. + * + * Font resources (from libraries or operating systems) render themselves + * to a particular device. Since they do not want to make most programmers + * worry about the font design space, the scaling API is simplified to + * involve just telling the font the required pixel size of the EM square + * (that is, in device space). + * + * + * Cairo's gstate view + * ------------------- + * + * In addition to the CTM and CTM inverse, we keep a matrix in the gstate + * called the "font matrix" which describes the user's most recent + * font-scaling or font-transforming request. This is kept in terms of an + * abstract scale factor, composed with the CTM and used to set the font's + * pixel size. So if the user asks to "scale the font by 12", the matrix + * is: + * + * [ 12.0, 0.0, 0.0, 12.0, 0.0, 0.0 ] + * + * It is an affine matrix, like all cairo matrices, but its tx and ty + * components are always set to zero; we don't permit "nudging" fonts + * around. + * + * In order to perform any action on a font, we must build an object + * called a cairo_font_scale_t; this contains the central 2x2 matrix + * resulting from "font matrix * CTM". + * + * We pass this to the font when making requests of it, which causes it to + * reply for a particular [user request, device] combination, under the CTM + * (to accomodate the "zoom in" == "bigger fonts" issue above). + * + * The other terms in our communication with the font are therefore in + * device space. When we ask it to perform text->glyph conversion, it will + * produce a glyph string in device space. Glyph vectors we pass to it for + * measuring or rendering should be in device space. The metrics which we + * get back from the font will be in device space. The contents of the + * global glyph image cache will be in device space. + * + * + * Cairo's public view + * ------------------- + * + * Since the values entering and leaving via public API calls are in user + * space, the gstate functions typically need to multiply argumens by the + * CTM (for user-input glyph vectors), and return values by the CTM inverse + * (for font responses such as metrics or glyph vectors). + * + */ -cairo_status_t -_cairo_gstate_set_font (cairo_gstate_t *gstate, - cairo_font_t *font) +static void +_build_font_scale (cairo_gstate_t *gstate, + cairo_font_scale_t *sc) { - if (gstate->font != NULL) - cairo_font_destroy (gstate->font); - gstate->font = font; - cairo_font_reference (gstate->font); - return CAIRO_STATUS_SUCCESS; + cairo_matrix_t tmp; + double dummy; + cairo_matrix_multiply (&tmp, &gstate->font_matrix, &gstate->ctm); + cairo_matrix_get_affine (&tmp, + &sc->matrix[0][0], + &sc->matrix[0][1], + &sc->matrix[1][0], + &sc->matrix[1][1], + &dummy, &dummy); } cairo_status_t -_cairo_gstate_text_extents (cairo_gstate_t *gstate, - const unsigned char *utf8, - cairo_text_extents_t *extents) +_cairo_gstate_current_font_extents (cairo_gstate_t *gstate, + cairo_font_extents_t *extents) { - cairo_matrix_t saved_font_matrix; - cairo_status_t status; - double scale_x, scale_y; - - cairo_matrix_copy (&saved_font_matrix, &gstate->font->matrix); - _cairo_matrix_compute_scale_factors (&gstate->ctm, &scale_x, &scale_y); - cairo_matrix_scale (&gstate->font->matrix, scale_x, scale_y); - - status = _cairo_font_text_extents (gstate->font, - utf8, extents); - - cairo_matrix_copy (&gstate->font->matrix, &saved_font_matrix); + cairo_int_status_t status; + cairo_font_scale_t sc; + double dummy = 0.0; - extents->x_bearing /= scale_x; - extents->y_bearing /= scale_y; - extents->width /= scale_x; - extents->height /= scale_y; - extents->x_advance /= scale_x; - extents->y_advance /= scale_y; + _build_font_scale (gstate, &sc); - return status; -} + status = _cairo_unscaled_font_font_extents (gstate->font, &sc, extents); -cairo_status_t -_cairo_gstate_glyph_extents (cairo_gstate_t *gstate, - cairo_glyph_t *glyphs, - int num_glyphs, - cairo_text_extents_t *extents) -{ - cairo_status_t status; - cairo_matrix_t saved_font_matrix; - double scale_x, scale_y; + /* The font responded in device space; convert to user space. */ - cairo_matrix_copy (&saved_font_matrix, &gstate->font->matrix); - _cairo_matrix_compute_scale_factors (&gstate->ctm, &scale_x, &scale_y); - cairo_matrix_scale (&gstate->font->matrix, scale_x, scale_y); + cairo_matrix_transform_distance (&gstate->ctm_inverse, + &dummy, + &extents->ascent); - status = _cairo_font_glyph_extents (gstate->font, - glyphs, num_glyphs, - extents); + cairo_matrix_transform_distance (&gstate->ctm_inverse, + &dummy, + &extents->descent); - cairo_matrix_copy (&gstate->font->matrix, &saved_font_matrix); + cairo_matrix_transform_distance (&gstate->ctm_inverse, + &dummy, + &extents->height); - extents->x_bearing /= scale_x; - extents->y_bearing /= scale_y; - extents->width /= scale_x; - extents->height /= scale_y; - extents->x_advance /= scale_x; - extents->y_advance /= scale_y; + cairo_matrix_transform_distance (&gstate->ctm_inverse, + &extents->max_x_advance, + &extents->max_y_advance); return status; } cairo_status_t -_cairo_gstate_show_text (cairo_gstate_t *gstate, - const unsigned char *utf8) +_cairo_gstate_text_to_glyphs (cairo_gstate_t *gstate, + const unsigned char *utf8, + cairo_glyph_t **glyphs, + int *nglyphs) { cairo_status_t status; - cairo_point_t point; - double x, y; - cairo_matrix_t saved_font_matrix; - cairo_pattern_t pattern; - cairo_box_t bbox; + cairo_font_scale_t sc; + + cairo_point_t point; + double dev_x, dev_y; + int i; + + _build_font_scale (gstate, &sc); status = _cairo_path_current_point (&gstate->path, &point); if (status == CAIRO_STATUS_NO_CURRENT_POINT) { - x = 0; - y = 0; - cairo_matrix_transform_point (&gstate->ctm, &x, &y); + dev_x = 0.0; + dev_y = 0.0; } else { - x = _cairo_fixed_to_double (point.x); - y = _cairo_fixed_to_double (point.y); + dev_x = _cairo_fixed_to_double (point.x); + dev_y = _cairo_fixed_to_double (point.y); } - - cairo_matrix_copy (&saved_font_matrix, &gstate->font->matrix); - cairo_matrix_multiply (&gstate->font->matrix, &gstate->ctm, &gstate->font->matrix); - _cairo_pattern_init_copy (&pattern, gstate->pattern); - - status = _cairo_font_text_bbox (gstate->font, gstate->surface, - x, y, utf8, &bbox); - if (status) - return status; - - status = _cairo_gstate_create_pattern (gstate, &pattern, &bbox); - if (status) + status = _cairo_unscaled_font_text_to_glyphs (gstate->font, + &sc, utf8, glyphs, nglyphs); + + if (status || !glyphs || !nglyphs || !(*glyphs) || !(nglyphs)) return status; - - if (gstate->clip.surface) - { - cairo_surface_t *intermediate; - cairo_color_t empty_color; - _cairo_color_init (&empty_color); - _cairo_color_set_alpha (&empty_color, .0); - intermediate = _cairo_surface_create_similar_solid (gstate->clip.surface, - CAIRO_FORMAT_A8, - gstate->clip.width, - gstate->clip.height, - &empty_color); + /* The font responded in device space, starting from (0,0); add any + current point offset in device space, and convert to user space. */ - status = _cairo_font_show_text (gstate->font, - CAIRO_OPERATOR_ADD, pattern.source, - intermediate, - gstate->clip.x - pattern.source_offset.x, - gstate->clip.y - pattern.source_offset.y, - x - gstate->clip.x, - y - gstate->clip.y, utf8); + for (i = 0; i < *nglyphs; ++i) { + (*glyphs)[i].x += dev_x; + (*glyphs)[i].y += dev_y; + cairo_matrix_transform_point (&gstate->ctm_inverse, + &((*glyphs)[i].x), + &((*glyphs)[i].y)); + } + + return CAIRO_STATUS_SUCCESS; +} - if (status) - goto BAIL; - - status = _cairo_surface_composite (CAIRO_OPERATOR_IN, - gstate->clip.surface, - NULL, - intermediate, - 0, 0, - 0, 0, - 0, 0, - gstate->clip.width, - gstate->clip.height); +cairo_status_t +_cairo_gstate_set_font (cairo_gstate_t *gstate, + cairo_font_t *font) +{ + if (gstate->font != NULL) + _cairo_unscaled_font_destroy (gstate->font); + gstate->font = font->unscaled; + _cairo_unscaled_font_reference (gstate->font); + cairo_matrix_set_affine (&gstate->font_matrix, + font->scale.matrix[0][0], + font->scale.matrix[0][1], + font->scale.matrix[1][0], + font->scale.matrix[1][1], + 0, 0); + return CAIRO_STATUS_SUCCESS; +} - if (status) - goto BAIL; +cairo_status_t +_cairo_gstate_glyph_extents (cairo_gstate_t *gstate, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_text_extents_t *extents) +{ + cairo_status_t status; + cairo_glyph_t *transformed_glyphs; + cairo_font_scale_t sc; + int i; - status = _cairo_surface_composite (gstate->operator, - pattern.source, - intermediate, - gstate->surface, - 0, 0, - 0, 0, - gstate->clip.x, - gstate->clip.y, - gstate->clip.width, - gstate->clip.height); + _build_font_scale (gstate, &sc); - BAIL: - cairo_surface_destroy (intermediate); - - } - else + transformed_glyphs = malloc (num_glyphs * sizeof(cairo_glyph_t)); + if (transformed_glyphs == NULL) + return CAIRO_STATUS_NO_MEMORY; + + for (i = 0; i < num_glyphs; ++i) { - status = _cairo_font_show_text (gstate->font, - gstate->operator, pattern.source, - gstate->surface, - -pattern.source_offset.x, - -pattern.source_offset.y, - x, y, utf8); + transformed_glyphs[i] = glyphs[i]; + cairo_matrix_transform_point (&gstate->ctm, + &transformed_glyphs[i].x, + &transformed_glyphs[i].y); } - - cairo_matrix_copy (&gstate->font->matrix, &saved_font_matrix); - _cairo_pattern_fini (&pattern); + status = _cairo_unscaled_font_glyph_extents (gstate->font, &sc, + transformed_glyphs, num_glyphs, + extents); + + /* The font responded in device space; convert to user space. */ + + cairo_matrix_transform_distance (&gstate->ctm_inverse, + &extents->x_bearing, + &extents->y_bearing); + + cairo_matrix_transform_distance (&gstate->ctm_inverse, + &extents->width, + &extents->height); + + cairo_matrix_transform_distance (&gstate->ctm_inverse, + &extents->x_advance, + &extents->y_advance); + + free (transformed_glyphs); return status; } @@ -2202,12 +2313,14 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate, int num_glyphs) { cairo_status_t status; - cairo_matrix_t saved_font_matrix; int i; cairo_glyph_t *transformed_glyphs = NULL; + cairo_font_scale_t sc; cairo_pattern_t pattern; cairo_box_t bbox; + _build_font_scale (gstate, &sc); + transformed_glyphs = malloc (num_glyphs * sizeof(cairo_glyph_t)); if (transformed_glyphs == NULL) return CAIRO_STATUS_NO_MEMORY; @@ -2216,16 +2329,14 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate, { transformed_glyphs[i] = glyphs[i]; cairo_matrix_transform_point (&gstate->ctm, - &(transformed_glyphs[i].x), - &(transformed_glyphs[i].y)); + &transformed_glyphs[i].x, + &transformed_glyphs[i].y); } - cairo_matrix_copy (&saved_font_matrix, &gstate->font->matrix); - cairo_matrix_multiply (&gstate->font->matrix, &gstate->ctm, &gstate->font->matrix); - _cairo_pattern_init_copy (&pattern, gstate->pattern); - status = _cairo_font_glyph_bbox (gstate->font, gstate->surface, - transformed_glyphs, num_glyphs, &bbox); + status = _cairo_unscaled_font_glyph_bbox (gstate->font, &sc, + transformed_glyphs, num_glyphs, + &bbox); if (status) return status; @@ -2253,12 +2364,13 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate, transformed_glyphs[i].y -= gstate->clip.y; } - status = _cairo_font_show_glyphs (gstate->font, - CAIRO_OPERATOR_ADD, - pattern.source, intermediate, - gstate->clip.x - pattern.source_offset.x, - gstate->clip.y - pattern.source_offset.y, - transformed_glyphs, num_glyphs); + status = _cairo_unscaled_font_show_glyphs (gstate->font, + &sc, + CAIRO_OPERATOR_ADD, + pattern.source, intermediate, + gstate->clip.x - pattern.source_offset.x, + gstate->clip.y - pattern.source_offset.y, + transformed_glyphs, num_glyphs); if (status) goto BAIL; @@ -2293,16 +2405,15 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate, } else { - status = _cairo_font_show_glyphs (gstate->font, - gstate->operator, pattern.source, - gstate->surface, - -pattern.source_offset.x, - -pattern.source_offset.y, - transformed_glyphs, num_glyphs); + status = _cairo_unscaled_font_show_glyphs (gstate->font, + &sc, + gstate->operator, pattern.source, + gstate->surface, + -pattern.source_offset.x, + -pattern.source_offset.y, + transformed_glyphs, num_glyphs); } - cairo_matrix_copy (&gstate->font->matrix, &saved_font_matrix); - _cairo_pattern_fini (&pattern); free (transformed_glyphs); @@ -2310,40 +2421,6 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate, return status; } - -cairo_status_t -_cairo_gstate_text_path (cairo_gstate_t *gstate, - const unsigned char *utf8) -{ - cairo_status_t status; - cairo_matrix_t saved_font_matrix; - cairo_point_t point; - double x, y; - - status = _cairo_path_current_point (&gstate->path, &point); - if (status == CAIRO_STATUS_NO_CURRENT_POINT) { - x = 0; - y = 0; - cairo_matrix_transform_point (&gstate->ctm, &x, &y); - } else { - x = _cairo_fixed_to_double (point.x); - y = _cairo_fixed_to_double (point.y); - } - - cairo_matrix_copy (&saved_font_matrix, &gstate->font->matrix); - cairo_matrix_multiply (&gstate->font->matrix, &gstate->ctm, &gstate->font->matrix); - - status = _cairo_font_text_path (gstate->font, - x, y, - utf8, - &gstate->path); - - cairo_matrix_copy (&gstate->font->matrix, &saved_font_matrix); - - return status; -} - - cairo_status_t _cairo_gstate_glyph_path (cairo_gstate_t *gstate, cairo_glyph_t *glyphs, @@ -2352,7 +2429,9 @@ _cairo_gstate_glyph_path (cairo_gstate_t *gstate, cairo_status_t status; int i; cairo_glyph_t *transformed_glyphs = NULL; - cairo_matrix_t saved_font_matrix; + cairo_font_scale_t sc; + + _build_font_scale (gstate, &sc); transformed_glyphs = malloc (num_glyphs * sizeof(cairo_glyph_t)); if (transformed_glyphs == NULL) @@ -2366,14 +2445,9 @@ _cairo_gstate_glyph_path (cairo_gstate_t *gstate, &(transformed_glyphs[i].y)); } - cairo_matrix_copy (&saved_font_matrix, &gstate->font->matrix); - cairo_matrix_multiply (&gstate->font->matrix, &gstate->ctm, &gstate->font->matrix); - - status = _cairo_font_glyph_path (gstate->font, - transformed_glyphs, num_glyphs, - &gstate->path); - - cairo_matrix_copy (&gstate->font->matrix, &saved_font_matrix); + status = _cairo_unscaled_font_glyph_path (gstate->font, &sc, + transformed_glyphs, num_glyphs, + &gstate->path); free (transformed_glyphs); return status; diff --git a/src/cairo-hash.c b/src/cairo-hash.c new file mode 100644 index 00000000..a33d69a0 --- /dev/null +++ b/src/cairo-hash.c @@ -0,0 +1,454 @@ +/* cairo - a vector graphics library with display and print output + * + * This file is Copyright © 2004 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Contributor(s): + * Keith Packard + * Graydon Hoare <graydon@redhat.com> + */ + +#include "cairoint.h" + +/* + * This structure, and accompanying table, is borrowed/modified from the + * file xserver/render/glyph.c in the freedesktop.org x server, with + * permission (and suggested modification of doubling sizes) by Keith + * Packard. + */ + +static cairo_cache_arrangement_t cache_arrangements [] = { + { 16, 43, 41 }, + { 32, 73, 71 }, + { 64, 151, 149 }, + { 128, 283, 281 }, + { 256, 571, 569 }, + { 512, 1153, 1151 }, + { 1024, 2269, 2267 }, + { 2048, 4519, 4517 }, + { 4096, 9013, 9011 }, + { 8192, 18043, 18041 }, + { 16384, 36109, 36107 }, + { 32768, 72091, 72089 }, + { 65536, 144409, 144407 }, + { 131072, 288361, 288359 }, + { 262144, 576883, 576881 }, + { 524288, 1153459, 1153457 }, + { 1048576, 2307163, 2307161 }, + { 2097152, 4613893, 4613891 }, + { 4194304, 9227641, 9227639 }, + { 8388608, 18455029, 18455027 }, + { 16777216, 36911011, 36911009 }, + { 33554432, 73819861, 73819859 }, + { 67108864, 147639589, 147639587 }, + { 134217728, 295279081, 295279079 }, + { 268435456, 590559793, 590559791 } +}; + +#define N_CACHE_SIZES (sizeof(cache_arrangements)/sizeof(cache_arrangements[0])) + +/* + * Entries 'e' are poiners, in one of 3 states: + * + * e == NULL: The entry has never had anything put in it + * e != DEAD_ENTRY: The entry has an active value in it currently + * e == DEAD_ENTRY: The entry *had* a value in it at some point, but the + * entry has been killed. Lookups requesting free space can + * reuse these entries; lookups requesting a precise match + * should neither return these entries nor stop searching when + * seeing these entries. + * + * We expect keys will not be destroyed frequently, so our table does not + * contain any explicit shrinking code nor any chain-coalescing code for + * entries randomly deleted by memory pressure (except during rehashing, of + * course). These assumptions are potentially bad, but they make the + * implementation straightforward. + * + * Revisit later if evidence appears that we're using excessive memory from + * a mostly-dead table. + * + * Generally you do not need to worry about freeing cache entries; the + * cache will expire entries randomly as it experiences memory pressure. + * There is currently no explicit entry-removing call, though one can be + * added easily. + * + * This table is open-addressed with double hashing. Each table size is a + * prime chosen to be a little more than double the high water mark for a + * given arrangement, so the tables should remain < 50% full. The table + * size makes for the "first" hash modulus; a second prime (2 less than the + * first prime) serves as the "second" hash modulus, which is co-prime and + * thus guarantees a complete permutation of table indices. + * + */ + +#define DEAD_ENTRY ((cairo_cache_entry_base_t *) 1) +#define NULL_ENTRY_P(cache, i) ((cache)->entries[i] == NULL) +#define DEAD_ENTRY_P(cache, i) ((cache)->entries[i] == DEAD_ENTRY) +#define LIVE_ENTRY_P(cache, i) \ + (!((NULL_ENTRY_P((cache),(i))) || (DEAD_ENTRY_P((cache),(i))))) + +#ifdef CAIRO_DO_SANITY_CHECKING +#include <assert.h> +static void +_cache_sane_state (cairo_cache_t *cache) +{ + assert (cache != NULL); + assert (cache->entries != NULL); + assert (cache->backend != NULL); + assert (cache->arrangement != NULL); + assert (cache->refcount > 0); + assert (cache->used_memory <= cache->max_memory); + assert (cache->live_entries <= cache->arrangement->size); +} +#else +#define _cache_sane_state(c) +#define assert(x) +#endif + +static void +_entry_destroy (cairo_cache_t *cache, unsigned long i) +{ + _cache_sane_state (cache); + + if (LIVE_ENTRY_P(cache, i)) + { + cairo_cache_entry_base_t *entry = cache->entries[i]; + assert(cache->live_entries > 0); + assert(cache->used_memory > entry->memory); + + cache->live_entries--; + cache->used_memory -= entry->memory; + cache->backend->destroy_entry (cache, entry); + cache->entries[i] = DEAD_ENTRY; + } +} + +static cairo_cache_entry_base_t ** +_cache_lookup (cairo_cache_t *cache, + void *key, + int (*predicate)(void*,void*,void*)) +{ + + cairo_cache_entry_base_t **probe; + unsigned long hash; + unsigned long table_size, i, idx, step; + + _cache_sane_state (cache); + assert (key != NULL); + + table_size = cache->arrangement->size; + hash = cache->backend->hash (cache, key); + idx = hash % table_size; + step = 0; + + for (i = 0; i < table_size; ++i) + { +#ifdef CAIRO_MEASURE_CACHE_PERFORMANCE + cache->probes++; +#endif + assert(idx < table_size); + probe = cache->entries + idx; + + /* + * There are two lookup modes: searching for a free slot and searching + * for an exact entry. + */ + + if (predicate != NULL) + { + /* We are looking up an exact entry. */ + if (*probe != NULL + && *probe != DEAD_ENTRY + && (*probe)->hashcode == hash + && predicate (cache, key, *probe)) + return probe; + } + else + { + /* We are just looking for a free slot. */ + if (*probe == NULL + || *probe == DEAD_ENTRY) + return probe; + } + + if (step == 0) { + step = hash % cache->arrangement->rehash; + if (step == 0) + step = 1; + } + + idx += step; + if (idx >= table_size) + idx -= table_size; + } + + /* + * The table should not have permitted you to get here if you were just + * looking for a free slot: there should have been room. + */ + assert(predicate != NULL); + return NULL; +} + +static cairo_cache_entry_base_t ** +_find_available_entry_for (cairo_cache_t *cache, + void *key) +{ + return _cache_lookup (cache, key, NULL); +} + +static cairo_cache_entry_base_t ** +_find_exact_live_entry_for (cairo_cache_t *cache, + void *key) +{ + return _cache_lookup (cache, key, cache->backend->keys_equal); +} + + +static cairo_cache_arrangement_t * +_find_cache_arrangement (unsigned long proposed_size) +{ + unsigned long idx; + + for (idx = 0; idx < N_CACHE_SIZES; ++idx) + if (cache_arrangements[idx].high_water_mark >= proposed_size) + return &cache_arrangements[idx]; + return NULL; +} + +static cairo_status_t +_resize_cache (cairo_cache_t *cache, unsigned long proposed_size) +{ + cairo_cache_t tmp; + cairo_cache_entry_base_t **e; + unsigned long new_size, i; + + tmp = *cache; + tmp.arrangement = _find_cache_arrangement (proposed_size); + assert(tmp.arrangement != NULL); + if (tmp.arrangement == cache->arrangement) + return CAIRO_STATUS_SUCCESS; + + new_size = tmp.arrangement->size; + tmp.entries = calloc (new_size, sizeof (cairo_cache_entry_base_t *)); + if (tmp.entries == NULL) + return CAIRO_STATUS_NO_MEMORY; + + for (i = 0; i < cache->arrangement->size; ++i) { + if (LIVE_ENTRY_P(cache, i)) { + e = _find_available_entry_for (&tmp, cache->entries[i]); + assert (e != NULL); + *e = cache->entries[i]; + } + } + free (cache->entries); + cache->entries = tmp.entries; + cache->arrangement = tmp.arrangement; + return CAIRO_STATUS_SUCCESS; +} + + +#ifdef CAIRO_MEASURE_CACHE_PERFORMANCE +static double +_load_factor (cairo_cache_t *cache) +{ + return ((double) cache->live_entries) + / ((double) cache->arrangement->size); +} +#endif + +static unsigned long +_random_live_entry (cairo_cache_t *cache) +{ + unsigned long idx; + assert(cache != NULL); + do { + idx = rand () % cache->arrangement->size; + } while (! LIVE_ENTRY_P(cache, idx)); + return idx; +} + + +/* public API follows */ + +cairo_status_t +_cairo_cache_init (cairo_cache_t *cache, + const cairo_cache_backend_t *backend, + unsigned long max_memory) +{ + assert(backend != NULL); + + if (cache != NULL){ + cache->arrangement = &cache_arrangements[0]; + cache->refcount = 1; + cache->max_memory = max_memory; + cache->used_memory = 0; + cache->live_entries = 0; + +#ifdef CAIRO_MEASURE_CACHE_PERFORMANCE + cache->hits = 0; + cache->misses = 0; + cache->probes = 0; +#endif + + cache->backend = backend; + cache->entries = calloc (sizeof(cairo_cache_entry_base_t *), + cache->arrangement->size); + if (cache->entries == NULL) + return CAIRO_STATUS_NO_MEMORY; + } + _cache_sane_state (cache); + return CAIRO_STATUS_SUCCESS; +} + +void +_cairo_cache_reference (cairo_cache_t *cache) +{ + _cache_sane_state (cache); + cache->refcount++; +} + +void +_cairo_cache_destroy (cairo_cache_t *cache) +{ + unsigned long i; + if (cache != NULL) { + + _cache_sane_state (cache); + + if (cache->refcount-- > 0) + return; + + for (i = 0; i < cache->arrangement->size; ++i) { + _entry_destroy (cache, i); + } + + free (cache->entries); + cache->entries = NULL; + cache->backend->destroy_cache (cache); + } +} + +cairo_status_t +_cairo_cache_lookup (cairo_cache_t *cache, + void *key, + void **entry_return) +{ + + unsigned long idx; + cairo_status_t status = CAIRO_STATUS_SUCCESS; + cairo_cache_entry_base_t **slot = NULL, *new_entry; + + _cache_sane_state (cache); + +#ifdef CAIRO_MEASURE_CACHE_PERFORMANCE + if ((cache->hits + cache->misses) % 0xffff == 0) + printf("cache %p stats: size %ld, live %ld, load %.2f\n" + " mem %ld/%ld, hit %ld, miss %ld\n" + " probe %ld, %.2f probe/access\n", + cache, + cache->arrangement->size, + cache->live_entries, + _load_factor (cache), + cache->used_memory, + cache->max_memory, + cache->hits, + cache->misses, + cache->probes, + ((double) cache->probes) + / ((double) (cache->hits + + cache->misses + 1))); +#endif + + /* See if we have an entry in the table already. */ + slot = _find_exact_live_entry_for (cache, key); + if (slot != NULL) { +#ifdef CAIRO_MEASURE_CACHE_PERFORMANCE + cache->hits++; +#endif + *entry_return = *slot; + return status; + } + +#ifdef CAIRO_MEASURE_CACHE_PERFORMANCE + cache->misses++; +#endif + + /* Build the new entry. */ + status = cache->backend->create_entry (cache, key, + entry_return); + if (status != CAIRO_STATUS_SUCCESS) + return status; + + new_entry = (cairo_cache_entry_base_t *) (*entry_return); + + /* Store the hash value in case the backend forgot. */ + new_entry->hashcode = cache->backend->hash (cache, key); + + /* Make some entries die if we're under memory pressure. */ + while (cache->live_entries > 0 && + ((cache->max_memory - cache->used_memory) < new_entry->memory)) { + idx = _random_live_entry (cache); + assert (idx < cache->arrangement->size); + _entry_destroy (cache, idx); + } + + assert(cache->max_memory >= (cache->used_memory + new_entry->memory)); + + /* Make room in the table for a new slot. */ + status = _resize_cache (cache, cache->live_entries + 1); + if (status != CAIRO_STATUS_SUCCESS) { + cache->backend->destroy_entry (cache, new_entry); + *entry_return = NULL; + return status; + } + + slot = _find_available_entry_for (cache, key); + assert(slot != NULL); + + /* Store entry in slot and increment statistics. */ + *slot = new_entry; + cache->live_entries++; + cache->used_memory += new_entry->memory; + + _cache_sane_state (cache); + + return status; +} + +unsigned long +_cairo_hash_string (const char *c) +{ + /* This is the djb2 hash. */ + unsigned long hash = 5381; + while (*c) + hash = ((hash << 5) + hash) + *c++; + return hash; +} + diff --git a/src/cairo-hull.c b/src/cairo-hull.c index 93115e6a..99b16d1a 100644 --- a/src/cairo-hull.c +++ b/src/cairo-hull.c @@ -1,22 +1,37 @@ /* cairo - a vector graphics library with display and print output * - * Copyright © 2003 University of Southern California + * Copyright © 2003 University of Southern California * * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. * - * This library 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 - * Library General Public License for more details. + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ * - * Author: Carl D. Worth <cworth@isi.edu> + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth <cworth@isi.edu> */ #include "cairoint.h" @@ -82,10 +97,13 @@ _cairo_hull_vertex_compare (const void *av, const void *bv) (cairo_fixed_48_16_t) a->slope.dy * a->slope.dy); b_dist = ((cairo_fixed_48_16_t) b->slope.dx * b->slope.dx + (cairo_fixed_48_16_t) b->slope.dy * b->slope.dy); - if (a_dist < b_dist) + if (a_dist < b_dist) { a->discard = 1; - else + ret = -1; + } else { b->discard = 1; + ret = 1; + } } return ret; diff --git a/src/cairo-image-surface.c b/src/cairo-image-surface.c index c8e05804..cbdc018a 100644 --- a/src/cairo-image-surface.c +++ b/src/cairo-image-surface.c @@ -1,22 +1,37 @@ /* cairo - a vector graphics library with display and print output * - * Copyright © 2003 University of Southern California + * Copyright © 2003 University of Southern California * * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. * - * This library 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 - * Library General Public License for more details. + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ * - * Author: Carl D. Worth <cworth@isi.edu> + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth <cworth@isi.edu> */ #include "cairoint.h" @@ -457,7 +472,20 @@ cairo_int_status_t _cairo_image_surface_set_clip_region (cairo_image_surface_t *surface, pixman_region16_t *region) { - pixman_image_set_clip_region (surface->pixman_image, region); + if (region) { + pixman_region16_t *rcopy; + + rcopy = pixman_region_create(); + /* pixman_image_set_clip_region expects to take ownership of the + * passed-in region, so we create a copy to give it. */ + /* XXX: I think that's probably a bug in pixman. But its + * memory management issues need auditing anyway, so a + * workaround like this is fine for now. */ + pixman_region_copy (rcopy, region); + pixman_image_set_clip_region (surface->pixman_image, rcopy); + } else { + pixman_image_set_clip_region (surface->pixman_image, region); + } return CAIRO_STATUS_SUCCESS; } @@ -497,5 +525,6 @@ static const cairo_surface_backend_t cairo_image_surface_backend = { _cairo_image_surface_copy_page, _cairo_image_surface_show_page, _cairo_image_abstract_surface_set_clip_region, - _cairo_image_abstract_surface_create_pattern + _cairo_image_abstract_surface_create_pattern, + NULL /* show_glyphs */ }; diff --git a/src/cairo-matrix.c b/src/cairo-matrix.c index 82b042f3..7fc2694f 100644 --- a/src/cairo-matrix.c +++ b/src/cairo-matrix.c @@ -1,22 +1,37 @@ /* cairo - a vector graphics library with display and print output * - * Copyright © 2002 University of Southern California + * Copyright © 2002 University of Southern California * * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. * - * This library 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 - * Library General Public License for more details. + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ * - * Author: Carl D. Worth <cworth@isi.edu> + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth <cworth@isi.edu> */ #include <stdlib.h> diff --git a/src/cairo-path-bounds.c b/src/cairo-path-bounds.c index 5795c5b1..cfcdd97e 100644 --- a/src/cairo-path-bounds.c +++ b/src/cairo-path-bounds.c @@ -1,22 +1,37 @@ /* cairo - a vector graphics library with display and print output * - * Copyright © 2003 University of Southern California + * Copyright © 2003 University of Southern California * * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. * - * This library 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 - * Library General Public License for more details. + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ * - * Author: Carl D. Worth <cworth@isi.edu> + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth <cworth@isi.edu> */ #include "cairoint.h" diff --git a/src/cairo-path-fill.c b/src/cairo-path-fill.c index fdb67bc4..6c6ebd97 100644 --- a/src/cairo-path-fill.c +++ b/src/cairo-path-fill.c @@ -1,22 +1,37 @@ /* cairo - a vector graphics library with display and print output * - * Copyright © 2002 University of Southern California + * Copyright © 2002 University of Southern California * * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. * - * This library 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 - * Library General Public License for more details. + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ * - * Author: Carl D. Worth <cworth@isi.edu> + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth <cworth@isi.edu> */ #include "cairoint.h" diff --git a/src/cairo-path-stroke.c b/src/cairo-path-stroke.c index bb704f15..ad022037 100644 --- a/src/cairo-path-stroke.c +++ b/src/cairo-path-stroke.c @@ -1,22 +1,37 @@ /* cairo - a vector graphics library with display and print output * - * Copyright © 2002 University of Southern California + * Copyright © 2002 University of Southern California * * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. * - * This library 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 - * Library General Public License for more details. + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ * - * Author: Carl D. Worth <cworth@isi.edu> + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth <cworth@isi.edu> */ #include "cairoint.h" diff --git a/src/cairo-path.c b/src/cairo-path.c index 31d9f250..36c25d63 100644 --- a/src/cairo-path.c +++ b/src/cairo-path.c @@ -1,22 +1,37 @@ /* cairo - a vector graphics library with display and print output * - * Copyright © 2002 University of Southern California + * Copyright © 2002 University of Southern California * * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. * - * This library 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 - * Library General Public License for more details. + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ * - * Author: Carl D. Worth <cworth@isi.edu> + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth <cworth@isi.edu> */ #include <stdlib.h> diff --git a/src/cairo-pattern.c b/src/cairo-pattern.c index e1001372..6cb98145 100644 --- a/src/cairo-pattern.c +++ b/src/cairo-pattern.c @@ -1,6 +1,6 @@ /* cairo - a vector graphics library with display and print output * - * Copyright © 2004 David Reveman + * Copyright © 2004 David Reveman * * Permission to use, copy, modify, distribute, and sell this software * and its documentation for any purpose is hereby granted without diff --git a/src/cairo-pen.c b/src/cairo-pen.c index c91e97d6..f365091d 100644 --- a/src/cairo-pen.c +++ b/src/cairo-pen.c @@ -1,28 +1,43 @@ /* cairo - a vector graphics library with display and print output * - * Copyright © 2002 University of Southern California + * Copyright © 2002 University of Southern California * * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. * - * This library 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 - * Library General Public License for more details. + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ * - * Author: Carl D. Worth <cworth@isi.edu> + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth <cworth@isi.edu> */ #include "cairoint.h" static int -_cairo_pen_vertices_needed (double radius, double tolerance, double expansion); +_cairo_pen_vertices_needed (double tolerance, double radius, cairo_matrix_t *matrix); static void _cairo_pen_compute_slopes (cairo_pen_t *pen); @@ -46,7 +61,7 @@ _cairo_pen_init (cairo_pen_t *pen, double radius, cairo_gstate_t *gstate) { int i; int reflect; - double det, expansion; + double det; if (pen->num_vertices) { /* XXX: It would be nice to notice that the pen is already properly constructed. @@ -61,24 +76,17 @@ _cairo_pen_init (cairo_pen_t *pen, double radius, cairo_gstate_t *gstate) pen->radius = radius; pen->tolerance = gstate->tolerance; - /* The determinant represents the area expansion factor of the - transform. In the worst case, this is entirely in one - dimension, which is what we assume here. */ - _cairo_matrix_compute_determinant (&gstate->ctm, &det); if (det >= 0) { reflect = 0; - expansion = det; } else { reflect = 1; - expansion = -det; } - - pen->num_vertices = _cairo_pen_vertices_needed (radius, gstate->tolerance, expansion); - /* number of vertices must be even */ - if (pen->num_vertices % 2) - pen->num_vertices++; + pen->num_vertices = _cairo_pen_vertices_needed (gstate->tolerance, + radius, + &gstate->ctm); + pen->vertices = malloc (pen->num_vertices * sizeof (cairo_pen_vertex_t)); if (pen->vertices == NULL) { return CAIRO_STATUS_NO_MEMORY; @@ -156,17 +164,253 @@ _cairo_pen_add_points (cairo_pen_t *pen, cairo_point_t *point, int num_points) return CAIRO_STATUS_SUCCESS; } +/* +The circular pen in user space is transformed into an ellipse in +device space. + +We construct the pen by computing points along the circumference +using equally spaced angles. + +We show below that this approximation to the ellipse has +maximum error at the major axis of the ellipse. +So, we need to compute the length of the major axis and then +use that to compute the number of sides needed in our pen. + +Thanks to Walter Brisken <wbrisken@aoc.nrao.edu> for this +derivation: + +1. First some notation: + +All capital letters represent vectors in two dimensions. A prime ' +represents a transformed coordinate. Matrices are written in underlined +form, ie _R_. Lowercase letters represent scalar real values. + +The letter t is used to represent the greek letter theta. + +2. The question has been posed: What is the maximum expansion factor +achieved by the linear transformation + +X' = _R_ X + +where _R_ is a real-valued 2x2 matrix with entries: + +_R_ = [a b] + [c d] . + +In other words, what is the maximum radius, MAX[ |X'| ], reached for any +X on the unit circle ( |X| = 1 ) ? + + +3. Some useful formulae + +(A) through (C) below are standard double-angle formulae. (D) is a lesser +known result and is derived below: + +(A) sin^2(t) = (1 - cos(2*t))/2 +(B) cos^2(t) = (1 + cos(2*t))/2 +(C) sin(t)*cos(t) = sin(2*t)/2 +(D) MAX[a*cos(t) + b*sin(t)] = sqrt(a^2 + b^2) + +Proof of (D): + +find the maximum of the function by setting the derivative to zero: + + -a*sin(t)+b*cos(t) = 0 + +From this it follows that + + tan(t) = b/a + +and hence + + sin(t) = b/sqrt(a^2 + b^2) + +and + + cos(t) = a/sqrt(a^2 + b^2) + +Thus the maximum value is + + MAX[a*cos(t) + b*sin(t)] = (a^2 + b^2)/sqrt(a^2 + b^2) + = sqrt(a^2 + b^2) + + +4. Derivation of maximum expansion + +To find MAX[ |X'| ] we search brute force method using calculus. The unit +circle on which X is constrained is to be parameterized by t: + + X(t) = (cos(t), sin(t)) + +Thus + + X'(t) = (a*cos(t) + b*sin(t), c*cos(t) + d*sin(t)) . + +Define + + r(t) = |X'(t)| + +Thus + + r^2(t) = (a*cos(t) + b*sin(t))^2 + (c*cos(t) + d*sin(t))^2 + = (a^2 + c^2)*cos^2(t) + (b^2 + d^2)*sin^2(t) + + 2*(a*b + c*d)*cos(t)*sin(t) + +Now apply the double angle formulae (A) to (C) from above: + + r^2(t) = (a^2 + b^2 + c^2 + d^2)/2 + + (a^2 - b^2 + c^2 - d^2)*cos(2*t)/2 + + (a*b + c*d)*sin(2*t) + = f + g*cos(u) + h*sin(u) + +Where + + f = (a^2 + b^2 + c^2 + d^2)/2 + g = (a^2 - b^2 + c^2 - d^2)/2 + h = (a*b + c*d) + u = 2*t + +It is clear that MAX[ |X'| ] = sqrt(MAX[ r^2 ]). Here we determine MAX[ r^2 ] +using (D) from above: + + MAX[ r^2 ] = f + sqrt(g^2 + h^2) + +And finally + + MAX[ |X'| ] = sqrt( f + sqrt(g^2 + h^2) ) + +Which is the solution to this problem. + + +Walter Brisken +2004/10/08 + +(Note that the minor axis length is at the minimum of the above solution, +which is just sqrt (f - sqrt (g^2 + h^2)) given the symmetry of (D)). + +Now to compute how many sides to use for the pen formed by +a regular polygon. + +Set + + M = major axis length (computed by above formula) + m = minor axis length (computed by above formula) + +Align 'M' along the X axis and 'm' along the Y axis and draw +an ellipse parameterized by angle 't': + + x = M cos t y = m sin t + +Perturb t by ± d and compute two new points (x+,y+), (x-,y-). +The distance from the average of these two points to (x,y) represents +the maximum error in approximating the ellipse with a polygon formed +from vertices 2∆ radians apart. + + x+ = M cos (t+∆) y+ = m sin (t+∆) + x- = M cos (t-∆) y- = m sin (t-∆) + +Now compute the approximation error, E: + + Ex = (x - (x+ + x-) / 2) + Ex = (M cos(t) - (Mcos(t+∆) + Mcos(t-∆))/2) + = M (cos(t) - (cos(t)cos(∆) + sin(t)sin(∆) + + cos(t)cos(∆) - sin(t)sin(∆))/2) + = M(cos(t) - cos(t)cos(∆)) + = M cos(t) (1 - cos(∆)) + + Ey = y - (y+ - y-) / 2 + = m sin (t) - (m sin(t+∆) + m sin(t-∆)) / 2 + = m (sin(t) - (sin(t)cos(∆) + cos(t)sin(∆) + + sin(t)cos(∆) - cos(t)sin(∆))/2) + = m (sin(t) - sin(t)cos(∆)) + = m sin(t) (1 - cos(∆)) + + E² = Ex² + Ey² + = (M cos(t) (1 - cos (∆)))² + (m sin(t) (1-cos(∆)))² + = (1 - cos(∆))² (M² cos²(t) + m² sin²(t)) + = (1 - cos(∆))² ((m² + M² - m²) cos² (t) + m² sin²(t)) + = (1 - cos(∆))² (M² - m²) cos² (t) + (1 - cos(∆))² m² + +Find the extremum by differentiation wrt t and setting that to zero + +∂(E²)/∂(t) = (1-cos(∆))² (M² - m²) (-2 cos(t) sin(t)) + + 0 = 2 cos (t) sin (t) + 0 = sin (2t) + t = nÏ€ + +Which is to say that the maximum and minimum errors occur on the +axes of the ellipse at 0 and Ï€ radians: + + E²(0) = (1-cos(∆))² (M² - m²) + (1-cos(∆))² m² + = (1-cos(∆))² M² + E²(Ï€) = (1-cos(∆))² m² + +maximum error = M (1-cos(∆)) +minimum error = m (1-cos(∆)) + +We must make maximum error ≤ tolerance, so compute the ∆ needed: + + tolerance = M (1-cos(∆)) + tolerance / M = 1 - cos (∆) + cos(∆) = 1 - tolerance/M + ∆ = acos (1 - tolerance / M); + +Remembering that ∆ is half of our angle between vertices, +the number of vertices is then + +vertices = ceil(2Ï€/2∆). + = ceil(Ï€/∆). + +Note that this also equation works for M == m (a circle) as it +doesn't matter where on the circle the error is computed. + +*/ + static int -_cairo_pen_vertices_needed (double radius, double tolerance, double expansion) +_cairo_pen_vertices_needed (double tolerance, + double radius, + cairo_matrix_t *matrix) { - double theta; + double a = matrix->m[0][0], c = matrix->m[0][1]; + double b = matrix->m[1][0], d = matrix->m[1][1]; - if (tolerance > expansion*radius) { - return 4; - } + double i = a*a + c*c; + double j = b*b + d*d; - theta = acos (1 - tolerance/(expansion * radius)); - return ceil (M_PI / theta); + double f = 0.5 * (i + j); + double g = 0.5 * (i - j); + double h = a*b + c*d; + + /* + * compute major and minor axes lengths for + * a pen with the specified radius + */ + + double major_axis = radius * sqrt (f + sqrt (g*g+h*h)); + + /* + * we don't need the minor axis length, which is + * double min = radius * sqrt (f - sqrt (g*g+h*h)); + */ + + /* + * compute number of vertices needed + */ + int num_vertices; + + /* Where tolerance / M is > 1, we use 4 points */ + if (tolerance >= major_axis) { + num_vertices = 4; + } else { + double delta = acos (1 - tolerance / major_axis); + num_vertices = ceil (M_PI / delta); + + /* number of vertices must be even */ + if (num_vertices % 2) + num_vertices++; + } + return num_vertices; } static void @@ -186,8 +430,8 @@ _cairo_pen_compute_slopes (cairo_pen_t *pen) _cairo_slope_init (&v->slope_ccw, &v->point, &next->point); } } - -/* Find active pen vertex for clockwise edge of stroke at the given slope. +/* + * Find active pen vertex for clockwise edge of stroke at the given slope. * * NOTE: The behavior of this function is sensitive to the sense of * the inequality within _cairo_slope_clockwise/_cairo_slope_counter_clockwise. diff --git a/src/cairo-polygon.c b/src/cairo-polygon.c index ad034406..8fa32f9f 100644 --- a/src/cairo-polygon.c +++ b/src/cairo-polygon.c @@ -1,22 +1,37 @@ /* cairo - a vector graphics library with display and print output * - * Copyright © 2002 University of Southern California + * Copyright © 2002 University of Southern California * * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. * - * This library 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 - * Library General Public License for more details. + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ * - * Author: Carl D. Worth <cworth@isi.edu> + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth <cworth@isi.edu> */ #include <stdlib.h> diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c index cf7e0a79..bfdfada3 100644 --- a/src/cairo-ps-surface.c +++ b/src/cairo-ps-surface.c @@ -1,22 +1,37 @@ /* cairo - a vector graphics library with display and print output * - * Copyright © 2003 University of Southern California + * Copyright © 2003 University of Southern California * * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. * - * This library 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 - * Library General Public License for more details. + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ * - * Author: Carl D. Worth <cworth@isi.edu> + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth <cworth@isi.edu> */ #include "cairoint.h" @@ -421,5 +436,6 @@ static const cairo_surface_backend_t cairo_ps_surface_backend = { _cairo_ps_surface_copy_page, _cairo_ps_surface_show_page, _cairo_ps_surface_set_clip_region, - _cairo_ps_surface_create_pattern + _cairo_ps_surface_create_pattern, + NULL /* show_glyphs */ }; diff --git a/src/cairo-slope.c b/src/cairo-slope.c index 885ba4c9..1a149798 100644 --- a/src/cairo-slope.c +++ b/src/cairo-slope.c @@ -1,22 +1,37 @@ /* cairo - a vector graphics library with display and print output * - * Copyright © 2002 University of Southern California + * Copyright © 2002 University of Southern California * * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. * - * This library 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 - * Library General Public License for more details. + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ * - * Author: Carl D. Worth <cworth@isi.edu> + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth <cworth@isi.edu> */ #include "cairoint.h" diff --git a/src/cairo-spline.c b/src/cairo-spline.c index 68bb75eb..bed351ef 100644 --- a/src/cairo-spline.c +++ b/src/cairo-spline.c @@ -1,22 +1,37 @@ /* cairo - a vector graphics library with display and print output * - * Copyright © 2002 University of Southern California + * Copyright © 2002 University of Southern California * * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. * - * This library 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 - * Library General Public License for more details. + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ * - * Author: Carl D. Worth <cworth@isi.edu> + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth <cworth@isi.edu> */ #include "cairoint.h" diff --git a/src/cairo-surface.c b/src/cairo-surface.c index b17368a5..a457d206 100644 --- a/src/cairo-surface.c +++ b/src/cairo-surface.c @@ -1,22 +1,37 @@ /* cairo - a vector graphics library with display and print output * - * Copyright © 2002 University of Southern California + * Copyright © 2002 University of Southern California * * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. * - * This library 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 - * Library General Public License for more details. + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ * - * Author: Carl D. Worth <cworth@isi.edu> + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth <cworth@isi.edu> */ #include <stdlib.h> diff --git a/src/cairo-traps.c b/src/cairo-traps.c index 000e05f4..d17a2728 100644 --- a/src/cairo-traps.c +++ b/src/cairo-traps.c @@ -52,6 +52,12 @@ _compare_cairo_edge_by_slope (const void *av, const void *bv); static cairo_fixed_16_16_t _compute_x (cairo_line_t *line, cairo_fixed_t y); +static double +_compute_inverse_slope (cairo_line_t *l); + +static double +_compute_x_intercept (cairo_line_t *l, double inverse_slope); + static int _line_segs_intersect_ceil (cairo_line_t *left, cairo_line_t *right, cairo_fixed_t *y_ret); @@ -321,108 +327,40 @@ _compare_cairo_edge_by_current_x_slope (const void *av, const void *bv) sub-computations -- just a bunch of determinants. I haven't looked at complexity, (both are probably similar and it probably doesn't matter much anyway). - */ -static const cairo_fixed_32_32_t -_det16_32 (cairo_fixed_16_16_t a, - cairo_fixed_16_16_t b, - cairo_fixed_16_16_t c, - cairo_fixed_16_16_t d) +static double +_det (double a, double b, double c, double d) { - return _cairo_int64_sub (_cairo_int32x32_64_mul (a, d), - _cairo_int32x32_64_mul (b, c)); + return a * d - b * c; } -static const cairo_fixed_64_64_t -_det32_64 (cairo_fixed_32_32_t a, - cairo_fixed_32_32_t b, - cairo_fixed_32_32_t c, - cairo_fixed_32_32_t d) +static int +_lines_intersect (cairo_line_t *l1, cairo_line_t *l2, cairo_fixed_t *y_intersection) { - return _cairo_int128_sub (_cairo_int64x64_128_mul (a, d), - _cairo_int64x64_128_mul (b, c)); -} + double dx1 = cairo_fixed_to_double (l1->p1.x - l1->p2.x); + double dy1 = cairo_fixed_to_double (l1->p1.y - l1->p2.y); -static const cairo_fixed_32_32_t -_fixed_16_16_to_fixed_32_32 (cairo_fixed_16_16_t a) -{ - return _cairo_int64_lsl (_cairo_int32_to_int64 (a), 16); -} + double dx2 = cairo_fixed_to_double (l2->p1.x - l2->p2.x); + double dy2 = cairo_fixed_to_double (l2->p1.y - l2->p2.y); -static int -_line_segs_intersect_ceil (cairo_line_t *l1, cairo_line_t *l2, cairo_fixed_t *y_intersection) -{ - cairo_fixed_16_16_t dx1, dx2, dy1, dy2; - cairo_fixed_32_32_t den_det; - cairo_fixed_32_32_t l1_det, l2_det; - cairo_fixed_64_64_t num_det; - cairo_fixed_32_32_t intersect_32_32; - cairo_fixed_48_16_t intersect_48_16; - cairo_fixed_16_16_t intersect_16_16; - cairo_quorem128_t qr; - - dx1 = l1->p1.x - l1->p2.x; - dy1 = l1->p1.y - l1->p2.y; - dx2 = l2->p1.x - l2->p2.x; - dy2 = l2->p1.y - l2->p2.y; - den_det = _det16_32 (dx1, dy1, - dx2, dy2); - - if (_cairo_int64_eq (den_det, _cairo_int32_to_int64(0))) - return 0; + double l1_det, l2_det; - l1_det = _det16_32 (l1->p1.x, l1->p1.y, - l1->p2.x, l1->p2.y); - l2_det = _det16_32 (l2->p1.x, l2->p1.y, - l2->p2.x, l2->p2.y); + double den_det = _det (dx1, dy1, dx2, dy2); - - num_det = _det32_64 (l1_det, _fixed_16_16_to_fixed_32_32 (dy1), - l2_det, _fixed_16_16_to_fixed_32_32 (dy2)); - - /* - * Ok, this one is a bit tricky in fixed point, the denominator - * needs to be left with 32-bits of fraction so that the - * result of the divide ends up with 32-bits of fraction (64 - 32 = 32) - */ - qr = _cairo_int128_divrem (num_det, _cairo_int64_to_int128 (den_det)); - - intersect_32_32 = _cairo_int128_to_int64 (qr.quo); - - /* - * Find the ceiling of the quotient -- divrem returns - * the quotient truncated towards zero, so if the - * quotient should be positive (num_den and den_det have same sign) - * bump the quotient up by one. - */ - - if (_cairo_int128_ne (qr.rem, _cairo_int32_to_int128 (0)) && - (_cairo_int128_ge (num_det, _cairo_int32_to_int128 (0)) == - _cairo_int64_ge (den_det, _cairo_int32_to_int64 (0)))) - { - intersect_32_32 = _cairo_int64_add (intersect_32_32, - _cairo_int32_to_int64 (1)); - } - - /* - * Now convert from 32.32 to 48.16 and take the ceiling; - * this requires adding in 15 1 bits and shifting the result - */ + if (den_det == 0) + return 0; - intersect_32_32 = _cairo_int64_add (intersect_32_32, - _cairo_int32_to_int64 ((1 << 16) - 1)); - intersect_48_16 = _cairo_int64_rsa (intersect_32_32, 16); - - /* - * And drop the top bits - */ - intersect_16_16 = _cairo_int64_to_int32 (intersect_48_16); - - *y_intersection = intersect_16_16; + l1_det = _det (l1->p1.x, l1->p1.y, + l1->p2.x, l1->p2.y); + l2_det = _det (l2->p1.x, l2->p1.y, + l2->p2.x, l2->p2.y); + + *y_intersection = _det (l1_det, dy1, + l2_det, dy2) / den_det; return 1; } - +*/ static cairo_fixed_16_16_t _compute_x (cairo_line_t *line, cairo_fixed_t y) { @@ -433,7 +371,6 @@ _compute_x (cairo_line_t *line, cairo_fixed_t y) return line->p1.x + (ex / dy); } -#if 0 static double _compute_inverse_slope (cairo_line_t *l) { @@ -523,7 +460,6 @@ _line_segs_intersect_ceil (cairo_line_t *l1, cairo_line_t *l2, cairo_fixed_t *y_ return 1; } -#endif /* The algorithm here is pretty simple: diff --git a/src/cairo-xcb-surface.c b/src/cairo-xcb-surface.c index f992bf5f..21760d76 100644 --- a/src/cairo-xcb-surface.c +++ b/src/cairo-xcb-surface.c @@ -1,22 +1,37 @@ /* cairo - a vector graphics library with display and print output * - * Copyright © 2002 University of Southern California + * Copyright © 2002 University of Southern California * * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. * - * This library 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 - * Library General Public License for more details. + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ * - * Author: Carl D. Worth <cworth@isi.edu> + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth <cworth@isi.edu> */ #include "cairoint.h" @@ -470,7 +485,7 @@ _cairo_xcb_surface_set_filter (void *abstract_surface, cairo_filter_t filter) } XCBRenderSetPictureFilter(surface->dpy, surface->picture, - strlen(render_filter), 0, render_filter, NULL); + strlen(render_filter), render_filter, 0, NULL); return CAIRO_STATUS_SUCCESS; } @@ -730,7 +745,8 @@ static const struct cairo_surface_backend cairo_xcb_surface_backend = { _cairo_xcb_surface_copy_page, _cairo_xcb_surface_show_page, _cairo_xcb_surface_set_clip_region, - _cairo_xcb_surface_create_pattern + _cairo_xcb_surface_create_pattern, + NULL /* show_glyphs */ }; static void diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c index 2036f8e4..dda7995b 100644 --- a/src/cairo-xlib-surface.c +++ b/src/cairo-xlib-surface.c @@ -1,22 +1,37 @@ /* cairo - a vector graphics library with display and print output * - * Copyright © 2002 University of Southern California + * Copyright © 2002 University of Southern California * * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. * - * This library 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 - * Library General Public License for more details. + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ * - * Author: Carl D. Worth <cworth@isi.edu> + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth <cworth@isi.edu> */ #include "cairoint.h" @@ -130,7 +145,7 @@ _cairo_xlib_surface_create_similar (void *abstract_src, scr = DefaultScreen (dpy); pix = XCreatePixmap (dpy, DefaultRootWindow (dpy), - width, height, + width <= 0 ? 1 : width, height <= 0 ? 1 : height, _CAIRO_FORMAT_DEPTH (format)); surface = (cairo_xlib_surface_t *) @@ -616,6 +631,8 @@ _cairo_xlib_surface_set_clip_region (void *abstract_surface, xr.height = surf->height; XUnionRectWithRegion (&xr, xregion, xregion); rects = malloc(sizeof(XRectangle)); + if (rects == NULL) + return CAIRO_STATUS_NO_MEMORY; rects[0] = xr; m = 1; @@ -626,6 +643,8 @@ _cairo_xlib_surface_set_clip_region (void *abstract_surface, if (n == 0) return CAIRO_STATUS_SUCCESS; rects = malloc(sizeof(XRectangle) * n); + if (rects == NULL) + return CAIRO_STATUS_NO_MEMORY; box = pixman_region_rects (region); xregion = XCreateRegion(); @@ -646,7 +665,7 @@ _cairo_xlib_surface_set_clip_region (void *abstract_surface, XSetClipRectangles(surf->dpy, surf->gc, 0, 0, rects, m, Unsorted); free(rects); if (surf->picture) - XRenderSetPictureClipRegion (surf->dpy, surf->picture, xregion); + XRenderSetPictureClipRegion (surf->dpy, surf->picture, xregion); XDestroyRegion(xregion); XSetGraphicsExposures(surf->dpy, surf->gc, gc_values.graphics_exposures); return CAIRO_STATUS_SUCCESS; @@ -660,6 +679,17 @@ _cairo_xlib_surface_create_pattern (void *abstract_surface, return CAIRO_INT_STATUS_UNSUPPORTED; } +static cairo_status_t +_cairo_xlib_surface_show_glyphs (cairo_unscaled_font_t *font, + cairo_font_scale_t *scale, + cairo_operator_t operator, + cairo_surface_t *source, + cairo_surface_t *surface, + int source_x, + int source_y, + const cairo_glyph_t *glyphs, + int num_glyphs); + static const struct cairo_surface_backend cairo_xlib_surface_backend = { _cairo_xlib_surface_create_similar, _cairo_xlib_surface_destroy, @@ -675,7 +705,8 @@ static const struct cairo_surface_backend cairo_xlib_surface_backend = { _cairo_xlib_surface_copy_page, _cairo_xlib_surface_show_page, _cairo_xlib_surface_set_clip_region, - _cairo_xlib_surface_create_pattern + _cairo_xlib_surface_create_pattern, + _cairo_xlib_surface_show_glyphs }; cairo_surface_t * @@ -746,3 +777,512 @@ cairo_xlib_surface_create (Display *dpy, return (cairo_surface_t *) surface; } DEPRECATE (cairo_surface_create_for_drawable, cairo_xlib_surface_create); + + +/* RENDER glyphset cache code */ + +typedef struct glyphset_cache { + cairo_cache_t base; + struct glyphset_cache *next; + Display *display; + XRenderPictFormat *a8_pict_format; + GlyphSet glyphset; + Glyph counter; +} glyphset_cache_t; + +typedef struct { + cairo_glyph_cache_key_t key; + Glyph glyph; + XGlyphInfo info; +} glyphset_cache_entry_t; + +static Glyph +_next_xlib_glyph (glyphset_cache_t *cache) +{ + return ++(cache->counter); +} + + +static cairo_status_t +_xlib_glyphset_cache_create_entry (void *cache, + void *key, + void **return_entry) +{ + glyphset_cache_t *g = (glyphset_cache_t *) cache; + cairo_glyph_cache_key_t *k = (cairo_glyph_cache_key_t *)key; + glyphset_cache_entry_t *v; + + cairo_status_t status; + + cairo_cache_t *im_cache; + cairo_image_glyph_cache_entry_t *im; + + v = malloc (sizeof (glyphset_cache_entry_t)); + _cairo_lock_global_image_glyph_cache (); + im_cache = _cairo_get_global_image_glyph_cache (); + + if (g == NULL || v == NULL ||g == NULL || im_cache == NULL) { + _cairo_unlock_global_image_glyph_cache (); + return CAIRO_STATUS_NO_MEMORY; + } + + status = _cairo_cache_lookup (im_cache, key, (void **) (&im)); + if (status != CAIRO_STATUS_SUCCESS || im == NULL) { + _cairo_unlock_global_image_glyph_cache (); + return CAIRO_STATUS_NO_MEMORY; + } + + v->key = *k; + _cairo_unscaled_font_reference (v->key.unscaled); + + v->glyph = _next_xlib_glyph (g); + + v->info.width = im->image ? im->image->stride : im->size.width; + v->info.height = im->size.height; + v->info.x = - im->extents.x_bearing; + v->info.y = im->extents.y_bearing; + v->info.xOff = 0; + v->info.yOff = 0; + + XRenderAddGlyphs (g->display, g->glyphset, + &(v->glyph), &(v->info), 1, + im->image ? im->image->data : NULL, + im->image ? v->info.height * v->info.width : 0); + + v->key.base.memory = im->image ? im->image->width * im->image->stride : 0; + *return_entry = v; + _cairo_unlock_global_image_glyph_cache (); + return CAIRO_STATUS_SUCCESS; +} + +static void +_xlib_glyphset_cache_destroy_cache (void *cache) +{ + /* FIXME: will we ever release glyphset caches? */ +} + +static void +_xlib_glyphset_cache_destroy_entry (void *cache, void *entry) +{ + glyphset_cache_t *g; + glyphset_cache_entry_t *v; + + g = (glyphset_cache_t *) cache; + v = (glyphset_cache_entry_t *) entry; + + _cairo_unscaled_font_destroy (v->key.unscaled); + XRenderFreeGlyphs (g->display, g->glyphset, &(v->glyph), 1); + free (v); +} + +const cairo_cache_backend_t _xlib_glyphset_cache_backend = { + _cairo_glyph_cache_hash, + _cairo_glyph_cache_keys_equal, + _xlib_glyphset_cache_create_entry, + _xlib_glyphset_cache_destroy_entry, + _xlib_glyphset_cache_destroy_cache +}; + + +static glyphset_cache_t * +_xlib_glyphset_caches = NULL; + +static void +_lock_xlib_glyphset_caches (void) +{ + /* FIXME: implement locking */ +} + +static void +_unlock_xlib_glyphset_caches (void) +{ + /* FIXME: implement locking */ +} + +static glyphset_cache_t * +_get_glyphset_cache (Display *d) +{ + /* + * There should usually only be one, or a very small number, of + * displays. So we just do a linear scan. + */ + + glyphset_cache_t *g; + + for (g = _xlib_glyphset_caches; g != NULL; g = g->next) { + if (g->display == d) + return g; + } + + g = malloc (sizeof (glyphset_cache_t)); + if (g == NULL) + goto ERR; + + g->counter = 0; + g->display = d; + g->a8_pict_format = XRenderFindStandardFormat (d, PictStandardA8); + if (g->a8_pict_format == NULL) + goto ERR; + + if (_cairo_cache_init (&g->base, + &_xlib_glyphset_cache_backend, + CAIRO_XLIB_GLYPH_CACHE_MEMORY_DEFAULT)) + goto FREE_GLYPHSET_CACHE; + + g->glyphset = XRenderCreateGlyphSet (d, g->a8_pict_format); + g->next = _xlib_glyphset_caches; + _xlib_glyphset_caches = g; + return g; + + FREE_GLYPHSET_CACHE: + free (g); + + ERR: + return NULL; +} + +#define N_STACK_BUF 1024 + +static cairo_status_t +_cairo_xlib_surface_show_glyphs32 (cairo_unscaled_font_t *font, + cairo_font_scale_t *scale, + cairo_operator_t operator, + glyphset_cache_t *g, + cairo_glyph_cache_key_t *key, + cairo_xlib_surface_t *src, + cairo_xlib_surface_t *self, + int source_x, + int source_y, + const cairo_glyph_t *glyphs, + glyphset_cache_entry_t **entries, + int num_glyphs) +{ + XGlyphElt32 *elts = NULL; + XGlyphElt32 stack_elts [N_STACK_BUF]; + + unsigned int *chars = NULL; + unsigned int stack_chars [N_STACK_BUF]; + + int i; + int lastX = 0, lastY = 0; + + /* Acquire arrays of suitable sizes. */ + if (num_glyphs < N_STACK_BUF) { + elts = stack_elts; + chars = stack_chars; + + } else { + elts = malloc (num_glyphs * sizeof (XGlyphElt32)); + if (elts == NULL) + goto FAIL; + + chars = malloc (num_glyphs * sizeof (unsigned int)); + if (chars == NULL) + goto FREE_ELTS; + + } + + for (i = 0; i < num_glyphs; ++i) { + chars[i] = entries[i]->glyph; + elts[i].chars = &(chars[i]); + elts[i].nchars = 1; + elts[i].glyphset = g->glyphset; + elts[i].xOff = glyphs[i].x - lastX; + elts[i].yOff = glyphs[i].y - lastY; + lastX = glyphs[i].x; + lastY = glyphs[i].y; + } + + XRenderCompositeText32 (self->dpy, + _render_operator (operator), + src->picture, + self->picture, + g->a8_pict_format, + source_x, source_y, + 0, 0, + elts, num_glyphs); + + if (num_glyphs >= N_STACK_BUF) { + free (chars); + free (elts); + } + + return CAIRO_STATUS_SUCCESS; + + FREE_ELTS: + if (num_glyphs >= N_STACK_BUF) + free (elts); + + FAIL: + return CAIRO_STATUS_NO_MEMORY; +} + + +static cairo_status_t +_cairo_xlib_surface_show_glyphs16 (cairo_unscaled_font_t *font, + cairo_font_scale_t *scale, + cairo_operator_t operator, + glyphset_cache_t *g, + cairo_glyph_cache_key_t *key, + cairo_xlib_surface_t *src, + cairo_xlib_surface_t *self, + int source_x, + int source_y, + const cairo_glyph_t *glyphs, + glyphset_cache_entry_t **entries, + int num_glyphs) +{ + XGlyphElt16 *elts = NULL; + XGlyphElt16 stack_elts [N_STACK_BUF]; + + unsigned short *chars = NULL; + unsigned short stack_chars [N_STACK_BUF]; + + int i; + int lastX = 0, lastY = 0; + + /* Acquire arrays of suitable sizes. */ + if (num_glyphs < N_STACK_BUF) { + elts = stack_elts; + chars = stack_chars; + + } else { + elts = malloc (num_glyphs * sizeof (XGlyphElt16)); + if (elts == NULL) + goto FAIL; + + chars = malloc (num_glyphs * sizeof (unsigned short)); + if (chars == NULL) + goto FREE_ELTS; + + } + + for (i = 0; i < num_glyphs; ++i) { + chars[i] = entries[i]->glyph; + elts[i].chars = &(chars[i]); + elts[i].nchars = 1; + elts[i].glyphset = g->glyphset; + elts[i].xOff = glyphs[i].x - lastX; + elts[i].yOff = glyphs[i].y - lastY; + lastX = glyphs[i].x; + lastY = glyphs[i].y; + } + + XRenderCompositeText16 (self->dpy, + _render_operator (operator), + src->picture, + self->picture, + g->a8_pict_format, + source_x, source_y, + 0, 0, + elts, num_glyphs); + + if (num_glyphs >= N_STACK_BUF) { + free (chars); + free (elts); + } + + return CAIRO_STATUS_SUCCESS; + + FREE_ELTS: + if (num_glyphs >= N_STACK_BUF) + free (elts); + + FAIL: + return CAIRO_STATUS_NO_MEMORY; +} + +static cairo_status_t +_cairo_xlib_surface_show_glyphs8 (cairo_unscaled_font_t *font, + cairo_font_scale_t *scale, + cairo_operator_t operator, + glyphset_cache_t *g, + cairo_glyph_cache_key_t *key, + cairo_xlib_surface_t *src, + cairo_xlib_surface_t *self, + int source_x, + int source_y, + const cairo_glyph_t *glyphs, + glyphset_cache_entry_t **entries, + int num_glyphs) +{ + XGlyphElt8 *elts = NULL; + XGlyphElt8 stack_elts [N_STACK_BUF]; + + char *chars = NULL; + char stack_chars [N_STACK_BUF]; + + int i; + int lastX = 0, lastY = 0; + + /* Acquire arrays of suitable sizes. */ + if (num_glyphs < N_STACK_BUF) { + elts = stack_elts; + chars = stack_chars; + + } else { + elts = malloc (num_glyphs * sizeof (XGlyphElt8)); + if (elts == NULL) + goto FAIL; + + chars = malloc (num_glyphs * sizeof (char)); + if (chars == NULL) + goto FREE_ELTS; + + } + + for (i = 0; i < num_glyphs; ++i) { + chars[i] = entries[i]->glyph; + elts[i].chars = &(chars[i]); + elts[i].nchars = 1; + elts[i].glyphset = g->glyphset; + elts[i].xOff = glyphs[i].x - lastX; + elts[i].yOff = glyphs[i].y - lastY; + lastX = glyphs[i].x; + lastY = glyphs[i].y; + } + + XRenderCompositeText8 (self->dpy, + _render_operator (operator), + src->picture, + self->picture, + g->a8_pict_format, + source_x, source_y, + 0, 0, + elts, num_glyphs); + + if (num_glyphs >= N_STACK_BUF) { + free (chars); + free (elts); + } + + return CAIRO_STATUS_SUCCESS; + + FREE_ELTS: + if (num_glyphs >= N_STACK_BUF) + free (elts); + + FAIL: + return CAIRO_STATUS_NO_MEMORY; +} + + +static cairo_status_t +_cairo_xlib_surface_show_glyphs (cairo_unscaled_font_t *font, + cairo_font_scale_t *scale, + cairo_operator_t operator, + cairo_surface_t *source, + cairo_surface_t *surface, + int source_x, + int source_y, + const cairo_glyph_t *glyphs, + int num_glyphs) +{ + unsigned int elt_size; + cairo_xlib_surface_t *self = (cairo_xlib_surface_t *) surface; + cairo_image_surface_t *tmp = NULL; + cairo_xlib_surface_t *src = NULL; + glyphset_cache_t *g; + cairo_status_t status; + cairo_glyph_cache_key_t key; + glyphset_cache_entry_t **entries; + glyphset_cache_entry_t *stack_entries [N_STACK_BUF]; + int i; + + /* Acquire an entry array of suitable size. */ + if (num_glyphs < N_STACK_BUF) { + entries = stack_entries; + + } else { + entries = malloc (num_glyphs * sizeof (glyphset_cache_entry_t *)); + if (entries == NULL) + goto FAIL; + } + + /* prep the source surface. */ + if (source->backend == surface->backend) { + src = (cairo_xlib_surface_t *) source; + + } else { + tmp = _cairo_surface_get_image (source); + if (tmp == NULL) + goto FREE_ENTRIES; + + src = (cairo_xlib_surface_t *) + _cairo_surface_create_similar_scratch (surface, self->format, 1, + tmp->width, tmp->height); + + if (src == NULL) + goto FREE_TMP; + + if (_cairo_surface_set_image (&(src->base), tmp) != CAIRO_STATUS_SUCCESS) + goto FREE_SRC; + } + + _lock_xlib_glyphset_caches (); + g = _get_glyphset_cache (self->dpy); + if (g == NULL) + goto UNLOCK; + + /* Work out the index size to use. */ + elt_size = 8; + key.scale = *scale; + key.unscaled = font; + + for (i = 0; i < num_glyphs; ++i) { + key.index = glyphs[i].index; + status = _cairo_cache_lookup (&g->base, &key, (void **) (&entries[i])); + if (status != CAIRO_STATUS_SUCCESS || entries[i] == NULL) + goto UNLOCK; + + if (elt_size == 8 && entries[i]->glyph > 0xff) + elt_size = 16; + if (elt_size == 16 && entries[i]->glyph > 0xffff) { + elt_size = 32; + break; + } + } + + /* Call the appropriate sub-function. */ + + if (elt_size == 8) + status = _cairo_xlib_surface_show_glyphs8 (font, scale, operator, g, &key, src, self, + source_x, source_y, + glyphs, entries, num_glyphs); + else if (elt_size == 16) + status = _cairo_xlib_surface_show_glyphs16 (font, scale, operator, g, &key, src, self, + source_x, source_y, + glyphs, entries, num_glyphs); + else + status = _cairo_xlib_surface_show_glyphs32 (font, scale, operator, g, &key, src, self, + source_x, source_y, + glyphs, entries, num_glyphs); + + _unlock_xlib_glyphset_caches (); + + if (tmp != NULL) { + cairo_surface_destroy (&(src->base)); + cairo_surface_destroy (&(tmp->base)); + } + + if (num_glyphs >= N_STACK_BUF) + free (entries); + + return status; + + UNLOCK: + _unlock_xlib_glyphset_caches (); + + FREE_SRC: + cairo_surface_destroy (&(src->base)); + + FREE_TMP: + cairo_surface_destroy (&(tmp->base)); + + FREE_ENTRIES: + if (num_glyphs >= N_STACK_BUF) + free (entries); + + FAIL: + return CAIRO_STATUS_NO_MEMORY; +} diff --git a/src/cairo.c b/src/cairo.c index 7c469854..7e6f1d7b 100644 --- a/src/cairo.c +++ b/src/cairo.c @@ -1,24 +1,40 @@ /* cairo - a vector graphics library with display and print output * - * Copyright © 2002 University of Southern California + * Copyright © 2002 University of Southern California * * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. * - * This library 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 - * Library General Public License for more details. + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ * - * Author: Carl D. Worth <cworth@isi.edu> + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth <cworth@isi.edu> */ + #include "cairoint.h" #define CAIRO_TOLERANCE_MINIMUM 0.0002 /* We're limited by 16 bits of sub-pixel precision */ @@ -884,12 +900,27 @@ cairo_text_extents (cairo_t *cr, const unsigned char *utf8, cairo_text_extents_t *extents) { + cairo_glyph_t *glyphs = NULL; + int nglyphs; + CAIRO_CHECK_SANITY (cr); if (cr->status) return; - - cr->status = _cairo_gstate_text_extents (cr->gstate, utf8, extents); + + cr->status = _cairo_gstate_text_to_glyphs (cr->gstate, utf8, &glyphs, &nglyphs); CAIRO_CHECK_SANITY (cr); + + if (cr->status) { + if (glyphs) + free (glyphs); + return; + } + + cr->status = _cairo_gstate_glyph_extents (cr->gstate, glyphs, nglyphs, extents); + CAIRO_CHECK_SANITY (cr); + + if (glyphs) + free (glyphs); } void @@ -910,6 +941,9 @@ cairo_glyph_extents (cairo_t *cr, void cairo_show_text (cairo_t *cr, const unsigned char *utf8) { + cairo_glyph_t *glyphs = NULL; + int nglyphs; + CAIRO_CHECK_SANITY (cr); if (cr->status) return; @@ -917,8 +951,20 @@ cairo_show_text (cairo_t *cr, const unsigned char *utf8) if (utf8 == NULL) return; - cr->status = _cairo_gstate_show_text (cr->gstate, utf8); + cr->status = _cairo_gstate_text_to_glyphs (cr->gstate, utf8, &glyphs, &nglyphs); CAIRO_CHECK_SANITY (cr); + + if (cr->status) { + if (glyphs) + free (glyphs); + return; + } + + cr->status = _cairo_gstate_show_glyphs (cr->gstate, glyphs, nglyphs); + CAIRO_CHECK_SANITY (cr); + + if (glyphs) + free (glyphs); } void @@ -935,12 +981,27 @@ cairo_show_glyphs (cairo_t *cr, cairo_glyph_t *glyphs, int num_glyphs) void cairo_text_path (cairo_t *cr, const unsigned char *utf8) { + cairo_glyph_t *glyphs = NULL; + int nglyphs; + CAIRO_CHECK_SANITY (cr); if (cr->status) return; - cr->status = _cairo_gstate_text_path (cr->gstate, utf8); + cr->status = _cairo_gstate_text_to_glyphs (cr->gstate, utf8, &glyphs, &nglyphs); CAIRO_CHECK_SANITY (cr); + + if (cr->status) { + if (glyphs) + free (glyphs); + return; + } + + cr->status = _cairo_gstate_glyph_path (cr->gstate, glyphs, nglyphs); + CAIRO_CHECK_SANITY (cr); + + if (glyphs) + free (glyphs); } void diff --git a/src/cairo.h b/src/cairo.h index 40848396..25dfd4d6 100644 --- a/src/cairo.h +++ b/src/cairo.h @@ -1,22 +1,37 @@ /* cairo - a vector graphics library with display and print output * - * Copyright © 2002 University of Southern California + * Copyright © 2002 University of Southern California * * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. * - * This library 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 - * Library General Public License for more details. + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ * - * Author: Carl D. Worth <cworth@isi.edu> + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth <cworth@isi.edu> */ #ifndef _CAIRO_H_ @@ -135,14 +150,14 @@ cairo_set_target_xcb (cairo_t *cr, cairo_format_t format); #endif /* CAIRO_HAS_XCB_SURFACE */ -#ifdef CAIRO_HAS_GL_SURFACE +#ifdef CAIRO_HAS_GLITZ_SURFACE #include <glitz.h> void -cairo_set_target_gl (cairo_t *cr, - glitz_surface_t *surface); -#endif /* CAIRO_HAS_GL_SURFACE */ +cairo_set_target_glitz (cairo_t *cr, + glitz_surface_t *surface); +#endif /* CAIRO_HAS_GLITZ_SURFACE */ typedef enum cairo_operator { CAIRO_OPERATOR_CLEAR, @@ -769,12 +784,12 @@ cairo_xlib_surface_set_size (cairo_surface_t *surface, int width, int height); #endif /* CAIRO_HAS_XLIB_SURFACE */ -#ifdef CAIRO_HAS_GL_SURFACE +#ifdef CAIRO_HAS_GLITZ_SURFACE cairo_surface_t * -cairo_gl_surface_create (glitz_surface_t *surface); +cairo_glitz_surface_create (glitz_surface_t *surface); -#endif /* CAIRO_HAS_GL_SURFACE */ +#endif /* CAIRO_HAS_GLITZ_SURFACE */ /* Matrix functions */ diff --git a/src/cairo_cache.c b/src/cairo_cache.c new file mode 100644 index 00000000..a33d69a0 --- /dev/null +++ b/src/cairo_cache.c @@ -0,0 +1,454 @@ +/* cairo - a vector graphics library with display and print output + * + * This file is Copyright © 2004 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Contributor(s): + * Keith Packard + * Graydon Hoare <graydon@redhat.com> + */ + +#include "cairoint.h" + +/* + * This structure, and accompanying table, is borrowed/modified from the + * file xserver/render/glyph.c in the freedesktop.org x server, with + * permission (and suggested modification of doubling sizes) by Keith + * Packard. + */ + +static cairo_cache_arrangement_t cache_arrangements [] = { + { 16, 43, 41 }, + { 32, 73, 71 }, + { 64, 151, 149 }, + { 128, 283, 281 }, + { 256, 571, 569 }, + { 512, 1153, 1151 }, + { 1024, 2269, 2267 }, + { 2048, 4519, 4517 }, + { 4096, 9013, 9011 }, + { 8192, 18043, 18041 }, + { 16384, 36109, 36107 }, + { 32768, 72091, 72089 }, + { 65536, 144409, 144407 }, + { 131072, 288361, 288359 }, + { 262144, 576883, 576881 }, + { 524288, 1153459, 1153457 }, + { 1048576, 2307163, 2307161 }, + { 2097152, 4613893, 4613891 }, + { 4194304, 9227641, 9227639 }, + { 8388608, 18455029, 18455027 }, + { 16777216, 36911011, 36911009 }, + { 33554432, 73819861, 73819859 }, + { 67108864, 147639589, 147639587 }, + { 134217728, 295279081, 295279079 }, + { 268435456, 590559793, 590559791 } +}; + +#define N_CACHE_SIZES (sizeof(cache_arrangements)/sizeof(cache_arrangements[0])) + +/* + * Entries 'e' are poiners, in one of 3 states: + * + * e == NULL: The entry has never had anything put in it + * e != DEAD_ENTRY: The entry has an active value in it currently + * e == DEAD_ENTRY: The entry *had* a value in it at some point, but the + * entry has been killed. Lookups requesting free space can + * reuse these entries; lookups requesting a precise match + * should neither return these entries nor stop searching when + * seeing these entries. + * + * We expect keys will not be destroyed frequently, so our table does not + * contain any explicit shrinking code nor any chain-coalescing code for + * entries randomly deleted by memory pressure (except during rehashing, of + * course). These assumptions are potentially bad, but they make the + * implementation straightforward. + * + * Revisit later if evidence appears that we're using excessive memory from + * a mostly-dead table. + * + * Generally you do not need to worry about freeing cache entries; the + * cache will expire entries randomly as it experiences memory pressure. + * There is currently no explicit entry-removing call, though one can be + * added easily. + * + * This table is open-addressed with double hashing. Each table size is a + * prime chosen to be a little more than double the high water mark for a + * given arrangement, so the tables should remain < 50% full. The table + * size makes for the "first" hash modulus; a second prime (2 less than the + * first prime) serves as the "second" hash modulus, which is co-prime and + * thus guarantees a complete permutation of table indices. + * + */ + +#define DEAD_ENTRY ((cairo_cache_entry_base_t *) 1) +#define NULL_ENTRY_P(cache, i) ((cache)->entries[i] == NULL) +#define DEAD_ENTRY_P(cache, i) ((cache)->entries[i] == DEAD_ENTRY) +#define LIVE_ENTRY_P(cache, i) \ + (!((NULL_ENTRY_P((cache),(i))) || (DEAD_ENTRY_P((cache),(i))))) + +#ifdef CAIRO_DO_SANITY_CHECKING +#include <assert.h> +static void +_cache_sane_state (cairo_cache_t *cache) +{ + assert (cache != NULL); + assert (cache->entries != NULL); + assert (cache->backend != NULL); + assert (cache->arrangement != NULL); + assert (cache->refcount > 0); + assert (cache->used_memory <= cache->max_memory); + assert (cache->live_entries <= cache->arrangement->size); +} +#else +#define _cache_sane_state(c) +#define assert(x) +#endif + +static void +_entry_destroy (cairo_cache_t *cache, unsigned long i) +{ + _cache_sane_state (cache); + + if (LIVE_ENTRY_P(cache, i)) + { + cairo_cache_entry_base_t *entry = cache->entries[i]; + assert(cache->live_entries > 0); + assert(cache->used_memory > entry->memory); + + cache->live_entries--; + cache->used_memory -= entry->memory; + cache->backend->destroy_entry (cache, entry); + cache->entries[i] = DEAD_ENTRY; + } +} + +static cairo_cache_entry_base_t ** +_cache_lookup (cairo_cache_t *cache, + void *key, + int (*predicate)(void*,void*,void*)) +{ + + cairo_cache_entry_base_t **probe; + unsigned long hash; + unsigned long table_size, i, idx, step; + + _cache_sane_state (cache); + assert (key != NULL); + + table_size = cache->arrangement->size; + hash = cache->backend->hash (cache, key); + idx = hash % table_size; + step = 0; + + for (i = 0; i < table_size; ++i) + { +#ifdef CAIRO_MEASURE_CACHE_PERFORMANCE + cache->probes++; +#endif + assert(idx < table_size); + probe = cache->entries + idx; + + /* + * There are two lookup modes: searching for a free slot and searching + * for an exact entry. + */ + + if (predicate != NULL) + { + /* We are looking up an exact entry. */ + if (*probe != NULL + && *probe != DEAD_ENTRY + && (*probe)->hashcode == hash + && predicate (cache, key, *probe)) + return probe; + } + else + { + /* We are just looking for a free slot. */ + if (*probe == NULL + || *probe == DEAD_ENTRY) + return probe; + } + + if (step == 0) { + step = hash % cache->arrangement->rehash; + if (step == 0) + step = 1; + } + + idx += step; + if (idx >= table_size) + idx -= table_size; + } + + /* + * The table should not have permitted you to get here if you were just + * looking for a free slot: there should have been room. + */ + assert(predicate != NULL); + return NULL; +} + +static cairo_cache_entry_base_t ** +_find_available_entry_for (cairo_cache_t *cache, + void *key) +{ + return _cache_lookup (cache, key, NULL); +} + +static cairo_cache_entry_base_t ** +_find_exact_live_entry_for (cairo_cache_t *cache, + void *key) +{ + return _cache_lookup (cache, key, cache->backend->keys_equal); +} + + +static cairo_cache_arrangement_t * +_find_cache_arrangement (unsigned long proposed_size) +{ + unsigned long idx; + + for (idx = 0; idx < N_CACHE_SIZES; ++idx) + if (cache_arrangements[idx].high_water_mark >= proposed_size) + return &cache_arrangements[idx]; + return NULL; +} + +static cairo_status_t +_resize_cache (cairo_cache_t *cache, unsigned long proposed_size) +{ + cairo_cache_t tmp; + cairo_cache_entry_base_t **e; + unsigned long new_size, i; + + tmp = *cache; + tmp.arrangement = _find_cache_arrangement (proposed_size); + assert(tmp.arrangement != NULL); + if (tmp.arrangement == cache->arrangement) + return CAIRO_STATUS_SUCCESS; + + new_size = tmp.arrangement->size; + tmp.entries = calloc (new_size, sizeof (cairo_cache_entry_base_t *)); + if (tmp.entries == NULL) + return CAIRO_STATUS_NO_MEMORY; + + for (i = 0; i < cache->arrangement->size; ++i) { + if (LIVE_ENTRY_P(cache, i)) { + e = _find_available_entry_for (&tmp, cache->entries[i]); + assert (e != NULL); + *e = cache->entries[i]; + } + } + free (cache->entries); + cache->entries = tmp.entries; + cache->arrangement = tmp.arrangement; + return CAIRO_STATUS_SUCCESS; +} + + +#ifdef CAIRO_MEASURE_CACHE_PERFORMANCE +static double +_load_factor (cairo_cache_t *cache) +{ + return ((double) cache->live_entries) + / ((double) cache->arrangement->size); +} +#endif + +static unsigned long +_random_live_entry (cairo_cache_t *cache) +{ + unsigned long idx; + assert(cache != NULL); + do { + idx = rand () % cache->arrangement->size; + } while (! LIVE_ENTRY_P(cache, idx)); + return idx; +} + + +/* public API follows */ + +cairo_status_t +_cairo_cache_init (cairo_cache_t *cache, + const cairo_cache_backend_t *backend, + unsigned long max_memory) +{ + assert(backend != NULL); + + if (cache != NULL){ + cache->arrangement = &cache_arrangements[0]; + cache->refcount = 1; + cache->max_memory = max_memory; + cache->used_memory = 0; + cache->live_entries = 0; + +#ifdef CAIRO_MEASURE_CACHE_PERFORMANCE + cache->hits = 0; + cache->misses = 0; + cache->probes = 0; +#endif + + cache->backend = backend; + cache->entries = calloc (sizeof(cairo_cache_entry_base_t *), + cache->arrangement->size); + if (cache->entries == NULL) + return CAIRO_STATUS_NO_MEMORY; + } + _cache_sane_state (cache); + return CAIRO_STATUS_SUCCESS; +} + +void +_cairo_cache_reference (cairo_cache_t *cache) +{ + _cache_sane_state (cache); + cache->refcount++; +} + +void +_cairo_cache_destroy (cairo_cache_t *cache) +{ + unsigned long i; + if (cache != NULL) { + + _cache_sane_state (cache); + + if (cache->refcount-- > 0) + return; + + for (i = 0; i < cache->arrangement->size; ++i) { + _entry_destroy (cache, i); + } + + free (cache->entries); + cache->entries = NULL; + cache->backend->destroy_cache (cache); + } +} + +cairo_status_t +_cairo_cache_lookup (cairo_cache_t *cache, + void *key, + void **entry_return) +{ + + unsigned long idx; + cairo_status_t status = CAIRO_STATUS_SUCCESS; + cairo_cache_entry_base_t **slot = NULL, *new_entry; + + _cache_sane_state (cache); + +#ifdef CAIRO_MEASURE_CACHE_PERFORMANCE + if ((cache->hits + cache->misses) % 0xffff == 0) + printf("cache %p stats: size %ld, live %ld, load %.2f\n" + " mem %ld/%ld, hit %ld, miss %ld\n" + " probe %ld, %.2f probe/access\n", + cache, + cache->arrangement->size, + cache->live_entries, + _load_factor (cache), + cache->used_memory, + cache->max_memory, + cache->hits, + cache->misses, + cache->probes, + ((double) cache->probes) + / ((double) (cache->hits + + cache->misses + 1))); +#endif + + /* See if we have an entry in the table already. */ + slot = _find_exact_live_entry_for (cache, key); + if (slot != NULL) { +#ifdef CAIRO_MEASURE_CACHE_PERFORMANCE + cache->hits++; +#endif + *entry_return = *slot; + return status; + } + +#ifdef CAIRO_MEASURE_CACHE_PERFORMANCE + cache->misses++; +#endif + + /* Build the new entry. */ + status = cache->backend->create_entry (cache, key, + entry_return); + if (status != CAIRO_STATUS_SUCCESS) + return status; + + new_entry = (cairo_cache_entry_base_t *) (*entry_return); + + /* Store the hash value in case the backend forgot. */ + new_entry->hashcode = cache->backend->hash (cache, key); + + /* Make some entries die if we're under memory pressure. */ + while (cache->live_entries > 0 && + ((cache->max_memory - cache->used_memory) < new_entry->memory)) { + idx = _random_live_entry (cache); + assert (idx < cache->arrangement->size); + _entry_destroy (cache, idx); + } + + assert(cache->max_memory >= (cache->used_memory + new_entry->memory)); + + /* Make room in the table for a new slot. */ + status = _resize_cache (cache, cache->live_entries + 1); + if (status != CAIRO_STATUS_SUCCESS) { + cache->backend->destroy_entry (cache, new_entry); + *entry_return = NULL; + return status; + } + + slot = _find_available_entry_for (cache, key); + assert(slot != NULL); + + /* Store entry in slot and increment statistics. */ + *slot = new_entry; + cache->live_entries++; + cache->used_memory += new_entry->memory; + + _cache_sane_state (cache); + + return status; +} + +unsigned long +_cairo_hash_string (const char *c) +{ + /* This is the djb2 hash. */ + unsigned long hash = 5381; + while (*c) + hash = ((hash << 5) + hash) + *c++; + return hash; +} + diff --git a/src/cairo_color.c b/src/cairo_color.c index 837a9a52..2fe793ac 100644 --- a/src/cairo_color.c +++ b/src/cairo_color.c @@ -1,22 +1,37 @@ /* cairo - a vector graphics library with display and print output * - * Copyright © 2002 University of Southern California + * Copyright © 2002 University of Southern California * * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. * - * This library 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 - * Library General Public License for more details. + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ * - * Author: Carl D. Worth <cworth@isi.edu> + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth <cworth@isi.edu> */ #include "cairoint.h" diff --git a/src/cairo_fixed.c b/src/cairo_fixed.c index 7dd1a07e..32368d7f 100644 --- a/src/cairo_fixed.c +++ b/src/cairo_fixed.c @@ -1,22 +1,37 @@ /* cairo - a vector graphics library with display and print output * - * Copyright © 2003 University of Southern California + * Copyright © 2003 University of Southern California * * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. * - * This library 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 - * Library General Public License for more details. + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ * - * Author: Carl D. Worth <cworth@isi.edu> + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth <cworth@isi.edu> */ #include "cairoint.h" diff --git a/src/cairo_font.c b/src/cairo_font.c index af397172..5ad9f041 100644 --- a/src/cairo_font.c +++ b/src/cairo_font.c @@ -1,40 +1,95 @@ /* cairo - a vector graphics library with display and print output * - * Copyright © 2002 University of Southern California + * Copyright © 2002 University of Southern California * * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. * - * This library 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 - * Library General Public License for more details. + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ * - * Author: Carl D. Worth <cworth@isi.edu> + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth <cworth@isi.edu> */ #include "cairoint.h" -static cairo_glyph_cache_t * -_cairo_glyph_cache_create (void); -static void -_cairo_glyph_cache_destroy (cairo_glyph_cache_t *glyph_cache); +/* First we implement a global font cache for named fonts. */ + +typedef struct { + cairo_cache_entry_base_t base; + const char *family; + cairo_font_slant_t slant; + cairo_font_weight_t weight; +} cairo_font_cache_key_t; + +typedef struct { + cairo_font_cache_key_t key; + cairo_unscaled_font_t *unscaled; +} cairo_font_cache_entry_t; + +static unsigned long +_font_cache_hash (void *cache, void *key) +{ + cairo_font_cache_key_t *in; + in = (cairo_font_cache_key_t *) key; + unsigned long hash; + + /* 1607 and 1451 are just a couple random primes. */ + hash = _cairo_hash_string (in->family); + hash += ((unsigned long) in->slant) * 1607; + hash += ((unsigned long) in->weight) * 1451; + return hash; +} -static void -_cairo_glyph_cache_reference (cairo_glyph_cache_t *glyph_cache); -cairo_font_t * -_cairo_font_create (const char *family, - cairo_font_slant_t slant, - cairo_font_weight_t weight) +static int +_font_cache_keys_equal (void *cache, + void *k1, + void *k2) { + cairo_font_cache_key_t *a, *b; + a = (cairo_font_cache_key_t *) k1; + b = (cairo_font_cache_key_t *) k2; + + return (strcmp (a->family, b->family) == 0) + && (a->weight == b->weight) + && (a->slant == b->slant); +} + + +static cairo_status_t +_font_cache_create_entry (void *cache, + void *key, + void **return_value) +{ + cairo_font_cache_key_t *k; + cairo_font_cache_entry_t *entry; + k = (cairo_font_cache_key_t *) key; + const struct cairo_font_backend *backend = CAIRO_FONT_BACKEND_DEFAULT; /* XXX: The current freetype backend may return NULL, (for example @@ -43,365 +98,428 @@ _cairo_font_create (const char *family, * like to build in some sort fo font here, (even a really lame, * ugly one if necessary). */ - return backend->create (family, slant, weight); + entry = malloc (sizeof (cairo_font_cache_entry_t)); + if (entry == NULL) + goto FAIL; + + entry->key.slant = k->slant; + entry->key.weight = k->weight; + entry->key.family = strdup(k->family); + if (entry->key.family == NULL) + goto FREE_ENTRY; + + entry->unscaled = backend->create (k->family, k->slant, k->weight); + if (entry->unscaled == NULL) + goto FREE_FAMILY; + + /* Not sure how to measure backend font mem; use a simple count for now.*/ + entry->key.base.memory = 1; + *return_value = entry; + return CAIRO_STATUS_SUCCESS; + + FREE_FAMILY: + free ((void *) entry->key.family); + + FREE_ENTRY: + free (entry); + + FAIL: + return CAIRO_STATUS_NO_MEMORY; } -cairo_status_t -_cairo_font_init (cairo_font_t *font, - const struct cairo_font_backend *backend) +static void +_font_cache_destroy_entry (void *cache, + void *entry) { - cairo_matrix_set_identity (&font->matrix); - font->refcount = 1; - font->backend = backend; - font->glyph_cache = _cairo_glyph_cache_create (); - if (font->glyph_cache == NULL) - return CAIRO_STATUS_NO_MEMORY; + cairo_font_cache_entry_t *e; - return CAIRO_STATUS_SUCCESS; + e = (cairo_font_cache_entry_t *) entry; + _cairo_unscaled_font_destroy (e->unscaled); + free ((void *) e->key.family); + free (e); } -cairo_font_t * -_cairo_font_copy (cairo_font_t *font) +static void +_font_cache_destroy_cache (void *cache) { - cairo_font_t *newfont = NULL; - char *tmp = NULL; + free (cache); +} - if (font == NULL || font->backend->copy == NULL) - return NULL; - - newfont = font->backend->copy (font); - if (newfont == NULL) { - free (tmp); - return NULL; - } +const struct cairo_cache_backend cairo_font_cache_backend = { + _font_cache_hash, + _font_cache_keys_equal, + _font_cache_create_entry, + _font_cache_destroy_entry, + _font_cache_destroy_cache +}; - newfont->refcount = 1; - cairo_matrix_copy(&newfont->matrix, &font->matrix); - newfont->backend = font->backend; - if (newfont->glyph_cache) - _cairo_glyph_cache_destroy (newfont->glyph_cache); - - newfont->glyph_cache = font->glyph_cache; - _cairo_glyph_cache_reference (font->glyph_cache); - - return newfont; +static void +_lock_global_font_cache (void) +{ + /* FIXME: implement locking. */ } -cairo_status_t -_cairo_font_scale (cairo_font_t *font, double scale) +static void +_unlock_global_font_cache (void) { - return cairo_matrix_scale (&font->matrix, scale, scale); + /* FIXME: implement locking. */ } -cairo_status_t -_cairo_font_transform (cairo_font_t *font, cairo_matrix_t *matrix) +static cairo_cache_t * +_global_font_cache = NULL; + +static cairo_cache_t * +_get_global_font_cache (void) { - return cairo_matrix_multiply (&font->matrix, matrix, &font->matrix); + if (_global_font_cache == NULL) { + _global_font_cache = malloc (sizeof (cairo_cache_t)); + + if (_global_font_cache == NULL) + goto FAIL; + + if (_cairo_cache_init (_global_font_cache, + &cairo_font_cache_backend, + CAIRO_FONT_CACHE_NUM_FONTS_DEFAULT)) + goto FAIL; + } + + return _global_font_cache; + + FAIL: + if (_global_font_cache) + free (_global_font_cache); + _global_font_cache = NULL; + return NULL; } -cairo_status_t -_cairo_font_text_extents (cairo_font_t *font, - const unsigned char *utf8, - cairo_text_extents_t *extents) +/* Now the internal "unscaled + scale" font API */ + +cairo_unscaled_font_t * +_cairo_unscaled_font_create (const char *family, + cairo_font_slant_t slant, + cairo_font_weight_t weight) { - return font->backend->text_extents(font, utf8, extents); + cairo_cache_t * cache; + cairo_font_cache_key_t key; + cairo_font_cache_entry_t *font; + cairo_status_t status; + + _lock_global_font_cache (); + cache = _get_global_font_cache (); + if (cache == NULL) { + _unlock_global_font_cache (); + return NULL; + } + + key.family = family; + key.slant = slant; + key.weight = weight; + + status = _cairo_cache_lookup (cache, &key, (void **) &font); + if (status) { + _unlock_global_font_cache (); + return NULL; + } + + _cairo_unscaled_font_reference (font->unscaled); + _unlock_global_font_cache (); + return font->unscaled; } -cairo_status_t -_cairo_font_glyph_extents (cairo_font_t *font, - cairo_glyph_t *glyphs, - int num_glyphs, - cairo_text_extents_t *extents) +void +_cairo_font_init (cairo_font_t *scaled, + cairo_font_scale_t *scale, + cairo_unscaled_font_t *unscaled) { - return font->backend->glyph_extents(font, glyphs, num_glyphs, extents); + scaled->scale = *scale; + scaled->unscaled = unscaled; + scaled->refcount = 1; } cairo_status_t -_cairo_font_text_bbox (cairo_font_t *font, - cairo_surface_t *surface, - double x, - double y, - const unsigned char *utf8, - cairo_box_t *bbox) +_cairo_unscaled_font_init (cairo_unscaled_font_t *font, + const struct cairo_font_backend *backend) { - return font->backend->text_bbox (font, surface, x, y, utf8, bbox); + font->refcount = 1; + font->backend = backend; + return CAIRO_STATUS_SUCCESS; } + cairo_status_t -_cairo_font_glyph_bbox (cairo_font_t *font, - cairo_surface_t *surface, - cairo_glyph_t *glyphs, - int num_glyphs, - cairo_box_t *bbox) +_cairo_unscaled_font_text_to_glyphs (cairo_unscaled_font_t *font, + cairo_font_scale_t *scale, + const unsigned char *utf8, + cairo_glyph_t **glyphs, + int *num_glyphs) { - return font->backend->glyph_bbox (font, surface, glyphs, num_glyphs, bbox); + return font->backend->text_to_glyphs (font, scale, utf8, glyphs, num_glyphs); } cairo_status_t -_cairo_font_show_text (cairo_font_t *font, - cairo_operator_t operator, - cairo_surface_t *source, - cairo_surface_t *surface, - int source_x, - int source_y, - double x, - double y, - const unsigned char *utf8) +_cairo_unscaled_font_glyph_extents (cairo_unscaled_font_t *font, + cairo_font_scale_t *scale, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_text_extents_t *extents) { - return font->backend->show_text(font, operator, source, - surface, source_x, source_y, x, y, utf8); + return font->backend->glyph_extents(font, scale, glyphs, num_glyphs, extents); } + cairo_status_t -_cairo_font_show_glyphs (cairo_font_t *font, - cairo_operator_t operator, - cairo_surface_t *source, - cairo_surface_t *surface, - int source_x, - int source_y, - cairo_glyph_t *glyphs, - int num_glyphs) +_cairo_unscaled_font_glyph_bbox (cairo_unscaled_font_t *font, + cairo_font_scale_t *scale, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_box_t *bbox) { - return font->backend->show_glyphs(font, operator, source, - surface, source_x, source_y, - glyphs, num_glyphs); + return font->backend->glyph_bbox (font, scale, glyphs, num_glyphs, bbox); } cairo_status_t -_cairo_font_text_path (cairo_font_t *font, - double x, - double y, - const unsigned char *utf8, - cairo_path_t *path) +_cairo_unscaled_font_show_glyphs (cairo_unscaled_font_t *font, + cairo_font_scale_t *scale, + cairo_operator_t operator, + cairo_surface_t *source, + cairo_surface_t *surface, + int source_x, + int source_y, + cairo_glyph_t *glyphs, + int num_glyphs) { - return font->backend->text_path(font, x, y, utf8, path); + cairo_status_t status; + if (surface->backend->show_glyphs != NULL) { + status = surface->backend->show_glyphs (font, scale, operator, source, + surface, source_x, source_y, + glyphs, num_glyphs); + if (status == CAIRO_STATUS_SUCCESS) + return status; + } + + /* Surface display routine either does not exist or failed. */ + return font->backend->show_glyphs (font, scale, operator, source, + surface, source_x, source_y, + glyphs, num_glyphs); } cairo_status_t -_cairo_font_glyph_path (cairo_font_t *font, - cairo_glyph_t *glyphs, - int num_glyphs, - cairo_path_t *path) +_cairo_unscaled_font_glyph_path (cairo_unscaled_font_t *font, + cairo_font_scale_t *scale, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_path_t *path) { - return font->backend->glyph_path(font, glyphs, num_glyphs, path); + return font->backend->glyph_path (font, scale, glyphs, num_glyphs, path); } cairo_status_t -_cairo_font_font_extents (cairo_font_t *font, - cairo_font_extents_t *extents) +_cairo_unscaled_font_font_extents (cairo_unscaled_font_t *font, + cairo_font_scale_t *scale, + cairo_font_extents_t *extents) { - return font->backend->font_extents(font, extents); + return font->backend->font_extents(font, scale, extents); } -static void -_cairo_glyph_cache_pop_last (cairo_glyph_cache_t *glyph_cache) +void +_cairo_unscaled_font_reference (cairo_unscaled_font_t *font) { - if (glyph_cache->last) { - cairo_glyph_surface_node_t *remove = glyph_cache->last; - - cairo_surface_destroy (remove->s.surface); - glyph_cache->last = remove->prev; - if (glyph_cache->last) - glyph_cache->last->next = NULL; + font->refcount++; +} - free (remove); - glyph_cache->n_nodes--; - } +void +_cairo_unscaled_font_destroy (cairo_unscaled_font_t *font) +{ + if (--(font->refcount) > 0) + return; + + if (font->backend) + font->backend->destroy (font); } -static cairo_glyph_cache_t * -_cairo_glyph_cache_create (void) -{ - cairo_glyph_cache_t *glyph_cache; - - glyph_cache = malloc (sizeof (cairo_glyph_cache_t)); - if (glyph_cache == NULL) - return NULL; - - glyph_cache->n_nodes = 0; - glyph_cache->first = NULL; - glyph_cache->last = NULL; - glyph_cache->cache_size = CAIRO_FONT_CACHE_SIZE_DEFAULT; - glyph_cache->ref_count = 1; - return glyph_cache; + +/* Public font API follows. */ + +void +cairo_font_reference (cairo_font_t *font) +{ + font->refcount++; } -static void -_cairo_glyph_cache_reference (cairo_glyph_cache_t *glyph_cache) +void +cairo_font_destroy (cairo_font_t *font) { - if (glyph_cache == NULL) + if (--(font->refcount) > 0) return; - glyph_cache->ref_count++; + if (font->unscaled) + _cairo_unscaled_font_destroy (font->unscaled); + + free (font); } -static void -_cairo_glyph_cache_destroy (cairo_glyph_cache_t *glyph_cache) +void +cairo_font_set_transform (cairo_font_t *font, + cairo_matrix_t *matrix) { - if (glyph_cache == NULL) - return; + double dummy; + cairo_matrix_get_affine (matrix, + &font->scale.matrix[0][0], + &font->scale.matrix[0][1], + &font->scale.matrix[1][0], + &font->scale.matrix[1][1], + &dummy, &dummy); +} + +void +cairo_font_current_transform (cairo_font_t *font, + cairo_matrix_t *matrix) +{ + cairo_matrix_set_affine (matrix, + font->scale.matrix[0][0], + font->scale.matrix[0][1], + font->scale.matrix[1][0], + font->scale.matrix[1][1], + 0, 0); +} - glyph_cache->ref_count--; - if (glyph_cache->ref_count) - return; - while (glyph_cache->last) - _cairo_glyph_cache_pop_last (glyph_cache); +/* Now we implement functions to access a default global image & metrics + * cache. + */ - free (glyph_cache); +unsigned long +_cairo_glyph_cache_hash (void *cache, void *key) +{ + cairo_glyph_cache_key_t *in; + in = (cairo_glyph_cache_key_t *) key; + return + ((unsigned long) in->unscaled) + ^ ((unsigned long) in->scale.matrix[0][0]) + ^ ((unsigned long) in->scale.matrix[0][1]) + ^ ((unsigned long) in->scale.matrix[1][0]) + ^ ((unsigned long) in->scale.matrix[1][1]) + ^ in->index; } -static void -_cairo_glyph_surface_init (cairo_font_t *font, - cairo_surface_t *surface, - const cairo_glyph_t *glyph, - cairo_glyph_surface_t *glyph_surface) +int +_cairo_glyph_cache_keys_equal (void *cache, + void *k1, + void *k2) { - cairo_surface_t *image; - - glyph_surface->surface = NULL; - glyph_surface->index = glyph->index; - glyph_surface->matrix[0][0] = font->matrix.m[0][0]; - glyph_surface->matrix[0][1] = font->matrix.m[0][1]; - glyph_surface->matrix[1][0] = font->matrix.m[1][0]; - glyph_surface->matrix[1][1] = font->matrix.m[1][1]; - - image = font->backend->create_glyph (font, glyph, &glyph_surface->size); - if (image == NULL) - return; - - if (surface->backend != image->backend) { - cairo_status_t status; - - glyph_surface->surface = - _cairo_surface_create_similar_scratch (surface, - CAIRO_FORMAT_A8, 0, - glyph_surface->size.width, - glyph_surface->size.height); - if (glyph_surface->surface == NULL) { - glyph_surface->surface = image; - return; - } - - status = _cairo_surface_set_image (glyph_surface->surface, - (cairo_image_surface_t *) image); - if (status) { - cairo_surface_destroy (glyph_surface->surface); - glyph_surface->surface = NULL; - } - cairo_surface_destroy (image); - } else - glyph_surface->surface = image; + cairo_glyph_cache_key_t *a, *b; + a = (cairo_glyph_cache_key_t *) k1; + b = (cairo_glyph_cache_key_t *) k2; + return (a->index == b->index) + && (a->unscaled == b->unscaled) + && (a->scale.matrix[0][0] == b->scale.matrix[0][0]) + && (a->scale.matrix[0][1] == b->scale.matrix[0][1]) + && (a->scale.matrix[1][0] == b->scale.matrix[1][0]) + && (a->scale.matrix[1][1] == b->scale.matrix[1][1]); } -cairo_surface_t * -_cairo_font_lookup_glyph (cairo_font_t *font, - cairo_surface_t *surface, - const cairo_glyph_t *glyph, - cairo_glyph_size_t *return_size) + +static cairo_status_t +_image_glyph_cache_create_entry (void *cache, + void *key, + void **return_value) { - cairo_glyph_surface_t glyph_surface; - cairo_glyph_cache_t *cache = font->glyph_cache; - cairo_glyph_surface_node_t *node; - - for (node = cache->first; node != NULL; node = node->next) { - cairo_glyph_surface_t *s = &node->s; - - if ((s->surface == NULL || s->surface->backend == surface->backend) && - s->index == glyph->index && - s->matrix[0][0] == font->matrix.m[0][0] && - s->matrix[0][1] == font->matrix.m[0][1] && - s->matrix[1][0] == font->matrix.m[1][0] && - s->matrix[1][1] == font->matrix.m[1][1]) { - - /* move node first in cache */ - if (node->prev) { - if (node->next == NULL) { - cache->last = node->prev; - node->prev->next = NULL; - } else { - node->prev->next = node->next; - node->next->prev = node->prev; - } - - node->prev = NULL; - node->next = cache->first; - cache->first = node; - if (node->next) - node->next->prev = node; - else - cache->last = node; - } - - cairo_surface_reference (s->surface); - *return_size = s->size; - - return s->surface; - } - } - - _cairo_glyph_surface_init (font, surface, glyph, &glyph_surface); + cairo_glyph_cache_key_t *k = (cairo_glyph_cache_key_t *) key; + cairo_image_glyph_cache_entry_t *im; + cairo_status_t status; - *return_size = glyph_surface.size; - - if (cache->cache_size > 0) { - if (cache->n_nodes == cache->cache_size) - _cairo_glyph_cache_pop_last (cache); - - node = malloc (sizeof (cairo_glyph_surface_node_t)); - if (node) { - cairo_surface_reference (glyph_surface.surface); - - /* insert node first in cache */ - node->s = glyph_surface; - node->prev = NULL; - node->next = cache->first; - cache->first = node; - if (node->next) - node->next->prev = node; - else - cache->last = node; - - cache->n_nodes++; - } + im = calloc (1, sizeof (cairo_image_glyph_cache_entry_t)); + if (im == NULL) + return CAIRO_STATUS_NO_MEMORY; + + im->key = *k; + status = im->key.unscaled->backend->create_glyph (im); + + if (status != CAIRO_STATUS_SUCCESS) { + free (im); + return status; } - - return glyph_surface.surface; + + _cairo_unscaled_font_reference (im->key.unscaled); + + im->key.base.memory = + sizeof (cairo_image_glyph_cache_entry_t) + + (im->image ? + sizeof (cairo_image_surface_t) + + 28 * sizeof (int) /* rough guess at size of pixman image structure */ + + (im->image->height * im->image->stride) : 0); + + *return_value = im; + + return CAIRO_STATUS_SUCCESS; } -/* public font interface follows */ -void -cairo_font_reference (cairo_font_t *font) +static void +_image_glyph_cache_destroy_entry (void *cache, + void *value) { - font->refcount++; + cairo_image_glyph_cache_entry_t *im; + + im = (cairo_image_glyph_cache_entry_t *) value; + _cairo_unscaled_font_destroy (im->key.unscaled); + cairo_surface_destroy (&(im->image->base)); + free (im); } -void -cairo_font_destroy (cairo_font_t *font) +static void +_image_glyph_cache_destroy_cache (void *cache) { - if (--(font->refcount) > 0) - return; + free (cache); +} - _cairo_glyph_cache_destroy (font->glyph_cache); +const cairo_cache_backend_t cairo_image_cache_backend = { + _cairo_glyph_cache_hash, + _cairo_glyph_cache_keys_equal, + _image_glyph_cache_create_entry, + _image_glyph_cache_destroy_entry, + _image_glyph_cache_destroy_cache +}; - if (font->backend->destroy) - font->backend->destroy (font); -} void -cairo_font_set_transform (cairo_font_t *font, - cairo_matrix_t *matrix) +_cairo_lock_global_image_glyph_cache() { - cairo_matrix_copy (&(font->matrix), matrix); + /* FIXME: implement locking. */ } void -cairo_font_current_transform (cairo_font_t *font, - cairo_matrix_t *matrix) +_cairo_unlock_global_image_glyph_cache() { - cairo_matrix_copy (matrix, &(font->matrix)); + /* FIXME: implement locking. */ +} + +static cairo_cache_t * +_global_image_glyph_cache = NULL; + +cairo_cache_t * +_cairo_get_global_image_glyph_cache () +{ + if (_global_image_glyph_cache == NULL) { + _global_image_glyph_cache = malloc (sizeof (cairo_cache_t)); + + if (_global_image_glyph_cache == NULL) + goto FAIL; + + if (_cairo_cache_init (_global_image_glyph_cache, + &cairo_image_cache_backend, + CAIRO_IMAGE_GLYPH_CACHE_MEMORY_DEFAULT)) + goto FAIL; + } + + return _global_image_glyph_cache; + + FAIL: + if (_global_image_glyph_cache) + free (_global_image_glyph_cache); + _global_image_glyph_cache = NULL; + return NULL; } diff --git a/src/cairo_ft_font.c b/src/cairo_ft_font.c index 5b0a7f64..f757db09 100644 --- a/src/cairo_ft_font.c +++ b/src/cairo_ft_font.c @@ -1,5 +1,5 @@ /* - * Copyright © 2003 Red Hat Inc. + * Copyright © 2003 Red Hat Inc. * * Permission to use, copy, modify, distribute, and sell this software and * its documentation for any purpose is hereby granted without fee, @@ -31,116 +31,294 @@ #include FT_OUTLINE_H #include FT_IMAGE_H -typedef struct { - cairo_font_t base; +#define DOUBLE_TO_26_6(d) ((FT_F26Dot6)((d) * 64.0)) +#define DOUBLE_FROM_26_6(t) ((double)(t) / 64.0) +#define DOUBLE_TO_16_16(d) ((FT_Fixed)((d) * 65536.0)) +#define DOUBLE_FROM_16_16(t) ((double)(t) / 65536.0) - FT_Library ft_library; - int owns_ft_library; +/* + * First we make a private, sharable implementation object which can be + * stored both in a private cache and in public font objects (including + * those connected to fonts we don't own) + */ + +typedef struct { + int refcount; FT_Face face; int owns_face; - FcPattern *pattern; -} cairo_ft_font_t; +} ft_font_val_t; -#define DOUBLE_TO_26_6(d) ((FT_F26Dot6)((d) * 64.0)) -#define DOUBLE_FROM_26_6(t) ((double)(t) / 64.0) -#define DOUBLE_TO_16_16(d) ((FT_Fixed)((d) * 65536.0)) -#define DOUBLE_FROM_16_16(t) ((double)(t) / 65536.0) +static ft_font_val_t * +_create_from_face (FT_Face face, int owns_face) +{ + ft_font_val_t *tmp = malloc (sizeof(ft_font_val_t)); + if (tmp) { + tmp->refcount = 1; + tmp->face = face; + tmp->owns_face = owns_face; + FT_Set_Char_Size (face, + DOUBLE_TO_26_6 (1.0), + DOUBLE_TO_26_6 (1.0), + 0, 0); + } + return tmp; +} -/* implement the platform-specific interface */ +static void +_reference_font_val (ft_font_val_t *f) +{ + f->refcount++; +} -cairo_font_t * -cairo_ft_font_create (FT_Library ft_library, FcPattern *pattern) +static void +_destroy_font_val (ft_font_val_t *f) { - cairo_ft_font_t *f = NULL; + if (--(f->refcount) > 0) + return; + + if (f->owns_face) + FT_Done_Face (f->face); + + free (f); +} + +static ft_font_val_t * +_create_from_library_and_pattern (FT_Library ft_library, FcPattern *pattern) +{ + ft_font_val_t *f = NULL; char *filename = NULL; - FT_Face face = NULL; int owns_face = 0; + FT_Face face = NULL; FcPattern *resolved = NULL; FcResult result = FcResultMatch; - + + if (pattern == NULL) + goto FAIL; + FcConfigSubstitute (0, pattern, FcMatchPattern); FcDefaultSubstitute (pattern); resolved = FcFontMatch (0, pattern, &result); + if (!resolved) + goto FAIL; + if (result != FcResultMatch) - { - if (resolved) - FcPatternDestroy (resolved); - return NULL; - } + goto FREE_RESOLVED; /* If the pattern has an FT_Face object, use that. */ if (FcPatternGetFTFace (resolved, FC_FT_FACE, 0, &face) != FcResultMatch || face == NULL) { - /* otherwise it had better have a filename */ - int open_res = 0; - owns_face = 1; result = FcPatternGetString (resolved, FC_FILE, 0, (FcChar8 **)(&filename)); if (result == FcResultMatch) - open_res = FT_New_Face (ft_library, filename, 0, &face); + if (FT_New_Face (ft_library, filename, 0, &face)) + goto FREE_RESOLVED; if (face == NULL) - return NULL; + goto FREE_RESOLVED; + + owns_face = 1; } - f = (cairo_ft_font_t *) cairo_ft_font_create_for_ft_face (face); - if (f != NULL) - f->pattern = FcPatternDuplicate (resolved); + f = _create_from_face (face, owns_face); + + FcPatternDestroy (resolved); + return f; + + FREE_RESOLVED: + if (resolved) + FcPatternDestroy (resolved); + + FAIL: + return NULL; +} - f->ft_library = ft_library; - f->owns_ft_library = 0; - f->owns_face = owns_face; +/* + * We then make the user-exposed structure out of one of these impls, such + * that it is reasonably cheap to copy and/or destroy. Unfortunately this + * duplicates a certain amount of the caching machinery in the font cache, + * but that's unavoidable as we also provide an FcPattern resolution API, + * which is not part of cairo's generic font finding system. + */ - FcPatternDestroy (resolved); - return (cairo_font_t *) f; +typedef struct { + cairo_unscaled_font_t base; + FcPattern *pattern; + ft_font_val_t *val; +} cairo_ft_font_t; + +/* + * We then make a key and entry type which are compatible with the generic + * cache system. This cache serves to share single ft_font_val_t instances + * between fonts (or between font lifecycles). + */ + +typedef struct { + cairo_cache_entry_base_t base; + FcPattern *pattern; +} cairo_ft_cache_key_t; + +typedef struct { + cairo_ft_cache_key_t key; + ft_font_val_t *val; +} cairo_ft_cache_entry_t; + +/* + * Then we create a cache which maps FcPattern keys to the refcounted + * ft_font_val_t values. + */ + +typedef struct { + cairo_cache_t base; + FT_Library lib; +} ft_cache_t; + + +static unsigned long +_ft_font_cache_hash (void *cache, void *key) +{ + cairo_ft_cache_key_t *in; + in = (cairo_ft_cache_key_t *) key; + return FcPatternHash (in->pattern); } -FT_Face -cairo_ft_font_face (cairo_font_t *abstract_font) +static int +_ft_font_cache_keys_equal (void *cache, + void *k1, + void *k2) { - cairo_ft_font_t *font = (cairo_ft_font_t *) abstract_font; + cairo_ft_cache_key_t *a; + cairo_ft_cache_key_t *b; + a = (cairo_ft_cache_key_t *) k1; + b = (cairo_ft_cache_key_t *) k2; + + return FcPatternEqual (a->pattern, b->pattern); +} - if (font == NULL) - return NULL; - return font->face; +static cairo_status_t +_ft_font_cache_create_entry (void *cache, + void *key, + void **return_entry) +{ + ft_cache_t *ftcache = (ft_cache_t *) cache; + cairo_ft_cache_key_t *k = (cairo_ft_cache_key_t *) key; + cairo_ft_cache_entry_t *entry; + + entry = malloc (sizeof (cairo_ft_cache_entry_t)); + if (entry == NULL) + return CAIRO_STATUS_NO_MEMORY; + + entry->key.pattern = FcPatternDuplicate (k->pattern); + if (!entry->key.pattern) { + free (entry); + return CAIRO_STATUS_NO_MEMORY; + } + + entry->val = _create_from_library_and_pattern (ftcache->lib, entry->key.pattern); + entry->key.base.memory = 1; + + *return_entry = entry; + + return CAIRO_STATUS_SUCCESS; } -FcPattern * -cairo_ft_font_pattern (cairo_font_t *abstract_font) +static void +_ft_font_cache_destroy_entry (void *cache, + void *entry) +{ + cairo_ft_cache_entry_t *e = (cairo_ft_cache_entry_t *) entry; + FcPatternDestroy (e->key.pattern); + _destroy_font_val (e->val); + free (e); +} + +static void +_ft_font_cache_destroy_cache (void *cache) { - cairo_ft_font_t *font = (cairo_ft_font_t *) abstract_font; + ft_cache_t *fc = (ft_cache_t *) cache; + FT_Done_FreeType (fc->lib); + free (fc); +} - if (font == NULL) - return NULL; +const struct cairo_cache_backend _ft_font_cache_backend = { + _ft_font_cache_hash, + _ft_font_cache_keys_equal, + _ft_font_cache_create_entry, + _ft_font_cache_destroy_entry, + _ft_font_cache_destroy_cache +}; - return font->pattern; + +static ft_cache_t *_global_ft_cache = NULL; + +static void +_lock_global_ft_cache (void) +{ + /* FIXME: Perform locking here. */ +} + +static void +_unlock_global_ft_cache (void) +{ + /* FIXME: Perform locking here. */ +} + +static cairo_cache_t * +_get_global_ft_cache (void) +{ + if (_global_ft_cache == NULL) + { + _global_ft_cache = malloc (sizeof(ft_cache_t)); + if (!_global_ft_cache) + goto FAIL; + + if (_cairo_cache_init (&_global_ft_cache->base, + &_ft_font_cache_backend, + CAIRO_FT_CACHE_NUM_FONTS_DEFAULT)) + goto FAIL; + + if (FT_Init_FreeType (&_global_ft_cache->lib)) + goto FAIL; + } + return &_global_ft_cache->base; + + FAIL: + if (_global_ft_cache) + free (_global_ft_cache); + _global_ft_cache = NULL; + return NULL; } /* implement the backend interface */ -static cairo_font_t * +const struct cairo_font_backend cairo_ft_font_backend; + +static cairo_unscaled_font_t * _cairo_ft_font_create (const char *family, cairo_font_slant_t slant, cairo_font_weight_t weight) { - cairo_ft_font_t *ft_font = NULL; - cairo_font_t *font = NULL; - FcPattern * pat = NULL; + cairo_status_t status; + cairo_ft_font_t *font = NULL; int fcslant; int fcweight; - FT_Library ft_library; - FT_Error error; + cairo_cache_t *cache; + cairo_ft_cache_entry_t *entry; + cairo_ft_cache_key_t key; - pat = FcPatternCreate (); - if (pat == NULL) - return NULL; + key.pattern = FcPatternCreate (); + if (key.pattern == NULL) + goto FAIL; + + font = malloc (sizeof (cairo_ft_font_t)); + if (font == NULL) + goto FREE_PATTERN; switch (weight) { @@ -167,52 +345,44 @@ _cairo_ft_font_create (const char *family, break; } - FcPatternAddString (pat, FC_FAMILY, family); - FcPatternAddInteger (pat, FC_SLANT, fcslant); - FcPatternAddInteger (pat, FC_WEIGHT, fcweight); + FcPatternAddString (key.pattern, FC_FAMILY, family); + FcPatternAddInteger (key.pattern, FC_SLANT, fcslant); + FcPatternAddInteger (key.pattern, FC_WEIGHT, fcweight); - error = FT_Init_FreeType (&ft_library); - if (error) { - FcPatternDestroy (pat); - return NULL; - } + if (_cairo_unscaled_font_init (&font->base, &cairo_ft_font_backend)) + goto FREE_PATTERN; - font = cairo_ft_font_create (ft_library, pat); - if (font == NULL) - return NULL; + _lock_global_ft_cache (); + cache = _get_global_ft_cache (); + if (cache == NULL) { + _unlock_global_ft_cache (); + goto FREE_PATTERN; + } - ft_font = (cairo_ft_font_t *) font; + status = _cairo_cache_lookup (cache, &key, (void **) &entry); + _unlock_global_ft_cache (); - ft_font->owns_ft_library = 1; + if (status) + goto FREE_PATTERN; - FT_Set_Char_Size (ft_font->face, - DOUBLE_TO_26_6 (1.0), - DOUBLE_TO_26_6 (1.0), - 0, 0); - - FcPatternDestroy (pat); - return font; -} + font->pattern = FcPatternDuplicate (entry->key.pattern); + if (font->pattern == NULL) + goto FREE_PATTERN; -static cairo_font_t * -_cairo_ft_font_copy (void *abstract_font) -{ - cairo_ft_font_t * font_new = NULL; - cairo_ft_font_t * font = abstract_font; - - if (font->base.backend != &cairo_ft_font_backend) - return NULL; + font->val = entry->val; + _reference_font_val (font->val); + + return &font->base; - font_new = (cairo_ft_font_t *) cairo_ft_font_create_for_ft_face (font->face); - if (font_new == NULL) - return NULL; + FREE_PATTERN: + FcPatternDestroy (key.pattern); - if (font_new != NULL && font->pattern != NULL) - font_new->pattern = FcPatternDuplicate (font->pattern); + FAIL: + return NULL; - return (cairo_font_t *) font_new; } + static void _cairo_ft_font_destroy (void *abstract_font) { @@ -220,15 +390,11 @@ _cairo_ft_font_destroy (void *abstract_font) if (font == NULL) return; - - if (font->face != NULL && font->owns_face) - FT_Done_Face (font->face); if (font->pattern != NULL) FcPatternDestroy (font->pattern); - if (font->ft_library && font->owns_ft_library) - FT_Done_FreeType (font->ft_library); + _destroy_font_val (font->val); free (font); } @@ -268,7 +434,7 @@ _utf8_to_ucs4 (char const *utf8, } static void -_install_font_matrix(cairo_matrix_t *matrix, FT_Face face) +_install_font_scale (cairo_font_scale_t *sc, FT_Face face) { cairo_matrix_t normalized; double scale_x, scale_y; @@ -276,16 +442,20 @@ _install_font_matrix(cairo_matrix_t *matrix, FT_Face face) FT_Matrix mat; /* The font matrix has x and y "scale" components which we extract and - * use as pixel scale values. These influence the way freetype chooses - * hints, as well as selecting different bitmaps in hand-rendered - * fonts. We also copy the normalized matrix to freetype's - * transformation. + * use as character scale values. These influence the way freetype + * chooses hints, as well as selecting different bitmaps in + * hand-rendered fonts. We also copy the normalized matrix to + * freetype's transformation. */ - _cairo_matrix_compute_scale_factors (matrix, &scale_x, &scale_y); - - cairo_matrix_copy (&normalized, matrix); + cairo_matrix_set_affine (&normalized, + sc->matrix[0][0], + sc->matrix[0][1], + sc->matrix[1][0], + sc->matrix[1][1], + 0, 0); + _cairo_matrix_compute_scale_factors (&normalized, &scale_x, &scale_y); cairo_matrix_scale (&normalized, 1.0 / scale_x, 1.0 / scale_y); cairo_matrix_get_affine (&normalized, &xx /* 00 */ , &yx /* 01 */, @@ -298,21 +468,28 @@ _install_font_matrix(cairo_matrix_t *matrix, FT_Face face) mat.yy = DOUBLE_TO_16_16(yy); FT_Set_Transform(face, &mat, NULL); - FT_Set_Char_Size(face, - DOUBLE_TO_26_6(scale_x), - DOUBLE_TO_26_6(scale_y), - 0, 0); + + FT_Set_Pixel_Sizes(face, + (FT_UInt) scale_x, + (FT_UInt) scale_y); } -static int -_utf8_to_glyphs (cairo_ft_font_t *font, - const unsigned char *utf8, - double x0, - double y0, - cairo_glyph_t **glyphs, - size_t *nglyphs) +static cairo_status_t +_cairo_ft_font_text_to_glyphs (void *abstract_font, + cairo_font_scale_t *sc, + const unsigned char *utf8, + cairo_glyph_t **glyphs, + int *nglyphs) { - FT_Face face = font->face; + cairo_ft_font_t *font = abstract_font; + FT_Face face = font->val->face; + cairo_glyph_cache_key_t key; + cairo_image_glyph_cache_entry_t *val; + cairo_cache_t *cache; + + key.unscaled = &font->base; + key.scale = *sc; + double x = 0., y = 0.; size_t i; FT_ULong *ucs4 = NULL; @@ -320,56 +497,70 @@ _utf8_to_glyphs (cairo_ft_font_t *font, _utf8_to_ucs4 (utf8, &ucs4, nglyphs); if (ucs4 == NULL) - return 0; + return CAIRO_STATUS_NO_MEMORY; *glyphs = (cairo_glyph_t *) malloc ((*nglyphs) * (sizeof (cairo_glyph_t))); if (*glyphs == NULL) { free (ucs4); - return 0; + return CAIRO_STATUS_NO_MEMORY; } - _install_font_matrix (&font->base.matrix, face); + _cairo_lock_global_image_glyph_cache (); + cache = _cairo_get_global_image_glyph_cache (); + if (cache == NULL) { + _cairo_unlock_global_image_glyph_cache (); + return CAIRO_STATUS_NO_MEMORY; + } for (i = 0; i < *nglyphs; i++) { (*glyphs)[i].index = FT_Get_Char_Index (face, ucs4[i]); - (*glyphs)[i].x = x0 + x; - (*glyphs)[i].y = y0 + y; - - FT_Load_Glyph (face, (*glyphs)[i].index, FT_LOAD_DEFAULT); + (*glyphs)[i].x = x; + (*glyphs)[i].y = y; - x += DOUBLE_FROM_26_6 (face->glyph->advance.x); - y -= DOUBLE_FROM_26_6 (face->glyph->advance.y); + val = NULL; + key.index = (*glyphs)[i].index; + + if (_cairo_cache_lookup (cache, &key, (void **) &val) + != CAIRO_STATUS_SUCCESS || val == NULL) + continue; + + x += val->extents.x_advance; + y -= val->extents.y_advance; } + _cairo_unlock_global_image_glyph_cache (); free (ucs4); - return 1; + return CAIRO_STATUS_SUCCESS; } + static cairo_status_t _cairo_ft_font_font_extents (void *abstract_font, + cairo_font_scale_t *sc, cairo_font_extents_t *extents) { cairo_ft_font_t *font = abstract_font; - FT_Face face = font->face; - double scale_x, scale_y; + FT_Face face = font->val->face; + FT_Size_Metrics *metrics = &face->size->metrics; - double upm = face->units_per_EM; + _install_font_scale (sc, face); - _cairo_matrix_compute_scale_factors (&font->base.matrix, &scale_x, &scale_y); + extents->ascent = DOUBLE_FROM_26_6(metrics->ascender); + extents->descent = DOUBLE_FROM_26_6(metrics->descender); + extents->height = DOUBLE_FROM_26_6(metrics->height); + extents->max_x_advance = DOUBLE_FROM_26_6(metrics->max_advance); - extents->ascent = face->ascender / upm * scale_y; - extents->descent = face->descender / upm * scale_y; - extents->height = face->height / upm * scale_y; - extents->max_x_advance = face->max_advance_width / upm * scale_x; - extents->max_y_advance = face->max_advance_height / upm * scale_y; + /* FIXME: this doesn't do vertical layout atm. */ + extents->max_y_advance = 0.0; return CAIRO_STATUS_SUCCESS; } static cairo_status_t _cairo_ft_font_glyph_extents (void *abstract_font, + cairo_font_scale_t *sc, cairo_glyph_t *glyphs, int num_glyphs, cairo_text_extents_t *extents) @@ -379,10 +570,10 @@ _cairo_ft_font_glyph_extents (void *abstract_font, cairo_point_double_t origin; cairo_point_double_t glyph_min, glyph_max; cairo_point_double_t total_min, total_max; - FT_Error error; - FT_Face face = font->face; - FT_GlyphSlot glyph = face->glyph; - FT_Glyph_Metrics *metrics = &glyph->metrics; + + cairo_image_glyph_cache_entry_t *img = NULL; + cairo_cache_t *cache; + cairo_glyph_cache_key_t key; if (num_glyphs == 0) { @@ -399,24 +590,33 @@ _cairo_ft_font_glyph_extents (void *abstract_font, origin.x = glyphs[0].x; origin.y = glyphs[0].y; - _install_font_matrix (&font->base.matrix, face); + _cairo_lock_global_image_glyph_cache (); + cache = _cairo_get_global_image_glyph_cache (); + if (cache == NULL) { + _cairo_unlock_global_image_glyph_cache (); + return CAIRO_STATUS_NO_MEMORY; + } + + key.unscaled = &font->base; + key.scale = *sc; for (i = 0; i < num_glyphs; i++) { - error = FT_Load_Glyph (face, glyphs[i].index, FT_LOAD_DEFAULT); - /* XXX: What to do in this error case? */ - if (error) + img = NULL; + key.index = glyphs[i].index; + if (_cairo_cache_lookup (cache, &key, (void **) &img) + != CAIRO_STATUS_SUCCESS || img == NULL) continue; - + /* XXX: Need to add code here to check the font's FcPattern for FC_VERTICAL_LAYOUT and if set get vertBearingX/Y instead. This will require that cairo_ft_font_create_for_ft_face accept an FcPattern. */ - glyph_min.x = glyphs[i].x + DOUBLE_FROM_26_6 (metrics->horiBearingX); - glyph_min.y = glyphs[i].y - DOUBLE_FROM_26_6 (metrics->horiBearingY); - glyph_max.x = glyph_min.x + DOUBLE_FROM_26_6 (metrics->width); - glyph_max.y = glyph_min.y + DOUBLE_FROM_26_6 (metrics->height); + glyph_min.x = glyphs[i].x + img->extents.x_bearing; + glyph_min.y = glyphs[i].y - img->extents.y_bearing; + glyph_max.x = glyph_min.x + img->extents.width; + glyph_max.y = glyph_min.y + img->extents.height; if (i==0) { total_min = glyph_min; @@ -433,12 +633,13 @@ _cairo_ft_font_glyph_extents (void *abstract_font, total_max.y = glyph_max.y; } } + _cairo_unlock_global_image_glyph_cache (); extents->x_bearing = total_min.x - origin.x; extents->y_bearing = total_min.y - origin.y; extents->width = total_max.x - total_min.x; extents->height = total_max.y - total_min.y; - extents->x_advance = glyphs[i-1].x + DOUBLE_FROM_26_6 (metrics->horiAdvance) - origin.x; + extents->x_advance = glyphs[i-1].x + (img == NULL ? 0 : img->extents.x_advance) - origin.x; extents->y_advance = glyphs[i-1].y + 0 - origin.y; return CAIRO_STATUS_SUCCESS; @@ -446,34 +647,16 @@ _cairo_ft_font_glyph_extents (void *abstract_font, static cairo_status_t -_cairo_ft_font_text_extents (void *abstract_font, - const unsigned char *utf8, - cairo_text_extents_t *extents) -{ - cairo_ft_font_t *font = abstract_font; - cairo_glyph_t *glyphs; - size_t nglyphs; - cairo_status_t status = CAIRO_STATUS_SUCCESS; - - if (_utf8_to_glyphs (font, utf8, 0, 0, &glyphs, &nglyphs)) - { - status = _cairo_ft_font_glyph_extents (font, glyphs, nglyphs, - extents); - free (glyphs); - } - return status; -} - -static cairo_status_t -_cairo_ft_font_glyph_bbox (void *abstract_font, - cairo_surface_t *surface, - const cairo_glyph_t *glyphs, - int num_glyphs, - cairo_box_t *bbox) +_cairo_ft_font_glyph_bbox (void *abstract_font, + cairo_font_scale_t *sc, + const cairo_glyph_t *glyphs, + int num_glyphs, + cairo_box_t *bbox) { + cairo_image_glyph_cache_entry_t *img; + cairo_cache_t *cache; + cairo_glyph_cache_key_t key; cairo_ft_font_t *font = abstract_font; - cairo_surface_t *mask = NULL; - cairo_glyph_size_t size; cairo_fixed_t x1, y1, x2, y2; int i; @@ -481,22 +664,33 @@ _cairo_ft_font_glyph_bbox (void *abstract_font, bbox->p1.x = bbox->p1.y = CAIRO_MAXSHORT << 16; bbox->p2.x = bbox->p2.y = CAIRO_MINSHORT << 16; - if (font == NULL - || surface == NULL - || glyphs == NULL) + _cairo_lock_global_image_glyph_cache (); + cache = _cairo_get_global_image_glyph_cache(); + + if (cache == NULL + || font == NULL + || glyphs == NULL) { + _cairo_unlock_global_image_glyph_cache (); return CAIRO_STATUS_NO_MEMORY; + } + + key.unscaled = &font->base; + key.scale = *sc; for (i = 0; i < num_glyphs; i++) { - mask = _cairo_font_lookup_glyph (&font->base, surface, - &glyphs[i], &size); - if (mask == NULL) + + img = NULL; + key.index = glyphs[i].index; + + if (_cairo_cache_lookup (cache, &key, (void **) &img) + != CAIRO_STATUS_SUCCESS || img == NULL) continue; - x1 = _cairo_fixed_from_double (glyphs[i].x + size.x); - y1 = _cairo_fixed_from_double (glyphs[i].y - size.y); - x2 = x1 + _cairo_fixed_from_double (size.width); - y2 = y1 + _cairo_fixed_from_double (size.height); + x1 = _cairo_fixed_from_double (glyphs[i].x + img->size.x); + y1 = _cairo_fixed_from_double (glyphs[i].y - img->size.y); + x2 = x1 + _cairo_fixed_from_double (img->size.width); + y2 = y1 + _cairo_fixed_from_double (img->size.height); if (x1 < bbox->p1.x) bbox->p1.x = x1; @@ -509,117 +703,82 @@ _cairo_ft_font_glyph_bbox (void *abstract_font, if (y2 > bbox->p2.y) bbox->p2.y = y2; - - if (mask) - cairo_surface_destroy (mask); } + _cairo_unlock_global_image_glyph_cache (); return CAIRO_STATUS_SUCCESS; } -static cairo_status_t -_cairo_ft_font_text_bbox (void *abstract_font, - cairo_surface_t *surface, - double x0, - double y0, - const unsigned char *utf8, - cairo_box_t *bbox) -{ - cairo_ft_font_t *font = abstract_font; - cairo_glyph_t *glyphs; - size_t num_glyphs; - - if (_utf8_to_glyphs (font, utf8, x0, y0, &glyphs, &num_glyphs)) - { - cairo_status_t res; - res = _cairo_ft_font_glyph_bbox (font, surface, - glyphs, num_glyphs, bbox); - free (glyphs); - return res; - } - else - return CAIRO_STATUS_NO_MEMORY; -} static cairo_status_t -_cairo_ft_font_show_glyphs (void *abstract_font, - cairo_operator_t operator, - cairo_surface_t *source, - cairo_surface_t *surface, - int source_x, - int source_y, - const cairo_glyph_t *glyphs, - int num_glyphs) +_cairo_ft_font_show_glyphs (void *abstract_font, + cairo_font_scale_t *sc, + cairo_operator_t operator, + cairo_surface_t *source, + cairo_surface_t *surface, + int source_x, + int source_y, + const cairo_glyph_t *glyphs, + int num_glyphs) { + cairo_image_glyph_cache_entry_t *img; + cairo_cache_t *cache; + cairo_glyph_cache_key_t key; cairo_ft_font_t *font = abstract_font; cairo_status_t status; - cairo_surface_t *mask = NULL; - cairo_glyph_size_t size; double x, y; int i; - if (font == NULL + _cairo_lock_global_image_glyph_cache (); + cache = _cairo_get_global_image_glyph_cache(); + + if (cache == NULL + || font == NULL || source == NULL || surface == NULL - || glyphs == NULL) + || glyphs == NULL) { + _cairo_unlock_global_image_glyph_cache (); return CAIRO_STATUS_NO_MEMORY; + } + + key.unscaled = &font->base; + key.scale = *sc; for (i = 0; i < num_glyphs; i++) { - mask = _cairo_font_lookup_glyph (&font->base, surface, - &glyphs[i], &size); - if (mask == NULL) + img = NULL; + key.index = glyphs[i].index; + + if (_cairo_cache_lookup (cache, &key, (void **) &img) + != CAIRO_STATUS_SUCCESS + || img == NULL + || img->image == NULL) continue; x = glyphs[i].x; y = glyphs[i].y; - status = _cairo_surface_composite (operator, source, mask, surface, - source_x + x + size.x, - source_y + y - size.y, + status = _cairo_surface_composite (operator, source, + &(img->image->base), + surface, + source_x + x + img->size.x, + source_y + y - img->size.y, 0, 0, - x + size.x, - y - size.y, - (double) size.width, - (double) size.height); - - cairo_surface_destroy (mask); + x + img->size.x, + y - img->size.y, + (double) img->size.width, + (double) img->size.height); - if (status) + if (status) { + _cairo_unlock_global_image_glyph_cache (); return status; + } } + _cairo_unlock_global_image_glyph_cache (); return CAIRO_STATUS_SUCCESS; } -static cairo_status_t -_cairo_ft_font_show_text (void *abstract_font, - cairo_operator_t operator, - cairo_surface_t *source, - cairo_surface_t *surface, - int source_x, - int source_y, - double x0, - double y0, - const unsigned char *utf8) -{ - cairo_ft_font_t *font = abstract_font; - cairo_glyph_t *glyphs; - size_t num_glyphs; - - if (_utf8_to_glyphs (font, utf8, x0, y0, &glyphs, &num_glyphs)) - { - cairo_status_t res; - res = _cairo_ft_font_show_glyphs (font, operator, - source, surface, - source_x, source_y, - glyphs, num_glyphs); - free (glyphs); - return res; - } - else - return CAIRO_STATUS_NO_MEMORY; -} static int _move_to (FT_Vector *to, void *closure) @@ -699,10 +858,11 @@ _cubic_to (FT_Vector *control1, FT_Vector *control2, FT_Vector *to, void *closur } static cairo_status_t -_cairo_ft_font_glyph_path (void *abstract_font, - cairo_glyph_t *glyphs, - int num_glyphs, - cairo_path_t *path) +_cairo_ft_font_glyph_path (void *abstract_font, + cairo_font_scale_t *sc, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_path_t *path) { int i; cairo_ft_font_t *font = abstract_font; @@ -717,8 +877,9 @@ _cairo_ft_font_glyph_path (void *abstract_font, 0, /* delta */ }; - glyph = font->face->glyph; - _install_font_matrix (&font->base.matrix, font->face); + glyph = font->val->face->glyph; + + _install_font_scale (sc, font->val->face); for (i = 0; i < num_glyphs; i++) { @@ -727,7 +888,7 @@ _cairo_ft_font_glyph_path (void *abstract_font, 0, DOUBLE_TO_16_16 (-1.0), }; - error = FT_Load_Glyph (font->face, glyphs[i].index, FT_LOAD_DEFAULT); + error = FT_Load_Glyph (font->val->face, glyphs[i].index, FT_LOAD_DEFAULT); /* XXX: What to do in this error case? */ if (error) continue; @@ -747,130 +908,218 @@ _cairo_ft_font_glyph_path (void *abstract_font, return CAIRO_STATUS_SUCCESS; } -static cairo_status_t -_cairo_ft_font_text_path (void *abstract_font, - double x, - double y, - const unsigned char *utf8, - cairo_path_t *path) -{ - cairo_ft_font_t *font = abstract_font; - cairo_glyph_t *glyphs; - size_t nglyphs; - - if (_utf8_to_glyphs (font, utf8, x, y, &glyphs, &nglyphs)) - { - cairo_status_t res; - res = _cairo_ft_font_glyph_path (font, glyphs, nglyphs, path); - free (glyphs); - return res; - } - else - return CAIRO_STATUS_NO_MEMORY; -} - -cairo_font_t * -cairo_ft_font_create_for_ft_face (FT_Face face) -{ - cairo_ft_font_t *f = NULL; - - f = malloc (sizeof (cairo_ft_font_t)); - if (f == NULL) - return NULL; - memset (f, 0, sizeof (cairo_ft_font_t)); - - _cairo_font_init (&f->base, - &cairo_ft_font_backend); - - f->ft_library = NULL; - f->owns_ft_library = 0; - - f->face = face; - f->owns_face = 0; - return (cairo_font_t *) f; -} - -static cairo_surface_t * -_cairo_ft_font_create_glyph (void *abstract_font, - const cairo_glyph_t *glyph, - cairo_glyph_size_t *return_size) +static cairo_status_t +_cairo_ft_font_create_glyph(cairo_image_glyph_cache_entry_t *val) { - cairo_ft_font_t *font = abstract_font; - cairo_image_surface_t *image; + cairo_ft_font_t *font = (cairo_ft_font_t *)val->key.unscaled; FT_GlyphSlot glyphslot; unsigned int width, height, stride; FT_Outline *outline; FT_BBox cbox; FT_Bitmap bitmap; - - glyphslot = font->face->glyph; - _install_font_matrix (&font->base.matrix, font->face); + FT_Glyph_Metrics *metrics; - FT_Load_Glyph (font->face, glyph->index, FT_LOAD_DEFAULT); + glyphslot = font->val->face->glyph; + metrics = &glyphslot->metrics; - outline = &glyphslot->outline; + _install_font_scale (&val->key.scale, font->val->face); + + if (FT_Load_Glyph (font->val->face, val->key.index, FT_LOAD_DEFAULT) != 0) + return CAIRO_STATUS_NO_MEMORY; + + val->extents.x_bearing = DOUBLE_FROM_26_6 (metrics->horiBearingX); + val->extents.y_bearing = DOUBLE_FROM_26_6 (metrics->horiBearingY); + val->extents.width = DOUBLE_FROM_26_6 (metrics->width); + val->extents.height = DOUBLE_FROM_26_6 (metrics->height); + val->extents.x_advance = DOUBLE_FROM_26_6 (font->val->face->glyph->advance.x); + val->extents.y_advance = DOUBLE_FROM_26_6 (font->val->face->glyph->advance.y); + outline = &glyphslot->outline; + FT_Outline_Get_CBox (outline, &cbox); cbox.xMin &= -64; cbox.yMin &= -64; cbox.xMax = (cbox.xMax + 63) & -64; cbox.yMax = (cbox.yMax + 63) & -64; - + width = (unsigned int) ((cbox.xMax - cbox.xMin) >> 6); height = (unsigned int) ((cbox.yMax - cbox.yMin) >> 6); stride = (width + 3) & -4; - bitmap.pixel_mode = ft_pixel_mode_grays; - bitmap.num_grays = 256; - bitmap.width = width; - bitmap.rows = height; - bitmap.pitch = stride; - if (width * height == 0) - return NULL; - - bitmap.buffer = malloc (stride * height); - if (bitmap.buffer == NULL) - return NULL; - - memset (bitmap.buffer, 0x0, stride * height); + val->image = NULL; + else + { - FT_Outline_Translate (outline, -cbox.xMin, -cbox.yMin); - FT_Outline_Get_Bitmap (glyphslot->library, outline, &bitmap); - - image = (cairo_image_surface_t *) + bitmap.pixel_mode = ft_pixel_mode_grays; + bitmap.num_grays = 256; + bitmap.width = width; + bitmap.rows = height; + bitmap.pitch = stride; + bitmap.buffer = calloc (1, stride * height); + + if (bitmap.buffer == NULL) { + return CAIRO_STATUS_NO_MEMORY; + }; + + FT_Outline_Translate (outline, -cbox.xMin, -cbox.yMin); + + if (FT_Outline_Get_Bitmap (glyphslot->library, outline, &bitmap) != 0) { + free (bitmap.buffer); + return CAIRO_STATUS_NO_MEMORY; + } + + val->image = (cairo_image_surface_t *) cairo_image_surface_create_for_data ((char *) bitmap.buffer, CAIRO_FORMAT_A8, width, height, stride); - if (image == NULL) { - free (bitmap.buffer); - return NULL; + if (val->image == NULL) { + free (bitmap.buffer); + return CAIRO_STATUS_NO_MEMORY; + } + + _cairo_image_surface_assume_ownership_of_data (val->image); } - - _cairo_image_surface_assume_ownership_of_data (image); - - return_size->width = (unsigned short) width; - return_size->height = (unsigned short) height; - return_size->x = (short) (cbox.xMin >> 6); - return_size->y = (short) (cbox.yMax >> 6); - return &image->base; + val->size.width = (unsigned short) width; + val->size.height = (unsigned short) height; + val->size.x = (short) (cbox.xMin >> 6); + val->size.y = (short) (cbox.yMax >> 6); + + return CAIRO_STATUS_SUCCESS; } const struct cairo_font_backend cairo_ft_font_backend = { _cairo_ft_font_create, - _cairo_ft_font_copy, _cairo_ft_font_destroy, _cairo_ft_font_font_extents, - _cairo_ft_font_text_extents, + _cairo_ft_font_text_to_glyphs, _cairo_ft_font_glyph_extents, - _cairo_ft_font_text_bbox, _cairo_ft_font_glyph_bbox, - _cairo_ft_font_show_text, _cairo_ft_font_show_glyphs, - _cairo_ft_font_text_path, _cairo_ft_font_glyph_path, _cairo_ft_font_create_glyph }; + + +/* implement the platform-specific interface */ + +cairo_font_t * +cairo_ft_font_create (FT_Library ft_library, FcPattern *pattern) +{ + cairo_font_scale_t scale; + cairo_font_t *scaled; + cairo_ft_font_t *f = NULL; + ft_font_val_t *v = NULL; + FcPattern *dup; + + scale.matrix[0][0] = 1.; + scale.matrix[0][1] = 0.; + scale.matrix[1][0] = 0.; + scale.matrix[1][1] = 1.; + + scaled = malloc (sizeof (cairo_font_t)); + if (scaled == NULL) + goto FAIL; + + dup = FcPatternDuplicate(pattern); + if (dup == NULL) + goto FREE_SCALED; + + v = _create_from_library_and_pattern (ft_library, pattern); + if (v == NULL) + goto FREE_PATTERN; + + f = malloc (sizeof(cairo_ft_font_t)); + if (f == NULL) + goto FREE_VAL; + + if (_cairo_unscaled_font_init (&f->base, &cairo_ft_font_backend)) + goto FREE_VAL; + + f->pattern = dup; + f->val = v; + + _cairo_font_init (scaled, &scale, &f->base); + + return scaled; + + FREE_VAL: + _destroy_font_val (v); + + FREE_PATTERN: + FcPatternDestroy (dup); + + FREE_SCALED: + free (scaled); + + FAIL: + return NULL; +} + +cairo_font_t * +cairo_ft_font_create_for_ft_face (FT_Face face) +{ + cairo_font_scale_t scale; + cairo_font_t *scaled; + cairo_ft_font_t *f = NULL; + ft_font_val_t *v = NULL; + + scale.matrix[0][0] = 1.; + scale.matrix[0][1] = 0.; + scale.matrix[1][0] = 0.; + scale.matrix[1][1] = 1.; + + scaled = malloc (sizeof (cairo_font_t)); + if (scaled == NULL) + goto FAIL; + + v = _create_from_face (face, 0); + if (v == NULL) + goto FREE_SCALED; + + f = malloc (sizeof(cairo_ft_font_t)); + if (f == NULL) + goto FREE_VAL; + + _cairo_unscaled_font_init (&f->base, &cairo_ft_font_backend); + f->pattern = NULL; + f->val = v; + + _cairo_font_init (scaled, &scale, &f->base); + + return scaled; + + FREE_VAL: + _destroy_font_val (v); + + FREE_SCALED: + free (scaled); + + FAIL: + return NULL; +} + +FT_Face +cairo_ft_font_face (cairo_font_t *abstract_font) +{ + cairo_ft_font_t *font = (cairo_ft_font_t *) abstract_font->unscaled; + + if (font == NULL || font->val == NULL) + return NULL; + + return font->val->face; +} + +FcPattern * +cairo_ft_font_pattern (cairo_font_t *abstract_font) +{ + cairo_ft_font_t *font = (cairo_ft_font_t *) abstract_font->unscaled; + + if (font == NULL) + return NULL; + + return font->pattern; +} diff --git a/src/cairo_gl_surface.c b/src/cairo_gl_surface.c deleted file mode 100644 index b56fc5fc..00000000 --- a/src/cairo_gl_surface.c +++ /dev/null @@ -1,967 +0,0 @@ -/* cairo - a vector graphics library with display and print output - * - * Copyright © 2004 David Reveman - * - * Permission to use, copy, modify, distribute, and sell this software - * and its documentation for any purpose is hereby granted without - * fee, provided that the above copyright notice appear in all copies - * and that both that copyright notice and this permission notice - * appear in supporting documentation, and that the name of David - * Reveman not be used in advertising or publicity pertaining to - * distribution of the software without specific, written prior - * permission. David Reveman makes no representations about the - * suitability of this software for any purpose. It is provided "as - * is" without express or implied warranty. - * - * DAVID REVEMAN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS - * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS, IN NO EVENT SHALL DAVID REVEMAN BE LIABLE FOR ANY SPECIAL, - * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER - * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION - * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR - * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - * Author: David Reveman <c99drn@cs.umu.se> - */ - -#include "cairoint.h" - -static cairo_surface_t * -_cairo_gl_surface_create (glitz_surface_t *surface, - int owns_surface); - -void -cairo_set_target_gl (cairo_t *cr, glitz_surface_t *surface) -{ - cairo_surface_t *crsurface; - - if (cr->status && cr->status != CAIRO_STATUS_NO_TARGET_SURFACE) - return; - - if (glitz_surface_get_hints (surface) & GLITZ_HINT_PROGRAMMATIC_MASK) { - cr->status = CAIRO_STATUS_NO_TARGET_SURFACE; - return; - } - - crsurface = _cairo_gl_surface_create (surface, 0); - if (crsurface == NULL) { - cr->status = CAIRO_STATUS_NO_MEMORY; - return; - } - - cairo_set_target_surface (cr, crsurface); - - cairo_surface_destroy (crsurface); -} - -typedef struct cairo_gl_surface cairo_gl_surface_t; - -struct cairo_gl_surface { - cairo_surface_t base; - - glitz_format_t *format; - long int features; - long int hints; - int owns_surface; - unsigned short opacity; - - cairo_pattern_t pattern; - cairo_box_t pattern_box; - - glitz_surface_t *surface; -}; - -#define CAIRO_GL_MULTITEXTURE_SUPPORT(surface) \ - (surface->features & GLITZ_FEATURE_ARB_MULTITEXTURE_MASK) - -#define CAIRO_GL_OFFSCREEN_SUPPORT(surface) \ - (surface->features & GLITZ_FEATURE_OFFSCREEN_DRAWING_MASK) - -#define CAIRO_GL_CONVOLUTION_SUPPORT(surface) \ - (surface->features & GLITZ_FEATURE_CONVOLUTION_FILTER_MASK) - -#define CAIRO_GL_FRAGMENT_PROGRAM_SUPPORT(surface) \ - (surface->features & GLITZ_FEATURE_ARB_FRAGMENT_PROGRAM_MASK) - -#define CAIRO_GL_TEXTURE_NPOT_SUPPORT(surface) \ - (surface->features & GLITZ_FEATURE_TEXTURE_NPOT_MASK) - -#define CAIRO_GL_TEXTURE_MIRRORED_REPEAT_SUPPORT(surface) \ - (surface->features & GLITZ_FEATURE_TEXTURE_MIRRORED_REPEAT_MASK) - -#define CAIRO_GL_COMPOSITE_TRAPEZOIDS_SUPPORT(surface) \ - (surface->format->stencil_size >= \ - ((surface->hints & GLITZ_HINT_CLIPPING_MASK)? 2: 1)) - -#define CAIRO_GL_SURFACE_IS_DRAWABLE(surface) \ - ((surface->hints & GLITZ_HINT_OFFSCREEN_MASK)? \ - surface->format->draw.offscreen: surface->format->draw.onscreen) - -#define CAIRO_GL_SURFACE_IS_SOLID(surface) \ - ((surface->hints & GLITZ_HINT_PROGRAMMATIC_MASK) && \ - (surface->pattern.type == CAIRO_PATTERN_SOLID)) - -#define CAIRO_GL_SURFACE_MULTISAMPLE(surface) \ - (surface->hints & GLITZ_HINT_MULTISAMPLE_MASK) - -static void -_cairo_gl_surface_destroy (void *abstract_surface) -{ - cairo_gl_surface_t *surface = abstract_surface; - - if (surface->owns_surface && surface->surface) - glitz_surface_destroy (surface->surface); - - _cairo_pattern_fini (&surface->pattern); - - free (surface); -} - -static double -_cairo_gl_surface_pixels_per_inch (void *abstract_surface) -{ - return 96.0; -} - -static cairo_image_surface_t * -_cairo_gl_surface_get_image (void *abstract_surface) -{ - cairo_gl_surface_t *surface = abstract_surface; - cairo_image_surface_t *image; - char *pixels; - int width, height; - int rowstride; - cairo_format_masks_t format; - glitz_pixel_buffer_t *buffer; - glitz_pixel_format_t pf; - - if (surface->hints & GLITZ_HINT_PROGRAMMATIC_MASK) - return _cairo_pattern_get_image (&surface->pattern, - &surface->pattern_box); - - width = glitz_surface_get_width (surface->surface); - height = glitz_surface_get_height (surface->surface); - - if (surface->format->red_size > 0) { - format.bpp = 32; - - if (surface->format->alpha_size > 0) - format.alpha_mask = 0xff000000; - else - format.alpha_mask = 0x0; - - format.red_mask = 0xff0000; - format.green_mask = 0xff00; - format.blue_mask = 0xff; - } else { - format.bpp = 8; - format.blue_mask = format.green_mask = format.red_mask = 0x0; - format.alpha_mask = 0xff; - } - - rowstride = (((width * format.bpp) / 8) + 3) & -4; - - pf.masks.bpp = format.bpp; - pf.masks.alpha_mask = format.alpha_mask; - pf.masks.red_mask = format.red_mask; - pf.masks.green_mask = format.green_mask; - pf.masks.blue_mask = format.blue_mask; - pf.xoffset = 0; - pf.skip_lines = 0; - pf.bytes_per_line = rowstride; - pf.scanline_order = GLITZ_PIXEL_SCANLINE_ORDER_TOP_DOWN; - - pixels = (char *) malloc (height * rowstride); - if (!pixels) - return NULL; - - buffer = glitz_pixel_buffer_create_for_data (pixels, &pf); - if (!buffer) { - free (pixels); - return NULL; - } - - glitz_get_pixels (surface->surface, - 0, 0, - width, height, - buffer); - - glitz_pixel_buffer_destroy (buffer); - - image = (cairo_image_surface_t *) - _cairo_image_surface_create_with_masks (pixels, - &format, - width, height, rowstride); - - _cairo_image_surface_assume_ownership_of_data (image); - - _cairo_image_surface_set_repeat (image, surface->base.repeat); - _cairo_image_surface_set_matrix (image, &(surface->base.matrix)); - - return image; -} - -static cairo_status_t -_cairo_gl_surface_set_image (void *abstract_surface, - cairo_image_surface_t *image) -{ - cairo_gl_surface_t *surface = abstract_surface; - glitz_pixel_buffer_t *buffer; - glitz_pixel_format_t pf; - - if (image->depth > 8) { - pf.masks.bpp = 32; - - if (surface->format->alpha_size) - pf.masks.alpha_mask = 0xff000000; - else - pf.masks.alpha_mask = 0x0; - - pf.masks.red_mask = 0xff0000; - pf.masks.green_mask = 0xff00; - pf.masks.blue_mask = 0xff; - } else { - pf.masks.bpp = 8; - pf.masks.alpha_mask = 0xff; - pf.masks.red_mask = pf.masks.green_mask = pf.masks.blue_mask = 0x0; - } - - pf.xoffset = 0; - pf.skip_lines = 0; - pf.bytes_per_line = (((image->width * pf.masks.bpp) / 8) + 3) & -4; - pf.scanline_order = GLITZ_PIXEL_SCANLINE_ORDER_TOP_DOWN; - - buffer = glitz_pixel_buffer_create_for_data (image->data, &pf); - if (!buffer) - return CAIRO_STATUS_NO_MEMORY; - - glitz_put_pixels (surface->surface, - 0, 0, - image->width, image->height, - buffer); - - glitz_pixel_buffer_destroy (buffer); - - return CAIRO_STATUS_SUCCESS; -} - -static cairo_status_t -_cairo_gl_surface_set_matrix (void *abstract_surface, cairo_matrix_t *matrix) -{ - cairo_gl_surface_t *surface = abstract_surface; - glitz_transform_t transform; - - if (!surface->surface) - return CAIRO_STATUS_SUCCESS; - - transform.matrix[0][0] = _cairo_fixed_from_double (matrix->m[0][0]); - transform.matrix[0][1] = _cairo_fixed_from_double (matrix->m[1][0]); - transform.matrix[0][2] = _cairo_fixed_from_double (matrix->m[2][0]); - - transform.matrix[1][0] = _cairo_fixed_from_double (matrix->m[0][1]); - transform.matrix[1][1] = _cairo_fixed_from_double (matrix->m[1][1]); - transform.matrix[1][2] = _cairo_fixed_from_double (matrix->m[2][1]); - - transform.matrix[2][0] = 0; - transform.matrix[2][1] = 0; - transform.matrix[2][2] = _cairo_fixed_from_double (1); - - glitz_surface_set_transform (surface->surface, &transform); - - return CAIRO_STATUS_SUCCESS; -} - -static cairo_status_t -_cairo_gl_surface_set_filter (void *abstract_surface, cairo_filter_t filter) -{ - cairo_gl_surface_t *surface = abstract_surface; - glitz_filter_t gl_filter; - - if (!surface->surface) - return CAIRO_STATUS_SUCCESS; - - switch (filter) { - case CAIRO_FILTER_FAST: - gl_filter = GLITZ_FILTER_FAST; - break; - case CAIRO_FILTER_GOOD: - gl_filter = GLITZ_FILTER_GOOD; - break; - case CAIRO_FILTER_BEST: - gl_filter = GLITZ_FILTER_BEST; - break; - case CAIRO_FILTER_NEAREST: - gl_filter = GLITZ_FILTER_NEAREST; - break; - case CAIRO_FILTER_BILINEAR: - gl_filter = GLITZ_FILTER_BILINEAR; - break; - default: - gl_filter = GLITZ_FILTER_BEST; - } - - glitz_surface_set_filter (surface->surface, gl_filter); - - return CAIRO_STATUS_SUCCESS; -} - -static cairo_status_t -_cairo_gl_surface_set_repeat (void *abstract_surface, int repeat) -{ - cairo_gl_surface_t *surface = abstract_surface; - - if (!surface->surface) - return CAIRO_STATUS_SUCCESS; - - glitz_surface_set_repeat (surface->surface, repeat); - - return CAIRO_STATUS_SUCCESS; -} - -static glitz_operator_t -_glitz_operator (cairo_operator_t operator) -{ - switch (operator) { - case CAIRO_OPERATOR_CLEAR: - return GLITZ_OPERATOR_CLEAR; - case CAIRO_OPERATOR_SRC: - return GLITZ_OPERATOR_SRC; - case CAIRO_OPERATOR_DST: - return GLITZ_OPERATOR_DST; - case CAIRO_OPERATOR_OVER: - return GLITZ_OPERATOR_OVER; - case CAIRO_OPERATOR_OVER_REVERSE: - return GLITZ_OPERATOR_OVER_REVERSE; - case CAIRO_OPERATOR_IN: - return GLITZ_OPERATOR_IN; - case CAIRO_OPERATOR_IN_REVERSE: - return GLITZ_OPERATOR_IN_REVERSE; - case CAIRO_OPERATOR_OUT: - return GLITZ_OPERATOR_OUT; - case CAIRO_OPERATOR_OUT_REVERSE: - return GLITZ_OPERATOR_OUT_REVERSE; - case CAIRO_OPERATOR_ATOP: - return GLITZ_OPERATOR_ATOP; - case CAIRO_OPERATOR_ATOP_REVERSE: - return GLITZ_OPERATOR_ATOP_REVERSE; - case CAIRO_OPERATOR_XOR: - return GLITZ_OPERATOR_XOR; - case CAIRO_OPERATOR_ADD: - return GLITZ_OPERATOR_ADD; - case CAIRO_OPERATOR_SATURATE: - return GLITZ_OPERATOR_SATURATE; - default: - return GLITZ_OPERATOR_OVER; - } -} - -static glitz_format_name_t -_glitz_format (cairo_format_t format) -{ - switch (format) { - case CAIRO_FORMAT_A1: - return GLITZ_STANDARD_A1; - break; - case CAIRO_FORMAT_A8: - return GLITZ_STANDARD_A8; - break; - case CAIRO_FORMAT_RGB24: - return GLITZ_STANDARD_RGB24; - break; - case CAIRO_FORMAT_ARGB32: - default: - return GLITZ_STANDARD_ARGB32; - break; - } -} - -static cairo_surface_t * -_cairo_gl_surface_create_similar (void *abstract_src, - cairo_format_t format, - int drawable, - int width, - int height) -{ - cairo_gl_surface_t *src = abstract_src; - glitz_surface_t *surface; - cairo_surface_t *crsurface; - glitz_format_t *glitz_format; - unsigned long option_mask; - glitz_format_name_t format_name = _glitz_format (format); - - option_mask = GLITZ_FORMAT_OPTION_OFFSCREEN_MASK; - - if (drawable) - option_mask |= GLITZ_FORMAT_OPTION_READDRAW_MASK; - else - option_mask |= GLITZ_FORMAT_OPTION_READONLY_MASK; - - if (src->format->multisample.samples < 2) - option_mask |= GLITZ_FORMAT_OPTION_NO_MULTISAMPLE_MASK; - - glitz_format = - glitz_surface_find_similar_standard_format (src->surface, option_mask, - format_name); - if (glitz_format == NULL) { - option_mask &= ~GLITZ_FORMAT_OPTION_READDRAW_MASK; - glitz_format = - glitz_surface_find_similar_standard_format (src->surface, - option_mask, - format_name); - } - - if (glitz_format == NULL) - return NULL; - - surface = glitz_surface_create_similar (src->surface, glitz_format, - width, height); - if (surface == NULL) - return NULL; - - crsurface = _cairo_gl_surface_create (surface, 1); - if (crsurface == NULL) - glitz_surface_destroy (surface); - - return crsurface; -} - -static cairo_gl_surface_t * -_cairo_gl_surface_clone_similar (cairo_surface_t *src, - cairo_gl_surface_t *template, - cairo_format_t format) -{ - cairo_gl_surface_t *clone; - cairo_image_surface_t *src_image; - - src_image = _cairo_surface_get_image (src); - - clone = (cairo_gl_surface_t *) - _cairo_gl_surface_create_similar (template, format, 0, - src_image->width, - src_image->height); - if (clone == NULL) - return NULL; - - _cairo_gl_surface_set_filter (clone, cairo_surface_get_filter (src)); - - _cairo_gl_surface_set_image (clone, src_image); - - _cairo_gl_surface_set_matrix (clone, &(src_image->base.matrix)); - - cairo_surface_destroy (&src_image->base); - - return clone; -} - -static cairo_int_status_t -_cairo_gl_surface_composite (cairo_operator_t operator, - cairo_surface_t *generic_src, - cairo_surface_t *generic_mask, - void *abstract_dst, - int src_x, - int src_y, - int mask_x, - int mask_y, - int dst_x, - int dst_y, - unsigned int width, - unsigned int height) -{ - cairo_gl_surface_t *dst = abstract_dst; - cairo_gl_surface_t *src = (cairo_gl_surface_t *) generic_src; - cairo_gl_surface_t *mask = (cairo_gl_surface_t *) generic_mask; - cairo_gl_surface_t *src_clone = NULL; - cairo_gl_surface_t *mask_clone = NULL; - - /* Make sure that target surface is OK. */ - if (glitz_surface_get_status (dst->surface)) - return CAIRO_STATUS_NO_TARGET_SURFACE; - - /* Make sure target surface is drawable */ - if (!CAIRO_GL_SURFACE_IS_DRAWABLE (dst)) - return CAIRO_INT_STATUS_UNSUPPORTED; - - /* We need multi-texturing or offscreen drawing when compositing with - non-solid mask. */ - if (mask && - (!CAIRO_GL_SURFACE_IS_SOLID (mask)) && - (!CAIRO_GL_MULTITEXTURE_SUPPORT (dst)) && - (!CAIRO_GL_OFFSCREEN_SUPPORT (dst))) - return CAIRO_INT_STATUS_UNSUPPORTED; - - if (generic_src->backend != dst->base.backend) { - src_clone = _cairo_gl_surface_clone_similar (generic_src, dst, - CAIRO_FORMAT_ARGB32); - if (!src_clone) - return CAIRO_INT_STATUS_UNSUPPORTED; - src = src_clone; - } - if (generic_mask && (generic_mask->backend != dst->base.backend)) { - mask_clone = _cairo_gl_surface_clone_similar (generic_mask, dst, - CAIRO_FORMAT_A8); - if (!mask_clone) - return CAIRO_INT_STATUS_UNSUPPORTED; - mask = mask_clone; - } - - glitz_composite (_glitz_operator (operator), - src->surface, - mask ? mask->surface : 0, - dst->surface, - src_x, src_y, - mask_x, mask_y, - dst_x, dst_y, - width, height); - - if (src_clone) - cairo_surface_destroy (&src_clone->base); - if (mask_clone) - cairo_surface_destroy (&mask_clone->base); - - if (glitz_surface_get_status (dst->surface) == GLITZ_STATUS_NOT_SUPPORTED) - return CAIRO_INT_STATUS_UNSUPPORTED; - - return CAIRO_STATUS_SUCCESS; -} - -static cairo_int_status_t -_cairo_gl_surface_fill_rectangles (void *abstract_surface, - cairo_operator_t operator, - const cairo_color_t *color, - cairo_rectangle_t *rects, - int num_rects) -{ - cairo_gl_surface_t *surface = abstract_surface; - glitz_color_t glitz_color; - - /* Make sure that target surface is OK. */ - if (glitz_surface_get_status (surface->surface)) - return CAIRO_STATUS_NO_TARGET_SURFACE; - - /* Make sure target surface is drawable */ - if (!CAIRO_GL_SURFACE_IS_DRAWABLE (surface)) - return CAIRO_INT_STATUS_UNSUPPORTED; - - glitz_color.red = color->red_short; - glitz_color.green = color->green_short; - glitz_color.blue = color->blue_short; - glitz_color.alpha = color->alpha_short; - - glitz_fill_rectangles (_glitz_operator (operator), - surface->surface, - &glitz_color, (glitz_rectangle_t *) rects, - num_rects); - - return CAIRO_STATUS_SUCCESS; -} - -/* This function will produce incorrect drawing if alpha is not 1.0. */ -static cairo_int_status_t -_cairo_gl_surface_fill_trapezoids (cairo_gl_surface_t *surface, - cairo_operator_t operator, - const cairo_color_t *color, - cairo_trapezoid_t *traps, - int num_traps) -{ - glitz_color_t glitz_color; - - glitz_color.red = color->red_short; - glitz_color.green = color->green_short; - glitz_color.blue = color->blue_short; - glitz_color.alpha = color->alpha_short; - - glitz_fill_trapezoids (_glitz_operator (operator), - surface->surface, - &glitz_color, - (glitz_trapezoid_t *) traps, num_traps); - - return CAIRO_STATUS_SUCCESS; -} - -static int -_cairo_gl_extract_rectangle (cairo_trapezoid_t *trap, - cairo_rectangle_t *rect) -{ - if (trap->left.p1.x == trap->left.p2.x && - trap->right.p1.x == trap->right.p2.x && - trap->left.p1.y == trap->right.p1.y && - trap->left.p2.y == trap->right.p2.y && - _cairo_fixed_is_integer (trap->left.p1.x) && - _cairo_fixed_is_integer (trap->left.p1.y) && - _cairo_fixed_is_integer (trap->left.p2.x) && - _cairo_fixed_is_integer (trap->left.p2.y) && - _cairo_fixed_is_integer (trap->right.p1.x) && - _cairo_fixed_is_integer (trap->right.p1.y) && - _cairo_fixed_is_integer (trap->right.p2.x) && - _cairo_fixed_is_integer (trap->right.p2.y)) { - - rect->x = _cairo_fixed_integer_part (trap->left.p1.x); - rect->y = _cairo_fixed_integer_part (trap->left.p1.y); - rect->width = _cairo_fixed_integer_part (trap->right.p1.x) - rect->x; - rect->height = _cairo_fixed_integer_part (trap->left.p2.y) - rect->y; - - return 1; - } - - return 0; -} - -static cairo_int_status_t -_cairo_gl_surface_composite_trapezoids (cairo_operator_t operator, - cairo_surface_t *generic_src, - void *abstract_dst, - int x_src, - int y_src, - cairo_trapezoid_t *traps, - int num_traps) -{ - cairo_gl_surface_t *dst = abstract_dst; - cairo_gl_surface_t *src = (cairo_gl_surface_t *) generic_src; - cairo_gl_surface_t *src_clone = NULL; - - /* Make sure that target surface is OK. */ - if (glitz_surface_get_status (dst->surface)) - return CAIRO_STATUS_NO_TARGET_SURFACE; - - /* Make sure target surface is drawable */ - if (!CAIRO_GL_SURFACE_IS_DRAWABLE (dst)) - return CAIRO_INT_STATUS_UNSUPPORTED; - - /* Need to get current hints as clipping may have changed. */ - dst->hints = glitz_surface_get_hints (dst->surface); - - /* Solid source? */ - if ((generic_src->backend == dst->base.backend) && - (src->pattern.type == CAIRO_PATTERN_SOLID)) { - cairo_rectangle_t rect; - - /* Check to see if we can represent these traps as a rectangle. */ - if (num_traps == 1 && _cairo_gl_extract_rectangle (traps, &rect)) - return _cairo_gl_surface_fill_rectangles (dst, operator, - &src->pattern.color, - &rect, 1); - - /* If we're not using software multi-sampling, then we can use - fill trapezoids if only one trapezoid should be drawn or if - solid color alpha is 1.0. */ - if ((!CAIRO_GL_SURFACE_MULTISAMPLE (dst)) && - (num_traps == 1 || src->pattern.color.alpha == 1.0)) - return _cairo_gl_surface_fill_trapezoids (dst, operator, - &src->pattern.color, - traps, num_traps); - } - - if (generic_src->backend != dst->base.backend) { - src_clone = _cairo_gl_surface_clone_similar (generic_src, dst, - CAIRO_FORMAT_ARGB32); - if (!src_clone) - return CAIRO_INT_STATUS_UNSUPPORTED; - src = src_clone; - } - - glitz_surface_set_polyopacity (dst->surface, src->opacity); - - glitz_composite_trapezoids (_glitz_operator (operator), - src->surface, dst->surface, - x_src, y_src, (glitz_trapezoid_t *) traps, - num_traps); - - glitz_surface_set_polyopacity (dst->surface, 0xffff); - - if (src_clone) - cairo_surface_destroy (&src_clone->base); - - if (glitz_surface_get_status (dst->surface) == GLITZ_STATUS_NOT_SUPPORTED) - return CAIRO_INT_STATUS_UNSUPPORTED; - - return CAIRO_STATUS_SUCCESS; -} - -static cairo_int_status_t -_cairo_gl_surface_copy_page (void *abstract_surface) -{ - return CAIRO_INT_STATUS_UNSUPPORTED; -} - -static cairo_int_status_t -_cairo_gl_surface_show_page (void *abstract_surface) -{ - return CAIRO_INT_STATUS_UNSUPPORTED; -} - -static void -_cairo_gl_create_color_range (cairo_pattern_t *pattern, - unsigned char *data, - unsigned int size) -{ - unsigned int i, bytes = size * 4; - cairo_shader_op_t op; - - _cairo_pattern_shader_init (pattern, &op); - - for (i = 0; i < bytes; i += 4) - _cairo_pattern_calc_color_at_pixel (&op, - ((double) i / bytes) * 65536, - (int *) &data[i]); -} - -static cairo_int_status_t -_cairo_gl_surface_create_pattern (void *abstract_surface, - cairo_pattern_t *pattern, - cairo_box_t *box) -{ - cairo_gl_surface_t *surface = abstract_surface; - glitz_surface_t *source = NULL; - cairo_gl_surface_t *src; - - switch (pattern->type) { - case CAIRO_PATTERN_SOLID: { - glitz_color_t color; - - color.red = pattern->color.red_short; - color.green = pattern->color.green_short; - color.blue = pattern->color.blue_short; - color.alpha = pattern->color.alpha_short; - - source = glitz_surface_create_solid (&color); - } break; - case CAIRO_PATTERN_RADIAL: - /* glitz doesn't support inner circle yet. */ - if (pattern->u.radial.center0.x != pattern->u.radial.center1.x || - pattern->u.radial.center0.y != pattern->u.radial.center1.y) - return CAIRO_INT_STATUS_UNSUPPORTED; - /* fall-through */ - case CAIRO_PATTERN_LINEAR: { - int color_range_size; - glitz_color_range_t *color_range; - int width = ((box->p2.x + 65535) >> 16) - (box->p1.x >> 16); - int height = ((box->p2.y + 65535) >> 16) - (box->p1.y >> 16); - - if (!CAIRO_GL_FRAGMENT_PROGRAM_SUPPORT (surface)) - return CAIRO_INT_STATUS_UNSUPPORTED; - - /* reflect could be emulated for hardware that doesn't support mirrored - repeat of textures, but I don't know of any card that support - fragment programs but not mirrored repeat, so what's the use. */ - if (pattern->extend == CAIRO_EXTEND_REFLECT && - (!CAIRO_GL_TEXTURE_MIRRORED_REPEAT_SUPPORT (surface))) - return CAIRO_INT_STATUS_UNSUPPORTED; - - /* TODO: how do we figure out the color range resolution? transforming - the gradient vector with the inverse of the pattern matrix should - give us a good hint. */ - color_range_size = 512; - - /* destination surface size less than color range size, an image - gradient is probably more efficient. */ - if ((width * height) <= color_range_size) - return CAIRO_INT_STATUS_UNSUPPORTED; - - color_range = glitz_color_range_create (surface->surface, - color_range_size); - if (!color_range) - return CAIRO_STATUS_NO_MEMORY; - - _cairo_gl_create_color_range (pattern, - glitz_color_range_get_data (color_range), - color_range_size); - - glitz_color_range_put_back_data (color_range); - - switch (pattern->extend) { - case CAIRO_EXTEND_REPEAT: - glitz_color_range_set_extend (color_range, GLITZ_EXTEND_REPEAT); - break; - case CAIRO_EXTEND_REFLECT: - glitz_color_range_set_extend (color_range, GLITZ_EXTEND_REFLECT); - break; - case CAIRO_EXTEND_NONE: - glitz_color_range_set_extend (color_range, GLITZ_EXTEND_PAD); - break; - } - - glitz_color_range_set_filter (color_range, GLITZ_FILTER_BILINEAR); - - if (pattern->type == CAIRO_PATTERN_LINEAR) { - glitz_point_fixed_t start; - glitz_point_fixed_t stop; - - start.x = _cairo_fixed_from_double (pattern->u.linear.point0.x); - start.y = _cairo_fixed_from_double (pattern->u.linear.point0.y); - stop.x = _cairo_fixed_from_double (pattern->u.linear.point1.x); - stop.y = _cairo_fixed_from_double (pattern->u.linear.point1.y); - - source = glitz_surface_create_linear (&start, &stop, color_range); - } else { - glitz_point_fixed_t center; - - center.x = _cairo_fixed_from_double (pattern->u.radial.center1.x); - center.y = _cairo_fixed_from_double (pattern->u.radial.center1.y); - - source = glitz_surface_create_radial - (¢er, - _cairo_fixed_from_double (pattern->u.radial.radius0), - _cairo_fixed_from_double (pattern->u.radial.radius1), - color_range); - } - - glitz_color_range_destroy (color_range); - } break; - case CAIRO_PATTERN_SURFACE: - if (CAIRO_GL_COMPOSITE_TRAPEZOIDS_SUPPORT (surface)) { - cairo_gl_surface_t *src_clone = NULL; - cairo_surface_t *generic_src = pattern->u.surface.surface; - - src = (cairo_gl_surface_t *) generic_src; - if (generic_src->backend != surface->base.backend) { - src_clone = - _cairo_gl_surface_clone_similar (generic_src, surface, - CAIRO_FORMAT_ARGB32); - if (!src_clone) - return CAIRO_INT_STATUS_UNSUPPORTED; - } else { - src_clone = (cairo_gl_surface_t *) - _cairo_gl_surface_create (src->surface, 0); - if (!src_clone) - return CAIRO_STATUS_NO_MEMORY; - - cairo_surface_set_filter - (&src_clone->base, cairo_surface_get_filter (generic_src)); - - cairo_surface_set_matrix (&src_clone->base, - &generic_src->matrix); - } - - cairo_surface_set_repeat (&src_clone->base, generic_src->repeat); - - src_clone->opacity = (unsigned short) - (pattern->color.alpha * 0xffff); - - pattern->source = &src_clone->base; - - return CAIRO_STATUS_SUCCESS; - } - return CAIRO_INT_STATUS_UNSUPPORTED; - break; - } - - if (!source) - return CAIRO_STATUS_NO_MEMORY; - - src = (cairo_gl_surface_t *) _cairo_gl_surface_create (source, 1); - if (!src) { - glitz_surface_destroy (source); - - return CAIRO_STATUS_NO_MEMORY; - } - - if (pattern->type == CAIRO_PATTERN_LINEAR || - pattern->type == CAIRO_PATTERN_RADIAL) - cairo_surface_set_matrix (&src->base, &pattern->matrix); - - _cairo_pattern_init_copy (&src->pattern, pattern); - src->pattern_box = *box; - - pattern->source = &src->base; - - return CAIRO_STATUS_SUCCESS; -} - -static cairo_int_status_t -_cairo_gl_surface_set_clip_region (void *abstract_surface, - pixman_region16_t *region) -{ - cairo_gl_surface_t *surface = abstract_surface; - glitz_rectangle_t *clip_rects; - pixman_box16_t *box; - int n, i; - - if (region == NULL) { - glitz_rectangle_t rect; - - rect.x = 0; - rect.y = 0; - rect.width = glitz_surface_get_width (surface->surface); - rect.height = glitz_surface_get_height (surface->surface); - - glitz_surface_clip_rectangles (surface->surface, - GLITZ_CLIP_OPERATOR_SET, &rect, 1); - } - - if (surface->format->stencil_size < 1) - return CAIRO_INT_STATUS_UNSUPPORTED; - - n = pixman_region_num_rects (region); - if (n == 0) - return CAIRO_STATUS_SUCCESS; - - box = pixman_region_rects (region); - - clip_rects = malloc (n * sizeof (glitz_rectangle_t)); - if (!clip_rects) - return CAIRO_STATUS_NO_MEMORY; - - for (i = 0; i < n; n++, box++) { - clip_rects[i].x = box->x1; - clip_rects[i].y = box->y1; - clip_rects[i].width = (unsigned short) (box->x2 - box->x1); - clip_rects[i].height = (unsigned short) (box->y2 - box->y1); - } - - glitz_surface_clip_rectangles (surface->surface, - GLITZ_CLIP_OPERATOR_SET, clip_rects, n); - - free (clip_rects); - - return CAIRO_STATUS_SUCCESS; -} - -static const struct cairo_surface_backend cairo_gl_surface_backend = { - _cairo_gl_surface_create_similar, - _cairo_gl_surface_destroy, - _cairo_gl_surface_pixels_per_inch, - _cairo_gl_surface_get_image, - _cairo_gl_surface_set_image, - _cairo_gl_surface_set_matrix, - _cairo_gl_surface_set_filter, - _cairo_gl_surface_set_repeat, - _cairo_gl_surface_composite, - _cairo_gl_surface_fill_rectangles, - _cairo_gl_surface_composite_trapezoids, - _cairo_gl_surface_copy_page, - _cairo_gl_surface_show_page, - _cairo_gl_surface_set_clip_region, - _cairo_gl_surface_create_pattern -}; - -static cairo_surface_t * -_cairo_gl_surface_create (glitz_surface_t *surface, int owns_surface) -{ - cairo_gl_surface_t *crsurface; - - if (!surface) - return NULL; - - crsurface = malloc (sizeof (cairo_gl_surface_t)); - if (crsurface == NULL) - return NULL; - - _cairo_surface_init (&crsurface->base, &cairo_gl_surface_backend); - _cairo_pattern_init (&crsurface->pattern); - crsurface->pattern.type = CAIRO_PATTERN_SURFACE; - crsurface->pattern.u.surface.surface = NULL; - crsurface->format = glitz_surface_get_format (surface); - crsurface->surface = surface; - crsurface->features = glitz_surface_get_features (surface); - crsurface->hints = glitz_surface_get_hints (surface); - crsurface->owns_surface = owns_surface; - crsurface->opacity = 0xffff; - - return (cairo_surface_t *) crsurface; -} - -cairo_surface_t * -cairo_gl_surface_create (glitz_surface_t *surface) -{ - return _cairo_gl_surface_create (surface, 0); -} diff --git a/src/cairo_glitz_surface.c b/src/cairo_glitz_surface.c new file mode 100644 index 00000000..21e88920 --- /dev/null +++ b/src/cairo_glitz_surface.c @@ -0,0 +1,930 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2004 David Reveman + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of David + * Reveman not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. David Reveman makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * DAVID REVEMAN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL DAVID REVEMAN BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: David Reveman <c99drn@cs.umu.se> + */ + +#include "cairoint.h" + +#define GLITZ_FIXED_TO_FLOAT(f) \ + (((glitz_float_t) (f)) / 65536) + +#define GLITZ_FIXED_LINE_X_TO_FLOAT(line, v) \ + (((glitz_float_t) \ + ((line).p1.x + (cairo_fixed_16_16_t) \ + (((cairo_fixed_32_32_t) ((v) - (line).p1.y) * \ + ((line).p2.x - (line).p1.x)) / \ + ((line).p2.y - (line).p1.y)))) / 65536) + +#define GLITZ_FIXED_LINE_X_CEIL_TO_FLOAT(line, v) \ + (((glitz_float_t) \ + ((line).p1.x + (cairo_fixed_16_16_t) \ + (((((line).p2.y - (line).p1.y) - 1) + \ + ((cairo_fixed_32_32_t) ((v) - (line).p1.y) * \ + ((line).p2.x - (line).p1.x))) / \ + ((line).p2.y - (line).p1.y)))) / 65536) + +void +cairo_set_target_glitz (cairo_t *cr, glitz_surface_t *surface) +{ + cairo_surface_t *crsurface; + + if (cr->status && cr->status != CAIRO_STATUS_NO_TARGET_SURFACE) + return; + + glitz_surface_reference (surface); + + crsurface = cairo_glitz_surface_create (surface); + if (crsurface == NULL) { + cr->status = CAIRO_STATUS_NO_MEMORY; + return; + } + + cairo_set_target_surface (cr, crsurface); + + cairo_surface_destroy (crsurface); +} + +typedef struct cairo_glitz_surface { + cairo_surface_t base; + + unsigned long features; + glitz_surface_t *surface; + glitz_format_t *format; + + cairo_pattern_t pattern; + cairo_box_t pattern_box; +} cairo_glitz_surface_t; + +static void +_cairo_glitz_surface_destroy (void *abstract_surface) +{ + cairo_glitz_surface_t *surface = abstract_surface; + + glitz_surface_destroy (surface->surface); + + _cairo_pattern_fini (&surface->pattern); + + free (surface); +} + +static double +_cairo_glitz_surface_pixels_per_inch (void *abstract_surface) +{ + return 96.0; +} + +static cairo_image_surface_t * +_cairo_glitz_surface_get_image (void *abstract_surface) +{ + cairo_glitz_surface_t *surface = abstract_surface; + cairo_image_surface_t *image; + char *pixels; + int width, height; + cairo_format_masks_t format; + glitz_buffer_t *buffer; + glitz_pixel_format_t pf; + + if (surface->pattern.type != CAIRO_PATTERN_SURFACE) { + cairo_box_t box; + + box.p1.x = box.p1.y = 0; + box.p2.x = surface->pattern_box.p2.x; + box.p2.y = surface->pattern_box.p2.y; + + return _cairo_pattern_get_image (&surface->pattern, &box); + } + + + width = glitz_surface_get_width (surface->surface); + height = glitz_surface_get_height (surface->surface); + + if (surface->format->red_size > 0) { + format.bpp = 32; + + if (surface->format->alpha_size > 0) + format.alpha_mask = 0xff000000; + else + format.alpha_mask = 0x0; + + format.red_mask = 0xff0000; + format.green_mask = 0xff00; + format.blue_mask = 0xff; + } else { + format.bpp = 8; + format.blue_mask = format.green_mask = format.red_mask = 0x0; + format.alpha_mask = 0xff; + } + + pf.masks.bpp = format.bpp; + pf.masks.alpha_mask = format.alpha_mask; + pf.masks.red_mask = format.red_mask; + pf.masks.green_mask = format.green_mask; + pf.masks.blue_mask = format.blue_mask; + pf.xoffset = 0; + pf.skip_lines = 0; + pf.bytes_per_line = (((width * format.bpp) / 8) + 3) & -4; + pf.scanline_order = GLITZ_PIXEL_SCANLINE_ORDER_TOP_DOWN; + + pixels = malloc (height * pf.bytes_per_line); + if (!pixels) + return NULL; + + buffer = glitz_buffer_create_for_data (pixels); + if (!buffer) { + free (pixels); + return NULL; + } + + glitz_get_pixels (surface->surface, + 0, 0, + width, height, + &pf, + buffer); + + glitz_buffer_destroy (buffer); + + image = (cairo_image_surface_t *) + _cairo_image_surface_create_with_masks (pixels, + &format, + width, height, + pf.bytes_per_line); + + _cairo_image_surface_assume_ownership_of_data (image); + + _cairo_image_surface_set_repeat (image, surface->base.repeat); + _cairo_image_surface_set_matrix (image, &(surface->base.matrix)); + + return image; +} + +static cairo_status_t +_cairo_glitz_surface_set_image (void *abstract_surface, + cairo_image_surface_t *image) +{ + cairo_glitz_surface_t *surface = abstract_surface; + glitz_buffer_t *buffer; + glitz_pixel_format_t pf; + pixman_format_t *format; + int am, rm, gm, bm; + + format = pixman_image_get_format (image->pixman_image); + if (format == NULL) + return CAIRO_STATUS_NO_MEMORY; + + pixman_format_get_masks (format, &pf.masks.bpp, &am, &rm, &gm, &bm); + + pf.masks.alpha_mask = am; + pf.masks.red_mask = rm; + pf.masks.green_mask = gm; + pf.masks.blue_mask = bm; + pf.xoffset = 0; + pf.skip_lines = 0; + pf.bytes_per_line = image->stride; + pf.scanline_order = GLITZ_PIXEL_SCANLINE_ORDER_TOP_DOWN; + + buffer = glitz_buffer_create_for_data (image->data); + if (!buffer) + return CAIRO_STATUS_NO_MEMORY; + + glitz_set_pixels (surface->surface, + 0, 0, + image->width, image->height, + &pf, + buffer); + + glitz_buffer_destroy (buffer); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_glitz_surface_set_matrix (void *abstract_surface, + cairo_matrix_t *matrix) +{ + cairo_glitz_surface_t *surface = abstract_surface; + glitz_transform_t transform; + + transform.matrix[0][0] = _cairo_fixed_from_double (matrix->m[0][0]); + transform.matrix[0][1] = _cairo_fixed_from_double (matrix->m[1][0]); + transform.matrix[0][2] = _cairo_fixed_from_double (matrix->m[2][0]); + + transform.matrix[1][0] = _cairo_fixed_from_double (matrix->m[0][1]); + transform.matrix[1][1] = _cairo_fixed_from_double (matrix->m[1][1]); + transform.matrix[1][2] = _cairo_fixed_from_double (matrix->m[2][1]); + + transform.matrix[2][0] = 0; + transform.matrix[2][1] = 0; + transform.matrix[2][2] = 1 << 16; + + glitz_surface_set_transform (surface->surface, &transform); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_glitz_surface_set_filter (void *abstract_surface, cairo_filter_t filter) +{ + cairo_glitz_surface_t *surface = abstract_surface; + glitz_filter_t glitz_filter; + + switch (filter) { + case CAIRO_FILTER_FAST: + case CAIRO_FILTER_NEAREST: + glitz_filter = GLITZ_FILTER_NEAREST; + break; + case CAIRO_FILTER_GOOD: + case CAIRO_FILTER_BEST: + case CAIRO_FILTER_BILINEAR: + default: + glitz_filter = GLITZ_FILTER_BILINEAR; + break; + } + + glitz_surface_set_filter (surface->surface, glitz_filter, NULL, 0); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_glitz_surface_set_repeat (void *abstract_surface, int repeat) +{ + cairo_glitz_surface_t *surface = abstract_surface; + + glitz_surface_set_fill (surface->surface, + (repeat)? GLITZ_FILL_REPEAT: + GLITZ_FILL_TRANSPARENT); + + return CAIRO_STATUS_SUCCESS; +} + +static glitz_operator_t +_glitz_operator (cairo_operator_t op) +{ + switch (op) { + case CAIRO_OPERATOR_CLEAR: + return GLITZ_OPERATOR_CLEAR; + case CAIRO_OPERATOR_SRC: + return GLITZ_OPERATOR_SRC; + case CAIRO_OPERATOR_DST: + return GLITZ_OPERATOR_DST; + case CAIRO_OPERATOR_OVER_REVERSE: + return GLITZ_OPERATOR_OVER_REVERSE; + case CAIRO_OPERATOR_IN: + return GLITZ_OPERATOR_IN; + case CAIRO_OPERATOR_IN_REVERSE: + return GLITZ_OPERATOR_IN_REVERSE; + case CAIRO_OPERATOR_OUT: + return GLITZ_OPERATOR_OUT; + case CAIRO_OPERATOR_OUT_REVERSE: + return GLITZ_OPERATOR_OUT_REVERSE; + case CAIRO_OPERATOR_ATOP: + return GLITZ_OPERATOR_ATOP; + case CAIRO_OPERATOR_ATOP_REVERSE: + return GLITZ_OPERATOR_ATOP_REVERSE; + case CAIRO_OPERATOR_XOR: + return GLITZ_OPERATOR_XOR; + case CAIRO_OPERATOR_ADD: + return GLITZ_OPERATOR_ADD; + case CAIRO_OPERATOR_SATURATE: + return GLITZ_OPERATOR_SATURATE; + case CAIRO_OPERATOR_OVER: + default: + return GLITZ_OPERATOR_OVER; + } +} + +static glitz_surface_t * +_glitz_surface_create_solid (glitz_surface_t *other, + glitz_format_name_t format_name, + glitz_color_t *color) +{ + glitz_surface_t *surface; + glitz_format_t *format; + + format = glitz_surface_find_similar_standard_format (other, format_name); + if (format == NULL) + return NULL; + + surface = glitz_surface_create_similar (other, format, 1, 1); + if (surface == NULL) + return NULL; + + glitz_set_rectangle (surface, color, 0, 0, 1, 1); + + glitz_surface_set_fill (surface, GLITZ_FILL_REPEAT); + + return surface; +} + +static cairo_surface_t * +_cairo_glitz_surface_create_similar (void *abstract_src, + cairo_format_t format, + int drawable, + int width, + int height) +{ + cairo_glitz_surface_t *src = abstract_src; + glitz_surface_t *surface; + cairo_surface_t *crsurface; + glitz_format_t *glitz_format; + glitz_format_t templ; + unsigned long mask; + + templ.read.offscreen = 1; + mask = GLITZ_FORMAT_READ_OFFSCREEN_MASK; + + if (drawable) { + templ.draw.offscreen = 1; + if (src->features & GLITZ_FEATURE_OFFSCREEN_MULTISAMPLE_MASK) { + templ.multisample.samples = src->format->multisample.samples; + mask |= GLITZ_FORMAT_MULTISAMPLE_SAMPLES_MASK; + } + } else + templ.draw.offscreen = 0; + + mask |= GLITZ_FORMAT_DRAW_OFFSCREEN_MASK; + + switch (format) { + case CAIRO_FORMAT_A1: + case CAIRO_FORMAT_A8: + templ.alpha_size = 8; + mask |= GLITZ_FORMAT_ALPHA_SIZE_MASK; + break; + case CAIRO_FORMAT_RGB24: + templ.red_size = 8; + mask |= GLITZ_FORMAT_RED_SIZE_MASK; + break; + case CAIRO_FORMAT_ARGB32: + default: + templ.alpha_size = templ.red_size = 8; + mask |= GLITZ_FORMAT_ALPHA_SIZE_MASK; + mask |= GLITZ_FORMAT_RED_SIZE_MASK; + break; + } + + glitz_format = + glitz_surface_find_similar_format (src->surface, mask, &templ, 0); + if (glitz_format == NULL) { + mask &= ~GLITZ_FORMAT_DRAW_OFFSCREEN_MASK; + glitz_format = + glitz_surface_find_similar_format (src->surface, mask, &templ, 0); + if (glitz_format == NULL) + return NULL; + } + + surface = glitz_surface_create_similar (src->surface, glitz_format, + width, height); + if (surface == NULL) + return NULL; + + crsurface = cairo_glitz_surface_create (surface); + if (crsurface == NULL) + glitz_surface_destroy (surface); + + return crsurface; +} + +static cairo_glitz_surface_t * +_cairo_glitz_surface_clone_similar (cairo_glitz_surface_t *templ, + cairo_surface_t *src, + cairo_format_t format) +{ + cairo_glitz_surface_t *clone; + cairo_image_surface_t *src_image; + + src_image = _cairo_surface_get_image (src); + + clone = (cairo_glitz_surface_t *) + _cairo_glitz_surface_create_similar (templ, format, 0, + src_image->width, + src_image->height); + if (clone == NULL) + return NULL; + + _cairo_glitz_surface_set_filter (clone, cairo_surface_get_filter (src)); + + _cairo_glitz_surface_set_image (clone, src_image); + + _cairo_glitz_surface_set_matrix (clone, &(src_image->base.matrix)); + + cairo_surface_destroy (&src_image->base); + + return clone; +} + +static cairo_int_status_t +_glitz_composite (glitz_operator_t op, + glitz_surface_t *src, + glitz_surface_t *mask, + glitz_surface_t *dst, + int src_x, + int src_y, + int mask_x, + int mask_y, + int dst_x, + int dst_y, + int width, + int height, + glitz_buffer_t *geometry, + glitz_geometry_format_t *format) +{ + if (glitz_surface_get_status (dst)) + return CAIRO_STATUS_NO_TARGET_SURFACE; + + glitz_set_geometry (dst, + 0, 0, + format, geometry); + + glitz_composite (op, + src, + mask, + dst, + src_x, src_y, + mask_x, mask_y, + dst_x, dst_y, + width, height); + + glitz_set_geometry (dst, 0, 0, NULL, NULL); + + if (glitz_surface_get_status (dst) == GLITZ_STATUS_NOT_SUPPORTED) + return CAIRO_INT_STATUS_UNSUPPORTED; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_glitz_surface_composite (cairo_operator_t op, + cairo_surface_t *generic_src, + cairo_surface_t *generic_mask, + void *abstract_dst, + int src_x, + int src_y, + int mask_x, + int mask_y, + int dst_x, + int dst_y, + unsigned int width, + unsigned int height) +{ + cairo_glitz_surface_t *dst = abstract_dst; + cairo_glitz_surface_t *src = (cairo_glitz_surface_t *) generic_src; + cairo_glitz_surface_t *mask = (cairo_glitz_surface_t *) generic_mask; + cairo_glitz_surface_t *src_clone = NULL; + cairo_glitz_surface_t *mask_clone = NULL; + cairo_int_status_t status; + + if (generic_src->backend != dst->base.backend) { + src_clone = _cairo_glitz_surface_clone_similar (dst, generic_src, + CAIRO_FORMAT_ARGB32); + if (!src_clone) + return CAIRO_INT_STATUS_UNSUPPORTED; + + src = src_clone; + } + + if (generic_mask && (generic_mask->backend != dst->base.backend)) { + mask_clone = _cairo_glitz_surface_clone_similar (dst, generic_mask, + CAIRO_FORMAT_A8); + if (!mask_clone) + return CAIRO_INT_STATUS_UNSUPPORTED; + + mask = mask_clone; + } + + status = _glitz_composite (_glitz_operator (op), + src->surface, + (mask)? mask->surface: NULL, + dst->surface, + src_x, src_y, + mask_x, mask_y, + dst_x, dst_y, + width, height, + NULL, NULL); + + if (src_clone) + cairo_surface_destroy (&src_clone->base); + + if (mask_clone) + cairo_surface_destroy (&mask_clone->base); + + return status; +} + +static cairo_int_status_t +_cairo_glitz_surface_fill_rectangles (void *abstract_dst, + cairo_operator_t op, + const cairo_color_t *color, + cairo_rectangle_t *rects, + int n_rects) +{ + cairo_glitz_surface_t *dst = abstract_dst; + glitz_color_t glitz_color; + + glitz_color.red = color->red_short; + glitz_color.green = color->green_short; + glitz_color.blue = color->blue_short; + glitz_color.alpha = color->alpha_short; + + if (op != CAIRO_OPERATOR_SRC) { + glitz_surface_t *solid; + glitz_float_t *vertices; + glitz_buffer_t *buffer; + glitz_geometry_format_t gf; + cairo_int_status_t status; + int width, height; + void *data; + + gf.mode = GLITZ_GEOMETRY_MODE_DIRECT; + gf.edge_hint = GLITZ_GEOMETRY_EDGE_HINT_SHARP; + gf.primitive = GLITZ_GEOMETRY_PRIMITIVE_QUADS; + gf.type = GLITZ_DATA_TYPE_FLOAT; + gf.first = 0; + gf.count = n_rects * 4; + + data = malloc (n_rects * 8 * sizeof (glitz_float_t)); + if (!data) + return CAIRO_STATUS_NO_MEMORY; + + buffer = glitz_buffer_create_for_data (data); + if (buffer == NULL) { + free (data); + return CAIRO_STATUS_NO_MEMORY; + } + + width = height = 0; + vertices = glitz_buffer_map (buffer, GLITZ_BUFFER_ACCESS_WRITE_ONLY); + for (; n_rects; rects++, n_rects--) { + *vertices++ = (glitz_float_t) rects->x; + *vertices++ = (glitz_float_t) rects->y; + *vertices++ = (glitz_float_t) (rects->x + rects->width); + *vertices++ = (glitz_float_t) rects->y; + *vertices++ = (glitz_float_t) (rects->x + rects->width); + *vertices++ = (glitz_float_t) (rects->y + rects->height); + *vertices++ = (glitz_float_t) rects->x; + *vertices++ = (glitz_float_t) (rects->y + rects->height); + + if ((rects->x + rects->width) > width) + width = rects->x + rects->width; + + if ((rects->y + rects->height) > height) + height = rects->y + rects->height; + } + glitz_buffer_unmap (buffer); + + solid = _glitz_surface_create_solid (dst->surface, + GLITZ_STANDARD_ARGB32, + &glitz_color); + if (solid == NULL) + return CAIRO_STATUS_NO_MEMORY; + + status = _glitz_composite (_glitz_operator (op), + solid, + NULL, + dst->surface, + 0, 0, + 0, 0, + 0, 0, + width, height, + buffer, &gf); + + glitz_surface_destroy (solid); + glitz_buffer_destroy (buffer); + free (data); + + return status; + } else + glitz_set_rectangles (dst->surface, &glitz_color, + (glitz_rectangle_t *) rects, n_rects); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_glitz_surface_composite_trapezoids (cairo_operator_t op, + cairo_surface_t *generic_src, + void *abstract_dst, + int x_src, + int y_src, + cairo_trapezoid_t *traps, + int n_traps) +{ + cairo_glitz_surface_t *dst = abstract_dst; + cairo_glitz_surface_t *src = (cairo_glitz_surface_t *) generic_src; + glitz_surface_t *mask = NULL; + glitz_float_t *vertices; + glitz_buffer_t *buffer; + glitz_geometry_format_t gf; + cairo_int_status_t status; + int x_dst, y_dst, x_rel, y_rel, width, height; + void *data; + + if (generic_src->backend != dst->base.backend) + return CAIRO_INT_STATUS_UNSUPPORTED; + + gf.mode = GLITZ_GEOMETRY_MODE_DIRECT; + gf.edge_hint = GLITZ_GEOMETRY_EDGE_HINT_GOOD_SMOOTH; + gf.primitive = GLITZ_GEOMETRY_PRIMITIVE_QUADS; + gf.type = GLITZ_DATA_TYPE_FLOAT; + gf.first = 0; + gf.count = n_traps * 4; + + data = malloc (n_traps * 8 * sizeof (glitz_float_t)); + if (!data) + return CAIRO_STATUS_NO_MEMORY; + + buffer = glitz_buffer_create_for_data (data); + if (buffer == NULL) { + free (data); + return CAIRO_STATUS_NO_MEMORY; + } + + x_dst = traps[0].left.p1.x >> 16; + y_dst = traps[0].left.p1.y >> 16; + + vertices = glitz_buffer_map (buffer, GLITZ_BUFFER_ACCESS_WRITE_ONLY); + for (; n_traps; traps++, n_traps--) { + glitz_float_t top, bottom; + + top = GLITZ_FIXED_TO_FLOAT (traps->top); + bottom = GLITZ_FIXED_TO_FLOAT (traps->bottom); + + *vertices++ = GLITZ_FIXED_LINE_X_TO_FLOAT (traps->left, traps->top); + *vertices++ = top; + *vertices++ = + GLITZ_FIXED_LINE_X_CEIL_TO_FLOAT (traps->right, traps->top); + *vertices++ = top; + *vertices++ = + GLITZ_FIXED_LINE_X_CEIL_TO_FLOAT (traps->right, traps->bottom); + *vertices++ = bottom; + *vertices++ = GLITZ_FIXED_LINE_X_TO_FLOAT (traps->left, traps->bottom); + *vertices++ = bottom; + } + glitz_buffer_unmap (buffer); + + if ((src->pattern.type == CAIRO_PATTERN_SURFACE) && + (src->pattern.color.alpha != 1.0)) { + glitz_color_t color; + + color.red = color.green = color.blue = 0; + color.alpha = src->pattern.color.alpha_short; + + mask = _glitz_surface_create_solid (dst->surface, + GLITZ_STANDARD_A8, + &color); + } + + x_rel = (src->pattern_box.p1.x >> 16) + x_src - x_dst; + y_rel = (src->pattern_box.p1.y >> 16) + y_src - y_dst; + + x_dst = src->pattern_box.p1.x >> 16; + y_dst = src->pattern_box.p1.y >> 16; + + width = ((src->pattern_box.p2.x + 65535) >> 16) - + (src->pattern_box.p1.x >> 16); + height = ((src->pattern_box.p2.y + 65535) >> 16) - + (src->pattern_box.p1.y >> 16); + + status = _glitz_composite (_glitz_operator (op), + src->surface, + mask, + dst->surface, + x_rel, y_rel, + 0, 0, + x_dst, y_dst, + width, height, + buffer, &gf); + + if (mask) + glitz_surface_destroy (mask); + + glitz_buffer_destroy (buffer); + free (data); + + return status; +} + +static cairo_int_status_t +_cairo_glitz_surface_copy_page (void *abstract_surface) +{ + return CAIRO_INT_STATUS_UNSUPPORTED; +} + +static cairo_int_status_t +_cairo_glitz_surface_show_page (void *abstract_surface) +{ + return CAIRO_INT_STATUS_UNSUPPORTED; +} + +static cairo_int_status_t +_cairo_glitz_surface_create_pattern (void *abstract_dst, + cairo_pattern_t *pattern, + cairo_box_t *box) +{ + cairo_glitz_surface_t *dst = abstract_dst; + cairo_surface_t *generic_src = NULL; + cairo_image_surface_t *image = NULL; + cairo_glitz_surface_t *src; + + switch (pattern->type) { + case CAIRO_PATTERN_SOLID: + generic_src = + _cairo_surface_create_similar_solid (abstract_dst, + CAIRO_FORMAT_ARGB32, + 1, 1, + &pattern->color); + if (generic_src) + cairo_surface_set_repeat (generic_src, 1); + break; + case CAIRO_PATTERN_RADIAL: + /* glitz doesn't support inner and outer circle with different + center points. */ + if (pattern->u.radial.center0.x != pattern->u.radial.center1.x || + pattern->u.radial.center0.y != pattern->u.radial.center1.y) + break; + /* fall-through */ + case CAIRO_PATTERN_LINEAR: { + glitz_fixed16_16_t *params; + int i, n_params; + + if (!(dst->features & GLITZ_FEATURE_FRAGMENT_PROGRAM_MASK)) + break; + + if (pattern->filter != CAIRO_FILTER_BILINEAR) + break; + + n_params = pattern->n_stops * 3 + 4; + + params = malloc (sizeof (glitz_fixed16_16_t) * n_params); + if (params == NULL) + return CAIRO_STATUS_NO_MEMORY; + + generic_src = + _cairo_glitz_surface_create_similar (abstract_dst, + CAIRO_FORMAT_ARGB32, 0, + pattern->n_stops, 1); + if (generic_src == NULL) { + free (params); + return CAIRO_STATUS_NO_MEMORY; + } + + src = (cairo_glitz_surface_t *) generic_src; + + for (i = 0; i < pattern->n_stops; i++) { + glitz_color_t color; + + color.alpha = pattern->stops[i].color_char[3]; + color.red = pattern->stops[i].color_char[0] * color.alpha; + color.green = pattern->stops[i].color_char[1] * color.alpha; + color.blue = pattern->stops[i].color_char[2] * color.alpha; + color.alpha *= 256; + + glitz_set_rectangle (src->surface, &color, i, 0, 1, 1); + + params[4 + 3 * i] = pattern->stops[i].offset; + params[5 + 3 * i] = i << 16; + params[6 + 3 * i] = 0; + } + + if (pattern->type == CAIRO_PATTERN_LINEAR) { + params[0] = _cairo_fixed_from_double (pattern->u.linear.point0.x); + params[1] = _cairo_fixed_from_double (pattern->u.linear.point0.y); + params[2] = _cairo_fixed_from_double (pattern->u.linear.point1.x); + params[3] = _cairo_fixed_from_double (pattern->u.linear.point1.y); + + glitz_surface_set_filter (src->surface, + GLITZ_FILTER_LINEAR_GRADIENT, + params, n_params); + } else { + params[0] = _cairo_fixed_from_double (pattern->u.radial.center0.x); + params[1] = _cairo_fixed_from_double (pattern->u.radial.center0.y); + params[2] = _cairo_fixed_from_double (pattern->u.radial.radius0); + params[3] = _cairo_fixed_from_double (pattern->u.radial.radius1); + + glitz_surface_set_filter (src->surface, + GLITZ_FILTER_RADIAL_GRADIENT, + params, n_params); + } + + switch (pattern->extend) { + case CAIRO_EXTEND_REPEAT: + glitz_surface_set_fill (src->surface, GLITZ_FILL_REPEAT); + break; + case CAIRO_EXTEND_REFLECT: + glitz_surface_set_fill (src->surface, GLITZ_FILL_REFLECT); + break; + case CAIRO_EXTEND_NONE: + default: + glitz_surface_set_fill (src->surface, GLITZ_FILL_NEAREST); + break; + } + + cairo_surface_set_matrix (&src->base, &pattern->matrix); + + free (params); + } break; + case CAIRO_PATTERN_SURFACE: + generic_src = pattern->u.surface.surface; + cairo_surface_reference (generic_src); + break; + } + + if (generic_src == NULL) { + image = _cairo_pattern_get_image (pattern, box); + if (image == NULL) + return CAIRO_STATUS_NO_MEMORY; + + generic_src = &image->base; + } + + if (generic_src->backend != dst->base.backend) { + src = _cairo_glitz_surface_clone_similar (dst, generic_src, + CAIRO_FORMAT_ARGB32); + if (src == NULL) + return CAIRO_STATUS_NO_MEMORY; + + cairo_surface_set_repeat (&src->base, generic_src->repeat); + } else + src = (cairo_glitz_surface_t *) generic_src; + + if (image) + cairo_surface_destroy (&image->base); + + _cairo_pattern_init_copy (&src->pattern, pattern); + src->pattern_box = *box; + + pattern->source = &src->base; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_glitz_surface_set_clip_region (void *abstract_surface, + pixman_region16_t *region) +{ + return CAIRO_INT_STATUS_UNSUPPORTED; +} + +static const struct cairo_surface_backend cairo_glitz_surface_backend = { + _cairo_glitz_surface_create_similar, + _cairo_glitz_surface_destroy, + _cairo_glitz_surface_pixels_per_inch, + _cairo_glitz_surface_get_image, + _cairo_glitz_surface_set_image, + _cairo_glitz_surface_set_matrix, + _cairo_glitz_surface_set_filter, + _cairo_glitz_surface_set_repeat, + _cairo_glitz_surface_composite, + _cairo_glitz_surface_fill_rectangles, + _cairo_glitz_surface_composite_trapezoids, + _cairo_glitz_surface_copy_page, + _cairo_glitz_surface_show_page, + _cairo_glitz_surface_set_clip_region, + _cairo_glitz_surface_create_pattern, + NULL /* show_glyphs */ +}; + +cairo_surface_t * +cairo_glitz_surface_create (glitz_surface_t *surface) +{ + cairo_glitz_surface_t *crsurface; + + if (!surface) + return NULL; + + crsurface = malloc (sizeof (cairo_glitz_surface_t)); + if (crsurface == NULL) + return NULL; + + _cairo_surface_init (&crsurface->base, &cairo_glitz_surface_backend); + + crsurface->surface = surface; + crsurface->features = glitz_surface_get_features (surface); + crsurface->format = glitz_surface_get_format (surface); + + _cairo_pattern_init (&crsurface->pattern); + crsurface->pattern.type = CAIRO_PATTERN_SURFACE; + crsurface->pattern.u.surface.surface = NULL; + + return (cairo_surface_t *) crsurface; +} diff --git a/src/cairo_gstate.c b/src/cairo_gstate.c index 563f84b4..9f9de69e 100644 --- a/src/cairo_gstate.c +++ b/src/cairo_gstate.c @@ -1,22 +1,37 @@ /* cairo - a vector graphics library with display and print output * - * Copyright © 2002 University of Southern California + * Copyright © 2002 University of Southern California * * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. * - * This library 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 - * Library General Public License for more details. + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ * - * Author: Carl D. Worth <cworth@isi.edu> + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth <cworth@isi.edu> */ #include <stdlib.h> @@ -62,9 +77,9 @@ _cairo_gstate_init (cairo_gstate_t *gstate) gstate->num_dashes = 0; gstate->dash_offset = 0.0; - gstate->font = _cairo_font_create (CAIRO_FONT_FAMILY_DEFAULT, - CAIRO_FONT_SLANT_DEFAULT, - CAIRO_FONT_WEIGHT_DEFAULT); + gstate->font = _cairo_unscaled_font_create (CAIRO_FONT_FAMILY_DEFAULT, + CAIRO_FONT_SLANT_DEFAULT, + CAIRO_FONT_WEIGHT_DEFAULT); gstate->surface = NULL; @@ -104,11 +119,8 @@ _cairo_gstate_init_copy (cairo_gstate_t *gstate, cairo_gstate_t *other) } if (other->font) { - gstate->font = _cairo_font_copy (other->font); - if (!gstate->font) { - status = CAIRO_STATUS_NO_MEMORY; - goto CLEANUP_DASHES; - } + gstate->font = other->font; + _cairo_unscaled_font_reference (gstate->font); } if (other->clip.region) @@ -134,9 +146,10 @@ _cairo_gstate_init_copy (cairo_gstate_t *gstate, cairo_gstate_t *other) CLEANUP_PATH: _cairo_path_fini (&gstate->path); + CLEANUP_FONT: - cairo_font_destroy (gstate->font); - CLEANUP_DASHES: + _cairo_unscaled_font_destroy (gstate->font); + free (gstate->dash); gstate->dash = NULL; @@ -146,7 +159,7 @@ _cairo_gstate_init_copy (cairo_gstate_t *gstate, cairo_gstate_t *other) void _cairo_gstate_fini (cairo_gstate_t *gstate) { - cairo_font_destroy (gstate->font); + _cairo_unscaled_font_destroy (gstate->font); if (gstate->surface) cairo_surface_destroy (gstate->surface); @@ -162,6 +175,8 @@ _cairo_gstate_fini (cairo_gstate_t *gstate) cairo_pattern_destroy (gstate->pattern); + _cairo_matrix_fini (&gstate->font_matrix); + _cairo_matrix_fini (&gstate->ctm); _cairo_matrix_fini (&gstate->ctm_inverse); @@ -612,6 +627,8 @@ _cairo_gstate_default_matrix (cairo_gstate_t *gstate) if (scale == 0) scale = 1; + cairo_matrix_set_identity (&gstate->font_matrix); + cairo_matrix_set_identity (&gstate->ctm); cairo_matrix_scale (&gstate->ctm, scale, scale); cairo_matrix_copy (&gstate->ctm_inverse, &gstate->ctm); @@ -1968,16 +1985,28 @@ _cairo_gstate_show_surface (cairo_gstate_t *gstate, return CAIRO_STATUS_SUCCESS; } + cairo_status_t _cairo_gstate_select_font (cairo_gstate_t *gstate, const char *family, cairo_font_slant_t slant, cairo_font_weight_t weight) { - if (gstate->font != NULL) - cairo_font_destroy (gstate->font); + cairo_unscaled_font_t *tmp; + + tmp = _cairo_unscaled_font_create (family, slant, weight); + + if (tmp == NULL) + return CAIRO_STATUS_NO_MEMORY; - gstate->font = _cairo_font_create (family, slant, weight); + if (gstate->font != tmp) + { + if (gstate->font != NULL) + _cairo_unscaled_font_destroy (gstate->font); + + cairo_matrix_set_identity (&gstate->font_matrix); + gstate->font = tmp; + } return CAIRO_STATUS_SUCCESS; } @@ -1986,212 +2015,294 @@ cairo_status_t _cairo_gstate_scale_font (cairo_gstate_t *gstate, double scale) { - return _cairo_font_scale (gstate->font, scale); + return cairo_matrix_scale (&gstate->font_matrix, scale, scale); } cairo_status_t _cairo_gstate_transform_font (cairo_gstate_t *gstate, cairo_matrix_t *matrix) { - return _cairo_font_transform (gstate->font, matrix); + cairo_matrix_t tmp; + double a, b, c, d, tx, ty; + cairo_matrix_get_affine (matrix, &a, &b, &c, &d, &tx, &ty); + cairo_matrix_set_affine (&tmp, a, b, c, d, 0, 0); + return cairo_matrix_multiply (&gstate->font_matrix, &gstate->font_matrix, &tmp); } + cairo_status_t _cairo_gstate_current_font (cairo_gstate_t *gstate, cairo_font_t **font) { - *font = gstate->font; + cairo_font_scale_t scale; + cairo_font_t *scaled; + double dummy; + + scaled = malloc (sizeof (cairo_font_t)); + if (scaled == NULL) + return CAIRO_STATUS_NO_MEMORY; + + cairo_matrix_get_affine (&gstate->font_matrix, + &scale.matrix[0][0], + &scale.matrix[0][1], + &scale.matrix[1][0], + &scale.matrix[1][1], + &dummy, &dummy); + + _cairo_font_init (scaled, &scale, gstate->font); + _cairo_unscaled_font_reference (gstate->font); + + *font = scaled; return CAIRO_STATUS_SUCCESS; } -cairo_status_t -_cairo_gstate_current_font_extents (cairo_gstate_t *gstate, - cairo_font_extents_t *extents) +void +_cairo_gstate_set_font_transform (cairo_gstate_t *gstate, + cairo_matrix_t *matrix) { - cairo_int_status_t status; - cairo_matrix_t saved_font_matrix; - - cairo_matrix_copy (&saved_font_matrix, &gstate->font->matrix); - cairo_matrix_multiply (&gstate->font->matrix, &gstate->ctm, &gstate->font->matrix); - - status = _cairo_font_font_extents (gstate->font, extents); - - cairo_matrix_copy (&gstate->font->matrix, &saved_font_matrix); + cairo_matrix_copy (&gstate->font_matrix, matrix); +} - return status; +void +_cairo_gstate_current_font_transform (cairo_gstate_t *gstate, + cairo_matrix_t *matrix) +{ + cairo_matrix_copy (matrix, &gstate->font_matrix); } +/* + * Like everything else in this file, fonts involve Too Many Coordinate Spaces; + * it is easy to get confused about what's going on. + * + * The user's view + * --------------- + * + * Users ask for things in user space. When cairo starts, a user space unit + * is about 1/96 inch, which is similar to (but importantly different from) + * the normal "point" units most users think in terms of. When a user + * selects a font, its scale is set to "one user unit". The user can then + * independently scale the user coordinate system *or* the font matrix, in + * order to adjust the rendered size of the font. + * + * If the user asks for a permanent reference to "a font", they are given a + * handle to a structure holding a scale matrix and an unscaled font. This + * effectively decouples the font from further changes to user space. Even + * if the user then "sets" the current cairo_t font to the handle they were + * passed, further changes to the cairo_t CTM will not affect externally + * held references to the font. + * + * + * The font's view + * --------------- + * + * Fonts are designed and stored (in say .ttf files) in "font space", which + * describes an "EM Square" (a design tile) and has some abstract number + * such as 1000, 1024, or 2048 units per "EM". This is basically an + * uninteresting space for us, but we need to remember that it exists. + * + * Font resources (from libraries or operating systems) render themselves + * to a particular device. Since they do not want to make most programmers + * worry about the font design space, the scaling API is simplified to + * involve just telling the font the required pixel size of the EM square + * (that is, in device space). + * + * + * Cairo's gstate view + * ------------------- + * + * In addition to the CTM and CTM inverse, we keep a matrix in the gstate + * called the "font matrix" which describes the user's most recent + * font-scaling or font-transforming request. This is kept in terms of an + * abstract scale factor, composed with the CTM and used to set the font's + * pixel size. So if the user asks to "scale the font by 12", the matrix + * is: + * + * [ 12.0, 0.0, 0.0, 12.0, 0.0, 0.0 ] + * + * It is an affine matrix, like all cairo matrices, but its tx and ty + * components are always set to zero; we don't permit "nudging" fonts + * around. + * + * In order to perform any action on a font, we must build an object + * called a cairo_font_scale_t; this contains the central 2x2 matrix + * resulting from "font matrix * CTM". + * + * We pass this to the font when making requests of it, which causes it to + * reply for a particular [user request, device] combination, under the CTM + * (to accomodate the "zoom in" == "bigger fonts" issue above). + * + * The other terms in our communication with the font are therefore in + * device space. When we ask it to perform text->glyph conversion, it will + * produce a glyph string in device space. Glyph vectors we pass to it for + * measuring or rendering should be in device space. The metrics which we + * get back from the font will be in device space. The contents of the + * global glyph image cache will be in device space. + * + * + * Cairo's public view + * ------------------- + * + * Since the values entering and leaving via public API calls are in user + * space, the gstate functions typically need to multiply argumens by the + * CTM (for user-input glyph vectors), and return values by the CTM inverse + * (for font responses such as metrics or glyph vectors). + * + */ -cairo_status_t -_cairo_gstate_set_font (cairo_gstate_t *gstate, - cairo_font_t *font) +static void +_build_font_scale (cairo_gstate_t *gstate, + cairo_font_scale_t *sc) { - if (gstate->font != NULL) - cairo_font_destroy (gstate->font); - gstate->font = font; - cairo_font_reference (gstate->font); - return CAIRO_STATUS_SUCCESS; + cairo_matrix_t tmp; + double dummy; + cairo_matrix_multiply (&tmp, &gstate->font_matrix, &gstate->ctm); + cairo_matrix_get_affine (&tmp, + &sc->matrix[0][0], + &sc->matrix[0][1], + &sc->matrix[1][0], + &sc->matrix[1][1], + &dummy, &dummy); } cairo_status_t -_cairo_gstate_text_extents (cairo_gstate_t *gstate, - const unsigned char *utf8, - cairo_text_extents_t *extents) +_cairo_gstate_current_font_extents (cairo_gstate_t *gstate, + cairo_font_extents_t *extents) { - cairo_matrix_t saved_font_matrix; - cairo_status_t status; - double scale_x, scale_y; - - cairo_matrix_copy (&saved_font_matrix, &gstate->font->matrix); - _cairo_matrix_compute_scale_factors (&gstate->ctm, &scale_x, &scale_y); - cairo_matrix_scale (&gstate->font->matrix, scale_x, scale_y); - - status = _cairo_font_text_extents (gstate->font, - utf8, extents); - - cairo_matrix_copy (&gstate->font->matrix, &saved_font_matrix); + cairo_int_status_t status; + cairo_font_scale_t sc; + double dummy = 0.0; - extents->x_bearing /= scale_x; - extents->y_bearing /= scale_y; - extents->width /= scale_x; - extents->height /= scale_y; - extents->x_advance /= scale_x; - extents->y_advance /= scale_y; + _build_font_scale (gstate, &sc); - return status; -} + status = _cairo_unscaled_font_font_extents (gstate->font, &sc, extents); -cairo_status_t -_cairo_gstate_glyph_extents (cairo_gstate_t *gstate, - cairo_glyph_t *glyphs, - int num_glyphs, - cairo_text_extents_t *extents) -{ - cairo_status_t status; - cairo_matrix_t saved_font_matrix; - double scale_x, scale_y; + /* The font responded in device space; convert to user space. */ - cairo_matrix_copy (&saved_font_matrix, &gstate->font->matrix); - _cairo_matrix_compute_scale_factors (&gstate->ctm, &scale_x, &scale_y); - cairo_matrix_scale (&gstate->font->matrix, scale_x, scale_y); + cairo_matrix_transform_distance (&gstate->ctm_inverse, + &dummy, + &extents->ascent); - status = _cairo_font_glyph_extents (gstate->font, - glyphs, num_glyphs, - extents); + cairo_matrix_transform_distance (&gstate->ctm_inverse, + &dummy, + &extents->descent); - cairo_matrix_copy (&gstate->font->matrix, &saved_font_matrix); + cairo_matrix_transform_distance (&gstate->ctm_inverse, + &dummy, + &extents->height); - extents->x_bearing /= scale_x; - extents->y_bearing /= scale_y; - extents->width /= scale_x; - extents->height /= scale_y; - extents->x_advance /= scale_x; - extents->y_advance /= scale_y; + cairo_matrix_transform_distance (&gstate->ctm_inverse, + &extents->max_x_advance, + &extents->max_y_advance); return status; } cairo_status_t -_cairo_gstate_show_text (cairo_gstate_t *gstate, - const unsigned char *utf8) +_cairo_gstate_text_to_glyphs (cairo_gstate_t *gstate, + const unsigned char *utf8, + cairo_glyph_t **glyphs, + int *nglyphs) { cairo_status_t status; - cairo_point_t point; - double x, y; - cairo_matrix_t saved_font_matrix; - cairo_pattern_t pattern; - cairo_box_t bbox; + cairo_font_scale_t sc; + + cairo_point_t point; + double dev_x, dev_y; + int i; + + _build_font_scale (gstate, &sc); status = _cairo_path_current_point (&gstate->path, &point); if (status == CAIRO_STATUS_NO_CURRENT_POINT) { - x = 0; - y = 0; - cairo_matrix_transform_point (&gstate->ctm, &x, &y); + dev_x = 0.0; + dev_y = 0.0; } else { - x = _cairo_fixed_to_double (point.x); - y = _cairo_fixed_to_double (point.y); + dev_x = _cairo_fixed_to_double (point.x); + dev_y = _cairo_fixed_to_double (point.y); } - - cairo_matrix_copy (&saved_font_matrix, &gstate->font->matrix); - cairo_matrix_multiply (&gstate->font->matrix, &gstate->ctm, &gstate->font->matrix); - _cairo_pattern_init_copy (&pattern, gstate->pattern); - - status = _cairo_font_text_bbox (gstate->font, gstate->surface, - x, y, utf8, &bbox); - if (status) - return status; - - status = _cairo_gstate_create_pattern (gstate, &pattern, &bbox); - if (status) + status = _cairo_unscaled_font_text_to_glyphs (gstate->font, + &sc, utf8, glyphs, nglyphs); + + if (status || !glyphs || !nglyphs || !(*glyphs) || !(nglyphs)) return status; - - if (gstate->clip.surface) - { - cairo_surface_t *intermediate; - cairo_color_t empty_color; - _cairo_color_init (&empty_color); - _cairo_color_set_alpha (&empty_color, .0); - intermediate = _cairo_surface_create_similar_solid (gstate->clip.surface, - CAIRO_FORMAT_A8, - gstate->clip.width, - gstate->clip.height, - &empty_color); + /* The font responded in device space, starting from (0,0); add any + current point offset in device space, and convert to user space. */ - status = _cairo_font_show_text (gstate->font, - CAIRO_OPERATOR_ADD, pattern.source, - intermediate, - gstate->clip.x - pattern.source_offset.x, - gstate->clip.y - pattern.source_offset.y, - x - gstate->clip.x, - y - gstate->clip.y, utf8); + for (i = 0; i < *nglyphs; ++i) { + (*glyphs)[i].x += dev_x; + (*glyphs)[i].y += dev_y; + cairo_matrix_transform_point (&gstate->ctm_inverse, + &((*glyphs)[i].x), + &((*glyphs)[i].y)); + } + + return CAIRO_STATUS_SUCCESS; +} - if (status) - goto BAIL; - - status = _cairo_surface_composite (CAIRO_OPERATOR_IN, - gstate->clip.surface, - NULL, - intermediate, - 0, 0, - 0, 0, - 0, 0, - gstate->clip.width, - gstate->clip.height); +cairo_status_t +_cairo_gstate_set_font (cairo_gstate_t *gstate, + cairo_font_t *font) +{ + if (gstate->font != NULL) + _cairo_unscaled_font_destroy (gstate->font); + gstate->font = font->unscaled; + _cairo_unscaled_font_reference (gstate->font); + cairo_matrix_set_affine (&gstate->font_matrix, + font->scale.matrix[0][0], + font->scale.matrix[0][1], + font->scale.matrix[1][0], + font->scale.matrix[1][1], + 0, 0); + return CAIRO_STATUS_SUCCESS; +} - if (status) - goto BAIL; +cairo_status_t +_cairo_gstate_glyph_extents (cairo_gstate_t *gstate, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_text_extents_t *extents) +{ + cairo_status_t status; + cairo_glyph_t *transformed_glyphs; + cairo_font_scale_t sc; + int i; - status = _cairo_surface_composite (gstate->operator, - pattern.source, - intermediate, - gstate->surface, - 0, 0, - 0, 0, - gstate->clip.x, - gstate->clip.y, - gstate->clip.width, - gstate->clip.height); + _build_font_scale (gstate, &sc); - BAIL: - cairo_surface_destroy (intermediate); - - } - else + transformed_glyphs = malloc (num_glyphs * sizeof(cairo_glyph_t)); + if (transformed_glyphs == NULL) + return CAIRO_STATUS_NO_MEMORY; + + for (i = 0; i < num_glyphs; ++i) { - status = _cairo_font_show_text (gstate->font, - gstate->operator, pattern.source, - gstate->surface, - -pattern.source_offset.x, - -pattern.source_offset.y, - x, y, utf8); + transformed_glyphs[i] = glyphs[i]; + cairo_matrix_transform_point (&gstate->ctm, + &transformed_glyphs[i].x, + &transformed_glyphs[i].y); } - - cairo_matrix_copy (&gstate->font->matrix, &saved_font_matrix); - _cairo_pattern_fini (&pattern); + status = _cairo_unscaled_font_glyph_extents (gstate->font, &sc, + transformed_glyphs, num_glyphs, + extents); + + /* The font responded in device space; convert to user space. */ + + cairo_matrix_transform_distance (&gstate->ctm_inverse, + &extents->x_bearing, + &extents->y_bearing); + + cairo_matrix_transform_distance (&gstate->ctm_inverse, + &extents->width, + &extents->height); + + cairo_matrix_transform_distance (&gstate->ctm_inverse, + &extents->x_advance, + &extents->y_advance); + + free (transformed_glyphs); return status; } @@ -2202,12 +2313,14 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate, int num_glyphs) { cairo_status_t status; - cairo_matrix_t saved_font_matrix; int i; cairo_glyph_t *transformed_glyphs = NULL; + cairo_font_scale_t sc; cairo_pattern_t pattern; cairo_box_t bbox; + _build_font_scale (gstate, &sc); + transformed_glyphs = malloc (num_glyphs * sizeof(cairo_glyph_t)); if (transformed_glyphs == NULL) return CAIRO_STATUS_NO_MEMORY; @@ -2216,16 +2329,14 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate, { transformed_glyphs[i] = glyphs[i]; cairo_matrix_transform_point (&gstate->ctm, - &(transformed_glyphs[i].x), - &(transformed_glyphs[i].y)); + &transformed_glyphs[i].x, + &transformed_glyphs[i].y); } - cairo_matrix_copy (&saved_font_matrix, &gstate->font->matrix); - cairo_matrix_multiply (&gstate->font->matrix, &gstate->ctm, &gstate->font->matrix); - _cairo_pattern_init_copy (&pattern, gstate->pattern); - status = _cairo_font_glyph_bbox (gstate->font, gstate->surface, - transformed_glyphs, num_glyphs, &bbox); + status = _cairo_unscaled_font_glyph_bbox (gstate->font, &sc, + transformed_glyphs, num_glyphs, + &bbox); if (status) return status; @@ -2253,12 +2364,13 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate, transformed_glyphs[i].y -= gstate->clip.y; } - status = _cairo_font_show_glyphs (gstate->font, - CAIRO_OPERATOR_ADD, - pattern.source, intermediate, - gstate->clip.x - pattern.source_offset.x, - gstate->clip.y - pattern.source_offset.y, - transformed_glyphs, num_glyphs); + status = _cairo_unscaled_font_show_glyphs (gstate->font, + &sc, + CAIRO_OPERATOR_ADD, + pattern.source, intermediate, + gstate->clip.x - pattern.source_offset.x, + gstate->clip.y - pattern.source_offset.y, + transformed_glyphs, num_glyphs); if (status) goto BAIL; @@ -2293,16 +2405,15 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate, } else { - status = _cairo_font_show_glyphs (gstate->font, - gstate->operator, pattern.source, - gstate->surface, - -pattern.source_offset.x, - -pattern.source_offset.y, - transformed_glyphs, num_glyphs); + status = _cairo_unscaled_font_show_glyphs (gstate->font, + &sc, + gstate->operator, pattern.source, + gstate->surface, + -pattern.source_offset.x, + -pattern.source_offset.y, + transformed_glyphs, num_glyphs); } - cairo_matrix_copy (&gstate->font->matrix, &saved_font_matrix); - _cairo_pattern_fini (&pattern); free (transformed_glyphs); @@ -2310,40 +2421,6 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate, return status; } - -cairo_status_t -_cairo_gstate_text_path (cairo_gstate_t *gstate, - const unsigned char *utf8) -{ - cairo_status_t status; - cairo_matrix_t saved_font_matrix; - cairo_point_t point; - double x, y; - - status = _cairo_path_current_point (&gstate->path, &point); - if (status == CAIRO_STATUS_NO_CURRENT_POINT) { - x = 0; - y = 0; - cairo_matrix_transform_point (&gstate->ctm, &x, &y); - } else { - x = _cairo_fixed_to_double (point.x); - y = _cairo_fixed_to_double (point.y); - } - - cairo_matrix_copy (&saved_font_matrix, &gstate->font->matrix); - cairo_matrix_multiply (&gstate->font->matrix, &gstate->ctm, &gstate->font->matrix); - - status = _cairo_font_text_path (gstate->font, - x, y, - utf8, - &gstate->path); - - cairo_matrix_copy (&gstate->font->matrix, &saved_font_matrix); - - return status; -} - - cairo_status_t _cairo_gstate_glyph_path (cairo_gstate_t *gstate, cairo_glyph_t *glyphs, @@ -2352,7 +2429,9 @@ _cairo_gstate_glyph_path (cairo_gstate_t *gstate, cairo_status_t status; int i; cairo_glyph_t *transformed_glyphs = NULL; - cairo_matrix_t saved_font_matrix; + cairo_font_scale_t sc; + + _build_font_scale (gstate, &sc); transformed_glyphs = malloc (num_glyphs * sizeof(cairo_glyph_t)); if (transformed_glyphs == NULL) @@ -2366,14 +2445,9 @@ _cairo_gstate_glyph_path (cairo_gstate_t *gstate, &(transformed_glyphs[i].y)); } - cairo_matrix_copy (&saved_font_matrix, &gstate->font->matrix); - cairo_matrix_multiply (&gstate->font->matrix, &gstate->ctm, &gstate->font->matrix); - - status = _cairo_font_glyph_path (gstate->font, - transformed_glyphs, num_glyphs, - &gstate->path); - - cairo_matrix_copy (&gstate->font->matrix, &saved_font_matrix); + status = _cairo_unscaled_font_glyph_path (gstate->font, &sc, + transformed_glyphs, num_glyphs, + &gstate->path); free (transformed_glyphs); return status; diff --git a/src/cairo_hull.c b/src/cairo_hull.c index 93115e6a..99b16d1a 100644 --- a/src/cairo_hull.c +++ b/src/cairo_hull.c @@ -1,22 +1,37 @@ /* cairo - a vector graphics library with display and print output * - * Copyright © 2003 University of Southern California + * Copyright © 2003 University of Southern California * * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. * - * This library 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 - * Library General Public License for more details. + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ * - * Author: Carl D. Worth <cworth@isi.edu> + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth <cworth@isi.edu> */ #include "cairoint.h" @@ -82,10 +97,13 @@ _cairo_hull_vertex_compare (const void *av, const void *bv) (cairo_fixed_48_16_t) a->slope.dy * a->slope.dy); b_dist = ((cairo_fixed_48_16_t) b->slope.dx * b->slope.dx + (cairo_fixed_48_16_t) b->slope.dy * b->slope.dy); - if (a_dist < b_dist) + if (a_dist < b_dist) { a->discard = 1; - else + ret = -1; + } else { b->discard = 1; + ret = 1; + } } return ret; diff --git a/src/cairo_image_surface.c b/src/cairo_image_surface.c index c8e05804..cbdc018a 100644 --- a/src/cairo_image_surface.c +++ b/src/cairo_image_surface.c @@ -1,22 +1,37 @@ /* cairo - a vector graphics library with display and print output * - * Copyright © 2003 University of Southern California + * Copyright © 2003 University of Southern California * * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. * - * This library 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 - * Library General Public License for more details. + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ * - * Author: Carl D. Worth <cworth@isi.edu> + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth <cworth@isi.edu> */ #include "cairoint.h" @@ -457,7 +472,20 @@ cairo_int_status_t _cairo_image_surface_set_clip_region (cairo_image_surface_t *surface, pixman_region16_t *region) { - pixman_image_set_clip_region (surface->pixman_image, region); + if (region) { + pixman_region16_t *rcopy; + + rcopy = pixman_region_create(); + /* pixman_image_set_clip_region expects to take ownership of the + * passed-in region, so we create a copy to give it. */ + /* XXX: I think that's probably a bug in pixman. But its + * memory management issues need auditing anyway, so a + * workaround like this is fine for now. */ + pixman_region_copy (rcopy, region); + pixman_image_set_clip_region (surface->pixman_image, rcopy); + } else { + pixman_image_set_clip_region (surface->pixman_image, region); + } return CAIRO_STATUS_SUCCESS; } @@ -497,5 +525,6 @@ static const cairo_surface_backend_t cairo_image_surface_backend = { _cairo_image_surface_copy_page, _cairo_image_surface_show_page, _cairo_image_abstract_surface_set_clip_region, - _cairo_image_abstract_surface_create_pattern + _cairo_image_abstract_surface_create_pattern, + NULL /* show_glyphs */ }; diff --git a/src/cairo_matrix.c b/src/cairo_matrix.c index 82b042f3..7fc2694f 100644 --- a/src/cairo_matrix.c +++ b/src/cairo_matrix.c @@ -1,22 +1,37 @@ /* cairo - a vector graphics library with display and print output * - * Copyright © 2002 University of Southern California + * Copyright © 2002 University of Southern California * * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. * - * This library 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 - * Library General Public License for more details. + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ * - * Author: Carl D. Worth <cworth@isi.edu> + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth <cworth@isi.edu> */ #include <stdlib.h> diff --git a/src/cairo_path.c b/src/cairo_path.c index 31d9f250..36c25d63 100644 --- a/src/cairo_path.c +++ b/src/cairo_path.c @@ -1,22 +1,37 @@ /* cairo - a vector graphics library with display and print output * - * Copyright © 2002 University of Southern California + * Copyright © 2002 University of Southern California * * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. * - * This library 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 - * Library General Public License for more details. + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ * - * Author: Carl D. Worth <cworth@isi.edu> + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth <cworth@isi.edu> */ #include <stdlib.h> diff --git a/src/cairo_path_bounds.c b/src/cairo_path_bounds.c index 5795c5b1..cfcdd97e 100644 --- a/src/cairo_path_bounds.c +++ b/src/cairo_path_bounds.c @@ -1,22 +1,37 @@ /* cairo - a vector graphics library with display and print output * - * Copyright © 2003 University of Southern California + * Copyright © 2003 University of Southern California * * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. * - * This library 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 - * Library General Public License for more details. + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ * - * Author: Carl D. Worth <cworth@isi.edu> + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth <cworth@isi.edu> */ #include "cairoint.h" diff --git a/src/cairo_path_fill.c b/src/cairo_path_fill.c index fdb67bc4..6c6ebd97 100644 --- a/src/cairo_path_fill.c +++ b/src/cairo_path_fill.c @@ -1,22 +1,37 @@ /* cairo - a vector graphics library with display and print output * - * Copyright © 2002 University of Southern California + * Copyright © 2002 University of Southern California * * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. * - * This library 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 - * Library General Public License for more details. + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ * - * Author: Carl D. Worth <cworth@isi.edu> + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth <cworth@isi.edu> */ #include "cairoint.h" diff --git a/src/cairo_path_stroke.c b/src/cairo_path_stroke.c index bb704f15..ad022037 100644 --- a/src/cairo_path_stroke.c +++ b/src/cairo_path_stroke.c @@ -1,22 +1,37 @@ /* cairo - a vector graphics library with display and print output * - * Copyright © 2002 University of Southern California + * Copyright © 2002 University of Southern California * * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. * - * This library 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 - * Library General Public License for more details. + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ * - * Author: Carl D. Worth <cworth@isi.edu> + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth <cworth@isi.edu> */ #include "cairoint.h" diff --git a/src/cairo_pattern.c b/src/cairo_pattern.c index e1001372..6cb98145 100644 --- a/src/cairo_pattern.c +++ b/src/cairo_pattern.c @@ -1,6 +1,6 @@ /* cairo - a vector graphics library with display and print output * - * Copyright © 2004 David Reveman + * Copyright © 2004 David Reveman * * Permission to use, copy, modify, distribute, and sell this software * and its documentation for any purpose is hereby granted without diff --git a/src/cairo_pen.c b/src/cairo_pen.c index c91e97d6..f365091d 100644 --- a/src/cairo_pen.c +++ b/src/cairo_pen.c @@ -1,28 +1,43 @@ /* cairo - a vector graphics library with display and print output * - * Copyright © 2002 University of Southern California + * Copyright © 2002 University of Southern California * * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. * - * This library 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 - * Library General Public License for more details. + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ * - * Author: Carl D. Worth <cworth@isi.edu> + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth <cworth@isi.edu> */ #include "cairoint.h" static int -_cairo_pen_vertices_needed (double radius, double tolerance, double expansion); +_cairo_pen_vertices_needed (double tolerance, double radius, cairo_matrix_t *matrix); static void _cairo_pen_compute_slopes (cairo_pen_t *pen); @@ -46,7 +61,7 @@ _cairo_pen_init (cairo_pen_t *pen, double radius, cairo_gstate_t *gstate) { int i; int reflect; - double det, expansion; + double det; if (pen->num_vertices) { /* XXX: It would be nice to notice that the pen is already properly constructed. @@ -61,24 +76,17 @@ _cairo_pen_init (cairo_pen_t *pen, double radius, cairo_gstate_t *gstate) pen->radius = radius; pen->tolerance = gstate->tolerance; - /* The determinant represents the area expansion factor of the - transform. In the worst case, this is entirely in one - dimension, which is what we assume here. */ - _cairo_matrix_compute_determinant (&gstate->ctm, &det); if (det >= 0) { reflect = 0; - expansion = det; } else { reflect = 1; - expansion = -det; } - - pen->num_vertices = _cairo_pen_vertices_needed (radius, gstate->tolerance, expansion); - /* number of vertices must be even */ - if (pen->num_vertices % 2) - pen->num_vertices++; + pen->num_vertices = _cairo_pen_vertices_needed (gstate->tolerance, + radius, + &gstate->ctm); + pen->vertices = malloc (pen->num_vertices * sizeof (cairo_pen_vertex_t)); if (pen->vertices == NULL) { return CAIRO_STATUS_NO_MEMORY; @@ -156,17 +164,253 @@ _cairo_pen_add_points (cairo_pen_t *pen, cairo_point_t *point, int num_points) return CAIRO_STATUS_SUCCESS; } +/* +The circular pen in user space is transformed into an ellipse in +device space. + +We construct the pen by computing points along the circumference +using equally spaced angles. + +We show below that this approximation to the ellipse has +maximum error at the major axis of the ellipse. +So, we need to compute the length of the major axis and then +use that to compute the number of sides needed in our pen. + +Thanks to Walter Brisken <wbrisken@aoc.nrao.edu> for this +derivation: + +1. First some notation: + +All capital letters represent vectors in two dimensions. A prime ' +represents a transformed coordinate. Matrices are written in underlined +form, ie _R_. Lowercase letters represent scalar real values. + +The letter t is used to represent the greek letter theta. + +2. The question has been posed: What is the maximum expansion factor +achieved by the linear transformation + +X' = _R_ X + +where _R_ is a real-valued 2x2 matrix with entries: + +_R_ = [a b] + [c d] . + +In other words, what is the maximum radius, MAX[ |X'| ], reached for any +X on the unit circle ( |X| = 1 ) ? + + +3. Some useful formulae + +(A) through (C) below are standard double-angle formulae. (D) is a lesser +known result and is derived below: + +(A) sin^2(t) = (1 - cos(2*t))/2 +(B) cos^2(t) = (1 + cos(2*t))/2 +(C) sin(t)*cos(t) = sin(2*t)/2 +(D) MAX[a*cos(t) + b*sin(t)] = sqrt(a^2 + b^2) + +Proof of (D): + +find the maximum of the function by setting the derivative to zero: + + -a*sin(t)+b*cos(t) = 0 + +From this it follows that + + tan(t) = b/a + +and hence + + sin(t) = b/sqrt(a^2 + b^2) + +and + + cos(t) = a/sqrt(a^2 + b^2) + +Thus the maximum value is + + MAX[a*cos(t) + b*sin(t)] = (a^2 + b^2)/sqrt(a^2 + b^2) + = sqrt(a^2 + b^2) + + +4. Derivation of maximum expansion + +To find MAX[ |X'| ] we search brute force method using calculus. The unit +circle on which X is constrained is to be parameterized by t: + + X(t) = (cos(t), sin(t)) + +Thus + + X'(t) = (a*cos(t) + b*sin(t), c*cos(t) + d*sin(t)) . + +Define + + r(t) = |X'(t)| + +Thus + + r^2(t) = (a*cos(t) + b*sin(t))^2 + (c*cos(t) + d*sin(t))^2 + = (a^2 + c^2)*cos^2(t) + (b^2 + d^2)*sin^2(t) + + 2*(a*b + c*d)*cos(t)*sin(t) + +Now apply the double angle formulae (A) to (C) from above: + + r^2(t) = (a^2 + b^2 + c^2 + d^2)/2 + + (a^2 - b^2 + c^2 - d^2)*cos(2*t)/2 + + (a*b + c*d)*sin(2*t) + = f + g*cos(u) + h*sin(u) + +Where + + f = (a^2 + b^2 + c^2 + d^2)/2 + g = (a^2 - b^2 + c^2 - d^2)/2 + h = (a*b + c*d) + u = 2*t + +It is clear that MAX[ |X'| ] = sqrt(MAX[ r^2 ]). Here we determine MAX[ r^2 ] +using (D) from above: + + MAX[ r^2 ] = f + sqrt(g^2 + h^2) + +And finally + + MAX[ |X'| ] = sqrt( f + sqrt(g^2 + h^2) ) + +Which is the solution to this problem. + + +Walter Brisken +2004/10/08 + +(Note that the minor axis length is at the minimum of the above solution, +which is just sqrt (f - sqrt (g^2 + h^2)) given the symmetry of (D)). + +Now to compute how many sides to use for the pen formed by +a regular polygon. + +Set + + M = major axis length (computed by above formula) + m = minor axis length (computed by above formula) + +Align 'M' along the X axis and 'm' along the Y axis and draw +an ellipse parameterized by angle 't': + + x = M cos t y = m sin t + +Perturb t by ± d and compute two new points (x+,y+), (x-,y-). +The distance from the average of these two points to (x,y) represents +the maximum error in approximating the ellipse with a polygon formed +from vertices 2∆ radians apart. + + x+ = M cos (t+∆) y+ = m sin (t+∆) + x- = M cos (t-∆) y- = m sin (t-∆) + +Now compute the approximation error, E: + + Ex = (x - (x+ + x-) / 2) + Ex = (M cos(t) - (Mcos(t+∆) + Mcos(t-∆))/2) + = M (cos(t) - (cos(t)cos(∆) + sin(t)sin(∆) + + cos(t)cos(∆) - sin(t)sin(∆))/2) + = M(cos(t) - cos(t)cos(∆)) + = M cos(t) (1 - cos(∆)) + + Ey = y - (y+ - y-) / 2 + = m sin (t) - (m sin(t+∆) + m sin(t-∆)) / 2 + = m (sin(t) - (sin(t)cos(∆) + cos(t)sin(∆) + + sin(t)cos(∆) - cos(t)sin(∆))/2) + = m (sin(t) - sin(t)cos(∆)) + = m sin(t) (1 - cos(∆)) + + E² = Ex² + Ey² + = (M cos(t) (1 - cos (∆)))² + (m sin(t) (1-cos(∆)))² + = (1 - cos(∆))² (M² cos²(t) + m² sin²(t)) + = (1 - cos(∆))² ((m² + M² - m²) cos² (t) + m² sin²(t)) + = (1 - cos(∆))² (M² - m²) cos² (t) + (1 - cos(∆))² m² + +Find the extremum by differentiation wrt t and setting that to zero + +∂(E²)/∂(t) = (1-cos(∆))² (M² - m²) (-2 cos(t) sin(t)) + + 0 = 2 cos (t) sin (t) + 0 = sin (2t) + t = nÏ€ + +Which is to say that the maximum and minimum errors occur on the +axes of the ellipse at 0 and Ï€ radians: + + E²(0) = (1-cos(∆))² (M² - m²) + (1-cos(∆))² m² + = (1-cos(∆))² M² + E²(Ï€) = (1-cos(∆))² m² + +maximum error = M (1-cos(∆)) +minimum error = m (1-cos(∆)) + +We must make maximum error ≤ tolerance, so compute the ∆ needed: + + tolerance = M (1-cos(∆)) + tolerance / M = 1 - cos (∆) + cos(∆) = 1 - tolerance/M + ∆ = acos (1 - tolerance / M); + +Remembering that ∆ is half of our angle between vertices, +the number of vertices is then + +vertices = ceil(2Ï€/2∆). + = ceil(Ï€/∆). + +Note that this also equation works for M == m (a circle) as it +doesn't matter where on the circle the error is computed. + +*/ + static int -_cairo_pen_vertices_needed (double radius, double tolerance, double expansion) +_cairo_pen_vertices_needed (double tolerance, + double radius, + cairo_matrix_t *matrix) { - double theta; + double a = matrix->m[0][0], c = matrix->m[0][1]; + double b = matrix->m[1][0], d = matrix->m[1][1]; - if (tolerance > expansion*radius) { - return 4; - } + double i = a*a + c*c; + double j = b*b + d*d; - theta = acos (1 - tolerance/(expansion * radius)); - return ceil (M_PI / theta); + double f = 0.5 * (i + j); + double g = 0.5 * (i - j); + double h = a*b + c*d; + + /* + * compute major and minor axes lengths for + * a pen with the specified radius + */ + + double major_axis = radius * sqrt (f + sqrt (g*g+h*h)); + + /* + * we don't need the minor axis length, which is + * double min = radius * sqrt (f - sqrt (g*g+h*h)); + */ + + /* + * compute number of vertices needed + */ + int num_vertices; + + /* Where tolerance / M is > 1, we use 4 points */ + if (tolerance >= major_axis) { + num_vertices = 4; + } else { + double delta = acos (1 - tolerance / major_axis); + num_vertices = ceil (M_PI / delta); + + /* number of vertices must be even */ + if (num_vertices % 2) + num_vertices++; + } + return num_vertices; } static void @@ -186,8 +430,8 @@ _cairo_pen_compute_slopes (cairo_pen_t *pen) _cairo_slope_init (&v->slope_ccw, &v->point, &next->point); } } - -/* Find active pen vertex for clockwise edge of stroke at the given slope. +/* + * Find active pen vertex for clockwise edge of stroke at the given slope. * * NOTE: The behavior of this function is sensitive to the sense of * the inequality within _cairo_slope_clockwise/_cairo_slope_counter_clockwise. diff --git a/src/cairo_png_surface.c b/src/cairo_png_surface.c index 1d1fa63e..4c689d59 100644 --- a/src/cairo_png_surface.c +++ b/src/cairo_png_surface.c @@ -1,3 +1,40 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2004 University of Southern California + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Olivier Andrieu <oliv__a@users.sourceforge.net> + * Carl D. Worth <cworth@isi.edu> + */ + #include <png.h> #include "cairoint.h" @@ -382,5 +419,6 @@ static const cairo_surface_backend_t cairo_png_surface_backend = { _cairo_png_surface_copy_page, _cairo_png_surface_show_page, _cairo_png_surface_set_clip_region, - _cairo_png_surface_create_pattern + _cairo_png_surface_create_pattern, + NULL /* show_glyphs */ }; diff --git a/src/cairo_polygon.c b/src/cairo_polygon.c index ad034406..8fa32f9f 100644 --- a/src/cairo_polygon.c +++ b/src/cairo_polygon.c @@ -1,22 +1,37 @@ /* cairo - a vector graphics library with display and print output * - * Copyright © 2002 University of Southern California + * Copyright © 2002 University of Southern California * * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. * - * This library 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 - * Library General Public License for more details. + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ * - * Author: Carl D. Worth <cworth@isi.edu> + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth <cworth@isi.edu> */ #include <stdlib.h> diff --git a/src/cairo_ps_surface.c b/src/cairo_ps_surface.c index cf7e0a79..bfdfada3 100644 --- a/src/cairo_ps_surface.c +++ b/src/cairo_ps_surface.c @@ -1,22 +1,37 @@ /* cairo - a vector graphics library with display and print output * - * Copyright © 2003 University of Southern California + * Copyright © 2003 University of Southern California * * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. * - * This library 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 - * Library General Public License for more details. + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ * - * Author: Carl D. Worth <cworth@isi.edu> + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth <cworth@isi.edu> */ #include "cairoint.h" @@ -421,5 +436,6 @@ static const cairo_surface_backend_t cairo_ps_surface_backend = { _cairo_ps_surface_copy_page, _cairo_ps_surface_show_page, _cairo_ps_surface_set_clip_region, - _cairo_ps_surface_create_pattern + _cairo_ps_surface_create_pattern, + NULL /* show_glyphs */ }; diff --git a/src/cairo_slope.c b/src/cairo_slope.c index 885ba4c9..1a149798 100644 --- a/src/cairo_slope.c +++ b/src/cairo_slope.c @@ -1,22 +1,37 @@ /* cairo - a vector graphics library with display and print output * - * Copyright © 2002 University of Southern California + * Copyright © 2002 University of Southern California * * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. * - * This library 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 - * Library General Public License for more details. + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ * - * Author: Carl D. Worth <cworth@isi.edu> + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth <cworth@isi.edu> */ #include "cairoint.h" diff --git a/src/cairo_spline.c b/src/cairo_spline.c index 68bb75eb..bed351ef 100644 --- a/src/cairo_spline.c +++ b/src/cairo_spline.c @@ -1,22 +1,37 @@ /* cairo - a vector graphics library with display and print output * - * Copyright © 2002 University of Southern California + * Copyright © 2002 University of Southern California * * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. * - * This library 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 - * Library General Public License for more details. + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ * - * Author: Carl D. Worth <cworth@isi.edu> + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth <cworth@isi.edu> */ #include "cairoint.h" diff --git a/src/cairo_surface.c b/src/cairo_surface.c index b17368a5..a457d206 100644 --- a/src/cairo_surface.c +++ b/src/cairo_surface.c @@ -1,22 +1,37 @@ /* cairo - a vector graphics library with display and print output * - * Copyright © 2002 University of Southern California + * Copyright © 2002 University of Southern California * * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. * - * This library 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 - * Library General Public License for more details. + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ * - * Author: Carl D. Worth <cworth@isi.edu> + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth <cworth@isi.edu> */ #include <stdlib.h> diff --git a/src/cairo_traps.c b/src/cairo_traps.c index 000e05f4..d17a2728 100644 --- a/src/cairo_traps.c +++ b/src/cairo_traps.c @@ -52,6 +52,12 @@ _compare_cairo_edge_by_slope (const void *av, const void *bv); static cairo_fixed_16_16_t _compute_x (cairo_line_t *line, cairo_fixed_t y); +static double +_compute_inverse_slope (cairo_line_t *l); + +static double +_compute_x_intercept (cairo_line_t *l, double inverse_slope); + static int _line_segs_intersect_ceil (cairo_line_t *left, cairo_line_t *right, cairo_fixed_t *y_ret); @@ -321,108 +327,40 @@ _compare_cairo_edge_by_current_x_slope (const void *av, const void *bv) sub-computations -- just a bunch of determinants. I haven't looked at complexity, (both are probably similar and it probably doesn't matter much anyway). - */ -static const cairo_fixed_32_32_t -_det16_32 (cairo_fixed_16_16_t a, - cairo_fixed_16_16_t b, - cairo_fixed_16_16_t c, - cairo_fixed_16_16_t d) +static double +_det (double a, double b, double c, double d) { - return _cairo_int64_sub (_cairo_int32x32_64_mul (a, d), - _cairo_int32x32_64_mul (b, c)); + return a * d - b * c; } -static const cairo_fixed_64_64_t -_det32_64 (cairo_fixed_32_32_t a, - cairo_fixed_32_32_t b, - cairo_fixed_32_32_t c, - cairo_fixed_32_32_t d) +static int +_lines_intersect (cairo_line_t *l1, cairo_line_t *l2, cairo_fixed_t *y_intersection) { - return _cairo_int128_sub (_cairo_int64x64_128_mul (a, d), - _cairo_int64x64_128_mul (b, c)); -} + double dx1 = cairo_fixed_to_double (l1->p1.x - l1->p2.x); + double dy1 = cairo_fixed_to_double (l1->p1.y - l1->p2.y); -static const cairo_fixed_32_32_t -_fixed_16_16_to_fixed_32_32 (cairo_fixed_16_16_t a) -{ - return _cairo_int64_lsl (_cairo_int32_to_int64 (a), 16); -} + double dx2 = cairo_fixed_to_double (l2->p1.x - l2->p2.x); + double dy2 = cairo_fixed_to_double (l2->p1.y - l2->p2.y); -static int -_line_segs_intersect_ceil (cairo_line_t *l1, cairo_line_t *l2, cairo_fixed_t *y_intersection) -{ - cairo_fixed_16_16_t dx1, dx2, dy1, dy2; - cairo_fixed_32_32_t den_det; - cairo_fixed_32_32_t l1_det, l2_det; - cairo_fixed_64_64_t num_det; - cairo_fixed_32_32_t intersect_32_32; - cairo_fixed_48_16_t intersect_48_16; - cairo_fixed_16_16_t intersect_16_16; - cairo_quorem128_t qr; - - dx1 = l1->p1.x - l1->p2.x; - dy1 = l1->p1.y - l1->p2.y; - dx2 = l2->p1.x - l2->p2.x; - dy2 = l2->p1.y - l2->p2.y; - den_det = _det16_32 (dx1, dy1, - dx2, dy2); - - if (_cairo_int64_eq (den_det, _cairo_int32_to_int64(0))) - return 0; + double l1_det, l2_det; - l1_det = _det16_32 (l1->p1.x, l1->p1.y, - l1->p2.x, l1->p2.y); - l2_det = _det16_32 (l2->p1.x, l2->p1.y, - l2->p2.x, l2->p2.y); + double den_det = _det (dx1, dy1, dx2, dy2); - - num_det = _det32_64 (l1_det, _fixed_16_16_to_fixed_32_32 (dy1), - l2_det, _fixed_16_16_to_fixed_32_32 (dy2)); - - /* - * Ok, this one is a bit tricky in fixed point, the denominator - * needs to be left with 32-bits of fraction so that the - * result of the divide ends up with 32-bits of fraction (64 - 32 = 32) - */ - qr = _cairo_int128_divrem (num_det, _cairo_int64_to_int128 (den_det)); - - intersect_32_32 = _cairo_int128_to_int64 (qr.quo); - - /* - * Find the ceiling of the quotient -- divrem returns - * the quotient truncated towards zero, so if the - * quotient should be positive (num_den and den_det have same sign) - * bump the quotient up by one. - */ - - if (_cairo_int128_ne (qr.rem, _cairo_int32_to_int128 (0)) && - (_cairo_int128_ge (num_det, _cairo_int32_to_int128 (0)) == - _cairo_int64_ge (den_det, _cairo_int32_to_int64 (0)))) - { - intersect_32_32 = _cairo_int64_add (intersect_32_32, - _cairo_int32_to_int64 (1)); - } - - /* - * Now convert from 32.32 to 48.16 and take the ceiling; - * this requires adding in 15 1 bits and shifting the result - */ + if (den_det == 0) + return 0; - intersect_32_32 = _cairo_int64_add (intersect_32_32, - _cairo_int32_to_int64 ((1 << 16) - 1)); - intersect_48_16 = _cairo_int64_rsa (intersect_32_32, 16); - - /* - * And drop the top bits - */ - intersect_16_16 = _cairo_int64_to_int32 (intersect_48_16); - - *y_intersection = intersect_16_16; + l1_det = _det (l1->p1.x, l1->p1.y, + l1->p2.x, l1->p2.y); + l2_det = _det (l2->p1.x, l2->p1.y, + l2->p2.x, l2->p2.y); + + *y_intersection = _det (l1_det, dy1, + l2_det, dy2) / den_det; return 1; } - +*/ static cairo_fixed_16_16_t _compute_x (cairo_line_t *line, cairo_fixed_t y) { @@ -433,7 +371,6 @@ _compute_x (cairo_line_t *line, cairo_fixed_t y) return line->p1.x + (ex / dy); } -#if 0 static double _compute_inverse_slope (cairo_line_t *l) { @@ -523,7 +460,6 @@ _line_segs_intersect_ceil (cairo_line_t *l1, cairo_line_t *l2, cairo_fixed_t *y_ return 1; } -#endif /* The algorithm here is pretty simple: diff --git a/src/cairo_xcb_surface.c b/src/cairo_xcb_surface.c index f992bf5f..21760d76 100644 --- a/src/cairo_xcb_surface.c +++ b/src/cairo_xcb_surface.c @@ -1,22 +1,37 @@ /* cairo - a vector graphics library with display and print output * - * Copyright © 2002 University of Southern California + * Copyright © 2002 University of Southern California * * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. * - * This library 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 - * Library General Public License for more details. + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ * - * Author: Carl D. Worth <cworth@isi.edu> + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth <cworth@isi.edu> */ #include "cairoint.h" @@ -470,7 +485,7 @@ _cairo_xcb_surface_set_filter (void *abstract_surface, cairo_filter_t filter) } XCBRenderSetPictureFilter(surface->dpy, surface->picture, - strlen(render_filter), 0, render_filter, NULL); + strlen(render_filter), render_filter, 0, NULL); return CAIRO_STATUS_SUCCESS; } @@ -730,7 +745,8 @@ static const struct cairo_surface_backend cairo_xcb_surface_backend = { _cairo_xcb_surface_copy_page, _cairo_xcb_surface_show_page, _cairo_xcb_surface_set_clip_region, - _cairo_xcb_surface_create_pattern + _cairo_xcb_surface_create_pattern, + NULL /* show_glyphs */ }; static void diff --git a/src/cairo_xlib_surface.c b/src/cairo_xlib_surface.c index 2036f8e4..dda7995b 100644 --- a/src/cairo_xlib_surface.c +++ b/src/cairo_xlib_surface.c @@ -1,22 +1,37 @@ /* cairo - a vector graphics library with display and print output * - * Copyright © 2002 University of Southern California + * Copyright © 2002 University of Southern California * * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. * - * This library 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 - * Library General Public License for more details. + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ * - * Author: Carl D. Worth <cworth@isi.edu> + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth <cworth@isi.edu> */ #include "cairoint.h" @@ -130,7 +145,7 @@ _cairo_xlib_surface_create_similar (void *abstract_src, scr = DefaultScreen (dpy); pix = XCreatePixmap (dpy, DefaultRootWindow (dpy), - width, height, + width <= 0 ? 1 : width, height <= 0 ? 1 : height, _CAIRO_FORMAT_DEPTH (format)); surface = (cairo_xlib_surface_t *) @@ -616,6 +631,8 @@ _cairo_xlib_surface_set_clip_region (void *abstract_surface, xr.height = surf->height; XUnionRectWithRegion (&xr, xregion, xregion); rects = malloc(sizeof(XRectangle)); + if (rects == NULL) + return CAIRO_STATUS_NO_MEMORY; rects[0] = xr; m = 1; @@ -626,6 +643,8 @@ _cairo_xlib_surface_set_clip_region (void *abstract_surface, if (n == 0) return CAIRO_STATUS_SUCCESS; rects = malloc(sizeof(XRectangle) * n); + if (rects == NULL) + return CAIRO_STATUS_NO_MEMORY; box = pixman_region_rects (region); xregion = XCreateRegion(); @@ -646,7 +665,7 @@ _cairo_xlib_surface_set_clip_region (void *abstract_surface, XSetClipRectangles(surf->dpy, surf->gc, 0, 0, rects, m, Unsorted); free(rects); if (surf->picture) - XRenderSetPictureClipRegion (surf->dpy, surf->picture, xregion); + XRenderSetPictureClipRegion (surf->dpy, surf->picture, xregion); XDestroyRegion(xregion); XSetGraphicsExposures(surf->dpy, surf->gc, gc_values.graphics_exposures); return CAIRO_STATUS_SUCCESS; @@ -660,6 +679,17 @@ _cairo_xlib_surface_create_pattern (void *abstract_surface, return CAIRO_INT_STATUS_UNSUPPORTED; } +static cairo_status_t +_cairo_xlib_surface_show_glyphs (cairo_unscaled_font_t *font, + cairo_font_scale_t *scale, + cairo_operator_t operator, + cairo_surface_t *source, + cairo_surface_t *surface, + int source_x, + int source_y, + const cairo_glyph_t *glyphs, + int num_glyphs); + static const struct cairo_surface_backend cairo_xlib_surface_backend = { _cairo_xlib_surface_create_similar, _cairo_xlib_surface_destroy, @@ -675,7 +705,8 @@ static const struct cairo_surface_backend cairo_xlib_surface_backend = { _cairo_xlib_surface_copy_page, _cairo_xlib_surface_show_page, _cairo_xlib_surface_set_clip_region, - _cairo_xlib_surface_create_pattern + _cairo_xlib_surface_create_pattern, + _cairo_xlib_surface_show_glyphs }; cairo_surface_t * @@ -746,3 +777,512 @@ cairo_xlib_surface_create (Display *dpy, return (cairo_surface_t *) surface; } DEPRECATE (cairo_surface_create_for_drawable, cairo_xlib_surface_create); + + +/* RENDER glyphset cache code */ + +typedef struct glyphset_cache { + cairo_cache_t base; + struct glyphset_cache *next; + Display *display; + XRenderPictFormat *a8_pict_format; + GlyphSet glyphset; + Glyph counter; +} glyphset_cache_t; + +typedef struct { + cairo_glyph_cache_key_t key; + Glyph glyph; + XGlyphInfo info; +} glyphset_cache_entry_t; + +static Glyph +_next_xlib_glyph (glyphset_cache_t *cache) +{ + return ++(cache->counter); +} + + +static cairo_status_t +_xlib_glyphset_cache_create_entry (void *cache, + void *key, + void **return_entry) +{ + glyphset_cache_t *g = (glyphset_cache_t *) cache; + cairo_glyph_cache_key_t *k = (cairo_glyph_cache_key_t *)key; + glyphset_cache_entry_t *v; + + cairo_status_t status; + + cairo_cache_t *im_cache; + cairo_image_glyph_cache_entry_t *im; + + v = malloc (sizeof (glyphset_cache_entry_t)); + _cairo_lock_global_image_glyph_cache (); + im_cache = _cairo_get_global_image_glyph_cache (); + + if (g == NULL || v == NULL ||g == NULL || im_cache == NULL) { + _cairo_unlock_global_image_glyph_cache (); + return CAIRO_STATUS_NO_MEMORY; + } + + status = _cairo_cache_lookup (im_cache, key, (void **) (&im)); + if (status != CAIRO_STATUS_SUCCESS || im == NULL) { + _cairo_unlock_global_image_glyph_cache (); + return CAIRO_STATUS_NO_MEMORY; + } + + v->key = *k; + _cairo_unscaled_font_reference (v->key.unscaled); + + v->glyph = _next_xlib_glyph (g); + + v->info.width = im->image ? im->image->stride : im->size.width; + v->info.height = im->size.height; + v->info.x = - im->extents.x_bearing; + v->info.y = im->extents.y_bearing; + v->info.xOff = 0; + v->info.yOff = 0; + + XRenderAddGlyphs (g->display, g->glyphset, + &(v->glyph), &(v->info), 1, + im->image ? im->image->data : NULL, + im->image ? v->info.height * v->info.width : 0); + + v->key.base.memory = im->image ? im->image->width * im->image->stride : 0; + *return_entry = v; + _cairo_unlock_global_image_glyph_cache (); + return CAIRO_STATUS_SUCCESS; +} + +static void +_xlib_glyphset_cache_destroy_cache (void *cache) +{ + /* FIXME: will we ever release glyphset caches? */ +} + +static void +_xlib_glyphset_cache_destroy_entry (void *cache, void *entry) +{ + glyphset_cache_t *g; + glyphset_cache_entry_t *v; + + g = (glyphset_cache_t *) cache; + v = (glyphset_cache_entry_t *) entry; + + _cairo_unscaled_font_destroy (v->key.unscaled); + XRenderFreeGlyphs (g->display, g->glyphset, &(v->glyph), 1); + free (v); +} + +const cairo_cache_backend_t _xlib_glyphset_cache_backend = { + _cairo_glyph_cache_hash, + _cairo_glyph_cache_keys_equal, + _xlib_glyphset_cache_create_entry, + _xlib_glyphset_cache_destroy_entry, + _xlib_glyphset_cache_destroy_cache +}; + + +static glyphset_cache_t * +_xlib_glyphset_caches = NULL; + +static void +_lock_xlib_glyphset_caches (void) +{ + /* FIXME: implement locking */ +} + +static void +_unlock_xlib_glyphset_caches (void) +{ + /* FIXME: implement locking */ +} + +static glyphset_cache_t * +_get_glyphset_cache (Display *d) +{ + /* + * There should usually only be one, or a very small number, of + * displays. So we just do a linear scan. + */ + + glyphset_cache_t *g; + + for (g = _xlib_glyphset_caches; g != NULL; g = g->next) { + if (g->display == d) + return g; + } + + g = malloc (sizeof (glyphset_cache_t)); + if (g == NULL) + goto ERR; + + g->counter = 0; + g->display = d; + g->a8_pict_format = XRenderFindStandardFormat (d, PictStandardA8); + if (g->a8_pict_format == NULL) + goto ERR; + + if (_cairo_cache_init (&g->base, + &_xlib_glyphset_cache_backend, + CAIRO_XLIB_GLYPH_CACHE_MEMORY_DEFAULT)) + goto FREE_GLYPHSET_CACHE; + + g->glyphset = XRenderCreateGlyphSet (d, g->a8_pict_format); + g->next = _xlib_glyphset_caches; + _xlib_glyphset_caches = g; + return g; + + FREE_GLYPHSET_CACHE: + free (g); + + ERR: + return NULL; +} + +#define N_STACK_BUF 1024 + +static cairo_status_t +_cairo_xlib_surface_show_glyphs32 (cairo_unscaled_font_t *font, + cairo_font_scale_t *scale, + cairo_operator_t operator, + glyphset_cache_t *g, + cairo_glyph_cache_key_t *key, + cairo_xlib_surface_t *src, + cairo_xlib_surface_t *self, + int source_x, + int source_y, + const cairo_glyph_t *glyphs, + glyphset_cache_entry_t **entries, + int num_glyphs) +{ + XGlyphElt32 *elts = NULL; + XGlyphElt32 stack_elts [N_STACK_BUF]; + + unsigned int *chars = NULL; + unsigned int stack_chars [N_STACK_BUF]; + + int i; + int lastX = 0, lastY = 0; + + /* Acquire arrays of suitable sizes. */ + if (num_glyphs < N_STACK_BUF) { + elts = stack_elts; + chars = stack_chars; + + } else { + elts = malloc (num_glyphs * sizeof (XGlyphElt32)); + if (elts == NULL) + goto FAIL; + + chars = malloc (num_glyphs * sizeof (unsigned int)); + if (chars == NULL) + goto FREE_ELTS; + + } + + for (i = 0; i < num_glyphs; ++i) { + chars[i] = entries[i]->glyph; + elts[i].chars = &(chars[i]); + elts[i].nchars = 1; + elts[i].glyphset = g->glyphset; + elts[i].xOff = glyphs[i].x - lastX; + elts[i].yOff = glyphs[i].y - lastY; + lastX = glyphs[i].x; + lastY = glyphs[i].y; + } + + XRenderCompositeText32 (self->dpy, + _render_operator (operator), + src->picture, + self->picture, + g->a8_pict_format, + source_x, source_y, + 0, 0, + elts, num_glyphs); + + if (num_glyphs >= N_STACK_BUF) { + free (chars); + free (elts); + } + + return CAIRO_STATUS_SUCCESS; + + FREE_ELTS: + if (num_glyphs >= N_STACK_BUF) + free (elts); + + FAIL: + return CAIRO_STATUS_NO_MEMORY; +} + + +static cairo_status_t +_cairo_xlib_surface_show_glyphs16 (cairo_unscaled_font_t *font, + cairo_font_scale_t *scale, + cairo_operator_t operator, + glyphset_cache_t *g, + cairo_glyph_cache_key_t *key, + cairo_xlib_surface_t *src, + cairo_xlib_surface_t *self, + int source_x, + int source_y, + const cairo_glyph_t *glyphs, + glyphset_cache_entry_t **entries, + int num_glyphs) +{ + XGlyphElt16 *elts = NULL; + XGlyphElt16 stack_elts [N_STACK_BUF]; + + unsigned short *chars = NULL; + unsigned short stack_chars [N_STACK_BUF]; + + int i; + int lastX = 0, lastY = 0; + + /* Acquire arrays of suitable sizes. */ + if (num_glyphs < N_STACK_BUF) { + elts = stack_elts; + chars = stack_chars; + + } else { + elts = malloc (num_glyphs * sizeof (XGlyphElt16)); + if (elts == NULL) + goto FAIL; + + chars = malloc (num_glyphs * sizeof (unsigned short)); + if (chars == NULL) + goto FREE_ELTS; + + } + + for (i = 0; i < num_glyphs; ++i) { + chars[i] = entries[i]->glyph; + elts[i].chars = &(chars[i]); + elts[i].nchars = 1; + elts[i].glyphset = g->glyphset; + elts[i].xOff = glyphs[i].x - lastX; + elts[i].yOff = glyphs[i].y - lastY; + lastX = glyphs[i].x; + lastY = glyphs[i].y; + } + + XRenderCompositeText16 (self->dpy, + _render_operator (operator), + src->picture, + self->picture, + g->a8_pict_format, + source_x, source_y, + 0, 0, + elts, num_glyphs); + + if (num_glyphs >= N_STACK_BUF) { + free (chars); + free (elts); + } + + return CAIRO_STATUS_SUCCESS; + + FREE_ELTS: + if (num_glyphs >= N_STACK_BUF) + free (elts); + + FAIL: + return CAIRO_STATUS_NO_MEMORY; +} + +static cairo_status_t +_cairo_xlib_surface_show_glyphs8 (cairo_unscaled_font_t *font, + cairo_font_scale_t *scale, + cairo_operator_t operator, + glyphset_cache_t *g, + cairo_glyph_cache_key_t *key, + cairo_xlib_surface_t *src, + cairo_xlib_surface_t *self, + int source_x, + int source_y, + const cairo_glyph_t *glyphs, + glyphset_cache_entry_t **entries, + int num_glyphs) +{ + XGlyphElt8 *elts = NULL; + XGlyphElt8 stack_elts [N_STACK_BUF]; + + char *chars = NULL; + char stack_chars [N_STACK_BUF]; + + int i; + int lastX = 0, lastY = 0; + + /* Acquire arrays of suitable sizes. */ + if (num_glyphs < N_STACK_BUF) { + elts = stack_elts; + chars = stack_chars; + + } else { + elts = malloc (num_glyphs * sizeof (XGlyphElt8)); + if (elts == NULL) + goto FAIL; + + chars = malloc (num_glyphs * sizeof (char)); + if (chars == NULL) + goto FREE_ELTS; + + } + + for (i = 0; i < num_glyphs; ++i) { + chars[i] = entries[i]->glyph; + elts[i].chars = &(chars[i]); + elts[i].nchars = 1; + elts[i].glyphset = g->glyphset; + elts[i].xOff = glyphs[i].x - lastX; + elts[i].yOff = glyphs[i].y - lastY; + lastX = glyphs[i].x; + lastY = glyphs[i].y; + } + + XRenderCompositeText8 (self->dpy, + _render_operator (operator), + src->picture, + self->picture, + g->a8_pict_format, + source_x, source_y, + 0, 0, + elts, num_glyphs); + + if (num_glyphs >= N_STACK_BUF) { + free (chars); + free (elts); + } + + return CAIRO_STATUS_SUCCESS; + + FREE_ELTS: + if (num_glyphs >= N_STACK_BUF) + free (elts); + + FAIL: + return CAIRO_STATUS_NO_MEMORY; +} + + +static cairo_status_t +_cairo_xlib_surface_show_glyphs (cairo_unscaled_font_t *font, + cairo_font_scale_t *scale, + cairo_operator_t operator, + cairo_surface_t *source, + cairo_surface_t *surface, + int source_x, + int source_y, + const cairo_glyph_t *glyphs, + int num_glyphs) +{ + unsigned int elt_size; + cairo_xlib_surface_t *self = (cairo_xlib_surface_t *) surface; + cairo_image_surface_t *tmp = NULL; + cairo_xlib_surface_t *src = NULL; + glyphset_cache_t *g; + cairo_status_t status; + cairo_glyph_cache_key_t key; + glyphset_cache_entry_t **entries; + glyphset_cache_entry_t *stack_entries [N_STACK_BUF]; + int i; + + /* Acquire an entry array of suitable size. */ + if (num_glyphs < N_STACK_BUF) { + entries = stack_entries; + + } else { + entries = malloc (num_glyphs * sizeof (glyphset_cache_entry_t *)); + if (entries == NULL) + goto FAIL; + } + + /* prep the source surface. */ + if (source->backend == surface->backend) { + src = (cairo_xlib_surface_t *) source; + + } else { + tmp = _cairo_surface_get_image (source); + if (tmp == NULL) + goto FREE_ENTRIES; + + src = (cairo_xlib_surface_t *) + _cairo_surface_create_similar_scratch (surface, self->format, 1, + tmp->width, tmp->height); + + if (src == NULL) + goto FREE_TMP; + + if (_cairo_surface_set_image (&(src->base), tmp) != CAIRO_STATUS_SUCCESS) + goto FREE_SRC; + } + + _lock_xlib_glyphset_caches (); + g = _get_glyphset_cache (self->dpy); + if (g == NULL) + goto UNLOCK; + + /* Work out the index size to use. */ + elt_size = 8; + key.scale = *scale; + key.unscaled = font; + + for (i = 0; i < num_glyphs; ++i) { + key.index = glyphs[i].index; + status = _cairo_cache_lookup (&g->base, &key, (void **) (&entries[i])); + if (status != CAIRO_STATUS_SUCCESS || entries[i] == NULL) + goto UNLOCK; + + if (elt_size == 8 && entries[i]->glyph > 0xff) + elt_size = 16; + if (elt_size == 16 && entries[i]->glyph > 0xffff) { + elt_size = 32; + break; + } + } + + /* Call the appropriate sub-function. */ + + if (elt_size == 8) + status = _cairo_xlib_surface_show_glyphs8 (font, scale, operator, g, &key, src, self, + source_x, source_y, + glyphs, entries, num_glyphs); + else if (elt_size == 16) + status = _cairo_xlib_surface_show_glyphs16 (font, scale, operator, g, &key, src, self, + source_x, source_y, + glyphs, entries, num_glyphs); + else + status = _cairo_xlib_surface_show_glyphs32 (font, scale, operator, g, &key, src, self, + source_x, source_y, + glyphs, entries, num_glyphs); + + _unlock_xlib_glyphset_caches (); + + if (tmp != NULL) { + cairo_surface_destroy (&(src->base)); + cairo_surface_destroy (&(tmp->base)); + } + + if (num_glyphs >= N_STACK_BUF) + free (entries); + + return status; + + UNLOCK: + _unlock_xlib_glyphset_caches (); + + FREE_SRC: + cairo_surface_destroy (&(src->base)); + + FREE_TMP: + cairo_surface_destroy (&(tmp->base)); + + FREE_ENTRIES: + if (num_glyphs >= N_STACK_BUF) + free (entries); + + FAIL: + return CAIRO_STATUS_NO_MEMORY; +} diff --git a/src/cairoint.h b/src/cairoint.h index 2b151dfe..be0e54e7 100644 --- a/src/cairoint.h +++ b/src/cairoint.h @@ -1,22 +1,37 @@ /* cairo - a vector graphics library with display and print output * - * Copyright © 2002 University of Southern California + * Copyright © 2002 University of Southern California * * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. * - * This library 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 - * Library General Public License for more details. + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ * - * Author: Carl D. Worth <cworth@isi.edu> + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth <cworth@isi.edu> */ /* @@ -34,7 +49,6 @@ #include "config.h" #endif -#include <assert.h> #include <stdlib.h> #include <string.h> #include <math.h> @@ -238,52 +252,204 @@ typedef struct cairo_pen { } cairo_pen_t; typedef struct cairo_color cairo_color_t; +typedef struct cairo_image_surface cairo_image_surface_t; + +/* cairo_cache.c structures and functions */ + +typedef struct cairo_cache_backend { + + unsigned long (*hash) (void *cache, + void *key); + + int (*keys_equal) (void *cache, + void *k1, + void *k2); + + cairo_status_t (*create_entry) (void *cache, + void *key, + void **entry_return); + + void (*destroy_entry) (void *cache, + void *entry); + + void (*destroy_cache) (void *cache); + +} cairo_cache_backend_t; + + +/* + * The cairo_cache system makes the following assumptions about + * entries in its cache: + * + * - a pointer to an entry can be cast to a cairo_cache_entry_base_t. + * - a pointer to an entry can also be cast to the "key type". + * + * The practical effect of this is that your entries must be laid + * out this way: + * + * struct my_entry { + * cairo_cache_entry_base_t; + * my_key_value_1; + * my_key_value_2; + * ... + * my_value; + * }; + */ + +typedef struct { + unsigned long memory; + unsigned long hashcode; +} cairo_cache_entry_base_t; + +typedef struct { + unsigned long high_water_mark; + unsigned long size; + unsigned long rehash; +} cairo_cache_arrangement_t; + +#undef CAIRO_MEASURE_CACHE_PERFORMANCE + +typedef struct { + unsigned long refcount; + const cairo_cache_backend_t *backend; + cairo_cache_arrangement_t *arrangement; + cairo_cache_entry_base_t **entries; + + unsigned long max_memory; + unsigned long used_memory; + unsigned long live_entries; + +#ifdef CAIRO_MEASURE_CACHE_PERFORMANCE + unsigned long hits; + unsigned long misses; + unsigned long probes; +#endif +} cairo_cache_t; + +extern cairo_status_t __internal_linkage +_cairo_cache_init (cairo_cache_t *cache, + const cairo_cache_backend_t *backend, + unsigned long max_memory); + +extern void __internal_linkage +_cairo_cache_reference (cairo_cache_t *cache); + +extern void __internal_linkage +_cairo_cache_destroy (cairo_cache_t *cache); + +extern cairo_status_t __internal_linkage +_cairo_cache_lookup (cairo_cache_t *cache, + void *key, + void **entry_return); + +extern unsigned long __internal_linkage +_cairo_hash_string (const char *c); + +#define CAIRO_IMAGE_GLYPH_CACHE_MEMORY_DEFAULT 0x100000 +#define CAIRO_XLIB_GLYPH_CACHE_MEMORY_DEFAULT 0x100000 +#define CAIRO_FONT_CACHE_NUM_FONTS_DEFAULT 20 +#define CAIRO_FT_CACHE_NUM_FONTS_DEFAULT 20 + +typedef struct { + double matrix[2][2]; +} cairo_font_scale_t; + +struct cairo_font_backend; + +typedef struct { + int refcount; + const struct cairo_font_backend *backend; +} cairo_unscaled_font_t; + +/* + * A cairo_font contains a pointer to a cairo_sizeless_font_t and a scale + * matrix. These are the things the user holds references to. + */ + +struct cairo_font { + int refcount; + cairo_font_scale_t scale; + cairo_unscaled_font_t *unscaled; +}; + + +/* cairo_font.c is responsible for two global caches: + * + * - font entries: [[[base], name, weight, slant], cairo_unscaled_font_t ] + * - glyph entries: [[[base], cairo_font_t, index], image, size, extents ] + * + * Surfaces may build their own glyph caches if they have surface-specific + * glyph resources to maintain; those caches can feed off of the global + * caches if need be (eg. cairo_xlib_surface.c does this). + */ + +typedef struct { + cairo_cache_entry_base_t base; + cairo_unscaled_font_t *unscaled; + cairo_font_scale_t scale; + unsigned long index; +} cairo_glyph_cache_key_t; + +typedef struct { + cairo_glyph_cache_key_t key; + cairo_image_surface_t *image; + cairo_glyph_size_t size; + cairo_text_extents_t extents; +} cairo_image_glyph_cache_entry_t; + +extern void __internal_linkage +_cairo_lock_global_image_glyph_cache (void); + +extern void __internal_linkage +_cairo_unlock_global_image_glyph_cache (void); + +extern cairo_cache_t * __internal_linkage +_cairo_get_global_image_glyph_cache (void); + +/* Some glyph cache functions you can reuse. */ + +extern unsigned long __internal_linkage +_cairo_glyph_cache_hash (void *cache, void *key); + +extern int __internal_linkage +_cairo_glyph_cache_keys_equal (void *cache, + void *k1, + void *k2); + + +/* the font backend interface */ typedef struct cairo_font_backend { - cairo_font_t *(*create) (const char *family, + cairo_unscaled_font_t *(*create) (const char *family, cairo_font_slant_t slant, cairo_font_weight_t weight); - cairo_font_t *(*copy) (void *font); - void (*destroy) (void *font); cairo_status_t (*font_extents) (void *font, + cairo_font_scale_t *scale, cairo_font_extents_t *extents); - cairo_status_t (*text_extents) (void *font, + cairo_status_t (*text_to_glyphs) (void *font, + cairo_font_scale_t *scale, const unsigned char *utf8, - cairo_text_extents_t *extents); - + cairo_glyph_t **glyphs, + int *num_glyphs); + cairo_status_t (*glyph_extents) (void *font, + cairo_font_scale_t *scale, cairo_glyph_t *glyphs, int num_glyphs, cairo_text_extents_t *extents); - cairo_status_t (*text_bbox) (void *font, - cairo_surface_t *surface, - double x, - double y, - const unsigned char *utf8, - cairo_box_t *bbox); - cairo_status_t (*glyph_bbox) (void *font, - cairo_surface_t *surface, + cairo_font_scale_t *scale, const cairo_glyph_t *glyphs, int num_glyphs, cairo_box_t *bbox); - cairo_status_t (*show_text) (void *font, - cairo_operator_t operator, - cairo_surface_t *source, - cairo_surface_t *surface, - int source_x, - int source_y, - double x, - double y, - const unsigned char *utf8); - cairo_status_t (*show_glyphs) (void *font, + cairo_font_scale_t *scale, cairo_operator_t operator, cairo_surface_t *source, cairo_surface_t *surface, @@ -292,25 +458,19 @@ typedef struct cairo_font_backend { const cairo_glyph_t *glyphs, int num_glyphs); - cairo_status_t (*text_path) (void *font, - double x, - double y, - const unsigned char *utf8, - cairo_path_t *path); - cairo_status_t (*glyph_path) (void *font, + cairo_font_scale_t *scale, cairo_glyph_t *glyphs, int num_glyphs, cairo_path_t *path); - cairo_surface_t *(*create_glyph) (void *font, - const cairo_glyph_t *glyph, - cairo_glyph_size_t *return_size); + + cairo_status_t (*create_glyph) (cairo_image_glyph_cache_entry_t *entry); + } cairo_font_backend_t; /* concrete font backends */ extern const struct cairo_font_backend cairo_ft_font_backend; -typedef struct cairo_image_surface cairo_image_surface_t; typedef struct cairo_surface_backend { cairo_surface_t * @@ -395,6 +555,23 @@ typedef struct cairo_surface_backend { (*create_pattern) (void *surface, cairo_pattern_t *pattern, cairo_box_t *extents); + + /* + * This is an optional entry to let the surface manage its own glyph + * resources. If null, the font will be asked to render against this + * surface, using image surfaces as glyphs. + */ + cairo_status_t + (*show_glyphs) (cairo_unscaled_font_t *font, + cairo_font_scale_t *scale, + cairo_operator_t operator, + cairo_surface_t *source, + cairo_surface_t *surface, + int source_x, + int source_y, + const cairo_glyph_t *glyphs, + int num_glyphs); + } cairo_surface_backend_t; struct cairo_matrix { @@ -523,6 +700,7 @@ typedef struct cairo_traps { cairo_trapezoid_t *traps; int num_traps; int traps_size; + cairo_box_t extents; } cairo_traps_t; #define CAIRO_FONT_FAMILY_DEFAULT "serif" @@ -532,40 +710,6 @@ typedef struct cairo_traps { /* XXX: Platform-specific. Other platforms may want a different default */ #define CAIRO_FONT_BACKEND_DEFAULT &cairo_ft_font_backend -#define CAIRO_FONT_CACHE_SIZE_DEFAULT 256 - -typedef struct { - unsigned long index; - double matrix[2][2]; - - unsigned int time; - - cairo_surface_t *surface; - cairo_glyph_size_t size; -} cairo_glyph_surface_t; - -typedef struct cairo_glyph_surface_node { - struct cairo_glyph_surface_node *next; - struct cairo_glyph_surface_node *prev; - - cairo_glyph_surface_t s; -} cairo_glyph_surface_node_t; - -typedef struct { - cairo_glyph_surface_node_t *first; - cairo_glyph_surface_node_t *last; - unsigned int n_nodes; - - unsigned int ref_count; - unsigned int cache_size; -} cairo_glyph_cache_t; - -struct cairo_font { - int refcount; - cairo_matrix_t matrix; - cairo_glyph_cache_t *glyph_cache; - const struct cairo_font_backend *backend; -}; #define CAIRO_GSTATE_OPERATOR_DEFAULT CAIRO_OPERATOR_OVER #define CAIRO_GSTATE_TOLERANCE_DEFAULT 0.1 @@ -603,7 +747,7 @@ typedef struct cairo_gstate { int num_dashes; double dash_offset; - cairo_font_t *font; + cairo_unscaled_font_t *font; cairo_surface_t *surface; @@ -613,6 +757,9 @@ typedef struct cairo_gstate { cairo_clip_rec_t clip; double pixels_per_inch; + + cairo_matrix_t font_matrix; + cairo_matrix_t ctm; cairo_matrix_t ctm_inverse; @@ -920,6 +1067,14 @@ extern cairo_status_t __internal_linkage _cairo_gstate_current_font (cairo_gstate_t *gstate, cairo_font_t **font); +extern void __internal_linkage +_cairo_gstate_set_font_transform (cairo_gstate_t *gstate, + cairo_matrix_t *matrix); + +extern void __internal_linkage +_cairo_gstate_current_font_transform (cairo_gstate_t *gstate, + cairo_matrix_t *matrix); + extern cairo_status_t __internal_linkage _cairo_gstate_current_font_extents (cairo_gstate_t *gstate, cairo_font_extents_t *extents); @@ -928,11 +1083,11 @@ extern cairo_status_t __internal_linkage _cairo_gstate_set_font (cairo_gstate_t *gstate, cairo_font_t *font); - extern cairo_status_t __internal_linkage -_cairo_gstate_text_extents (cairo_gstate_t *gstate, - const unsigned char *utf8, - cairo_text_extents_t *extents); +_cairo_gstate_text_to_glyphs (cairo_gstate_t *font, + const unsigned char *utf8, + cairo_glyph_t **glyphs, + int *num_glyphs); extern cairo_status_t __internal_linkage _cairo_gstate_glyph_extents (cairo_gstate_t *gstate, @@ -941,19 +1096,11 @@ _cairo_gstate_glyph_extents (cairo_gstate_t *gstate, cairo_text_extents_t *extents); extern cairo_status_t __internal_linkage -_cairo_gstate_show_text (cairo_gstate_t *gstate, - const unsigned char *utf8); - -extern cairo_status_t __internal_linkage _cairo_gstate_show_glyphs (cairo_gstate_t *gstate, cairo_glyph_t *glyphs, int num_glyphs); extern cairo_status_t __internal_linkage -_cairo_gstate_text_path (cairo_gstate_t *gstate, - const unsigned char *utf8); - -extern cairo_status_t __internal_linkage _cairo_gstate_glyph_path (cairo_gstate_t *gstate, cairo_glyph_t *glyphs, int num_glyphs); @@ -977,95 +1124,69 @@ _cairo_color_set_alpha (cairo_color_t *color, double alpha); /* cairo_font.c */ -extern cairo_font_t * __internal_linkage -_cairo_font_create (const char *family, - cairo_font_slant_t slant, - cairo_font_weight_t weight); - -extern cairo_status_t __internal_linkage -_cairo_font_init (cairo_font_t *font, - const struct cairo_font_backend *backend); - -extern cairo_font_t * __internal_linkage -_cairo_font_copy (cairo_font_t *font); - -extern cairo_status_t __internal_linkage -_cairo_font_scale (cairo_font_t *font, double scale); +extern cairo_unscaled_font_t * __internal_linkage +_cairo_unscaled_font_create (const char *family, + cairo_font_slant_t slant, + cairo_font_weight_t weight); -extern cairo_status_t __internal_linkage -_cairo_font_transform (cairo_font_t *font, cairo_matrix_t *matrix); +extern void __internal_linkage +_cairo_font_init (cairo_font_t *scaled, + cairo_font_scale_t *scale, + cairo_unscaled_font_t *unscaled); extern cairo_status_t __internal_linkage -_cairo_font_font_extents (cairo_font_t *font, - cairo_font_extents_t *extents); +_cairo_unscaled_font_init (cairo_unscaled_font_t *font, + const struct cairo_font_backend *backend); -extern cairo_status_t __internal_linkage -_cairo_font_text_extents (cairo_font_t *font, - const unsigned char *utf8, - cairo_text_extents_t *extents); +extern void __internal_linkage +_cairo_unscaled_font_reference (cairo_unscaled_font_t *font); -extern cairo_status_t __internal_linkage -_cairo_font_glyph_extents (cairo_font_t *font, - cairo_glyph_t *glyphs, - int num_glyphs, - cairo_text_extents_t *extents); +extern void __internal_linkage +_cairo_unscaled_font_destroy (cairo_unscaled_font_t *font); extern cairo_status_t __internal_linkage -_cairo_font_text_bbox (cairo_font_t *font, - cairo_surface_t *surface, - double x, - double y, - const unsigned char *utf8, - cairo_box_t *bbox); +_cairo_unscaled_font_font_extents (cairo_unscaled_font_t *font, + cairo_font_scale_t *scale, + cairo_font_extents_t *extents); extern cairo_status_t __internal_linkage -_cairo_font_glyph_bbox (cairo_font_t *font, - cairo_surface_t *surface, - cairo_glyph_t *glyphs, - int num_glyphs, - cairo_box_t *bbox); +_cairo_unscaled_font_text_to_glyphs (cairo_unscaled_font_t *font, + cairo_font_scale_t *scale, + const unsigned char *utf8, + cairo_glyph_t **glyphs, + int *num_glyphs); extern cairo_status_t __internal_linkage -_cairo_font_show_text (cairo_font_t *font, - cairo_operator_t operator, - cairo_surface_t *source, - cairo_surface_t *surface, - int source_x, - int source_y, - double x, - double y, - const unsigned char *utf8); - +_cairo_unscaled_font_glyph_extents (cairo_unscaled_font_t *font, + cairo_font_scale_t *scale, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_text_extents_t *extents); extern cairo_status_t __internal_linkage -_cairo_font_show_glyphs (cairo_font_t *font, - cairo_operator_t operator, - cairo_surface_t *source, - cairo_surface_t *surface, - int source_x, - int source_y, - cairo_glyph_t *glyphs, - int num_glyphs); - +_cairo_unscaled_font_glyph_bbox (cairo_unscaled_font_t *font, + cairo_font_scale_t *size, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_box_t *bbox); extern cairo_status_t __internal_linkage -_cairo_font_text_path (cairo_font_t *font, - double x, - double y, - const unsigned char *utf8, - cairo_path_t *path); +_cairo_unscaled_font_show_glyphs (cairo_unscaled_font_t *font, + cairo_font_scale_t *size, + cairo_operator_t operator, + cairo_surface_t *source, + cairo_surface_t *surface, + int source_x, + int source_y, + cairo_glyph_t *glyphs, + int num_glyphs); extern cairo_status_t __internal_linkage -_cairo_font_glyph_path (cairo_font_t *font, - cairo_glyph_t *glyphs, - int num_glyphs, - cairo_path_t *path); - -extern cairo_surface_t *__internal_linkage -_cairo_font_lookup_glyph (cairo_font_t *font, - cairo_surface_t *surface, - const cairo_glyph_t *glyph, - cairo_glyph_size_t *return_size); +_cairo_unscaled_font_glyph_path (cairo_unscaled_font_t *font, + cairo_font_scale_t *size, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_path_t *path); /* cairo_hull.c */ extern cairo_status_t diff --git a/test/.cvsignore b/test/.cvsignore new file mode 100644 index 00000000..3b530421 --- /dev/null +++ b/test/.cvsignore @@ -0,0 +1,11 @@ +.deps +.libs +Makefile +Makefile.in +fill_rule +line_width +move_to_show_surface +*-out.png +*-diff.png + + diff --git a/test/Makefile.am b/test/Makefile.am new file mode 100644 index 00000000..2f80f9f8 --- /dev/null +++ b/test/Makefile.am @@ -0,0 +1,53 @@ +# All new test cases go here +TESTS = \ +fill_rule \ +line_width \ +move_to_show_surface + +# And all new test go here too. I really don't like having to repeat +# this list. Anyone know a good way to avoid it? Can I use a wildcard +# here? +EXTRA_DIST = \ +fill_rule-ref.png \ +line_width-ref.png \ +move_to_show_surface-ref.png + +# This list is only for known bugs (not regressions). We do need to +# fix these before the next release, but they are expected to fail for +# now, so they don't need to hold up any new code commit. +# +# When new bugs are found in committed code they can be listed +# here. New failures due to local, uncommitted code changes are +# regression bugs that should not be listed here. Instead they should +# be fixed before the code is committed. +XFAIL_TESTS = \ +move_to_show_surface + +check_PROGRAMS = $(TESTS) + +# We're using _GNU_SOURCE to get the prototype for asprintf. This may +# not be the most portable approach, but it is pragmatic and I'm +# willing to do something cleaner as soon as it causes someone a +# problem. +INCLUDES = -D_GNU_SOURCE -I$(srcdir) $(CAIRO_CFLAGS) -I$(srcdir)/../src + +AM_LDFLAGS = $(CAIRO_LIBS) ../src/libcairo.la + +cairo_test_lib =\ +cairo_test.c \ +cairo_test.h \ +read_png.c \ +read_png.h \ +write_png.c \ +write_png.h \ +xmalloc.c \ +xmalloc.h + +# ARGH! I have to repeat the list of tests a third time. Maybe it's +# time to break down and auto-generate the Makefile.am or something +# from autogen.sh. My, but this is painful... +fill_rule_SOURCES = fill_rule.c $(cairo_test_lib) +line_width_SOURCES = line_width.c $(cairo_test_lib) +move_to_show_surface_SOURCES = move_to_show_surface.c $(cairo_test_lib) + +CLEANFILES = *-out.png *-diff.png diff --git a/test/README b/test/README new file mode 100644 index 00000000..edff360b --- /dev/null +++ b/test/README @@ -0,0 +1,64 @@ +Regression test suite for cairo. + +Using this test should be as simple as running: + + make check + +assuming that the cairo distribution in the directory above has been +configured and built. The test suite here goes through some effort to +run against the locally compiled library rather than any installed +version. + +The test suite needs to be run before any code is committed and before +any release. Here are the rules governing the use of the suite: + +Before committing +----------------- + +All tests should return a result of PASS or XFAIL. The XFAIL results +indicate known bugs. The final message should be one of the following: + + All XX tests behaved as expected (YY expected failures) + All XX tests passed + +If any tests have a status of FAIL, then the new code has caused a +regression error which should be fixed before the code is committed. + +When a new bug is found +----------------------- +A new test case should be added by imitating the style of an existing +test. This means adding the following files: + + new_bug.c + new_bug-ref.png + +Where new_bug.c is a minimal program to demonstrate the bug, following +the style of existing tests. The new_bug-ref.png image should contain +the desired result of new_bug.c if the bug were fixed. + +Makefile.am should be edited, adding new_bug.c to both the TESTS and +XFAIL_TESTS lists. + +When a new feature is added +--------------------------- +It's important for the regression suite to keep pace with development +of the library. So a new test should be added for each new +feature. The work involved is similar the work described above for new +bugs. The only distinction is that the test is expected to pass so it +should not be added to the XFAIL_TESTS list. + + +When a bug is fixed +------------------- +The fix should be verified by running the test suite which should +result in an "unexpected pass" for the test of interest. Rejoice as +appropriate, then remove the relevant file name from the XFAIL_TESTS +variable in Makefile.am. + +Before releasing +---------------- +All tests should return a result of PASS meaning all known bugs are +fixed, resulting in the happy message: + + All XX tests passed + diff --git a/test/cairo-test.c b/test/cairo-test.c new file mode 100644 index 00000000..75327c89 --- /dev/null +++ b/test/cairo-test.c @@ -0,0 +1,198 @@ +/* + * Copyright © 2004 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. 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: Carl D. Worth <cworth@cworth.org> + */ + +#include <unistd.h> +#include <errno.h> + +#include "cairo_test.h" + +#include "read_png.h" +#include "write_png.h" +#include "xmalloc.h" + +#define CAIRO_TEST_PNG_SUFFIX "-out.png" +#define CAIRO_TEST_REF_SUFFIX "-ref.png" +#define CAIRO_TEST_DIFF_SUFFIX "-diff.png" + +static void +xasprintf (char **strp, const char *fmt, ...) +{ + va_list va; + int ret; + + va_start (va, fmt); + ret = vasprintf (strp, fmt, va); + va_end (va); + + if (ret < 0) { + fprintf (stderr, "Out of memory\n"); + exit (1); + } +} + +/* Image comparison code courttesy of Richard Worth. + * Returns number of pixels changed. + * Also fills out a "diff" image intended to visually show where the + * images differ. + */ +static int +image_diff (char *buf_a, char *buf_b, char *buf_diff, + int width, int height, int stride) +{ + int x, y; + int total_pixels_changed = 0; + unsigned char *row_a, *row_b, *row; + + for (y = 0; y < height; y++) + { + row_a = buf_a + y * stride; + row_b = buf_b + y * stride; + row = buf_diff + y * stride; + for (x = 0; x < width; x++) + { + int channel; + unsigned char value_a, value_b; + int pixel_changed = 0; + for (channel = 0; channel < 4; channel++) + { + double diff; + value_a = row_a[x * 4 + channel]; + value_b = row_b[x * 4 + channel]; + if (value_a != value_b) + pixel_changed = 1; + diff = value_a - value_b; + row[x * 4 + channel] = 128 + diff / 3.0; + } + if (pixel_changed) { + total_pixels_changed++; + } else { + row[x*4+0] = 0; + row[x*4+1] = 0; + row[x*4+2] = 0; + } + row[x * 4 + 3] = 0xff; /* Set ALPHA to 100% (opaque) */ + } + } + + return total_pixels_changed; +} + +cairo_test_status_t +cairo_test (cairo_test_t *test, cairo_test_draw_function_t draw) +{ + cairo_t *cr; + int stride; + unsigned char *png_buf, *ref_buf, *diff_buf; + char *png_name, *ref_name, *diff_name; + char *srcdir; + int pixels_changed; + int ref_width, ref_height, ref_stride; + read_png_status_t png_status; + cairo_test_status_t ret; + + /* The cairo part of the test is the easiest part */ + cr = cairo_create (); + + stride = 4 * test->width; + + png_buf = xcalloc (stride * test->height, 1); + diff_buf = xcalloc (stride * test->height, 1); + + cairo_set_target_image (cr, png_buf, CAIRO_FORMAT_ARGB32, + test->width, test->height, stride); + + (draw) (cr, test->width, test->height); + + cairo_destroy (cr); + + /* Then we've got a bunch of string manipulation and file I/O for the check */ + srcdir = getenv ("srcdir"); + if (!srcdir) + srcdir = ""; + xasprintf (&png_name, "%s%s", test->name, CAIRO_TEST_PNG_SUFFIX); + xasprintf (&ref_name, "%s/%s%s", srcdir, test->name, CAIRO_TEST_REF_SUFFIX); + xasprintf (&diff_name, "%s%s", test->name, CAIRO_TEST_DIFF_SUFFIX); + + write_png_argb32 (png_buf, png_name, test->width, test->height, stride); + + ref_buf = NULL; + png_status = (read_png_argb32 (ref_name, &ref_buf, &ref_width, &ref_height, &ref_stride)); + if (png_status) { + switch (png_status) + { + case READ_PNG_FILE_NOT_FOUND: + fprintf (stderr, " Error: No reference image found: %s\n", ref_name); + break; + case READ_PNG_FILE_NOT_PNG: + fprintf (stderr, " Error: %s is not a png image\n", ref_name); + break; + default: + fprintf (stderr, " Error: Failed to read %s\n", ref_name); + } + + ret = CAIRO_TEST_FAILURE; + goto BAIL; + } + + if (test->width != ref_width || test->height != ref_height) { + fprintf (stderr, + " Error: Image size mismatch: (%dx%d) vs. (%dx%d)\n" + " for %s vs %s\n", + test->width, test->height, + ref_width, ref_height, + png_name, ref_name); + ret = CAIRO_TEST_FAILURE; + goto BAIL; + } + + pixels_changed = image_diff (png_buf, ref_buf, diff_buf, + test->width, test->height, stride); + if (pixels_changed) { + fprintf (stderr, " Error: %d pixels differ from reference image %s\n", + pixels_changed, ref_name); + write_png_argb32 (diff_buf, diff_name, test->width, test->height, stride); + ret = CAIRO_TEST_FAILURE; + goto BAIL; + } else { + if (unlink (diff_name) < 0 && errno != ENOENT) { + fprintf (stderr, " Error: Cannot remove %s: %s\n", + diff_name, strerror (errno)); + ret = CAIRO_TEST_FAILURE; + goto BAIL; + } + } + + ret = CAIRO_TEST_SUCCESS; + +BAIL: + free (png_buf); + free (ref_buf); + free (diff_buf); + free (png_name); + free (ref_name); + free (diff_name); + + return ret; +} diff --git a/test/cairo-test.h b/test/cairo-test.h new file mode 100644 index 00000000..7062f029 --- /dev/null +++ b/test/cairo-test.h @@ -0,0 +1,50 @@ +/* + * Copyright © 2004 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. 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: Carl D. Worth <cworth@cworth.org> + */ + +#ifndef _CAIRO_TEST_H_ +#define _CAIRO_TEST_H_ + +#include <cairo.h> + +typedef enum cairo_test_status { + CAIRO_TEST_SUCCESS = 0, + CAIRO_TEST_FAILURE +} cairo_test_status_t; + +typedef struct cairo_test { + char *name; + char *description; + int width; + int height; +} cairo_test_t; + +typedef void (*cairo_test_draw_function_t) (cairo_t *cr, int width, int height); + +/* cairo_test.c */ +cairo_test_status_t +cairo_test (cairo_test_t *test, cairo_test_draw_function_t draw); + +#endif + diff --git a/test/cairo_test.c b/test/cairo_test.c new file mode 100644 index 00000000..75327c89 --- /dev/null +++ b/test/cairo_test.c @@ -0,0 +1,198 @@ +/* + * Copyright © 2004 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. 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: Carl D. Worth <cworth@cworth.org> + */ + +#include <unistd.h> +#include <errno.h> + +#include "cairo_test.h" + +#include "read_png.h" +#include "write_png.h" +#include "xmalloc.h" + +#define CAIRO_TEST_PNG_SUFFIX "-out.png" +#define CAIRO_TEST_REF_SUFFIX "-ref.png" +#define CAIRO_TEST_DIFF_SUFFIX "-diff.png" + +static void +xasprintf (char **strp, const char *fmt, ...) +{ + va_list va; + int ret; + + va_start (va, fmt); + ret = vasprintf (strp, fmt, va); + va_end (va); + + if (ret < 0) { + fprintf (stderr, "Out of memory\n"); + exit (1); + } +} + +/* Image comparison code courttesy of Richard Worth. + * Returns number of pixels changed. + * Also fills out a "diff" image intended to visually show where the + * images differ. + */ +static int +image_diff (char *buf_a, char *buf_b, char *buf_diff, + int width, int height, int stride) +{ + int x, y; + int total_pixels_changed = 0; + unsigned char *row_a, *row_b, *row; + + for (y = 0; y < height; y++) + { + row_a = buf_a + y * stride; + row_b = buf_b + y * stride; + row = buf_diff + y * stride; + for (x = 0; x < width; x++) + { + int channel; + unsigned char value_a, value_b; + int pixel_changed = 0; + for (channel = 0; channel < 4; channel++) + { + double diff; + value_a = row_a[x * 4 + channel]; + value_b = row_b[x * 4 + channel]; + if (value_a != value_b) + pixel_changed = 1; + diff = value_a - value_b; + row[x * 4 + channel] = 128 + diff / 3.0; + } + if (pixel_changed) { + total_pixels_changed++; + } else { + row[x*4+0] = 0; + row[x*4+1] = 0; + row[x*4+2] = 0; + } + row[x * 4 + 3] = 0xff; /* Set ALPHA to 100% (opaque) */ + } + } + + return total_pixels_changed; +} + +cairo_test_status_t +cairo_test (cairo_test_t *test, cairo_test_draw_function_t draw) +{ + cairo_t *cr; + int stride; + unsigned char *png_buf, *ref_buf, *diff_buf; + char *png_name, *ref_name, *diff_name; + char *srcdir; + int pixels_changed; + int ref_width, ref_height, ref_stride; + read_png_status_t png_status; + cairo_test_status_t ret; + + /* The cairo part of the test is the easiest part */ + cr = cairo_create (); + + stride = 4 * test->width; + + png_buf = xcalloc (stride * test->height, 1); + diff_buf = xcalloc (stride * test->height, 1); + + cairo_set_target_image (cr, png_buf, CAIRO_FORMAT_ARGB32, + test->width, test->height, stride); + + (draw) (cr, test->width, test->height); + + cairo_destroy (cr); + + /* Then we've got a bunch of string manipulation and file I/O for the check */ + srcdir = getenv ("srcdir"); + if (!srcdir) + srcdir = ""; + xasprintf (&png_name, "%s%s", test->name, CAIRO_TEST_PNG_SUFFIX); + xasprintf (&ref_name, "%s/%s%s", srcdir, test->name, CAIRO_TEST_REF_SUFFIX); + xasprintf (&diff_name, "%s%s", test->name, CAIRO_TEST_DIFF_SUFFIX); + + write_png_argb32 (png_buf, png_name, test->width, test->height, stride); + + ref_buf = NULL; + png_status = (read_png_argb32 (ref_name, &ref_buf, &ref_width, &ref_height, &ref_stride)); + if (png_status) { + switch (png_status) + { + case READ_PNG_FILE_NOT_FOUND: + fprintf (stderr, " Error: No reference image found: %s\n", ref_name); + break; + case READ_PNG_FILE_NOT_PNG: + fprintf (stderr, " Error: %s is not a png image\n", ref_name); + break; + default: + fprintf (stderr, " Error: Failed to read %s\n", ref_name); + } + + ret = CAIRO_TEST_FAILURE; + goto BAIL; + } + + if (test->width != ref_width || test->height != ref_height) { + fprintf (stderr, + " Error: Image size mismatch: (%dx%d) vs. (%dx%d)\n" + " for %s vs %s\n", + test->width, test->height, + ref_width, ref_height, + png_name, ref_name); + ret = CAIRO_TEST_FAILURE; + goto BAIL; + } + + pixels_changed = image_diff (png_buf, ref_buf, diff_buf, + test->width, test->height, stride); + if (pixels_changed) { + fprintf (stderr, " Error: %d pixels differ from reference image %s\n", + pixels_changed, ref_name); + write_png_argb32 (diff_buf, diff_name, test->width, test->height, stride); + ret = CAIRO_TEST_FAILURE; + goto BAIL; + } else { + if (unlink (diff_name) < 0 && errno != ENOENT) { + fprintf (stderr, " Error: Cannot remove %s: %s\n", + diff_name, strerror (errno)); + ret = CAIRO_TEST_FAILURE; + goto BAIL; + } + } + + ret = CAIRO_TEST_SUCCESS; + +BAIL: + free (png_buf); + free (ref_buf); + free (diff_buf); + free (png_name); + free (ref_name); + free (diff_name); + + return ret; +} diff --git a/test/cairo_test.h b/test/cairo_test.h new file mode 100644 index 00000000..7062f029 --- /dev/null +++ b/test/cairo_test.h @@ -0,0 +1,50 @@ +/* + * Copyright © 2004 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. 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: Carl D. Worth <cworth@cworth.org> + */ + +#ifndef _CAIRO_TEST_H_ +#define _CAIRO_TEST_H_ + +#include <cairo.h> + +typedef enum cairo_test_status { + CAIRO_TEST_SUCCESS = 0, + CAIRO_TEST_FAILURE +} cairo_test_status_t; + +typedef struct cairo_test { + char *name; + char *description; + int width; + int height; +} cairo_test_t; + +typedef void (*cairo_test_draw_function_t) (cairo_t *cr, int width, int height); + +/* cairo_test.c */ +cairo_test_status_t +cairo_test (cairo_test_t *test, cairo_test_draw_function_t draw); + +#endif + diff --git a/test/fill-rule-ref.png b/test/fill-rule-ref.png Binary files differnew file mode 100644 index 00000000..25442c04 --- /dev/null +++ b/test/fill-rule-ref.png diff --git a/test/fill-rule.c b/test/fill-rule.c new file mode 100644 index 00000000..40ab9a12 --- /dev/null +++ b/test/fill-rule.c @@ -0,0 +1,90 @@ +/* + * Copyright © 2004 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. 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: Carl D. Worth <cworth@cworth.org> + */ + +/* Bug history + * + * 2004-10-27 Carl Worth <cworth@cworth.org> + * + * There's currently a regression bug in the tessellation code. This + * causes each of these simple star shapes to be filled incorrectly. + * + * It looks like right now we can get this test to pass by doing: + * + * cvs update -r 1.16 src/cairo_traps.c + * + * But we don't want to revert that change permanently since it + * really does correct some bugs. It must be that the old version of + * the code is masking some other bugs in the tessellation code. My + * current plan is to back this revision up for the next snapshot, + * but not to list the test as an expected failure since I'm + * planning on doing the new tessellator which should fix this + * problem. + * + */ + +#include "cairo_test.h" + +#define STAR_SIZE 20 + +cairo_test_t test = { + "fill_rule", + "Tests cairo_set_full_rule with a star shape", + STAR_SIZE * 2 + 3, STAR_SIZE +2 +}; + + +/* Not a perfect star, but one that does show the tessellation bug. */ +static void +star_path (cairo_t *cr) +{ + cairo_move_to (cr, 10, 0); + cairo_rel_line_to (cr, 6, 20); + cairo_rel_line_to (cr, -16, -12); + cairo_rel_line_to (cr, 20, 0); + cairo_rel_line_to (cr, -16, 12); +} + +/* Fill the same path twice, once with each fill rule */ +static void +draw (cairo_t *cr, int width, int height) +{ + cairo_set_rgb_color (cr, 1, 0, 0); + + cairo_translate (cr, 1, 1); + star_path (cr); + cairo_set_fill_rule (cr, CAIRO_FILL_RULE_WINDING); + cairo_fill (cr); + + cairo_translate (cr, STAR_SIZE + 1, 0); + star_path (cr); + cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD); + cairo_fill (cr); +} + +int +main (void) +{ + return cairo_test (&test, draw); +} diff --git a/test/fill_rule-ref.png b/test/fill_rule-ref.png Binary files differnew file mode 100644 index 00000000..25442c04 --- /dev/null +++ b/test/fill_rule-ref.png diff --git a/test/fill_rule.c b/test/fill_rule.c new file mode 100644 index 00000000..40ab9a12 --- /dev/null +++ b/test/fill_rule.c @@ -0,0 +1,90 @@ +/* + * Copyright © 2004 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. 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: Carl D. Worth <cworth@cworth.org> + */ + +/* Bug history + * + * 2004-10-27 Carl Worth <cworth@cworth.org> + * + * There's currently a regression bug in the tessellation code. This + * causes each of these simple star shapes to be filled incorrectly. + * + * It looks like right now we can get this test to pass by doing: + * + * cvs update -r 1.16 src/cairo_traps.c + * + * But we don't want to revert that change permanently since it + * really does correct some bugs. It must be that the old version of + * the code is masking some other bugs in the tessellation code. My + * current plan is to back this revision up for the next snapshot, + * but not to list the test as an expected failure since I'm + * planning on doing the new tessellator which should fix this + * problem. + * + */ + +#include "cairo_test.h" + +#define STAR_SIZE 20 + +cairo_test_t test = { + "fill_rule", + "Tests cairo_set_full_rule with a star shape", + STAR_SIZE * 2 + 3, STAR_SIZE +2 +}; + + +/* Not a perfect star, but one that does show the tessellation bug. */ +static void +star_path (cairo_t *cr) +{ + cairo_move_to (cr, 10, 0); + cairo_rel_line_to (cr, 6, 20); + cairo_rel_line_to (cr, -16, -12); + cairo_rel_line_to (cr, 20, 0); + cairo_rel_line_to (cr, -16, 12); +} + +/* Fill the same path twice, once with each fill rule */ +static void +draw (cairo_t *cr, int width, int height) +{ + cairo_set_rgb_color (cr, 1, 0, 0); + + cairo_translate (cr, 1, 1); + star_path (cr); + cairo_set_fill_rule (cr, CAIRO_FILL_RULE_WINDING); + cairo_fill (cr); + + cairo_translate (cr, STAR_SIZE + 1, 0); + star_path (cr); + cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD); + cairo_fill (cr); +} + +int +main (void) +{ + return cairo_test (&test, draw); +} diff --git a/test/line-width-ref.png b/test/line-width-ref.png Binary files differnew file mode 100644 index 00000000..1490b1b4 --- /dev/null +++ b/test/line-width-ref.png diff --git a/test/line-width.c b/test/line-width.c new file mode 100644 index 00000000..9c3ed89b --- /dev/null +++ b/test/line-width.c @@ -0,0 +1,63 @@ +/* + * Copyright © 2004 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. 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: Carl D. Worth <cworth@cworth.org> + */ + +#include "cairo_test.h" + +#define LINES 5 +#define LINE_LENGTH 10 +#define IMAGE_WIDTH 2 * LINE_LENGTH + 6 +#define IMAGE_HEIGHT ((LINES+4)*LINES)/2 + 2 + +cairo_test_t test = { + "line_width", + "Tests cairo_set_line_width", + IMAGE_WIDTH, IMAGE_HEIGHT +}; + +static void +draw (cairo_t *cr, int width, int height) +{ + int i; + + cairo_set_rgb_color (cr, 0, 0, 0); + cairo_translate (cr, 2, 2); + + for (i=0; i < LINES; i++) { + cairo_set_line_width (cr, i+1); + cairo_move_to (cr, 0, 0); + cairo_rel_line_to (cr, LINE_LENGTH, 0); + cairo_stroke (cr); + cairo_move_to (cr, LINE_LENGTH + 2, 0.5); + cairo_rel_line_to (cr, LINE_LENGTH, 0); + cairo_stroke (cr); + cairo_translate (cr, 0, i+3); + } +} + +int +main (void) +{ + return cairo_test (&test, draw); +} diff --git a/test/line_width-ref.png b/test/line_width-ref.png Binary files differnew file mode 100644 index 00000000..1490b1b4 --- /dev/null +++ b/test/line_width-ref.png diff --git a/test/line_width.c b/test/line_width.c new file mode 100644 index 00000000..9c3ed89b --- /dev/null +++ b/test/line_width.c @@ -0,0 +1,63 @@ +/* + * Copyright © 2004 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. 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: Carl D. Worth <cworth@cworth.org> + */ + +#include "cairo_test.h" + +#define LINES 5 +#define LINE_LENGTH 10 +#define IMAGE_WIDTH 2 * LINE_LENGTH + 6 +#define IMAGE_HEIGHT ((LINES+4)*LINES)/2 + 2 + +cairo_test_t test = { + "line_width", + "Tests cairo_set_line_width", + IMAGE_WIDTH, IMAGE_HEIGHT +}; + +static void +draw (cairo_t *cr, int width, int height) +{ + int i; + + cairo_set_rgb_color (cr, 0, 0, 0); + cairo_translate (cr, 2, 2); + + for (i=0; i < LINES; i++) { + cairo_set_line_width (cr, i+1); + cairo_move_to (cr, 0, 0); + cairo_rel_line_to (cr, LINE_LENGTH, 0); + cairo_stroke (cr); + cairo_move_to (cr, LINE_LENGTH + 2, 0.5); + cairo_rel_line_to (cr, LINE_LENGTH, 0); + cairo_stroke (cr); + cairo_translate (cr, 0, i+3); + } +} + +int +main (void) +{ + return cairo_test (&test, draw); +} diff --git a/test/move-to-show-surface-ref.png b/test/move-to-show-surface-ref.png Binary files differnew file mode 100644 index 00000000..765adc4a --- /dev/null +++ b/test/move-to-show-surface-ref.png diff --git a/test/move-to-show-surface.c b/test/move-to-show-surface.c new file mode 100644 index 00000000..6dcda210 --- /dev/null +++ b/test/move-to-show-surface.c @@ -0,0 +1,69 @@ +/* + * Copyright © 2004 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. 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: Carl D. Worth <cworth@cworth.org> + */ + +/* Bug history + * + * 2004-10-25 Carl Worth <cworth@cworth.org> + * + * It looks like cairo_show_surface has no effect if it follows a + * call to cairo_move_to to any coordinate other than 0,0. A little + * bit of poking around suggests this isn't a regression, (at least + * not since the last pixman snapshot). + * + */ + + +#include "cairo_test.h" + +cairo_test_t test = { + "move_to_show_surface", + "Tests calls to cairo_show_surface after cairo_move_to", + 2, 2 +}; + +static void +draw (cairo_t *cr, int width, int height) +{ + cairo_surface_t *surface; + uint32_t colors[4] = { + 0xffffffff, 0xffff0000, + 0xff00ff00, 0xff0000ff + }; + int i; + + for (i=0; i < 4; i++) { + surface = cairo_surface_create_for_image ((char *) &colors[i], + CAIRO_FORMAT_ARGB32, 1, 1, 4); + cairo_move_to (cr, i % 2, i / 2); + cairo_show_surface (cr, surface, 1, 1); + cairo_surface_destroy (surface); + } +} + +int +main (void) +{ + return cairo_test (&test, draw); +} diff --git a/test/move_to_show_surface-ref.png b/test/move_to_show_surface-ref.png Binary files differnew file mode 100644 index 00000000..765adc4a --- /dev/null +++ b/test/move_to_show_surface-ref.png diff --git a/test/move_to_show_surface.c b/test/move_to_show_surface.c new file mode 100644 index 00000000..6dcda210 --- /dev/null +++ b/test/move_to_show_surface.c @@ -0,0 +1,69 @@ +/* + * Copyright © 2004 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. 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: Carl D. Worth <cworth@cworth.org> + */ + +/* Bug history + * + * 2004-10-25 Carl Worth <cworth@cworth.org> + * + * It looks like cairo_show_surface has no effect if it follows a + * call to cairo_move_to to any coordinate other than 0,0. A little + * bit of poking around suggests this isn't a regression, (at least + * not since the last pixman snapshot). + * + */ + + +#include "cairo_test.h" + +cairo_test_t test = { + "move_to_show_surface", + "Tests calls to cairo_show_surface after cairo_move_to", + 2, 2 +}; + +static void +draw (cairo_t *cr, int width, int height) +{ + cairo_surface_t *surface; + uint32_t colors[4] = { + 0xffffffff, 0xffff0000, + 0xff00ff00, 0xff0000ff + }; + int i; + + for (i=0; i < 4; i++) { + surface = cairo_surface_create_for_image ((char *) &colors[i], + CAIRO_FORMAT_ARGB32, 1, 1, 4); + cairo_move_to (cr, i % 2, i / 2); + cairo_show_surface (cr, surface, 1, 1); + cairo_surface_destroy (surface); + } +} + +int +main (void) +{ + return cairo_test (&test, draw); +} diff --git a/test/read-png.c b/test/read-png.c new file mode 100644 index 00000000..23f91e83 --- /dev/null +++ b/test/read-png.c @@ -0,0 +1,166 @@ +/* + * Copyright © 2003 USC, Information Sciences Institute + * + * 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 + * University of Southern California not be used in advertising or + * publicity pertaining to distribution of the software without + * specific, written prior permission. The University of Southern + * California makes no representations about the suitability of this + * software for any purpose. It is provided "as is" without express + * or implied warranty. + * + * THE UNIVERSITY OF SOUTHERN CALIFORNIA DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF + * SOUTHERN CALIFORNIA 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: Carl D. Worth <cworth@isi.edu> + */ + +#include <stdio.h> +#include <stdlib.h> +#include <png.h> + +#include "read_png.h" +#include "xmalloc.h" + +static void +premultiply_data (png_structp png, + png_row_infop row_info, + png_bytep data) +{ + int i; + + for (i = 0; i < row_info->rowbytes; i += 4) { + unsigned char *base = &data[i]; + unsigned char blue = base[0]; + unsigned char green = base[1]; + unsigned char red = base[2]; + unsigned char alpha = base[3]; + unsigned long p; + + red = (unsigned) red * (unsigned) alpha / 255; + green = (unsigned) green * (unsigned) alpha / 255; + blue = (unsigned) blue * (unsigned) alpha / 255; + p = (alpha << 24) | (red << 16) | (green << 8) | (blue << 0); + memcpy (base, &p, sizeof (unsigned long)); + } +} + +read_png_status_t +read_png_argb32 (const char *filename, + unsigned char **data, + unsigned int *width, + unsigned int *height, + unsigned int *stride) +{ + int i; + FILE *file; + static const int PNG_SIG_SIZE = 8; + unsigned char png_sig[PNG_SIG_SIZE]; + int sig_bytes; + png_struct *png; + png_info *info; + png_uint_32 png_width, png_height; + int depth, color_type, interlace; + unsigned int pixel_size; + png_byte **row_pointers; + + file = fopen (filename, "rb"); + if (file == NULL) { + return READ_PNG_FILE_NOT_FOUND; + } + + sig_bytes = fread (png_sig, 1, PNG_SIG_SIZE, file); + if (png_check_sig (png_sig, sig_bytes) == 0) { + fclose (file); + return READ_PNG_FILE_NOT_PNG; + } + + /* XXX: Perhaps we'll want some other error handlers? */ + png = png_create_read_struct (PNG_LIBPNG_VER_STRING, + NULL, + NULL, + NULL); + if (png == NULL) { + fclose (file); + return READ_PNG_NO_MEMORY; + } + + info = png_create_info_struct (png); + if (info == NULL) { + fclose (file); + png_destroy_read_struct (&png, NULL, NULL); + return READ_PNG_NO_MEMORY; + } + + png_init_io (png, file); + png_set_sig_bytes (png, sig_bytes); + + png_read_info (png, info); + + png_get_IHDR (png, info, + &png_width, &png_height, &depth, + &color_type, &interlace, NULL, NULL); + *width = png_width; + *height = png_height; + *stride = 4 * png_width; + + + /* convert palette/gray image to rgb */ + if (color_type == PNG_COLOR_TYPE_PALETTE) + png_set_palette_to_rgb (png); + + /* expand gray bit depth if needed */ + if (color_type == PNG_COLOR_TYPE_GRAY && depth < 8) + png_set_gray_1_2_4_to_8 (png); + /* transform transparency to alpha */ + if (png_get_valid(png, info, PNG_INFO_tRNS)) + png_set_tRNS_to_alpha (png); + + if (depth == 16) + png_set_strip_16 (png); + + if (depth < 8) + png_set_packing (png); + + /* convert grayscale to RGB */ + if (color_type == PNG_COLOR_TYPE_GRAY + || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + png_set_gray_to_rgb (png); + + if (interlace != PNG_INTERLACE_NONE) + png_set_interlace_handling (png); + + png_set_bgr (png); + png_set_filler (png, 0xff, PNG_FILLER_AFTER); + + png_set_read_user_transform_fn (png, premultiply_data); + + png_read_update_info (png, info); + + pixel_size = 4; + *data = xmalloc (png_width * png_height * pixel_size); + + row_pointers = malloc (png_height * sizeof(char *)); + for (i=0; i < png_height; i++) + row_pointers[i] = (png_byte *) (*data + i * png_width * pixel_size); + + png_read_image (png, row_pointers); + png_read_end (png, info); + + free (row_pointers); + fclose (file); + + png_destroy_read_struct (&png, &info, NULL); + + return READ_PNG_SUCCESS; +} diff --git a/test/read-png.h b/test/read-png.h new file mode 100644 index 00000000..9c9ba433 --- /dev/null +++ b/test/read-png.h @@ -0,0 +1,45 @@ +/* + * Copyright © 2003 USC, Information Sciences Institute + * + * 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 + * University of Southern California not be used in advertising or + * publicity pertaining to distribution of the software without + * specific, written prior permission. The University of Southern + * California makes no representations about the suitability of this + * software for any purpose. It is provided "as is" without express + * or implied warranty. + * + * THE UNIVERSITY OF SOUTHERN CALIFORNIA DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF + * SOUTHERN CALIFORNIA 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: Carl D. Worth <cworth@isi.edu> + */ + +#ifndef READ_PNG_H +#define READ_PNG_H + +typedef enum { + READ_PNG_SUCCESS = 0, + READ_PNG_FILE_NOT_FOUND, + READ_PNG_FILE_NOT_PNG, + READ_PNG_NO_MEMORY +} read_png_status_t; + +read_png_status_t +read_png_argb32 (const char *filename, + unsigned char **data, + unsigned int *width, + unsigned int *height, + unsigned int *stride); + +#endif diff --git a/test/read_png.c b/test/read_png.c new file mode 100644 index 00000000..23f91e83 --- /dev/null +++ b/test/read_png.c @@ -0,0 +1,166 @@ +/* + * Copyright © 2003 USC, Information Sciences Institute + * + * 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 + * University of Southern California not be used in advertising or + * publicity pertaining to distribution of the software without + * specific, written prior permission. The University of Southern + * California makes no representations about the suitability of this + * software for any purpose. It is provided "as is" without express + * or implied warranty. + * + * THE UNIVERSITY OF SOUTHERN CALIFORNIA DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF + * SOUTHERN CALIFORNIA 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: Carl D. Worth <cworth@isi.edu> + */ + +#include <stdio.h> +#include <stdlib.h> +#include <png.h> + +#include "read_png.h" +#include "xmalloc.h" + +static void +premultiply_data (png_structp png, + png_row_infop row_info, + png_bytep data) +{ + int i; + + for (i = 0; i < row_info->rowbytes; i += 4) { + unsigned char *base = &data[i]; + unsigned char blue = base[0]; + unsigned char green = base[1]; + unsigned char red = base[2]; + unsigned char alpha = base[3]; + unsigned long p; + + red = (unsigned) red * (unsigned) alpha / 255; + green = (unsigned) green * (unsigned) alpha / 255; + blue = (unsigned) blue * (unsigned) alpha / 255; + p = (alpha << 24) | (red << 16) | (green << 8) | (blue << 0); + memcpy (base, &p, sizeof (unsigned long)); + } +} + +read_png_status_t +read_png_argb32 (const char *filename, + unsigned char **data, + unsigned int *width, + unsigned int *height, + unsigned int *stride) +{ + int i; + FILE *file; + static const int PNG_SIG_SIZE = 8; + unsigned char png_sig[PNG_SIG_SIZE]; + int sig_bytes; + png_struct *png; + png_info *info; + png_uint_32 png_width, png_height; + int depth, color_type, interlace; + unsigned int pixel_size; + png_byte **row_pointers; + + file = fopen (filename, "rb"); + if (file == NULL) { + return READ_PNG_FILE_NOT_FOUND; + } + + sig_bytes = fread (png_sig, 1, PNG_SIG_SIZE, file); + if (png_check_sig (png_sig, sig_bytes) == 0) { + fclose (file); + return READ_PNG_FILE_NOT_PNG; + } + + /* XXX: Perhaps we'll want some other error handlers? */ + png = png_create_read_struct (PNG_LIBPNG_VER_STRING, + NULL, + NULL, + NULL); + if (png == NULL) { + fclose (file); + return READ_PNG_NO_MEMORY; + } + + info = png_create_info_struct (png); + if (info == NULL) { + fclose (file); + png_destroy_read_struct (&png, NULL, NULL); + return READ_PNG_NO_MEMORY; + } + + png_init_io (png, file); + png_set_sig_bytes (png, sig_bytes); + + png_read_info (png, info); + + png_get_IHDR (png, info, + &png_width, &png_height, &depth, + &color_type, &interlace, NULL, NULL); + *width = png_width; + *height = png_height; + *stride = 4 * png_width; + + + /* convert palette/gray image to rgb */ + if (color_type == PNG_COLOR_TYPE_PALETTE) + png_set_palette_to_rgb (png); + + /* expand gray bit depth if needed */ + if (color_type == PNG_COLOR_TYPE_GRAY && depth < 8) + png_set_gray_1_2_4_to_8 (png); + /* transform transparency to alpha */ + if (png_get_valid(png, info, PNG_INFO_tRNS)) + png_set_tRNS_to_alpha (png); + + if (depth == 16) + png_set_strip_16 (png); + + if (depth < 8) + png_set_packing (png); + + /* convert grayscale to RGB */ + if (color_type == PNG_COLOR_TYPE_GRAY + || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + png_set_gray_to_rgb (png); + + if (interlace != PNG_INTERLACE_NONE) + png_set_interlace_handling (png); + + png_set_bgr (png); + png_set_filler (png, 0xff, PNG_FILLER_AFTER); + + png_set_read_user_transform_fn (png, premultiply_data); + + png_read_update_info (png, info); + + pixel_size = 4; + *data = xmalloc (png_width * png_height * pixel_size); + + row_pointers = malloc (png_height * sizeof(char *)); + for (i=0; i < png_height; i++) + row_pointers[i] = (png_byte *) (*data + i * png_width * pixel_size); + + png_read_image (png, row_pointers); + png_read_end (png, info); + + free (row_pointers); + fclose (file); + + png_destroy_read_struct (&png, &info, NULL); + + return READ_PNG_SUCCESS; +} diff --git a/test/read_png.h b/test/read_png.h new file mode 100644 index 00000000..9c9ba433 --- /dev/null +++ b/test/read_png.h @@ -0,0 +1,45 @@ +/* + * Copyright © 2003 USC, Information Sciences Institute + * + * 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 + * University of Southern California not be used in advertising or + * publicity pertaining to distribution of the software without + * specific, written prior permission. The University of Southern + * California makes no representations about the suitability of this + * software for any purpose. It is provided "as is" without express + * or implied warranty. + * + * THE UNIVERSITY OF SOUTHERN CALIFORNIA DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF + * SOUTHERN CALIFORNIA 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: Carl D. Worth <cworth@isi.edu> + */ + +#ifndef READ_PNG_H +#define READ_PNG_H + +typedef enum { + READ_PNG_SUCCESS = 0, + READ_PNG_FILE_NOT_FOUND, + READ_PNG_FILE_NOT_PNG, + READ_PNG_NO_MEMORY +} read_png_status_t; + +read_png_status_t +read_png_argb32 (const char *filename, + unsigned char **data, + unsigned int *width, + unsigned int *height, + unsigned int *stride); + +#endif diff --git a/test/write-png.c b/test/write-png.c new file mode 100644 index 00000000..2ea29d06 --- /dev/null +++ b/test/write-png.c @@ -0,0 +1,102 @@ +/* + * Copyright © 2003 USC, Information Sciences Institute + * + * 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 + * University of Southern California not be used in advertising or + * publicity pertaining to distribution of the software without + * specific, written prior permission. The University of Southern + * California makes no representations about the suitability of this + * software for any purpose. It is provided "as is" without express + * or implied warranty. + * + * THE UNIVERSITY OF SOUTHERN CALIFORNIA DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF + * SOUTHERN CALIFORNIA 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: Carl D. Worth <cworth@isi.edu> + */ + +#include <stdio.h> +#include <stdlib.h> +#include <png.h> + +#include "write_png.h" + +static void +unpremultiply_data (png_structp png, png_row_infop row_info, png_bytep data) +{ + int i; + + for (i = 0; i < row_info->rowbytes; i += 4) { + unsigned char *b = &data[i]; + unsigned int pixel; + unsigned char alpha; + + memcpy (&pixel, b, sizeof (unsigned int)); + alpha = (pixel & 0xff000000) >> 24; + if (alpha == 0) { + b[0] = b[1] = b[2] = b[3] = 0; + } else { + b[0] = (((pixel & 0x0000ff) >> 0) * 255) / alpha; + b[1] = (((pixel & 0x00ff00) >> 8) * 255) / alpha; + b[2] = (((pixel & 0xff0000) >> 16) * 255) / alpha; + b[3] = alpha; + } + } +} + +void +write_png_argb32 (char *buffer, char *filename, + int width, int height, int stride) +{ + FILE *f; + int i; + png_struct *png; + png_info *info; + png_byte **rows; + png_color_16 white; + + f = fopen (filename, "w"); + rows = malloc (height * sizeof(png_byte*)); + + for (i = 0; i < height; i++) { + rows[i] = buffer + i * stride; + } + + png = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + info = png_create_info_struct (png); + + png_init_io (png, f); + png_set_IHDR (png, info, + width, height, 8, + PNG_COLOR_TYPE_RGB_ALPHA, + PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_DEFAULT, + PNG_FILTER_TYPE_DEFAULT); + + white.red = 0xff; + white.blue = 0xff; + white.green = 0xff; + png_set_bKGD (png, info, &white); + + png_set_write_user_transform_fn (png, unpremultiply_data); + png_set_bgr (png); + + png_write_info (png, info); + png_write_image (png, rows); + png_write_end (png, info); + + png_destroy_write_struct (&png, &info); + + free (rows); + fclose (f); +} diff --git a/test/write-png.h b/test/write-png.h new file mode 100644 index 00000000..a71ca6a3 --- /dev/null +++ b/test/write-png.h @@ -0,0 +1,35 @@ +/* + * Copyright © 2003 USC, Information Sciences Institute + * + * 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 + * University of Southern California not be used in advertising or + * publicity pertaining to distribution of the software without + * specific, written prior permission. The University of Southern + * California makes no representations about the suitability of this + * software for any purpose. It is provided "as is" without express + * or implied warranty. + * + * THE UNIVERSITY OF SOUTHERN CALIFORNIA DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF + * SOUTHERN CALIFORNIA 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: Carl D. Worth <cworth@isi.edu> + */ + +#ifndef WRITE_PNG_H +#define WRITE_PNG_H + +void +write_png_argb32 (char *buffer, char *filename, + int width, int height, int stride); + +#endif diff --git a/test/write_png.c b/test/write_png.c new file mode 100644 index 00000000..2ea29d06 --- /dev/null +++ b/test/write_png.c @@ -0,0 +1,102 @@ +/* + * Copyright © 2003 USC, Information Sciences Institute + * + * 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 + * University of Southern California not be used in advertising or + * publicity pertaining to distribution of the software without + * specific, written prior permission. The University of Southern + * California makes no representations about the suitability of this + * software for any purpose. It is provided "as is" without express + * or implied warranty. + * + * THE UNIVERSITY OF SOUTHERN CALIFORNIA DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF + * SOUTHERN CALIFORNIA 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: Carl D. Worth <cworth@isi.edu> + */ + +#include <stdio.h> +#include <stdlib.h> +#include <png.h> + +#include "write_png.h" + +static void +unpremultiply_data (png_structp png, png_row_infop row_info, png_bytep data) +{ + int i; + + for (i = 0; i < row_info->rowbytes; i += 4) { + unsigned char *b = &data[i]; + unsigned int pixel; + unsigned char alpha; + + memcpy (&pixel, b, sizeof (unsigned int)); + alpha = (pixel & 0xff000000) >> 24; + if (alpha == 0) { + b[0] = b[1] = b[2] = b[3] = 0; + } else { + b[0] = (((pixel & 0x0000ff) >> 0) * 255) / alpha; + b[1] = (((pixel & 0x00ff00) >> 8) * 255) / alpha; + b[2] = (((pixel & 0xff0000) >> 16) * 255) / alpha; + b[3] = alpha; + } + } +} + +void +write_png_argb32 (char *buffer, char *filename, + int width, int height, int stride) +{ + FILE *f; + int i; + png_struct *png; + png_info *info; + png_byte **rows; + png_color_16 white; + + f = fopen (filename, "w"); + rows = malloc (height * sizeof(png_byte*)); + + for (i = 0; i < height; i++) { + rows[i] = buffer + i * stride; + } + + png = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + info = png_create_info_struct (png); + + png_init_io (png, f); + png_set_IHDR (png, info, + width, height, 8, + PNG_COLOR_TYPE_RGB_ALPHA, + PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_DEFAULT, + PNG_FILTER_TYPE_DEFAULT); + + white.red = 0xff; + white.blue = 0xff; + white.green = 0xff; + png_set_bKGD (png, info, &white); + + png_set_write_user_transform_fn (png, unpremultiply_data); + png_set_bgr (png); + + png_write_info (png, info); + png_write_image (png, rows); + png_write_end (png, info); + + png_destroy_write_struct (&png, &info); + + free (rows); + fclose (f); +} diff --git a/test/write_png.h b/test/write_png.h new file mode 100644 index 00000000..a71ca6a3 --- /dev/null +++ b/test/write_png.h @@ -0,0 +1,35 @@ +/* + * Copyright © 2003 USC, Information Sciences Institute + * + * 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 + * University of Southern California not be used in advertising or + * publicity pertaining to distribution of the software without + * specific, written prior permission. The University of Southern + * California makes no representations about the suitability of this + * software for any purpose. It is provided "as is" without express + * or implied warranty. + * + * THE UNIVERSITY OF SOUTHERN CALIFORNIA DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF + * SOUTHERN CALIFORNIA 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: Carl D. Worth <cworth@isi.edu> + */ + +#ifndef WRITE_PNG_H +#define WRITE_PNG_H + +void +write_png_argb32 (char *buffer, char *filename, + int width, int height, int stride); + +#endif diff --git a/test/xmalloc.c b/test/xmalloc.c new file mode 100644 index 00000000..04ed38af --- /dev/null +++ b/test/xmalloc.c @@ -0,0 +1,58 @@ +/* + * Copyright © 2004 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. 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: Carl D. Worth <cworth@cworth.org> + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "xmalloc.h" + +void * +xmalloc (size_t size) +{ + void *buf; + + buf = malloc (size); + if (!buf) { + fprintf (stderr, "Error: Out of memory. Exiting.\n"); + exit (1); + } + + return buf; +} + +void * +xcalloc (size_t nmemb, size_t size) +{ + void *buf; + + buf = calloc (nmemb, size); + if (!buf) { + fprintf (stderr, "Error: Out of memory. Exiting\n"); + exit (1); + } + + return buf; +} + diff --git a/test/xmalloc.h b/test/xmalloc.h new file mode 100644 index 00000000..a4ba24b6 --- /dev/null +++ b/test/xmalloc.h @@ -0,0 +1,35 @@ +/* + * Copyright © 2004 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. 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: Carl D. Worth <cworth@cworth.org> + */ + +#ifndef _XMALLOC_H_ +#define _XMALLOC_H_ + +void * +xmalloc (size_t size); + +void * +xcalloc (size_t nmemb, size_t size); + +#endif |