From 61d3929db06692a9b95fa0bee0bdf411c708fac6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Chlumsk=C3=BD?= Date: Sun, 24 Apr 2016 23:58:54 +0200 Subject: [PATCH] Version 1.0 --- LICENSE.txt | 677 +++ Makefile | 3 + Msdfgen.rc | Bin 0 -> 3954 bytes Msdfgen.sln | 28 + Msdfgen.vcxproj | 182 + Msdfgen.vcxproj.filters | 151 + README.md | 176 + core/Bitmap.cpp | 77 + core/Bitmap.h | 40 + core/Contour.cpp | 26 + core/Contour.h | 28 + core/EdgeColor.h | 18 + core/EdgeHolder.cpp | 67 + core/EdgeHolder.h | 38 + core/Shape.cpp | 56 + core/Shape.h | 35 + core/SignedDistance.cpp | 30 + core/SignedDistance.h | 25 + core/Vector2.cpp | 146 + core/Vector2.h | 66 + core/arithmetics.hpp | 57 + core/edge-coloring.cpp | 75 + core/edge-coloring.h | 15 + core/edge-segments.cpp | 334 ++ core/edge-segments.h | 101 + core/equation-solver.cpp | 69 + core/equation-solver.h | 15 + core/msdfgen.cpp | 166 + core/render-sdf.cpp | 107 + core/render-sdf.h | 19 + core/save-bmp.cpp | 109 + core/save-bmp.h | 12 + core/shape-description.cpp | 285 ++ core/shape-description.h | 16 + example.bat | 1 + ext/import-font.cpp | 192 + ext/import-font.h | 29 + ext/import-svg.cpp | 184 + ext/import-svg.h | 12 + ext/save-png.cpp | 30 + ext/save-png.h | 12 + freetype6.dll | Bin 0 -> 522240 bytes icon.ico | Bin 0 -> 32038 bytes include/freetype/config/ftconfig.h | 350 ++ include/freetype/config/ftheader.h | 729 ++++ include/freetype/config/ftmodule.h | 22 + include/freetype/config/ftoption.h | 695 ++++ include/freetype/config/ftstdlib.h | 180 + include/freetype/freetype.h | 3434 +++++++++++++++ include/freetype/ftbbox.h | 94 + include/freetype/ftbdf.h | 200 + include/freetype/ftbitmap.h | 206 + include/freetype/ftcache.h | 1110 +++++ include/freetype/ftchapters.h | 100 + include/freetype/fterrdef.h | 239 ++ include/freetype/fterrors.h | 206 + include/freetype/ftgasp.h | 113 + include/freetype/ftglyph.h | 575 +++ include/freetype/ftgxval.h | 358 ++ include/freetype/ftgzip.h | 102 + include/freetype/ftimage.h | 1237 ++++++ include/freetype/ftincrem.h | 331 ++ include/freetype/ftlcdfil.h | 166 + include/freetype/ftlist.h | 273 ++ include/freetype/ftlzw.h | 99 + include/freetype/ftmac.h | 272 ++ include/freetype/ftmm.h | 378 ++ include/freetype/ftmodapi.h | 406 ++ include/freetype/ftmoderr.h | 155 + include/freetype/ftotval.h | 198 + include/freetype/ftoutln.h | 526 +++ include/freetype/ftpfr.h | 172 + include/freetype/ftrender.h | 229 + include/freetype/ftsizes.h | 159 + include/freetype/ftsnames.h | 170 + include/freetype/ftstroke.h | 716 ++++ include/freetype/ftsynth.h | 73 + include/freetype/ftsystem.h | 346 ++ include/freetype/fttrigon.h | 350 ++ include/freetype/fttypes.h | 583 +++ include/freetype/ftwinfnt.h | 263 ++ include/freetype/ftxf86.h | 80 + include/freetype/t1tables.h | 450 ++ include/freetype/ttnameid.h | 1132 +++++ include/freetype/tttables.h | 756 ++++ include/freetype/tttags.h | 99 + include/freetype/ttunpat.h | 59 + include/ft2build.h | 61 + include/lodepng.h | 1759 ++++++++ include/tinyxml2.h | 2102 ++++++++++ lib/FTL.TXT | 169 + lib/freetype.lib | Bin 0 -> 55978 bytes lib/lodepng.cpp | 6223 ++++++++++++++++++++++++++++ lib/tinyxml2.cpp | 2467 +++++++++++ main.cpp | 754 ++++ msdfgen-ext.h | 23 + msdfgen.exe | Bin 0 -> 335360 bytes msdfgen.h | 40 + resource.h | Bin 0 -> 902 bytes 99 files changed, 35698 insertions(+) create mode 100644 LICENSE.txt create mode 100644 Makefile create mode 100644 Msdfgen.rc create mode 100644 Msdfgen.sln create mode 100644 Msdfgen.vcxproj create mode 100644 Msdfgen.vcxproj.filters create mode 100644 README.md create mode 100644 core/Bitmap.cpp create mode 100644 core/Bitmap.h create mode 100644 core/Contour.cpp create mode 100644 core/Contour.h create mode 100644 core/EdgeColor.h create mode 100644 core/EdgeHolder.cpp create mode 100644 core/EdgeHolder.h create mode 100644 core/Shape.cpp create mode 100644 core/Shape.h create mode 100644 core/SignedDistance.cpp create mode 100644 core/SignedDistance.h create mode 100644 core/Vector2.cpp create mode 100644 core/Vector2.h create mode 100644 core/arithmetics.hpp create mode 100644 core/edge-coloring.cpp create mode 100644 core/edge-coloring.h create mode 100644 core/edge-segments.cpp create mode 100644 core/edge-segments.h create mode 100644 core/equation-solver.cpp create mode 100644 core/equation-solver.h create mode 100644 core/msdfgen.cpp create mode 100644 core/render-sdf.cpp create mode 100644 core/render-sdf.h create mode 100644 core/save-bmp.cpp create mode 100644 core/save-bmp.h create mode 100644 core/shape-description.cpp create mode 100644 core/shape-description.h create mode 100644 example.bat create mode 100644 ext/import-font.cpp create mode 100644 ext/import-font.h create mode 100644 ext/import-svg.cpp create mode 100644 ext/import-svg.h create mode 100644 ext/save-png.cpp create mode 100644 ext/save-png.h create mode 100644 freetype6.dll create mode 100644 icon.ico create mode 100644 include/freetype/config/ftconfig.h create mode 100644 include/freetype/config/ftheader.h create mode 100644 include/freetype/config/ftmodule.h create mode 100644 include/freetype/config/ftoption.h create mode 100644 include/freetype/config/ftstdlib.h create mode 100644 include/freetype/freetype.h create mode 100644 include/freetype/ftbbox.h create mode 100644 include/freetype/ftbdf.h create mode 100644 include/freetype/ftbitmap.h create mode 100644 include/freetype/ftcache.h create mode 100644 include/freetype/ftchapters.h create mode 100644 include/freetype/fterrdef.h create mode 100644 include/freetype/fterrors.h create mode 100644 include/freetype/ftgasp.h create mode 100644 include/freetype/ftglyph.h create mode 100644 include/freetype/ftgxval.h create mode 100644 include/freetype/ftgzip.h create mode 100644 include/freetype/ftimage.h create mode 100644 include/freetype/ftincrem.h create mode 100644 include/freetype/ftlcdfil.h create mode 100644 include/freetype/ftlist.h create mode 100644 include/freetype/ftlzw.h create mode 100644 include/freetype/ftmac.h create mode 100644 include/freetype/ftmm.h create mode 100644 include/freetype/ftmodapi.h create mode 100644 include/freetype/ftmoderr.h create mode 100644 include/freetype/ftotval.h create mode 100644 include/freetype/ftoutln.h create mode 100644 include/freetype/ftpfr.h create mode 100644 include/freetype/ftrender.h create mode 100644 include/freetype/ftsizes.h create mode 100644 include/freetype/ftsnames.h create mode 100644 include/freetype/ftstroke.h create mode 100644 include/freetype/ftsynth.h create mode 100644 include/freetype/ftsystem.h create mode 100644 include/freetype/fttrigon.h create mode 100644 include/freetype/fttypes.h create mode 100644 include/freetype/ftwinfnt.h create mode 100644 include/freetype/ftxf86.h create mode 100644 include/freetype/t1tables.h create mode 100644 include/freetype/ttnameid.h create mode 100644 include/freetype/tttables.h create mode 100644 include/freetype/tttags.h create mode 100644 include/freetype/ttunpat.h create mode 100644 include/ft2build.h create mode 100644 include/lodepng.h create mode 100644 include/tinyxml2.h create mode 100644 lib/FTL.TXT create mode 100644 lib/freetype.lib create mode 100644 lib/lodepng.cpp create mode 100644 lib/tinyxml2.cpp create mode 100644 main.cpp create mode 100644 msdfgen-ext.h create mode 100644 msdfgen.exe create mode 100644 msdfgen.h create mode 100644 resource.h diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..f27031a --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,677 @@ + + + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + {one line to give the program's name and a brief idea of what it does.} + Copyright (C) {year} {name of author} + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + {project} Copyright (C) {year} {fullname} + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. + diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..ebdf199 --- /dev/null +++ b/Makefile @@ -0,0 +1,3 @@ + +all: + g++ -I include -D MSDFGEN_STANDALONE -O2 -o msdfgen core/*.cpp lib/*.cpp ext/*.cpp main.cpp -lfreetype diff --git a/Msdfgen.rc b/Msdfgen.rc new file mode 100644 index 0000000000000000000000000000000000000000..1893993edeb4fe7d5ec8fb705ece50ea7fcfeb09 GIT binary patch literal 3954 zcmds)Yj09P5QgWoiT`1xUu-nR%P-(25@Oa-LvhXa8R)y zj%IV%-PxJl*}1$s{PVOB$#YBc!1Im0oc6BR zOY2(C`c}7=y|AI3S_5jG@riZpHIy#D$5w^XVI0qw4#jIxyVyHxVwamX9%H4sU2y*; z){z~0-1-&2EpA=op0Y;+`V+pJ9{IHoK70EHxpn&&&tg%d5FIOQrAQic@BLyUT0ZVu ztUhX|9Q?{X&+)&r`)jjP=$B;FJMv1Ie7GeBl1xTTytVGFW!8v2EB1_-3K`WUd-~*7 zji?$DTOFGA{YG=Sl0Eh~C4z^@DGLw%sU4^%Q2X>vAEl8ZzBf>6_S_z_Zx@~_Ck1|; z+d!uZ)DE#OTLiD`2KioBPMo2C8|k{2D3(vN+C=}xJ}VB5niA1&c{aShCL<+fcq_n;28F0a!I4g9F}QYni9f(>*o%({m2UDB()T zl%SWqwhd!8qfNHU-{Cg$I2%F58td-yE0$(iZKR>*jx3o`)d)9}6j}RFCRf!>o3S`X z{{1ZivMNWLzk#fQuLA~jbI^62V+hK&{~_O9`>@5EH^)nnl8ryd{llvB2&DSS;qN&! z)vc;^TVS5EPrlY&L3O;QQ)a4WRpF}oT%^29B%MbGRmZBB9GsV4LT|6?;)&PB(XZN6af?^B#mlL>SFgdY7WsDZWY + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + {84BE2D91-F071-4151-BE12-61460464C494} + Msdfgen + 8.1 + + + + Application + true + v140 + MultiByte + + + Application + false + v140 + true + MultiByte + + + Application + true + v140 + MultiByte + + + Application + false + v140 + true + MultiByte + + + + + + + + + + + + + + + + + + + + + msdfgen + + + msdfgen + $(SolutionDir)\ + + + + Level3 + Disabled + true + MSDFGEN_STANDALONE;MSDFGEN_USE_CPP11;%(PreprocessorDefinitions) + MultiThreadedDebug + include;%(AdditionalIncludeDirectories) + + + Console + lib;%(AdditionalLibraryDirectories) + + + + + Level3 + Disabled + true + + + + + Level3 + MaxSpeed + true + true + true + MSDFGEN_STANDALONE;MSDFGEN_USE_CPP11;%(PreprocessorDefinitions) + MultiThreaded + include;%(AdditionalIncludeDirectories) + + + true + true + Console + lib;%(AdditionalLibraryDirectories) + + + + + Level3 + MaxSpeed + true + true + true + + + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Msdfgen.vcxproj.filters b/Msdfgen.vcxproj.filters new file mode 100644 index 0000000..5fd3183 --- /dev/null +++ b/Msdfgen.vcxproj.filters @@ -0,0 +1,151 @@ + + + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + {110bf5de-0605-40a4-92b4-68ca012d572f} + + + {8abe3d60-6507-4ee1-8d4f-eab2c43a3220} + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {42db228a-5d46-439c-ad30-7595a74d635f} + + + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Extensions + + + Extensions + + + Extensions + + + Extensions + + + + + + Standalone + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Extensions + + + Extensions + + + Core + + + Core + + + Extensions + + + Core + + + Core + + + Core + + + Core + + + Source Dependencies + + + Source Dependencies + + + Core + + + + + Resource Files + + + + + Resource Files + + + \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..7c756e4 --- /dev/null +++ b/README.md @@ -0,0 +1,176 @@ +# Multi-channel signed distance field generator + +This is a utility for generating signed distance fields from vector shapes and font glyphs, +which serve as a texture representation that can be used in real-time graphics to efficiently reproduce said shapes. +Although it can also be used to generate conventional signed distance fields best known from +[this Valve paper](http://www.valvesoftware.com/publications/2007/SIGGRAPH2007_AlphaTestedMagnification.pdf) +and pseudo-distance fields, its primary purpose is to generate multi-channel distance fields, +using a method I have developed. Unlike monochrome distance fields, they have the ability +to reproduce sharp corners almost perfectly by utilizing all three color channels. + +The following sequence of images demonstrates the improvement in image quality. + +![demo-msdf16](https://cloud.githubusercontent.com/assets/18639794/14770355/14cda9f8-0a70-11e6-8346-2bd14b5b832f.png) +![demo-sdf16](https://cloud.githubusercontent.com/assets/18639794/14770360/20c51156-0a70-11e6-8f03-ed7632d07997.png) +![demo-sdf32](https://cloud.githubusercontent.com/assets/18639794/14770361/251a4406-0a70-11e6-95a7-e30e235ac729.png) + +## Getting started + +The project can be used either as a library or as a console program. is divided into two parts, **[core](core)** +and **[extensions](ext)**. The core module has no dependencies and only uses bare C++. It contains all +key data structures and algorithms, which can be accessed through the [msdfgen.h](msdfgen.h) header. +Extensions contain utilities for loading fonts and SVG files, as well as saving PNG images. +Those are exposed by the [msdfgen-ext.h](msdfgen-ext.h) header. This module uses +[FreeType](http://www.freetype.org/), +[TinyXML2](http://www.grinninglizard.com/tinyxml2/), +and [LodePNG](http://lodev.org/lodepng/). + +Additionaly, there is the [main.cpp](main.cpp), which wraps the functionality into +a comprehensive standalone console program. To start using the program immediately, +a Windows binary of this program, [msdfgen.exe](msdfgen.exe), is available in the root directory. + +## Console commands + +The standalone program is executed as +``` +msdfgen.exe +``` +where only the input specification is required. + +Mode can be one of: + - **sdf** – generates a conventional monochrome signed distance field. + - **psdf** – generates a monochrome signed pseudo-distance field. + - **msdf** (default) – generates a multi-channel signed distance field using my new method. + +The input can be specified as one of: + - **-font \ \** – to load a glyph from a font file. + Character code can be expressed as either a decimal (63) or hexadecimal (0x3F) Unicode value, or an ASCII character + in single quotes ('?'). + - **-svg \** – to load an SVG file. Note that only the first vector path in the file will be used. + - **-shapedesc \**, -defineshape \, -stdin – to load a text description of the shape + from either a file, the next argument, or the standard input, respectively. Its syntax is documented further down. + +The complete list of available options can be printed with **-help**. +Some of the important ones are: + - **-o \** – specifies the output file name. The desired format will be deduced from the extension + (png, bmp, txt, bin). Otherwise, use -format. + - **-size \ \** – specifies the dimensions of the output distance field (in pixels). + - **-range \**, **-pxrange \** – specifies the width of the range around the shape + between the minimum and maximum representable signed distance in shape units or distance field pixels, respectivelly. + - **-autoframe** – automatically frames the shape to fit the distance field. If the output must be precisely aligned, + you should manually position it using -translate and -scale instead. + - **-scale \** – sets the scale used to convert shape units to distance field pixels. + - **-translate \ \** – sets the translation of the shape in shape units. Otherwise the origin (0, 0) + lies in the bottom left corner. + - **-angle \** – specifies the maximum angle to be considered a corner. + Can be expressed in radians (3.0) or degrees with D at the end (171.9D). + - **-testrender \ \ \** - tests the generated distance field by using it to render an image + of the original shape into a PNG file with the specified dimensions. Alternatively, -testrendermulti renders + an image without combining the color channels, and may give you an insight in how the multi-channel distance field works. + - **-exportshape \** - saves the text description of the shape with edge coloring to the specified file. + This can be later edited and used as input through -shapedesc. + - **-printmetrics** – prints some useful information about the shape's layout. + +For example, +``` +msdfgen.exe msdf -font C:\Windows\Fonts\arialbd.ttf 'M' -o msdf.png -size 32 32 -pxrange 4 -autoframe -testrender render.png 1024 1024 +``` + +will take the glyph capital M from the Arial Bold typeface, generate a 32×32 multi-channel distance field +with a 4 pixels wide distance range, store it into msdf.png, and create a test render of the glyph as render.png. + +## Library API + +If you choose to use this utility inside your own program, there are a few simple steps you need to perform +in order to generate a distance field. Please note that all classes and functions are in the `msdfgen` namespace. + + - Acquire a `Shape` object. You can either load it via `loadGlyph` or `loadSvgShape`, or construct it manually. + It consists of closed contours, which in turn consist of edges. An edge is represented by a `LinearEdge`, `QuadraticEdge`, + or `CubicEdge`. You can construct them from two endpoints and 0 to 2 Bézier control points. + - Normalize the shape using its `normalize` method and assign colors to edges if you need a multi-channel SDF. + This can be performed automatically using the `edgeColoringSimple` heuristic, or manually by setting each edge's + `color` member. Keep in mind that at least two color channels must be turned on in each edge, and the color should + only change at corners. + - Call `generateSDF`, `generatePseudoSDF`, or `generateMSDF` to generate a distance field into a floating point + `Bitmap` object. This can then be worked with further or saved to a file using `saveBmp` or `savePng`. + - You may also render an image from the distance field using `renderSDF`. Consider calling `simulate8bit` + on the distance field beforehand to simulate the standard 8 bits/pixel image format. + +Example: +```c++ +#include "msdfgen.h" +#include "msdfgen-ext.h" + +using namespace msdfgen; + +int main() { + FreetypeHandle *ft = initializeFreetype(); + if (ft) { + FontHandle *font = loadFont(ft, "C:\\Windows\\Fonts\\arialbd.ttf"); + if (font) { + Shape shape; + if (loadGlyph(shape, font, 'A')) { + shape.normalize(); + // max. angle + edgeColoringSimple(shape, 3.0); + // image width, height + Bitmap msdf(32, 32); + // range, scale, translation + generateMSDF(msdf, shape, 4.0, 1.0, Vector2(4.0, 4.0)); + savePng(msdf, "output.png"); + } + destroyFont(font); + } + deinitializeFreetype(ft); + } + return 0; +} + +``` + +## Using a multi-channel distance field + +Using a multi-channel distance field generated by this program is similarly simple to how a monochrome distance field is used. +The only additional operation is computing the **median** of the three channels inside the fragment shader, +right after sampling the distance field. This signed distance value can then be used the same way as usual. + +The following is an example GLSL fragment shader including anti-aliasing: + +```glsl +in vec2 pos; +out vec4 color; +uniform sampler2D msdf; +uniform vec4 bgColor; +uniform vec4 fgColor; + +float median(float r, float g, float b) { + return max(min(r, g), min(max(r, g), b)); +} + +void main() { + vec3 sample = texture(msdf, pos).rgb; + float sigDist = median(sample.r, sample.g, sample.b) - 0.5; + float opacity = clamp(sigDist/fwidth(sigDist) + 0.5, 0.0, 1.0); + color = mix(bgColor, fgColor, opacity); +} +``` + +## Shape description syntax + +The text shape description has the following syntax. + - Each closed contour is enclosed by braces: `{ } { }` + - Each point (and control point) is written as two real numbers separated by a comma. + - Points in a contour are separated with semicolons. + - The last point of each contour must be equal to the first, or the symbol `#` can be used, which represents the first point. + - There can be an edge segment specification between any two points, also separated by semicolons. + This can include the edge's color (`c`, `m`, or `y`) and/or one or two curve control points inside parentheses. + +For example, +``` +{ -1, -1; m; -1, +1; y; +1, +1; m; +1, -1; y; # } +``` +would represent a square with magenta and yellow edges, +``` +{ 0, 1; (+1.6, -0.8; -1.6, -0.8); # } +``` +is a teardrop shape formed by a single cubic Bézier curve. diff --git a/core/Bitmap.cpp b/core/Bitmap.cpp new file mode 100644 index 0000000..645aebc --- /dev/null +++ b/core/Bitmap.cpp @@ -0,0 +1,77 @@ + +#include "Bitmap.h" + +#include + +namespace msdfgen { + +template +Bitmap::Bitmap() : content(NULL), w(0), h(0) { } + +template +Bitmap::Bitmap(int width, int height) : w(width), h(height) { + content = new T[w*h]; +} + +template +Bitmap::Bitmap(const Bitmap &orig) : w(orig.w), h(orig.h) { + content = new T[w*h]; + memcpy(content, orig.content, w*h*sizeof(T)); +} + +#ifdef MSDFGEN_USE_CPP11 +template +Bitmap::Bitmap(Bitmap &&orig) : content(orig.content), w(orig.w), h(orig.h) { + orig.content = NULL; +} +#endif + +template +Bitmap::~Bitmap() { + delete [] content; +} + +template +Bitmap & Bitmap::operator=(const Bitmap &orig) { + delete [] content; + w = orig.w, h = orig.h; + content = new T[w*h]; + memcpy(content, orig.content, w*h*sizeof(T)); + return *this; +} + +#ifdef MSDFGEN_USE_CPP11 +template +Bitmap & Bitmap::operator=(Bitmap &&orig) { + delete [] content; + content = orig.content; + w = orig.w, h = orig.h; + orig.content = NULL; + return *this; +} +#endif + +template +int Bitmap::width() const { + return w; +} + +template +int Bitmap::height() const { + return h; +} + +template +T & Bitmap::operator()(int x, int y) { + return content[y*w+x]; +} + +template +const T & Bitmap::operator()(int x, int y) const { + return content[y*w+x]; +} + +template class Bitmap; +template class Bitmap; + +} diff --git a/core/Bitmap.h b/core/Bitmap.h new file mode 100644 index 0000000..6ae84ed --- /dev/null +++ b/core/Bitmap.h @@ -0,0 +1,40 @@ + +#pragma once + +namespace msdfgen { + +/// A floating-point RGB pixel. +struct FloatRGB { + float r, g, b; +}; + +/// A 2D image bitmap. +template +class Bitmap { + +public: + Bitmap(); + Bitmap(int width, int height); + Bitmap(const Bitmap &orig); +#ifdef MSDFGEN_USE_CPP11 + Bitmap(Bitmap &&orig); +#endif + ~Bitmap(); + Bitmap & operator=(const Bitmap &orig); +#ifdef MSDFGEN_USE_CPP11 + Bitmap & operator=(Bitmap &&orig); +#endif + /// Bitmap width in pixels. + int width() const; + /// Bitmap height in pixels. + int height() const; + T & operator()(int x, int y); + const T & operator()(int x, int y) const; + +private: + T *content; + int w, h; + +}; + +} diff --git a/core/Contour.cpp b/core/Contour.cpp new file mode 100644 index 0000000..f34736f --- /dev/null +++ b/core/Contour.cpp @@ -0,0 +1,26 @@ + +#include "Contour.h" + +namespace msdfgen { + +void Contour::addEdge(const EdgeHolder &edge) { + edges.push_back(edge); +} + +#ifdef MSDFGEN_USE_CPP11 +void Contour::addEdge(EdgeHolder &&edge) { + edges.push_back((EdgeHolder &&) edge); +} +#endif + +EdgeHolder & Contour::addEdge() { + edges.resize(edges.size()+1); + return edges[edges.size()-1]; +} + +void Contour::bounds(double &l, double &b, double &r, double &t) const { + for (std::vector::const_iterator edge = edges.begin(); edge != edges.end(); ++edge) + (*edge)->bounds(l, b, r, t); +} + +} diff --git a/core/Contour.h b/core/Contour.h new file mode 100644 index 0000000..ba7e7e6 --- /dev/null +++ b/core/Contour.h @@ -0,0 +1,28 @@ + +#pragma once + +#include +#include "EdgeHolder.h" + +namespace msdfgen { + +/// A single closed contour of a shape. +class Contour { + +public: + /// The sequence of edges that make up the contour. + std::vector edges; + + /// Adds an edge to the contour. + void addEdge(const EdgeHolder &edge); +#ifdef MSDFGEN_USE_CPP11 + void addEdge(EdgeHolder &&edge); +#endif + /// Creates a new edge in the contour and returns its reference. + EdgeHolder & addEdge(); + /// Computes the bounding box of the contour. + void bounds(double &l, double &b, double &r, double &t) const; + +}; + +} diff --git a/core/EdgeColor.h b/core/EdgeColor.h new file mode 100644 index 0000000..9d49a5a --- /dev/null +++ b/core/EdgeColor.h @@ -0,0 +1,18 @@ + +#pragma once + +namespace msdfgen { + +/// Edge color specifies which color channels an edge belongs to. +enum EdgeColor { + BLACK = 0, + RED = 1, + GREEN = 2, + YELLOW = 3, + BLUE = 4, + MAGENTA = 5, + CYAN = 6, + WHITE = 7 +}; + +} diff --git a/core/EdgeHolder.cpp b/core/EdgeHolder.cpp new file mode 100644 index 0000000..581dff4 --- /dev/null +++ b/core/EdgeHolder.cpp @@ -0,0 +1,67 @@ + +#include "EdgeHolder.h" + +namespace msdfgen { + +EdgeHolder::EdgeHolder() : edgeSegment(NULL) { } + +EdgeHolder::EdgeHolder(EdgeSegment *segment) : edgeSegment(segment) { } + +EdgeHolder::EdgeHolder(Point2 p0, Point2 p1, EdgeColor edgeColor) : edgeSegment(new LinearSegment(p0, p1, edgeColor)) { } + +EdgeHolder::EdgeHolder(Point2 p0, Point2 p1, Point2 p2, EdgeColor edgeColor) : edgeSegment(new QuadraticSegment(p0, p1, p2, edgeColor)) { } + +EdgeHolder::EdgeHolder(Point2 p0, Point2 p1, Point2 p2, Point2 p3, EdgeColor edgeColor) : edgeSegment(new CubicSegment(p0, p1, p2, p3, edgeColor)) { } + +EdgeHolder::EdgeHolder(const EdgeHolder &orig) : edgeSegment(orig.edgeSegment ? orig.edgeSegment->clone() : NULL) { } + +#ifdef MSDFGEN_USE_CPP11 +EdgeHolder::EdgeHolder(EdgeHolder &&orig) : edgeSegment(orig.edgeSegment) { + orig.edgeSegment = NULL; +} +#endif + +EdgeHolder::~EdgeHolder() { + delete edgeSegment; +} + +EdgeHolder & EdgeHolder::operator=(const EdgeHolder &orig) { + delete edgeSegment; + edgeSegment = orig.edgeSegment ? orig.edgeSegment->clone() : NULL; + return *this; +} + +#ifdef MSDFGEN_USE_CPP11 +EdgeHolder & EdgeHolder::operator=(EdgeHolder &&orig) { + delete edgeSegment; + edgeSegment = orig.edgeSegment; + orig.edgeSegment = NULL; + return *this; +} +#endif + +EdgeSegment & EdgeHolder::operator*() { + return *edgeSegment; +} + +const EdgeSegment & EdgeHolder::operator*() const { + return *edgeSegment; +} + +EdgeSegment * EdgeHolder::operator->() { + return edgeSegment; +} + +const EdgeSegment * EdgeHolder::operator->() const { + return edgeSegment; +} + +EdgeHolder::operator EdgeSegment *() { + return edgeSegment; +} + +EdgeHolder::operator const EdgeSegment *() const { + return edgeSegment; +} + +} diff --git a/core/EdgeHolder.h b/core/EdgeHolder.h new file mode 100644 index 0000000..427de02 --- /dev/null +++ b/core/EdgeHolder.h @@ -0,0 +1,38 @@ + +#pragma once + +#include "edge-segments.h" + +namespace msdfgen { + +/// Container for a single edge of dynamic type. +class EdgeHolder { + +public: + EdgeHolder(); + EdgeHolder(EdgeSegment *segment); + EdgeHolder(Point2 p0, Point2 p1, EdgeColor edgeColor = WHITE); + EdgeHolder(Point2 p0, Point2 p1, Point2 p2, EdgeColor edgeColor = WHITE); + EdgeHolder(Point2 p0, Point2 p1, Point2 p2, Point2 p3, EdgeColor edgeColor = WHITE); + EdgeHolder(const EdgeHolder &orig); +#ifdef MSDFGEN_USE_CPP11 + EdgeHolder(EdgeHolder &&orig); +#endif + ~EdgeHolder(); + EdgeHolder & operator=(const EdgeHolder &orig); +#ifdef MSDFGEN_USE_CPP11 + EdgeHolder & operator=(EdgeHolder &&orig); +#endif + EdgeSegment & operator*(); + const EdgeSegment & operator*() const; + EdgeSegment * operator->(); + const EdgeSegment * operator->() const; + operator EdgeSegment *(); + operator const EdgeSegment *() const; + +private: + EdgeSegment *edgeSegment; + +}; + +} diff --git a/core/Shape.cpp b/core/Shape.cpp new file mode 100644 index 0000000..fc4050d --- /dev/null +++ b/core/Shape.cpp @@ -0,0 +1,56 @@ + +#include "Shape.h" + +namespace msdfgen { + +Shape::Shape() : inverseYAxis(false) { } + +void Shape::addContour(const Contour &contour) { + contours.push_back(contour); +} + +#ifdef MSDFGEN_USE_CPP11 +void Shape::addContour(Contour &&contour) { + contours.push_back((Contour &&) contour); +} +#endif + +Contour & Shape::addContour() { + contours.resize(contours.size()+1); + return contours[contours.size()-1]; +} + +bool Shape::validate() const { + for (std::vector::const_iterator contour = contours.begin(); contour != contours.end(); ++contour) { + if (!contour->edges.empty()) { + Point2 corner = (*(contour->edges.end()-1))->point(1); + for (std::vector::const_iterator edge = contour->edges.begin(); edge != contour->edges.end(); ++edge) { + if (!*edge) + return false; + if ((*edge)->point(0) != corner) + return false; + corner = (*edge)->point(1); + } + } + } + return true; +} + +void Shape::normalize() { + for (std::vector::iterator contour = contours.begin(); contour != contours.end(); ++contour) + if (contour->edges.size() == 1) { + EdgeSegment *parts[3] = { }; + contour->edges[0]->splitInThirds(parts[0], parts[1], parts[2]); + contour->edges.clear(); + contour->edges.push_back(EdgeHolder(parts[0])); + contour->edges.push_back(EdgeHolder(parts[1])); + contour->edges.push_back(EdgeHolder(parts[2])); + } +} + +void Shape::bounds(double &l, double &b, double &r, double &t) const { + for (std::vector::const_iterator contour = contours.begin(); contour != contours.end(); ++contour) + contour->bounds(l, b, r, t); +} + +} diff --git a/core/Shape.h b/core/Shape.h new file mode 100644 index 0000000..0c12541 --- /dev/null +++ b/core/Shape.h @@ -0,0 +1,35 @@ + +#pragma once + +#include +#include "Contour.h" + +namespace msdfgen { + +/// Vector shape representation. +class Shape { + +public: + /// The list of contours the shape consists of. + std::vector contours; + /// Specifies whether the shape uses bottom-to-top (false) or top-to-bottom (true) Y coordinates. + bool inverseYAxis; + + Shape(); + /// Adds a contour. + void addContour(const Contour &contour); +#ifdef MSDFGEN_USE_CPP11 + void addContour(Contour &&contour); +#endif + /// Adds a blank contour and returns its reference. + Contour & addContour(); + /// Normalizes the shape geometry for distance field generation. + void normalize(); + /// Performs basic checks to determine if the object represents a valid shape. + bool validate() const; + /// Computes the shape's bounding box. + void bounds(double &l, double &b, double &r, double &t) const; + +}; + +} diff --git a/core/SignedDistance.cpp b/core/SignedDistance.cpp new file mode 100644 index 0000000..18c9d2c --- /dev/null +++ b/core/SignedDistance.cpp @@ -0,0 +1,30 @@ + +#include "SignedDistance.h" + +#include + +namespace msdfgen { + +const SignedDistance SignedDistance::INFINITE(-1e240, 1); + +SignedDistance::SignedDistance() : distance(-1e240), dot(1) { } + +SignedDistance::SignedDistance(double dist, double d) : distance(dist), dot(d) { } + +bool operator<(SignedDistance a, SignedDistance b) { + return fabs(a.distance) < fabs(b.distance) || (fabs(a.distance) == fabs(b.distance) && a.dot < b.dot); +} + +bool operator>(SignedDistance a, SignedDistance b) { + return fabs(a.distance) > fabs(b.distance) || (fabs(a.distance) == fabs(b.distance) && a.dot > b.dot); +} + +bool operator<=(SignedDistance a, SignedDistance b) { + return fabs(a.distance) < fabs(b.distance) || (fabs(a.distance) == fabs(b.distance) && a.dot <= b.dot); +} + +bool operator>=(SignedDistance a, SignedDistance b) { + return fabs(a.distance) > fabs(b.distance) || (fabs(a.distance) == fabs(b.distance) && a.dot >= b.dot); +} + +} diff --git a/core/SignedDistance.h b/core/SignedDistance.h new file mode 100644 index 0000000..034210f --- /dev/null +++ b/core/SignedDistance.h @@ -0,0 +1,25 @@ + +#pragma once + +namespace msdfgen { + +/// Represents a signed distance and alignment, which together can be compared to uniquely determine the closest edge segment. +class SignedDistance { + +public: + static const SignedDistance INFINITE; + + double distance; + double dot; + + SignedDistance(); + SignedDistance(double dist, double d); + + friend bool operator<(SignedDistance a, SignedDistance b); + friend bool operator>(SignedDistance a, SignedDistance b); + friend bool operator<=(SignedDistance a, SignedDistance b); + friend bool operator>=(SignedDistance a, SignedDistance b); + +}; + +} diff --git a/core/Vector2.cpp b/core/Vector2.cpp new file mode 100644 index 0000000..896963f --- /dev/null +++ b/core/Vector2.cpp @@ -0,0 +1,146 @@ + +#include "Vector2.h" + +namespace msdfgen { + +Vector2::Vector2(double val) : x(val), y(val) { } + +Vector2::Vector2(double x, double y) : x(x), y(y) { } + +void Vector2::reset() { + x = 0, y = 0; +} + +void Vector2::set(double x, double y) { + Vector2::x = x, Vector2::y = y; +} + +double Vector2::length() const { + return sqrt(x*x+y*y); +} + +double Vector2::direction() const { + return atan2(y, x); +} + +Vector2 Vector2::normalize(bool allowZero) const { + double len = length(); + if (len == 0) + return Vector2(0, !allowZero); + return Vector2(x/len, y/len); +} + +Vector2 Vector2::getOrthogonal(bool polarity) const { + return polarity ? Vector2(-y, x) : Vector2(y, -x); +} + +Vector2 Vector2::getOrthonormal(bool polarity, bool allowZero) const { + double len = length(); + if (len == 0) + return polarity ? Vector2(0, !allowZero) : Vector2(0, -!allowZero); + return polarity ? Vector2(-y/len, x/len) : Vector2(y/len, -x/len); +} + +Vector2 Vector2::project(const Vector2 &vector, bool positive) const { + Vector2 n = normalize(true); + double t = dotProduct(vector, n); + if (positive && t <= 0) + return Vector2(); + return t*n; +} + +Vector2::operator const void*() const { + return x || y ? this : NULL; +} + +bool Vector2::operator!() const { + return !x && !y; +} + +bool Vector2::operator==(const Vector2 &other) const { + return x == other.x && y == other.y; +} + +bool Vector2::operator!=(const Vector2 &other) const { + return x != other.x || y != other.y; +} + +Vector2 Vector2::operator+() const { + return *this; +} + +Vector2 Vector2::operator-() const { + return Vector2(-x, -y); +} + +Vector2 Vector2::operator+(const Vector2 &other) const { + return Vector2(x+other.x, y+other.y); +} + +Vector2 Vector2::operator-(const Vector2 &other) const { + return Vector2(x-other.x, y-other.y); +} + +Vector2 Vector2::operator*(const Vector2 &other) const { + return Vector2(x*other.x, y*other.y); +} + +Vector2 Vector2::operator/(const Vector2 &other) const { + return Vector2(x/other.x, y/other.y); +} + +Vector2 Vector2::operator*(double value) const { + return Vector2(x*value, y*value); +} + +Vector2 Vector2::operator/(double value) const { + return Vector2(x/value, y/value); +} + +Vector2 & Vector2::operator+=(const Vector2 &other) { + x += other.x, y += other.y; + return *this; +} + +Vector2 & Vector2::operator-=(const Vector2 &other) { + x -= other.x, y -= other.y; + return *this; +} + +Vector2 & Vector2::operator*=(const Vector2 &other) { + x *= other.x, y *= other.y; + return *this; +} + +Vector2 & Vector2::operator/=(const Vector2 &other) { + x /= other.x, y /= other.y; + return *this; +} + +Vector2 & Vector2::operator*=(double value) { + x *= value, y *= value; + return *this; +} + +Vector2 & Vector2::operator/=(double value) { + x /= value, y /= value; + return *this; +} + +double dotProduct(const Vector2 &a, const Vector2 &b) { + return a.x*b.x+a.y*b.y; +} + +double crossProduct(const Vector2 &a, const Vector2 &b) { + return a.x*b.y-a.y*b.x; +} + +Vector2 operator*(double value, const Vector2 &vector) { + return Vector2(value*vector.x, value*vector.y); +} + +Vector2 operator/(double value, const Vector2 &vector) { + return Vector2(value/vector.x, value/vector.y); +} + +} diff --git a/core/Vector2.h b/core/Vector2.h new file mode 100644 index 0000000..47ca637 --- /dev/null +++ b/core/Vector2.h @@ -0,0 +1,66 @@ + +#pragma once + +#include +#include + +namespace msdfgen { + +/** +* A 2-dimensional euclidean vector with double precision. +* Implementation based on the Vector2 template from Artery Engine. +* @author Viktor Chlumsky +*/ +struct Vector2 { + + double x, y; + + Vector2(double val = 0); + Vector2(double x, double y); + /// Sets the vector to zero. + void reset(); + /// Sets individual elements of the vector. + void set(double x, double y); + /// Returns the vector's length. + double length() const; + /// Returns the angle of the vector in radians (atan2). + double direction() const; + /// Returns the normalized vector - one that has the same direction but unit length. + Vector2 normalize(bool allowZero = false) const; + /// Returns a vector with the same length that is orthogonal to this one. + Vector2 getOrthogonal(bool polarity = true) const; + /// Returns a vector with unit length that is orthogonal to this one. + Vector2 getOrthonormal(bool polarity = true, bool allowZero = false) const; + /// Returns a vector projected along this one. + Vector2 project(const Vector2 &vector, bool positive = false) const; + operator const void *() const; + bool operator!() const; + bool operator==(const Vector2 &other) const; + bool operator!=(const Vector2 &other) const; + Vector2 operator+() const; + Vector2 operator-() const; + Vector2 operator+(const Vector2 &other) const; + Vector2 operator-(const Vector2 &other) const; + Vector2 operator*(const Vector2 &other) const; + Vector2 operator/(const Vector2 &other) const; + Vector2 operator*(double value) const; + Vector2 operator/(double value) const; + Vector2 & operator+=(const Vector2 &other); + Vector2 & operator-=(const Vector2 &other); + Vector2 & operator*=(const Vector2 &other); + Vector2 & operator/=(const Vector2 &other); + Vector2 & operator*=(double value); + Vector2 & operator/=(double value); + /// Dot product of two vectors. + friend double dotProduct(const Vector2 &a, const Vector2 &b); + /// A special version of the cross product for 2D vectors (returns scalar value). + friend double crossProduct(const Vector2 &a, const Vector2 &b); + friend Vector2 operator*(double value, const Vector2 &vector); + friend Vector2 operator/(double value, const Vector2 &vector); + +}; + +/// A vector may also represent a point, which shall be differentiated semantically using the alias Point2. +typedef Vector2 Point2; + +} diff --git a/core/arithmetics.hpp b/core/arithmetics.hpp new file mode 100644 index 0000000..8ec62f1 --- /dev/null +++ b/core/arithmetics.hpp @@ -0,0 +1,57 @@ + +#pragma once + +#include +#include + +namespace msdfgen { + +/// Returns the smaller of the arguments. +template +inline T min(T a, T b) { + return b < a ? b : a; +} + +/// Returns the larger of the arguments. +template +inline T max(T a, T b) { + return a < b ? b : a; +} + +/// Returns the middle out of three values +template +inline T median(T a, T b, T c) { + return max(min(a, b), min(max(a, b), c)); +} + +/// Returns the weighted average of a and b. +template +inline T mix(T a, T b, S weight) { + return T((S(1)-weight)*a+weight*b); +} + +/// Clamps the number to the interval from 0 to 1. +template +inline T clamp(T n) { + return n >= T(0) && n <= T(1) ? n : T(n > T(0)); +} + +/// Clamps the number to the interval from 0 to b. +template +inline T clamp(T n, T b) { + return n >= T(0) && n <= b ? n : T(n > T(0))*b; +} + +/// Clamps the number to the interval from a to b. +template +inline T clamp(T n, T a, T b) { + return n >= a && n <= b ? n : n < a ? a : b; +} + +/// Returns 1 for non-negative values and -1 for negative values. +template +inline int nonZeroSign(T n) { + return 2*(n > T(0))-1; +} + +} diff --git a/core/edge-coloring.cpp b/core/edge-coloring.cpp new file mode 100644 index 0000000..2978d89 --- /dev/null +++ b/core/edge-coloring.cpp @@ -0,0 +1,75 @@ + +#include "edge-coloring.h" + +namespace msdfgen { + +static bool isCorner(const Vector2 &aDir, const Vector2 &bDir, double crossThreshold) { + return dotProduct(aDir, bDir) <= 0 || fabs(crossProduct(aDir, bDir)) > crossThreshold; +} + +void edgeColoringSimple(Shape &shape, double angleThreshold) { + double crossThreshold = sin(angleThreshold); + std::vector corners; + for (std::vector::iterator contour = shape.contours.begin(); contour != shape.contours.end(); ++contour) { + // Identify corners + corners.clear(); + if (!contour->edges.empty()) { + Vector2 prevDirection = (*(contour->edges.end()-1))->direction(1); + int index = 0; + for (std::vector::const_iterator edge = contour->edges.begin(); edge != contour->edges.end(); ++edge, ++index) { + if (isCorner(prevDirection.normalize(), (*edge)->direction(0).normalize(), crossThreshold)) + corners.push_back(index); + prevDirection = (*edge)->direction(1); + } + } + + // Smooth contour + if (corners.empty()) + for (std::vector::iterator edge = contour->edges.begin(); edge != contour->edges.end(); ++edge) + (*edge)->color = WHITE; + // "Teardrop" case + else if (corners.size() == 1) { + const EdgeColor colors[] = { MAGENTA, WHITE, YELLOW }; + int corner = corners[0]; + if (contour->edges.size() >= 3) { + int m = contour->edges.size(); + for (int i = 0; i < m; ++i) + contour->edges[(corner+i)%m]->color = (colors+1)[int(3+2.875*i/(m-1)-1.4375+.5)-3]; + } else if (contour->edges.size() >= 1) { + // Less than three edge segments for three colors => edges must be split + EdgeSegment *parts[7] = { }; + contour->edges[0]->splitInThirds(parts[0+3*corner], parts[1+3*corner], parts[2+3*corner]); + if (contour->edges.size() >= 2) { + contour->edges[1]->splitInThirds(parts[3-3*corner], parts[4-3*corner], parts[5-3*corner]); + parts[0]->color = parts[1]->color = colors[0]; + parts[2]->color = parts[3]->color = colors[1]; + parts[4]->color = parts[5]->color = colors[2]; + } else { + parts[0]->color = colors[0]; + parts[1]->color = colors[1]; + parts[2]->color = colors[2]; + } + contour->edges.clear(); + for (int i = 0; parts[i]; ++i) + contour->edges.push_back(EdgeHolder(parts[i])); + } + } + // Multiple corners + else { + int cornerCount = corners.size(); + // CMYCMYCMYCMY / YMYCMYC if corner count % 3 == 1 + EdgeColor colors[] = { cornerCount%3 == 1 ? YELLOW : CYAN, CYAN, MAGENTA, YELLOW }; + int spline = 0; + int start = corners[0]; + int m = contour->edges.size(); + for (int i = 0; i < m; ++i) { + int index = (start+i)%m; + if (cornerCount > spline+1 && corners[spline+1] == index) + ++spline; + contour->edges[index]->color = (colors+1)[spline%3-!spline]; + } + } + } +} + +} diff --git a/core/edge-coloring.h b/core/edge-coloring.h new file mode 100644 index 0000000..4193015 --- /dev/null +++ b/core/edge-coloring.h @@ -0,0 +1,15 @@ + +#pragma once + +#include "Shape.h" + +namespace msdfgen { + +/** Assigns colors to edges of the shape in accordance to the multi-channel distance field technique. + * May split some edges if necessary. + * angleThreshold specifies the maximum angle (in radians) to be considered a corner, for example 3 (~172 degrees). + * Values below 1/2 PI will be treated as the external angle. + */ +void edgeColoringSimple(Shape &shape, double angleThreshold); + +} diff --git a/core/edge-segments.cpp b/core/edge-segments.cpp new file mode 100644 index 0000000..eb21c0e --- /dev/null +++ b/core/edge-segments.cpp @@ -0,0 +1,334 @@ + +#include "edge-segments.h" + +#include "arithmetics.hpp" +#include "equation-solver.h" + +namespace msdfgen { + +void EdgeSegment::distanceToPseudoDistance(SignedDistance &distance, Point2 origin, double param) const { + if (param < 0) { + Vector2 dir = direction(0).normalize(); + Vector2 aq = origin-point(0); + double ts = dotProduct(aq, dir); + if (ts < 0) { + double pseudoDistance = crossProduct(aq, dir); + if (fabs(pseudoDistance) <= fabs(distance.distance)) { + distance.distance = pseudoDistance; + distance.dot = 0; + } + } + } else if (param > 1) { + Vector2 dir = direction(1).normalize(); + Vector2 bq = origin-point(1); + double ts = dotProduct(bq, dir); + if (ts > 0) { + double pseudoDistance = crossProduct(bq, dir); + if (fabs(pseudoDistance) <= fabs(distance.distance)) { + distance.distance = pseudoDistance; + distance.dot = 0; + } + } + } +} + +LinearSegment::LinearSegment(Point2 p0, Point2 p1, EdgeColor edgeColor) : EdgeSegment(edgeColor) { + p[0] = p0; + p[1] = p1; +} + +QuadraticSegment::QuadraticSegment(Point2 p0, Point2 p1, Point2 p2, EdgeColor edgeColor) : EdgeSegment(edgeColor) { + p[0] = p0; + p[1] = p1; + p[2] = p2; +} + +CubicSegment::CubicSegment(Point2 p0, Point2 p1, Point2 p2, Point2 p3, EdgeColor edgeColor) : EdgeSegment(edgeColor) { + p[0] = p0; + p[1] = p1; + p[2] = p2; + p[3] = p3; +} + +LinearSegment * LinearSegment::clone() const { + return new LinearSegment(p[0], p[1], color); +} + +QuadraticSegment * QuadraticSegment::clone() const { + return new QuadraticSegment(p[0], p[1], p[2], color); +} + +CubicSegment * CubicSegment::clone() const { + return new CubicSegment(p[0], p[1], p[2], p[3], color); +} + +Point2 LinearSegment::point(double param) const { + return mix(p[0], p[1], param); +} + +Point2 QuadraticSegment::point(double param) const { + return mix(mix(p[0], p[1], param), mix(p[1], p[2], param), param); +} + +Point2 CubicSegment::point(double param) const { + Vector2 p12 = mix(p[1], p[2], param); + return mix(mix(mix(p[0], p[1], param), p12, param), mix(p12, mix(p[2], p[3], param), param), param); +} + +Vector2 LinearSegment::direction(double param) const { + return p[1]-p[0]; +} + +Vector2 QuadraticSegment::direction(double param) const { + return mix(p[1]-p[0], p[2]-p[1], param); +} + +Vector2 CubicSegment::direction(double param) const { + return mix(mix(p[1]-p[0], p[2]-p[1], param), mix(p[2]-p[1], p[3]-p[2], param), param); +} + +SignedDistance LinearSegment::signedDistance(Point2 origin, double ¶m) const { + Vector2 aq = origin-p[0]; + Vector2 ab = p[1]-p[0]; + param = dotProduct(aq, ab)/dotProduct(ab, ab); + Vector2 eq = p[param > .5]-origin; + double endpointDistance = eq.length(); + if (param > 0 && param < 1) { + double orthoDistance = dotProduct(ab.getOrthonormal(false), aq); + if (fabs(orthoDistance) < endpointDistance) + return SignedDistance(orthoDistance, 0); + } + return SignedDistance(nonZeroSign(crossProduct(aq, ab))*endpointDistance, fabs(dotProduct(ab.normalize(), eq.normalize()))); +} + +SignedDistance QuadraticSegment::signedDistance(Point2 origin, double ¶m) const { + Vector2 qa = p[0]-origin; + Vector2 ab = p[1]-p[0]; + Vector2 br = p[0]+p[2]-p[1]-p[1]; + double a = dotProduct(br, br); + double b = 3*dotProduct(ab, br); + double c = 2*dotProduct(ab, ab)+dotProduct(qa, br); + double d = dotProduct(qa, ab); + double t[3]; + int solutions = solveCubic(t, a, b, c, d); + + double minDistance = nonZeroSign(crossProduct(ab, qa))*qa.length(); // distance from A + param = -dotProduct(qa, ab)/dotProduct(ab, ab); + { + double distance = nonZeroSign(crossProduct(p[2]-p[1], p[2]-origin))*(p[2]-origin).length(); // distance from B + if (fabs(distance) < fabs(minDistance)) { + minDistance = distance; + param = dotProduct(origin-p[1], p[2]-p[1])/dotProduct(p[2]-p[1], p[2]-p[1]); + } + } + for (int i = 0; i < solutions; ++i) { + if (t[i] > 0 && t[i] < 1) { + Point2 endpoint = p[0]+2*t[i]*ab+t[i]*t[i]*br; + double distance = nonZeroSign(crossProduct(p[2]-p[0], endpoint-origin))*(endpoint-origin).length(); + if (fabs(distance) <= fabs(minDistance)) { + minDistance = distance; + param = t[i]; + } + } + } + + if (param >= 0 && param <= 1) + return SignedDistance(minDistance, 0); + if (param < .5) + return SignedDistance(minDistance, fabs(dotProduct(ab.normalize(), qa.normalize()))); + else + return SignedDistance(minDistance, fabs(dotProduct((p[2]-p[1]).normalize(), (p[2]-origin).normalize()))); +} + +SignedDistance CubicSegment::signedDistance(Point2 origin, double ¶m) const { + Vector2 qa = p[0]-origin; + Vector2 ab = p[1]-p[0]; + Vector2 br = p[2]-p[1]-ab; + Vector2 as = (p[3]-p[2])-(p[2]-p[1])-br; + + double minDistance = nonZeroSign(crossProduct(ab, qa))*qa.length(); // distance from A + param = -dotProduct(qa, ab)/dotProduct(ab, ab); + { + double distance = nonZeroSign(crossProduct(p[3]-p[2], p[3]-origin))*(p[3]-origin).length(); // distance from B + if (fabs(distance) < fabs(minDistance)) { + minDistance = distance; + param = dotProduct(origin-p[2], p[3]-p[2])/dotProduct(p[3]-p[2], p[3]-p[2]); + } + } + // Iterative minimum distance search + for (int i = 0; i <= MSDFGEN_CUBIC_SEARCH_STARTS; ++i) { + double t = (double) i/MSDFGEN_CUBIC_SEARCH_STARTS; + for (int step = 0;; ++step) { + Vector2 qpt = point(t)-origin; + double distance = nonZeroSign(crossProduct(direction(t), qpt))*qpt.length(); + if (fabs(distance) < fabs(minDistance)) { + minDistance = distance; + param = t; + } + if (step == MSDFGEN_CUBIC_SEARCH_STEPS) + break; + // Improve t + Vector2 d1 = 3*as*t*t+6*br*t+3*ab; + Vector2 d2 = 6*as*t+6*br; + t -= dotProduct(qpt, d1)/(dotProduct(d1, d1)+dotProduct(qpt, d2)); + if (t < 0 || t > 1) + break; + } + } + + if (param >= 0 && param <= 1) + return SignedDistance(minDistance, 0); + if (param < .5) + return SignedDistance(minDistance, fabs(dotProduct(ab.normalize(), qa.normalize()))); + else + return SignedDistance(minDistance, fabs(dotProduct((p[3]-p[2]).normalize(), (p[3]-origin).normalize()))); +} + +// Original method by solving a fifth order polynomial +/*SignedDistance CubicSegment::signedDistance(Point2 origin, double ¶m) const { + Vector2 qa = p[0]-origin; + Vector2 ab = p[1]-p[0]; + Vector2 br = p[2]-p[1]-ab; + Vector2 as = (p[3]-p[2])-(p[2]-p[1])-br; + double a = dotProduct(as, as); + double b = 5*dotProduct(br, as); + double c = 4*dotProduct(ab, as)+6*dotProduct(br, br); + double d = 9*dotProduct(ab, br)+dotProduct(qa, as); + double e = 3*dotProduct(ab, ab)+2*dotProduct(qa, br); + double f = dotProduct(qa, ab); + double t[5]; + int solutions = solveQuintic(t, a, b, c, d, e, f); + + double minDistance = nonZeroSign(crossProduct(ab, qa))*qa.length(); // distance from A + param = -dotProduct(qa, ab)/dotProduct(ab, ab); + { + double distance = nonZeroSign(crossProduct(p[3]-p[2], p[3]-origin))*(p[3]-origin).length(); // distance from B + if (fabs(distance) < fabs(minDistance)) { + minDistance = distance; + param = dotProduct(origin-p[2], p[3]-p[2])/dotProduct(p[3]-p[2], p[3]-p[2]); + } + } + for (int i = 0; i < solutions; ++i) { + if (t[i] > 0 && t[i] < 1) { + Point2 endpoint = p[0]+3*t[i]*ab+3*t[i]*t[i]*br+t[i]*t[i]*t[i]*as; + Vector2 dirVec = t[i]*t[i]*as+2*t[i]*br+ab; + double distance = nonZeroSign(crossProduct(dirVec, endpoint-origin))*(endpoint-origin).length(); + if (fabs(distance) <= fabs(minDistance)) { + minDistance = distance; + param = t[i]; + } + } + } + + if (param >= 0 && param <= 1) + return SignedDistance(minDistance, 0); + if (param < .5) + return SignedDistance(minDistance, fabs(dotProduct(ab.normalize(), qa.normalize()))); + else + return SignedDistance(minDistance, fabs(dotProduct((p[3]-p[2]).normalize(), (p[3]-origin).normalize()))); +}*/ + +static void pointBounds(Point2 p, double &l, double &b, double &r, double &t) { + if (p.x < l) l = p.x; + if (p.y < b) b = p.y; + if (p.x > r) r = p.x; + if (p.y > t) t = p.y; +} + +void LinearSegment::bounds(double &l, double &b, double &r, double &t) const { + pointBounds(p[0], l, b, r, t); + pointBounds(p[1], l, b, r, t); +} + +void QuadraticSegment::bounds(double &l, double &b, double &r, double &t) const { + pointBounds(p[0], l, b, r, t); + pointBounds(p[2], l, b, r, t); + Vector2 bot = (p[1]-p[0])-(p[2]-p[1]); + if (bot.x) { + double param = (p[1].x-p[0].x)/bot.x; + if (param > 0 && param < 1) + pointBounds(point(param), l, b, r, t); + } + if (bot.y) { + double param = (p[1].y-p[0].y)/bot.y; + if (param > 0 && param < 1) + pointBounds(point(param), l, b, r, t); + } +} + +void CubicSegment::bounds(double &l, double &b, double &r, double &t) const { + pointBounds(p[0], l, b, r, t); + pointBounds(p[3], l, b, r, t); + Vector2 a0 = p[1]-p[0]; + Vector2 a1 = 2*(p[2]-p[1]-a0); + Vector2 a2 = p[3]-3*p[2]+3*p[1]-p[0]; + double params[2]; + int solutions; + solutions = solveQuadratic(params, a2.x, a1.x, a0.x); + for (int i = 0; i < solutions; ++i) + if (params[i] > 0 && params[i] < 1) + pointBounds(point(params[i]), l, b, r, t); + solutions = solveQuadratic(params, a2.y, a1.y, a0.y); + for (int i = 0; i < solutions; ++i) + if (params[i] > 0 && params[i] < 1) + pointBounds(point(params[i]), l, b, r, t); +} + +void LinearSegment::moveStartPoint(Point2 to) { + p[0] = to; +} + +void QuadraticSegment::moveStartPoint(Point2 to) { + Vector2 origSDir = p[0]-p[1]; + Point2 origP1 = p[1]; + p[1] += crossProduct(p[0]-p[1], to-p[0])/crossProduct(p[0]-p[1], p[2]-p[1])*(p[2]-p[1]); + p[0] = to; + if (dotProduct(origSDir, p[0]-p[1]) < 0) + p[1] = origP1; +} + +void CubicSegment::moveStartPoint(Point2 to) { + p[1] += to-p[0]; + p[0] = to; +} + +void LinearSegment::moveEndPoint(Point2 to) { + p[1] = to; +} + +void QuadraticSegment::moveEndPoint(Point2 to) { + Vector2 origEDir = p[2]-p[1]; + Point2 origP1 = p[1]; + p[1] += crossProduct(p[2]-p[1], to-p[2])/crossProduct(p[2]-p[1], p[0]-p[1])*(p[0]-p[1]); + p[2] = to; + if (dotProduct(origEDir, p[2]-p[1]) < 0) + p[1] = origP1; +} + +void CubicSegment::moveEndPoint(Point2 to) { + p[2] += to-p[3]; + p[3] = to; +} + +void LinearSegment::splitInThirds(EdgeSegment *&part1, EdgeSegment *&part2, EdgeSegment *&part3) const { + part1 = new LinearSegment(p[0], point(1/3.), color); + part2 = new LinearSegment(point(1/3.), point(2/3.), color); + part3 = new LinearSegment(point(2/3.), p[1], color); +} + +void QuadraticSegment::splitInThirds(EdgeSegment *&part1, EdgeSegment *&part2, EdgeSegment *&part3) const { + part1 = new QuadraticSegment(p[0], mix(p[0], p[1], 1/3.), point(1/3.), color); + part2 = new QuadraticSegment(point(1/3.), mix(mix(p[0], p[1], 5/9.), mix(p[1], p[2], 4/9.), .5), point(2/3.), color); + part3 = new QuadraticSegment(point(2/3.), mix(p[1], p[2], 2/3.), p[2], color); +} + +void CubicSegment::splitInThirds(EdgeSegment *&part1, EdgeSegment *&part2, EdgeSegment *&part3) const { + part1 = new CubicSegment(p[0], mix(p[0], p[1], 1/3.), mix(mix(p[0], p[1], 1/3.), mix(p[1], p[2], 1/3.), 1/3.), point(1/3.), color); + part2 = new CubicSegment(point(1/3.), + mix(mix(mix(p[0], p[1], 1/3.), mix(p[1], p[2], 1/3.), 1/3.), mix(mix(p[1], p[2], 1/3.), mix(p[2], p[3], 1/3.), 1/3.), 2/3.), + mix(mix(mix(p[0], p[1], 2/3.), mix(p[1], p[2], 2/3.), 2/3.), mix(mix(p[1], p[2], 2/3.), mix(p[2], p[3], 2/3.), 2/3.), 1/3.), + point(2/3.), color); + part3 = new CubicSegment(point(2/3.), mix(mix(p[1], p[2], 2/3.), mix(p[2], p[3], 2/3.), 2/3.), mix(p[2], p[3], 2/3.), p[3], color); +} + +} diff --git a/core/edge-segments.h b/core/edge-segments.h new file mode 100644 index 0000000..d201ab8 --- /dev/null +++ b/core/edge-segments.h @@ -0,0 +1,101 @@ + +#pragma once + +#include "Vector2.h" +#include "SignedDistance.h" +#include "EdgeColor.h" + +namespace msdfgen { + +// Parameters for iterative search of closest point on a cubic Bezier curve. Increase for higher precision. +#define MSDFGEN_CUBIC_SEARCH_STARTS 4 +#define MSDFGEN_CUBIC_SEARCH_STEPS 4 + +/// An abstract edge segment. +class EdgeSegment { + +public: + EdgeColor color; + + EdgeSegment(EdgeColor edgeColor = WHITE) : color(edgeColor) { } + virtual ~EdgeSegment() { } + /// Creates a copy of the edge segment. + virtual EdgeSegment * clone() const = 0; + /// Returns the point on the edge specified by the parameter (between 0 and 1). + virtual Point2 point(double param) const = 0; + /// Returns the direction the edge has at the point specified by the parameter. + virtual Vector2 direction(double param) const = 0; + /// Returns the minimum signed distance between origin and the edge. + virtual SignedDistance signedDistance(Point2 origin, double ¶m) const = 0; + /// Converts a previously retrieved signed distance from origin to pseudo-distance. + virtual void distanceToPseudoDistance(SignedDistance &distance, Point2 origin, double param) const; + /// Adjusts the bounding box to fit the edge segment. + virtual void bounds(double &l, double &b, double &r, double &t) const = 0; + + /// Moves the start point of the edge segment. + virtual void moveStartPoint(Point2 to) = 0; + /// Moves the end point of the edge segment. + virtual void moveEndPoint(Point2 to) = 0; + /// Splits the edge segments into thirds which together represent the original edge. + virtual void splitInThirds(EdgeSegment *&part1, EdgeSegment *&part2, EdgeSegment *&part3) const = 0; + +}; + +/// A line segment. +class LinearSegment : public EdgeSegment { + +public: + Point2 p[2]; + + LinearSegment(Point2 p0, Point2 p1, EdgeColor edgeColor = WHITE); + LinearSegment * clone() const; + Point2 point(double param) const; + Vector2 direction(double param) const; + SignedDistance signedDistance(Point2 origin, double ¶m) const; + void bounds(double &l, double &b, double &r, double &t) const; + + void moveStartPoint(Point2 to); + void moveEndPoint(Point2 to); + void splitInThirds(EdgeSegment *&part1, EdgeSegment *&part2, EdgeSegment *&part3) const; + +}; + +/// A quadratic Bezier curve. +class QuadraticSegment : public EdgeSegment { + +public: + Point2 p[3]; + + QuadraticSegment(Point2 p0, Point2 p1, Point2 p2, EdgeColor edgeColor = WHITE); + QuadraticSegment * clone() const; + Point2 point(double param) const; + Vector2 direction(double param) const; + SignedDistance signedDistance(Point2 origin, double ¶m) const; + void bounds(double &l, double &b, double &r, double &t) const; + + void moveStartPoint(Point2 to); + void moveEndPoint(Point2 to); + void splitInThirds(EdgeSegment *&part1, EdgeSegment *&part2, EdgeSegment *&part3) const; + +}; + +/// A cubic Bezier curve. +class CubicSegment : public EdgeSegment { + +public: + Point2 p[4]; + + CubicSegment(Point2 p0, Point2 p1, Point2 p2, Point2 p3, EdgeColor edgeColor = WHITE); + CubicSegment * clone() const; + Point2 point(double param) const; + Vector2 direction(double param) const; + SignedDistance signedDistance(Point2 origin, double ¶m) const; + void bounds(double &l, double &b, double &r, double &t) const; + + void moveStartPoint(Point2 to); + void moveEndPoint(Point2 to); + void splitInThirds(EdgeSegment *&part1, EdgeSegment *&part2, EdgeSegment *&part3) const; + +}; + +} diff --git a/core/equation-solver.cpp b/core/equation-solver.cpp new file mode 100644 index 0000000..769be30 --- /dev/null +++ b/core/equation-solver.cpp @@ -0,0 +1,69 @@ + +#include "equation-solver.h" + +#define _USE_MATH_DEFINES +#include + +namespace msdfgen { + +int solveQuadratic(double x[2], double a, double b, double c) { + if (fabs(a) < 1e-14) { + if (fabs(b) < 1e-14) { + if (c == 0) + return -1; + return 0; + } + x[0] = -c/b; + return 1; + } + double dscr = b*b-4*a*c; + if (dscr > 0) { + dscr = sqrt(dscr); + x[0] = (-b+dscr)/(2*a); + x[1] = (-b-dscr)/(2*a); + return 2; + } else if (dscr == 0) { + x[0] = -b/(2*a); + return 1; + } else + return 0; +} + +int solveCubicNormed(double *x, double a, double b, double c) { + double a2 = a*a; + double q = (a2 - 3*b)/9; + double r = (a*(2*a2-9*b) + 27*c)/54; + double r2 = r*r; + double q3 = q*q*q; + double A, B; + if (r2 < q3) { + double t = r/sqrt(q3); + if (t < -1) t = -1; + if (t > 1) t = 1; + t = acos(t); + a /= 3; q = -2*sqrt(q); + x[0] = q*cos(t/3)-a; + x[1] = q*cos((t+2*M_PI)/3)-a; + x[2] = q*cos((t-2*M_PI)/3)-a; + return 3; + } else { + A = -pow(fabs(r)+sqrt(r2-q3), 1/3.); + if (r < 0) A = -A; + B = A == 0 ? 0 : q/A; + a /= 3; + x[0] = (A+B)-a; + x[1] = -0.5*(A+B)-a; + x[2] = 0.5*sqrt(3.)*(A-B); + if (fabs(x[2]) < 1e-14) + return 2; + return 1; + } +} + +int solveCubic(double x[3], double a, double b, double c, double d) { + if (fabs(a) < 1e-14) + return solveQuadratic(x, b, c, d); + return solveCubicNormed(x, b/a, c/a, d/a); +} + +} diff --git a/core/equation-solver.h b/core/equation-solver.h new file mode 100644 index 0000000..6ebabe0 --- /dev/null +++ b/core/equation-solver.h @@ -0,0 +1,15 @@ + +#pragma once + +namespace msdfgen { + +// ax^2 + bx + c = 0 +int solveQuadratic(double x[2], double a, double b, double c); + +// ax^3 + bx^2 + cx + d = 0 +int solveCubic(double x[3], double a, double b, double c, double d); + +// ax^5 + bx^4 + cx^3 + dx^2 + ex + f = 0 +//int solveQuintic(double x[5], double a, double b, double c, double d, double e, double f); + +} diff --git a/core/msdfgen.cpp b/core/msdfgen.cpp new file mode 100644 index 0000000..0483c30 --- /dev/null +++ b/core/msdfgen.cpp @@ -0,0 +1,166 @@ + +#include "../msdfgen.h" + +#include "arithmetics.hpp" + +namespace msdfgen { + +void generateSDF(Bitmap &output, const Shape &shape, double range, const Vector2 &scale, const Vector2 &translate) { + int w = output.width(), h = output.height(); +#ifdef MSDFGEN_USE_OPENMP + #pragma omp parallel for +#endif + for (int y = 0; y < h; ++y) { + int row = shape.inverseYAxis ? h-y-1 : y; + for (int x = 0; x < w; ++x) { + double dummy; + Point2 p = Vector2(x+.5, y+.5)/scale-translate; + SignedDistance minDistance; + for (std::vector::const_iterator contour = shape.contours.begin(); contour != shape.contours.end(); ++contour) + for (std::vector::const_iterator edge = contour->edges.begin(); edge != contour->edges.end(); ++edge) { + SignedDistance distance = (*edge)->signedDistance(p, dummy); + if (distance < minDistance) + minDistance = distance; + } + output(x, row) = float(minDistance.distance/range+.5); + } + } +} + +void generatePseudoSDF(Bitmap &output, const Shape &shape, double range, const Vector2 &scale, const Vector2 &translate) { + int w = output.width(), h = output.height(); +#ifdef MSDFGEN_USE_OPENMP + #pragma omp parallel for +#endif + for (int y = 0; y < h; ++y) { + int row = shape.inverseYAxis ? h-y-1 : y; + for (int x = 0; x < w; ++x) { + Point2 p = Vector2(x+.5, y+.5)/scale-translate; + SignedDistance minDistance; + const EdgeHolder *nearEdge = NULL; + double nearParam = 0; + for (std::vector::const_iterator contour = shape.contours.begin(); contour != shape.contours.end(); ++contour) + for (std::vector::const_iterator edge = contour->edges.begin(); edge != contour->edges.end(); ++edge) { + double param; + SignedDistance distance = (*edge)->signedDistance(p, param); + if (distance < minDistance) { + minDistance = distance; + nearEdge = &*edge; + nearParam = param; + } + } + if (nearEdge) + (*nearEdge)->distanceToPseudoDistance(minDistance, p, nearParam); + output(x, row) = float(minDistance.distance/range+.5); + } + } +} + +static inline bool pixelClash(const FloatRGB &a, const FloatRGB &b, double threshold) { + // Only consider pair where both are on the inside or both are on the outside + bool aIn = (a.r > .5f)+(a.g > .5f)+(a.b > .5f) >= 2; + bool bIn = (b.r > .5f)+(b.g > .5f)+(b.b > .5f) >= 2; + if (aIn != bIn) return false; + // If the change is 0 <-> 1 or 2 <-> 3 channels and not 1 <-> 1 or 2 <-> 2, it is not a clash + if ((a.r > .5f && a.g > .5f && a.b > .5f) || (a.r < .5f && a.g < .5f && a.b < .5f) + || (b.r > .5f && b.g > .5f && b.b > .5f) || (b.r < .5f && b.g < .5f && b.b < .5f)) + return false; + // Find which color is which: _a, _b = the changing channels, _c = the remaining one + float aa, ab, ba, bb, ac, bc; + if ((a.r > .5f) != (b.r > .5f) && (a.r < .5f) != (b.r < .5f)) { + aa = a.r, ba = b.r; + if ((a.g > .5f) != (b.g > .5f) && (a.g < .5f) != (b.g < .5f)) { + ab = a.g, bb = b.g; + ac = a.b, bc = b.b; + } else if ((a.b > .5f) != (b.b > .5f) && (a.b < .5f) != (b.b < .5f)) { + ab = a.b, bb = b.b; + ac = a.g, bc = b.g; + } else + return false; // this should never happen + } else if ((a.g > .5f) != (b.g > .5f) && (a.g < .5f) != (b.g < .5f) + && (a.b > .5f) != (b.b > .5f) && (a.b < .5f) != (b.b < .5f)) { + aa = a.g, ba = b.g; + ab = a.b, bb = b.b; + ac = a.r, bc = b.r; + } else + return false; + // Find if the channels are in fact discontinuous + return (fabsf(aa-ba) >= threshold) + && (fabsf(ab-bb) >= threshold) + && fabsf(ac-.5f) >= fabsf(bc-.5f); // Out of the pair, only flag the pixel farther from a shape edge +} + +void msdfErrorCorrection(Bitmap &output, const Vector2 &threshold) { + std::vector > clashes; + int w = output.width(), h = output.height(); + for (int y = 0; y < h; ++y) + for (int x = 0; x < w; ++x) { + if ((x > 0 && pixelClash(output(x, y), output(x-1, y), threshold.x)) + || (x < w-1 && pixelClash(output(x, y), output(x+1, y), threshold.x)) + || (y > 0 && pixelClash(output(x, y), output(x, y-1), threshold.y)) + || (y < h-1 && pixelClash(output(x, y), output(x, y+1), threshold.y))) + clashes.push_back(std::make_pair(x, y)); + } + for (std::vector >::const_iterator clash = clashes.begin(); clash != clashes.end(); ++clash) { + FloatRGB &pixel = output(clash->first, clash->second); + float med = median(pixel.r, pixel.g, pixel.b); + pixel.r = med, pixel.g = med, pixel.b = med; + } +} + +void generateMSDF(Bitmap &output, const Shape &shape, double range, const Vector2 &scale, const Vector2 &translate, double edgeThreshold) { + int w = output.width(), h = output.height(); +#ifdef MSDFGEN_USE_OPENMP + #pragma omp parallel for +#endif + for (int y = 0; y < h; ++y) { + int row = shape.inverseYAxis ? h-y-1 : y; + for (int x = 0; x < w; ++x) { + Point2 p = Vector2(x+.5, y+.5)/scale-translate; + + struct { + SignedDistance minDistance; + const EdgeHolder *nearEdge; + double nearParam; + } r, g, b; + r.nearEdge = g.nearEdge = b.nearEdge = NULL; + r.nearParam = g.nearParam = b.nearParam = 0; + + for (std::vector::const_iterator contour = shape.contours.begin(); contour != shape.contours.end(); ++contour) + for (std::vector::const_iterator edge = contour->edges.begin(); edge != contour->edges.end(); ++edge) { + double param; + SignedDistance distance = (*edge)->signedDistance(p, param); + if ((*edge)->color&RED && distance < r.minDistance) { + r.minDistance = distance; + r.nearEdge = &*edge; + r.nearParam = param; + } + if ((*edge)->color&GREEN && distance < g.minDistance) { + g.minDistance = distance; + g.nearEdge = &*edge; + g.nearParam = param; + } + if ((*edge)->color&BLUE && distance < b.minDistance) { + b.minDistance = distance; + b.nearEdge = &*edge; + b.nearParam = param; + } + } + + if (r.nearEdge) + (*r.nearEdge)->distanceToPseudoDistance(r.minDistance, p, r.nearParam); + if (g.nearEdge) + (*g.nearEdge)->distanceToPseudoDistance(g.minDistance, p, g.nearParam); + if (b.nearEdge) + (*b.nearEdge)->distanceToPseudoDistance(b.minDistance, p, b.nearParam); + output(x, row).r = float(r.minDistance.distance/range+.5); + output(x, row).g = float(g.minDistance.distance/range+.5); + output(x, row).b = float(b.minDistance.distance/range+.5); + } + } + + if (edgeThreshold > 0) + msdfErrorCorrection(output, edgeThreshold/(scale*range)); +} + +} diff --git a/core/render-sdf.cpp b/core/render-sdf.cpp new file mode 100644 index 0000000..2943736 --- /dev/null +++ b/core/render-sdf.cpp @@ -0,0 +1,107 @@ + +#include "render-sdf.h" + +#include "arithmetics.hpp" + +namespace msdfgen { + +template +inline FloatRGB mix(FloatRGB a, FloatRGB b, S weight) { + FloatRGB output = { + mix(a.r, b.r, weight), + mix(a.g, b.g, weight), + mix(a.b, b.b, weight) + }; + return output; +} + +template +static T sample(const Bitmap &bitmap, Point2 pos) { + int w = bitmap.width(), h = bitmap.height(); + double x = pos.x*w-.5; + double y = pos.y*h-.5; + int l = (int) floor(x); + int b = (int) floor(y); + int r = l+1; + int t = b+1; + double lr = x-l; + double bt = y-b; + l = clamp(l, w-1), r = clamp(r, w-1); + b = clamp(b, h-1), t = clamp(t, h-1); + return mix(mix(bitmap(l, b), bitmap(r, b), lr), mix(bitmap(l, t), bitmap(r, t), lr), bt); +} + +static float distVal(float dist, double pxRange) { + if (!pxRange) + return dist > .5; + return (float) clamp((dist-.5)*pxRange+.5); +} + +void renderSDF(Bitmap &output, const Bitmap &sdf, double pxRange) { + int w = output.width(), h = output.height(); + pxRange *= (w+h)/(sdf.width()+sdf.height()); + for (int y = 0; y < h; ++y) + for (int x = 0; x < w; ++x) { + float s = sample(sdf, Point2((x+.5)/w, (y+.5)/h)); + output(x, y) = distVal(s, pxRange); + } +} + +void renderSDF(Bitmap &output, const Bitmap &sdf, double pxRange) { + int w = output.width(), h = output.height(); + pxRange *= (w+h)/(sdf.width()+sdf.height()); + for (int y = 0; y < h; ++y) + for (int x = 0; x < w; ++x) { + float s = sample(sdf, Point2((x+.5)/w, (y+.5)/h)); + float v = distVal(s, pxRange); + output(x, y).r = v; + output(x, y).g = v; + output(x, y).b = v; + } +} + +void renderSDF(Bitmap &output, const Bitmap &sdf, double pxRange) { + int w = output.width(), h = output.height(); + pxRange *= (w+h)/(sdf.width()+sdf.height()); + for (int y = 0; y < h; ++y) + for (int x = 0; x < w; ++x) { + FloatRGB s = sample(sdf, Point2((x+.5)/w, (y+.5)/h)); + output(x, y) = distVal(median(s.r, s.g, s.b), pxRange); + } +} + +void renderSDF(Bitmap &output, const Bitmap &sdf, double pxRange) { + int w = output.width(), h = output.height(); + pxRange *= (w+h)/(sdf.width()+sdf.height()); + for (int y = 0; y < h; ++y) + for (int x = 0; x < w; ++x) { + FloatRGB s = sample(sdf, Point2((x+.5)/w, (y+.5)/h)); + output(x, y).r = distVal(s.r, pxRange); + output(x, y).g = distVal(s.g, pxRange); + output(x, y).b = distVal(s.b, pxRange); + } +} + +void simulate8bit(Bitmap &bitmap) { + int w = bitmap.width(), h = bitmap.height(); + for (int y = 0; y < h; ++y) + for (int x = 0; x < w; ++x) { + unsigned char v = clamp(int(bitmap(x, y)*0x100), 0xff); + bitmap(x, y) = v/255.f; + } +} + +void simulate8bit(Bitmap &bitmap) { + int w = bitmap.width(), h = bitmap.height(); + for (int y = 0; y < h; ++y) + for (int x = 0; x < w; ++x) { + unsigned char r = clamp(int(bitmap(x, y).r*0x100), 0xff); + unsigned char g = clamp(int(bitmap(x, y).g*0x100), 0xff); + unsigned char b = clamp(int(bitmap(x, y).b*0x100), 0xff); + bitmap(x, y).r = r/255.f; + bitmap(x, y).g = g/255.f; + bitmap(x, y).b = b/255.f; + } +} + +} diff --git a/core/render-sdf.h b/core/render-sdf.h new file mode 100644 index 0000000..c63186d --- /dev/null +++ b/core/render-sdf.h @@ -0,0 +1,19 @@ + +#pragma once + +#include "Vector2.h" +#include "Bitmap.h" + +namespace msdfgen { + +/// Reconstructs the shape's appearance into output from the distance field sdf. +void renderSDF(Bitmap &output, const Bitmap &sdf, double pxRange = 0); +void renderSDF(Bitmap &output, const Bitmap &sdf, double pxRange = 0); +void renderSDF(Bitmap &output, const Bitmap &sdf, double pxRange = 0); +void renderSDF(Bitmap &output, const Bitmap &sdf, double pxRange = 0); + +/// Snaps the values of the floating-point bitmaps into one of the 256 values representable in a standard 8-bit bitmap. +void simulate8bit(Bitmap &bitmap); +void simulate8bit(Bitmap &bitmap); + +} diff --git a/core/save-bmp.cpp b/core/save-bmp.cpp new file mode 100644 index 0000000..6ff8fba --- /dev/null +++ b/core/save-bmp.cpp @@ -0,0 +1,109 @@ + +#include "save-bmp.h" + +#define _CRT_SECURE_NO_WARNINGS + +#include + +#ifdef MSDFGEN_USE_CPP11 + #include +#else + typedef int int32_t; + typedef unsigned uint32_t; + typedef unsigned short uint16_t; + typedef unsigned char uint8_t; +#endif + +#include "arithmetics.hpp" + +namespace msdfgen { + +template +static bool writeValue(FILE *file, T value) { + #ifdef __BIG_ENDIAN__ + T reverse = 0; + for (int i = 0; i < sizeof(T); ++i) { + reverse <<= 8; + reverse |= value&T(0xff); + value >>= 8; + } + return fwrite(&reverse, sizeof(T), 1, file) == 1; + #else + return fwrite(&value, sizeof(T), 1, file) == 1; + #endif +} + +static bool writeBmpHeader(FILE *file, int width, int height, int &paddedWidth) { + paddedWidth = 3*width+3&~3; + const uint32_t bitmapStart = 54; + const uint32_t bitmapSize = paddedWidth*height; + const uint32_t fileSize = bitmapStart+bitmapSize; + + writeValue(file, 0x4d42u); + writeValue(file, fileSize); + writeValue(file, 0); + writeValue(file, 0); + writeValue(file, bitmapStart); + + writeValue(file, 40); + writeValue(file, width); + writeValue(file, height); + writeValue(file, 1); + writeValue(file, 24); + writeValue(file, 0); + writeValue(file, bitmapSize); + writeValue(file, 2835); + writeValue(file, 2835); + writeValue(file, 0); + writeValue(file, 0); + + return true; +} + +bool saveBmp(const Bitmap &bitmap, const char *filename) { + FILE *file = fopen(filename, "wb"); + if (!file) + return false; + + int paddedWidth; + writeBmpHeader(file, bitmap.width(), bitmap.height(), paddedWidth); + + const uint8_t padding[4] = { }; + for (int y = 0; y < bitmap.height(); ++y) { + for (int x = 0; x < bitmap.width(); ++x) { + uint8_t px = (uint8_t) clamp(int(bitmap(x, y)*0x100), 0xff); + fwrite(&px, sizeof(uint8_t), 1, file); + fwrite(&px, sizeof(uint8_t), 1, file); + fwrite(&px, sizeof(uint8_t), 1, file); + } + fwrite(padding, 1, paddedWidth-3*bitmap.width(), file); + } + + return !fclose(file); +} + +bool saveBmp(const Bitmap &bitmap, const char *filename) { + FILE *file = fopen(filename, "wb"); + if (!file) + return false; + + int paddedWidth; + writeBmpHeader(file, bitmap.width(), bitmap.height(), paddedWidth); + + const uint8_t padding[4] = { }; + for (int y = 0; y < bitmap.height(); ++y) { + for (int x = 0; x < bitmap.width(); ++x) { + uint8_t bgr[3] = { + (uint8_t) clamp(int(bitmap(x, y).b*0x100), 0xff), + (uint8_t) clamp(int(bitmap(x, y).g*0x100), 0xff), + (uint8_t) clamp(int(bitmap(x, y).r*0x100), 0xff) + }; + fwrite(bgr, sizeof(uint8_t), 3, file); + } + fwrite(padding, 1, paddedWidth-3*bitmap.width(), file); + } + + return !fclose(file); +} + +} diff --git a/core/save-bmp.h b/core/save-bmp.h new file mode 100644 index 0000000..9642f2d --- /dev/null +++ b/core/save-bmp.h @@ -0,0 +1,12 @@ + +#pragma once + +#include "Bitmap.h" + +namespace msdfgen { + +/// Saves the bitmap as a BMP file. +bool saveBmp(const Bitmap &bitmap, const char *filename); +bool saveBmp(const Bitmap &bitmap, const char *filename); + +} diff --git a/core/shape-description.cpp b/core/shape-description.cpp new file mode 100644 index 0000000..06f33c5 --- /dev/null +++ b/core/shape-description.cpp @@ -0,0 +1,285 @@ + +#include "shape-description.h" + +namespace msdfgen { + +#ifdef _WIN32 + #pragma warning(disable:4996) +#endif + +int readCharF(FILE *input) { + int c = '\0'; + do { + c = fgetc(input); + } while (c == ' ' || c == '\t' || c == '\r' || c == '\n'); + return c; +} + +int readCharS(const char **input) { + int c = '\0'; + do { + c = *(*input)++; + } while (c == ' ' || c == '\t' || c == '\r' || c == '\n'); + if (!c) { + --c; + return EOF; + } + return c; +} + +int readCoordF(FILE *input, Point2 &coord) { + return fscanf(input, "%lf,%lf", &coord.x, &coord.y); +} + +int readCoordS(const char **input, Point2 &coord) { + int read = 0; + int result = sscanf(*input, "%lf,%lf%n", &coord.x, &coord.y, &read); + *input += read; + return result; +} + +static bool writeCoord(FILE *output, Point2 coord) { + fprintf(output, "%.12g, %.12g", coord.x, coord.y); + return true; +} + +template +static int readControlPoints(T *input, Point2 *output) { + int result = readCoord(input, output[0]); + if (result == 2) { + switch (readChar(input)) { + case ')': + return 1; + case ';': + break; + default: + return -1; + } + result = readCoord(input, output[1]); + if (result == 2 && readChar(input) == ')') + return 2; + } else if (result != 1 && readChar(input) == ')') + return 0; + return -1; +} + +template +static bool readContour(T *input, Contour &output, const Point2 *first, int terminator, bool &colorsSpecified) { + Point2 p[4], start; + if (first) + p[0] = *first; + else { + int result = readCoord(input, p[0]); + if (result != 2) + return result != 1 && readChar(input) == terminator; + } + start = p[0]; + int c = '\0'; + while ((c = readChar(input)) != terminator) { + if (c != ';') + return false; + bool parenthesis = false; + EdgeColor color = WHITE; + int result = readCoord(input, p[1]); + if (result == 2) { + output.addEdge(EdgeHolder(p[0], p[1], color)); + p[0] = p[1]; + continue; + } else if (result == 1) + return false; + else { + int controlPoints = 0; + switch ((c = readChar(input))) { + case '#': + output.addEdge(EdgeHolder(p[0], start, color)); + p[0] = start; + continue; + case ';': + goto FINISH_EDGE; + case '(': + goto READ_CONTROL_POINTS; + case 'C': case 'c': + color = CYAN; + colorsSpecified = true; + break; + case 'M': case 'm': + color = MAGENTA; + colorsSpecified = true; + break; + case 'Y': case 'y': + color = YELLOW; + colorsSpecified = true; + break; + case 'W': case 'w': + color = WHITE; + colorsSpecified = true; + break; + default: + return c == terminator; + } + switch (readChar(input)) { + case ';': + goto FINISH_EDGE; + case '(': + READ_CONTROL_POINTS: + if ((controlPoints = readControlPoints(input, p+1)) < 0) + return false; + break; + default: + return false; + } + if (readChar(input) != ';') + return false; + FINISH_EDGE: + result = readCoord(input, p[1+controlPoints]); + if (result != 2) { + if (result == 1) + return false; + else { + if (readChar(input) == '#') + p[1+controlPoints] = start; + else + return false; + } + } + switch (controlPoints) { + case 0: + output.addEdge(EdgeHolder(p[0], p[1], color)); + p[0] = p[1]; + continue; + case 1: + output.addEdge(EdgeHolder(p[0], p[1], p[2], color)); + p[0] = p[2]; + continue; + case 2: + output.addEdge(EdgeHolder(p[0], p[1], p[2], p[3], color)); + p[0] = p[3]; + continue; + } + } + } + return true; +} + +bool readShapeDescription(FILE *input, Shape &output, bool *colorsSpecified) { + bool locColorsSpec = false; + output.contours.clear(); + output.inverseYAxis = false; + Point2 p; + int result = readCoordF(input, p); + if (result == 2) { + return readContour(input, output.addContour(), &p, EOF, locColorsSpec); + } else if (result == 1) + return false; + else { + int c = readCharF(input); + if (c == '@') { + char after = '\0'; + if (fscanf(input, "invert-y%c", &after) != 1) + return feof(input) != 0; + output.inverseYAxis = true; + c = after; + if (c == ' ' || c == '\t' || c == '\r' || c == '\n') + c = readCharF(input); + } + for (; c == '{'; c = readCharF(input)) + if (!readContour(input, output.addContour(), NULL, '}', locColorsSpec)) + return false; + if (colorsSpecified) + *colorsSpecified = locColorsSpec; + return c == EOF && feof(input); + } +} + +bool readShapeDescription(const char *input, Shape &output, bool *colorsSpecified) { + bool locColorsSpec = false; + output.contours.clear(); + output.inverseYAxis = false; + Point2 p; + int result = readCoordS(&input, p); + if (result == 2) { + return readContour(&input, output.addContour(), &p, EOF, locColorsSpec); + } else if (result == 1) + return false; + else { + int c = readCharS(&input); + if (c == '@') { + for (int i = 0; i < sizeof("invert-y")-1; ++i) + if (input[i] != "invert-y"[i]) + return false; + output.inverseYAxis = true; + input += sizeof("invert-y")-1; + c = readCharS(&input); + } + for (; c == '{'; c = readCharS(&input)) + if (!readContour(&input, output.addContour(), NULL, '}', locColorsSpec)) + return false; + if (colorsSpecified) + *colorsSpecified = locColorsSpec; + return c == EOF; + } +} + +bool writeShapeDescription(FILE *output, const Shape &shape) { + if (!shape.validate()) + return false; + if (shape.inverseYAxis) + fprintf(output, "@invert-y\n"); + for (std::vector::const_iterator contour = shape.contours.begin(); contour != shape.contours.end(); ++contour) { + fprintf(output, "{\n"); + if (!contour->edges.empty()) { + for (std::vector::const_iterator edge = contour->edges.begin(); edge != contour->edges.end(); ++edge) { + char colorCode = '\0'; + switch ((*edge)->color) { + case YELLOW: colorCode = 'y'; break; + case MAGENTA: colorCode = 'm'; break; + case CYAN: colorCode = 'c'; break; + case WHITE: colorCode = 'w'; break; + } + { + const LinearSegment *e = dynamic_cast(&**edge); + if (e) { + fprintf(output, "\t"); + writeCoord(output, e->p[0]); + fprintf(output, ";\n"); + if (colorCode) + fprintf(output, "\t\t%c;\n", colorCode); + } + } + { + const QuadraticSegment *e = dynamic_cast(&**edge); + if (e) { + fprintf(output, "\t"); + writeCoord(output, e->p[0]); + fprintf(output, ";\n\t\t"); + if (colorCode) + fprintf(output, "%c", colorCode); + fprintf(output, "("); + writeCoord(output, e->p[1]); + fprintf(output, ");\n"); + } + } + { + const CubicSegment *e = dynamic_cast(&**edge); + if (e) { + fprintf(output, "\t"); + writeCoord(output, e->p[0]); + fprintf(output, ";\n\t\t"); + if (colorCode) + fprintf(output, "%c", colorCode); + fprintf(output, "("); + writeCoord(output, e->p[1]); + fprintf(output, "; "); + writeCoord(output, e->p[2]); + fprintf(output, ");\n"); + } + } + } + fprintf(output, "\t#\n"); + } + fprintf(output, "}\n"); + } + return true; +} + +} diff --git a/core/shape-description.h b/core/shape-description.h new file mode 100644 index 0000000..5df7c50 --- /dev/null +++ b/core/shape-description.h @@ -0,0 +1,16 @@ + +#pragma once + +#include +#include +#include "Shape.h" + +namespace msdfgen { + +/// Deserializes a text description of a vector shape into output. +bool readShapeDescription(FILE *input, Shape &output, bool *colorsSpecified = NULL); +bool readShapeDescription(const char *input, Shape &output, bool *colorsSpecified = NULL); +/// Serializes a shape object into a text description. +bool writeShapeDescription(FILE *output, const Shape &shape); + +} diff --git a/example.bat b/example.bat new file mode 100644 index 0000000..a530762 --- /dev/null +++ b/example.bat @@ -0,0 +1 @@ +msdfgen.exe -defineshape "{ 1471,0; 1149,0; 1021,333; 435,333; 314,0; 0,0; 571,1466; 884,1466; # }{ 926,580; 724,1124; 526,580; # }" -size 16 16 -autoframe -testrender render.png 1024 1024 diff --git a/ext/import-font.cpp b/ext/import-font.cpp new file mode 100644 index 0000000..655ddd0 --- /dev/null +++ b/ext/import-font.cpp @@ -0,0 +1,192 @@ + +#include "import-font.h" + +#include +#include +#include +#include FT_FREETYPE_H + +#ifdef _WIN32 + #pragma comment(lib, "freetype.lib") +#endif + +namespace msdfgen { + +#define REQUIRE(cond) { if (!(cond)) return false; } + +class FreetypeHandle { + friend FreetypeHandle * initializeFreetype(); + friend void deinitializeFreetype(FreetypeHandle *library); + friend FontHandle * loadFont(FreetypeHandle *library, const char *filename); + + FT_Library library; + +}; + +class FontHandle { + friend FontHandle * loadFont(FreetypeHandle *library, const char *filename); + friend void destroyFont(FontHandle *font); + friend bool getFontScale(double &output, FontHandle *font); + friend bool getFontWhitespaceWidth(double &spaceAdvance, double &tabAdvance, FontHandle *font); + friend bool loadGlyph(Shape &output, FontHandle *font, int unicode, double *advance); + friend bool getKerning(double &output, FontHandle *font, int unicode1, int unicode2); + + FT_Face face; + +}; + +FreetypeHandle * initializeFreetype() { + FreetypeHandle *handle = new FreetypeHandle; + FT_Error error = FT_Init_FreeType(&handle->library); + if (error) { + delete handle; + return NULL; + } + return handle; +} + +void deinitializeFreetype(FreetypeHandle *library) { + FT_Done_FreeType(library->library); + delete library; +} + +FontHandle * loadFont(FreetypeHandle *library, const char *filename) { + if (!library) + return NULL; + FontHandle *handle = new FontHandle; + FT_Error error = FT_New_Face(library->library, filename, 0, &handle->face); + if (error) { + delete handle; + return NULL; + } + return handle; +} + +void destroyFont(FontHandle *font) { + FT_Done_Face(font->face); + delete font; +} + +bool getFontScale(double &output, FontHandle *font) { + output = font->face->units_per_EM/64.; + return true; +} + +bool getFontWhitespaceWidth(double &spaceAdvance, double &tabAdvance, FontHandle *font) { + FT_Error error = FT_Load_Char(font->face, ' ', FT_LOAD_NO_SCALE); + if (error) + return false; + spaceAdvance = font->face->glyph->advance.x/64.; + error = FT_Load_Char(font->face, '\t', FT_LOAD_NO_SCALE); + if (error) + return false; + tabAdvance = font->face->glyph->advance.x/64.; + return true; +} + +bool loadGlyph(Shape &output, FontHandle *font, int unicode, double *advance) { + enum PointType { + NONE = 0, + PATH_POINT, + QUADRATIC_POINT, + CUBIC_POINT, + CUBIC_POINT2 + }; + + if (!font) + return NULL; + FT_Error error = FT_Load_Char(font->face, unicode, FT_LOAD_NO_SCALE); + if (error) + return NULL; + output.contours.clear(); + output.inverseYAxis = false; + if (advance) + *advance = font->face->glyph->advance.x/64.; + + int last = -1; + // For each contour + for (int i = 0; i < font->face->glyph->outline.n_contours; ++i) { + + Contour &contour = output.addContour(); + int first = last+1; + last = font->face->glyph->outline.contours[i]; + + PointType state = NONE; + Point2 startPoint; + Point2 controlPoint[2]; + + // For each point on the contour + for (int round = 0, index = first; round == 0; ++index) { + // Close contour + if (index > last) { + index = first; + round++; + } + + Point2 point(font->face->glyph->outline.points[index].x/64., font->face->glyph->outline.points[index].y/64.); + PointType pointType = font->face->glyph->outline.tags[index]&1 ? PATH_POINT : font->face->glyph->outline.tags[index]&2 ? CUBIC_POINT : QUADRATIC_POINT; + + switch (state) { + case NONE: + REQUIRE(pointType == PATH_POINT); + startPoint = point; + state = PATH_POINT; + break; + case PATH_POINT: + if (pointType == PATH_POINT) { + contour.addEdge(new LinearSegment(startPoint, point)); + startPoint = point; + } else { + controlPoint[0] = point; + state = pointType; + } + break; + case QUADRATIC_POINT: + REQUIRE(pointType != CUBIC_POINT); + if (pointType == PATH_POINT) { + contour.addEdge(new QuadraticSegment(startPoint, controlPoint[0], point)); + startPoint = point; + state = PATH_POINT; + } else { + Point2 midPoint = .5*controlPoint[0]+.5*point; + contour.addEdge(new QuadraticSegment(startPoint, controlPoint[0], midPoint)); + startPoint = midPoint; + controlPoint[0] = point; + } + break; + case CUBIC_POINT: + REQUIRE(pointType == CUBIC_POINT); + controlPoint[1] = point; + state = CUBIC_POINT2; + break; + case CUBIC_POINT2: + REQUIRE(pointType != QUADRATIC_POINT); + if (pointType == PATH_POINT) { + contour.addEdge(new CubicSegment(startPoint, controlPoint[0], controlPoint[1], point)); + startPoint = point; + } else { + Point2 midPoint = .5*controlPoint[1]+.5*point; + contour.addEdge(new CubicSegment(startPoint, controlPoint[0], controlPoint[1], midPoint)); + startPoint = midPoint; + controlPoint[0] = point; + } + state = pointType; + break; + } + + } + } + return true; +} + +bool getKerning(double &output, FontHandle *font, int unicode1, int unicode2) { + FT_Vector kerning; + if (FT_Get_Kerning(font->face, FT_Get_Char_Index(font->face, unicode1), FT_Get_Char_Index(font->face, unicode2), FT_KERNING_UNSCALED, &kerning)) { + output = 0; + return false; + } + output = kerning.x/64.; + return true; +} + +} diff --git a/ext/import-font.h b/ext/import-font.h new file mode 100644 index 0000000..32ff42a --- /dev/null +++ b/ext/import-font.h @@ -0,0 +1,29 @@ + +#pragma once + +#include +#include "../core/Shape.h" + +namespace msdfgen { + +class FreetypeHandle; +class FontHandle; + +/// Initializes the FreeType library +FreetypeHandle * initializeFreetype(); +/// Deinitializes the FreeType library +void deinitializeFreetype(FreetypeHandle *library); +/// Loads a font file and returns its handle +FontHandle * loadFont(FreetypeHandle *library, const char *filename); +/// Unloads a font file +void destroyFont(FontHandle *font); +/// Returns the size of one EM in the font's coordinate system +bool getFontScale(double &output, FontHandle *font); +/// Returns the width of space and tab +bool getFontWhitespaceWidth(double &spaceAdvance, double &tabAdvance, FontHandle *font); +/// Loads the shape prototype of a glyph from font file +bool loadGlyph(Shape &output, FontHandle *font, int unicode, double *advance = NULL); +/// Returns the kerning distance adjustment between two specific glyphs. +bool getKerning(double &output, FontHandle *font, int unicode1, int unicode2); + +} diff --git a/ext/import-svg.cpp b/ext/import-svg.cpp new file mode 100644 index 0000000..bf16bc4 --- /dev/null +++ b/ext/import-svg.cpp @@ -0,0 +1,184 @@ + +#include "import-svg.h" + +#include +#include + +#ifdef _WIN32 + #pragma warning(disable:4996) +#endif + +namespace msdfgen { + +#define REQUIRE(cond) { if (!(cond)) return false; } + +static bool readNodeType(char &output, const char *&pathDef) { + int shift; + char nodeType; + if (sscanf(pathDef, " %c%n", &nodeType, &shift) == 1 && nodeType != '+' && nodeType != '-' && nodeType != '.' && nodeType != ',' && (nodeType < '0' || nodeType > '9')) { + pathDef += shift; + output = nodeType; + return true; + } + return false; +} + +static bool readCoord(Point2 &output, const char *&pathDef) { + int shift; + double x, y; + if (sscanf(pathDef, "%lf%lf%n", &x, &y, &shift) == 2) { + output.x = x; + output.y = y; + pathDef += shift; + return true; + } + if (sscanf(pathDef, "%lf,%lf%n", &x, &y, &shift) == 2) { + output.x = x; + output.y = y; + pathDef += shift; + return true; + } + return false; +} + +static bool readDouble(double &output, const char *&pathDef) { + int shift; + double v; + if (sscanf(pathDef, "%lf%n", &v, &shift) == 1) { + pathDef += shift; + output = v; + return true; + } + return false; +} + +static bool buildFromPath(Shape &shape, const char *pathDef) { + char nodeType; + Point2 prevNode(0, 0); + while (readNodeType(nodeType, pathDef)) { + Contour &contour = shape.addContour(); + bool contourStart = true; + + Point2 startPoint; + Point2 controlPoint[2]; + Point2 node; + + while (true) { + switch (nodeType) { + case 'M': + REQUIRE(contourStart); + REQUIRE(readCoord(node, pathDef)); + startPoint = node; + nodeType = 'L'; + break; + case 'm': + REQUIRE(contourStart); + REQUIRE(readCoord(node, pathDef)); + node += prevNode; + startPoint = node; + nodeType = 'l'; + break; + case 'Z': + case 'z': + if (prevNode != startPoint) + contour.addEdge(new LinearSegment(prevNode, startPoint)); + goto NEXT_CONTOUR; + case 'L': + REQUIRE(readCoord(node, pathDef)); + contour.addEdge(new LinearSegment(prevNode, node)); + break; + case 'l': + REQUIRE(readCoord(node, pathDef)); + node += prevNode; + contour.addEdge(new LinearSegment(prevNode, node)); + break; + case 'H': + REQUIRE(readDouble(node.x, pathDef)); + contour.addEdge(new LinearSegment(prevNode, node)); + break; + case 'h': + REQUIRE(readDouble(node.x, pathDef)); + node.x += prevNode.x; + contour.addEdge(new LinearSegment(prevNode, node)); + break; + case 'V': + REQUIRE(readDouble(node.y, pathDef)); + contour.addEdge(new LinearSegment(prevNode, node)); + break; + case 'v': + REQUIRE(readDouble(node.y, pathDef)); + node.y += prevNode.y; + contour.addEdge(new LinearSegment(prevNode, node)); + break; + case 'Q': + REQUIRE(readCoord(controlPoint[0], pathDef)); + REQUIRE(readCoord(node, pathDef)); + contour.addEdge(new QuadraticSegment(prevNode, controlPoint[0], node)); + break; + case 'q': + REQUIRE(readCoord(controlPoint[0], pathDef)); + REQUIRE(readCoord(node, pathDef)); + controlPoint[0] += prevNode; + node += prevNode; + contour.addEdge(new QuadraticSegment(prevNode, controlPoint[0], node)); + break; + // TODO T, t + case 'C': + REQUIRE(readCoord(controlPoint[0], pathDef)); + REQUIRE(readCoord(controlPoint[1], pathDef)); + REQUIRE(readCoord(node, pathDef)); + contour.addEdge(new CubicSegment(prevNode, controlPoint[0], controlPoint[1], node)); + break; + case 'c': + REQUIRE(readCoord(controlPoint[0], pathDef)); + REQUIRE(readCoord(controlPoint[1], pathDef)); + REQUIRE(readCoord(node, pathDef)); + controlPoint[0] += prevNode; + controlPoint[1] += prevNode; + node += prevNode; + contour.addEdge(new CubicSegment(prevNode, controlPoint[0], controlPoint[1], node)); + break; + // TODO S, s + // TODO A, a + default: + REQUIRE(false); + } + contourStart &= nodeType == 'M' || nodeType == 'm'; + prevNode = node; + readNodeType(nodeType, pathDef); + } + NEXT_CONTOUR:; + } + return true; +} + +bool loadSvgShape(Shape &output, const char *filename, Vector2 *dimensions) { + tinyxml2::XMLDocument doc; + if (doc.LoadFile(filename)) + return false; + tinyxml2::XMLElement *root = doc.FirstChildElement("svg"); + if (!root) + return false; + + tinyxml2::XMLElement *path = root->FirstChildElement("path"); + if (!path) { + tinyxml2::XMLElement *g = root->FirstChildElement("g"); + if (g) + path = g->FirstChildElement("path"); + } + if (!path) + return false; + const char *pd = path->Attribute("d"); + if (!pd) + return false; + + output.contours.clear(); + output.inverseYAxis = true; + if (dimensions) { + dimensions->x = root->DoubleAttribute("width"); + dimensions->y = root->DoubleAttribute("height"); + } + return buildFromPath(output, pd); +} + +} diff --git a/ext/import-svg.h b/ext/import-svg.h new file mode 100644 index 0000000..405ab69 --- /dev/null +++ b/ext/import-svg.h @@ -0,0 +1,12 @@ + +#pragma once + +#include +#include "../core/Shape.h" + +namespace msdfgen { + +/// Reads the first path found in the specified SVG file and stores it as a Shape in output. +bool loadSvgShape(Shape &output, const char *filename, Vector2 *dimensions = NULL); + +} diff --git a/ext/save-png.cpp b/ext/save-png.cpp new file mode 100644 index 0000000..06dbdd6 --- /dev/null +++ b/ext/save-png.cpp @@ -0,0 +1,30 @@ + +#include "save-png.h" + +#include "../core/arithmetics.hpp" +#include + +namespace msdfgen { + +bool savePng(const Bitmap &bitmap, const char *filename) { + std::vector pixels(bitmap.width()*bitmap.height()); + std::vector::iterator it = pixels.begin(); + for (int y = bitmap.height()-1; y >= 0; --y) + for (int x = 0; x < bitmap.width(); ++x) + *it++ = clamp(int(bitmap(x, y)*0x100), 0xff); + return !lodepng::encode(filename, pixels, bitmap.width(), bitmap.height(), LCT_GREY); +} + +bool savePng(const Bitmap &bitmap, const char *filename) { + std::vector pixels(3*bitmap.width()*bitmap.height()); + std::vector::iterator it = pixels.begin(); + for (int y = bitmap.height()-1; y >= 0; --y) + for (int x = 0; x < bitmap.width(); ++x) { + *it++ = clamp(int(bitmap(x, y).r*0x100), 0xff); + *it++ = clamp(int(bitmap(x, y).g*0x100), 0xff); + *it++ = clamp(int(bitmap(x, y).b*0x100), 0xff); + } + return !lodepng::encode(filename, pixels, bitmap.width(), bitmap.height(), LCT_RGB); +} + +} diff --git a/ext/save-png.h b/ext/save-png.h new file mode 100644 index 0000000..e1103ca --- /dev/null +++ b/ext/save-png.h @@ -0,0 +1,12 @@ + +#pragma once + +#include "../core/Bitmap.h" + +namespace msdfgen { + +/// Saves the bitmap as a PNG file. +bool savePng(const Bitmap &bitmap, const char *filename); +bool savePng(const Bitmap &bitmap, const char *filename); + +} diff --git a/freetype6.dll b/freetype6.dll new file mode 100644 index 0000000000000000000000000000000000000000..e35edc6bb07a741798aef2b642c13005b8b8ffde GIT binary patch literal 522240 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

3;kYxczwOC% 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%0Dy#{TMfqvmj8^ln4r zL9Zin3s&?>&p1Q%3KG>ti4j^eh(3aq0*TaY=)F4mUGA-+9Ig}@qgCJQgzM+TpG5c* zIoty|c;g2IgaDu<(O#=rO^u82tt_q3O4zF`bVrwZxbd&kHSxo}R{7LvKKNXS3{5%* z=&qFRt9|qU6@gD#`>+d>(Pm-NK6;o99Il6Zqx5iFF5`9K@y!S4#&dE`-u}7E;;B@R zoF;&>som!HiTycu_1eg5Bw_?6rbHUtl~Urlj|}F&XATigPArMcn`+lu9Li5VurWR4 zIHBvb=w4aSyy5>7_wMmgRpEfQX#a zG!2(pBom+t7@Q2rW;-_4Yg=16=h#zD>k+(xc!30z;H?F%S8AnN?H=O=wE{(De(%rP zdmz%D-|PGR>pL&V-g{l2^{i(->silw*0U(WF&^`sZtoOo;>YG7Cfl||$vr`CbXMZW zI{F9+m(Z{0aqgyD-&)x}OB3;i)NwX|>57N?ag})!kqToC;Bb9q0lt*a<93(udANhf zwPIgEJa?|?)OQoitgV%U*k( zj-^mj zaPN3cxRa{o;?eh;c||Fz7y;@mE5|TJz&ck+MX`u`W4L{Jp|w34 zUSxmJ|JrbSPRQCmFTB`(x&QUy_QJ5Wh3fkMI^6zIk+r=(`~&-OpC|OcI-E7SwS89j zGTk6G+@3Vv+Oj14L$V3lJo|?wFpKu+!hf^6s=yJd>x)|K=C))X(uEILtY25(6wsI+ z;d~aa9-p(T@|^3;@UJZ0U6n25pOMk|u=K-d!taM}T4N6{;S0_Af05PNk+_>LYsZcE z@)#?R=mqw)LOs&7P+KU+5#<9_hJjgKKNn(SSDt!?)m_BvK-DT3t@Ib-v#|?T1=l_l z?xZ^L-;U9Is8jS|b^V7@Fm7)(UDkk-LDN#~(It)U;olqHgj=Z~8>qQ6nwuKk*PikY zYT#kpnX0=#BZ+z82*(j-sX!HUgDHsZhumMA)4bTR1r9>bAuf_2-E5`fz__1|66TTi zfX4<&HY;!pPFx_g2kaGv9pCjQPG{XlG8#VVToQD)-_94qDGzZ)Bku;!a}A!y-lOHf z(af$-IMtr#KKu)FKDZtLDs}d^Aa!}6yOBWHu4=L;6$)&8_t3nRPo|rf~CIt|{?KSz#sf^a_q4O#eWAaM~ zMzDBS2;i5TEZSiXb$%QbZ}!L0%`5fc?N2&eSLwrZJqu6d!`a%SAnz29v*Q{*%)AIu zT3yRNp+wK8vrj2@RR{^g5ae$R3C=CDr^%&G7ZBj77!uJ)wWsBiOhmD}Haj5T?Mn(| zRlhov{08&vKl1+M`#=xfPNDtOe1U3?*YhDpT+ElKoH-fCJCG)i`RbM2L``^+bED?> zNCN+P8tw}g1sLf|32ft+Q+-l~Iug8A=NowvKJIi!;d(hp+H{Oxx@#(Q$9IL`C)k5W0$59(&Dko~+B8&4z3K%sT@ zxxB3(-7_nEPOLwR)4a#b5#kxCoSk^jsc-)s7yg~Y?P~CUdrh9*l;2ZVkbGZ2&7xcI zsxrl^tJu_4d5ro}=HfwQtfIkFsjpaX_>mDRIO|fz)NEZX#F$#Y^iONuL#gC!ANIK6s!z(Ga&A3%_mbExPRVhZ!HomB5wjEeqwYY6Fe^Qs{HaD5m z?jZ#DUAk;HgUQzHCIOq|=q)lr3m}Jdv z=mVi5#0A18pE5wBT=#(%(!OT{Y1V8{R0ewoGN8tcs$t4icD=%{dW*f<<7ER8H#FQz z_&`ONzZr~$^xYJ7LFbkVadrRJhRDCO|5Rb_RJid!Oiuu-e``Z<=&cR@eHiI`TiT0| zB8KaNCgfJq<04hXwwdz0Yc*<*mp78->u_UIFlwN>NDwI_vqvPQn^36HY*fBz&k;gFa0#GM_ZgaZ2@2-duDyl{M~zu{OqRrWq&p|jRd z@B4|8-UvOA7ir>Bk<=Jdmc6^!ZR0mPKGAu z_`M)QV2QrT2Z~2|u}v+{OD(6#P}hk&M7*(=3t@$H$mCIQ3LS)oiKgh+kXdl(P~Fwq z8DBdf0>f3!q86*mR+4$FM+`}To}(F8jTxNT+FMul{+g*O(OIiZiNb>%mj&s6rQ1^D z8{Gpp;~%CvI6!`G&6pc$bbm((?V;vur*{LP6yZC|xoQiz)u<^--L29Z-G5j1D1%^~ zzV#!kiax*5jT7g&|C~KHwIbN)Mit<>0G&TOwIaLG{WlYmt$cGXW}~msjhK*Jg(z2E zqx)?WVmLnTM(2g|QunCgjqVqTfJh1ky7jH!>^TG78_XMn5D2oAf-&x0ra1r7)G}&# z=OzPk!9bmQuV?@_1Hm z`~F5@?kg`0f%5Di75m3ZszM)clg+@6d9WXI$wB;!teP1c>8zU(=hQ$1qF1Q`n6xSw zl3?qAN${YY-c#`bN*faUQ!kc=xs_!|Hn=9!9-P@A=YIyq54@BpO2Om` zs#^PzcIU4O?hc-pky!HCLy22W)n$Y2XT!HUC$hc1m^wSJ476Kam5A%rWrNGy$fA)A zq?9tD!M*rNqicFFgLFVXlEAgTwuzABEKkv8y7;bZsLZ}xr|9)PPzj6xEFZwt`HayK zgpfyLf2A`w54K(G-w&}$sN)8QXr6aB#9IHmV-&rkvSO2Sb#``@GrhvQuf(S~E-SI8 zlsnUFFm$@Wi{ToR8U@cSVUL*LZx2)z3XXxQkRJBjQhSPbqe;#28%>TRf>-@7x0$fQ z69Br@WIC6c%;!>*zp)9L;$0()t)qS?IRi>%#^mP z`|Lj6M&^ti-F^eDcqf)XiEB)^jD3RE9w0g~FKZ;ngyw;|dE>luLgGQ51G;o)Z@FOz zL9Pd{a?LB17^(_5>yn7PzZnJQS8XiKW9*9(1|%;Z&yq8A;s`uHZQvlF@eq-{ty-4D=1r=;12^n~tY`$OJe0 zsTm(YrAm;%W)C)sBs)(3*dvGQ(%9-c0`^q(iOgQrK5rOOnCGUL(ey`kx_4xQ9#a!1 zaxl$`t)VFJE!ebjxd~f121LiYf9RphX|8wC$SuGDJ*dPF{;T6mZ;bwhFSp|{GfJqg zP364}<2pjP6~DscXY&XJAHt<9C3qxCMy-9+3>Xh65dM%Ly*G_%0j3{>kjn*o3y@8a zP5oZ_H2TX)Dg@r)HSZ2nQsR<#myM*wDm6BEnw&zm=bJJ*FZg2g(i9Sz!j`=~(MxZ| zp76NRkbV?$Rq(xD!5)ZK>_60~6R7(cpPj2Sz80;(elXX&hyLSjvh&*UOZD7yAWI5C zHQVVeh5%9iU3;a-$R{XZ@ti=d&cvI9Aa1|6)_!kn(tdnO?5NHU-AmYt4G`dFUJm@U zZt-AFFaDhL6{cuC9qx&-x_(5dT(;Ag(Q#lx-^bfjiT%p^cOKq%;Y6>Ljy=Y)>)YiBuJ<-h>KGVNt)GM#q>?&Q7}uS=w3MOUQ+=GAq1* zYkqi7w(v*en@7fu;}jeJ4eQqgn_%E*>@)C(14Jk0O&pOto3(N4!Clrz7`hut=#Kue8M;2J8HgR1N(?*bB}qEvU$6C2dSf0k68%APqC9Ovh2ZX=9ywAM zcvPdLnw=sjD>y2lX*I*Triw2sK8}2T^=o&DUVVlLxTZg2w-UB?w?q~wbrlq_5}o2e zRhR&HE)%65*`u?e5nU%Vf{)YrK!#iC;LF{c>ve5F!DfiX>betj*wy)XCN@4|&G-5M z9<;h{C&s%+sh(nWk5a9k+@r)DzUCgK9PUxF;t5S;gHIi&P)4OU7~h81GDy@un%nay zK4(Df9|K~;q9QP}EIdy4n>21kDOQSg2}^AZ^9}TRJDN8s}l4wn56meolpl(A&FT=Os? z2)d@kB|%WGl4GxZ+%RL2zV7GC{mWkrpwzCWfh)l)9=8!#Icf19GSex`R# zdAIX)f0{6TXdDA7+KTTauQG8i%G&f}^{l*%o5Vq1mE1>-Ug8@`O!wVFDyJ?)u$ndD zkh4SidhMh5=e+^G`ft+2H#~$zafQ}TzcH!N1W$(bWlxsx}4baQr9&f%d zRsMo1k;y&$I)xj3oQx}A1n2K*gG-%@aR)>`F|$0-BZrPrK{xgPSN{qc5=ow-3A zLHTK851*V?+{UoivNuPaaPTBAKSs}s>&NBLa`G-1baiF&r{aAO=N(4w(PfD(w8edB zyJ=#wpHzS*me*?kXi9PmT{7BI1`bZNm9x92AKW)rk zR^n$4J=WOgH4`~MQx_)kA52sp(RCo6BexZkAUw0^K|Y{%wQY~mab%E!W*{_0O?4qN zTqJi`@!e{#H|?8AU2eA1#UQXyjA+digAXOLNU#%JgIfVmXj;2dz$7I-b-^e9`T+%c zywtv^Ao&8Hpc`6WN;x7@cLvmS=_Q1;q(h#u(V0C89+G`vfVq z#eOvT+YfPb%Kd;p_c7?)EI|M%s_O%pop>9p_+_Wa3H#%HSJfncYx)cPz9hD~kqGzE zb*7;{e%OGgh=H1yg2ZVRy@5w{*=>4Q*Dg`9#Ib7IrfwRaE~L{h#GkotR3T3NOThu2 z;N==zD_=4kzr4UhsiGvXhDdOMHiu#03~PO-Wsm=|QjBJ;vNoBTmS<6T&O zk@nkGybB_o(C1T2!1(`Xy^XrRSNc-)GC`+Pvl!?d)>-IM0)( zJnz&W{A&J$K3~sjbn|T?xQ6?Y=?J3>_w;NfWSoq4z<$?L5i6%$pN(KJ?~I1K5N^ zJuh|br`jU+HTvH$^XhIdp7lXsPtQws|AhU10jGk;PtCo`2h|vWzJm&9><2(wwrPXf zw(gsNq{YGKd1`O3XojbRUj*?99#Kq9IIPBHk;G{1v$hH^O{T!lZuwLTUm=3@A!oD5 zKau+mZk;NFc9QO^=>PL@mMu56NG!Zr9ME3Z#{0m!CH&PdQL>(%s&MXnfe(9=kssIn zQSaT_YISZppm(#=>fHGklSUh@&SgPooy(_l(_8#yiD|Z6?VG!Zv^Oo#-*;AC+H59F zv!y^Sp;R;4y1cO;%xG|y;8FC$Mw(NPS|O6U{*TH*r=pf*KSKZA|3tX+Q4xEj7@fr> zyY82|0)h(bIhdSqXz*^|Zmgb#4nt~z9+w7Tz-@YqiP*{-v=-G0i3$ppn^(G_9c&$b zGy{%q@)Yj;;SD`h#6+AxxN5>57d8R0N5-qe zwL@yV{q9Kox%PC0f5oRb-o4?am~Sum!O_d`OZP3Ec=@xHYb}>GlI^FRk1e$vEPYZdg!rNtioFE-f$?2fdqbcNEBb+a)3GnD>gbxyPC2m@e&& zJ(ZPQ3#-~)6aGRVxrMjHqyoT_N>%j$TCTHI73prFi%NIbWz(^H`5qVBqj;~|I0~zi ziG@Du?Mda>`rK-I)HC;3r!99eih1G5iHnvrsP!}4Z{H~*(?Hc;g#PEdUzXGZsW?mJ zOsy1(DW{$cI;(WfY;KsEA18hm8{F&~(A+|MhO9M8mBy(o1oU#Y$+*W^$)aeVqTw*f z3&CgX^?<#suwxCSFTgzF3mMKP4NCl6Iy*M<5*4h_*IB#2;Irs(b2{f`#|G8BR z`mEV=xy2&r=IdkVCjCoF1+EKZ#&PIMQ*j|yBy%oqPAxBV|Dup3Kw4{{01323%p~8v z>o+E9G7XWBl)|x3*uu~L zTL?=O_B#1tYtz2K`yLcGP!>=ymd@w`iWiWZQ8${o%5#M5VW?8K0Kh}xX=d!M3acX8K3yJ0sXJyubX!a1P%|V zJ$6IB)%9zW4*LP6qqNo#sAGK7GMO^34jup2dt~*hyijca(+0EE=bgzZhGCWo(Ji(Ywq2U(0f--lH-f1 zUQvdybHDziV>MQ1Yx6rV0zsCfmbGYQ-nb|{!;L%((PBM|0>S3~5^}ShJK!vuXU|=b zWQ`;n2eXf?3&)Ez^*|nBXL@ApN1XM2jOuc!2nVbkWit}&ThB;T2e>>SiPuX;Dc7mg zMJP0vLeGpeaNEEi?#bff^T_Vt7^9;iihWRTSJ=!y;-G5mrS;Ak=2{-{g)mH*C9ybH zA`;*l&(-MxU~SYnI%a1;1z9{f1~QMv8WS zN3A`nK7J?>+-Og#h?dgM*se@#`{H9pgt;=6^R8VM>km%vaFv4_#(Y$_9>?(mCva@< zy=0dO7cxxB2~S_DKu?BKBg&o8^nhl~LM5U}1(8K!lOgxP%^tRPgQ^0}Mv|rBGUH>9 z1}82FmoVrRz<%9&tEWCZrUyp^Z0zCK%G%y=3}5)wDQsMbQ{_PC#lw6kzHHb2+e@{)0K&Hz92vDlxFC4Mw4_FAUq340ADlGl<@Hj87p(b+y~ zZF&agoXwyI3Y7t~9m7Oz4rA2Qv8W&o+Ze!eGl%1I_F0==u&3uGa>wDY zA2<8>>(9&i$ey21%SxSxCBu3rj_mvNZl7;$nI8=NqKkLoA@)e2nbzPXmBZ~i#KwOH z(>e_gdRr_wK% zZ7T7@RL&l2)60h8WPv-oDKF8$*qw4Lwu|;Hf-6)XGl?ORr^wp>dS1>z&L{R|`N_`# zjpi8-oN*pFYEAMh#6V---s-(-FNS?c5_@>f>N1{|A&I332bz!>LU&$a+QQnM3$+%~ z|9-JixA>tUF&Bw4ej{~_=)nM zo4*X5l+&f<8CZ1GgqK=9l7SB~@dim`CSsl?CUI9Ci><_zOl+%KtnRHQe^tQvy=VAQ z?^5b0rIZrW!PK4w?c(vc>`m+HGo){4_sW^AefiQv`StLVB{ohSF?^eVp~Qs!gJZ!@ zqB2v^uDIAhvpwP&ku6Qx{W;H(F=UtgY~Q==W?He~Kyzrp{^%FtwCCM@$>;j!?J zdlEAO5N^wgQ&HswcH8@e1MZbj^Fxr12y1w($o)OkUM zW#0*RH4SJh1ZT63BR4Phs6@0`@EyE)*dGxYp`KOFx2^8)Qwx=?H0awhvg%(e~oq0aUKEU$Ekzu#o|-marEKWlT;4WplQ~nUP<%*Xo{49-$t%>ID}( zgA^CbD9@Q+kSN(@#fp_gd$}qTHkJGg)RdT!C0ttF*HXF~Xl<`z>`XCZ2WJ>T`x*Px z!vi6T9H?U+=gh^qiE7iCR`-16QQPTIxP;+W`;=!F{v#xkWWkKAu0MhpvlTNAYO(Q0 zpP7#NYdWS_F_&c@9;guPOOUH%5Ni>Ayt4NYh)rc%BFAvkp({lyQaO9=x_tYHF6tgkwu|$>WY;|ACoa+&? z=R0m`@=irp`IxLQ(NhBScd1A0gWFV0cCtA%z*4)PQpZDIpJ1CJI)G z!at>U>a{jkE<}8rf4_RqY&l)McPMJY+l<=@sj_zyUZVCZ__hzG$>}E$v~~4clxWCJ zmh7-%13stBhtQoYH>|72@z*4j-8u;+h_Gmgr#gnkJ_$z8?|&!gWWnfA%$g{#D2#q5 zmA$*nR&&+VBPjo36hJ#$Xs6~ie;hB?j@*_Btq*5;w77I|^Y(G4W@PY2Ni?Kg*B`H^BwbJE@p^K- zdbq$dXxxh`pHJi$|1ZT~O7Y@d@T?_R^LJhq%1F#9jW)=|mbK$e`<+&&va}WEbnf&C zPh%wlFD_a$%Gz+MV&SU6hOxOF9JFT* z26xw-k`XYT>W_f*=-|bsqb7g4aNK4u^a`JMx+z?DQ2dK2e14{sO#e`L&CBrdm$4xl zWeRWYWde&*bW{@P>r$^Xr6uPvcg1HDA{D0OFDvs%Ab zlY6%@{0a&GNWkg7xll@ciCgo7$&F~FA&ONJGel%*na19QKpb^XxyPf*{oLWHT>bNT+I=Q6`3F<8QRf@&Y|kfo5=CBPWTx`M0=Gsk|o_B)yf8Icvzb?5sbv`z%or^w6Wlh4lm{cV}oRPVgnGkIN)N%|awmTbRI~Of=t9jmF9hlT>i1ynnyps=$Q#p?&vjtr`5%=SoM4u9xkeF}_ocud2d{F(JtOZ)u z+}>1sNYcUfaU`Pfa(I-BuY<44~|w11%gt3$#4kf|iOTl0z5Ei6sbsj`Qp z>Y7Xf`$$q#mk2k>hKs*z(+OCOiKSVo%L`&}eB3m15!X^C9}yjD?Y+dVDo_S78M*SZ zm*ppyKtWz>&f|^!rLtO<``>34Xr+74o!)A<%Sx~)_D*JUh9;0Y&kMl+P1~ZdCBZy6H<}WAD`PnVZl5Fq)WP>JfG+ndvIK;6{Q|I#2V>|Ph6P?Vms)OyP zRPt5!#ESQ1n!Rhg5NqC8Gop|gsK_S(Lv<-^GQ2YrHQ_vtEl(yB)Slm7>@3Y69H}{W zZlLUm_J6VWjD2CBo5(NF$-ZD&`S57ovcK5-%AQ#EdTZ~+X5;7L`7F-N{*Ts#O;l9q zl!Bmw0q_3PNzNjwC>yksluod-EPpV&*DL?*e=PqS>GF|!US3{+_vHgY24F!}C0;1) z!ft=Z&vzy&7_-ST)A@$AfXg`fv zf(+D6R>VMEh4(1eBelGx*?n`NS9psTG0%G}&?B{_lfTXG07%ptts~b!ZAhVMl?7#+SA9^qdJ#cRk%P0dBp7c_>2%I5|Uq2Y*dJ_QqBQgDdvOR_2y1e|GK4 z?2%Y#cRV@xq~WPsHCr~hmryOY02of~nczgf2h;ZKZs^Y?9e3I<+2sZjWyxLniTv7-0JlYcr)fm{xZOdYrkK0 zcr9VS;QK@C5CT<)v=`jZrv_~vZpF^`GBJTm-;xOaB+}$we~aHS$BQ2ArJ~F+=`!~) zw|iy6i5FP$cjyXgCrO6c0YT|`JcSkCODtn<0V(X;4pNid7z7LZ+D@+N*IqG@R9llf zi#ZF$mF-W4zdn1C9sjeYhq5Oj|Xe}R8J|_ zkji=76pRn)jxV4iJ)WSN^*xDL-%Ha+x;?D#Yr|gMU(_SyIkrO)d?J%KJ(GH;-564$ zifEfRtIlIs7$#@GXmx)MXsj(`?Ed)EgI{DVGba;i0oZd)_zATQL5I?68`wIReW$VQ ziTzf*n_l&o)`_XZ(6-H6u>=Jqi%a#lG?(V623+yy~R*narEnn zhT%vm^HzKoGz>#Sn}vMlmugQd8a&M}#$W7bQyEfull$04LySIAGd>yT@B=HpO4ILc zW`_82q2`IELc|N5884*Yjen3t_eLThe&;r6jP0A1+MX61h->KUXUD}_A^TZP?t|Y; zlfBlK@prwfjI0ZO{i%rOh`@divMRLK-avL|dMHtRCcASE6>{g54lEq zx$>>;|By?T-qcm_54qS!OjMo>XwqOtWUCZxiI%$RuyN5iiSJxzPNB8cwJ$B_j7UwQ<_8(h z<)I-bP*zkpb3)GL1@^Q3pRk19W$k#*+VRxby=DCalR_$})xMO|C@VOPvRhwcKOkU= zSLr;Na=$~UJ`YuDN9at>EX zj~%o>?0-EN_|Q(m{Q^%Vg75UZd9CQBs34*PEvVSkAFT|3$qQNL?Pt8xI{Dj zTP$eMS<;Wl{Bv8%+`%wPIebdmqg(AtE`1)3myJ5z@Lid0&&XxhH`bq5_Rg}G>>m~; ze+^h>pB$B`?A=*kTk%RQP+m^dN?FVR__979HG_4Fl*QAIPbQaWGI@a*R=4xTb+iqy z!Ioq+vHbIL8G=I2kM+%p?VL^Od^kql;F(jbu6zbH?HE6nBIw@|jLuZdoFEGT_Moh8 znbpC|j<{yiR7**+lA(r_r$ETj#0F(7lFO8TXn#j@OH+Ia?n8s z1eQCoqgfpZc=h<$+uG}il1-ZxMS4b0?OZi3mC-T6iyt=OF=+3`{s~W)z1eQ951tis zL*ms`n3-g|@5}(}gS})5+rgjdMBRbJoNUcDR(GBOWHgP1od@j3r2+%)9blSKEgt)i z{?n2FwhSb&VfqS2k-)Tou8F;t%_^B3 zHAr8c35W^iYJ&DCtLqQq#yh=4>?j#ZHHlC@C{eaOIT#&Qr9$+{g!9uOIkwC_W~>Ft z@gi`W9Juwxf@H47%Uq2QP}tx}eprXd@I(9MV7MS>CkmvHI00+`&;_&=o5s|mnli2U zcOYA9%P3Sysy->}k3?mdcC!~QpBITahye}W7G!MZFh1 zK7m)Lq5EI<)RJTlrObpZLy*1>Sxbx7Z*|>=QYYCCP4#*MPy^Ik)*3GX|JMUFAKYj= zubATU8KB9z)T;rx>coKjW^Z~x7ArLa@^{{VEOpQMNqRsQdjoPa`%z|~?P6~&&0UQ7 zlC@=IRdShFyykQl1PxuM9*_vY8{=J6Y%BjWEBqV5TmQp-#v0} z=ba@;Ht^mY!-<4ucLvqk{tc8xujM%p+{&AC#>XgQ@V;TrVt(*jnt{HjP#ah?-S#7j0X`~9FTnpd_aZ^f{(HTmtQ zIp4(V!9glMZb1RNNG<0?`MkNt+ErGu^zO?TLIsJkHZ^6>Y;>Rh`OwHdM+O)85@(KL z5zyf7VU}lgzX|5&Ow&k_0dQ!2)3Ba>xMGXFn%PqyKD%dD_$&$^yUTtdI^Eht-YgVx zUHAy7)@YP<$c&HSil6kqTEH^Q+A`-@&Q1-Hmv~L(yu_VPU9Z!o_R$EgBN1{lJF>)1 zrOm^}5F@j^iUJs2{Qb1NtMrzZQhC} zO;)SxKZ&9|hP@Ba90Sm6*w@ z6czI6B2M?=m<1fn_baw1+udZdvyHJ4#}bS>reE{qUUx7L0vBLT*Q5LCQ3qkV73XHekz9A zGu(c{)R4EMS@vovV8(MQeK=SeuNzHdGbcwWM)&90-WRhY>t5BYT*qzi*S@7=?W}u? z^tb^#YaZ8lkD0+({}QPw_NL-bGhRz+ti-2sJy}%Wu7`Jw4)QIGW|v(pW%P=3kfk>g zH=O^Jtk<=Vs2Zcj!%v-edrXcMe@V4*=0yoPU!#Nr27;w+5;G9yImB{{Vpq(|+SJL5 zal+zU+G4HKv2pT-d01N~=MJ9ITO}LE=d5*02`U=}e@MqxoLW{L>^R^wWaIyHTaaR+ znRgAdpNqYb89Np*mZ3rMr5DYd?o2HJ`&mEMO5wygyCx6W^5Yu6fR>TOX($x42_Xa_t(@BJ-lYxGE7}V+wbg5WpYPM4q;zN1?r%}ihpId)}cRujdKqq#p{)w>P zo!J-b8|Hy3R%P#rG1w7Z*liE^dJOVrIPHZdqRcx=X~k9|;OX>I4$nc|+1W*^FH!#+ z!N7CCZ|1*9oBaf|vVmxCYQwrH7e1{66wYP21C^dF{qk%q@L9{Z%IgVE$J}N!T5^3~ zO-(v-Bf`{dWxwEF_#%R|kxcvs#H$6QKOXKDFtOeFp2r8j_VwPSN}QGTPm)&V#SR>c zeGp(nR5Xl=^j<@qu}2GHuLWX{2l2RSL_so$YFlGJ!mr@EId?0bDL()h`9Tw8p5OmeLo;MrBg@r#CvHSNd?$+6@%pV7#~{Z^EJ080Y_)TS6S0TvGzM8~<<9V3JvLX2X7q zWLmzBZ}8@$0DF--3<)x^3Mo5y)srSqN1l6wGS%jp!x}}YjzTwP0@B9ip0@)X;=F_E z-RW4X1Cc9GZVeycG4@Y(hxo%=yxT{|c^(PJK2N-6nrX{9dt4ka3&6DZ~(g~s#YilKQMs~#QC;8kt;NuSz0#ORPSr3bpDdBz|I$9#4 zalbTU2y?rHGUz$t_7ay)a_diqB)LFP`i4uWCOoeL6#57moE2fXStoBYV}76MVioV$ zjEN%GXCp!_Sg*Z;*Rm$OJt3tH%YCF-sWd#(EA*u%PuI89o@>X!dSV~3sDBT-a&XE9j)qhT40X1(1X@q@MCrRrwGaF+N*An7s1O}=OKN)k!O~Xh=RLwo&z+| zSP}_N>yK60`dBVuDw0+9{))G(?H2~D?QOECTWRl0_KRS>>s07QLq*LI#+(|ICaVtz zs*PV(Jhdj~jzF)pd(!-X-CTek30mqSrL=6r?TbRto$%6+qGpf1qTarA79vZ!+(}_Z zhA_mvcCo(D;g@0u`t}{gC#*fG$iKP;NWvnhst{xsc+cAOCwo$f{lgafqPB)+cT@Ke z!rSBlemmu@zgpzUK@R{Ho&jGCaTbU1YuN0}ucuxU;9d2CV;S@W51H;kQ85op$Sfp6 z&WtseIZI*AYrb!PXl)uqW^K-JBH7O5T+k{uL|4D1#~tP@Jo{bLlc-LiBnb2$eu+Lm zpjeMB#a4x9!+w7#0=xPSbu0n&@hQBjKEg#;ktBWsQs%VAd=}Bu%_90miZb2!2cu~T zR3>HXkeEEI>^-adi!?pfhcUdYOWUx3kUz*dQs_$%-<9($ta@eguPi`0EEs=}0fn73A^DuLRR)yDA&)2F+x^MyCOlK&?F!#Anzg^IYQ`O^q>|C;+i6!Y z69^2mvih`B&ZTA=!tPf2qU5u-uLP8($5_vDW(WK3!?M#gdRY5$J2~NPG;<$;f?`mb zu|tUELrgs5e*Lko-AA)f-jC5fTl*>2mT}cFnX7(vy}qVWmiq(B+J{@FZ(WxKX%ofv4Kwbqfm>wq-Ug|$5|j@EY{r!AoDPf zLPz*4nd^O+CId|dx8%KPKO1{}MEvQi%97tCe`_zJWpc)kf}^k&p1!XoJeh?f2Ts=1 z0bM-{@KbuuOqViYf8~_;(`&}4`$m+x9dyQsNg#6a;Dc*1%vMEK*PlUJ&zT0GUGPX= zJr`10o+Q9XJU}}8MPEReus>b;;C~_qme}ubg#3{GxUn4FrXqorE@Gu1AW5(V|iw#*ZgD5h2l>YJ$-uVyTFRCt< zj6pe0_uoW6zQu;Kq6K9t0g?r_c2Po;`<+SXhK#iapBYGj?bz>qS%K9-g&^Tc#Z+KI zveRkUUL9^ia?@$@n%uwDDOaAK<{nJ|P3|iSjOpD^d5<`FlRIF-^{yZF-lMJ9CU=tw z*SmhyeoxSZ-)zG5uAkCtXQ9cx%7p7(Kczpy6I%)su6O;E{$rj^?nNeC@A@gdu+3Rb z6Rvmt@LIU_EmQtE3h&mtex%=84BKyVN0@NE>xbMr&|Tzz3{1*b*ubO$Jy;;4cR*x_ zxQ9_kkTSVioM?FlE-H?N z)v4~URwIJz=v5xNTRRwbZ&{$?^Nj^qbCU{3q2hcywY=C}O%yngl4YyO{IO9PNNu|l z2lj?a5^Hi%VZ?Ule!PwKRmKOuviHt4u%A@cgpG2ucN>##)-_bjdxCx+IucG zIG2HHZW>=_t}{ml^C`_si2Bk?3XWls_;uYtyI~2zCm zfmoN``3;y;>fYNmCPZPkq~EG1o2cqi?_qczU0JUGVl%0w#hza!8c}5K0Z_kk`sxNU zI5%$4--P*FRf^;NkL}+jRu`B(L%X)r-uuC?=mD-D;NAhdqufhx@3vP@ra7yZ5W7<* z5&8CWiPiOY4QFlquqkU&i*r$%UE5+$Ys0;?>M$I|>F&|{kJS$QMupq=shxIQ;dVmd z=&JlvNf^7~bDv7UaH)+kkmdgP zJD;RD`Ayoio8w6*+#Kh+ONpjO^EkE*y7Jrw-gmy|#yH=Nc;5wHe4$(6eTTgGkUQS{ z4#Rm1rNt9Wg<<6~{$-VKH(^FTFMOJPn*nu4efTr>G}Mot?*jZA zYb(ZY^JLn#fV}ghIO_cikV0YXPm@Z@vf8(SonpEvA>RO}+EZuivNbj{Gn?HTeyXv~6$kPdP|DQXXjkVB z_Vgwi17?DwHdVvP<-v`<-@dWw2F9DgAef5`#MBJIo1FToATeQY*WPTRR>jA+CQXU?{~21uv0{dh6>p(rjsr!*#qIyHD7$SUP)JiP*CwT@ z=Hfc_5s}MY1MU#@YGtV26B^DVro@WL#mD;Lq{BYr4$_M{Px%E4?FHl)ag`7N&6jiLvdL&9BTg$O0TuYQ9%gRxIp9(t4y+; z^TxiDs0&0IO)DV8($vgi(*zKU%RD84HE>-DS2^zvo|>Wk!=yR;ZQu=|wN`S3hKaP; zh!yZe1CteRBPiY3kp4ireaQwQ64SFpiB_zbkIprL?^$tens=_rZ1pa#Uf-03-abJiU7< zxQRH;+0G=1|3&mtF<1`^>pTneglf(}1JYdRoI!Ii(VrDAY#)hU)3!P7*aX zxL<$pNKOOUlF3ewPf0~s#`3?|E&8^Zk4{A8s$2^2ruLe!5p(zsQIr5MfS5Dk&N)c- zh3!9CpQXN*Gs^OEt1FwQwdJ5Uj91i|s;#&-N5Cy*Yar#><>6Fw2ortv2A!(|_RcvD z?h$5X1rqH#8Bl0+qi0yLuPM$u$=vk?y=%)TKis)$3F5w0tyu2+E=AlJM$tdy!{@tZiqABCnP?h5}gIZsxTP+>>h6ehh_O3~jqWH&3wgvH$xZWkphVsYsZ?Oqx{8`Zl&Jw_#C$ZYg)?+{he`x=HL~t&#ylkw)rQ zX%luWqt6oZj`I!=9U&yxD zVr&e9fg~vl1R&v>ZUkV2h=#<%+{Q(@K0J@1^82Uo{1W>0;Q8IB;7Kk9haNsdPP6G} z27#8<_DhGK&N_pd?0u@MKY30hQ8JQN7wkJGrW5w7Y@$jLKPX5yegfH{{ZRo5w$E7< zAb$zI*U1B66@!c#h-SR>zGO-ckUEtcPQJqvnzGMN%F^ffI6FQsB^=2QiF@|w@AZ8;t z8x&#eXUdNU0&fu|WOT&5`U<&74Pf7~Vt*tQR{cGzYfyvs+g8`(gm|fja9m9{@aT@d zL{oqx;<0-*vLCcY^ilmBj)3ocA;bQyBK&UnkunRiMFr043{RBZu9;5aggLp$fnH})AwJhSmGmsq-8JPWSGGa9uoH7u7pBfvLgB8M z{}t3(lbUg&e5p+c8;|dv)Y2ekj-1`{)7Ajz0poUkM)}vQuJz;+%|19Jw?C4s_{}GBlTRaR*<+^vlUERvSd&%ut`$2CfT76C zta!G0%S2mnjOg`sS#oZRXTwxEj_0t`N|obx?tk>e?cA^Q2p(UxW!+1nh5YayxMK&_D=+NvSoRL250B-;^hALruvws95LHj6l?V}TCn zy^LiH(OPObm$b0Mj#kF3Q{v)oZR7c4EJxoW!A$qIAIP34H{q4XCQvk8YZnLNRXqT7 zh3ike8kLk6+U18v7HPvsjdQPDY=jJy?YHuY-Y{-vp}00V(G&>~=aM#ON{~VYqJHF6 z!x3jQfJ1OaQln?j1#SUL!qOA9m-w%{eek&G*0s*}7utTaF^=haC5U|gkh#D)14|ZG z|8QULOt=+)fI`p^7wh5eMzKF~fO-SJXF;%v50?)r7A*QfrHLEN*GznH=8{h&$M#9t zy(XU(J5ObKAA_@6dqus)X8V0;#ymfxSFq;zEQL_Gr@EJ4_jKW2SqR*#tk`pa02i<8 z*qEq06A5}%`>!9IOOJoNjk85uKZf(~n^cOo_b7kws%g$~WS%JX1_Q1jx1T9{A3ho# zZ0nr3xZ?}n@rG6HXFbqn3TDqd!~T=~yg23+IC_w5@hLb@ZcE2R#izUPM2(&*6ai_~ zvYVK;qrQ$XIh=unEomARbe#yM}2J=?O(bLV^P_T0$IRU;Ib( zGM_K_pWNB0&)faacfHSC@+on~5R#zYgOp}2nf9;(U?>5Y>Ho}mb1 zuj>wyFl5D&vvNyw z)S7Y$Nh1su-Qn5J#9cznes3-#%j)jt@8piJkW{5rSJhN1o2tm%s zElNZ|BKrn+1y*UIcF*od!$fY0RWyus3sU&WMgN*;=gRze%4rYc8e2p(H9Kn*1XB#o zp|0^f;Lc*y2=CcV4ekKi)su@^pkh4J6o~9Eg4^R1Y@w(Gxb>}u3uCZI(xh&y^Lfxi z;d@EYZ0>?OG1|LMW2Tk74UKjZ@7)zeyg&TAbcd*kXSbC2CX+usMWp#b{2-V!^~kb7 zZNQ%4s|I{9rxxm$e4JFKtZTTXQs!4r)4t>~FK>E~cdJz*v`eX((VlGPdAuL*8J^Y` z)>RtY<6ciY0=pkz&!vuqNioO}v?Xs5VN((8|a&Z8~_dD%>{4N-Wn#&-Hz`qjkf#kYnEBPe)%`pNY6r zTsop-@A11Hp7-v0pn{GE9S(ey^)aCo+t1tmOho_fT)&4xVn-393|osmqR%6l(H!Gn z`!{f~M7#?a5_6BpuEMh)v$_`%K}(Gk;2Aw>aj=S(e@tRcYBiu*t7Na`$%nAarc=bS z)Gx^<&=0}+{gxI;zW$Y=1U|GA2RRSJ_!lvO%%ysGmTqj#VH|C*6i;>v$vNKGh5R2N=G>*YgRdTAK~43K)3?hS>%C&$`NNu z>Cf?qp!LkYrF7T$fuN(ckW<)$1X~{8-#QSSg89xkt^ixbA~rh+4|D&w~VeT0!zGAw#XGVOfMa@Ikeq)h?NAm#_C$ zc)H!l>iSntK%XoxTC1~xrye{=0Z?OHMO|B|c)0?dh3|$EKCq~Xt`TX*f39&ssxJx-ZC zY%0z5E1eMi*CpwhAS)yJHySO`$%^%Jph|q;8Y6|up?n^Aojo^kZ}SXEvs; ze^P_`I2TH`nFM(h6QYykRieathX;3nah>+8cKF39dU2q1zt-_810pDsK8=-hX^ z3JU&`B0{WZq<%?O6E9wV+{hSt6YZDN*+yFVj(|FH;coZ>7e6}L7x?|8%Gf0xjx_7} z!$cHqkMKvehuj+%WZ`aHEi&_kXS>|@YiyTyaX8Ji)Z4&@+JeqVXRYeM<60XYe=)CE zICf8kU6t?OPfD8Xaokq=SXm^0d6v|>dvXg)rqK50@ymI=@tkahlqqWsb8!-;Z@@&oOn6y1v=X zD>6qdV*1h#Yo<@Wke!Ha;2V#L?mSb# z;4OrE{ujh6;jiL%(4u)%wxn%P;Y!XGZ39=Qt3&p2%f_Y$4vY_tn0M23L)%;bUAMT| zJ^zQFinY3?Bht`Uf7dCoVtWsFArhb^R@|#NUyr*~L926FYirqME!GWaa*rkoA3lvh zdro%enkJa;QPQ=pT{HKbtmUJCSJ`40=4OieVYHlk#K)8lKEmkSUtWcTdyNqjG%xM4 zD??C9v1+wcjB{B_tGzh0)oGg5n$@(R73W=B*G$m`20C2!n$@+5f{TDYg`VsZOk zADe6fbgko?slgO^i~0l-UE1PA+M+eiZ#U?h^R*HKkCSPWyYP#jaCgPP2{LVRn+OsU z@_;)*KICHF6k=2Dp(gihezJQ_g+BTEw5$GF`-o;uqp_u{1IbU&;y|~pviF%b7x*WG zpp3iNLb#b1!H>#brnLVEKZ|8W`NIqwaxx5Q!>__84YelsCj^~n1I%;siFPEBU9f3; z+qzaVh7c)SZSEQZFmUdeOklE)q~cZCi3d0Ejep-36hV}nydMpvy{j>SHgN1SGZKrr zZkug9cb^vx|10LEn{^ufR(!U!ncG!B)|%*yhUSQS=f!vlzEiQggX1*epjVxl+M)nw zyZ)xdLJ5U4yiJW7w+riN4T+sz!Rb-)cOl0cRQ8N~XGZR!onUppI$FoU-&89r3;yt% zy2Z%?qaVP9SEO;#| zv(4z#H~evoL_A8I^lq!J%#L3uSlLy~pbw%#F0%xt8RSrnU?K zL;?_jxpyuyfH6p5w++G8wMR1$b@j;FoY}F!ylm6117|swmrV~EcQGt;*M2*LruPL| zrq(&;g|uXw27yBKOpYYP+Img+RX(h(HR0)jJtB&8O_C6S8h>~cdh_!qwRaz~ z6;ak!PxoeRy*Kn zkk-~0oaRs>_u@p&dK?{uOtOuBGFIukI(D0&PrN!>5xUQX|L03CMR?JIF`IX5E4~vG zxib^N^@+m1z%vss4O-prYIu5>EPIpL*^h#!Gwc>w7 z0;kc$6(weISiA5#TKoIYoz&XTdGxf1_D=ooNpZu7^I0Fwa18fucK6U2YwMvo_!6?; zd*)RVh-2Af((xNjyos}~zg?X&DU@xOhuy=JZ*J)l$vd0XrKxW=yX9$+67v~$(u+he zj)5kc-EV#0hscWmgm5O;lLy_JlLp;Xf6%qIuAP{X+40qZ<3>xZX@ezRG$(0_^bMDI zS#LrPRi}sNxnNGf-KJ^Q%!~Pnn>LV$J+gKzG2Z<*6RuI0)ZT_C6QxJx!gQ|msEn}w zjG*~_gc2IsHkeVlz#G+&i9dA5k!bBh;Xc(;D-Qh@1-BBST=fBZly5%w@OdC(6ah~V z;PcoC`&(HB>?X=Tw3~r9y*h!KtQcD4{SnT=jfzkb7)+17>p+B z^W?lbl-y6fLbj)?Y<9nL&Pi05Pt6gQBVw#G+ZGu3!k>l@r!_3IU@}q=um&s?TNtVF z>1lSYtzBW=MG)9k_M(;eqDS(`;o(H|@jSTbw$Gka=LU*vViv8L(H1ck-g7dSSfdJ! z=`Due6!=BP@l`an2Fq6ig-!w+ZZz-Y!mG)u8-XUx2IoBn|;^p=-I7kEI6jhspY{Q zy^qxU$mBsyPsaMPJZm2IkIn9`!jpRaHxwA5NiC7KQqwCBd!zgWMtfAHFCS-?xzV#L z{F%)jKG?0wPE%#4B`<_mM-nI`nojWQde3~;AFsZI0^`!gyrWCwylYf! znGm)BwtdU(ploJyVs_9Sm4^EyZfT{V{eQ+SFF)JIXh(h|v2FtpYpv4k_Fr-mrhhBC z^MpeuklYHkbe>w13g^O7q+LfC6Mo*k@j>B@`p9vVLRWfYh!)7x}k*ei6dfGInJ7p2=feTiC$!FVu92b z-d1+)YqF@%J)A^gB!ftKa?I^N8tni3Ib$D>?F`wta?I*KIvjCm?BwVQl`w)57(m!^ zc-JN{4{)ZJw0^>l=h*;aMc031c-h{LXGMV9{k9EYss7fvYTJr>YwM(W*4E~K0TO=PwVFm-s$Zt3u`r;>6XXtkkg~mV~^I;M)s`X zu)!$q$fLu`B6%xL2jcAE#G9kBzUl;LlnN%48RrrHQa)xx4U1?zvn|_hS=J5x)|S5~ zYQ7Vsdx9J?>UzvuI9Of(O@_p+BgC6^Tf=sIZ^-G*vST^B@w?vw>a5qQx)Iyj2&^;tcc)me?%coqHI z^htvUz=;%L+$Sbwr?quXWS~MCkPLf%+dy3lFL>?@a-^DC=~7ez{jUwTKOCqthuQ2k z1vU=c))e_`ReOFo_Gkf~A^tUN#*Dy8&Hxspo0Tc~;jKX-q|I z7mA2g@1{w`K4O?+P&-f`kzN?ZR!vsQx$Yq}LJTBr(`giGr|Egp*!^q&tlQ45_&Jog zF=%yZy%uR~>%4V+O1KAESB!h|C{0BlL>lpSx29IWAs+8*%4q+_7 z($VfG4i8P-;Aiq;}f|&GR&=Y0H+V2?+reWg%~<0cneAM5;(OfC`wf zyTHxm+O)p5kF7qf&r_?mT17z6ynqmVsq*3rz9GJ#dxoDoKa=<9CmBQEA3pe|84Ll!^RoUr`s5$M5_%g<3!NK%C}3 zIxp}7jY?^?^D@s0uoLDf@)l$%?%&cXx21yywv@F#WOqqZ(Z9eXx4;XRLHKnL2kQHr zGs&IwS*ZXEEZw3xT4QFgv3w6tSg>X3E&up-H$NDY^kHdpTl}h%zf82QUrnl}w!Spp zh&}=+amNtbxrT$@#yg6su(H)IJZLq}uin=;EiOEz zNa@}sBd{sd9w&_2BaHfCkH|TXxd}ev-Z&nO*!|Qce5!A+mkU>=5%KZ(*nlXDUCE}d zX%;iPzG(C>nqg(fNHOd%4Z^j=CqcZS=RGt71wyt4L=`q-vLUis=9L5YD4fmBTjI$x z+l%+%(ZLE&axxbR2?RS0+Wc(}MUhTog(MQn2<2;&*B?ox62`<|gxJGx8j-A%XzxaI zeQ%KU)8_k?*+Mn&fVTehqr`txXk28ypVKm25U)^;Y(dlHh_5u=*Zc%4fyV*SyH@7q z#s~UA`%6D)uant`$;F*CT^i83M!MbG@blS5^boXKBeJBgyQ3$Nm7WwHk}pbHw?0`y zQwMR-uBevc)T!FYL#b=upb)O`&cqDz37WB0`Hk9#1M=Q*3R+z!t)>SjC zwOtgT5=qnSoXzG)$!G#;y^^fsXkHcq8&Q+hjjB@Gow`L`)i84gT%w+C7r2}nTu`(p z_@cF{i#Jt^txt$Ec0|TUO3uzRqCd_`3Hc8tKt*co2n%ralAq(45$XxuBaNAX$lorD@z0;hS9 zWbz7w2agyxtp+#zMt|W6Z?SW4w5xyrDSO@HTCVqb!e!R=8Er#KCWieb*Mu`l&JX)a zu52zy4o2+5#Nfs~aU#A$46c%E*6gP)qISwi(^n)bgsHB=H9X{%aNgb!FI&zqz+R|`4GDxmAiXGW@?S-PGXQcp4UJo+!{k)AJlt!V2Lj0l|gu}Rz_NjNS=Z`sL%{9_98 zhreO=95x+uuUMLy9sTE<%T)%u{#5Un$f5K_8wfs{4|hrN?}Fvw#}vq}PI-}1_LT|5 z!cGDBjF=CEk0*t={}hG0X;-r zar3A$iQOwhfiW^&Zsv-7=~*-}*$@9oqfn)0C5lgqA1qJxd8dq$O5yX*jGIn^uguS* zPlcbeOXgZYu`4>HJBCWP8?k*dMD;Y&QdLly)6DO6;lz0dl}u<&6~;BVBP;L zKh|1lt@lL~+ts>wZDNxTy&Sb9w$JE-xM=R7T%8ukot(A24n@ zNAqHh8s~HE3dVVt5&Z$F*7%G__aGIXm9^bw;y%cVZWA=B=ia_FRXep-dloHp>l*LY zwR}Kb)v3C!*L78^F-%=*43{#pZ2yb2%`=i~wg!3mbDaI#@7W$t$DgKV{>0pV;6wDg z00fi;Lx9TyJ|EV7aKy-N!GtThl898%@XJvSmVtdNsx|xG1HIq0tX0uxZGZS&o>%`WXvuM1Oc%O*4ZaiQC` zYWq{rn2-c_0pLzn;G}O&7gk^ZtP4`Gb|OrGb%DStflg0+$|8RPNB!l*!GxAY%o)S_ zhWO8+P2XUQ{t3gWvfE-Im??X<56H07=E?XcAG5s0Pl+Tom^dv+_N11g6cfvmG442$ z?go^a#Oh`QtDDEF_+l)*9WxHi7`ZtWDye6byRb20@1vrSn+s*E>JhTE!FgBU&D4cZ z!=L3frG|HNdR%lm9j^wXm}{qw%|ILJTRPr^@N|{(1X`9T<+qFIFM-+lL?t8W4`1Vx;%8S1)GWAT4bRw~g~ zn`YI-?aQT>JQrV=aG05f|nBV$hsDs z5_pXUPN3HLH+E2mqP5oI;09_Ml0 zn={3LuNpFl7*C3$=s=~b#;TzLESSs?xKL#vzkBw8i0sk; z>8mahq_5Pn!H69eBch(ef+`-q5p!JLTA}i~%O_t=e5bM#L&4$RHnW0zw<6*QY%UgW<>jG zq)_>e{!Z5jBGNT$Wm#v$w$ZM$76j&xI}3da$HZBhR+1~kxij;~Opo#4C-jfvn>$F3 zpQCIRvci>ivkWJk&e~EQaqH1kvi(0wQS+|Kfpjur4e(`AqVP4wi7hu;A}D9|R`w&y zyO7rC+(dgKpC`iKHn;!wz?W1~K(N#>m+eYK9`9ymp4q1FP=h()kZ)XhaGznf1B*Tv z)P2nl^@G<1Jh8!QON}dH27iLgt(Se%DqkzgP=Z?)59}qP3kO#};#cVKxblI<nW_?<=y2 z0yoAVtSIu&oo5Y!bwq?(6-6?T#gfNk29M&C$fKV}aiW$3&qIhZZ<3Ma6h8!-^z-9K zk_iOj;?d~>z`S1Wc$4zn55bcZH^+#-q#(o#aW0C)*=VU;HcI$@fEY`6iBRMwxGiU~ z(>3<|AhF*sfbg_cN-Zbg&bOki&ip-M<0|TEXeVr~J%J(CQj(Jw zPA~2KXrnLZKT3P!2#dR=$_tqDM*D-^YxJCV9KASl6F5D|NBKvWrpEuKq!+yrI}^8m z3d;01VYEztZX~U3AAwuH=@ih(=`>qFi_uGjl>F-t`j>s6e<7f&0X>`wl47)|%XwWu zqr)imr#!<6vY`wJcuDm0#7d!YP27*823*p!L|)~eJB67~JL3TWhc^nXkJ1;`IY;RW zQ9sx^-xrS5Ccu>G(^U>u0!+0=#e_}?*_?cmzf+tET#bgORNSF zY2KRnY!y>xfVobDu@UmW92f3#jowox z_uRekf%1_WMW&QFQ7z{?sa$t&U|eAV_?$h5SyY zW@+DKc7P>ws3soyrKX9*_oxVFKvP8jJqfsls`OcbKV$Pn~3y zl|ikY%LyEF$78iMH8lr_P&h)C7{nvkCIw{?*I-_n=5&xDSf&c=p+65ACNTl)2j z6q=zDQwl^5SA95HsMbojIuBCsTEv0$=g4iT9-UL5dek{rxr(F;pI3?sb15T7hE}rS zXOeii`yzVIX_9FgnOgc~8bsn{sZ4w0pPi>UT$@K4%vRBJoRbirx@T_yFa7iuPm}HC zilki3nIh@sxCXis6OuB}6g^)v7e7R`oJfW>LiPiySPde&x?jcxpbN6cn!8K&|N0sT>tyIFAWH`kJ#Y8;sbw zG_7cB?{FrG*_LlxgEe8B&#ZXSgUa)wZ%pveg7;|0on$xHsG0aanT6>OENAl}nMlF- zQylr$%@nxKE@AwnYHh^+Oj^`Xhv7aywiM@GM#ndAOFh2 z3qk#H!DU6DMM1T)e-+z0zkn<9$R~BqQ zaCb>o*Xm~#>vq-E#19?R&CwIDa}Tr@e2>!Y^I#ektcPzBt65Q^Qx|n!V=#~o6{O=6 z4@*ttk(c;?x!`rhWO<#`o`__Tf6ktFmH!xnO`RRk`cIbCs?{GkHlWTjeBFJR`z>{t z;3X_>+18ZorjxPhbB7xnO(pBYCpY=cb-^ujK9sO(xbBbl2DkKnjKkr2pFPLxCThQZ zRUWS;D~I5M6SKdP5IoXxoHkj4TIydaGTHFXsoK(=(8K; zmW3SiG}#J`s~GRxvl-mf`y!uT^7X!%^i_~E4*AyAGZHJMc{TAxoSN@hBG2-VJswv} zX&~L|khu#+!*@QVt%QGJEfLFMKR`A2lU zm0kSS#Jg3xJj*|jpPOA1e?Sr|vnA#7DT%o`HSyo6lpIN+?A*MX_%fA}Cn?fo5fU}= zCIwBNloq&IGd@rnK-If&WwT-=R zCFx#5_l6kr)m%1tFrN3e1er8qI{{(cEWo%9;C`tZJLm{c*g$PQt}U(P%J5irMam?m z<_Hye+lc;}Ob|XG$702@n=eOZD*|VFQBiEtQGyyB@Kwo> z@Y$Hph}oA>$2}x7lZmHeIXTT-D|9rQ8ll+U_=h_c#i9}qM?n;S{m7HjJmt_m)xFEaxM!x)|A`3Jb|Lb>TETU1HoOeV6c6vc!L> zJPQ}5q`OkKa#so+<*t;a+?7~Ri3L8&%@j*t@+^OQA5QY2_EpM( z8}lMP5&&5uYh2YBZVpyu&7IB4lsgb!N)TT^T}9wDI=K-=?&s(xW1i7D*t}qZ(OH|e zaomYsONnrr`Bu8JMQz*3(Niw0Bg{VT{o(ROKUAks|62(Qwp8VMh5=qeDqe|lh=L@k zfi%APReQ{k?t|&QneFx%qx+z5%T6w_GaeiQjpf9ExNsE2{{jP$z;!QjYNkV^h1~XX zHPMLrlK(7uGYFMl6aSy@^v{2jb-&C%2R4YbX|ASmz6%JPWoBbDfe(z8UUS`+-CK4> z-mdx1ePqd8$K7>%xJ)gr^=%<&WY^imSKi&d%h$cz*Sc%3WZAv!gfb!{UAIodCNi$m zy*sVjA$FCQ+hT%GhrbosRoK19r>JE*ie5(aR|1YRk;<0~u7k?8gN@E%W=$j1=lYw$ z_@9{<%@DGS_ubh1kx!eOEJL%f@b%a{vnI#9DA#&K_4p$SL7bi58*KLWj8$$-T*;CyS<>6e(%L5RkhZLh?A#RMi+q`W=bRQ4ux81g=%sj{*>NdUAMtCi?)%F9m!+M(V zwBEtC8Z*q9KFxIEyr;j26zhFg7ADP|E<=jw6W>1ZBm1?;Vc|%;KYuNBg8t*8V5e9}yZJ`#v1kBKVR%r~cq#b|We!V@LtQ7QKa_CY7CjCH*q(_)VK{Fe8n znIIDoWX$=#)oRK1k@=-;9di?-TC$abkj;TX?qoa-&p%O=B}~%v_#EeYy}-{VirgGH}JyUZ=&Q_Vxr z(A-|uy;F$YcEZT*(XDoFVe8s*FkK)k z6o2G9$v*j2?;nz~xt=zKi2%OeT;Efw)F6DS7$RUiTOySZ#{L`l&yXVK%<=q+BLS%f zH?QzU*A}|xv*Y{jZ<`P>l6}&9Rzv%;O=|o^-Wt*sPv7>wv9injJY#~d5O0U$1=LWv zu}XsEw0wS6^VXK@yy>nk z&jCWn&HIz8JcG67W9fkpZxCgf{Q~hJd_shP(w^HvdbVBsT*0-d6+B=sCQuVlWsZ!7vX{tFAT(HTuBPveKhmTv7Sc|h ziOY9Ug~$a>+Jb(h#nDKrs>*PFKwTaDKcaX2>QZ1yt@7(!PljYlfu!_q6j>$?mXo*? zE8q);e9Bd1!C>Pq4h1unL4PebXEAK1Gmz`8mSq&>Z9H%r0U`kE+hmC|-CEPad(r-A zmvy-x-Y*XiU$)NNtH=3n#`#{xd2xR82j*Vu8ZAzXZ??|mEbRzu2xFpr6sm|H+gRj7 zUvNj$E<1exVfjoiEeK3+?YX5?pwq+U9y+~5DyE|Fsck2SJUK=^7zfC*qsXK@3M%=nTY}!TZ$n%75>l@PJY|zvIXjWq7a@uU&)XraywTC9L zDI!;Do`t~(E)b%di&Yk)mB6N)a+Je7h{NetL<)89^x4JU!{%n~Q+5DP6TDAUFMskk zYN|1xndv#OO&#b~khfrV(vSt-;O5E7F=$38{y<*3XX+FrW}|iTjK5W0m42(h@2T{O zfa$4JGEt;0|Btr@$89-cr+k&693I7TZ^87$5-9`R>OiBpjUcI%r470#ulKi|z(jm@ z?+NX=f5_CZd*t>qJ2ziV!!kFN^q+>+96UnJ!DmZfhJmH$;a#bDSn-W@&4kg{j5ngs zKycz(XzV#TzIZ<+Ms7CO$t{K;mwuZfB&1WjI#yH2`?1BgOPYC|&&1u$XI+{hTC^Oj zzXV1-1x7V~3X!#tBUAd;(fBD%wjQ!9FW-D-S=$-nFN5)`NZh_NH_Qve*iVwoSj~J00Yd zYlmVd^MLKGg)%aY-2|!I21|RQJgN4``8v-Nx-n~Lq|q^4HHL=h>0%|92-A`TEh$nh z2^bH)Y^=1TC6zXz7yB15BzIpkwwMQGR%k{hv^e*p5SPf zhh#j%gc8K#;}1sDCyx zs=qQa5IR$s_TonLRS-R}UB-z7_Y&Sh-KtYeFek(<*MuR^Gtgf~!(qzztLDg=`!vs|3Xgy=(yv7)1rnd<_+Q079)g{$Jcu1Q+#Gid5`Ro(bY7pc%MjH2hJ* zd!3pV#ZR?5K2(|SvjkB&rVVY`M&>1(7w|xq@+Ptr>F@kp@BpVi$BsKs%;< zhGIClO1kq8fb?tGkD;t;4$Y#hTK73;XxfX8*!sb9mvjVUsekKeLex~ zH>qt4y|-~#O_%H>iuH}DFnSK$j&xN({`0_wJd%y*0$O;u^KP*0ms2*!4|m=>Fwu)- zJg|Wp*;(2OsKcEP=?t<#B=D~$!{N>~I#I|j^Y1QlMs}4N(LKO~>Dehc$R~CwKH#Tn zP<|eMChI8^|ByXJTJQqNTKch)tQ3^pcHb&l(HhWc-L=*!%w|Ph=OhxKwDgCpV^}{g z%NfS7Ss!_4gxRy~mF~nKb@m5}NwbL?Fkx+e>}g{6fFFQ`Ts`HvuqJ1QW6@Ia_n;pY ziN@s$xb5QIsQr$u3yVizh^V-V8ptGN?JK=@_EXm7qZqGJ$h@Z5&c0bfGhdQxrkR)e z2sA;m3z~qTBm2om)9G{yL0MHtyQ0$^ zA9j?XZNp_v`Z-i&EdheZvrKtsvVblI5RBHNBxend&4p(Nt|+IK}&M*`!3%6arl9Q&jN{ z+?pk8Exh2XL0odO;yT;K(R?xeswtsbHpzZ{aynsQ{&T2^2uNqY(zs07o>mKWgTPHm|@l=71YSoI><8Y$)47K0Kdf?=`w4IOPzhB3!kje<7sXV zq!mKM|46`wo=U}bmrpf6b4Ob124RaTHPp;_ycO4gqnYRxq#`>or&!Gy@J<#t0vk)` zz?MB@!CAB-Xxb%D{0kqaav8BwaOAGB*NkX~jCA_{apftBp$pVDleJQLrzAW6*CQP*c>BPD+-{lrF0U0s_|c+#94+r1F}UMIj&T=K$ma|$l2KV{qn13 z%9X;>@WhZ$h&L{6FdqnOQnwP$U8&O1P6JR zz2a()=P1o_!Pn|RN^dl`Mc$TEEMhBdTdsbT`C|iGWIJv>T;k+k_u5@TqBllFUzvjr4{DDu6CC`Zr9P6>NSE~awSq<%DmibO?ODiKT?`QM^ zQSO6#n=&@~PR--3%~-4u!cJI(Trz?a^9oV714(xI{SOqoyv~;a>@s$g5gQ4S-SHSXF3&lQ*TbF9YH2Dm zOQxUw{F=KFg3IKBxehU|x?LiV&U;L#z=maN2f4XP2a0g%mgD#`3WjdJWdE0y=N(#e%G|-l{0@D-zUXnf1{sK;=&8ILU zc}nRc5y@s+Lr?2~c`Gq4!+BYeV%q>xL}j_4{6!CUzN)^MTV&S$2kdpYbH{+ZFNdLhXi~}7W0PvuKO>bC`#Mqy z<7qvR^8-T>hx?!8==C~grY0hvr`qbAp-hBV7jeiS@xxlU8tH$3z<2iHM zA_ztAOrvvy z90F?Otix~mn_09VP8N{t2-A0lh!n=Q{*=U9QZh5Fv!XTkF(ty^@CK_aJNZ>} zb^~!-S?%*RB*)KHf%K5S!5W)I#s;%yxB{g`0Rtq9C3M&oFAdhDETY%@$+$@BOF{G} zdENyKv|-6=HB#0I`!}Y6*|286#_cLU(ME^5C|lPBEMoK-v3Y59z;kl#x*CNiIPKz1 zsuYlVx8I^PG1+fz@=U)C@wxrBRrIkwev`ak?YH``?>8xM%zjffx&5ZMi(El5Cf6B` zt7B3Cj|*7ieG+x^0y+<>JPttXqSDb9aRu2_8b>~rG_JxW8EZbfq}{&6%LO%VesgN6 zImDdkbERlcxl+KLbgJoRc(@g(Q_;(^r~#4j06%%Kv$j3V=i@k1A0ib*5IRmhNunh^ zpmZaGwT`l{Ev-#774~UJH;mM~3Moyx9Mx!;oLymE$CA~V#JXBk4}qgkzrjv z$ir`{Z&6kVD0jdQP`1j@%pVteY1V7K$Rn#5cUj zKpMZeZ?oPocGdWQplF21)kPuL-gvMqE7Vwesu$#%hH_u-(>k}FDdB8c??@%q5GS44 zF9f+&(I$#EW!0*pWN9G_;cSOajz9U7g3u7eqbGW@?q6Zk2p1f2441^?rH5sHDfgK@ zk)0#dth=lm(*foJ%?z2hJRwZxwjcP49colKx>D(^mgiCn6Wk;E_xPhsF7)_px5q^t z=+^}6-Mk^(!tvF6Dce4S>sC` zj^y-5;xeX1keKBnanArG&Xu{}RYhFlp5hb?Y{d^zN&wL40=RPkfE+%KOU{5^VcRbO z*^lc-Xr->+EiI(%qk&untxC&iRi)n-m9WoPcdf2_hFe-@m%h@~$+~53QKf^V^ef$~ zOHX%8i;V9p{amuNNO)EH5mJ)((XaqcDkYsQoo%KF$ z>j%;|E{8y>3f?e!i>}_eiy^LV8jZawdGzAcnk`%PDpm_VPTYc;UpKjNA31FfPFKYb z`qDkqz{D>sTbZ{;wot0#Prrrwg27T5$eM5L1Jyua#8PR4z?@APoT!GGl?9VS8YY`& zwefp^IfW6UV3y~t5i5OdeC`04XE7K7>Ta=TG?0k}wJ!P^rzu}xqK5R!96H?EJ#srsd3SpzKEvpaw$cQ%e z;UdWjm$vG_kG>9{8#O)$FcK9Ez~{^)K0gwC3Yavt)6QE6cgdN=Cr#mFPaQ&wCbTRZ z;xS(hA8(J%*f^HQb#TuFJW1hW#RcQ?CY!tCO>d^y>Zm?NhBpccxrZD3uVOoW{isj~ ze~AR%2Hm@S=~su0SSzm%C#(|e=Cnt<7z8Dl)zFNLj!kUsmf*X=N_SD)RF9&~S>Yzu z)}^f*Zz&ZP_nS`9YhX7D;^4QV_Nhn8HVpgJc;uNC|| z^;xo4{SciFUAWU=RMR^&rcm~qZ%`kbIA6mYf%1qxM%7f3d zBA+MQR(a;N8IB+7ZXA>Fs10zsYLMCuUjhz#FGoo(Y@C3x8uPHK%I-Y>!b7cFmzB~J z)d9ASWz$CcI}l%%tYXaCP8uB`B`GwYH=?5j2#FDUjrV$aH==*yuSiAVSBS7es=)v! zKd6@cV7`y^3~8A^1c!UG$ITMy5j!|g76=rGW$Ob@mMtiS5;zM_o#NeBUX^IZia#kn zXhhO}Ken2_Ux4xc40BuhRI%Du#b5g}4Xgd>L(`k5ATsPlUUT6T$;I%V&;Rw%mDl># zCxsSz?r_^>owk2HgAvmilV>KVbRNHk9pfYotougg(a4yxiK6i{K9R^lwJRE4V5Mr;VI!9~D>#L1^a z*rKVBifii3S8?lE`2u_v4J-qWlCwf6&RN2J<(wrN{Y@z}XES}NIOp=bT0ymTCP5(@ z4{0r#DN}}K7;8)(l$y;a)z&*ClRY6Yzo%R`DP1*3A49=UwO?~i z)6HR=&5rHiItT*h%;$f=j}q{@7p$uSR#P4;cym#1Pi261CY)3G-2MasfUqx~($|aH zC*UmU;m+?Jm8`C$jJ)GBqNC8tlU*yF!yXYOkWi2J{q);B{QHZ?BHrx`x+H@4Ys(H{ z6@3I0!%xGA{){?A3oxQnc+xA@2}8kGIhZt1{Y)8AHSnP_FnpJXq#I1pezj#FCXs;A zxlv3x6Ov2Ra=RFhnUj)PRYupv1{2N}2?jIMWA0V<8%O+M7!Ood{}5HnxR7?sbHDNN zZ;;}DkI6^NweVKFvsjVB?Ktjky$VeficB%0A5g2>GmO5?lQxf5rzm1XuM}&aUaB9{ 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%0D`EY1S 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%0DS=- zfXM(eAOVmC*a#>G90yzg+ylIH2Xz6c0fPZw0DJ&uz+6BoU=^SMuoJK!@FSoZ@F$@C z-FDR0z!xwZkOWu>*aFxGXarmb{0(^JPviyY18@h72lxP{ z0pPd#Ac4e0z9T^-n1ql} zVkTi^8VM&6B$7mt>0}0(NoJARq#ETCmYB{Qb0D5LQ+IF zlP#o}Y$YXR8`(~FkW#Xfl#y~$L3WYdWDlt%Rb(%zCN*RqsU`bK9XUV_l6rE8941G| zQF4qNCnv~Ba*CWLXUJL7KpM%9 z?O_fzvN%Ejm$j$C_n(5tVFF@--8Q+g#t`##BaJ=G!vb-vF~S(hhKx4*8NI&@4LAC; zuj2-qB44OX+dx@eq)%Ml-UECiP16mLMsL1w-UIynygiKmhN$33?@?yIs9<9Ra$lOHI+hMU>SdYGp3k!eZ1`Q~IZVv`sTHl*n6*CD~P!U8Sd#s!<%+Ogk9 zntZ|y;cWHT_fcqM*{eWznu+(IK%;Na`0ywr&A|(W3XNn7#C{xSjQlb*j14sU4K;;E znnD9;zMjEmb2wjK^a<~Q9-c_Z5Du2{X8Fil2=xj#hk@{HS!ftbK2LLah=DDx7&Oul z8W05rmqn)udJhZrGqN;gF%d#r(<0E*6dr+e@rjmjA!FWV@z9A4wRJX2DPn-z+v8lLjz1; zaDks`Dickio}cN4ETQa^R4T5XGG?L8H_}Y8sBmC0WkD<_dzrzd9Ie`Z5(@j` zS992`e~AY%5@{SfGcw%JHaFU_+J^CxfF%iEPOord7)(!XF$L-BEyo>eoM8%;sztlB zw_FghxNPVcpJ3CpC@EDga7HLEtHj*Uew>u!T8R>S&_FZSpV+((&fr2b#l$ zmSC~Qn_oy6jT{=`kA6(^8fu83Y{_Lp8HpwFuuxN^h3w+Rk~gHvNMApQY`(_`;nL9R zJ<^0e&9^c8>}d*x&}0WQ?jr(NQn6o$g+}nwoqI*Xym)2bxj~MWlzsh@l@7FlM6toX zu;pj5=qF2V=SEp?dDj_bh{VVv2vfX;n`WXT2;&SNz>0^kU{(O)8FHTHz&&}7HhYgn z4`VBWAYP(^jl=z;l-H?qT#bhro`@GLsm{cM|zKNQCA=YsyoTv$=o_ZbiGA{EQMi%0A)o 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

r&XcBGALU%*XsJ zz=CHMBP_}u7(otfF$Msb&SJ-4P%w{dtX0NQny13#V>$Ac6 zx+iSPW?!y;$M&Z?@Nh5paX%06AP@0-^r#4r@&}Hv&f{G1Bywn)XLy$9c%DD;0x$9s zFY^ko@@J&eI&bhMf8jQ7@iu?u9o|K!>G3`v@F5@ZF`w`$pK*uJ`GPO`im&;GZ~2bz z`GFttLc7=S8Ga*R1dWh!Z-kAA5j7qRVo+4!d;NW`yrHo&y&@_yqJsW96id7e9|3V? zY0H6J$fFFa6q449>Z`drsC(-lQ|R$@?mSUE$9E2kAhAipT11OtRwo+Ol3E6C^60La z!g@rHg2<$v($kjB@n@}sA!ABvF} zi-~YV6xEuQIa!j=vL+j{DPM4k4$f_%mTIH6YJ)x(cno6Rilcs0kLkzEV-_>$ooDIt zj*d~l-PB_?x`W#p9NfhYH5fqM5!74u0@aur2}JSrA=8o!KC_ zf2y(-+u=h80gy;QUlznwK$#7)`k=`HK|9=g0HhEj32PT%>N@P)fsx0s@CxSjz_wu+ zHVLa1;vWWc?UlrQod!EukrR3Ggju_YbXx{XRq-rp$iEHI6feRCTW#?wI-)Dykl*`a z0M_2mZ7OCsySZ3^y_Hytjo6Bv*o%^^%DU{xE;bT9%xeQVlp{IDZel8D(!u<;kW0Ce zYq^nI>_YbP09rlDt9;6@0xF^&6j5=dz;8xnRbD-*qAIJ3dR8^n0MWK;t5?-kJ+M7g zBQ;SoOr7qtTH{&mK>HD&h45NF%a1)p&QKbmesaituE$} zp4GS3$R^vwF0oG>5=YDxcOK>b6T@w0_(_j1kRq9qIp)wM*`ee6(eFdrJ+gmB%W8S; zNsFLb2n??DQ0)G@bum3xf?EgMSQO6wX6q*0`9^!7Xh4S`X@VWt3_Q6#JbE!^30C~( z!zqmIy87LAuIv8Jbl=?eZZ_9zpPlw@G}mW~E0eh%b1fFQ7_0;$`{#TxMK<`A&V4Wg zu-k)(e}~aqDnFR~Ao7Dpm&SuQiV)0r+m&Ugttbkctwy;He{RMKJ#5}P` zERkw&*m3SWHFqQYFW4!OGIDU0Jj1$m>@%9!mD;35+DOG6OK5MJG<`%ir$garH1D~L`{{J-~%%%y7-evoc$z4a;K_VvLz z%LUG^IbD27 xa7XkP?{7<0w}$!sIVx@_bjp;G{$ETvA3Cg50~rZ~vK}zW^q-^nCyT literal 0 HcmV?d00001 diff --git a/icon.ico b/icon.ico new file mode 100644 index 0000000000000000000000000000000000000000..a43b2d7ba285b3e928a14ca0dbbc46f7e280b992 GIT binary patch literal 32038 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 A@&Et; literal 0 HcmV?d00001 diff --git a/include/freetype/config/ftconfig.h b/include/freetype/config/ftconfig.h new file mode 100644 index 0000000..3b44750 --- /dev/null +++ b/include/freetype/config/ftconfig.h @@ -0,0 +1,350 @@ +/* ftconfig.h. Generated from ftconfig.in by configure. */ +/***************************************************************************/ +/* */ +/* ftconfig.in */ +/* */ +/* UNIX-specific configuration file (specification only). */ +/* */ +/* Copyright 1996-2001, 2002, 2003, 2004, 2006, 2007 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + + /*************************************************************************/ + /* */ + /* This header file contains a number of macro definitions that are used */ + /* by the rest of the engine. Most of the macros here are automatically */ + /* determined at compile time, and you should not need to change it to */ + /* port FreeType, except to compile the library with a non-ANSI */ + /* compiler. */ + /* */ + /* Note however that if some specific modifications are needed, we */ + /* advise you to place a modified copy in your build directory. */ + /* */ + /* The build directory is usually `freetype/builds/', and */ + /* contains system-specific files that are always included first when */ + /* building the library. */ + /* */ + /*************************************************************************/ + + +#ifndef __FTCONFIG_H__ +#define __FTCONFIG_H__ + +#include +#include FT_CONFIG_OPTIONS_H +#include FT_CONFIG_STANDARD_LIBRARY_H + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /* */ + /* PLATFORM-SPECIFIC CONFIGURATION MACROS */ + /* */ + /* These macros can be toggled to suit a specific system. The current */ + /* ones are defaults used to compile FreeType in an ANSI C environment */ + /* (16bit compilers are also supported). Copy this file to your own */ + /* `freetype/builds/' directory, and edit it to port the engine. */ + /* */ + /*************************************************************************/ + + +#define HAVE_UNISTD_H 1 +#define HAVE_FCNTL_H 1 + +#define SIZEOF_INT 4 +#define SIZEOF_LONG 4 + + +#define FT_SIZEOF_INT SIZEOF_INT +#define FT_SIZEOF_LONG SIZEOF_LONG + +#define FT_CHAR_BIT CHAR_BIT + + /* Preferred alignment of data */ +#define FT_ALIGNMENT 8 + + + /* FT_UNUSED is a macro used to indicate that a given parameter is not */ + /* used -- this is only used to get rid of unpleasant compiler warnings */ +#ifndef FT_UNUSED +#define FT_UNUSED( arg ) ( (arg) = (arg) ) +#endif + + + /*************************************************************************/ + /* */ + /* AUTOMATIC CONFIGURATION MACROS */ + /* */ + /* These macros are computed from the ones defined above. Don't touch */ + /* their definition, unless you know precisely what you are doing. No */ + /* porter should need to mess with them. */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* Mac support */ + /* */ + /* This is the only necessary change, so it is defined here instead */ + /* providing a new configuration file. */ + /* */ +#if ( defined( __APPLE__ ) && !defined( DARWIN_NO_CARBON ) ) || \ + ( defined( __MWERKS__ ) && defined( macintosh ) ) + /* no Carbon frameworks for 64bit 10.4.x */ +#include "AvailabilityMacros.h" +#if defined( __LP64__ ) && \ + ( MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_4 ) +#define DARWIN_NO_CARBON 1 +#else +#define FT_MACINTOSH 1 +#endif +#endif + + + /* Fix compiler warning with sgi compiler */ +#if defined( __sgi ) && !defined( __GNUC__ ) +#if defined( _COMPILER_VERSION ) && ( _COMPILER_VERSION >= 730 ) +#pragma set woff 3505 +#endif +#endif + + + /*************************************************************************/ + /* */ + /* IntN types */ + /* */ + /* Used to guarantee the size of some specific integers. */ + /* */ + typedef signed short FT_Int16; + typedef unsigned short FT_UInt16; + +#if FT_SIZEOF_INT == 4 + + typedef signed int FT_Int32; + typedef unsigned int FT_UInt32; + +#elif FT_SIZEOF_LONG == 4 + + typedef signed long FT_Int32; + typedef unsigned long FT_UInt32; + +#else +#error "no 32bit type found -- please check your configuration files" +#endif + + + /* look up an integer type that is at least 32 bits */ +#if FT_SIZEOF_INT >= 4 + + typedef int FT_Fast; + typedef unsigned int FT_UFast; + +#elif FT_SIZEOF_LONG >= 4 + + typedef long FT_Fast; + typedef unsigned long FT_UFast; + +#endif + + + /* determine whether we have a 64-bit int type for platforms without */ + /* Autoconf */ +#if FT_SIZEOF_LONG == 8 + + /* FT_LONG64 must be defined if a 64-bit type is available */ +#define FT_LONG64 +#define FT_INT64 long + +#elif defined( _MSC_VER ) && _MSC_VER >= 900 /* Visual C++ (and Intel C++) */ + + /* this compiler provides the __int64 type */ +#define FT_LONG64 +#define FT_INT64 __int64 + +#elif defined( __BORLANDC__ ) /* Borland C++ */ + + /* XXXX: We should probably check the value of __BORLANDC__ in order */ + /* to test the compiler version. */ + + /* this compiler provides the __int64 type */ +#define FT_LONG64 +#define FT_INT64 __int64 + +#elif defined( __WATCOMC__ ) /* Watcom C++ */ + + /* Watcom doesn't provide 64-bit data types */ + +#elif defined( __MWERKS__ ) /* Metrowerks CodeWarrior */ + +#define FT_LONG64 +#define FT_INT64 long long int + +#elif defined( __GNUC__ ) + + /* GCC provides the `long long' type */ +#define FT_LONG64 +#define FT_INT64 long long int + +#endif /* FT_SIZEOF_LONG == 8 */ + + +#define FT_BEGIN_STMNT do { +#define FT_END_STMNT } while ( 0 ) +#define FT_DUMMY_STMNT FT_BEGIN_STMNT FT_END_STMNT + + + /*************************************************************************/ + /* */ + /* A 64-bit data type will create compilation problems if you compile */ + /* in strict ANSI mode. To avoid them, we disable their use if */ + /* __STDC__ is defined. You can however ignore this rule by */ + /* defining the FT_CONFIG_OPTION_FORCE_INT64 configuration macro. */ + /* */ +#if defined( FT_LONG64 ) && !defined( FT_CONFIG_OPTION_FORCE_INT64 ) + +#ifdef __STDC__ + + /* Undefine the 64-bit macros in strict ANSI compilation mode. */ + /* Since `#undef' doesn't survive in configuration header files */ + /* we use the postprocessing facility of AC_CONFIG_HEADERS to */ + /* replace the leading `/' with `#'. */ +#undef FT_LONG64 +#undef FT_INT64 + +#endif /* __STDC__ */ + +#endif /* FT_LONG64 && !FT_CONFIG_OPTION_FORCE_INT64 */ + + +#ifdef FT_MAKE_OPTION_SINGLE_OBJECT + +#define FT_LOCAL( x ) static x +#define FT_LOCAL_DEF( x ) static x + +#else + +#ifdef __cplusplus +#define FT_LOCAL( x ) extern "C" x +#define FT_LOCAL_DEF( x ) extern "C" x +#else +#define FT_LOCAL( x ) extern x +#define FT_LOCAL_DEF( x ) x +#endif + +#endif /* FT_MAKE_OPTION_SINGLE_OBJECT */ + + +#ifndef FT_BASE + +#ifdef __cplusplus +#define FT_BASE( x ) extern "C" x +#else +#define FT_BASE( x ) extern x +#endif + +#endif /* !FT_BASE */ + + +#ifndef FT_BASE_DEF + +#ifdef __cplusplus +#define FT_BASE_DEF( x ) x +#else +#define FT_BASE_DEF( x ) x +#endif + +#endif /* !FT_BASE_DEF */ + + +#ifndef FT_EXPORT + +#ifdef __cplusplus +#define FT_EXPORT( x ) extern "C" x +#else +#define FT_EXPORT( x ) extern x +#endif + +#endif /* !FT_EXPORT */ + + +#ifndef FT_EXPORT_DEF + +#ifdef __cplusplus +#define FT_EXPORT_DEF( x ) extern "C" x +#else +#define FT_EXPORT_DEF( x ) extern x +#endif + +#endif /* !FT_EXPORT_DEF */ + + +#ifndef FT_EXPORT_VAR + +#ifdef __cplusplus +#define FT_EXPORT_VAR( x ) extern "C" x +#else +#define FT_EXPORT_VAR( x ) extern x +#endif + +#endif /* !FT_EXPORT_VAR */ + + /* The following macros are needed to compile the library with a */ + /* C++ compiler and with 16bit compilers. */ + /* */ + + /* This is special. Within C++, you must specify `extern "C"' for */ + /* functions which are used via function pointers, and you also */ + /* must do that for structures which contain function pointers to */ + /* assure C linkage -- it's not possible to have (local) anonymous */ + /* functions which are accessed by (global) function pointers. */ + /* */ + /* */ + /* FT_CALLBACK_DEF is used to _define_ a callback function. */ + /* */ + /* FT_CALLBACK_TABLE is used to _declare_ a constant variable that */ + /* contains pointers to callback functions. */ + /* */ + /* FT_CALLBACK_TABLE_DEF is used to _define_ a constant variable */ + /* that contains pointers to callback functions. */ + /* */ + /* */ + /* Some 16bit compilers have to redefine these macros to insert */ + /* the infamous `_cdecl' or `__fastcall' declarations. */ + /* */ +#ifndef FT_CALLBACK_DEF +#ifdef __cplusplus +#define FT_CALLBACK_DEF( x ) extern "C" x +#else +#define FT_CALLBACK_DEF( x ) static x +#endif +#endif /* FT_CALLBACK_DEF */ + +#ifndef FT_CALLBACK_TABLE +#ifdef __cplusplus +#define FT_CALLBACK_TABLE extern "C" +#define FT_CALLBACK_TABLE_DEF extern "C" +#else +#define FT_CALLBACK_TABLE extern +#define FT_CALLBACK_TABLE_DEF /* nothing */ +#endif +#endif /* FT_CALLBACK_TABLE */ + + +FT_END_HEADER + + +#endif /* __FTCONFIG_H__ */ + + +/* END */ diff --git a/include/freetype/config/ftheader.h b/include/freetype/config/ftheader.h new file mode 100644 index 0000000..b957d05 --- /dev/null +++ b/include/freetype/config/ftheader.h @@ -0,0 +1,729 @@ +/***************************************************************************/ +/* */ +/* ftheader.h */ +/* */ +/* Build macros of the FreeType 2 library. */ +/* */ +/* Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2007 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + +#ifndef __FT_HEADER_H__ +#define __FT_HEADER_H__ + + + /*@***********************************************************************/ + /* */ + /* */ + /* FT_BEGIN_HEADER */ + /* */ + /* */ + /* This macro is used in association with @FT_END_HEADER in header */ + /* files to ensure that the declarations within are properly */ + /* encapsulated in an `extern "C" { .. }' block when included from a */ + /* C++ compiler. */ + /* */ +#ifdef __cplusplus +#define FT_BEGIN_HEADER extern "C" { +#else +#define FT_BEGIN_HEADER /* nothing */ +#endif + + + /*@***********************************************************************/ + /* */ + /* */ + /* FT_END_HEADER */ + /* */ + /* */ + /* This macro is used in association with @FT_BEGIN_HEADER in header */ + /* files to ensure that the declarations within are properly */ + /* encapsulated in an `extern "C" { .. }' block when included from a */ + /* C++ compiler. */ + /* */ +#ifdef __cplusplus +#define FT_END_HEADER } +#else +#define FT_END_HEADER /* nothing */ +#endif + + + /*************************************************************************/ + /* */ + /* Aliases for the FreeType 2 public and configuration files. */ + /* */ + /*************************************************************************/ + + /*************************************************************************/ + /* */ + /*
*/ + /* header_file_macros */ + /* */ + /* */ + /* Header File Macros */ + /* */ + /* <Abstract> */ + /* Macro definitions used to #include specific header files. */ + /* */ + /* <Description> */ + /* The following macros are defined to the name of specific */ + /* FreeType 2 header files. They can be used directly in #include */ + /* statements as in: */ + /* */ + /* { */ + /* #include FT_FREETYPE_H */ + /* #include FT_MULTIPLE_MASTERS_H */ + /* #include FT_GLYPH_H */ + /* } */ + /* */ + /* There are several reasons why we are now using macros to name */ + /* public header files. The first one is that such macros are not */ + /* limited to the infamous 8.3 naming rule required by DOS (and */ + /* `FT_MULTIPLE_MASTERS_H' is a lot more meaningful than `ftmm.h'). */ + /* */ + /* The second reason is that it allows for more flexibility in the */ + /* way FreeType 2 is installed on a given system. */ + /* */ + /*************************************************************************/ + + + /* configuration files */ + + /************************************************************************* + * + * @macro: + * FT_CONFIG_CONFIG_H + * + * @description: + * A macro used in #include statements to name the file containing + * FreeType 2 configuration data. + * + */ +#ifndef FT_CONFIG_CONFIG_H +#define FT_CONFIG_CONFIG_H <freetype/config/ftconfig.h> +#endif + + + /************************************************************************* + * + * @macro: + * FT_CONFIG_STANDARD_LIBRARY_H + * + * @description: + * A macro used in #include statements to name the file containing + * FreeType 2 interface to the standard C library functions. + * + */ +#ifndef FT_CONFIG_STANDARD_LIBRARY_H +#define FT_CONFIG_STANDARD_LIBRARY_H <freetype/config/ftstdlib.h> +#endif + + + /************************************************************************* + * + * @macro: + * FT_CONFIG_OPTIONS_H + * + * @description: + * A macro used in #include statements to name the file containing + * FreeType 2 project-specific configuration options. + * + */ +#ifndef FT_CONFIG_OPTIONS_H +#define FT_CONFIG_OPTIONS_H <freetype/config/ftoption.h> +#endif + + + /************************************************************************* + * + * @macro: + * FT_CONFIG_MODULES_H + * + * @description: + * A macro used in #include statements to name the file containing the + * list of FreeType 2 modules that are statically linked to new library + * instances in @FT_Init_FreeType. + * + */ +#ifndef FT_CONFIG_MODULES_H +#define FT_CONFIG_MODULES_H <freetype/config/ftmodule.h> +#endif + + + /* public headers */ + + /************************************************************************* + * + * @macro: + * FT_FREETYPE_H + * + * @description: + * A macro used in #include statements to name the file containing the + * base FreeType 2 API. + * + */ +#define FT_FREETYPE_H <freetype/freetype.h> + + + /************************************************************************* + * + * @macro: + * FT_ERRORS_H + * + * @description: + * A macro used in #include statements to name the file containing the + * list of FreeType 2 error codes (and messages). + * + * It is included by @FT_FREETYPE_H. + * + */ +#define FT_ERRORS_H <freetype/fterrors.h> + + + /************************************************************************* + * + * @macro: + * FT_MODULE_ERRORS_H + * + * @description: + * A macro used in #include statements to name the file containing the + * list of FreeType 2 module error offsets (and messages). + * + */ +#define FT_MODULE_ERRORS_H <freetype/ftmoderr.h> + + + /************************************************************************* + * + * @macro: + * FT_SYSTEM_H + * + * @description: + * A macro used in #include statements to name the file containing the + * FreeType 2 interface to low-level operations (i.e., memory management + * and stream i/o). + * + * It is included by @FT_FREETYPE_H. + * + */ +#define FT_SYSTEM_H <freetype/ftsystem.h> + + + /************************************************************************* + * + * @macro: + * FT_IMAGE_H + * + * @description: + * A macro used in #include statements to name the file containing type + * definitions related to glyph images (i.e., bitmaps, outlines, + * scan-converter parameters). + * + * It is included by @FT_FREETYPE_H. + * + */ +#define FT_IMAGE_H <freetype/ftimage.h> + + + /************************************************************************* + * + * @macro: + * FT_TYPES_H + * + * @description: + * A macro used in #include statements to name the file containing the + * basic data types defined by FreeType 2. + * + * It is included by @FT_FREETYPE_H. + * + */ +#define FT_TYPES_H <freetype/fttypes.h> + + + /************************************************************************* + * + * @macro: + * FT_LIST_H + * + * @description: + * A macro used in #include statements to name the file containing the + * list management API of FreeType 2. + * + * (Most applications will never need to include this file.) + * + */ +#define FT_LIST_H <freetype/ftlist.h> + + + /************************************************************************* + * + * @macro: + * FT_OUTLINE_H + * + * @description: + * A macro used in #include statements to name the file containing the + * scalable outline management API of FreeType 2. + * + */ +#define FT_OUTLINE_H <freetype/ftoutln.h> + + + /************************************************************************* + * + * @macro: + * FT_SIZES_H + * + * @description: + * A macro used in #include statements to name the file containing the + * API which manages multiple @FT_Size objects per face. + * + */ +#define FT_SIZES_H <freetype/ftsizes.h> + + + /************************************************************************* + * + * @macro: + * FT_MODULE_H + * + * @description: + * A macro used in #include statements to name the file containing the + * module management API of FreeType 2. + * + */ +#define FT_MODULE_H <freetype/ftmodapi.h> + + + /************************************************************************* + * + * @macro: + * FT_RENDER_H + * + * @description: + * A macro used in #include statements to name the file containing the + * renderer module management API of FreeType 2. + * + */ +#define FT_RENDER_H <freetype/ftrender.h> + + + /************************************************************************* + * + * @macro: + * FT_TYPE1_TABLES_H + * + * @description: + * A macro used in #include statements to name the file containing the + * types and API specific to the Type 1 format. + * + */ +#define FT_TYPE1_TABLES_H <freetype/t1tables.h> + + + /************************************************************************* + * + * @macro: + * FT_TRUETYPE_IDS_H + * + * @description: + * A macro used in #include statements to name the file containing the + * enumeration values which identify name strings, languages, encodings, + * etc. This file really contains a _large_ set of constant macro + * definitions, taken from the TrueType and OpenType specifications. + * + */ +#define FT_TRUETYPE_IDS_H <freetype/ttnameid.h> + + + /************************************************************************* + * + * @macro: + * FT_TRUETYPE_TABLES_H + * + * @description: + * A macro used in #include statements to name the file containing the + * types and API specific to the TrueType (as well as OpenType) format. + * + */ +#define FT_TRUETYPE_TABLES_H <freetype/tttables.h> + + + /************************************************************************* + * + * @macro: + * FT_TRUETYPE_TAGS_H + * + * @description: + * A macro used in #include statements to name the file containing the + * definitions of TrueType four-byte `tags' which identify blocks in + * SFNT-based font formats (i.e., TrueType and OpenType). + * + */ +#define FT_TRUETYPE_TAGS_H <freetype/tttags.h> + + + /************************************************************************* + * + * @macro: + * FT_BDF_H + * + * @description: + * A macro used in #include statements to name the file containing the + * definitions of an API which accesses BDF-specific strings from a + * face. + * + */ +#define FT_BDF_H <freetype/ftbdf.h> + + + /************************************************************************* + * + * @macro: + * FT_GZIP_H + * + * @description: + * A macro used in #include statements to name the file containing the + * definitions of an API which supports gzip-compressed files. + * + */ +#define FT_GZIP_H <freetype/ftgzip.h> + + + /************************************************************************* + * + * @macro: + * FT_LZW_H + * + * @description: + * A macro used in #include statements to name the file containing the + * definitions of an API which supports LZW-compressed files. + * + */ +#define FT_LZW_H <freetype/ftlzw.h> + + + /************************************************************************* + * + * @macro: + * FT_WINFONTS_H + * + * @description: + * A macro used in #include statements to name the file containing the + * definitions of an API which supports Windows FNT files. + * + */ +#define FT_WINFONTS_H <freetype/ftwinfnt.h> + + + /************************************************************************* + * + * @macro: + * FT_GLYPH_H + * + * @description: + * A macro used in #include statements to name the file containing the + * API of the optional glyph management component. + * + */ +#define FT_GLYPH_H <freetype/ftglyph.h> + + + /************************************************************************* + * + * @macro: + * FT_BITMAP_H + * + * @description: + * A macro used in #include statements to name the file containing the + * API of the optional bitmap conversion component. + * + */ +#define FT_BITMAP_H <freetype/ftbitmap.h> + + + /************************************************************************* + * + * @macro: + * FT_BBOX_H + * + * @description: + * A macro used in #include statements to name the file containing the + * API of the optional exact bounding box computation routines. + * + */ +#define FT_BBOX_H <freetype/ftbbox.h> + + + /************************************************************************* + * + * @macro: + * FT_CACHE_H + * + * @description: + * A macro used in #include statements to name the file containing the + * API of the optional FreeType 2 cache sub-system. + * + */ +#define FT_CACHE_H <freetype/ftcache.h> + + + /************************************************************************* + * + * @macro: + * FT_CACHE_IMAGE_H + * + * @description: + * A macro used in #include statements to name the file containing the + * `glyph image' API of the FreeType 2 cache sub-system. + * + * It is used to define a cache for @FT_Glyph elements. You can also + * use the API defined in @FT_CACHE_SMALL_BITMAPS_H if you only need to + * store small glyph bitmaps, as it will use less memory. + * + * This macro is deprecated. Simply include @FT_CACHE_H to have all + * glyph image-related cache declarations. + * + */ +#define FT_CACHE_IMAGE_H FT_CACHE_H + + + /************************************************************************* + * + * @macro: + * FT_CACHE_SMALL_BITMAPS_H + * + * @description: + * A macro used in #include statements to name the file containing the + * `small bitmaps' API of the FreeType 2 cache sub-system. + * + * It is used to define a cache for small glyph bitmaps in a relatively + * memory-efficient way. You can also use the API defined in + * @FT_CACHE_IMAGE_H if you want to cache arbitrary glyph images, + * including scalable outlines. + * + * This macro is deprecated. Simply include @FT_CACHE_H to have all + * small bitmaps-related cache declarations. + * + */ +#define FT_CACHE_SMALL_BITMAPS_H FT_CACHE_H + + + /************************************************************************* + * + * @macro: + * FT_CACHE_CHARMAP_H + * + * @description: + * A macro used in #include statements to name the file containing the + * `charmap' API of the FreeType 2 cache sub-system. + * + * This macro is deprecated. Simply include @FT_CACHE_H to have all + * charmap-based cache declarations. + * + */ +#define FT_CACHE_CHARMAP_H FT_CACHE_H + + + /************************************************************************* + * + * @macro: + * FT_MAC_H + * + * @description: + * A macro used in #include statements to name the file containing the + * Macintosh-specific FreeType 2 API. The latter is used to access + * fonts embedded in resource forks. + * + * This header file must be explicitly included by client applications + * compiled on the Mac (note that the base API still works though). + * + */ +#define FT_MAC_H <freetype/ftmac.h> + + + /************************************************************************* + * + * @macro: + * FT_MULTIPLE_MASTERS_H + * + * @description: + * A macro used in #include statements to name the file containing the + * optional multiple-masters management API of FreeType 2. + * + */ +#define FT_MULTIPLE_MASTERS_H <freetype/ftmm.h> + + + /************************************************************************* + * + * @macro: + * FT_SFNT_NAMES_H + * + * @description: + * A macro used in #include statements to name the file containing the + * optional FreeType 2 API which accesses embedded `name' strings in + * SFNT-based font formats (i.e., TrueType and OpenType). + * + */ +#define FT_SFNT_NAMES_H <freetype/ftsnames.h> + + + /************************************************************************* + * + * @macro: + * FT_OPENTYPE_VALIDATE_H + * + * @description: + * A macro used in #include statements to name the file containing the + * optional FreeType 2 API which validates OpenType tables (BASE, GDEF, + * GPOS, GSUB, JSTF). + * + */ +#define FT_OPENTYPE_VALIDATE_H <freetype/ftotval.h> + + + /************************************************************************* + * + * @macro: + * FT_GX_VALIDATE_H + * + * @description: + * A macro used in #include statements to name the file containing the + * optional FreeType 2 API which validates TrueTypeGX/AAT tables (feat, + * mort, morx, bsln, just, kern, opbd, trak, prop). + * + */ +#define FT_GX_VALIDATE_H <freetype/ftgxval.h> + + + /************************************************************************* + * + * @macro: + * FT_PFR_H + * + * @description: + * A macro used in #include statements to name the file containing the + * FreeType 2 API which accesses PFR-specific data. + * + */ +#define FT_PFR_H <freetype/ftpfr.h> + + + /************************************************************************* + * + * @macro: + * FT_STROKER_H + * + * @description: + * A macro used in #include statements to name the file containing the + * FreeType 2 API which provides functions to stroke outline paths. + */ +#define FT_STROKER_H <freetype/ftstroke.h> + + + /************************************************************************* + * + * @macro: + * FT_SYNTHESIS_H + * + * @description: + * A macro used in #include statements to name the file containing the + * FreeType 2 API which performs artificial obliquing and emboldening. + */ +#define FT_SYNTHESIS_H <freetype/ftsynth.h> + + + /************************************************************************* + * + * @macro: + * FT_XFREE86_H + * + * @description: + * A macro used in #include statements to name the file containing the + * FreeType 2 API which provides functions specific to the XFree86 and + * X.Org X11 servers. + */ +#define FT_XFREE86_H <freetype/ftxf86.h> + + + /************************************************************************* + * + * @macro: + * FT_TRIGONOMETRY_H + * + * @description: + * A macro used in #include statements to name the file containing the + * FreeType 2 API which performs trigonometric computations (e.g., + * cosines and arc tangents). + */ +#define FT_TRIGONOMETRY_H <freetype/fttrigon.h> + + + /************************************************************************* + * + * @macro: + * FT_LCD_FILTER_H + * + * @description: + * A macro used in #include statements to name the file containing the + * FreeType 2 API which performs color filtering for subpixel rendering. + */ +#define FT_LCD_FILTER_H <freetype/ftlcdfil.h> + + + /************************************************************************* + * + * @macro: + * FT_GASP_H + * + * @description: + * A macro used in #include statements to name the file containing the + * FreeType 2 API which returns entries from the TrueType GASP table. + */ +#define FT_GASP_H <freetype/ftgasp.h> + + + /* */ + +#define FT_ERROR_DEFINITIONS_H <freetype/fterrdef.h> + + + /* The internals of the cache sub-system are no longer exposed. We */ + /* default to FT_CACHE_H at the moment just in case, but we know of */ + /* no rogue client that uses them. */ + /* */ +#define FT_CACHE_MANAGER_H <freetype/ftcache.h> +#define FT_CACHE_INTERNAL_MRU_H <freetype/ftcache.h> +#define FT_CACHE_INTERNAL_MANAGER_H <freetype/ftcache.h> +#define FT_CACHE_INTERNAL_CACHE_H <freetype/ftcache.h> +#define FT_CACHE_INTERNAL_GLYPH_H <freetype/ftcache.h> +#define FT_CACHE_INTERNAL_IMAGE_H <freetype/ftcache.h> +#define FT_CACHE_INTERNAL_SBITS_H <freetype/ftcache.h> + + +#define FT_INCREMENTAL_H <freetype/ftincrem.h> + +#define FT_TRUETYPE_UNPATENTED_H <freetype/ttunpat.h> + + + /* + * Include internal headers definitions from <freetype/internal/...> + * only when building the library. + */ +#ifdef FT2_BUILD_LIBRARY +#define FT_INTERNAL_INTERNAL_H <freetype/internal/internal.h> +#include FT_INTERNAL_INTERNAL_H +#endif /* FT2_BUILD_LIBRARY */ + + +#endif /* __FT2_BUILD_H__ */ + + +/* END */ diff --git a/include/freetype/config/ftmodule.h b/include/freetype/config/ftmodule.h new file mode 100644 index 0000000..c28052b --- /dev/null +++ b/include/freetype/config/ftmodule.h @@ -0,0 +1,22 @@ +/* This is a generated file. */ +FT_USE_MODULE(tt_driver_class) +FT_USE_MODULE(t1_driver_class) +FT_USE_MODULE(cff_driver_class) +FT_USE_MODULE(t1cid_driver_class) +FT_USE_MODULE(pfr_driver_class) +FT_USE_MODULE(t42_driver_class) +FT_USE_MODULE(winfnt_driver_class) +FT_USE_MODULE(pcf_driver_class) +FT_USE_MODULE(bdf_driver_class) +FT_USE_MODULE(sfnt_module_class) +FT_USE_MODULE(autofit_module_class) +FT_USE_MODULE(pshinter_module_class) +FT_USE_MODULE(ft_raster1_renderer_class) +FT_USE_MODULE(ft_smooth_renderer_class) +FT_USE_MODULE(ft_smooth_lcd_renderer_class) +FT_USE_MODULE(ft_smooth_lcdv_renderer_class) +FT_USE_MODULE(gxv_module_class) +FT_USE_MODULE(otv_module_class) +FT_USE_MODULE(psaux_module_class) +FT_USE_MODULE(psnames_module_class) +/* EOF */ diff --git a/include/freetype/config/ftoption.h b/include/freetype/config/ftoption.h new file mode 100644 index 0000000..0b5c66d --- /dev/null +++ b/include/freetype/config/ftoption.h @@ -0,0 +1,695 @@ +/***************************************************************************/ +/* */ +/* ftoption.h */ +/* */ +/* User-selectable configuration macros (specification only). */ +/* */ +/* Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2007 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef __FTOPTION_H__ +#define __FTOPTION_H__ + + +#include <ft2build.h> + + +FT_BEGIN_HEADER + + /*************************************************************************/ + /* */ + /* USER-SELECTABLE CONFIGURATION MACROS */ + /* */ + /* This file contains the default configuration macro definitions for */ + /* a standard build of the FreeType library. There are three ways to */ + /* use this file to build project-specific versions of the library: */ + /* */ + /* - You can modify this file by hand, but this is not recommended in */ + /* cases where you would like to build several versions of the */ + /* library from a single source directory. */ + /* */ + /* - You can put a copy of this file in your build directory, more */ + /* precisely in `$BUILD/freetype/config/ftoption.h', where `$BUILD' */ + /* is the name of a directory that is included _before_ the FreeType */ + /* include path during compilation. */ + /* */ + /* The default FreeType Makefiles and Jamfiles use the build */ + /* directory `builds/<system>' by default, but you can easily change */ + /* that for your own projects. */ + /* */ + /* - Copy the file <ft2build.h> to `$BUILD/ft2build.h' and modify it */ + /* slightly to pre-define the macro FT_CONFIG_OPTIONS_H used to */ + /* locate this file during the build. For example, */ + /* */ + /* #define FT_CONFIG_OPTIONS_H <myftoptions.h> */ + /* #include <freetype/config/ftheader.h> */ + /* */ + /* will use `$BUILD/myftoptions.h' instead of this file for macro */ + /* definitions. */ + /* */ + /* Note also that you can similarly pre-define the macro */ + /* FT_CONFIG_MODULES_H used to locate the file listing of the modules */ + /* that are statically linked to the library at compile time. By */ + /* default, this file is <freetype/config/ftmodule.h>. */ + /* */ + /* We highly recommend using the third method whenever possible. */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** G E N E R A L F R E E T Y P E 2 C O N F I G U R A T I O N ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* Uncomment the line below if you want to activate sub-pixel rendering */ + /* (a.k.a. LCD rendering, or ClearType) in this build of the library. */ + /* */ + /* Note that this feature is covered by several Microsoft patents */ + /* and should not be activated in any default build of the library. */ + /* */ + /* This macro has no impact on the FreeType API, only on its */ + /* _implementation_. For example, using FT_RENDER_MODE_LCD when calling */ + /* FT_Render_Glyph still generates a bitmap that is 3 times larger than */ + /* the original size; the difference will be that each triplet of */ + /* subpixels has R=G=B. */ + /* */ + /* This is done to allow FreeType clients to run unmodified, forcing */ + /* them to display normal gray-level anti-aliased glyphs. */ + /* */ +#define FT_CONFIG_OPTION_SUBPIXEL_RENDERING + + + /*************************************************************************/ + /* */ + /* Many compilers provide a non-ANSI 64-bit data type that can be used */ + /* by FreeType to speed up some computations. However, this will create */ + /* some problems when compiling the library in strict ANSI mode. */ + /* */ + /* For this reason, the use of 64-bit integers is normally disabled when */ + /* the __STDC__ macro is defined. You can however disable this by */ + /* defining the macro FT_CONFIG_OPTION_FORCE_INT64 here. */ + /* */ + /* For most compilers, this will only create compilation warnings when */ + /* building the library. */ + /* */ + /* ObNote: The compiler-specific 64-bit integers are detected in the */ + /* file `ftconfig.h' either statically or through the */ + /* `configure' script on supported platforms. */ + /* */ +#undef FT_CONFIG_OPTION_FORCE_INT64 + + + /*************************************************************************/ + /* */ + /* LZW-compressed file support. */ + /* */ + /* FreeType now handles font files that have been compressed with the */ + /* `compress' program. This is mostly used to parse many of the PCF */ + /* files that come with various X11 distributions. The implementation */ + /* uses NetBSD's `zopen' to partially uncompress the file on the fly */ + /* (see src/lzw/ftgzip.c). */ + /* */ + /* Define this macro if you want to enable this `feature'. */ + /* */ +#define FT_CONFIG_OPTION_USE_LZW + + + /*************************************************************************/ + /* */ + /* Gzip-compressed file support. */ + /* */ + /* FreeType now handles font files that have been compressed with the */ + /* `gzip' program. This is mostly used to parse many of the PCF files */ + /* that come with XFree86. The implementation uses `zlib' to */ + /* partially uncompress the file on the fly (see src/gzip/ftgzip.c). */ + /* */ + /* Define this macro if you want to enable this `feature'. See also */ + /* the macro FT_CONFIG_OPTION_SYSTEM_ZLIB below. */ + /* */ +#define FT_CONFIG_OPTION_USE_ZLIB + + + /*************************************************************************/ + /* */ + /* ZLib library selection */ + /* */ + /* This macro is only used when FT_CONFIG_OPTION_USE_ZLIB is defined. */ + /* It allows FreeType's `ftgzip' component to link to the system's */ + /* installation of the ZLib library. This is useful on systems like */ + /* Unix or VMS where it generally is already available. */ + /* */ + /* If you let it undefined, the component will use its own copy */ + /* of the zlib sources instead. These have been modified to be */ + /* included directly within the component and *not* export external */ + /* function names. This allows you to link any program with FreeType */ + /* _and_ ZLib without linking conflicts. */ + /* */ + /* Do not #undef this macro here since the build system might define */ + /* it for certain configurations only. */ + /* */ +/* #define FT_CONFIG_OPTION_SYSTEM_ZLIB */ + + + /*************************************************************************/ + /* */ + /* DLL export compilation */ + /* */ + /* When compiling FreeType as a DLL, some systems/compilers need a */ + /* special keyword in front OR after the return type of function */ + /* declarations. */ + /* */ + /* Two macros are used within the FreeType source code to define */ + /* exported library functions: FT_EXPORT and FT_EXPORT_DEF. */ + /* */ + /* FT_EXPORT( return_type ) */ + /* */ + /* is used in a function declaration, as in */ + /* */ + /* FT_EXPORT( FT_Error ) */ + /* FT_Init_FreeType( FT_Library* alibrary ); */ + /* */ + /* */ + /* FT_EXPORT_DEF( return_type ) */ + /* */ + /* is used in a function definition, as in */ + /* */ + /* FT_EXPORT_DEF( FT_Error ) */ + /* FT_Init_FreeType( FT_Library* alibrary ) */ + /* { */ + /* ... some code ... */ + /* return FT_Err_Ok; */ + /* } */ + /* */ + /* You can provide your own implementation of FT_EXPORT and */ + /* FT_EXPORT_DEF here if you want. If you leave them undefined, they */ + /* will be later automatically defined as `extern return_type' to */ + /* allow normal compilation. */ + /* */ + /* Do not #undef these macros here since the build system might define */ + /* them for certain configurations only. */ + /* */ +/* #define FT_EXPORT(x) extern x */ +/* #define FT_EXPORT_DEF(x) x */ +#ifndef __GNUC__ +# define __DLL_IMPORT__ __declspec(dllimport) +# define __DLL_EXPORT__ __declspec(dllexport) +#else +# define __DLL_IMPORT__ __attribute__((dllimport)) extern +# define __DLL_EXPORT__ __attribute__((dllexport)) extern +#endif + +#if (defined __WIN32__) || (defined _WIN32) +# ifdef BUILD_FREETYPE2_DLL +# define FREETYPE2_DLL_IMPEXP __DLL_EXPORT__ +# elif defined(FREETYPE2_STATIC) +# define FREETYPE2_DLL_IMPEXP +# elif defined (USE_FREETYPE2_DLL) +# define FREETYPE2_DLL_IMPEXP __DLL_IMPORT__ +# elif defined (USE_FREETYPE2_STATIC) +# define FREETYPE2_DLL_IMPEXP +# else /* assume USE_FREETYPE2_DLL */ +# define FREETYPE2_DLL_IMPEXP __DLL_IMPORT__ +# endif +#else /* __WIN32__ */ +# define FREETYPE2_DLL_IMPEXP +#endif + +#define FT_EXPORT(x) FREETYPE2_DLL_IMPEXP x +#define FT_BASE(x) FREETYPE2_DLL_IMPEXP x + + + /*************************************************************************/ + /* */ + /* Glyph Postscript Names handling */ + /* */ + /* By default, FreeType 2 is compiled with the `PSNames' module. This */ + /* module is in charge of converting a glyph name string into a */ + /* Unicode value, or return a Macintosh standard glyph name for the */ + /* use with the TrueType `post' table. */ + /* */ + /* Undefine this macro if you do not want `PSNames' compiled in your */ + /* build of FreeType. This has the following effects: */ + /* */ + /* - The TrueType driver will provide its own set of glyph names, */ + /* if you build it to support postscript names in the TrueType */ + /* `post' table. */ + /* */ + /* - The Type 1 driver will not be able to synthetize a Unicode */ + /* charmap out of the glyphs found in the fonts. */ + /* */ + /* You would normally undefine this configuration macro when building */ + /* a version of FreeType that doesn't contain a Type 1 or CFF driver. */ + /* */ +#define FT_CONFIG_OPTION_POSTSCRIPT_NAMES + + + /*************************************************************************/ + /* */ + /* Postscript Names to Unicode Values support */ + /* */ + /* By default, FreeType 2 is built with the `PSNames' module compiled */ + /* in. Among other things, the module is used to convert a glyph name */ + /* into a Unicode value. This is especially useful in order to */ + /* synthetize on the fly a Unicode charmap from the CFF/Type 1 driver */ + /* through a big table named the `Adobe Glyph List' (AGL). */ + /* */ + /* Undefine this macro if you do not want the Adobe Glyph List */ + /* compiled in your `PSNames' module. The Type 1 driver will not be */ + /* able to synthetize a Unicode charmap out of the glyphs found in the */ + /* fonts. */ + /* */ +#define FT_CONFIG_OPTION_ADOBE_GLYPH_LIST + + + /*************************************************************************/ + /* */ + /* Support for Mac fonts */ + /* */ + /* Define this macro if you want support for outline fonts in Mac */ + /* format (mac dfont, mac resource, macbinary containing a mac */ + /* resource) on non-Mac platforms. */ + /* */ + /* Note that the `FOND' resource isn't checked. */ + /* */ +#define FT_CONFIG_OPTION_MAC_FONTS + + + /*************************************************************************/ + /* */ + /* Guessing methods to access embedded resource forks */ + /* */ + /* Enable extra Mac fonts support on non-Mac platforms (e.g. */ + /* GNU/Linux). */ + /* */ + /* Resource forks which include fonts data are stored sometimes in */ + /* locations which users or developers don't expected. In some cases, */ + /* resource forks start with some offset from the head of a file. In */ + /* other cases, the actual resource fork is stored in file different */ + /* from what the user specifies. If this option is activated, */ + /* FreeType tries to guess whether such offsets or different file */ + /* names must be used. */ + /* */ + /* Note that normal, direct access of resource forks is controlled via */ + /* the FT_CONFIG_OPTION_MAC_FONTS option. */ + /* */ +#ifdef FT_CONFIG_OPTION_MAC_FONTS +#define FT_CONFIG_OPTION_GUESSING_EMBEDDED_RFORK +#endif + + + /*************************************************************************/ + /* */ + /* Allow the use of FT_Incremental_Interface to load typefaces that */ + /* contain no glyph data, but supply it via a callback function. */ + /* This allows FreeType to be used with the PostScript language, using */ + /* the GhostScript interpreter. */ + /* */ +/* #define FT_CONFIG_OPTION_INCREMENTAL */ + + + /*************************************************************************/ + /* */ + /* The size in bytes of the render pool used by the scan-line converter */ + /* to do all of its work. */ + /* */ + /* This must be greater than 4KByte if you use FreeType to rasterize */ + /* glyphs; otherwise, you may set it to zero to avoid unnecessary */ + /* allocation of the render pool. */ + /* */ +#define FT_RENDER_POOL_SIZE 16384L + + + /*************************************************************************/ + /* */ + /* FT_MAX_MODULES */ + /* */ + /* The maximum number of modules that can be registered in a single */ + /* FreeType library object. 32 is the default. */ + /* */ +#define FT_MAX_MODULES 32 + + + /*************************************************************************/ + /* */ + /* Debug level */ + /* */ + /* FreeType can be compiled in debug or trace mode. In debug mode, */ + /* errors are reported through the `ftdebug' component. In trace */ + /* mode, additional messages are sent to the standard output during */ + /* execution. */ + /* */ + /* Define FT_DEBUG_LEVEL_ERROR to build the library in debug mode. */ + /* Define FT_DEBUG_LEVEL_TRACE to build it in trace mode. */ + /* */ + /* Don't define any of these macros to compile in `release' mode! */ + /* */ + /* Do not #undef these macros here since the build system might define */ + /* them for certain configurations only. */ + /* */ +/* #define FT_DEBUG_LEVEL_ERROR */ +/* #define FT_DEBUG_LEVEL_TRACE */ + + + /*************************************************************************/ + /* */ + /* Memory Debugging */ + /* */ + /* FreeType now comes with an integrated memory debugger that is */ + /* capable of detecting simple errors like memory leaks or double */ + /* deletes. To compile it within your build of the library, you */ + /* should define FT_DEBUG_MEMORY here. */ + /* */ + /* Note that the memory debugger is only activated at runtime when */ + /* when the _environment_ variable `FT2_DEBUG_MEMORY' is defined also! */ + /* */ + /* Do not #undef this macro here since the build system might define */ + /* it for certain configurations only. */ + /* */ +/* #define FT_DEBUG_MEMORY */ + + + /*************************************************************************/ + /* */ + /* Module errors */ + /* */ + /* If this macro is set (which is _not_ the default), the higher byte */ + /* of an error code gives the module in which the error has occurred, */ + /* while the lower byte is the real error code. */ + /* */ + /* Setting this macro makes sense for debugging purposes only, since */ + /* it would break source compatibility of certain programs that use */ + /* FreeType 2. */ + /* */ + /* More details can be found in the files ftmoderr.h and fterrors.h. */ + /* */ +#undef FT_CONFIG_OPTION_USE_MODULE_ERRORS + + + + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** S F N T D R I V E R C O N F I G U R A T I O N ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* Define TT_CONFIG_OPTION_EMBEDDED_BITMAPS if you want to support */ + /* embedded bitmaps in all formats using the SFNT module (namely */ + /* TrueType & OpenType). */ + /* */ +#define TT_CONFIG_OPTION_EMBEDDED_BITMAPS + + + /*************************************************************************/ + /* */ + /* Define TT_CONFIG_OPTION_POSTSCRIPT_NAMES if you want to be able to */ + /* load and enumerate the glyph Postscript names in a TrueType or */ + /* OpenType file. */ + /* */ + /* Note that when you do not compile the `PSNames' module by undefining */ + /* the above FT_CONFIG_OPTION_POSTSCRIPT_NAMES, the `sfnt' module will */ + /* contain additional code used to read the PS Names table from a font. */ + /* */ + /* (By default, the module uses `PSNames' to extract glyph names.) */ + /* */ +#define TT_CONFIG_OPTION_POSTSCRIPT_NAMES + + + /*************************************************************************/ + /* */ + /* Define TT_CONFIG_OPTION_SFNT_NAMES if your applications need to */ + /* access the internal name table in a SFNT-based format like TrueType */ + /* or OpenType. The name table contains various strings used to */ + /* describe the font, like family name, copyright, version, etc. It */ + /* does not contain any glyph name though. */ + /* */ + /* Accessing SFNT names is done through the functions declared in */ + /* `freetype/ftnames.h'. */ + /* */ +#define TT_CONFIG_OPTION_SFNT_NAMES + + + /*************************************************************************/ + /* */ + /* TrueType CMap support */ + /* */ + /* Here you can fine-tune which TrueType CMap table format shall be */ + /* supported. */ +#define TT_CONFIG_CMAP_FORMAT_0 +#define TT_CONFIG_CMAP_FORMAT_2 +#define TT_CONFIG_CMAP_FORMAT_4 +#define TT_CONFIG_CMAP_FORMAT_6 +#define TT_CONFIG_CMAP_FORMAT_8 +#define TT_CONFIG_CMAP_FORMAT_10 +#define TT_CONFIG_CMAP_FORMAT_12 + + + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** T R U E T Y P E D R I V E R C O N F I G U R A T I O N ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + + /*************************************************************************/ + /* */ + /* Define TT_CONFIG_OPTION_BYTECODE_INTERPRETER if you want to compile */ + /* a bytecode interpreter in the TrueType driver. Note that there are */ + /* important patent issues related to the use of the interpreter. */ + /* */ + /* By undefining this, you will only compile the code necessary to load */ + /* TrueType glyphs without hinting. */ + /* */ + /* Do not #undef this macro here, since the build system might */ + /* define it for certain configurations only. */ + /* */ +/* #define TT_CONFIG_OPTION_BYTECODE_INTERPRETER */ + + + /*************************************************************************/ + /* */ + /* If you define TT_CONFIG_OPTION_UNPATENTED_HINTING, a special version */ + /* of the TrueType bytecode interpreter is used that doesn't implement */ + /* any of the patented opcodes and algorithms. Note that the */ + /* the TT_CONFIG_OPTION_UNPATENTED_HINTING macro is *ignored* if you */ + /* define TT_CONFIG_OPTION_BYTECODE_INTERPRETER; with other words, */ + /* either define TT_CONFIG_OPTION_BYTECODE_INTERPRETER or */ + /* TT_CONFIG_OPTION_UNPATENTED_HINTING but not both at the same time. */ + /* */ + /* This macro is only useful for a small number of font files (mostly */ + /* for Asian scripts) that require bytecode interpretation to properly */ + /* load glyphs. For all other fonts, this produces unpleasant results, */ + /* thus the unpatented interpreter is never used to load glyphs from */ + /* TrueType fonts unless one of the following two options is used. */ + /* */ + /* - The unpatented interpreter is explicitly activated by the user */ + /* through the FT_PARAM_TAG_UNPATENTED_HINTING parameter tag */ + /* when opening the FT_Face. */ + /* */ + /* - FreeType detects that the FT_Face corresponds to one of the */ + /* `trick' fonts (e.g., `Mingliu') it knows about. The font engine */ + /* contains a hard-coded list of font names and other matching */ + /* parameters (see function `tt_face_init' in file */ + /* `src/truetype/ttobjs.c'). */ + /* */ + /* Here a sample code snippet for using FT_PARAM_TAG_UNPATENTED_HINTING. */ + /* */ + /* { */ + /* FT_Parameter parameter; */ + /* FT_Open_Args open_args; */ + /* */ + /* */ + /* parameter.tag = FT_PARAM_TAG_UNPATENTED_HINTING; */ + /* */ + /* open_args.flags = FT_OPEN_PATHNAME | FT_OPEN_PARAMS; */ + /* open_args.pathname = my_font_pathname; */ + /* open_args.num_params = 1; */ + /* open_args.params = ¶meter; */ + /* */ + /* error = FT_Open_Face( library, &open_args, index, &face ); */ + /* ... */ + /* } */ + /* */ +#define TT_CONFIG_OPTION_UNPATENTED_HINTING + + + /*************************************************************************/ + /* */ + /* Define TT_CONFIG_OPTION_INTERPRETER_SWITCH to compile the TrueType */ + /* bytecode interpreter with a huge switch statement, rather than a call */ + /* table. This results in smaller and faster code for a number of */ + /* architectures. */ + /* */ + /* Note however that on some compiler/processor combinations, undefining */ + /* this macro will generate faster, though larger, code. */ + /* */ +#define TT_CONFIG_OPTION_INTERPRETER_SWITCH + + + /*************************************************************************/ + /* */ + /* Define TT_CONFIG_OPTION_COMPONENT_OFFSET_SCALED to compile the */ + /* TrueType glyph loader to use Apple's definition of how to handle */ + /* component offsets in composite glyphs. */ + /* */ + /* Apple and MS disagree on the default behavior of component offsets */ + /* in composites. Apple says that they should be scaled by the scaling */ + /* factors in the transformation matrix (roughly, it's more complex) */ + /* while MS says they should not. OpenType defines two bits in the */ + /* composite flags array which can be used to disambiguate, but old */ + /* fonts will not have them. */ + /* */ + /* http://partners.adobe.com/asn/developer/opentype/glyf.html */ + /* http://fonts.apple.com/TTRefMan/RM06/Chap6glyf.html */ + /* */ +#undef TT_CONFIG_OPTION_COMPONENT_OFFSET_SCALED + + + /*************************************************************************/ + /* */ + /* Define TT_CONFIG_OPTION_GX_VAR_SUPPORT if you want to include */ + /* support for Apple's distortable font technology (fvar, gvar, cvar, */ + /* and avar tables). This has many similarities to Type 1 Multiple */ + /* Masters support. */ + /* */ +#define TT_CONFIG_OPTION_GX_VAR_SUPPORT + + + /*************************************************************************/ + /* */ + /* Define TT_CONFIG_OPTION_BDF if you want to include support for */ + /* an embedded `BDF ' table within SFNT-based bitmap formats. */ + /* */ +#define TT_CONFIG_OPTION_BDF + + + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** T Y P E 1 D R I V E R C O N F I G U R A T I O N ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* T1_MAX_DICT_DEPTH is the maximal depth of nest dictionaries and */ + /* arrays in the Type 1 stream (see t1load.c). A minimum of 4 is */ + /* required. */ + /* */ +#define T1_MAX_DICT_DEPTH 5 + + + /*************************************************************************/ + /* */ + /* T1_MAX_SUBRS_CALLS details the maximum number of nested sub-routine */ + /* calls during glyph loading. */ + /* */ +#define T1_MAX_SUBRS_CALLS 16 + + + /*************************************************************************/ + /* */ + /* T1_MAX_CHARSTRING_OPERANDS is the charstring stack's capacity. A */ + /* minimum of 16 is required. */ + /* */ + /* The Chinese font MingTiEG-Medium (CNS 11643 character set) needs 256. */ + /* */ +#define T1_MAX_CHARSTRINGS_OPERANDS 256 + + + /*************************************************************************/ + /* */ + /* Define this configuration macro if you want to prevent the */ + /* compilation of `t1afm', which is in charge of reading Type 1 AFM */ + /* files into an existing face. Note that if set, the T1 driver will be */ + /* unable to produce kerning distances. */ + /* */ +#undef T1_CONFIG_OPTION_NO_AFM + + + /*************************************************************************/ + /* */ + /* Define this configuration macro if you want to prevent the */ + /* compilation of the Multiple Masters font support in the Type 1 */ + /* driver. */ + /* */ +#undef T1_CONFIG_OPTION_NO_MM_SUPPORT + + + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** A U T O F I T M O D U L E C O N F I G U R A T I O N ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* Compile autofit module with CJK script support. */ + /* */ +#define AF_CONFIG_OPTION_CJK + + /*************************************************************************/ + /* */ + /* Compile autofit module with Indic script support. */ + /* */ +#define AF_CONFIG_OPTION_INDIC + + /* */ + + + /* + * Define this variable if you want to keep the layout of internal + * structures that was used prior to FreeType 2.2. This also compiles in + * a few obsolete functions to avoid linking problems on typical Unix + * distributions. + * + * For embedded systems or building a new distribution from scratch, it + * is recommended to disable the macro since it reduces the library's code + * size and activates a few memory-saving optimizations as well. + */ +/* #define FT_CONFIG_OPTION_OLD_INTERNALS */ + + + /* + * This variable is defined if either unpatented or native TrueType + * hinting is requested by the definitions above. + */ +#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER +#define TT_USE_BYTECODE_INTERPRETER +#elif defined TT_CONFIG_OPTION_UNPATENTED_HINTING +#define TT_USE_BYTECODE_INTERPRETER +#endif + +FT_END_HEADER + + +#endif /* __FTOPTION_H__ */ + + +/* END */ diff --git a/include/freetype/config/ftstdlib.h b/include/freetype/config/ftstdlib.h new file mode 100644 index 0000000..f923f3e --- /dev/null +++ b/include/freetype/config/ftstdlib.h @@ -0,0 +1,180 @@ +/***************************************************************************/ +/* */ +/* ftstdlib.h */ +/* */ +/* ANSI-specific library and header configuration file (specification */ +/* only). */ +/* */ +/* Copyright 2002, 2003, 2004, 2005, 2006, 2007 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + + /*************************************************************************/ + /* */ + /* This file is used to group all #includes to the ANSI C library that */ + /* FreeType normally requires. It also defines macros to rename the */ + /* standard functions within the FreeType source code. */ + /* */ + /* Load a file which defines __FTSTDLIB_H__ before this one to override */ + /* it. */ + /* */ + /*************************************************************************/ + + +#ifndef __FTSTDLIB_H__ +#define __FTSTDLIB_H__ + + +#include <stddef.h> + +#define ft_ptrdiff_t ptrdiff_t + + + /**********************************************************************/ + /* */ + /* integer limits */ + /* */ + /* UINT_MAX and ULONG_MAX are used to automatically compute the size */ + /* of `int' and `long' in bytes at compile-time. So far, this works */ + /* for all platforms the library has been tested on. */ + /* */ + /* Note that on the extremely rare platforms that do not provide */ + /* integer types that are _exactly_ 16 and 32 bits wide (e.g. some */ + /* old Crays where `int' is 36 bits), we do not make any guarantee */ + /* about the correct behaviour of FT2 with all fonts. */ + /* */ + /* In these case, `ftconfig.h' will refuse to compile anyway with a */ + /* message like `couldn't find 32-bit type' or something similar. */ + /* */ + /* IMPORTANT NOTE: We do not define aliases for heap management and */ + /* i/o routines (i.e. malloc/free/fopen/fread/...) */ + /* since these functions should all be encapsulated */ + /* by platform-specific implementations of */ + /* `ftsystem.c'. */ + /* */ + /**********************************************************************/ + + +#include <limits.h> + +#define FT_CHAR_BIT CHAR_BIT +#define FT_INT_MAX INT_MAX +#define FT_UINT_MAX UINT_MAX +#define FT_ULONG_MAX ULONG_MAX + + + /**********************************************************************/ + /* */ + /* character and string processing */ + /* */ + /**********************************************************************/ + + +#include <string.h> + +#define ft_memchr memchr +#define ft_memcmp memcmp +#define ft_memcpy memcpy +#define ft_memmove memmove +#define ft_memset memset +#define ft_strcat strcat +#define ft_strcmp strcmp +#define ft_strcpy strcpy +#define ft_strlen strlen +#define ft_strncmp strncmp +#define ft_strncpy strncpy +#define ft_strrchr strrchr +#define ft_strstr strstr + + + /**********************************************************************/ + /* */ + /* file handling */ + /* */ + /**********************************************************************/ + + +#include <stdio.h> + +#define FT_FILE FILE +#define ft_fclose fclose +#define ft_fopen fopen +#define ft_fread fread +#define ft_fseek fseek +#define ft_ftell ftell +#define ft_sprintf sprintf + + + /**********************************************************************/ + /* */ + /* sorting */ + /* */ + /**********************************************************************/ + + +#include <stdlib.h> + +#define ft_qsort qsort + +#define ft_exit exit /* only used to exit from unhandled exceptions */ + + + /**********************************************************************/ + /* */ + /* memory allocation */ + /* */ + /**********************************************************************/ + + +#define ft_scalloc calloc +#define ft_sfree free +#define ft_smalloc malloc +#define ft_srealloc realloc + + + /**********************************************************************/ + /* */ + /* miscellaneous */ + /* */ + /**********************************************************************/ + + +#define ft_atol atol +#define ft_labs labs + + + /**********************************************************************/ + /* */ + /* execution control */ + /* */ + /**********************************************************************/ + + +#include <setjmp.h> + +#define ft_jmp_buf jmp_buf /* note: this cannot be a typedef since */ + /* jmp_buf is defined as a macro */ + /* on certain platforms */ + +#define ft_longjmp longjmp +#define ft_setjmp( b ) setjmp( *(jmp_buf*) &(b) ) /* same thing here */ + + + /* the following is only used for debugging purposes, i.e., if */ + /* FT_DEBUG_LEVEL_ERROR or FT_DEBUG_LEVEL_TRACE are defined */ + +#include <stdarg.h> + + +#endif /* __FTSTDLIB_H__ */ + + +/* END */ diff --git a/include/freetype/freetype.h b/include/freetype/freetype.h new file mode 100644 index 0000000..dbca087 --- /dev/null +++ b/include/freetype/freetype.h @@ -0,0 +1,3434 @@ +/***************************************************************************/ +/* */ +/* freetype.h */ +/* */ +/* FreeType high-level API and common types (specification only). */ +/* */ +/* Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2007 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef FT_FREETYPE_H +#error "`ft2build.h' hasn't been included yet!" +#error "Please always use macros to include FreeType header files." +#error "Example:" +#error " #include <ft2build.h>" +#error " #include FT_FREETYPE_H" +#endif + + + /*************************************************************************/ + /* */ + /* The `raster' component duplicates some of the declarations in */ + /* freetype.h for stand-alone use if _FREETYPE_ isn't defined. */ + /* */ + /*************************************************************************/ + + +#ifndef __FREETYPE_H__ +#define __FREETYPE_H__ + + +#include <ft2build.h> +#include FT_CONFIG_CONFIG_H +#include FT_ERRORS_H +#include FT_TYPES_H + + +FT_BEGIN_HEADER + + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* user_allocation */ + /* */ + /* <Title> */ + /* User allocation */ + /* */ + /* <Abstract> */ + /* How client applications should allocate FreeType data structures. */ + /* */ + /* <Description> */ + /* FreeType assumes that structures allocated by the user and passed */ + /* as arguments are zeroed out except for the actual data. With */ + /* other words, it is recommended to use `calloc' (or variants of it) */ + /* instead of `malloc' for allocation. */ + /* */ + /*************************************************************************/ + + + + /*************************************************************************/ + /*************************************************************************/ + /* */ + /* B A S I C T Y P E S */ + /* */ + /*************************************************************************/ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* base_interface */ + /* */ + /* <Title> */ + /* Base Interface */ + /* */ + /* <Abstract> */ + /* The FreeType 2 base font interface. */ + /* */ + /* <Description> */ + /* This section describes the public high-level API of FreeType 2. */ + /* */ + /* <Order> */ + /* FT_Library */ + /* FT_Face */ + /* FT_Size */ + /* FT_GlyphSlot */ + /* FT_CharMap */ + /* FT_Encoding */ + /* */ + /* FT_FaceRec */ + /* */ + /* FT_FACE_FLAG_SCALABLE */ + /* FT_FACE_FLAG_FIXED_SIZES */ + /* FT_FACE_FLAG_FIXED_WIDTH */ + /* FT_FACE_FLAG_HORIZONTAL */ + /* FT_FACE_FLAG_VERTICAL */ + /* FT_FACE_FLAG_SFNT */ + /* FT_FACE_FLAG_KERNING */ + /* FT_FACE_FLAG_MULTIPLE_MASTERS */ + /* FT_FACE_FLAG_GLYPH_NAMES */ + /* FT_FACE_FLAG_EXTERNAL_STREAM */ + /* FT_FACE_FLAG_FAST_GLYPHS */ + /* FT_FACE_FLAG_HINTER */ + /* */ + /* FT_STYLE_FLAG_BOLD */ + /* FT_STYLE_FLAG_ITALIC */ + /* */ + /* FT_SizeRec */ + /* FT_Size_Metrics */ + /* */ + /* FT_GlyphSlotRec */ + /* FT_Glyph_Metrics */ + /* FT_SubGlyph */ + /* */ + /* FT_Bitmap_Size */ + /* */ + /* FT_Init_FreeType */ + /* FT_Done_FreeType */ + /* */ + /* FT_New_Face */ + /* FT_Done_Face */ + /* FT_New_Memory_Face */ + /* FT_Open_Face */ + /* FT_Open_Args */ + /* FT_Parameter */ + /* FT_Attach_File */ + /* FT_Attach_Stream */ + /* */ + /* FT_Set_Char_Size */ + /* FT_Set_Pixel_Sizes */ + /* FT_Request_Size */ + /* FT_Select_Size */ + /* FT_Size_Request_Type */ + /* FT_Size_Request */ + /* FT_Set_Transform */ + /* FT_Load_Glyph */ + /* FT_Get_Char_Index */ + /* FT_Get_Name_Index */ + /* FT_Load_Char */ + /* */ + /* FT_OPEN_MEMORY */ + /* FT_OPEN_STREAM */ + /* FT_OPEN_PATHNAME */ + /* FT_OPEN_DRIVER */ + /* FT_OPEN_PARAMS */ + /* */ + /* FT_LOAD_DEFAULT */ + /* FT_LOAD_RENDER */ + /* FT_LOAD_MONOCHROME */ + /* FT_LOAD_LINEAR_DESIGN */ + /* FT_LOAD_NO_SCALE */ + /* FT_LOAD_NO_HINTING */ + /* FT_LOAD_NO_BITMAP */ + /* FT_LOAD_CROP_BITMAP */ + /* */ + /* FT_LOAD_VERTICAL_LAYOUT */ + /* FT_LOAD_IGNORE_TRANSFORM */ + /* FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH */ + /* FT_LOAD_FORCE_AUTOHINT */ + /* FT_LOAD_NO_RECURSE */ + /* FT_LOAD_PEDANTIC */ + /* */ + /* FT_LOAD_TARGET_NORMAL */ + /* FT_LOAD_TARGET_LIGHT */ + /* FT_LOAD_TARGET_MONO */ + /* FT_LOAD_TARGET_LCD */ + /* FT_LOAD_TARGET_LCD_V */ + /* */ + /* FT_Render_Glyph */ + /* FT_Render_Mode */ + /* FT_Get_Kerning */ + /* FT_Kerning_Mode */ + /* FT_Get_Track_Kerning */ + /* FT_Get_Glyph_Name */ + /* FT_Get_Postscript_Name */ + /* */ + /* FT_CharMapRec */ + /* FT_Select_Charmap */ + /* FT_Set_Charmap */ + /* FT_Get_Charmap_Index */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_Glyph_Metrics */ + /* */ + /* <Description> */ + /* A structure used to model the metrics of a single glyph. The */ + /* values are expressed in 26.6 fractional pixel format; if the flag */ + /* @FT_LOAD_NO_SCALE has been used while loading the glyph, values */ + /* are expressed in font units instead. */ + /* */ + /* <Fields> */ + /* width :: */ + /* The glyph's width. */ + /* */ + /* height :: */ + /* The glyph's height. */ + /* */ + /* horiBearingX :: */ + /* Left side bearing for horizontal layout. */ + /* */ + /* horiBearingY :: */ + /* Top side bearing for horizontal layout. */ + /* */ + /* horiAdvance :: */ + /* Advance width for horizontal layout. */ + /* */ + /* vertBearingX :: */ + /* Left side bearing for vertical layout. */ + /* */ + /* vertBearingY :: */ + /* Top side bearing for vertical layout. */ + /* */ + /* vertAdvance :: */ + /* Advance height for vertical layout. */ + /* */ + typedef struct FT_Glyph_Metrics_ + { + FT_Pos width; + FT_Pos height; + + FT_Pos horiBearingX; + FT_Pos horiBearingY; + FT_Pos horiAdvance; + + FT_Pos vertBearingX; + FT_Pos vertBearingY; + FT_Pos vertAdvance; + + } FT_Glyph_Metrics; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_Bitmap_Size */ + /* */ + /* <Description> */ + /* This structure models the metrics of a bitmap strike (i.e., a set */ + /* of glyphs for a given point size and resolution) in a bitmap font. */ + /* It is used for the `available_sizes' field of @FT_Face. */ + /* */ + /* <Fields> */ + /* height :: The vertical distance, in pixels, between two */ + /* consecutive baselines. It is always positive. */ + /* */ + /* width :: The average width, in pixels, of all glyphs in the */ + /* strike. */ + /* */ + /* size :: The nominal size of the strike in 26.6 fractional */ + /* points. This field is not very useful. */ + /* */ + /* x_ppem :: The horizontal ppem (nominal width) in 26.6 fractional */ + /* pixels. */ + /* */ + /* y_ppem :: The vertical ppem (nominal height) in 26.6 fractional */ + /* pixels. */ + /* */ + /* <Note> */ + /* Windows FNT: */ + /* The nominal size given in a FNT font is not reliable. Thus when */ + /* the driver finds it incorrect, it sets `size' to some calculated */ + /* values and sets `x_ppem' and `y_ppem' to the pixel width and */ + /* height given in the font, respectively. */ + /* */ + /* TrueType embedded bitmaps: */ + /* `size', `width', and `height' values are not contained in the */ + /* bitmap strike itself. They are computed from the global font */ + /* parameters. */ + /* */ + typedef struct FT_Bitmap_Size_ + { + FT_Short height; + FT_Short width; + + FT_Pos size; + + FT_Pos x_ppem; + FT_Pos y_ppem; + + } FT_Bitmap_Size; + + + /*************************************************************************/ + /*************************************************************************/ + /* */ + /* O B J E C T C L A S S E S */ + /* */ + /*************************************************************************/ + /*************************************************************************/ + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_Library */ + /* */ + /* <Description> */ + /* A handle to a FreeType library instance. Each `library' is */ + /* completely independent from the others; it is the `root' of a set */ + /* of objects like fonts, faces, sizes, etc. */ + /* */ + /* It also embeds a memory manager (see @FT_Memory), as well as a */ + /* scan-line converter object (see @FT_Raster). */ + /* */ + /* For multi-threading applications each thread should have its own */ + /* FT_Library object. */ + /* */ + /* <Note> */ + /* Library objects are normally created by @FT_Init_FreeType, and */ + /* destroyed with @FT_Done_FreeType. */ + /* */ + typedef struct FT_LibraryRec_ *FT_Library; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_Module */ + /* */ + /* <Description> */ + /* A handle to a given FreeType module object. Each module can be a */ + /* font driver, a renderer, or anything else that provides services */ + /* to the formers. */ + /* */ + typedef struct FT_ModuleRec_* FT_Module; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_Driver */ + /* */ + /* <Description> */ + /* A handle to a given FreeType font driver object. Each font driver */ + /* is a special module capable of creating faces from font files. */ + /* */ + typedef struct FT_DriverRec_* FT_Driver; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_Renderer */ + /* */ + /* <Description> */ + /* A handle to a given FreeType renderer. A renderer is a special */ + /* module in charge of converting a glyph image to a bitmap, when */ + /* necessary. Each renderer supports a given glyph image format, and */ + /* one or more target surface depths. */ + /* */ + typedef struct FT_RendererRec_* FT_Renderer; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_Face */ + /* */ + /* <Description> */ + /* A handle to a given typographic face object. A face object models */ + /* a given typeface, in a given style. */ + /* */ + /* <Note> */ + /* Each face object also owns a single @FT_GlyphSlot object, as well */ + /* as one or more @FT_Size objects. */ + /* */ + /* Use @FT_New_Face or @FT_Open_Face to create a new face object from */ + /* a given filepathname or a custom input stream. */ + /* */ + /* Use @FT_Done_Face to destroy it (along with its slot and sizes). */ + /* */ + /* <Also> */ + /* The @FT_FaceRec details the publicly accessible fields of a given */ + /* face object. */ + /* */ + typedef struct FT_FaceRec_* FT_Face; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_Size */ + /* */ + /* <Description> */ + /* A handle to an object used to model a face scaled to a given */ + /* character size. */ + /* */ + /* <Note> */ + /* Each @FT_Face has an _active_ @FT_Size object that is used by */ + /* functions like @FT_Load_Glyph to determine the scaling */ + /* transformation which is used to load and hint glyphs and metrics. */ + /* */ + /* You can use @FT_Set_Char_Size, @FT_Set_Pixel_Sizes, */ + /* @FT_Request_Size or even @FT_Select_Size to change the content */ + /* (i.e., the scaling values) of the active @FT_Size. */ + /* */ + /* You can use @FT_New_Size to create additional size objects for a */ + /* given @FT_Face, but they won't be used by other functions until */ + /* you activate it through @FT_Activate_Size. Only one size can be */ + /* activated at any given time per face. */ + /* */ + /* <Also> */ + /* The @FT_SizeRec structure details the publicly accessible fields */ + /* of a given size object. */ + /* */ + typedef struct FT_SizeRec_* FT_Size; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_GlyphSlot */ + /* */ + /* <Description> */ + /* A handle to a given `glyph slot'. A slot is a container where it */ + /* is possible to load any one of the glyphs contained in its parent */ + /* face. */ + /* */ + /* In other words, each time you call @FT_Load_Glyph or */ + /* @FT_Load_Char, the slot's content is erased by the new glyph data, */ + /* i.e., the glyph's metrics, its image (bitmap or outline), and */ + /* other control information. */ + /* */ + /* <Also> */ + /* @FT_GlyphSlotRec details the publicly accessible glyph fields. */ + /* */ + typedef struct FT_GlyphSlotRec_* FT_GlyphSlot; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_CharMap */ + /* */ + /* <Description> */ + /* A handle to a given character map. A charmap is used to translate */ + /* character codes in a given encoding into glyph indexes for its */ + /* parent's face. Some font formats may provide several charmaps per */ + /* font. */ + /* */ + /* Each face object owns zero or more charmaps, but only one of them */ + /* can be `active' and used by @FT_Get_Char_Index or @FT_Load_Char. */ + /* */ + /* The list of available charmaps in a face is available through the */ + /* `face->num_charmaps' and `face->charmaps' fields of @FT_FaceRec. */ + /* */ + /* The currently active charmap is available as `face->charmap'. */ + /* You should call @FT_Set_Charmap to change it. */ + /* */ + /* <Note> */ + /* When a new face is created (either through @FT_New_Face or */ + /* @FT_Open_Face), the library looks for a Unicode charmap within */ + /* the list and automatically activates it. */ + /* */ + /* <Also> */ + /* The @FT_CharMapRec details the publicly accessible fields of a */ + /* given character map. */ + /* */ + typedef struct FT_CharMapRec_* FT_CharMap; + + + /*************************************************************************/ + /* */ + /* <Macro> */ + /* FT_ENC_TAG */ + /* */ + /* <Description> */ + /* This macro converts four-letter tags into an unsigned long. It is */ + /* used to define `encoding' identifiers (see @FT_Encoding). */ + /* */ + /* <Note> */ + /* Since many 16bit compilers don't like 32bit enumerations, you */ + /* should redefine this macro in case of problems to something like */ + /* this: */ + /* */ + /* { */ + /* #define FT_ENC_TAG( value, a, b, c, d ) value */ + /* } */ + /* */ + /* to get a simple enumeration without assigning special numbers. */ + /* */ + +#ifndef FT_ENC_TAG +#define FT_ENC_TAG( value, a, b, c, d ) \ + value = ( ( (FT_UInt32)(a) << 24 ) | \ + ( (FT_UInt32)(b) << 16 ) | \ + ( (FT_UInt32)(c) << 8 ) | \ + (FT_UInt32)(d) ) + +#endif /* FT_ENC_TAG */ + + + /*************************************************************************/ + /* */ + /* <Enum> */ + /* FT_Encoding */ + /* */ + /* <Description> */ + /* An enumeration used to specify character sets supported by */ + /* charmaps. Used in the @FT_Select_Charmap API function. */ + /* */ + /* <Note> */ + /* Despite the name, this enumeration lists specific character */ + /* repertories (i.e., charsets), and not text encoding methods (e.g., */ + /* UTF-8, UTF-16, GB2312_EUC, etc.). */ + /* */ + /* Because of 32-bit charcodes defined in Unicode (i.e., surrogates), */ + /* all character codes must be expressed as FT_Longs. */ + /* */ + /* Other encodings might be defined in the future. */ + /* */ + /* <Values> */ + /* FT_ENCODING_NONE :: */ + /* The encoding value 0 is reserved. */ + /* */ + /* FT_ENCODING_UNICODE :: */ + /* Corresponds to the Unicode character set. This value covers */ + /* all versions of the Unicode repertoire, including ASCII and */ + /* Latin-1. Most fonts include a Unicode charmap, but not all */ + /* of them. */ + /* */ + /* FT_ENCODING_MS_SYMBOL :: */ + /* Corresponds to the Microsoft Symbol encoding, used to encode */ + /* mathematical symbols in the 32..255 character code range. For */ + /* more information, see `http://www.ceviz.net/symbol.htm'. */ + /* */ + /* FT_ENCODING_SJIS :: */ + /* Corresponds to Japanese SJIS encoding. More info at */ + /* at `http://langsupport.japanreference.com/encoding.shtml'. */ + /* See note on multi-byte encodings below. */ + /* */ + /* FT_ENCODING_GB2312 :: */ + /* Corresponds to an encoding system for Simplified Chinese as used */ + /* used in mainland China. */ + /* */ + /* FT_ENCODING_BIG5 :: */ + /* Corresponds to an encoding system for Traditional Chinese as used */ + /* in Taiwan and Hong Kong. */ + /* */ + /* FT_ENCODING_WANSUNG :: */ + /* Corresponds to the Korean encoding system known as Wansung. */ + /* For more information see */ + /* `http://www.microsoft.com/typography/unicode/949.txt'. */ + /* */ + /* FT_ENCODING_JOHAB :: */ + /* The Korean standard character set (KS C-5601-1992), which */ + /* corresponds to MS Windows code page 1361. This character set */ + /* includes all possible Hangeul character combinations. */ + /* */ + /* FT_ENCODING_ADOBE_LATIN_1 :: */ + /* Corresponds to a Latin-1 encoding as defined in a Type 1 */ + /* Postscript font. It is limited to 256 character codes. */ + /* */ + /* FT_ENCODING_ADOBE_STANDARD :: */ + /* Corresponds to the Adobe Standard encoding, as found in Type 1, */ + /* CFF, and OpenType/CFF fonts. It is limited to 256 character */ + /* codes. */ + /* */ + /* FT_ENCODING_ADOBE_EXPERT :: */ + /* Corresponds to the Adobe Expert encoding, as found in Type 1, */ + /* CFF, and OpenType/CFF fonts. It is limited to 256 character */ + /* codes. */ + /* */ + /* FT_ENCODING_ADOBE_CUSTOM :: */ + /* Corresponds to a custom encoding, as found in Type 1, CFF, and */ + /* OpenType/CFF fonts. It is limited to 256 character codes. */ + /* */ + /* FT_ENCODING_APPLE_ROMAN :: */ + /* Corresponds to the 8-bit Apple roman encoding. Many TrueType and */ + /* OpenType fonts contain a charmap for this encoding, since older */ + /* versions of Mac OS are able to use it. */ + /* */ + /* FT_ENCODING_OLD_LATIN_2 :: */ + /* This value is deprecated and was never used nor reported by */ + /* FreeType. Don't use or test for it. */ + /* */ + /* FT_ENCODING_MS_SJIS :: */ + /* Same as FT_ENCODING_SJIS. Deprecated. */ + /* */ + /* FT_ENCODING_MS_GB2312 :: */ + /* Same as FT_ENCODING_GB2312. Deprecated. */ + /* */ + /* FT_ENCODING_MS_BIG5 :: */ + /* Same as FT_ENCODING_BIG5. Deprecated. */ + /* */ + /* FT_ENCODING_MS_WANSUNG :: */ + /* Same as FT_ENCODING_WANSUNG. Deprecated. */ + /* */ + /* FT_ENCODING_MS_JOHAB :: */ + /* Same as FT_ENCODING_JOHAB. Deprecated. */ + /* */ + /* <Note> */ + /* By default, FreeType automatically synthetizes a Unicode charmap */ + /* for Postscript fonts, using their glyph names dictionaries. */ + /* However, it also reports the encodings defined explicitly in the */ + /* font file, for the cases when they are needed, with the Adobe */ + /* values as well. */ + /* */ + /* FT_ENCODING_NONE is set by the BDF and PCF drivers if the charmap */ + /* is neither Unicode nor ISO-8859-1 (otherwise it is set to */ + /* FT_ENCODING_UNICODE). Use @FT_Get_BDF_Charset_ID to find out which */ + /* encoding is really present. If, for example, the `cs_registry' */ + /* field is `KOI8' and the `cs_encoding' field is `R', the font is */ + /* encoded in KOI8-R. */ + /* */ + /* FT_ENCODING_NONE is always set (with a single exception) by the */ + /* winfonts driver. Use @FT_Get_WinFNT_Header and examine the */ + /* `charset' field of the @FT_WinFNT_HeaderRec structure to find out */ + /* which encoding is really present. For example, */ + /* @FT_WinFNT_ID_CP1251 (204) means Windows code page 1251 (for */ + /* Russian). */ + /* */ + /* FT_ENCODING_NONE is set if `platform_id' is @TT_PLATFORM_MACINTOSH */ + /* and `encoding_id' is not @TT_MAC_ID_ROMAN (otherwise it is set to */ + /* FT_ENCODING_APPLE_ROMAN). */ + /* */ + /* If `platform_id' is @TT_PLATFORM_MACINTOSH, use the function c */ + /* @FT_Get_CMap_Language_ID to query the Mac language ID which may be */ + /* needed to be able to distinguish Apple encoding variants. See */ + /* */ + /* http://www.unicode.org/Public/MAPPINGS/VENDORS/APPLE/README.TXT */ + /* */ + /* to get an idea how to do that. Basically, if the language ID is 0, */ + /* don't use it, otherwise subtract 1 from the language ID. Then */ + /* examine `encoding_id'. If, for example, `encoding_id' is */ + /* @TT_MAC_ID_ROMAN and the language ID (minus 1) is */ + /* `TT_MAC_LANGID_GREEK', it is the Greek encoding, not Roman. */ + /* @TT_MAC_ID_ARABIC with `TT_MAC_LANGID_FARSI' means the Farsi */ + /* variant the Arabic encoding. */ + /* */ + typedef enum FT_Encoding_ + { + FT_ENC_TAG( FT_ENCODING_NONE, 0, 0, 0, 0 ), + + FT_ENC_TAG( FT_ENCODING_MS_SYMBOL, 's', 'y', 'm', 'b' ), + FT_ENC_TAG( FT_ENCODING_UNICODE, 'u', 'n', 'i', 'c' ), + + FT_ENC_TAG( FT_ENCODING_SJIS, 's', 'j', 'i', 's' ), + FT_ENC_TAG( FT_ENCODING_GB2312, 'g', 'b', ' ', ' ' ), + FT_ENC_TAG( FT_ENCODING_BIG5, 'b', 'i', 'g', '5' ), + FT_ENC_TAG( FT_ENCODING_WANSUNG, 'w', 'a', 'n', 's' ), + FT_ENC_TAG( FT_ENCODING_JOHAB, 'j', 'o', 'h', 'a' ), + + /* for backwards compatibility */ + FT_ENCODING_MS_SJIS = FT_ENCODING_SJIS, + FT_ENCODING_MS_GB2312 = FT_ENCODING_GB2312, + FT_ENCODING_MS_BIG5 = FT_ENCODING_BIG5, + FT_ENCODING_MS_WANSUNG = FT_ENCODING_WANSUNG, + FT_ENCODING_MS_JOHAB = FT_ENCODING_JOHAB, + + FT_ENC_TAG( FT_ENCODING_ADOBE_STANDARD, 'A', 'D', 'O', 'B' ), + FT_ENC_TAG( FT_ENCODING_ADOBE_EXPERT, 'A', 'D', 'B', 'E' ), + FT_ENC_TAG( FT_ENCODING_ADOBE_CUSTOM, 'A', 'D', 'B', 'C' ), + FT_ENC_TAG( FT_ENCODING_ADOBE_LATIN_1, 'l', 'a', 't', '1' ), + + FT_ENC_TAG( FT_ENCODING_OLD_LATIN_2, 'l', 'a', 't', '2' ), + + FT_ENC_TAG( FT_ENCODING_APPLE_ROMAN, 'a', 'r', 'm', 'n' ) + + } FT_Encoding; + + + /*************************************************************************/ + /* */ + /* <Enum> */ + /* ft_encoding_xxx */ + /* */ + /* <Description> */ + /* These constants are deprecated; use the corresponding @FT_Encoding */ + /* values instead. */ + /* */ +#define ft_encoding_none FT_ENCODING_NONE +#define ft_encoding_unicode FT_ENCODING_UNICODE +#define ft_encoding_symbol FT_ENCODING_MS_SYMBOL +#define ft_encoding_latin_1 FT_ENCODING_ADOBE_LATIN_1 +#define ft_encoding_latin_2 FT_ENCODING_OLD_LATIN_2 +#define ft_encoding_sjis FT_ENCODING_SJIS +#define ft_encoding_gb2312 FT_ENCODING_GB2312 +#define ft_encoding_big5 FT_ENCODING_BIG5 +#define ft_encoding_wansung FT_ENCODING_WANSUNG +#define ft_encoding_johab FT_ENCODING_JOHAB + +#define ft_encoding_adobe_standard FT_ENCODING_ADOBE_STANDARD +#define ft_encoding_adobe_expert FT_ENCODING_ADOBE_EXPERT +#define ft_encoding_adobe_custom FT_ENCODING_ADOBE_CUSTOM +#define ft_encoding_apple_roman FT_ENCODING_APPLE_ROMAN + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_CharMapRec */ + /* */ + /* <Description> */ + /* The base charmap structure. */ + /* */ + /* <Fields> */ + /* face :: A handle to the parent face object. */ + /* */ + /* encoding :: An @FT_Encoding tag identifying the charmap. Use */ + /* this with @FT_Select_Charmap. */ + /* */ + /* platform_id :: An ID number describing the platform for the */ + /* following encoding ID. This comes directly from */ + /* the TrueType specification and should be emulated */ + /* for other formats. */ + /* */ + /* encoding_id :: A platform specific encoding number. This also */ + /* comes from the TrueType specification and should be */ + /* emulated similarly. */ + /* */ + typedef struct FT_CharMapRec_ + { + FT_Face face; + FT_Encoding encoding; + FT_UShort platform_id; + FT_UShort encoding_id; + + } FT_CharMapRec; + + + /*************************************************************************/ + /*************************************************************************/ + /* */ + /* B A S E O B J E C T C L A S S E S */ + /* */ + /*************************************************************************/ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_Face_Internal */ + /* */ + /* <Description> */ + /* An opaque handle to an `FT_Face_InternalRec' structure, used to */ + /* model private data of a given @FT_Face object. */ + /* */ + /* This structure might change between releases of FreeType 2 and is */ + /* not generally available to client applications. */ + /* */ + typedef struct FT_Face_InternalRec_* FT_Face_Internal; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_FaceRec */ + /* */ + /* <Description> */ + /* FreeType root face class structure. A face object models a */ + /* typeface in a font file. */ + /* */ + /* <Fields> */ + /* num_faces :: The number of faces in the font file. Some */ + /* font formats can have multiple faces in */ + /* a font file. */ + /* */ + /* face_index :: The index of the face in the font file. It */ + /* is set to 0 if there is only one face in */ + /* the font file. */ + /* */ + /* face_flags :: A set of bit flags that give important */ + /* information about the face; see */ + /* @FT_FACE_FLAG_XXX for the details. */ + /* */ + /* style_flags :: A set of bit flags indicating the style of */ + /* the face; see @FT_STYLE_FLAG_XXX for the */ + /* details. */ + /* */ + /* num_glyphs :: The number of glyphs in the face. If the */ + /* face is scalable and has sbits (see */ + /* `num_fixed_sizes'), it is set to the number */ + /* of outline glyphs. */ + /* */ + /* family_name :: The face's family name. This is an ASCII */ + /* string, usually in English, which describes */ + /* the typeface's family (like `Times New */ + /* Roman', `Bodoni', `Garamond', etc). This */ + /* is a least common denominator used to list */ + /* fonts. Some formats (TrueType & OpenType) */ + /* provide localized and Unicode versions of */ + /* this string. Applications should use the */ + /* format specific interface to access them. */ + /* */ + /* style_name :: The face's style name. This is an ASCII */ + /* string, usually in English, which describes */ + /* the typeface's style (like `Italic', */ + /* `Bold', `Condensed', etc). Not all font */ + /* formats provide a style name, so this field */ + /* is optional, and can be set to NULL. As */ + /* for `family_name', some formats provide */ + /* localized and Unicode versions of this */ + /* string. Applications should use the format */ + /* specific interface to access them. */ + /* */ + /* num_fixed_sizes :: The number of bitmap strikes in the face. */ + /* Even if the face is scalable, there might */ + /* still be bitmap strikes, which are called */ + /* `sbits' in that case. */ + /* */ + /* available_sizes :: An array of @FT_Bitmap_Size for all bitmap */ + /* strikes in the face. It is set to NULL if */ + /* there is no bitmap strike. */ + /* */ + /* num_charmaps :: The number of charmaps in the face. */ + /* */ + /* charmaps :: An array of the charmaps of the face. */ + /* */ + /* generic :: A field reserved for client uses. See the */ + /* @FT_Generic type description. */ + /* */ + /* bbox :: The font bounding box. Coordinates are */ + /* expressed in font units (see */ + /* `units_per_EM'). The box is large enough */ + /* to contain any glyph from the font. Thus, */ + /* `bbox.yMax' can be seen as the `maximal */ + /* ascender', and `bbox.yMin' as the `minimal */ + /* descender'. Only relevant for scalable */ + /* formats. */ + /* */ + /* units_per_EM :: The number of font units per EM square for */ + /* this face. This is typically 2048 for */ + /* TrueType fonts, and 1000 for Type 1 fonts. */ + /* Only relevant for scalable formats. */ + /* */ + /* ascender :: The typographic ascender of the face, */ + /* expressed in font units. For font formats */ + /* not having this information, it is set to */ + /* `bbox.yMax'. Only relevant for scalable */ + /* formats. */ + /* */ + /* descender :: The typographic descender of the face, */ + /* expressed in font units. For font formats */ + /* not having this information, it is set to */ + /* `bbox.yMin'. Note that this field is */ + /* usually negative. Only relevant for */ + /* scalable formats. */ + /* */ + /* height :: The height is the vertical distance */ + /* between two consecutive baselines, */ + /* expressed in font units. It is always */ + /* positive. Only relevant for scalable */ + /* formats. */ + /* */ + /* max_advance_width :: The maximal advance width, in font units, */ + /* for all glyphs in this face. This can be */ + /* used to make word wrapping computations */ + /* faster. Only relevant for scalable */ + /* formats. */ + /* */ + /* max_advance_height :: The maximal advance height, in font units, */ + /* for all glyphs in this face. This is only */ + /* relevant for vertical layouts, and is set */ + /* to `height' for fonts that do not provide */ + /* vertical metrics. Only relevant for */ + /* scalable formats. */ + /* */ + /* underline_position :: The position, in font units, of the */ + /* underline line for this face. It's the */ + /* center of the underlining stem. Only */ + /* relevant for scalable formats. */ + /* */ + /* underline_thickness :: The thickness, in font units, of the */ + /* underline for this face. Only relevant for */ + /* scalable formats. */ + /* */ + /* glyph :: The face's associated glyph slot(s). */ + /* */ + /* size :: The current active size for this face. */ + /* */ + /* charmap :: The current active charmap for this face. */ + /* */ + /* <Note> */ + /* Fields may be changed after a call to @FT_Attach_File or */ + /* @FT_Attach_Stream. */ + /* */ + typedef struct FT_FaceRec_ + { + FT_Long num_faces; + FT_Long face_index; + + FT_Long face_flags; + FT_Long style_flags; + + FT_Long num_glyphs; + + FT_String* family_name; + FT_String* style_name; + + FT_Int num_fixed_sizes; + FT_Bitmap_Size* available_sizes; + + FT_Int num_charmaps; + FT_CharMap* charmaps; + + FT_Generic generic; + + /*# The following member variables (down to `underline_thickness') */ + /*# are only relevant to scalable outlines; cf. @FT_Bitmap_Size */ + /*# for bitmap fonts. */ + FT_BBox bbox; + + FT_UShort units_per_EM; + FT_Short ascender; + FT_Short descender; + FT_Short height; + + FT_Short max_advance_width; + FT_Short max_advance_height; + + FT_Short underline_position; + FT_Short underline_thickness; + + FT_GlyphSlot glyph; + FT_Size size; + FT_CharMap charmap; + + /*@private begin */ + + FT_Driver driver; + FT_Memory memory; + FT_Stream stream; + + FT_ListRec sizes_list; + + FT_Generic autohint; + void* extensions; + + FT_Face_Internal internal; + + /*@private end */ + + } FT_FaceRec; + + + /*************************************************************************/ + /* */ + /* <Enum> */ + /* FT_FACE_FLAG_XXX */ + /* */ + /* <Description> */ + /* A list of bit flags used in the `face_flags' field of the */ + /* @FT_FaceRec structure. They inform client applications of */ + /* properties of the corresponding face. */ + /* */ + /* <Values> */ + /* FT_FACE_FLAG_SCALABLE :: */ + /* Indicates that the face contains outline glyphs. This doesn't */ + /* prevent bitmap strikes, i.e., a face can have both this and */ + /* and @FT_FACE_FLAG_FIXED_SIZES set. */ + /* */ + /* FT_FACE_FLAG_FIXED_SIZES :: */ + /* Indicates that the face contains bitmap strikes. See also the */ + /* `num_fixed_sizes' and `available_sizes' fields of @FT_FaceRec. */ + /* */ + /* FT_FACE_FLAG_FIXED_WIDTH :: */ + /* Indicates that the face contains fixed-width characters (like */ + /* Courier, Lucido, MonoType, etc.). */ + /* */ + /* FT_FACE_FLAG_SFNT :: */ + /* Indicates that the face uses the `sfnt' storage scheme. For */ + /* now, this means TrueType and OpenType. */ + /* */ + /* FT_FACE_FLAG_HORIZONTAL :: */ + /* Indicates that the face contains horizontal glyph metrics. This */ + /* should be set for all common formats. */ + /* */ + /* FT_FACE_FLAG_VERTICAL :: */ + /* Indicates that the face contains vertical glyph metrics. This */ + /* is only available in some formats, not all of them. */ + /* */ + /* FT_FACE_FLAG_KERNING :: */ + /* Indicates that the face contains kerning information. If set, */ + /* the kerning distance can be retrieved through the function */ + /* @FT_Get_Kerning. Otherwise the function always return the */ + /* vector (0,0). Note that FreeType doesn't handle kerning data */ + /* from the `GPOS' table (as present in some OpenType fonts). */ + /* */ + /* FT_FACE_FLAG_FAST_GLYPHS :: */ + /* THIS FLAG IS DEPRECATED. DO NOT USE OR TEST IT. */ + /* */ + /* FT_FACE_FLAG_MULTIPLE_MASTERS :: */ + /* Indicates that the font contains multiple masters and is capable */ + /* of interpolating between them. See the multiple-masters */ + /* specific API for details. */ + /* */ + /* FT_FACE_FLAG_GLYPH_NAMES :: */ + /* Indicates that the font contains glyph names that can be */ + /* retrieved through @FT_Get_Glyph_Name. Note that some TrueType */ + /* fonts contain broken glyph name tables. Use the function */ + /* @FT_Has_PS_Glyph_Names when needed. */ + /* */ + /* FT_FACE_FLAG_EXTERNAL_STREAM :: */ + /* Used internally by FreeType to indicate that a face's stream was */ + /* provided by the client application and should not be destroyed */ + /* when @FT_Done_Face is called. Don't read or test this flag. */ + /* */ + /* FT_FACE_FLAG_HINTER :: */ + /* Set if the font driver has a hinting machine of its own. For */ + /* example, with TrueType fonts, it makes sense to use data from */ + /* the SFNT `gasp' table only if the native TrueType hinting engine */ + /* (with the bytecode interpreter) is available and active. */ + /* */ +#define FT_FACE_FLAG_SCALABLE ( 1L << 0 ) +#define FT_FACE_FLAG_FIXED_SIZES ( 1L << 1 ) +#define FT_FACE_FLAG_FIXED_WIDTH ( 1L << 2 ) +#define FT_FACE_FLAG_SFNT ( 1L << 3 ) +#define FT_FACE_FLAG_HORIZONTAL ( 1L << 4 ) +#define FT_FACE_FLAG_VERTICAL ( 1L << 5 ) +#define FT_FACE_FLAG_KERNING ( 1L << 6 ) +#define FT_FACE_FLAG_FAST_GLYPHS ( 1L << 7 ) +#define FT_FACE_FLAG_MULTIPLE_MASTERS ( 1L << 8 ) +#define FT_FACE_FLAG_GLYPH_NAMES ( 1L << 9 ) +#define FT_FACE_FLAG_EXTERNAL_STREAM ( 1L << 10 ) +#define FT_FACE_FLAG_HINTER ( 1L << 11 ) + + /* */ + + + /************************************************************************* + * + * @macro: + * FT_HAS_HORIZONTAL( face ) + * + * @description: + * A macro that returns true whenever a face object contains + * horizontal metrics (this is true for all font formats though). + * + * @also: + * @FT_HAS_VERTICAL can be used to check for vertical metrics. + * + */ +#define FT_HAS_HORIZONTAL( face ) \ + ( face->face_flags & FT_FACE_FLAG_HORIZONTAL ) + + + /************************************************************************* + * + * @macro: + * FT_HAS_VERTICAL( face ) + * + * @description: + * A macro that returns true whenever a face object contains vertical + * metrics. + * + */ +#define FT_HAS_VERTICAL( face ) \ + ( face->face_flags & FT_FACE_FLAG_VERTICAL ) + + + /************************************************************************* + * + * @macro: + * FT_HAS_KERNING( face ) + * + * @description: + * A macro that returns true whenever a face object contains kerning + * data that can be accessed with @FT_Get_Kerning. + * + */ +#define FT_HAS_KERNING( face ) \ + ( face->face_flags & FT_FACE_FLAG_KERNING ) + + + /************************************************************************* + * + * @macro: + * FT_IS_SCALABLE( face ) + * + * @description: + * A macro that returns true whenever a face object contains a scalable + * font face (true for TrueType, Type 1, Type 42, CID, OpenType/CFF, + * and PFR font formats. + * + */ +#define FT_IS_SCALABLE( face ) \ + ( face->face_flags & FT_FACE_FLAG_SCALABLE ) + + + /************************************************************************* + * + * @macro: + * FT_IS_SFNT( face ) + * + * @description: + * A macro that returns true whenever a face object contains a font + * whose format is based on the SFNT storage scheme. This usually + * means: TrueType fonts, OpenType fonts, as well as SFNT-based embedded + * bitmap fonts. + * + * If this macro is true, all functions defined in @FT_SFNT_NAMES_H and + * @FT_TRUETYPE_TABLES_H are available. + * + */ +#define FT_IS_SFNT( face ) \ + ( face->face_flags & FT_FACE_FLAG_SFNT ) + + + /************************************************************************* + * + * @macro: + * FT_IS_FIXED_WIDTH( face ) + * + * @description: + * A macro that returns true whenever a face object contains a font face + * that contains fixed-width (or `monospace', `fixed-pitch', etc.) + * glyphs. + * + */ +#define FT_IS_FIXED_WIDTH( face ) \ + ( face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ) + + + /************************************************************************* + * + * @macro: + * FT_HAS_FIXED_SIZES( face ) + * + * @description: + * A macro that returns true whenever a face object contains some + * embedded bitmaps. See the `available_sizes' field of the + * @FT_FaceRec structure. + * + */ +#define FT_HAS_FIXED_SIZES( face ) \ + ( face->face_flags & FT_FACE_FLAG_FIXED_SIZES ) + + /* */ + + + /************************************************************************* + * + * @macro: + * FT_HAS_FAST_GLYPHS( face ) + * + * @description: + * Deprecated. + * + */ +#define FT_HAS_FAST_GLYPHS( face ) 0 + + + /************************************************************************* + * + * @macro: + * FT_HAS_GLYPH_NAMES( face ) + * + * @description: + * A macro that returns true whenever a face object contains some glyph + * names that can be accessed through @FT_Get_Glyph_Name. + * + */ +#define FT_HAS_GLYPH_NAMES( face ) \ + ( face->face_flags & FT_FACE_FLAG_GLYPH_NAMES ) + + + /************************************************************************* + * + * @macro: + * FT_HAS_MULTIPLE_MASTERS( face ) + * + * @description: + * A macro that returns true whenever a face object contains some + * multiple masters. The functions provided by @FT_MULTIPLE_MASTERS_H + * are then available to choose the exact design you want. + * + */ +#define FT_HAS_MULTIPLE_MASTERS( face ) \ + ( face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS ) + + + /*************************************************************************/ + /* */ + /* <Constant> */ + /* FT_STYLE_FLAG_XXX */ + /* */ + /* <Description> */ + /* A list of bit-flags used to indicate the style of a given face. */ + /* These are used in the `style_flags' field of @FT_FaceRec. */ + /* */ + /* <Values> */ + /* FT_STYLE_FLAG_ITALIC :: */ + /* Indicates that a given face is italicized. */ + /* */ + /* FT_STYLE_FLAG_BOLD :: */ + /* Indicates that a given face is bold. */ + /* */ +#define FT_STYLE_FLAG_ITALIC ( 1 << 0 ) +#define FT_STYLE_FLAG_BOLD ( 1 << 1 ) + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_Size_Internal */ + /* */ + /* <Description> */ + /* An opaque handle to an `FT_Size_InternalRec' structure, used to */ + /* model private data of a given FT_Size object. */ + /* */ + typedef struct FT_Size_InternalRec_* FT_Size_Internal; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_Size_Metrics */ + /* */ + /* <Description> */ + /* The size metrics structure gives the metrics of a size object. */ + /* */ + /* <Fields> */ + /* x_ppem :: The width of the scaled EM square in pixels, hence */ + /* the term `ppem' (pixels per EM). It is also */ + /* referred to as `nominal width'. */ + /* */ + /* y_ppem :: The height of the scaled EM square in pixels, */ + /* hence the term `ppem' (pixels per EM). It is also */ + /* referred to as `nominal height'. */ + /* */ + /* x_scale :: A 16.16 fractional scaling value used to convert */ + /* horizontal metrics from font units to 26.6 */ + /* fractional pixels. Only relevant for scalable */ + /* font formats. */ + /* */ + /* y_scale :: A 16.16 fractional scaling value used to convert */ + /* vertical metrics from font units to 26.6 */ + /* fractional pixels. Only relevant for scalable */ + /* font formats. */ + /* */ + /* ascender :: The ascender in 26.6 fractional pixels. See */ + /* @FT_FaceRec for the details. */ + /* */ + /* descender :: The descender in 26.6 fractional pixels. See */ + /* @FT_FaceRec for the details. */ + /* */ + /* height :: The height in 26.6 fractional pixels. See */ + /* @FT_FaceRec for the details. */ + /* */ + /* max_advance :: The maximal advance width in 26.6 fractional */ + /* pixels. See @FT_FaceRec for the details. */ + /* */ + /* <Note> */ + /* The scaling values, if relevant, are determined first during a */ + /* size changing operation. The remaining fields are then set by the */ + /* driver. For scalable formats, they are usually set to scaled */ + /* values of the corresponding fields in @FT_FaceRec. */ + /* */ + /* Note that due to glyph hinting, these values might not be exact */ + /* for certain fonts. Thus they must be treated as unreliable */ + /* with an error margin of at least one pixel! */ + /* */ + /* Indeed, the only way to get the exact metrics is to render _all_ */ + /* glyphs. As this would be a definite performance hit, it is up to */ + /* client applications to perform such computations. */ + /* */ + /* The FT_Size_Metrics structure is valid for bitmap fonts also. */ + /* */ + typedef struct FT_Size_Metrics_ + { + FT_UShort x_ppem; /* horizontal pixels per EM */ + FT_UShort y_ppem; /* vertical pixels per EM */ + + FT_Fixed x_scale; /* scaling values used to convert font */ + FT_Fixed y_scale; /* units to 26.6 fractional pixels */ + + FT_Pos ascender; /* ascender in 26.6 frac. pixels */ + FT_Pos descender; /* descender in 26.6 frac. pixels */ + FT_Pos height; /* text height in 26.6 frac. pixels */ + FT_Pos max_advance; /* max horizontal advance, in 26.6 pixels */ + + } FT_Size_Metrics; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_SizeRec */ + /* */ + /* <Description> */ + /* FreeType root size class structure. A size object models a face */ + /* object at a given size. */ + /* */ + /* <Fields> */ + /* face :: Handle to the parent face object. */ + /* */ + /* generic :: A typeless pointer, which is unused by the FreeType */ + /* library or any of its drivers. It can be used by */ + /* client applications to link their own data to each size */ + /* object. */ + /* */ + /* metrics :: Metrics for this size object. This field is read-only. */ + /* */ + typedef struct FT_SizeRec_ + { + FT_Face face; /* parent face object */ + FT_Generic generic; /* generic pointer for client uses */ + FT_Size_Metrics metrics; /* size metrics */ + FT_Size_Internal internal; + + } FT_SizeRec; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_SubGlyph */ + /* */ + /* <Description> */ + /* The subglyph structure is an internal object used to describe */ + /* subglyphs (for example, in the case of composites). */ + /* */ + /* <Note> */ + /* The subglyph implementation is not part of the high-level API, */ + /* hence the forward structure declaration. */ + /* */ + /* You can however retrieve subglyph information with */ + /* @FT_Get_SubGlyph_Info. */ + /* */ + typedef struct FT_SubGlyphRec_* FT_SubGlyph; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_Slot_Internal */ + /* */ + /* <Description> */ + /* An opaque handle to an `FT_Slot_InternalRec' structure, used to */ + /* model private data of a given FT_GlyphSlot object. */ + /* */ + typedef struct FT_Slot_InternalRec_* FT_Slot_Internal; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_GlyphSlotRec */ + /* */ + /* <Description> */ + /* FreeType root glyph slot class structure. A glyph slot is a */ + /* container where individual glyphs can be loaded, be they in */ + /* outline or bitmap format. */ + /* */ + /* <Fields> */ + /* library :: A handle to the FreeType library instance */ + /* this slot belongs to. */ + /* */ + /* face :: A handle to the parent face object. */ + /* */ + /* next :: In some cases (like some font tools), several */ + /* glyph slots per face object can be a good */ + /* thing. As this is rare, the glyph slots are */ + /* listed through a direct, single-linked list */ + /* using its `next' field. */ + /* */ + /* generic :: A typeless pointer which is unused by the */ + /* FreeType library or any of its drivers. It */ + /* can be used by client applications to link */ + /* their own data to each glyph slot object. */ + /* */ + /* metrics :: The metrics of the last loaded glyph in the */ + /* slot. The returned values depend on the last */ + /* load flags (see the @FT_Load_Glyph API */ + /* function) and can be expressed either in 26.6 */ + /* fractional pixels or font units. */ + /* */ + /* Note that even when the glyph image is */ + /* transformed, the metrics are not. */ + /* */ + /* linearHoriAdvance :: The advance width of the unhinted glyph. */ + /* Its value is expressed in 16.16 fractional */ + /* pixels, unless @FT_LOAD_LINEAR_DESIGN is set */ + /* when loading the glyph. This field can be */ + /* important to perform correct WYSIWYG layout. */ + /* Only relevant for outline glyphs. */ + /* */ + /* linearVertAdvance :: The advance height of the unhinted glyph. */ + /* Its value is expressed in 16.16 fractional */ + /* pixels, unless @FT_LOAD_LINEAR_DESIGN is set */ + /* when loading the glyph. This field can be */ + /* important to perform correct WYSIWYG layout. */ + /* Only relevant for outline glyphs. */ + /* */ + /* advance :: This is the transformed advance width for the */ + /* glyph. */ + /* */ + /* format :: This field indicates the format of the image */ + /* contained in the glyph slot. Typically */ + /* @FT_GLYPH_FORMAT_BITMAP, */ + /* @FT_GLYPH_FORMAT_OUTLINE, or */ + /* @FT_GLYPH_FORMAT_COMPOSITE, but others are */ + /* possible. */ + /* */ + /* bitmap :: This field is used as a bitmap descriptor */ + /* when the slot format is */ + /* @FT_GLYPH_FORMAT_BITMAP. Note that the */ + /* address and content of the bitmap buffer can */ + /* change between calls of @FT_Load_Glyph and a */ + /* few other functions. */ + /* */ + /* bitmap_left :: This is the bitmap's left bearing expressed */ + /* in integer pixels. Of course, this is only */ + /* valid if the format is */ + /* @FT_GLYPH_FORMAT_BITMAP. */ + /* */ + /* bitmap_top :: This is the bitmap's top bearing expressed in */ + /* integer pixels. Remember that this is the */ + /* distance from the baseline to the top-most */ + /* glyph scanline, upwards y-coordinates being */ + /* *positive*. */ + /* */ + /* outline :: The outline descriptor for the current glyph */ + /* image if its format is */ + /* @FT_GLYPH_FORMAT_OUTLINE. Once a glyph is */ + /* loaded, `outline' can be transformed, */ + /* distorted, embolded, etc. However, it must */ + /* not be freed. */ + /* */ + /* num_subglyphs :: The number of subglyphs in a composite glyph. */ + /* This field is only valid for the composite */ + /* glyph format that should normally only be */ + /* loaded with the @FT_LOAD_NO_RECURSE flag. */ + /* For now this is internal to FreeType. */ + /* */ + /* subglyphs :: An array of subglyph descriptors for */ + /* composite glyphs. There are `num_subglyphs' */ + /* elements in there. Currently internal to */ + /* FreeType. */ + /* */ + /* control_data :: Certain font drivers can also return the */ + /* control data for a given glyph image (e.g. */ + /* TrueType bytecode, Type 1 charstrings, etc.). */ + /* This field is a pointer to such data. */ + /* */ + /* control_len :: This is the length in bytes of the control */ + /* data. */ + /* */ + /* other :: Really wicked formats can use this pointer to */ + /* present their own glyph image to client */ + /* applications. Note that the application */ + /* needs to know about the image format. */ + /* */ + /* lsb_delta :: The difference between hinted and unhinted */ + /* left side bearing while autohinting is */ + /* active. Zero otherwise. */ + /* */ + /* rsb_delta :: The difference between hinted and unhinted */ + /* right side bearing while autohinting is */ + /* active. Zero otherwise. */ + /* */ + /* <Note> */ + /* If @FT_Load_Glyph is called with default flags (see */ + /* @FT_LOAD_DEFAULT) the glyph image is loaded in the glyph slot in */ + /* its native format (e.g., an outline glyph for TrueType and Type 1 */ + /* formats). */ + /* */ + /* This image can later be converted into a bitmap by calling */ + /* @FT_Render_Glyph. This function finds the current renderer for */ + /* the native image's format then invokes it. */ + /* */ + /* The renderer is in charge of transforming the native image through */ + /* the slot's face transformation fields, then convert it into a */ + /* bitmap that is returned in `slot->bitmap'. */ + /* */ + /* Note that `slot->bitmap_left' and `slot->bitmap_top' are also used */ + /* to specify the position of the bitmap relative to the current pen */ + /* position (e.g., coordinates (0,0) on the baseline). Of course, */ + /* `slot->format' is also changed to @FT_GLYPH_FORMAT_BITMAP. */ + /* */ + /* <Note> */ + /* Here a small pseudo code fragment which shows how to use */ + /* `lsb_delta' and `rsb_delta': */ + /* */ + /* { */ + /* FT_Pos origin_x = 0; */ + /* FT_Pos prev_rsb_delta = 0; */ + /* */ + /* */ + /* for all glyphs do */ + /* <compute kern between current and previous glyph and add it to */ + /* `origin_x'> */ + /* */ + /* <load glyph with `FT_Load_Glyph'> */ + /* */ + /* if ( prev_rsb_delta - face->glyph->lsb_delta >= 32 ) */ + /* origin_x -= 64; */ + /* else if ( prev_rsb_delta - face->glyph->lsb_delta < -32 ) */ + /* origin_x += 64; */ + /* */ + /* prev_rsb_delta = face->glyph->rsb_delta; */ + /* */ + /* <save glyph image, or render glyph, or ...> */ + /* */ + /* origin_x += face->glyph->advance.x; */ + /* endfor */ + /* } */ + /* */ + typedef struct FT_GlyphSlotRec_ + { + FT_Library library; + FT_Face face; + FT_GlyphSlot next; + FT_UInt reserved; /* retained for binary compatibility */ + FT_Generic generic; + + FT_Glyph_Metrics metrics; + FT_Fixed linearHoriAdvance; + FT_Fixed linearVertAdvance; + FT_Vector advance; + + FT_Glyph_Format format; + + FT_Bitmap bitmap; + FT_Int bitmap_left; + FT_Int bitmap_top; + + FT_Outline outline; + + FT_UInt num_subglyphs; + FT_SubGlyph subglyphs; + + void* control_data; + long control_len; + + FT_Pos lsb_delta; + FT_Pos rsb_delta; + + void* other; + + FT_Slot_Internal internal; + + } FT_GlyphSlotRec; + + + /*************************************************************************/ + /*************************************************************************/ + /* */ + /* F U N C T I O N S */ + /* */ + /*************************************************************************/ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Init_FreeType */ + /* */ + /* <Description> */ + /* Initialize a new FreeType library object. The set of modules */ + /* that are registered by this function is determined at build time. */ + /* */ + /* <Output> */ + /* alibrary :: A handle to a new library object. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Init_FreeType( FT_Library *alibrary ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Done_FreeType */ + /* */ + /* <Description> */ + /* Destroy a given FreeType library object and all of its children, */ + /* including resources, drivers, faces, sizes, etc. */ + /* */ + /* <Input> */ + /* library :: A handle to the target library object. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Done_FreeType( FT_Library library ); + + + /*************************************************************************/ + /* */ + /* <Enum> */ + /* FT_OPEN_XXX */ + /* */ + /* <Description> */ + /* A list of bit-field constants used within the `flags' field of the */ + /* @FT_Open_Args structure. */ + /* */ + /* <Values> */ + /* FT_OPEN_MEMORY :: This is a memory-based stream. */ + /* */ + /* FT_OPEN_STREAM :: Copy the stream from the `stream' field. */ + /* */ + /* FT_OPEN_PATHNAME :: Create a new input stream from a C */ + /* path name. */ + /* */ + /* FT_OPEN_DRIVER :: Use the `driver' field. */ + /* */ + /* FT_OPEN_PARAMS :: Use the `num_params' and `params' fields. */ + /* */ + /* ft_open_memory :: Deprecated; use @FT_OPEN_MEMORY instead. */ + /* */ + /* ft_open_stream :: Deprecated; use @FT_OPEN_STREAM instead. */ + /* */ + /* ft_open_pathname :: Deprecated; use @FT_OPEN_PATHNAME instead. */ + /* */ + /* ft_open_driver :: Deprecated; use @FT_OPEN_DRIVER instead. */ + /* */ + /* ft_open_params :: Deprecated; use @FT_OPEN_PARAMS instead. */ + /* */ + /* <Note> */ + /* The `FT_OPEN_MEMORY', `FT_OPEN_STREAM', and `FT_OPEN_PATHNAME' */ + /* flags are mutually exclusive. */ + /* */ +#define FT_OPEN_MEMORY 0x1 +#define FT_OPEN_STREAM 0x2 +#define FT_OPEN_PATHNAME 0x4 +#define FT_OPEN_DRIVER 0x8 +#define FT_OPEN_PARAMS 0x10 + +#define ft_open_memory FT_OPEN_MEMORY /* deprecated */ +#define ft_open_stream FT_OPEN_STREAM /* deprecated */ +#define ft_open_pathname FT_OPEN_PATHNAME /* deprecated */ +#define ft_open_driver FT_OPEN_DRIVER /* deprecated */ +#define ft_open_params FT_OPEN_PARAMS /* deprecated */ + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_Parameter */ + /* */ + /* <Description> */ + /* A simple structure used to pass more or less generic parameters */ + /* to @FT_Open_Face. */ + /* */ + /* <Fields> */ + /* tag :: A four-byte identification tag. */ + /* */ + /* data :: A pointer to the parameter data. */ + /* */ + /* <Note> */ + /* The ID and function of parameters are driver-specific. */ + /* */ + typedef struct FT_Parameter_ + { + FT_ULong tag; + FT_Pointer data; + + } FT_Parameter; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_Open_Args */ + /* */ + /* <Description> */ + /* A structure used to indicate how to open a new font file or */ + /* stream. A pointer to such a structure can be used as a parameter */ + /* for the functions @FT_Open_Face and @FT_Attach_Stream. */ + /* */ + /* <Fields> */ + /* flags :: A set of bit flags indicating how to use the */ + /* structure. */ + /* */ + /* memory_base :: The first byte of the file in memory. */ + /* */ + /* memory_size :: The size in bytes of the file in memory. */ + /* */ + /* pathname :: A pointer to an 8-bit file pathname. */ + /* */ + /* stream :: A handle to a source stream object. */ + /* */ + /* driver :: This field is exclusively used by @FT_Open_Face; */ + /* it simply specifies the font driver to use to open */ + /* the face. If set to 0, FreeType tries to load the */ + /* face with each one of the drivers in its list. */ + /* */ + /* num_params :: The number of extra parameters. */ + /* */ + /* params :: Extra parameters passed to the font driver when */ + /* opening a new face. */ + /* */ + /* <Note> */ + /* The stream type is determined by the contents of `flags' which */ + /* are tested in the following order by @FT_Open_Face: */ + /* */ + /* If the `FT_OPEN_MEMORY' bit is set, assume that this is a */ + /* memory file of `memory_size' bytes, located at `memory_address'. */ + /* The data are are not copied, and the client is responsible for */ + /* releasing and destroying them _after_ the corresponding call to */ + /* @FT_Done_Face. */ + /* */ + /* Otherwise, if the `FT_OPEN_STREAM' bit is set, assume that a */ + /* custom input stream `stream' is used. */ + /* */ + /* Otherwise, if the `FT_OPEN_PATHNAME' bit is set, assume that this */ + /* is a normal file and use `pathname' to open it. */ + /* */ + /* If the `FT_OPEN_DRIVER' bit is set, @FT_Open_Face only tries to */ + /* open the file with the driver whose handler is in `driver'. */ + /* */ + /* If the `FT_OPEN_PARAMS' bit is set, the parameters given by */ + /* `num_params' and `params' is used. They are ignored otherwise. */ + /* */ + /* Ideally, both the `pathname' and `params' fields should be tagged */ + /* as `const'; this is missing for API backwards compatibility. With */ + /* other words, applications should treat them as read-only. */ + /* */ + typedef struct FT_Open_Args_ + { + FT_UInt flags; + const FT_Byte* memory_base; + FT_Long memory_size; + FT_String* pathname; + FT_Stream stream; + FT_Module driver; + FT_Int num_params; + FT_Parameter* params; + + } FT_Open_Args; + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_New_Face */ + /* */ + /* <Description> */ + /* This function calls @FT_Open_Face to open a font by its pathname. */ + /* */ + /* <InOut> */ + /* library :: A handle to the library resource. */ + /* */ + /* <Input> */ + /* pathname :: A path to the font file. */ + /* */ + /* face_index :: The index of the face within the font. The first */ + /* face has index 0. */ + /* */ + /* <Output> */ + /* aface :: A handle to a new face object. If `face_index' is */ + /* greater than or equal to zero, it must be non-NULL. */ + /* See @FT_Open_Face for more details. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_EXPORT( FT_Error ) + FT_New_Face( FT_Library library, + const char* filepathname, + FT_Long face_index, + FT_Face *aface ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_New_Memory_Face */ + /* */ + /* <Description> */ + /* This function calls @FT_Open_Face to open a font which has been */ + /* loaded into memory. */ + /* */ + /* <InOut> */ + /* library :: A handle to the library resource. */ + /* */ + /* <Input> */ + /* file_base :: A pointer to the beginning of the font data. */ + /* */ + /* file_size :: The size of the memory chunk used by the font data. */ + /* */ + /* face_index :: The index of the face within the font. The first */ + /* face has index 0. */ + /* */ + /* <Output> */ + /* aface :: A handle to a new face object. If `face_index' is */ + /* greater than or equal to zero, it must be non-NULL. */ + /* See @FT_Open_Face for more details. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* You must not deallocate the memory before calling @FT_Done_Face. */ + /* */ + FT_EXPORT( FT_Error ) + FT_New_Memory_Face( FT_Library library, + const FT_Byte* file_base, + FT_Long file_size, + FT_Long face_index, + FT_Face *aface ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Open_Face */ + /* */ + /* <Description> */ + /* Create a face object from a given resource described by */ + /* @FT_Open_Args. */ + /* */ + /* <InOut> */ + /* library :: A handle to the library resource. */ + /* */ + /* <Input> */ + /* args :: A pointer to an `FT_Open_Args' structure which must */ + /* be filled by the caller. */ + /* */ + /* face_index :: The index of the face within the font. The first */ + /* face has index 0. */ + /* */ + /* <Output> */ + /* aface :: A handle to a new face object. If `face_index' is */ + /* greater than or equal to zero, it must be non-NULL. */ + /* See note below. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* Unlike FreeType 1.x, this function automatically creates a glyph */ + /* slot for the face object which can be accessed directly through */ + /* `face->glyph'. */ + /* */ + /* FT_Open_Face can be used to quickly check whether the font */ + /* format of a given font resource is supported by FreeType. If the */ + /* `face_index' field is negative, the function's return value is 0 */ + /* if the font format is recognized, or non-zero otherwise; */ + /* the function returns a more or less empty face handle in `*aface' */ + /* (if `aface' isn't NULL). The only useful field in this special */ + /* case is `face->num_faces' which gives the number of faces within */ + /* the font file. After examination, the returned @FT_Face structure */ + /* should be deallocated with a call to @FT_Done_Face. */ + /* */ + /* Each new face object created with this function also owns a */ + /* default @FT_Size object, accessible as `face->size'. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Open_Face( FT_Library library, + const FT_Open_Args* args, + FT_Long face_index, + FT_Face *aface ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Attach_File */ + /* */ + /* <Description> */ + /* This function calls @FT_Attach_Stream to attach a file. */ + /* */ + /* <InOut> */ + /* face :: The target face object. */ + /* */ + /* <Input> */ + /* filepathname :: The pathname. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Attach_File( FT_Face face, + const char* filepathname ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Attach_Stream */ + /* */ + /* <Description> */ + /* `Attach' data to a face object. Normally, this is used to read */ + /* additional information for the face object. For example, you can */ + /* attach an AFM file that comes with a Type 1 font to get the */ + /* kerning values and other metrics. */ + /* */ + /* <InOut> */ + /* face :: The target face object. */ + /* */ + /* <Input> */ + /* parameters :: A pointer to @FT_Open_Args which must be filled by */ + /* the caller. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* The meaning of the `attach' (i.e., what really happens when the */ + /* new file is read) is not fixed by FreeType itself. It really */ + /* depends on the font format (and thus the font driver). */ + /* */ + /* Client applications are expected to know what they are doing */ + /* when invoking this function. Most drivers simply do not implement */ + /* file attachments. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Attach_Stream( FT_Face face, + FT_Open_Args* parameters ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Done_Face */ + /* */ + /* <Description> */ + /* Discard a given face object, as well as all of its child slots and */ + /* sizes. */ + /* */ + /* <Input> */ + /* face :: A handle to a target face object. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Done_Face( FT_Face face ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Select_Size */ + /* */ + /* <Description> */ + /* Select a bitmap strike. */ + /* */ + /* <InOut> */ + /* face :: A handle to a target face object. */ + /* */ + /* <Input> */ + /* strike_index :: The index of the bitmap strike in the */ + /* `available_sizes' field of @FT_FaceRec structure. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Select_Size( FT_Face face, + FT_Int strike_index ); + + + /*************************************************************************/ + /* */ + /* <Enum> */ + /* FT_Size_Request_Type */ + /* */ + /* <Description> */ + /* An enumeration type that lists the supported size request types. */ + /* */ + /* <Values> */ + /* FT_SIZE_REQUEST_TYPE_NOMINAL :: */ + /* The nominal size. The `units_per_EM' field of @FT_FaceRec is */ + /* used to determine both scaling values. */ + /* */ + /* FT_SIZE_REQUEST_TYPE_REAL_DIM :: */ + /* The real dimension. The sum of the the `Ascender' and (minus */ + /* of) the `Descender' fields of @FT_FaceRec are used to determine */ + /* both scaling values. */ + /* */ + /* FT_SIZE_REQUEST_TYPE_BBOX :: */ + /* The font bounding box. The width and height of the `bbox' field */ + /* of @FT_FaceRec are used to determine the horizontal and vertical */ + /* scaling value, respectively. */ + /* */ + /* FT_SIZE_REQUEST_TYPE_CELL :: */ + /* The `max_advance_width' field of @FT_FaceRec is used to */ + /* determine the horizontal scaling value; the vertical scaling */ + /* value is determined the same way as */ + /* @FT_SIZE_REQUEST_TYPE_REAL_DIM does. Finally, both scaling */ + /* values are set to the smaller one. This type is useful if you */ + /* want to specify the font size for, say, a window of a given */ + /* dimension and 80x24 cells. */ + /* */ + /* FT_SIZE_REQUEST_TYPE_SCALES :: */ + /* Specify the scaling values directly. */ + /* */ + /* <Note> */ + /* The above descriptions only apply to scalable formats. For bitmap */ + /* formats, the behaviour is up to the driver. */ + /* */ + /* See the note section of @FT_Size_Metrics if you wonder how size */ + /* requesting relates to scaling values. */ + /* */ + typedef enum FT_Size_Request_Type_ + { + FT_SIZE_REQUEST_TYPE_NOMINAL, + FT_SIZE_REQUEST_TYPE_REAL_DIM, + FT_SIZE_REQUEST_TYPE_BBOX, + FT_SIZE_REQUEST_TYPE_CELL, + FT_SIZE_REQUEST_TYPE_SCALES, + + FT_SIZE_REQUEST_TYPE_MAX + + } FT_Size_Request_Type; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_Size_RequestRec */ + /* */ + /* <Description> */ + /* A structure used to model a size request. */ + /* */ + /* <Fields> */ + /* type :: See @FT_Size_Request_Type. */ + /* */ + /* width :: The desired width. */ + /* */ + /* height :: The desired height. */ + /* */ + /* horiResolution :: The horizontal resolution. If set to zero, */ + /* `width' is treated as a 26.6 fractional pixel */ + /* value. */ + /* */ + /* vertResolution :: The vertical resolution. If set to zero, */ + /* `height' is treated as a 26.6 fractional pixel */ + /* value. */ + /* */ + /* <Note> */ + /* If `width' is zero, then the horizontal scaling value is set */ + /* equal to the vertical scaling value, and vice versa. */ + /* */ + typedef struct FT_Size_RequestRec_ + { + FT_Size_Request_Type type; + FT_Long width; + FT_Long height; + FT_UInt horiResolution; + FT_UInt vertResolution; + + } FT_Size_RequestRec, *FT_Size_Request; + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Request_Size */ + /* */ + /* <Description> */ + /* Resize the scale of the active @FT_Size object in a face. */ + /* */ + /* <InOut> */ + /* face :: A handle to a target face object. */ + /* */ + /* <Input> */ + /* req :: A pointer to a @FT_Size_RequestRec. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* Although drivers may select the bitmap strike matching the */ + /* request, you should not rely on this if you intend to select a */ + /* particular bitmap strike. Use @FT_Select_Size instead in that */ + /* case. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Request_Size( FT_Face face, + FT_Size_Request req ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Set_Char_Size */ + /* */ + /* <Description> */ + /* This function calls @FT_Request_Size to request the nominal size */ + /* (in points). */ + /* */ + /* <InOut> */ + /* face :: A handle to a target face object. */ + /* */ + /* <Input> */ + /* char_width :: The nominal width, in 26.6 fractional points. */ + /* */ + /* char_height :: The nominal height, in 26.6 fractional points. */ + /* */ + /* horz_resolution :: The horizontal resolution in dpi. */ + /* */ + /* vert_resolution :: The vertical resolution in dpi. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* If either the character width or height is zero, it is set equal */ + /* to the other value. */ + /* */ + /* If either the horizontal or vertical resolution is zero, it is set */ + /* equal to the other value. */ + /* */ + /* A character width or height smaller than 1pt is set to 1pt; if */ + /* both resolution values are zero, they are set to 72dpi. */ + /* */ + + FT_EXPORT( FT_Error ) + FT_Set_Char_Size( FT_Face face, + FT_F26Dot6 char_width, + FT_F26Dot6 char_height, + FT_UInt horz_resolution, + FT_UInt vert_resolution ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Set_Pixel_Sizes */ + /* */ + /* <Description> */ + /* This function calls @FT_Request_Size to request the nominal size */ + /* (in pixels). */ + /* */ + /* <InOut> */ + /* face :: A handle to the target face object. */ + /* */ + /* <Input> */ + /* pixel_width :: The nominal width, in pixels. */ + /* */ + /* pixel_height :: The nominal height, in pixels. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Set_Pixel_Sizes( FT_Face face, + FT_UInt pixel_width, + FT_UInt pixel_height ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Load_Glyph */ + /* */ + /* <Description> */ + /* A function used to load a single glyph into the glyph slot of a */ + /* face object. */ + /* */ + /* <InOut> */ + /* face :: A handle to the target face object where the glyph */ + /* is loaded. */ + /* */ + /* <Input> */ + /* glyph_index :: The index of the glyph in the font file. For */ + /* CID-keyed fonts (either in PS or in CFF format) */ + /* this argument specifies the CID value. */ + /* */ + /* load_flags :: A flag indicating what to load for this glyph. The */ + /* @FT_LOAD_XXX constants can be used to control the */ + /* glyph loading process (e.g., whether the outline */ + /* should be scaled, whether to load bitmaps or not, */ + /* whether to hint the outline, etc). */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* The loaded glyph may be transformed. See @FT_Set_Transform for */ + /* the details. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Load_Glyph( FT_Face face, + FT_UInt glyph_index, + FT_Int32 load_flags ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Load_Char */ + /* */ + /* <Description> */ + /* A function used to load a single glyph into the glyph slot of a */ + /* face object, according to its character code. */ + /* */ + /* <InOut> */ + /* face :: A handle to a target face object where the glyph */ + /* is loaded. */ + /* */ + /* <Input> */ + /* char_code :: The glyph's character code, according to the */ + /* current charmap used in the face. */ + /* */ + /* load_flags :: A flag indicating what to load for this glyph. The */ + /* @FT_LOAD_XXX constants can be used to control the */ + /* glyph loading process (e.g., whether the outline */ + /* should be scaled, whether to load bitmaps or not, */ + /* whether to hint the outline, etc). */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* This function simply calls @FT_Get_Char_Index and @FT_Load_Glyph. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Load_Char( FT_Face face, + FT_ULong char_code, + FT_Int32 load_flags ); + + + /************************************************************************* + * + * @enum: + * FT_LOAD_XXX + * + * @description: + * A list of bit-field constants used with @FT_Load_Glyph to indicate + * what kind of operations to perform during glyph loading. + * + * @values: + * FT_LOAD_DEFAULT :: + * Corresponding to 0, this value is used as the default glyph load + * operation. In this case, the following happens: + * + * 1. FreeType looks for a bitmap for the glyph corresponding to the + * face's current size. If one is found, the function returns. + * The bitmap data can be accessed from the glyph slot (see note + * below). + * + * 2. If no embedded bitmap is searched or found, FreeType looks for a + * scalable outline. If one is found, it is loaded from the font + * file, scaled to device pixels, then `hinted' to the pixel grid + * in order to optimize it. The outline data can be accessed from + * the glyph slot (see note below). + * + * Note that by default, the glyph loader doesn't render outlines into + * bitmaps. The following flags are used to modify this default + * behaviour to more specific and useful cases. + * + * FT_LOAD_NO_SCALE :: + * Don't scale the outline glyph loaded, but keep it in font units. + * + * This flag implies @FT_LOAD_NO_HINTING and @FT_LOAD_NO_BITMAP, and + * unsets @FT_LOAD_RENDER. + * + * FT_LOAD_NO_HINTING :: + * Disable hinting. This generally generates `blurrier' bitmap glyph + * when the glyph is rendered in any of the anti-aliased modes. See + * also the note below. + * + * This flag is implied by @FT_LOAD_NO_SCALE. + * + * FT_LOAD_RENDER :: + * Call @FT_Render_Glyph after the glyph is loaded. By default, the + * glyph is rendered in @FT_RENDER_MODE_NORMAL mode. This can be + * overridden by @FT_LOAD_TARGET_XXX or @FT_LOAD_MONOCHROME. + * + * This flag is unset by @FT_LOAD_NO_SCALE. + * + * FT_LOAD_NO_BITMAP :: + * Ignore bitmap strikes when loading. Bitmap-only fonts ignore this + * flag. + * + * @FT_LOAD_NO_SCALE always sets this flag. + * + * FT_LOAD_VERTICAL_LAYOUT :: + * Load the glyph for vertical text layout. _Don't_ use it as it is + * problematic currently. + * + * FT_LOAD_FORCE_AUTOHINT :: + * Indicates that the auto-hinter is preferred over the font's native + * hinter. See also the note below. + * + * FT_LOAD_CROP_BITMAP :: + * Indicates that the font driver should crop the loaded bitmap glyph + * (i.e., remove all space around its black bits). Not all drivers + * implement this. + * + * FT_LOAD_PEDANTIC :: + * Indicates that the font driver should perform pedantic verifications + * during glyph loading. This is mostly used to detect broken glyphs + * in fonts. By default, FreeType tries to handle broken fonts also. + * + * FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH :: + * Indicates that the font driver should ignore the global advance + * width defined in the font. By default, that value is used as the + * advance width for all glyphs when the face has + * @FT_FACE_FLAG_FIXED_WIDTH set. + * + * This flag exists for historical reasons (to support buggy CJK + * fonts). + * + * FT_LOAD_NO_RECURSE :: + * This flag is only used internally. It merely indicates that the + * font driver should not load composite glyphs recursively. Instead, + * it should set the `num_subglyph' and `subglyphs' values of the + * glyph slot accordingly, and set `glyph->format' to + * @FT_GLYPH_FORMAT_COMPOSITE. + * + * The description of sub-glyphs is not available to client + * applications for now. + * + * This flag implies @FT_LOAD_NO_SCALE and @FT_LOAD_IGNORE_TRANSFORM. + * + * FT_LOAD_IGNORE_TRANSFORM :: + * Indicates that the transform matrix set by @FT_Set_Transform should + * be ignored. + * + * FT_LOAD_MONOCHROME :: + * This flag is used with @FT_LOAD_RENDER to indicate that you want to + * render an outline glyph to a 1-bit monochrome bitmap glyph, with + * 8 pixels packed into each byte of the bitmap data. + * + * Note that this has no effect on the hinting algorithm used. You + * should use @FT_LOAD_TARGET_MONO instead so that the + * monochrome-optimized hinting algorithm is used. + * + * FT_LOAD_LINEAR_DESIGN :: + * Indicates that the `linearHoriAdvance' and `linearVertAdvance' + * fields of @FT_GlyphSlotRec should be kept in font units. See + * @FT_GlyphSlotRec for details. + * + * FT_LOAD_NO_AUTOHINT :: + * Disable auto-hinter. See also the note below. + * + * @note: + * By default, hinting is enabled and the font's native hinter (see + * @FT_FACE_FLAG_HINTER) is preferred over the auto-hinter. You can + * disable hinting by setting @FT_LOAD_NO_HINTING or change the + * precedence by setting @FT_LOAD_FORCE_AUTOHINT. You can also set + * @FT_LOAD_NO_AUTOHINT in case you don't want the auto-hinter to be + * used at all. + * + * Besides deciding which hinter to use, you can also decide which + * hinting algorithm to use. See @FT_LOAD_TARGET_XXX for details. + */ +#define FT_LOAD_DEFAULT 0x0 +#define FT_LOAD_NO_SCALE 0x1 +#define FT_LOAD_NO_HINTING 0x2 +#define FT_LOAD_RENDER 0x4 +#define FT_LOAD_NO_BITMAP 0x8 +#define FT_LOAD_VERTICAL_LAYOUT 0x10 +#define FT_LOAD_FORCE_AUTOHINT 0x20 +#define FT_LOAD_CROP_BITMAP 0x40 +#define FT_LOAD_PEDANTIC 0x80 +#define FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH 0x200 +#define FT_LOAD_NO_RECURSE 0x400 +#define FT_LOAD_IGNORE_TRANSFORM 0x800 +#define FT_LOAD_MONOCHROME 0x1000 +#define FT_LOAD_LINEAR_DESIGN 0x2000 + + /* temporary hack! */ +#define FT_LOAD_SBITS_ONLY 0x4000 +#define FT_LOAD_NO_AUTOHINT 0x8000U + + /* */ + + + /************************************************************************** + * + * @enum: + * FT_LOAD_TARGET_XXX + * + * @description: + * A list of values that are used to select a specific hinting algorithm + * to use by the hinter. You should OR one of these values to your + * `load_flags' when calling @FT_Load_Glyph. + * + * Note that font's native hinters may ignore the hinting algorithm you + * have specified (e.g., the TrueType bytecode interpreter). You can set + * @FT_LOAD_FORCE_AUTOHINT to ensure that the auto-hinter is used. + * + * Also note that @FT_LOAD_TARGET_LIGHT is an exception, in that it + * always implies @FT_LOAD_FORCE_AUTOHINT. + * + * @values: + * FT_LOAD_TARGET_NORMAL :: + * This corresponds to the default hinting algorithm, optimized for + * standard gray-level rendering. For monochrome output, use + * @FT_LOAD_TARGET_MONO instead. + * + * FT_LOAD_TARGET_LIGHT :: + * A lighter hinting algorithm for non-monochrome modes. Many + * generated glyphs are more fuzzy but better resemble its original + * shape. A bit like rendering on Mac OS X. + * + * As a special exception, this target implies @FT_LOAD_FORCE_AUTOHINT. + * + * FT_LOAD_TARGET_MONO :: + * Strong hinting algorithm that should only be used for monochrome + * output. The result is probably unpleasant if the glyph is rendered + * in non-monochrome modes. + * + * FT_LOAD_TARGET_LCD :: + * A variant of @FT_LOAD_TARGET_NORMAL optimized for horizontally + * decimated LCD displays. + * + * FT_LOAD_TARGET_LCD_V :: + * A variant of @FT_LOAD_TARGET_NORMAL optimized for vertically + * decimated LCD displays. + * + * @note: + * You should use only _one_ of the FT_LOAD_TARGET_XXX values in your + * `load_flags'. They can't be ORed. + * + * If @FT_LOAD_RENDER is also set, the glyph is rendered in the + * corresponding mode (i.e., the mode which matches the used algorithm + * best) unless @FT_LOAD_MONOCHROME is set. + * + * You can use a hinting algorithm that doesn't correspond to the same + * rendering mode. As an example, it is possible to use the `light' + * hinting algorithm and have the results rendered in horizontal LCD + * pixel mode, with code like + * + * { + * FT_Load_Glyph( face, glyph_index, + * load_flags | FT_LOAD_TARGET_LIGHT ); + * + * FT_Render_Glyph( face->glyph, FT_RENDER_MODE_LCD ); + * } + */ + +#define FT_LOAD_TARGET_( x ) ( (FT_Int32)( (x) & 15 ) << 16 ) + +#define FT_LOAD_TARGET_NORMAL FT_LOAD_TARGET_( FT_RENDER_MODE_NORMAL ) +#define FT_LOAD_TARGET_LIGHT FT_LOAD_TARGET_( FT_RENDER_MODE_LIGHT ) +#define FT_LOAD_TARGET_MONO FT_LOAD_TARGET_( FT_RENDER_MODE_MONO ) +#define FT_LOAD_TARGET_LCD FT_LOAD_TARGET_( FT_RENDER_MODE_LCD ) +#define FT_LOAD_TARGET_LCD_V FT_LOAD_TARGET_( FT_RENDER_MODE_LCD_V ) + + + /* + * @macro: + * FT_LOAD_TARGET_MODE + * + * @description: + * Return the @FT_Render_Mode corresponding to a given + * @FT_LOAD_TARGET_XXX value. + */ + +#define FT_LOAD_TARGET_MODE( x ) ( (FT_Render_Mode)( ( (x) >> 16 ) & 15 ) ) + + /* */ + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Set_Transform */ + /* */ + /* <Description> */ + /* A function used to set the transformation that is applied to glyph */ + /* images when they are loaded into a glyph slot through */ + /* @FT_Load_Glyph. */ + /* */ + /* <InOut> */ + /* face :: A handle to the source face object. */ + /* */ + /* <Input> */ + /* matrix :: A pointer to the transformation's 2x2 matrix. Use 0 for */ + /* the identity matrix. */ + /* delta :: A pointer to the translation vector. Use 0 for the null */ + /* vector. */ + /* */ + /* <Note> */ + /* The transformation is only applied to scalable image formats after */ + /* the glyph has been loaded. It means that hinting is unaltered by */ + /* the transformation and is performed on the character size given in */ + /* the last call to @FT_Set_Char_Size or @FT_Set_Pixel_Sizes. */ + /* */ + /* Note that this also transforms the `face.glyph.advance' field, but */ + /* *not* the values in `face.glyph.metrics'. */ + /* */ + FT_EXPORT( void ) + FT_Set_Transform( FT_Face face, + FT_Matrix* matrix, + FT_Vector* delta ); + + + /*************************************************************************/ + /* */ + /* <Enum> */ + /* FT_Render_Mode */ + /* */ + /* <Description> */ + /* An enumeration type that lists the render modes supported by */ + /* FreeType 2. Each mode corresponds to a specific type of scanline */ + /* conversion performed on the outline. */ + /* */ + /* For bitmap fonts the `bitmap->pixel_mode' field in the */ + /* @FT_GlyphSlotRec structure gives the format of the returned */ + /* bitmap. */ + /* */ + /* <Values> */ + /* FT_RENDER_MODE_NORMAL :: */ + /* This is the default render mode; it corresponds to 8-bit */ + /* anti-aliased bitmaps, using 256 levels of opacity. */ + /* */ + /* FT_RENDER_MODE_LIGHT :: */ + /* This is equivalent to @FT_RENDER_MODE_NORMAL. It is only */ + /* defined as a separate value because render modes are also used */ + /* indirectly to define hinting algorithm selectors. See */ + /* @FT_LOAD_TARGET_XXX for details. */ + /* */ + /* FT_RENDER_MODE_MONO :: */ + /* This mode corresponds to 1-bit bitmaps. */ + /* */ + /* FT_RENDER_MODE_LCD :: */ + /* This mode corresponds to horizontal RGB and BGR sub-pixel */ + /* displays, like LCD-screens. It produces 8-bit bitmaps that are */ + /* 3 times the width of the original glyph outline in pixels, and */ + /* which use the @FT_PIXEL_MODE_LCD mode. */ + /* */ + /* FT_RENDER_MODE_LCD_V :: */ + /* This mode corresponds to vertical RGB and BGR sub-pixel displays */ + /* (like PDA screens, rotated LCD displays, etc.). It produces */ + /* 8-bit bitmaps that are 3 times the height of the original */ + /* glyph outline in pixels and use the @FT_PIXEL_MODE_LCD_V mode. */ + /* */ + /* <Note> */ + /* The LCD-optimized glyph bitmaps produced by FT_Render_Glyph are */ + /* _not_ _filtered_ to reduce color-fringes. It is up to the caller */ + /* to perform this pass. */ + /* */ + typedef enum FT_Render_Mode_ + { + FT_RENDER_MODE_NORMAL = 0, + FT_RENDER_MODE_LIGHT, + FT_RENDER_MODE_MONO, + FT_RENDER_MODE_LCD, + FT_RENDER_MODE_LCD_V, + + FT_RENDER_MODE_MAX + + } FT_Render_Mode; + + + /*************************************************************************/ + /* */ + /* <Enum> */ + /* ft_render_mode_xxx */ + /* */ + /* <Description> */ + /* These constants are deprecated. Use the corresponding */ + /* @FT_Render_Mode values instead. */ + /* */ + /* <Values> */ + /* ft_render_mode_normal :: see @FT_RENDER_MODE_NORMAL */ + /* ft_render_mode_mono :: see @FT_RENDER_MODE_MONO */ + /* */ +#define ft_render_mode_normal FT_RENDER_MODE_NORMAL +#define ft_render_mode_mono FT_RENDER_MODE_MONO + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Render_Glyph */ + /* */ + /* <Description> */ + /* Convert a given glyph image to a bitmap. It does so by inspecting */ + /* the glyph image format, finding the relevant renderer, and */ + /* invoking it. */ + /* */ + /* <InOut> */ + /* slot :: A handle to the glyph slot containing the image to */ + /* convert. */ + /* */ + /* <Input> */ + /* render_mode :: This is the render mode used to render the glyph */ + /* image into a bitmap. See @FT_Render_Mode for a */ + /* list of possible values. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Render_Glyph( FT_GlyphSlot slot, + FT_Render_Mode render_mode ); + + + /*************************************************************************/ + /* */ + /* <Enum> */ + /* FT_Kerning_Mode */ + /* */ + /* <Description> */ + /* An enumeration used to specify which kerning values to return in */ + /* @FT_Get_Kerning. */ + /* */ + /* <Values> */ + /* FT_KERNING_DEFAULT :: Return scaled and grid-fitted kerning */ + /* distances (value is 0). */ + /* */ + /* FT_KERNING_UNFITTED :: Return scaled but un-grid-fitted kerning */ + /* distances. */ + /* */ + /* FT_KERNING_UNSCALED :: Return the kerning vector in original font */ + /* units. */ + /* */ + typedef enum FT_Kerning_Mode_ + { + FT_KERNING_DEFAULT = 0, + FT_KERNING_UNFITTED, + FT_KERNING_UNSCALED + + } FT_Kerning_Mode; + + + /*************************************************************************/ + /* */ + /* <Const> */ + /* ft_kerning_default */ + /* */ + /* <Description> */ + /* This constant is deprecated. Please use @FT_KERNING_DEFAULT */ + /* instead. */ + /* */ +#define ft_kerning_default FT_KERNING_DEFAULT + + + /*************************************************************************/ + /* */ + /* <Const> */ + /* ft_kerning_unfitted */ + /* */ + /* <Description> */ + /* This constant is deprecated. Please use @FT_KERNING_UNFITTED */ + /* instead. */ + /* */ +#define ft_kerning_unfitted FT_KERNING_UNFITTED + + + /*************************************************************************/ + /* */ + /* <Const> */ + /* ft_kerning_unscaled */ + /* */ + /* <Description> */ + /* This constant is deprecated. Please use @FT_KERNING_UNSCALED */ + /* instead. */ + /* */ +#define ft_kerning_unscaled FT_KERNING_UNSCALED + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Get_Kerning */ + /* */ + /* <Description> */ + /* Return the kerning vector between two glyphs of a same face. */ + /* */ + /* <Input> */ + /* face :: A handle to a source face object. */ + /* */ + /* left_glyph :: The index of the left glyph in the kern pair. */ + /* */ + /* right_glyph :: The index of the right glyph in the kern pair. */ + /* */ + /* kern_mode :: See @FT_Kerning_Mode for more information. */ + /* Determines the scale and dimension of the returned */ + /* kerning vector. */ + /* */ + /* <Output> */ + /* akerning :: The kerning vector. This is either in font units */ + /* or in pixels (26.6 format) for scalable formats, */ + /* and in pixels for fixed-sizes formats. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* Only horizontal layouts (left-to-right & right-to-left) are */ + /* supported by this method. Other layouts, or more sophisticated */ + /* kernings, are out of the scope of this API function -- they can be */ + /* implemented through format-specific interfaces. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Get_Kerning( FT_Face face, + FT_UInt left_glyph, + FT_UInt right_glyph, + FT_UInt kern_mode, + FT_Vector *akerning ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Get_Track_Kerning */ + /* */ + /* <Description> */ + /* Return the track kerning for a given face object at a given size. */ + /* */ + /* <Input> */ + /* face :: A handle to a source face object. */ + /* */ + /* point_size :: The point size in 16.16 fractional points. */ + /* */ + /* degree :: The degree of tightness. */ + /* */ + /* <Output> */ + /* akerning :: The kerning in 16.16 fractional points. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Get_Track_Kerning( FT_Face face, + FT_Fixed point_size, + FT_Int degree, + FT_Fixed* akerning ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Get_Glyph_Name */ + /* */ + /* <Description> */ + /* Retrieve the ASCII name of a given glyph in a face. This only */ + /* works for those faces where @FT_HAS_GLYPH_NAMES(face) returns 1. */ + /* */ + /* <Input> */ + /* face :: A handle to a source face object. */ + /* */ + /* glyph_index :: The glyph index. */ + /* */ + /* buffer_max :: The maximal number of bytes available in the */ + /* buffer. */ + /* */ + /* <Output> */ + /* buffer :: A pointer to a target buffer where the name is */ + /* copied to. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* An error is returned if the face doesn't provide glyph names or if */ + /* the glyph index is invalid. In all cases of failure, the first */ + /* byte of `buffer' is set to 0 to indicate an empty name. */ + /* */ + /* The glyph name is truncated to fit within the buffer if it is too */ + /* long. The returned string is always zero-terminated. */ + /* */ + /* This function is not compiled within the library if the config */ + /* macro `FT_CONFIG_OPTION_NO_GLYPH_NAMES' is defined in */ + /* `include/freetype/config/ftoptions.h'. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Get_Glyph_Name( FT_Face face, + FT_UInt glyph_index, + FT_Pointer buffer, + FT_UInt buffer_max ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Get_Postscript_Name */ + /* */ + /* <Description> */ + /* Retrieve the ASCII Postscript name of a given face, if available. */ + /* This only works with Postscript and TrueType fonts. */ + /* */ + /* <Input> */ + /* face :: A handle to the source face object. */ + /* */ + /* <Return> */ + /* A pointer to the face's Postscript name. NULL if unavailable. */ + /* */ + /* <Note> */ + /* The returned pointer is owned by the face and is destroyed with */ + /* it. */ + /* */ + FT_EXPORT( const char* ) + FT_Get_Postscript_Name( FT_Face face ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Select_Charmap */ + /* */ + /* <Description> */ + /* Select a given charmap by its encoding tag (as listed in */ + /* `freetype.h'). */ + /* */ + /* <InOut> */ + /* face :: A handle to the source face object. */ + /* */ + /* <Input> */ + /* encoding :: A handle to the selected encoding. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* This function returns an error if no charmap in the face */ + /* corresponds to the encoding queried here. */ + /* */ + /* Because many fonts contain more than a single cmap for Unicode */ + /* encoding, this function has some special code to select the one */ + /* which covers Unicode best. It is thus preferable to */ + /* @FT_Set_Charmap in this case. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Select_Charmap( FT_Face face, + FT_Encoding encoding ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Set_Charmap */ + /* */ + /* <Description> */ + /* Select a given charmap for character code to glyph index mapping. */ + /* */ + /* <InOut> */ + /* face :: A handle to the source face object. */ + /* */ + /* <Input> */ + /* charmap :: A handle to the selected charmap. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* This function returns an error if the charmap is not part of */ + /* the face (i.e., if it is not listed in the `face->charmaps' */ + /* table). */ + /* */ + FT_EXPORT( FT_Error ) + FT_Set_Charmap( FT_Face face, + FT_CharMap charmap ); + + + /************************************************************************* + * + * @function: + * FT_Get_Charmap_Index + * + * @description: + * Retrieve index of a given charmap. + * + * @input: + * charmap :: + * A handle to a charmap. + * + * @return: + * The index into the array of character maps within the face to which + * `charmap' belongs. + * + */ + FT_EXPORT( FT_Int ) + FT_Get_Charmap_Index( FT_CharMap charmap ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Get_Char_Index */ + /* */ + /* <Description> */ + /* Return the glyph index of a given character code. This function */ + /* uses a charmap object to do the mapping. */ + /* */ + /* <Input> */ + /* face :: A handle to the source face object. */ + /* */ + /* charcode :: The character code. */ + /* */ + /* <Return> */ + /* The glyph index. 0 means `undefined character code'. */ + /* */ + /* <Note> */ + /* If you use FreeType to manipulate the contents of font files */ + /* directly, be aware that the glyph index returned by this function */ + /* doesn't always correspond to the internal indices used within */ + /* the file. This is done to ensure that value 0 always corresponds */ + /* to the `missing glyph'. */ + /* */ + FT_EXPORT( FT_UInt ) + FT_Get_Char_Index( FT_Face face, + FT_ULong charcode ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Get_First_Char */ + /* */ + /* <Description> */ + /* This function is used to return the first character code in the */ + /* current charmap of a given face. It also returns the */ + /* corresponding glyph index. */ + /* */ + /* <Input> */ + /* face :: A handle to the source face object. */ + /* */ + /* <Output> */ + /* agindex :: Glyph index of first character code. 0 if charmap is */ + /* empty. */ + /* */ + /* <Return> */ + /* The charmap's first character code. */ + /* */ + /* <Note> */ + /* You should use this function with @FT_Get_Next_Char to be able to */ + /* parse all character codes available in a given charmap. The code */ + /* should look like this: */ + /* */ + /* { */ + /* FT_ULong charcode; */ + /* FT_UInt gindex; */ + /* */ + /* */ + /* charcode = FT_Get_First_Char( face, &gindex ); */ + /* while ( gindex != 0 ) */ + /* { */ + /* ... do something with (charcode,gindex) pair ... */ + /* */ + /* charcode = FT_Get_Next_Char( face, charcode, &gindex ); */ + /* } */ + /* } */ + /* */ + /* Note that `*agindex' is set to 0 if the charmap is empty. The */ + /* result itself can be 0 in two cases: if the charmap is empty or */ + /* when the value 0 is the first valid character code. */ + /* */ + FT_EXPORT( FT_ULong ) + FT_Get_First_Char( FT_Face face, + FT_UInt *agindex ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Get_Next_Char */ + /* */ + /* <Description> */ + /* This function is used to return the next character code in the */ + /* current charmap of a given face following the value `char_code', */ + /* as well as the corresponding glyph index. */ + /* */ + /* <Input> */ + /* face :: A handle to the source face object. */ + /* char_code :: The starting character code. */ + /* */ + /* <Output> */ + /* agindex :: Glyph index of first character code. 0 if charmap */ + /* is empty. */ + /* */ + /* <Return> */ + /* The charmap's next character code. */ + /* */ + /* <Note> */ + /* You should use this function with @FT_Get_First_Char to walk */ + /* over all character codes available in a given charmap. See the */ + /* note for this function for a simple code example. */ + /* */ + /* Note that `*agindex' is set to 0 when there are no more codes in */ + /* the charmap. */ + /* */ + FT_EXPORT( FT_ULong ) + FT_Get_Next_Char( FT_Face face, + FT_ULong char_code, + FT_UInt *agindex ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Get_Name_Index */ + /* */ + /* <Description> */ + /* Return the glyph index of a given glyph name. This function uses */ + /* driver specific objects to do the translation. */ + /* */ + /* <Input> */ + /* face :: A handle to the source face object. */ + /* */ + /* glyph_name :: The glyph name. */ + /* */ + /* <Return> */ + /* The glyph index. 0 means `undefined character code'. */ + /* */ + FT_EXPORT( FT_UInt ) + FT_Get_Name_Index( FT_Face face, + FT_String* glyph_name ); + + + /************************************************************************* + * + * @macro: + * FT_SUBGLYPH_FLAG_XXX + * + * @description: + * A list of constants used to describe subglyphs. Please refer to the + * TrueType specification for the meaning of the various flags. + * + * @values: + * FT_SUBGLYPH_FLAG_ARGS_ARE_WORDS :: + * FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES :: + * FT_SUBGLYPH_FLAG_ROUND_XY_TO_GRID :: + * FT_SUBGLYPH_FLAG_SCALE :: + * FT_SUBGLYPH_FLAG_XY_SCALE :: + * FT_SUBGLYPH_FLAG_2X2 :: + * FT_SUBGLYPH_FLAG_USE_MY_METRICS :: + * + */ +#define FT_SUBGLYPH_FLAG_ARGS_ARE_WORDS 1 +#define FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES 2 +#define FT_SUBGLYPH_FLAG_ROUND_XY_TO_GRID 4 +#define FT_SUBGLYPH_FLAG_SCALE 8 +#define FT_SUBGLYPH_FLAG_XY_SCALE 0x40 +#define FT_SUBGLYPH_FLAG_2X2 0x80 +#define FT_SUBGLYPH_FLAG_USE_MY_METRICS 0x200 + + + /************************************************************************* + * + * @func: + * FT_Get_SubGlyph_Info + * + * @description: + * Retrieve a description of a given subglyph. Only use it if + * `glyph->format' is @FT_GLYPH_FORMAT_COMPOSITE, or an error is + * returned. + * + * @input: + * glyph :: + * The source glyph slot. + * + * sub_index :: + * The index of subglyph. Must be less than `glyph->num_subglyphs'. + * + * @output: + * p_index :: + * The glyph index of the subglyph. + * + * p_flags :: + * The subglyph flags, see @FT_SUBGLYPH_FLAG_XXX. + * + * p_arg1 :: + * The subglyph's first argument (if any). + * + * p_arg2 :: + * The subglyph's second argument (if any). + * + * p_transform :: + * The subglyph transformation (if any). + * + * @return: + * FreeType error code. 0 means success. + * + * @note: + * The values of `*p_arg1', `*p_arg2', and `*p_transform' must be + * interpreted depending on the flags returned in `*p_flags'. See the + * TrueType specification for details. + * + */ + FT_EXPORT( FT_Error ) + FT_Get_SubGlyph_Info( FT_GlyphSlot glyph, + FT_UInt sub_index, + FT_Int *p_index, + FT_UInt *p_flags, + FT_Int *p_arg1, + FT_Int *p_arg2, + FT_Matrix *p_transform ); + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* computations */ + /* */ + /* <Title> */ + /* Computations */ + /* */ + /* <Abstract> */ + /* Crunching fixed numbers and vectors. */ + /* */ + /* <Description> */ + /* This section contains various functions used to perform */ + /* computations on 16.16 fixed-float numbers or 2d vectors. */ + /* */ + /* <Order> */ + /* FT_MulDiv */ + /* FT_MulFix */ + /* FT_DivFix */ + /* FT_RoundFix */ + /* FT_CeilFix */ + /* FT_FloorFix */ + /* FT_Vector_Transform */ + /* FT_Matrix_Multiply */ + /* FT_Matrix_Invert */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_MulDiv */ + /* */ + /* <Description> */ + /* A very simple function used to perform the computation `(a*b)/c' */ + /* with maximal accuracy (it uses a 64-bit intermediate integer */ + /* whenever necessary). */ + /* */ + /* This function isn't necessarily as fast as some processor specific */ + /* operations, but is at least completely portable. */ + /* */ + /* <Input> */ + /* a :: The first multiplier. */ + /* b :: The second multiplier. */ + /* c :: The divisor. */ + /* */ + /* <Return> */ + /* The result of `(a*b)/c'. This function never traps when trying to */ + /* divide by zero; it simply returns `MaxInt' or `MinInt' depending */ + /* on the signs of `a' and `b'. */ + /* */ + FT_EXPORT( FT_Long ) + FT_MulDiv( FT_Long a, + FT_Long b, + FT_Long c ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_MulFix */ + /* */ + /* <Description> */ + /* A very simple function used to perform the computation */ + /* `(a*b)/0x10000' with maximal accuracy. Most of the time this is */ + /* used to multiply a given value by a 16.16 fixed float factor. */ + /* */ + /* <Input> */ + /* a :: The first multiplier. */ + /* b :: The second multiplier. Use a 16.16 factor here whenever */ + /* possible (see note below). */ + /* */ + /* <Return> */ + /* The result of `(a*b)/0x10000'. */ + /* */ + /* <Note> */ + /* This function has been optimized for the case where the absolute */ + /* value of `a' is less than 2048, and `b' is a 16.16 scaling factor. */ + /* As this happens mainly when scaling from notional units to */ + /* fractional pixels in FreeType, it resulted in noticeable speed */ + /* improvements between versions 2.x and 1.x. */ + /* */ + /* As a conclusion, always try to place a 16.16 factor as the */ + /* _second_ argument of this function; this can make a great */ + /* difference. */ + /* */ + FT_EXPORT( FT_Long ) + FT_MulFix( FT_Long a, + FT_Long b ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_DivFix */ + /* */ + /* <Description> */ + /* A very simple function used to perform the computation */ + /* `(a*0x10000)/b' with maximal accuracy. Most of the time, this is */ + /* used to divide a given value by a 16.16 fixed float factor. */ + /* */ + /* <Input> */ + /* a :: The first multiplier. */ + /* b :: The second multiplier. Use a 16.16 factor here whenever */ + /* possible (see note below). */ + /* */ + /* <Return> */ + /* The result of `(a*0x10000)/b'. */ + /* */ + /* <Note> */ + /* The optimization for FT_DivFix() is simple: If (a << 16) fits in */ + /* 32 bits, then the division is computed directly. Otherwise, we */ + /* use a specialized version of @FT_MulDiv. */ + /* */ + FT_EXPORT( FT_Long ) + FT_DivFix( FT_Long a, + FT_Long b ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_RoundFix */ + /* */ + /* <Description> */ + /* A very simple function used to round a 16.16 fixed number. */ + /* */ + /* <Input> */ + /* a :: The number to be rounded. */ + /* */ + /* <Return> */ + /* The result of `(a + 0x8000) & -0x10000'. */ + /* */ + FT_EXPORT( FT_Fixed ) + FT_RoundFix( FT_Fixed a ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_CeilFix */ + /* */ + /* <Description> */ + /* A very simple function used to compute the ceiling function of a */ + /* 16.16 fixed number. */ + /* */ + /* <Input> */ + /* a :: The number for which the ceiling function is to be computed. */ + /* */ + /* <Return> */ + /* The result of `(a + 0x10000 - 1) & -0x10000'. */ + /* */ + FT_EXPORT( FT_Fixed ) + FT_CeilFix( FT_Fixed a ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_FloorFix */ + /* */ + /* <Description> */ + /* A very simple function used to compute the floor function of a */ + /* 16.16 fixed number. */ + /* */ + /* <Input> */ + /* a :: The number for which the floor function is to be computed. */ + /* */ + /* <Return> */ + /* The result of `a & -0x10000'. */ + /* */ + FT_EXPORT( FT_Fixed ) + FT_FloorFix( FT_Fixed a ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Vector_Transform */ + /* */ + /* <Description> */ + /* Transform a single vector through a 2x2 matrix. */ + /* */ + /* <InOut> */ + /* vector :: The target vector to transform. */ + /* */ + /* <Input> */ + /* matrix :: A pointer to the source 2x2 matrix. */ + /* */ + /* <Note> */ + /* The result is undefined if either `vector' or `matrix' is invalid. */ + /* */ + FT_EXPORT( void ) + FT_Vector_Transform( FT_Vector* vec, + const FT_Matrix* matrix ); + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* version */ + /* */ + /* <Title> */ + /* FreeType Version */ + /* */ + /* <Abstract> */ + /* Functions and macros related to FreeType versions. */ + /* */ + /* <Description> */ + /* Note that those functions and macros are of limited use because */ + /* even a new release of FreeType with only documentation changes */ + /* increases the version number. */ + /* */ + /*************************************************************************/ + + + /************************************************************************* + * + * @enum: + * FREETYPE_XXX + * + * @description: + * These three macros identify the FreeType source code version. + * Use @FT_Library_Version to access them at runtime. + * + * @values: + * FREETYPE_MAJOR :: The major version number. + * FREETYPE_MINOR :: The minor version number. + * FREETYPE_PATCH :: The patch level. + * + * @note: + * The version number of FreeType if built as a dynamic link library + * with the `libtool' package is _not_ controlled by these three + * macros. + */ +#define FREETYPE_MAJOR 2 +#define FREETYPE_MINOR 3 +#define FREETYPE_PATCH 5 + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Library_Version */ + /* */ + /* <Description> */ + /* Return the version of the FreeType library being used. This is */ + /* useful when dynamically linking to the library, since one cannot */ + /* use the macros @FREETYPE_MAJOR, @FREETYPE_MINOR, and */ + /* @FREETYPE_PATCH. */ + /* */ + /* <Input> */ + /* library :: A source library handle. */ + /* */ + /* <Output> */ + /* amajor :: The major version number. */ + /* */ + /* aminor :: The minor version number. */ + /* */ + /* apatch :: The patch version number. */ + /* */ + /* <Note> */ + /* The reason why this function takes a `library' argument is because */ + /* certain programs implement library initialization in a custom way */ + /* that doesn't use @FT_Init_FreeType. */ + /* */ + /* In such cases, the library version might not be available before */ + /* the library object has been created. */ + /* */ + FT_EXPORT( void ) + FT_Library_Version( FT_Library library, + FT_Int *amajor, + FT_Int *aminor, + FT_Int *apatch ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Face_CheckTrueTypePatents */ + /* */ + /* <Description> */ + /* Parse all bytecode instructions of a TrueType font file to check */ + /* whether any of the patented opcodes are used. This is only useful */ + /* if you want to be able to use the unpatented hinter with */ + /* fonts that do *not* use these opcodes. */ + /* */ + /* Note that this function parses *all* glyph instructions in the */ + /* font file, which may be slow. */ + /* */ + /* <Input> */ + /* face :: A face handle. */ + /* */ + /* <Return> */ + /* 1 if this is a TrueType font that uses one of the patented */ + /* opcodes, 0 otherwise. */ + /* */ + /* <Since> */ + /* 2.3.5 */ + /* */ + FT_EXPORT( FT_Bool ) + FT_Face_CheckTrueTypePatents( FT_Face face ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Face_SetUnpatentedHinting */ + /* */ + /* <Description> */ + /* Enable or disable the unpatented hinter for a given face. */ + /* Only enable it if you have determined that the face doesn't */ + /* use any patented opcodes (see @FT_Face_CheckTrueTypePatents). */ + /* */ + /* <Input> */ + /* face :: A face handle. */ + /* */ + /* value :: New boolean setting. */ + /* */ + /* <Return> */ + /* The old setting value. This will always be false if this is not */ + /* a SFNT font, or if the unpatented hinter is not compiled in this */ + /* instance of the library. */ + /* */ + /* <Since> */ + /* 2.3.5 */ + /* */ + FT_EXPORT( FT_Bool ) + FT_Face_SetUnpatentedHinting( FT_Face face, + FT_Bool value ); + + /* */ + + +FT_END_HEADER + +#endif /* __FREETYPE_H__ */ + + +/* END */ diff --git a/include/freetype/ftbbox.h b/include/freetype/ftbbox.h new file mode 100644 index 0000000..5f79c32 --- /dev/null +++ b/include/freetype/ftbbox.h @@ -0,0 +1,94 @@ +/***************************************************************************/ +/* */ +/* ftbbox.h */ +/* */ +/* FreeType exact bbox computation (specification). */ +/* */ +/* Copyright 1996-2001, 2003 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + + /*************************************************************************/ + /* */ + /* This component has a _single_ role: to compute exact outline bounding */ + /* boxes. */ + /* */ + /* It is separated from the rest of the engine for various technical */ + /* reasons. It may well be integrated in `ftoutln' later. */ + /* */ + /*************************************************************************/ + + +#ifndef __FTBBOX_H__ +#define __FTBBOX_H__ + + +#include <ft2build.h> +#include FT_FREETYPE_H + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* outline_processing */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Outline_Get_BBox */ + /* */ + /* <Description> */ + /* Computes the exact bounding box of an outline. This is slower */ + /* than computing the control box. However, it uses an advanced */ + /* algorithm which returns _very_ quickly when the two boxes */ + /* coincide. Otherwise, the outline Bézier arcs are walked over to */ + /* extract their extrema. */ + /* */ + /* <Input> */ + /* outline :: A pointer to the source outline. */ + /* */ + /* <Output> */ + /* abbox :: The outline's exact bounding box. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Outline_Get_BBox( FT_Outline* outline, + FT_BBox *abbox ); + + + /* */ + + +FT_END_HEADER + +#endif /* __FTBBOX_H__ */ + + +/* END */ + + +/* Local Variables: */ +/* coding: utf-8 */ +/* End: */ diff --git a/include/freetype/ftbdf.h b/include/freetype/ftbdf.h new file mode 100644 index 0000000..9555694 --- /dev/null +++ b/include/freetype/ftbdf.h @@ -0,0 +1,200 @@ +/***************************************************************************/ +/* */ +/* ftbdf.h */ +/* */ +/* FreeType API for accessing BDF-specific strings (specification). */ +/* */ +/* Copyright 2002, 2003, 2004, 2006 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef __FTBDF_H__ +#define __FTBDF_H__ + +#include <ft2build.h> +#include FT_FREETYPE_H + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* bdf_fonts */ + /* */ + /* <Title> */ + /* BDF Files */ + /* */ + /* <Abstract> */ + /* BDF specific API. */ + /* */ + /* <Description> */ + /* This section contains the declaration of BDF specific functions. */ + /* */ + /*************************************************************************/ + + + /********************************************************************** + * + * @enum: + * FT_PropertyType + * + * @description: + * A list of BDF property types. + * + * @values: + * BDF_PROPERTY_TYPE_NONE :: + * Value 0 is used to indicate a missing property. + * + * BDF_PROPERTY_TYPE_ATOM :: + * Property is a string atom. + * + * BDF_PROPERTY_TYPE_INTEGER :: + * Property is a 32-bit signed integer. + * + * BDF_PROPERTY_TYPE_CARDINAL :: + * Property is a 32-bit unsigned integer. + */ + typedef enum BDF_PropertyType_ + { + BDF_PROPERTY_TYPE_NONE = 0, + BDF_PROPERTY_TYPE_ATOM = 1, + BDF_PROPERTY_TYPE_INTEGER = 2, + BDF_PROPERTY_TYPE_CARDINAL = 3 + + } BDF_PropertyType; + + + /********************************************************************** + * + * @type: + * BDF_Property + * + * @description: + * A handle to a @BDF_PropertyRec structure to model a given + * BDF/PCF property. + */ + typedef struct BDF_PropertyRec_* BDF_Property; + + + /********************************************************************** + * + * @struct: + * BDF_PropertyRec + * + * @description: + * This structure models a given BDF/PCF property. + * + * @fields: + * type :: + * The property type. + * + * u.atom :: + * The atom string, if type is @BDF_PROPERTY_TYPE_ATOM. + * + * u.integer :: + * A signed integer, if type is @BDF_PROPERTY_TYPE_INTEGER. + * + * u.cardinal :: + * An unsigned integer, if type is @BDF_PROPERTY_TYPE_CARDINAL. + */ + typedef struct BDF_PropertyRec_ + { + BDF_PropertyType type; + union { + const char* atom; + FT_Int32 integer; + FT_UInt32 cardinal; + + } u; + + } BDF_PropertyRec; + + + /********************************************************************** + * + * @function: + * FT_Get_BDF_Charset_ID + * + * @description: + * Retrieves a BDF font character set identity, according to + * the BDF specification. + * + * @input: + * face :: + * A handle to the input face. + * + * @output: + * acharset_encoding :: + * Charset encoding, as a C string, owned by the face. + * + * acharset_registry :: + * Charset registry, as a C string, owned by the face. + * + * @return: + * FreeType error code. 0 means success. + * + * @note: + * This function only works with BDF faces, returning an error otherwise. + */ + FT_EXPORT( FT_Error ) + FT_Get_BDF_Charset_ID( FT_Face face, + const char* *acharset_encoding, + const char* *acharset_registry ); + + + /********************************************************************** + * + * @function: + * FT_Get_BDF_Property + * + * @description: + * Retrieves a BDF property from a BDF or PCF font file. + * + * @input: + * face :: A handle to the input face. + * + * name :: The property name. + * + * @output: + * aproperty :: The property. + * + * @return: + * FreeType error code. 0 means success. + * + * @note: + * This function works with BDF _and_ PCF fonts. It returns an error + * otherwise. It also returns an error if the property is not in the + * font. + * + * In case of error, `aproperty->type' is always set to + * @BDF_PROPERTY_TYPE_NONE. + */ + FT_EXPORT( FT_Error ) + FT_Get_BDF_Property( FT_Face face, + const char* prop_name, + BDF_PropertyRec *aproperty ); + + /* */ + +FT_END_HEADER + +#endif /* __FTBDF_H__ */ + + +/* END */ diff --git a/include/freetype/ftbitmap.h b/include/freetype/ftbitmap.h new file mode 100644 index 0000000..337d888 --- /dev/null +++ b/include/freetype/ftbitmap.h @@ -0,0 +1,206 @@ +/***************************************************************************/ +/* */ +/* ftbitmap.h */ +/* */ +/* FreeType utility functions for converting 1bpp, 2bpp, 4bpp, and 8bpp */ +/* bitmaps into 8bpp format (specification). */ +/* */ +/* Copyright 2004, 2005, 2006 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef __FTBITMAP_H__ +#define __FTBITMAP_H__ + + +#include <ft2build.h> +#include FT_FREETYPE_H + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* bitmap_handling */ + /* */ + /* <Title> */ + /* Bitmap Handling */ + /* */ + /* <Abstract> */ + /* Handling FT_Bitmap objects. */ + /* */ + /* <Description> */ + /* This section contains functions for converting FT_Bitmap objects. */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Bitmap_New */ + /* */ + /* <Description> */ + /* Initialize a pointer to an @FT_Bitmap structure. */ + /* */ + /* <InOut> */ + /* abitmap :: A pointer to the bitmap structure. */ + /* */ + FT_EXPORT( void ) + FT_Bitmap_New( FT_Bitmap *abitmap ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Bitmap_Copy */ + /* */ + /* <Description> */ + /* Copies an bitmap into another one. */ + /* */ + /* <Input> */ + /* library :: A handle to a library object. */ + /* */ + /* source :: A handle to the source bitmap. */ + /* */ + /* <Output> */ + /* target :: A handle to the target bitmap. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Bitmap_Copy( FT_Library library, + const FT_Bitmap *source, + FT_Bitmap *target); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Bitmap_Embolden */ + /* */ + /* <Description> */ + /* Embolden a bitmap. The new bitmap will be about `xStrength' */ + /* pixels wider and `yStrength' pixels higher. The left and bottom */ + /* borders are kept unchanged. */ + /* */ + /* <Input> */ + /* library :: A handle to a library object. */ + /* */ + /* xStrength :: How strong the glyph is emboldened horizontally. */ + /* Expressed in 26.6 pixel format. */ + /* */ + /* yStrength :: How strong the glyph is emboldened vertically. */ + /* Expressed in 26.6 pixel format. */ + /* */ + /* <InOut> */ + /* bitmap :: A handle to the target bitmap. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* The current implementation restricts `xStrength' to be less than */ + /* or equal to 8 if bitmap is of pixel_mode @FT_PIXEL_MODE_MONO. */ + /* */ + /* If you want to embolden the bitmap owned by a @FT_GlyphSlotRec, */ + /* you should call `FT_GlyphSlot_Own_Bitmap' on the slot first. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Bitmap_Embolden( FT_Library library, + FT_Bitmap* bitmap, + FT_Pos xStrength, + FT_Pos yStrength ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Bitmap_Convert */ + /* */ + /* <Description> */ + /* Convert a bitmap object with depth 1bpp, 2bpp, 4bpp, or 8bpp to a */ + /* bitmap object with depth 8bpp, making the number of used bytes per */ + /* line (a.k.a. the `pitch') a multiple of `alignment'. */ + /* */ + /* <Input> */ + /* library :: A handle to a library object. */ + /* */ + /* source :: The source bitmap. */ + /* */ + /* alignment :: The pitch of the bitmap is a multiple of this */ + /* parameter. Common values are 1, 2, or 4. */ + /* */ + /* <Output> */ + /* target :: The target bitmap. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* It is possible to call @FT_Bitmap_Convert multiple times without */ + /* calling @FT_Bitmap_Done (the memory is simply reallocated). */ + /* */ + /* Use @FT_Bitmap_Done to finally remove the bitmap object. */ + /* */ + /* The `library' argument is taken to have access to FreeType's */ + /* memory handling functions. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Bitmap_Convert( FT_Library library, + const FT_Bitmap *source, + FT_Bitmap *target, + FT_Int alignment ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Bitmap_Done */ + /* */ + /* <Description> */ + /* Destroy a bitmap object created with @FT_Bitmap_New. */ + /* */ + /* <Input> */ + /* library :: A handle to a library object. */ + /* */ + /* bitmap :: The bitmap object to be freed. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* The `library' argument is taken to have access to FreeType's */ + /* memory handling functions. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Bitmap_Done( FT_Library library, + FT_Bitmap *bitmap ); + + + /* */ + + +FT_END_HEADER + +#endif /* __FTBITMAP_H__ */ + + +/* END */ diff --git a/include/freetype/ftcache.h b/include/freetype/ftcache.h new file mode 100644 index 0000000..721aa16 --- /dev/null +++ b/include/freetype/ftcache.h @@ -0,0 +1,1110 @@ +/***************************************************************************/ +/* */ +/* ftcache.h */ +/* */ +/* FreeType Cache subsystem (specification). */ +/* */ +/* Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2007 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef __FTCACHE_H__ +#define __FTCACHE_H__ + + +#include <ft2build.h> +#include FT_GLYPH_H + + +FT_BEGIN_HEADER + + + /************************************************************************* + * + * <Section> + * cache_subsystem + * + * <Title> + * Cache Sub-System + * + * <Abstract> + * How to cache face, size, and glyph data with FreeType 2. + * + * <Description> + * This section describes the FreeType 2 cache sub-system, which is used + * to limit the number of concurrently opened @FT_Face and @FT_Size + * objects, as well as caching information like character maps and glyph + * images while limiting their maximum memory usage. + * + * Note that all types and functions begin with the `FTC_' prefix. + * + * The cache is highly portable and thus doesn't know anything about the + * fonts installed on your system, or how to access them. This implies + * the following scheme: + * + * First, available or installed font faces are uniquely identified by + * @FTC_FaceID values, provided to the cache by the client. Note that + * the cache only stores and compares these values, and doesn't try to + * interpret them in any way. + * + * Second, the cache calls, only when needed, a client-provided function + * to convert a @FTC_FaceID into a new @FT_Face object. The latter is + * then completely managed by the cache, including its termination + * through @FT_Done_Face. + * + * Clients are free to map face IDs to anything else. The most simple + * usage is to associate them to a (pathname,face_index) pair that is + * used to call @FT_New_Face. However, more complex schemes are also + * possible. + * + * Note that for the cache to work correctly, the face ID values must be + * *persistent*, which means that the contents they point to should not + * change at runtime, or that their value should not become invalid. + * + * If this is unavoidable (e.g., when a font is uninstalled at runtime), + * you should call @FTC_Manager_RemoveFaceID as soon as possible, to let + * the cache get rid of any references to the old @FTC_FaceID it may + * keep internally. Failure to do so will lead to incorrect behaviour + * or even crashes. + * + * To use the cache, start with calling @FTC_Manager_New to create a new + * @FTC_Manager object, which models a single cache instance. You can + * then look up @FT_Face and @FT_Size objects with + * @FTC_Manager_LookupFace and @FTC_Manager_LookupSize, respectively. + * + * If you want to use the charmap caching, call @FTC_CMapCache_New, then + * later use @FTC_CMapCache_Lookup to perform the equivalent of + * @FT_Get_Char_Index, only much faster. + * + * If you want to use the @FT_Glyph caching, call @FTC_ImageCache, then + * later use @FTC_ImageCache_Lookup to retrieve the corresponding + * @FT_Glyph objects from the cache. + * + * If you need lots of small bitmaps, it is much more memory efficient + * to call @FTC_SBitCache_New followed by @FTC_SBitCache_Lookup. This + * returns @FTC_SBitRec structures, which are used to store small + * bitmaps directly. (A small bitmap is one whose metrics and + * dimensions all fit into 8-bit integers). + * + * We hope to also provide a kerning cache in the near future. + * + * + * <Order> + * FTC_Manager + * FTC_FaceID + * FTC_Face_Requester + * + * FTC_Manager_New + * FTC_Manager_Reset + * FTC_Manager_Done + * FTC_Manager_LookupFace + * FTC_Manager_LookupSize + * FTC_Manager_RemoveFaceID + * + * FTC_Node + * FTC_Node_Unref + * + * FTC_ImageCache + * FTC_ImageCache_New + * FTC_ImageCache_Lookup + * + * FTC_SBit + * FTC_SBitCache + * FTC_SBitCache_New + * FTC_SBitCache_Lookup + * + * FTC_CMapCache + * FTC_CMapCache_New + * FTC_CMapCache_Lookup + * + *************************************************************************/ + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** BASIC TYPE DEFINITIONS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /************************************************************************* + * + * @type: FTC_FaceID + * + * @description: + * An opaque pointer type that is used to identity face objects. The + * contents of such objects is application-dependent. + * + * These pointers are typically used to point to a user-defined + * structure containing a font file path, and face index. + * + * @note: + * Never use NULL as a valid @FTC_FaceID. + * + * Face IDs are passed by the client to the cache manager, which calls, + * when needed, the @FTC_Face_Requester to translate them into new + * @FT_Face objects. + * + * If the content of a given face ID changes at runtime, or if the value + * becomes invalid (e.g., when uninstalling a font), you should + * immediately call @FTC_Manager_RemoveFaceID before any other cache + * function. + * + * Failure to do so will result in incorrect behaviour or even + * memory leaks and crashes. + */ + typedef struct FTC_FaceIDRec_* FTC_FaceID; + + + /************************************************************************ + * + * @functype: + * FTC_Face_Requester + * + * @description: + * A callback function provided by client applications. It is used by + * the cache manager to translate a given @FTC_FaceID into a new valid + * @FT_Face object, on demand. + * + * <Input> + * face_id :: + * The face ID to resolve. + * + * library :: + * A handle to a FreeType library object. + * + * req_data :: + * Application-provided request data (see note below). + * + * <Output> + * aface :: + * A new @FT_Face handle. + * + * <Return> + * FreeType error code. 0 means success. + * + * <Note> + * The third parameter `req_data' is the same as the one passed by the + * client when @FTC_Manager_New is called. + * + * The face requester should not perform funny things on the returned + * face object, like creating a new @FT_Size for it, or setting a + * transformation through @FT_Set_Transform! + */ + typedef FT_Error + (*FTC_Face_Requester)( FTC_FaceID face_id, + FT_Library library, + FT_Pointer request_data, + FT_Face* aface ); + + /* */ + +#define FT_POINTER_TO_ULONG( p ) ( (FT_ULong)(FT_Pointer)(p) ) + +#define FTC_FACE_ID_HASH( i ) \ + ((FT_UInt32)(( FT_POINTER_TO_ULONG( i ) >> 3 ) ^ \ + ( FT_POINTER_TO_ULONG( i ) << 7 ) ) ) + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** CACHE MANAGER OBJECT *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FTC_Manager */ + /* */ + /* <Description> */ + /* This object corresponds to one instance of the cache-subsystem. */ + /* It is used to cache one or more @FT_Face objects, along with */ + /* corresponding @FT_Size objects. */ + /* */ + /* The manager intentionally limits the total number of opened */ + /* @FT_Face and @FT_Size objects to control memory usage. See the */ + /* `max_faces' and `max_sizes' parameters of @FTC_Manager_New. */ + /* */ + /* The manager is also used to cache `nodes' of various types while */ + /* limiting their total memory usage. */ + /* */ + /* All limitations are enforced by keeping lists of managed objects */ + /* in most-recently-used order, and flushing old nodes to make room */ + /* for new ones. */ + /* */ + typedef struct FTC_ManagerRec_* FTC_Manager; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FTC_Node */ + /* */ + /* <Description> */ + /* An opaque handle to a cache node object. Each cache node is */ + /* reference-counted. A node with a count of 0 might be flushed */ + /* out of a full cache whenever a lookup request is performed. */ + /* */ + /* If you lookup nodes, you have the ability to `acquire' them, i.e., */ + /* to increment their reference count. This will prevent the node */ + /* from being flushed out of the cache until you explicitly `release' */ + /* it (see @FTC_Node_Unref). */ + /* */ + /* See also @FTC_SBitCache_Lookup and @FTC_ImageCache_Lookup. */ + /* */ + typedef struct FTC_NodeRec_* FTC_Node; + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FTC_Manager_New */ + /* */ + /* <Description> */ + /* Creates a new cache manager. */ + /* */ + /* <Input> */ + /* library :: The parent FreeType library handle to use. */ + /* */ + /* max_faces :: Maximum number of opened @FT_Face objects managed by */ + /* this cache instance. Use 0 for defaults. */ + /* */ + /* max_sizes :: Maximum number of opened @FT_Size objects managed by */ + /* this cache instance. Use 0 for defaults. */ + /* */ + /* max_bytes :: Maximum number of bytes to use for cached data nodes. */ + /* Use 0 for defaults. Note that this value does not */ + /* account for managed @FT_Face and @FT_Size objects. */ + /* */ + /* requester :: An application-provided callback used to translate */ + /* face IDs into real @FT_Face objects. */ + /* */ + /* req_data :: A generic pointer that is passed to the requester */ + /* each time it is called (see @FTC_Face_Requester). */ + /* */ + /* <Output> */ + /* amanager :: A handle to a new manager object. 0 in case of */ + /* failure. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_EXPORT( FT_Error ) + FTC_Manager_New( FT_Library library, + FT_UInt max_faces, + FT_UInt max_sizes, + FT_ULong max_bytes, + FTC_Face_Requester requester, + FT_Pointer req_data, + FTC_Manager *amanager ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FTC_Manager_Reset */ + /* */ + /* <Description> */ + /* Empties a given cache manager. This simply gets rid of all the */ + /* currently cached @FT_Face and @FT_Size objects within the manager. */ + /* */ + /* <InOut> */ + /* manager :: A handle to the manager. */ + /* */ + FT_EXPORT( void ) + FTC_Manager_Reset( FTC_Manager manager ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FTC_Manager_Done */ + /* */ + /* <Description> */ + /* Destroys a given manager after emptying it. */ + /* */ + /* <Input> */ + /* manager :: A handle to the target cache manager object. */ + /* */ + FT_EXPORT( void ) + FTC_Manager_Done( FTC_Manager manager ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FTC_Manager_LookupFace */ + /* */ + /* <Description> */ + /* Retrieves the @FT_Face object that corresponds to a given face ID */ + /* through a cache manager. */ + /* */ + /* <Input> */ + /* manager :: A handle to the cache manager. */ + /* */ + /* face_id :: The ID of the face object. */ + /* */ + /* <Output> */ + /* aface :: A handle to the face object. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* The returned @FT_Face object is always owned by the manager. You */ + /* should never try to discard it yourself. */ + /* */ + /* The @FT_Face object doesn't necessarily have a current size object */ + /* (i.e., face->size can be 0). If you need a specific `font size', */ + /* use @FTC_Manager_LookupSize instead. */ + /* */ + /* Never change the face's transformation matrix (i.e., never call */ + /* the @FT_Set_Transform function) on a returned face! If you need */ + /* to transform glyphs, do it yourself after glyph loading. */ + /* */ + /* When you perform a lookup, out-of-memory errors are detected */ + /* _within_ the lookup and force incremental flushes of the cache */ + /* until enough memory is released for the lookup to succeed. */ + /* */ + /* If a lookup fails with `FT_Err_Out_Of_Memory' the cache has */ + /* already been completely flushed, and still no memory was available */ + /* for the operation. */ + /* */ + FT_EXPORT( FT_Error ) + FTC_Manager_LookupFace( FTC_Manager manager, + FTC_FaceID face_id, + FT_Face *aface ); + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FTC_ScalerRec */ + /* */ + /* <Description> */ + /* A structure used to describe a given character size in either */ + /* pixels or points to the cache manager. See */ + /* @FTC_Manager_LookupSize. */ + /* */ + /* <Fields> */ + /* face_id :: The source face ID. */ + /* */ + /* width :: The character width. */ + /* */ + /* height :: The character height. */ + /* */ + /* pixel :: A Boolean. If 1, the `width' and `height' fields are */ + /* interpreted as integer pixel character sizes. */ + /* Otherwise, they are expressed as 1/64th of points. */ + /* */ + /* x_res :: Only used when `pixel' is value 0 to indicate the */ + /* horizontal resolution in dpi. */ + /* */ + /* y_res :: Only used when `pixel' is value 0 to indicate the */ + /* vertical resolution in dpi. */ + /* */ + /* <Note> */ + /* This type is mainly used to retrieve @FT_Size objects through the */ + /* cache manager. */ + /* */ + typedef struct FTC_ScalerRec_ + { + FTC_FaceID face_id; + FT_UInt width; + FT_UInt height; + FT_Int pixel; + FT_UInt x_res; + FT_UInt y_res; + + } FTC_ScalerRec, *FTC_Scaler; + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FTC_Manager_LookupSize */ + /* */ + /* <Description> */ + /* Retrieve the @FT_Size object that corresponds to a given */ + /* @FTC_ScalerRec pointer through a cache manager. */ + /* */ + /* <Input> */ + /* manager :: A handle to the cache manager. */ + /* */ + /* scaler :: A scaler handle. */ + /* */ + /* <Output> */ + /* asize :: A handle to the size object. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* The returned @FT_Size object is always owned by the manager. You */ + /* should never try to discard it by yourself. */ + /* */ + /* You can access the parent @FT_Face object simply as `size->face' */ + /* if you need it. Note that this object is also owned by the */ + /* manager. */ + /* */ + /* <Note> */ + /* When you perform a lookup, out-of-memory errors are detected */ + /* _within_ the lookup and force incremental flushes of the cache */ + /* until enough memory is released for the lookup to succeed. */ + /* */ + /* If a lookup fails with `FT_Err_Out_Of_Memory' the cache has */ + /* already been completely flushed, and still no memory is available */ + /* for the operation. */ + /* */ + FT_EXPORT( FT_Error ) + FTC_Manager_LookupSize( FTC_Manager manager, + FTC_Scaler scaler, + FT_Size *asize ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FTC_Node_Unref */ + /* */ + /* <Description> */ + /* Decrement a cache node's internal reference count. When the count */ + /* reaches 0, it is not destroyed but becomes eligible for subsequent */ + /* cache flushes. */ + /* */ + /* <Input> */ + /* node :: The cache node handle. */ + /* */ + /* manager :: The cache manager handle. */ + /* */ + FT_EXPORT( void ) + FTC_Node_Unref( FTC_Node node, + FTC_Manager manager ); + + + /************************************************************************* + * + * @function: + * FTC_Manager_RemoveFaceID + * + * @description: + * A special function used to indicate to the cache manager that + * a given @FTC_FaceID is no longer valid, either because its + * content changed, or because it was deallocated or uninstalled. + * + * @input: + * manager :: + * The cache manager handle. + * + * face_id :: + * The @FTC_FaceID to be removed. + * + * @note: + * This function flushes all nodes from the cache corresponding to this + * `face_id', with the exception of nodes with a non-null reference + * count. + * + * Such nodes are however modified internally so as to never appear + * in later lookups with the same `face_id' value, and to be immediately + * destroyed when released by all their users. + * + */ + FT_EXPORT( void ) + FTC_Manager_RemoveFaceID( FTC_Manager manager, + FTC_FaceID face_id ); + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* cache_subsystem */ + /* */ + /*************************************************************************/ + + /************************************************************************* + * + * @type: + * FTC_CMapCache + * + * @description: + * An opaque handle used to model a charmap cache. This cache is to + * hold character codes -> glyph indices mappings. + * + */ + typedef struct FTC_CMapCacheRec_* FTC_CMapCache; + + + /************************************************************************* + * + * @function: + * FTC_CMapCache_New + * + * @description: + * Create a new charmap cache. + * + * @input: + * manager :: + * A handle to the cache manager. + * + * @output: + * acache :: + * A new cache handle. NULL in case of error. + * + * @return: + * FreeType error code. 0 means success. + * + * @note: + * Like all other caches, this one will be destroyed with the cache + * manager. + * + */ + FT_EXPORT( FT_Error ) + FTC_CMapCache_New( FTC_Manager manager, + FTC_CMapCache *acache ); + + + /************************************************************************ + * + * @function: + * FTC_CMapCache_Lookup + * + * @description: + * Translate a character code into a glyph index, using the charmap + * cache. + * + * @input: + * cache :: + * A charmap cache handle. + * + * face_id :: + * The source face ID. + * + * cmap_index :: + * The index of the charmap in the source face. + * + * char_code :: + * The character code (in the corresponding charmap). + * + * @return: + * Glyph index. 0 means `no glyph'. + * + */ + FT_EXPORT( FT_UInt ) + FTC_CMapCache_Lookup( FTC_CMapCache cache, + FTC_FaceID face_id, + FT_Int cmap_index, + FT_UInt32 char_code ); + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* cache_subsystem */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** IMAGE CACHE OBJECT *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /************************************************************************* + * + * @struct: + * FTC_ImageTypeRec + * + * @description: + * A structure used to model the type of images in a glyph cache. + * + * @fields: + * face_id :: + * The face ID. + * + * width :: + * The width in pixels. + * + * height :: + * The height in pixels. + * + * flags :: + * The load flags, as in @FT_Load_Glyph. + * + */ + typedef struct FTC_ImageTypeRec_ + { + FTC_FaceID face_id; + FT_Int width; + FT_Int height; + FT_Int32 flags; + + } FTC_ImageTypeRec; + + + /************************************************************************* + * + * @type: + * FTC_ImageType + * + * @description: + * A handle to an @FTC_ImageTypeRec structure. + * + */ + typedef struct FTC_ImageTypeRec_* FTC_ImageType; + + + /* */ + + +#define FTC_IMAGE_TYPE_COMPARE( d1, d2 ) \ + ( (d1)->face_id == (d2)->face_id && \ + (d1)->width == (d2)->width && \ + (d1)->flags == (d2)->flags ) + +#define FTC_IMAGE_TYPE_HASH( d ) \ + (FT_UFast)( FTC_FACE_ID_HASH( (d)->face_id ) ^ \ + ( (d)->width << 8 ) ^ (d)->height ^ \ + ( (d)->flags << 4 ) ) + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FTC_ImageCache */ + /* */ + /* <Description> */ + /* A handle to an glyph image cache object. They are designed to */ + /* hold many distinct glyph images while not exceeding a certain */ + /* memory threshold. */ + /* */ + typedef struct FTC_ImageCacheRec_* FTC_ImageCache; + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FTC_ImageCache_New */ + /* */ + /* <Description> */ + /* Creates a new glyph image cache. */ + /* */ + /* <Input> */ + /* manager :: The parent manager for the image cache. */ + /* */ + /* <Output> */ + /* acache :: A handle to the new glyph image cache object. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_EXPORT( FT_Error ) + FTC_ImageCache_New( FTC_Manager manager, + FTC_ImageCache *acache ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FTC_ImageCache_Lookup */ + /* */ + /* <Description> */ + /* Retrieves a given glyph image from a glyph image cache. */ + /* */ + /* <Input> */ + /* cache :: A handle to the source glyph image cache. */ + /* */ + /* type :: A pointer to a glyph image type descriptor. */ + /* */ + /* gindex :: The glyph index to retrieve. */ + /* */ + /* <Output> */ + /* aglyph :: The corresponding @FT_Glyph object. 0 in case of */ + /* failure. */ + /* */ + /* anode :: Used to return the address of of the corresponding cache */ + /* node after incrementing its reference count (see note */ + /* below). */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* The returned glyph is owned and managed by the glyph image cache. */ + /* Never try to transform or discard it manually! You can however */ + /* create a copy with @FT_Glyph_Copy and modify the new one. */ + /* */ + /* If `anode' is _not_ NULL, it receives the address of the cache */ + /* node containing the glyph image, after increasing its reference */ + /* count. This ensures that the node (as well as the @FT_Glyph) will */ + /* always be kept in the cache until you call @FTC_Node_Unref to */ + /* `release' it. */ + /* */ + /* If `anode' is NULL, the cache node is left unchanged, which means */ + /* that the @FT_Glyph could be flushed out of the cache on the next */ + /* call to one of the caching sub-system APIs. Don't assume that it */ + /* is persistent! */ + /* */ + FT_EXPORT( FT_Error ) + FTC_ImageCache_Lookup( FTC_ImageCache cache, + FTC_ImageType type, + FT_UInt gindex, + FT_Glyph *aglyph, + FTC_Node *anode ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FTC_ImageCache_LookupScaler */ + /* */ + /* <Description> */ + /* A variant of @FTC_ImageCache_Lookup that uses an @FTC_ScalerRec */ + /* to specify the face ID and its size. */ + /* */ + /* <Input> */ + /* cache :: A handle to the source glyph image cache. */ + /* */ + /* scaler :: A pointer to a scaler descriptor. */ + /* */ + /* load_flags :: The corresponding load flags. */ + /* */ + /* gindex :: The glyph index to retrieve. */ + /* */ + /* <Output> */ + /* aglyph :: The corresponding @FT_Glyph object. 0 in case of */ + /* failure. */ + /* */ + /* anode :: Used to return the address of of the corresponding */ + /* cache node after incrementing its reference count */ + /* (see note below). */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* The returned glyph is owned and managed by the glyph image cache. */ + /* Never try to transform or discard it manually! You can however */ + /* create a copy with @FT_Glyph_Copy and modify the new one. */ + /* */ + /* If `anode' is _not_ NULL, it receives the address of the cache */ + /* node containing the glyph image, after increasing its reference */ + /* count. This ensures that the node (as well as the @FT_Glyph) will */ + /* always be kept in the cache until you call @FTC_Node_Unref to */ + /* `release' it. */ + /* */ + /* If `anode' is NULL, the cache node is left unchanged, which means */ + /* that the @FT_Glyph could be flushed out of the cache on the next */ + /* call to one of the caching sub-system APIs. Don't assume that it */ + /* is persistent! */ + /* */ + FT_EXPORT( FT_Error ) + FTC_ImageCache_LookupScaler( FTC_ImageCache cache, + FTC_Scaler scaler, + FT_ULong load_flags, + FT_UInt gindex, + FT_Glyph *aglyph, + FTC_Node *anode ); + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FTC_SBit */ + /* */ + /* <Description> */ + /* A handle to a small bitmap descriptor. See the @FTC_SBitRec */ + /* structure for details. */ + /* */ + typedef struct FTC_SBitRec_* FTC_SBit; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FTC_SBitRec */ + /* */ + /* <Description> */ + /* A very compact structure used to describe a small glyph bitmap. */ + /* */ + /* <Fields> */ + /* width :: The bitmap width in pixels. */ + /* */ + /* height :: The bitmap height in pixels. */ + /* */ + /* left :: The horizontal distance from the pen position to the */ + /* left bitmap border (a.k.a. `left side bearing', or */ + /* `lsb'). */ + /* */ + /* top :: The vertical distance from the pen position (on the */ + /* baseline) to the upper bitmap border (a.k.a. `top */ + /* side bearing'). The distance is positive for upwards */ + /* Y coordinates. */ + /* */ + /* format :: The format of the glyph bitmap (monochrome or gray). */ + /* */ + /* max_grays :: Maximum gray level value (in the range 1 to 255). */ + /* */ + /* pitch :: The number of bytes per bitmap line. May be positive */ + /* or negative. */ + /* */ + /* xadvance :: The horizontal advance width in pixels. */ + /* */ + /* yadvance :: The vertical advance height in pixels. */ + /* */ + /* buffer :: A pointer to the bitmap pixels. */ + /* */ + typedef struct FTC_SBitRec_ + { + FT_Byte width; + FT_Byte height; + FT_Char left; + FT_Char top; + + FT_Byte format; + FT_Byte max_grays; + FT_Short pitch; + FT_Char xadvance; + FT_Char yadvance; + + FT_Byte* buffer; + + } FTC_SBitRec; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FTC_SBitCache */ + /* */ + /* <Description> */ + /* A handle to a small bitmap cache. These are special cache objects */ + /* used to store small glyph bitmaps (and anti-aliased pixmaps) in a */ + /* much more efficient way than the traditional glyph image cache */ + /* implemented by @FTC_ImageCache. */ + /* */ + typedef struct FTC_SBitCacheRec_* FTC_SBitCache; + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FTC_SBitCache_New */ + /* */ + /* <Description> */ + /* Creates a new cache to store small glyph bitmaps. */ + /* */ + /* <Input> */ + /* manager :: A handle to the source cache manager. */ + /* */ + /* <Output> */ + /* acache :: A handle to the new sbit cache. NULL in case of error. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_EXPORT( FT_Error ) + FTC_SBitCache_New( FTC_Manager manager, + FTC_SBitCache *acache ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FTC_SBitCache_Lookup */ + /* */ + /* <Description> */ + /* Looks up a given small glyph bitmap in a given sbit cache and */ + /* `lock' it to prevent its flushing from the cache until needed. */ + /* */ + /* <Input> */ + /* cache :: A handle to the source sbit cache. */ + /* */ + /* type :: A pointer to the glyph image type descriptor. */ + /* */ + /* gindex :: The glyph index. */ + /* */ + /* <Output> */ + /* sbit :: A handle to a small bitmap descriptor. */ + /* */ + /* anode :: Used to return the address of of the corresponding cache */ + /* node after incrementing its reference count (see note */ + /* below). */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* The small bitmap descriptor and its bit buffer are owned by the */ + /* cache and should never be freed by the application. They might */ + /* as well disappear from memory on the next cache lookup, so don't */ + /* treat them as persistent data. */ + /* */ + /* The descriptor's `buffer' field is set to 0 to indicate a missing */ + /* glyph bitmap. */ + /* */ + /* If `anode' is _not_ NULL, it receives the address of the cache */ + /* node containing the bitmap, after increasing its reference count. */ + /* This ensures that the node (as well as the image) will always be */ + /* kept in the cache until you call @FTC_Node_Unref to `release' it. */ + /* */ + /* If `anode' is NULL, the cache node is left unchanged, which means */ + /* that the bitmap could be flushed out of the cache on the next */ + /* call to one of the caching sub-system APIs. Don't assume that it */ + /* is persistent! */ + /* */ + FT_EXPORT( FT_Error ) + FTC_SBitCache_Lookup( FTC_SBitCache cache, + FTC_ImageType type, + FT_UInt gindex, + FTC_SBit *sbit, + FTC_Node *anode ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FTC_SBitCache_LookupScaler */ + /* */ + /* <Description> */ + /* A variant of @FTC_SBitCache_Lookup that uses an @FTC_ScalerRec */ + /* to specify the face ID and its size. */ + /* */ + /* <Input> */ + /* cache :: A handle to the source sbit cache. */ + /* */ + /* scaler :: A pointer to the scaler descriptor. */ + /* */ + /* load_flags :: The corresponding load flags. */ + /* */ + /* gindex :: The glyph index. */ + /* */ + /* <Output> */ + /* sbit :: A handle to a small bitmap descriptor. */ + /* */ + /* anode :: Used to return the address of of the corresponding */ + /* cache node after incrementing its reference count */ + /* (see note below). */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* The small bitmap descriptor and its bit buffer are owned by the */ + /* cache and should never be freed by the application. They might */ + /* as well disappear from memory on the next cache lookup, so don't */ + /* treat them as persistent data. */ + /* */ + /* The descriptor's `buffer' field is set to 0 to indicate a missing */ + /* glyph bitmap. */ + /* */ + /* If `anode' is _not_ NULL, it receives the address of the cache */ + /* node containing the bitmap, after increasing its reference count. */ + /* This ensures that the node (as well as the image) will always be */ + /* kept in the cache until you call @FTC_Node_Unref to `release' it. */ + /* */ + /* If `anode' is NULL, the cache node is left unchanged, which means */ + /* that the bitmap could be flushed out of the cache on the next */ + /* call to one of the caching sub-system APIs. Don't assume that it */ + /* is persistent! */ + /* */ + FT_EXPORT( FT_Error ) + FTC_SBitCache_LookupScaler( FTC_SBitCache cache, + FTC_Scaler scaler, + FT_ULong load_flags, + FT_UInt gindex, + FTC_SBit *sbit, + FTC_Node *anode ); + + + /* */ + +#ifdef FT_CONFIG_OPTION_OLD_INTERNALS + + /*@***********************************************************************/ + /* */ + /* <Struct> */ + /* FTC_FontRec */ + /* */ + /* <Description> */ + /* A simple structure used to describe a given `font' to the cache */ + /* manager. Note that a `font' is the combination of a given face */ + /* with a given character size. */ + /* */ + /* <Fields> */ + /* face_id :: The ID of the face to use. */ + /* */ + /* pix_width :: The character width in integer pixels. */ + /* */ + /* pix_height :: The character height in integer pixels. */ + /* */ + typedef struct FTC_FontRec_ + { + FTC_FaceID face_id; + FT_UShort pix_width; + FT_UShort pix_height; + + } FTC_FontRec; + + + /* */ + + +#define FTC_FONT_COMPARE( f1, f2 ) \ + ( (f1)->face_id == (f2)->face_id && \ + (f1)->pix_width == (f2)->pix_width && \ + (f1)->pix_height == (f2)->pix_height ) + +#define FTC_FONT_HASH( f ) \ + (FT_UInt32)( FTC_FACE_ID_HASH((f)->face_id) ^ \ + ((f)->pix_width << 8) ^ \ + ((f)->pix_height) ) + + typedef FTC_FontRec* FTC_Font; + + + FT_EXPORT( FT_Error ) + FTC_Manager_Lookup_Face( FTC_Manager manager, + FTC_FaceID face_id, + FT_Face *aface ); + + FT_EXPORT( FT_Error ) + FTC_Manager_Lookup_Size( FTC_Manager manager, + FTC_Font font, + FT_Face *aface, + FT_Size *asize ); + +#endif /* FT_CONFIG_OPTION_OLD_INTERNALS */ + + + /* */ + +FT_END_HEADER + +#endif /* __FTCACHE_H__ */ + + +/* END */ diff --git a/include/freetype/ftchapters.h b/include/freetype/ftchapters.h new file mode 100644 index 0000000..bd812c8 --- /dev/null +++ b/include/freetype/ftchapters.h @@ -0,0 +1,100 @@ +/***************************************************************************/ +/* */ +/* This file defines the structure of the FreeType reference. */ +/* It is used by the python script which generates the HTML files. */ +/* */ +/***************************************************************************/ + + +/***************************************************************************/ +/* */ +/* <Chapter> */ +/* general_remarks */ +/* */ +/* <Title> */ +/* General Remarks */ +/* */ +/* <Sections> */ +/* user_allocation */ +/* */ +/***************************************************************************/ + + +/***************************************************************************/ +/* */ +/* <Chapter> */ +/* core_api */ +/* */ +/* <Title> */ +/* Core API */ +/* */ +/* <Sections> */ +/* version */ +/* basic_types */ +/* base_interface */ +/* glyph_management */ +/* mac_specific */ +/* sizes_management */ +/* header_file_macros */ +/* */ +/***************************************************************************/ + + +/***************************************************************************/ +/* */ +/* <Chapter> */ +/* format_specific */ +/* */ +/* <Title> */ +/* Format-Specific API */ +/* */ +/* <Sections> */ +/* multiple_masters */ +/* truetype_tables */ +/* type1_tables */ +/* sfnt_names */ +/* bdf_fonts */ +/* pfr_fonts */ +/* winfnt_fonts */ +/* font_formats */ +/* gasp_table */ +/* */ +/***************************************************************************/ + + +/***************************************************************************/ +/* */ +/* <Chapter> */ +/* cache_subsystem */ +/* */ +/* <Title> */ +/* Cache Sub-System */ +/* */ +/* <Sections> */ +/* cache_subsystem */ +/* */ +/***************************************************************************/ + + +/***************************************************************************/ +/* */ +/* <Chapter> */ +/* support_api */ +/* */ +/* <Title> */ +/* Support API */ +/* */ +/* <Sections> */ +/* computations */ +/* list_processing */ +/* outline_processing */ +/* bitmap_handling */ +/* raster */ +/* glyph_stroker */ +/* system_interface */ +/* module_management */ +/* gzip */ +/* lzw */ +/* lcd_filtering */ +/* */ +/***************************************************************************/ diff --git a/include/freetype/fterrdef.h b/include/freetype/fterrdef.h new file mode 100644 index 0000000..d7ad256 --- /dev/null +++ b/include/freetype/fterrdef.h @@ -0,0 +1,239 @@ +/***************************************************************************/ +/* */ +/* fterrdef.h */ +/* */ +/* FreeType error codes (specification). */ +/* */ +/* Copyright 2002, 2004, 2006, 2007 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + + /*******************************************************************/ + /*******************************************************************/ + /***** *****/ + /***** LIST OF ERROR CODES/MESSAGES *****/ + /***** *****/ + /*******************************************************************/ + /*******************************************************************/ + + + /* You need to define both FT_ERRORDEF_ and FT_NOERRORDEF_ before */ + /* including this file. */ + + + /* generic errors */ + + FT_NOERRORDEF_( Ok, 0x00, \ + "no error" ) + + FT_ERRORDEF_( Cannot_Open_Resource, 0x01, \ + "cannot open resource" ) + FT_ERRORDEF_( Unknown_File_Format, 0x02, \ + "unknown file format" ) + FT_ERRORDEF_( Invalid_File_Format, 0x03, \ + "broken file" ) + FT_ERRORDEF_( Invalid_Version, 0x04, \ + "invalid FreeType version" ) + FT_ERRORDEF_( Lower_Module_Version, 0x05, \ + "module version is too low" ) + FT_ERRORDEF_( Invalid_Argument, 0x06, \ + "invalid argument" ) + FT_ERRORDEF_( Unimplemented_Feature, 0x07, \ + "unimplemented feature" ) + FT_ERRORDEF_( Invalid_Table, 0x08, \ + "broken table" ) + FT_ERRORDEF_( Invalid_Offset, 0x09, \ + "broken offset within table" ) + FT_ERRORDEF_( Array_Too_Large, 0x0A, \ + "array allocation size too large" ) + + /* glyph/character errors */ + + FT_ERRORDEF_( Invalid_Glyph_Index, 0x10, \ + "invalid glyph index" ) + FT_ERRORDEF_( Invalid_Character_Code, 0x11, \ + "invalid character code" ) + FT_ERRORDEF_( Invalid_Glyph_Format, 0x12, \ + "unsupported glyph image format" ) + FT_ERRORDEF_( Cannot_Render_Glyph, 0x13, \ + "cannot render this glyph format" ) + FT_ERRORDEF_( Invalid_Outline, 0x14, \ + "invalid outline" ) + FT_ERRORDEF_( Invalid_Composite, 0x15, \ + "invalid composite glyph" ) + FT_ERRORDEF_( Too_Many_Hints, 0x16, \ + "too many hints" ) + FT_ERRORDEF_( Invalid_Pixel_Size, 0x17, \ + "invalid pixel size" ) + + /* handle errors */ + + FT_ERRORDEF_( Invalid_Handle, 0x20, \ + "invalid object handle" ) + FT_ERRORDEF_( Invalid_Library_Handle, 0x21, \ + "invalid library handle" ) + FT_ERRORDEF_( Invalid_Driver_Handle, 0x22, \ + "invalid module handle" ) + FT_ERRORDEF_( Invalid_Face_Handle, 0x23, \ + "invalid face handle" ) + FT_ERRORDEF_( Invalid_Size_Handle, 0x24, \ + "invalid size handle" ) + FT_ERRORDEF_( Invalid_Slot_Handle, 0x25, \ + "invalid glyph slot handle" ) + FT_ERRORDEF_( Invalid_CharMap_Handle, 0x26, \ + "invalid charmap handle" ) + FT_ERRORDEF_( Invalid_Cache_Handle, 0x27, \ + "invalid cache manager handle" ) + FT_ERRORDEF_( Invalid_Stream_Handle, 0x28, \ + "invalid stream handle" ) + + /* driver errors */ + + FT_ERRORDEF_( Too_Many_Drivers, 0x30, \ + "too many modules" ) + FT_ERRORDEF_( Too_Many_Extensions, 0x31, \ + "too many extensions" ) + + /* memory errors */ + + FT_ERRORDEF_( Out_Of_Memory, 0x40, \ + "out of memory" ) + FT_ERRORDEF_( Unlisted_Object, 0x41, \ + "unlisted object" ) + + /* stream errors */ + + FT_ERRORDEF_( Cannot_Open_Stream, 0x51, \ + "cannot open stream" ) + FT_ERRORDEF_( Invalid_Stream_Seek, 0x52, \ + "invalid stream seek" ) + FT_ERRORDEF_( Invalid_Stream_Skip, 0x53, \ + "invalid stream skip" ) + FT_ERRORDEF_( Invalid_Stream_Read, 0x54, \ + "invalid stream read" ) + FT_ERRORDEF_( Invalid_Stream_Operation, 0x55, \ + "invalid stream operation" ) + FT_ERRORDEF_( Invalid_Frame_Operation, 0x56, \ + "invalid frame operation" ) + FT_ERRORDEF_( Nested_Frame_Access, 0x57, \ + "nested frame access" ) + FT_ERRORDEF_( Invalid_Frame_Read, 0x58, \ + "invalid frame read" ) + + /* raster errors */ + + FT_ERRORDEF_( Raster_Uninitialized, 0x60, \ + "raster uninitialized" ) + FT_ERRORDEF_( Raster_Corrupted, 0x61, \ + "raster corrupted" ) + FT_ERRORDEF_( Raster_Overflow, 0x62, \ + "raster overflow" ) + FT_ERRORDEF_( Raster_Negative_Height, 0x63, \ + "negative height while rastering" ) + + /* cache errors */ + + FT_ERRORDEF_( Too_Many_Caches, 0x70, \ + "too many registered caches" ) + + /* TrueType and SFNT errors */ + + FT_ERRORDEF_( Invalid_Opcode, 0x80, \ + "invalid opcode" ) + FT_ERRORDEF_( Too_Few_Arguments, 0x81, \ + "too few arguments" ) + FT_ERRORDEF_( Stack_Overflow, 0x82, \ + "stack overflow" ) + FT_ERRORDEF_( Code_Overflow, 0x83, \ + "code overflow" ) + FT_ERRORDEF_( Bad_Argument, 0x84, \ + "bad argument" ) + FT_ERRORDEF_( Divide_By_Zero, 0x85, \ + "division by zero" ) + FT_ERRORDEF_( Invalid_Reference, 0x86, \ + "invalid reference" ) + FT_ERRORDEF_( Debug_OpCode, 0x87, \ + "found debug opcode" ) + FT_ERRORDEF_( ENDF_In_Exec_Stream, 0x88, \ + "found ENDF opcode in execution stream" ) + FT_ERRORDEF_( Nested_DEFS, 0x89, \ + "nested DEFS" ) + FT_ERRORDEF_( Invalid_CodeRange, 0x8A, \ + "invalid code range" ) + FT_ERRORDEF_( Execution_Too_Long, 0x8B, \ + "execution context too long" ) + FT_ERRORDEF_( Too_Many_Function_Defs, 0x8C, \ + "too many function definitions" ) + FT_ERRORDEF_( Too_Many_Instruction_Defs, 0x8D, \ + "too many instruction definitions" ) + FT_ERRORDEF_( Table_Missing, 0x8E, \ + "SFNT font table missing" ) + FT_ERRORDEF_( Horiz_Header_Missing, 0x8F, \ + "horizontal header (hhea) table missing" ) + FT_ERRORDEF_( Locations_Missing, 0x90, \ + "locations (loca) table missing" ) + FT_ERRORDEF_( Name_Table_Missing, 0x91, \ + "name table missing" ) + FT_ERRORDEF_( CMap_Table_Missing, 0x92, \ + "character map (cmap) table missing" ) + FT_ERRORDEF_( Hmtx_Table_Missing, 0x93, \ + "horizontal metrics (hmtx) table missing" ) + FT_ERRORDEF_( Post_Table_Missing, 0x94, \ + "PostScript (post) table missing" ) + FT_ERRORDEF_( Invalid_Horiz_Metrics, 0x95, \ + "invalid horizontal metrics" ) + FT_ERRORDEF_( Invalid_CharMap_Format, 0x96, \ + "invalid character map (cmap) format" ) + FT_ERRORDEF_( Invalid_PPem, 0x97, \ + "invalid ppem value" ) + FT_ERRORDEF_( Invalid_Vert_Metrics, 0x98, \ + "invalid vertical metrics" ) + FT_ERRORDEF_( Could_Not_Find_Context, 0x99, \ + "could not find context" ) + FT_ERRORDEF_( Invalid_Post_Table_Format, 0x9A, \ + "invalid PostScript (post) table format" ) + FT_ERRORDEF_( Invalid_Post_Table, 0x9B, \ + "invalid PostScript (post) table" ) + + /* CFF, CID, and Type 1 errors */ + + FT_ERRORDEF_( Syntax_Error, 0xA0, \ + "opcode syntax error" ) + FT_ERRORDEF_( Stack_Underflow, 0xA1, \ + "argument stack underflow" ) + FT_ERRORDEF_( Ignore, 0xA2, \ + "ignore" ) + + /* BDF errors */ + + FT_ERRORDEF_( Missing_Startfont_Field, 0xB0, \ + "`STARTFONT' field missing" ) + FT_ERRORDEF_( Missing_Font_Field, 0xB1, \ + "`FONT' field missing" ) + FT_ERRORDEF_( Missing_Size_Field, 0xB2, \ + "`SIZE' field missing" ) + FT_ERRORDEF_( Missing_Chars_Field, 0xB3, \ + "`CHARS' field missing" ) + FT_ERRORDEF_( Missing_Startchar_Field, 0xB4, \ + "`STARTCHAR' field missing" ) + FT_ERRORDEF_( Missing_Encoding_Field, 0xB5, \ + "`ENCODING' field missing" ) + FT_ERRORDEF_( Missing_Bbx_Field, 0xB6, \ + "`BBX' field missing" ) + FT_ERRORDEF_( Bbx_Too_Big, 0xB7, \ + "`BBX' too big" ) + FT_ERRORDEF_( Corrupted_Font_Header, 0xB8, \ + "Font header corrupted or missing fields" ) + FT_ERRORDEF_( Corrupted_Font_Glyphs, 0xB9, \ + "Font glyphs corrupted or missing fields" ) + + +/* END */ diff --git a/include/freetype/fterrors.h b/include/freetype/fterrors.h new file mode 100644 index 0000000..6600dad --- /dev/null +++ b/include/freetype/fterrors.h @@ -0,0 +1,206 @@ +/***************************************************************************/ +/* */ +/* fterrors.h */ +/* */ +/* FreeType error code handling (specification). */ +/* */ +/* Copyright 1996-2001, 2002, 2004, 2007 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + + /*************************************************************************/ + /* */ + /* This special header file is used to define the handling of FT2 */ + /* enumeration constants. It can also be used to generate error message */ + /* strings with a small macro trick explained below. */ + /* */ + /* I - Error Formats */ + /* ----------------- */ + /* */ + /* The configuration macro FT_CONFIG_OPTION_USE_MODULE_ERRORS can be */ + /* defined in ftoption.h in order to make the higher byte indicate */ + /* the module where the error has happened (this is not compatible */ + /* with standard builds of FreeType 2). You can then use the macro */ + /* FT_ERROR_BASE macro to extract the generic error code from an */ + /* FT_Error value. */ + /* */ + /* */ + /* II - Error Message strings */ + /* -------------------------- */ + /* */ + /* The error definitions below are made through special macros that */ + /* allow client applications to build a table of error message strings */ + /* if they need it. The strings are not included in a normal build of */ + /* FreeType 2 to save space (most client applications do not use */ + /* them). */ + /* */ + /* To do so, you have to define the following macros before including */ + /* this file: */ + /* */ + /* FT_ERROR_START_LIST :: */ + /* This macro is called before anything else to define the start of */ + /* the error list. It is followed by several FT_ERROR_DEF calls */ + /* (see below). */ + /* */ + /* FT_ERROR_DEF( e, v, s ) :: */ + /* This macro is called to define one single error. */ + /* `e' is the error code identifier (e.g. FT_Err_Invalid_Argument). */ + /* `v' is the error numerical value. */ + /* `s' is the corresponding error string. */ + /* */ + /* FT_ERROR_END_LIST :: */ + /* This macro ends the list. */ + /* */ + /* Additionally, you have to undefine __FTERRORS_H__ before #including */ + /* this file. */ + /* */ + /* Here is a simple example: */ + /* */ + /* { */ + /* #undef __FTERRORS_H__ */ + /* #define FT_ERRORDEF( e, v, s ) { e, s }, */ + /* #define FT_ERROR_START_LIST { */ + /* #define FT_ERROR_END_LIST { 0, 0 } }; */ + /* */ + /* const struct */ + /* { */ + /* int err_code; */ + /* const char* err_msg; */ + /* } ft_errors[] = */ + /* */ + /* #include FT_ERRORS_H */ + /* } */ + /* */ + /*************************************************************************/ + + +#ifndef __FTERRORS_H__ +#define __FTERRORS_H__ + + + /* include module base error codes */ +#include FT_MODULE_ERRORS_H + + + /*******************************************************************/ + /*******************************************************************/ + /***** *****/ + /***** SETUP MACROS *****/ + /***** *****/ + /*******************************************************************/ + /*******************************************************************/ + + +#undef FT_NEED_EXTERN_C + +#undef FT_ERR_XCAT +#undef FT_ERR_CAT + +#define FT_ERR_XCAT( x, y ) x ## y +#define FT_ERR_CAT( x, y ) FT_ERR_XCAT( x, y ) + + + /* FT_ERR_PREFIX is used as a prefix for error identifiers. */ + /* By default, we use `FT_Err_'. */ + /* */ +#ifndef FT_ERR_PREFIX +#define FT_ERR_PREFIX FT_Err_ +#endif + + + /* FT_ERR_BASE is used as the base for module-specific errors. */ + /* */ +#ifdef FT_CONFIG_OPTION_USE_MODULE_ERRORS + +#ifndef FT_ERR_BASE +#define FT_ERR_BASE FT_Mod_Err_Base +#endif + +#else + +#undef FT_ERR_BASE +#define FT_ERR_BASE 0 + +#endif /* FT_CONFIG_OPTION_USE_MODULE_ERRORS */ + + + /* If FT_ERRORDEF is not defined, we need to define a simple */ + /* enumeration type. */ + /* */ +#ifndef FT_ERRORDEF + +#define FT_ERRORDEF( e, v, s ) e = v, +#define FT_ERROR_START_LIST enum { +#define FT_ERROR_END_LIST FT_ERR_CAT( FT_ERR_PREFIX, Max ) }; + +#ifdef __cplusplus +#define FT_NEED_EXTERN_C + extern "C" { +#endif + +#endif /* !FT_ERRORDEF */ + + + /* this macro is used to define an error */ +#define FT_ERRORDEF_( e, v, s ) \ + FT_ERRORDEF( FT_ERR_CAT( FT_ERR_PREFIX, e ), v + FT_ERR_BASE, s ) + + /* this is only used for <module>_Err_Ok, which must be 0! */ +#define FT_NOERRORDEF_( e, v, s ) \ + FT_ERRORDEF( FT_ERR_CAT( FT_ERR_PREFIX, e ), v, s ) + + +#ifdef FT_ERROR_START_LIST + FT_ERROR_START_LIST +#endif + + + /* now include the error codes */ +#include FT_ERROR_DEFINITIONS_H + + +#ifdef FT_ERROR_END_LIST + FT_ERROR_END_LIST +#endif + + + /*******************************************************************/ + /*******************************************************************/ + /***** *****/ + /***** SIMPLE CLEANUP *****/ + /***** *****/ + /*******************************************************************/ + /*******************************************************************/ + +#ifdef FT_NEED_EXTERN_C + } +#endif + +#undef FT_ERROR_START_LIST +#undef FT_ERROR_END_LIST + +#undef FT_ERRORDEF +#undef FT_ERRORDEF_ +#undef FT_NOERRORDEF_ + +#undef FT_NEED_EXTERN_C +#undef FT_ERR_CONCAT +#undef FT_ERR_BASE + + /* FT_KEEP_ERR_PREFIX is needed for ftvalid.h */ +#ifndef FT_KEEP_ERR_PREFIX +#undef FT_ERR_PREFIX +#endif + +#endif /* __FTERRORS_H__ */ + + +/* END */ diff --git a/include/freetype/ftgasp.h b/include/freetype/ftgasp.h new file mode 100644 index 0000000..97cd330 --- /dev/null +++ b/include/freetype/ftgasp.h @@ -0,0 +1,113 @@ +/***************************************************************************/ +/* */ +/* ftgasp.h */ +/* */ +/* Access of TrueType's `gasp' table (specification). */ +/* */ +/* Copyright 2007 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef _FT_GASP_H_ +#define _FT_GASP_H_ + +#include <ft2build.h> +#include FT_FREETYPE_H + + /*************************************************************************** + * + * @section: + * gasp_table + * + * @title: + * Gasp Table + * + * @abstract: + * Retrieving TrueType `gasp' table entries + * + * @description: + * The function @FT_Get_Gasp can be used to query a TrueType or OpenType + * font for specific entries in their `gasp' table, if any. This is + * mainly useful when implementing native TrueType hinting with the + * bytecode interpreter to duplicate the Windows text rendering results. + */ + + /************************************************************************* + * + * @enum: + * FT_GASP_XXX + * + * @description: + * A list of values and/or bit-flags returned by the @FT_Get_Gasp + * function. + * + * @values: + * FT_GASP_NO_TABLE :: + * This special value means that there is no GASP table in this face. + * It is up to the client to decide what to do. + * + * FT_GASP_DO_GRIDFIT :: + * Grid-fitting and hinting should be performed at the specified ppem. + * This *really* means TrueType bytecode interpretation. + * + * FT_GASP_DO_GRAY :: + * Anti-aliased rendering should be performed at the specified ppem. + * + * FT_GASP_SYMMETRIC_SMOOTHING :: + * Smoothing along multiple axes must be used with ClearType. + * + * FT_GASP_SYMMETRIC_GRIDFIT :: + * Grid-fitting must be used with ClearType's symmetric smoothing. + * + * @note: + * `ClearType' is Microsoft's implementation of LCD rendering, partly + * protected by patents. + * + * @since: + * 2.3.0 + */ +#define FT_GASP_NO_TABLE -1 +#define FT_GASP_DO_GRIDFIT 0x01 +#define FT_GASP_DO_GRAY 0x02 +#define FT_GASP_SYMMETRIC_SMOOTHING 0x08 +#define FT_GASP_SYMMETRIC_GRIDFIT 0x10 + + + /************************************************************************* + * + * @func: + * FT_Get_Gasp + * + * @description: + * Read the `gasp' table from a TrueType or OpenType font file and + * return the entry corresponding to a given character pixel size. + * + * @input: + * face :: The source face handle. + * ppem :: The vertical character pixel size. + * + * @return: + * Bit flags (see @FT_GASP_XXX), or @FT_GASP_NO_TABLE is there is no + * `gasp' table in the face. + * + * @since: + * 2.3.0 + */ + FT_EXPORT( FT_Int ) + FT_Get_Gasp( FT_Face face, + FT_UInt ppem ); + +/* */ + +#endif /* _FT_GASP_H_ */ + + +/* END */ diff --git a/include/freetype/ftglyph.h b/include/freetype/ftglyph.h new file mode 100644 index 0000000..08058da --- /dev/null +++ b/include/freetype/ftglyph.h @@ -0,0 +1,575 @@ +/***************************************************************************/ +/* */ +/* ftglyph.h */ +/* */ +/* FreeType convenience functions to handle glyphs (specification). */ +/* */ +/* Copyright 1996-2001, 2002, 2003, 2006 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + + /*************************************************************************/ + /* */ + /* This file contains the definition of several convenience functions */ + /* that can be used by client applications to easily retrieve glyph */ + /* bitmaps and outlines from a given face. */ + /* */ + /* These functions should be optional if you are writing a font server */ + /* or text layout engine on top of FreeType. However, they are pretty */ + /* handy for many other simple uses of the library. */ + /* */ + /*************************************************************************/ + + +#ifndef __FTGLYPH_H__ +#define __FTGLYPH_H__ + + +#include <ft2build.h> +#include FT_FREETYPE_H + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* glyph_management */ + /* */ + /* <Title> */ + /* Glyph Management */ + /* */ + /* <Abstract> */ + /* Generic interface to manage individual glyph data. */ + /* */ + /* <Description> */ + /* This section contains definitions used to manage glyph data */ + /* through generic FT_Glyph objects. Each of them can contain a */ + /* bitmap, a vector outline, or even images in other formats. */ + /* */ + /*************************************************************************/ + + + /* forward declaration to a private type */ + typedef struct FT_Glyph_Class_ FT_Glyph_Class; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_Glyph */ + /* */ + /* <Description> */ + /* Handle to an object used to model generic glyph images. It is a */ + /* pointer to the @FT_GlyphRec structure and can contain a glyph */ + /* bitmap or pointer. */ + /* */ + /* <Note> */ + /* Glyph objects are not owned by the library. You must thus release */ + /* them manually (through @FT_Done_Glyph) _before_ calling */ + /* @FT_Done_FreeType. */ + /* */ + typedef struct FT_GlyphRec_* FT_Glyph; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_GlyphRec */ + /* */ + /* <Description> */ + /* The root glyph structure contains a given glyph image plus its */ + /* advance width in 16.16 fixed float format. */ + /* */ + /* <Fields> */ + /* library :: A handle to the FreeType library object. */ + /* */ + /* clazz :: A pointer to the glyph's class. Private. */ + /* */ + /* format :: The format of the glyph's image. */ + /* */ + /* advance :: A 16.16 vector that gives the glyph's advance width. */ + /* */ + typedef struct FT_GlyphRec_ + { + FT_Library library; + const FT_Glyph_Class* clazz; + FT_Glyph_Format format; + FT_Vector advance; + + } FT_GlyphRec; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_BitmapGlyph */ + /* */ + /* <Description> */ + /* A handle to an object used to model a bitmap glyph image. This is */ + /* a sub-class of @FT_Glyph, and a pointer to @FT_BitmapGlyphRec. */ + /* */ + typedef struct FT_BitmapGlyphRec_* FT_BitmapGlyph; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_BitmapGlyphRec */ + /* */ + /* <Description> */ + /* A structure used for bitmap glyph images. This really is a */ + /* `sub-class' of @FT_GlyphRec. */ + /* */ + /* <Fields> */ + /* root :: The root @FT_Glyph fields. */ + /* */ + /* left :: The left-side bearing, i.e., the horizontal distance */ + /* from the current pen position to the left border of the */ + /* glyph bitmap. */ + /* */ + /* top :: The top-side bearing, i.e., the vertical distance from */ + /* the current pen position to the top border of the glyph */ + /* bitmap. This distance is positive for upwards-y! */ + /* */ + /* bitmap :: A descriptor for the bitmap. */ + /* */ + /* <Note> */ + /* You can typecast an @FT_Glyph to @FT_BitmapGlyph if you have */ + /* `glyph->format == FT_GLYPH_FORMAT_BITMAP'. This lets you access */ + /* the bitmap's contents easily. */ + /* */ + /* The corresponding pixel buffer is always owned by @FT_BitmapGlyph */ + /* and is thus created and destroyed with it. */ + /* */ + typedef struct FT_BitmapGlyphRec_ + { + FT_GlyphRec root; + FT_Int left; + FT_Int top; + FT_Bitmap bitmap; + + } FT_BitmapGlyphRec; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_OutlineGlyph */ + /* */ + /* <Description> */ + /* A handle to an object used to model an outline glyph image. This */ + /* is a sub-class of @FT_Glyph, and a pointer to @FT_OutlineGlyphRec. */ + /* */ + typedef struct FT_OutlineGlyphRec_* FT_OutlineGlyph; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_OutlineGlyphRec */ + /* */ + /* <Description> */ + /* A structure used for outline (vectorial) glyph images. This */ + /* really is a `sub-class' of @FT_GlyphRec. */ + /* */ + /* <Fields> */ + /* root :: The root @FT_Glyph fields. */ + /* */ + /* outline :: A descriptor for the outline. */ + /* */ + /* <Note> */ + /* You can typecast a @FT_Glyph to @FT_OutlineGlyph if you have */ + /* `glyph->format == FT_GLYPH_FORMAT_OUTLINE'. This lets you access */ + /* the outline's content easily. */ + /* */ + /* As the outline is extracted from a glyph slot, its coordinates are */ + /* expressed normally in 26.6 pixels, unless the flag */ + /* @FT_LOAD_NO_SCALE was used in @FT_Load_Glyph() or @FT_Load_Char(). */ + /* */ + /* The outline's tables are always owned by the object and are */ + /* destroyed with it. */ + /* */ + typedef struct FT_OutlineGlyphRec_ + { + FT_GlyphRec root; + FT_Outline outline; + + } FT_OutlineGlyphRec; + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Get_Glyph */ + /* */ + /* <Description> */ + /* A function used to extract a glyph image from a slot. */ + /* */ + /* <Input> */ + /* slot :: A handle to the source glyph slot. */ + /* */ + /* <Output> */ + /* aglyph :: A handle to the glyph object. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Get_Glyph( FT_GlyphSlot slot, + FT_Glyph *aglyph ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Glyph_Copy */ + /* */ + /* <Description> */ + /* A function used to copy a glyph image. Note that the created */ + /* @FT_Glyph object must be released with @FT_Done_Glyph. */ + /* */ + /* <Input> */ + /* source :: A handle to the source glyph object. */ + /* */ + /* <Output> */ + /* target :: A handle to the target glyph object. 0 in case of */ + /* error. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Glyph_Copy( FT_Glyph source, + FT_Glyph *target ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Glyph_Transform */ + /* */ + /* <Description> */ + /* Transforms a glyph image if its format is scalable. */ + /* */ + /* <InOut> */ + /* glyph :: A handle to the target glyph object. */ + /* */ + /* <Input> */ + /* matrix :: A pointer to a 2x2 matrix to apply. */ + /* */ + /* delta :: A pointer to a 2d vector to apply. Coordinates are */ + /* expressed in 1/64th of a pixel. */ + /* */ + /* <Return> */ + /* FreeType error code (if not 0, the glyph format is not scalable). */ + /* */ + /* <Note> */ + /* The 2x2 transformation matrix is also applied to the glyph's */ + /* advance vector. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Glyph_Transform( FT_Glyph glyph, + FT_Matrix* matrix, + FT_Vector* delta ); + + + /*************************************************************************/ + /* */ + /* <Enum> */ + /* FT_Glyph_BBox_Mode */ + /* */ + /* <Description> */ + /* The mode how the values of @FT_Glyph_Get_CBox are returned. */ + /* */ + /* <Values> */ + /* FT_GLYPH_BBOX_UNSCALED :: */ + /* Return unscaled font units. */ + /* */ + /* FT_GLYPH_BBOX_SUBPIXELS :: */ + /* Return unfitted 26.6 coordinates. */ + /* */ + /* FT_GLYPH_BBOX_GRIDFIT :: */ + /* Return grid-fitted 26.6 coordinates. */ + /* */ + /* FT_GLYPH_BBOX_TRUNCATE :: */ + /* Return coordinates in integer pixels. */ + /* */ + /* FT_GLYPH_BBOX_PIXELS :: */ + /* Return grid-fitted pixel coordinates. */ + /* */ + typedef enum FT_Glyph_BBox_Mode_ + { + FT_GLYPH_BBOX_UNSCALED = 0, + FT_GLYPH_BBOX_SUBPIXELS = 0, + FT_GLYPH_BBOX_GRIDFIT = 1, + FT_GLYPH_BBOX_TRUNCATE = 2, + FT_GLYPH_BBOX_PIXELS = 3 + + } FT_Glyph_BBox_Mode; + + + /*************************************************************************/ + /* */ + /* <Enum> */ + /* ft_glyph_bbox_xxx */ + /* */ + /* <Description> */ + /* These constants are deprecated. Use the corresponding */ + /* @FT_Glyph_BBox_Mode values instead. */ + /* */ + /* <Values> */ + /* ft_glyph_bbox_unscaled :: See @FT_GLYPH_BBOX_UNSCALED. */ + /* ft_glyph_bbox_subpixels :: See @FT_GLYPH_BBOX_SUBPIXELS. */ + /* ft_glyph_bbox_gridfit :: See @FT_GLYPH_BBOX_GRIDFIT. */ + /* ft_glyph_bbox_truncate :: See @FT_GLYPH_BBOX_TRUNCATE. */ + /* ft_glyph_bbox_pixels :: See @FT_GLYPH_BBOX_PIXELS. */ + /* */ +#define ft_glyph_bbox_unscaled FT_GLYPH_BBOX_UNSCALED +#define ft_glyph_bbox_subpixels FT_GLYPH_BBOX_SUBPIXELS +#define ft_glyph_bbox_gridfit FT_GLYPH_BBOX_GRIDFIT +#define ft_glyph_bbox_truncate FT_GLYPH_BBOX_TRUNCATE +#define ft_glyph_bbox_pixels FT_GLYPH_BBOX_PIXELS + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Glyph_Get_CBox */ + /* */ + /* <Description> */ + /* Return a glyph's `control box'. The control box encloses all the */ + /* outline's points, including Bézier control points. Though it */ + /* coincides with the exact bounding box for most glyphs, it can be */ + /* slightly larger in some situations (like when rotating an outline */ + /* which contains Bézier outside arcs). */ + /* */ + /* Computing the control box is very fast, while getting the bounding */ + /* box can take much more time as it needs to walk over all segments */ + /* and arcs in the outline. To get the latter, you can use the */ + /* `ftbbox' component which is dedicated to this single task. */ + /* */ + /* <Input> */ + /* glyph :: A handle to the source glyph object. */ + /* */ + /* mode :: The mode which indicates how to interpret the returned */ + /* bounding box values. */ + /* */ + /* <Output> */ + /* acbox :: The glyph coordinate bounding box. Coordinates are */ + /* expressed in 1/64th of pixels if it is grid-fitted. */ + /* */ + /* <Note> */ + /* Coordinates are relative to the glyph origin, using the Y-upwards */ + /* convention. */ + /* */ + /* If the glyph has been loaded with @FT_LOAD_NO_SCALE, `bbox_mode' */ + /* must be set to @FT_GLYPH_BBOX_UNSCALED to get unscaled font */ + /* units in 26.6 pixel format. The value @FT_GLYPH_BBOX_SUBPIXELS */ + /* is another name for this constant. */ + /* */ + /* Note that the maximum coordinates are exclusive, which means that */ + /* one can compute the width and height of the glyph image (be it in */ + /* integer or 26.6 pixels) as: */ + /* */ + /* { */ + /* width = bbox.xMax - bbox.xMin; */ + /* height = bbox.yMax - bbox.yMin; */ + /* } */ + /* */ + /* Note also that for 26.6 coordinates, if `bbox_mode' is set to */ + /* @FT_GLYPH_BBOX_GRIDFIT, the coordinates will also be grid-fitted, */ + /* which corresponds to: */ + /* */ + /* { */ + /* bbox.xMin = FLOOR(bbox.xMin); */ + /* bbox.yMin = FLOOR(bbox.yMin); */ + /* bbox.xMax = CEILING(bbox.xMax); */ + /* bbox.yMax = CEILING(bbox.yMax); */ + /* } */ + /* */ + /* To get the bbox in pixel coordinates, set `bbox_mode' to */ + /* @FT_GLYPH_BBOX_TRUNCATE. */ + /* */ + /* To get the bbox in grid-fitted pixel coordinates, set `bbox_mode' */ + /* to @FT_GLYPH_BBOX_PIXELS. */ + /* */ + FT_EXPORT( void ) + FT_Glyph_Get_CBox( FT_Glyph glyph, + FT_UInt bbox_mode, + FT_BBox *acbox ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Glyph_To_Bitmap */ + /* */ + /* <Description> */ + /* Converts a given glyph object to a bitmap glyph object. */ + /* */ + /* <InOut> */ + /* the_glyph :: A pointer to a handle to the target glyph. */ + /* */ + /* <Input> */ + /* render_mode :: An enumeration that describe how the data is */ + /* rendered. */ + /* */ + /* origin :: A pointer to a vector used to translate the glyph */ + /* image before rendering. Can be 0 (if no */ + /* translation). The origin is expressed in */ + /* 26.6 pixels. */ + /* */ + /* destroy :: A boolean that indicates that the original glyph */ + /* image should be destroyed by this function. It is */ + /* never destroyed in case of error. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* The glyph image is translated with the `origin' vector before */ + /* rendering. */ + /* */ + /* The first parameter is a pointer to an @FT_Glyph handle, that will */ + /* be replaced by this function. Typically, you would use (omitting */ + /* error handling): */ + /* */ + /* */ + /* { */ + /* FT_Glyph glyph; */ + /* FT_BitmapGlyph glyph_bitmap; */ + /* */ + /* */ + /* // load glyph */ + /* error = FT_Load_Char( face, glyph_index, FT_LOAD_DEFAUT ); */ + /* */ + /* // extract glyph image */ + /* error = FT_Get_Glyph( face->glyph, &glyph ); */ + /* */ + /* // convert to a bitmap (default render mode + destroy old) */ + /* if ( glyph->format != FT_GLYPH_FORMAT_BITMAP ) */ + /* { */ + /* error = FT_Glyph_To_Bitmap( &glyph, FT_RENDER_MODE_DEFAULT, */ + /* 0, 1 ); */ + /* if ( error ) // glyph unchanged */ + /* ... */ + /* } */ + /* */ + /* // access bitmap content by typecasting */ + /* glyph_bitmap = (FT_BitmapGlyph)glyph; */ + /* */ + /* // do funny stuff with it, like blitting/drawing */ + /* ... */ + /* */ + /* // discard glyph image (bitmap or not) */ + /* FT_Done_Glyph( glyph ); */ + /* } */ + /* */ + /* */ + /* This function does nothing if the glyph format isn't scalable. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Glyph_To_Bitmap( FT_Glyph* the_glyph, + FT_Render_Mode render_mode, + FT_Vector* origin, + FT_Bool destroy ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Done_Glyph */ + /* */ + /* <Description> */ + /* Destroys a given glyph. */ + /* */ + /* <Input> */ + /* glyph :: A handle to the target glyph object. */ + /* */ + FT_EXPORT( void ) + FT_Done_Glyph( FT_Glyph glyph ); + + /* */ + + + /* other helpful functions */ + + /*************************************************************************/ + /* */ + /* <Section> */ + /* computations */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Matrix_Multiply */ + /* */ + /* <Description> */ + /* Performs the matrix operation `b = a*b'. */ + /* */ + /* <Input> */ + /* a :: A pointer to matrix `a'. */ + /* */ + /* <InOut> */ + /* b :: A pointer to matrix `b'. */ + /* */ + /* <Note> */ + /* The result is undefined if either `a' or `b' is zero. */ + /* */ + FT_EXPORT( void ) + FT_Matrix_Multiply( const FT_Matrix* a, + FT_Matrix* b ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Matrix_Invert */ + /* */ + /* <Description> */ + /* Inverts a 2x2 matrix. Returns an error if it can't be inverted. */ + /* */ + /* <InOut> */ + /* matrix :: A pointer to the target matrix. Remains untouched in */ + /* case of error. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Matrix_Invert( FT_Matrix* matrix ); + + + /* */ + + +FT_END_HEADER + +#endif /* __FTGLYPH_H__ */ + + +/* END */ + + +/* Local Variables: */ +/* coding: utf-8 */ +/* End: */ diff --git a/include/freetype/ftgxval.h b/include/freetype/ftgxval.h new file mode 100644 index 0000000..c7ea861 --- /dev/null +++ b/include/freetype/ftgxval.h @@ -0,0 +1,358 @@ +/***************************************************************************/ +/* */ +/* ftgxval.h */ +/* */ +/* FreeType API for validating TrueTypeGX/AAT tables (specification). */ +/* */ +/* Copyright 2004, 2005, 2006 by */ +/* Masatake YAMATO, Redhat K.K, */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + +/***************************************************************************/ +/* */ +/* gxvalid is derived from both gxlayout module and otvalid module. */ +/* Development of gxlayout is supported by the Information-technology */ +/* Promotion Agency(IPA), Japan. */ +/* */ +/***************************************************************************/ + + +#ifndef __FTGXVAL_H__ +#define __FTGXVAL_H__ + +#include <ft2build.h> +#include FT_FREETYPE_H + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* gx_validation */ + /* */ + /* <Title> */ + /* TrueTypeGX/AAT Validation */ + /* */ + /* <Abstract> */ + /* An API to validate TrueTypeGX/AAT tables. */ + /* */ + /* <Description> */ + /* This section contains the declaration of functions to validate */ + /* some TrueTypeGX tables (feat, mort, morx, bsln, just, kern, opbd, */ + /* trak, prop, lcar). */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* */ + /* Warning: Use FT_VALIDATE_XXX to validate a table. */ + /* Following definitions are for gxvalid developers. */ + /* */ + /* */ + /*************************************************************************/ + +#define FT_VALIDATE_feat_INDEX 0 +#define FT_VALIDATE_mort_INDEX 1 +#define FT_VALIDATE_morx_INDEX 2 +#define FT_VALIDATE_bsln_INDEX 3 +#define FT_VALIDATE_just_INDEX 4 +#define FT_VALIDATE_kern_INDEX 5 +#define FT_VALIDATE_opbd_INDEX 6 +#define FT_VALIDATE_trak_INDEX 7 +#define FT_VALIDATE_prop_INDEX 8 +#define FT_VALIDATE_lcar_INDEX 9 +#define FT_VALIDATE_GX_LAST_INDEX FT_VALIDATE_lcar_INDEX + + + /************************************************************************* + * + * @macro: + * FT_VALIDATE_GX_LENGTH + * + * @description: + * The number of tables checked in this module. Use it as a parameter + * for the `table-length' argument of function @FT_TrueTypeGX_Validate. + */ +#define FT_VALIDATE_GX_LENGTH (FT_VALIDATE_GX_LAST_INDEX + 1) + + /* */ + + /* Up to 0x1000 is used by otvalid. + Ox2xxx is reserved for feature OT extension. */ +#define FT_VALIDATE_GX_START 0x4000 +#define FT_VALIDATE_GX_BITFIELD( tag ) \ + ( FT_VALIDATE_GX_START << FT_VALIDATE_##tag##_INDEX ) + + + /********************************************************************** + * + * @enum: + * FT_VALIDATE_GXXXX + * + * @description: + * A list of bit-field constants used with @FT_TrueTypeGX_Validate to + * indicate which TrueTypeGX/AAT Type tables should be validated. + * + * @values: + * FT_VALIDATE_feat :: + * Validate `feat' table. + * + * FT_VALIDATE_mort :: + * Validate `mort' table. + * + * FT_VALIDATE_morx :: + * Validate `morx' table. + * + * FT_VALIDATE_bsln :: + * Validate `bsln' table. + * + * FT_VALIDATE_just :: + * Validate `just' table. + * + * FT_VALIDATE_kern :: + * Validate `kern' table. + * + * FT_VALIDATE_opbd :: + * Validate `opbd' table. + * + * FT_VALIDATE_trak :: + * Validate `trak' table. + * + * FT_VALIDATE_prop :: + * Validate `prop' table. + * + * FT_VALIDATE_lcar :: + * Validate `lcar' table. + * + * FT_VALIDATE_GX :: + * Validate all TrueTypeGX tables (feat, mort, morx, bsln, just, kern, + * opbd, trak, prop and lcar). + * + */ + +#define FT_VALIDATE_feat FT_VALIDATE_GX_BITFIELD( feat ) +#define FT_VALIDATE_mort FT_VALIDATE_GX_BITFIELD( mort ) +#define FT_VALIDATE_morx FT_VALIDATE_GX_BITFIELD( morx ) +#define FT_VALIDATE_bsln FT_VALIDATE_GX_BITFIELD( bsln ) +#define FT_VALIDATE_just FT_VALIDATE_GX_BITFIELD( just ) +#define FT_VALIDATE_kern FT_VALIDATE_GX_BITFIELD( kern ) +#define FT_VALIDATE_opbd FT_VALIDATE_GX_BITFIELD( opbd ) +#define FT_VALIDATE_trak FT_VALIDATE_GX_BITFIELD( trak ) +#define FT_VALIDATE_prop FT_VALIDATE_GX_BITFIELD( prop ) +#define FT_VALIDATE_lcar FT_VALIDATE_GX_BITFIELD( lcar ) + +#define FT_VALIDATE_GX ( FT_VALIDATE_feat | \ + FT_VALIDATE_mort | \ + FT_VALIDATE_morx | \ + FT_VALIDATE_bsln | \ + FT_VALIDATE_just | \ + FT_VALIDATE_kern | \ + FT_VALIDATE_opbd | \ + FT_VALIDATE_trak | \ + FT_VALIDATE_prop | \ + FT_VALIDATE_lcar ) + + + /* */ + + /********************************************************************** + * + * @function: + * FT_TrueTypeGX_Validate + * + * @description: + * Validate various TrueTypeGX tables to assure that all offsets and + * indices are valid. The idea is that a higher-level library which + * actually does the text layout can access those tables without + * error checking (which can be quite time consuming). + * + * @input: + * face :: + * A handle to the input face. + * + * validation_flags :: + * A bit field which specifies the tables to be validated. See + * @FT_VALIDATE_GXXXX for possible values. + * + * table_length :: + * The size of the `tables' array. Normally, @FT_VALIDATE_GX_LENGTH + * should be passed. + * + * @output: + * tables :: + * The array where all validated sfnt tables are stored. + * The array itself must be allocated by a client. + * + * @return: + * FreeType error code. 0 means success. + * + * @note: + * This function only works with TrueTypeGX fonts, returning an error + * otherwise. + * + * After use, the application should deallocate the buffers pointed to by + * each `tables' element, by calling @FT_TrueTypeGX_Free. A NULL value + * indicates that the table either doesn't exist in the font, the + * application hasn't asked for validation, or the validator doesn't have + * the ability to validate the sfnt table. + */ + FT_EXPORT( FT_Error ) + FT_TrueTypeGX_Validate( FT_Face face, + FT_UInt validation_flags, + FT_Bytes tables[FT_VALIDATE_GX_LENGTH], + FT_UInt table_length ); + + + /* */ + + /********************************************************************** + * + * @function: + * FT_TrueTypeGX_Free + * + * @description: + * Free the buffer allocated by TrueTypeGX validator. + * + * @input: + * face :: + * A handle to the input face. + * + * table :: + * The pointer to the buffer allocated by + * @FT_TrueTypeGX_Validate. + * + * @note: + * This function must be used to free the buffer allocated by + * @FT_TrueTypeGX_Validate only. + */ + FT_EXPORT( void ) + FT_TrueTypeGX_Free( FT_Face face, + FT_Bytes table ); + + + /* */ + + /********************************************************************** + * + * @enum: + * FT_VALIDATE_CKERNXXX + * + * @description: + * A list of bit-field constants used with @FT_ClassicKern_Validate + * to indicate the classic kern dialect or dialects. If the selected + * type doesn't fit, @FT_ClassicKern_Validate regards the table as + * invalid. + * + * @values: + * FT_VALIDATE_MS :: + * Handle the `kern' table as a classic Microsoft kern table. + * + * FT_VALIDATE_APPLE :: + * Handle the `kern' table as a classic Apple kern table. + * + * FT_VALIDATE_CKERN :: + * Handle the `kern' as either classic Apple or Microsoft kern table. + */ +#define FT_VALIDATE_MS ( FT_VALIDATE_GX_START << 0 ) +#define FT_VALIDATE_APPLE ( FT_VALIDATE_GX_START << 1 ) + +#define FT_VALIDATE_CKERN ( FT_VALIDATE_MS | FT_VALIDATE_APPLE ) + + + /* */ + + /********************************************************************** + * + * @function: + * FT_ClassicKern_Validate + * + * @description: + * Validate classic (16bit format) kern table to assure that the offsets + * and indices are valid. The idea is that a higher-level library which + * actually does the text layout can access those tables without error + * checking (which can be quite time consuming). + * + * The `kern' table validator in @FT_TrueTypeGX_Validate deals with both + * the new 32bit format and the classic 16bit format, while + * FT_ClassicKern_Validate only supports the classic 16bit format. + * + * @input: + * face :: + * A handle to the input face. + * + * validation_flags :: + * A bit field which specifies the dialect to be validated. See + * @FT_VALIDATE_CKERNXXX for possible values. + * + * @output: + * ckern_table :: + * A pointer to the kern table. + * + * @return: + * FreeType error code. 0 means success. + * + * @note: + * After use, the application should deallocate the buffers pointed to by + * `ckern_table', by calling @FT_ClassicKern_Free. A NULL value + * indicates that the table doesn't exist in the font. + */ + FT_EXPORT( FT_Error ) + FT_ClassicKern_Validate( FT_Face face, + FT_UInt validation_flags, + FT_Bytes *ckern_table ); + + + /* */ + + /********************************************************************** + * + * @function: + * FT_ClassicKern_Free + * + * @description: + * Free the buffer allocated by classic Kern validator. + * + * @input: + * face :: + * A handle to the input face. + * + * table :: + * The pointer to the buffer that is allocated by + * @FT_ClassicKern_Validate. + * + * @note: + * This function must be used to free the buffer allocated by + * @FT_ClassicKern_Validate only. + */ + FT_EXPORT( void ) + FT_ClassicKern_Free( FT_Face face, + FT_Bytes table ); + + + /* */ + + +FT_END_HEADER + +#endif /* __FTGXVAL_H__ */ + + +/* END */ diff --git a/include/freetype/ftgzip.h b/include/freetype/ftgzip.h new file mode 100644 index 0000000..9893437 --- /dev/null +++ b/include/freetype/ftgzip.h @@ -0,0 +1,102 @@ +/***************************************************************************/ +/* */ +/* ftgzip.h */ +/* */ +/* Gzip-compressed stream support. */ +/* */ +/* Copyright 2002, 2003, 2004, 2006 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef __FTGZIP_H__ +#define __FTGZIP_H__ + +#include <ft2build.h> +#include FT_FREETYPE_H + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + /*************************************************************************/ + /* */ + /* <Section> */ + /* gzip */ + /* */ + /* <Title> */ + /* GZIP Streams */ + /* */ + /* <Abstract> */ + /* Using gzip-compressed font files. */ + /* */ + /* <Description> */ + /* This section contains the declaration of Gzip-specific functions. */ + /* */ + /*************************************************************************/ + + + /************************************************************************ + * + * @function: + * FT_Stream_OpenGzip + * + * @description: + * Open a new stream to parse gzip-compressed font files. This is + * mainly used to support the compressed `*.pcf.gz' fonts that come + * with XFree86. + * + * @input: + * stream :: + * The target embedding stream. + * + * source :: + * The source stream. + * + * @return: + * FreeType error code. 0 means success. + * + * @note: + * The source stream must be opened _before_ calling this function. + * + * Calling the internal function `FT_Stream_Close' on the new stream will + * *not* call `FT_Stream_Close' on the source stream. None of the stream + * objects will be released to the heap. + * + * The stream implementation is very basic and resets the decompression + * process each time seeking backwards is needed within the stream. + * + * In certain builds of the library, gzip compression recognition is + * automatically handled when calling @FT_New_Face or @FT_Open_Face. + * This means that if no font driver is capable of handling the raw + * compressed file, the library will try to open a gzipped stream from + * it and re-open the face with it. + * + * This function may return `FT_Err_Unimplemented_Feature' if your build + * of FreeType was not compiled with zlib support. + */ + FT_EXPORT( FT_Error ) + FT_Stream_OpenGzip( FT_Stream stream, + FT_Stream source ); + + /* */ + + +FT_END_HEADER + +#endif /* __FTGZIP_H__ */ + + +/* END */ diff --git a/include/freetype/ftimage.h b/include/freetype/ftimage.h new file mode 100644 index 0000000..1c428f1 --- /dev/null +++ b/include/freetype/ftimage.h @@ -0,0 +1,1237 @@ +/***************************************************************************/ +/* */ +/* ftimage.h */ +/* */ +/* FreeType glyph image formats and default raster interface */ +/* (specification). */ +/* */ +/* Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2007 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + /*************************************************************************/ + /* */ + /* Note: A `raster' is simply a scan-line converter, used to render */ + /* FT_Outlines into FT_Bitmaps. */ + /* */ + /*************************************************************************/ + + +#ifndef __FTIMAGE_H__ +#define __FTIMAGE_H__ + + +/* _STANDALONE_ is from ftgrays.c */ +#ifndef _STANDALONE_ +#include <ft2build.h> +#endif + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* basic_types */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_Pos */ + /* */ + /* <Description> */ + /* The type FT_Pos is a 32-bit integer used to store vectorial */ + /* coordinates. Depending on the context, these can represent */ + /* distances in integer font units, or 16,16, or 26.6 fixed float */ + /* pixel coordinates. */ + /* */ + typedef signed long FT_Pos; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_Vector */ + /* */ + /* <Description> */ + /* A simple structure used to store a 2D vector; coordinates are of */ + /* the FT_Pos type. */ + /* */ + /* <Fields> */ + /* x :: The horizontal coordinate. */ + /* y :: The vertical coordinate. */ + /* */ + typedef struct FT_Vector_ + { + FT_Pos x; + FT_Pos y; + + } FT_Vector; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_BBox */ + /* */ + /* <Description> */ + /* A structure used to hold an outline's bounding box, i.e., the */ + /* coordinates of its extrema in the horizontal and vertical */ + /* directions. */ + /* */ + /* <Fields> */ + /* xMin :: The horizontal minimum (left-most). */ + /* */ + /* yMin :: The vertical minimum (bottom-most). */ + /* */ + /* xMax :: The horizontal maximum (right-most). */ + /* */ + /* yMax :: The vertical maximum (top-most). */ + /* */ + typedef struct FT_BBox_ + { + FT_Pos xMin, yMin; + FT_Pos xMax, yMax; + + } FT_BBox; + + + /*************************************************************************/ + /* */ + /* <Enum> */ + /* FT_Pixel_Mode */ + /* */ + /* <Description> */ + /* An enumeration type used to describe the format of pixels in a */ + /* given bitmap. Note that additional formats may be added in the */ + /* future. */ + /* */ + /* <Values> */ + /* FT_PIXEL_MODE_NONE :: */ + /* Value 0 is reserved. */ + /* */ + /* FT_PIXEL_MODE_MONO :: */ + /* A monochrome bitmap, using 1 bit per pixel. Note that pixels */ + /* are stored in most-significant order (MSB), which means that */ + /* the left-most pixel in a byte has value 128. */ + /* */ + /* FT_PIXEL_MODE_GRAY :: */ + /* An 8-bit bitmap, generally used to represent anti-aliased glyph */ + /* images. Each pixel is stored in one byte. Note that the number */ + /* of value `gray' levels is stored in the `num_bytes' field of */ + /* the @FT_Bitmap structure (it generally is 256). */ + /* */ + /* FT_PIXEL_MODE_GRAY2 :: */ + /* A 2-bit/pixel bitmap, used to represent embedded anti-aliased */ + /* bitmaps in font files according to the OpenType specification. */ + /* We haven't found a single font using this format, however. */ + /* */ + /* FT_PIXEL_MODE_GRAY4 :: */ + /* A 4-bit/pixel bitmap, used to represent embedded anti-aliased */ + /* bitmaps in font files according to the OpenType specification. */ + /* We haven't found a single font using this format, however. */ + /* */ + /* FT_PIXEL_MODE_LCD :: */ + /* An 8-bit bitmap, used to represent RGB or BGR decimated glyph */ + /* images used for display on LCD displays; the bitmap is three */ + /* times wider than the original glyph image. See also */ + /* @FT_RENDER_MODE_LCD. */ + /* */ + /* FT_PIXEL_MODE_LCD_V :: */ + /* An 8-bit bitmap, used to represent RGB or BGR decimated glyph */ + /* images used for display on rotated LCD displays; the bitmap */ + /* is three times taller than the original glyph image. See also */ + /* @FT_RENDER_MODE_LCD_V. */ + /* */ + typedef enum FT_Pixel_Mode_ + { + FT_PIXEL_MODE_NONE = 0, + FT_PIXEL_MODE_MONO, + FT_PIXEL_MODE_GRAY, + FT_PIXEL_MODE_GRAY2, + FT_PIXEL_MODE_GRAY4, + FT_PIXEL_MODE_LCD, + FT_PIXEL_MODE_LCD_V, + + FT_PIXEL_MODE_MAX /* do not remove */ + + } FT_Pixel_Mode; + + + /*************************************************************************/ + /* */ + /* <Enum> */ + /* ft_pixel_mode_xxx */ + /* */ + /* <Description> */ + /* A list of deprecated constants. Use the corresponding */ + /* @FT_Pixel_Mode values instead. */ + /* */ + /* <Values> */ + /* ft_pixel_mode_none :: See @FT_PIXEL_MODE_NONE. */ + /* ft_pixel_mode_mono :: See @FT_PIXEL_MODE_MONO. */ + /* ft_pixel_mode_grays :: See @FT_PIXEL_MODE_GRAY. */ + /* ft_pixel_mode_pal2 :: See @FT_PIXEL_MODE_GRAY2. */ + /* ft_pixel_mode_pal4 :: See @FT_PIXEL_MODE_GRAY4. */ + /* */ +#define ft_pixel_mode_none FT_PIXEL_MODE_NONE +#define ft_pixel_mode_mono FT_PIXEL_MODE_MONO +#define ft_pixel_mode_grays FT_PIXEL_MODE_GRAY +#define ft_pixel_mode_pal2 FT_PIXEL_MODE_GRAY2 +#define ft_pixel_mode_pal4 FT_PIXEL_MODE_GRAY4 + + /* */ + +#if 0 + + /*************************************************************************/ + /* */ + /* <Enum> */ + /* FT_Palette_Mode */ + /* */ + /* <Description> */ + /* THIS TYPE IS DEPRECATED. DO NOT USE IT! */ + /* */ + /* An enumeration type to describe the format of a bitmap palette, */ + /* used with ft_pixel_mode_pal4 and ft_pixel_mode_pal8. */ + /* */ + /* <Fields> */ + /* ft_palette_mode_rgb :: The palette is an array of 3-bytes RGB */ + /* records. */ + /* */ + /* ft_palette_mode_rgba :: The palette is an array of 4-bytes RGBA */ + /* records. */ + /* */ + /* <Note> */ + /* As ft_pixel_mode_pal2, pal4 and pal8 are currently unused by */ + /* FreeType, these types are not handled by the library itself. */ + /* */ + typedef enum FT_Palette_Mode_ + { + ft_palette_mode_rgb = 0, + ft_palette_mode_rgba, + + ft_palettte_mode_max /* do not remove */ + + } FT_Palette_Mode; + + /* */ + +#endif + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_Bitmap */ + /* */ + /* <Description> */ + /* A structure used to describe a bitmap or pixmap to the raster. */ + /* Note that we now manage pixmaps of various depths through the */ + /* `pixel_mode' field. */ + /* */ + /* <Fields> */ + /* rows :: The number of bitmap rows. */ + /* */ + /* width :: The number of pixels in bitmap row. */ + /* */ + /* pitch :: The pitch's absolute value is the number of bytes */ + /* taken by one bitmap row, including padding. */ + /* However, the pitch is positive when the bitmap has */ + /* a `down' flow, and negative when it has an `up' */ + /* flow. In all cases, the pitch is an offset to add */ + /* to a bitmap pointer in order to go down one row. */ + /* */ + /* buffer :: A typeless pointer to the bitmap buffer. This */ + /* value should be aligned on 32-bit boundaries in */ + /* most cases. */ + /* */ + /* num_grays :: This field is only used with */ + /* @FT_PIXEL_MODE_GRAY; it gives the number of gray */ + /* levels used in the bitmap. */ + /* */ + /* pixel_mode :: The pixel mode, i.e., how pixel bits are stored. */ + /* See @FT_Pixel_Mode for possible values. */ + /* */ + /* palette_mode :: This field is intended for paletted pixel modes; */ + /* it indicates how the palette is stored. Not */ + /* used currently. */ + /* */ + /* palette :: A typeless pointer to the bitmap palette; this */ + /* field is intended for paletted pixel modes. Not */ + /* used currently. */ + /* */ + /* <Note> */ + /* For now, the only pixel modes supported by FreeType are mono and */ + /* grays. However, drivers might be added in the future to support */ + /* more `colorful' options. */ + /* */ + typedef struct FT_Bitmap_ + { + int rows; + int width; + int pitch; + unsigned char* buffer; + short num_grays; + char pixel_mode; + char palette_mode; + void* palette; + + } FT_Bitmap; + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* outline_processing */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_Outline */ + /* */ + /* <Description> */ + /* This structure is used to describe an outline to the scan-line */ + /* converter. */ + /* */ + /* <Fields> */ + /* n_contours :: The number of contours in the outline. */ + /* */ + /* n_points :: The number of points in the outline. */ + /* */ + /* points :: A pointer to an array of `n_points' @FT_Vector */ + /* elements, giving the outline's point coordinates. */ + /* */ + /* tags :: A pointer to an array of `n_points' chars, giving */ + /* each outline point's type. If bit 0 is unset, the */ + /* point is `off' the curve, i.e., a Bézier control */ + /* point, while it is `on' when set. */ + /* */ + /* Bit 1 is meaningful for `off' points only. If set, */ + /* it indicates a third-order Bézier arc control point; */ + /* and a second-order control point if unset. */ + /* */ + /* contours :: An array of `n_contours' shorts, giving the end */ + /* point of each contour within the outline. For */ + /* example, the first contour is defined by the points */ + /* `0' to `contours[0]', the second one is defined by */ + /* the points `contours[0]+1' to `contours[1]', etc. */ + /* */ + /* flags :: A set of bit flags used to characterize the outline */ + /* and give hints to the scan-converter and hinter on */ + /* how to convert/grid-fit it. See @FT_OUTLINE_FLAGS. */ + /* */ + typedef struct FT_Outline_ + { + short n_contours; /* number of contours in glyph */ + short n_points; /* number of points in the glyph */ + + FT_Vector* points; /* the outline's points */ + char* tags; /* the points flags */ + short* contours; /* the contour end points */ + + int flags; /* outline masks */ + + } FT_Outline; + + + /*************************************************************************/ + /* */ + /* <Enum> */ + /* FT_OUTLINE_FLAGS */ + /* */ + /* <Description> */ + /* A list of bit-field constants use for the flags in an outline's */ + /* `flags' field. */ + /* */ + /* <Values> */ + /* FT_OUTLINE_NONE :: Value 0 is reserved. */ + /* */ + /* FT_OUTLINE_OWNER :: If set, this flag indicates that the */ + /* outline's field arrays (i.e., */ + /* `points', `flags' & `contours') are */ + /* `owned' by the outline object, and */ + /* should thus be freed when it is */ + /* destroyed. */ + /* */ + /* FT_OUTLINE_EVEN_ODD_FILL :: By default, outlines are filled using */ + /* the non-zero winding rule. If set to */ + /* 1, the outline will be filled using */ + /* the even-odd fill rule (only works */ + /* with the smooth raster). */ + /* */ + /* FT_OUTLINE_REVERSE_FILL :: By default, outside contours of an */ + /* outline are oriented in clock-wise */ + /* direction, as defined in the TrueType */ + /* specification. This flag is set if */ + /* the outline uses the opposite */ + /* direction (typically for Type 1 */ + /* fonts). This flag is ignored by the */ + /* scan-converter. */ + /* */ + /* FT_OUTLINE_IGNORE_DROPOUTS :: By default, the scan converter will */ + /* try to detect drop-outs in an outline */ + /* and correct the glyph bitmap to */ + /* ensure consistent shape continuity. */ + /* If set, this flag hints the scan-line */ + /* converter to ignore such cases. */ + /* */ + /* FT_OUTLINE_HIGH_PRECISION :: This flag indicates that the */ + /* scan-line converter should try to */ + /* convert this outline to bitmaps with */ + /* the highest possible quality. It is */ + /* typically set for small character */ + /* sizes. Note that this is only a */ + /* hint, that might be completely */ + /* ignored by a given scan-converter. */ + /* */ + /* FT_OUTLINE_SINGLE_PASS :: This flag is set to force a given */ + /* scan-converter to only use a single */ + /* pass over the outline to render a */ + /* bitmap glyph image. Normally, it is */ + /* set for very large character sizes. */ + /* It is only a hint, that might be */ + /* completely ignored by a given */ + /* scan-converter. */ + /* */ +#define FT_OUTLINE_NONE 0x0 +#define FT_OUTLINE_OWNER 0x1 +#define FT_OUTLINE_EVEN_ODD_FILL 0x2 +#define FT_OUTLINE_REVERSE_FILL 0x4 +#define FT_OUTLINE_IGNORE_DROPOUTS 0x8 + +#define FT_OUTLINE_HIGH_PRECISION 0x100 +#define FT_OUTLINE_SINGLE_PASS 0x200 + + + /************************************************************************* + * + * @enum: + * ft_outline_flags + * + * @description: + * These constants are deprecated. Please use the corresponding + * @FT_OUTLINE_FLAGS values. + * + * @values: + * ft_outline_none :: See @FT_OUTLINE_NONE. + * ft_outline_owner :: See @FT_OUTLINE_OWNER. + * ft_outline_even_odd_fill :: See @FT_OUTLINE_EVEN_ODD_FILL. + * ft_outline_reverse_fill :: See @FT_OUTLINE_REVERSE_FILL. + * ft_outline_ignore_dropouts :: See @FT_OUTLINE_IGNORE_DROPOUTS. + * ft_outline_high_precision :: See @FT_OUTLINE_HIGH_PRECISION. + * ft_outline_single_pass :: See @FT_OUTLINE_SINGLE_PASS. + */ +#define ft_outline_none FT_OUTLINE_NONE +#define ft_outline_owner FT_OUTLINE_OWNER +#define ft_outline_even_odd_fill FT_OUTLINE_EVEN_ODD_FILL +#define ft_outline_reverse_fill FT_OUTLINE_REVERSE_FILL +#define ft_outline_ignore_dropouts FT_OUTLINE_IGNORE_DROPOUTS +#define ft_outline_high_precision FT_OUTLINE_HIGH_PRECISION +#define ft_outline_single_pass FT_OUTLINE_SINGLE_PASS + + /* */ + +#define FT_CURVE_TAG( flag ) ( flag & 3 ) + +#define FT_CURVE_TAG_ON 1 +#define FT_CURVE_TAG_CONIC 0 +#define FT_CURVE_TAG_CUBIC 2 + +#define FT_CURVE_TAG_TOUCH_X 8 /* reserved for the TrueType hinter */ +#define FT_CURVE_TAG_TOUCH_Y 16 /* reserved for the TrueType hinter */ + +#define FT_CURVE_TAG_TOUCH_BOTH ( FT_CURVE_TAG_TOUCH_X | \ + FT_CURVE_TAG_TOUCH_Y ) + +#define FT_Curve_Tag_On FT_CURVE_TAG_ON +#define FT_Curve_Tag_Conic FT_CURVE_TAG_CONIC +#define FT_Curve_Tag_Cubic FT_CURVE_TAG_CUBIC +#define FT_Curve_Tag_Touch_X FT_CURVE_TAG_TOUCH_X +#define FT_Curve_Tag_Touch_Y FT_CURVE_TAG_TOUCH_Y + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* FT_Outline_MoveToFunc */ + /* */ + /* <Description> */ + /* A function pointer type used to describe the signature of a `move */ + /* to' function during outline walking/decomposition. */ + /* */ + /* A `move to' is emitted to start a new contour in an outline. */ + /* */ + /* <Input> */ + /* to :: A pointer to the target point of the `move to'. */ + /* */ + /* user :: A typeless pointer which is passed from the caller of the */ + /* decomposition function. */ + /* */ + /* <Return> */ + /* Error code. 0 means success. */ + /* */ + typedef int + (*FT_Outline_MoveToFunc)( const FT_Vector* to, + void* user ); + +#define FT_Outline_MoveTo_Func FT_Outline_MoveToFunc + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* FT_Outline_LineToFunc */ + /* */ + /* <Description> */ + /* A function pointer type used to describe the signature of a `line */ + /* to' function during outline walking/decomposition. */ + /* */ + /* A `line to' is emitted to indicate a segment in the outline. */ + /* */ + /* <Input> */ + /* to :: A pointer to the target point of the `line to'. */ + /* */ + /* user :: A typeless pointer which is passed from the caller of the */ + /* decomposition function. */ + /* */ + /* <Return> */ + /* Error code. 0 means success. */ + /* */ + typedef int + (*FT_Outline_LineToFunc)( const FT_Vector* to, + void* user ); + +#define FT_Outline_LineTo_Func FT_Outline_LineToFunc + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* FT_Outline_ConicToFunc */ + /* */ + /* <Description> */ + /* A function pointer type use to describe the signature of a `conic */ + /* to' function during outline walking/decomposition. */ + /* */ + /* A `conic to' is emitted to indicate a second-order Bézier arc in */ + /* the outline. */ + /* */ + /* <Input> */ + /* control :: An intermediate control point between the last position */ + /* and the new target in `to'. */ + /* */ + /* to :: A pointer to the target end point of the conic arc. */ + /* */ + /* user :: A typeless pointer which is passed from the caller of */ + /* the decomposition function. */ + /* */ + /* <Return> */ + /* Error code. 0 means success. */ + /* */ + typedef int + (*FT_Outline_ConicToFunc)( const FT_Vector* control, + const FT_Vector* to, + void* user ); + +#define FT_Outline_ConicTo_Func FT_Outline_ConicToFunc + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* FT_Outline_CubicToFunc */ + /* */ + /* <Description> */ + /* A function pointer type used to describe the signature of a `cubic */ + /* to' function during outline walking/decomposition. */ + /* */ + /* A `cubic to' is emitted to indicate a third-order Bézier arc. */ + /* */ + /* <Input> */ + /* control1 :: A pointer to the first Bézier control point. */ + /* */ + /* control2 :: A pointer to the second Bézier control point. */ + /* */ + /* to :: A pointer to the target end point. */ + /* */ + /* user :: A typeless pointer which is passed from the caller of */ + /* the decomposition function. */ + /* */ + /* <Return> */ + /* Error code. 0 means success. */ + /* */ + typedef int + (*FT_Outline_CubicToFunc)( const FT_Vector* control1, + const FT_Vector* control2, + const FT_Vector* to, + void* user ); + +#define FT_Outline_CubicTo_Func FT_Outline_CubicToFunc + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_Outline_Funcs */ + /* */ + /* <Description> */ + /* A structure to hold various function pointers used during outline */ + /* decomposition in order to emit segments, conic, and cubic Béziers, */ + /* as well as `move to' and `close to' operations. */ + /* */ + /* <Fields> */ + /* move_to :: The `move to' emitter. */ + /* */ + /* line_to :: The segment emitter. */ + /* */ + /* conic_to :: The second-order Bézier arc emitter. */ + /* */ + /* cubic_to :: The third-order Bézier arc emitter. */ + /* */ + /* shift :: The shift that is applied to coordinates before they */ + /* are sent to the emitter. */ + /* */ + /* delta :: The delta that is applied to coordinates before they */ + /* are sent to the emitter, but after the shift. */ + /* */ + /* <Note> */ + /* The point coordinates sent to the emitters are the transformed */ + /* version of the original coordinates (this is important for high */ + /* accuracy during scan-conversion). The transformation is simple: */ + /* */ + /* { */ + /* x' = (x << shift) - delta */ + /* y' = (x << shift) - delta */ + /* } */ + /* */ + /* Set the value of `shift' and `delta' to 0 to get the original */ + /* point coordinates. */ + /* */ + typedef struct FT_Outline_Funcs_ + { + FT_Outline_MoveToFunc move_to; + FT_Outline_LineToFunc line_to; + FT_Outline_ConicToFunc conic_to; + FT_Outline_CubicToFunc cubic_to; + + int shift; + FT_Pos delta; + + } FT_Outline_Funcs; + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* basic_types */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Macro> */ + /* FT_IMAGE_TAG */ + /* */ + /* <Description> */ + /* This macro converts four-letter tags to an unsigned long type. */ + /* */ + /* <Note> */ + /* Since many 16bit compilers don't like 32bit enumerations, you */ + /* should redefine this macro in case of problems to something like */ + /* this: */ + /* */ + /* { */ + /* #define FT_IMAGE_TAG( value, _x1, _x2, _x3, _x4 ) value */ + /* } */ + /* */ + /* to get a simple enumeration without assigning special numbers. */ + /* */ +#ifndef FT_IMAGE_TAG +#define FT_IMAGE_TAG( value, _x1, _x2, _x3, _x4 ) \ + value = ( ( (unsigned long)_x1 << 24 ) | \ + ( (unsigned long)_x2 << 16 ) | \ + ( (unsigned long)_x3 << 8 ) | \ + (unsigned long)_x4 ) +#endif /* FT_IMAGE_TAG */ + + + /*************************************************************************/ + /* */ + /* <Enum> */ + /* FT_Glyph_Format */ + /* */ + /* <Description> */ + /* An enumeration type used to describe the format of a given glyph */ + /* image. Note that this version of FreeType only supports two image */ + /* formats, even though future font drivers will be able to register */ + /* their own format. */ + /* */ + /* <Values> */ + /* FT_GLYPH_FORMAT_NONE :: */ + /* The value 0 is reserved. */ + /* */ + /* FT_GLYPH_FORMAT_COMPOSITE :: */ + /* The glyph image is a composite of several other images. This */ + /* format is _only_ used with @FT_LOAD_NO_RECURSE, and is used to */ + /* report compound glyphs (like accented characters). */ + /* */ + /* FT_GLYPH_FORMAT_BITMAP :: */ + /* The glyph image is a bitmap, and can be described as an */ + /* @FT_Bitmap. You generally need to access the `bitmap' field of */ + /* the @FT_GlyphSlotRec structure to read it. */ + /* */ + /* FT_GLYPH_FORMAT_OUTLINE :: */ + /* The glyph image is a vectorial outline made of line segments */ + /* and Bézier arcs; it can be described as an @FT_Outline; you */ + /* generally want to access the `outline' field of the */ + /* @FT_GlyphSlotRec structure to read it. */ + /* */ + /* FT_GLYPH_FORMAT_PLOTTER :: */ + /* The glyph image is a vectorial path with no inside and outside */ + /* contours. Some Type 1 fonts, like those in the Hershey family, */ + /* contain glyphs in this format. These are described as */ + /* @FT_Outline, but FreeType isn't currently capable of rendering */ + /* them correctly. */ + /* */ + typedef enum FT_Glyph_Format_ + { + FT_IMAGE_TAG( FT_GLYPH_FORMAT_NONE, 0, 0, 0, 0 ), + + FT_IMAGE_TAG( FT_GLYPH_FORMAT_COMPOSITE, 'c', 'o', 'm', 'p' ), + FT_IMAGE_TAG( FT_GLYPH_FORMAT_BITMAP, 'b', 'i', 't', 's' ), + FT_IMAGE_TAG( FT_GLYPH_FORMAT_OUTLINE, 'o', 'u', 't', 'l' ), + FT_IMAGE_TAG( FT_GLYPH_FORMAT_PLOTTER, 'p', 'l', 'o', 't' ) + + } FT_Glyph_Format; + + + /*************************************************************************/ + /* */ + /* <Enum> */ + /* ft_glyph_format_xxx */ + /* */ + /* <Description> */ + /* A list of deprecated constants. Use the corresponding */ + /* @FT_Glyph_Format values instead. */ + /* */ + /* <Values> */ + /* ft_glyph_format_none :: See @FT_GLYPH_FORMAT_NONE. */ + /* ft_glyph_format_composite :: See @FT_GLYPH_FORMAT_COMPOSITE. */ + /* ft_glyph_format_bitmap :: See @FT_GLYPH_FORMAT_BITMAP. */ + /* ft_glyph_format_outline :: See @FT_GLYPH_FORMAT_OUTLINE. */ + /* ft_glyph_format_plotter :: See @FT_GLYPH_FORMAT_PLOTTER. */ + /* */ +#define ft_glyph_format_none FT_GLYPH_FORMAT_NONE +#define ft_glyph_format_composite FT_GLYPH_FORMAT_COMPOSITE +#define ft_glyph_format_bitmap FT_GLYPH_FORMAT_BITMAP +#define ft_glyph_format_outline FT_GLYPH_FORMAT_OUTLINE +#define ft_glyph_format_plotter FT_GLYPH_FORMAT_PLOTTER + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** R A S T E R D E F I N I T I O N S *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* A raster is a scan converter, in charge of rendering an outline into */ + /* a a bitmap. This section contains the public API for rasters. */ + /* */ + /* Note that in FreeType 2, all rasters are now encapsulated within */ + /* specific modules called `renderers'. See `freetype/ftrender.h' for */ + /* more details on renderers. */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* raster */ + /* */ + /* <Title> */ + /* Scanline Converter */ + /* */ + /* <Abstract> */ + /* How vectorial outlines are converted into bitmaps and pixmaps. */ + /* */ + /* <Description> */ + /* This section contains technical definitions. */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_Raster */ + /* */ + /* <Description> */ + /* A handle (pointer) to a raster object. Each object can be used */ + /* independently to convert an outline into a bitmap or pixmap. */ + /* */ + typedef struct FT_RasterRec_* FT_Raster; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_Span */ + /* */ + /* <Description> */ + /* A structure used to model a single span of gray (or black) pixels */ + /* when rendering a monochrome or anti-aliased bitmap. */ + /* */ + /* <Fields> */ + /* x :: The span's horizontal start position. */ + /* */ + /* len :: The span's length in pixels. */ + /* */ + /* coverage :: The span color/coverage, ranging from 0 (background) */ + /* to 255 (foreground). Only used for anti-aliased */ + /* rendering. */ + /* */ + /* <Note> */ + /* This structure is used by the span drawing callback type named */ + /* @FT_SpanFunc which takes the y-coordinate of the span as a */ + /* a parameter. */ + /* */ + /* The coverage value is always between 0 and 255. */ + /* */ + typedef struct FT_Span_ + { + short x; + unsigned short len; + unsigned char coverage; + + } FT_Span; + + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* FT_SpanFunc */ + /* */ + /* <Description> */ + /* A function used as a call-back by the anti-aliased renderer in */ + /* order to let client applications draw themselves the gray pixel */ + /* spans on each scan line. */ + /* */ + /* <Input> */ + /* y :: The scanline's y-coordinate. */ + /* */ + /* count :: The number of spans to draw on this scanline. */ + /* */ + /* spans :: A table of `count' spans to draw on the scanline. */ + /* */ + /* user :: User-supplied data that is passed to the callback. */ + /* */ + /* <Note> */ + /* This callback allows client applications to directly render the */ + /* gray spans of the anti-aliased bitmap to any kind of surfaces. */ + /* */ + /* This can be used to write anti-aliased outlines directly to a */ + /* given background bitmap, and even perform translucency. */ + /* */ + /* Note that the `count' field cannot be greater than a fixed value */ + /* defined by the `FT_MAX_GRAY_SPANS' configuration macro in */ + /* `ftoption.h'. By default, this value is set to 32, which means */ + /* that if there are more than 32 spans on a given scanline, the */ + /* callback is called several times with the same `y' parameter in */ + /* order to draw all callbacks. */ + /* */ + /* Otherwise, the callback is only called once per scan-line, and */ + /* only for those scanlines that do have `gray' pixels on them. */ + /* */ + typedef void + (*FT_SpanFunc)( int y, + int count, + const FT_Span* spans, + void* user ); + +#define FT_Raster_Span_Func FT_SpanFunc + + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* FT_Raster_BitTest_Func */ + /* */ + /* <Description> */ + /* THIS TYPE IS DEPRECATED. DO NOT USE IT. */ + /* */ + /* A function used as a call-back by the monochrome scan-converter */ + /* to test whether a given target pixel is already set to the drawing */ + /* `color'. These tests are crucial to implement drop-out control */ + /* per-se the TrueType spec. */ + /* */ + /* <Input> */ + /* y :: The pixel's y-coordinate. */ + /* */ + /* x :: The pixel's x-coordinate. */ + /* */ + /* user :: User-supplied data that is passed to the callback. */ + /* */ + /* <Return> */ + /* 1 if the pixel is `set', 0 otherwise. */ + /* */ + typedef int + (*FT_Raster_BitTest_Func)( int y, + int x, + void* user ); + + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* FT_Raster_BitSet_Func */ + /* */ + /* <Description> */ + /* THIS TYPE IS DEPRECATED. DO NOT USE IT. */ + /* */ + /* A function used as a call-back by the monochrome scan-converter */ + /* to set an individual target pixel. This is crucial to implement */ + /* drop-out control according to the TrueType specification. */ + /* */ + /* <Input> */ + /* y :: The pixel's y-coordinate. */ + /* */ + /* x :: The pixel's x-coordinate. */ + /* */ + /* user :: User-supplied data that is passed to the callback. */ + /* */ + /* <Return> */ + /* 1 if the pixel is `set', 0 otherwise. */ + /* */ + typedef void + (*FT_Raster_BitSet_Func)( int y, + int x, + void* user ); + + + /*************************************************************************/ + /* */ + /* <Enum> */ + /* FT_RASTER_FLAG_XXX */ + /* */ + /* <Description> */ + /* A list of bit flag constants as used in the `flags' field of a */ + /* @FT_Raster_Params structure. */ + /* */ + /* <Values> */ + /* FT_RASTER_FLAG_DEFAULT :: This value is 0. */ + /* */ + /* FT_RASTER_FLAG_AA :: This flag is set to indicate that an */ + /* anti-aliased glyph image should be */ + /* generated. Otherwise, it will be */ + /* monochrome (1-bit). */ + /* */ + /* FT_RASTER_FLAG_DIRECT :: This flag is set to indicate direct */ + /* rendering. In this mode, client */ + /* applications must provide their own span */ + /* callback. This lets them directly */ + /* draw or compose over an existing bitmap. */ + /* If this bit is not set, the target */ + /* pixmap's buffer _must_ be zeroed before */ + /* rendering. */ + /* */ + /* Note that for now, direct rendering is */ + /* only possible with anti-aliased glyphs. */ + /* */ + /* FT_RASTER_FLAG_CLIP :: This flag is only used in direct */ + /* rendering mode. If set, the output will */ + /* be clipped to a box specified in the */ + /* `clip_box' field of the */ + /* @FT_Raster_Params structure. */ + /* */ + /* Note that by default, the glyph bitmap */ + /* is clipped to the target pixmap, except */ + /* in direct rendering mode where all spans */ + /* are generated if no clipping box is set. */ + /* */ +#define FT_RASTER_FLAG_DEFAULT 0x0 +#define FT_RASTER_FLAG_AA 0x1 +#define FT_RASTER_FLAG_DIRECT 0x2 +#define FT_RASTER_FLAG_CLIP 0x4 + + /* deprecated */ +#define ft_raster_flag_default FT_RASTER_FLAG_DEFAULT +#define ft_raster_flag_aa FT_RASTER_FLAG_AA +#define ft_raster_flag_direct FT_RASTER_FLAG_DIRECT +#define ft_raster_flag_clip FT_RASTER_FLAG_CLIP + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_Raster_Params */ + /* */ + /* <Description> */ + /* A structure to hold the arguments used by a raster's render */ + /* function. */ + /* */ + /* <Fields> */ + /* target :: The target bitmap. */ + /* */ + /* source :: A pointer to the source glyph image (e.g., an */ + /* @FT_Outline). */ + /* */ + /* flags :: The rendering flags. */ + /* */ + /* gray_spans :: The gray span drawing callback. */ + /* */ + /* black_spans :: The black span drawing callback. */ + /* */ + /* bit_test :: The bit test callback. UNIMPLEMENTED! */ + /* */ + /* bit_set :: The bit set callback. UNIMPLEMENTED! */ + /* */ + /* user :: User-supplied data that is passed to each drawing */ + /* callback. */ + /* */ + /* clip_box :: An optional clipping box. It is only used in */ + /* direct rendering mode. Note that coordinates here */ + /* should be expressed in _integer_ pixels (and not in */ + /* 26.6 fixed-point units). */ + /* */ + /* <Note> */ + /* An anti-aliased glyph bitmap is drawn if the @FT_RASTER_FLAG_AA */ + /* bit flag is set in the `flags' field, otherwise a monochrome */ + /* bitmap is generated. */ + /* */ + /* If the @FT_RASTER_FLAG_DIRECT bit flag is set in `flags', the */ + /* raster will call the `gray_spans' callback to draw gray pixel */ + /* spans, in the case of an aa glyph bitmap, it will call */ + /* `black_spans', and `bit_test' and `bit_set' in the case of a */ + /* monochrome bitmap. This allows direct composition over a */ + /* pre-existing bitmap through user-provided callbacks to perform the */ + /* span drawing/composition. */ + /* */ + /* Note that the `bit_test' and `bit_set' callbacks are required when */ + /* rendering a monochrome bitmap, as they are crucial to implement */ + /* correct drop-out control as defined in the TrueType specification. */ + /* */ + typedef struct FT_Raster_Params_ + { + const FT_Bitmap* target; + const void* source; + int flags; + FT_SpanFunc gray_spans; + FT_SpanFunc black_spans; + FT_Raster_BitTest_Func bit_test; /* doesn't work! */ + FT_Raster_BitSet_Func bit_set; /* doesn't work! */ + void* user; + FT_BBox clip_box; + + } FT_Raster_Params; + + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* FT_Raster_NewFunc */ + /* */ + /* <Description> */ + /* A function used to create a new raster object. */ + /* */ + /* <Input> */ + /* memory :: A handle to the memory allocator. */ + /* */ + /* <Output> */ + /* raster :: A handle to the new raster object. */ + /* */ + /* <Return> */ + /* Error code. 0 means success. */ + /* */ + /* <Note> */ + /* The `memory' parameter is a typeless pointer in order to avoid */ + /* un-wanted dependencies on the rest of the FreeType code. In */ + /* practice, it is an @FT_Memory object, i.e., a handle to the */ + /* standard FreeType memory allocator. However, this field can be */ + /* completely ignored by a given raster implementation. */ + /* */ + typedef int + (*FT_Raster_NewFunc)( void* memory, + FT_Raster* raster ); + +#define FT_Raster_New_Func FT_Raster_NewFunc + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* FT_Raster_DoneFunc */ + /* */ + /* <Description> */ + /* A function used to destroy a given raster object. */ + /* */ + /* <Input> */ + /* raster :: A handle to the raster object. */ + /* */ + typedef void + (*FT_Raster_DoneFunc)( FT_Raster raster ); + +#define FT_Raster_Done_Func FT_Raster_DoneFunc + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* FT_Raster_ResetFunc */ + /* */ + /* <Description> */ + /* FreeType provides an area of memory called the `render pool', */ + /* available to all registered rasters. This pool can be freely used */ + /* during a given scan-conversion but is shared by all rasters. Its */ + /* content is thus transient. */ + /* */ + /* This function is called each time the render pool changes, or just */ + /* after a new raster object is created. */ + /* */ + /* <Input> */ + /* raster :: A handle to the new raster object. */ + /* */ + /* pool_base :: The address in memory of the render pool. */ + /* */ + /* pool_size :: The size in bytes of the render pool. */ + /* */ + /* <Note> */ + /* Rasters can ignore the render pool and rely on dynamic memory */ + /* allocation if they want to (a handle to the memory allocator is */ + /* passed to the raster constructor). However, this is not */ + /* recommended for efficiency purposes. */ + /* */ + typedef void + (*FT_Raster_ResetFunc)( FT_Raster raster, + unsigned char* pool_base, + unsigned long pool_size ); + +#define FT_Raster_Reset_Func FT_Raster_ResetFunc + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* FT_Raster_SetModeFunc */ + /* */ + /* <Description> */ + /* This function is a generic facility to change modes or attributes */ + /* in a given raster. This can be used for debugging purposes, or */ + /* simply to allow implementation-specific `features' in a given */ + /* raster module. */ + /* */ + /* <Input> */ + /* raster :: A handle to the new raster object. */ + /* */ + /* mode :: A 4-byte tag used to name the mode or property. */ + /* */ + /* args :: A pointer to the new mode/property to use. */ + /* */ + typedef int + (*FT_Raster_SetModeFunc)( FT_Raster raster, + unsigned long mode, + void* args ); + +#define FT_Raster_Set_Mode_Func FT_Raster_SetModeFunc + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* FT_Raster_RenderFunc */ + /* */ + /* <Description> */ + /* Invokes a given raster to scan-convert a given glyph image into a */ + /* target bitmap. */ + /* */ + /* <Input> */ + /* raster :: A handle to the raster object. */ + /* */ + /* params :: A pointer to an @FT_Raster_Params structure used to */ + /* store the rendering parameters. */ + /* */ + /* <Return> */ + /* Error code. 0 means success. */ + /* */ + /* <Note> */ + /* The exact format of the source image depends on the raster's glyph */ + /* format defined in its @FT_Raster_Funcs structure. It can be an */ + /* @FT_Outline or anything else in order to support a large array of */ + /* glyph formats. */ + /* */ + /* Note also that the render function can fail and return a */ + /* `FT_Err_Unimplemented_Feature' error code if the raster used does */ + /* not support direct composition. */ + /* */ + /* XXX: For now, the standard raster doesn't support direct */ + /* composition but this should change for the final release (see */ + /* the files `demos/src/ftgrays.c' and `demos/src/ftgrays2.c' */ + /* for examples of distinct implementations which support direct */ + /* composition). */ + /* */ + typedef int + (*FT_Raster_RenderFunc)( FT_Raster raster, + const FT_Raster_Params* params ); + +#define FT_Raster_Render_Func FT_Raster_RenderFunc + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_Raster_Funcs */ + /* */ + /* <Description> */ + /* A structure used to describe a given raster class to the library. */ + /* */ + /* <Fields> */ + /* glyph_format :: The supported glyph format for this raster. */ + /* */ + /* raster_new :: The raster constructor. */ + /* */ + /* raster_reset :: Used to reset the render pool within the raster. */ + /* */ + /* raster_render :: A function to render a glyph into a given bitmap. */ + /* */ + /* raster_done :: The raster destructor. */ + /* */ + typedef struct FT_Raster_Funcs_ + { + FT_Glyph_Format glyph_format; + FT_Raster_NewFunc raster_new; + FT_Raster_ResetFunc raster_reset; + FT_Raster_SetModeFunc raster_set_mode; + FT_Raster_RenderFunc raster_render; + FT_Raster_DoneFunc raster_done; + + } FT_Raster_Funcs; + + + /* */ + + +FT_END_HEADER + +#endif /* __FTIMAGE_H__ */ + + +/* END */ + + +/* Local Variables: */ +/* coding: utf-8 */ +/* End: */ diff --git a/include/freetype/ftincrem.h b/include/freetype/ftincrem.h new file mode 100644 index 0000000..46bc8bd --- /dev/null +++ b/include/freetype/ftincrem.h @@ -0,0 +1,331 @@ +/***************************************************************************/ +/* */ +/* ftincrem.h */ +/* */ +/* FreeType incremental loading (specification). */ +/* */ +/* Copyright 2002, 2003, 2006, 2007 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef __FTINCREM_H__ +#define __FTINCREM_H__ + +#include <ft2build.h> +#include FT_FREETYPE_H + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + /*************************************************************************** + * + * @section: + * incremental + * + * @title: + * Incremental Loading + * + * @abstract: + * Custom Glyph Loading. + * + * @description: + * This section contains various functions used to perform so-called + * `incremental' glyph loading. This is a mode where all glyphs loaded + * from a given @FT_Face are provided by the client application, + * + * Apart from that, all other tables are loaded normally from the font + * file. This mode is useful when FreeType is used within another + * engine, e.g., a Postscript Imaging Processor. + * + * To enable this mode, you must use @FT_Open_Face, passing an + * @FT_Parameter with the @FT_PARAM_TAG_INCREMENTAL tag and an + * @FT_Incremental_Interface value. See the comments for + * @FT_Incremental_InterfaceRec for an example. + * + */ + + + /*************************************************************************** + * + * @type: + * FT_Incremental + * + * @description: + * An opaque type describing a user-provided object used to implement + * `incremental' glyph loading within FreeType. This is used to support + * embedded fonts in certain environments (e.g., Postscript interpreters), + * where the glyph data isn't in the font file, or must be overridden by + * different values. + * + * @note: + * It is up to client applications to create and implement @FT_Incremental + * objects, as long as they provide implementations for the methods + * @FT_Incremental_GetGlyphDataFunc, @FT_Incremental_FreeGlyphDataFunc + * and @FT_Incremental_GetGlyphMetricsFunc. + * + * See the description of @FT_Incremental_InterfaceRec to understand how + * to use incremental objects with FreeType. + */ + typedef struct FT_IncrementalRec_* FT_Incremental; + + + /*************************************************************************** + * + * @struct: + * FT_Incremental_Metrics + * + * @description: + * A small structure used to contain the basic glyph metrics returned + * by the @FT_Incremental_GetGlyphMetricsFunc method. + * + * @fields: + * bearing_x :: + * Left bearing, in font units. + * + * bearing_y :: + * Top bearing, in font units. + * + * advance :: + * Glyph advance, in font units. + * + * @note: + * These correspond to horizontal or vertical metrics depending on the + * value of the `vertical' argument to the function + * @FT_Incremental_GetGlyphMetricsFunc. + */ + typedef struct FT_Incremental_MetricsRec_ + { + FT_Long bearing_x; + FT_Long bearing_y; + FT_Long advance; + + } FT_Incremental_MetricsRec, *FT_Incremental_Metrics; + + + /*************************************************************************** + * + * @type: + * FT_Incremental_GetGlyphDataFunc + * + * @description: + * A function called by FreeType to access a given glyph's data bytes + * during @FT_Load_Glyph or @FT_Load_Char if incremental loading is + * enabled. + * + * Note that the format of the glyph's data bytes depends on the font + * file format. For TrueType, it must correspond to the raw bytes within + * the `glyf' table. For Postscript formats, it must correspond to the + * *unencrypted* charstring bytes, without any `lenIV' header. It is + * undefined for any other format. + * + * @input: + * incremental :: + * Handle to an opaque @FT_Incremental handle provided by the client + * application. + * + * glyph_index :: + * Index of relevant glyph. + * + * @output: + * adata :: + * A structure describing the returned glyph data bytes (which will be + * accessed as a read-only byte block). + * + * @return: + * FreeType error code. 0 means success. + * + * @note: + * If this function returns successfully the method + * @FT_Incremental_FreeGlyphDataFunc will be called later to release + * the data bytes. + * + * Nested calls to @FT_Incremental_GetGlyphDataFunc can happen for + * compound glyphs. + */ + typedef FT_Error + (*FT_Incremental_GetGlyphDataFunc)( FT_Incremental incremental, + FT_UInt glyph_index, + FT_Data* adata ); + + + /*************************************************************************** + * + * @type: + * FT_Incremental_FreeGlyphDataFunc + * + * @description: + * A function used to release the glyph data bytes returned by a + * successful call to @FT_Incremental_GetGlyphDataFunc. + * + * @input: + * incremental :: + * A handle to an opaque @FT_Incremental handle provided by the client + * application. + * + * data :: + * A structure describing the glyph data bytes (which will be accessed + * as a read-only byte block). + */ + typedef void + (*FT_Incremental_FreeGlyphDataFunc)( FT_Incremental incremental, + FT_Data* data ); + + + /*************************************************************************** + * + * @type: + * FT_Incremental_GetGlyphMetricsFunc + * + * @description: + * A function used to retrieve the basic metrics of a given glyph index + * before accessing its data. This is necessary because, in certain + * formats like TrueType, the metrics are stored in a different place from + * the glyph images proper. + * + * @input: + * incremental :: + * A handle to an opaque @FT_Incremental handle provided by the client + * application. + * + * glyph_index :: + * Index of relevant glyph. + * + * vertical :: + * If true, return vertical metrics. + * + * ametrics :: + * This parameter is used for both input and output. + * The original glyph metrics, if any, in font units. If metrics are + * not available all the values must be set to zero. + * + * @output: + * ametrics :: + * The replacement glyph metrics in font units. + * + */ + typedef FT_Error + (*FT_Incremental_GetGlyphMetricsFunc) + ( FT_Incremental incremental, + FT_UInt glyph_index, + FT_Bool vertical, + FT_Incremental_MetricsRec *ametrics ); + + + /************************************************************************** + * + * @struct: + * FT_Incremental_FuncsRec + * + * @description: + * A table of functions for accessing fonts that load data + * incrementally. Used in @FT_Incremental_InterfaceRec. + * + * @fields: + * get_glyph_data :: + * The function to get glyph data. Must not be null. + * + * free_glyph_data :: + * The function to release glyph data. Must not be null. + * + * get_glyph_metrics :: + * The function to get glyph metrics. May be null if the font does + * not provide overriding glyph metrics. + */ + typedef struct FT_Incremental_FuncsRec_ + { + FT_Incremental_GetGlyphDataFunc get_glyph_data; + FT_Incremental_FreeGlyphDataFunc free_glyph_data; + FT_Incremental_GetGlyphMetricsFunc get_glyph_metrics; + + } FT_Incremental_FuncsRec; + + + /*************************************************************************** + * + * @struct: + * FT_Incremental_InterfaceRec + * + * @description: + * A structure to be used with @FT_Open_Face to indicate that the user + * wants to support incremental glyph loading. You should use it with + * @FT_PARAM_TAG_INCREMENTAL as in the following example: + * + * { + * FT_Incremental_InterfaceRec inc_int; + * FT_Parameter parameter; + * FT_Open_Args open_args; + * + * + * // set up incremental descriptor + * inc_int.funcs = my_funcs; + * inc_int.object = my_object; + * + * // set up optional parameter + * parameter.tag = FT_PARAM_TAG_INCREMENTAL; + * parameter.data = &inc_int; + * + * // set up FT_Open_Args structure + * open_args.flags = FT_OPEN_PATHNAME | FT_OPEN_PARAMS; + * open_args.pathname = my_font_pathname; + * open_args.num_params = 1; + * open_args.params = ¶meter; // we use one optional argument + * + * // open the font + * error = FT_Open_Face( library, &open_args, index, &face ); + * ... + * } + */ + typedef struct FT_Incremental_InterfaceRec_ + { + const FT_Incremental_FuncsRec* funcs; + FT_Incremental object; + + } FT_Incremental_InterfaceRec; + + + /*************************************************************************** + * + * @type: + * FT_Incremental_Interface + * + * @description: + * A pointer to an @FT_Incremental_InterfaceRec structure. + * + */ + typedef FT_Incremental_InterfaceRec* FT_Incremental_Interface; + + + /*************************************************************************** + * + * @constant: + * FT_PARAM_TAG_INCREMENTAL + * + * @description: + * A constant used as the tag of @FT_Parameter structures to indicate + * an incremental loading object to be used by FreeType. + * + */ +#define FT_PARAM_TAG_INCREMENTAL FT_MAKE_TAG( 'i', 'n', 'c', 'r' ) + + /* */ + +FT_END_HEADER + +#endif /* __FTINCREM_H__ */ + + +/* END */ diff --git a/include/freetype/ftlcdfil.h b/include/freetype/ftlcdfil.h new file mode 100644 index 0000000..9a61377 --- /dev/null +++ b/include/freetype/ftlcdfil.h @@ -0,0 +1,166 @@ +/***************************************************************************/ +/* */ +/* ftlcdfil.h */ +/* */ +/* FreeType API for color filtering of subpixel bitmap glyphs */ +/* (specification). */ +/* */ +/* Copyright 2006, 2007 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef __FT_LCD_FILTER_H__ +#define __FT_LCD_FILTER_H__ + +#include <ft2build.h> +#include FT_FREETYPE_H + + +FT_BEGIN_HEADER + + /*************************************************************************** + * + * @section: + * lcd_filtering + * + * @title: + * LCD Filtering + * + * @abstract: + * Reduce color fringes of LCD-optimized bitmaps. + * + * @description: + * The @FT_Library_SetLcdFilter API can be used to specify a low-pass + * filter which is then applied to LCD-optimized bitmaps generated + * through @FT_Render_Glyph. This is useful to reduce color fringes + * which would occur with unfiltered rendering. + * + * Note that no filter is active by default, and that this function is + * *not* implemented in default builds of the library. You need to + * #define FT_CONFIG_OPTION_SUBPIXEL_RENDERING in your `ftoption.h' file + * in order to activate it. + */ + + + /**************************************************************************** + * + * @func: + * FT_LcdFilter + * + * @description: + * A list of values to identify various types of LCD filters. + * + * @values: + * FT_LCD_FILTER_NONE :: + * Do not perform filtering. When used with subpixel rendering, this + * results in sometimes severe color fringes. + * + * FT_LCD_FILTER_DEFAULT :: + * The default filter reduces color fringes considerably, at the cost + * of a slight blurriness in the output. + * + * FT_LCD_FILTER_LIGHT :: + * The light filter is a variant that produces less blurriness at the + * cost of slightly more color fringes than the default one. It might + * be better, depending on taste, your monitor, or your personal vision. + * + * FT_LCD_FILTER_LEGACY :: + * This filter corresponds to the original libXft color filter. It + * provides high contrast output but can exhibit really bad color + * fringes if glyphs are not extremely well hinted to the pixel grid. + * In other words, it only works well if the TrueType bytecode + * interpreter is enabled *and* high-quality hinted fonts are used. + * + * This filter is only provided for comparison purposes, and might be + * disabled or stay unsupported in the future. + * + * @since: + * 2.3.0 + */ + typedef enum + { + FT_LCD_FILTER_NONE = 0, + FT_LCD_FILTER_DEFAULT = 1, + FT_LCD_FILTER_LIGHT = 2, + FT_LCD_FILTER_LEGACY = 16, + + FT_LCD_FILTER_MAX /* do not remove */ + + } FT_LcdFilter; + + + /************************************************************************** + * + * @func: + * FT_Library_SetLcdFilter + * + * @description: + * This function is used to apply color filtering to LCD decimated + * bitmaps, like the ones used when calling @FT_Render_Glyph with + * @FT_RENDER_MODE_LCD or @FT_RENDER_MODE_LCD_V. + * + * @input: + * library :: + * A handle to the target library instance. + * + * filter :: + * The filter type. + * + * You can use @FT_LCD_FILTER_NONE here to disable this feature, or + * @FT_LCD_FILTER_DEFAULT to use a default filter that should work + * well on most LCD screens. + * + * @return: + * FreeType error code. 0 means success. + * + * @note: + * This feature is always disabled by default. Clients must make an + * explicit call to this function with a `filter' value other than + * @FT_LCD_FILTER_NONE in order to enable it. + * + * Due to *PATENTS* covering subpixel rendering, this function doesn't + * do anything except returning `FT_Err_Unimplemented_Feature' if the + * configuration macro FT_CONFIG_OPTION_SUBPIXEL_RENDERING is not + * defined in your build of the library, which should correspond to all + * default builds of FreeType. + * + * The filter affects glyph bitmaps rendered through @FT_Render_Glyph, + * @FT_Outline_Get_Bitmap, @FT_Load_Glyph, and @FT_Load_Char. + * + * It does _not_ affect the output of @FT_Outline_Render and + * @FT_Outline_Get_Bitmap. + * + * If this feature is activated, the dimensions of LCD glyph bitmaps are + * either larger or taller than the dimensions of the corresponding + * outline with regards to the pixel grid. For example, for + * @FT_RENDER_MODE_LCD, the filter adds up to 3 pixels to the left, and + * up to 3 pixels to the right. + * + * The bitmap offset values are adjusted correctly, so clients shouldn't + * need to modify their layout and glyph positioning code when enabling + * the filter. + * + * @since: + * 2.3.0 + */ + FT_EXPORT( FT_Error ) + FT_Library_SetLcdFilter( FT_Library library, + FT_LcdFilter filter ); + + /* */ + + +FT_END_HEADER + +#endif /* __FT_LCD_FILTER_H__ */ + + +/* END */ diff --git a/include/freetype/ftlist.h b/include/freetype/ftlist.h new file mode 100644 index 0000000..f3223ee --- /dev/null +++ b/include/freetype/ftlist.h @@ -0,0 +1,273 @@ +/***************************************************************************/ +/* */ +/* ftlist.h */ +/* */ +/* Generic list support for FreeType (specification). */ +/* */ +/* Copyright 1996-2001, 2003, 2007 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + + /*************************************************************************/ + /* */ + /* This file implements functions relative to list processing. Its */ + /* data structures are defined in `freetype.h'. */ + /* */ + /*************************************************************************/ + + +#ifndef __FTLIST_H__ +#define __FTLIST_H__ + + +#include <ft2build.h> +#include FT_FREETYPE_H + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* list_processing */ + /* */ + /* <Title> */ + /* List Processing */ + /* */ + /* <Abstract> */ + /* Simple management of lists. */ + /* */ + /* <Description> */ + /* This section contains various definitions related to list */ + /* processing using doubly-linked nodes. */ + /* */ + /* <Order> */ + /* FT_List */ + /* FT_ListNode */ + /* FT_ListRec */ + /* FT_ListNodeRec */ + /* */ + /* FT_List_Add */ + /* FT_List_Insert */ + /* FT_List_Find */ + /* FT_List_Remove */ + /* FT_List_Up */ + /* FT_List_Iterate */ + /* FT_List_Iterator */ + /* FT_List_Finalize */ + /* FT_List_Destructor */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_List_Find */ + /* */ + /* <Description> */ + /* Finds the list node for a given listed object. */ + /* */ + /* <Input> */ + /* list :: A pointer to the parent list. */ + /* data :: The address of the listed object. */ + /* */ + /* <Return> */ + /* List node. NULL if it wasn't found. */ + /* */ + FT_EXPORT( FT_ListNode ) + FT_List_Find( FT_List list, + void* data ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_List_Add */ + /* */ + /* <Description> */ + /* Appends an element to the end of a list. */ + /* */ + /* <InOut> */ + /* list :: A pointer to the parent list. */ + /* node :: The node to append. */ + /* */ + FT_EXPORT( void ) + FT_List_Add( FT_List list, + FT_ListNode node ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_List_Insert */ + /* */ + /* <Description> */ + /* Inserts an element at the head of a list. */ + /* */ + /* <InOut> */ + /* list :: A pointer to parent list. */ + /* node :: The node to insert. */ + /* */ + FT_EXPORT( void ) + FT_List_Insert( FT_List list, + FT_ListNode node ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_List_Remove */ + /* */ + /* <Description> */ + /* Removes a node from a list. This function doesn't check whether */ + /* the node is in the list! */ + /* */ + /* <Input> */ + /* node :: The node to remove. */ + /* */ + /* <InOut> */ + /* list :: A pointer to the parent list. */ + /* */ + FT_EXPORT( void ) + FT_List_Remove( FT_List list, + FT_ListNode node ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_List_Up */ + /* */ + /* <Description> */ + /* Moves a node to the head/top of a list. Used to maintain LRU */ + /* lists. */ + /* */ + /* <InOut> */ + /* list :: A pointer to the parent list. */ + /* node :: The node to move. */ + /* */ + FT_EXPORT( void ) + FT_List_Up( FT_List list, + FT_ListNode node ); + + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* FT_List_Iterator */ + /* */ + /* <Description> */ + /* An FT_List iterator function which is called during a list parse */ + /* by @FT_List_Iterate. */ + /* */ + /* <Input> */ + /* node :: The current iteration list node. */ + /* */ + /* user :: A typeless pointer passed to @FT_List_Iterate. */ + /* Can be used to point to the iteration's state. */ + /* */ + typedef FT_Error + (*FT_List_Iterator)( FT_ListNode node, + void* user ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_List_Iterate */ + /* */ + /* <Description> */ + /* Parses a list and calls a given iterator function on each element. */ + /* Note that parsing is stopped as soon as one of the iterator calls */ + /* returns a non-zero value. */ + /* */ + /* <Input> */ + /* list :: A handle to the list. */ + /* iterator :: An iterator function, called on each node of the list. */ + /* user :: A user-supplied field which is passed as the second */ + /* argument to the iterator. */ + /* */ + /* <Return> */ + /* The result (a FreeType error code) of the last iterator call. */ + /* */ + FT_EXPORT( FT_Error ) + FT_List_Iterate( FT_List list, + FT_List_Iterator iterator, + void* user ); + + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* FT_List_Destructor */ + /* */ + /* <Description> */ + /* An @FT_List iterator function which is called during a list */ + /* finalization by @FT_List_Finalize to destroy all elements in a */ + /* given list. */ + /* */ + /* <Input> */ + /* system :: The current system object. */ + /* */ + /* data :: The current object to destroy. */ + /* */ + /* user :: A typeless pointer passed to @FT_List_Iterate. It can */ + /* be used to point to the iteration's state. */ + /* */ + typedef void + (*FT_List_Destructor)( FT_Memory memory, + void* data, + void* user ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_List_Finalize */ + /* */ + /* <Description> */ + /* Destroys all elements in the list as well as the list itself. */ + /* */ + /* <Input> */ + /* list :: A handle to the list. */ + /* */ + /* destroy :: A list destructor that will be applied to each element */ + /* of the list. */ + /* */ + /* memory :: The current memory object which handles deallocation. */ + /* */ + /* user :: A user-supplied field which is passed as the last */ + /* argument to the destructor. */ + /* */ + FT_EXPORT( void ) + FT_List_Finalize( FT_List list, + FT_List_Destructor destroy, + FT_Memory memory, + void* user ); + + + /* */ + + +FT_END_HEADER + +#endif /* __FTLIST_H__ */ + + +/* END */ diff --git a/include/freetype/ftlzw.h b/include/freetype/ftlzw.h new file mode 100644 index 0000000..d950653 --- /dev/null +++ b/include/freetype/ftlzw.h @@ -0,0 +1,99 @@ +/***************************************************************************/ +/* */ +/* ftlzw.h */ +/* */ +/* LZW-compressed stream support. */ +/* */ +/* Copyright 2004, 2006 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef __FTLZW_H__ +#define __FTLZW_H__ + +#include <ft2build.h> +#include FT_FREETYPE_H + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + /*************************************************************************/ + /* */ + /* <Section> */ + /* lzw */ + /* */ + /* <Title> */ + /* LZW Streams */ + /* */ + /* <Abstract> */ + /* Using LZW-compressed font files. */ + /* */ + /* <Description> */ + /* This section contains the declaration of LZW-specific functions. */ + /* */ + /*************************************************************************/ + + /************************************************************************ + * + * @function: + * FT_Stream_OpenLZW + * + * @description: + * Open a new stream to parse LZW-compressed font files. This is + * mainly used to support the compressed `*.pcf.Z' fonts that come + * with XFree86. + * + * @input: + * stream :: The target embedding stream. + * + * source :: The source stream. + * + * @return: + * FreeType error code. 0 means success. + * + * @note: + * The source stream must be opened _before_ calling this function. + * + * Calling the internal function `FT_Stream_Close' on the new stream will + * *not* call `FT_Stream_Close' on the source stream. None of the stream + * objects will be released to the heap. + * + * The stream implementation is very basic and resets the decompression + * process each time seeking backwards is needed within the stream + * + * In certain builds of the library, LZW compression recognition is + * automatically handled when calling @FT_New_Face or @FT_Open_Face. + * This means that if no font driver is capable of handling the raw + * compressed file, the library will try to open a LZW stream from it + * and re-open the face with it. + * + * This function may return `FT_Err_Unimplemented_Feature' if your build + * of FreeType was not compiled with LZW support. + */ + FT_EXPORT( FT_Error ) + FT_Stream_OpenLZW( FT_Stream stream, + FT_Stream source ); + + /* */ + + +FT_END_HEADER + +#endif /* __FTLZW_H__ */ + + +/* END */ diff --git a/include/freetype/ftmac.h b/include/freetype/ftmac.h new file mode 100644 index 0000000..3c6fafe --- /dev/null +++ b/include/freetype/ftmac.h @@ -0,0 +1,272 @@ +/***************************************************************************/ +/* */ +/* ftmac.h */ +/* */ +/* Additional Mac-specific API. */ +/* */ +/* Copyright 1996-2001, 2004, 2006, 2007 by */ +/* Just van Rossum, David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +/***************************************************************************/ +/* */ +/* NOTE: Include this file after <freetype/freetype.h> and after the */ +/* Mac-specific <Types.h> header (or any other Mac header that */ +/* includes <Types.h>); we use Handle type. */ +/* */ +/***************************************************************************/ + + +#ifndef __FTMAC_H__ +#define __FTMAC_H__ + + +#include <ft2build.h> + + +FT_BEGIN_HEADER + + +/* gcc-3.4.1 and later can warn about functions tagged as deprecated */ +#ifndef FT_DEPRECATED_ATTRIBUTE +#if defined(__GNUC__) && \ + ((__GNUC__ >= 4) || ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 1))) +#define FT_DEPRECATED_ATTRIBUTE __attribute__((deprecated)) +#else +#define FT_DEPRECATED_ATTRIBUTE +#endif +#endif + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* mac_specific */ + /* */ + /* <Title> */ + /* Mac Specific Interface */ + /* */ + /* <Abstract> */ + /* Only available on the Macintosh. */ + /* */ + /* <Description> */ + /* The following definitions are only available if FreeType is */ + /* compiled on a Macintosh. */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_New_Face_From_FOND */ + /* */ + /* <Description> */ + /* Create a new face object from a FOND resource. */ + /* */ + /* <InOut> */ + /* library :: A handle to the library resource. */ + /* */ + /* <Input> */ + /* fond :: A FOND resource. */ + /* */ + /* face_index :: Only supported for the -1 `sanity check' special */ + /* case. */ + /* */ + /* <Output> */ + /* aface :: A handle to a new face object. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Notes> */ + /* This function can be used to create @FT_Face objects from fonts */ + /* that are installed in the system as follows. */ + /* */ + /* { */ + /* fond = GetResource( 'FOND', fontName ); */ + /* error = FT_New_Face_From_FOND( library, fond, 0, &face ); */ + /* } */ + /* */ + FT_EXPORT( FT_Error ) + FT_New_Face_From_FOND( FT_Library library, + Handle fond, + FT_Long face_index, + FT_Face *aface ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_GetFile_From_Mac_Name */ + /* */ + /* <Description> */ + /* Return an FSSpec for the disk file containing the named font. */ + /* */ + /* <Input> */ + /* fontName :: Mac OS name of the font (e.g., Times New Roman */ + /* Bold). */ + /* */ + /* <Output> */ + /* pathSpec :: FSSpec to the file. For passing to */ + /* @FT_New_Face_From_FSSpec. */ + /* */ + /* face_index :: Index of the face. For passing to */ + /* @FT_New_Face_From_FSSpec. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_EXPORT( FT_Error ) + FT_GetFile_From_Mac_Name( const char* fontName, + FSSpec* pathSpec, + FT_Long* face_index ) + FT_DEPRECATED_ATTRIBUTE; + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_GetFile_From_Mac_ATS_Name */ + /* */ + /* <Description> */ + /* Return an FSSpec for the disk file containing the named font. */ + /* */ + /* <Input> */ + /* fontName :: Mac OS name of the font in ATS framework. */ + /* */ + /* <Output> */ + /* pathSpec :: FSSpec to the file. For passing to */ + /* @FT_New_Face_From_FSSpec. */ + /* */ + /* face_index :: Index of the face. For passing to */ + /* @FT_New_Face_From_FSSpec. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_EXPORT( FT_Error ) + FT_GetFile_From_Mac_ATS_Name( const char* fontName, + FSSpec* pathSpec, + FT_Long* face_index ) + FT_DEPRECATED_ATTRIBUTE; + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_GetFilePath_From_Mac_ATS_Name */ + /* */ + /* <Description> */ + /* Return a pathname of the disk file and face index for given font */ + /* name which is handled by ATS framework. */ + /* */ + /* <Input> */ + /* fontName :: Mac OS name of the font in ATS framework. */ + /* */ + /* <Output> */ + /* path :: Buffer to store pathname of the file. For passing */ + /* to @FT_New_Face. The client must allocate this */ + /* buffer before calling this function. */ + /* */ + /* maxPathSize :: Lengths of the buffer `path' that client allocated. */ + /* */ + /* face_index :: Index of the face. For passing to @FT_New_Face. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_EXPORT( FT_Error ) + FT_GetFilePath_From_Mac_ATS_Name( const char* fontName, + UInt8* path, + UInt32 maxPathSize, + FT_Long* face_index ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_New_Face_From_FSSpec */ + /* */ + /* <Description> */ + /* Create a new face object from a given resource and typeface index */ + /* using an FSSpec to the font file. */ + /* */ + /* <InOut> */ + /* library :: A handle to the library resource. */ + /* */ + /* <Input> */ + /* spec :: FSSpec to the font file. */ + /* */ + /* face_index :: The index of the face within the resource. The */ + /* first face has index 0. */ + /* <Output> */ + /* aface :: A handle to a new face object. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* @FT_New_Face_From_FSSpec is identical to @FT_New_Face except */ + /* it accepts an FSSpec instead of a path. */ + /* */ + FT_EXPORT( FT_Error ) + FT_New_Face_From_FSSpec( FT_Library library, + const FSSpec *spec, + FT_Long face_index, + FT_Face *aface ) + FT_DEPRECATED_ATTRIBUTE; + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_New_Face_From_FSRef */ + /* */ + /* <Description> */ + /* Create a new face object from a given resource and typeface index */ + /* using an FSRef to the font file. */ + /* */ + /* <InOut> */ + /* library :: A handle to the library resource. */ + /* */ + /* <Input> */ + /* spec :: FSRef to the font file. */ + /* */ + /* face_index :: The index of the face within the resource. The */ + /* first face has index 0. */ + /* <Output> */ + /* aface :: A handle to a new face object. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* @FT_New_Face_From_FSRef is identical to @FT_New_Face except */ + /* it accepts an FSRef instead of a path. */ + /* */ + FT_EXPORT( FT_Error ) + FT_New_Face_From_FSRef( FT_Library library, + const FSRef *ref, + FT_Long face_index, + FT_Face *aface ) + FT_DEPRECATED_ATTRIBUTE; + + /* */ + + +FT_END_HEADER + + +#endif /* __FTMAC_H__ */ + + +/* END */ diff --git a/include/freetype/ftmm.h b/include/freetype/ftmm.h new file mode 100644 index 0000000..a9ccfe7 --- /dev/null +++ b/include/freetype/ftmm.h @@ -0,0 +1,378 @@ +/***************************************************************************/ +/* */ +/* ftmm.h */ +/* */ +/* FreeType Multiple Master font interface (specification). */ +/* */ +/* Copyright 1996-2001, 2003, 2004, 2006 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef __FTMM_H__ +#define __FTMM_H__ + + +#include <ft2build.h> +#include FT_TYPE1_TABLES_H + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* multiple_masters */ + /* */ + /* <Title> */ + /* Multiple Masters */ + /* */ + /* <Abstract> */ + /* How to manage Multiple Masters fonts. */ + /* */ + /* <Description> */ + /* The following types and functions are used to manage Multiple */ + /* Master fonts, i.e., the selection of specific design instances by */ + /* setting design axis coordinates. */ + /* */ + /* George Williams has extended this interface to make it work with */ + /* both Type 1 Multiple Masters fonts and GX distortable (var) */ + /* fonts. Some of these routines only work with MM fonts, others */ + /* will work with both types. They are similar enough that a */ + /* consistent interface makes sense. */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_MM_Axis */ + /* */ + /* <Description> */ + /* A simple structure used to model a given axis in design space for */ + /* Multiple Masters fonts. */ + /* */ + /* This structure can't be used for GX var fonts. */ + /* */ + /* <Fields> */ + /* name :: The axis's name. */ + /* */ + /* minimum :: The axis's minimum design coordinate. */ + /* */ + /* maximum :: The axis's maximum design coordinate. */ + /* */ + typedef struct FT_MM_Axis_ + { + FT_String* name; + FT_Long minimum; + FT_Long maximum; + + } FT_MM_Axis; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_Multi_Master */ + /* */ + /* <Description> */ + /* A structure used to model the axes and space of a Multiple Masters */ + /* font. */ + /* */ + /* This structure can't be used for GX var fonts. */ + /* */ + /* <Fields> */ + /* num_axis :: Number of axes. Cannot exceed 4. */ + /* */ + /* num_designs :: Number of designs; should be normally 2^num_axis */ + /* even though the Type 1 specification strangely */ + /* allows for intermediate designs to be present. This */ + /* number cannot exceed 16. */ + /* */ + /* axis :: A table of axis descriptors. */ + /* */ + typedef struct FT_Multi_Master_ + { + FT_UInt num_axis; + FT_UInt num_designs; + FT_MM_Axis axis[T1_MAX_MM_AXIS]; + + } FT_Multi_Master; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_Var_Axis */ + /* */ + /* <Description> */ + /* A simple structure used to model a given axis in design space for */ + /* Multiple Masters and GX var fonts. */ + /* */ + /* <Fields> */ + /* name :: The axis's name. */ + /* Not always meaningful for GX. */ + /* */ + /* minimum :: The axis's minimum design coordinate. */ + /* */ + /* def :: The axis's default design coordinate. */ + /* FreeType computes meaningful default values for MM; it */ + /* is then an integer value, not in 16.16 format. */ + /* */ + /* maximum :: The axis's maximum design coordinate. */ + /* */ + /* tag :: The axis's tag (the GX equivalent to `name'). */ + /* FreeType provides default values for MM if possible. */ + /* */ + /* strid :: The entry in `name' table (another GX version of */ + /* `name'). */ + /* Not meaningful for MM. */ + /* */ + typedef struct FT_Var_Axis_ + { + FT_String* name; + + FT_Fixed minimum; + FT_Fixed def; + FT_Fixed maximum; + + FT_ULong tag; + FT_UInt strid; + + } FT_Var_Axis; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_Var_Named_Style */ + /* */ + /* <Description> */ + /* A simple structure used to model a named style in a GX var font. */ + /* */ + /* This structure can't be used for MM fonts. */ + /* */ + /* <Fields> */ + /* coords :: The design coordinates for this style. */ + /* This is an array with one entry for each axis. */ + /* */ + /* strid :: The entry in `name' table identifying this style. */ + /* */ + typedef struct FT_Var_Named_Style_ + { + FT_Fixed* coords; + FT_UInt strid; + + } FT_Var_Named_Style; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_MM_Var */ + /* */ + /* <Description> */ + /* A structure used to model the axes and space of a Multiple Masters */ + /* or GX var distortable font. */ + /* */ + /* Some fields are specific to one format and not to the other. */ + /* */ + /* <Fields> */ + /* num_axis :: The number of axes. The maximum value is 4 for */ + /* MM; no limit in GX. */ + /* */ + /* num_designs :: The number of designs; should be normally */ + /* 2^num_axis for MM fonts. Not meaningful for GX */ + /* (where every glyph could have a different */ + /* number of designs). */ + /* */ + /* num_namedstyles :: The number of named styles; only meaningful for */ + /* GX which allows certain design coordinates to */ + /* have a string ID (in the `name' table) */ + /* associated with them. The font can tell the */ + /* user that, for example, Weight=1.5 is `Bold'. */ + /* */ + /* axis :: A table of axis descriptors. */ + /* GX fonts contain slightly more data than MM. */ + /* */ + /* namedstyles :: A table of named styles. */ + /* Only meaningful with GX. */ + /* */ + typedef struct FT_MM_Var_ + { + FT_UInt num_axis; + FT_UInt num_designs; + FT_UInt num_namedstyles; + FT_Var_Axis* axis; + FT_Var_Named_Style* namedstyle; + + } FT_MM_Var; + + + /* */ + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Get_Multi_Master */ + /* */ + /* <Description> */ + /* Retrieves the Multiple Master descriptor of a given font. */ + /* */ + /* This function can't be used with GX fonts. */ + /* */ + /* <Input> */ + /* face :: A handle to the source face. */ + /* */ + /* <Output> */ + /* amaster :: The Multiple Masters descriptor. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Get_Multi_Master( FT_Face face, + FT_Multi_Master *amaster ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Get_MM_Var */ + /* */ + /* <Description> */ + /* Retrieves the Multiple Master/GX var descriptor of a given font. */ + /* */ + /* <Input> */ + /* face :: A handle to the source face. */ + /* */ + /* <Output> */ + /* amaster :: The Multiple Masters descriptor. */ + /* Allocates a data structure, which the user must free */ + /* (a single call to FT_FREE will do it). */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Get_MM_Var( FT_Face face, + FT_MM_Var* *amaster ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Set_MM_Design_Coordinates */ + /* */ + /* <Description> */ + /* For Multiple Masters fonts, choose an interpolated font design */ + /* through design coordinates. */ + /* */ + /* This function can't be used with GX fonts. */ + /* */ + /* <InOut> */ + /* face :: A handle to the source face. */ + /* */ + /* <Input> */ + /* num_coords :: The number of design coordinates (must be equal to */ + /* the number of axes in the font). */ + /* */ + /* coords :: An array of design coordinates. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Set_MM_Design_Coordinates( FT_Face face, + FT_UInt num_coords, + FT_Long* coords ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Set_Var_Design_Coordinates */ + /* */ + /* <Description> */ + /* For Multiple Master or GX Var fonts, choose an interpolated font */ + /* design through design coordinates. */ + /* */ + /* <InOut> */ + /* face :: A handle to the source face. */ + /* */ + /* <Input> */ + /* num_coords :: The number of design coordinates (must be equal to */ + /* the number of axes in the font). */ + /* */ + /* coords :: An array of design coordinates. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Set_Var_Design_Coordinates( FT_Face face, + FT_UInt num_coords, + FT_Fixed* coords ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Set_MM_Blend_Coordinates */ + /* */ + /* <Description> */ + /* For Multiple Masters and GX var fonts, choose an interpolated font */ + /* design through normalized blend coordinates. */ + /* */ + /* <InOut> */ + /* face :: A handle to the source face. */ + /* */ + /* <Input> */ + /* num_coords :: The number of design coordinates (must be equal to */ + /* the number of axes in the font). */ + /* */ + /* coords :: The design coordinates array (each element must be */ + /* between 0 and 1.0). */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Set_MM_Blend_Coordinates( FT_Face face, + FT_UInt num_coords, + FT_Fixed* coords ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Set_Var_Blend_Coordinates */ + /* */ + /* <Description> */ + /* This is another name of @FT_Set_MM_Blend_Coordinates. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Set_Var_Blend_Coordinates( FT_Face face, + FT_UInt num_coords, + FT_Fixed* coords ); + + + /* */ + + +FT_END_HEADER + +#endif /* __FTMM_H__ */ + + +/* END */ diff --git a/include/freetype/ftmodapi.h b/include/freetype/ftmodapi.h new file mode 100644 index 0000000..9cc32af --- /dev/null +++ b/include/freetype/ftmodapi.h @@ -0,0 +1,406 @@ +/***************************************************************************/ +/* */ +/* ftmodapi.h */ +/* */ +/* FreeType modules public interface (specification). */ +/* */ +/* Copyright 1996-2001, 2002, 2003, 2006 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef __FTMODAPI_H__ +#define __FTMODAPI_H__ + + +#include <ft2build.h> +#include FT_FREETYPE_H + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* module_management */ + /* */ + /* <Title> */ + /* Module Management */ + /* */ + /* <Abstract> */ + /* How to add, upgrade, and remove modules from FreeType. */ + /* */ + /* <Description> */ + /* The definitions below are used to manage modules within FreeType. */ + /* Modules can be added, upgraded, and removed at runtime. */ + /* */ + /*************************************************************************/ + + + /* module bit flags */ +#define FT_MODULE_FONT_DRIVER 1 /* this module is a font driver */ +#define FT_MODULE_RENDERER 2 /* this module is a renderer */ +#define FT_MODULE_HINTER 4 /* this module is a glyph hinter */ +#define FT_MODULE_STYLER 8 /* this module is a styler */ + +#define FT_MODULE_DRIVER_SCALABLE 0x100 /* the driver supports */ + /* scalable fonts */ +#define FT_MODULE_DRIVER_NO_OUTLINES 0x200 /* the driver does not */ + /* support vector outlines */ +#define FT_MODULE_DRIVER_HAS_HINTER 0x400 /* the driver provides its */ + /* own hinter */ + + + /* deprecated values */ +#define ft_module_font_driver FT_MODULE_FONT_DRIVER +#define ft_module_renderer FT_MODULE_RENDERER +#define ft_module_hinter FT_MODULE_HINTER +#define ft_module_styler FT_MODULE_STYLER + +#define ft_module_driver_scalable FT_MODULE_DRIVER_SCALABLE +#define ft_module_driver_no_outlines FT_MODULE_DRIVER_NO_OUTLINES +#define ft_module_driver_has_hinter FT_MODULE_DRIVER_HAS_HINTER + + + typedef FT_Pointer FT_Module_Interface; + + typedef FT_Error + (*FT_Module_Constructor)( FT_Module module ); + + typedef void + (*FT_Module_Destructor)( FT_Module module ); + + typedef FT_Module_Interface + (*FT_Module_Requester)( FT_Module module, + const char* name ); + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_Module_Class */ + /* */ + /* <Description> */ + /* The module class descriptor. */ + /* */ + /* <Fields> */ + /* module_flags :: Bit flags describing the module. */ + /* */ + /* module_size :: The size of one module object/instance in */ + /* bytes. */ + /* */ + /* module_name :: The name of the module. */ + /* */ + /* module_version :: The version, as a 16.16 fixed number */ + /* (major.minor). */ + /* */ + /* module_requires :: The version of FreeType this module requires, */ + /* as a 16.16 fixed number (major.minor). Starts */ + /* at version 2.0, i.e., 0x20000. */ + /* */ + /* module_init :: A function used to initialize (not create) a */ + /* new module object. */ + /* */ + /* module_done :: A function used to finalize (not destroy) a */ + /* given module object */ + /* */ + /* get_interface :: Queries a given module for a specific */ + /* interface by name. */ + /* */ + typedef struct FT_Module_Class_ + { + FT_ULong module_flags; + FT_Long module_size; + const FT_String* module_name; + FT_Fixed module_version; + FT_Fixed module_requires; + + const void* module_interface; + + FT_Module_Constructor module_init; + FT_Module_Destructor module_done; + FT_Module_Requester get_interface; + + } FT_Module_Class; + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Add_Module */ + /* */ + /* <Description> */ + /* Adds a new module to a given library instance. */ + /* */ + /* <InOut> */ + /* library :: A handle to the library object. */ + /* */ + /* <Input> */ + /* clazz :: A pointer to class descriptor for the module. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* An error will be returned if a module already exists by that name, */ + /* or if the module requires a version of FreeType that is too great. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Add_Module( FT_Library library, + const FT_Module_Class* clazz ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Get_Module */ + /* */ + /* <Description> */ + /* Finds a module by its name. */ + /* */ + /* <Input> */ + /* library :: A handle to the library object. */ + /* */ + /* module_name :: The module's name (as an ASCII string). */ + /* */ + /* <Return> */ + /* A module handle. 0 if none was found. */ + /* */ + /* <Note> */ + /* FreeType's internal modules aren't documented very well, and you */ + /* should look up the source code for details. */ + /* */ + FT_EXPORT( FT_Module ) + FT_Get_Module( FT_Library library, + const char* module_name ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Remove_Module */ + /* */ + /* <Description> */ + /* Removes a given module from a library instance. */ + /* */ + /* <InOut> */ + /* library :: A handle to a library object. */ + /* */ + /* <Input> */ + /* module :: A handle to a module object. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* The module object is destroyed by the function in case of success. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Remove_Module( FT_Library library, + FT_Module module ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_New_Library */ + /* */ + /* <Description> */ + /* This function is used to create a new FreeType library instance */ + /* from a given memory object. It is thus possible to use libraries */ + /* with distinct memory allocators within the same program. */ + /* */ + /* <Input> */ + /* memory :: A handle to the original memory object. */ + /* */ + /* <Output> */ + /* alibrary :: A pointer to handle of a new library object. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_EXPORT( FT_Error ) + FT_New_Library( FT_Memory memory, + FT_Library *alibrary ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Done_Library */ + /* */ + /* <Description> */ + /* Discards a given library object. This closes all drivers and */ + /* discards all resource objects. */ + /* */ + /* <Input> */ + /* library :: A handle to the target library. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Done_Library( FT_Library library ); + +/* */ + + typedef void + (*FT_DebugHook_Func)( void* arg ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Set_Debug_Hook */ + /* */ + /* <Description> */ + /* Sets a debug hook function for debugging the interpreter of a font */ + /* format. */ + /* */ + /* <InOut> */ + /* library :: A handle to the library object. */ + /* */ + /* <Input> */ + /* hook_index :: The index of the debug hook. You should use the */ + /* values defined in `ftobjs.h', e.g., */ + /* `FT_DEBUG_HOOK_TRUETYPE'. */ + /* */ + /* debug_hook :: The function used to debug the interpreter. */ + /* */ + /* <Note> */ + /* Currently, four debug hook slots are available, but only two (for */ + /* the TrueType and the Type 1 interpreter) are defined. */ + /* */ + /* Since the internal headers of FreeType are no longer installed, */ + /* the symbol `FT_DEBUG_HOOK_TRUETYPE' isn't available publicly. */ + /* This is a bug and will be fixed in a forthcoming release. */ + /* */ + FT_EXPORT( void ) + FT_Set_Debug_Hook( FT_Library library, + FT_UInt hook_index, + FT_DebugHook_Func debug_hook ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Add_Default_Modules */ + /* */ + /* <Description> */ + /* Adds the set of default drivers to a given library object. */ + /* This is only useful when you create a library object with */ + /* @FT_New_Library (usually to plug a custom memory manager). */ + /* */ + /* <InOut> */ + /* library :: A handle to a new library object. */ + /* */ + FT_EXPORT( void ) + FT_Add_Default_Modules( FT_Library library ); + + + + /************************************************************************** + * + * @section: + * truetype_engine + * + * @title: + * The TrueType Engine + * + * @abstract: + * TrueType bytecode support. + * + * @description: + * This section contains a function used to query the level of TrueType + * bytecode support compiled in this version of the library. + * + */ + + + /************************************************************************** + * + * @enum: + * FT_TrueTypeEngineType + * + * @description: + * A list of values describing which kind of TrueType bytecode + * engine is implemented in a given FT_Library instance. It is used + * by the @FT_Get_TrueType_Engine_Type function. + * + * @values: + * FT_TRUETYPE_ENGINE_TYPE_NONE :: + * The library doesn't implement any kind of bytecode interpreter. + * + * FT_TRUETYPE_ENGINE_TYPE_UNPATENTED :: + * The library implements a bytecode interpreter that doesn't + * support the patented operations of the TrueType virtual machine. + * + * Its main use is to load certain Asian fonts which position and + * scale glyph components with bytecode instructions. It produces + * bad output for most other fonts. + * + * FT_TRUETYPE_ENGINE_TYPE_PATENTED :: + * The library implements a bytecode interpreter that covers + * the full instruction set of the TrueType virtual machine. + * See the file `docs/PATENTS' for legal aspects. + * + * @since: + * 2.2 + * + */ + typedef enum + { + FT_TRUETYPE_ENGINE_TYPE_NONE = 0, + FT_TRUETYPE_ENGINE_TYPE_UNPATENTED, + FT_TRUETYPE_ENGINE_TYPE_PATENTED + + } FT_TrueTypeEngineType; + + + /************************************************************************** + * + * @func: + * FT_Get_TrueType_Engine_Type + * + * @description: + * Return a @FT_TrueTypeEngineType value to indicate which level of + * the TrueType virtual machine a given library instance supports. + * + * @input: + * library :: + * A library instance. + * + * @return: + * A value indicating which level is supported. + * + * @since: + * 2.2 + * + */ + FT_EXPORT( FT_TrueTypeEngineType ) + FT_Get_TrueType_Engine_Type( FT_Library library ); + + + /* */ + + +FT_END_HEADER + +#endif /* __FTMODAPI_H__ */ + + +/* END */ diff --git a/include/freetype/ftmoderr.h b/include/freetype/ftmoderr.h new file mode 100644 index 0000000..b0115dd --- /dev/null +++ b/include/freetype/ftmoderr.h @@ -0,0 +1,155 @@ +/***************************************************************************/ +/* */ +/* ftmoderr.h */ +/* */ +/* FreeType module error offsets (specification). */ +/* */ +/* Copyright 2001, 2002, 2003, 2004, 2005 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + + /*************************************************************************/ + /* */ + /* This file is used to define the FreeType module error offsets. */ + /* */ + /* The lower byte gives the error code, the higher byte gives the */ + /* module. The base module has error offset 0. For example, the error */ + /* `FT_Err_Invalid_File_Format' has value 0x003, the error */ + /* `TT_Err_Invalid_File_Format' has value 0x1103, the error */ + /* `T1_Err_Invalid_File_Format' has value 0x1203, etc. */ + /* */ + /* Undefine the macro FT_CONFIG_OPTION_USE_MODULE_ERRORS in ftoption.h */ + /* to make the higher byte always zero (disabling the module error */ + /* mechanism). */ + /* */ + /* It can also be used to create a module error message table easily */ + /* with something like */ + /* */ + /* { */ + /* #undef __FTMODERR_H__ */ + /* #define FT_MODERRDEF( e, v, s ) { FT_Mod_Err_ ## e, s }, */ + /* #define FT_MODERR_START_LIST { */ + /* #define FT_MODERR_END_LIST { 0, 0 } }; */ + /* */ + /* const struct */ + /* { */ + /* int mod_err_offset; */ + /* const char* mod_err_msg */ + /* } ft_mod_errors[] = */ + /* */ + /* #include FT_MODULE_ERRORS_H */ + /* } */ + /* */ + /* To use such a table, all errors must be ANDed with 0xFF00 to remove */ + /* the error code. */ + /* */ + /*************************************************************************/ + + +#ifndef __FTMODERR_H__ +#define __FTMODERR_H__ + + + /*******************************************************************/ + /*******************************************************************/ + /***** *****/ + /***** SETUP MACROS *****/ + /***** *****/ + /*******************************************************************/ + /*******************************************************************/ + + +#undef FT_NEED_EXTERN_C + +#ifndef FT_MODERRDEF + +#ifdef FT_CONFIG_OPTION_USE_MODULE_ERRORS +#define FT_MODERRDEF( e, v, s ) FT_Mod_Err_ ## e = v, +#else +#define FT_MODERRDEF( e, v, s ) FT_Mod_Err_ ## e = 0, +#endif + +#define FT_MODERR_START_LIST enum { +#define FT_MODERR_END_LIST FT_Mod_Err_Max }; + +#ifdef __cplusplus +#define FT_NEED_EXTERN_C + extern "C" { +#endif + +#endif /* !FT_MODERRDEF */ + + + /*******************************************************************/ + /*******************************************************************/ + /***** *****/ + /***** LIST MODULE ERROR BASES *****/ + /***** *****/ + /*******************************************************************/ + /*******************************************************************/ + + +#ifdef FT_MODERR_START_LIST + FT_MODERR_START_LIST +#endif + + + FT_MODERRDEF( Base, 0x000, "base module" ) + FT_MODERRDEF( Autofit, 0x100, "autofitter module" ) + FT_MODERRDEF( BDF, 0x200, "BDF module" ) + FT_MODERRDEF( Cache, 0x300, "cache module" ) + FT_MODERRDEF( CFF, 0x400, "CFF module" ) + FT_MODERRDEF( CID, 0x500, "CID module" ) + FT_MODERRDEF( Gzip, 0x600, "Gzip module" ) + FT_MODERRDEF( LZW, 0x700, "LZW module" ) + FT_MODERRDEF( OTvalid, 0x800, "OpenType validation module" ) + FT_MODERRDEF( PCF, 0x900, "PCF module" ) + FT_MODERRDEF( PFR, 0xA00, "PFR module" ) + FT_MODERRDEF( PSaux, 0xB00, "PS auxiliary module" ) + FT_MODERRDEF( PShinter, 0xC00, "PS hinter module" ) + FT_MODERRDEF( PSnames, 0xD00, "PS names module" ) + FT_MODERRDEF( Raster, 0xE00, "raster module" ) + FT_MODERRDEF( SFNT, 0xF00, "SFNT module" ) + FT_MODERRDEF( Smooth, 0x1000, "smooth raster module" ) + FT_MODERRDEF( TrueType, 0x1100, "TrueType module" ) + FT_MODERRDEF( Type1, 0x1200, "Type 1 module" ) + FT_MODERRDEF( Type42, 0x1300, "Type 42 module" ) + FT_MODERRDEF( Winfonts, 0x1400, "Windows FON/FNT module" ) + + +#ifdef FT_MODERR_END_LIST + FT_MODERR_END_LIST +#endif + + + /*******************************************************************/ + /*******************************************************************/ + /***** *****/ + /***** CLEANUP *****/ + /***** *****/ + /*******************************************************************/ + /*******************************************************************/ + + +#ifdef FT_NEED_EXTERN_C + } +#endif + +#undef FT_MODERR_START_LIST +#undef FT_MODERR_END_LIST +#undef FT_MODERRDEF +#undef FT_NEED_EXTERN_C + + +#endif /* __FTMODERR_H__ */ + + +/* END */ diff --git a/include/freetype/ftotval.h b/include/freetype/ftotval.h new file mode 100644 index 0000000..7c488fd --- /dev/null +++ b/include/freetype/ftotval.h @@ -0,0 +1,198 @@ +/***************************************************************************/ +/* */ +/* ftotval.h */ +/* */ +/* FreeType API for validating OpenType tables (specification). */ +/* */ +/* Copyright 2004, 2005, 2006 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +/***************************************************************************/ +/* */ +/* */ +/* Warning: This module might be moved to a different library in the */ +/* future to avoid a tight dependency between FreeType and the */ +/* OpenType specification. */ +/* */ +/* */ +/***************************************************************************/ + + +#ifndef __FTOTVAL_H__ +#define __FTOTVAL_H__ + +#include <ft2build.h> +#include FT_FREETYPE_H + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* ot_validation */ + /* */ + /* <Title> */ + /* OpenType Validation */ + /* */ + /* <Abstract> */ + /* An API to validate OpenType tables. */ + /* */ + /* <Description> */ + /* This section contains the declaration of functions to validate */ + /* some OpenType tables (BASE, GDEF, GPOS, GSUB, JSTF). */ + /* */ + /*************************************************************************/ + + + /********************************************************************** + * + * @enum: + * FT_VALIDATE_OTXXX + * + * @description: + * A list of bit-field constants used with @FT_OpenType_Validate to + * indicate which OpenType tables should be validated. + * + * @values: + * FT_VALIDATE_BASE :: + * Validate BASE table. + * + * FT_VALIDATE_GDEF :: + * Validate GDEF table. + * + * FT_VALIDATE_GPOS :: + * Validate GPOS table. + * + * FT_VALIDATE_GSUB :: + * Validate GSUB table. + * + * FT_VALIDATE_JSTF :: + * Validate JSTF table. + * + * FT_VALIDATE_OT :: + * Validate all OpenType tables (BASE, GDEF, GPOS, GSUB, JSTF). + * + */ +#define FT_VALIDATE_BASE 0x0100 +#define FT_VALIDATE_GDEF 0x0200 +#define FT_VALIDATE_GPOS 0x0400 +#define FT_VALIDATE_GSUB 0x0800 +#define FT_VALIDATE_JSTF 0x1000 + +#define FT_VALIDATE_OT FT_VALIDATE_BASE | \ + FT_VALIDATE_GDEF | \ + FT_VALIDATE_GPOS | \ + FT_VALIDATE_GSUB | \ + FT_VALIDATE_JSTF + + /* */ + + /********************************************************************** + * + * @function: + * FT_OpenType_Validate + * + * @description: + * Validate various OpenType tables to assure that all offsets and + * indices are valid. The idea is that a higher-level library which + * actually does the text layout can access those tables without + * error checking (which can be quite time consuming). + * + * @input: + * face :: + * A handle to the input face. + * + * validation_flags :: + * A bit field which specifies the tables to be validated. See + * @FT_VALIDATE_OTXXX for possible values. + * + * @output: + * BASE_table :: + * A pointer to the BASE table. + * + * GDEF_table :: + * A pointer to the GDEF table. + * + * GPOS_table :: + * A pointer to the GPOS table. + * + * GSUB_table :: + * A pointer to the GSUB table. + * + * JSTF_table :: + * A pointer to the JSTF table. + * + * @return: + * FreeType error code. 0 means success. + * + * @note: + * This function only works with OpenType fonts, returning an error + * otherwise. + * + * After use, the application should deallocate the five tables with + * @FT_OpenType_Free. A NULL value indicates that the table either + * doesn't exist in the font, or the application hasn't asked for + * validation. + */ + FT_EXPORT( FT_Error ) + FT_OpenType_Validate( FT_Face face, + FT_UInt validation_flags, + FT_Bytes *BASE_table, + FT_Bytes *GDEF_table, + FT_Bytes *GPOS_table, + FT_Bytes *GSUB_table, + FT_Bytes *JSTF_table ); + + /* */ + + /********************************************************************** + * + * @function: + * FT_OpenType_Free + * + * @description: + * Free the buffer allocated by OpenType validator. + * + * @input: + * face :: + * A handle to the input face. + * + * table :: + * The pointer to the buffer that is allocated by + * @FT_OpenType_Validate. + * + * @note: + * This function must be used to free the buffer allocated by + * @FT_OpenType_Validate only. + */ + FT_EXPORT( void ) + FT_OpenType_Free( FT_Face face, + FT_Bytes table ); + + + /* */ + + +FT_END_HEADER + +#endif /* __FTOTVAL_H__ */ + + +/* END */ diff --git a/include/freetype/ftoutln.h b/include/freetype/ftoutln.h new file mode 100644 index 0000000..786ae13 --- /dev/null +++ b/include/freetype/ftoutln.h @@ -0,0 +1,526 @@ +/***************************************************************************/ +/* */ +/* ftoutln.h */ +/* */ +/* Support for the FT_Outline type used to store glyph shapes of */ +/* most scalable font formats (specification). */ +/* */ +/* Copyright 1996-2001, 2002, 2003, 2005, 2006, 2007 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef __FTOUTLN_H__ +#define __FTOUTLN_H__ + + +#include <ft2build.h> +#include FT_FREETYPE_H + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* outline_processing */ + /* */ + /* <Title> */ + /* Outline Processing */ + /* */ + /* <Abstract> */ + /* Functions to create, transform, and render vectorial glyph images. */ + /* */ + /* <Description> */ + /* This section contains routines used to create and destroy scalable */ + /* glyph images known as `outlines'. These can also be measured, */ + /* transformed, and converted into bitmaps and pixmaps. */ + /* */ + /* <Order> */ + /* FT_Outline */ + /* FT_OUTLINE_FLAGS */ + /* FT_Outline_New */ + /* FT_Outline_Done */ + /* FT_Outline_Copy */ + /* FT_Outline_Translate */ + /* FT_Outline_Transform */ + /* FT_Outline_Embolden */ + /* FT_Outline_Reverse */ + /* FT_Outline_Check */ + /* */ + /* FT_Outline_Get_CBox */ + /* FT_Outline_Get_BBox */ + /* */ + /* FT_Outline_Get_Bitmap */ + /* FT_Outline_Render */ + /* */ + /* FT_Outline_Decompose */ + /* FT_Outline_Funcs */ + /* FT_Outline_MoveTo_Func */ + /* FT_Outline_LineTo_Func */ + /* FT_Outline_ConicTo_Func */ + /* FT_Outline_CubicTo_Func */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Outline_Decompose */ + /* */ + /* <Description> */ + /* Walks over an outline's structure to decompose it into individual */ + /* segments and Bézier arcs. This function is also able to emit */ + /* `move to' and `close to' operations to indicate the start and end */ + /* of new contours in the outline. */ + /* */ + /* <Input> */ + /* outline :: A pointer to the source target. */ + /* */ + /* func_interface :: A table of `emitters', i.e,. function pointers */ + /* called during decomposition to indicate path */ + /* operations. */ + /* */ + /* <InOut> */ + /* user :: A typeless pointer which is passed to each */ + /* emitter during the decomposition. It can be */ + /* used to store the state during the */ + /* decomposition. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Outline_Decompose( FT_Outline* outline, + const FT_Outline_Funcs* func_interface, + void* user ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Outline_New */ + /* */ + /* <Description> */ + /* Creates a new outline of a given size. */ + /* */ + /* <Input> */ + /* library :: A handle to the library object from where the */ + /* outline is allocated. Note however that the new */ + /* outline will *not* necessarily be *freed*, when */ + /* destroying the library, by @FT_Done_FreeType. */ + /* */ + /* numPoints :: The maximal number of points within the outline. */ + /* */ + /* numContours :: The maximal number of contours within the outline. */ + /* */ + /* <Output> */ + /* anoutline :: A handle to the new outline. NULL in case of */ + /* error. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* The reason why this function takes a `library' parameter is simply */ + /* to use the library's memory allocator. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Outline_New( FT_Library library, + FT_UInt numPoints, + FT_Int numContours, + FT_Outline *anoutline ); + + + FT_EXPORT( FT_Error ) + FT_Outline_New_Internal( FT_Memory memory, + FT_UInt numPoints, + FT_Int numContours, + FT_Outline *anoutline ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Outline_Done */ + /* */ + /* <Description> */ + /* Destroys an outline created with @FT_Outline_New. */ + /* */ + /* <Input> */ + /* library :: A handle of the library object used to allocate the */ + /* outline. */ + /* */ + /* outline :: A pointer to the outline object to be discarded. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* If the outline's `owner' field is not set, only the outline */ + /* descriptor will be released. */ + /* */ + /* The reason why this function takes an `library' parameter is */ + /* simply to use ft_mem_free(). */ + /* */ + FT_EXPORT( FT_Error ) + FT_Outline_Done( FT_Library library, + FT_Outline* outline ); + + + FT_EXPORT( FT_Error ) + FT_Outline_Done_Internal( FT_Memory memory, + FT_Outline* outline ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Outline_Check */ + /* */ + /* <Description> */ + /* Check the contents of an outline descriptor. */ + /* */ + /* <Input> */ + /* outline :: A handle to a source outline. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Outline_Check( FT_Outline* outline ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Outline_Get_CBox */ + /* */ + /* <Description> */ + /* Returns an outline's `control box'. The control box encloses all */ + /* the outline's points, including Bézier control points. Though it */ + /* coincides with the exact bounding box for most glyphs, it can be */ + /* slightly larger in some situations (like when rotating an outline */ + /* which contains Bézier outside arcs). */ + /* */ + /* Computing the control box is very fast, while getting the bounding */ + /* box can take much more time as it needs to walk over all segments */ + /* and arcs in the outline. To get the latter, you can use the */ + /* `ftbbox' component which is dedicated to this single task. */ + /* */ + /* <Input> */ + /* outline :: A pointer to the source outline descriptor. */ + /* */ + /* <Output> */ + /* acbox :: The outline's control box. */ + /* */ + FT_EXPORT( void ) + FT_Outline_Get_CBox( const FT_Outline* outline, + FT_BBox *acbox ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Outline_Translate */ + /* */ + /* <Description> */ + /* Applies a simple translation to the points of an outline. */ + /* */ + /* <InOut> */ + /* outline :: A pointer to the target outline descriptor. */ + /* */ + /* <Input> */ + /* xOffset :: The horizontal offset. */ + /* */ + /* yOffset :: The vertical offset. */ + /* */ + FT_EXPORT( void ) + FT_Outline_Translate( const FT_Outline* outline, + FT_Pos xOffset, + FT_Pos yOffset ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Outline_Copy */ + /* */ + /* <Description> */ + /* Copies an outline into another one. Both objects must have the */ + /* same sizes (number of points & number of contours) when this */ + /* function is called. */ + /* */ + /* <Input> */ + /* source :: A handle to the source outline. */ + /* */ + /* <Output> */ + /* target :: A handle to the target outline. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Outline_Copy( const FT_Outline* source, + FT_Outline *target ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Outline_Transform */ + /* */ + /* <Description> */ + /* Applies a simple 2x2 matrix to all of an outline's points. Useful */ + /* for applying rotations, slanting, flipping, etc. */ + /* */ + /* <InOut> */ + /* outline :: A pointer to the target outline descriptor. */ + /* */ + /* <Input> */ + /* matrix :: A pointer to the transformation matrix. */ + /* */ + /* <Note> */ + /* You can use @FT_Outline_Translate if you need to translate the */ + /* outline's points. */ + /* */ + FT_EXPORT( void ) + FT_Outline_Transform( const FT_Outline* outline, + const FT_Matrix* matrix ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Outline_Embolden */ + /* */ + /* <Description> */ + /* Emboldens an outline. The new outline will be at most 4 times */ + /* `strength' pixels wider and higher. You may think of the left and */ + /* bottom borders as unchanged. */ + /* */ + /* Negative `strength' values to reduce the outline thickness are */ + /* possible also. */ + /* */ + /* <InOut> */ + /* outline :: A handle to the target outline. */ + /* */ + /* <Input> */ + /* strength :: How strong the glyph is emboldened. Expressed in */ + /* 26.6 pixel format. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* The used algorithm to increase or decrease the thickness of the */ + /* glyph doesn't change the number of points; this means that certain */ + /* situations like acute angles or intersections are sometimes */ + /* handled incorrectly. */ + /* */ + /* Example call: */ + /* */ + /* { */ + /* FT_Load_Glyph( face, index, FT_LOAD_DEFAULT ); */ + /* if ( face->slot->format == FT_GLYPH_FORMAT_OUTLINE ) */ + /* FT_Outline_Embolden( &face->slot->outline, strength ); */ + /* } */ + /* */ + FT_EXPORT( FT_Error ) + FT_Outline_Embolden( FT_Outline* outline, + FT_Pos strength ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Outline_Reverse */ + /* */ + /* <Description> */ + /* Reverses the drawing direction of an outline. This is used to */ + /* ensure consistent fill conventions for mirrored glyphs. */ + /* */ + /* <InOut> */ + /* outline :: A pointer to the target outline descriptor. */ + /* */ + /* <Note> */ + /* This functions toggles the bit flag @FT_OUTLINE_REVERSE_FILL in */ + /* the outline's `flags' field. */ + /* */ + /* It shouldn't be used by a normal client application, unless it */ + /* knows what it is doing. */ + /* */ + FT_EXPORT( void ) + FT_Outline_Reverse( FT_Outline* outline ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Outline_Get_Bitmap */ + /* */ + /* <Description> */ + /* Renders an outline within a bitmap. The outline's image is simply */ + /* OR-ed to the target bitmap. */ + /* */ + /* <Input> */ + /* library :: A handle to a FreeType library object. */ + /* */ + /* outline :: A pointer to the source outline descriptor. */ + /* */ + /* <InOut> */ + /* abitmap :: A pointer to the target bitmap descriptor. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* This function does NOT CREATE the bitmap, it only renders an */ + /* outline image within the one you pass to it! */ + /* */ + /* It will use the raster corresponding to the default glyph format. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Outline_Get_Bitmap( FT_Library library, + FT_Outline* outline, + const FT_Bitmap *abitmap ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Outline_Render */ + /* */ + /* <Description> */ + /* Renders an outline within a bitmap using the current scan-convert. */ + /* This functions uses an @FT_Raster_Params structure as an argument, */ + /* allowing advanced features like direct composition, translucency, */ + /* etc. */ + /* */ + /* <Input> */ + /* library :: A handle to a FreeType library object. */ + /* */ + /* outline :: A pointer to the source outline descriptor. */ + /* */ + /* <InOut> */ + /* params :: A pointer to an @FT_Raster_Params structure used to */ + /* describe the rendering operation. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* You should know what you are doing and how @FT_Raster_Params works */ + /* to use this function. */ + /* */ + /* The field `params.source' will be set to `outline' before the scan */ + /* converter is called, which means that the value you give to it is */ + /* actually ignored. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Outline_Render( FT_Library library, + FT_Outline* outline, + FT_Raster_Params* params ); + + + /************************************************************************** + * + * @enum: + * FT_Orientation + * + * @description: + * A list of values used to describe an outline's contour orientation. + * + * The TrueType and Postscript specifications use different conventions + * to determine whether outline contours should be filled or unfilled. + * + * @values: + * FT_ORIENTATION_TRUETYPE :: + * According to the TrueType specification, clockwise contours must + * be filled, and counter-clockwise ones must be unfilled. + * + * FT_ORIENTATION_POSTSCRIPT :: + * According to the Postscript specification, counter-clockwise contours + * must be filled, and clockwise ones must be unfilled. + * + * FT_ORIENTATION_FILL_RIGHT :: + * This is identical to @FT_ORIENTATION_TRUETYPE, but is used to + * remember that in TrueType, everything that is to the right of + * the drawing direction of a contour must be filled. + * + * FT_ORIENTATION_FILL_LEFT :: + * This is identical to @FT_ORIENTATION_POSTSCRIPT, but is used to + * remember that in Postscript, everything that is to the left of + * the drawing direction of a contour must be filled. + * + * FT_ORIENTATION_NONE :: + * The orientation cannot be determined. That is, different parts of + * the glyph have different orientation. + * + */ + typedef enum + { + FT_ORIENTATION_TRUETYPE = 0, + FT_ORIENTATION_POSTSCRIPT = 1, + FT_ORIENTATION_FILL_RIGHT = FT_ORIENTATION_TRUETYPE, + FT_ORIENTATION_FILL_LEFT = FT_ORIENTATION_POSTSCRIPT, + FT_ORIENTATION_NONE + + } FT_Orientation; + + + /************************************************************************** + * + * @function: + * FT_Outline_Get_Orientation + * + * @description: + * This function analyzes a glyph outline and tries to compute its + * fill orientation (see @FT_Orientation). This is done by computing + * the direction of each global horizontal and/or vertical extrema + * within the outline. + * + * Note that this will return @FT_ORIENTATION_TRUETYPE for empty + * outlines. + * + * @input: + * outline :: + * A handle to the source outline. + * + * @return: + * The orientation. + * + */ + FT_EXPORT( FT_Orientation ) + FT_Outline_Get_Orientation( FT_Outline* outline ); + + + /* */ + + +FT_END_HEADER + +#endif /* __FTOUTLN_H__ */ + + +/* END */ + + +/* Local Variables: */ +/* coding: utf-8 */ +/* End: */ diff --git a/include/freetype/ftpfr.h b/include/freetype/ftpfr.h new file mode 100644 index 0000000..e2801fd --- /dev/null +++ b/include/freetype/ftpfr.h @@ -0,0 +1,172 @@ +/***************************************************************************/ +/* */ +/* ftpfr.h */ +/* */ +/* FreeType API for accessing PFR-specific data (specification only). */ +/* */ +/* Copyright 2002, 2003, 2004, 2006 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef __FTPFR_H__ +#define __FTPFR_H__ + +#include <ft2build.h> +#include FT_FREETYPE_H + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* pfr_fonts */ + /* */ + /* <Title> */ + /* PFR Fonts */ + /* */ + /* <Abstract> */ + /* PFR/TrueDoc specific API. */ + /* */ + /* <Description> */ + /* This section contains the declaration of PFR-specific functions. */ + /* */ + /*************************************************************************/ + + + /********************************************************************** + * + * @function: + * FT_Get_PFR_Metrics + * + * @description: + * Return the outline and metrics resolutions of a given PFR face. + * + * @input: + * face :: Handle to the input face. It can be a non-PFR face. + * + * @output: + * aoutline_resolution :: + * Outline resolution. This is equivalent to `face->units_per_EM'. + * Optional (parameter can be NULL). + * + * ametrics_resolution :: + * Metrics resolution. This is equivalent to `outline_resolution' + * for non-PFR fonts. Optional (parameter can be NULL). + * + * ametrics_x_scale :: + * A 16.16 fixed-point number used to scale distance expressed + * in metrics units to device sub-pixels. This is equivalent to + * `face->size->x_scale', but for metrics only. Optional (parameter + * can be NULL) + * + * ametrics_y_scale :: + * Same as `ametrics_x_scale' but for the vertical direction. + * optional (parameter can be NULL) + * + * @return: + * FreeType error code. 0 means success. + * + * @note: + * If the input face is not a PFR, this function will return an error. + * However, in all cases, it will return valid values. + */ + FT_EXPORT( FT_Error ) + FT_Get_PFR_Metrics( FT_Face face, + FT_UInt *aoutline_resolution, + FT_UInt *ametrics_resolution, + FT_Fixed *ametrics_x_scale, + FT_Fixed *ametrics_y_scale ); + + + /********************************************************************** + * + * @function: + * FT_Get_PFR_Kerning + * + * @description: + * Return the kerning pair corresponding to two glyphs in a PFR face. + * The distance is expressed in metrics units, unlike the result of + * @FT_Get_Kerning. + * + * @input: + * face :: A handle to the input face. + * + * left :: Index of the left glyph. + * + * right :: Index of the right glyph. + * + * @output: + * avector :: A kerning vector. + * + * @return: + * FreeType error code. 0 means success. + * + * @note: + * This function always return distances in original PFR metrics + * units. This is unlike @FT_Get_Kerning with the @FT_KERNING_UNSCALED + * mode, which always returns distances converted to outline units. + * + * You can use the value of the `x_scale' and `y_scale' parameters + * returned by @FT_Get_PFR_Metrics to scale these to device sub-pixels. + */ + FT_EXPORT( FT_Error ) + FT_Get_PFR_Kerning( FT_Face face, + FT_UInt left, + FT_UInt right, + FT_Vector *avector ); + + + /********************************************************************** + * + * @function: + * FT_Get_PFR_Advance + * + * @description: + * Return a given glyph advance, expressed in original metrics units, + * from a PFR font. + * + * @input: + * face :: A handle to the input face. + * + * gindex :: The glyph index. + * + * @output: + * aadvance :: The glyph advance in metrics units. + * + * @return: + * FreeType error code. 0 means success. + * + * @note: + * You can use the `x_scale' or `y_scale' results of @FT_Get_PFR_Metrics + * to convert the advance to device sub-pixels (i.e., 1/64th of pixels). + */ + FT_EXPORT( FT_Error ) + FT_Get_PFR_Advance( FT_Face face, + FT_UInt gindex, + FT_Pos *aadvance ); + + /* */ + + +FT_END_HEADER + +#endif /* __FTPFR_H__ */ + + +/* END */ diff --git a/include/freetype/ftrender.h b/include/freetype/ftrender.h new file mode 100644 index 0000000..5b07f08 --- /dev/null +++ b/include/freetype/ftrender.h @@ -0,0 +1,229 @@ +/***************************************************************************/ +/* */ +/* ftrender.h */ +/* */ +/* FreeType renderer modules public interface (specification). */ +/* */ +/* Copyright 1996-2001, 2005, 2006 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef __FTRENDER_H__ +#define __FTRENDER_H__ + + +#include <ft2build.h> +#include FT_MODULE_H +#include FT_GLYPH_H + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* module_management */ + /* */ + /*************************************************************************/ + + + /* create a new glyph object */ + typedef FT_Error + (*FT_Glyph_InitFunc)( FT_Glyph glyph, + FT_GlyphSlot slot ); + + /* destroys a given glyph object */ + typedef void + (*FT_Glyph_DoneFunc)( FT_Glyph glyph ); + + typedef void + (*FT_Glyph_TransformFunc)( FT_Glyph glyph, + const FT_Matrix* matrix, + const FT_Vector* delta ); + + typedef void + (*FT_Glyph_GetBBoxFunc)( FT_Glyph glyph, + FT_BBox* abbox ); + + typedef FT_Error + (*FT_Glyph_CopyFunc)( FT_Glyph source, + FT_Glyph target ); + + typedef FT_Error + (*FT_Glyph_PrepareFunc)( FT_Glyph glyph, + FT_GlyphSlot slot ); + +/* deprecated */ +#define FT_Glyph_Init_Func FT_Glyph_InitFunc +#define FT_Glyph_Done_Func FT_Glyph_DoneFunc +#define FT_Glyph_Transform_Func FT_Glyph_TransformFunc +#define FT_Glyph_BBox_Func FT_Glyph_GetBBoxFunc +#define FT_Glyph_Copy_Func FT_Glyph_CopyFunc +#define FT_Glyph_Prepare_Func FT_Glyph_PrepareFunc + + + struct FT_Glyph_Class_ + { + FT_Long glyph_size; + FT_Glyph_Format glyph_format; + FT_Glyph_InitFunc glyph_init; + FT_Glyph_DoneFunc glyph_done; + FT_Glyph_CopyFunc glyph_copy; + FT_Glyph_TransformFunc glyph_transform; + FT_Glyph_GetBBoxFunc glyph_bbox; + FT_Glyph_PrepareFunc glyph_prepare; + }; + + + typedef FT_Error + (*FT_Renderer_RenderFunc)( FT_Renderer renderer, + FT_GlyphSlot slot, + FT_UInt mode, + const FT_Vector* origin ); + + typedef FT_Error + (*FT_Renderer_TransformFunc)( FT_Renderer renderer, + FT_GlyphSlot slot, + const FT_Matrix* matrix, + const FT_Vector* delta ); + + + typedef void + (*FT_Renderer_GetCBoxFunc)( FT_Renderer renderer, + FT_GlyphSlot slot, + FT_BBox* cbox ); + + + typedef FT_Error + (*FT_Renderer_SetModeFunc)( FT_Renderer renderer, + FT_ULong mode_tag, + FT_Pointer mode_ptr ); + +/* deprecated identifiers */ +#define FTRenderer_render FT_Renderer_RenderFunc +#define FTRenderer_transform FT_Renderer_TransformFunc +#define FTRenderer_getCBox FT_Renderer_GetCBoxFunc +#define FTRenderer_setMode FT_Renderer_SetModeFunc + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_Renderer_Class */ + /* */ + /* <Description> */ + /* The renderer module class descriptor. */ + /* */ + /* <Fields> */ + /* root :: The root @FT_Module_Class fields. */ + /* */ + /* glyph_format :: The glyph image format this renderer handles. */ + /* */ + /* render_glyph :: A method used to render the image that is in a */ + /* given glyph slot into a bitmap. */ + /* */ + /* set_mode :: A method used to pass additional parameters. */ + /* */ + /* raster_class :: For @FT_GLYPH_FORMAT_OUTLINE renderers only. This */ + /* is a pointer to its raster's class. */ + /* */ + /* raster :: For @FT_GLYPH_FORMAT_OUTLINE renderers only. This */ + /* is a pointer to the corresponding raster object, */ + /* if any. */ + /* */ + typedef struct FT_Renderer_Class_ + { + FT_Module_Class root; + + FT_Glyph_Format glyph_format; + + FT_Renderer_RenderFunc render_glyph; + FT_Renderer_TransformFunc transform_glyph; + FT_Renderer_GetCBoxFunc get_glyph_cbox; + FT_Renderer_SetModeFunc set_mode; + + FT_Raster_Funcs* raster_class; + + } FT_Renderer_Class; + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Get_Renderer */ + /* */ + /* <Description> */ + /* Retrieves the current renderer for a given glyph format. */ + /* */ + /* <Input> */ + /* library :: A handle to the library object. */ + /* */ + /* format :: The glyph format. */ + /* */ + /* <Return> */ + /* A renderer handle. 0 if none found. */ + /* */ + /* <Note> */ + /* An error will be returned if a module already exists by that name, */ + /* or if the module requires a version of FreeType that is too great. */ + /* */ + /* To add a new renderer, simply use @FT_Add_Module. To retrieve a */ + /* renderer by its name, use @FT_Get_Module. */ + /* */ + FT_EXPORT( FT_Renderer ) + FT_Get_Renderer( FT_Library library, + FT_Glyph_Format format ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Set_Renderer */ + /* */ + /* <Description> */ + /* Sets the current renderer to use, and set additional mode. */ + /* */ + /* <InOut> */ + /* library :: A handle to the library object. */ + /* */ + /* <Input> */ + /* renderer :: A handle to the renderer object. */ + /* */ + /* num_params :: The number of additional parameters. */ + /* */ + /* parameters :: Additional parameters. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* In case of success, the renderer will be used to convert glyph */ + /* images in the renderer's known format into bitmaps. */ + /* */ + /* This doesn't change the current renderer for other formats. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Set_Renderer( FT_Library library, + FT_Renderer renderer, + FT_UInt num_params, + FT_Parameter* parameters ); + + + /* */ + + +FT_END_HEADER + +#endif /* __FTRENDER_H__ */ + + +/* END */ diff --git a/include/freetype/ftsizes.h b/include/freetype/ftsizes.h new file mode 100644 index 0000000..622df16 --- /dev/null +++ b/include/freetype/ftsizes.h @@ -0,0 +1,159 @@ +/***************************************************************************/ +/* */ +/* ftsizes.h */ +/* */ +/* FreeType size objects management (specification). */ +/* */ +/* Copyright 1996-2001, 2003, 2004, 2006 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + + /*************************************************************************/ + /* */ + /* Typical application would normally not need to use these functions. */ + /* However, they have been placed in a public API for the rare cases */ + /* where they are needed. */ + /* */ + /*************************************************************************/ + + +#ifndef __FTSIZES_H__ +#define __FTSIZES_H__ + + +#include <ft2build.h> +#include FT_FREETYPE_H + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* sizes_management */ + /* */ + /* <Title> */ + /* Size Management */ + /* */ + /* <Abstract> */ + /* Managing multiple sizes per face. */ + /* */ + /* <Description> */ + /* When creating a new face object (e.g., with @FT_New_Face), an */ + /* @FT_Size object is automatically created and used to store all */ + /* pixel-size dependent information, available in the `face->size' */ + /* field. */ + /* */ + /* It is however possible to create more sizes for a given face, */ + /* mostly in order to manage several character pixel sizes of the */ + /* same font family and style. See @FT_New_Size and @FT_Done_Size. */ + /* */ + /* Note that @FT_Set_Pixel_Sizes and @FT_Set_Char_Size only */ + /* modify the contents of the current `active' size; you thus need */ + /* to use @FT_Activate_Size to change it. */ + /* */ + /* 99% of applications won't need the functions provided here, */ + /* especially if they use the caching sub-system, so be cautious */ + /* when using these. */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_New_Size */ + /* */ + /* <Description> */ + /* Create a new size object from a given face object. */ + /* */ + /* <Input> */ + /* face :: A handle to a parent face object. */ + /* */ + /* <Output> */ + /* asize :: A handle to a new size object. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* You need to call @FT_Activate_Size in order to select the new size */ + /* for upcoming calls to @FT_Set_Pixel_Sizes, @FT_Set_Char_Size, */ + /* @FT_Load_Glyph, @FT_Load_Char, etc. */ + /* */ + FT_EXPORT( FT_Error ) + FT_New_Size( FT_Face face, + FT_Size* size ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Done_Size */ + /* */ + /* <Description> */ + /* Discard a given size object. Note that @FT_Done_Face */ + /* automatically discards all size objects allocated with */ + /* @FT_New_Size. */ + /* */ + /* <Input> */ + /* size :: A handle to a target size object. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Done_Size( FT_Size size ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Activate_Size */ + /* */ + /* <Description> */ + /* Even though it is possible to create several size objects for a */ + /* given face (see @FT_New_Size for details), functions like */ + /* @FT_Load_Glyph or @FT_Load_Char only use the last-created one to */ + /* determine the `current character pixel size'. */ + /* */ + /* This function can be used to `activate' a previously created size */ + /* object. */ + /* */ + /* <Input> */ + /* size :: A handle to a target size object. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* If `face' is the size's parent face object, this function changes */ + /* the value of `face->size' to the input size handle. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Activate_Size( FT_Size size ); + + /* */ + + +FT_END_HEADER + +#endif /* __FTSIZES_H__ */ + + +/* END */ diff --git a/include/freetype/ftsnames.h b/include/freetype/ftsnames.h new file mode 100644 index 0000000..003cbcd --- /dev/null +++ b/include/freetype/ftsnames.h @@ -0,0 +1,170 @@ +/***************************************************************************/ +/* */ +/* ftsnames.h */ +/* */ +/* Simple interface to access SFNT name tables (which are used */ +/* to hold font names, copyright info, notices, etc.) (specification). */ +/* */ +/* This is _not_ used to retrieve glyph names! */ +/* */ +/* Copyright 1996-2001, 2002, 2003, 2006 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef __FT_SFNT_NAMES_H__ +#define __FT_SFNT_NAMES_H__ + + +#include <ft2build.h> +#include FT_FREETYPE_H + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* sfnt_names */ + /* */ + /* <Title> */ + /* SFNT Names */ + /* */ + /* <Abstract> */ + /* Access the names embedded in TrueType and OpenType files. */ + /* */ + /* <Description> */ + /* The TrueType and OpenType specification allow the inclusion of */ + /* a special `names table' in font files. This table contains */ + /* textual (and internationalized) information regarding the font, */ + /* like family name, copyright, version, etc. */ + /* */ + /* The definitions below are used to access them if available. */ + /* */ + /* Note that this has nothing to do with glyph names! */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_SfntName */ + /* */ + /* <Description> */ + /* A structure used to model an SFNT `name' table entry. */ + /* */ + /* <Fields> */ + /* platform_id :: The platform ID for `string'. */ + /* */ + /* encoding_id :: The encoding ID for `string'. */ + /* */ + /* language_id :: The language ID for `string'. */ + /* */ + /* name_id :: An identifier for `string'. */ + /* */ + /* string :: The `name' string. Note that its format differs */ + /* depending on the (platform,encoding) pair. It can */ + /* be a Pascal String, a UTF-16 one, etc. */ + /* */ + /* Generally speaking, the string is not */ + /* zero-terminated. Please refer to the TrueType */ + /* specification for details. */ + /* */ + /* string_len :: The length of `string' in bytes. */ + /* */ + /* <Note> */ + /* Possible values for `platform_id', `encoding_id', `language_id', */ + /* and `name_id' are given in the file `ttnameid.h'. For details */ + /* please refer to the TrueType or OpenType specification. */ + /* */ + /* See also @TT_PLATFORM_XXX, @TT_APPLE_ID_XXX, @TT_MAC_ID_XXX, */ + /* @TT_ISO_ID_XXX, and @TT_MS_ID_XXX. */ + /* */ + typedef struct FT_SfntName_ + { + FT_UShort platform_id; + FT_UShort encoding_id; + FT_UShort language_id; + FT_UShort name_id; + + FT_Byte* string; /* this string is *not* null-terminated! */ + FT_UInt string_len; /* in bytes */ + + } FT_SfntName; + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Get_Sfnt_Name_Count */ + /* */ + /* <Description> */ + /* Retrieves the number of name strings in the SFNT `name' table. */ + /* */ + /* <Input> */ + /* face :: A handle to the source face. */ + /* */ + /* <Return> */ + /* The number of strings in the `name' table. */ + /* */ + FT_EXPORT( FT_UInt ) + FT_Get_Sfnt_Name_Count( FT_Face face ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Get_Sfnt_Name */ + /* */ + /* <Description> */ + /* Retrieves a string of the SFNT `name' table for a given index. */ + /* */ + /* <Input> */ + /* face :: A handle to the source face. */ + /* */ + /* idx :: The index of the `name' string. */ + /* */ + /* <Output> */ + /* aname :: The indexed @FT_SfntName structure. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* The `string' array returned in the `aname' structure is not */ + /* null-terminated. */ + /* */ + /* Use @FT_Get_Sfnt_Name_Count to get the total number of available */ + /* `name' table entries, then do a loop until you get the right */ + /* platform, encoding, and name ID. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Get_Sfnt_Name( FT_Face face, + FT_UInt idx, + FT_SfntName *aname ); + + + /* */ + + +FT_END_HEADER + +#endif /* __FT_SFNT_NAMES_H__ */ + + +/* END */ diff --git a/include/freetype/ftstroke.h b/include/freetype/ftstroke.h new file mode 100644 index 0000000..738b43c --- /dev/null +++ b/include/freetype/ftstroke.h @@ -0,0 +1,716 @@ +/***************************************************************************/ +/* */ +/* ftstroke.h */ +/* */ +/* FreeType path stroker (specification). */ +/* */ +/* Copyright 2002, 2003, 2004, 2005, 2006 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef __FT_STROKE_H__ +#define __FT_STROKE_H__ + +#include <ft2build.h> +#include FT_OUTLINE_H +#include FT_GLYPH_H + + +FT_BEGIN_HEADER + + + /************************************************************************ + * + * @section: + * glyph_stroker + * + * @title: + * Glyph Stroker + * + * @abstract: + * Generating bordered and stroked glyphs. + * + * @description: + * This component generates stroked outlines of a given vectorial + * glyph. It also allows you to retrieve the `outside' and/or the + * `inside' borders of the stroke. + * + * This can be useful to generate `bordered' glyph, i.e., glyphs + * displayed with a coloured (and anti-aliased) border around their + * shape. + */ + + + /************************************************************** + * + * @type: + * FT_Stroker + * + * @description: + * Opaque handler to a path stroker object. + */ + typedef struct FT_StrokerRec_* FT_Stroker; + + + /************************************************************** + * + * @enum: + * FT_Stroker_LineJoin + * + * @description: + * These values determine how two joining lines are rendered + * in a stroker. + * + * @values: + * FT_STROKER_LINEJOIN_ROUND :: + * Used to render rounded line joins. Circular arcs are used + * to join two lines smoothly. + * + * FT_STROKER_LINEJOIN_BEVEL :: + * Used to render beveled line joins; i.e., the two joining lines + * are extended until they intersect. + * + * FT_STROKER_LINEJOIN_MITER :: + * Same as beveled rendering, except that an additional line + * break is added if the angle between the two joining lines + * is too closed (this is useful to avoid unpleasant spikes + * in beveled rendering). + */ + typedef enum + { + FT_STROKER_LINEJOIN_ROUND = 0, + FT_STROKER_LINEJOIN_BEVEL, + FT_STROKER_LINEJOIN_MITER + + } FT_Stroker_LineJoin; + + + /************************************************************** + * + * @enum: + * FT_Stroker_LineCap + * + * @description: + * These values determine how the end of opened sub-paths are + * rendered in a stroke. + * + * @values: + * FT_STROKER_LINECAP_BUTT :: + * The end of lines is rendered as a full stop on the last + * point itself. + * + * FT_STROKER_LINECAP_ROUND :: + * The end of lines is rendered as a half-circle around the + * last point. + * + * FT_STROKER_LINECAP_SQUARE :: + * The end of lines is rendered as a square around the + * last point. + */ + typedef enum + { + FT_STROKER_LINECAP_BUTT = 0, + FT_STROKER_LINECAP_ROUND, + FT_STROKER_LINECAP_SQUARE + + } FT_Stroker_LineCap; + + + /************************************************************** + * + * @enum: + * FT_StrokerBorder + * + * @description: + * These values are used to select a given stroke border + * in @FT_Stroker_GetBorderCounts and @FT_Stroker_ExportBorder. + * + * @values: + * FT_STROKER_BORDER_LEFT :: + * Select the left border, relative to the drawing direction. + * + * FT_STROKER_BORDER_RIGHT :: + * Select the right border, relative to the drawing direction. + * + * @note: + * Applications are generally interested in the `inside' and `outside' + * borders. However, there is no direct mapping between these and the + * `left' and `right' ones, since this really depends on the glyph's + * drawing orientation, which varies between font formats. + * + * You can however use @FT_Outline_GetInsideBorder and + * @FT_Outline_GetOutsideBorder to get these. + */ + typedef enum + { + FT_STROKER_BORDER_LEFT = 0, + FT_STROKER_BORDER_RIGHT + + } FT_StrokerBorder; + + + /************************************************************** + * + * @function: + * FT_Outline_GetInsideBorder + * + * @description: + * Retrieve the @FT_StrokerBorder value corresponding to the + * `inside' borders of a given outline. + * + * @input: + * outline :: + * The source outline handle. + * + * @return: + * The border index. @FT_STROKER_BORDER_LEFT for empty or invalid + * outlines. + */ + FT_EXPORT( FT_StrokerBorder ) + FT_Outline_GetInsideBorder( FT_Outline* outline ); + + + /************************************************************** + * + * @function: + * FT_Outline_GetOutsideBorder + * + * @description: + * Retrieve the @FT_StrokerBorder value corresponding to the + * `outside' borders of a given outline. + * + * @input: + * outline :: + * The source outline handle. + * + * @return: + * The border index. @FT_STROKER_BORDER_LEFT for empty or invalid + * outlines. + */ + FT_EXPORT( FT_StrokerBorder ) + FT_Outline_GetOutsideBorder( FT_Outline* outline ); + + + /************************************************************** + * + * @function: + * FT_Stroker_New + * + * @description: + * Create a new stroker object. + * + * @input: + * library :: + * FreeType library handle. + * + * @output: + * astroker :: + * A new stroker object handle. NULL in case of error. + * + * @return: + * FreeType error code. 0 means success. + */ + FT_EXPORT( FT_Error ) + FT_Stroker_New( FT_Library library, + FT_Stroker *astroker ); + + + /************************************************************** + * + * @function: + * FT_Stroker_Set + * + * @description: + * Reset a stroker object's attributes. + * + * @input: + * stroker :: + * The target stroker handle. + * + * radius :: + * The border radius. + * + * line_cap :: + * The line cap style. + * + * line_join :: + * The line join style. + * + * miter_limit :: + * The miter limit for the FT_STROKER_LINEJOIN_MITER style, + * expressed as 16.16 fixed point value. + * + * @note: + * The radius is expressed in the same units that the outline + * coordinates. + */ + FT_EXPORT( void ) + FT_Stroker_Set( FT_Stroker stroker, + FT_Fixed radius, + FT_Stroker_LineCap line_cap, + FT_Stroker_LineJoin line_join, + FT_Fixed miter_limit ); + + + /************************************************************** + * + * @function: + * FT_Stroker_Rewind + * + * @description: + * Reset a stroker object without changing its attributes. + * You should call this function before beginning a new + * series of calls to @FT_Stroker_BeginSubPath or + * @FT_Stroker_EndSubPath. + * + * @input: + * stroker :: + * The target stroker handle. + */ + FT_EXPORT( void ) + FT_Stroker_Rewind( FT_Stroker stroker ); + + + /************************************************************** + * + * @function: + * FT_Stroker_ParseOutline + * + * @description: + * A convenience function used to parse a whole outline with + * the stroker. The resulting outline(s) can be retrieved + * later by functions like @FT_Stroker_GetCounts and @FT_Stroker_Export. + * + * @input: + * stroker :: + * The target stroker handle. + * + * outline :: + * The source outline. + * + * opened :: + * A boolean. If 1, the outline is treated as an open path instead + * of a closed one. + * + * @return: + * FreeType error code. 0 means success. + * + * @note: + * If `opened' is 0 (the default), the outline is treated as a closed + * path, and the stroker will generate two distinct `border' outlines. + * + * If `opened' is 1, the outline is processed as an open path, and the + * stroker will generate a single `stroke' outline. + * + * This function calls @FT_Stroker_Rewind automatically. + */ + FT_EXPORT( FT_Error ) + FT_Stroker_ParseOutline( FT_Stroker stroker, + FT_Outline* outline, + FT_Bool opened ); + + + /************************************************************** + * + * @function: + * FT_Stroker_BeginSubPath + * + * @description: + * Start a new sub-path in the stroker. + * + * @input: + * stroker :: + * The target stroker handle. + * + * to :: + * A pointer to the start vector. + * + * open :: + * A boolean. If 1, the sub-path is treated as an open one. + * + * @return: + * FreeType error code. 0 means success. + * + * @note: + * This function is useful when you need to stroke a path that is + * not stored as an @FT_Outline object. + */ + FT_EXPORT( FT_Error ) + FT_Stroker_BeginSubPath( FT_Stroker stroker, + FT_Vector* to, + FT_Bool open ); + + + /************************************************************** + * + * @function: + * FT_Stroker_EndSubPath + * + * @description: + * Close the current sub-path in the stroker. + * + * @input: + * stroker :: + * The target stroker handle. + * + * @return: + * FreeType error code. 0 means success. + * + * @note: + * You should call this function after @FT_Stroker_BeginSubPath. + * If the subpath was not `opened', this function will `draw' a + * single line segment to the start position when needed. + */ + FT_EXPORT( FT_Error ) + FT_Stroker_EndSubPath( FT_Stroker stroker ); + + + /************************************************************** + * + * @function: + * FT_Stroker_LineTo + * + * @description: + * `Draw' a single line segment in the stroker's current sub-path, + * from the last position. + * + * @input: + * stroker :: + * The target stroker handle. + * + * to :: + * A pointer to the destination point. + * + * @return: + * FreeType error code. 0 means success. + * + * @note: + * You should call this function between @FT_Stroker_BeginSubPath and + * @FT_Stroker_EndSubPath. + */ + FT_EXPORT( FT_Error ) + FT_Stroker_LineTo( FT_Stroker stroker, + FT_Vector* to ); + + + /************************************************************** + * + * @function: + * FT_Stroker_ConicTo + * + * @description: + * `Draw' a single quadratic Bézier in the stroker's current sub-path, + * from the last position. + * + * @input: + * stroker :: + * The target stroker handle. + * + * control :: + * A pointer to a Bézier control point. + * + * to :: + * A pointer to the destination point. + * + * @return: + * FreeType error code. 0 means success. + * + * @note: + * You should call this function between @FT_Stroker_BeginSubPath and + * @FT_Stroker_EndSubPath. + */ + FT_EXPORT( FT_Error ) + FT_Stroker_ConicTo( FT_Stroker stroker, + FT_Vector* control, + FT_Vector* to ); + + + /************************************************************** + * + * @function: + * FT_Stroker_CubicTo + * + * @description: + * `Draw' a single cubic Bézier in the stroker's current sub-path, + * from the last position. + * + * @input: + * stroker :: + * The target stroker handle. + * + * control1 :: + * A pointer to the first Bézier control point. + * + * control2 :: + * A pointer to second Bézier control point. + * + * to :: + * A pointer to the destination point. + * + * @return: + * FreeType error code. 0 means success. + * + * @note: + * You should call this function between @FT_Stroker_BeginSubPath and + * @FT_Stroker_EndSubPath. + */ + FT_EXPORT( FT_Error ) + FT_Stroker_CubicTo( FT_Stroker stroker, + FT_Vector* control1, + FT_Vector* control2, + FT_Vector* to ); + + + /************************************************************** + * + * @function: + * FT_Stroker_GetBorderCounts + * + * @description: + * Call this function once you have finished parsing your paths + * with the stroker. It will return the number of points and + * contours necessary to export one of the `border' or `stroke' + * outlines generated by the stroker. + * + * @input: + * stroker :: + * The target stroker handle. + * + * border :: + * The border index. + * + * @output: + * anum_points :: + * The number of points. + * + * anum_contours :: + * The number of contours. + * + * @return: + * FreeType error code. 0 means success. + * + * @note: + * When an outline, or a sub-path, is `closed', the stroker generates + * two independent `border' outlines, named `left' and `right'. + * + * When the outline, or a sub-path, is `opened', the stroker merges + * the `border' outlines with caps. The `left' border receives all + * points, while the `right' border becomes empty. + * + * Use the function @FT_Stroker_GetCounts instead if you want to + * retrieve the counts associated to both borders. + */ + FT_EXPORT( FT_Error ) + FT_Stroker_GetBorderCounts( FT_Stroker stroker, + FT_StrokerBorder border, + FT_UInt *anum_points, + FT_UInt *anum_contours ); + + + /************************************************************** + * + * @function: + * FT_Stroker_ExportBorder + * + * @description: + * Call this function after @FT_Stroker_GetBorderCounts to + * export the corresponding border to your own @FT_Outline + * structure. + * + * Note that this function will append the border points and + * contours to your outline, but will not try to resize its + * arrays. + * + * @input: + * stroker :: + * The target stroker handle. + * + * border :: + * The border index. + * + * outline :: + * The target outline handle. + * + * @note: + * Always call this function after @FT_Stroker_GetBorderCounts to + * get sure that there is enough room in your @FT_Outline object to + * receive all new data. + * + * When an outline, or a sub-path, is `closed', the stroker generates + * two independent `border' outlines, named `left' and `right' + * + * When the outline, or a sub-path, is `opened', the stroker merges + * the `border' outlines with caps. The `left' border receives all + * points, while the `right' border becomes empty. + * + * Use the function @FT_Stroker_Export instead if you want to + * retrieve all borders at once. + */ + FT_EXPORT( void ) + FT_Stroker_ExportBorder( FT_Stroker stroker, + FT_StrokerBorder border, + FT_Outline* outline ); + + + /************************************************************** + * + * @function: + * FT_Stroker_GetCounts + * + * @description: + * Call this function once you have finished parsing your paths + * with the stroker. It returns the number of points and + * contours necessary to export all points/borders from the stroked + * outline/path. + * + * @input: + * stroker :: + * The target stroker handle. + * + * @output: + * anum_points :: + * The number of points. + * + * anum_contours :: + * The number of contours. + * + * @return: + * FreeType error code. 0 means success. + */ + FT_EXPORT( FT_Error ) + FT_Stroker_GetCounts( FT_Stroker stroker, + FT_UInt *anum_points, + FT_UInt *anum_contours ); + + + /************************************************************** + * + * @function: + * FT_Stroker_Export + * + * @description: + * Call this function after @FT_Stroker_GetBorderCounts to + * export the all borders to your own @FT_Outline structure. + * + * Note that this function will append the border points and + * contours to your outline, but will not try to resize its + * arrays. + * + * @input: + * stroker :: + * The target stroker handle. + * + * outline :: + * The target outline handle. + */ + FT_EXPORT( void ) + FT_Stroker_Export( FT_Stroker stroker, + FT_Outline* outline ); + + + /************************************************************** + * + * @function: + * FT_Stroker_Done + * + * @description: + * Destroy a stroker object. + * + * @input: + * stroker :: + * A stroker handle. Can be NULL. + */ + FT_EXPORT( void ) + FT_Stroker_Done( FT_Stroker stroker ); + + + /************************************************************** + * + * @function: + * FT_Glyph_Stroke + * + * @description: + * Stroke a given outline glyph object with a given stroker. + * + * @inout: + * pglyph :: + * Source glyph handle on input, new glyph handle on output. + * + * @input: + * stroker :: + * A stroker handle. + * + * destroy :: + * A Boolean. If 1, the source glyph object is destroyed + * on success. + * + * @return: + * FreeType error code. 0 means success. + * + * @note: + * The source glyph is untouched in case of error. + */ + FT_EXPORT( FT_Error ) + FT_Glyph_Stroke( FT_Glyph *pglyph, + FT_Stroker stroker, + FT_Bool destroy ); + + + /************************************************************** + * + * @function: + * FT_Glyph_StrokeBorder + * + * @description: + * Stroke a given outline glyph object with a given stroker, but + * only return either its inside or outside border. + * + * @inout: + * pglyph :: + * Source glyph handle on input, new glyph handle on output. + * + * @input: + * stroker :: + * A stroker handle. + * + * inside :: + * A Boolean. If 1, return the inside border, otherwise + * the outside border. + * + * destroy :: + * A Boolean. If 1, the source glyph object is destroyed + * on success. + * + * @return: + * FreeType error code. 0 means success. + * + * @note: + * The source glyph is untouched in case of error. + */ + FT_EXPORT( FT_Error ) + FT_Glyph_StrokeBorder( FT_Glyph *pglyph, + FT_Stroker stroker, + FT_Bool inside, + FT_Bool destroy ); + + /* */ + +FT_END_HEADER + +#endif /* __FT_STROKE_H__ */ + + +/* END */ + + +/* Local Variables: */ +/* coding: utf-8 */ +/* End: */ diff --git a/include/freetype/ftsynth.h b/include/freetype/ftsynth.h new file mode 100644 index 0000000..36984bf --- /dev/null +++ b/include/freetype/ftsynth.h @@ -0,0 +1,73 @@ +/***************************************************************************/ +/* */ +/* ftsynth.h */ +/* */ +/* FreeType synthesizing code for emboldening and slanting */ +/* (specification). */ +/* */ +/* Copyright 2000-2001, 2003, 2006 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /********* *********/ + /********* WARNING, THIS IS ALPHA CODE, THIS API *********/ + /********* IS DUE TO CHANGE UNTIL STRICTLY NOTIFIED BY THE *********/ + /********* FREETYPE DEVELOPMENT TEAM *********/ + /********* *********/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + +#ifndef __FTSYNTH_H__ +#define __FTSYNTH_H__ + + +#include <ft2build.h> +#include FT_FREETYPE_H + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + /* Make sure slot owns slot->bitmap. */ + FT_EXPORT( FT_Error ) + FT_GlyphSlot_Own_Bitmap( FT_GlyphSlot slot ); + + /* Do not use this function directly! Copy the code to */ + /* your application and modify it to suit your need. */ + FT_EXPORT( void ) + FT_GlyphSlot_Embolden( FT_GlyphSlot slot ); + + + FT_EXPORT( void ) + FT_GlyphSlot_Oblique( FT_GlyphSlot slot ); + + /* */ + +FT_END_HEADER + +#endif /* __FTSYNTH_H__ */ + + +/* END */ diff --git a/include/freetype/ftsystem.h b/include/freetype/ftsystem.h new file mode 100644 index 0000000..59cd019 --- /dev/null +++ b/include/freetype/ftsystem.h @@ -0,0 +1,346 @@ +/***************************************************************************/ +/* */ +/* ftsystem.h */ +/* */ +/* FreeType low-level system interface definition (specification). */ +/* */ +/* Copyright 1996-2001, 2002, 2005 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef __FTSYSTEM_H__ +#define __FTSYSTEM_H__ + + +#include <ft2build.h> + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* system_interface */ + /* */ + /* <Title> */ + /* System Interface */ + /* */ + /* <Abstract> */ + /* How FreeType manages memory and i/o. */ + /* */ + /* <Description> */ + /* This section contains various definitions related to memory */ + /* management and i/o access. You need to understand this */ + /* information if you want to use a custom memory manager or you own */ + /* i/o streams. */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* M E M O R Y M A N A G E M E N T */ + /* */ + /*************************************************************************/ + + + /************************************************************************* + * + * @type: + * FT_Memory + * + * @description: + * A handle to a given memory manager object, defined with an + * @FT_MemoryRec structure. + * + */ + typedef struct FT_MemoryRec_* FT_Memory; + + + /************************************************************************* + * + * @functype: + * FT_Alloc_Func + * + * @description: + * A function used to allocate `size' bytes from `memory'. + * + * @input: + * memory :: + * A handle to the source memory manager. + * + * size :: + * The size in bytes to allocate. + * + * @return: + * Address of new memory block. 0 in case of failure. + * + */ + typedef void* + (*FT_Alloc_Func)( FT_Memory memory, + long size ); + + + /************************************************************************* + * + * @functype: + * FT_Free_Func + * + * @description: + * A function used to release a given block of memory. + * + * @input: + * memory :: + * A handle to the source memory manager. + * + * block :: + * The address of the target memory block. + * + */ + typedef void + (*FT_Free_Func)( FT_Memory memory, + void* block ); + + + /************************************************************************* + * + * @functype: + * FT_Realloc_Func + * + * @description: + * A function used to re-allocate a given block of memory. + * + * @input: + * memory :: + * A handle to the source memory manager. + * + * cur_size :: + * The block's current size in bytes. + * + * new_size :: + * The block's requested new size. + * + * block :: + * The block's current address. + * + * @return: + * New block address. 0 in case of memory shortage. + * + * @note: + * In case of error, the old block must still be available. + * + */ + typedef void* + (*FT_Realloc_Func)( FT_Memory memory, + long cur_size, + long new_size, + void* block ); + + + /************************************************************************* + * + * @struct: + * FT_MemoryRec + * + * @description: + * A structure used to describe a given memory manager to FreeType 2. + * + * @fields: + * user :: + * A generic typeless pointer for user data. + * + * alloc :: + * A pointer type to an allocation function. + * + * free :: + * A pointer type to an memory freeing function. + * + * realloc :: + * A pointer type to a reallocation function. + * + */ + struct FT_MemoryRec_ + { + void* user; + FT_Alloc_Func alloc; + FT_Free_Func free; + FT_Realloc_Func realloc; + }; + + + /*************************************************************************/ + /* */ + /* I / O M A N A G E M E N T */ + /* */ + /*************************************************************************/ + + + /************************************************************************* + * + * @type: + * FT_Stream + * + * @description: + * A handle to an input stream. + * + */ + typedef struct FT_StreamRec_* FT_Stream; + + + /************************************************************************* + * + * @struct: + * FT_StreamDesc + * + * @description: + * A union type used to store either a long or a pointer. This is used + * to store a file descriptor or a `FILE*' in an input stream. + * + */ + typedef union FT_StreamDesc_ + { + long value; + void* pointer; + + } FT_StreamDesc; + + + /************************************************************************* + * + * @functype: + * FT_Stream_IoFunc + * + * @description: + * A function used to seek and read data from a given input stream. + * + * @input: + * stream :: + * A handle to the source stream. + * + * offset :: + * The offset of read in stream (always from start). + * + * buffer :: + * The address of the read buffer. + * + * count :: + * The number of bytes to read from the stream. + * + * @return: + * The number of bytes effectively read by the stream. + * + * @note: + * This function might be called to perform a seek or skip operation + * with a `count' of 0. + * + */ + typedef unsigned long + (*FT_Stream_IoFunc)( FT_Stream stream, + unsigned long offset, + unsigned char* buffer, + unsigned long count ); + + + /************************************************************************* + * + * @functype: + * FT_Stream_CloseFunc + * + * @description: + * A function used to close a given input stream. + * + * @input: + * stream :: + * A handle to the target stream. + * + */ + typedef void + (*FT_Stream_CloseFunc)( FT_Stream stream ); + + + /************************************************************************* + * + * @struct: + * FT_StreamRec + * + * @description: + * A structure used to describe an input stream. + * + * @input: + * base :: + * For memory-based streams, this is the address of the first stream + * byte in memory. This field should always be set to NULL for + * disk-based streams. + * + * size :: + * The stream size in bytes. + * + * pos :: + * The current position within the stream. + * + * descriptor :: + * This field is a union that can hold an integer or a pointer. It is + * used by stream implementations to store file descriptors or `FILE*' + * pointers. + * + * pathname :: + * This field is completely ignored by FreeType. However, it is often + * useful during debugging to use it to store the stream's filename + * (where available). + * + * read :: + * The stream's input function. + * + * close :: + * The stream;s close function. + * + * memory :: + * The memory manager to use to preload frames. This is set + * internally by FreeType and shouldn't be touched by stream + * implementations. + * + * cursor :: + * This field is set and used internally by FreeType when parsing + * frames. + * + * limit :: + * This field is set and used internally by FreeType when parsing + * frames. + * + */ + typedef struct FT_StreamRec_ + { + unsigned char* base; + unsigned long size; + unsigned long pos; + + FT_StreamDesc descriptor; + FT_StreamDesc pathname; + FT_Stream_IoFunc read; + FT_Stream_CloseFunc close; + + FT_Memory memory; + unsigned char* cursor; + unsigned char* limit; + + } FT_StreamRec; + + + /* */ + + +FT_END_HEADER + +#endif /* __FTSYSTEM_H__ */ + + +/* END */ diff --git a/include/freetype/fttrigon.h b/include/freetype/fttrigon.h new file mode 100644 index 0000000..6b77d2e --- /dev/null +++ b/include/freetype/fttrigon.h @@ -0,0 +1,350 @@ +/***************************************************************************/ +/* */ +/* fttrigon.h */ +/* */ +/* FreeType trigonometric functions (specification). */ +/* */ +/* Copyright 2001, 2003, 2005, 2007 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef __FTTRIGON_H__ +#define __FTTRIGON_H__ + +#include FT_FREETYPE_H + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* computations */ + /* */ + /*************************************************************************/ + + + /************************************************************************* + * + * @type: + * FT_Angle + * + * @description: + * This type is used to model angle values in FreeType. Note that the + * angle is a 16.16 fixed float value expressed in degrees. + * + */ + typedef FT_Fixed FT_Angle; + + + /************************************************************************* + * + * @macro: + * FT_ANGLE_PI + * + * @description: + * The angle pi expressed in @FT_Angle units. + * + */ +#define FT_ANGLE_PI ( 180L << 16 ) + + + /************************************************************************* + * + * @macro: + * FT_ANGLE_2PI + * + * @description: + * The angle 2*pi expressed in @FT_Angle units. + * + */ +#define FT_ANGLE_2PI ( FT_ANGLE_PI * 2 ) + + + /************************************************************************* + * + * @macro: + * FT_ANGLE_PI2 + * + * @description: + * The angle pi/2 expressed in @FT_Angle units. + * + */ +#define FT_ANGLE_PI2 ( FT_ANGLE_PI / 2 ) + + + /************************************************************************* + * + * @macro: + * FT_ANGLE_PI4 + * + * @description: + * The angle pi/4 expressed in @FT_Angle units. + * + */ +#define FT_ANGLE_PI4 ( FT_ANGLE_PI / 4 ) + + + /************************************************************************* + * + * @function: + * FT_Sin + * + * @description: + * Return the sinus of a given angle in fixed point format. + * + * @input: + * angle :: + * The input angle. + * + * @return: + * The sinus value. + * + * @note: + * If you need both the sinus and cosinus for a given angle, use the + * function @FT_Vector_Unit. + * + */ + FT_EXPORT( FT_Fixed ) + FT_Sin( FT_Angle angle ); + + + /************************************************************************* + * + * @function: + * FT_Cos + * + * @description: + * Return the cosinus of a given angle in fixed point format. + * + * @input: + * angle :: + * The input angle. + * + * @return: + * The cosinus value. + * + * @note: + * If you need both the sinus and cosinus for a given angle, use the + * function @FT_Vector_Unit. + * + */ + FT_EXPORT( FT_Fixed ) + FT_Cos( FT_Angle angle ); + + + /************************************************************************* + * + * @function: + * FT_Tan + * + * @description: + * Return the tangent of a given angle in fixed point format. + * + * @input: + * angle :: + * The input angle. + * + * @return: + * The tangent value. + * + */ + FT_EXPORT( FT_Fixed ) + FT_Tan( FT_Angle angle ); + + + /************************************************************************* + * + * @function: + * FT_Atan2 + * + * @description: + * Return the arc-tangent corresponding to a given vector (x,y) in + * the 2d plane. + * + * @input: + * x :: + * The horizontal vector coordinate. + * + * y :: + * The vertical vector coordinate. + * + * @return: + * The arc-tangent value (i.e. angle). + * + */ + FT_EXPORT( FT_Angle ) + FT_Atan2( FT_Fixed x, + FT_Fixed y ); + + + /************************************************************************* + * + * @function: + * FT_Angle_Diff + * + * @description: + * Return the difference between two angles. The result is always + * constrained to the ]-PI..PI] interval. + * + * @input: + * angle1 :: + * First angle. + * + * angle2 :: + * Second angle. + * + * @return: + * Constrained value of `value2-value1'. + * + */ + FT_EXPORT( FT_Angle ) + FT_Angle_Diff( FT_Angle angle1, + FT_Angle angle2 ); + + + /************************************************************************* + * + * @function: + * FT_Vector_Unit + * + * @description: + * Return the unit vector corresponding to a given angle. After the + * call, the value of `vec.x' will be `sin(angle)', and the value of + * `vec.y' will be `cos(angle)'. + * + * This function is useful to retrieve both the sinus and cosinus of a + * given angle quickly. + * + * @output: + * vec :: + * The address of target vector. + * + * @input: + * angle :: + * The address of angle. + * + */ + FT_EXPORT( void ) + FT_Vector_Unit( FT_Vector* vec, + FT_Angle angle ); + + + /************************************************************************* + * + * @function: + * FT_Vector_Rotate + * + * @description: + * Rotate a vector by a given angle. + * + * @inout: + * vec :: + * The address of target vector. + * + * @input: + * angle :: + * The address of angle. + * + */ + FT_EXPORT( void ) + FT_Vector_Rotate( FT_Vector* vec, + FT_Angle angle ); + + + /************************************************************************* + * + * @function: + * FT_Vector_Length + * + * @description: + * Return the length of a given vector. + * + * @input: + * vec :: + * The address of target vector. + * + * @return: + * The vector length, expressed in the same units that the original + * vector coordinates. + * + */ + FT_EXPORT( FT_Fixed ) + FT_Vector_Length( FT_Vector* vec ); + + + /************************************************************************* + * + * @function: + * FT_Vector_Polarize + * + * @description: + * Compute both the length and angle of a given vector. + * + * @input: + * vec :: + * The address of source vector. + * + * @output: + * length :: + * The vector length. + * + * angle :: + * The vector angle. + * + */ + FT_EXPORT( void ) + FT_Vector_Polarize( FT_Vector* vec, + FT_Fixed *length, + FT_Angle *angle ); + + + /************************************************************************* + * + * @function: + * FT_Vector_From_Polar + * + * @description: + * Compute vector coordinates from a length and angle. + * + * @output: + * vec :: + * The address of source vector. + * + * @input: + * length :: + * The vector length. + * + * angle :: + * The vector angle. + * + */ + FT_EXPORT( void ) + FT_Vector_From_Polar( FT_Vector* vec, + FT_Fixed length, + FT_Angle angle ); + + /* */ + + +FT_END_HEADER + +#endif /* __FTTRIGON_H__ */ + + +/* END */ diff --git a/include/freetype/fttypes.h b/include/freetype/fttypes.h new file mode 100644 index 0000000..2340bac --- /dev/null +++ b/include/freetype/fttypes.h @@ -0,0 +1,583 @@ +/***************************************************************************/ +/* */ +/* fttypes.h */ +/* */ +/* FreeType simple types definitions (specification only). */ +/* */ +/* Copyright 1996-2001, 2002, 2004, 2006, 2007 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef __FTTYPES_H__ +#define __FTTYPES_H__ + + +#include <ft2build.h> +#include FT_CONFIG_CONFIG_H +#include FT_SYSTEM_H +#include FT_IMAGE_H + +#include <stddef.h> + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* basic_types */ + /* */ + /* <Title> */ + /* Basic Data Types */ + /* */ + /* <Abstract> */ + /* The basic data types defined by the library. */ + /* */ + /* <Description> */ + /* This section contains the basic data types defined by FreeType 2, */ + /* ranging from simple scalar types to bitmap descriptors. More */ + /* font-specific structures are defined in a different section. */ + /* */ + /* <Order> */ + /* FT_Byte */ + /* FT_Bytes */ + /* FT_Char */ + /* FT_Int */ + /* FT_UInt */ + /* FT_Short */ + /* FT_UShort */ + /* FT_Long */ + /* FT_ULong */ + /* FT_Bool */ + /* FT_Offset */ + /* FT_PtrDist */ + /* FT_String */ + /* FT_Tag */ + /* FT_Error */ + /* FT_Fixed */ + /* FT_Pointer */ + /* FT_Pos */ + /* FT_Vector */ + /* FT_BBox */ + /* FT_Matrix */ + /* FT_FWord */ + /* FT_UFWord */ + /* FT_F2Dot14 */ + /* FT_UnitVector */ + /* FT_F26Dot6 */ + /* */ + /* */ + /* FT_Generic */ + /* FT_Generic_Finalizer */ + /* */ + /* FT_Bitmap */ + /* FT_Pixel_Mode */ + /* FT_Palette_Mode */ + /* FT_Glyph_Format */ + /* FT_IMAGE_TAG */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_Bool */ + /* */ + /* <Description> */ + /* A typedef of unsigned char, used for simple booleans. As usual, */ + /* values 1 and 0 represent true and false, respectively. */ + /* */ + typedef unsigned char FT_Bool; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_FWord */ + /* */ + /* <Description> */ + /* A signed 16-bit integer used to store a distance in original font */ + /* units. */ + /* */ + typedef signed short FT_FWord; /* distance in FUnits */ + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_UFWord */ + /* */ + /* <Description> */ + /* An unsigned 16-bit integer used to store a distance in original */ + /* font units. */ + /* */ + typedef unsigned short FT_UFWord; /* unsigned distance */ + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_Char */ + /* */ + /* <Description> */ + /* A simple typedef for the _signed_ char type. */ + /* */ + typedef signed char FT_Char; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_Byte */ + /* */ + /* <Description> */ + /* A simple typedef for the _unsigned_ char type. */ + /* */ + typedef unsigned char FT_Byte; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_Bytes */ + /* */ + /* <Description> */ + /* A typedef for constant memory areas. */ + /* */ + typedef const FT_Byte* FT_Bytes; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_Tag */ + /* */ + /* <Description> */ + /* A typedef for 32bit tags (as used in the SFNT format). */ + /* */ + typedef FT_UInt32 FT_Tag; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_String */ + /* */ + /* <Description> */ + /* A simple typedef for the char type, usually used for strings. */ + /* */ + typedef char FT_String; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_Short */ + /* */ + /* <Description> */ + /* A typedef for signed short. */ + /* */ + typedef signed short FT_Short; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_UShort */ + /* */ + /* <Description> */ + /* A typedef for unsigned short. */ + /* */ + typedef unsigned short FT_UShort; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_Int */ + /* */ + /* <Description> */ + /* A typedef for the int type. */ + /* */ + typedef signed int FT_Int; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_UInt */ + /* */ + /* <Description> */ + /* A typedef for the unsigned int type. */ + /* */ + typedef unsigned int FT_UInt; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_Long */ + /* */ + /* <Description> */ + /* A typedef for signed long. */ + /* */ + typedef signed long FT_Long; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_ULong */ + /* */ + /* <Description> */ + /* A typedef for unsigned long. */ + /* */ + typedef unsigned long FT_ULong; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_F2Dot14 */ + /* */ + /* <Description> */ + /* A signed 2.14 fixed float type used for unit vectors. */ + /* */ + typedef signed short FT_F2Dot14; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_F26Dot6 */ + /* */ + /* <Description> */ + /* A signed 26.6 fixed float type used for vectorial pixel */ + /* coordinates. */ + /* */ + typedef signed long FT_F26Dot6; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_Fixed */ + /* */ + /* <Description> */ + /* This type is used to store 16.16 fixed float values, like scaling */ + /* values or matrix coefficients. */ + /* */ + typedef signed long FT_Fixed; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_Error */ + /* */ + /* <Description> */ + /* The FreeType error code type. A value of 0 is always interpreted */ + /* as a successful operation. */ + /* */ + typedef int FT_Error; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_Pointer */ + /* */ + /* <Description> */ + /* A simple typedef for a typeless pointer. */ + /* */ + typedef void* FT_Pointer; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_Offset */ + /* */ + /* <Description> */ + /* This is equivalent to the ANSI C `size_t' type, i.e., the largest */ + /* _unsigned_ integer type used to express a file size or position, */ + /* or a memory block size. */ + /* */ + typedef size_t FT_Offset; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_PtrDist */ + /* */ + /* <Description> */ + /* This is equivalent to the ANSI C `ptrdiff_t' type, i.e., the */ + /* largest _signed_ integer type used to express the distance */ + /* between two pointers. */ + /* */ + typedef ft_ptrdiff_t FT_PtrDist; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_UnitVector */ + /* */ + /* <Description> */ + /* A simple structure used to store a 2D vector unit vector. Uses */ + /* FT_F2Dot14 types. */ + /* */ + /* <Fields> */ + /* x :: Horizontal coordinate. */ + /* */ + /* y :: Vertical coordinate. */ + /* */ + typedef struct FT_UnitVector_ + { + FT_F2Dot14 x; + FT_F2Dot14 y; + + } FT_UnitVector; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_Matrix */ + /* */ + /* <Description> */ + /* A simple structure used to store a 2x2 matrix. Coefficients are */ + /* in 16.16 fixed float format. The computation performed is: */ + /* */ + /* { */ + /* x' = x*xx + y*xy */ + /* y' = x*yx + y*yy */ + /* } */ + /* */ + /* <Fields> */ + /* xx :: Matrix coefficient. */ + /* */ + /* xy :: Matrix coefficient. */ + /* */ + /* yx :: Matrix coefficient. */ + /* */ + /* yy :: Matrix coefficient. */ + /* */ + typedef struct FT_Matrix_ + { + FT_Fixed xx, xy; + FT_Fixed yx, yy; + + } FT_Matrix; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_Data */ + /* */ + /* <Description> */ + /* Read-only binary data represented as a pointer and a length. */ + /* */ + /* <Fields> */ + /* pointer :: The data. */ + /* */ + /* length :: The length of the data in bytes. */ + /* */ + typedef struct FT_Data_ + { + const FT_Byte* pointer; + FT_Int length; + + } FT_Data; + + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* FT_Generic_Finalizer */ + /* */ + /* <Description> */ + /* Describes a function used to destroy the `client' data of any */ + /* FreeType object. See the description of the @FT_Generic type for */ + /* details of usage. */ + /* */ + /* <Input> */ + /* The address of the FreeType object which is under finalization. */ + /* Its client data is accessed through its `generic' field. */ + /* */ + typedef void (*FT_Generic_Finalizer)(void* object); + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_Generic */ + /* */ + /* <Description> */ + /* Client applications often need to associate their own data to a */ + /* variety of FreeType core objects. For example, a text layout API */ + /* might want to associate a glyph cache to a given size object. */ + /* */ + /* Most FreeType object contains a `generic' field, of type */ + /* FT_Generic, which usage is left to client applications and font */ + /* servers. */ + /* */ + /* It can be used to store a pointer to client-specific data, as well */ + /* as the address of a `finalizer' function, which will be called by */ + /* FreeType when the object is destroyed (for example, the previous */ + /* client example would put the address of the glyph cache destructor */ + /* in the `finalizer' field). */ + /* */ + /* <Fields> */ + /* data :: A typeless pointer to any client-specified data. This */ + /* field is completely ignored by the FreeType library. */ + /* */ + /* finalizer :: A pointer to a `generic finalizer' function, which */ + /* will be called when the object is destroyed. If this */ + /* field is set to NULL, no code will be called. */ + /* */ + typedef struct FT_Generic_ + { + void* data; + FT_Generic_Finalizer finalizer; + + } FT_Generic; + + + /*************************************************************************/ + /* */ + /* <Macro> */ + /* FT_MAKE_TAG */ + /* */ + /* <Description> */ + /* This macro converts four-letter tags which are used to label */ + /* TrueType tables into an unsigned long to be used within FreeType. */ + /* */ + /* <Note> */ + /* The produced values *must* be 32bit integers. Don't redefine this */ + /* macro. */ + /* */ +#define FT_MAKE_TAG( _x1, _x2, _x3, _x4 ) \ + ( ( (FT_ULong)_x1 << 24 ) | \ + ( (FT_ULong)_x2 << 16 ) | \ + ( (FT_ULong)_x3 << 8 ) | \ + (FT_ULong)_x4 ) + + + /*************************************************************************/ + /*************************************************************************/ + /* */ + /* L I S T M A N A G E M E N T */ + /* */ + /*************************************************************************/ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* list_processing */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_ListNode */ + /* */ + /* <Description> */ + /* Many elements and objects in FreeType are listed through an */ + /* @FT_List record (see @FT_ListRec). As its name suggests, an */ + /* FT_ListNode is a handle to a single list element. */ + /* */ + typedef struct FT_ListNodeRec_* FT_ListNode; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_List */ + /* */ + /* <Description> */ + /* A handle to a list record (see @FT_ListRec). */ + /* */ + typedef struct FT_ListRec_* FT_List; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_ListNodeRec */ + /* */ + /* <Description> */ + /* A structure used to hold a single list element. */ + /* */ + /* <Fields> */ + /* prev :: The previous element in the list. NULL if first. */ + /* */ + /* next :: The next element in the list. NULL if last. */ + /* */ + /* data :: A typeless pointer to the listed object. */ + /* */ + typedef struct FT_ListNodeRec_ + { + FT_ListNode prev; + FT_ListNode next; + void* data; + + } FT_ListNodeRec; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_ListRec */ + /* */ + /* <Description> */ + /* A structure used to hold a simple doubly-linked list. These are */ + /* used in many parts of FreeType. */ + /* */ + /* <Fields> */ + /* head :: The head (first element) of doubly-linked list. */ + /* */ + /* tail :: The tail (last element) of doubly-linked list. */ + /* */ + typedef struct FT_ListRec_ + { + FT_ListNode head; + FT_ListNode tail; + + } FT_ListRec; + + + /* */ + +#define FT_IS_EMPTY( list ) ( (list).head == 0 ) + + /* return base error code (without module-specific prefix) */ +#define FT_ERROR_BASE( x ) ( (x) & 0xFF ) + + /* return module error code */ +#define FT_ERROR_MODULE( x ) ( (x) & 0xFF00U ) + +#define FT_BOOL( x ) ( (FT_Bool)( x ) ) + +FT_END_HEADER + +#endif /* __FTTYPES_H__ */ + + +/* END */ diff --git a/include/freetype/ftwinfnt.h b/include/freetype/ftwinfnt.h new file mode 100644 index 0000000..a0063cc --- /dev/null +++ b/include/freetype/ftwinfnt.h @@ -0,0 +1,263 @@ +/***************************************************************************/ +/* */ +/* ftwinfnt.h */ +/* */ +/* FreeType API for accessing Windows fnt-specific data. */ +/* */ +/* Copyright 2003, 2004 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef __FTWINFNT_H__ +#define __FTWINFNT_H__ + +#include <ft2build.h> +#include FT_FREETYPE_H + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* winfnt_fonts */ + /* */ + /* <Title> */ + /* Window FNT Files */ + /* */ + /* <Abstract> */ + /* Windows FNT specific API. */ + /* */ + /* <Description> */ + /* This section contains the declaration of Windows FNT specific */ + /* functions. */ + /* */ + /*************************************************************************/ + + + /************************************************************************* + * + * @enum: + * FT_WinFNT_ID_XXX + * + * @description: + * A list of valid values for the `charset' byte in + * @FT_WinFNT_HeaderRec. Exact mapping tables for the various cpXXXX + * encodings (except for cp1361) can be found at ftp://ftp.unicode.org + * in the MAPPINGS/VENDORS/MICSFT/WINDOWS subdirectory. cp1361 is + * roughly a superset of MAPPINGS/OBSOLETE/EASTASIA/KSC/JOHAB.TXT. + * + * @values: + * FT_WinFNT_ID_DEFAULT :: + * This is used for font enumeration and font creation as a + * `don't care' value. Valid font files don't contain this value. + * When querying for information about the character set of the font + * that is currently selected into a specified device context, this + * return value (of the related Windows API) simply denotes failure. + * + * FT_WinFNT_ID_SYMBOL :: + * There is no known mapping table available. + * + * FT_WinFNT_ID_MAC :: + * Mac Roman encoding. + * + * FT_WinFNT_ID_OEM :: + * From Michael Pöttgen <michael@poettgen.de>: + * + * The `Windows Font Mapping' article says that FT_WinFNT_ID_OEM + * is used for the charset of vector fonts, like `modern.fon', + * `roman.fon', and `script.fon' on Windows. + * + * The `CreateFont' documentation says: The FT_WinFNT_ID_OEM value + * specifies a character set that is operating-system dependent. + * + * The `IFIMETRICS' documentation from the `Windows Driver + * Development Kit' says: This font supports an OEM-specific + * character set. The OEM character set is system dependent. + * + * In general OEM, as opposed to ANSI (i.e., cp1252), denotes the + * second default codepage that most international versions of + * Windows have. It is one of the OEM codepages from + * + * http://www.microsoft.com/globaldev/reference/cphome.mspx, + * + * and is used for the `DOS boxes', to support legacy applications. + * A German Windows version for example usually uses ANSI codepage + * 1252 and OEM codepage 850. + * + * FT_WinFNT_ID_CP874 :: + * A superset of Thai TIS 620 and ISO 8859-11. + * + * FT_WinFNT_ID_CP932 :: + * A superset of Japanese Shift-JIS (with minor deviations). + * + * FT_WinFNT_ID_CP936 :: + * A superset of simplified Chinese GB 2312-1980 (with different + * ordering and minor deviations). + * + * FT_WinFNT_ID_CP949 :: + * A superset of Korean Hangul KS C 5601-1987 (with different + * ordering and minor deviations). + * + * FT_WinFNT_ID_CP950 :: + * A superset of traditional Chinese Big 5 ETen (with different + * ordering and minor deviations). + * + * FT_WinFNT_ID_CP1250 :: + * A superset of East European ISO 8859-2 (with slightly different + * ordering). + * + * FT_WinFNT_ID_CP1251 :: + * A superset of Russian ISO 8859-5 (with different ordering). + * + * FT_WinFNT_ID_CP1252 :: + * ANSI encoding. A superset of ISO 8859-1. + * + * FT_WinFNT_ID_CP1253 :: + * A superset of Greek ISO 8859-7 (with minor modifications). + * + * FT_WinFNT_ID_CP1254 :: + * A superset of Turkish ISO 8859-9. + * + * FT_WinFNT_ID_CP1255 :: + * A superset of Hebrew ISO 8859-8 (with some modifications). + * + * FT_WinFNT_ID_CP1256 :: + * A superset of Arabic ISO 8859-6 (with different ordering). + * + * FT_WinFNT_ID_CP1257 :: + * A superset of Baltic ISO 8859-13 (with some deviations). + * + * FT_WinFNT_ID_CP1258 :: + * For Vietnamese. This encoding doesn't cover all necessary + * characters. + * + * FT_WinFNT_ID_CP1361 :: + * Korean (Johab). + */ + +#define FT_WinFNT_ID_CP1252 0 +#define FT_WinFNT_ID_DEFAULT 1 +#define FT_WinFNT_ID_SYMBOL 2 +#define FT_WinFNT_ID_MAC 77 +#define FT_WinFNT_ID_CP932 128 +#define FT_WinFNT_ID_CP949 129 +#define FT_WinFNT_ID_CP1361 130 +#define FT_WinFNT_ID_CP936 134 +#define FT_WinFNT_ID_CP950 136 +#define FT_WinFNT_ID_CP1253 161 +#define FT_WinFNT_ID_CP1254 162 +#define FT_WinFNT_ID_CP1258 163 +#define FT_WinFNT_ID_CP1255 177 +#define FT_WinFNT_ID_CP1256 178 +#define FT_WinFNT_ID_CP1257 186 +#define FT_WinFNT_ID_CP1251 204 +#define FT_WinFNT_ID_CP874 222 +#define FT_WinFNT_ID_CP1250 238 +#define FT_WinFNT_ID_OEM 255 + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_WinFNT_HeaderRec */ + /* */ + /* <Description> */ + /* Windows FNT Header info. */ + /* */ + typedef struct FT_WinFNT_HeaderRec_ + { + FT_UShort version; + FT_ULong file_size; + FT_Byte copyright[60]; + FT_UShort file_type; + FT_UShort nominal_point_size; + FT_UShort vertical_resolution; + FT_UShort horizontal_resolution; + FT_UShort ascent; + FT_UShort internal_leading; + FT_UShort external_leading; + FT_Byte italic; + FT_Byte underline; + FT_Byte strike_out; + FT_UShort weight; + FT_Byte charset; + FT_UShort pixel_width; + FT_UShort pixel_height; + FT_Byte pitch_and_family; + FT_UShort avg_width; + FT_UShort max_width; + FT_Byte first_char; + FT_Byte last_char; + FT_Byte default_char; + FT_Byte break_char; + FT_UShort bytes_per_row; + FT_ULong device_offset; + FT_ULong face_name_offset; + FT_ULong bits_pointer; + FT_ULong bits_offset; + FT_Byte reserved; + FT_ULong flags; + FT_UShort A_space; + FT_UShort B_space; + FT_UShort C_space; + FT_UShort color_table_offset; + FT_ULong reserved1[4]; + + } FT_WinFNT_HeaderRec, *FT_WinFNT_Header; + + + /********************************************************************** + * + * @function: + * FT_Get_WinFNT_Header + * + * @description: + * Retrieve a Windows FNT font info header. + * + * @input: + * face :: A handle to the input face. + * + * @output: + * aheader :: The WinFNT header. + * + * @return: + * FreeType error code. 0 means success. + * + * @note: + * This function only works with Windows FNT faces, returning an error + * otherwise. + */ + FT_EXPORT( FT_Error ) + FT_Get_WinFNT_Header( FT_Face face, + FT_WinFNT_HeaderRec *aheader ); + + + /* */ + +FT_END_HEADER + +#endif /* __FTWINFNT_H__ */ + + +/* END */ + + +/* Local Variables: */ +/* coding: utf-8 */ +/* End: */ diff --git a/include/freetype/ftxf86.h b/include/freetype/ftxf86.h new file mode 100644 index 0000000..ea82abb --- /dev/null +++ b/include/freetype/ftxf86.h @@ -0,0 +1,80 @@ +/***************************************************************************/ +/* */ +/* ftxf86.h */ +/* */ +/* Support functions for X11. */ +/* */ +/* Copyright 2002, 2003, 2004, 2006, 2007 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef __FTXF86_H__ +#define __FTXF86_H__ + +#include <ft2build.h> +#include FT_FREETYPE_H + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* font_formats */ + /* */ + /* <Title> */ + /* Font Formats */ + /* */ + /* <Abstract> */ + /* Getting the font format. */ + /* */ + /* <Description> */ + /* The single function in this section can be used to get the font */ + /* format. Note that this information is not needed normally; */ + /* however, there are special cases (like in PDF devices) where it is */ + /* important to differentiate, in spite of FreeType's uniform API. */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Get_X11_Font_Format */ + /* */ + /* <Description> */ + /* Return a string describing the format of a given face, using values */ + /* which can be used as an X11 FONT_PROPERTY. Possible values are */ + /* `TrueType', `Type 1', `BDF', `PCF', `Type 42', `CID Type 1', `CFF', */ + /* `PFR', and `Windows FNT'. */ + /* */ + /* <Input> */ + /* face :: */ + /* Input face handle. */ + /* */ + /* <Return> */ + /* Font format string. NULL in case of error. */ + /* */ + FT_EXPORT( const char* ) + FT_Get_X11_Font_Format( FT_Face face ); + + /* */ + +FT_END_HEADER + +#endif /* __FTXF86_H__ */ diff --git a/include/freetype/t1tables.h b/include/freetype/t1tables.h new file mode 100644 index 0000000..250629d --- /dev/null +++ b/include/freetype/t1tables.h @@ -0,0 +1,450 @@ +/***************************************************************************/ +/* */ +/* t1tables.h */ +/* */ +/* Basic Type 1/Type 2 tables definitions and interface (specification */ +/* only). */ +/* */ +/* Copyright 1996-2001, 2002, 2003, 2004, 2006 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef __T1TABLES_H__ +#define __T1TABLES_H__ + + +#include <ft2build.h> +#include FT_FREETYPE_H + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* type1_tables */ + /* */ + /* <Title> */ + /* Type 1 Tables */ + /* */ + /* <Abstract> */ + /* Type 1 (PostScript) specific font tables. */ + /* */ + /* <Description> */ + /* This section contains the definition of Type 1-specific tables, */ + /* including structures related to other PostScript font formats. */ + /* */ + /*************************************************************************/ + + + /* Note that we separate font data in PS_FontInfoRec and PS_PrivateRec */ + /* structures in order to support Multiple Master fonts. */ + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* PS_FontInfoRec */ + /* */ + /* <Description> */ + /* A structure used to model a Type1/Type2 FontInfo dictionary. Note */ + /* that for Multiple Master fonts, each instance has its own */ + /* FontInfo dictionary. */ + /* */ + typedef struct PS_FontInfoRec + { + FT_String* version; + FT_String* notice; + FT_String* full_name; + FT_String* family_name; + FT_String* weight; + FT_Long italic_angle; + FT_Bool is_fixed_pitch; + FT_Short underline_position; + FT_UShort underline_thickness; + + } PS_FontInfoRec, *PS_FontInfo; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* T1_FontInfo */ + /* */ + /* <Description> */ + /* This type is equivalent to @PS_FontInfoRec. It is deprecated but */ + /* kept to maintain source compatibility between various versions of */ + /* FreeType. */ + /* */ + typedef PS_FontInfoRec T1_FontInfo; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* PS_PrivateRec */ + /* */ + /* <Description> */ + /* A structure used to model a Type1/Type2 private dictionary. Note */ + /* that for Multiple Master fonts, each instance has its own Private */ + /* dictionary. */ + /* */ + typedef struct PS_PrivateRec_ + { + FT_Int unique_id; + FT_Int lenIV; + + FT_Byte num_blue_values; + FT_Byte num_other_blues; + FT_Byte num_family_blues; + FT_Byte num_family_other_blues; + + FT_Short blue_values[14]; + FT_Short other_blues[10]; + + FT_Short family_blues [14]; + FT_Short family_other_blues[10]; + + FT_Fixed blue_scale; + FT_Int blue_shift; + FT_Int blue_fuzz; + + FT_UShort standard_width[1]; + FT_UShort standard_height[1]; + + FT_Byte num_snap_widths; + FT_Byte num_snap_heights; + FT_Bool force_bold; + FT_Bool round_stem_up; + + FT_Short snap_widths [13]; /* including std width */ + FT_Short snap_heights[13]; /* including std height */ + + FT_Fixed expansion_factor; + + FT_Long language_group; + FT_Long password; + + FT_Short min_feature[2]; + + } PS_PrivateRec, *PS_Private; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* T1_Private */ + /* */ + /* <Description> */ + /* This type is equivalent to @PS_PrivateRec. It is deprecated but */ + /* kept to maintain source compatibility between various versions of */ + /* FreeType. */ + /* */ + typedef PS_PrivateRec T1_Private; + + + /*************************************************************************/ + /* */ + /* <Enum> */ + /* T1_Blend_Flags */ + /* */ + /* <Description> */ + /* A set of flags used to indicate which fields are present in a */ + /* given blend dictionary (font info or private). Used to support */ + /* Multiple Masters fonts. */ + /* */ + typedef enum + { + /*# required fields in a FontInfo blend dictionary */ + T1_BLEND_UNDERLINE_POSITION = 0, + T1_BLEND_UNDERLINE_THICKNESS, + T1_BLEND_ITALIC_ANGLE, + + /*# required fields in a Private blend dictionary */ + T1_BLEND_BLUE_VALUES, + T1_BLEND_OTHER_BLUES, + T1_BLEND_STANDARD_WIDTH, + T1_BLEND_STANDARD_HEIGHT, + T1_BLEND_STEM_SNAP_WIDTHS, + T1_BLEND_STEM_SNAP_HEIGHTS, + T1_BLEND_BLUE_SCALE, + T1_BLEND_BLUE_SHIFT, + T1_BLEND_FAMILY_BLUES, + T1_BLEND_FAMILY_OTHER_BLUES, + T1_BLEND_FORCE_BOLD, + + /*# never remove */ + T1_BLEND_MAX + + } T1_Blend_Flags; + + /* */ + + + /*# backwards compatible definitions */ +#define t1_blend_underline_position T1_BLEND_UNDERLINE_POSITION +#define t1_blend_underline_thickness T1_BLEND_UNDERLINE_THICKNESS +#define t1_blend_italic_angle T1_BLEND_ITALIC_ANGLE +#define t1_blend_blue_values T1_BLEND_BLUE_VALUES +#define t1_blend_other_blues T1_BLEND_OTHER_BLUES +#define t1_blend_standard_widths T1_BLEND_STANDARD_WIDTH +#define t1_blend_standard_height T1_BLEND_STANDARD_HEIGHT +#define t1_blend_stem_snap_widths T1_BLEND_STEM_SNAP_WIDTHS +#define t1_blend_stem_snap_heights T1_BLEND_STEM_SNAP_HEIGHTS +#define t1_blend_blue_scale T1_BLEND_BLUE_SCALE +#define t1_blend_blue_shift T1_BLEND_BLUE_SHIFT +#define t1_blend_family_blues T1_BLEND_FAMILY_BLUES +#define t1_blend_family_other_blues T1_BLEND_FAMILY_OTHER_BLUES +#define t1_blend_force_bold T1_BLEND_FORCE_BOLD +#define t1_blend_max T1_BLEND_MAX + + + /* maximum number of Multiple Masters designs, as defined in the spec */ +#define T1_MAX_MM_DESIGNS 16 + + /* maximum number of Multiple Masters axes, as defined in the spec */ +#define T1_MAX_MM_AXIS 4 + + /* maximum number of elements in a design map */ +#define T1_MAX_MM_MAP_POINTS 20 + + + /* this structure is used to store the BlendDesignMap entry for an axis */ + typedef struct PS_DesignMap_ + { + FT_Byte num_points; + FT_Long* design_points; + FT_Fixed* blend_points; + + } PS_DesignMapRec, *PS_DesignMap; + + /* backwards-compatible definition */ + typedef PS_DesignMapRec T1_DesignMap; + + + typedef struct PS_BlendRec_ + { + FT_UInt num_designs; + FT_UInt num_axis; + + FT_String* axis_names[T1_MAX_MM_AXIS]; + FT_Fixed* design_pos[T1_MAX_MM_DESIGNS]; + PS_DesignMapRec design_map[T1_MAX_MM_AXIS]; + + FT_Fixed* weight_vector; + FT_Fixed* default_weight_vector; + + PS_FontInfo font_infos[T1_MAX_MM_DESIGNS + 1]; + PS_Private privates [T1_MAX_MM_DESIGNS + 1]; + + FT_ULong blend_bitflags; + + FT_BBox* bboxes [T1_MAX_MM_DESIGNS + 1]; + + /* since 2.3.0 */ + + /* undocumented, optional: the default design instance; */ + /* corresponds to default_weight_vector -- */ + /* num_default_design_vector == 0 means it is not present */ + /* in the font and associated metrics files */ + FT_UInt default_design_vector[T1_MAX_MM_DESIGNS]; + FT_UInt num_default_design_vector; + + } PS_BlendRec, *PS_Blend; + + + /* backwards-compatible definition */ + typedef PS_BlendRec T1_Blend; + + + typedef struct CID_FaceDictRec_ + { + PS_PrivateRec private_dict; + + FT_UInt len_buildchar; + FT_Fixed forcebold_threshold; + FT_Pos stroke_width; + FT_Fixed expansion_factor; + + FT_Byte paint_type; + FT_Byte font_type; + FT_Matrix font_matrix; + FT_Vector font_offset; + + FT_UInt num_subrs; + FT_ULong subrmap_offset; + FT_Int sd_bytes; + + } CID_FaceDictRec, *CID_FaceDict; + + + /* backwards-compatible definition */ + typedef CID_FaceDictRec CID_FontDict; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* CID_FaceInfoRec */ + /* */ + /* <Description> */ + /* A structure used to represent CID Face information. */ + /* */ + typedef struct CID_FaceInfoRec_ + { + FT_String* cid_font_name; + FT_Fixed cid_version; + FT_Int cid_font_type; + + FT_String* registry; + FT_String* ordering; + FT_Int supplement; + + PS_FontInfoRec font_info; + FT_BBox font_bbox; + FT_ULong uid_base; + + FT_Int num_xuid; + FT_ULong xuid[16]; + + FT_ULong cidmap_offset; + FT_Int fd_bytes; + FT_Int gd_bytes; + FT_ULong cid_count; + + FT_Int num_dicts; + CID_FaceDict font_dicts; + + FT_ULong data_offset; + + } CID_FaceInfoRec, *CID_FaceInfo; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* CID_Info */ + /* */ + /* <Description> */ + /* This type is equivalent to @CID_FaceInfoRec. It is deprecated but */ + /* kept to maintain source compatibility between various versions of */ + /* FreeType. */ + /* */ + typedef CID_FaceInfoRec CID_Info; + + /* */ + + + /************************************************************************ + * + * @function: + * FT_Has_PS_Glyph_Names + * + * @description: + * Return true if a given face provides reliable Postscript glyph + * names. This is similar to using the @FT_HAS_GLYPH_NAMES macro, + * except that certain fonts (mostly TrueType) contain incorrect + * glyph name tables. + * + * When this function returns true, the caller is sure that the glyph + * names returned by @FT_Get_Glyph_Name are reliable. + * + * @input: + * face :: + * face handle + * + * @return: + * Boolean. True if glyph names are reliable. + */ + FT_EXPORT( FT_Int ) + FT_Has_PS_Glyph_Names( FT_Face face ); + + + /************************************************************************ + * + * @function: + * FT_Get_PS_Font_Info + * + * @description: + * Retrieve the @PS_FontInfoRec structure corresponding to a given + * Postscript font. + * + * @input: + * face :: + * Postscript face handle. + * + * @output: + * afont_info :: + * Output font info structure pointer. + * + * @return: + * FreeType error code. 0 means success. + * + * @note: + * The string pointers within the font info structure are owned by + * the face and don't need to be freed by the caller. + * + * If the font's format is not Postscript-based, this function will + * return the `FT_Err_Invalid_Argument' error code. + */ + FT_EXPORT( FT_Error ) + FT_Get_PS_Font_Info( FT_Face face, + PS_FontInfoRec *afont_info ); + + + /************************************************************************ + * + * @function: + * FT_Get_PS_Font_Private + * + * @description: + * Retrieve the @PS_PrivateRec structure corresponding to a given + * Postscript font. + * + * @input: + * face :: + * Postscript face handle. + * + * @output: + * afont_private :: + * Output private dictionary structure pointer. + * + * @return: + * FreeType error code. 0 means success. + * + * @note: + * The string pointers within the font info structure are owned by + * the face and don't need to be freed by the caller. + * + * If the font's format is not Postscript-based, this function will + * return the `FT_Err_Invalid_Argument' error code. + */ + FT_EXPORT( FT_Error ) + FT_Get_PS_Font_Private( FT_Face face, + PS_PrivateRec *afont_private ); + + /* */ + + + +FT_END_HEADER + +#endif /* __T1TABLES_H__ */ + + +/* END */ diff --git a/include/freetype/ttnameid.h b/include/freetype/ttnameid.h new file mode 100644 index 0000000..b9acbda --- /dev/null +++ b/include/freetype/ttnameid.h @@ -0,0 +1,1132 @@ +/***************************************************************************/ +/* */ +/* ttnameid.h */ +/* */ +/* TrueType name ID definitions (specification only). */ +/* */ +/* Copyright 1996-2002, 2003, 2004, 2006, 2007 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef __TTNAMEID_H__ +#define __TTNAMEID_H__ + + +#include <ft2build.h> + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /* */ + /* Possible values for the `platform' identifier code in the name */ + /* records of the TTF `name' table. */ + /* */ + /*************************************************************************/ + + + /*********************************************************************** + * + * @enum: + * TT_PLATFORM_XXX + * + * @description: + * A list of valid values for the `platform_id' identifier code in + * @FT_CharMapRec and @FT_SfntName structures. + * + * @values: + * TT_PLATFORM_APPLE_UNICODE :: + * Used by Apple to indicate a Unicode character map and/or name entry. + * See @TT_APPLE_ID_XXX for corresponding `encoding_id' values. Note + * that name entries in this format are coded as big-endian UCS-2 + * character codes _only_. + * + * TT_PLATFORM_MACINTOSH :: + * Used by Apple to indicate a MacOS-specific charmap and/or name entry. + * See @TT_MAC_ID_XXX for corresponding `encoding_id' values. Note that + * most TrueType fonts contain an Apple roman charmap to be usable on + * MacOS systems (even if they contain a Microsoft charmap as well). + * + * TT_PLATFORM_ISO :: + * This value was used to specify Unicode charmaps. It is however + * now deprecated. See @TT_ISO_ID_XXX for a list of corresponding + * `encoding_id' values. + * + * TT_PLATFORM_MICROSOFT :: + * Used by Microsoft to indicate Windows-specific charmaps. See + * @TT_MS_ID_XXX for a list of corresponding `encoding_id' values. + * Note that most fonts contain a Unicode charmap using + * (TT_PLATFORM_MICROSOFT, @TT_MS_ID_UNICODE_CS). + * + * TT_PLATFORM_CUSTOM :: + * Used to indicate application-specific charmaps. + * + * TT_PLATFORM_ADOBE :: + * This value isn't part of any font format specification, but is used + * by FreeType to report Adobe-specific charmaps in an @FT_CharMapRec + * structure. See @TT_ADOBE_ID_XXX. + */ + +#define TT_PLATFORM_APPLE_UNICODE 0 +#define TT_PLATFORM_MACINTOSH 1 +#define TT_PLATFORM_ISO 2 /* deprecated */ +#define TT_PLATFORM_MICROSOFT 3 +#define TT_PLATFORM_CUSTOM 4 +#define TT_PLATFORM_ADOBE 7 /* artificial */ + + + /*********************************************************************** + * + * @enum: + * TT_APPLE_ID_XXX + * + * @description: + * A list of valid values for the `encoding_id' for + * @TT_PLATFORM_APPLE_UNICODE charmaps and name entries. + * + * @values: + * TT_APPLE_ID_DEFAULT :: + * Unicode version 1.0. + * + * TT_APPLE_ID_UNICODE_1_1 :: + * Unicode 1.1; specifies Hangul characters starting at U+34xx. + * + * TT_APPLE_ID_ISO_10646 :: + * Deprecated (identical to preceding). + * + * TT_APPLE_ID_UNICODE_2_0 :: + * Unicode 2.0 and beyond (UTF-16 BMP only). + * + * TT_APPLE_ID_UNICODE_32 :: + * Unicode 3.1 and beyond, using UTF-32. + */ + +#define TT_APPLE_ID_DEFAULT 0 /* Unicode 1.0 */ +#define TT_APPLE_ID_UNICODE_1_1 1 /* specify Hangul at U+34xx */ +#define TT_APPLE_ID_ISO_10646 2 /* deprecated */ +#define TT_APPLE_ID_UNICODE_2_0 3 /* or later */ +#define TT_APPLE_ID_UNICODE_32 4 /* 2.0 or later, full repertoire */ + + + /*********************************************************************** + * + * @enum: + * TT_MAC_ID_XXX + * + * @description: + * A list of valid values for the `encoding_id' for + * @TT_PLATFORM_MACINTOSH charmaps and name entries. + * + * @values: + * TT_MAC_ID_ROMAN :: + * TT_MAC_ID_JAPANESE :: + * TT_MAC_ID_TRADITIONAL_CHINESE :: + * TT_MAC_ID_KOREAN :: + * TT_MAC_ID_ARABIC :: + * TT_MAC_ID_HEBREW :: + * TT_MAC_ID_GREEK :: + * TT_MAC_ID_RUSSIAN :: + * TT_MAC_ID_RSYMBOL :: + * TT_MAC_ID_DEVANAGARI :: + * TT_MAC_ID_GURMUKHI :: + * TT_MAC_ID_GUJARATI :: + * TT_MAC_ID_ORIYA :: + * TT_MAC_ID_BENGALI :: + * TT_MAC_ID_TAMIL :: + * TT_MAC_ID_TELUGU :: + * TT_MAC_ID_KANNADA :: + * TT_MAC_ID_MALAYALAM :: + * TT_MAC_ID_SINHALESE :: + * TT_MAC_ID_BURMESE :: + * TT_MAC_ID_KHMER :: + * TT_MAC_ID_THAI :: + * TT_MAC_ID_LAOTIAN :: + * TT_MAC_ID_GEORGIAN :: + * TT_MAC_ID_ARMENIAN :: + * TT_MAC_ID_MALDIVIAN :: + * TT_MAC_ID_SIMPLIFIED_CHINESE :: + * TT_MAC_ID_TIBETAN :: + * TT_MAC_ID_MONGOLIAN :: + * TT_MAC_ID_GEEZ :: + * TT_MAC_ID_SLAVIC :: + * TT_MAC_ID_VIETNAMESE :: + * TT_MAC_ID_SINDHI :: + * TT_MAC_ID_UNINTERP :: + */ + +#define TT_MAC_ID_ROMAN 0 +#define TT_MAC_ID_JAPANESE 1 +#define TT_MAC_ID_TRADITIONAL_CHINESE 2 +#define TT_MAC_ID_KOREAN 3 +#define TT_MAC_ID_ARABIC 4 +#define TT_MAC_ID_HEBREW 5 +#define TT_MAC_ID_GREEK 6 +#define TT_MAC_ID_RUSSIAN 7 +#define TT_MAC_ID_RSYMBOL 8 +#define TT_MAC_ID_DEVANAGARI 9 +#define TT_MAC_ID_GURMUKHI 10 +#define TT_MAC_ID_GUJARATI 11 +#define TT_MAC_ID_ORIYA 12 +#define TT_MAC_ID_BENGALI 13 +#define TT_MAC_ID_TAMIL 14 +#define TT_MAC_ID_TELUGU 15 +#define TT_MAC_ID_KANNADA 16 +#define TT_MAC_ID_MALAYALAM 17 +#define TT_MAC_ID_SINHALESE 18 +#define TT_MAC_ID_BURMESE 19 +#define TT_MAC_ID_KHMER 20 +#define TT_MAC_ID_THAI 21 +#define TT_MAC_ID_LAOTIAN 22 +#define TT_MAC_ID_GEORGIAN 23 +#define TT_MAC_ID_ARMENIAN 24 +#define TT_MAC_ID_MALDIVIAN 25 +#define TT_MAC_ID_SIMPLIFIED_CHINESE 25 +#define TT_MAC_ID_TIBETAN 26 +#define TT_MAC_ID_MONGOLIAN 27 +#define TT_MAC_ID_GEEZ 28 +#define TT_MAC_ID_SLAVIC 29 +#define TT_MAC_ID_VIETNAMESE 30 +#define TT_MAC_ID_SINDHI 31 +#define TT_MAC_ID_UNINTERP 32 + + + /*********************************************************************** + * + * @enum: + * TT_ISO_ID_XXX + * + * @description: + * A list of valid values for the `encoding_id' for + * @TT_PLATFORM_ISO charmaps and name entries. + * + * Their use is now deprecated. + * + * @values: + * TT_ISO_ID_7BIT_ASCII :: + * ASCII. + * TT_ISO_ID_10646 :: + * ISO/10646. + * TT_ISO_ID_8859_1 :: + * Also known as Latin-1. + */ + +#define TT_ISO_ID_7BIT_ASCII 0 +#define TT_ISO_ID_10646 1 +#define TT_ISO_ID_8859_1 2 + + + /*********************************************************************** + * + * @enum: + * TT_MS_ID_XXX + * + * @description: + * A list of valid values for the `encoding_id' for + * @TT_PLATFORM_MICROSOFT charmaps and name entries. + * + * @values: + * TT_MS_ID_SYMBOL_CS :: + * Corresponds to Microsoft symbol encoding. See + * @FT_ENCODING_MS_SYMBOL. + * + * TT_MS_ID_UNICODE_CS :: + * Corresponds to a Microsoft WGL4 charmap, matching Unicode. See + * @FT_ENCODING_UNICODE. + * + * TT_MS_ID_SJIS :: + * Corresponds to SJIS Japanese encoding. See @FT_ENCODING_SJIS. + * + * TT_MS_ID_GB2312 :: + * Corresponds to Simplified Chinese as used in Mainland China. See + * @FT_ENCODING_GB2312. + * + * TT_MS_ID_BIG_5 :: + * Corresponds to Traditional Chinese as used in Taiwan and Hong Kong. + * See @FT_ENCODING_BIG5. + * + * TT_MS_ID_WANSUNG :: + * Corresponds to Korean Wansung encoding. See @FT_ENCODING_WANSUNG. + * + * TT_MS_ID_JOHAB :: + * Corresponds to Johab encoding. See @FT_ENCODING_JOHAB. + * + * TT_MS_ID_UCS_4 :: + * Corresponds to UCS-4 or UTF-32 charmaps. This has been added to + * the OpenType specification version 1.4 (mid-2001.) + */ + +#define TT_MS_ID_SYMBOL_CS 0 +#define TT_MS_ID_UNICODE_CS 1 +#define TT_MS_ID_SJIS 2 +#define TT_MS_ID_GB2312 3 +#define TT_MS_ID_BIG_5 4 +#define TT_MS_ID_WANSUNG 5 +#define TT_MS_ID_JOHAB 6 +#define TT_MS_ID_UCS_4 10 + + + /*********************************************************************** + * + * @enum: + * TT_ADOBE_ID_XXX + * + * @description: + * A list of valid values for the `encoding_id' for + * @TT_PLATFORM_ADOBE charmaps. This is a FreeType-specific extension! + * + * @values: + * TT_ADOBE_ID_STANDARD :: + * Adobe standard encoding. + * TT_ADOBE_ID_EXPERT :: + * Adobe expert encoding. + * TT_ADOBE_ID_CUSTOM :: + * Adobe custom encoding. + */ + +#define TT_ADOBE_ID_STANDARD 0 +#define TT_ADOBE_ID_EXPERT 1 +#define TT_ADOBE_ID_CUSTOM 2 +#define TT_ADOBE_ID_LATIN_1 3 + + + /*************************************************************************/ + /* */ + /* Possible values of the language identifier field in the name records */ + /* of the TTF `name' table if the `platform' identifier code is */ + /* TT_PLATFORM_MACINTOSH. */ + /* */ + /* The canonical source for the Apple assigned Language ID's is at */ + /* */ + /* http://fonts.apple.com/TTRefMan/RM06/Chap6name.html */ + /* */ +#define TT_MAC_LANGID_ENGLISH 0 +#define TT_MAC_LANGID_FRENCH 1 +#define TT_MAC_LANGID_GERMAN 2 +#define TT_MAC_LANGID_ITALIAN 3 +#define TT_MAC_LANGID_DUTCH 4 +#define TT_MAC_LANGID_SWEDISH 5 +#define TT_MAC_LANGID_SPANISH 6 +#define TT_MAC_LANGID_DANISH 7 +#define TT_MAC_LANGID_PORTUGUESE 8 +#define TT_MAC_LANGID_NORWEGIAN 9 +#define TT_MAC_LANGID_HEBREW 10 +#define TT_MAC_LANGID_JAPANESE 11 +#define TT_MAC_LANGID_ARABIC 12 +#define TT_MAC_LANGID_FINNISH 13 +#define TT_MAC_LANGID_GREEK 14 +#define TT_MAC_LANGID_ICELANDIC 15 +#define TT_MAC_LANGID_MALTESE 16 +#define TT_MAC_LANGID_TURKISH 17 +#define TT_MAC_LANGID_CROATIAN 18 +#define TT_MAC_LANGID_CHINESE_TRADITIONAL 19 +#define TT_MAC_LANGID_URDU 20 +#define TT_MAC_LANGID_HINDI 21 +#define TT_MAC_LANGID_THAI 22 +#define TT_MAC_LANGID_KOREAN 23 +#define TT_MAC_LANGID_LITHUANIAN 24 +#define TT_MAC_LANGID_POLISH 25 +#define TT_MAC_LANGID_HUNGARIAN 26 +#define TT_MAC_LANGID_ESTONIAN 27 +#define TT_MAC_LANGID_LETTISH 28 +#define TT_MAC_LANGID_SAAMISK 29 +#define TT_MAC_LANGID_FAEROESE 30 +#define TT_MAC_LANGID_FARSI 31 +#define TT_MAC_LANGID_RUSSIAN 32 +#define TT_MAC_LANGID_CHINESE_SIMPLIFIED 33 +#define TT_MAC_LANGID_FLEMISH 34 +#define TT_MAC_LANGID_IRISH 35 +#define TT_MAC_LANGID_ALBANIAN 36 +#define TT_MAC_LANGID_ROMANIAN 37 +#define TT_MAC_LANGID_CZECH 38 +#define TT_MAC_LANGID_SLOVAK 39 +#define TT_MAC_LANGID_SLOVENIAN 40 +#define TT_MAC_LANGID_YIDDISH 41 +#define TT_MAC_LANGID_SERBIAN 42 +#define TT_MAC_LANGID_MACEDONIAN 43 +#define TT_MAC_LANGID_BULGARIAN 44 +#define TT_MAC_LANGID_UKRAINIAN 45 +#define TT_MAC_LANGID_BYELORUSSIAN 46 +#define TT_MAC_LANGID_UZBEK 47 +#define TT_MAC_LANGID_KAZAKH 48 +#define TT_MAC_LANGID_AZERBAIJANI 49 +#define TT_MAC_LANGID_AZERBAIJANI_CYRILLIC_SCRIPT 49 +#define TT_MAC_LANGID_AZERBAIJANI_ARABIC_SCRIPT 50 +#define TT_MAC_LANGID_ARMENIAN 51 +#define TT_MAC_LANGID_GEORGIAN 52 +#define TT_MAC_LANGID_MOLDAVIAN 53 +#define TT_MAC_LANGID_KIRGHIZ 54 +#define TT_MAC_LANGID_TAJIKI 55 +#define TT_MAC_LANGID_TURKMEN 56 +#define TT_MAC_LANGID_MONGOLIAN 57 +#define TT_MAC_LANGID_MONGOLIAN_MONGOLIAN_SCRIPT 57 +#define TT_MAC_LANGID_MONGOLIAN_CYRILLIC_SCRIPT 58 +#define TT_MAC_LANGID_PASHTO 59 +#define TT_MAC_LANGID_KURDISH 60 +#define TT_MAC_LANGID_KASHMIRI 61 +#define TT_MAC_LANGID_SINDHI 62 +#define TT_MAC_LANGID_TIBETAN 63 +#define TT_MAC_LANGID_NEPALI 64 +#define TT_MAC_LANGID_SANSKRIT 65 +#define TT_MAC_LANGID_MARATHI 66 +#define TT_MAC_LANGID_BENGALI 67 +#define TT_MAC_LANGID_ASSAMESE 68 +#define TT_MAC_LANGID_GUJARATI 69 +#define TT_MAC_LANGID_PUNJABI 70 +#define TT_MAC_LANGID_ORIYA 71 +#define TT_MAC_LANGID_MALAYALAM 72 +#define TT_MAC_LANGID_KANNADA 73 +#define TT_MAC_LANGID_TAMIL 74 +#define TT_MAC_LANGID_TELUGU 75 +#define TT_MAC_LANGID_SINHALESE 76 +#define TT_MAC_LANGID_BURMESE 77 +#define TT_MAC_LANGID_KHMER 78 +#define TT_MAC_LANGID_LAO 79 +#define TT_MAC_LANGID_VIETNAMESE 80 +#define TT_MAC_LANGID_INDONESIAN 81 +#define TT_MAC_LANGID_TAGALOG 82 +#define TT_MAC_LANGID_MALAY_ROMAN_SCRIPT 83 +#define TT_MAC_LANGID_MALAY_ARABIC_SCRIPT 84 +#define TT_MAC_LANGID_AMHARIC 85 +#define TT_MAC_LANGID_TIGRINYA 86 +#define TT_MAC_LANGID_GALLA 87 +#define TT_MAC_LANGID_SOMALI 88 +#define TT_MAC_LANGID_SWAHILI 89 +#define TT_MAC_LANGID_RUANDA 90 +#define TT_MAC_LANGID_RUNDI 91 +#define TT_MAC_LANGID_CHEWA 92 +#define TT_MAC_LANGID_MALAGASY 93 +#define TT_MAC_LANGID_ESPERANTO 94 +#define TT_MAC_LANGID_WELSH 128 +#define TT_MAC_LANGID_BASQUE 129 +#define TT_MAC_LANGID_CATALAN 130 +#define TT_MAC_LANGID_LATIN 131 +#define TT_MAC_LANGID_QUECHUA 132 +#define TT_MAC_LANGID_GUARANI 133 +#define TT_MAC_LANGID_AYMARA 134 +#define TT_MAC_LANGID_TATAR 135 +#define TT_MAC_LANGID_UIGHUR 136 +#define TT_MAC_LANGID_DZONGKHA 137 +#define TT_MAC_LANGID_JAVANESE 138 +#define TT_MAC_LANGID_SUNDANESE 139 + + +#if 0 /* these seem to be errors that have been dropped */ + +#define TT_MAC_LANGID_SCOTTISH_GAELIC 140 +#define TT_MAC_LANGID_IRISH_GAELIC 141 + +#endif + + + /* The following codes are new as of 2000-03-10 */ +#define TT_MAC_LANGID_GALICIAN 140 +#define TT_MAC_LANGID_AFRIKAANS 141 +#define TT_MAC_LANGID_BRETON 142 +#define TT_MAC_LANGID_INUKTITUT 143 +#define TT_MAC_LANGID_SCOTTISH_GAELIC 144 +#define TT_MAC_LANGID_MANX_GAELIC 145 +#define TT_MAC_LANGID_IRISH_GAELIC 146 +#define TT_MAC_LANGID_TONGAN 147 +#define TT_MAC_LANGID_GREEK_POLYTONIC 148 +#define TT_MAC_LANGID_GREELANDIC 149 +#define TT_MAC_LANGID_AZERBAIJANI_ROMAN_SCRIPT 150 + + + /*************************************************************************/ + /* */ + /* Possible values of the language identifier field in the name records */ + /* of the TTF `name' table if the `platform' identifier code is */ + /* TT_PLATFORM_MICROSOFT. */ + /* */ + /* The canonical source for the MS assigned LCID's (seems to) be at */ + /* */ + /* http://www.microsoft.com/globaldev/reference/lcid-all.mspx */ + /* */ + /* It used to be at various places, among them */ + /* */ + /* http://www.microsoft.com/typography/OTSPEC/lcid-cp.txt */ + /* http://www.microsoft.com/globaldev/reference/loclanghome.asp */ + /* http://support.microsoft.com/support/kb/articles/Q224/8/04.ASP */ + /* http://msdn.microsoft.com/library/en-us/passport25/ */ + /* NET_Passport_VBScript_Documentation/Single_Sign_In/ */ + /* Advanced_Single_Sign_In/Localization_and_LCIDs.asp */ + /* */ + /* Hopefully, it seems now that the Globaldev site prevails... */ + /* (updated by Antoine, 2004-02-17) */ + +#define TT_MS_LANGID_ARABIC_GENERAL 0x0001 +#define TT_MS_LANGID_ARABIC_SAUDI_ARABIA 0x0401 +#define TT_MS_LANGID_ARABIC_IRAQ 0x0801 +#define TT_MS_LANGID_ARABIC_EGYPT 0x0c01 +#define TT_MS_LANGID_ARABIC_LIBYA 0x1001 +#define TT_MS_LANGID_ARABIC_ALGERIA 0x1401 +#define TT_MS_LANGID_ARABIC_MOROCCO 0x1801 +#define TT_MS_LANGID_ARABIC_TUNISIA 0x1c01 +#define TT_MS_LANGID_ARABIC_OMAN 0x2001 +#define TT_MS_LANGID_ARABIC_YEMEN 0x2401 +#define TT_MS_LANGID_ARABIC_SYRIA 0x2801 +#define TT_MS_LANGID_ARABIC_JORDAN 0x2c01 +#define TT_MS_LANGID_ARABIC_LEBANON 0x3001 +#define TT_MS_LANGID_ARABIC_KUWAIT 0x3401 +#define TT_MS_LANGID_ARABIC_UAE 0x3801 +#define TT_MS_LANGID_ARABIC_BAHRAIN 0x3c01 +#define TT_MS_LANGID_ARABIC_QATAR 0x4001 +#define TT_MS_LANGID_BULGARIAN_BULGARIA 0x0402 +#define TT_MS_LANGID_CATALAN_SPAIN 0x0403 +#define TT_MS_LANGID_CHINESE_GENERAL 0x0004 +#define TT_MS_LANGID_CHINESE_TAIWAN 0x0404 +#define TT_MS_LANGID_CHINESE_PRC 0x0804 +#define TT_MS_LANGID_CHINESE_HONG_KONG 0x0c04 +#define TT_MS_LANGID_CHINESE_SINGAPORE 0x1004 + +#if 1 /* this looks like the correct value */ +#define TT_MS_LANGID_CHINESE_MACAU 0x1404 +#else /* but beware, Microsoft may change its mind... + the most recent Word reference has the following: */ +#define TT_MS_LANGID_CHINESE_MACAU TT_MS_LANGID_CHINESE_HONG_KONG +#endif + +#if 0 /* used only with .NET `cultures'; commented out */ +#define TT_MS_LANGID_CHINESE_TRADITIONAL 0x7C04 +#endif + +#define TT_MS_LANGID_CZECH_CZECH_REPUBLIC 0x0405 +#define TT_MS_LANGID_DANISH_DENMARK 0x0406 +#define TT_MS_LANGID_GERMAN_GERMANY 0x0407 +#define TT_MS_LANGID_GERMAN_SWITZERLAND 0x0807 +#define TT_MS_LANGID_GERMAN_AUSTRIA 0x0c07 +#define TT_MS_LANGID_GERMAN_LUXEMBOURG 0x1007 +#define TT_MS_LANGID_GERMAN_LIECHTENSTEI 0x1407 +#define TT_MS_LANGID_GREEK_GREECE 0x0408 + + /* don't ask what this one means... It is commented out currently. */ +#if 0 +#define TT_MS_LANGID_GREEK_GREECE2 0x2008 +#endif + +#define TT_MS_LANGID_ENGLISH_GENERAL 0x0009 +#define TT_MS_LANGID_ENGLISH_UNITED_STATES 0x0409 +#define TT_MS_LANGID_ENGLISH_UNITED_KINGDOM 0x0809 +#define TT_MS_LANGID_ENGLISH_AUSTRALIA 0x0c09 +#define TT_MS_LANGID_ENGLISH_CANADA 0x1009 +#define TT_MS_LANGID_ENGLISH_NEW_ZEALAND 0x1409 +#define TT_MS_LANGID_ENGLISH_IRELAND 0x1809 +#define TT_MS_LANGID_ENGLISH_SOUTH_AFRICA 0x1c09 +#define TT_MS_LANGID_ENGLISH_JAMAICA 0x2009 +#define TT_MS_LANGID_ENGLISH_CARIBBEAN 0x2409 +#define TT_MS_LANGID_ENGLISH_BELIZE 0x2809 +#define TT_MS_LANGID_ENGLISH_TRINIDAD 0x2c09 +#define TT_MS_LANGID_ENGLISH_ZIMBABWE 0x3009 +#define TT_MS_LANGID_ENGLISH_PHILIPPINES 0x3409 +#define TT_MS_LANGID_ENGLISH_INDONESIA 0x3809 +#define TT_MS_LANGID_ENGLISH_HONG_KONG 0x3c09 +#define TT_MS_LANGID_ENGLISH_INDIA 0x4009 +#define TT_MS_LANGID_ENGLISH_MALAYSIA 0x4409 +#define TT_MS_LANGID_ENGLISH_SINGAPORE 0x4809 +#define TT_MS_LANGID_SPANISH_SPAIN_TRADITIONAL_SORT 0x040a +#define TT_MS_LANGID_SPANISH_MEXICO 0x080a +#define TT_MS_LANGID_SPANISH_SPAIN_INTERNATIONAL_SORT 0x0c0a +#define TT_MS_LANGID_SPANISH_GUATEMALA 0x100a +#define TT_MS_LANGID_SPANISH_COSTA_RICA 0x140a +#define TT_MS_LANGID_SPANISH_PANAMA 0x180a +#define TT_MS_LANGID_SPANISH_DOMINICAN_REPUBLIC 0x1c0a +#define TT_MS_LANGID_SPANISH_VENEZUELA 0x200a +#define TT_MS_LANGID_SPANISH_COLOMBIA 0x240a +#define TT_MS_LANGID_SPANISH_PERU 0x280a +#define TT_MS_LANGID_SPANISH_ARGENTINA 0x2c0a +#define TT_MS_LANGID_SPANISH_ECUADOR 0x300a +#define TT_MS_LANGID_SPANISH_CHILE 0x340a +#define TT_MS_LANGID_SPANISH_URUGUAY 0x380a +#define TT_MS_LANGID_SPANISH_PARAGUAY 0x3c0a +#define TT_MS_LANGID_SPANISH_BOLIVIA 0x400a +#define TT_MS_LANGID_SPANISH_EL_SALVADOR 0x440a +#define TT_MS_LANGID_SPANISH_HONDURAS 0x480a +#define TT_MS_LANGID_SPANISH_NICARAGUA 0x4c0a +#define TT_MS_LANGID_SPANISH_PUERTO_RICO 0x500a +#define TT_MS_LANGID_SPANISH_UNITED_STATES 0x540a + /* The following ID blatantly violate MS specs by using a */ + /* sublanguage > 0x1F. */ +#define TT_MS_LANGID_SPANISH_LATIN_AMERICA 0xE40aU +#define TT_MS_LANGID_FINNISH_FINLAND 0x040b +#define TT_MS_LANGID_FRENCH_FRANCE 0x040c +#define TT_MS_LANGID_FRENCH_BELGIUM 0x080c +#define TT_MS_LANGID_FRENCH_CANADA 0x0c0c +#define TT_MS_LANGID_FRENCH_SWITZERLAND 0x100c +#define TT_MS_LANGID_FRENCH_LUXEMBOURG 0x140c +#define TT_MS_LANGID_FRENCH_MONACO 0x180c +#define TT_MS_LANGID_FRENCH_WEST_INDIES 0x1c0c +#define TT_MS_LANGID_FRENCH_REUNION 0x200c +#define TT_MS_LANGID_FRENCH_CONGO 0x240c + /* which was formerly: */ +#define TT_MS_LANGID_FRENCH_ZAIRE TT_MS_LANGID_FRENCH_CONGO +#define TT_MS_LANGID_FRENCH_SENEGAL 0x280c +#define TT_MS_LANGID_FRENCH_CAMEROON 0x2c0c +#define TT_MS_LANGID_FRENCH_COTE_D_IVOIRE 0x300c +#define TT_MS_LANGID_FRENCH_MALI 0x340c +#define TT_MS_LANGID_FRENCH_MOROCCO 0x380c +#define TT_MS_LANGID_FRENCH_HAITI 0x3c0c + /* and another violation of the spec (see 0xE40aU) */ +#define TT_MS_LANGID_FRENCH_NORTH_AFRICA 0xE40cU +#define TT_MS_LANGID_HEBREW_ISRAEL 0x040d +#define TT_MS_LANGID_HUNGARIAN_HUNGARY 0x040e +#define TT_MS_LANGID_ICELANDIC_ICELAND 0x040f +#define TT_MS_LANGID_ITALIAN_ITALY 0x0410 +#define TT_MS_LANGID_ITALIAN_SWITZERLAND 0x0810 +#define TT_MS_LANGID_JAPANESE_JAPAN 0x0411 +#define TT_MS_LANGID_KOREAN_EXTENDED_WANSUNG_KOREA 0x0412 +#define TT_MS_LANGID_KOREAN_JOHAB_KOREA 0x0812 +#define TT_MS_LANGID_DUTCH_NETHERLANDS 0x0413 +#define TT_MS_LANGID_DUTCH_BELGIUM 0x0813 +#define TT_MS_LANGID_NORWEGIAN_NORWAY_BOKMAL 0x0414 +#define TT_MS_LANGID_NORWEGIAN_NORWAY_NYNORSK 0x0814 +#define TT_MS_LANGID_POLISH_POLAND 0x0415 +#define TT_MS_LANGID_PORTUGUESE_BRAZIL 0x0416 +#define TT_MS_LANGID_PORTUGUESE_PORTUGAL 0x0816 +#define TT_MS_LANGID_RHAETO_ROMANIC_SWITZERLAND 0x0417 +#define TT_MS_LANGID_ROMANIAN_ROMANIA 0x0418 +#define TT_MS_LANGID_MOLDAVIAN_MOLDAVIA 0x0818 +#define TT_MS_LANGID_RUSSIAN_RUSSIA 0x0419 +#define TT_MS_LANGID_RUSSIAN_MOLDAVIA 0x0819 +#define TT_MS_LANGID_CROATIAN_CROATIA 0x041a +#define TT_MS_LANGID_SERBIAN_SERBIA_LATIN 0x081a +#define TT_MS_LANGID_SERBIAN_SERBIA_CYRILLIC 0x0c1a + +#if 0 /* this used to be this value, but it looks like we were wrong */ +#define TT_MS_LANGID_BOSNIAN_BOSNIA_HERZEGOVINA 0x101a +#else /* current sources say */ +#define TT_MS_LANGID_CROATIAN_BOSNIA_HERZEGOVINA 0x101a +#define TT_MS_LANGID_BOSNIAN_BOSNIA_HERZEGOVINA 0x141a + /* and XPsp2 Platform SDK added (2004-07-26) */ + /* Names are shortened to be significant within 40 chars. */ +#define TT_MS_LANGID_SERBIAN_BOSNIA_HERZ_LATIN 0x181a +#define TT_MS_LANGID_SERBIAN_BOSNIA_HERZ_CYRILLIC 0x181a +#endif + +#define TT_MS_LANGID_SLOVAK_SLOVAKIA 0x041b +#define TT_MS_LANGID_ALBANIAN_ALBANIA 0x041c +#define TT_MS_LANGID_SWEDISH_SWEDEN 0x041d +#define TT_MS_LANGID_SWEDISH_FINLAND 0x081d +#define TT_MS_LANGID_THAI_THAILAND 0x041e +#define TT_MS_LANGID_TURKISH_TURKEY 0x041f +#define TT_MS_LANGID_URDU_PAKISTAN 0x0420 +#define TT_MS_LANGID_URDU_INDIA 0x0820 +#define TT_MS_LANGID_INDONESIAN_INDONESIA 0x0421 +#define TT_MS_LANGID_UKRAINIAN_UKRAINE 0x0422 +#define TT_MS_LANGID_BELARUSIAN_BELARUS 0x0423 +#define TT_MS_LANGID_SLOVENE_SLOVENIA 0x0424 +#define TT_MS_LANGID_ESTONIAN_ESTONIA 0x0425 +#define TT_MS_LANGID_LATVIAN_LATVIA 0x0426 +#define TT_MS_LANGID_LITHUANIAN_LITHUANIA 0x0427 +#define TT_MS_LANGID_CLASSIC_LITHUANIAN_LITHUANIA 0x0827 +#define TT_MS_LANGID_TAJIK_TAJIKISTAN 0x0428 +#define TT_MS_LANGID_FARSI_IRAN 0x0429 +#define TT_MS_LANGID_VIETNAMESE_VIET_NAM 0x042a +#define TT_MS_LANGID_ARMENIAN_ARMENIA 0x042b +#define TT_MS_LANGID_AZERI_AZERBAIJAN_LATIN 0x042c +#define TT_MS_LANGID_AZERI_AZERBAIJAN_CYRILLIC 0x082c +#define TT_MS_LANGID_BASQUE_SPAIN 0x042d +#define TT_MS_LANGID_SORBIAN_GERMANY 0x042e +#define TT_MS_LANGID_MACEDONIAN_MACEDONIA 0x042f +#define TT_MS_LANGID_SUTU_SOUTH_AFRICA 0x0430 +#define TT_MS_LANGID_TSONGA_SOUTH_AFRICA 0x0431 +#define TT_MS_LANGID_TSWANA_SOUTH_AFRICA 0x0432 +#define TT_MS_LANGID_VENDA_SOUTH_AFRICA 0x0433 +#define TT_MS_LANGID_XHOSA_SOUTH_AFRICA 0x0434 +#define TT_MS_LANGID_ZULU_SOUTH_AFRICA 0x0435 +#define TT_MS_LANGID_AFRIKAANS_SOUTH_AFRICA 0x0436 +#define TT_MS_LANGID_GEORGIAN_GEORGIA 0x0437 +#define TT_MS_LANGID_FAEROESE_FAEROE_ISLANDS 0x0438 +#define TT_MS_LANGID_HINDI_INDIA 0x0439 +#define TT_MS_LANGID_MALTESE_MALTA 0x043a + /* Added by XPsp2 Platform SDK (2004-07-26) */ +#define TT_MS_LANGID_SAMI_NORTHERN_NORWAY 0x043b +#define TT_MS_LANGID_SAMI_NORTHERN_SWEDEN 0x083b +#define TT_MS_LANGID_SAMI_NORTHERN_FINLAND 0x0C3b +#define TT_MS_LANGID_SAMI_LULE_NORWAY 0x103b +#define TT_MS_LANGID_SAMI_LULE_SWEDEN 0x143b +#define TT_MS_LANGID_SAMI_SOUTHERN_NORWAY 0x183b +#define TT_MS_LANGID_SAMI_SOUTHERN_SWEDEN 0x1C3b +#define TT_MS_LANGID_SAMI_SKOLT_FINLAND 0x203b +#define TT_MS_LANGID_SAMI_INARI_FINLAND 0x243b + /* ... and we also keep our old identifier... */ +#define TT_MS_LANGID_SAAMI_LAPONIA 0x043b + +#if 0 /* this seems to be a previous inversion */ +#define TT_MS_LANGID_IRISH_GAELIC_IRELAND 0x043c +#define TT_MS_LANGID_SCOTTISH_GAELIC_UNITED_KINGDOM 0x083c +#else +#define TT_MS_LANGID_SCOTTISH_GAELIC_UNITED_KINGDOM 0x083c +#define TT_MS_LANGID_IRISH_GAELIC_IRELAND 0x043c +#endif + +#define TT_MS_LANGID_YIDDISH_GERMANY 0x043d +#define TT_MS_LANGID_MALAY_MALAYSIA 0x043e +#define TT_MS_LANGID_MALAY_BRUNEI_DARUSSALAM 0x083e +#define TT_MS_LANGID_KAZAK_KAZAKSTAN 0x043f +#define TT_MS_LANGID_KIRGHIZ_KIRGHIZSTAN /* Cyrillic*/ 0x0440 + /* alias declared in Windows 2000 */ +#define TT_MS_LANGID_KIRGHIZ_KIRGHIZ_REPUBLIC \ + TT_MS_LANGID_KIRGHIZ_KIRGHIZSTAN + +#define TT_MS_LANGID_SWAHILI_KENYA 0x0441 +#define TT_MS_LANGID_TURKMEN_TURKMENISTAN 0x0442 +#define TT_MS_LANGID_UZBEK_UZBEKISTAN_LATIN 0x0443 +#define TT_MS_LANGID_UZBEK_UZBEKISTAN_CYRILLIC 0x0843 +#define TT_MS_LANGID_TATAR_TATARSTAN 0x0444 +#define TT_MS_LANGID_BENGALI_INDIA 0x0445 +#define TT_MS_LANGID_BENGALI_BANGLADESH 0x0845 +#define TT_MS_LANGID_PUNJABI_INDIA 0x0446 +#define TT_MS_LANGID_PUNJABI_ARABIC_PAKISTAN 0x0846 +#define TT_MS_LANGID_GUJARATI_INDIA 0x0447 +#define TT_MS_LANGID_ORIYA_INDIA 0x0448 +#define TT_MS_LANGID_TAMIL_INDIA 0x0449 +#define TT_MS_LANGID_TELUGU_INDIA 0x044a +#define TT_MS_LANGID_KANNADA_INDIA 0x044b +#define TT_MS_LANGID_MALAYALAM_INDIA 0x044c +#define TT_MS_LANGID_ASSAMESE_INDIA 0x044d +#define TT_MS_LANGID_MARATHI_INDIA 0x044e +#define TT_MS_LANGID_SANSKRIT_INDIA 0x044f +#define TT_MS_LANGID_MONGOLIAN_MONGOLIA /* Cyrillic */ 0x0450 +#define TT_MS_LANGID_MONGOLIAN_MONGOLIA_MONGOLIAN 0x0850 +#define TT_MS_LANGID_TIBETAN_CHINA 0x0451 + /* Don't use the next constant! It has */ + /* (1) the wrong spelling (Dzonghka) */ + /* (2) Microsoft doesn't officially define it -- */ + /* at least it is not in the List of Local */ + /* ID Values. */ + /* (3) Dzongkha is not the same language as */ + /* Tibetan, so merging it is wrong anyway. */ + /* */ + /* TT_MS_LANGID_TIBETAN_BHUTAN is correct, BTW. */ +#define TT_MS_LANGID_DZONGHKA_BHUTAN 0x0851 + +#if 0 + /* the following used to be defined */ +#define TT_MS_LANGID_TIBETAN_BHUTAN 0x0451 + /* ... but it was changed; */ +#else + /* So we will continue to #define it, but with the correct value */ +#define TT_MS_LANGID_TIBETAN_BHUTAN TT_MS_LANGID_DZONGHKA_BHUTAN +#endif + +#define TT_MS_LANGID_WELSH_WALES 0x0452 +#define TT_MS_LANGID_KHMER_CAMBODIA 0x0453 +#define TT_MS_LANGID_LAO_LAOS 0x0454 +#define TT_MS_LANGID_BURMESE_MYANMAR 0x0455 +#define TT_MS_LANGID_GALICIAN_SPAIN 0x0456 +#define TT_MS_LANGID_KONKANI_INDIA 0x0457 +#define TT_MS_LANGID_MANIPURI_INDIA /* Bengali */ 0x0458 +#define TT_MS_LANGID_SINDHI_INDIA /* Arabic */ 0x0459 +#define TT_MS_LANGID_SINDHI_PAKISTAN 0x0859 + /* Missing a LCID for Sindhi in Devanagari script */ +#define TT_MS_LANGID_SYRIAC_SYRIA 0x045a +#define TT_MS_LANGID_SINHALESE_SRI_LANKA 0x045b +#define TT_MS_LANGID_CHEROKEE_UNITED_STATES 0x045c +#define TT_MS_LANGID_INUKTITUT_CANADA 0x045d +#define TT_MS_LANGID_AMHARIC_ETHIOPIA 0x045e +#define TT_MS_LANGID_TAMAZIGHT_MOROCCO /* Arabic */ 0x045f +#define TT_MS_LANGID_TAMAZIGHT_MOROCCO_LATIN 0x085f + /* Missing a LCID for Tifinagh script */ +#define TT_MS_LANGID_KASHMIRI_PAKISTAN /* Arabic */ 0x0460 + /* Spelled this way by XPsp2 Platform SDK (2004-07-26) */ + /* script is yet unclear... might be Arabic, Nagari or Sharada */ +#define TT_MS_LANGID_KASHMIRI_SASIA 0x0860 + /* ... and aliased (by MS) for compatibility reasons. */ +#define TT_MS_LANGID_KASHMIRI_INDIA TT_MS_LANGID_KASHMIRI_SASIA +#define TT_MS_LANGID_NEPALI_NEPAL 0x0461 +#define TT_MS_LANGID_NEPALI_INDIA 0x0861 +#define TT_MS_LANGID_FRISIAN_NETHERLANDS 0x0462 +#define TT_MS_LANGID_PASHTO_AFGHANISTAN 0x0463 +#define TT_MS_LANGID_FILIPINO_PHILIPPINES 0x0464 +#define TT_MS_LANGID_DHIVEHI_MALDIVES 0x0465 + /* alias declared in Windows 2000 */ +#define TT_MS_LANGID_DIVEHI_MALDIVES TT_MS_LANGID_DHIVEHI_MALDIVES +#define TT_MS_LANGID_EDO_NIGERIA 0x0466 +#define TT_MS_LANGID_FULFULDE_NIGERIA 0x0467 +#define TT_MS_LANGID_HAUSA_NIGERIA 0x0468 +#define TT_MS_LANGID_IBIBIO_NIGERIA 0x0469 +#define TT_MS_LANGID_YORUBA_NIGERIA 0x046a +#define TT_MS_LANGID_QUECHUA_BOLIVIA 0x046b +#define TT_MS_LANGID_QUECHUA_ECUADOR 0x086b +#define TT_MS_LANGID_QUECHUA_PERU 0x0c6b +#define TT_MS_LANGID_SEPEDI_SOUTH_AFRICA 0x046c + /* Also spelled by XPsp2 Platform SDK (2004-07-26) */ +#define TT_MS_LANGID_SOTHO_SOUTHERN_SOUTH_AFRICA \ + TT_MS_LANGID_SEPEDI_SOUTH_AFRICA + /* language codes 0x046d, 0x046e and 0x046f are (still) unknown. */ +#define TT_MS_LANGID_IGBO_NIGERIA 0x0470 +#define TT_MS_LANGID_KANURI_NIGERIA 0x0471 +#define TT_MS_LANGID_OROMO_ETHIOPIA 0x0472 +#define TT_MS_LANGID_TIGRIGNA_ETHIOPIA 0x0473 +#define TT_MS_LANGID_TIGRIGNA_ERYTHREA 0x0873 + /* also spelled in the `Passport SDK' list as: */ +#define TT_MS_LANGID_TIGRIGNA_ERYTREA TT_MS_LANGID_TIGRIGNA_ERYTHREA +#define TT_MS_LANGID_GUARANI_PARAGUAY 0x0474 +#define TT_MS_LANGID_HAWAIIAN_UNITED_STATES 0x0475 +#define TT_MS_LANGID_LATIN 0x0476 +#define TT_MS_LANGID_SOMALI_SOMALIA 0x0477 + /* Note: Yi does not have a (proper) ISO 639-2 code, since it is mostly */ + /* not written (but OTOH the peculiar writing system is worth */ + /* studying). */ +#define TT_MS_LANGID_YI_CHINA 0x0478 +#define TT_MS_LANGID_PAPIAMENTU_NETHERLANDS_ANTILLES 0x0479 + /* language codes from 0x047a to 0x047f are (still) unknown. */ +#define TT_MS_LANGID_UIGHUR_CHINA 0x0480 +#define TT_MS_LANGID_MAORI_NEW_ZEALAND 0x0481 + +#if 0 /* not deemed useful for fonts */ +#define TT_MS_LANGID_HUMAN_INTERFACE_DEVICE 0x04ff +#endif + + + /*************************************************************************/ + /* */ + /* Possible values of the `name' identifier field in the name records of */ + /* the TTF `name' table. These values are platform independent. */ + /* */ +#define TT_NAME_ID_COPYRIGHT 0 +#define TT_NAME_ID_FONT_FAMILY 1 +#define TT_NAME_ID_FONT_SUBFAMILY 2 +#define TT_NAME_ID_UNIQUE_ID 3 +#define TT_NAME_ID_FULL_NAME 4 +#define TT_NAME_ID_VERSION_STRING 5 +#define TT_NAME_ID_PS_NAME 6 +#define TT_NAME_ID_TRADEMARK 7 + + /* the following values are from the OpenType spec */ +#define TT_NAME_ID_MANUFACTURER 8 +#define TT_NAME_ID_DESIGNER 9 +#define TT_NAME_ID_DESCRIPTION 10 +#define TT_NAME_ID_VENDOR_URL 11 +#define TT_NAME_ID_DESIGNER_URL 12 +#define TT_NAME_ID_LICENSE 13 +#define TT_NAME_ID_LICENSE_URL 14 + /* number 15 is reserved */ +#define TT_NAME_ID_PREFERRED_FAMILY 16 +#define TT_NAME_ID_PREFERRED_SUBFAMILY 17 +#define TT_NAME_ID_MAC_FULL_NAME 18 + + /* The following code is new as of 2000-01-21 */ +#define TT_NAME_ID_SAMPLE_TEXT 19 + + /* This is new in OpenType 1.3 */ +#define TT_NAME_ID_CID_FINDFONT_NAME 20 + + + /*************************************************************************/ + /* */ + /* Bit mask values for the Unicode Ranges from the TTF `OS2 ' table. */ + /* */ + /* Updated 02-Jul-2000. */ + /* */ + + /* General Scripts Area */ + + /* Bit 0 Basic Latin */ +#define TT_UCR_BASIC_LATIN (1L << 0) /* U+0020-U+007E */ + /* Bit 1 C1 Controls and Latin-1 Supplement */ +#define TT_UCR_LATIN1_SUPPLEMENT (1L << 1) /* U+0080-U+00FF */ + /* Bit 2 Latin Extended-A */ +#define TT_UCR_LATIN_EXTENDED_A (1L << 2) /* U+0100-U+017F */ + /* Bit 3 Latin Extended-B */ +#define TT_UCR_LATIN_EXTENDED_B (1L << 3) /* U+0180-U+024F */ + /* Bit 4 IPA Extensions */ +#define TT_UCR_IPA_EXTENSIONS (1L << 4) /* U+0250-U+02AF */ + /* Bit 5 Spacing Modifier Letters */ +#define TT_UCR_SPACING_MODIFIER (1L << 5) /* U+02B0-U+02FF */ + /* Bit 6 Combining Diacritical Marks */ +#define TT_UCR_COMBINING_DIACRITICS (1L << 6) /* U+0300-U+036F */ + /* Bit 7 Greek and Coptic */ +#define TT_UCR_GREEK (1L << 7) /* U+0370-U+03FF */ + /* Bit 8 is reserved (was: Greek Symbols and Coptic) */ + /* Bit 9 Cyrillic + */ + /* Cyrillic Supplementary */ +#define TT_UCR_CYRILLIC (1L << 9) /* U+0400-U+04FF */ + /* U+0500-U+052F */ + /* Bit 10 Armenian */ +#define TT_UCR_ARMENIAN (1L << 10) /* U+0530-U+058F */ + /* Bit 11 Hebrew */ +#define TT_UCR_HEBREW (1L << 11) /* U+0590-U+05FF */ + /* Bit 12 is reserved (was: Hebrew Extended) */ + /* Bit 13 Arabic */ +#define TT_UCR_ARABIC (1L << 13) /* U+0600-U+06FF */ + /* Bit 14 is reserved (was: Arabic Extended) */ + /* Bit 15 Devanagari */ +#define TT_UCR_DEVANAGARI (1L << 15) /* U+0900-U+097F */ + /* Bit 16 Bengali */ +#define TT_UCR_BENGALI (1L << 16) /* U+0980-U+09FF */ + /* Bit 17 Gurmukhi */ +#define TT_UCR_GURMUKHI (1L << 17) /* U+0A00-U+0A7F */ + /* Bit 18 Gujarati */ +#define TT_UCR_GUJARATI (1L << 18) /* U+0A80-U+0AFF */ + /* Bit 19 Oriya */ +#define TT_UCR_ORIYA (1L << 19) /* U+0B00-U+0B7F */ + /* Bit 20 Tamil */ +#define TT_UCR_TAMIL (1L << 20) /* U+0B80-U+0BFF */ + /* Bit 21 Telugu */ +#define TT_UCR_TELUGU (1L << 21) /* U+0C00-U+0C7F */ + /* Bit 22 Kannada */ +#define TT_UCR_KANNADA (1L << 22) /* U+0C80-U+0CFF */ + /* Bit 23 Malayalam */ +#define TT_UCR_MALAYALAM (1L << 23) /* U+0D00-U+0D7F */ + /* Bit 24 Thai */ +#define TT_UCR_THAI (1L << 24) /* U+0E00-U+0E7F */ + /* Bit 25 Lao */ +#define TT_UCR_LAO (1L << 25) /* U+0E80-U+0EFF */ + /* Bit 26 Georgian */ +#define TT_UCR_GEORGIAN (1L << 26) /* U+10A0-U+10FF */ + /* Bit 27 is reserved (was Georgian Extended) */ + /* Bit 28 Hangul Jamo */ +#define TT_UCR_HANGUL_JAMO (1L << 28) /* U+1100-U+11FF */ + /* Bit 29 Latin Extended Additional */ +#define TT_UCR_LATIN_EXTENDED_ADDITIONAL (1L << 29) /* U+1E00-U+1EFF */ + /* Bit 30 Greek Extended */ +#define TT_UCR_GREEK_EXTENDED (1L << 30) /* U+1F00-U+1FFF */ + + /* Symbols Area */ + + /* Bit 31 General Punctuation */ +#define TT_UCR_GENERAL_PUNCTUATION (1L << 31) /* U+2000-U+206F */ + /* Bit 32 Superscripts And Subscripts */ +#define TT_UCR_SUPERSCRIPTS_SUBSCRIPTS (1L << 0) /* U+2070-U+209F */ + /* Bit 33 Currency Symbols */ +#define TT_UCR_CURRENCY_SYMBOLS (1L << 1) /* U+20A0-U+20CF */ + /* Bit 34 Combining Diacritical Marks For Symbols */ +#define TT_UCR_COMBINING_DIACRITICS_SYMB (1L << 2) /* U+20D0-U+20FF */ + /* Bit 35 Letterlike Symbols */ +#define TT_UCR_LETTERLIKE_SYMBOLS (1L << 3) /* U+2100-U+214F */ + /* Bit 36 Number Forms */ +#define TT_UCR_NUMBER_FORMS (1L << 4) /* U+2150-U+218F */ + /* Bit 37 Arrows + */ + /* Supplemental Arrows-A + */ + /* Supplemental Arrows-B */ +#define TT_UCR_ARROWS (1L << 5) /* U+2190-U+21FF */ + /* U+27F0-U+27FF */ + /* U+2900-U+297F */ + /* Bit 38 Mathematical Operators + */ + /* Supplemental Mathematical Operators + */ + /* Miscellaneous Mathematical Symbols-A + */ + /* Miscellaneous Mathematical Symbols-B */ +#define TT_UCR_MATHEMATICAL_OPERATORS (1L << 6) /* U+2200-U+22FF */ + /* U+2A00-U+2AFF */ + /* U+27C0-U+27EF */ + /* U+2980-U+29FF */ + /* Bit 39 Miscellaneous Technical */ +#define TT_UCR_MISCELLANEOUS_TECHNICAL (1L << 7) /* U+2300-U+23FF */ + /* Bit 40 Control Pictures */ +#define TT_UCR_CONTROL_PICTURES (1L << 8) /* U+2400-U+243F */ + /* Bit 41 Optical Character Recognition */ +#define TT_UCR_OCR (1L << 9) /* U+2440-U+245F */ + /* Bit 42 Enclosed Alphanumerics */ +#define TT_UCR_ENCLOSED_ALPHANUMERICS (1L << 10) /* U+2460-U+24FF */ + /* Bit 43 Box Drawing */ +#define TT_UCR_BOX_DRAWING (1L << 11) /* U+2500-U+257F */ + /* Bit 44 Block Elements */ +#define TT_UCR_BLOCK_ELEMENTS (1L << 12) /* U+2580-U+259F */ + /* Bit 45 Geometric Shapes */ +#define TT_UCR_GEOMETRIC_SHAPES (1L << 13) /* U+25A0-U+25FF */ + /* Bit 46 Miscellaneous Symbols */ +#define TT_UCR_MISCELLANEOUS_SYMBOLS (1L << 14) /* U+2600-U+26FF */ + /* Bit 47 Dingbats */ +#define TT_UCR_DINGBATS (1L << 15) /* U+2700-U+27BF */ + + /* CJK Phonetics and Symbols Area */ + + /* Bit 48 CJK Symbols and Punctuation */ +#define TT_UCR_CJK_SYMBOLS (1L << 16) /* U+3000-U+303F */ + /* Bit 49 Hiragana */ +#define TT_UCR_HIRAGANA (1L << 17) /* U+3040-U+309F */ + /* Bit 50 Katakana + */ + /* Katakana Phonetic Extensions */ +#define TT_UCR_KATAKANA (1L << 18) /* U+30A0-U+30FF */ + /* U+31F0-U+31FF */ + /* Bit 51 Bopomofo + */ + /* Bopomofo Extended */ +#define TT_UCR_BOPOMOFO (1L << 19) /* U+3100-U+312F */ + /* U+31A0-U+31BF */ + /* Bit 52 Hangul Compatibility Jamo */ +#define TT_UCR_HANGUL_COMPATIBILITY_JAMO (1L << 20) /* U+3130-U+318F */ + /* Bit 53 Kanbun */ +#define TT_UCR_CJK_MISC (1L << 21) /* U+3190-U+319F */ +#define TT_UCR_KANBUN TT_UCR_CJK_MISC + /* Bit 54 Enclosed CJK Letters and Months */ +#define TT_UCR_ENCLOSED_CJK_LETTERS_MONTHS (1L << 22) /* U+3200-U+32FF */ + /* Bit 55 CJK Compatibility */ +#define TT_UCR_CJK_COMPATIBILITY (1L << 23) /* U+3300-U+33FF */ + + /* Hangul Syllables Area */ + + /* Bit 56 Hangul */ +#define TT_UCR_HANGUL (1L << 24) /* U+AC00-U+D7A3 */ + + /* Surrogates Area */ + + /* Bit 57 High Surrogates + */ + /* High Private Use Surrogates + */ + /* Low Surrogates */ +#define TT_UCR_SURROGATES (1L << 25) /* U+D800-U+DB7F */ + /* U+DB80-U+DBFF */ + /* U+DC00-U+DFFF */ + /* According to OpenType specs v.1.3+, setting bit 57 implies that there */ + /* is at least one codepoint beyond the Basic Multilingual Plane that is */ + /* supported by this font. So it really means: >= U+10000 */ + + /* Bit 58 is reserved for Unicode SubRanges */ + + /* CJK Ideographs Area */ + + /* Bit 59 CJK Unified Ideographs + */ + /* CJK Radicals Supplement + */ + /* Kangxi Radicals + */ + /* Ideographic Description Characters + */ + /* CJK Unified Ideographs Extension A */ + /* CJK Unified Ideographs Extension A + */ + /* CJK Unified Ideographs Extension B + */ + /* Kanbun */ +#define TT_UCR_CJK_UNIFIED_IDEOGRAPHS (1L << 27) /* U+4E00-U+9FFF */ + /* U+2E80-U+2EFF */ + /* U+2F00-U+2FDF */ + /* U+2FF0-U+2FFF */ + /* U+3400-U+4DB5 */ + /*U+20000-U+2A6DF*/ + /* U+3190-U+319F */ + + /* Private Use Area */ + + /* Bit 60 Private Use */ +#define TT_UCR_PRIVATE_USE (1L << 28) /* U+E000-U+F8FF */ + + /* Compatibility Area and Specials */ + + /* Bit 61 CJK Compatibility Ideographs + */ + /* CJK Compatibility Ideographs Supplement */ +#define TT_UCR_CJK_COMPATIBILITY_IDEOGRAPHS (1L << 29) /* U+F900-U+FAFF */ + /*U+2F800-U+2FA1F*/ + /* Bit 62 Alphabetic Presentation Forms */ +#define TT_UCR_ALPHABETIC_PRESENTATION_FORMS (1L << 30) /* U+FB00-U+FB4F */ + /* Bit 63 Arabic Presentation Forms-A */ +#define TT_UCR_ARABIC_PRESENTATIONS_A (1L << 31) /* U+FB50-U+FDFF */ + /* Bit 64 Combining Half Marks */ +#define TT_UCR_COMBINING_HALF_MARKS (1L << 0) /* U+FE20-U+FE2F */ + /* Bit 65 CJK Compatibility Forms */ +#define TT_UCR_CJK_COMPATIBILITY_FORMS (1L << 1) /* U+FE30-U+FE4F */ + /* Bit 66 Small Form Variants */ +#define TT_UCR_SMALL_FORM_VARIANTS (1L << 2) /* U+FE50-U+FE6F */ + /* Bit 67 Arabic Presentation Forms-B */ +#define TT_UCR_ARABIC_PRESENTATIONS_B (1L << 3) /* U+FE70-U+FEFE */ + /* Bit 68 Halfwidth and Fullwidth Forms */ +#define TT_UCR_HALFWIDTH_FULLWIDTH_FORMS (1L << 4) /* U+FF00-U+FFEF */ + /* Bit 69 Specials */ +#define TT_UCR_SPECIALS (1L << 5) /* U+FFF0-U+FFFD */ + /* Bit 70 Tibetan */ +#define TT_UCR_TIBETAN (1L << 6) /* U+0F00-U+0FFF */ + /* Bit 71 Syriac */ +#define TT_UCR_SYRIAC (1L << 7) /* U+0700-U+074F */ + /* Bit 72 Thaana */ +#define TT_UCR_THAANA (1L << 8) /* U+0780-U+07BF */ + /* Bit 73 Sinhala */ +#define TT_UCR_SINHALA (1L << 9) /* U+0D80-U+0DFF */ + /* Bit 74 Myanmar */ +#define TT_UCR_MYANMAR (1L << 10) /* U+1000-U+109F */ + /* Bit 75 Ethiopic */ +#define TT_UCR_ETHIOPIC (1L << 11) /* U+1200-U+137F */ + /* Bit 76 Cherokee */ +#define TT_UCR_CHEROKEE (1L << 12) /* U+13A0-U+13FF */ + /* Bit 77 Unified Canadian Aboriginal Syllabics */ +#define TT_UCR_CANADIAN_ABORIGINAL_SYLLABICS (1L << 13) /* U+1400-U+167F */ + /* Bit 78 Ogham */ +#define TT_UCR_OGHAM (1L << 14) /* U+1680-U+169F */ + /* Bit 79 Runic */ +#define TT_UCR_RUNIC (1L << 15) /* U+16A0-U+16FF */ + /* Bit 80 Khmer */ +#define TT_UCR_KHMER (1L << 16) /* U+1780-U+17FF */ + /* Bit 81 Mongolian */ +#define TT_UCR_MONGOLIAN (1L << 17) /* U+1800-U+18AF */ + /* Bit 82 Braille Patterns */ +#define TT_UCR_BRAILLE (1L << 18) /* U+2800-U+28FF */ + /* Bit 83 Yi Syllables + */ + /* Yi Radicals */ +#define TT_UCR_YI (1L << 19) /* U+A000-U+A48F */ + /* U+A490-U+A4CF */ + /* Bit 84 Tagalog + */ + /* Hanunoo + */ + /* Buhid + */ + /* Tagbanwa */ +#define TT_UCR_PHILIPPINE (1L << 20) /* U+1700-U+171F */ + /* U+1720-U+173F */ + /* U+1740-U+175F */ + /* U+1760-U+177F */ + /* Bit 85 Old Italic */ +#define TT_UCR_OLD_ITALIC (1L << 21) /*U+10300-U+1032F*/ + /* Bit 86 Gothic */ +#define TT_UCR_GOTHIC (1L << 22) /*U+10330-U+1034F*/ + /* Bit 87 Deseret */ +#define TT_UCR_DESERET (1L << 23) /*U+10400-U+1044F*/ + /* Bit 88 Byzantine Musical Symbols + */ + /* Musical Symbols */ +#define TT_UCR_MUSICAL_SYMBOLS (1L << 24) /*U+1D000-U+1D0FF*/ + /*U+1D100-U+1D1FF*/ + /* Bit 89 Mathematical Alphanumeric Symbols */ +#define TT_UCR_MATH_ALPHANUMERIC_SYMBOLS (1L << 25) /*U+1D400-U+1D7FF*/ + /* Bit 90 Private Use (plane 15) + */ + /* Private Use (plane 16) */ +#define TT_UCR_PRIVATE_USE_SUPPLEMENTARY (1L << 26) /*U+F0000-U+FFFFD*/ + /*U+100000-U+10FFFD*/ + /* Bit 91 Variation Selectors */ +#define TT_UCR_VARIATION_SELECTORS (1L << 27) /* U+FE00-U+FE0F */ + /* Bit 92 Tags */ +#define TT_UCR_TAGS (1L << 28) /*U+E0000-U+E007F*/ + + + /*************************************************************************/ + /* */ + /* Some compilers have a very limited length of identifiers. */ + /* */ +#if defined( __TURBOC__ ) && __TURBOC__ < 0x0410 || defined( __PACIFIC__ ) +#define HAVE_LIMIT_ON_IDENTS +#endif + + +#ifndef HAVE_LIMIT_ON_IDENTS + + + /*************************************************************************/ + /* */ + /* Here some alias #defines in order to be clearer. */ + /* */ + /* These are not always #defined to stay within the 31 character limit */ + /* which some compilers have. */ + /* */ + /* Credits go to Dave Hoo <dhoo@flash.net> for pointing out that modern */ + /* Borland compilers (read: from BC++ 3.1 on) can increase this limit. */ + /* If you get a warning with such a compiler, use the -i40 switch. */ + /* */ +#define TT_UCR_ARABIC_PRESENTATION_FORMS_A \ + TT_UCR_ARABIC_PRESENTATIONS_A +#define TT_UCR_ARABIC_PRESENTATION_FORMS_B \ + TT_UCR_ARABIC_PRESENTATIONS_B + +#define TT_UCR_COMBINING_DIACRITICAL_MARKS \ + TT_UCR_COMBINING_DIACRITICS +#define TT_UCR_COMBINING_DIACRITICAL_MARKS_SYMB \ + TT_UCR_COMBINING_DIACRITICS_SYMB + + +#endif /* !HAVE_LIMIT_ON_IDENTS */ + + +FT_END_HEADER + +#endif /* __TTNAMEID_H__ */ + + +/* END */ diff --git a/include/freetype/tttables.h b/include/freetype/tttables.h new file mode 100644 index 0000000..43eca2e --- /dev/null +++ b/include/freetype/tttables.h @@ -0,0 +1,756 @@ +/***************************************************************************/ +/* */ +/* tttables.h */ +/* */ +/* Basic SFNT/TrueType tables definitions and interface */ +/* (specification only). */ +/* */ +/* Copyright 1996-2001, 2002, 2003, 2004, 2005 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef __TTTABLES_H__ +#define __TTTABLES_H__ + + +#include <ft2build.h> +#include FT_FREETYPE_H + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + /*************************************************************************/ + /* */ + /* <Section> */ + /* truetype_tables */ + /* */ + /* <Title> */ + /* TrueType Tables */ + /* */ + /* <Abstract> */ + /* TrueType specific table types and functions. */ + /* */ + /* <Description> */ + /* This section contains the definition of TrueType-specific tables */ + /* as well as some routines used to access and process them. */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* TT_Header */ + /* */ + /* <Description> */ + /* A structure used to model a TrueType font header table. All */ + /* fields follow the TrueType specification. */ + /* */ + typedef struct TT_Header_ + { + FT_Fixed Table_Version; + FT_Fixed Font_Revision; + + FT_Long CheckSum_Adjust; + FT_Long Magic_Number; + + FT_UShort Flags; + FT_UShort Units_Per_EM; + + FT_Long Created [2]; + FT_Long Modified[2]; + + FT_Short xMin; + FT_Short yMin; + FT_Short xMax; + FT_Short yMax; + + FT_UShort Mac_Style; + FT_UShort Lowest_Rec_PPEM; + + FT_Short Font_Direction; + FT_Short Index_To_Loc_Format; + FT_Short Glyph_Data_Format; + + } TT_Header; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* TT_HoriHeader */ + /* */ + /* <Description> */ + /* A structure used to model a TrueType horizontal header, the `hhea' */ + /* table, as well as the corresponding horizontal metrics table, */ + /* i.e., the `hmtx' table. */ + /* */ + /* <Fields> */ + /* Version :: The table version. */ + /* */ + /* Ascender :: The font's ascender, i.e., the distance */ + /* from the baseline to the top-most of all */ + /* glyph points found in the font. */ + /* */ + /* This value is invalid in many fonts, as */ + /* it is usually set by the font designer, */ + /* and often reflects only a portion of the */ + /* glyphs found in the font (maybe ASCII). */ + /* */ + /* You should use the `sTypoAscender' field */ + /* of the OS/2 table instead if you want */ + /* the correct one. */ + /* */ + /* Descender :: The font's descender, i.e., the distance */ + /* from the baseline to the bottom-most of */ + /* all glyph points found in the font. It */ + /* is negative. */ + /* */ + /* This value is invalid in many fonts, as */ + /* it is usually set by the font designer, */ + /* and often reflects only a portion of the */ + /* glyphs found in the font (maybe ASCII). */ + /* */ + /* You should use the `sTypoDescender' */ + /* field of the OS/2 table instead if you */ + /* want the correct one. */ + /* */ + /* Line_Gap :: The font's line gap, i.e., the distance */ + /* to add to the ascender and descender to */ + /* get the BTB, i.e., the */ + /* baseline-to-baseline distance for the */ + /* font. */ + /* */ + /* advance_Width_Max :: This field is the maximum of all advance */ + /* widths found in the font. It can be */ + /* used to compute the maximum width of an */ + /* arbitrary string of text. */ + /* */ + /* min_Left_Side_Bearing :: The minimum left side bearing of all */ + /* glyphs within the font. */ + /* */ + /* min_Right_Side_Bearing :: The minimum right side bearing of all */ + /* glyphs within the font. */ + /* */ + /* xMax_Extent :: The maximum horizontal extent (i.e., the */ + /* `width' of a glyph's bounding box) for */ + /* all glyphs in the font. */ + /* */ + /* caret_Slope_Rise :: The rise coefficient of the cursor's */ + /* slope of the cursor (slope=rise/run). */ + /* */ + /* caret_Slope_Run :: The run coefficient of the cursor's */ + /* slope. */ + /* */ + /* Reserved :: 10 reserved bytes. */ + /* */ + /* metric_Data_Format :: Always 0. */ + /* */ + /* number_Of_HMetrics :: Number of HMetrics entries in the `hmtx' */ + /* table -- this value can be smaller than */ + /* the total number of glyphs in the font. */ + /* */ + /* long_metrics :: A pointer into the `hmtx' table. */ + /* */ + /* short_metrics :: A pointer into the `hmtx' table. */ + /* */ + /* <Note> */ + /* IMPORTANT: The TT_HoriHeader and TT_VertHeader structures should */ + /* be identical except for the names of their fields which */ + /* are different. */ + /* */ + /* This ensures that a single function in the `ttload' */ + /* module is able to read both the horizontal and vertical */ + /* headers. */ + /* */ + typedef struct TT_HoriHeader_ + { + FT_Fixed Version; + FT_Short Ascender; + FT_Short Descender; + FT_Short Line_Gap; + + FT_UShort advance_Width_Max; /* advance width maximum */ + + FT_Short min_Left_Side_Bearing; /* minimum left-sb */ + FT_Short min_Right_Side_Bearing; /* minimum right-sb */ + FT_Short xMax_Extent; /* xmax extents */ + FT_Short caret_Slope_Rise; + FT_Short caret_Slope_Run; + FT_Short caret_Offset; + + FT_Short Reserved[4]; + + FT_Short metric_Data_Format; + FT_UShort number_Of_HMetrics; + + /* The following fields are not defined by the TrueType specification */ + /* but they are used to connect the metrics header to the relevant */ + /* `HMTX' table. */ + + void* long_metrics; + void* short_metrics; + + } TT_HoriHeader; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* TT_VertHeader */ + /* */ + /* <Description> */ + /* A structure used to model a TrueType vertical header, the `vhea' */ + /* table, as well as the corresponding vertical metrics table, i.e., */ + /* the `vmtx' table. */ + /* */ + /* <Fields> */ + /* Version :: The table version. */ + /* */ + /* Ascender :: The font's ascender, i.e., the distance */ + /* from the baseline to the top-most of */ + /* all glyph points found in the font. */ + /* */ + /* This value is invalid in many fonts, as */ + /* it is usually set by the font designer, */ + /* and often reflects only a portion of */ + /* the glyphs found in the font (maybe */ + /* ASCII). */ + /* */ + /* You should use the `sTypoAscender' */ + /* field of the OS/2 table instead if you */ + /* want the correct one. */ + /* */ + /* Descender :: The font's descender, i.e., the */ + /* distance from the baseline to the */ + /* bottom-most of all glyph points found */ + /* in the font. It is negative. */ + /* */ + /* This value is invalid in many fonts, as */ + /* it is usually set by the font designer, */ + /* and often reflects only a portion of */ + /* the glyphs found in the font (maybe */ + /* ASCII). */ + /* */ + /* You should use the `sTypoDescender' */ + /* field of the OS/2 table instead if you */ + /* want the correct one. */ + /* */ + /* Line_Gap :: The font's line gap, i.e., the distance */ + /* to add to the ascender and descender to */ + /* get the BTB, i.e., the */ + /* baseline-to-baseline distance for the */ + /* font. */ + /* */ + /* advance_Height_Max :: This field is the maximum of all */ + /* advance heights found in the font. It */ + /* can be used to compute the maximum */ + /* height of an arbitrary string of text. */ + /* */ + /* min_Top_Side_Bearing :: The minimum top side bearing of all */ + /* glyphs within the font. */ + /* */ + /* min_Bottom_Side_Bearing :: The minimum bottom side bearing of all */ + /* glyphs within the font. */ + /* */ + /* yMax_Extent :: The maximum vertical extent (i.e., the */ + /* `height' of a glyph's bounding box) for */ + /* all glyphs in the font. */ + /* */ + /* caret_Slope_Rise :: The rise coefficient of the cursor's */ + /* slope of the cursor (slope=rise/run). */ + /* */ + /* caret_Slope_Run :: The run coefficient of the cursor's */ + /* slope. */ + /* */ + /* caret_Offset :: The cursor's offset for slanted fonts. */ + /* This value is `reserved' in vmtx */ + /* version 1.0. */ + /* */ + /* Reserved :: 8 reserved bytes. */ + /* */ + /* metric_Data_Format :: Always 0. */ + /* */ + /* number_Of_HMetrics :: Number of VMetrics entries in the */ + /* `vmtx' table -- this value can be */ + /* smaller than the total number of glyphs */ + /* in the font. */ + /* */ + /* long_metrics :: A pointer into the `vmtx' table. */ + /* */ + /* short_metrics :: A pointer into the `vmtx' table. */ + /* */ + /* <Note> */ + /* IMPORTANT: The TT_HoriHeader and TT_VertHeader structures should */ + /* be identical except for the names of their fields which */ + /* are different. */ + /* */ + /* This ensures that a single function in the `ttload' */ + /* module is able to read both the horizontal and vertical */ + /* headers. */ + /* */ + typedef struct TT_VertHeader_ + { + FT_Fixed Version; + FT_Short Ascender; + FT_Short Descender; + FT_Short Line_Gap; + + FT_UShort advance_Height_Max; /* advance height maximum */ + + FT_Short min_Top_Side_Bearing; /* minimum left-sb or top-sb */ + FT_Short min_Bottom_Side_Bearing; /* minimum right-sb or bottom-sb */ + FT_Short yMax_Extent; /* xmax or ymax extents */ + FT_Short caret_Slope_Rise; + FT_Short caret_Slope_Run; + FT_Short caret_Offset; + + FT_Short Reserved[4]; + + FT_Short metric_Data_Format; + FT_UShort number_Of_VMetrics; + + /* The following fields are not defined by the TrueType specification */ + /* but they're used to connect the metrics header to the relevant */ + /* `HMTX' or `VMTX' table. */ + + void* long_metrics; + void* short_metrics; + + } TT_VertHeader; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* TT_OS2 */ + /* */ + /* <Description> */ + /* A structure used to model a TrueType OS/2 table. This is the long */ + /* table version. All fields comply to the TrueType specification. */ + /* */ + /* Note that we now support old Mac fonts which do not include an */ + /* OS/2 table. In this case, the `version' field is always set to */ + /* 0xFFFF. */ + /* */ + typedef struct TT_OS2_ + { + FT_UShort version; /* 0x0001 - more or 0xFFFF */ + FT_Short xAvgCharWidth; + FT_UShort usWeightClass; + FT_UShort usWidthClass; + FT_Short fsType; + FT_Short ySubscriptXSize; + FT_Short ySubscriptYSize; + FT_Short ySubscriptXOffset; + FT_Short ySubscriptYOffset; + FT_Short ySuperscriptXSize; + FT_Short ySuperscriptYSize; + FT_Short ySuperscriptXOffset; + FT_Short ySuperscriptYOffset; + FT_Short yStrikeoutSize; + FT_Short yStrikeoutPosition; + FT_Short sFamilyClass; + + FT_Byte panose[10]; + + FT_ULong ulUnicodeRange1; /* Bits 0-31 */ + FT_ULong ulUnicodeRange2; /* Bits 32-63 */ + FT_ULong ulUnicodeRange3; /* Bits 64-95 */ + FT_ULong ulUnicodeRange4; /* Bits 96-127 */ + + FT_Char achVendID[4]; + + FT_UShort fsSelection; + FT_UShort usFirstCharIndex; + FT_UShort usLastCharIndex; + FT_Short sTypoAscender; + FT_Short sTypoDescender; + FT_Short sTypoLineGap; + FT_UShort usWinAscent; + FT_UShort usWinDescent; + + /* only version 1 tables: */ + + FT_ULong ulCodePageRange1; /* Bits 0-31 */ + FT_ULong ulCodePageRange2; /* Bits 32-63 */ + + /* only version 2 tables: */ + + FT_Short sxHeight; + FT_Short sCapHeight; + FT_UShort usDefaultChar; + FT_UShort usBreakChar; + FT_UShort usMaxContext; + + } TT_OS2; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* TT_Postscript */ + /* */ + /* <Description> */ + /* A structure used to model a TrueType Postscript table. All fields */ + /* comply to the TrueType specification. This structure does not */ + /* reference the Postscript glyph names, which can be nevertheless */ + /* accessed with the `ttpost' module. */ + /* */ + typedef struct TT_Postscript_ + { + FT_Fixed FormatType; + FT_Fixed italicAngle; + FT_Short underlinePosition; + FT_Short underlineThickness; + FT_ULong isFixedPitch; + FT_ULong minMemType42; + FT_ULong maxMemType42; + FT_ULong minMemType1; + FT_ULong maxMemType1; + + /* Glyph names follow in the file, but we don't */ + /* load them by default. See the ttpost.c file. */ + + } TT_Postscript; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* TT_PCLT */ + /* */ + /* <Description> */ + /* A structure used to model a TrueType PCLT table. All fields */ + /* comply to the TrueType specification. */ + /* */ + typedef struct TT_PCLT_ + { + FT_Fixed Version; + FT_ULong FontNumber; + FT_UShort Pitch; + FT_UShort xHeight; + FT_UShort Style; + FT_UShort TypeFamily; + FT_UShort CapHeight; + FT_UShort SymbolSet; + FT_Char TypeFace[16]; + FT_Char CharacterComplement[8]; + FT_Char FileName[6]; + FT_Char StrokeWeight; + FT_Char WidthType; + FT_Byte SerifStyle; + FT_Byte Reserved; + + } TT_PCLT; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* TT_MaxProfile */ + /* */ + /* <Description> */ + /* The maximum profile is a table containing many max values which */ + /* can be used to pre-allocate arrays. This ensures that no memory */ + /* allocation occurs during a glyph load. */ + /* */ + /* <Fields> */ + /* version :: The version number. */ + /* */ + /* numGlyphs :: The number of glyphs in this TrueType */ + /* font. */ + /* */ + /* maxPoints :: The maximum number of points in a */ + /* non-composite TrueType glyph. See also */ + /* the structure element */ + /* `maxCompositePoints'. */ + /* */ + /* maxContours :: The maximum number of contours in a */ + /* non-composite TrueType glyph. See also */ + /* the structure element */ + /* `maxCompositeContours'. */ + /* */ + /* maxCompositePoints :: The maximum number of points in a */ + /* composite TrueType glyph. See also the */ + /* structure element `maxPoints'. */ + /* */ + /* maxCompositeContours :: The maximum number of contours in a */ + /* composite TrueType glyph. See also the */ + /* structure element `maxContours'. */ + /* */ + /* maxZones :: The maximum number of zones used for */ + /* glyph hinting. */ + /* */ + /* maxTwilightPoints :: The maximum number of points in the */ + /* twilight zone used for glyph hinting. */ + /* */ + /* maxStorage :: The maximum number of elements in the */ + /* storage area used for glyph hinting. */ + /* */ + /* maxFunctionDefs :: The maximum number of function */ + /* definitions in the TrueType bytecode for */ + /* this font. */ + /* */ + /* maxInstructionDefs :: The maximum number of instruction */ + /* definitions in the TrueType bytecode for */ + /* this font. */ + /* */ + /* maxStackElements :: The maximum number of stack elements used */ + /* during bytecode interpretation. */ + /* */ + /* maxSizeOfInstructions :: The maximum number of TrueType opcodes */ + /* used for glyph hinting. */ + /* */ + /* maxComponentElements :: The maximum number of simple (i.e., non- */ + /* composite) glyphs in a composite glyph. */ + /* */ + /* maxComponentDepth :: The maximum nesting depth of composite */ + /* glyphs. */ + /* */ + /* <Note> */ + /* This structure is only used during font loading. */ + /* */ + typedef struct TT_MaxProfile_ + { + FT_Fixed version; + FT_UShort numGlyphs; + FT_UShort maxPoints; + FT_UShort maxContours; + FT_UShort maxCompositePoints; + FT_UShort maxCompositeContours; + FT_UShort maxZones; + FT_UShort maxTwilightPoints; + FT_UShort maxStorage; + FT_UShort maxFunctionDefs; + FT_UShort maxInstructionDefs; + FT_UShort maxStackElements; + FT_UShort maxSizeOfInstructions; + FT_UShort maxComponentElements; + FT_UShort maxComponentDepth; + + } TT_MaxProfile; + + + /*************************************************************************/ + /* */ + /* <Enum> */ + /* FT_Sfnt_Tag */ + /* */ + /* <Description> */ + /* An enumeration used to specify the index of an SFNT table. */ + /* Used in the @FT_Get_Sfnt_Table API function. */ + /* */ + typedef enum + { + ft_sfnt_head = 0, + ft_sfnt_maxp = 1, + ft_sfnt_os2 = 2, + ft_sfnt_hhea = 3, + ft_sfnt_vhea = 4, + ft_sfnt_post = 5, + ft_sfnt_pclt = 6, + + sfnt_max /* internal end mark */ + + } FT_Sfnt_Tag; + + /* */ + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Get_Sfnt_Table */ + /* */ + /* <Description> */ + /* Returns a pointer to a given SFNT table within a face. */ + /* */ + /* <Input> */ + /* face :: A handle to the source. */ + /* */ + /* tag :: The index of the SFNT table. */ + /* */ + /* <Return> */ + /* A type-less pointer to the table. This will be 0 in case of */ + /* error, or if the corresponding table was not found *OR* loaded */ + /* from the file. */ + /* */ + /* <Note> */ + /* The table is owned by the face object and disappears with it. */ + /* */ + /* This function is only useful to access SFNT tables that are loaded */ + /* by the sfnt, truetype, and opentype drivers. See @FT_Sfnt_Tag for */ + /* a list. */ + /* */ + FT_EXPORT( void* ) + FT_Get_Sfnt_Table( FT_Face face, + FT_Sfnt_Tag tag ); + + + /************************************************************************** + * + * @function: + * FT_Load_Sfnt_Table + * + * @description: + * Loads any font table into client memory. + * + * @input: + * face :: + * A handle to the source face. + * + * tag :: + * The four-byte tag of the table to load. Use the value 0 if you want + * to access the whole font file. Otherwise, you can use one of the + * definitions found in the @FT_TRUETYPE_TAGS_H file, or forge a new + * one with @FT_MAKE_TAG. + * + * offset :: + * The starting offset in the table (or file if tag == 0). + * + * @output: + * buffer :: + * The target buffer address. The client must ensure that the memory + * array is big enough to hold the data. + * + * @inout: + * length :: + * If the `length' parameter is NULL, then try to load the whole table. + * Return an error code if it fails. + * + * Else, if `*length' is 0, exit immediately while returning the + * table's (or file) full size in it. + * + * Else the number of bytes to read from the table or file, from the + * starting offset. + * + * @return: + * FreeType error code. 0 means success. + * + * @note: + * If you need to determine the table's length you should first call this + * function with `*length' set to 0, as in the following example: + * + * { + * FT_ULong length = 0; + * + * + * error = FT_Load_Sfnt_Table( face, tag, 0, NULL, &length ); + * if ( error ) { ... table does not exist ... } + * + * buffer = malloc( length ); + * if ( buffer == NULL ) { ... not enough memory ... } + * + * error = FT_Load_Sfnt_Table( face, tag, 0, buffer, &length ); + * if ( error ) { ... could not load table ... } + * } + */ + FT_EXPORT( FT_Error ) + FT_Load_Sfnt_Table( FT_Face face, + FT_ULong tag, + FT_Long offset, + FT_Byte* buffer, + FT_ULong* length ); + + + /************************************************************************** + * + * @function: + * FT_Sfnt_Table_Info + * + * @description: + * Returns information on an SFNT table. + * + * @input: + * face :: + * A handle to the source face. + * + * table_index :: + * The index of an SFNT table. The function returns + * FT_Err_Table_Missing for an invalid value. + * + * @output: + * tag :: + * The name tag of the SFNT table. + * + * length :: + * The length of the SFNT table. + * + * @return: + * FreeType error code. 0 means success. + * + * @note: + * SFNT tables with length zero are treated as missing by Windows. + * + */ + FT_EXPORT( FT_Error ) + FT_Sfnt_Table_Info( FT_Face face, + FT_UInt table_index, + FT_ULong *tag, + FT_ULong *length ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Get_CMap_Language_ID */ + /* */ + /* <Description> */ + /* Return TrueType/sfnt specific cmap language ID. Definitions of */ + /* language ID values are in `freetype/ttnameid.h'. */ + /* */ + /* <Input> */ + /* charmap :: */ + /* The target charmap. */ + /* */ + /* <Return> */ + /* The language ID of `charmap'. If `charmap' doesn't belong to a */ + /* TrueType/sfnt face, just return 0 as the default value. */ + /* */ + FT_EXPORT( FT_ULong ) + FT_Get_CMap_Language_ID( FT_CharMap charmap ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Get_CMap_Format */ + /* */ + /* <Description> */ + /* Return TrueType/sfnt specific cmap format. */ + /* */ + /* <Input> */ + /* charmap :: */ + /* The target charmap. */ + /* */ + /* <Return> */ + /* The format of `charmap'. If `charmap' doesn't belong to a */ + /* TrueType/sfnt face, return -1. */ + /* */ + FT_EXPORT( FT_Long ) + FT_Get_CMap_Format( FT_CharMap charmap ); + + /* */ + + +FT_END_HEADER + +#endif /* __TTTABLES_H__ */ + + +/* END */ diff --git a/include/freetype/tttags.h b/include/freetype/tttags.h new file mode 100644 index 0000000..e10244c --- /dev/null +++ b/include/freetype/tttags.h @@ -0,0 +1,99 @@ +/***************************************************************************/ +/* */ +/* tttags.h */ +/* */ +/* Tags for TrueType and OpenType tables (specification only). */ +/* */ +/* Copyright 1996-2001, 2004, 2005 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef __TTAGS_H__ +#define __TTAGS_H__ + + +#include <ft2build.h> +#include FT_FREETYPE_H + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + +#define TTAG_avar FT_MAKE_TAG( 'a', 'v', 'a', 'r' ) +#define TTAG_BASE FT_MAKE_TAG( 'B', 'A', 'S', 'E' ) +#define TTAG_bdat FT_MAKE_TAG( 'b', 'd', 'a', 't' ) +#define TTAG_BDF FT_MAKE_TAG( 'B', 'D', 'F', ' ' ) +#define TTAG_bhed FT_MAKE_TAG( 'b', 'h', 'e', 'd' ) +#define TTAG_bloc FT_MAKE_TAG( 'b', 'l', 'o', 'c' ) +#define TTAG_bsln FT_MAKE_TAG( 'b', 's', 'l', 'n' ) +#define TTAG_CFF FT_MAKE_TAG( 'C', 'F', 'F', ' ' ) +#define TTAG_cmap FT_MAKE_TAG( 'c', 'm', 'a', 'p' ) +#define TTAG_cvar FT_MAKE_TAG( 'c', 'v', 'a', 'r' ) +#define TTAG_cvt FT_MAKE_TAG( 'c', 'v', 't', ' ' ) +#define TTAG_DSIG FT_MAKE_TAG( 'D', 'S', 'I', 'G' ) +#define TTAG_EBDT FT_MAKE_TAG( 'E', 'B', 'D', 'T' ) +#define TTAG_EBLC FT_MAKE_TAG( 'E', 'B', 'L', 'C' ) +#define TTAG_EBSC FT_MAKE_TAG( 'E', 'B', 'S', 'C' ) +#define TTAG_feat FT_MAKE_TAG( 'f', 'e', 'a', 't' ) +#define TTAG_fpgm FT_MAKE_TAG( 'f', 'p', 'g', 'm' ) +#define TTAG_fvar FT_MAKE_TAG( 'f', 'v', 'a', 'r' ) +#define TTAG_gasp FT_MAKE_TAG( 'g', 'a', 's', 'p' ) +#define TTAG_GDEF FT_MAKE_TAG( 'G', 'D', 'E', 'F' ) +#define TTAG_glyf FT_MAKE_TAG( 'g', 'l', 'y', 'f' ) +#define TTAG_GPOS FT_MAKE_TAG( 'G', 'P', 'O', 'S' ) +#define TTAG_GSUB FT_MAKE_TAG( 'G', 'S', 'U', 'B' ) +#define TTAG_gvar FT_MAKE_TAG( 'g', 'v', 'a', 'r' ) +#define TTAG_hdmx FT_MAKE_TAG( 'h', 'd', 'm', 'x' ) +#define TTAG_head FT_MAKE_TAG( 'h', 'e', 'a', 'd' ) +#define TTAG_hhea FT_MAKE_TAG( 'h', 'h', 'e', 'a' ) +#define TTAG_hmtx FT_MAKE_TAG( 'h', 'm', 't', 'x' ) +#define TTAG_JSTF FT_MAKE_TAG( 'J', 'S', 'T', 'F' ) +#define TTAG_just FT_MAKE_TAG( 'j', 'u', 's', 't' ) +#define TTAG_kern FT_MAKE_TAG( 'k', 'e', 'r', 'n' ) +#define TTAG_lcar FT_MAKE_TAG( 'l', 'c', 'a', 'r' ) +#define TTAG_loca FT_MAKE_TAG( 'l', 'o', 'c', 'a' ) +#define TTAG_LTSH FT_MAKE_TAG( 'L', 'T', 'S', 'H' ) +#define TTAG_maxp FT_MAKE_TAG( 'm', 'a', 'x', 'p' ) +#define TTAG_META FT_MAKE_TAG( 'M', 'E', 'T', 'A' ) +#define TTAG_MMFX FT_MAKE_TAG( 'M', 'M', 'F', 'X' ) +#define TTAG_MMSD FT_MAKE_TAG( 'M', 'M', 'S', 'D' ) +#define TTAG_mort FT_MAKE_TAG( 'm', 'o', 'r', 't' ) +#define TTAG_morx FT_MAKE_TAG( 'm', 'o', 'r', 'x' ) +#define TTAG_name FT_MAKE_TAG( 'n', 'a', 'm', 'e' ) +#define TTAG_opbd FT_MAKE_TAG( 'o', 'p', 'b', 'd' ) +#define TTAG_OS2 FT_MAKE_TAG( 'O', 'S', '/', '2' ) +#define TTAG_OTTO FT_MAKE_TAG( 'O', 'T', 'T', 'O' ) +#define TTAG_PCLT FT_MAKE_TAG( 'P', 'C', 'L', 'T' ) +#define TTAG_post FT_MAKE_TAG( 'p', 'o', 's', 't' ) +#define TTAG_prep FT_MAKE_TAG( 'p', 'r', 'e', 'p' ) +#define TTAG_prop FT_MAKE_TAG( 'p', 'r', 'o', 'p' ) +#define TTAG_SING FT_MAKE_TAG( 'S', 'I', 'N', 'G' ) +#define TTAG_trak FT_MAKE_TAG( 't', 'r', 'a', 'k' ) +#define TTAG_true FT_MAKE_TAG( 't', 'r', 'u', 'e' ) +#define TTAG_ttc FT_MAKE_TAG( 't', 't', 'c', ' ' ) +#define TTAG_ttcf FT_MAKE_TAG( 't', 't', 'c', 'f' ) +#define TTAG_VDMX FT_MAKE_TAG( 'V', 'D', 'M', 'X' ) +#define TTAG_vhea FT_MAKE_TAG( 'v', 'h', 'e', 'a' ) +#define TTAG_vmtx FT_MAKE_TAG( 'v', 'm', 't', 'x' ) + + +FT_END_HEADER + +#endif /* __TTAGS_H__ */ + + +/* END */ diff --git a/include/freetype/ttunpat.h b/include/freetype/ttunpat.h new file mode 100644 index 0000000..a016275 --- /dev/null +++ b/include/freetype/ttunpat.h @@ -0,0 +1,59 @@ +/***************************************************************************/ +/* */ +/* ttunpat.h */ +/* */ +/* Definitions for the unpatented TrueType hinting system */ +/* */ +/* Copyright 2003, 2006 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* Written by Graham Asher <graham.asher@btinternet.com> */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef __TTUNPAT_H__ +#define __TTUNPAT_H__ + + +#include <ft2build.h> +#include FT_FREETYPE_H + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /*************************************************************************** + * + * @constant: + * FT_PARAM_TAG_UNPATENTED_HINTING + * + * @description: + * A constant used as the tag of an @FT_Parameter structure to indicate + * that unpatented methods only should be used by the TrueType bytecode + * interpreter for a typeface opened by @FT_Open_Face. + * + */ +#define FT_PARAM_TAG_UNPATENTED_HINTING FT_MAKE_TAG( 'u', 'n', 'p', 'a' ) + + /* */ + +FT_END_HEADER + + +#endif /* __TTUNPAT_H__ */ + + +/* END */ diff --git a/include/ft2build.h b/include/ft2build.h new file mode 100644 index 0000000..6a3b8d9 --- /dev/null +++ b/include/ft2build.h @@ -0,0 +1,61 @@ +/***************************************************************************/ +/* */ +/* ft2build.h */ +/* */ +/* Build macros of the FreeType 2 library. */ +/* */ +/* Copyright 1996-2001, 2003, 2006 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + + /*************************************************************************/ + /* */ + /* This is a Unix-specific version of <ft2build.h> that should be used */ + /* exclusively *after* installation of the library. */ + /* */ + /* It assumes that `/usr/local/include/freetype2' (or whatever is */ + /* returned by the `freetype-config --cflags' or `pkg-config --cflags' */ + /* command) is in your compilation include path. */ + /* */ + /* We don't need to do anything special in this release. However, for */ + /* a future FreeType 2 release, the following installation changes will */ + /* be performed: */ + /* */ + /* - The contents of `freetype-2.x/include/freetype' will be installed */ + /* to `/usr/local/include/freetype2' instead of */ + /* `/usr/local/include/freetype2/freetype'. */ + /* */ + /* - This file will #include <freetype2/config/ftheader.h>, instead */ + /* of <freetype/config/ftheader.h>. */ + /* */ + /* - The contents of `ftheader.h' will be processed with `sed' to */ + /* replace all `<freetype/xxx>' with `<freetype2/xxx>'. */ + /* */ + /* - Adding `/usr/local/include/freetype2' to your compilation include */ + /* path will not be necessary anymore. */ + /* */ + /* These changes will be transparent to client applications which use */ + /* freetype-config (or pkg-config). No modifications will be necessary */ + /* to compile with the new scheme. */ + /* */ + /*************************************************************************/ + + +#ifndef __FT2_BUILD_UNIX_H__ +#define __FT2_BUILD_UNIX_H__ + + /* `<prefix>/include/freetype2' must be in your current inclusion path */ +#include <freetype/config/ftheader.h> + +#endif /* __FT2_BUILD_UNIX_H__ */ + + +/* END */ diff --git a/include/lodepng.h b/include/lodepng.h new file mode 100644 index 0000000..ee08cea --- /dev/null +++ b/include/lodepng.h @@ -0,0 +1,1759 @@ +/* +LodePNG version 20160418 + +Copyright (c) 2005-2016 Lode Vandevenne + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. +*/ + +#ifndef LODEPNG_H +#define LODEPNG_H + +#include <string.h> /*for size_t*/ + +extern const char* LODEPNG_VERSION_STRING; + +/* +The following #defines are used to create code sections. They can be disabled +to disable code sections, which can give faster compile time and smaller binary. +The "NO_COMPILE" defines are designed to be used to pass as defines to the +compiler command to disable them without modifying this header, e.g. +-DLODEPNG_NO_COMPILE_ZLIB for gcc. +In addition to those below, you can also define LODEPNG_NO_COMPILE_CRC to +allow implementing a custom lodepng_crc32. +*/ +/*deflate & zlib. If disabled, you must specify alternative zlib functions in +the custom_zlib field of the compress and decompress settings*/ +#ifndef LODEPNG_NO_COMPILE_ZLIB +#define LODEPNG_COMPILE_ZLIB +#endif +/*png encoder and png decoder*/ +#ifndef LODEPNG_NO_COMPILE_PNG +#define LODEPNG_COMPILE_PNG +#endif +/*deflate&zlib decoder and png decoder*/ +#ifndef LODEPNG_NO_COMPILE_DECODER +#define LODEPNG_COMPILE_DECODER +#endif +/*deflate&zlib encoder and png encoder*/ +#ifndef LODEPNG_NO_COMPILE_ENCODER +#define LODEPNG_COMPILE_ENCODER +#endif +/*the optional built in harddisk file loading and saving functions*/ +#ifndef LODEPNG_NO_COMPILE_DISK +#define LODEPNG_COMPILE_DISK +#endif +/*support for chunks other than IHDR, IDAT, PLTE, tRNS, IEND: ancillary and unknown chunks*/ +#ifndef LODEPNG_NO_COMPILE_ANCILLARY_CHUNKS +#define LODEPNG_COMPILE_ANCILLARY_CHUNKS +#endif +/*ability to convert error numerical codes to English text string*/ +#ifndef LODEPNG_NO_COMPILE_ERROR_TEXT +#define LODEPNG_COMPILE_ERROR_TEXT +#endif +/*Compile the default allocators (C's free, malloc and realloc). If you disable this, +you can define the functions lodepng_free, lodepng_malloc and lodepng_realloc in your +source files with custom allocators.*/ +#ifndef LODEPNG_NO_COMPILE_ALLOCATORS +#define LODEPNG_COMPILE_ALLOCATORS +#endif +/*compile the C++ version (you can disable the C++ wrapper here even when compiling for C++)*/ +#ifdef __cplusplus +#ifndef LODEPNG_NO_COMPILE_CPP +#define LODEPNG_COMPILE_CPP +#endif +#endif + +#ifdef LODEPNG_COMPILE_CPP +#include <vector> +#include <string> +#endif /*LODEPNG_COMPILE_CPP*/ + +#ifdef LODEPNG_COMPILE_PNG +/*The PNG color types (also used for raw).*/ +typedef enum LodePNGColorType +{ + LCT_GREY = 0, /*greyscale: 1,2,4,8,16 bit*/ + LCT_RGB = 2, /*RGB: 8,16 bit*/ + LCT_PALETTE = 3, /*palette: 1,2,4,8 bit*/ + LCT_GREY_ALPHA = 4, /*greyscale with alpha: 8,16 bit*/ + LCT_RGBA = 6 /*RGB with alpha: 8,16 bit*/ +} LodePNGColorType; + +#ifdef LODEPNG_COMPILE_DECODER +/* +Converts PNG data in memory to raw pixel data. +out: Output parameter. Pointer to buffer that will contain the raw pixel data. + After decoding, its size is w * h * (bytes per pixel) bytes larger than + initially. Bytes per pixel depends on colortype and bitdepth. + Must be freed after usage with free(*out). + Note: for 16-bit per channel colors, uses big endian format like PNG does. +w: Output parameter. Pointer to width of pixel data. +h: Output parameter. Pointer to height of pixel data. +in: Memory buffer with the PNG file. +insize: size of the in buffer. +colortype: the desired color type for the raw output image. See explanation on PNG color types. +bitdepth: the desired bit depth for the raw output image. See explanation on PNG color types. +Return value: LodePNG error code (0 means no error). +*/ +unsigned lodepng_decode_memory(unsigned char** out, unsigned* w, unsigned* h, + const unsigned char* in, size_t insize, + LodePNGColorType colortype, unsigned bitdepth); + +/*Same as lodepng_decode_memory, but always decodes to 32-bit RGBA raw image*/ +unsigned lodepng_decode32(unsigned char** out, unsigned* w, unsigned* h, + const unsigned char* in, size_t insize); + +/*Same as lodepng_decode_memory, but always decodes to 24-bit RGB raw image*/ +unsigned lodepng_decode24(unsigned char** out, unsigned* w, unsigned* h, + const unsigned char* in, size_t insize); + +#ifdef LODEPNG_COMPILE_DISK +/* +Load PNG from disk, from file with given name. +Same as the other decode functions, but instead takes a filename as input. +*/ +unsigned lodepng_decode_file(unsigned char** out, unsigned* w, unsigned* h, + const char* filename, + LodePNGColorType colortype, unsigned bitdepth); + +/*Same as lodepng_decode_file, but always decodes to 32-bit RGBA raw image.*/ +unsigned lodepng_decode32_file(unsigned char** out, unsigned* w, unsigned* h, + const char* filename); + +/*Same as lodepng_decode_file, but always decodes to 24-bit RGB raw image.*/ +unsigned lodepng_decode24_file(unsigned char** out, unsigned* w, unsigned* h, + const char* filename); +#endif /*LODEPNG_COMPILE_DISK*/ +#endif /*LODEPNG_COMPILE_DECODER*/ + + +#ifdef LODEPNG_COMPILE_ENCODER +/* +Converts raw pixel data into a PNG image in memory. The colortype and bitdepth + of the output PNG image cannot be chosen, they are automatically determined + by the colortype, bitdepth and content of the input pixel data. + Note: for 16-bit per channel colors, needs big endian format like PNG does. +out: Output parameter. Pointer to buffer that will contain the PNG image data. + Must be freed after usage with free(*out). +outsize: Output parameter. Pointer to the size in bytes of the out buffer. +image: The raw pixel data to encode. The size of this buffer should be + w * h * (bytes per pixel), bytes per pixel depends on colortype and bitdepth. +w: width of the raw pixel data in pixels. +h: height of the raw pixel data in pixels. +colortype: the color type of the raw input image. See explanation on PNG color types. +bitdepth: the bit depth of the raw input image. See explanation on PNG color types. +Return value: LodePNG error code (0 means no error). +*/ +unsigned lodepng_encode_memory(unsigned char** out, size_t* outsize, + const unsigned char* image, unsigned w, unsigned h, + LodePNGColorType colortype, unsigned bitdepth); + +/*Same as lodepng_encode_memory, but always encodes from 32-bit RGBA raw image.*/ +unsigned lodepng_encode32(unsigned char** out, size_t* outsize, + const unsigned char* image, unsigned w, unsigned h); + +/*Same as lodepng_encode_memory, but always encodes from 24-bit RGB raw image.*/ +unsigned lodepng_encode24(unsigned char** out, size_t* outsize, + const unsigned char* image, unsigned w, unsigned h); + +#ifdef LODEPNG_COMPILE_DISK +/* +Converts raw pixel data into a PNG file on disk. +Same as the other encode functions, but instead takes a filename as output. +NOTE: This overwrites existing files without warning! +*/ +unsigned lodepng_encode_file(const char* filename, + const unsigned char* image, unsigned w, unsigned h, + LodePNGColorType colortype, unsigned bitdepth); + +/*Same as lodepng_encode_file, but always encodes from 32-bit RGBA raw image.*/ +unsigned lodepng_encode32_file(const char* filename, + const unsigned char* image, unsigned w, unsigned h); + +/*Same as lodepng_encode_file, but always encodes from 24-bit RGB raw image.*/ +unsigned lodepng_encode24_file(const char* filename, + const unsigned char* image, unsigned w, unsigned h); +#endif /*LODEPNG_COMPILE_DISK*/ +#endif /*LODEPNG_COMPILE_ENCODER*/ + + +#ifdef LODEPNG_COMPILE_CPP +namespace lodepng +{ +#ifdef LODEPNG_COMPILE_DECODER +/*Same as lodepng_decode_memory, but decodes to an std::vector. The colortype +is the format to output the pixels to. Default is RGBA 8-bit per channel.*/ +unsigned decode(std::vector<unsigned char>& out, unsigned& w, unsigned& h, + const unsigned char* in, size_t insize, + LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); +unsigned decode(std::vector<unsigned char>& out, unsigned& w, unsigned& h, + const std::vector<unsigned char>& in, + LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); +#ifdef LODEPNG_COMPILE_DISK +/* +Converts PNG file from disk to raw pixel data in memory. +Same as the other decode functions, but instead takes a filename as input. +*/ +unsigned decode(std::vector<unsigned char>& out, unsigned& w, unsigned& h, + const std::string& filename, + LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); +#endif /* LODEPNG_COMPILE_DISK */ +#endif /* LODEPNG_COMPILE_DECODER */ + +#ifdef LODEPNG_COMPILE_ENCODER +/*Same as lodepng_encode_memory, but encodes to an std::vector. colortype +is that of the raw input data. The output PNG color type will be auto chosen.*/ +unsigned encode(std::vector<unsigned char>& out, + const unsigned char* in, unsigned w, unsigned h, + LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); +unsigned encode(std::vector<unsigned char>& out, + const std::vector<unsigned char>& in, unsigned w, unsigned h, + LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); +#ifdef LODEPNG_COMPILE_DISK +/* +Converts 32-bit RGBA raw pixel data into a PNG file on disk. +Same as the other encode functions, but instead takes a filename as output. +NOTE: This overwrites existing files without warning! +*/ +unsigned encode(const std::string& filename, + const unsigned char* in, unsigned w, unsigned h, + LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); +unsigned encode(const std::string& filename, + const std::vector<unsigned char>& in, unsigned w, unsigned h, + LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); +#endif /* LODEPNG_COMPILE_DISK */ +#endif /* LODEPNG_COMPILE_ENCODER */ +} /* namespace lodepng */ +#endif /*LODEPNG_COMPILE_CPP*/ +#endif /*LODEPNG_COMPILE_PNG*/ + +#ifdef LODEPNG_COMPILE_ERROR_TEXT +/*Returns an English description of the numerical error code.*/ +const char* lodepng_error_text(unsigned code); +#endif /*LODEPNG_COMPILE_ERROR_TEXT*/ + +#ifdef LODEPNG_COMPILE_DECODER +/*Settings for zlib decompression*/ +typedef struct LodePNGDecompressSettings LodePNGDecompressSettings; +struct LodePNGDecompressSettings +{ + unsigned ignore_adler32; /*if 1, continue and don't give an error message if the Adler32 checksum is corrupted*/ + + /*use custom zlib decoder instead of built in one (default: null)*/ + unsigned (*custom_zlib)(unsigned char**, size_t*, + const unsigned char*, size_t, + const LodePNGDecompressSettings*); + /*use custom deflate decoder instead of built in one (default: null) + if custom_zlib is used, custom_deflate is ignored since only the built in + zlib function will call custom_deflate*/ + unsigned (*custom_inflate)(unsigned char**, size_t*, + const unsigned char*, size_t, + const LodePNGDecompressSettings*); + + const void* custom_context; /*optional custom settings for custom functions*/ +}; + +extern const LodePNGDecompressSettings lodepng_default_decompress_settings; +void lodepng_decompress_settings_init(LodePNGDecompressSettings* settings); +#endif /*LODEPNG_COMPILE_DECODER*/ + +#ifdef LODEPNG_COMPILE_ENCODER +/* +Settings for zlib compression. Tweaking these settings tweaks the balance +between speed and compression ratio. +*/ +typedef struct LodePNGCompressSettings LodePNGCompressSettings; +struct LodePNGCompressSettings /*deflate = compress*/ +{ + /*LZ77 related settings*/ + unsigned btype; /*the block type for LZ (0, 1, 2 or 3, see zlib standard). Should be 2 for proper compression.*/ + unsigned use_lz77; /*whether or not to use LZ77. Should be 1 for proper compression.*/ + unsigned windowsize; /*must be a power of two <= 32768. higher compresses more but is slower. Default value: 2048.*/ + unsigned minmatch; /*mininum lz77 length. 3 is normally best, 6 can be better for some PNGs. Default: 0*/ + unsigned nicematch; /*stop searching if >= this length found. Set to 258 for best compression. Default: 128*/ + unsigned lazymatching; /*use lazy matching: better compression but a bit slower. Default: true*/ + + /*use custom zlib encoder instead of built in one (default: null)*/ + unsigned (*custom_zlib)(unsigned char**, size_t*, + const unsigned char*, size_t, + const LodePNGCompressSettings*); + /*use custom deflate encoder instead of built in one (default: null) + if custom_zlib is used, custom_deflate is ignored since only the built in + zlib function will call custom_deflate*/ + unsigned (*custom_deflate)(unsigned char**, size_t*, + const unsigned char*, size_t, + const LodePNGCompressSettings*); + + const void* custom_context; /*optional custom settings for custom functions*/ +}; + +extern const LodePNGCompressSettings lodepng_default_compress_settings; +void lodepng_compress_settings_init(LodePNGCompressSettings* settings); +#endif /*LODEPNG_COMPILE_ENCODER*/ + +#ifdef LODEPNG_COMPILE_PNG +/* +Color mode of an image. Contains all information required to decode the pixel +bits to RGBA colors. This information is the same as used in the PNG file +format, and is used both for PNG and raw image data in LodePNG. +*/ +typedef struct LodePNGColorMode +{ + /*header (IHDR)*/ + LodePNGColorType colortype; /*color type, see PNG standard or documentation further in this header file*/ + unsigned bitdepth; /*bits per sample, see PNG standard or documentation further in this header file*/ + + /* + palette (PLTE and tRNS) + + Dynamically allocated with the colors of the palette, including alpha. + When encoding a PNG, to store your colors in the palette of the LodePNGColorMode, first use + lodepng_palette_clear, then for each color use lodepng_palette_add. + If you encode an image without alpha with palette, don't forget to put value 255 in each A byte of the palette. + + When decoding, by default you can ignore this palette, since LodePNG already + fills the palette colors in the pixels of the raw RGBA output. + + The palette is only supported for color type 3. + */ + unsigned char* palette; /*palette in RGBARGBA... order. When allocated, must be either 0, or have size 1024*/ + size_t palettesize; /*palette size in number of colors (amount of bytes is 4 * palettesize)*/ + + /* + transparent color key (tRNS) + + This color uses the same bit depth as the bitdepth value in this struct, which can be 1-bit to 16-bit. + For greyscale PNGs, r, g and b will all 3 be set to the same. + + When decoding, by default you can ignore this information, since LodePNG sets + pixels with this key to transparent already in the raw RGBA output. + + The color key is only supported for color types 0 and 2. + */ + unsigned key_defined; /*is a transparent color key given? 0 = false, 1 = true*/ + unsigned key_r; /*red/greyscale component of color key*/ + unsigned key_g; /*green component of color key*/ + unsigned key_b; /*blue component of color key*/ +} LodePNGColorMode; + +/*init, cleanup and copy functions to use with this struct*/ +void lodepng_color_mode_init(LodePNGColorMode* info); +void lodepng_color_mode_cleanup(LodePNGColorMode* info); +/*return value is error code (0 means no error)*/ +unsigned lodepng_color_mode_copy(LodePNGColorMode* dest, const LodePNGColorMode* source); + +void lodepng_palette_clear(LodePNGColorMode* info); +/*add 1 color to the palette*/ +unsigned lodepng_palette_add(LodePNGColorMode* info, + unsigned char r, unsigned char g, unsigned char b, unsigned char a); + +/*get the total amount of bits per pixel, based on colortype and bitdepth in the struct*/ +unsigned lodepng_get_bpp(const LodePNGColorMode* info); +/*get the amount of color channels used, based on colortype in the struct. +If a palette is used, it counts as 1 channel.*/ +unsigned lodepng_get_channels(const LodePNGColorMode* info); +/*is it a greyscale type? (only colortype 0 or 4)*/ +unsigned lodepng_is_greyscale_type(const LodePNGColorMode* info); +/*has it got an alpha channel? (only colortype 2 or 6)*/ +unsigned lodepng_is_alpha_type(const LodePNGColorMode* info); +/*has it got a palette? (only colortype 3)*/ +unsigned lodepng_is_palette_type(const LodePNGColorMode* info); +/*only returns true if there is a palette and there is a value in the palette with alpha < 255. +Loops through the palette to check this.*/ +unsigned lodepng_has_palette_alpha(const LodePNGColorMode* info); +/* +Check if the given color info indicates the possibility of having non-opaque pixels in the PNG image. +Returns true if the image can have translucent or invisible pixels (it still be opaque if it doesn't use such pixels). +Returns false if the image can only have opaque pixels. +In detail, it returns true only if it's a color type with alpha, or has a palette with non-opaque values, +or if "key_defined" is true. +*/ +unsigned lodepng_can_have_alpha(const LodePNGColorMode* info); +/*Returns the byte size of a raw image buffer with given width, height and color mode*/ +size_t lodepng_get_raw_size(unsigned w, unsigned h, const LodePNGColorMode* color); + +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS +/*The information of a Time chunk in PNG.*/ +typedef struct LodePNGTime +{ + unsigned year; /*2 bytes used (0-65535)*/ + unsigned month; /*1-12*/ + unsigned day; /*1-31*/ + unsigned hour; /*0-23*/ + unsigned minute; /*0-59*/ + unsigned second; /*0-60 (to allow for leap seconds)*/ +} LodePNGTime; +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + +/*Information about the PNG image, except pixels, width and height.*/ +typedef struct LodePNGInfo +{ + /*header (IHDR), palette (PLTE) and transparency (tRNS) chunks*/ + unsigned compression_method;/*compression method of the original file. Always 0.*/ + unsigned filter_method; /*filter method of the original file*/ + unsigned interlace_method; /*interlace method of the original file*/ + LodePNGColorMode color; /*color type and bits, palette and transparency of the PNG file*/ + +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + /* + suggested background color chunk (bKGD) + This color uses the same color mode as the PNG (except alpha channel), which can be 1-bit to 16-bit. + + For greyscale PNGs, r, g and b will all 3 be set to the same. When encoding + the encoder writes the red one. For palette PNGs: When decoding, the RGB value + will be stored, not a palette index. But when encoding, specify the index of + the palette in background_r, the other two are then ignored. + + The decoder does not use this background color to edit the color of pixels. + */ + unsigned background_defined; /*is a suggested background color given?*/ + unsigned background_r; /*red component of suggested background color*/ + unsigned background_g; /*green component of suggested background color*/ + unsigned background_b; /*blue component of suggested background color*/ + + /* + non-international text chunks (tEXt and zTXt) + + The char** arrays each contain num strings. The actual messages are in + text_strings, while text_keys are keywords that give a short description what + the actual text represents, e.g. Title, Author, Description, or anything else. + + A keyword is minimum 1 character and maximum 79 characters long. It's + discouraged to use a single line length longer than 79 characters for texts. + + Don't allocate these text buffers yourself. Use the init/cleanup functions + correctly and use lodepng_add_text and lodepng_clear_text. + */ + size_t text_num; /*the amount of texts in these char** buffers (there may be more texts in itext)*/ + char** text_keys; /*the keyword of a text chunk (e.g. "Comment")*/ + char** text_strings; /*the actual text*/ + + /* + international text chunks (iTXt) + Similar to the non-international text chunks, but with additional strings + "langtags" and "transkeys". + */ + size_t itext_num; /*the amount of international texts in this PNG*/ + char** itext_keys; /*the English keyword of the text chunk (e.g. "Comment")*/ + char** itext_langtags; /*language tag for this text's language, ISO/IEC 646 string, e.g. ISO 639 language tag*/ + char** itext_transkeys; /*keyword translated to the international language - UTF-8 string*/ + char** itext_strings; /*the actual international text - UTF-8 string*/ + + /*time chunk (tIME)*/ + unsigned time_defined; /*set to 1 to make the encoder generate a tIME chunk*/ + LodePNGTime time; + + /*phys chunk (pHYs)*/ + unsigned phys_defined; /*if 0, there is no pHYs chunk and the values below are undefined, if 1 else there is one*/ + unsigned phys_x; /*pixels per unit in x direction*/ + unsigned phys_y; /*pixels per unit in y direction*/ + unsigned phys_unit; /*may be 0 (unknown unit) or 1 (metre)*/ + + /* + unknown chunks + There are 3 buffers, one for each position in the PNG where unknown chunks can appear + each buffer contains all unknown chunks for that position consecutively + The 3 buffers are the unknown chunks between certain critical chunks: + 0: IHDR-PLTE, 1: PLTE-IDAT, 2: IDAT-IEND + Do not allocate or traverse this data yourself. Use the chunk traversing functions declared + later, such as lodepng_chunk_next and lodepng_chunk_append, to read/write this struct. + */ + unsigned char* unknown_chunks_data[3]; + size_t unknown_chunks_size[3]; /*size in bytes of the unknown chunks, given for protection*/ +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ +} LodePNGInfo; + +/*init, cleanup and copy functions to use with this struct*/ +void lodepng_info_init(LodePNGInfo* info); +void lodepng_info_cleanup(LodePNGInfo* info); +/*return value is error code (0 means no error)*/ +unsigned lodepng_info_copy(LodePNGInfo* dest, const LodePNGInfo* source); + +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS +void lodepng_clear_text(LodePNGInfo* info); /*use this to clear the texts again after you filled them in*/ +unsigned lodepng_add_text(LodePNGInfo* info, const char* key, const char* str); /*push back both texts at once*/ + +void lodepng_clear_itext(LodePNGInfo* info); /*use this to clear the itexts again after you filled them in*/ +unsigned lodepng_add_itext(LodePNGInfo* info, const char* key, const char* langtag, + const char* transkey, const char* str); /*push back the 4 texts of 1 chunk at once*/ +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + +/* +Converts raw buffer from one color type to another color type, based on +LodePNGColorMode structs to describe the input and output color type. +See the reference manual at the end of this header file to see which color conversions are supported. +return value = LodePNG error code (0 if all went ok, an error if the conversion isn't supported) +The out buffer must have size (w * h * bpp + 7) / 8, where bpp is the bits per pixel +of the output color type (lodepng_get_bpp). +For < 8 bpp images, there should not be padding bits at the end of scanlines. +For 16-bit per channel colors, uses big endian format like PNG does. +Return value is LodePNG error code +*/ +unsigned lodepng_convert(unsigned char* out, const unsigned char* in, + const LodePNGColorMode* mode_out, const LodePNGColorMode* mode_in, + unsigned w, unsigned h); + +#ifdef LODEPNG_COMPILE_DECODER +/* +Settings for the decoder. This contains settings for the PNG and the Zlib +decoder, but not the Info settings from the Info structs. +*/ +typedef struct LodePNGDecoderSettings +{ + LodePNGDecompressSettings zlibsettings; /*in here is the setting to ignore Adler32 checksums*/ + + unsigned ignore_crc; /*ignore CRC checksums*/ + + unsigned color_convert; /*whether to convert the PNG to the color type you want. Default: yes*/ + +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + unsigned read_text_chunks; /*if false but remember_unknown_chunks is true, they're stored in the unknown chunks*/ + /*store all bytes from unknown chunks in the LodePNGInfo (off by default, useful for a png editor)*/ + unsigned remember_unknown_chunks; +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ +} LodePNGDecoderSettings; + +void lodepng_decoder_settings_init(LodePNGDecoderSettings* settings); +#endif /*LODEPNG_COMPILE_DECODER*/ + +#ifdef LODEPNG_COMPILE_ENCODER +/*automatically use color type with less bits per pixel if losslessly possible. Default: AUTO*/ +typedef enum LodePNGFilterStrategy +{ + /*every filter at zero*/ + LFS_ZERO, + /*Use filter that gives minimum sum, as described in the official PNG filter heuristic.*/ + LFS_MINSUM, + /*Use the filter type that gives smallest Shannon entropy for this scanline. Depending + on the image, this is better or worse than minsum.*/ + LFS_ENTROPY, + /* + Brute-force-search PNG filters by compressing each filter for each scanline. + Experimental, very slow, and only rarely gives better compression than MINSUM. + */ + LFS_BRUTE_FORCE, + /*use predefined_filters buffer: you specify the filter type for each scanline*/ + LFS_PREDEFINED +} LodePNGFilterStrategy; + +/*Gives characteristics about the colors of the image, which helps decide which color model to use for encoding. +Used internally by default if "auto_convert" is enabled. Public because it's useful for custom algorithms.*/ +typedef struct LodePNGColorProfile +{ + unsigned colored; /*not greyscale*/ + unsigned key; /*if true, image is not opaque. Only if true and alpha is false, color key is possible.*/ + unsigned short key_r; /*these values are always in 16-bit bitdepth in the profile*/ + unsigned short key_g; + unsigned short key_b; + unsigned alpha; /*alpha channel or alpha palette required*/ + unsigned numcolors; /*amount of colors, up to 257. Not valid if bits == 16.*/ + unsigned char palette[1024]; /*Remembers up to the first 256 RGBA colors, in no particular order*/ + unsigned bits; /*bits per channel (not for palette). 1,2 or 4 for greyscale only. 16 if 16-bit per channel required.*/ +} LodePNGColorProfile; + +void lodepng_color_profile_init(LodePNGColorProfile* profile); + +/*Get a LodePNGColorProfile of the image.*/ +unsigned lodepng_get_color_profile(LodePNGColorProfile* profile, + const unsigned char* image, unsigned w, unsigned h, + const LodePNGColorMode* mode_in); +/*The function LodePNG uses internally to decide the PNG color with auto_convert. +Chooses an optimal color model, e.g. grey if only grey pixels, palette if < 256 colors, ...*/ +unsigned lodepng_auto_choose_color(LodePNGColorMode* mode_out, + const unsigned char* image, unsigned w, unsigned h, + const LodePNGColorMode* mode_in); + +/*Settings for the encoder.*/ +typedef struct LodePNGEncoderSettings +{ + LodePNGCompressSettings zlibsettings; /*settings for the zlib encoder, such as window size, ...*/ + + unsigned auto_convert; /*automatically choose output PNG color type. Default: true*/ + + /*If true, follows the official PNG heuristic: if the PNG uses a palette or lower than + 8 bit depth, set all filters to zero. Otherwise use the filter_strategy. Note that to + completely follow the official PNG heuristic, filter_palette_zero must be true and + filter_strategy must be LFS_MINSUM*/ + unsigned filter_palette_zero; + /*Which filter strategy to use when not using zeroes due to filter_palette_zero. + Set filter_palette_zero to 0 to ensure always using your chosen strategy. Default: LFS_MINSUM*/ + LodePNGFilterStrategy filter_strategy; + /*used if filter_strategy is LFS_PREDEFINED. In that case, this must point to a buffer with + the same length as the amount of scanlines in the image, and each value must <= 5. You + have to cleanup this buffer, LodePNG will never free it. Don't forget that filter_palette_zero + must be set to 0 to ensure this is also used on palette or low bitdepth images.*/ + const unsigned char* predefined_filters; + + /*force creating a PLTE chunk if colortype is 2 or 6 (= a suggested palette). + If colortype is 3, PLTE is _always_ created.*/ + unsigned force_palette; +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + /*add LodePNG identifier and version as a text chunk, for debugging*/ + unsigned add_id; + /*encode text chunks as zTXt chunks instead of tEXt chunks, and use compression in iTXt chunks*/ + unsigned text_compression; +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ +} LodePNGEncoderSettings; + +void lodepng_encoder_settings_init(LodePNGEncoderSettings* settings); +#endif /*LODEPNG_COMPILE_ENCODER*/ + + +#if defined(LODEPNG_COMPILE_DECODER) || defined(LODEPNG_COMPILE_ENCODER) +/*The settings, state and information for extended encoding and decoding.*/ +typedef struct LodePNGState +{ +#ifdef LODEPNG_COMPILE_DECODER + LodePNGDecoderSettings decoder; /*the decoding settings*/ +#endif /*LODEPNG_COMPILE_DECODER*/ +#ifdef LODEPNG_COMPILE_ENCODER + LodePNGEncoderSettings encoder; /*the encoding settings*/ +#endif /*LODEPNG_COMPILE_ENCODER*/ + LodePNGColorMode info_raw; /*specifies the format in which you would like to get the raw pixel buffer*/ + LodePNGInfo info_png; /*info of the PNG image obtained after decoding*/ + unsigned error; +#ifdef LODEPNG_COMPILE_CPP + /* For the lodepng::State subclass. */ + virtual ~LodePNGState(){} +#endif +} LodePNGState; + +/*init, cleanup and copy functions to use with this struct*/ +void lodepng_state_init(LodePNGState* state); +void lodepng_state_cleanup(LodePNGState* state); +void lodepng_state_copy(LodePNGState* dest, const LodePNGState* source); +#endif /* defined(LODEPNG_COMPILE_DECODER) || defined(LODEPNG_COMPILE_ENCODER) */ + +#ifdef LODEPNG_COMPILE_DECODER +/* +Same as lodepng_decode_memory, but uses a LodePNGState to allow custom settings and +getting much more information about the PNG image and color mode. +*/ +unsigned lodepng_decode(unsigned char** out, unsigned* w, unsigned* h, + LodePNGState* state, + const unsigned char* in, size_t insize); + +/* +Read the PNG header, but not the actual data. This returns only the information +that is in the header chunk of the PNG, such as width, height and color type. The +information is placed in the info_png field of the LodePNGState. +*/ +unsigned lodepng_inspect(unsigned* w, unsigned* h, + LodePNGState* state, + const unsigned char* in, size_t insize); +#endif /*LODEPNG_COMPILE_DECODER*/ + + +#ifdef LODEPNG_COMPILE_ENCODER +/*This function allocates the out buffer with standard malloc and stores the size in *outsize.*/ +unsigned lodepng_encode(unsigned char** out, size_t* outsize, + const unsigned char* image, unsigned w, unsigned h, + LodePNGState* state); +#endif /*LODEPNG_COMPILE_ENCODER*/ + +/* +The lodepng_chunk functions are normally not needed, except to traverse the +unknown chunks stored in the LodePNGInfo struct, or add new ones to it. +It also allows traversing the chunks of an encoded PNG file yourself. + +PNG standard chunk naming conventions: +First byte: uppercase = critical, lowercase = ancillary +Second byte: uppercase = public, lowercase = private +Third byte: must be uppercase +Fourth byte: uppercase = unsafe to copy, lowercase = safe to copy +*/ + +/* +Gets the length of the data of the chunk. Total chunk length has 12 bytes more. +There must be at least 4 bytes to read from. If the result value is too large, +it may be corrupt data. +*/ +unsigned lodepng_chunk_length(const unsigned char* chunk); + +/*puts the 4-byte type in null terminated string*/ +void lodepng_chunk_type(char type[5], const unsigned char* chunk); + +/*check if the type is the given type*/ +unsigned char lodepng_chunk_type_equals(const unsigned char* chunk, const char* type); + +/*0: it's one of the critical chunk types, 1: it's an ancillary chunk (see PNG standard)*/ +unsigned char lodepng_chunk_ancillary(const unsigned char* chunk); + +/*0: public, 1: private (see PNG standard)*/ +unsigned char lodepng_chunk_private(const unsigned char* chunk); + +/*0: the chunk is unsafe to copy, 1: the chunk is safe to copy (see PNG standard)*/ +unsigned char lodepng_chunk_safetocopy(const unsigned char* chunk); + +/*get pointer to the data of the chunk, where the input points to the header of the chunk*/ +unsigned char* lodepng_chunk_data(unsigned char* chunk); +const unsigned char* lodepng_chunk_data_const(const unsigned char* chunk); + +/*returns 0 if the crc is correct, 1 if it's incorrect (0 for OK as usual!)*/ +unsigned lodepng_chunk_check_crc(const unsigned char* chunk); + +/*generates the correct CRC from the data and puts it in the last 4 bytes of the chunk*/ +void lodepng_chunk_generate_crc(unsigned char* chunk); + +/*iterate to next chunks. don't use on IEND chunk, as there is no next chunk then*/ +unsigned char* lodepng_chunk_next(unsigned char* chunk); +const unsigned char* lodepng_chunk_next_const(const unsigned char* chunk); + +/* +Appends chunk to the data in out. The given chunk should already have its chunk header. +The out variable and outlength are updated to reflect the new reallocated buffer. +Returns error code (0 if it went ok) +*/ +unsigned lodepng_chunk_append(unsigned char** out, size_t* outlength, const unsigned char* chunk); + +/* +Appends new chunk to out. The chunk to append is given by giving its length, type +and data separately. The type is a 4-letter string. +The out variable and outlength are updated to reflect the new reallocated buffer. +Returne error code (0 if it went ok) +*/ +unsigned lodepng_chunk_create(unsigned char** out, size_t* outlength, unsigned length, + const char* type, const unsigned char* data); + + +/*Calculate CRC32 of buffer*/ +unsigned lodepng_crc32(const unsigned char* buf, size_t len); +#endif /*LODEPNG_COMPILE_PNG*/ + + +#ifdef LODEPNG_COMPILE_ZLIB +/* +This zlib part can be used independently to zlib compress and decompress a +buffer. It cannot be used to create gzip files however, and it only supports the +part of zlib that is required for PNG, it does not support dictionaries. +*/ + +#ifdef LODEPNG_COMPILE_DECODER +/*Inflate a buffer. Inflate is the decompression step of deflate. Out buffer must be freed after use.*/ +unsigned lodepng_inflate(unsigned char** out, size_t* outsize, + const unsigned char* in, size_t insize, + const LodePNGDecompressSettings* settings); + +/* +Decompresses Zlib data. Reallocates the out buffer and appends the data. The +data must be according to the zlib specification. +Either, *out must be NULL and *outsize must be 0, or, *out must be a valid +buffer and *outsize its size in bytes. out must be freed by user after usage. +*/ +unsigned lodepng_zlib_decompress(unsigned char** out, size_t* outsize, + const unsigned char* in, size_t insize, + const LodePNGDecompressSettings* settings); +#endif /*LODEPNG_COMPILE_DECODER*/ + +#ifdef LODEPNG_COMPILE_ENCODER +/* +Compresses data with Zlib. Reallocates the out buffer and appends the data. +Zlib adds a small header and trailer around the deflate data. +The data is output in the format of the zlib specification. +Either, *out must be NULL and *outsize must be 0, or, *out must be a valid +buffer and *outsize its size in bytes. out must be freed by user after usage. +*/ +unsigned lodepng_zlib_compress(unsigned char** out, size_t* outsize, + const unsigned char* in, size_t insize, + const LodePNGCompressSettings* settings); + +/* +Find length-limited Huffman code for given frequencies. This function is in the +public interface only for tests, it's used internally by lodepng_deflate. +*/ +unsigned lodepng_huffman_code_lengths(unsigned* lengths, const unsigned* frequencies, + size_t numcodes, unsigned maxbitlen); + +/*Compress a buffer with deflate. See RFC 1951. Out buffer must be freed after use.*/ +unsigned lodepng_deflate(unsigned char** out, size_t* outsize, + const unsigned char* in, size_t insize, + const LodePNGCompressSettings* settings); + +#endif /*LODEPNG_COMPILE_ENCODER*/ +#endif /*LODEPNG_COMPILE_ZLIB*/ + +#ifdef LODEPNG_COMPILE_DISK +/* +Load a file from disk into buffer. The function allocates the out buffer, and +after usage you should free it. +out: output parameter, contains pointer to loaded buffer. +outsize: output parameter, size of the allocated out buffer +filename: the path to the file to load +return value: error code (0 means ok) +*/ +unsigned lodepng_load_file(unsigned char** out, size_t* outsize, const char* filename); + +/* +Save a file from buffer to disk. Warning, if it exists, this function overwrites +the file without warning! +buffer: the buffer to write +buffersize: size of the buffer to write +filename: the path to the file to save to +return value: error code (0 means ok) +*/ +unsigned lodepng_save_file(const unsigned char* buffer, size_t buffersize, const char* filename); +#endif /*LODEPNG_COMPILE_DISK*/ + +#ifdef LODEPNG_COMPILE_CPP +/* The LodePNG C++ wrapper uses std::vectors instead of manually allocated memory buffers. */ +namespace lodepng +{ +#ifdef LODEPNG_COMPILE_PNG +class State : public LodePNGState +{ + public: + State(); + State(const State& other); + virtual ~State(); + State& operator=(const State& other); +}; + +#ifdef LODEPNG_COMPILE_DECODER +/* Same as other lodepng::decode, but using a State for more settings and information. */ +unsigned decode(std::vector<unsigned char>& out, unsigned& w, unsigned& h, + State& state, + const unsigned char* in, size_t insize); +unsigned decode(std::vector<unsigned char>& out, unsigned& w, unsigned& h, + State& state, + const std::vector<unsigned char>& in); +#endif /*LODEPNG_COMPILE_DECODER*/ + +#ifdef LODEPNG_COMPILE_ENCODER +/* Same as other lodepng::encode, but using a State for more settings and information. */ +unsigned encode(std::vector<unsigned char>& out, + const unsigned char* in, unsigned w, unsigned h, + State& state); +unsigned encode(std::vector<unsigned char>& out, + const std::vector<unsigned char>& in, unsigned w, unsigned h, + State& state); +#endif /*LODEPNG_COMPILE_ENCODER*/ + +#ifdef LODEPNG_COMPILE_DISK +/* +Load a file from disk into an std::vector. +return value: error code (0 means ok) +*/ +unsigned load_file(std::vector<unsigned char>& buffer, const std::string& filename); + +/* +Save the binary data in an std::vector to a file on disk. The file is overwritten +without warning. +*/ +unsigned save_file(const std::vector<unsigned char>& buffer, const std::string& filename); +#endif /* LODEPNG_COMPILE_DISK */ +#endif /* LODEPNG_COMPILE_PNG */ + +#ifdef LODEPNG_COMPILE_ZLIB +#ifdef LODEPNG_COMPILE_DECODER +/* Zlib-decompress an unsigned char buffer */ +unsigned decompress(std::vector<unsigned char>& out, const unsigned char* in, size_t insize, + const LodePNGDecompressSettings& settings = lodepng_default_decompress_settings); + +/* Zlib-decompress an std::vector */ +unsigned decompress(std::vector<unsigned char>& out, const std::vector<unsigned char>& in, + const LodePNGDecompressSettings& settings = lodepng_default_decompress_settings); +#endif /* LODEPNG_COMPILE_DECODER */ + +#ifdef LODEPNG_COMPILE_ENCODER +/* Zlib-compress an unsigned char buffer */ +unsigned compress(std::vector<unsigned char>& out, const unsigned char* in, size_t insize, + const LodePNGCompressSettings& settings = lodepng_default_compress_settings); + +/* Zlib-compress an std::vector */ +unsigned compress(std::vector<unsigned char>& out, const std::vector<unsigned char>& in, + const LodePNGCompressSettings& settings = lodepng_default_compress_settings); +#endif /* LODEPNG_COMPILE_ENCODER */ +#endif /* LODEPNG_COMPILE_ZLIB */ +} /* namespace lodepng */ +#endif /*LODEPNG_COMPILE_CPP*/ + +/* +TODO: +[.] test if there are no memory leaks or security exploits - done a lot but needs to be checked often +[.] check compatibility with various compilers - done but needs to be redone for every newer version +[X] converting color to 16-bit per channel types +[ ] read all public PNG chunk types (but never let the color profile and gamma ones touch RGB values) +[ ] make sure encoder generates no chunks with size > (2^31)-1 +[ ] partial decoding (stream processing) +[X] let the "isFullyOpaque" function check color keys and transparent palettes too +[X] better name for the variables "codes", "codesD", "codelengthcodes", "clcl" and "lldl" +[ ] don't stop decoding on errors like 69, 57, 58 (make warnings) +[ ] let the C++ wrapper catch exceptions coming from the standard library and return LodePNG error codes +[ ] allow user to provide custom color conversion functions, e.g. for premultiplied alpha, padding bits or not, ... +[ ] allow user to give data (void*) to custom allocator +*/ + +#endif /*LODEPNG_H inclusion guard*/ + +/* +LodePNG Documentation +--------------------- + +0. table of contents +-------------------- + + 1. about + 1.1. supported features + 1.2. features not supported + 2. C and C++ version + 3. security + 4. decoding + 5. encoding + 6. color conversions + 6.1. PNG color types + 6.2. color conversions + 6.3. padding bits + 6.4. A note about 16-bits per channel and endianness + 7. error values + 8. chunks and PNG editing + 9. compiler support + 10. examples + 10.1. decoder C++ example + 10.2. decoder C example + 11. state settings reference + 12. changes + 13. contact information + + +1. about +-------- + +PNG is a file format to store raster images losslessly with good compression, +supporting different color types and alpha channel. + +LodePNG is a PNG codec according to the Portable Network Graphics (PNG) +Specification (Second Edition) - W3C Recommendation 10 November 2003. + +The specifications used are: + +*) Portable Network Graphics (PNG) Specification (Second Edition): + http://www.w3.org/TR/2003/REC-PNG-20031110 +*) RFC 1950 ZLIB Compressed Data Format version 3.3: + http://www.gzip.org/zlib/rfc-zlib.html +*) RFC 1951 DEFLATE Compressed Data Format Specification ver 1.3: + http://www.gzip.org/zlib/rfc-deflate.html + +The most recent version of LodePNG can currently be found at +http://lodev.org/lodepng/ + +LodePNG works both in C (ISO C90) and C++, with a C++ wrapper that adds +extra functionality. + +LodePNG exists out of two files: +-lodepng.h: the header file for both C and C++ +-lodepng.c(pp): give it the name lodepng.c or lodepng.cpp (or .cc) depending on your usage + +If you want to start using LodePNG right away without reading this doc, get the +examples from the LodePNG website to see how to use it in code, or check the +smaller examples in chapter 13 here. + +LodePNG is simple but only supports the basic requirements. To achieve +simplicity, the following design choices were made: There are no dependencies +on any external library. There are functions to decode and encode a PNG with +a single function call, and extended versions of these functions taking a +LodePNGState struct allowing to specify or get more information. By default +the colors of the raw image are always RGB or RGBA, no matter what color type +the PNG file uses. To read and write files, there are simple functions to +convert the files to/from buffers in memory. + +This all makes LodePNG suitable for loading textures in games, demos and small +programs, ... It's less suitable for full fledged image editors, loading PNGs +over network (it requires all the image data to be available before decoding can +begin), life-critical systems, ... + +1.1. supported features +----------------------- + +The following features are supported by the decoder: + +*) decoding of PNGs with any color type, bit depth and interlace mode, to a 24- or 32-bit color raw image, + or the same color type as the PNG +*) encoding of PNGs, from any raw image to 24- or 32-bit color, or the same color type as the raw image +*) Adam7 interlace and deinterlace for any color type +*) loading the image from harddisk or decoding it from a buffer from other sources than harddisk +*) support for alpha channels, including RGBA color model, translucent palettes and color keying +*) zlib decompression (inflate) +*) zlib compression (deflate) +*) CRC32 and ADLER32 checksums +*) handling of unknown chunks, allowing making a PNG editor that stores custom and unknown chunks. +*) the following chunks are supported (generated/interpreted) by both encoder and decoder: + IHDR: header information + PLTE: color palette + IDAT: pixel data + IEND: the final chunk + tRNS: transparency for palettized images + tEXt: textual information + zTXt: compressed textual information + iTXt: international textual information + bKGD: suggested background color + pHYs: physical dimensions + tIME: modification time + +1.2. features not supported +--------------------------- + +The following features are _not_ supported: + +*) some features needed to make a conformant PNG-Editor might be still missing. +*) partial loading/stream processing. All data must be available and is processed in one call. +*) The following public chunks are not supported but treated as unknown chunks by LodePNG + cHRM, gAMA, iCCP, sRGB, sBIT, hIST, sPLT + Some of these are not supported on purpose: LodePNG wants to provide the RGB values + stored in the pixels, not values modified by system dependent gamma or color models. + + +2. C and C++ version +-------------------- + +The C version uses buffers allocated with alloc that you need to free() +yourself. You need to use init and cleanup functions for each struct whenever +using a struct from the C version to avoid exploits and memory leaks. + +The C++ version has extra functions with std::vectors in the interface and the +lodepng::State class which is a LodePNGState with constructor and destructor. + +These files work without modification for both C and C++ compilers because all +the additional C++ code is in "#ifdef __cplusplus" blocks that make C-compilers +ignore it, and the C code is made to compile both with strict ISO C90 and C++. + +To use the C++ version, you need to rename the source file to lodepng.cpp +(instead of lodepng.c), and compile it with a C++ compiler. + +To use the C version, you need to rename the source file to lodepng.c (instead +of lodepng.cpp), and compile it with a C compiler. + + +3. Security +----------- + +Even if carefully designed, it's always possible that LodePNG contains possible +exploits. If you discover one, please let me know, and it will be fixed. + +When using LodePNG, care has to be taken with the C version of LodePNG, as well +as the C-style structs when working with C++. The following conventions are used +for all C-style structs: + +-if a struct has a corresponding init function, always call the init function when making a new one +-if a struct has a corresponding cleanup function, call it before the struct disappears to avoid memory leaks +-if a struct has a corresponding copy function, use the copy function instead of "=". + The destination must also be inited already. + + +4. Decoding +----------- + +Decoding converts a PNG compressed image to a raw pixel buffer. + +Most documentation on using the decoder is at its declarations in the header +above. For C, simple decoding can be done with functions such as +lodepng_decode32, and more advanced decoding can be done with the struct +LodePNGState and lodepng_decode. For C++, all decoding can be done with the +various lodepng::decode functions, and lodepng::State can be used for advanced +features. + +When using the LodePNGState, it uses the following fields for decoding: +*) LodePNGInfo info_png: it stores extra information about the PNG (the input) in here +*) LodePNGColorMode info_raw: here you can say what color mode of the raw image (the output) you want to get +*) LodePNGDecoderSettings decoder: you can specify a few extra settings for the decoder to use + +LodePNGInfo info_png +-------------------- + +After decoding, this contains extra information of the PNG image, except the actual +pixels, width and height because these are already gotten directly from the decoder +functions. + +It contains for example the original color type of the PNG image, text comments, +suggested background color, etc... More details about the LodePNGInfo struct are +at its declaration documentation. + +LodePNGColorMode info_raw +------------------------- + +When decoding, here you can specify which color type you want +the resulting raw image to be. If this is different from the colortype of the +PNG, then the decoder will automatically convert the result. This conversion +always works, except if you want it to convert a color PNG to greyscale or to +a palette with missing colors. + +By default, 32-bit color is used for the result. + +LodePNGDecoderSettings decoder +------------------------------ + +The settings can be used to ignore the errors created by invalid CRC and Adler32 +chunks, and to disable the decoding of tEXt chunks. + +There's also a setting color_convert, true by default. If false, no conversion +is done, the resulting data will be as it was in the PNG (after decompression) +and you'll have to puzzle the colors of the pixels together yourself using the +color type information in the LodePNGInfo. + + +5. Encoding +----------- + +Encoding converts a raw pixel buffer to a PNG compressed image. + +Most documentation on using the encoder is at its declarations in the header +above. For C, simple encoding can be done with functions such as +lodepng_encode32, and more advanced decoding can be done with the struct +LodePNGState and lodepng_encode. For C++, all encoding can be done with the +various lodepng::encode functions, and lodepng::State can be used for advanced +features. + +Like the decoder, the encoder can also give errors. However it gives less errors +since the encoder input is trusted, the decoder input (a PNG image that could +be forged by anyone) is not trusted. + +When using the LodePNGState, it uses the following fields for encoding: +*) LodePNGInfo info_png: here you specify how you want the PNG (the output) to be. +*) LodePNGColorMode info_raw: here you say what color type of the raw image (the input) has +*) LodePNGEncoderSettings encoder: you can specify a few settings for the encoder to use + +LodePNGInfo info_png +-------------------- + +When encoding, you use this the opposite way as when decoding: for encoding, +you fill in the values you want the PNG to have before encoding. By default it's +not needed to specify a color type for the PNG since it's automatically chosen, +but it's possible to choose it yourself given the right settings. + +The encoder will not always exactly match the LodePNGInfo struct you give, +it tries as close as possible. Some things are ignored by the encoder. The +encoder uses, for example, the following settings from it when applicable: +colortype and bitdepth, text chunks, time chunk, the color key, the palette, the +background color, the interlace method, unknown chunks, ... + +When encoding to a PNG with colortype 3, the encoder will generate a PLTE chunk. +If the palette contains any colors for which the alpha channel is not 255 (so +there are translucent colors in the palette), it'll add a tRNS chunk. + +LodePNGColorMode info_raw +------------------------- + +You specify the color type of the raw image that you give to the input here, +including a possible transparent color key and palette you happen to be using in +your raw image data. + +By default, 32-bit color is assumed, meaning your input has to be in RGBA +format with 4 bytes (unsigned chars) per pixel. + +LodePNGEncoderSettings encoder +------------------------------ + +The following settings are supported (some are in sub-structs): +*) auto_convert: when this option is enabled, the encoder will +automatically choose the smallest possible color mode (including color key) that +can encode the colors of all pixels without information loss. +*) btype: the block type for LZ77. 0 = uncompressed, 1 = fixed huffman tree, + 2 = dynamic huffman tree (best compression). Should be 2 for proper + compression. +*) use_lz77: whether or not to use LZ77 for compressed block types. Should be + true for proper compression. +*) windowsize: the window size used by the LZ77 encoder (1 - 32768). Has value + 2048 by default, but can be set to 32768 for better, but slow, compression. +*) force_palette: if colortype is 2 or 6, you can make the encoder write a PLTE + chunk if force_palette is true. This can used as suggested palette to convert + to by viewers that don't support more than 256 colors (if those still exist) +*) add_id: add text chunk "Encoder: LodePNG <version>" to the image. +*) text_compression: default 1. If 1, it'll store texts as zTXt instead of tEXt chunks. + zTXt chunks use zlib compression on the text. This gives a smaller result on + large texts but a larger result on small texts (such as a single program name). + It's all tEXt or all zTXt though, there's no separate setting per text yet. + + +6. color conversions +-------------------- + +An important thing to note about LodePNG, is that the color type of the PNG, and +the color type of the raw image, are completely independent. By default, when +you decode a PNG, you get the result as a raw image in the color type you want, +no matter whether the PNG was encoded with a palette, greyscale or RGBA color. +And if you encode an image, by default LodePNG will automatically choose the PNG +color type that gives good compression based on the values of colors and amount +of colors in the image. It can be configured to let you control it instead as +well, though. + +To be able to do this, LodePNG does conversions from one color mode to another. +It can convert from almost any color type to any other color type, except the +following conversions: RGB to greyscale is not supported, and converting to a +palette when the palette doesn't have a required color is not supported. This is +not supported on purpose: this is information loss which requires a color +reduction algorithm that is beyong the scope of a PNG encoder (yes, RGB to grey +is easy, but there are multiple ways if you want to give some channels more +weight). + +By default, when decoding, you get the raw image in 32-bit RGBA or 24-bit RGB +color, no matter what color type the PNG has. And by default when encoding, +LodePNG automatically picks the best color model for the output PNG, and expects +the input image to be 32-bit RGBA or 24-bit RGB. So, unless you want to control +the color format of the images yourself, you can skip this chapter. + +6.1. PNG color types +-------------------- + +A PNG image can have many color types, ranging from 1-bit color to 64-bit color, +as well as palettized color modes. After the zlib decompression and unfiltering +in the PNG image is done, the raw pixel data will have that color type and thus +a certain amount of bits per pixel. If you want the output raw image after +decoding to have another color type, a conversion is done by LodePNG. + +The PNG specification gives the following color types: + +0: greyscale, bit depths 1, 2, 4, 8, 16 +2: RGB, bit depths 8 and 16 +3: palette, bit depths 1, 2, 4 and 8 +4: greyscale with alpha, bit depths 8 and 16 +6: RGBA, bit depths 8 and 16 + +Bit depth is the amount of bits per pixel per color channel. So the total amount +of bits per pixel is: amount of channels * bitdepth. + +6.2. color conversions +---------------------- + +As explained in the sections about the encoder and decoder, you can specify +color types and bit depths in info_png and info_raw to change the default +behaviour. + +If, when decoding, you want the raw image to be something else than the default, +you need to set the color type and bit depth you want in the LodePNGColorMode, +or the parameters colortype and bitdepth of the simple decoding function. + +If, when encoding, you use another color type than the default in the raw input +image, you need to specify its color type and bit depth in the LodePNGColorMode +of the raw image, or use the parameters colortype and bitdepth of the simple +encoding function. + +If, when encoding, you don't want LodePNG to choose the output PNG color type +but control it yourself, you need to set auto_convert in the encoder settings +to false, and specify the color type you want in the LodePNGInfo of the +encoder (including palette: it can generate a palette if auto_convert is true, +otherwise not). + +If the input and output color type differ (whether user chosen or auto chosen), +LodePNG will do a color conversion, which follows the rules below, and may +sometimes result in an error. + +To avoid some confusion: +-the decoder converts from PNG to raw image +-the encoder converts from raw image to PNG +-the colortype and bitdepth in LodePNGColorMode info_raw, are those of the raw image +-the colortype and bitdepth in the color field of LodePNGInfo info_png, are those of the PNG +-when encoding, the color type in LodePNGInfo is ignored if auto_convert + is enabled, it is automatically generated instead +-when decoding, the color type in LodePNGInfo is set by the decoder to that of the original + PNG image, but it can be ignored since the raw image has the color type you requested instead +-if the color type of the LodePNGColorMode and PNG image aren't the same, a conversion + between the color types is done if the color types are supported. If it is not + supported, an error is returned. If the types are the same, no conversion is done. +-even though some conversions aren't supported, LodePNG supports loading PNGs from any + colortype and saving PNGs to any colortype, sometimes it just requires preparing + the raw image correctly before encoding. +-both encoder and decoder use the same color converter. + +Non supported color conversions: +-color to greyscale: no error is thrown, but the result will look ugly because +only the red channel is taken +-anything to palette when that palette does not have that color in it: in this +case an error is thrown + +Supported color conversions: +-anything to 8-bit RGB, 8-bit RGBA, 16-bit RGB, 16-bit RGBA +-any grey or grey+alpha, to grey or grey+alpha +-anything to a palette, as long as the palette has the requested colors in it +-removing alpha channel +-higher to smaller bitdepth, and vice versa + +If you want no color conversion to be done (e.g. for speed or control): +-In the encoder, you can make it save a PNG with any color type by giving the +raw color mode and LodePNGInfo the same color mode, and setting auto_convert to +false. +-In the decoder, you can make it store the pixel data in the same color type +as the PNG has, by setting the color_convert setting to false. Settings in +info_raw are then ignored. + +The function lodepng_convert does the color conversion. It is available in the +interface but normally isn't needed since the encoder and decoder already call +it. + +6.3. padding bits +----------------- + +In the PNG file format, if a less than 8-bit per pixel color type is used and the scanlines +have a bit amount that isn't a multiple of 8, then padding bits are used so that each +scanline starts at a fresh byte. But that is NOT true for the LodePNG raw input and output. +The raw input image you give to the encoder, and the raw output image you get from the decoder +will NOT have these padding bits, e.g. in the case of a 1-bit image with a width +of 7 pixels, the first pixel of the second scanline will the the 8th bit of the first byte, +not the first bit of a new byte. + +6.4. A note about 16-bits per channel and endianness +---------------------------------------------------- + +LodePNG uses unsigned char arrays for 16-bit per channel colors too, just like +for any other color format. The 16-bit values are stored in big endian (most +significant byte first) in these arrays. This is the opposite order of the +little endian used by x86 CPU's. + +LodePNG always uses big endian because the PNG file format does so internally. +Conversions to other formats than PNG uses internally are not supported by +LodePNG on purpose, there are myriads of formats, including endianness of 16-bit +colors, the order in which you store R, G, B and A, and so on. Supporting and +converting to/from all that is outside the scope of LodePNG. + +This may mean that, depending on your use case, you may want to convert the big +endian output of LodePNG to little endian with a for loop. This is certainly not +always needed, many applications and libraries support big endian 16-bit colors +anyway, but it means you cannot simply cast the unsigned char* buffer to an +unsigned short* buffer on x86 CPUs. + + +7. error values +--------------- + +All functions in LodePNG that return an error code, return 0 if everything went +OK, or a non-zero code if there was an error. + +The meaning of the LodePNG error values can be retrieved with the function +lodepng_error_text: given the numerical error code, it returns a description +of the error in English as a string. + +Check the implementation of lodepng_error_text to see the meaning of each code. + + +8. chunks and PNG editing +------------------------- + +If you want to add extra chunks to a PNG you encode, or use LodePNG for a PNG +editor that should follow the rules about handling of unknown chunks, or if your +program is able to read other types of chunks than the ones handled by LodePNG, +then that's possible with the chunk functions of LodePNG. + +A PNG chunk has the following layout: + +4 bytes length +4 bytes type name +length bytes data +4 bytes CRC + +8.1. iterating through chunks +----------------------------- + +If you have a buffer containing the PNG image data, then the first chunk (the +IHDR chunk) starts at byte number 8 of that buffer. The first 8 bytes are the +signature of the PNG and are not part of a chunk. But if you start at byte 8 +then you have a chunk, and can check the following things of it. + +NOTE: none of these functions check for memory buffer boundaries. To avoid +exploits, always make sure the buffer contains all the data of the chunks. +When using lodepng_chunk_next, make sure the returned value is within the +allocated memory. + +unsigned lodepng_chunk_length(const unsigned char* chunk): + +Get the length of the chunk's data. The total chunk length is this length + 12. + +void lodepng_chunk_type(char type[5], const unsigned char* chunk): +unsigned char lodepng_chunk_type_equals(const unsigned char* chunk, const char* type): + +Get the type of the chunk or compare if it's a certain type + +unsigned char lodepng_chunk_critical(const unsigned char* chunk): +unsigned char lodepng_chunk_private(const unsigned char* chunk): +unsigned char lodepng_chunk_safetocopy(const unsigned char* chunk): + +Check if the chunk is critical in the PNG standard (only IHDR, PLTE, IDAT and IEND are). +Check if the chunk is private (public chunks are part of the standard, private ones not). +Check if the chunk is safe to copy. If it's not, then, when modifying data in a critical +chunk, unsafe to copy chunks of the old image may NOT be saved in the new one if your +program doesn't handle that type of unknown chunk. + +unsigned char* lodepng_chunk_data(unsigned char* chunk): +const unsigned char* lodepng_chunk_data_const(const unsigned char* chunk): + +Get a pointer to the start of the data of the chunk. + +unsigned lodepng_chunk_check_crc(const unsigned char* chunk): +void lodepng_chunk_generate_crc(unsigned char* chunk): + +Check if the crc is correct or generate a correct one. + +unsigned char* lodepng_chunk_next(unsigned char* chunk): +const unsigned char* lodepng_chunk_next_const(const unsigned char* chunk): + +Iterate to the next chunk. This works if you have a buffer with consecutive chunks. Note that these +functions do no boundary checking of the allocated data whatsoever, so make sure there is enough +data available in the buffer to be able to go to the next chunk. + +unsigned lodepng_chunk_append(unsigned char** out, size_t* outlength, const unsigned char* chunk): +unsigned lodepng_chunk_create(unsigned char** out, size_t* outlength, unsigned length, + const char* type, const unsigned char* data): + +These functions are used to create new chunks that are appended to the data in *out that has +length *outlength. The append function appends an existing chunk to the new data. The create +function creates a new chunk with the given parameters and appends it. Type is the 4-letter +name of the chunk. + +8.2. chunks in info_png +----------------------- + +The LodePNGInfo struct contains fields with the unknown chunk in it. It has 3 +buffers (each with size) to contain 3 types of unknown chunks: +the ones that come before the PLTE chunk, the ones that come between the PLTE +and the IDAT chunks, and the ones that come after the IDAT chunks. +It's necessary to make the distionction between these 3 cases because the PNG +standard forces to keep the ordering of unknown chunks compared to the critical +chunks, but does not force any other ordering rules. + +info_png.unknown_chunks_data[0] is the chunks before PLTE +info_png.unknown_chunks_data[1] is the chunks after PLTE, before IDAT +info_png.unknown_chunks_data[2] is the chunks after IDAT + +The chunks in these 3 buffers can be iterated through and read by using the same +way described in the previous subchapter. + +When using the decoder to decode a PNG, you can make it store all unknown chunks +if you set the option settings.remember_unknown_chunks to 1. By default, this +option is off (0). + +The encoder will always encode unknown chunks that are stored in the info_png. +If you need it to add a particular chunk that isn't known by LodePNG, you can +use lodepng_chunk_append or lodepng_chunk_create to the chunk data in +info_png.unknown_chunks_data[x]. + +Chunks that are known by LodePNG should not be added in that way. E.g. to make +LodePNG add a bKGD chunk, set background_defined to true and add the correct +parameters there instead. + + +9. compiler support +------------------- + +No libraries other than the current standard C library are needed to compile +LodePNG. For the C++ version, only the standard C++ library is needed on top. +Add the files lodepng.c(pp) and lodepng.h to your project, include +lodepng.h where needed, and your program can read/write PNG files. + +It is compatible with C90 and up, and C++03 and up. + +If performance is important, use optimization when compiling! For both the +encoder and decoder, this makes a large difference. + +Make sure that LodePNG is compiled with the same compiler of the same version +and with the same settings as the rest of the program, or the interfaces with +std::vectors and std::strings in C++ can be incompatible. + +CHAR_BITS must be 8 or higher, because LodePNG uses unsigned chars for octets. + +*) gcc and g++ + +LodePNG is developed in gcc so this compiler is natively supported. It gives no +warnings with compiler options "-Wall -Wextra -pedantic -ansi", with gcc and g++ +version 4.7.1 on Linux, 32-bit and 64-bit. + +*) Clang + +Fully supported and warning-free. + +*) Mingw + +The Mingw compiler (a port of gcc for Windows) should be fully supported by +LodePNG. + +*) Visual Studio and Visual C++ Express Edition + +LodePNG should be warning-free with warning level W4. Two warnings were disabled +with pragmas though: warning 4244 about implicit conversions, and warning 4996 +where it wants to use a non-standard function fopen_s instead of the standard C +fopen. + +Visual Studio may want "stdafx.h" files to be included in each source file and +give an error "unexpected end of file while looking for precompiled header". +This is not standard C++ and will not be added to the stock LodePNG. You can +disable it for lodepng.cpp only by right clicking it, Properties, C/C++, +Precompiled Headers, and set it to Not Using Precompiled Headers there. + +NOTE: Modern versions of VS should be fully supported, but old versions, e.g. +VS6, are not guaranteed to work. + +*) Compilers on Macintosh + +LodePNG has been reported to work both with gcc and LLVM for Macintosh, both for +C and C++. + +*) Other Compilers + +If you encounter problems on any compilers, feel free to let me know and I may +try to fix it if the compiler is modern and standards complient. + + +10. examples +------------ + +This decoder example shows the most basic usage of LodePNG. More complex +examples can be found on the LodePNG website. + +10.1. decoder C++ example +------------------------- + +#include "lodepng.h" +#include <iostream> + +int main(int argc, char *argv[]) +{ + const char* filename = argc > 1 ? argv[1] : "test.png"; + + //load and decode + std::vector<unsigned char> image; + unsigned width, height; + unsigned error = lodepng::decode(image, width, height, filename); + + //if there's an error, display it + if(error) std::cout << "decoder error " << error << ": " << lodepng_error_text(error) << std::endl; + + //the pixels are now in the vector "image", 4 bytes per pixel, ordered RGBARGBA..., use it as texture, draw it, ... +} + +10.2. decoder C example +----------------------- + +#include "lodepng.h" + +int main(int argc, char *argv[]) +{ + unsigned error; + unsigned char* image; + size_t width, height; + const char* filename = argc > 1 ? argv[1] : "test.png"; + + error = lodepng_decode32_file(&image, &width, &height, filename); + + if(error) printf("decoder error %u: %s\n", error, lodepng_error_text(error)); + + / * use image here * / + + free(image); + return 0; +} + +11. state settings reference +---------------------------- + +A quick reference of some settings to set on the LodePNGState + +For decoding: + +state.decoder.zlibsettings.ignore_adler32: ignore ADLER32 checksums +state.decoder.zlibsettings.custom_...: use custom inflate function +state.decoder.ignore_crc: ignore CRC checksums +state.decoder.color_convert: convert internal PNG color to chosen one +state.decoder.read_text_chunks: whether to read in text metadata chunks +state.decoder.remember_unknown_chunks: whether to read in unknown chunks +state.info_raw.colortype: desired color type for decoded image +state.info_raw.bitdepth: desired bit depth for decoded image +state.info_raw....: more color settings, see struct LodePNGColorMode +state.info_png....: no settings for decoder but ouput, see struct LodePNGInfo + +For encoding: + +state.encoder.zlibsettings.btype: disable compression by setting it to 0 +state.encoder.zlibsettings.use_lz77: use LZ77 in compression +state.encoder.zlibsettings.windowsize: tweak LZ77 windowsize +state.encoder.zlibsettings.minmatch: tweak min LZ77 length to match +state.encoder.zlibsettings.nicematch: tweak LZ77 match where to stop searching +state.encoder.zlibsettings.lazymatching: try one more LZ77 matching +state.encoder.zlibsettings.custom_...: use custom deflate function +state.encoder.auto_convert: choose optimal PNG color type, if 0 uses info_png +state.encoder.filter_palette_zero: PNG filter strategy for palette +state.encoder.filter_strategy: PNG filter strategy to encode with +state.encoder.force_palette: add palette even if not encoding to one +state.encoder.add_id: add LodePNG identifier and version as a text chunk +state.encoder.text_compression: use compressed text chunks for metadata +state.info_raw.colortype: color type of raw input image you provide +state.info_raw.bitdepth: bit depth of raw input image you provide +state.info_raw: more color settings, see struct LodePNGColorMode +state.info_png.color.colortype: desired color type if auto_convert is false +state.info_png.color.bitdepth: desired bit depth if auto_convert is false +state.info_png.color....: more color settings, see struct LodePNGColorMode +state.info_png....: more PNG related settings, see struct LodePNGInfo + + +12. changes +----------- + +The version number of LodePNG is the date of the change given in the format +yyyymmdd. + +Some changes aren't backwards compatible. Those are indicated with a (!) +symbol. + +*) 18 apr 2016: Changed qsort to custom stable sort (for platforms w/o qsort). +*) 09 apr 2016: Fixed colorkey usage detection, and better file loading (within + the limits of pure C90). +*) 08 dec 2015: Made load_file function return error if file can't be opened. +*) 24 okt 2015: Bugfix with decoding to palette output. +*) 18 apr 2015: Boundary PM instead of just package-merge for faster encoding. +*) 23 aug 2014: Reduced needless memory usage of decoder. +*) 28 jun 2014: Removed fix_png setting, always support palette OOB for + simplicity. Made ColorProfile public. +*) 09 jun 2014: Faster encoder by fixing hash bug and more zeros optimization. +*) 22 dec 2013: Power of two windowsize required for optimization. +*) 15 apr 2013: Fixed bug with LAC_ALPHA and color key. +*) 25 mar 2013: Added an optional feature to ignore some PNG errors (fix_png). +*) 11 mar 2013 (!): Bugfix with custom free. Changed from "my" to "lodepng_" + prefix for the custom allocators and made it possible with a new #define to + use custom ones in your project without needing to change lodepng's code. +*) 28 jan 2013: Bugfix with color key. +*) 27 okt 2012: Tweaks in text chunk keyword length error handling. +*) 8 okt 2012 (!): Added new filter strategy (entropy) and new auto color mode. + (no palette). Better deflate tree encoding. New compression tweak settings. + Faster color conversions while decoding. Some internal cleanups. +*) 23 sep 2012: Reduced warnings in Visual Studio a little bit. +*) 1 sep 2012 (!): Removed #define's for giving custom (de)compression functions + and made it work with function pointers instead. +*) 23 jun 2012: Added more filter strategies. Made it easier to use custom alloc + and free functions and toggle #defines from compiler flags. Small fixes. +*) 6 may 2012 (!): Made plugging in custom zlib/deflate functions more flexible. +*) 22 apr 2012 (!): Made interface more consistent, renaming a lot. Removed + redundant C++ codec classes. Reduced amount of structs. Everything changed, + but it is cleaner now imho and functionality remains the same. Also fixed + several bugs and shrunk the implementation code. Made new samples. +*) 6 nov 2011 (!): By default, the encoder now automatically chooses the best + PNG color model and bit depth, based on the amount and type of colors of the + raw image. For this, autoLeaveOutAlphaChannel replaced by auto_choose_color. +*) 9 okt 2011: simpler hash chain implementation for the encoder. +*) 8 sep 2011: lz77 encoder lazy matching instead of greedy matching. +*) 23 aug 2011: tweaked the zlib compression parameters after benchmarking. + A bug with the PNG filtertype heuristic was fixed, so that it chooses much + better ones (it's quite significant). A setting to do an experimental, slow, + brute force search for PNG filter types is added. +*) 17 aug 2011 (!): changed some C zlib related function names. +*) 16 aug 2011: made the code less wide (max 120 characters per line). +*) 17 apr 2011: code cleanup. Bugfixes. Convert low to 16-bit per sample colors. +*) 21 feb 2011: fixed compiling for C90. Fixed compiling with sections disabled. +*) 11 dec 2010: encoding is made faster, based on suggestion by Peter Eastman + to optimize long sequences of zeros. +*) 13 nov 2010: added LodePNG_InfoColor_hasPaletteAlpha and + LodePNG_InfoColor_canHaveAlpha functions for convenience. +*) 7 nov 2010: added LodePNG_error_text function to get error code description. +*) 30 okt 2010: made decoding slightly faster +*) 26 okt 2010: (!) changed some C function and struct names (more consistent). + Reorganized the documentation and the declaration order in the header. +*) 08 aug 2010: only changed some comments and external samples. +*) 05 jul 2010: fixed bug thanks to warnings in the new gcc version. +*) 14 mar 2010: fixed bug where too much memory was allocated for char buffers. +*) 02 sep 2008: fixed bug where it could create empty tree that linux apps could + read by ignoring the problem but windows apps couldn't. +*) 06 jun 2008: added more error checks for out of memory cases. +*) 26 apr 2008: added a few more checks here and there to ensure more safety. +*) 06 mar 2008: crash with encoding of strings fixed +*) 02 feb 2008: support for international text chunks added (iTXt) +*) 23 jan 2008: small cleanups, and #defines to divide code in sections +*) 20 jan 2008: support for unknown chunks allowing using LodePNG for an editor. +*) 18 jan 2008: support for tIME and pHYs chunks added to encoder and decoder. +*) 17 jan 2008: ability to encode and decode compressed zTXt chunks added + Also various fixes, such as in the deflate and the padding bits code. +*) 13 jan 2008: Added ability to encode Adam7-interlaced images. Improved + filtering code of encoder. +*) 07 jan 2008: (!) changed LodePNG to use ISO C90 instead of C++. A + C++ wrapper around this provides an interface almost identical to before. + Having LodePNG be pure ISO C90 makes it more portable. The C and C++ code + are together in these files but it works both for C and C++ compilers. +*) 29 dec 2007: (!) changed most integer types to unsigned int + other tweaks +*) 30 aug 2007: bug fixed which makes this Borland C++ compatible +*) 09 aug 2007: some VS2005 warnings removed again +*) 21 jul 2007: deflate code placed in new namespace separate from zlib code +*) 08 jun 2007: fixed bug with 2- and 4-bit color, and small interlaced images +*) 04 jun 2007: improved support for Visual Studio 2005: crash with accessing + invalid std::vector element [0] fixed, and level 3 and 4 warnings removed +*) 02 jun 2007: made the encoder add a tag with version by default +*) 27 may 2007: zlib and png code separated (but still in the same file), + simple encoder/decoder functions added for more simple usage cases +*) 19 may 2007: minor fixes, some code cleaning, new error added (error 69), + moved some examples from here to lodepng_examples.cpp +*) 12 may 2007: palette decoding bug fixed +*) 24 apr 2007: changed the license from BSD to the zlib license +*) 11 mar 2007: very simple addition: ability to encode bKGD chunks. +*) 04 mar 2007: (!) tEXt chunk related fixes, and support for encoding + palettized PNG images. Plus little interface change with palette and texts. +*) 03 mar 2007: Made it encode dynamic Huffman shorter with repeat codes. + Fixed a bug where the end code of a block had length 0 in the Huffman tree. +*) 26 feb 2007: Huffman compression with dynamic trees (BTYPE 2) now implemented + and supported by the encoder, resulting in smaller PNGs at the output. +*) 27 jan 2007: Made the Adler-32 test faster so that a timewaste is gone. +*) 24 jan 2007: gave encoder an error interface. Added color conversion from any + greyscale type to 8-bit greyscale with or without alpha. +*) 21 jan 2007: (!) Totally changed the interface. It allows more color types + to convert to and is more uniform. See the manual for how it works now. +*) 07 jan 2007: Some cleanup & fixes, and a few changes over the last days: + encode/decode custom tEXt chunks, separate classes for zlib & deflate, and + at last made the decoder give errors for incorrect Adler32 or Crc. +*) 01 jan 2007: Fixed bug with encoding PNGs with less than 8 bits per channel. +*) 29 dec 2006: Added support for encoding images without alpha channel, and + cleaned out code as well as making certain parts faster. +*) 28 dec 2006: Added "Settings" to the encoder. +*) 26 dec 2006: The encoder now does LZ77 encoding and produces much smaller files now. + Removed some code duplication in the decoder. Fixed little bug in an example. +*) 09 dec 2006: (!) Placed output parameters of public functions as first parameter. + Fixed a bug of the decoder with 16-bit per color. +*) 15 okt 2006: Changed documentation structure +*) 09 okt 2006: Encoder class added. It encodes a valid PNG image from the + given image buffer, however for now it's not compressed. +*) 08 sep 2006: (!) Changed to interface with a Decoder class +*) 30 jul 2006: (!) LodePNG_InfoPng , width and height are now retrieved in different + way. Renamed decodePNG to decodePNGGeneric. +*) 29 jul 2006: (!) Changed the interface: image info is now returned as a + struct of type LodePNG::LodePNG_Info, instead of a vector, which was a bit clumsy. +*) 28 jul 2006: Cleaned the code and added new error checks. + Corrected terminology "deflate" into "inflate". +*) 23 jun 2006: Added SDL example in the documentation in the header, this + example allows easy debugging by displaying the PNG and its transparency. +*) 22 jun 2006: (!) Changed way to obtain error value. Added + loadFile function for convenience. Made decodePNG32 faster. +*) 21 jun 2006: (!) Changed type of info vector to unsigned. + Changed position of palette in info vector. Fixed an important bug that + happened on PNGs with an uncompressed block. +*) 16 jun 2006: Internally changed unsigned into unsigned where + needed, and performed some optimizations. +*) 07 jun 2006: (!) Renamed functions to decodePNG and placed them + in LodePNG namespace. Changed the order of the parameters. Rewrote the + documentation in the header. Renamed files to lodepng.cpp and lodepng.h +*) 22 apr 2006: Optimized and improved some code +*) 07 sep 2005: (!) Changed to std::vector interface +*) 12 aug 2005: Initial release (C++, decoder only) + + +13. contact information +----------------------- + +Feel free to contact me with suggestions, problems, comments, ... concerning +LodePNG. If you encounter a PNG image that doesn't work properly with this +decoder, feel free to send it and I'll use it to find and fix the problem. + +My email address is (puzzle the account and domain together with an @ symbol): +Domain: gmail dot com. +Account: lode dot vandevenne. + + +Copyright (c) 2005-2016 Lode Vandevenne +*/ diff --git a/include/tinyxml2.h b/include/tinyxml2.h new file mode 100644 index 0000000..06eee30 --- /dev/null +++ b/include/tinyxml2.h @@ -0,0 +1,2102 @@ +/* +Original code by Lee Thomason (www.grinninglizard.com) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must +not claim that you wrote the original software. If you use this +software in a product, an acknowledgment in the product documentation +would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ + +#ifndef TINYXML2_INCLUDED +#define TINYXML2_INCLUDED + +#if defined(ANDROID_NDK) || defined(__BORLANDC__) || defined(__QNXNTO__) +# include <ctype.h> +# include <limits.h> +# include <stdio.h> +# include <stdlib.h> +# include <string.h> +#else +# include <cctype> +# include <climits> +# include <cstdio> +# include <cstdlib> +# include <cstring> +#endif + +/* + TODO: intern strings instead of allocation. +*/ +/* + gcc: + g++ -Wall -DDEBUG tinyxml2.cpp xmltest.cpp -o gccxmltest.exe + + Formatting, Artistic Style: + AStyle.exe --style=1tbs --indent-switches --break-closing-brackets --indent-preprocessor tinyxml2.cpp tinyxml2.h +*/ + +#if defined( _DEBUG ) || defined( DEBUG ) || defined (__DEBUG__) +# ifndef DEBUG +# define DEBUG +# endif +#endif + +#ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable: 4251) +#endif + +#ifdef _WIN32 +# ifdef TINYXML2_EXPORT +# define TINYXML2_LIB __declspec(dllexport) +# elif defined(TINYXML2_IMPORT) +# define TINYXML2_LIB __declspec(dllimport) +# else +# define TINYXML2_LIB +# endif +#else +# define TINYXML2_LIB +#endif + + +#if defined(DEBUG) +# if defined(_MSC_VER) +# // "(void)0," is for suppressing C4127 warning in "assert(false)", "assert(true)" and the like +# define TIXMLASSERT( x ) if ( !((void)0,(x))) { __debugbreak(); } +# elif defined (ANDROID_NDK) +# include <android/log.h> +# define TIXMLASSERT( x ) if ( !(x)) { __android_log_assert( "assert", "grinliz", "ASSERT in '%s' at %d.", __FILE__, __LINE__ ); } +# else +# include <assert.h> +# define TIXMLASSERT assert +# endif +#else +# define TIXMLASSERT( x ) {} +#endif + + +/* Versioning, past 1.0.14: + http://semver.org/ +*/ +static const int TIXML2_MAJOR_VERSION = 3; +static const int TIXML2_MINOR_VERSION = 0; +static const int TIXML2_PATCH_VERSION = 0; + +namespace tinyxml2 +{ +class XMLDocument; +class XMLElement; +class XMLAttribute; +class XMLComment; +class XMLText; +class XMLDeclaration; +class XMLUnknown; +class XMLPrinter; + +/* + A class that wraps strings. Normally stores the start and end + pointers into the XML file itself, and will apply normalization + and entity translation if actually read. Can also store (and memory + manage) a traditional char[] +*/ +class StrPair +{ +public: + enum { + NEEDS_ENTITY_PROCESSING = 0x01, + NEEDS_NEWLINE_NORMALIZATION = 0x02, + NEEDS_WHITESPACE_COLLAPSING = 0x04, + + TEXT_ELEMENT = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION, + TEXT_ELEMENT_LEAVE_ENTITIES = NEEDS_NEWLINE_NORMALIZATION, + ATTRIBUTE_NAME = 0, + ATTRIBUTE_VALUE = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION, + ATTRIBUTE_VALUE_LEAVE_ENTITIES = NEEDS_NEWLINE_NORMALIZATION, + COMMENT = NEEDS_NEWLINE_NORMALIZATION + }; + + StrPair() : _flags( 0 ), _start( 0 ), _end( 0 ) {} + ~StrPair(); + + void Set( char* start, char* end, int flags ) { + Reset(); + _start = start; + _end = end; + _flags = flags | NEEDS_FLUSH; + } + + const char* GetStr(); + + bool Empty() const { + return _start == _end; + } + + void SetInternedStr( const char* str ) { + Reset(); + _start = const_cast<char*>(str); + } + + void SetStr( const char* str, int flags=0 ); + + char* ParseText( char* in, const char* endTag, int strFlags ); + char* ParseName( char* in ); + + void TransferTo( StrPair* other ); + +private: + void Reset(); + void CollapseWhitespace(); + + enum { + NEEDS_FLUSH = 0x100, + NEEDS_DELETE = 0x200 + }; + + int _flags; + char* _start; + char* _end; + + StrPair( const StrPair& other ); // not supported + void operator=( StrPair& other ); // not supported, use TransferTo() +}; + + +/* + A dynamic array of Plain Old Data. Doesn't support constructors, etc. + Has a small initial memory pool, so that low or no usage will not + cause a call to new/delete +*/ +template <class T, int INITIAL_SIZE> +class DynArray +{ +public: + DynArray() { + _mem = _pool; + _allocated = INITIAL_SIZE; + _size = 0; + } + + ~DynArray() { + if ( _mem != _pool ) { + delete [] _mem; + } + } + + void Clear() { + _size = 0; + } + + void Push( T t ) { + TIXMLASSERT( _size < INT_MAX ); + EnsureCapacity( _size+1 ); + _mem[_size++] = t; + } + + T* PushArr( int count ) { + TIXMLASSERT( count >= 0 ); + TIXMLASSERT( _size <= INT_MAX - count ); + EnsureCapacity( _size+count ); + T* ret = &_mem[_size]; + _size += count; + return ret; + } + + T Pop() { + TIXMLASSERT( _size > 0 ); + return _mem[--_size]; + } + + void PopArr( int count ) { + TIXMLASSERT( _size >= count ); + _size -= count; + } + + bool Empty() const { + return _size == 0; + } + + T& operator[](int i) { + TIXMLASSERT( i>= 0 && i < _size ); + return _mem[i]; + } + + const T& operator[](int i) const { + TIXMLASSERT( i>= 0 && i < _size ); + return _mem[i]; + } + + const T& PeekTop() const { + TIXMLASSERT( _size > 0 ); + return _mem[ _size - 1]; + } + + int Size() const { + TIXMLASSERT( _size >= 0 ); + return _size; + } + + int Capacity() const { + TIXMLASSERT( _allocated >= INITIAL_SIZE ); + return _allocated; + } + + const T* Mem() const { + TIXMLASSERT( _mem ); + return _mem; + } + + T* Mem() { + TIXMLASSERT( _mem ); + return _mem; + } + +private: + DynArray( const DynArray& ); // not supported + void operator=( const DynArray& ); // not supported + + void EnsureCapacity( int cap ) { + TIXMLASSERT( cap > 0 ); + if ( cap > _allocated ) { + TIXMLASSERT( cap <= INT_MAX / 2 ); + int newAllocated = cap * 2; + T* newMem = new T[newAllocated]; + memcpy( newMem, _mem, sizeof(T)*_size ); // warning: not using constructors, only works for PODs + if ( _mem != _pool ) { + delete [] _mem; + } + _mem = newMem; + _allocated = newAllocated; + } + } + + T* _mem; + T _pool[INITIAL_SIZE]; + int _allocated; // objects allocated + int _size; // number objects in use +}; + + +/* + Parent virtual class of a pool for fast allocation + and deallocation of objects. +*/ +class MemPool +{ +public: + MemPool() {} + virtual ~MemPool() {} + + virtual int ItemSize() const = 0; + virtual void* Alloc() = 0; + virtual void Free( void* ) = 0; + virtual void SetTracked() = 0; + virtual void Clear() = 0; +}; + + +/* + Template child class to create pools of the correct type. +*/ +template< int SIZE > +class MemPoolT : public MemPool +{ +public: + MemPoolT() : _root(0), _currentAllocs(0), _nAllocs(0), _maxAllocs(0), _nUntracked(0) {} + ~MemPoolT() { + Clear(); + } + + void Clear() { + // Delete the blocks. + while( !_blockPtrs.Empty()) { + Block* b = _blockPtrs.Pop(); + delete b; + } + _root = 0; + _currentAllocs = 0; + _nAllocs = 0; + _maxAllocs = 0; + _nUntracked = 0; + } + + virtual int ItemSize() const { + return SIZE; + } + int CurrentAllocs() const { + return _currentAllocs; + } + + virtual void* Alloc() { + if ( !_root ) { + // Need a new block. + Block* block = new Block(); + _blockPtrs.Push( block ); + + for( int i=0; i<COUNT-1; ++i ) { + block->chunk[i].next = &block->chunk[i+1]; + } + block->chunk[COUNT-1].next = 0; + _root = block->chunk; + } + void* result = _root; + _root = _root->next; + + ++_currentAllocs; + if ( _currentAllocs > _maxAllocs ) { + _maxAllocs = _currentAllocs; + } + _nAllocs++; + _nUntracked++; + return result; + } + + virtual void Free( void* mem ) { + if ( !mem ) { + return; + } + --_currentAllocs; + Chunk* chunk = static_cast<Chunk*>( mem ); +#ifdef DEBUG + memset( chunk, 0xfe, sizeof(Chunk) ); +#endif + chunk->next = _root; + _root = chunk; + } + void Trace( const char* name ) { + printf( "Mempool %s watermark=%d [%dk] current=%d size=%d nAlloc=%d blocks=%d\n", + name, _maxAllocs, _maxAllocs*SIZE/1024, _currentAllocs, SIZE, _nAllocs, _blockPtrs.Size() ); + } + + void SetTracked() { + _nUntracked--; + } + + int Untracked() const { + return _nUntracked; + } + + // This number is perf sensitive. 4k seems like a good tradeoff on my machine. + // The test file is large, 170k. + // Release: VS2010 gcc(no opt) + // 1k: 4000 + // 2k: 4000 + // 4k: 3900 21000 + // 16k: 5200 + // 32k: 4300 + // 64k: 4000 21000 + enum { COUNT = (4*1024)/SIZE }; // Some compilers do not accept to use COUNT in private part if COUNT is private + +private: + MemPoolT( const MemPoolT& ); // not supported + void operator=( const MemPoolT& ); // not supported + + union Chunk { + Chunk* next; + char mem[SIZE]; + }; + struct Block { + Chunk chunk[COUNT]; + }; + DynArray< Block*, 10 > _blockPtrs; + Chunk* _root; + + int _currentAllocs; + int _nAllocs; + int _maxAllocs; + int _nUntracked; +}; + + + +/** + Implements the interface to the "Visitor pattern" (see the Accept() method.) + If you call the Accept() method, it requires being passed a XMLVisitor + class to handle callbacks. For nodes that contain other nodes (Document, Element) + you will get called with a VisitEnter/VisitExit pair. Nodes that are always leafs + are simply called with Visit(). + + If you return 'true' from a Visit method, recursive parsing will continue. If you return + false, <b>no children of this node or its siblings</b> will be visited. + + All flavors of Visit methods have a default implementation that returns 'true' (continue + visiting). You need to only override methods that are interesting to you. + + Generally Accept() is called on the XMLDocument, although all nodes support visiting. + + You should never change the document from a callback. + + @sa XMLNode::Accept() +*/ +class TINYXML2_LIB XMLVisitor +{ +public: + virtual ~XMLVisitor() {} + + /// Visit a document. + virtual bool VisitEnter( const XMLDocument& /*doc*/ ) { + return true; + } + /// Visit a document. + virtual bool VisitExit( const XMLDocument& /*doc*/ ) { + return true; + } + + /// Visit an element. + virtual bool VisitEnter( const XMLElement& /*element*/, const XMLAttribute* /*firstAttribute*/ ) { + return true; + } + /// Visit an element. + virtual bool VisitExit( const XMLElement& /*element*/ ) { + return true; + } + + /// Visit a declaration. + virtual bool Visit( const XMLDeclaration& /*declaration*/ ) { + return true; + } + /// Visit a text node. + virtual bool Visit( const XMLText& /*text*/ ) { + return true; + } + /// Visit a comment node. + virtual bool Visit( const XMLComment& /*comment*/ ) { + return true; + } + /// Visit an unknown node. + virtual bool Visit( const XMLUnknown& /*unknown*/ ) { + return true; + } +}; + +// WARNING: must match XMLDocument::_errorNames[] +enum XMLError { + XML_SUCCESS = 0, + XML_NO_ERROR = 0, + XML_NO_ATTRIBUTE, + XML_WRONG_ATTRIBUTE_TYPE, + XML_ERROR_FILE_NOT_FOUND, + XML_ERROR_FILE_COULD_NOT_BE_OPENED, + XML_ERROR_FILE_READ_ERROR, + XML_ERROR_ELEMENT_MISMATCH, + XML_ERROR_PARSING_ELEMENT, + XML_ERROR_PARSING_ATTRIBUTE, + XML_ERROR_IDENTIFYING_TAG, + XML_ERROR_PARSING_TEXT, + XML_ERROR_PARSING_CDATA, + XML_ERROR_PARSING_COMMENT, + XML_ERROR_PARSING_DECLARATION, + XML_ERROR_PARSING_UNKNOWN, + XML_ERROR_EMPTY_DOCUMENT, + XML_ERROR_MISMATCHED_ELEMENT, + XML_ERROR_PARSING, + XML_CAN_NOT_CONVERT_TEXT, + XML_NO_TEXT_NODE, + + XML_ERROR_COUNT +}; + + +/* + Utility functionality. +*/ +class XMLUtil +{ +public: + static const char* SkipWhiteSpace( const char* p ) { + TIXMLASSERT( p ); + while( IsWhiteSpace(*p) ) { + ++p; + } + TIXMLASSERT( p ); + return p; + } + static char* SkipWhiteSpace( char* p ) { + return const_cast<char*>( SkipWhiteSpace( const_cast<const char*>(p) ) ); + } + + // Anything in the high order range of UTF-8 is assumed to not be whitespace. This isn't + // correct, but simple, and usually works. + static bool IsWhiteSpace( char p ) { + return !IsUTF8Continuation(p) && isspace( static_cast<unsigned char>(p) ); + } + + inline static bool IsNameStartChar( unsigned char ch ) { + if ( ch >= 128 ) { + // This is a heuristic guess in attempt to not implement Unicode-aware isalpha() + return true; + } + if ( isalpha( ch ) ) { + return true; + } + return ch == ':' || ch == '_'; + } + + inline static bool IsNameChar( unsigned char ch ) { + return IsNameStartChar( ch ) + || isdigit( ch ) + || ch == '.' + || ch == '-'; + } + + inline static bool StringEqual( const char* p, const char* q, int nChar=INT_MAX ) { + if ( p == q ) { + return true; + } + return strncmp( p, q, nChar ) == 0; + } + + inline static bool IsUTF8Continuation( char p ) { + return ( p & 0x80 ) != 0; + } + + static const char* ReadBOM( const char* p, bool* hasBOM ); + // p is the starting location, + // the UTF-8 value of the entity will be placed in value, and length filled in. + static const char* GetCharacterRef( const char* p, char* value, int* length ); + static void ConvertUTF32ToUTF8( unsigned long input, char* output, int* length ); + + // converts primitive types to strings + static void ToStr( int v, char* buffer, int bufferSize ); + static void ToStr( unsigned v, char* buffer, int bufferSize ); + static void ToStr( bool v, char* buffer, int bufferSize ); + static void ToStr( float v, char* buffer, int bufferSize ); + static void ToStr( double v, char* buffer, int bufferSize ); + + // converts strings to primitive types + static bool ToInt( const char* str, int* value ); + static bool ToUnsigned( const char* str, unsigned* value ); + static bool ToBool( const char* str, bool* value ); + static bool ToFloat( const char* str, float* value ); + static bool ToDouble( const char* str, double* value ); +}; + + +/** XMLNode is a base class for every object that is in the + XML Document Object Model (DOM), except XMLAttributes. + Nodes have siblings, a parent, and children which can + be navigated. A node is always in a XMLDocument. + The type of a XMLNode can be queried, and it can + be cast to its more defined type. + + A XMLDocument allocates memory for all its Nodes. + When the XMLDocument gets deleted, all its Nodes + will also be deleted. + + @verbatim + A Document can contain: Element (container or leaf) + Comment (leaf) + Unknown (leaf) + Declaration( leaf ) + + An Element can contain: Element (container or leaf) + Text (leaf) + Attributes (not on tree) + Comment (leaf) + Unknown (leaf) + + @endverbatim +*/ +class TINYXML2_LIB XMLNode +{ + friend class XMLDocument; + friend class XMLElement; +public: + + /// Get the XMLDocument that owns this XMLNode. + const XMLDocument* GetDocument() const { + TIXMLASSERT( _document ); + return _document; + } + /// Get the XMLDocument that owns this XMLNode. + XMLDocument* GetDocument() { + TIXMLASSERT( _document ); + return _document; + } + + /// Safely cast to an Element, or null. + virtual XMLElement* ToElement() { + return 0; + } + /// Safely cast to Text, or null. + virtual XMLText* ToText() { + return 0; + } + /// Safely cast to a Comment, or null. + virtual XMLComment* ToComment() { + return 0; + } + /// Safely cast to a Document, or null. + virtual XMLDocument* ToDocument() { + return 0; + } + /// Safely cast to a Declaration, or null. + virtual XMLDeclaration* ToDeclaration() { + return 0; + } + /// Safely cast to an Unknown, or null. + virtual XMLUnknown* ToUnknown() { + return 0; + } + + virtual const XMLElement* ToElement() const { + return 0; + } + virtual const XMLText* ToText() const { + return 0; + } + virtual const XMLComment* ToComment() const { + return 0; + } + virtual const XMLDocument* ToDocument() const { + return 0; + } + virtual const XMLDeclaration* ToDeclaration() const { + return 0; + } + virtual const XMLUnknown* ToUnknown() const { + return 0; + } + + /** The meaning of 'value' changes for the specific type. + @verbatim + Document: empty (NULL is returned, not an empty string) + Element: name of the element + Comment: the comment text + Unknown: the tag contents + Text: the text string + @endverbatim + */ + const char* Value() const; + + /** Set the Value of an XML node. + @sa Value() + */ + void SetValue( const char* val, bool staticMem=false ); + + /// Get the parent of this node on the DOM. + const XMLNode* Parent() const { + return _parent; + } + + XMLNode* Parent() { + return _parent; + } + + /// Returns true if this node has no children. + bool NoChildren() const { + return !_firstChild; + } + + /// Get the first child node, or null if none exists. + const XMLNode* FirstChild() const { + return _firstChild; + } + + XMLNode* FirstChild() { + return _firstChild; + } + + /** Get the first child element, or optionally the first child + element with the specified name. + */ + const XMLElement* FirstChildElement( const char* name = 0 ) const; + + XMLElement* FirstChildElement( const char* name = 0 ) { + return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->FirstChildElement( name )); + } + + /// Get the last child node, or null if none exists. + const XMLNode* LastChild() const { + return _lastChild; + } + + XMLNode* LastChild() { + return _lastChild; + } + + /** Get the last child element or optionally the last child + element with the specified name. + */ + const XMLElement* LastChildElement( const char* name = 0 ) const; + + XMLElement* LastChildElement( const char* name = 0 ) { + return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->LastChildElement(name) ); + } + + /// Get the previous (left) sibling node of this node. + const XMLNode* PreviousSibling() const { + return _prev; + } + + XMLNode* PreviousSibling() { + return _prev; + } + + /// Get the previous (left) sibling element of this node, with an optionally supplied name. + const XMLElement* PreviousSiblingElement( const char* name = 0 ) const ; + + XMLElement* PreviousSiblingElement( const char* name = 0 ) { + return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->PreviousSiblingElement( name ) ); + } + + /// Get the next (right) sibling node of this node. + const XMLNode* NextSibling() const { + return _next; + } + + XMLNode* NextSibling() { + return _next; + } + + /// Get the next (right) sibling element of this node, with an optionally supplied name. + const XMLElement* NextSiblingElement( const char* name = 0 ) const; + + XMLElement* NextSiblingElement( const char* name = 0 ) { + return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->NextSiblingElement( name ) ); + } + + /** + Add a child node as the last (right) child. + If the child node is already part of the document, + it is moved from its old location to the new location. + Returns the addThis argument or 0 if the node does not + belong to the same document. + */ + XMLNode* InsertEndChild( XMLNode* addThis ); + + XMLNode* LinkEndChild( XMLNode* addThis ) { + return InsertEndChild( addThis ); + } + /** + Add a child node as the first (left) child. + If the child node is already part of the document, + it is moved from its old location to the new location. + Returns the addThis argument or 0 if the node does not + belong to the same document. + */ + XMLNode* InsertFirstChild( XMLNode* addThis ); + /** + Add a node after the specified child node. + If the child node is already part of the document, + it is moved from its old location to the new location. + Returns the addThis argument or 0 if the afterThis node + is not a child of this node, or if the node does not + belong to the same document. + */ + XMLNode* InsertAfterChild( XMLNode* afterThis, XMLNode* addThis ); + + /** + Delete all the children of this node. + */ + void DeleteChildren(); + + /** + Delete a child of this node. + */ + void DeleteChild( XMLNode* node ); + + /** + Make a copy of this node, but not its children. + You may pass in a Document pointer that will be + the owner of the new Node. If the 'document' is + null, then the node returned will be allocated + from the current Document. (this->GetDocument()) + + Note: if called on a XMLDocument, this will return null. + */ + virtual XMLNode* ShallowClone( XMLDocument* document ) const = 0; + + /** + Test if 2 nodes are the same, but don't test children. + The 2 nodes do not need to be in the same Document. + + Note: if called on a XMLDocument, this will return false. + */ + virtual bool ShallowEqual( const XMLNode* compare ) const = 0; + + /** Accept a hierarchical visit of the nodes in the TinyXML-2 DOM. Every node in the + XML tree will be conditionally visited and the host will be called back + via the XMLVisitor interface. + + This is essentially a SAX interface for TinyXML-2. (Note however it doesn't re-parse + the XML for the callbacks, so the performance of TinyXML-2 is unchanged by using this + interface versus any other.) + + The interface has been based on ideas from: + + - http://www.saxproject.org/ + - http://c2.com/cgi/wiki?HierarchicalVisitorPattern + + Which are both good references for "visiting". + + An example of using Accept(): + @verbatim + XMLPrinter printer; + tinyxmlDoc.Accept( &printer ); + const char* xmlcstr = printer.CStr(); + @endverbatim + */ + virtual bool Accept( XMLVisitor* visitor ) const = 0; + +protected: + XMLNode( XMLDocument* ); + virtual ~XMLNode(); + + virtual char* ParseDeep( char*, StrPair* ); + + XMLDocument* _document; + XMLNode* _parent; + mutable StrPair _value; + + XMLNode* _firstChild; + XMLNode* _lastChild; + + XMLNode* _prev; + XMLNode* _next; + +private: + MemPool* _memPool; + void Unlink( XMLNode* child ); + static void DeleteNode( XMLNode* node ); + void InsertChildPreamble( XMLNode* insertThis ) const; + + XMLNode( const XMLNode& ); // not supported + XMLNode& operator=( const XMLNode& ); // not supported +}; + + +/** XML text. + + Note that a text node can have child element nodes, for example: + @verbatim + <root>This is <b>bold</b></root> + @endverbatim + + A text node can have 2 ways to output the next. "normal" output + and CDATA. It will default to the mode it was parsed from the XML file and + you generally want to leave it alone, but you can change the output mode with + SetCData() and query it with CData(). +*/ +class TINYXML2_LIB XMLText : public XMLNode +{ + friend class XMLBase; + friend class XMLDocument; +public: + virtual bool Accept( XMLVisitor* visitor ) const; + + virtual XMLText* ToText() { + return this; + } + virtual const XMLText* ToText() const { + return this; + } + + /// Declare whether this should be CDATA or standard text. + void SetCData( bool isCData ) { + _isCData = isCData; + } + /// Returns true if this is a CDATA text element. + bool CData() const { + return _isCData; + } + + virtual XMLNode* ShallowClone( XMLDocument* document ) const; + virtual bool ShallowEqual( const XMLNode* compare ) const; + +protected: + XMLText( XMLDocument* doc ) : XMLNode( doc ), _isCData( false ) {} + virtual ~XMLText() {} + + char* ParseDeep( char*, StrPair* endTag ); + +private: + bool _isCData; + + XMLText( const XMLText& ); // not supported + XMLText& operator=( const XMLText& ); // not supported +}; + + +/** An XML Comment. */ +class TINYXML2_LIB XMLComment : public XMLNode +{ + friend class XMLDocument; +public: + virtual XMLComment* ToComment() { + return this; + } + virtual const XMLComment* ToComment() const { + return this; + } + + virtual bool Accept( XMLVisitor* visitor ) const; + + virtual XMLNode* ShallowClone( XMLDocument* document ) const; + virtual bool ShallowEqual( const XMLNode* compare ) const; + +protected: + XMLComment( XMLDocument* doc ); + virtual ~XMLComment(); + + char* ParseDeep( char*, StrPair* endTag ); + +private: + XMLComment( const XMLComment& ); // not supported + XMLComment& operator=( const XMLComment& ); // not supported +}; + + +/** In correct XML the declaration is the first entry in the file. + @verbatim + <?xml version="1.0" standalone="yes"?> + @endverbatim + + TinyXML-2 will happily read or write files without a declaration, + however. + + The text of the declaration isn't interpreted. It is parsed + and written as a string. +*/ +class TINYXML2_LIB XMLDeclaration : public XMLNode +{ + friend class XMLDocument; +public: + virtual XMLDeclaration* ToDeclaration() { + return this; + } + virtual const XMLDeclaration* ToDeclaration() const { + return this; + } + + virtual bool Accept( XMLVisitor* visitor ) const; + + virtual XMLNode* ShallowClone( XMLDocument* document ) const; + virtual bool ShallowEqual( const XMLNode* compare ) const; + +protected: + XMLDeclaration( XMLDocument* doc ); + virtual ~XMLDeclaration(); + + char* ParseDeep( char*, StrPair* endTag ); + +private: + XMLDeclaration( const XMLDeclaration& ); // not supported + XMLDeclaration& operator=( const XMLDeclaration& ); // not supported +}; + + +/** Any tag that TinyXML-2 doesn't recognize is saved as an + unknown. It is a tag of text, but should not be modified. + It will be written back to the XML, unchanged, when the file + is saved. + + DTD tags get thrown into XMLUnknowns. +*/ +class TINYXML2_LIB XMLUnknown : public XMLNode +{ + friend class XMLDocument; +public: + virtual XMLUnknown* ToUnknown() { + return this; + } + virtual const XMLUnknown* ToUnknown() const { + return this; + } + + virtual bool Accept( XMLVisitor* visitor ) const; + + virtual XMLNode* ShallowClone( XMLDocument* document ) const; + virtual bool ShallowEqual( const XMLNode* compare ) const; + +protected: + XMLUnknown( XMLDocument* doc ); + virtual ~XMLUnknown(); + + char* ParseDeep( char*, StrPair* endTag ); + +private: + XMLUnknown( const XMLUnknown& ); // not supported + XMLUnknown& operator=( const XMLUnknown& ); // not supported +}; + + + +/** An attribute is a name-value pair. Elements have an arbitrary + number of attributes, each with a unique name. + + @note The attributes are not XMLNodes. You may only query the + Next() attribute in a list. +*/ +class TINYXML2_LIB XMLAttribute +{ + friend class XMLElement; +public: + /// The name of the attribute. + const char* Name() const; + + /// The value of the attribute. + const char* Value() const; + + /// The next attribute in the list. + const XMLAttribute* Next() const { + return _next; + } + + /** IntValue interprets the attribute as an integer, and returns the value. + If the value isn't an integer, 0 will be returned. There is no error checking; + use QueryIntValue() if you need error checking. + */ + int IntValue() const { + int i=0; + QueryIntValue( &i ); + return i; + } + /// Query as an unsigned integer. See IntValue() + unsigned UnsignedValue() const { + unsigned i=0; + QueryUnsignedValue( &i ); + return i; + } + /// Query as a boolean. See IntValue() + bool BoolValue() const { + bool b=false; + QueryBoolValue( &b ); + return b; + } + /// Query as a double. See IntValue() + double DoubleValue() const { + double d=0; + QueryDoubleValue( &d ); + return d; + } + /// Query as a float. See IntValue() + float FloatValue() const { + float f=0; + QueryFloatValue( &f ); + return f; + } + + /** QueryIntValue interprets the attribute as an integer, and returns the value + in the provided parameter. The function will return XML_NO_ERROR on success, + and XML_WRONG_ATTRIBUTE_TYPE if the conversion is not successful. + */ + XMLError QueryIntValue( int* value ) const; + /// See QueryIntValue + XMLError QueryUnsignedValue( unsigned int* value ) const; + /// See QueryIntValue + XMLError QueryBoolValue( bool* value ) const; + /// See QueryIntValue + XMLError QueryDoubleValue( double* value ) const; + /// See QueryIntValue + XMLError QueryFloatValue( float* value ) const; + + /// Set the attribute to a string value. + void SetAttribute( const char* value ); + /// Set the attribute to value. + void SetAttribute( int value ); + /// Set the attribute to value. + void SetAttribute( unsigned value ); + /// Set the attribute to value. + void SetAttribute( bool value ); + /// Set the attribute to value. + void SetAttribute( double value ); + /// Set the attribute to value. + void SetAttribute( float value ); + +private: + enum { BUF_SIZE = 200 }; + + XMLAttribute() : _next( 0 ), _memPool( 0 ) {} + virtual ~XMLAttribute() {} + + XMLAttribute( const XMLAttribute& ); // not supported + void operator=( const XMLAttribute& ); // not supported + void SetName( const char* name ); + + char* ParseDeep( char* p, bool processEntities ); + + mutable StrPair _name; + mutable StrPair _value; + XMLAttribute* _next; + MemPool* _memPool; +}; + + +/** The element is a container class. It has a value, the element name, + and can contain other elements, text, comments, and unknowns. + Elements also contain an arbitrary number of attributes. +*/ +class TINYXML2_LIB XMLElement : public XMLNode +{ + friend class XMLBase; + friend class XMLDocument; +public: + /// Get the name of an element (which is the Value() of the node.) + const char* Name() const { + return Value(); + } + /// Set the name of the element. + void SetName( const char* str, bool staticMem=false ) { + SetValue( str, staticMem ); + } + + virtual XMLElement* ToElement() { + return this; + } + virtual const XMLElement* ToElement() const { + return this; + } + virtual bool Accept( XMLVisitor* visitor ) const; + + /** Given an attribute name, Attribute() returns the value + for the attribute of that name, or null if none + exists. For example: + + @verbatim + const char* value = ele->Attribute( "foo" ); + @endverbatim + + The 'value' parameter is normally null. However, if specified, + the attribute will only be returned if the 'name' and 'value' + match. This allow you to write code: + + @verbatim + if ( ele->Attribute( "foo", "bar" ) ) callFooIsBar(); + @endverbatim + + rather than: + @verbatim + if ( ele->Attribute( "foo" ) ) { + if ( strcmp( ele->Attribute( "foo" ), "bar" ) == 0 ) callFooIsBar(); + } + @endverbatim + */ + const char* Attribute( const char* name, const char* value=0 ) const; + + /** Given an attribute name, IntAttribute() returns the value + of the attribute interpreted as an integer. 0 will be + returned if there is an error. For a method with error + checking, see QueryIntAttribute() + */ + int IntAttribute( const char* name ) const { + int i=0; + QueryIntAttribute( name, &i ); + return i; + } + /// See IntAttribute() + unsigned UnsignedAttribute( const char* name ) const { + unsigned i=0; + QueryUnsignedAttribute( name, &i ); + return i; + } + /// See IntAttribute() + bool BoolAttribute( const char* name ) const { + bool b=false; + QueryBoolAttribute( name, &b ); + return b; + } + /// See IntAttribute() + double DoubleAttribute( const char* name ) const { + double d=0; + QueryDoubleAttribute( name, &d ); + return d; + } + /// See IntAttribute() + float FloatAttribute( const char* name ) const { + float f=0; + QueryFloatAttribute( name, &f ); + return f; + } + + /** Given an attribute name, QueryIntAttribute() returns + XML_NO_ERROR, XML_WRONG_ATTRIBUTE_TYPE if the conversion + can't be performed, or XML_NO_ATTRIBUTE if the attribute + doesn't exist. If successful, the result of the conversion + will be written to 'value'. If not successful, nothing will + be written to 'value'. This allows you to provide default + value: + + @verbatim + int value = 10; + QueryIntAttribute( "foo", &value ); // if "foo" isn't found, value will still be 10 + @endverbatim + */ + XMLError QueryIntAttribute( const char* name, int* value ) const { + const XMLAttribute* a = FindAttribute( name ); + if ( !a ) { + return XML_NO_ATTRIBUTE; + } + return a->QueryIntValue( value ); + } + /// See QueryIntAttribute() + XMLError QueryUnsignedAttribute( const char* name, unsigned int* value ) const { + const XMLAttribute* a = FindAttribute( name ); + if ( !a ) { + return XML_NO_ATTRIBUTE; + } + return a->QueryUnsignedValue( value ); + } + /// See QueryIntAttribute() + XMLError QueryBoolAttribute( const char* name, bool* value ) const { + const XMLAttribute* a = FindAttribute( name ); + if ( !a ) { + return XML_NO_ATTRIBUTE; + } + return a->QueryBoolValue( value ); + } + /// See QueryIntAttribute() + XMLError QueryDoubleAttribute( const char* name, double* value ) const { + const XMLAttribute* a = FindAttribute( name ); + if ( !a ) { + return XML_NO_ATTRIBUTE; + } + return a->QueryDoubleValue( value ); + } + /// See QueryIntAttribute() + XMLError QueryFloatAttribute( const char* name, float* value ) const { + const XMLAttribute* a = FindAttribute( name ); + if ( !a ) { + return XML_NO_ATTRIBUTE; + } + return a->QueryFloatValue( value ); + } + + + /** Given an attribute name, QueryAttribute() returns + XML_NO_ERROR, XML_WRONG_ATTRIBUTE_TYPE if the conversion + can't be performed, or XML_NO_ATTRIBUTE if the attribute + doesn't exist. It is overloaded for the primitive types, + and is a generally more convenient replacement of + QueryIntAttribute() and related functions. + + If successful, the result of the conversion + will be written to 'value'. If not successful, nothing will + be written to 'value'. This allows you to provide default + value: + + @verbatim + int value = 10; + QueryAttribute( "foo", &value ); // if "foo" isn't found, value will still be 10 + @endverbatim + */ + int QueryAttribute( const char* name, int* value ) const { + return QueryIntAttribute( name, value ); + } + + int QueryAttribute( const char* name, unsigned int* value ) const { + return QueryUnsignedAttribute( name, value ); + } + + int QueryAttribute( const char* name, bool* value ) const { + return QueryBoolAttribute( name, value ); + } + + int QueryAttribute( const char* name, double* value ) const { + return QueryDoubleAttribute( name, value ); + } + + int QueryAttribute( const char* name, float* value ) const { + return QueryFloatAttribute( name, value ); + } + + /// Sets the named attribute to value. + void SetAttribute( const char* name, const char* value ) { + XMLAttribute* a = FindOrCreateAttribute( name ); + a->SetAttribute( value ); + } + /// Sets the named attribute to value. + void SetAttribute( const char* name, int value ) { + XMLAttribute* a = FindOrCreateAttribute( name ); + a->SetAttribute( value ); + } + /// Sets the named attribute to value. + void SetAttribute( const char* name, unsigned value ) { + XMLAttribute* a = FindOrCreateAttribute( name ); + a->SetAttribute( value ); + } + /// Sets the named attribute to value. + void SetAttribute( const char* name, bool value ) { + XMLAttribute* a = FindOrCreateAttribute( name ); + a->SetAttribute( value ); + } + /// Sets the named attribute to value. + void SetAttribute( const char* name, double value ) { + XMLAttribute* a = FindOrCreateAttribute( name ); + a->SetAttribute( value ); + } + /// Sets the named attribute to value. + void SetAttribute( const char* name, float value ) { + XMLAttribute* a = FindOrCreateAttribute( name ); + a->SetAttribute( value ); + } + + /** + Delete an attribute. + */ + void DeleteAttribute( const char* name ); + + /// Return the first attribute in the list. + const XMLAttribute* FirstAttribute() const { + return _rootAttribute; + } + /// Query a specific attribute in the list. + const XMLAttribute* FindAttribute( const char* name ) const; + + /** Convenience function for easy access to the text inside an element. Although easy + and concise, GetText() is limited compared to getting the XMLText child + and accessing it directly. + + If the first child of 'this' is a XMLText, the GetText() + returns the character string of the Text node, else null is returned. + + This is a convenient method for getting the text of simple contained text: + @verbatim + <foo>This is text</foo> + const char* str = fooElement->GetText(); + @endverbatim + + 'str' will be a pointer to "This is text". + + Note that this function can be misleading. If the element foo was created from + this XML: + @verbatim + <foo><b>This is text</b></foo> + @endverbatim + + then the value of str would be null. The first child node isn't a text node, it is + another element. From this XML: + @verbatim + <foo>This is <b>text</b></foo> + @endverbatim + GetText() will return "This is ". + */ + const char* GetText() const; + + /** Convenience function for easy access to the text inside an element. Although easy + and concise, SetText() is limited compared to creating an XMLText child + and mutating it directly. + + If the first child of 'this' is a XMLText, SetText() sets its value to + the given string, otherwise it will create a first child that is an XMLText. + + This is a convenient method for setting the text of simple contained text: + @verbatim + <foo>This is text</foo> + fooElement->SetText( "Hullaballoo!" ); + <foo>Hullaballoo!</foo> + @endverbatim + + Note that this function can be misleading. If the element foo was created from + this XML: + @verbatim + <foo><b>This is text</b></foo> + @endverbatim + + then it will not change "This is text", but rather prefix it with a text element: + @verbatim + <foo>Hullaballoo!<b>This is text</b></foo> + @endverbatim + + For this XML: + @verbatim + <foo /> + @endverbatim + SetText() will generate + @verbatim + <foo>Hullaballoo!</foo> + @endverbatim + */ + void SetText( const char* inText ); + /// Convenience method for setting text inside an element. See SetText() for important limitations. + void SetText( int value ); + /// Convenience method for setting text inside an element. See SetText() for important limitations. + void SetText( unsigned value ); + /// Convenience method for setting text inside an element. See SetText() for important limitations. + void SetText( bool value ); + /// Convenience method for setting text inside an element. See SetText() for important limitations. + void SetText( double value ); + /// Convenience method for setting text inside an element. See SetText() for important limitations. + void SetText( float value ); + + /** + Convenience method to query the value of a child text node. This is probably best + shown by example. Given you have a document is this form: + @verbatim + <point> + <x>1</x> + <y>1.4</y> + </point> + @endverbatim + + The QueryIntText() and similar functions provide a safe and easier way to get to the + "value" of x and y. + + @verbatim + int x = 0; + float y = 0; // types of x and y are contrived for example + const XMLElement* xElement = pointElement->FirstChildElement( "x" ); + const XMLElement* yElement = pointElement->FirstChildElement( "y" ); + xElement->QueryIntText( &x ); + yElement->QueryFloatText( &y ); + @endverbatim + + @returns XML_SUCCESS (0) on success, XML_CAN_NOT_CONVERT_TEXT if the text cannot be converted + to the requested type, and XML_NO_TEXT_NODE if there is no child text to query. + + */ + XMLError QueryIntText( int* ival ) const; + /// See QueryIntText() + XMLError QueryUnsignedText( unsigned* uval ) const; + /// See QueryIntText() + XMLError QueryBoolText( bool* bval ) const; + /// See QueryIntText() + XMLError QueryDoubleText( double* dval ) const; + /// See QueryIntText() + XMLError QueryFloatText( float* fval ) const; + + // internal: + enum { + OPEN, // <foo> + CLOSED, // <foo/> + CLOSING // </foo> + }; + int ClosingType() const { + return _closingType; + } + virtual XMLNode* ShallowClone( XMLDocument* document ) const; + virtual bool ShallowEqual( const XMLNode* compare ) const; + +protected: + char* ParseDeep( char* p, StrPair* endTag ); + +private: + XMLElement( XMLDocument* doc ); + virtual ~XMLElement(); + XMLElement( const XMLElement& ); // not supported + void operator=( const XMLElement& ); // not supported + + XMLAttribute* FindAttribute( const char* name ) { + return const_cast<XMLAttribute*>(const_cast<const XMLElement*>(this)->FindAttribute( name )); + } + XMLAttribute* FindOrCreateAttribute( const char* name ); + //void LinkAttribute( XMLAttribute* attrib ); + char* ParseAttributes( char* p ); + static void DeleteAttribute( XMLAttribute* attribute ); + + enum { BUF_SIZE = 200 }; + int _closingType; + // The attribute list is ordered; there is no 'lastAttribute' + // because the list needs to be scanned for dupes before adding + // a new attribute. + XMLAttribute* _rootAttribute; +}; + + +enum Whitespace { + PRESERVE_WHITESPACE, + COLLAPSE_WHITESPACE +}; + + +/** A Document binds together all the functionality. + It can be saved, loaded, and printed to the screen. + All Nodes are connected and allocated to a Document. + If the Document is deleted, all its Nodes are also deleted. +*/ +class TINYXML2_LIB XMLDocument : public XMLNode +{ + friend class XMLElement; +public: + /// constructor + XMLDocument( bool processEntities = true, Whitespace = PRESERVE_WHITESPACE ); + ~XMLDocument(); + + virtual XMLDocument* ToDocument() { + TIXMLASSERT( this == _document ); + return this; + } + virtual const XMLDocument* ToDocument() const { + TIXMLASSERT( this == _document ); + return this; + } + + /** + Parse an XML file from a character string. + Returns XML_NO_ERROR (0) on success, or + an errorID. + + You may optionally pass in the 'nBytes', which is + the number of bytes which will be parsed. If not + specified, TinyXML-2 will assume 'xml' points to a + null terminated string. + */ + XMLError Parse( const char* xml, size_t nBytes=(size_t)(-1) ); + + /** + Load an XML file from disk. + Returns XML_NO_ERROR (0) on success, or + an errorID. + */ + XMLError LoadFile( const char* filename ); + + /** + Load an XML file from disk. You are responsible + for providing and closing the FILE*. + + NOTE: The file should be opened as binary ("rb") + not text in order for TinyXML-2 to correctly + do newline normalization. + + Returns XML_NO_ERROR (0) on success, or + an errorID. + */ + XMLError LoadFile( FILE* ); + + /** + Save the XML file to disk. + Returns XML_NO_ERROR (0) on success, or + an errorID. + */ + XMLError SaveFile( const char* filename, bool compact = false ); + + /** + Save the XML file to disk. You are responsible + for providing and closing the FILE*. + + Returns XML_NO_ERROR (0) on success, or + an errorID. + */ + XMLError SaveFile( FILE* fp, bool compact = false ); + + bool ProcessEntities() const { + return _processEntities; + } + Whitespace WhitespaceMode() const { + return _whitespace; + } + + /** + Returns true if this document has a leading Byte Order Mark of UTF8. + */ + bool HasBOM() const { + return _writeBOM; + } + /** Sets whether to write the BOM when writing the file. + */ + void SetBOM( bool useBOM ) { + _writeBOM = useBOM; + } + + /** Return the root element of DOM. Equivalent to FirstChildElement(). + To get the first node, use FirstChild(). + */ + XMLElement* RootElement() { + return FirstChildElement(); + } + const XMLElement* RootElement() const { + return FirstChildElement(); + } + + /** Print the Document. If the Printer is not provided, it will + print to stdout. If you provide Printer, this can print to a file: + @verbatim + XMLPrinter printer( fp ); + doc.Print( &printer ); + @endverbatim + + Or you can use a printer to print to memory: + @verbatim + XMLPrinter printer; + doc.Print( &printer ); + // printer.CStr() has a const char* to the XML + @endverbatim + */ + void Print( XMLPrinter* streamer=0 ) const; + virtual bool Accept( XMLVisitor* visitor ) const; + + /** + Create a new Element associated with + this Document. The memory for the Element + is managed by the Document. + */ + XMLElement* NewElement( const char* name ); + /** + Create a new Comment associated with + this Document. The memory for the Comment + is managed by the Document. + */ + XMLComment* NewComment( const char* comment ); + /** + Create a new Text associated with + this Document. The memory for the Text + is managed by the Document. + */ + XMLText* NewText( const char* text ); + /** + Create a new Declaration associated with + this Document. The memory for the object + is managed by the Document. + + If the 'text' param is null, the standard + declaration is used.: + @verbatim + <?xml version="1.0" encoding="UTF-8"?> + @endverbatim + */ + XMLDeclaration* NewDeclaration( const char* text=0 ); + /** + Create a new Unknown associated with + this Document. The memory for the object + is managed by the Document. + */ + XMLUnknown* NewUnknown( const char* text ); + + /** + Delete a node associated with this document. + It will be unlinked from the DOM. + */ + void DeleteNode( XMLNode* node ); + + void SetError( XMLError error, const char* str1, const char* str2 ); + + /// Return true if there was an error parsing the document. + bool Error() const { + return _errorID != XML_NO_ERROR; + } + /// Return the errorID. + XMLError ErrorID() const { + return _errorID; + } + const char* ErrorName() const; + + /// Return a possibly helpful diagnostic location or string. + const char* GetErrorStr1() const { + return _errorStr1; + } + /// Return a possibly helpful secondary diagnostic location or string. + const char* GetErrorStr2() const { + return _errorStr2; + } + /// If there is an error, print it to stdout. + void PrintError() const; + + /// Clear the document, resetting it to the initial state. + void Clear(); + + // internal + char* Identify( char* p, XMLNode** node ); + + virtual XMLNode* ShallowClone( XMLDocument* /*document*/ ) const { + return 0; + } + virtual bool ShallowEqual( const XMLNode* /*compare*/ ) const { + return false; + } + +private: + XMLDocument( const XMLDocument& ); // not supported + void operator=( const XMLDocument& ); // not supported + + bool _writeBOM; + bool _processEntities; + XMLError _errorID; + Whitespace _whitespace; + const char* _errorStr1; + const char* _errorStr2; + char* _charBuffer; + + MemPoolT< sizeof(XMLElement) > _elementPool; + MemPoolT< sizeof(XMLAttribute) > _attributePool; + MemPoolT< sizeof(XMLText) > _textPool; + MemPoolT< sizeof(XMLComment) > _commentPool; + + static const char* _errorNames[XML_ERROR_COUNT]; + + void Parse(); +}; + + +/** + A XMLHandle is a class that wraps a node pointer with null checks; this is + an incredibly useful thing. Note that XMLHandle is not part of the TinyXML-2 + DOM structure. It is a separate utility class. + + Take an example: + @verbatim + <Document> + <Element attributeA = "valueA"> + <Child attributeB = "value1" /> + <Child attributeB = "value2" /> + </Element> + </Document> + @endverbatim + + Assuming you want the value of "attributeB" in the 2nd "Child" element, it's very + easy to write a *lot* of code that looks like: + + @verbatim + XMLElement* root = document.FirstChildElement( "Document" ); + if ( root ) + { + XMLElement* element = root->FirstChildElement( "Element" ); + if ( element ) + { + XMLElement* child = element->FirstChildElement( "Child" ); + if ( child ) + { + XMLElement* child2 = child->NextSiblingElement( "Child" ); + if ( child2 ) + { + // Finally do something useful. + @endverbatim + + And that doesn't even cover "else" cases. XMLHandle addresses the verbosity + of such code. A XMLHandle checks for null pointers so it is perfectly safe + and correct to use: + + @verbatim + XMLHandle docHandle( &document ); + XMLElement* child2 = docHandle.FirstChildElement( "Document" ).FirstChildElement( "Element" ).FirstChildElement().NextSiblingElement(); + if ( child2 ) + { + // do something useful + @endverbatim + + Which is MUCH more concise and useful. + + It is also safe to copy handles - internally they are nothing more than node pointers. + @verbatim + XMLHandle handleCopy = handle; + @endverbatim + + See also XMLConstHandle, which is the same as XMLHandle, but operates on const objects. +*/ +class TINYXML2_LIB XMLHandle +{ +public: + /// Create a handle from any node (at any depth of the tree.) This can be a null pointer. + XMLHandle( XMLNode* node ) { + _node = node; + } + /// Create a handle from a node. + XMLHandle( XMLNode& node ) { + _node = &node; + } + /// Copy constructor + XMLHandle( const XMLHandle& ref ) { + _node = ref._node; + } + /// Assignment + XMLHandle& operator=( const XMLHandle& ref ) { + _node = ref._node; + return *this; + } + + /// Get the first child of this handle. + XMLHandle FirstChild() { + return XMLHandle( _node ? _node->FirstChild() : 0 ); + } + /// Get the first child element of this handle. + XMLHandle FirstChildElement( const char* name = 0 ) { + return XMLHandle( _node ? _node->FirstChildElement( name ) : 0 ); + } + /// Get the last child of this handle. + XMLHandle LastChild() { + return XMLHandle( _node ? _node->LastChild() : 0 ); + } + /// Get the last child element of this handle. + XMLHandle LastChildElement( const char* name = 0 ) { + return XMLHandle( _node ? _node->LastChildElement( name ) : 0 ); + } + /// Get the previous sibling of this handle. + XMLHandle PreviousSibling() { + return XMLHandle( _node ? _node->PreviousSibling() : 0 ); + } + /// Get the previous sibling element of this handle. + XMLHandle PreviousSiblingElement( const char* name = 0 ) { + return XMLHandle( _node ? _node->PreviousSiblingElement( name ) : 0 ); + } + /// Get the next sibling of this handle. + XMLHandle NextSibling() { + return XMLHandle( _node ? _node->NextSibling() : 0 ); + } + /// Get the next sibling element of this handle. + XMLHandle NextSiblingElement( const char* name = 0 ) { + return XMLHandle( _node ? _node->NextSiblingElement( name ) : 0 ); + } + + /// Safe cast to XMLNode. This can return null. + XMLNode* ToNode() { + return _node; + } + /// Safe cast to XMLElement. This can return null. + XMLElement* ToElement() { + return ( ( _node == 0 ) ? 0 : _node->ToElement() ); + } + /// Safe cast to XMLText. This can return null. + XMLText* ToText() { + return ( ( _node == 0 ) ? 0 : _node->ToText() ); + } + /// Safe cast to XMLUnknown. This can return null. + XMLUnknown* ToUnknown() { + return ( ( _node == 0 ) ? 0 : _node->ToUnknown() ); + } + /// Safe cast to XMLDeclaration. This can return null. + XMLDeclaration* ToDeclaration() { + return ( ( _node == 0 ) ? 0 : _node->ToDeclaration() ); + } + +private: + XMLNode* _node; +}; + + +/** + A variant of the XMLHandle class for working with const XMLNodes and Documents. It is the + same in all regards, except for the 'const' qualifiers. See XMLHandle for API. +*/ +class TINYXML2_LIB XMLConstHandle +{ +public: + XMLConstHandle( const XMLNode* node ) { + _node = node; + } + XMLConstHandle( const XMLNode& node ) { + _node = &node; + } + XMLConstHandle( const XMLConstHandle& ref ) { + _node = ref._node; + } + + XMLConstHandle& operator=( const XMLConstHandle& ref ) { + _node = ref._node; + return *this; + } + + const XMLConstHandle FirstChild() const { + return XMLConstHandle( _node ? _node->FirstChild() : 0 ); + } + const XMLConstHandle FirstChildElement( const char* name = 0 ) const { + return XMLConstHandle( _node ? _node->FirstChildElement( name ) : 0 ); + } + const XMLConstHandle LastChild() const { + return XMLConstHandle( _node ? _node->LastChild() : 0 ); + } + const XMLConstHandle LastChildElement( const char* name = 0 ) const { + return XMLConstHandle( _node ? _node->LastChildElement( name ) : 0 ); + } + const XMLConstHandle PreviousSibling() const { + return XMLConstHandle( _node ? _node->PreviousSibling() : 0 ); + } + const XMLConstHandle PreviousSiblingElement( const char* name = 0 ) const { + return XMLConstHandle( _node ? _node->PreviousSiblingElement( name ) : 0 ); + } + const XMLConstHandle NextSibling() const { + return XMLConstHandle( _node ? _node->NextSibling() : 0 ); + } + const XMLConstHandle NextSiblingElement( const char* name = 0 ) const { + return XMLConstHandle( _node ? _node->NextSiblingElement( name ) : 0 ); + } + + + const XMLNode* ToNode() const { + return _node; + } + const XMLElement* ToElement() const { + return ( ( _node == 0 ) ? 0 : _node->ToElement() ); + } + const XMLText* ToText() const { + return ( ( _node == 0 ) ? 0 : _node->ToText() ); + } + const XMLUnknown* ToUnknown() const { + return ( ( _node == 0 ) ? 0 : _node->ToUnknown() ); + } + const XMLDeclaration* ToDeclaration() const { + return ( ( _node == 0 ) ? 0 : _node->ToDeclaration() ); + } + +private: + const XMLNode* _node; +}; + + +/** + Printing functionality. The XMLPrinter gives you more + options than the XMLDocument::Print() method. + + It can: + -# Print to memory. + -# Print to a file you provide. + -# Print XML without a XMLDocument. + + Print to Memory + + @verbatim + XMLPrinter printer; + doc.Print( &printer ); + SomeFunction( printer.CStr() ); + @endverbatim + + Print to a File + + You provide the file pointer. + @verbatim + XMLPrinter printer( fp ); + doc.Print( &printer ); + @endverbatim + + Print without a XMLDocument + + When loading, an XML parser is very useful. However, sometimes + when saving, it just gets in the way. The code is often set up + for streaming, and constructing the DOM is just overhead. + + The Printer supports the streaming case. The following code + prints out a trivially simple XML file without ever creating + an XML document. + + @verbatim + XMLPrinter printer( fp ); + printer.OpenElement( "foo" ); + printer.PushAttribute( "foo", "bar" ); + printer.CloseElement(); + @endverbatim +*/ +class TINYXML2_LIB XMLPrinter : public XMLVisitor +{ +public: + /** Construct the printer. If the FILE* is specified, + this will print to the FILE. Else it will print + to memory, and the result is available in CStr(). + If 'compact' is set to true, then output is created + with only required whitespace and newlines. + */ + XMLPrinter( FILE* file=0, bool compact = false, int depth = 0 ); + virtual ~XMLPrinter() {} + + /** If streaming, write the BOM and declaration. */ + void PushHeader( bool writeBOM, bool writeDeclaration ); + /** If streaming, start writing an element. + The element must be closed with CloseElement() + */ + void OpenElement( const char* name, bool compactMode=false ); + /// If streaming, add an attribute to an open element. + void PushAttribute( const char* name, const char* value ); + void PushAttribute( const char* name, int value ); + void PushAttribute( const char* name, unsigned value ); + void PushAttribute( const char* name, bool value ); + void PushAttribute( const char* name, double value ); + /// If streaming, close the Element. + virtual void CloseElement( bool compactMode=false ); + + /// Add a text node. + void PushText( const char* text, bool cdata=false ); + /// Add a text node from an integer. + void PushText( int value ); + /// Add a text node from an unsigned. + void PushText( unsigned value ); + /// Add a text node from a bool. + void PushText( bool value ); + /// Add a text node from a float. + void PushText( float value ); + /// Add a text node from a double. + void PushText( double value ); + + /// Add a comment + void PushComment( const char* comment ); + + void PushDeclaration( const char* value ); + void PushUnknown( const char* value ); + + virtual bool VisitEnter( const XMLDocument& /*doc*/ ); + virtual bool VisitExit( const XMLDocument& /*doc*/ ) { + return true; + } + + virtual bool VisitEnter( const XMLElement& element, const XMLAttribute* attribute ); + virtual bool VisitExit( const XMLElement& element ); + + virtual bool Visit( const XMLText& text ); + virtual bool Visit( const XMLComment& comment ); + virtual bool Visit( const XMLDeclaration& declaration ); + virtual bool Visit( const XMLUnknown& unknown ); + + /** + If in print to memory mode, return a pointer to + the XML file in memory. + */ + const char* CStr() const { + return _buffer.Mem(); + } + /** + If in print to memory mode, return the size + of the XML file in memory. (Note the size returned + includes the terminating null.) + */ + int CStrSize() const { + return _buffer.Size(); + } + /** + If in print to memory mode, reset the buffer to the + beginning. + */ + void ClearBuffer() { + _buffer.Clear(); + _buffer.Push(0); + } + +protected: + virtual bool CompactMode( const XMLElement& ) { return _compactMode; } + + /** Prints out the space before an element. You may override to change + the space and tabs used. A PrintSpace() override should call Print(). + */ + virtual void PrintSpace( int depth ); + void Print( const char* format, ... ); + + void SealElementIfJustOpened(); + bool _elementJustOpened; + DynArray< const char*, 10 > _stack; + +private: + void PrintString( const char*, bool restrictedEntitySet ); // prints out, after detecting entities. + + bool _firstElement; + FILE* _fp; + int _depth; + int _textDepth; + bool _processEntities; + bool _compactMode; + + enum { + ENTITY_RANGE = 64, + BUF_SIZE = 200 + }; + bool _entityFlag[ENTITY_RANGE]; + bool _restrictedEntityFlag[ENTITY_RANGE]; + + DynArray< char, 20 > _buffer; +}; + + +} // tinyxml2 + +#if defined(_MSC_VER) +# pragma warning(pop) +#endif + +#endif // TINYXML2_INCLUDED diff --git a/lib/FTL.TXT b/lib/FTL.TXT new file mode 100644 index 0000000..bbaba33 --- /dev/null +++ b/lib/FTL.TXT @@ -0,0 +1,169 @@ + The FreeType Project LICENSE + ---------------------------- + + 2006-Jan-27 + + Copyright 1996-2002, 2006 by + David Turner, Robert Wilhelm, and Werner Lemberg + + + +Introduction +============ + + The FreeType Project is distributed in several archive packages; + some of them may contain, in addition to the FreeType font engine, + various tools and contributions which rely on, or relate to, the + FreeType Project. + + This license applies to all files found in such packages, and + which do not fall under their own explicit license. The license + affects thus the FreeType font engine, the test programs, + documentation and makefiles, at the very least. + + This license was inspired by the BSD, Artistic, and IJG + (Independent JPEG Group) licenses, which all encourage inclusion + and use of free software in commercial and freeware products + alike. As a consequence, its main points are that: + + o We don't promise that this software works. However, we will be + interested in any kind of bug reports. (`as is' distribution) + + o You can use this software for whatever you want, in parts or + full form, without having to pay us. (`royalty-free' usage) + + o You may not pretend that you wrote this software. If you use + it, or only parts of it, in a program, you must acknowledge + somewhere in your documentation that you have used the + FreeType code. (`credits') + + We specifically permit and encourage the inclusion of this + software, with or without modifications, in commercial products. + We disclaim all warranties covering The FreeType Project and + assume no liability related to The FreeType Project. + + + Finally, many people asked us for a preferred form for a + credit/disclaimer to use in compliance with this license. We thus + encourage you to use the following text: + + """ + Portions of this software are copyright © <year> The FreeType + Project (www.freetype.org). All rights reserved. + """ + + Please replace <year> with the value from the FreeType version you + actually use. + + +Legal Terms +=========== + +0. Definitions +-------------- + + Throughout this license, the terms `package', `FreeType Project', + and `FreeType archive' refer to the set of files originally + distributed by the authors (David Turner, Robert Wilhelm, and + Werner Lemberg) as the `FreeType Project', be they named as alpha, + beta or final release. + + `You' refers to the licensee, or person using the project, where + `using' is a generic term including compiling the project's source + code as well as linking it to form a `program' or `executable'. + This program is referred to as `a program using the FreeType + engine'. + + This license applies to all files distributed in the original + FreeType Project, including all source code, binaries and + documentation, unless otherwise stated in the file in its + original, unmodified form as distributed in the original archive. + If you are unsure whether or not a particular file is covered by + this license, you must contact us to verify this. + + The FreeType Project is copyright (C) 1996-2000 by David Turner, + Robert Wilhelm, and Werner Lemberg. All rights reserved except as + specified below. + +1. No Warranty +-------------- + + THE FREETYPE PROJECT IS PROVIDED `AS IS' WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE. IN NO EVENT WILL ANY OF THE AUTHORS OR COPYRIGHT HOLDERS + BE LIABLE FOR ANY DAMAGES CAUSED BY THE USE OR THE INABILITY TO + USE, OF THE FREETYPE PROJECT. + +2. Redistribution +----------------- + + This license grants a worldwide, royalty-free, perpetual and + irrevocable right and license to use, execute, perform, compile, + display, copy, create derivative works of, distribute and + sublicense the FreeType Project (in both source and object code + forms) and derivative works thereof for any purpose; and to + authorize others to exercise some or all of the rights granted + herein, subject to the following conditions: + + o Redistribution of source code must retain this license file + (`FTL.TXT') unaltered; any additions, deletions or changes to + the original files must be clearly indicated in accompanying + documentation. The copyright notices of the unaltered, + original files must be preserved in all copies of source + files. + + o Redistribution in binary form must provide a disclaimer that + states that the software is based in part of the work of the + FreeType Team, in the distribution documentation. We also + encourage you to put an URL to the FreeType web page in your + documentation, though this isn't mandatory. + + These conditions apply to any software derived from or based on + the FreeType Project, not just the unmodified files. If you use + our work, you must acknowledge us. However, no fee need be paid + to us. + +3. Advertising +-------------- + + Neither the FreeType authors and contributors nor you shall use + the name of the other for commercial, advertising, or promotional + purposes without specific prior written permission. + + We suggest, but do not require, that you use one or more of the + following phrases to refer to this software in your documentation + or advertising materials: `FreeType Project', `FreeType Engine', + `FreeType library', or `FreeType Distribution'. + + As you have not signed this license, you are not required to + accept it. However, as the FreeType Project is copyrighted + material, only this license, or another one contracted with the + authors, grants you the right to use, distribute, and modify it. + Therefore, by using, distributing, or modifying the FreeType + Project, you indicate that you understand and accept all the terms + of this license. + +4. Contacts +----------- + + There are two mailing lists related to FreeType: + + o freetype@nongnu.org + + Discusses general use and applications of FreeType, as well as + future and wanted additions to the library and distribution. + If you are looking for support, start in this list if you + haven't found anything to help you in the documentation. + + o freetype-devel@nongnu.org + + Discusses bugs, as well as engine internals, design issues, + specific licenses, porting, etc. + + Our home page can be found at + + http://www.freetype.org + + +--- end of FTL.TXT --- diff --git a/lib/freetype.lib b/lib/freetype.lib new file mode 100644 index 0000000000000000000000000000000000000000..983d4ddd749fa4d94ffb973ba5f6159565a3984c GIT binary patch literal 55978 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 H)P(;FsKp?i literal 0 HcmV?d00001 diff --git a/lib/lodepng.cpp b/lib/lodepng.cpp new file mode 100644 index 0000000..7e80f11 --- /dev/null +++ b/lib/lodepng.cpp @@ -0,0 +1,6223 @@ +/* +LodePNG version 20160418 + +Copyright (c) 2005-2016 Lode Vandevenne + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. +*/ + +/* +The manual and changelog are in the header file "lodepng.h" +Rename this file to lodepng.cpp to use it for C++, or to lodepng.c to use it for C. +*/ + +#include "lodepng.h" + +#include <limits.h> +#include <stdio.h> +#include <stdlib.h> + +#if defined(_MSC_VER) && (_MSC_VER >= 1310) /*Visual Studio: A few warning types are not desired here.*/ +#pragma warning( disable : 4244 ) /*implicit conversions: not warned by gcc -Wall -Wextra and requires too much casts*/ +#pragma warning( disable : 4996 ) /*VS does not like fopen, but fopen_s is not standard C so unusable here*/ +#endif /*_MSC_VER */ + +const char* LODEPNG_VERSION_STRING = "20160418"; + +/* +This source file is built up in the following large parts. The code sections +with the "LODEPNG_COMPILE_" #defines divide this up further in an intermixed way. +-Tools for C and common code for PNG and Zlib +-C Code for Zlib (huffman, deflate, ...) +-C Code for PNG (file format chunks, adam7, PNG filters, color conversions, ...) +-The C++ wrapper around all of the above +*/ + +/*The malloc, realloc and free functions defined here with "lodepng_" in front +of the name, so that you can easily change them to others related to your +platform if needed. Everything else in the code calls these. Pass +-DLODEPNG_NO_COMPILE_ALLOCATORS to the compiler, or comment out +#define LODEPNG_COMPILE_ALLOCATORS in the header, to disable the ones here and +define them in your own project's source files without needing to change +lodepng source code. Don't forget to remove "static" if you copypaste them +from here.*/ + +#ifdef LODEPNG_COMPILE_ALLOCATORS +static void* lodepng_malloc(size_t size) +{ + return malloc(size); +} + +static void* lodepng_realloc(void* ptr, size_t new_size) +{ + return realloc(ptr, new_size); +} + +static void lodepng_free(void* ptr) +{ + free(ptr); +} +#else /*LODEPNG_COMPILE_ALLOCATORS*/ +void* lodepng_malloc(size_t size); +void* lodepng_realloc(void* ptr, size_t new_size); +void lodepng_free(void* ptr); +#endif /*LODEPNG_COMPILE_ALLOCATORS*/ + +/* ////////////////////////////////////////////////////////////////////////// */ +/* ////////////////////////////////////////////////////////////////////////// */ +/* // Tools for C, and common code for PNG and Zlib. // */ +/* ////////////////////////////////////////////////////////////////////////// */ +/* ////////////////////////////////////////////////////////////////////////// */ + +/* +Often in case of an error a value is assigned to a variable and then it breaks +out of a loop (to go to the cleanup phase of a function). This macro does that. +It makes the error handling code shorter and more readable. + +Example: if(!uivector_resizev(&frequencies_ll, 286, 0)) ERROR_BREAK(83); +*/ +#define CERROR_BREAK(errorvar, code)\ +{\ + errorvar = code;\ + break;\ +} + +/*version of CERROR_BREAK that assumes the common case where the error variable is named "error"*/ +#define ERROR_BREAK(code) CERROR_BREAK(error, code) + +/*Set error var to the error code, and return it.*/ +#define CERROR_RETURN_ERROR(errorvar, code)\ +{\ + errorvar = code;\ + return code;\ +} + +/*Try the code, if it returns error, also return the error.*/ +#define CERROR_TRY_RETURN(call)\ +{\ + unsigned error = call;\ + if(error) return error;\ +} + +/*Set error var to the error code, and return from the void function.*/ +#define CERROR_RETURN(errorvar, code)\ +{\ + errorvar = code;\ + return;\ +} + +/* +About uivector, ucvector and string: +-All of them wrap dynamic arrays or text strings in a similar way. +-LodePNG was originally written in C++. The vectors replace the std::vectors that were used in the C++ version. +-The string tools are made to avoid problems with compilers that declare things like strncat as deprecated. +-They're not used in the interface, only internally in this file as static functions. +-As with many other structs in this file, the init and cleanup functions serve as ctor and dtor. +*/ + +#ifdef LODEPNG_COMPILE_ZLIB +/*dynamic vector of unsigned ints*/ +typedef struct uivector +{ + unsigned* data; + size_t size; /*size in number of unsigned longs*/ + size_t allocsize; /*allocated size in bytes*/ +} uivector; + +static void uivector_cleanup(void* p) +{ + ((uivector*)p)->size = ((uivector*)p)->allocsize = 0; + lodepng_free(((uivector*)p)->data); + ((uivector*)p)->data = NULL; +} + +/*returns 1 if success, 0 if failure ==> nothing done*/ +static unsigned uivector_reserve(uivector* p, size_t allocsize) +{ + if(allocsize > p->allocsize) + { + size_t newsize = (allocsize > p->allocsize * 2) ? allocsize : (allocsize * 3 / 2); + void* data = lodepng_realloc(p->data, newsize); + if(data) + { + p->allocsize = newsize; + p->data = (unsigned*)data; + } + else return 0; /*error: not enough memory*/ + } + return 1; +} + +/*returns 1 if success, 0 if failure ==> nothing done*/ +static unsigned uivector_resize(uivector* p, size_t size) +{ + if(!uivector_reserve(p, size * sizeof(unsigned))) return 0; + p->size = size; + return 1; /*success*/ +} + +/*resize and give all new elements the value*/ +static unsigned uivector_resizev(uivector* p, size_t size, unsigned value) +{ + size_t oldsize = p->size, i; + if(!uivector_resize(p, size)) return 0; + for(i = oldsize; i < size; ++i) p->data[i] = value; + return 1; +} + +static void uivector_init(uivector* p) +{ + p->data = NULL; + p->size = p->allocsize = 0; +} + +#ifdef LODEPNG_COMPILE_ENCODER +/*returns 1 if success, 0 if failure ==> nothing done*/ +static unsigned uivector_push_back(uivector* p, unsigned c) +{ + if(!uivector_resize(p, p->size + 1)) return 0; + p->data[p->size - 1] = c; + return 1; +} +#endif /*LODEPNG_COMPILE_ENCODER*/ +#endif /*LODEPNG_COMPILE_ZLIB*/ + +/* /////////////////////////////////////////////////////////////////////////// */ + +/*dynamic vector of unsigned chars*/ +typedef struct ucvector +{ + unsigned char* data; + size_t size; /*used size*/ + size_t allocsize; /*allocated size*/ +} ucvector; + +/*returns 1 if success, 0 if failure ==> nothing done*/ +static unsigned ucvector_reserve(ucvector* p, size_t allocsize) +{ + if(allocsize > p->allocsize) + { + size_t newsize = (allocsize > p->allocsize * 2) ? allocsize : (allocsize * 3 / 2); + void* data = lodepng_realloc(p->data, newsize); + if(data) + { + p->allocsize = newsize; + p->data = (unsigned char*)data; + } + else return 0; /*error: not enough memory*/ + } + return 1; +} + +/*returns 1 if success, 0 if failure ==> nothing done*/ +static unsigned ucvector_resize(ucvector* p, size_t size) +{ + if(!ucvector_reserve(p, size * sizeof(unsigned char))) return 0; + p->size = size; + return 1; /*success*/ +} + +#ifdef LODEPNG_COMPILE_PNG + +static void ucvector_cleanup(void* p) +{ + ((ucvector*)p)->size = ((ucvector*)p)->allocsize = 0; + lodepng_free(((ucvector*)p)->data); + ((ucvector*)p)->data = NULL; +} + +static void ucvector_init(ucvector* p) +{ + p->data = NULL; + p->size = p->allocsize = 0; +} +#endif /*LODEPNG_COMPILE_PNG*/ + +#ifdef LODEPNG_COMPILE_ZLIB +/*you can both convert from vector to buffer&size and vica versa. If you use +init_buffer to take over a buffer and size, it is not needed to use cleanup*/ +static void ucvector_init_buffer(ucvector* p, unsigned char* buffer, size_t size) +{ + p->data = buffer; + p->allocsize = p->size = size; +} +#endif /*LODEPNG_COMPILE_ZLIB*/ + +#if (defined(LODEPNG_COMPILE_PNG) && defined(LODEPNG_COMPILE_ANCILLARY_CHUNKS)) || defined(LODEPNG_COMPILE_ENCODER) +/*returns 1 if success, 0 if failure ==> nothing done*/ +static unsigned ucvector_push_back(ucvector* p, unsigned char c) +{ + if(!ucvector_resize(p, p->size + 1)) return 0; + p->data[p->size - 1] = c; + return 1; +} +#endif /*defined(LODEPNG_COMPILE_PNG) || defined(LODEPNG_COMPILE_ENCODER)*/ + + +/* ////////////////////////////////////////////////////////////////////////// */ + +#ifdef LODEPNG_COMPILE_PNG +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS +/*returns 1 if success, 0 if failure ==> nothing done*/ +static unsigned string_resize(char** out, size_t size) +{ + char* data = (char*)lodepng_realloc(*out, size + 1); + if(data) + { + data[size] = 0; /*null termination char*/ + *out = data; + } + return data != 0; +} + +/*init a {char*, size_t} pair for use as string*/ +static void string_init(char** out) +{ + *out = NULL; + string_resize(out, 0); +} + +/*free the above pair again*/ +static void string_cleanup(char** out) +{ + lodepng_free(*out); + *out = NULL; +} + +static void string_set(char** out, const char* in) +{ + size_t insize = strlen(in), i; + if(string_resize(out, insize)) + { + for(i = 0; i != insize; ++i) + { + (*out)[i] = in[i]; + } + } +} +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ +#endif /*LODEPNG_COMPILE_PNG*/ + +/* ////////////////////////////////////////////////////////////////////////// */ + +unsigned lodepng_read32bitInt(const unsigned char* buffer) +{ + return (unsigned)((buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3]); +} + +#if defined(LODEPNG_COMPILE_PNG) || defined(LODEPNG_COMPILE_ENCODER) +/*buffer must have at least 4 allocated bytes available*/ +static void lodepng_set32bitInt(unsigned char* buffer, unsigned value) +{ + buffer[0] = (unsigned char)((value >> 24) & 0xff); + buffer[1] = (unsigned char)((value >> 16) & 0xff); + buffer[2] = (unsigned char)((value >> 8) & 0xff); + buffer[3] = (unsigned char)((value ) & 0xff); +} +#endif /*defined(LODEPNG_COMPILE_PNG) || defined(LODEPNG_COMPILE_ENCODER)*/ + +#ifdef LODEPNG_COMPILE_ENCODER +static void lodepng_add32bitInt(ucvector* buffer, unsigned value) +{ + ucvector_resize(buffer, buffer->size + 4); /*todo: give error if resize failed*/ + lodepng_set32bitInt(&buffer->data[buffer->size - 4], value); +} +#endif /*LODEPNG_COMPILE_ENCODER*/ + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / File IO / */ +/* ////////////////////////////////////////////////////////////////////////// */ + +#ifdef LODEPNG_COMPILE_DISK + +/* returns negative value on error. This should be pure C compatible, so no fstat. */ +static long lodepng_filesize(const char* filename) +{ + FILE* file; + long size; + file = fopen(filename, "rb"); + if(!file) return -1; + + if(fseek(file, 0, SEEK_END) != 0) + { + fclose(file); + return -1; + } + + size = ftell(file); + /* It may give LONG_MAX as directory size, this is invalid for us. */ + if(size == LONG_MAX) size = -1; + + fclose(file); + return size; +} + +/* load file into buffer that already has the correct allocated size. Returns error code.*/ +static unsigned lodepng_buffer_file(unsigned char* out, size_t size, const char* filename) +{ + FILE* file; + size_t readsize; + file = fopen(filename, "rb"); + if(!file) return 78; + + readsize = fread(out, 1, size, file); + fclose(file); + + if (readsize != size) return 78; + return 0; +} + +unsigned lodepng_load_file(unsigned char** out, size_t* outsize, const char* filename) +{ + long size = lodepng_filesize(filename); + if (size < 0) return 78; + *outsize = (size_t)size; + + *out = (unsigned char*)lodepng_malloc((size_t)size); + if(!(*out) && size > 0) return 83; /*the above malloc failed*/ + + return lodepng_buffer_file(*out, (size_t)size, filename); +} + +/*write given buffer to the file, overwriting the file, it doesn't append to it.*/ +unsigned lodepng_save_file(const unsigned char* buffer, size_t buffersize, const char* filename) +{ + FILE* file; + file = fopen(filename, "wb" ); + if(!file) return 79; + fwrite((char*)buffer , 1 , buffersize, file); + fclose(file); + return 0; +} + +#endif /*LODEPNG_COMPILE_DISK*/ + +/* ////////////////////////////////////////////////////////////////////////// */ +/* ////////////////////////////////////////////////////////////////////////// */ +/* // End of common code and tools. Begin of Zlib related code. // */ +/* ////////////////////////////////////////////////////////////////////////// */ +/* ////////////////////////////////////////////////////////////////////////// */ + +#ifdef LODEPNG_COMPILE_ZLIB +#ifdef LODEPNG_COMPILE_ENCODER +/*TODO: this ignores potential out of memory errors*/ +#define addBitToStream(/*size_t**/ bitpointer, /*ucvector**/ bitstream, /*unsigned char*/ bit)\ +{\ + /*add a new byte at the end*/\ + if(((*bitpointer) & 7) == 0) ucvector_push_back(bitstream, (unsigned char)0);\ + /*earlier bit of huffman code is in a lesser significant bit of an earlier byte*/\ + (bitstream->data[bitstream->size - 1]) |= (bit << ((*bitpointer) & 0x7));\ + ++(*bitpointer);\ +} + +static void addBitsToStream(size_t* bitpointer, ucvector* bitstream, unsigned value, size_t nbits) +{ + size_t i; + for(i = 0; i != nbits; ++i) addBitToStream(bitpointer, bitstream, (unsigned char)((value >> i) & 1)); +} + +static void addBitsToStreamReversed(size_t* bitpointer, ucvector* bitstream, unsigned value, size_t nbits) +{ + size_t i; + for(i = 0; i != nbits; ++i) addBitToStream(bitpointer, bitstream, (unsigned char)((value >> (nbits - 1 - i)) & 1)); +} +#endif /*LODEPNG_COMPILE_ENCODER*/ + +#ifdef LODEPNG_COMPILE_DECODER + +#define READBIT(bitpointer, bitstream) ((bitstream[bitpointer >> 3] >> (bitpointer & 0x7)) & (unsigned char)1) + +static unsigned char readBitFromStream(size_t* bitpointer, const unsigned char* bitstream) +{ + unsigned char result = (unsigned char)(READBIT(*bitpointer, bitstream)); + ++(*bitpointer); + return result; +} + +static unsigned readBitsFromStream(size_t* bitpointer, const unsigned char* bitstream, size_t nbits) +{ + unsigned result = 0, i; + for(i = 0; i != nbits; ++i) + { + result += ((unsigned)READBIT(*bitpointer, bitstream)) << i; + ++(*bitpointer); + } + return result; +} +#endif /*LODEPNG_COMPILE_DECODER*/ + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / Deflate - Huffman / */ +/* ////////////////////////////////////////////////////////////////////////// */ + +#define FIRST_LENGTH_CODE_INDEX 257 +#define LAST_LENGTH_CODE_INDEX 285 +/*256 literals, the end code, some length codes, and 2 unused codes*/ +#define NUM_DEFLATE_CODE_SYMBOLS 288 +/*the distance codes have their own symbols, 30 used, 2 unused*/ +#define NUM_DISTANCE_SYMBOLS 32 +/*the code length codes. 0-15: code lengths, 16: copy previous 3-6 times, 17: 3-10 zeros, 18: 11-138 zeros*/ +#define NUM_CODE_LENGTH_CODES 19 + +/*the base lengths represented by codes 257-285*/ +static const unsigned LENGTHBASE[29] + = {3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, + 67, 83, 99, 115, 131, 163, 195, 227, 258}; + +/*the extra bits used by codes 257-285 (added to base length)*/ +static const unsigned LENGTHEXTRA[29] + = {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, + 4, 4, 4, 4, 5, 5, 5, 5, 0}; + +/*the base backwards distances (the bits of distance codes appear after length codes and use their own huffman tree)*/ +static const unsigned DISTANCEBASE[30] + = {1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, + 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577}; + +/*the extra bits of backwards distances (added to base)*/ +static const unsigned DISTANCEEXTRA[30] + = {0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, + 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13}; + +/*the order in which "code length alphabet code lengths" are stored, out of this +the huffman tree of the dynamic huffman tree lengths is generated*/ +static const unsigned CLCL_ORDER[NUM_CODE_LENGTH_CODES] + = {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + +/* ////////////////////////////////////////////////////////////////////////// */ + +/* +Huffman tree struct, containing multiple representations of the tree +*/ +typedef struct HuffmanTree +{ + unsigned* tree2d; + unsigned* tree1d; + unsigned* lengths; /*the lengths of the codes of the 1d-tree*/ + unsigned maxbitlen; /*maximum number of bits a single code can get*/ + unsigned numcodes; /*number of symbols in the alphabet = number of codes*/ +} HuffmanTree; + +/*function used for debug purposes to draw the tree in ascii art with C++*/ +/* +static void HuffmanTree_draw(HuffmanTree* tree) +{ + std::cout << "tree. length: " << tree->numcodes << " maxbitlen: " << tree->maxbitlen << std::endl; + for(size_t i = 0; i != tree->tree1d.size; ++i) + { + if(tree->lengths.data[i]) + std::cout << i << " " << tree->tree1d.data[i] << " " << tree->lengths.data[i] << std::endl; + } + std::cout << std::endl; +}*/ + +static void HuffmanTree_init(HuffmanTree* tree) +{ + tree->tree2d = 0; + tree->tree1d = 0; + tree->lengths = 0; +} + +static void HuffmanTree_cleanup(HuffmanTree* tree) +{ + lodepng_free(tree->tree2d); + lodepng_free(tree->tree1d); + lodepng_free(tree->lengths); +} + +/*the tree representation used by the decoder. return value is error*/ +static unsigned HuffmanTree_make2DTree(HuffmanTree* tree) +{ + unsigned nodefilled = 0; /*up to which node it is filled*/ + unsigned treepos = 0; /*position in the tree (1 of the numcodes columns)*/ + unsigned n, i; + + tree->tree2d = (unsigned*)lodepng_malloc(tree->numcodes * 2 * sizeof(unsigned)); + if(!tree->tree2d) return 83; /*alloc fail*/ + + /* + convert tree1d[] to tree2d[][]. In the 2D array, a value of 32767 means + uninited, a value >= numcodes is an address to another bit, a value < numcodes + is a code. The 2 rows are the 2 possible bit values (0 or 1), there are as + many columns as codes - 1. + A good huffman tree has N * 2 - 1 nodes, of which N - 1 are internal nodes. + Here, the internal nodes are stored (what their 0 and 1 option point to). + There is only memory for such good tree currently, if there are more nodes + (due to too long length codes), error 55 will happen + */ + for(n = 0; n < tree->numcodes * 2; ++n) + { + tree->tree2d[n] = 32767; /*32767 here means the tree2d isn't filled there yet*/ + } + + for(n = 0; n < tree->numcodes; ++n) /*the codes*/ + { + for(i = 0; i != tree->lengths[n]; ++i) /*the bits for this code*/ + { + unsigned char bit = (unsigned char)((tree->tree1d[n] >> (tree->lengths[n] - i - 1)) & 1); + /*oversubscribed, see comment in lodepng_error_text*/ + if(treepos > 2147483647 || treepos + 2 > tree->numcodes) return 55; + if(tree->tree2d[2 * treepos + bit] == 32767) /*not yet filled in*/ + { + if(i + 1 == tree->lengths[n]) /*last bit*/ + { + tree->tree2d[2 * treepos + bit] = n; /*put the current code in it*/ + treepos = 0; + } + else + { + /*put address of the next step in here, first that address has to be found of course + (it's just nodefilled + 1)...*/ + ++nodefilled; + /*addresses encoded with numcodes added to it*/ + tree->tree2d[2 * treepos + bit] = nodefilled + tree->numcodes; + treepos = nodefilled; + } + } + else treepos = tree->tree2d[2 * treepos + bit] - tree->numcodes; + } + } + + for(n = 0; n < tree->numcodes * 2; ++n) + { + if(tree->tree2d[n] == 32767) tree->tree2d[n] = 0; /*remove possible remaining 32767's*/ + } + + return 0; +} + +/* +Second step for the ...makeFromLengths and ...makeFromFrequencies functions. +numcodes, lengths and maxbitlen must already be filled in correctly. return +value is error. +*/ +static unsigned HuffmanTree_makeFromLengths2(HuffmanTree* tree) +{ + uivector blcount; + uivector nextcode; + unsigned error = 0; + unsigned bits, n; + + uivector_init(&blcount); + uivector_init(&nextcode); + + tree->tree1d = (unsigned*)lodepng_malloc(tree->numcodes * sizeof(unsigned)); + if(!tree->tree1d) error = 83; /*alloc fail*/ + + if(!uivector_resizev(&blcount, tree->maxbitlen + 1, 0) + || !uivector_resizev(&nextcode, tree->maxbitlen + 1, 0)) + error = 83; /*alloc fail*/ + + if(!error) + { + /*step 1: count number of instances of each code length*/ + for(bits = 0; bits != tree->numcodes; ++bits) ++blcount.data[tree->lengths[bits]]; + /*step 2: generate the nextcode values*/ + for(bits = 1; bits <= tree->maxbitlen; ++bits) + { + nextcode.data[bits] = (nextcode.data[bits - 1] + blcount.data[bits - 1]) << 1; + } + /*step 3: generate all the codes*/ + for(n = 0; n != tree->numcodes; ++n) + { + if(tree->lengths[n] != 0) tree->tree1d[n] = nextcode.data[tree->lengths[n]]++; + } + } + + uivector_cleanup(&blcount); + uivector_cleanup(&nextcode); + + if(!error) return HuffmanTree_make2DTree(tree); + else return error; +} + +/* +given the code lengths (as stored in the PNG file), generate the tree as defined +by Deflate. maxbitlen is the maximum bits that a code in the tree can have. +return value is error. +*/ +static unsigned HuffmanTree_makeFromLengths(HuffmanTree* tree, const unsigned* bitlen, + size_t numcodes, unsigned maxbitlen) +{ + unsigned i; + tree->lengths = (unsigned*)lodepng_malloc(numcodes * sizeof(unsigned)); + if(!tree->lengths) return 83; /*alloc fail*/ + for(i = 0; i != numcodes; ++i) tree->lengths[i] = bitlen[i]; + tree->numcodes = (unsigned)numcodes; /*number of symbols*/ + tree->maxbitlen = maxbitlen; + return HuffmanTree_makeFromLengths2(tree); +} + +#ifdef LODEPNG_COMPILE_ENCODER + +/*BPM: Boundary Package Merge, see "A Fast and Space-Economical Algorithm for Length-Limited Coding", +Jyrki Katajainen, Alistair Moffat, Andrew Turpin, 1995.*/ + +/*chain node for boundary package merge*/ +typedef struct BPMNode +{ + int weight; /*the sum of all weights in this chain*/ + unsigned index; /*index of this leaf node (called "count" in the paper)*/ + struct BPMNode* tail; /*the next nodes in this chain (null if last)*/ + int in_use; +} BPMNode; + +/*lists of chains*/ +typedef struct BPMLists +{ + /*memory pool*/ + unsigned memsize; + BPMNode* memory; + unsigned numfree; + unsigned nextfree; + BPMNode** freelist; + /*two heads of lookahead chains per list*/ + unsigned listsize; + BPMNode** chains0; + BPMNode** chains1; +} BPMLists; + +/*creates a new chain node with the given parameters, from the memory in the lists */ +static BPMNode* bpmnode_create(BPMLists* lists, int weight, unsigned index, BPMNode* tail) +{ + unsigned i; + BPMNode* result; + + /*memory full, so garbage collect*/ + if(lists->nextfree >= lists->numfree) + { + /*mark only those that are in use*/ + for(i = 0; i != lists->memsize; ++i) lists->memory[i].in_use = 0; + for(i = 0; i != lists->listsize; ++i) + { + BPMNode* node; + for(node = lists->chains0[i]; node != 0; node = node->tail) node->in_use = 1; + for(node = lists->chains1[i]; node != 0; node = node->tail) node->in_use = 1; + } + /*collect those that are free*/ + lists->numfree = 0; + for(i = 0; i != lists->memsize; ++i) + { + if(!lists->memory[i].in_use) lists->freelist[lists->numfree++] = &lists->memory[i]; + } + lists->nextfree = 0; + } + + result = lists->freelist[lists->nextfree++]; + result->weight = weight; + result->index = index; + result->tail = tail; + return result; +} + +/*sort the leaves with stable mergesort*/ +static void bpmnode_sort(BPMNode* leaves, size_t num) +{ + BPMNode* mem = (BPMNode*)lodepng_malloc(sizeof(*leaves) * num); + size_t width, counter = 0; + for(width = 1; width < num; width *= 2) + { + BPMNode* a = (counter & 1) ? mem : leaves; + BPMNode* b = (counter & 1) ? leaves : mem; + size_t p; + for(p = 0; p < num; p += 2 * width) + { + size_t q = (p + width > num) ? num : (p + width); + size_t r = (p + 2 * width > num) ? num : (p + 2 * width); + size_t i = p, j = q, k; + for(k = p; k < r; k++) + { + if(i < q && (j >= r || a[i].weight <= a[j].weight)) b[k] = a[i++]; + else b[k] = a[j++]; + } + } + counter++; + } + if(counter & 1) memcpy(leaves, mem, sizeof(*leaves) * num); + lodepng_free(mem); +} + +/*Boundary Package Merge step, numpresent is the amount of leaves, and c is the current chain.*/ +static void boundaryPM(BPMLists* lists, BPMNode* leaves, size_t numpresent, int c, int num) +{ + unsigned lastindex = lists->chains1[c]->index; + + if(c == 0) + { + if(lastindex >= numpresent) return; + lists->chains0[c] = lists->chains1[c]; + lists->chains1[c] = bpmnode_create(lists, leaves[lastindex].weight, lastindex + 1, 0); + } + else + { + /*sum of the weights of the head nodes of the previous lookahead chains.*/ + int sum = lists->chains0[c - 1]->weight + lists->chains1[c - 1]->weight; + lists->chains0[c] = lists->chains1[c]; + if(lastindex < numpresent && sum > leaves[lastindex].weight) + { + lists->chains1[c] = bpmnode_create(lists, leaves[lastindex].weight, lastindex + 1, lists->chains1[c]->tail); + return; + } + lists->chains1[c] = bpmnode_create(lists, sum, lastindex, lists->chains1[c - 1]); + /*in the end we are only interested in the chain of the last list, so no + need to recurse if we're at the last one (this gives measurable speedup)*/ + if(num + 1 < (int)(2 * numpresent - 2)) + { + boundaryPM(lists, leaves, numpresent, c - 1, num); + boundaryPM(lists, leaves, numpresent, c - 1, num); + } + } +} + +unsigned lodepng_huffman_code_lengths(unsigned* lengths, const unsigned* frequencies, + size_t numcodes, unsigned maxbitlen) +{ + unsigned error = 0; + unsigned i; + size_t numpresent = 0; /*number of symbols with non-zero frequency*/ + BPMNode* leaves; /*the symbols, only those with > 0 frequency*/ + + if(numcodes == 0) return 80; /*error: a tree of 0 symbols is not supposed to be made*/ + if((1u << maxbitlen) < numcodes) return 80; /*error: represent all symbols*/ + + leaves = (BPMNode*)lodepng_malloc(numcodes * sizeof(*leaves)); + if(!leaves) return 83; /*alloc fail*/ + + for(i = 0; i != numcodes; ++i) + { + if(frequencies[i] > 0) + { + leaves[numpresent].weight = (int)frequencies[i]; + leaves[numpresent].index = i; + ++numpresent; + } + } + + for(i = 0; i != numcodes; ++i) lengths[i] = 0; + + /*ensure at least two present symbols. There should be at least one symbol + according to RFC 1951 section 3.2.7. Some decoders incorrectly require two. To + make these work as well ensure there are at least two symbols. The + Package-Merge code below also doesn't work correctly if there's only one + symbol, it'd give it the theoritical 0 bits but in practice zlib wants 1 bit*/ + if(numpresent == 0) + { + lengths[0] = lengths[1] = 1; /*note that for RFC 1951 section 3.2.7, only lengths[0] = 1 is needed*/ + } + else if(numpresent == 1) + { + lengths[leaves[0].index] = 1; + lengths[leaves[0].index == 0 ? 1 : 0] = 1; + } + else + { + BPMLists lists; + BPMNode* node; + + bpmnode_sort(leaves, numpresent); + + lists.listsize = maxbitlen; + lists.memsize = 2 * maxbitlen * (maxbitlen + 1); + lists.nextfree = 0; + lists.numfree = lists.memsize; + lists.memory = (BPMNode*)lodepng_malloc(lists.memsize * sizeof(*lists.memory)); + lists.freelist = (BPMNode**)lodepng_malloc(lists.memsize * sizeof(BPMNode*)); + lists.chains0 = (BPMNode**)lodepng_malloc(lists.listsize * sizeof(BPMNode*)); + lists.chains1 = (BPMNode**)lodepng_malloc(lists.listsize * sizeof(BPMNode*)); + if(!lists.memory || !lists.freelist || !lists.chains0 || !lists.chains1) error = 83; /*alloc fail*/ + + if(!error) + { + for(i = 0; i != lists.memsize; ++i) lists.freelist[i] = &lists.memory[i]; + + bpmnode_create(&lists, leaves[0].weight, 1, 0); + bpmnode_create(&lists, leaves[1].weight, 2, 0); + + for(i = 0; i != lists.listsize; ++i) + { + lists.chains0[i] = &lists.memory[0]; + lists.chains1[i] = &lists.memory[1]; + } + + /*each boundaryPM call adds one chain to the last list, and we need 2 * numpresent - 2 chains.*/ + for(i = 2; i != 2 * numpresent - 2; ++i) boundaryPM(&lists, leaves, numpresent, (int)maxbitlen - 1, (int)i); + + for(node = lists.chains1[maxbitlen - 1]; node; node = node->tail) + { + for(i = 0; i != node->index; ++i) ++lengths[leaves[i].index]; + } + } + + lodepng_free(lists.memory); + lodepng_free(lists.freelist); + lodepng_free(lists.chains0); + lodepng_free(lists.chains1); + } + + lodepng_free(leaves); + return error; +} + +/*Create the Huffman tree given the symbol frequencies*/ +static unsigned HuffmanTree_makeFromFrequencies(HuffmanTree* tree, const unsigned* frequencies, + size_t mincodes, size_t numcodes, unsigned maxbitlen) +{ + unsigned error = 0; + while(!frequencies[numcodes - 1] && numcodes > mincodes) --numcodes; /*trim zeroes*/ + tree->maxbitlen = maxbitlen; + tree->numcodes = (unsigned)numcodes; /*number of symbols*/ + tree->lengths = (unsigned*)lodepng_realloc(tree->lengths, numcodes * sizeof(unsigned)); + if(!tree->lengths) return 83; /*alloc fail*/ + /*initialize all lengths to 0*/ + memset(tree->lengths, 0, numcodes * sizeof(unsigned)); + + error = lodepng_huffman_code_lengths(tree->lengths, frequencies, numcodes, maxbitlen); + if(!error) error = HuffmanTree_makeFromLengths2(tree); + return error; +} + +static unsigned HuffmanTree_getCode(const HuffmanTree* tree, unsigned index) +{ + return tree->tree1d[index]; +} + +static unsigned HuffmanTree_getLength(const HuffmanTree* tree, unsigned index) +{ + return tree->lengths[index]; +} +#endif /*LODEPNG_COMPILE_ENCODER*/ + +/*get the literal and length code tree of a deflated block with fixed tree, as per the deflate specification*/ +static unsigned generateFixedLitLenTree(HuffmanTree* tree) +{ + unsigned i, error = 0; + unsigned* bitlen = (unsigned*)lodepng_malloc(NUM_DEFLATE_CODE_SYMBOLS * sizeof(unsigned)); + if(!bitlen) return 83; /*alloc fail*/ + + /*288 possible codes: 0-255=literals, 256=endcode, 257-285=lengthcodes, 286-287=unused*/ + for(i = 0; i <= 143; ++i) bitlen[i] = 8; + for(i = 144; i <= 255; ++i) bitlen[i] = 9; + for(i = 256; i <= 279; ++i) bitlen[i] = 7; + for(i = 280; i <= 287; ++i) bitlen[i] = 8; + + error = HuffmanTree_makeFromLengths(tree, bitlen, NUM_DEFLATE_CODE_SYMBOLS, 15); + + lodepng_free(bitlen); + return error; +} + +/*get the distance code tree of a deflated block with fixed tree, as specified in the deflate specification*/ +static unsigned generateFixedDistanceTree(HuffmanTree* tree) +{ + unsigned i, error = 0; + unsigned* bitlen = (unsigned*)lodepng_malloc(NUM_DISTANCE_SYMBOLS * sizeof(unsigned)); + if(!bitlen) return 83; /*alloc fail*/ + + /*there are 32 distance codes, but 30-31 are unused*/ + for(i = 0; i != NUM_DISTANCE_SYMBOLS; ++i) bitlen[i] = 5; + error = HuffmanTree_makeFromLengths(tree, bitlen, NUM_DISTANCE_SYMBOLS, 15); + + lodepng_free(bitlen); + return error; +} + +#ifdef LODEPNG_COMPILE_DECODER + +/* +returns the code, or (unsigned)(-1) if error happened +inbitlength is the length of the complete buffer, in bits (so its byte length times 8) +*/ +static unsigned huffmanDecodeSymbol(const unsigned char* in, size_t* bp, + const HuffmanTree* codetree, size_t inbitlength) +{ + unsigned treepos = 0, ct; + for(;;) + { + if(*bp >= inbitlength) return (unsigned)(-1); /*error: end of input memory reached without endcode*/ + /* + decode the symbol from the tree. The "readBitFromStream" code is inlined in + the expression below because this is the biggest bottleneck while decoding + */ + ct = codetree->tree2d[(treepos << 1) + READBIT(*bp, in)]; + ++(*bp); + if(ct < codetree->numcodes) return ct; /*the symbol is decoded, return it*/ + else treepos = ct - codetree->numcodes; /*symbol not yet decoded, instead move tree position*/ + + if(treepos >= codetree->numcodes) return (unsigned)(-1); /*error: it appeared outside the codetree*/ + } +} +#endif /*LODEPNG_COMPILE_DECODER*/ + +#ifdef LODEPNG_COMPILE_DECODER + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / Inflator (Decompressor) / */ +/* ////////////////////////////////////////////////////////////////////////// */ + +/*get the tree of a deflated block with fixed tree, as specified in the deflate specification*/ +static void getTreeInflateFixed(HuffmanTree* tree_ll, HuffmanTree* tree_d) +{ + /*TODO: check for out of memory errors*/ + generateFixedLitLenTree(tree_ll); + generateFixedDistanceTree(tree_d); +} + +/*get the tree of a deflated block with dynamic tree, the tree itself is also Huffman compressed with a known tree*/ +static unsigned getTreeInflateDynamic(HuffmanTree* tree_ll, HuffmanTree* tree_d, + const unsigned char* in, size_t* bp, size_t inlength) +{ + /*make sure that length values that aren't filled in will be 0, or a wrong tree will be generated*/ + unsigned error = 0; + unsigned n, HLIT, HDIST, HCLEN, i; + size_t inbitlength = inlength * 8; + + /*see comments in deflateDynamic for explanation of the context and these variables, it is analogous*/ + unsigned* bitlen_ll = 0; /*lit,len code lengths*/ + unsigned* bitlen_d = 0; /*dist code lengths*/ + /*code length code lengths ("clcl"), the bit lengths of the huffman tree used to compress bitlen_ll and bitlen_d*/ + unsigned* bitlen_cl = 0; + HuffmanTree tree_cl; /*the code tree for code length codes (the huffman tree for compressed huffman trees)*/ + + if((*bp) + 14 > (inlength << 3)) return 49; /*error: the bit pointer is or will go past the memory*/ + + /*number of literal/length codes + 257. Unlike the spec, the value 257 is added to it here already*/ + HLIT = readBitsFromStream(bp, in, 5) + 257; + /*number of distance codes. Unlike the spec, the value 1 is added to it here already*/ + HDIST = readBitsFromStream(bp, in, 5) + 1; + /*number of code length codes. Unlike the spec, the value 4 is added to it here already*/ + HCLEN = readBitsFromStream(bp, in, 4) + 4; + + if((*bp) + HCLEN * 3 > (inlength << 3)) return 50; /*error: the bit pointer is or will go past the memory*/ + + HuffmanTree_init(&tree_cl); + + while(!error) + { + /*read the code length codes out of 3 * (amount of code length codes) bits*/ + + bitlen_cl = (unsigned*)lodepng_malloc(NUM_CODE_LENGTH_CODES * sizeof(unsigned)); + if(!bitlen_cl) ERROR_BREAK(83 /*alloc fail*/); + + for(i = 0; i != NUM_CODE_LENGTH_CODES; ++i) + { + if(i < HCLEN) bitlen_cl[CLCL_ORDER[i]] = readBitsFromStream(bp, in, 3); + else bitlen_cl[CLCL_ORDER[i]] = 0; /*if not, it must stay 0*/ + } + + error = HuffmanTree_makeFromLengths(&tree_cl, bitlen_cl, NUM_CODE_LENGTH_CODES, 7); + if(error) break; + + /*now we can use this tree to read the lengths for the tree that this function will return*/ + bitlen_ll = (unsigned*)lodepng_malloc(NUM_DEFLATE_CODE_SYMBOLS * sizeof(unsigned)); + bitlen_d = (unsigned*)lodepng_malloc(NUM_DISTANCE_SYMBOLS * sizeof(unsigned)); + if(!bitlen_ll || !bitlen_d) ERROR_BREAK(83 /*alloc fail*/); + for(i = 0; i != NUM_DEFLATE_CODE_SYMBOLS; ++i) bitlen_ll[i] = 0; + for(i = 0; i != NUM_DISTANCE_SYMBOLS; ++i) bitlen_d[i] = 0; + + /*i is the current symbol we're reading in the part that contains the code lengths of lit/len and dist codes*/ + i = 0; + while(i < HLIT + HDIST) + { + unsigned code = huffmanDecodeSymbol(in, bp, &tree_cl, inbitlength); + if(code <= 15) /*a length code*/ + { + if(i < HLIT) bitlen_ll[i] = code; + else bitlen_d[i - HLIT] = code; + ++i; + } + else if(code == 16) /*repeat previous*/ + { + unsigned replength = 3; /*read in the 2 bits that indicate repeat length (3-6)*/ + unsigned value; /*set value to the previous code*/ + + if(i == 0) ERROR_BREAK(54); /*can't repeat previous if i is 0*/ + + if((*bp + 2) > inbitlength) ERROR_BREAK(50); /*error, bit pointer jumps past memory*/ + replength += readBitsFromStream(bp, in, 2); + + if(i < HLIT + 1) value = bitlen_ll[i - 1]; + else value = bitlen_d[i - HLIT - 1]; + /*repeat this value in the next lengths*/ + for(n = 0; n < replength; ++n) + { + if(i >= HLIT + HDIST) ERROR_BREAK(13); /*error: i is larger than the amount of codes*/ + if(i < HLIT) bitlen_ll[i] = value; + else bitlen_d[i - HLIT] = value; + ++i; + } + } + else if(code == 17) /*repeat "0" 3-10 times*/ + { + unsigned replength = 3; /*read in the bits that indicate repeat length*/ + if((*bp + 3) > inbitlength) ERROR_BREAK(50); /*error, bit pointer jumps past memory*/ + replength += readBitsFromStream(bp, in, 3); + + /*repeat this value in the next lengths*/ + for(n = 0; n < replength; ++n) + { + if(i >= HLIT + HDIST) ERROR_BREAK(14); /*error: i is larger than the amount of codes*/ + + if(i < HLIT) bitlen_ll[i] = 0; + else bitlen_d[i - HLIT] = 0; + ++i; + } + } + else if(code == 18) /*repeat "0" 11-138 times*/ + { + unsigned replength = 11; /*read in the bits that indicate repeat length*/ + if((*bp + 7) > inbitlength) ERROR_BREAK(50); /*error, bit pointer jumps past memory*/ + replength += readBitsFromStream(bp, in, 7); + + /*repeat this value in the next lengths*/ + for(n = 0; n < replength; ++n) + { + if(i >= HLIT + HDIST) ERROR_BREAK(15); /*error: i is larger than the amount of codes*/ + + if(i < HLIT) bitlen_ll[i] = 0; + else bitlen_d[i - HLIT] = 0; + ++i; + } + } + else /*if(code == (unsigned)(-1))*/ /*huffmanDecodeSymbol returns (unsigned)(-1) in case of error*/ + { + if(code == (unsigned)(-1)) + { + /*return error code 10 or 11 depending on the situation that happened in huffmanDecodeSymbol + (10=no endcode, 11=wrong jump outside of tree)*/ + error = (*bp) > inbitlength ? 10 : 11; + } + else error = 16; /*unexisting code, this can never happen*/ + break; + } + } + if(error) break; + + if(bitlen_ll[256] == 0) ERROR_BREAK(64); /*the length of the end code 256 must be larger than 0*/ + + /*now we've finally got HLIT and HDIST, so generate the code trees, and the function is done*/ + error = HuffmanTree_makeFromLengths(tree_ll, bitlen_ll, NUM_DEFLATE_CODE_SYMBOLS, 15); + if(error) break; + error = HuffmanTree_makeFromLengths(tree_d, bitlen_d, NUM_DISTANCE_SYMBOLS, 15); + + break; /*end of error-while*/ + } + + lodepng_free(bitlen_cl); + lodepng_free(bitlen_ll); + lodepng_free(bitlen_d); + HuffmanTree_cleanup(&tree_cl); + + return error; +} + +/*inflate a block with dynamic of fixed Huffman tree*/ +static unsigned inflateHuffmanBlock(ucvector* out, const unsigned char* in, size_t* bp, + size_t* pos, size_t inlength, unsigned btype) +{ + unsigned error = 0; + HuffmanTree tree_ll; /*the huffman tree for literal and length codes*/ + HuffmanTree tree_d; /*the huffman tree for distance codes*/ + size_t inbitlength = inlength * 8; + + HuffmanTree_init(&tree_ll); + HuffmanTree_init(&tree_d); + + if(btype == 1) getTreeInflateFixed(&tree_ll, &tree_d); + else if(btype == 2) error = getTreeInflateDynamic(&tree_ll, &tree_d, in, bp, inlength); + + while(!error) /*decode all symbols until end reached, breaks at end code*/ + { + /*code_ll is literal, length or end code*/ + unsigned code_ll = huffmanDecodeSymbol(in, bp, &tree_ll, inbitlength); + if(code_ll <= 255) /*literal symbol*/ + { + /*ucvector_push_back would do the same, but for some reason the two lines below run 10% faster*/ + if(!ucvector_resize(out, (*pos) + 1)) ERROR_BREAK(83 /*alloc fail*/); + out->data[*pos] = (unsigned char)code_ll; + ++(*pos); + } + else if(code_ll >= FIRST_LENGTH_CODE_INDEX && code_ll <= LAST_LENGTH_CODE_INDEX) /*length code*/ + { + unsigned code_d, distance; + unsigned numextrabits_l, numextrabits_d; /*extra bits for length and distance*/ + size_t start, forward, backward, length; + + /*part 1: get length base*/ + length = LENGTHBASE[code_ll - FIRST_LENGTH_CODE_INDEX]; + + /*part 2: get extra bits and add the value of that to length*/ + numextrabits_l = LENGTHEXTRA[code_ll - FIRST_LENGTH_CODE_INDEX]; + if((*bp + numextrabits_l) > inbitlength) ERROR_BREAK(51); /*error, bit pointer will jump past memory*/ + length += readBitsFromStream(bp, in, numextrabits_l); + + /*part 3: get distance code*/ + code_d = huffmanDecodeSymbol(in, bp, &tree_d, inbitlength); + if(code_d > 29) + { + if(code_ll == (unsigned)(-1)) /*huffmanDecodeSymbol returns (unsigned)(-1) in case of error*/ + { + /*return error code 10 or 11 depending on the situation that happened in huffmanDecodeSymbol + (10=no endcode, 11=wrong jump outside of tree)*/ + error = (*bp) > inlength * 8 ? 10 : 11; + } + else error = 18; /*error: invalid distance code (30-31 are never used)*/ + break; + } + distance = DISTANCEBASE[code_d]; + + /*part 4: get extra bits from distance*/ + numextrabits_d = DISTANCEEXTRA[code_d]; + if((*bp + numextrabits_d) > inbitlength) ERROR_BREAK(51); /*error, bit pointer will jump past memory*/ + distance += readBitsFromStream(bp, in, numextrabits_d); + + /*part 5: fill in all the out[n] values based on the length and dist*/ + start = (*pos); + if(distance > start) ERROR_BREAK(52); /*too long backward distance*/ + backward = start - distance; + + if(!ucvector_resize(out, (*pos) + length)) ERROR_BREAK(83 /*alloc fail*/); + if (distance < length) { + for(forward = 0; forward < length; ++forward) + { + out->data[(*pos)++] = out->data[backward++]; + } + } else { + memcpy(out->data + *pos, out->data + backward, length); + *pos += length; + } + } + else if(code_ll == 256) + { + break; /*end code, break the loop*/ + } + else /*if(code == (unsigned)(-1))*/ /*huffmanDecodeSymbol returns (unsigned)(-1) in case of error*/ + { + /*return error code 10 or 11 depending on the situation that happened in huffmanDecodeSymbol + (10=no endcode, 11=wrong jump outside of tree)*/ + error = ((*bp) > inlength * 8) ? 10 : 11; + break; + } + } + + HuffmanTree_cleanup(&tree_ll); + HuffmanTree_cleanup(&tree_d); + + return error; +} + +static unsigned inflateNoCompression(ucvector* out, const unsigned char* in, size_t* bp, size_t* pos, size_t inlength) +{ + size_t p; + unsigned LEN, NLEN, n, error = 0; + + /*go to first boundary of byte*/ + while(((*bp) & 0x7) != 0) ++(*bp); + p = (*bp) / 8; /*byte position*/ + + /*read LEN (2 bytes) and NLEN (2 bytes)*/ + if(p + 4 >= inlength) return 52; /*error, bit pointer will jump past memory*/ + LEN = in[p] + 256u * in[p + 1]; p += 2; + NLEN = in[p] + 256u * in[p + 1]; p += 2; + + /*check if 16-bit NLEN is really the one's complement of LEN*/ + if(LEN + NLEN != 65535) return 21; /*error: NLEN is not one's complement of LEN*/ + + if(!ucvector_resize(out, (*pos) + LEN)) return 83; /*alloc fail*/ + + /*read the literal data: LEN bytes are now stored in the out buffer*/ + if(p + LEN > inlength) return 23; /*error: reading outside of in buffer*/ + for(n = 0; n < LEN; ++n) out->data[(*pos)++] = in[p++]; + + (*bp) = p * 8; + + return error; +} + +static unsigned lodepng_inflatev(ucvector* out, + const unsigned char* in, size_t insize, + const LodePNGDecompressSettings* settings) +{ + /*bit pointer in the "in" data, current byte is bp >> 3, current bit is bp & 0x7 (from lsb to msb of the byte)*/ + size_t bp = 0; + unsigned BFINAL = 0; + size_t pos = 0; /*byte position in the out buffer*/ + unsigned error = 0; + + (void)settings; + + while(!BFINAL) + { + unsigned BTYPE; + if(bp + 2 >= insize * 8) return 52; /*error, bit pointer will jump past memory*/ + BFINAL = readBitFromStream(&bp, in); + BTYPE = 1u * readBitFromStream(&bp, in); + BTYPE += 2u * readBitFromStream(&bp, in); + + if(BTYPE == 3) return 20; /*error: invalid BTYPE*/ + else if(BTYPE == 0) error = inflateNoCompression(out, in, &bp, &pos, insize); /*no compression*/ + else error = inflateHuffmanBlock(out, in, &bp, &pos, insize, BTYPE); /*compression, BTYPE 01 or 10*/ + + if(error) return error; + } + + return error; +} + +unsigned lodepng_inflate(unsigned char** out, size_t* outsize, + const unsigned char* in, size_t insize, + const LodePNGDecompressSettings* settings) +{ + unsigned error; + ucvector v; + ucvector_init_buffer(&v, *out, *outsize); + error = lodepng_inflatev(&v, in, insize, settings); + *out = v.data; + *outsize = v.size; + return error; +} + +static unsigned inflate(unsigned char** out, size_t* outsize, + const unsigned char* in, size_t insize, + const LodePNGDecompressSettings* settings) +{ + if(settings->custom_inflate) + { + return settings->custom_inflate(out, outsize, in, insize, settings); + } + else + { + return lodepng_inflate(out, outsize, in, insize, settings); + } +} + +#endif /*LODEPNG_COMPILE_DECODER*/ + +#ifdef LODEPNG_COMPILE_ENCODER + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / Deflator (Compressor) / */ +/* ////////////////////////////////////////////////////////////////////////// */ + +static const size_t MAX_SUPPORTED_DEFLATE_LENGTH = 258; + +/*bitlen is the size in bits of the code*/ +static void addHuffmanSymbol(size_t* bp, ucvector* compressed, unsigned code, unsigned bitlen) +{ + addBitsToStreamReversed(bp, compressed, code, bitlen); +} + +/*search the index in the array, that has the largest value smaller than or equal to the given value, +given array must be sorted (if no value is smaller, it returns the size of the given array)*/ +static size_t searchCodeIndex(const unsigned* array, size_t array_size, size_t value) +{ + /*binary search (only small gain over linear). TODO: use CPU log2 instruction for getting symbols instead*/ + size_t left = 1; + size_t right = array_size - 1; + + while(left <= right) { + size_t mid = (left + right) >> 1; + if (array[mid] >= value) right = mid - 1; + else left = mid + 1; + } + if(left >= array_size || array[left] > value) left--; + return left; +} + +static void addLengthDistance(uivector* values, size_t length, size_t distance) +{ + /*values in encoded vector are those used by deflate: + 0-255: literal bytes + 256: end + 257-285: length/distance pair (length code, followed by extra length bits, distance code, extra distance bits) + 286-287: invalid*/ + + unsigned length_code = (unsigned)searchCodeIndex(LENGTHBASE, 29, length); + unsigned extra_length = (unsigned)(length - LENGTHBASE[length_code]); + unsigned dist_code = (unsigned)searchCodeIndex(DISTANCEBASE, 30, distance); + unsigned extra_distance = (unsigned)(distance - DISTANCEBASE[dist_code]); + + uivector_push_back(values, length_code + FIRST_LENGTH_CODE_INDEX); + uivector_push_back(values, extra_length); + uivector_push_back(values, dist_code); + uivector_push_back(values, extra_distance); +} + +/*3 bytes of data get encoded into two bytes. The hash cannot use more than 3 +bytes as input because 3 is the minimum match length for deflate*/ +static const unsigned HASH_NUM_VALUES = 65536; +static const unsigned HASH_BIT_MASK = 65535; /*HASH_NUM_VALUES - 1, but C90 does not like that as initializer*/ + +typedef struct Hash +{ + int* head; /*hash value to head circular pos - can be outdated if went around window*/ + /*circular pos to prev circular pos*/ + unsigned short* chain; + int* val; /*circular pos to hash value*/ + + /*TODO: do this not only for zeros but for any repeated byte. However for PNG + it's always going to be the zeros that dominate, so not important for PNG*/ + int* headz; /*similar to head, but for chainz*/ + unsigned short* chainz; /*those with same amount of zeros*/ + unsigned short* zeros; /*length of zeros streak, used as a second hash chain*/ +} Hash; + +static unsigned hash_init(Hash* hash, unsigned windowsize) +{ + unsigned i; + hash->head = (int*)lodepng_malloc(sizeof(int) * HASH_NUM_VALUES); + hash->val = (int*)lodepng_malloc(sizeof(int) * windowsize); + hash->chain = (unsigned short*)lodepng_malloc(sizeof(unsigned short) * windowsize); + + hash->zeros = (unsigned short*)lodepng_malloc(sizeof(unsigned short) * windowsize); + hash->headz = (int*)lodepng_malloc(sizeof(int) * (MAX_SUPPORTED_DEFLATE_LENGTH + 1)); + hash->chainz = (unsigned short*)lodepng_malloc(sizeof(unsigned short) * windowsize); + + if(!hash->head || !hash->chain || !hash->val || !hash->headz|| !hash->chainz || !hash->zeros) + { + return 83; /*alloc fail*/ + } + + /*initialize hash table*/ + for(i = 0; i != HASH_NUM_VALUES; ++i) hash->head[i] = -1; + for(i = 0; i != windowsize; ++i) hash->val[i] = -1; + for(i = 0; i != windowsize; ++i) hash->chain[i] = i; /*same value as index indicates uninitialized*/ + + for(i = 0; i <= MAX_SUPPORTED_DEFLATE_LENGTH; ++i) hash->headz[i] = -1; + for(i = 0; i != windowsize; ++i) hash->chainz[i] = i; /*same value as index indicates uninitialized*/ + + return 0; +} + +static void hash_cleanup(Hash* hash) +{ + lodepng_free(hash->head); + lodepng_free(hash->val); + lodepng_free(hash->chain); + + lodepng_free(hash->zeros); + lodepng_free(hash->headz); + lodepng_free(hash->chainz); +} + + + +static unsigned getHash(const unsigned char* data, size_t size, size_t pos) +{ + unsigned result = 0; + if(pos + 2 < size) + { + /*A simple shift and xor hash is used. Since the data of PNGs is dominated + by zeroes due to the filters, a better hash does not have a significant + effect on speed in traversing the chain, and causes more time spend on + calculating the hash.*/ + result ^= (unsigned)(data[pos + 0] << 0u); + result ^= (unsigned)(data[pos + 1] << 4u); + result ^= (unsigned)(data[pos + 2] << 8u); + } else { + size_t amount, i; + if(pos >= size) return 0; + amount = size - pos; + for(i = 0; i != amount; ++i) result ^= (unsigned)(data[pos + i] << (i * 8u)); + } + return result & HASH_BIT_MASK; +} + +static unsigned countZeros(const unsigned char* data, size_t size, size_t pos) +{ + const unsigned char* start = data + pos; + const unsigned char* end = start + MAX_SUPPORTED_DEFLATE_LENGTH; + if(end > data + size) end = data + size; + data = start; + while(data != end && *data == 0) ++data; + /*subtracting two addresses returned as 32-bit number (max value is MAX_SUPPORTED_DEFLATE_LENGTH)*/ + return (unsigned)(data - start); +} + +/*wpos = pos & (windowsize - 1)*/ +static void updateHashChain(Hash* hash, size_t wpos, unsigned hashval, unsigned short numzeros) +{ + hash->val[wpos] = (int)hashval; + if(hash->head[hashval] != -1) hash->chain[wpos] = hash->head[hashval]; + hash->head[hashval] = wpos; + + hash->zeros[wpos] = numzeros; + if(hash->headz[numzeros] != -1) hash->chainz[wpos] = hash->headz[numzeros]; + hash->headz[numzeros] = wpos; +} + +/* +LZ77-encode the data. Return value is error code. The input are raw bytes, the output +is in the form of unsigned integers with codes representing for example literal bytes, or +length/distance pairs. +It uses a hash table technique to let it encode faster. When doing LZ77 encoding, a +sliding window (of windowsize) is used, and all past bytes in that window can be used as +the "dictionary". A brute force search through all possible distances would be slow, and +this hash technique is one out of several ways to speed this up. +*/ +static unsigned encodeLZ77(uivector* out, Hash* hash, + const unsigned char* in, size_t inpos, size_t insize, unsigned windowsize, + unsigned minmatch, unsigned nicematch, unsigned lazymatching) +{ + size_t pos; + unsigned i, error = 0; + /*for large window lengths, assume the user wants no compression loss. Otherwise, max hash chain length speedup.*/ + unsigned maxchainlength = windowsize >= 8192 ? windowsize : windowsize / 8; + unsigned maxlazymatch = windowsize >= 8192 ? MAX_SUPPORTED_DEFLATE_LENGTH : 64; + + unsigned usezeros = 1; /*not sure if setting it to false for windowsize < 8192 is better or worse*/ + unsigned numzeros = 0; + + unsigned offset; /*the offset represents the distance in LZ77 terminology*/ + unsigned length; + unsigned lazy = 0; + unsigned lazylength = 0, lazyoffset = 0; + unsigned hashval; + unsigned current_offset, current_length; + unsigned prev_offset; + const unsigned char *lastptr, *foreptr, *backptr; + unsigned hashpos; + + if(windowsize == 0 || windowsize > 32768) return 60; /*error: windowsize smaller/larger than allowed*/ + if((windowsize & (windowsize - 1)) != 0) return 90; /*error: must be power of two*/ + + if(nicematch > MAX_SUPPORTED_DEFLATE_LENGTH) nicematch = MAX_SUPPORTED_DEFLATE_LENGTH; + + for(pos = inpos; pos < insize; ++pos) + { + size_t wpos = pos & (windowsize - 1); /*position for in 'circular' hash buffers*/ + unsigned chainlength = 0; + + hashval = getHash(in, insize, pos); + + if(usezeros && hashval == 0) + { + if(numzeros == 0) numzeros = countZeros(in, insize, pos); + else if(pos + numzeros > insize || in[pos + numzeros - 1] != 0) --numzeros; + } + else + { + numzeros = 0; + } + + updateHashChain(hash, wpos, hashval, numzeros); + + /*the length and offset found for the current position*/ + length = 0; + offset = 0; + + hashpos = hash->chain[wpos]; + + lastptr = &in[insize < pos + MAX_SUPPORTED_DEFLATE_LENGTH ? insize : pos + MAX_SUPPORTED_DEFLATE_LENGTH]; + + /*search for the longest string*/ + prev_offset = 0; + for(;;) + { + if(chainlength++ >= maxchainlength) break; + current_offset = hashpos <= wpos ? wpos - hashpos : wpos - hashpos + windowsize; + + if(current_offset < prev_offset) break; /*stop when went completely around the circular buffer*/ + prev_offset = current_offset; + if(current_offset > 0) + { + /*test the next characters*/ + foreptr = &in[pos]; + backptr = &in[pos - current_offset]; + + /*common case in PNGs is lots of zeros. Quickly skip over them as a speedup*/ + if(numzeros >= 3) + { + unsigned skip = hash->zeros[hashpos]; + if(skip > numzeros) skip = numzeros; + backptr += skip; + foreptr += skip; + } + + while(foreptr != lastptr && *backptr == *foreptr) /*maximum supported length by deflate is max length*/ + { + ++backptr; + ++foreptr; + } + current_length = (unsigned)(foreptr - &in[pos]); + + if(current_length > length) + { + length = current_length; /*the longest length*/ + offset = current_offset; /*the offset that is related to this longest length*/ + /*jump out once a length of max length is found (speed gain). This also jumps + out if length is MAX_SUPPORTED_DEFLATE_LENGTH*/ + if(current_length >= nicematch) break; + } + } + + if(hashpos == hash->chain[hashpos]) break; + + if(numzeros >= 3 && length > numzeros) + { + hashpos = hash->chainz[hashpos]; + if(hash->zeros[hashpos] != numzeros) break; + } + else + { + hashpos = hash->chain[hashpos]; + /*outdated hash value, happens if particular value was not encountered in whole last window*/ + if(hash->val[hashpos] != (int)hashval) break; + } + } + + if(lazymatching) + { + if(!lazy && length >= 3 && length <= maxlazymatch && length < MAX_SUPPORTED_DEFLATE_LENGTH) + { + lazy = 1; + lazylength = length; + lazyoffset = offset; + continue; /*try the next byte*/ + } + if(lazy) + { + lazy = 0; + if(pos == 0) ERROR_BREAK(81); + if(length > lazylength + 1) + { + /*push the previous character as literal*/ + if(!uivector_push_back(out, in[pos - 1])) ERROR_BREAK(83 /*alloc fail*/); + } + else + { + length = lazylength; + offset = lazyoffset; + hash->head[hashval] = -1; /*the same hashchain update will be done, this ensures no wrong alteration*/ + hash->headz[numzeros] = -1; /*idem*/ + --pos; + } + } + } + if(length >= 3 && offset > windowsize) ERROR_BREAK(86 /*too big (or overflown negative) offset*/); + + /*encode it as length/distance pair or literal value*/ + if(length < 3) /*only lengths of 3 or higher are supported as length/distance pair*/ + { + if(!uivector_push_back(out, in[pos])) ERROR_BREAK(83 /*alloc fail*/); + } + else if(length < minmatch || (length == 3 && offset > 4096)) + { + /*compensate for the fact that longer offsets have more extra bits, a + length of only 3 may be not worth it then*/ + if(!uivector_push_back(out, in[pos])) ERROR_BREAK(83 /*alloc fail*/); + } + else + { + addLengthDistance(out, length, offset); + for(i = 1; i < length; ++i) + { + ++pos; + wpos = pos & (windowsize - 1); + hashval = getHash(in, insize, pos); + if(usezeros && hashval == 0) + { + if(numzeros == 0) numzeros = countZeros(in, insize, pos); + else if(pos + numzeros > insize || in[pos + numzeros - 1] != 0) --numzeros; + } + else + { + numzeros = 0; + } + updateHashChain(hash, wpos, hashval, numzeros); + } + } + } /*end of the loop through each character of input*/ + + return error; +} + +/* /////////////////////////////////////////////////////////////////////////// */ + +static unsigned deflateNoCompression(ucvector* out, const unsigned char* data, size_t datasize) +{ + /*non compressed deflate block data: 1 bit BFINAL,2 bits BTYPE,(5 bits): it jumps to start of next byte, + 2 bytes LEN, 2 bytes NLEN, LEN bytes literal DATA*/ + + size_t i, j, numdeflateblocks = (datasize + 65534) / 65535; + unsigned datapos = 0; + for(i = 0; i != numdeflateblocks; ++i) + { + unsigned BFINAL, BTYPE, LEN, NLEN; + unsigned char firstbyte; + + BFINAL = (i == numdeflateblocks - 1); + BTYPE = 0; + + firstbyte = (unsigned char)(BFINAL + ((BTYPE & 1) << 1) + ((BTYPE & 2) << 1)); + ucvector_push_back(out, firstbyte); + + LEN = 65535; + if(datasize - datapos < 65535) LEN = (unsigned)datasize - datapos; + NLEN = 65535 - LEN; + + ucvector_push_back(out, (unsigned char)(LEN & 255)); + ucvector_push_back(out, (unsigned char)(LEN >> 8)); + ucvector_push_back(out, (unsigned char)(NLEN & 255)); + ucvector_push_back(out, (unsigned char)(NLEN >> 8)); + + /*Decompressed data*/ + for(j = 0; j < 65535 && datapos < datasize; ++j) + { + ucvector_push_back(out, data[datapos++]); + } + } + + return 0; +} + +/* +write the lz77-encoded data, which has lit, len and dist codes, to compressed stream using huffman trees. +tree_ll: the tree for lit and len codes. +tree_d: the tree for distance codes. +*/ +static void writeLZ77data(size_t* bp, ucvector* out, const uivector* lz77_encoded, + const HuffmanTree* tree_ll, const HuffmanTree* tree_d) +{ + size_t i = 0; + for(i = 0; i != lz77_encoded->size; ++i) + { + unsigned val = lz77_encoded->data[i]; + addHuffmanSymbol(bp, out, HuffmanTree_getCode(tree_ll, val), HuffmanTree_getLength(tree_ll, val)); + if(val > 256) /*for a length code, 3 more things have to be added*/ + { + unsigned length_index = val - FIRST_LENGTH_CODE_INDEX; + unsigned n_length_extra_bits = LENGTHEXTRA[length_index]; + unsigned length_extra_bits = lz77_encoded->data[++i]; + + unsigned distance_code = lz77_encoded->data[++i]; + + unsigned distance_index = distance_code; + unsigned n_distance_extra_bits = DISTANCEEXTRA[distance_index]; + unsigned distance_extra_bits = lz77_encoded->data[++i]; + + addBitsToStream(bp, out, length_extra_bits, n_length_extra_bits); + addHuffmanSymbol(bp, out, HuffmanTree_getCode(tree_d, distance_code), + HuffmanTree_getLength(tree_d, distance_code)); + addBitsToStream(bp, out, distance_extra_bits, n_distance_extra_bits); + } + } +} + +/*Deflate for a block of type "dynamic", that is, with freely, optimally, created huffman trees*/ +static unsigned deflateDynamic(ucvector* out, size_t* bp, Hash* hash, + const unsigned char* data, size_t datapos, size_t dataend, + const LodePNGCompressSettings* settings, unsigned final) +{ + unsigned error = 0; + + /* + A block is compressed as follows: The PNG data is lz77 encoded, resulting in + literal bytes and length/distance pairs. This is then huffman compressed with + two huffman trees. One huffman tree is used for the lit and len values ("ll"), + another huffman tree is used for the dist values ("d"). These two trees are + stored using their code lengths, and to compress even more these code lengths + are also run-length encoded and huffman compressed. This gives a huffman tree + of code lengths "cl". The code lenghts used to describe this third tree are + the code length code lengths ("clcl"). + */ + + /*The lz77 encoded data, represented with integers since there will also be length and distance codes in it*/ + uivector lz77_encoded; + HuffmanTree tree_ll; /*tree for lit,len values*/ + HuffmanTree tree_d; /*tree for distance codes*/ + HuffmanTree tree_cl; /*tree for encoding the code lengths representing tree_ll and tree_d*/ + uivector frequencies_ll; /*frequency of lit,len codes*/ + uivector frequencies_d; /*frequency of dist codes*/ + uivector frequencies_cl; /*frequency of code length codes*/ + uivector bitlen_lld; /*lit,len,dist code lenghts (int bits), literally (without repeat codes).*/ + uivector bitlen_lld_e; /*bitlen_lld encoded with repeat codes (this is a rudemtary run length compression)*/ + /*bitlen_cl is the code length code lengths ("clcl"). The bit lengths of codes to represent tree_cl + (these are written as is in the file, it would be crazy to compress these using yet another huffman + tree that needs to be represented by yet another set of code lengths)*/ + uivector bitlen_cl; + size_t datasize = dataend - datapos; + + /* + Due to the huffman compression of huffman tree representations ("two levels"), there are some anologies: + bitlen_lld is to tree_cl what data is to tree_ll and tree_d. + bitlen_lld_e is to bitlen_lld what lz77_encoded is to data. + bitlen_cl is to bitlen_lld_e what bitlen_lld is to lz77_encoded. + */ + + unsigned BFINAL = final; + size_t numcodes_ll, numcodes_d, i; + unsigned HLIT, HDIST, HCLEN; + + uivector_init(&lz77_encoded); + HuffmanTree_init(&tree_ll); + HuffmanTree_init(&tree_d); + HuffmanTree_init(&tree_cl); + uivector_init(&frequencies_ll); + uivector_init(&frequencies_d); + uivector_init(&frequencies_cl); + uivector_init(&bitlen_lld); + uivector_init(&bitlen_lld_e); + uivector_init(&bitlen_cl); + + /*This while loop never loops due to a break at the end, it is here to + allow breaking out of it to the cleanup phase on error conditions.*/ + while(!error) + { + if(settings->use_lz77) + { + error = encodeLZ77(&lz77_encoded, hash, data, datapos, dataend, settings->windowsize, + settings->minmatch, settings->nicematch, settings->lazymatching); + if(error) break; + } + else + { + if(!uivector_resize(&lz77_encoded, datasize)) ERROR_BREAK(83 /*alloc fail*/); + for(i = datapos; i < dataend; ++i) lz77_encoded.data[i - datapos] = data[i]; /*no LZ77, but still will be Huffman compressed*/ + } + + if(!uivector_resizev(&frequencies_ll, 286, 0)) ERROR_BREAK(83 /*alloc fail*/); + if(!uivector_resizev(&frequencies_d, 30, 0)) ERROR_BREAK(83 /*alloc fail*/); + + /*Count the frequencies of lit, len and dist codes*/ + for(i = 0; i != lz77_encoded.size; ++i) + { + unsigned symbol = lz77_encoded.data[i]; + ++frequencies_ll.data[symbol]; + if(symbol > 256) + { + unsigned dist = lz77_encoded.data[i + 2]; + ++frequencies_d.data[dist]; + i += 3; + } + } + frequencies_ll.data[256] = 1; /*there will be exactly 1 end code, at the end of the block*/ + + /*Make both huffman trees, one for the lit and len codes, one for the dist codes*/ + error = HuffmanTree_makeFromFrequencies(&tree_ll, frequencies_ll.data, 257, frequencies_ll.size, 15); + if(error) break; + /*2, not 1, is chosen for mincodes: some buggy PNG decoders require at least 2 symbols in the dist tree*/ + error = HuffmanTree_makeFromFrequencies(&tree_d, frequencies_d.data, 2, frequencies_d.size, 15); + if(error) break; + + numcodes_ll = tree_ll.numcodes; if(numcodes_ll > 286) numcodes_ll = 286; + numcodes_d = tree_d.numcodes; if(numcodes_d > 30) numcodes_d = 30; + /*store the code lengths of both generated trees in bitlen_lld*/ + for(i = 0; i != numcodes_ll; ++i) uivector_push_back(&bitlen_lld, HuffmanTree_getLength(&tree_ll, (unsigned)i)); + for(i = 0; i != numcodes_d; ++i) uivector_push_back(&bitlen_lld, HuffmanTree_getLength(&tree_d, (unsigned)i)); + + /*run-length compress bitlen_ldd into bitlen_lld_e by using repeat codes 16 (copy length 3-6 times), + 17 (3-10 zeroes), 18 (11-138 zeroes)*/ + for(i = 0; i != (unsigned)bitlen_lld.size; ++i) + { + unsigned j = 0; /*amount of repititions*/ + while(i + j + 1 < (unsigned)bitlen_lld.size && bitlen_lld.data[i + j + 1] == bitlen_lld.data[i]) ++j; + + if(bitlen_lld.data[i] == 0 && j >= 2) /*repeat code for zeroes*/ + { + ++j; /*include the first zero*/ + if(j <= 10) /*repeat code 17 supports max 10 zeroes*/ + { + uivector_push_back(&bitlen_lld_e, 17); + uivector_push_back(&bitlen_lld_e, j - 3); + } + else /*repeat code 18 supports max 138 zeroes*/ + { + if(j > 138) j = 138; + uivector_push_back(&bitlen_lld_e, 18); + uivector_push_back(&bitlen_lld_e, j - 11); + } + i += (j - 1); + } + else if(j >= 3) /*repeat code for value other than zero*/ + { + size_t k; + unsigned num = j / 6, rest = j % 6; + uivector_push_back(&bitlen_lld_e, bitlen_lld.data[i]); + for(k = 0; k < num; ++k) + { + uivector_push_back(&bitlen_lld_e, 16); + uivector_push_back(&bitlen_lld_e, 6 - 3); + } + if(rest >= 3) + { + uivector_push_back(&bitlen_lld_e, 16); + uivector_push_back(&bitlen_lld_e, rest - 3); + } + else j -= rest; + i += j; + } + else /*too short to benefit from repeat code*/ + { + uivector_push_back(&bitlen_lld_e, bitlen_lld.data[i]); + } + } + + /*generate tree_cl, the huffmantree of huffmantrees*/ + + if(!uivector_resizev(&frequencies_cl, NUM_CODE_LENGTH_CODES, 0)) ERROR_BREAK(83 /*alloc fail*/); + for(i = 0; i != bitlen_lld_e.size; ++i) + { + ++frequencies_cl.data[bitlen_lld_e.data[i]]; + /*after a repeat code come the bits that specify the number of repetitions, + those don't need to be in the frequencies_cl calculation*/ + if(bitlen_lld_e.data[i] >= 16) ++i; + } + + error = HuffmanTree_makeFromFrequencies(&tree_cl, frequencies_cl.data, + frequencies_cl.size, frequencies_cl.size, 7); + if(error) break; + + if(!uivector_resize(&bitlen_cl, tree_cl.numcodes)) ERROR_BREAK(83 /*alloc fail*/); + for(i = 0; i != tree_cl.numcodes; ++i) + { + /*lenghts of code length tree is in the order as specified by deflate*/ + bitlen_cl.data[i] = HuffmanTree_getLength(&tree_cl, CLCL_ORDER[i]); + } + while(bitlen_cl.data[bitlen_cl.size - 1] == 0 && bitlen_cl.size > 4) + { + /*remove zeros at the end, but minimum size must be 4*/ + if(!uivector_resize(&bitlen_cl, bitlen_cl.size - 1)) ERROR_BREAK(83 /*alloc fail*/); + } + if(error) break; + + /* + Write everything into the output + + After the BFINAL and BTYPE, the dynamic block consists out of the following: + - 5 bits HLIT, 5 bits HDIST, 4 bits HCLEN + - (HCLEN+4)*3 bits code lengths of code length alphabet + - HLIT + 257 code lenghts of lit/length alphabet (encoded using the code length + alphabet, + possible repetition codes 16, 17, 18) + - HDIST + 1 code lengths of distance alphabet (encoded using the code length + alphabet, + possible repetition codes 16, 17, 18) + - compressed data + - 256 (end code) + */ + + /*Write block type*/ + addBitToStream(bp, out, BFINAL); + addBitToStream(bp, out, 0); /*first bit of BTYPE "dynamic"*/ + addBitToStream(bp, out, 1); /*second bit of BTYPE "dynamic"*/ + + /*write the HLIT, HDIST and HCLEN values*/ + HLIT = (unsigned)(numcodes_ll - 257); + HDIST = (unsigned)(numcodes_d - 1); + HCLEN = (unsigned)bitlen_cl.size - 4; + /*trim zeroes for HCLEN. HLIT and HDIST were already trimmed at tree creation*/ + while(!bitlen_cl.data[HCLEN + 4 - 1] && HCLEN > 0) --HCLEN; + addBitsToStream(bp, out, HLIT, 5); + addBitsToStream(bp, out, HDIST, 5); + addBitsToStream(bp, out, HCLEN, 4); + + /*write the code lenghts of the code length alphabet*/ + for(i = 0; i != HCLEN + 4; ++i) addBitsToStream(bp, out, bitlen_cl.data[i], 3); + + /*write the lenghts of the lit/len AND the dist alphabet*/ + for(i = 0; i != bitlen_lld_e.size; ++i) + { + addHuffmanSymbol(bp, out, HuffmanTree_getCode(&tree_cl, bitlen_lld_e.data[i]), + HuffmanTree_getLength(&tree_cl, bitlen_lld_e.data[i])); + /*extra bits of repeat codes*/ + if(bitlen_lld_e.data[i] == 16) addBitsToStream(bp, out, bitlen_lld_e.data[++i], 2); + else if(bitlen_lld_e.data[i] == 17) addBitsToStream(bp, out, bitlen_lld_e.data[++i], 3); + else if(bitlen_lld_e.data[i] == 18) addBitsToStream(bp, out, bitlen_lld_e.data[++i], 7); + } + + /*write the compressed data symbols*/ + writeLZ77data(bp, out, &lz77_encoded, &tree_ll, &tree_d); + /*error: the length of the end code 256 must be larger than 0*/ + if(HuffmanTree_getLength(&tree_ll, 256) == 0) ERROR_BREAK(64); + + /*write the end code*/ + addHuffmanSymbol(bp, out, HuffmanTree_getCode(&tree_ll, 256), HuffmanTree_getLength(&tree_ll, 256)); + + break; /*end of error-while*/ + } + + /*cleanup*/ + uivector_cleanup(&lz77_encoded); + HuffmanTree_cleanup(&tree_ll); + HuffmanTree_cleanup(&tree_d); + HuffmanTree_cleanup(&tree_cl); + uivector_cleanup(&frequencies_ll); + uivector_cleanup(&frequencies_d); + uivector_cleanup(&frequencies_cl); + uivector_cleanup(&bitlen_lld_e); + uivector_cleanup(&bitlen_lld); + uivector_cleanup(&bitlen_cl); + + return error; +} + +static unsigned deflateFixed(ucvector* out, size_t* bp, Hash* hash, + const unsigned char* data, + size_t datapos, size_t dataend, + const LodePNGCompressSettings* settings, unsigned final) +{ + HuffmanTree tree_ll; /*tree for literal values and length codes*/ + HuffmanTree tree_d; /*tree for distance codes*/ + + unsigned BFINAL = final; + unsigned error = 0; + size_t i; + + HuffmanTree_init(&tree_ll); + HuffmanTree_init(&tree_d); + + generateFixedLitLenTree(&tree_ll); + generateFixedDistanceTree(&tree_d); + + addBitToStream(bp, out, BFINAL); + addBitToStream(bp, out, 1); /*first bit of BTYPE*/ + addBitToStream(bp, out, 0); /*second bit of BTYPE*/ + + if(settings->use_lz77) /*LZ77 encoded*/ + { + uivector lz77_encoded; + uivector_init(&lz77_encoded); + error = encodeLZ77(&lz77_encoded, hash, data, datapos, dataend, settings->windowsize, + settings->minmatch, settings->nicematch, settings->lazymatching); + if(!error) writeLZ77data(bp, out, &lz77_encoded, &tree_ll, &tree_d); + uivector_cleanup(&lz77_encoded); + } + else /*no LZ77, but still will be Huffman compressed*/ + { + for(i = datapos; i < dataend; ++i) + { + addHuffmanSymbol(bp, out, HuffmanTree_getCode(&tree_ll, data[i]), HuffmanTree_getLength(&tree_ll, data[i])); + } + } + /*add END code*/ + if(!error) addHuffmanSymbol(bp, out, HuffmanTree_getCode(&tree_ll, 256), HuffmanTree_getLength(&tree_ll, 256)); + + /*cleanup*/ + HuffmanTree_cleanup(&tree_ll); + HuffmanTree_cleanup(&tree_d); + + return error; +} + +static unsigned lodepng_deflatev(ucvector* out, const unsigned char* in, size_t insize, + const LodePNGCompressSettings* settings) +{ + unsigned error = 0; + size_t i, blocksize, numdeflateblocks; + size_t bp = 0; /*the bit pointer*/ + Hash hash; + + if(settings->btype > 2) return 61; + else if(settings->btype == 0) return deflateNoCompression(out, in, insize); + else if(settings->btype == 1) blocksize = insize; + else /*if(settings->btype == 2)*/ + { + /*on PNGs, deflate blocks of 65-262k seem to give most dense encoding*/ + blocksize = insize / 8 + 8; + if(blocksize < 65536) blocksize = 65536; + if(blocksize > 262144) blocksize = 262144; + } + + numdeflateblocks = (insize + blocksize - 1) / blocksize; + if(numdeflateblocks == 0) numdeflateblocks = 1; + + error = hash_init(&hash, settings->windowsize); + if(error) return error; + + for(i = 0; i != numdeflateblocks && !error; ++i) + { + unsigned final = (i == numdeflateblocks - 1); + size_t start = i * blocksize; + size_t end = start + blocksize; + if(end > insize) end = insize; + + if(settings->btype == 1) error = deflateFixed(out, &bp, &hash, in, start, end, settings, final); + else if(settings->btype == 2) error = deflateDynamic(out, &bp, &hash, in, start, end, settings, final); + } + + hash_cleanup(&hash); + + return error; +} + +unsigned lodepng_deflate(unsigned char** out, size_t* outsize, + const unsigned char* in, size_t insize, + const LodePNGCompressSettings* settings) +{ + unsigned error; + ucvector v; + ucvector_init_buffer(&v, *out, *outsize); + error = lodepng_deflatev(&v, in, insize, settings); + *out = v.data; + *outsize = v.size; + return error; +} + +static unsigned deflate(unsigned char** out, size_t* outsize, + const unsigned char* in, size_t insize, + const LodePNGCompressSettings* settings) +{ + if(settings->custom_deflate) + { + return settings->custom_deflate(out, outsize, in, insize, settings); + } + else + { + return lodepng_deflate(out, outsize, in, insize, settings); + } +} + +#endif /*LODEPNG_COMPILE_DECODER*/ + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / Adler32 */ +/* ////////////////////////////////////////////////////////////////////////// */ + +static unsigned update_adler32(unsigned adler, const unsigned char* data, unsigned len) +{ + unsigned s1 = adler & 0xffff; + unsigned s2 = (adler >> 16) & 0xffff; + + while(len > 0) + { + /*at least 5550 sums can be done before the sums overflow, saving a lot of module divisions*/ + unsigned amount = len > 5550 ? 5550 : len; + len -= amount; + while(amount > 0) + { + s1 += (*data++); + s2 += s1; + --amount; + } + s1 %= 65521; + s2 %= 65521; + } + + return (s2 << 16) | s1; +} + +/*Return the adler32 of the bytes data[0..len-1]*/ +static unsigned adler32(const unsigned char* data, unsigned len) +{ + return update_adler32(1L, data, len); +} + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / Zlib / */ +/* ////////////////////////////////////////////////////////////////////////// */ + +#ifdef LODEPNG_COMPILE_DECODER + +unsigned lodepng_zlib_decompress(unsigned char** out, size_t* outsize, const unsigned char* in, + size_t insize, const LodePNGDecompressSettings* settings) +{ + unsigned error = 0; + unsigned CM, CINFO, FDICT; + + if(insize < 2) return 53; /*error, size of zlib data too small*/ + /*read information from zlib header*/ + if((in[0] * 256 + in[1]) % 31 != 0) + { + /*error: 256 * in[0] + in[1] must be a multiple of 31, the FCHECK value is supposed to be made that way*/ + return 24; + } + + CM = in[0] & 15; + CINFO = (in[0] >> 4) & 15; + /*FCHECK = in[1] & 31;*/ /*FCHECK is already tested above*/ + FDICT = (in[1] >> 5) & 1; + /*FLEVEL = (in[1] >> 6) & 3;*/ /*FLEVEL is not used here*/ + + if(CM != 8 || CINFO > 7) + { + /*error: only compression method 8: inflate with sliding window of 32k is supported by the PNG spec*/ + return 25; + } + if(FDICT != 0) + { + /*error: the specification of PNG says about the zlib stream: + "The additional flags shall not specify a preset dictionary."*/ + return 26; + } + + error = inflate(out, outsize, in + 2, insize - 2, settings); + if(error) return error; + + if(!settings->ignore_adler32) + { + unsigned ADLER32 = lodepng_read32bitInt(&in[insize - 4]); + unsigned checksum = adler32(*out, (unsigned)(*outsize)); + if(checksum != ADLER32) return 58; /*error, adler checksum not correct, data must be corrupted*/ + } + + return 0; /*no error*/ +} + +static unsigned zlib_decompress(unsigned char** out, size_t* outsize, const unsigned char* in, + size_t insize, const LodePNGDecompressSettings* settings) +{ + if(settings->custom_zlib) + { + return settings->custom_zlib(out, outsize, in, insize, settings); + } + else + { + return lodepng_zlib_decompress(out, outsize, in, insize, settings); + } +} + +#endif /*LODEPNG_COMPILE_DECODER*/ + +#ifdef LODEPNG_COMPILE_ENCODER + +unsigned lodepng_zlib_compress(unsigned char** out, size_t* outsize, const unsigned char* in, + size_t insize, const LodePNGCompressSettings* settings) +{ + /*initially, *out must be NULL and outsize 0, if you just give some random *out + that's pointing to a non allocated buffer, this'll crash*/ + ucvector outv; + size_t i; + unsigned error; + unsigned char* deflatedata = 0; + size_t deflatesize = 0; + + /*zlib data: 1 byte CMF (CM+CINFO), 1 byte FLG, deflate data, 4 byte ADLER32 checksum of the Decompressed data*/ + unsigned CMF = 120; /*0b01111000: CM 8, CINFO 7. With CINFO 7, any window size up to 32768 can be used.*/ + unsigned FLEVEL = 0; + unsigned FDICT = 0; + unsigned CMFFLG = 256 * CMF + FDICT * 32 + FLEVEL * 64; + unsigned FCHECK = 31 - CMFFLG % 31; + CMFFLG += FCHECK; + + /*ucvector-controlled version of the output buffer, for dynamic array*/ + ucvector_init_buffer(&outv, *out, *outsize); + + ucvector_push_back(&outv, (unsigned char)(CMFFLG >> 8)); + ucvector_push_back(&outv, (unsigned char)(CMFFLG & 255)); + + error = deflate(&deflatedata, &deflatesize, in, insize, settings); + + if(!error) + { + unsigned ADLER32 = adler32(in, (unsigned)insize); + for(i = 0; i != deflatesize; ++i) ucvector_push_back(&outv, deflatedata[i]); + lodepng_free(deflatedata); + lodepng_add32bitInt(&outv, ADLER32); + } + + *out = outv.data; + *outsize = outv.size; + + return error; +} + +/* compress using the default or custom zlib function */ +static unsigned zlib_compress(unsigned char** out, size_t* outsize, const unsigned char* in, + size_t insize, const LodePNGCompressSettings* settings) +{ + if(settings->custom_zlib) + { + return settings->custom_zlib(out, outsize, in, insize, settings); + } + else + { + return lodepng_zlib_compress(out, outsize, in, insize, settings); + } +} + +#endif /*LODEPNG_COMPILE_ENCODER*/ + +#else /*no LODEPNG_COMPILE_ZLIB*/ + +#ifdef LODEPNG_COMPILE_DECODER +static unsigned zlib_decompress(unsigned char** out, size_t* outsize, const unsigned char* in, + size_t insize, const LodePNGDecompressSettings* settings) +{ + if(!settings->custom_zlib) return 87; /*no custom zlib function provided */ + return settings->custom_zlib(out, outsize, in, insize, settings); +} +#endif /*LODEPNG_COMPILE_DECODER*/ +#ifdef LODEPNG_COMPILE_ENCODER +static unsigned zlib_compress(unsigned char** out, size_t* outsize, const unsigned char* in, + size_t insize, const LodePNGCompressSettings* settings) +{ + if(!settings->custom_zlib) return 87; /*no custom zlib function provided */ + return settings->custom_zlib(out, outsize, in, insize, settings); +} +#endif /*LODEPNG_COMPILE_ENCODER*/ + +#endif /*LODEPNG_COMPILE_ZLIB*/ + +/* ////////////////////////////////////////////////////////////////////////// */ + +#ifdef LODEPNG_COMPILE_ENCODER + +/*this is a good tradeoff between speed and compression ratio*/ +#define DEFAULT_WINDOWSIZE 2048 + +void lodepng_compress_settings_init(LodePNGCompressSettings* settings) +{ + /*compress with dynamic huffman tree (not in the mathematical sense, just not the predefined one)*/ + settings->btype = 2; + settings->use_lz77 = 1; + settings->windowsize = DEFAULT_WINDOWSIZE; + settings->minmatch = 3; + settings->nicematch = 128; + settings->lazymatching = 1; + + settings->custom_zlib = 0; + settings->custom_deflate = 0; + settings->custom_context = 0; +} + +const LodePNGCompressSettings lodepng_default_compress_settings = {2, 1, DEFAULT_WINDOWSIZE, 3, 128, 1, 0, 0, 0}; + + +#endif /*LODEPNG_COMPILE_ENCODER*/ + +#ifdef LODEPNG_COMPILE_DECODER + +void lodepng_decompress_settings_init(LodePNGDecompressSettings* settings) +{ + settings->ignore_adler32 = 0; + + settings->custom_zlib = 0; + settings->custom_inflate = 0; + settings->custom_context = 0; +} + +const LodePNGDecompressSettings lodepng_default_decompress_settings = {0, 0, 0, 0}; + +#endif /*LODEPNG_COMPILE_DECODER*/ + +/* ////////////////////////////////////////////////////////////////////////// */ +/* ////////////////////////////////////////////////////////////////////////// */ +/* // End of Zlib related code. Begin of PNG related code. // */ +/* ////////////////////////////////////////////////////////////////////////// */ +/* ////////////////////////////////////////////////////////////////////////// */ + +#ifdef LODEPNG_COMPILE_PNG + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / CRC32 / */ +/* ////////////////////////////////////////////////////////////////////////// */ + + +#ifndef LODEPNG_NO_COMPILE_CRC +/* CRC polynomial: 0xedb88320 */ +static unsigned lodepng_crc32_table[256] = { + 0u, 1996959894u, 3993919788u, 2567524794u, 124634137u, 1886057615u, 3915621685u, 2657392035u, + 249268274u, 2044508324u, 3772115230u, 2547177864u, 162941995u, 2125561021u, 3887607047u, 2428444049u, + 498536548u, 1789927666u, 4089016648u, 2227061214u, 450548861u, 1843258603u, 4107580753u, 2211677639u, + 325883990u, 1684777152u, 4251122042u, 2321926636u, 335633487u, 1661365465u, 4195302755u, 2366115317u, + 997073096u, 1281953886u, 3579855332u, 2724688242u, 1006888145u, 1258607687u, 3524101629u, 2768942443u, + 901097722u, 1119000684u, 3686517206u, 2898065728u, 853044451u, 1172266101u, 3705015759u, 2882616665u, + 651767980u, 1373503546u, 3369554304u, 3218104598u, 565507253u, 1454621731u, 3485111705u, 3099436303u, + 671266974u, 1594198024u, 3322730930u, 2970347812u, 795835527u, 1483230225u, 3244367275u, 3060149565u, + 1994146192u, 31158534u, 2563907772u, 4023717930u, 1907459465u, 112637215u, 2680153253u, 3904427059u, + 2013776290u, 251722036u, 2517215374u, 3775830040u, 2137656763u, 141376813u, 2439277719u, 3865271297u, + 1802195444u, 476864866u, 2238001368u, 4066508878u, 1812370925u, 453092731u, 2181625025u, 4111451223u, + 1706088902u, 314042704u, 2344532202u, 4240017532u, 1658658271u, 366619977u, 2362670323u, 4224994405u, + 1303535960u, 984961486u, 2747007092u, 3569037538u, 1256170817u, 1037604311u, 2765210733u, 3554079995u, + 1131014506u, 879679996u, 2909243462u, 3663771856u, 1141124467u, 855842277u, 2852801631u, 3708648649u, + 1342533948u, 654459306u, 3188396048u, 3373015174u, 1466479909u, 544179635u, 3110523913u, 3462522015u, + 1591671054u, 702138776u, 2966460450u, 3352799412u, 1504918807u, 783551873u, 3082640443u, 3233442989u, + 3988292384u, 2596254646u, 62317068u, 1957810842u, 3939845945u, 2647816111u, 81470997u, 1943803523u, + 3814918930u, 2489596804u, 225274430u, 2053790376u, 3826175755u, 2466906013u, 167816743u, 2097651377u, + 4027552580u, 2265490386u, 503444072u, 1762050814u, 4150417245u, 2154129355u, 426522225u, 1852507879u, + 4275313526u, 2312317920u, 282753626u, 1742555852u, 4189708143u, 2394877945u, 397917763u, 1622183637u, + 3604390888u, 2714866558u, 953729732u, 1340076626u, 3518719985u, 2797360999u, 1068828381u, 1219638859u, + 3624741850u, 2936675148u, 906185462u, 1090812512u, 3747672003u, 2825379669u, 829329135u, 1181335161u, + 3412177804u, 3160834842u, 628085408u, 1382605366u, 3423369109u, 3138078467u, 570562233u, 1426400815u, + 3317316542u, 2998733608u, 733239954u, 1555261956u, 3268935591u, 3050360625u, 752459403u, 1541320221u, + 2607071920u, 3965973030u, 1969922972u, 40735498u, 2617837225u, 3943577151u, 1913087877u, 83908371u, + 2512341634u, 3803740692u, 2075208622u, 213261112u, 2463272603u, 3855990285u, 2094854071u, 198958881u, + 2262029012u, 4057260610u, 1759359992u, 534414190u, 2176718541u, 4139329115u, 1873836001u, 414664567u, + 2282248934u, 4279200368u, 1711684554u, 285281116u, 2405801727u, 4167216745u, 1634467795u, 376229701u, + 2685067896u, 3608007406u, 1308918612u, 956543938u, 2808555105u, 3495958263u, 1231636301u, 1047427035u, + 2932959818u, 3654703836u, 1088359270u, 936918000u, 2847714899u, 3736837829u, 1202900863u, 817233897u, + 3183342108u, 3401237130u, 1404277552u, 615818150u, 3134207493u, 3453421203u, 1423857449u, 601450431u, + 3009837614u, 3294710456u, 1567103746u, 711928724u, 3020668471u, 3272380065u, 1510334235u, 755167117u +}; + +/*Return the CRC of the bytes buf[0..len-1].*/ +unsigned lodepng_crc32(const unsigned char* data, size_t length) +{ + unsigned r = 0xffffffffu; + size_t i; + for(i = 0; i < length; ++i) + { + r = lodepng_crc32_table[(r ^ data[i]) & 0xff] ^ (r >> 8); + } + return r ^ 0xffffffffu; +} +#else /* !LODEPNG_NO_COMPILE_CRC */ +unsigned lodepng_crc32(const unsigned char* data, size_t length); +#endif /* !LODEPNG_NO_COMPILE_CRC */ + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / Reading and writing single bits and bytes from/to stream for LodePNG / */ +/* ////////////////////////////////////////////////////////////////////////// */ + +static unsigned char readBitFromReversedStream(size_t* bitpointer, const unsigned char* bitstream) +{ + unsigned char result = (unsigned char)((bitstream[(*bitpointer) >> 3] >> (7 - ((*bitpointer) & 0x7))) & 1); + ++(*bitpointer); + return result; +} + +static unsigned readBitsFromReversedStream(size_t* bitpointer, const unsigned char* bitstream, size_t nbits) +{ + unsigned result = 0; + size_t i; + for(i = nbits - 1; i < nbits; --i) + { + result += (unsigned)readBitFromReversedStream(bitpointer, bitstream) << i; + } + return result; +} + +#ifdef LODEPNG_COMPILE_DECODER +static void setBitOfReversedStream0(size_t* bitpointer, unsigned char* bitstream, unsigned char bit) +{ + /*the current bit in bitstream must be 0 for this to work*/ + if(bit) + { + /*earlier bit of huffman code is in a lesser significant bit of an earlier byte*/ + bitstream[(*bitpointer) >> 3] |= (bit << (7 - ((*bitpointer) & 0x7))); + } + ++(*bitpointer); +} +#endif /*LODEPNG_COMPILE_DECODER*/ + +static void setBitOfReversedStream(size_t* bitpointer, unsigned char* bitstream, unsigned char bit) +{ + /*the current bit in bitstream may be 0 or 1 for this to work*/ + if(bit == 0) bitstream[(*bitpointer) >> 3] &= (unsigned char)(~(1 << (7 - ((*bitpointer) & 0x7)))); + else bitstream[(*bitpointer) >> 3] |= (1 << (7 - ((*bitpointer) & 0x7))); + ++(*bitpointer); +} + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / PNG chunks / */ +/* ////////////////////////////////////////////////////////////////////////// */ + +unsigned lodepng_chunk_length(const unsigned char* chunk) +{ + return lodepng_read32bitInt(&chunk[0]); +} + +void lodepng_chunk_type(char type[5], const unsigned char* chunk) +{ + unsigned i; + for(i = 0; i != 4; ++i) type[i] = (char)chunk[4 + i]; + type[4] = 0; /*null termination char*/ +} + +unsigned char lodepng_chunk_type_equals(const unsigned char* chunk, const char* type) +{ + if(strlen(type) != 4) return 0; + return (chunk[4] == type[0] && chunk[5] == type[1] && chunk[6] == type[2] && chunk[7] == type[3]); +} + +unsigned char lodepng_chunk_ancillary(const unsigned char* chunk) +{ + return((chunk[4] & 32) != 0); +} + +unsigned char lodepng_chunk_private(const unsigned char* chunk) +{ + return((chunk[6] & 32) != 0); +} + +unsigned char lodepng_chunk_safetocopy(const unsigned char* chunk) +{ + return((chunk[7] & 32) != 0); +} + +unsigned char* lodepng_chunk_data(unsigned char* chunk) +{ + return &chunk[8]; +} + +const unsigned char* lodepng_chunk_data_const(const unsigned char* chunk) +{ + return &chunk[8]; +} + +unsigned lodepng_chunk_check_crc(const unsigned char* chunk) +{ + unsigned length = lodepng_chunk_length(chunk); + unsigned CRC = lodepng_read32bitInt(&chunk[length + 8]); + /*the CRC is taken of the data and the 4 chunk type letters, not the length*/ + unsigned checksum = lodepng_crc32(&chunk[4], length + 4); + if(CRC != checksum) return 1; + else return 0; +} + +void lodepng_chunk_generate_crc(unsigned char* chunk) +{ + unsigned length = lodepng_chunk_length(chunk); + unsigned CRC = lodepng_crc32(&chunk[4], length + 4); + lodepng_set32bitInt(chunk + 8 + length, CRC); +} + +unsigned char* lodepng_chunk_next(unsigned char* chunk) +{ + unsigned total_chunk_length = lodepng_chunk_length(chunk) + 12; + return &chunk[total_chunk_length]; +} + +const unsigned char* lodepng_chunk_next_const(const unsigned char* chunk) +{ + unsigned total_chunk_length = lodepng_chunk_length(chunk) + 12; + return &chunk[total_chunk_length]; +} + +unsigned lodepng_chunk_append(unsigned char** out, size_t* outlength, const unsigned char* chunk) +{ + unsigned i; + unsigned total_chunk_length = lodepng_chunk_length(chunk) + 12; + unsigned char *chunk_start, *new_buffer; + size_t new_length = (*outlength) + total_chunk_length; + if(new_length < total_chunk_length || new_length < (*outlength)) return 77; /*integer overflow happened*/ + + new_buffer = (unsigned char*)lodepng_realloc(*out, new_length); + if(!new_buffer) return 83; /*alloc fail*/ + (*out) = new_buffer; + (*outlength) = new_length; + chunk_start = &(*out)[new_length - total_chunk_length]; + + for(i = 0; i != total_chunk_length; ++i) chunk_start[i] = chunk[i]; + + return 0; +} + +unsigned lodepng_chunk_create(unsigned char** out, size_t* outlength, unsigned length, + const char* type, const unsigned char* data) +{ + unsigned i; + unsigned char *chunk, *new_buffer; + size_t new_length = (*outlength) + length + 12; + if(new_length < length + 12 || new_length < (*outlength)) return 77; /*integer overflow happened*/ + new_buffer = (unsigned char*)lodepng_realloc(*out, new_length); + if(!new_buffer) return 83; /*alloc fail*/ + (*out) = new_buffer; + (*outlength) = new_length; + chunk = &(*out)[(*outlength) - length - 12]; + + /*1: length*/ + lodepng_set32bitInt(chunk, (unsigned)length); + + /*2: chunk name (4 letters)*/ + chunk[4] = (unsigned char)type[0]; + chunk[5] = (unsigned char)type[1]; + chunk[6] = (unsigned char)type[2]; + chunk[7] = (unsigned char)type[3]; + + /*3: the data*/ + for(i = 0; i != length; ++i) chunk[8 + i] = data[i]; + + /*4: CRC (of the chunkname characters and the data)*/ + lodepng_chunk_generate_crc(chunk); + + return 0; +} + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / Color types and such / */ +/* ////////////////////////////////////////////////////////////////////////// */ + +/*return type is a LodePNG error code*/ +static unsigned checkColorValidity(LodePNGColorType colortype, unsigned bd) /*bd = bitdepth*/ +{ + switch(colortype) + { + case 0: if(!(bd == 1 || bd == 2 || bd == 4 || bd == 8 || bd == 16)) return 37; break; /*grey*/ + case 2: if(!( bd == 8 || bd == 16)) return 37; break; /*RGB*/ + case 3: if(!(bd == 1 || bd == 2 || bd == 4 || bd == 8 )) return 37; break; /*palette*/ + case 4: if(!( bd == 8 || bd == 16)) return 37; break; /*grey + alpha*/ + case 6: if(!( bd == 8 || bd == 16)) return 37; break; /*RGBA*/ + default: return 31; + } + return 0; /*allowed color type / bits combination*/ +} + +static unsigned getNumColorChannels(LodePNGColorType colortype) +{ + switch(colortype) + { + case 0: return 1; /*grey*/ + case 2: return 3; /*RGB*/ + case 3: return 1; /*palette*/ + case 4: return 2; /*grey + alpha*/ + case 6: return 4; /*RGBA*/ + } + return 0; /*unexisting color type*/ +} + +static unsigned lodepng_get_bpp_lct(LodePNGColorType colortype, unsigned bitdepth) +{ + /*bits per pixel is amount of channels * bits per channel*/ + return getNumColorChannels(colortype) * bitdepth; +} + +/* ////////////////////////////////////////////////////////////////////////// */ + +void lodepng_color_mode_init(LodePNGColorMode* info) +{ + info->key_defined = 0; + info->key_r = info->key_g = info->key_b = 0; + info->colortype = LCT_RGBA; + info->bitdepth = 8; + info->palette = 0; + info->palettesize = 0; +} + +void lodepng_color_mode_cleanup(LodePNGColorMode* info) +{ + lodepng_palette_clear(info); +} + +unsigned lodepng_color_mode_copy(LodePNGColorMode* dest, const LodePNGColorMode* source) +{ + size_t i; + lodepng_color_mode_cleanup(dest); + *dest = *source; + if(source->palette) + { + dest->palette = (unsigned char*)lodepng_malloc(1024); + if(!dest->palette && source->palettesize) return 83; /*alloc fail*/ + for(i = 0; i != source->palettesize * 4; ++i) dest->palette[i] = source->palette[i]; + } + return 0; +} + +static int lodepng_color_mode_equal(const LodePNGColorMode* a, const LodePNGColorMode* b) +{ + size_t i; + if(a->colortype != b->colortype) return 0; + if(a->bitdepth != b->bitdepth) return 0; + if(a->key_defined != b->key_defined) return 0; + if(a->key_defined) + { + if(a->key_r != b->key_r) return 0; + if(a->key_g != b->key_g) return 0; + if(a->key_b != b->key_b) return 0; + } + /*if one of the palette sizes is 0, then we consider it to be the same as the + other: it means that e.g. the palette was not given by the user and should be + considered the same as the palette inside the PNG.*/ + if(1/*a->palettesize != 0 && b->palettesize != 0*/) { + if(a->palettesize != b->palettesize) return 0; + for(i = 0; i != a->palettesize * 4; ++i) + { + if(a->palette[i] != b->palette[i]) return 0; + } + } + return 1; +} + +void lodepng_palette_clear(LodePNGColorMode* info) +{ + if(info->palette) lodepng_free(info->palette); + info->palette = 0; + info->palettesize = 0; +} + +unsigned lodepng_palette_add(LodePNGColorMode* info, + unsigned char r, unsigned char g, unsigned char b, unsigned char a) +{ + unsigned char* data; + /*the same resize technique as C++ std::vectors is used, and here it's made so that for a palette with + the max of 256 colors, it'll have the exact alloc size*/ + if(!info->palette) /*allocate palette if empty*/ + { + /*room for 256 colors with 4 bytes each*/ + data = (unsigned char*)lodepng_realloc(info->palette, 1024); + if(!data) return 83; /*alloc fail*/ + else info->palette = data; + } + info->palette[4 * info->palettesize + 0] = r; + info->palette[4 * info->palettesize + 1] = g; + info->palette[4 * info->palettesize + 2] = b; + info->palette[4 * info->palettesize + 3] = a; + ++info->palettesize; + return 0; +} + +unsigned lodepng_get_bpp(const LodePNGColorMode* info) +{ + /*calculate bits per pixel out of colortype and bitdepth*/ + return lodepng_get_bpp_lct(info->colortype, info->bitdepth); +} + +unsigned lodepng_get_channels(const LodePNGColorMode* info) +{ + return getNumColorChannels(info->colortype); +} + +unsigned lodepng_is_greyscale_type(const LodePNGColorMode* info) +{ + return info->colortype == LCT_GREY || info->colortype == LCT_GREY_ALPHA; +} + +unsigned lodepng_is_alpha_type(const LodePNGColorMode* info) +{ + return (info->colortype & 4) != 0; /*4 or 6*/ +} + +unsigned lodepng_is_palette_type(const LodePNGColorMode* info) +{ + return info->colortype == LCT_PALETTE; +} + +unsigned lodepng_has_palette_alpha(const LodePNGColorMode* info) +{ + size_t i; + for(i = 0; i != info->palettesize; ++i) + { + if(info->palette[i * 4 + 3] < 255) return 1; + } + return 0; +} + +unsigned lodepng_can_have_alpha(const LodePNGColorMode* info) +{ + return info->key_defined + || lodepng_is_alpha_type(info) + || lodepng_has_palette_alpha(info); +} + +size_t lodepng_get_raw_size(unsigned w, unsigned h, const LodePNGColorMode* color) +{ + /*will not overflow for any color type if roughly w * h < 268435455*/ + size_t bpp = lodepng_get_bpp(color); + size_t n = w * h; + return ((n / 8) * bpp) + ((n & 7) * bpp + 7) / 8; +} + +size_t lodepng_get_raw_size_lct(unsigned w, unsigned h, LodePNGColorType colortype, unsigned bitdepth) +{ + /*will not overflow for any color type if roughly w * h < 268435455*/ + size_t bpp = lodepng_get_bpp_lct(colortype, bitdepth); + size_t n = w * h; + return ((n / 8) * bpp) + ((n & 7) * bpp + 7) / 8; +} + + +#ifdef LODEPNG_COMPILE_PNG +#ifdef LODEPNG_COMPILE_DECODER +/*in an idat chunk, each scanline is a multiple of 8 bits, unlike the lodepng output buffer*/ +static size_t lodepng_get_raw_size_idat(unsigned w, unsigned h, const LodePNGColorMode* color) +{ + /*will not overflow for any color type if roughly w * h < 268435455*/ + size_t bpp = lodepng_get_bpp(color); + size_t line = ((w / 8) * bpp) + ((w & 7) * bpp + 7) / 8; + return h * line; +} +#endif /*LODEPNG_COMPILE_DECODER*/ +#endif /*LODEPNG_COMPILE_PNG*/ + +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + +static void LodePNGUnknownChunks_init(LodePNGInfo* info) +{ + unsigned i; + for(i = 0; i != 3; ++i) info->unknown_chunks_data[i] = 0; + for(i = 0; i != 3; ++i) info->unknown_chunks_size[i] = 0; +} + +static void LodePNGUnknownChunks_cleanup(LodePNGInfo* info) +{ + unsigned i; + for(i = 0; i != 3; ++i) lodepng_free(info->unknown_chunks_data[i]); +} + +static unsigned LodePNGUnknownChunks_copy(LodePNGInfo* dest, const LodePNGInfo* src) +{ + unsigned i; + + LodePNGUnknownChunks_cleanup(dest); + + for(i = 0; i != 3; ++i) + { + size_t j; + dest->unknown_chunks_size[i] = src->unknown_chunks_size[i]; + dest->unknown_chunks_data[i] = (unsigned char*)lodepng_malloc(src->unknown_chunks_size[i]); + if(!dest->unknown_chunks_data[i] && dest->unknown_chunks_size[i]) return 83; /*alloc fail*/ + for(j = 0; j < src->unknown_chunks_size[i]; ++j) + { + dest->unknown_chunks_data[i][j] = src->unknown_chunks_data[i][j]; + } + } + + return 0; +} + +/******************************************************************************/ + +static void LodePNGText_init(LodePNGInfo* info) +{ + info->text_num = 0; + info->text_keys = NULL; + info->text_strings = NULL; +} + +static void LodePNGText_cleanup(LodePNGInfo* info) +{ + size_t i; + for(i = 0; i != info->text_num; ++i) + { + string_cleanup(&info->text_keys[i]); + string_cleanup(&info->text_strings[i]); + } + lodepng_free(info->text_keys); + lodepng_free(info->text_strings); +} + +static unsigned LodePNGText_copy(LodePNGInfo* dest, const LodePNGInfo* source) +{ + size_t i = 0; + dest->text_keys = 0; + dest->text_strings = 0; + dest->text_num = 0; + for(i = 0; i != source->text_num; ++i) + { + CERROR_TRY_RETURN(lodepng_add_text(dest, source->text_keys[i], source->text_strings[i])); + } + return 0; +} + +void lodepng_clear_text(LodePNGInfo* info) +{ + LodePNGText_cleanup(info); +} + +unsigned lodepng_add_text(LodePNGInfo* info, const char* key, const char* str) +{ + char** new_keys = (char**)(lodepng_realloc(info->text_keys, sizeof(char*) * (info->text_num + 1))); + char** new_strings = (char**)(lodepng_realloc(info->text_strings, sizeof(char*) * (info->text_num + 1))); + if(!new_keys || !new_strings) + { + lodepng_free(new_keys); + lodepng_free(new_strings); + return 83; /*alloc fail*/ + } + + ++info->text_num; + info->text_keys = new_keys; + info->text_strings = new_strings; + + string_init(&info->text_keys[info->text_num - 1]); + string_set(&info->text_keys[info->text_num - 1], key); + + string_init(&info->text_strings[info->text_num - 1]); + string_set(&info->text_strings[info->text_num - 1], str); + + return 0; +} + +/******************************************************************************/ + +static void LodePNGIText_init(LodePNGInfo* info) +{ + info->itext_num = 0; + info->itext_keys = NULL; + info->itext_langtags = NULL; + info->itext_transkeys = NULL; + info->itext_strings = NULL; +} + +static void LodePNGIText_cleanup(LodePNGInfo* info) +{ + size_t i; + for(i = 0; i != info->itext_num; ++i) + { + string_cleanup(&info->itext_keys[i]); + string_cleanup(&info->itext_langtags[i]); + string_cleanup(&info->itext_transkeys[i]); + string_cleanup(&info->itext_strings[i]); + } + lodepng_free(info->itext_keys); + lodepng_free(info->itext_langtags); + lodepng_free(info->itext_transkeys); + lodepng_free(info->itext_strings); +} + +static unsigned LodePNGIText_copy(LodePNGInfo* dest, const LodePNGInfo* source) +{ + size_t i = 0; + dest->itext_keys = 0; + dest->itext_langtags = 0; + dest->itext_transkeys = 0; + dest->itext_strings = 0; + dest->itext_num = 0; + for(i = 0; i != source->itext_num; ++i) + { + CERROR_TRY_RETURN(lodepng_add_itext(dest, source->itext_keys[i], source->itext_langtags[i], + source->itext_transkeys[i], source->itext_strings[i])); + } + return 0; +} + +void lodepng_clear_itext(LodePNGInfo* info) +{ + LodePNGIText_cleanup(info); +} + +unsigned lodepng_add_itext(LodePNGInfo* info, const char* key, const char* langtag, + const char* transkey, const char* str) +{ + char** new_keys = (char**)(lodepng_realloc(info->itext_keys, sizeof(char*) * (info->itext_num + 1))); + char** new_langtags = (char**)(lodepng_realloc(info->itext_langtags, sizeof(char*) * (info->itext_num + 1))); + char** new_transkeys = (char**)(lodepng_realloc(info->itext_transkeys, sizeof(char*) * (info->itext_num + 1))); + char** new_strings = (char**)(lodepng_realloc(info->itext_strings, sizeof(char*) * (info->itext_num + 1))); + if(!new_keys || !new_langtags || !new_transkeys || !new_strings) + { + lodepng_free(new_keys); + lodepng_free(new_langtags); + lodepng_free(new_transkeys); + lodepng_free(new_strings); + return 83; /*alloc fail*/ + } + + ++info->itext_num; + info->itext_keys = new_keys; + info->itext_langtags = new_langtags; + info->itext_transkeys = new_transkeys; + info->itext_strings = new_strings; + + string_init(&info->itext_keys[info->itext_num - 1]); + string_set(&info->itext_keys[info->itext_num - 1], key); + + string_init(&info->itext_langtags[info->itext_num - 1]); + string_set(&info->itext_langtags[info->itext_num - 1], langtag); + + string_init(&info->itext_transkeys[info->itext_num - 1]); + string_set(&info->itext_transkeys[info->itext_num - 1], transkey); + + string_init(&info->itext_strings[info->itext_num - 1]); + string_set(&info->itext_strings[info->itext_num - 1], str); + + return 0; +} +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + +void lodepng_info_init(LodePNGInfo* info) +{ + lodepng_color_mode_init(&info->color); + info->interlace_method = 0; + info->compression_method = 0; + info->filter_method = 0; +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + info->background_defined = 0; + info->background_r = info->background_g = info->background_b = 0; + + LodePNGText_init(info); + LodePNGIText_init(info); + + info->time_defined = 0; + info->phys_defined = 0; + + LodePNGUnknownChunks_init(info); +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ +} + +void lodepng_info_cleanup(LodePNGInfo* info) +{ + lodepng_color_mode_cleanup(&info->color); +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + LodePNGText_cleanup(info); + LodePNGIText_cleanup(info); + + LodePNGUnknownChunks_cleanup(info); +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ +} + +unsigned lodepng_info_copy(LodePNGInfo* dest, const LodePNGInfo* source) +{ + lodepng_info_cleanup(dest); + *dest = *source; + lodepng_color_mode_init(&dest->color); + CERROR_TRY_RETURN(lodepng_color_mode_copy(&dest->color, &source->color)); + +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + CERROR_TRY_RETURN(LodePNGText_copy(dest, source)); + CERROR_TRY_RETURN(LodePNGIText_copy(dest, source)); + + LodePNGUnknownChunks_init(dest); + CERROR_TRY_RETURN(LodePNGUnknownChunks_copy(dest, source)); +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + return 0; +} + +void lodepng_info_swap(LodePNGInfo* a, LodePNGInfo* b) +{ + LodePNGInfo temp = *a; + *a = *b; + *b = temp; +} + +/* ////////////////////////////////////////////////////////////////////////// */ + +/*index: bitgroup index, bits: bitgroup size(1, 2 or 4), in: bitgroup value, out: octet array to add bits to*/ +static void addColorBits(unsigned char* out, size_t index, unsigned bits, unsigned in) +{ + unsigned m = bits == 1 ? 7 : bits == 2 ? 3 : 1; /*8 / bits - 1*/ + /*p = the partial index in the byte, e.g. with 4 palettebits it is 0 for first half or 1 for second half*/ + unsigned p = index & m; + in &= (1u << bits) - 1u; /*filter out any other bits of the input value*/ + in = in << (bits * (m - p)); + if(p == 0) out[index * bits / 8] = in; + else out[index * bits / 8] |= in; +} + +typedef struct ColorTree ColorTree; + +/* +One node of a color tree +This is the data structure used to count the number of unique colors and to get a palette +index for a color. It's like an octree, but because the alpha channel is used too, each +node has 16 instead of 8 children. +*/ +struct ColorTree +{ + ColorTree* children[16]; /*up to 16 pointers to ColorTree of next level*/ + int index; /*the payload. Only has a meaningful value if this is in the last level*/ +}; + +static void color_tree_init(ColorTree* tree) +{ + int i; + for(i = 0; i != 16; ++i) tree->children[i] = 0; + tree->index = -1; +} + +static void color_tree_cleanup(ColorTree* tree) +{ + int i; + for(i = 0; i != 16; ++i) + { + if(tree->children[i]) + { + color_tree_cleanup(tree->children[i]); + lodepng_free(tree->children[i]); + } + } +} + +/*returns -1 if color not present, its index otherwise*/ +static int color_tree_get(ColorTree* tree, unsigned char r, unsigned char g, unsigned char b, unsigned char a) +{ + int bit = 0; + for(bit = 0; bit < 8; ++bit) + { + int i = 8 * ((r >> bit) & 1) + 4 * ((g >> bit) & 1) + 2 * ((b >> bit) & 1) + 1 * ((a >> bit) & 1); + if(!tree->children[i]) return -1; + else tree = tree->children[i]; + } + return tree ? tree->index : -1; +} + +#ifdef LODEPNG_COMPILE_ENCODER +static int color_tree_has(ColorTree* tree, unsigned char r, unsigned char g, unsigned char b, unsigned char a) +{ + return color_tree_get(tree, r, g, b, a) >= 0; +} +#endif /*LODEPNG_COMPILE_ENCODER*/ + +/*color is not allowed to already exist. +Index should be >= 0 (it's signed to be compatible with using -1 for "doesn't exist")*/ +static void color_tree_add(ColorTree* tree, + unsigned char r, unsigned char g, unsigned char b, unsigned char a, unsigned index) +{ + int bit; + for(bit = 0; bit < 8; ++bit) + { + int i = 8 * ((r >> bit) & 1) + 4 * ((g >> bit) & 1) + 2 * ((b >> bit) & 1) + 1 * ((a >> bit) & 1); + if(!tree->children[i]) + { + tree->children[i] = (ColorTree*)lodepng_malloc(sizeof(ColorTree)); + color_tree_init(tree->children[i]); + } + tree = tree->children[i]; + } + tree->index = (int)index; +} + +/*put a pixel, given its RGBA color, into image of any color type*/ +static unsigned rgba8ToPixel(unsigned char* out, size_t i, + const LodePNGColorMode* mode, ColorTree* tree /*for palette*/, + unsigned char r, unsigned char g, unsigned char b, unsigned char a) +{ + if(mode->colortype == LCT_GREY) + { + unsigned char grey = r; /*((unsigned short)r + g + b) / 3*/; + if(mode->bitdepth == 8) out[i] = grey; + else if(mode->bitdepth == 16) out[i * 2 + 0] = out[i * 2 + 1] = grey; + else + { + /*take the most significant bits of grey*/ + grey = (grey >> (8 - mode->bitdepth)) & ((1 << mode->bitdepth) - 1); + addColorBits(out, i, mode->bitdepth, grey); + } + } + else if(mode->colortype == LCT_RGB) + { + if(mode->bitdepth == 8) + { + out[i * 3 + 0] = r; + out[i * 3 + 1] = g; + out[i * 3 + 2] = b; + } + else + { + out[i * 6 + 0] = out[i * 6 + 1] = r; + out[i * 6 + 2] = out[i * 6 + 3] = g; + out[i * 6 + 4] = out[i * 6 + 5] = b; + } + } + else if(mode->colortype == LCT_PALETTE) + { + int index = color_tree_get(tree, r, g, b, a); + if(index < 0) return 82; /*color not in palette*/ + if(mode->bitdepth == 8) out[i] = index; + else addColorBits(out, i, mode->bitdepth, (unsigned)index); + } + else if(mode->colortype == LCT_GREY_ALPHA) + { + unsigned char grey = r; /*((unsigned short)r + g + b) / 3*/; + if(mode->bitdepth == 8) + { + out[i * 2 + 0] = grey; + out[i * 2 + 1] = a; + } + else if(mode->bitdepth == 16) + { + out[i * 4 + 0] = out[i * 4 + 1] = grey; + out[i * 4 + 2] = out[i * 4 + 3] = a; + } + } + else if(mode->colortype == LCT_RGBA) + { + if(mode->bitdepth == 8) + { + out[i * 4 + 0] = r; + out[i * 4 + 1] = g; + out[i * 4 + 2] = b; + out[i * 4 + 3] = a; + } + else + { + out[i * 8 + 0] = out[i * 8 + 1] = r; + out[i * 8 + 2] = out[i * 8 + 3] = g; + out[i * 8 + 4] = out[i * 8 + 5] = b; + out[i * 8 + 6] = out[i * 8 + 7] = a; + } + } + + return 0; /*no error*/ +} + +/*put a pixel, given its RGBA16 color, into image of any color 16-bitdepth type*/ +static void rgba16ToPixel(unsigned char* out, size_t i, + const LodePNGColorMode* mode, + unsigned short r, unsigned short g, unsigned short b, unsigned short a) +{ + if(mode->colortype == LCT_GREY) + { + unsigned short grey = r; /*((unsigned)r + g + b) / 3*/; + out[i * 2 + 0] = (grey >> 8) & 255; + out[i * 2 + 1] = grey & 255; + } + else if(mode->colortype == LCT_RGB) + { + out[i * 6 + 0] = (r >> 8) & 255; + out[i * 6 + 1] = r & 255; + out[i * 6 + 2] = (g >> 8) & 255; + out[i * 6 + 3] = g & 255; + out[i * 6 + 4] = (b >> 8) & 255; + out[i * 6 + 5] = b & 255; + } + else if(mode->colortype == LCT_GREY_ALPHA) + { + unsigned short grey = r; /*((unsigned)r + g + b) / 3*/; + out[i * 4 + 0] = (grey >> 8) & 255; + out[i * 4 + 1] = grey & 255; + out[i * 4 + 2] = (a >> 8) & 255; + out[i * 4 + 3] = a & 255; + } + else if(mode->colortype == LCT_RGBA) + { + out[i * 8 + 0] = (r >> 8) & 255; + out[i * 8 + 1] = r & 255; + out[i * 8 + 2] = (g >> 8) & 255; + out[i * 8 + 3] = g & 255; + out[i * 8 + 4] = (b >> 8) & 255; + out[i * 8 + 5] = b & 255; + out[i * 8 + 6] = (a >> 8) & 255; + out[i * 8 + 7] = a & 255; + } +} + +/*Get RGBA8 color of pixel with index i (y * width + x) from the raw image with given color type.*/ +static void getPixelColorRGBA8(unsigned char* r, unsigned char* g, + unsigned char* b, unsigned char* a, + const unsigned char* in, size_t i, + const LodePNGColorMode* mode) +{ + if(mode->colortype == LCT_GREY) + { + if(mode->bitdepth == 8) + { + *r = *g = *b = in[i]; + if(mode->key_defined && *r == mode->key_r) *a = 0; + else *a = 255; + } + else if(mode->bitdepth == 16) + { + *r = *g = *b = in[i * 2 + 0]; + if(mode->key_defined && 256U * in[i * 2 + 0] + in[i * 2 + 1] == mode->key_r) *a = 0; + else *a = 255; + } + else + { + unsigned highest = ((1U << mode->bitdepth) - 1U); /*highest possible value for this bit depth*/ + size_t j = i * mode->bitdepth; + unsigned value = readBitsFromReversedStream(&j, in, mode->bitdepth); + *r = *g = *b = (value * 255) / highest; + if(mode->key_defined && value == mode->key_r) *a = 0; + else *a = 255; + } + } + else if(mode->colortype == LCT_RGB) + { + if(mode->bitdepth == 8) + { + *r = in[i * 3 + 0]; *g = in[i * 3 + 1]; *b = in[i * 3 + 2]; + if(mode->key_defined && *r == mode->key_r && *g == mode->key_g && *b == mode->key_b) *a = 0; + else *a = 255; + } + else + { + *r = in[i * 6 + 0]; + *g = in[i * 6 + 2]; + *b = in[i * 6 + 4]; + if(mode->key_defined && 256U * in[i * 6 + 0] + in[i * 6 + 1] == mode->key_r + && 256U * in[i * 6 + 2] + in[i * 6 + 3] == mode->key_g + && 256U * in[i * 6 + 4] + in[i * 6 + 5] == mode->key_b) *a = 0; + else *a = 255; + } + } + else if(mode->colortype == LCT_PALETTE) + { + unsigned index; + if(mode->bitdepth == 8) index = in[i]; + else + { + size_t j = i * mode->bitdepth; + index = readBitsFromReversedStream(&j, in, mode->bitdepth); + } + + if(index >= mode->palettesize) + { + /*This is an error according to the PNG spec, but common PNG decoders make it black instead. + Done here too, slightly faster due to no error handling needed.*/ + *r = *g = *b = 0; + *a = 255; + } + else + { + *r = mode->palette[index * 4 + 0]; + *g = mode->palette[index * 4 + 1]; + *b = mode->palette[index * 4 + 2]; + *a = mode->palette[index * 4 + 3]; + } + } + else if(mode->colortype == LCT_GREY_ALPHA) + { + if(mode->bitdepth == 8) + { + *r = *g = *b = in[i * 2 + 0]; + *a = in[i * 2 + 1]; + } + else + { + *r = *g = *b = in[i * 4 + 0]; + *a = in[i * 4 + 2]; + } + } + else if(mode->colortype == LCT_RGBA) + { + if(mode->bitdepth == 8) + { + *r = in[i * 4 + 0]; + *g = in[i * 4 + 1]; + *b = in[i * 4 + 2]; + *a = in[i * 4 + 3]; + } + else + { + *r = in[i * 8 + 0]; + *g = in[i * 8 + 2]; + *b = in[i * 8 + 4]; + *a = in[i * 8 + 6]; + } + } +} + +/*Similar to getPixelColorRGBA8, but with all the for loops inside of the color +mode test cases, optimized to convert the colors much faster, when converting +to RGBA or RGB with 8 bit per cannel. buffer must be RGBA or RGB output with +enough memory, if has_alpha is true the output is RGBA. mode has the color mode +of the input buffer.*/ +static void getPixelColorsRGBA8(unsigned char* buffer, size_t numpixels, + unsigned has_alpha, const unsigned char* in, + const LodePNGColorMode* mode) +{ + unsigned num_channels = has_alpha ? 4 : 3; + size_t i; + if(mode->colortype == LCT_GREY) + { + if(mode->bitdepth == 8) + { + for(i = 0; i != numpixels; ++i, buffer += num_channels) + { + buffer[0] = buffer[1] = buffer[2] = in[i]; + if(has_alpha) buffer[3] = mode->key_defined && in[i] == mode->key_r ? 0 : 255; + } + } + else if(mode->bitdepth == 16) + { + for(i = 0; i != numpixels; ++i, buffer += num_channels) + { + buffer[0] = buffer[1] = buffer[2] = in[i * 2]; + if(has_alpha) buffer[3] = mode->key_defined && 256U * in[i * 2 + 0] + in[i * 2 + 1] == mode->key_r ? 0 : 255; + } + } + else + { + unsigned highest = ((1U << mode->bitdepth) - 1U); /*highest possible value for this bit depth*/ + size_t j = 0; + for(i = 0; i != numpixels; ++i, buffer += num_channels) + { + unsigned value = readBitsFromReversedStream(&j, in, mode->bitdepth); + buffer[0] = buffer[1] = buffer[2] = (value * 255) / highest; + if(has_alpha) buffer[3] = mode->key_defined && value == mode->key_r ? 0 : 255; + } + } + } + else if(mode->colortype == LCT_RGB) + { + if(mode->bitdepth == 8) + { + for(i = 0; i != numpixels; ++i, buffer += num_channels) + { + buffer[0] = in[i * 3 + 0]; + buffer[1] = in[i * 3 + 1]; + buffer[2] = in[i * 3 + 2]; + if(has_alpha) buffer[3] = mode->key_defined && buffer[0] == mode->key_r + && buffer[1]== mode->key_g && buffer[2] == mode->key_b ? 0 : 255; + } + } + else + { + for(i = 0; i != numpixels; ++i, buffer += num_channels) + { + buffer[0] = in[i * 6 + 0]; + buffer[1] = in[i * 6 + 2]; + buffer[2] = in[i * 6 + 4]; + if(has_alpha) buffer[3] = mode->key_defined + && 256U * in[i * 6 + 0] + in[i * 6 + 1] == mode->key_r + && 256U * in[i * 6 + 2] + in[i * 6 + 3] == mode->key_g + && 256U * in[i * 6 + 4] + in[i * 6 + 5] == mode->key_b ? 0 : 255; + } + } + } + else if(mode->colortype == LCT_PALETTE) + { + unsigned index; + size_t j = 0; + for(i = 0; i != numpixels; ++i, buffer += num_channels) + { + if(mode->bitdepth == 8) index = in[i]; + else index = readBitsFromReversedStream(&j, in, mode->bitdepth); + + if(index >= mode->palettesize) + { + /*This is an error according to the PNG spec, but most PNG decoders make it black instead. + Done here too, slightly faster due to no error handling needed.*/ + buffer[0] = buffer[1] = buffer[2] = 0; + if(has_alpha) buffer[3] = 255; + } + else + { + buffer[0] = mode->palette[index * 4 + 0]; + buffer[1] = mode->palette[index * 4 + 1]; + buffer[2] = mode->palette[index * 4 + 2]; + if(has_alpha) buffer[3] = mode->palette[index * 4 + 3]; + } + } + } + else if(mode->colortype == LCT_GREY_ALPHA) + { + if(mode->bitdepth == 8) + { + for(i = 0; i != numpixels; ++i, buffer += num_channels) + { + buffer[0] = buffer[1] = buffer[2] = in[i * 2 + 0]; + if(has_alpha) buffer[3] = in[i * 2 + 1]; + } + } + else + { + for(i = 0; i != numpixels; ++i, buffer += num_channels) + { + buffer[0] = buffer[1] = buffer[2] = in[i * 4 + 0]; + if(has_alpha) buffer[3] = in[i * 4 + 2]; + } + } + } + else if(mode->colortype == LCT_RGBA) + { + if(mode->bitdepth == 8) + { + for(i = 0; i != numpixels; ++i, buffer += num_channels) + { + buffer[0] = in[i * 4 + 0]; + buffer[1] = in[i * 4 + 1]; + buffer[2] = in[i * 4 + 2]; + if(has_alpha) buffer[3] = in[i * 4 + 3]; + } + } + else + { + for(i = 0; i != numpixels; ++i, buffer += num_channels) + { + buffer[0] = in[i * 8 + 0]; + buffer[1] = in[i * 8 + 2]; + buffer[2] = in[i * 8 + 4]; + if(has_alpha) buffer[3] = in[i * 8 + 6]; + } + } + } +} + +/*Get RGBA16 color of pixel with index i (y * width + x) from the raw image with +given color type, but the given color type must be 16-bit itself.*/ +static void getPixelColorRGBA16(unsigned short* r, unsigned short* g, unsigned short* b, unsigned short* a, + const unsigned char* in, size_t i, const LodePNGColorMode* mode) +{ + if(mode->colortype == LCT_GREY) + { + *r = *g = *b = 256 * in[i * 2 + 0] + in[i * 2 + 1]; + if(mode->key_defined && 256U * in[i * 2 + 0] + in[i * 2 + 1] == mode->key_r) *a = 0; + else *a = 65535; + } + else if(mode->colortype == LCT_RGB) + { + *r = 256u * in[i * 6 + 0] + in[i * 6 + 1]; + *g = 256u * in[i * 6 + 2] + in[i * 6 + 3]; + *b = 256u * in[i * 6 + 4] + in[i * 6 + 5]; + if(mode->key_defined + && 256u * in[i * 6 + 0] + in[i * 6 + 1] == mode->key_r + && 256u * in[i * 6 + 2] + in[i * 6 + 3] == mode->key_g + && 256u * in[i * 6 + 4] + in[i * 6 + 5] == mode->key_b) *a = 0; + else *a = 65535; + } + else if(mode->colortype == LCT_GREY_ALPHA) + { + *r = *g = *b = 256u * in[i * 4 + 0] + in[i * 4 + 1]; + *a = 256u * in[i * 4 + 2] + in[i * 4 + 3]; + } + else if(mode->colortype == LCT_RGBA) + { + *r = 256u * in[i * 8 + 0] + in[i * 8 + 1]; + *g = 256u * in[i * 8 + 2] + in[i * 8 + 3]; + *b = 256u * in[i * 8 + 4] + in[i * 8 + 5]; + *a = 256u * in[i * 8 + 6] + in[i * 8 + 7]; + } +} + +unsigned lodepng_convert(unsigned char* out, const unsigned char* in, + const LodePNGColorMode* mode_out, const LodePNGColorMode* mode_in, + unsigned w, unsigned h) +{ + size_t i; + ColorTree tree; + size_t numpixels = w * h; + + if(lodepng_color_mode_equal(mode_out, mode_in)) + { + size_t numbytes = lodepng_get_raw_size(w, h, mode_in); + for(i = 0; i != numbytes; ++i) out[i] = in[i]; + return 0; + } + + if(mode_out->colortype == LCT_PALETTE) + { + size_t palettesize = mode_out->palettesize; + const unsigned char* palette = mode_out->palette; + size_t palsize = 1u << mode_out->bitdepth; + /*if the user specified output palette but did not give the values, assume + they want the values of the input color type (assuming that one is palette). + Note that we never create a new palette ourselves.*/ + if(palettesize == 0) + { + palettesize = mode_in->palettesize; + palette = mode_in->palette; + } + if(palettesize < palsize) palsize = palettesize; + color_tree_init(&tree); + for(i = 0; i != palsize; ++i) + { + const unsigned char* p = &palette[i * 4]; + color_tree_add(&tree, p[0], p[1], p[2], p[3], i); + } + } + + if(mode_in->bitdepth == 16 && mode_out->bitdepth == 16) + { + for(i = 0; i != numpixels; ++i) + { + unsigned short r = 0, g = 0, b = 0, a = 0; + getPixelColorRGBA16(&r, &g, &b, &a, in, i, mode_in); + rgba16ToPixel(out, i, mode_out, r, g, b, a); + } + } + else if(mode_out->bitdepth == 8 && mode_out->colortype == LCT_RGBA) + { + getPixelColorsRGBA8(out, numpixels, 1, in, mode_in); + } + else if(mode_out->bitdepth == 8 && mode_out->colortype == LCT_RGB) + { + getPixelColorsRGBA8(out, numpixels, 0, in, mode_in); + } + else + { + unsigned char r = 0, g = 0, b = 0, a = 0; + for(i = 0; i != numpixels; ++i) + { + getPixelColorRGBA8(&r, &g, &b, &a, in, i, mode_in); + CERROR_TRY_RETURN(rgba8ToPixel(out, i, mode_out, &tree, r, g, b, a)); + } + } + + if(mode_out->colortype == LCT_PALETTE) + { + color_tree_cleanup(&tree); + } + + return 0; /*no error*/ +} + +#ifdef LODEPNG_COMPILE_ENCODER + +void lodepng_color_profile_init(LodePNGColorProfile* profile) +{ + profile->colored = 0; + profile->key = 0; + profile->alpha = 0; + profile->key_r = profile->key_g = profile->key_b = 0; + profile->numcolors = 0; + profile->bits = 1; +} + +/*function used for debug purposes with C++*/ +/*void printColorProfile(LodePNGColorProfile* p) +{ + std::cout << "colored: " << (int)p->colored << ", "; + std::cout << "key: " << (int)p->key << ", "; + std::cout << "key_r: " << (int)p->key_r << ", "; + std::cout << "key_g: " << (int)p->key_g << ", "; + std::cout << "key_b: " << (int)p->key_b << ", "; + std::cout << "alpha: " << (int)p->alpha << ", "; + std::cout << "numcolors: " << (int)p->numcolors << ", "; + std::cout << "bits: " << (int)p->bits << std::endl; +}*/ + +/*Returns how many bits needed to represent given value (max 8 bit)*/ +static unsigned getValueRequiredBits(unsigned char value) +{ + if(value == 0 || value == 255) return 1; + /*The scaling of 2-bit and 4-bit values uses multiples of 85 and 17*/ + if(value % 17 == 0) return value % 85 == 0 ? 2 : 4; + return 8; +} + +/*profile must already have been inited with mode. +It's ok to set some parameters of profile to done already.*/ +unsigned lodepng_get_color_profile(LodePNGColorProfile* profile, + const unsigned char* in, unsigned w, unsigned h, + const LodePNGColorMode* mode) +{ + unsigned error = 0; + size_t i; + ColorTree tree; + size_t numpixels = w * h; + + unsigned colored_done = lodepng_is_greyscale_type(mode) ? 1 : 0; + unsigned alpha_done = lodepng_can_have_alpha(mode) ? 0 : 1; + unsigned numcolors_done = 0; + unsigned bpp = lodepng_get_bpp(mode); + unsigned bits_done = bpp == 1 ? 1 : 0; + unsigned maxnumcolors = 257; + unsigned sixteen = 0; + if(bpp <= 8) maxnumcolors = bpp == 1 ? 2 : (bpp == 2 ? 4 : (bpp == 4 ? 16 : 256)); + + color_tree_init(&tree); + + /*Check if the 16-bit input is truly 16-bit*/ + if(mode->bitdepth == 16) + { + unsigned short r, g, b, a; + for(i = 0; i != numpixels; ++i) + { + getPixelColorRGBA16(&r, &g, &b, &a, in, i, mode); + if((r & 255) != ((r >> 8) & 255) || (g & 255) != ((g >> 8) & 255) || + (b & 255) != ((b >> 8) & 255) || (a & 255) != ((a >> 8) & 255)) /*first and second byte differ*/ + { + sixteen = 1; + break; + } + } + } + + if(sixteen) + { + unsigned short r = 0, g = 0, b = 0, a = 0; + profile->bits = 16; + bits_done = numcolors_done = 1; /*counting colors no longer useful, palette doesn't support 16-bit*/ + + for(i = 0; i != numpixels; ++i) + { + getPixelColorRGBA16(&r, &g, &b, &a, in, i, mode); + + if(!colored_done && (r != g || r != b)) + { + profile->colored = 1; + colored_done = 1; + } + + if(!alpha_done) + { + unsigned matchkey = (r == profile->key_r && g == profile->key_g && b == profile->key_b); + if(a != 65535 && (a != 0 || (profile->key && !matchkey))) + { + profile->alpha = 1; + alpha_done = 1; + if(profile->bits < 8) profile->bits = 8; /*PNG has no alphachannel modes with less than 8-bit per channel*/ + } + else if(a == 0 && !profile->alpha && !profile->key) + { + profile->key = 1; + profile->key_r = r; + profile->key_g = g; + profile->key_b = b; + } + else if(a == 65535 && profile->key && matchkey) + { + /* Color key cannot be used if an opaque pixel also has that RGB color. */ + profile->alpha = 1; + alpha_done = 1; + } + } + if(alpha_done && numcolors_done && colored_done && bits_done) break; + } + + if(profile->key && !profile->alpha) + { + for(i = 0; i != numpixels; ++i) + { + getPixelColorRGBA16(&r, &g, &b, &a, in, i, mode); + if(a != 0 && r == profile->key_r && g == profile->key_g && b == profile->key_b) + { + /* Color key cannot be used if an opaque pixel also has that RGB color. */ + profile->alpha = 1; + alpha_done = 1; + } + } + } + } + else /* < 16-bit */ + { + unsigned char r = 0, g = 0, b = 0, a = 0; + for(i = 0; i != numpixels; ++i) + { + getPixelColorRGBA8(&r, &g, &b, &a, in, i, mode); + + if(!bits_done && profile->bits < 8) + { + /*only r is checked, < 8 bits is only relevant for greyscale*/ + unsigned bits = getValueRequiredBits(r); + if(bits > profile->bits) profile->bits = bits; + } + bits_done = (profile->bits >= bpp); + + if(!colored_done && (r != g || r != b)) + { + profile->colored = 1; + colored_done = 1; + if(profile->bits < 8) profile->bits = 8; /*PNG has no colored modes with less than 8-bit per channel*/ + } + + if(!alpha_done) + { + unsigned matchkey = (r == profile->key_r && g == profile->key_g && b == profile->key_b); + if(a != 255 && (a != 0 || (profile->key && !matchkey))) + { + profile->alpha = 1; + alpha_done = 1; + if(profile->bits < 8) profile->bits = 8; /*PNG has no alphachannel modes with less than 8-bit per channel*/ + } + else if(a == 0 && !profile->alpha && !profile->key) + { + profile->key = 1; + profile->key_r = r; + profile->key_g = g; + profile->key_b = b; + } + else if(a == 255 && profile->key && matchkey) + { + /* Color key cannot be used if an opaque pixel also has that RGB color. */ + profile->alpha = 1; + alpha_done = 1; + if(profile->bits < 8) profile->bits = 8; /*PNG has no alphachannel modes with less than 8-bit per channel*/ + } + } + + if(!numcolors_done) + { + if(!color_tree_has(&tree, r, g, b, a)) + { + color_tree_add(&tree, r, g, b, a, profile->numcolors); + if(profile->numcolors < 256) + { + unsigned char* p = profile->palette; + unsigned n = profile->numcolors; + p[n * 4 + 0] = r; + p[n * 4 + 1] = g; + p[n * 4 + 2] = b; + p[n * 4 + 3] = a; + } + ++profile->numcolors; + numcolors_done = profile->numcolors >= maxnumcolors; + } + } + + if(alpha_done && numcolors_done && colored_done && bits_done) break; + } + + if(profile->key && !profile->alpha) + { + for(i = 0; i != numpixels; ++i) + { + getPixelColorRGBA8(&r, &g, &b, &a, in, i, mode); + if(a != 0 && r == profile->key_r && g == profile->key_g && b == profile->key_b) + { + /* Color key cannot be used if an opaque pixel also has that RGB color. */ + profile->alpha = 1; + alpha_done = 1; + } + } + } + + /*make the profile's key always 16-bit for consistency - repeat each byte twice*/ + profile->key_r += (profile->key_r << 8); + profile->key_g += (profile->key_g << 8); + profile->key_b += (profile->key_b << 8); + } + + color_tree_cleanup(&tree); + return error; +} + +/*Automatically chooses color type that gives smallest amount of bits in the +output image, e.g. grey if there are only greyscale pixels, palette if there +are less than 256 colors, ... +Updates values of mode with a potentially smaller color model. mode_out should +contain the user chosen color model, but will be overwritten with the new chosen one.*/ +unsigned lodepng_auto_choose_color(LodePNGColorMode* mode_out, + const unsigned char* image, unsigned w, unsigned h, + const LodePNGColorMode* mode_in) +{ + LodePNGColorProfile prof; + unsigned error = 0; + unsigned i, n, palettebits, grey_ok, palette_ok; + + lodepng_color_profile_init(&prof); + error = lodepng_get_color_profile(&prof, image, w, h, mode_in); + if(error) return error; + mode_out->key_defined = 0; + + if(prof.key && w * h <= 16) + { + prof.alpha = 1; /*too few pixels to justify tRNS chunk overhead*/ + if(prof.bits < 8) prof.bits = 8; /*PNG has no alphachannel modes with less than 8-bit per channel*/ + } + grey_ok = !prof.colored && !prof.alpha; /*grey without alpha, with potentially low bits*/ + n = prof.numcolors; + palettebits = n <= 2 ? 1 : (n <= 4 ? 2 : (n <= 16 ? 4 : 8)); + palette_ok = n <= 256 && (n * 2 < w * h) && prof.bits <= 8; + if(w * h < n * 2) palette_ok = 0; /*don't add palette overhead if image has only a few pixels*/ + if(grey_ok && prof.bits <= palettebits) palette_ok = 0; /*grey is less overhead*/ + + if(palette_ok) + { + unsigned char* p = prof.palette; + lodepng_palette_clear(mode_out); /*remove potential earlier palette*/ + for(i = 0; i != prof.numcolors; ++i) + { + error = lodepng_palette_add(mode_out, p[i * 4 + 0], p[i * 4 + 1], p[i * 4 + 2], p[i * 4 + 3]); + if(error) break; + } + + mode_out->colortype = LCT_PALETTE; + mode_out->bitdepth = palettebits; + + if(mode_in->colortype == LCT_PALETTE && mode_in->palettesize >= mode_out->palettesize + && mode_in->bitdepth == mode_out->bitdepth) + { + /*If input should have same palette colors, keep original to preserve its order and prevent conversion*/ + lodepng_color_mode_cleanup(mode_out); + lodepng_color_mode_copy(mode_out, mode_in); + } + } + else /*8-bit or 16-bit per channel*/ + { + mode_out->bitdepth = prof.bits; + mode_out->colortype = prof.alpha ? (prof.colored ? LCT_RGBA : LCT_GREY_ALPHA) + : (prof.colored ? LCT_RGB : LCT_GREY); + + if(prof.key && !prof.alpha) + { + unsigned mask = (1u << mode_out->bitdepth) - 1u; /*profile always uses 16-bit, mask converts it*/ + mode_out->key_r = prof.key_r & mask; + mode_out->key_g = prof.key_g & mask; + mode_out->key_b = prof.key_b & mask; + mode_out->key_defined = 1; + } + } + + return error; +} + +#endif /* #ifdef LODEPNG_COMPILE_ENCODER */ + +/* +Paeth predicter, used by PNG filter type 4 +The parameters are of type short, but should come from unsigned chars, the shorts +are only needed to make the paeth calculation correct. +*/ +static unsigned char paethPredictor(short a, short b, short c) +{ + short pa = abs(b - c); + short pb = abs(a - c); + short pc = abs(a + b - c - c); + + if(pc < pa && pc < pb) return (unsigned char)c; + else if(pb < pa) return (unsigned char)b; + else return (unsigned char)a; +} + +/*shared values used by multiple Adam7 related functions*/ + +static const unsigned ADAM7_IX[7] = { 0, 4, 0, 2, 0, 1, 0 }; /*x start values*/ +static const unsigned ADAM7_IY[7] = { 0, 0, 4, 0, 2, 0, 1 }; /*y start values*/ +static const unsigned ADAM7_DX[7] = { 8, 8, 4, 4, 2, 2, 1 }; /*x delta values*/ +static const unsigned ADAM7_DY[7] = { 8, 8, 8, 4, 4, 2, 2 }; /*y delta values*/ + +/* +Outputs various dimensions and positions in the image related to the Adam7 reduced images. +passw: output containing the width of the 7 passes +passh: output containing the height of the 7 passes +filter_passstart: output containing the index of the start and end of each + reduced image with filter bytes +padded_passstart output containing the index of the start and end of each + reduced image when without filter bytes but with padded scanlines +passstart: output containing the index of the start and end of each reduced + image without padding between scanlines, but still padding between the images +w, h: width and height of non-interlaced image +bpp: bits per pixel +"padded" is only relevant if bpp is less than 8 and a scanline or image does not + end at a full byte +*/ +static void Adam7_getpassvalues(unsigned passw[7], unsigned passh[7], size_t filter_passstart[8], + size_t padded_passstart[8], size_t passstart[8], unsigned w, unsigned h, unsigned bpp) +{ + /*the passstart values have 8 values: the 8th one indicates the byte after the end of the 7th (= last) pass*/ + unsigned i; + + /*calculate width and height in pixels of each pass*/ + for(i = 0; i != 7; ++i) + { + passw[i] = (w + ADAM7_DX[i] - ADAM7_IX[i] - 1) / ADAM7_DX[i]; + passh[i] = (h + ADAM7_DY[i] - ADAM7_IY[i] - 1) / ADAM7_DY[i]; + if(passw[i] == 0) passh[i] = 0; + if(passh[i] == 0) passw[i] = 0; + } + + filter_passstart[0] = padded_passstart[0] = passstart[0] = 0; + for(i = 0; i != 7; ++i) + { + /*if passw[i] is 0, it's 0 bytes, not 1 (no filtertype-byte)*/ + filter_passstart[i + 1] = filter_passstart[i] + + ((passw[i] && passh[i]) ? passh[i] * (1 + (passw[i] * bpp + 7) / 8) : 0); + /*bits padded if needed to fill full byte at end of each scanline*/ + padded_passstart[i + 1] = padded_passstart[i] + passh[i] * ((passw[i] * bpp + 7) / 8); + /*only padded at end of reduced image*/ + passstart[i + 1] = passstart[i] + (passh[i] * passw[i] * bpp + 7) / 8; + } +} + +#ifdef LODEPNG_COMPILE_DECODER + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / PNG Decoder / */ +/* ////////////////////////////////////////////////////////////////////////// */ + +/*read the information from the header and store it in the LodePNGInfo. return value is error*/ +unsigned lodepng_inspect(unsigned* w, unsigned* h, LodePNGState* state, + const unsigned char* in, size_t insize) +{ + LodePNGInfo* info = &state->info_png; + if(insize == 0 || in == 0) + { + CERROR_RETURN_ERROR(state->error, 48); /*error: the given data is empty*/ + } + if(insize < 33) + { + CERROR_RETURN_ERROR(state->error, 27); /*error: the data length is smaller than the length of a PNG header*/ + } + + /*when decoding a new PNG image, make sure all parameters created after previous decoding are reset*/ + lodepng_info_cleanup(info); + lodepng_info_init(info); + + if(in[0] != 137 || in[1] != 80 || in[2] != 78 || in[3] != 71 + || in[4] != 13 || in[5] != 10 || in[6] != 26 || in[7] != 10) + { + CERROR_RETURN_ERROR(state->error, 28); /*error: the first 8 bytes are not the correct PNG signature*/ + } + if(lodepng_chunk_length(in + 8) != 13) + { + CERROR_RETURN_ERROR(state->error, 94); /*error: header size must be 13 bytes*/ + } + if(!lodepng_chunk_type_equals(in + 8, "IHDR")) + { + CERROR_RETURN_ERROR(state->error, 29); /*error: it doesn't start with a IHDR chunk!*/ + } + + /*read the values given in the header*/ + *w = lodepng_read32bitInt(&in[16]); + *h = lodepng_read32bitInt(&in[20]); + info->color.bitdepth = in[24]; + info->color.colortype = (LodePNGColorType)in[25]; + info->compression_method = in[26]; + info->filter_method = in[27]; + info->interlace_method = in[28]; + + if(*w == 0 || *h == 0) + { + CERROR_RETURN_ERROR(state->error, 93); + } + + if(!state->decoder.ignore_crc) + { + unsigned CRC = lodepng_read32bitInt(&in[29]); + unsigned checksum = lodepng_crc32(&in[12], 17); + if(CRC != checksum) + { + CERROR_RETURN_ERROR(state->error, 57); /*invalid CRC*/ + } + } + + /*error: only compression method 0 is allowed in the specification*/ + if(info->compression_method != 0) CERROR_RETURN_ERROR(state->error, 32); + /*error: only filter method 0 is allowed in the specification*/ + if(info->filter_method != 0) CERROR_RETURN_ERROR(state->error, 33); + /*error: only interlace methods 0 and 1 exist in the specification*/ + if(info->interlace_method > 1) CERROR_RETURN_ERROR(state->error, 34); + + state->error = checkColorValidity(info->color.colortype, info->color.bitdepth); + return state->error; +} + +static unsigned unfilterScanline(unsigned char* recon, const unsigned char* scanline, const unsigned char* precon, + size_t bytewidth, unsigned char filterType, size_t length) +{ + /* + For PNG filter method 0 + unfilter a PNG image scanline by scanline. when the pixels are smaller than 1 byte, + the filter works byte per byte (bytewidth = 1) + precon is the previous unfiltered scanline, recon the result, scanline the current one + the incoming scanlines do NOT include the filtertype byte, that one is given in the parameter filterType instead + recon and scanline MAY be the same memory address! precon must be disjoint. + */ + + size_t i; + switch(filterType) + { + case 0: + for(i = 0; i != length; ++i) recon[i] = scanline[i]; + break; + case 1: + for(i = 0; i != bytewidth; ++i) recon[i] = scanline[i]; + for(i = bytewidth; i < length; ++i) recon[i] = scanline[i] + recon[i - bytewidth]; + break; + case 2: + if(precon) + { + for(i = 0; i != length; ++i) recon[i] = scanline[i] + precon[i]; + } + else + { + for(i = 0; i != length; ++i) recon[i] = scanline[i]; + } + break; + case 3: + if(precon) + { + for(i = 0; i != bytewidth; ++i) recon[i] = scanline[i] + (precon[i] >> 1); + for(i = bytewidth; i < length; ++i) recon[i] = scanline[i] + ((recon[i - bytewidth] + precon[i]) >> 1); + } + else + { + for(i = 0; i != bytewidth; ++i) recon[i] = scanline[i]; + for(i = bytewidth; i < length; ++i) recon[i] = scanline[i] + (recon[i - bytewidth] >> 1); + } + break; + case 4: + if(precon) + { + for(i = 0; i != bytewidth; ++i) + { + recon[i] = (scanline[i] + precon[i]); /*paethPredictor(0, precon[i], 0) is always precon[i]*/ + } + for(i = bytewidth; i < length; ++i) + { + recon[i] = (scanline[i] + paethPredictor(recon[i - bytewidth], precon[i], precon[i - bytewidth])); + } + } + else + { + for(i = 0; i != bytewidth; ++i) + { + recon[i] = scanline[i]; + } + for(i = bytewidth; i < length; ++i) + { + /*paethPredictor(recon[i - bytewidth], 0, 0) is always recon[i - bytewidth]*/ + recon[i] = (scanline[i] + recon[i - bytewidth]); + } + } + break; + default: return 36; /*error: unexisting filter type given*/ + } + return 0; +} + +static unsigned unfilter(unsigned char* out, const unsigned char* in, unsigned w, unsigned h, unsigned bpp) +{ + /* + For PNG filter method 0 + this function unfilters a single image (e.g. without interlacing this is called once, with Adam7 seven times) + out must have enough bytes allocated already, in must have the scanlines + 1 filtertype byte per scanline + w and h are image dimensions or dimensions of reduced image, bpp is bits per pixel + in and out are allowed to be the same memory address (but aren't the same size since in has the extra filter bytes) + */ + + unsigned y; + unsigned char* prevline = 0; + + /*bytewidth is used for filtering, is 1 when bpp < 8, number of bytes per pixel otherwise*/ + size_t bytewidth = (bpp + 7) / 8; + size_t linebytes = (w * bpp + 7) / 8; + + for(y = 0; y < h; ++y) + { + size_t outindex = linebytes * y; + size_t inindex = (1 + linebytes) * y; /*the extra filterbyte added to each row*/ + unsigned char filterType = in[inindex]; + + CERROR_TRY_RETURN(unfilterScanline(&out[outindex], &in[inindex + 1], prevline, bytewidth, filterType, linebytes)); + + prevline = &out[outindex]; + } + + return 0; +} + +/* +in: Adam7 interlaced image, with no padding bits between scanlines, but between + reduced images so that each reduced image starts at a byte. +out: the same pixels, but re-ordered so that they're now a non-interlaced image with size w*h +bpp: bits per pixel +out has the following size in bits: w * h * bpp. +in is possibly bigger due to padding bits between reduced images. +out must be big enough AND must be 0 everywhere if bpp < 8 in the current implementation +(because that's likely a little bit faster) +NOTE: comments about padding bits are only relevant if bpp < 8 +*/ +static void Adam7_deinterlace(unsigned char* out, const unsigned char* in, unsigned w, unsigned h, unsigned bpp) +{ + unsigned passw[7], passh[7]; + size_t filter_passstart[8], padded_passstart[8], passstart[8]; + unsigned i; + + Adam7_getpassvalues(passw, passh, filter_passstart, padded_passstart, passstart, w, h, bpp); + + if(bpp >= 8) + { + for(i = 0; i != 7; ++i) + { + unsigned x, y, b; + size_t bytewidth = bpp / 8; + for(y = 0; y < passh[i]; ++y) + for(x = 0; x < passw[i]; ++x) + { + size_t pixelinstart = passstart[i] + (y * passw[i] + x) * bytewidth; + size_t pixeloutstart = ((ADAM7_IY[i] + y * ADAM7_DY[i]) * w + ADAM7_IX[i] + x * ADAM7_DX[i]) * bytewidth; + for(b = 0; b < bytewidth; ++b) + { + out[pixeloutstart + b] = in[pixelinstart + b]; + } + } + } + } + else /*bpp < 8: Adam7 with pixels < 8 bit is a bit trickier: with bit pointers*/ + { + for(i = 0; i != 7; ++i) + { + unsigned x, y, b; + unsigned ilinebits = bpp * passw[i]; + unsigned olinebits = bpp * w; + size_t obp, ibp; /*bit pointers (for out and in buffer)*/ + for(y = 0; y < passh[i]; ++y) + for(x = 0; x < passw[i]; ++x) + { + ibp = (8 * passstart[i]) + (y * ilinebits + x * bpp); + obp = (ADAM7_IY[i] + y * ADAM7_DY[i]) * olinebits + (ADAM7_IX[i] + x * ADAM7_DX[i]) * bpp; + for(b = 0; b < bpp; ++b) + { + unsigned char bit = readBitFromReversedStream(&ibp, in); + /*note that this function assumes the out buffer is completely 0, use setBitOfReversedStream otherwise*/ + setBitOfReversedStream0(&obp, out, bit); + } + } + } + } +} + +static void removePaddingBits(unsigned char* out, const unsigned char* in, + size_t olinebits, size_t ilinebits, unsigned h) +{ + /* + After filtering there are still padding bits if scanlines have non multiple of 8 bit amounts. They need + to be removed (except at last scanline of (Adam7-reduced) image) before working with pure image buffers + for the Adam7 code, the color convert code and the output to the user. + in and out are allowed to be the same buffer, in may also be higher but still overlapping; in must + have >= ilinebits*h bits, out must have >= olinebits*h bits, olinebits must be <= ilinebits + also used to move bits after earlier such operations happened, e.g. in a sequence of reduced images from Adam7 + only useful if (ilinebits - olinebits) is a value in the range 1..7 + */ + unsigned y; + size_t diff = ilinebits - olinebits; + size_t ibp = 0, obp = 0; /*input and output bit pointers*/ + for(y = 0; y < h; ++y) + { + size_t x; + for(x = 0; x < olinebits; ++x) + { + unsigned char bit = readBitFromReversedStream(&ibp, in); + setBitOfReversedStream(&obp, out, bit); + } + ibp += diff; + } +} + +/*out must be buffer big enough to contain full image, and in must contain the full decompressed data from +the IDAT chunks (with filter index bytes and possible padding bits) +return value is error*/ +static unsigned postProcessScanlines(unsigned char* out, unsigned char* in, + unsigned w, unsigned h, const LodePNGInfo* info_png) +{ + /* + This function converts the filtered-padded-interlaced data into pure 2D image buffer with the PNG's colortype. + Steps: + *) if no Adam7: 1) unfilter 2) remove padding bits (= posible extra bits per scanline if bpp < 8) + *) if adam7: 1) 7x unfilter 2) 7x remove padding bits 3) Adam7_deinterlace + NOTE: the in buffer will be overwritten with intermediate data! + */ + unsigned bpp = lodepng_get_bpp(&info_png->color); + if(bpp == 0) return 31; /*error: invalid colortype*/ + + if(info_png->interlace_method == 0) + { + if(bpp < 8 && w * bpp != ((w * bpp + 7) / 8) * 8) + { + CERROR_TRY_RETURN(unfilter(in, in, w, h, bpp)); + removePaddingBits(out, in, w * bpp, ((w * bpp + 7) / 8) * 8, h); + } + /*we can immediately filter into the out buffer, no other steps needed*/ + else CERROR_TRY_RETURN(unfilter(out, in, w, h, bpp)); + } + else /*interlace_method is 1 (Adam7)*/ + { + unsigned passw[7], passh[7]; size_t filter_passstart[8], padded_passstart[8], passstart[8]; + unsigned i; + + Adam7_getpassvalues(passw, passh, filter_passstart, padded_passstart, passstart, w, h, bpp); + + for(i = 0; i != 7; ++i) + { + CERROR_TRY_RETURN(unfilter(&in[padded_passstart[i]], &in[filter_passstart[i]], passw[i], passh[i], bpp)); + /*TODO: possible efficiency improvement: if in this reduced image the bits fit nicely in 1 scanline, + move bytes instead of bits or move not at all*/ + if(bpp < 8) + { + /*remove padding bits in scanlines; after this there still may be padding + bits between the different reduced images: each reduced image still starts nicely at a byte*/ + removePaddingBits(&in[passstart[i]], &in[padded_passstart[i]], passw[i] * bpp, + ((passw[i] * bpp + 7) / 8) * 8, passh[i]); + } + } + + Adam7_deinterlace(out, in, w, h, bpp); + } + + return 0; +} + +static unsigned readChunk_PLTE(LodePNGColorMode* color, const unsigned char* data, size_t chunkLength) +{ + unsigned pos = 0, i; + if(color->palette) lodepng_free(color->palette); + color->palettesize = chunkLength / 3; + color->palette = (unsigned char*)lodepng_malloc(4 * color->palettesize); + if(!color->palette && color->palettesize) + { + color->palettesize = 0; + return 83; /*alloc fail*/ + } + if(color->palettesize > 256) return 38; /*error: palette too big*/ + + for(i = 0; i != color->palettesize; ++i) + { + color->palette[4 * i + 0] = data[pos++]; /*R*/ + color->palette[4 * i + 1] = data[pos++]; /*G*/ + color->palette[4 * i + 2] = data[pos++]; /*B*/ + color->palette[4 * i + 3] = 255; /*alpha*/ + } + + return 0; /* OK */ +} + +static unsigned readChunk_tRNS(LodePNGColorMode* color, const unsigned char* data, size_t chunkLength) +{ + unsigned i; + if(color->colortype == LCT_PALETTE) + { + /*error: more alpha values given than there are palette entries*/ + if(chunkLength > color->palettesize) return 38; + + for(i = 0; i != chunkLength; ++i) color->palette[4 * i + 3] = data[i]; + } + else if(color->colortype == LCT_GREY) + { + /*error: this chunk must be 2 bytes for greyscale image*/ + if(chunkLength != 2) return 30; + + color->key_defined = 1; + color->key_r = color->key_g = color->key_b = 256u * data[0] + data[1]; + } + else if(color->colortype == LCT_RGB) + { + /*error: this chunk must be 6 bytes for RGB image*/ + if(chunkLength != 6) return 41; + + color->key_defined = 1; + color->key_r = 256u * data[0] + data[1]; + color->key_g = 256u * data[2] + data[3]; + color->key_b = 256u * data[4] + data[5]; + } + else return 42; /*error: tRNS chunk not allowed for other color models*/ + + return 0; /* OK */ +} + + +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS +/*background color chunk (bKGD)*/ +static unsigned readChunk_bKGD(LodePNGInfo* info, const unsigned char* data, size_t chunkLength) +{ + if(info->color.colortype == LCT_PALETTE) + { + /*error: this chunk must be 1 byte for indexed color image*/ + if(chunkLength != 1) return 43; + + info->background_defined = 1; + info->background_r = info->background_g = info->background_b = data[0]; + } + else if(info->color.colortype == LCT_GREY || info->color.colortype == LCT_GREY_ALPHA) + { + /*error: this chunk must be 2 bytes for greyscale image*/ + if(chunkLength != 2) return 44; + + info->background_defined = 1; + info->background_r = info->background_g = info->background_b = 256u * data[0] + data[1]; + } + else if(info->color.colortype == LCT_RGB || info->color.colortype == LCT_RGBA) + { + /*error: this chunk must be 6 bytes for greyscale image*/ + if(chunkLength != 6) return 45; + + info->background_defined = 1; + info->background_r = 256u * data[0] + data[1]; + info->background_g = 256u * data[2] + data[3]; + info->background_b = 256u * data[4] + data[5]; + } + + return 0; /* OK */ +} + +/*text chunk (tEXt)*/ +static unsigned readChunk_tEXt(LodePNGInfo* info, const unsigned char* data, size_t chunkLength) +{ + unsigned error = 0; + char *key = 0, *str = 0; + unsigned i; + + while(!error) /*not really a while loop, only used to break on error*/ + { + unsigned length, string2_begin; + + length = 0; + while(length < chunkLength && data[length] != 0) ++length; + /*even though it's not allowed by the standard, no error is thrown if + there's no null termination char, if the text is empty*/ + if(length < 1 || length > 79) CERROR_BREAK(error, 89); /*keyword too short or long*/ + + key = (char*)lodepng_malloc(length + 1); + if(!key) CERROR_BREAK(error, 83); /*alloc fail*/ + + key[length] = 0; + for(i = 0; i != length; ++i) key[i] = (char)data[i]; + + string2_begin = length + 1; /*skip keyword null terminator*/ + + length = chunkLength < string2_begin ? 0 : chunkLength - string2_begin; + str = (char*)lodepng_malloc(length + 1); + if(!str) CERROR_BREAK(error, 83); /*alloc fail*/ + + str[length] = 0; + for(i = 0; i != length; ++i) str[i] = (char)data[string2_begin + i]; + + error = lodepng_add_text(info, key, str); + + break; + } + + lodepng_free(key); + lodepng_free(str); + + return error; +} + +/*compressed text chunk (zTXt)*/ +static unsigned readChunk_zTXt(LodePNGInfo* info, const LodePNGDecompressSettings* zlibsettings, + const unsigned char* data, size_t chunkLength) +{ + unsigned error = 0; + unsigned i; + + unsigned length, string2_begin; + char *key = 0; + ucvector decoded; + + ucvector_init(&decoded); + + while(!error) /*not really a while loop, only used to break on error*/ + { + for(length = 0; length < chunkLength && data[length] != 0; ++length) ; + if(length + 2 >= chunkLength) CERROR_BREAK(error, 75); /*no null termination, corrupt?*/ + if(length < 1 || length > 79) CERROR_BREAK(error, 89); /*keyword too short or long*/ + + key = (char*)lodepng_malloc(length + 1); + if(!key) CERROR_BREAK(error, 83); /*alloc fail*/ + + key[length] = 0; + for(i = 0; i != length; ++i) key[i] = (char)data[i]; + + if(data[length + 1] != 0) CERROR_BREAK(error, 72); /*the 0 byte indicating compression must be 0*/ + + string2_begin = length + 2; + if(string2_begin > chunkLength) CERROR_BREAK(error, 75); /*no null termination, corrupt?*/ + + length = chunkLength - string2_begin; + /*will fail if zlib error, e.g. if length is too small*/ + error = zlib_decompress(&decoded.data, &decoded.size, + (unsigned char*)(&data[string2_begin]), + length, zlibsettings); + if(error) break; + ucvector_push_back(&decoded, 0); + + error = lodepng_add_text(info, key, (char*)decoded.data); + + break; + } + + lodepng_free(key); + ucvector_cleanup(&decoded); + + return error; +} + +/*international text chunk (iTXt)*/ +static unsigned readChunk_iTXt(LodePNGInfo* info, const LodePNGDecompressSettings* zlibsettings, + const unsigned char* data, size_t chunkLength) +{ + unsigned error = 0; + unsigned i; + + unsigned length, begin, compressed; + char *key = 0, *langtag = 0, *transkey = 0; + ucvector decoded; + ucvector_init(&decoded); + + while(!error) /*not really a while loop, only used to break on error*/ + { + /*Quick check if the chunk length isn't too small. Even without check + it'd still fail with other error checks below if it's too short. This just gives a different error code.*/ + if(chunkLength < 5) CERROR_BREAK(error, 30); /*iTXt chunk too short*/ + + /*read the key*/ + for(length = 0; length < chunkLength && data[length] != 0; ++length) ; + if(length + 3 >= chunkLength) CERROR_BREAK(error, 75); /*no null termination char, corrupt?*/ + if(length < 1 || length > 79) CERROR_BREAK(error, 89); /*keyword too short or long*/ + + key = (char*)lodepng_malloc(length + 1); + if(!key) CERROR_BREAK(error, 83); /*alloc fail*/ + + key[length] = 0; + for(i = 0; i != length; ++i) key[i] = (char)data[i]; + + /*read the compression method*/ + compressed = data[length + 1]; + if(data[length + 2] != 0) CERROR_BREAK(error, 72); /*the 0 byte indicating compression must be 0*/ + + /*even though it's not allowed by the standard, no error is thrown if + there's no null termination char, if the text is empty for the next 3 texts*/ + + /*read the langtag*/ + begin = length + 3; + length = 0; + for(i = begin; i < chunkLength && data[i] != 0; ++i) ++length; + + langtag = (char*)lodepng_malloc(length + 1); + if(!langtag) CERROR_BREAK(error, 83); /*alloc fail*/ + + langtag[length] = 0; + for(i = 0; i != length; ++i) langtag[i] = (char)data[begin + i]; + + /*read the transkey*/ + begin += length + 1; + length = 0; + for(i = begin; i < chunkLength && data[i] != 0; ++i) ++length; + + transkey = (char*)lodepng_malloc(length + 1); + if(!transkey) CERROR_BREAK(error, 83); /*alloc fail*/ + + transkey[length] = 0; + for(i = 0; i != length; ++i) transkey[i] = (char)data[begin + i]; + + /*read the actual text*/ + begin += length + 1; + + length = chunkLength < begin ? 0 : chunkLength - begin; + + if(compressed) + { + /*will fail if zlib error, e.g. if length is too small*/ + error = zlib_decompress(&decoded.data, &decoded.size, + (unsigned char*)(&data[begin]), + length, zlibsettings); + if(error) break; + if(decoded.allocsize < decoded.size) decoded.allocsize = decoded.size; + ucvector_push_back(&decoded, 0); + } + else + { + if(!ucvector_resize(&decoded, length + 1)) CERROR_BREAK(error, 83 /*alloc fail*/); + + decoded.data[length] = 0; + for(i = 0; i != length; ++i) decoded.data[i] = data[begin + i]; + } + + error = lodepng_add_itext(info, key, langtag, transkey, (char*)decoded.data); + + break; + } + + lodepng_free(key); + lodepng_free(langtag); + lodepng_free(transkey); + ucvector_cleanup(&decoded); + + return error; +} + +static unsigned readChunk_tIME(LodePNGInfo* info, const unsigned char* data, size_t chunkLength) +{ + if(chunkLength != 7) return 73; /*invalid tIME chunk size*/ + + info->time_defined = 1; + info->time.year = 256u * data[0] + data[1]; + info->time.month = data[2]; + info->time.day = data[3]; + info->time.hour = data[4]; + info->time.minute = data[5]; + info->time.second = data[6]; + + return 0; /* OK */ +} + +static unsigned readChunk_pHYs(LodePNGInfo* info, const unsigned char* data, size_t chunkLength) +{ + if(chunkLength != 9) return 74; /*invalid pHYs chunk size*/ + + info->phys_defined = 1; + info->phys_x = 16777216u * data[0] + 65536u * data[1] + 256u * data[2] + data[3]; + info->phys_y = 16777216u * data[4] + 65536u * data[5] + 256u * data[6] + data[7]; + info->phys_unit = data[8]; + + return 0; /* OK */ +} +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + +/*read a PNG, the result will be in the same color type as the PNG (hence "generic")*/ +static void decodeGeneric(unsigned char** out, unsigned* w, unsigned* h, + LodePNGState* state, + const unsigned char* in, size_t insize) +{ + unsigned char IEND = 0; + const unsigned char* chunk; + size_t i; + ucvector idat; /*the data from idat chunks*/ + ucvector scanlines; + size_t predict; + size_t numpixels; + size_t outsize = 0; + + /*for unknown chunk order*/ + unsigned unknown = 0; +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + unsigned critical_pos = 1; /*1 = after IHDR, 2 = after PLTE, 3 = after IDAT*/ +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + + /*provide some proper output values if error will happen*/ + *out = 0; + + state->error = lodepng_inspect(w, h, state, in, insize); /*reads header and resets other parameters in state->info_png*/ + if(state->error) return; + + numpixels = *w * *h; + + /*multiplication overflow*/ + if(*h != 0 && numpixels / *h != *w) CERROR_RETURN(state->error, 92); + /*multiplication overflow possible further below. Allows up to 2^31-1 pixel + bytes with 16-bit RGBA, the rest is room for filter bytes.*/ + if(numpixels > 268435455) CERROR_RETURN(state->error, 92); + + ucvector_init(&idat); + chunk = &in[33]; /*first byte of the first chunk after the header*/ + + /*loop through the chunks, ignoring unknown chunks and stopping at IEND chunk. + IDAT data is put at the start of the in buffer*/ + while(!IEND && !state->error) + { + unsigned chunkLength; + const unsigned char* data; /*the data in the chunk*/ + + /*error: size of the in buffer too small to contain next chunk*/ + if((size_t)((chunk - in) + 12) > insize || chunk < in) CERROR_BREAK(state->error, 30); + + /*length of the data of the chunk, excluding the length bytes, chunk type and CRC bytes*/ + chunkLength = lodepng_chunk_length(chunk); + /*error: chunk length larger than the max PNG chunk size*/ + if(chunkLength > 2147483647) CERROR_BREAK(state->error, 63); + + if((size_t)((chunk - in) + chunkLength + 12) > insize || (chunk + chunkLength + 12) < in) + { + CERROR_BREAK(state->error, 64); /*error: size of the in buffer too small to contain next chunk*/ + } + + data = lodepng_chunk_data_const(chunk); + + /*IDAT chunk, containing compressed image data*/ + if(lodepng_chunk_type_equals(chunk, "IDAT")) + { + size_t oldsize = idat.size; + if(!ucvector_resize(&idat, oldsize + chunkLength)) CERROR_BREAK(state->error, 83 /*alloc fail*/); + for(i = 0; i != chunkLength; ++i) idat.data[oldsize + i] = data[i]; +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + critical_pos = 3; +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + } + /*IEND chunk*/ + else if(lodepng_chunk_type_equals(chunk, "IEND")) + { + IEND = 1; + } + /*palette chunk (PLTE)*/ + else if(lodepng_chunk_type_equals(chunk, "PLTE")) + { + state->error = readChunk_PLTE(&state->info_png.color, data, chunkLength); + if(state->error) break; +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + critical_pos = 2; +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + } + /*palette transparency chunk (tRNS)*/ + else if(lodepng_chunk_type_equals(chunk, "tRNS")) + { + state->error = readChunk_tRNS(&state->info_png.color, data, chunkLength); + if(state->error) break; + } +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + /*background color chunk (bKGD)*/ + else if(lodepng_chunk_type_equals(chunk, "bKGD")) + { + state->error = readChunk_bKGD(&state->info_png, data, chunkLength); + if(state->error) break; + } + /*text chunk (tEXt)*/ + else if(lodepng_chunk_type_equals(chunk, "tEXt")) + { + if(state->decoder.read_text_chunks) + { + state->error = readChunk_tEXt(&state->info_png, data, chunkLength); + if(state->error) break; + } + } + /*compressed text chunk (zTXt)*/ + else if(lodepng_chunk_type_equals(chunk, "zTXt")) + { + if(state->decoder.read_text_chunks) + { + state->error = readChunk_zTXt(&state->info_png, &state->decoder.zlibsettings, data, chunkLength); + if(state->error) break; + } + } + /*international text chunk (iTXt)*/ + else if(lodepng_chunk_type_equals(chunk, "iTXt")) + { + if(state->decoder.read_text_chunks) + { + state->error = readChunk_iTXt(&state->info_png, &state->decoder.zlibsettings, data, chunkLength); + if(state->error) break; + } + } + else if(lodepng_chunk_type_equals(chunk, "tIME")) + { + state->error = readChunk_tIME(&state->info_png, data, chunkLength); + if(state->error) break; + } + else if(lodepng_chunk_type_equals(chunk, "pHYs")) + { + state->error = readChunk_pHYs(&state->info_png, data, chunkLength); + if(state->error) break; + } +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + else /*it's not an implemented chunk type, so ignore it: skip over the data*/ + { + /*error: unknown critical chunk (5th bit of first byte of chunk type is 0)*/ + if(!lodepng_chunk_ancillary(chunk)) CERROR_BREAK(state->error, 69); + + unknown = 1; +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + if(state->decoder.remember_unknown_chunks) + { + state->error = lodepng_chunk_append(&state->info_png.unknown_chunks_data[critical_pos - 1], + &state->info_png.unknown_chunks_size[critical_pos - 1], chunk); + if(state->error) break; + } +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + } + + if(!state->decoder.ignore_crc && !unknown) /*check CRC if wanted, only on known chunk types*/ + { + if(lodepng_chunk_check_crc(chunk)) CERROR_BREAK(state->error, 57); /*invalid CRC*/ + } + + if(!IEND) chunk = lodepng_chunk_next_const(chunk); + } + + ucvector_init(&scanlines); + /*predict output size, to allocate exact size for output buffer to avoid more dynamic allocation. + If the decompressed size does not match the prediction, the image must be corrupt.*/ + if(state->info_png.interlace_method == 0) + { + /*The extra *h is added because this are the filter bytes every scanline starts with*/ + predict = lodepng_get_raw_size_idat(*w, *h, &state->info_png.color) + *h; + } + else + { + /*Adam-7 interlaced: predicted size is the sum of the 7 sub-images sizes*/ + const LodePNGColorMode* color = &state->info_png.color; + predict = 0; + predict += lodepng_get_raw_size_idat((*w + 7) >> 3, (*h + 7) >> 3, color) + ((*h + 7) >> 3); + if(*w > 4) predict += lodepng_get_raw_size_idat((*w + 3) >> 3, (*h + 7) >> 3, color) + ((*h + 7) >> 3); + predict += lodepng_get_raw_size_idat((*w + 3) >> 2, (*h + 3) >> 3, color) + ((*h + 3) >> 3); + if(*w > 2) predict += lodepng_get_raw_size_idat((*w + 1) >> 2, (*h + 3) >> 2, color) + ((*h + 3) >> 2); + predict += lodepng_get_raw_size_idat((*w + 1) >> 1, (*h + 1) >> 2, color) + ((*h + 1) >> 2); + if(*w > 1) predict += lodepng_get_raw_size_idat((*w + 0) >> 1, (*h + 1) >> 1, color) + ((*h + 1) >> 1); + predict += lodepng_get_raw_size_idat((*w + 0), (*h + 0) >> 1, color) + ((*h + 0) >> 1); + } + if(!state->error && !ucvector_reserve(&scanlines, predict)) state->error = 83; /*alloc fail*/ + if(!state->error) + { + state->error = zlib_decompress(&scanlines.data, &scanlines.size, idat.data, + idat.size, &state->decoder.zlibsettings); + if(!state->error && scanlines.size != predict) state->error = 91; /*decompressed size doesn't match prediction*/ + } + ucvector_cleanup(&idat); + + if(!state->error) + { + outsize = lodepng_get_raw_size(*w, *h, &state->info_png.color); + *out = (unsigned char*)lodepng_malloc(outsize); + if(!*out) state->error = 83; /*alloc fail*/ + } + if(!state->error) + { + for(i = 0; i < outsize; i++) (*out)[i] = 0; + state->error = postProcessScanlines(*out, scanlines.data, *w, *h, &state->info_png); + } + ucvector_cleanup(&scanlines); +} + +unsigned lodepng_decode(unsigned char** out, unsigned* w, unsigned* h, + LodePNGState* state, + const unsigned char* in, size_t insize) +{ + *out = 0; + decodeGeneric(out, w, h, state, in, insize); + if(state->error) return state->error; + if(!state->decoder.color_convert || lodepng_color_mode_equal(&state->info_raw, &state->info_png.color)) + { + /*same color type, no copying or converting of data needed*/ + /*store the info_png color settings on the info_raw so that the info_raw still reflects what colortype + the raw image has to the end user*/ + if(!state->decoder.color_convert) + { + state->error = lodepng_color_mode_copy(&state->info_raw, &state->info_png.color); + if(state->error) return state->error; + } + } + else + { + /*color conversion needed; sort of copy of the data*/ + unsigned char* data = *out; + size_t outsize; + + /*TODO: check if this works according to the statement in the documentation: "The converter can convert + from greyscale input color type, to 8-bit greyscale or greyscale with alpha"*/ + if(!(state->info_raw.colortype == LCT_RGB || state->info_raw.colortype == LCT_RGBA) + && !(state->info_raw.bitdepth == 8)) + { + return 56; /*unsupported color mode conversion*/ + } + + outsize = lodepng_get_raw_size(*w, *h, &state->info_raw); + *out = (unsigned char*)lodepng_malloc(outsize); + if(!(*out)) + { + state->error = 83; /*alloc fail*/ + } + else state->error = lodepng_convert(*out, data, &state->info_raw, + &state->info_png.color, *w, *h); + lodepng_free(data); + } + return state->error; +} + +unsigned lodepng_decode_memory(unsigned char** out, unsigned* w, unsigned* h, const unsigned char* in, + size_t insize, LodePNGColorType colortype, unsigned bitdepth) +{ + unsigned error; + LodePNGState state; + lodepng_state_init(&state); + state.info_raw.colortype = colortype; + state.info_raw.bitdepth = bitdepth; + error = lodepng_decode(out, w, h, &state, in, insize); + lodepng_state_cleanup(&state); + return error; +} + +unsigned lodepng_decode32(unsigned char** out, unsigned* w, unsigned* h, const unsigned char* in, size_t insize) +{ + return lodepng_decode_memory(out, w, h, in, insize, LCT_RGBA, 8); +} + +unsigned lodepng_decode24(unsigned char** out, unsigned* w, unsigned* h, const unsigned char* in, size_t insize) +{ + return lodepng_decode_memory(out, w, h, in, insize, LCT_RGB, 8); +} + +#ifdef LODEPNG_COMPILE_DISK +unsigned lodepng_decode_file(unsigned char** out, unsigned* w, unsigned* h, const char* filename, + LodePNGColorType colortype, unsigned bitdepth) +{ + unsigned char* buffer = 0; + size_t buffersize; + unsigned error; + error = lodepng_load_file(&buffer, &buffersize, filename); + if(!error) error = lodepng_decode_memory(out, w, h, buffer, buffersize, colortype, bitdepth); + lodepng_free(buffer); + return error; +} + +unsigned lodepng_decode32_file(unsigned char** out, unsigned* w, unsigned* h, const char* filename) +{ + return lodepng_decode_file(out, w, h, filename, LCT_RGBA, 8); +} + +unsigned lodepng_decode24_file(unsigned char** out, unsigned* w, unsigned* h, const char* filename) +{ + return lodepng_decode_file(out, w, h, filename, LCT_RGB, 8); +} +#endif /*LODEPNG_COMPILE_DISK*/ + +void lodepng_decoder_settings_init(LodePNGDecoderSettings* settings) +{ + settings->color_convert = 1; +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + settings->read_text_chunks = 1; + settings->remember_unknown_chunks = 0; +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + settings->ignore_crc = 0; + lodepng_decompress_settings_init(&settings->zlibsettings); +} + +#endif /*LODEPNG_COMPILE_DECODER*/ + +#if defined(LODEPNG_COMPILE_DECODER) || defined(LODEPNG_COMPILE_ENCODER) + +void lodepng_state_init(LodePNGState* state) +{ +#ifdef LODEPNG_COMPILE_DECODER + lodepng_decoder_settings_init(&state->decoder); +#endif /*LODEPNG_COMPILE_DECODER*/ +#ifdef LODEPNG_COMPILE_ENCODER + lodepng_encoder_settings_init(&state->encoder); +#endif /*LODEPNG_COMPILE_ENCODER*/ + lodepng_color_mode_init(&state->info_raw); + lodepng_info_init(&state->info_png); + state->error = 1; +} + +void lodepng_state_cleanup(LodePNGState* state) +{ + lodepng_color_mode_cleanup(&state->info_raw); + lodepng_info_cleanup(&state->info_png); +} + +void lodepng_state_copy(LodePNGState* dest, const LodePNGState* source) +{ + lodepng_state_cleanup(dest); + *dest = *source; + lodepng_color_mode_init(&dest->info_raw); + lodepng_info_init(&dest->info_png); + dest->error = lodepng_color_mode_copy(&dest->info_raw, &source->info_raw); if(dest->error) return; + dest->error = lodepng_info_copy(&dest->info_png, &source->info_png); if(dest->error) return; +} + +#endif /* defined(LODEPNG_COMPILE_DECODER) || defined(LODEPNG_COMPILE_ENCODER) */ + +#ifdef LODEPNG_COMPILE_ENCODER + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / PNG Encoder / */ +/* ////////////////////////////////////////////////////////////////////////// */ + +/*chunkName must be string of 4 characters*/ +static unsigned addChunk(ucvector* out, const char* chunkName, const unsigned char* data, size_t length) +{ + CERROR_TRY_RETURN(lodepng_chunk_create(&out->data, &out->size, (unsigned)length, chunkName, data)); + out->allocsize = out->size; /*fix the allocsize again*/ + return 0; +} + +static void writeSignature(ucvector* out) +{ + /*8 bytes PNG signature, aka the magic bytes*/ + ucvector_push_back(out, 137); + ucvector_push_back(out, 80); + ucvector_push_back(out, 78); + ucvector_push_back(out, 71); + ucvector_push_back(out, 13); + ucvector_push_back(out, 10); + ucvector_push_back(out, 26); + ucvector_push_back(out, 10); +} + +static unsigned addChunk_IHDR(ucvector* out, unsigned w, unsigned h, + LodePNGColorType colortype, unsigned bitdepth, unsigned interlace_method) +{ + unsigned error = 0; + ucvector header; + ucvector_init(&header); + + lodepng_add32bitInt(&header, w); /*width*/ + lodepng_add32bitInt(&header, h); /*height*/ + ucvector_push_back(&header, (unsigned char)bitdepth); /*bit depth*/ + ucvector_push_back(&header, (unsigned char)colortype); /*color type*/ + ucvector_push_back(&header, 0); /*compression method*/ + ucvector_push_back(&header, 0); /*filter method*/ + ucvector_push_back(&header, interlace_method); /*interlace method*/ + + error = addChunk(out, "IHDR", header.data, header.size); + ucvector_cleanup(&header); + + return error; +} + +static unsigned addChunk_PLTE(ucvector* out, const LodePNGColorMode* info) +{ + unsigned error = 0; + size_t i; + ucvector PLTE; + ucvector_init(&PLTE); + for(i = 0; i != info->palettesize * 4; ++i) + { + /*add all channels except alpha channel*/ + if(i % 4 != 3) ucvector_push_back(&PLTE, info->palette[i]); + } + error = addChunk(out, "PLTE", PLTE.data, PLTE.size); + ucvector_cleanup(&PLTE); + + return error; +} + +static unsigned addChunk_tRNS(ucvector* out, const LodePNGColorMode* info) +{ + unsigned error = 0; + size_t i; + ucvector tRNS; + ucvector_init(&tRNS); + if(info->colortype == LCT_PALETTE) + { + size_t amount = info->palettesize; + /*the tail of palette values that all have 255 as alpha, does not have to be encoded*/ + for(i = info->palettesize; i != 0; --i) + { + if(info->palette[4 * (i - 1) + 3] == 255) --amount; + else break; + } + /*add only alpha channel*/ + for(i = 0; i != amount; ++i) ucvector_push_back(&tRNS, info->palette[4 * i + 3]); + } + else if(info->colortype == LCT_GREY) + { + if(info->key_defined) + { + ucvector_push_back(&tRNS, (unsigned char)(info->key_r >> 8)); + ucvector_push_back(&tRNS, (unsigned char)(info->key_r & 255)); + } + } + else if(info->colortype == LCT_RGB) + { + if(info->key_defined) + { + ucvector_push_back(&tRNS, (unsigned char)(info->key_r >> 8)); + ucvector_push_back(&tRNS, (unsigned char)(info->key_r & 255)); + ucvector_push_back(&tRNS, (unsigned char)(info->key_g >> 8)); + ucvector_push_back(&tRNS, (unsigned char)(info->key_g & 255)); + ucvector_push_back(&tRNS, (unsigned char)(info->key_b >> 8)); + ucvector_push_back(&tRNS, (unsigned char)(info->key_b & 255)); + } + } + + error = addChunk(out, "tRNS", tRNS.data, tRNS.size); + ucvector_cleanup(&tRNS); + + return error; +} + +static unsigned addChunk_IDAT(ucvector* out, const unsigned char* data, size_t datasize, + LodePNGCompressSettings* zlibsettings) +{ + ucvector zlibdata; + unsigned error = 0; + + /*compress with the Zlib compressor*/ + ucvector_init(&zlibdata); + error = zlib_compress(&zlibdata.data, &zlibdata.size, data, datasize, zlibsettings); + if(!error) error = addChunk(out, "IDAT", zlibdata.data, zlibdata.size); + ucvector_cleanup(&zlibdata); + + return error; +} + +static unsigned addChunk_IEND(ucvector* out) +{ + unsigned error = 0; + error = addChunk(out, "IEND", 0, 0); + return error; +} + +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + +static unsigned addChunk_tEXt(ucvector* out, const char* keyword, const char* textstring) +{ + unsigned error = 0; + size_t i; + ucvector text; + ucvector_init(&text); + for(i = 0; keyword[i] != 0; ++i) ucvector_push_back(&text, (unsigned char)keyword[i]); + if(i < 1 || i > 79) return 89; /*error: invalid keyword size*/ + ucvector_push_back(&text, 0); /*0 termination char*/ + for(i = 0; textstring[i] != 0; ++i) ucvector_push_back(&text, (unsigned char)textstring[i]); + error = addChunk(out, "tEXt", text.data, text.size); + ucvector_cleanup(&text); + + return error; +} + +static unsigned addChunk_zTXt(ucvector* out, const char* keyword, const char* textstring, + LodePNGCompressSettings* zlibsettings) +{ + unsigned error = 0; + ucvector data, compressed; + size_t i, textsize = strlen(textstring); + + ucvector_init(&data); + ucvector_init(&compressed); + for(i = 0; keyword[i] != 0; ++i) ucvector_push_back(&data, (unsigned char)keyword[i]); + if(i < 1 || i > 79) return 89; /*error: invalid keyword size*/ + ucvector_push_back(&data, 0); /*0 termination char*/ + ucvector_push_back(&data, 0); /*compression method: 0*/ + + error = zlib_compress(&compressed.data, &compressed.size, + (unsigned char*)textstring, textsize, zlibsettings); + if(!error) + { + for(i = 0; i != compressed.size; ++i) ucvector_push_back(&data, compressed.data[i]); + error = addChunk(out, "zTXt", data.data, data.size); + } + + ucvector_cleanup(&compressed); + ucvector_cleanup(&data); + return error; +} + +static unsigned addChunk_iTXt(ucvector* out, unsigned compressed, const char* keyword, const char* langtag, + const char* transkey, const char* textstring, LodePNGCompressSettings* zlibsettings) +{ + unsigned error = 0; + ucvector data; + size_t i, textsize = strlen(textstring); + + ucvector_init(&data); + + for(i = 0; keyword[i] != 0; ++i) ucvector_push_back(&data, (unsigned char)keyword[i]); + if(i < 1 || i > 79) return 89; /*error: invalid keyword size*/ + ucvector_push_back(&data, 0); /*null termination char*/ + ucvector_push_back(&data, compressed ? 1 : 0); /*compression flag*/ + ucvector_push_back(&data, 0); /*compression method*/ + for(i = 0; langtag[i] != 0; ++i) ucvector_push_back(&data, (unsigned char)langtag[i]); + ucvector_push_back(&data, 0); /*null termination char*/ + for(i = 0; transkey[i] != 0; ++i) ucvector_push_back(&data, (unsigned char)transkey[i]); + ucvector_push_back(&data, 0); /*null termination char*/ + + if(compressed) + { + ucvector compressed_data; + ucvector_init(&compressed_data); + error = zlib_compress(&compressed_data.data, &compressed_data.size, + (unsigned char*)textstring, textsize, zlibsettings); + if(!error) + { + for(i = 0; i != compressed_data.size; ++i) ucvector_push_back(&data, compressed_data.data[i]); + } + ucvector_cleanup(&compressed_data); + } + else /*not compressed*/ + { + for(i = 0; textstring[i] != 0; ++i) ucvector_push_back(&data, (unsigned char)textstring[i]); + } + + if(!error) error = addChunk(out, "iTXt", data.data, data.size); + ucvector_cleanup(&data); + return error; +} + +static unsigned addChunk_bKGD(ucvector* out, const LodePNGInfo* info) +{ + unsigned error = 0; + ucvector bKGD; + ucvector_init(&bKGD); + if(info->color.colortype == LCT_GREY || info->color.colortype == LCT_GREY_ALPHA) + { + ucvector_push_back(&bKGD, (unsigned char)(info->background_r >> 8)); + ucvector_push_back(&bKGD, (unsigned char)(info->background_r & 255)); + } + else if(info->color.colortype == LCT_RGB || info->color.colortype == LCT_RGBA) + { + ucvector_push_back(&bKGD, (unsigned char)(info->background_r >> 8)); + ucvector_push_back(&bKGD, (unsigned char)(info->background_r & 255)); + ucvector_push_back(&bKGD, (unsigned char)(info->background_g >> 8)); + ucvector_push_back(&bKGD, (unsigned char)(info->background_g & 255)); + ucvector_push_back(&bKGD, (unsigned char)(info->background_b >> 8)); + ucvector_push_back(&bKGD, (unsigned char)(info->background_b & 255)); + } + else if(info->color.colortype == LCT_PALETTE) + { + ucvector_push_back(&bKGD, (unsigned char)(info->background_r & 255)); /*palette index*/ + } + + error = addChunk(out, "bKGD", bKGD.data, bKGD.size); + ucvector_cleanup(&bKGD); + + return error; +} + +static unsigned addChunk_tIME(ucvector* out, const LodePNGTime* time) +{ + unsigned error = 0; + unsigned char* data = (unsigned char*)lodepng_malloc(7); + if(!data) return 83; /*alloc fail*/ + data[0] = (unsigned char)(time->year >> 8); + data[1] = (unsigned char)(time->year & 255); + data[2] = (unsigned char)time->month; + data[3] = (unsigned char)time->day; + data[4] = (unsigned char)time->hour; + data[5] = (unsigned char)time->minute; + data[6] = (unsigned char)time->second; + error = addChunk(out, "tIME", data, 7); + lodepng_free(data); + return error; +} + +static unsigned addChunk_pHYs(ucvector* out, const LodePNGInfo* info) +{ + unsigned error = 0; + ucvector data; + ucvector_init(&data); + + lodepng_add32bitInt(&data, info->phys_x); + lodepng_add32bitInt(&data, info->phys_y); + ucvector_push_back(&data, info->phys_unit); + + error = addChunk(out, "pHYs", data.data, data.size); + ucvector_cleanup(&data); + + return error; +} + +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + +static void filterScanline(unsigned char* out, const unsigned char* scanline, const unsigned char* prevline, + size_t length, size_t bytewidth, unsigned char filterType) +{ + size_t i; + switch(filterType) + { + case 0: /*None*/ + for(i = 0; i != length; ++i) out[i] = scanline[i]; + break; + case 1: /*Sub*/ + for(i = 0; i != bytewidth; ++i) out[i] = scanline[i]; + for(i = bytewidth; i < length; ++i) out[i] = scanline[i] - scanline[i - bytewidth]; + break; + case 2: /*Up*/ + if(prevline) + { + for(i = 0; i != length; ++i) out[i] = scanline[i] - prevline[i]; + } + else + { + for(i = 0; i != length; ++i) out[i] = scanline[i]; + } + break; + case 3: /*Average*/ + if(prevline) + { + for(i = 0; i != bytewidth; ++i) out[i] = scanline[i] - (prevline[i] >> 1); + for(i = bytewidth; i < length; ++i) out[i] = scanline[i] - ((scanline[i - bytewidth] + prevline[i]) >> 1); + } + else + { + for(i = 0; i != bytewidth; ++i) out[i] = scanline[i]; + for(i = bytewidth; i < length; ++i) out[i] = scanline[i] - (scanline[i - bytewidth] >> 1); + } + break; + case 4: /*Paeth*/ + if(prevline) + { + /*paethPredictor(0, prevline[i], 0) is always prevline[i]*/ + for(i = 0; i != bytewidth; ++i) out[i] = (scanline[i] - prevline[i]); + for(i = bytewidth; i < length; ++i) + { + out[i] = (scanline[i] - paethPredictor(scanline[i - bytewidth], prevline[i], prevline[i - bytewidth])); + } + } + else + { + for(i = 0; i != bytewidth; ++i) out[i] = scanline[i]; + /*paethPredictor(scanline[i - bytewidth], 0, 0) is always scanline[i - bytewidth]*/ + for(i = bytewidth; i < length; ++i) out[i] = (scanline[i] - scanline[i - bytewidth]); + } + break; + default: return; /*unexisting filter type given*/ + } +} + +/* log2 approximation. A slight bit faster than std::log. */ +static float flog2(float f) +{ + float result = 0; + while(f > 32) { result += 4; f /= 16; } + while(f > 2) { ++result; f /= 2; } + return result + 1.442695f * (f * f * f / 3 - 3 * f * f / 2 + 3 * f - 1.83333f); +} + +static unsigned filter(unsigned char* out, const unsigned char* in, unsigned w, unsigned h, + const LodePNGColorMode* info, const LodePNGEncoderSettings* settings) +{ + /* + For PNG filter method 0 + out must be a buffer with as size: h + (w * h * bpp + 7) / 8, because there are + the scanlines with 1 extra byte per scanline + */ + + unsigned bpp = lodepng_get_bpp(info); + /*the width of a scanline in bytes, not including the filter type*/ + size_t linebytes = (w * bpp + 7) / 8; + /*bytewidth is used for filtering, is 1 when bpp < 8, number of bytes per pixel otherwise*/ + size_t bytewidth = (bpp + 7) / 8; + const unsigned char* prevline = 0; + unsigned x, y; + unsigned error = 0; + LodePNGFilterStrategy strategy = settings->filter_strategy; + + /* + There is a heuristic called the minimum sum of absolute differences heuristic, suggested by the PNG standard: + * If the image type is Palette, or the bit depth is smaller than 8, then do not filter the image (i.e. + use fixed filtering, with the filter None). + * (The other case) If the image type is Grayscale or RGB (with or without Alpha), and the bit depth is + not smaller than 8, then use adaptive filtering heuristic as follows: independently for each row, apply + all five filters and select the filter that produces the smallest sum of absolute values per row. + This heuristic is used if filter strategy is LFS_MINSUM and filter_palette_zero is true. + + If filter_palette_zero is true and filter_strategy is not LFS_MINSUM, the above heuristic is followed, + but for "the other case", whatever strategy filter_strategy is set to instead of the minimum sum + heuristic is used. + */ + if(settings->filter_palette_zero && + (info->colortype == LCT_PALETTE || info->bitdepth < 8)) strategy = LFS_ZERO; + + if(bpp == 0) return 31; /*error: invalid color type*/ + + if(strategy == LFS_ZERO) + { + for(y = 0; y != h; ++y) + { + size_t outindex = (1 + linebytes) * y; /*the extra filterbyte added to each row*/ + size_t inindex = linebytes * y; + out[outindex] = 0; /*filter type byte*/ + filterScanline(&out[outindex + 1], &in[inindex], prevline, linebytes, bytewidth, 0); + prevline = &in[inindex]; + } + } + else if(strategy == LFS_MINSUM) + { + /*adaptive filtering*/ + size_t sum[5]; + unsigned char* attempt[5]; /*five filtering attempts, one for each filter type*/ + size_t smallest = 0; + unsigned char type, bestType = 0; + + for(type = 0; type != 5; ++type) + { + attempt[type] = (unsigned char*)lodepng_malloc(linebytes); + if(!attempt[type]) return 83; /*alloc fail*/ + } + + if(!error) + { + for(y = 0; y != h; ++y) + { + /*try the 5 filter types*/ + for(type = 0; type != 5; ++type) + { + filterScanline(attempt[type], &in[y * linebytes], prevline, linebytes, bytewidth, type); + + /*calculate the sum of the result*/ + sum[type] = 0; + if(type == 0) + { + for(x = 0; x != linebytes; ++x) sum[type] += (unsigned char)(attempt[type][x]); + } + else + { + for(x = 0; x != linebytes; ++x) + { + /*For differences, each byte should be treated as signed, values above 127 are negative + (converted to signed char). Filtertype 0 isn't a difference though, so use unsigned there. + This means filtertype 0 is almost never chosen, but that is justified.*/ + unsigned char s = attempt[type][x]; + sum[type] += s < 128 ? s : (255U - s); + } + } + + /*check if this is smallest sum (or if type == 0 it's the first case so always store the values)*/ + if(type == 0 || sum[type] < smallest) + { + bestType = type; + smallest = sum[type]; + } + } + + prevline = &in[y * linebytes]; + + /*now fill the out values*/ + out[y * (linebytes + 1)] = bestType; /*the first byte of a scanline will be the filter type*/ + for(x = 0; x != linebytes; ++x) out[y * (linebytes + 1) + 1 + x] = attempt[bestType][x]; + } + } + + for(type = 0; type != 5; ++type) lodepng_free(attempt[type]); + } + else if(strategy == LFS_ENTROPY) + { + float sum[5]; + unsigned char* attempt[5]; /*five filtering attempts, one for each filter type*/ + float smallest = 0; + unsigned type, bestType = 0; + unsigned count[256]; + + for(type = 0; type != 5; ++type) + { + attempt[type] = (unsigned char*)lodepng_malloc(linebytes); + if(!attempt[type]) return 83; /*alloc fail*/ + } + + for(y = 0; y != h; ++y) + { + /*try the 5 filter types*/ + for(type = 0; type != 5; ++type) + { + filterScanline(attempt[type], &in[y * linebytes], prevline, linebytes, bytewidth, type); + for(x = 0; x != 256; ++x) count[x] = 0; + for(x = 0; x != linebytes; ++x) ++count[attempt[type][x]]; + ++count[type]; /*the filter type itself is part of the scanline*/ + sum[type] = 0; + for(x = 0; x != 256; ++x) + { + float p = count[x] / (float)(linebytes + 1); + sum[type] += count[x] == 0 ? 0 : flog2(1 / p) * p; + } + /*check if this is smallest sum (or if type == 0 it's the first case so always store the values)*/ + if(type == 0 || sum[type] < smallest) + { + bestType = type; + smallest = sum[type]; + } + } + + prevline = &in[y * linebytes]; + + /*now fill the out values*/ + out[y * (linebytes + 1)] = bestType; /*the first byte of a scanline will be the filter type*/ + for(x = 0; x != linebytes; ++x) out[y * (linebytes + 1) + 1 + x] = attempt[bestType][x]; + } + + for(type = 0; type != 5; ++type) lodepng_free(attempt[type]); + } + else if(strategy == LFS_PREDEFINED) + { + for(y = 0; y != h; ++y) + { + size_t outindex = (1 + linebytes) * y; /*the extra filterbyte added to each row*/ + size_t inindex = linebytes * y; + unsigned char type = settings->predefined_filters[y]; + out[outindex] = type; /*filter type byte*/ + filterScanline(&out[outindex + 1], &in[inindex], prevline, linebytes, bytewidth, type); + prevline = &in[inindex]; + } + } + else if(strategy == LFS_BRUTE_FORCE) + { + /*brute force filter chooser. + deflate the scanline after every filter attempt to see which one deflates best. + This is very slow and gives only slightly smaller, sometimes even larger, result*/ + size_t size[5]; + unsigned char* attempt[5]; /*five filtering attempts, one for each filter type*/ + size_t smallest = 0; + unsigned type = 0, bestType = 0; + unsigned char* dummy; + LodePNGCompressSettings zlibsettings = settings->zlibsettings; + /*use fixed tree on the attempts so that the tree is not adapted to the filtertype on purpose, + to simulate the true case where the tree is the same for the whole image. Sometimes it gives + better result with dynamic tree anyway. Using the fixed tree sometimes gives worse, but in rare + cases better compression. It does make this a bit less slow, so it's worth doing this.*/ + zlibsettings.btype = 1; + /*a custom encoder likely doesn't read the btype setting and is optimized for complete PNG + images only, so disable it*/ + zlibsettings.custom_zlib = 0; + zlibsettings.custom_deflate = 0; + for(type = 0; type != 5; ++type) + { + attempt[type] = (unsigned char*)lodepng_malloc(linebytes); + if(!attempt[type]) return 83; /*alloc fail*/ + } + for(y = 0; y != h; ++y) /*try the 5 filter types*/ + { + for(type = 0; type != 5; ++type) + { + unsigned testsize = linebytes; + /*if(testsize > 8) testsize /= 8;*/ /*it already works good enough by testing a part of the row*/ + + filterScanline(attempt[type], &in[y * linebytes], prevline, linebytes, bytewidth, type); + size[type] = 0; + dummy = 0; + zlib_compress(&dummy, &size[type], attempt[type], testsize, &zlibsettings); + lodepng_free(dummy); + /*check if this is smallest size (or if type == 0 it's the first case so always store the values)*/ + if(type == 0 || size[type] < smallest) + { + bestType = type; + smallest = size[type]; + } + } + prevline = &in[y * linebytes]; + out[y * (linebytes + 1)] = bestType; /*the first byte of a scanline will be the filter type*/ + for(x = 0; x != linebytes; ++x) out[y * (linebytes + 1) + 1 + x] = attempt[bestType][x]; + } + for(type = 0; type != 5; ++type) lodepng_free(attempt[type]); + } + else return 88; /* unknown filter strategy */ + + return error; +} + +static void addPaddingBits(unsigned char* out, const unsigned char* in, + size_t olinebits, size_t ilinebits, unsigned h) +{ + /*The opposite of the removePaddingBits function + olinebits must be >= ilinebits*/ + unsigned y; + size_t diff = olinebits - ilinebits; + size_t obp = 0, ibp = 0; /*bit pointers*/ + for(y = 0; y != h; ++y) + { + size_t x; + for(x = 0; x < ilinebits; ++x) + { + unsigned char bit = readBitFromReversedStream(&ibp, in); + setBitOfReversedStream(&obp, out, bit); + } + /*obp += diff; --> no, fill in some value in the padding bits too, to avoid + "Use of uninitialised value of size ###" warning from valgrind*/ + for(x = 0; x != diff; ++x) setBitOfReversedStream(&obp, out, 0); + } +} + +/* +in: non-interlaced image with size w*h +out: the same pixels, but re-ordered according to PNG's Adam7 interlacing, with + no padding bits between scanlines, but between reduced images so that each + reduced image starts at a byte. +bpp: bits per pixel +there are no padding bits, not between scanlines, not between reduced images +in has the following size in bits: w * h * bpp. +out is possibly bigger due to padding bits between reduced images +NOTE: comments about padding bits are only relevant if bpp < 8 +*/ +static void Adam7_interlace(unsigned char* out, const unsigned char* in, unsigned w, unsigned h, unsigned bpp) +{ + unsigned passw[7], passh[7]; + size_t filter_passstart[8], padded_passstart[8], passstart[8]; + unsigned i; + + Adam7_getpassvalues(passw, passh, filter_passstart, padded_passstart, passstart, w, h, bpp); + + if(bpp >= 8) + { + for(i = 0; i != 7; ++i) + { + unsigned x, y, b; + size_t bytewidth = bpp / 8; + for(y = 0; y < passh[i]; ++y) + for(x = 0; x < passw[i]; ++x) + { + size_t pixelinstart = ((ADAM7_IY[i] + y * ADAM7_DY[i]) * w + ADAM7_IX[i] + x * ADAM7_DX[i]) * bytewidth; + size_t pixeloutstart = passstart[i] + (y * passw[i] + x) * bytewidth; + for(b = 0; b < bytewidth; ++b) + { + out[pixeloutstart + b] = in[pixelinstart + b]; + } + } + } + } + else /*bpp < 8: Adam7 with pixels < 8 bit is a bit trickier: with bit pointers*/ + { + for(i = 0; i != 7; ++i) + { + unsigned x, y, b; + unsigned ilinebits = bpp * passw[i]; + unsigned olinebits = bpp * w; + size_t obp, ibp; /*bit pointers (for out and in buffer)*/ + for(y = 0; y < passh[i]; ++y) + for(x = 0; x < passw[i]; ++x) + { + ibp = (ADAM7_IY[i] + y * ADAM7_DY[i]) * olinebits + (ADAM7_IX[i] + x * ADAM7_DX[i]) * bpp; + obp = (8 * passstart[i]) + (y * ilinebits + x * bpp); + for(b = 0; b < bpp; ++b) + { + unsigned char bit = readBitFromReversedStream(&ibp, in); + setBitOfReversedStream(&obp, out, bit); + } + } + } + } +} + +/*out must be buffer big enough to contain uncompressed IDAT chunk data, and in must contain the full image. +return value is error**/ +static unsigned preProcessScanlines(unsigned char** out, size_t* outsize, const unsigned char* in, + unsigned w, unsigned h, + const LodePNGInfo* info_png, const LodePNGEncoderSettings* settings) +{ + /* + This function converts the pure 2D image with the PNG's colortype, into filtered-padded-interlaced data. Steps: + *) if no Adam7: 1) add padding bits (= posible extra bits per scanline if bpp < 8) 2) filter + *) if adam7: 1) Adam7_interlace 2) 7x add padding bits 3) 7x filter + */ + unsigned bpp = lodepng_get_bpp(&info_png->color); + unsigned error = 0; + + if(info_png->interlace_method == 0) + { + *outsize = h + (h * ((w * bpp + 7) / 8)); /*image size plus an extra byte per scanline + possible padding bits*/ + *out = (unsigned char*)lodepng_malloc(*outsize); + if(!(*out) && (*outsize)) error = 83; /*alloc fail*/ + + if(!error) + { + /*non multiple of 8 bits per scanline, padding bits needed per scanline*/ + if(bpp < 8 && w * bpp != ((w * bpp + 7) / 8) * 8) + { + unsigned char* padded = (unsigned char*)lodepng_malloc(h * ((w * bpp + 7) / 8)); + if(!padded) error = 83; /*alloc fail*/ + if(!error) + { + addPaddingBits(padded, in, ((w * bpp + 7) / 8) * 8, w * bpp, h); + error = filter(*out, padded, w, h, &info_png->color, settings); + } + lodepng_free(padded); + } + else + { + /*we can immediately filter into the out buffer, no other steps needed*/ + error = filter(*out, in, w, h, &info_png->color, settings); + } + } + } + else /*interlace_method is 1 (Adam7)*/ + { + unsigned passw[7], passh[7]; + size_t filter_passstart[8], padded_passstart[8], passstart[8]; + unsigned char* adam7; + + Adam7_getpassvalues(passw, passh, filter_passstart, padded_passstart, passstart, w, h, bpp); + + *outsize = filter_passstart[7]; /*image size plus an extra byte per scanline + possible padding bits*/ + *out = (unsigned char*)lodepng_malloc(*outsize); + if(!(*out)) error = 83; /*alloc fail*/ + + adam7 = (unsigned char*)lodepng_malloc(passstart[7]); + if(!adam7 && passstart[7]) error = 83; /*alloc fail*/ + + if(!error) + { + unsigned i; + + Adam7_interlace(adam7, in, w, h, bpp); + for(i = 0; i != 7; ++i) + { + if(bpp < 8) + { + unsigned char* padded = (unsigned char*)lodepng_malloc(padded_passstart[i + 1] - padded_passstart[i]); + if(!padded) ERROR_BREAK(83); /*alloc fail*/ + addPaddingBits(padded, &adam7[passstart[i]], + ((passw[i] * bpp + 7) / 8) * 8, passw[i] * bpp, passh[i]); + error = filter(&(*out)[filter_passstart[i]], padded, + passw[i], passh[i], &info_png->color, settings); + lodepng_free(padded); + } + else + { + error = filter(&(*out)[filter_passstart[i]], &adam7[padded_passstart[i]], + passw[i], passh[i], &info_png->color, settings); + } + + if(error) break; + } + } + + lodepng_free(adam7); + } + + return error; +} + +/* +palette must have 4 * palettesize bytes allocated, and given in format RGBARGBARGBARGBA... +returns 0 if the palette is opaque, +returns 1 if the palette has a single color with alpha 0 ==> color key +returns 2 if the palette is semi-translucent. +*/ +static unsigned getPaletteTranslucency(const unsigned char* palette, size_t palettesize) +{ + size_t i; + unsigned key = 0; + unsigned r = 0, g = 0, b = 0; /*the value of the color with alpha 0, so long as color keying is possible*/ + for(i = 0; i != palettesize; ++i) + { + if(!key && palette[4 * i + 3] == 0) + { + r = palette[4 * i + 0]; g = palette[4 * i + 1]; b = palette[4 * i + 2]; + key = 1; + i = (size_t)(-1); /*restart from beginning, to detect earlier opaque colors with key's value*/ + } + else if(palette[4 * i + 3] != 255) return 2; + /*when key, no opaque RGB may have key's RGB*/ + else if(key && r == palette[i * 4 + 0] && g == palette[i * 4 + 1] && b == palette[i * 4 + 2]) return 2; + } + return key; +} + +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS +static unsigned addUnknownChunks(ucvector* out, unsigned char* data, size_t datasize) +{ + unsigned char* inchunk = data; + while((size_t)(inchunk - data) < datasize) + { + CERROR_TRY_RETURN(lodepng_chunk_append(&out->data, &out->size, inchunk)); + out->allocsize = out->size; /*fix the allocsize again*/ + inchunk = lodepng_chunk_next(inchunk); + } + return 0; +} +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + +unsigned lodepng_encode(unsigned char** out, size_t* outsize, + const unsigned char* image, unsigned w, unsigned h, + LodePNGState* state) +{ + LodePNGInfo info; + ucvector outv; + unsigned char* data = 0; /*uncompressed version of the IDAT chunk data*/ + size_t datasize = 0; + + /*provide some proper output values if error will happen*/ + *out = 0; + *outsize = 0; + state->error = 0; + + lodepng_info_init(&info); + lodepng_info_copy(&info, &state->info_png); + + if((info.color.colortype == LCT_PALETTE || state->encoder.force_palette) + && (info.color.palettesize == 0 || info.color.palettesize > 256)) + { + state->error = 68; /*invalid palette size, it is only allowed to be 1-256*/ + return state->error; + } + + if(state->encoder.auto_convert) + { + state->error = lodepng_auto_choose_color(&info.color, image, w, h, &state->info_raw); + } + if(state->error) return state->error; + + if(state->encoder.zlibsettings.btype > 2) + { + CERROR_RETURN_ERROR(state->error, 61); /*error: unexisting btype*/ + } + if(state->info_png.interlace_method > 1) + { + CERROR_RETURN_ERROR(state->error, 71); /*error: unexisting interlace mode*/ + } + + state->error = checkColorValidity(info.color.colortype, info.color.bitdepth); + if(state->error) return state->error; /*error: unexisting color type given*/ + state->error = checkColorValidity(state->info_raw.colortype, state->info_raw.bitdepth); + if(state->error) return state->error; /*error: unexisting color type given*/ + + if(!lodepng_color_mode_equal(&state->info_raw, &info.color)) + { + unsigned char* converted; + size_t size = (w * h * lodepng_get_bpp(&info.color) + 7) / 8; + + converted = (unsigned char*)lodepng_malloc(size); + if(!converted && size) state->error = 83; /*alloc fail*/ + if(!state->error) + { + state->error = lodepng_convert(converted, image, &info.color, &state->info_raw, w, h); + } + if(!state->error) preProcessScanlines(&data, &datasize, converted, w, h, &info, &state->encoder); + lodepng_free(converted); + } + else preProcessScanlines(&data, &datasize, image, w, h, &info, &state->encoder); + + ucvector_init(&outv); + while(!state->error) /*while only executed once, to break on error*/ + { +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + size_t i; +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + /*write signature and chunks*/ + writeSignature(&outv); + /*IHDR*/ + addChunk_IHDR(&outv, w, h, info.color.colortype, info.color.bitdepth, info.interlace_method); +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + /*unknown chunks between IHDR and PLTE*/ + if(info.unknown_chunks_data[0]) + { + state->error = addUnknownChunks(&outv, info.unknown_chunks_data[0], info.unknown_chunks_size[0]); + if(state->error) break; + } +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + /*PLTE*/ + if(info.color.colortype == LCT_PALETTE) + { + addChunk_PLTE(&outv, &info.color); + } + if(state->encoder.force_palette && (info.color.colortype == LCT_RGB || info.color.colortype == LCT_RGBA)) + { + addChunk_PLTE(&outv, &info.color); + } + /*tRNS*/ + if(info.color.colortype == LCT_PALETTE && getPaletteTranslucency(info.color.palette, info.color.palettesize) != 0) + { + addChunk_tRNS(&outv, &info.color); + } + if((info.color.colortype == LCT_GREY || info.color.colortype == LCT_RGB) && info.color.key_defined) + { + addChunk_tRNS(&outv, &info.color); + } +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + /*bKGD (must come between PLTE and the IDAt chunks*/ + if(info.background_defined) addChunk_bKGD(&outv, &info); + /*pHYs (must come before the IDAT chunks)*/ + if(info.phys_defined) addChunk_pHYs(&outv, &info); + + /*unknown chunks between PLTE and IDAT*/ + if(info.unknown_chunks_data[1]) + { + state->error = addUnknownChunks(&outv, info.unknown_chunks_data[1], info.unknown_chunks_size[1]); + if(state->error) break; + } +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + /*IDAT (multiple IDAT chunks must be consecutive)*/ + state->error = addChunk_IDAT(&outv, data, datasize, &state->encoder.zlibsettings); + if(state->error) break; +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + /*tIME*/ + if(info.time_defined) addChunk_tIME(&outv, &info.time); + /*tEXt and/or zTXt*/ + for(i = 0; i != info.text_num; ++i) + { + if(strlen(info.text_keys[i]) > 79) + { + state->error = 66; /*text chunk too large*/ + break; + } + if(strlen(info.text_keys[i]) < 1) + { + state->error = 67; /*text chunk too small*/ + break; + } + if(state->encoder.text_compression) + { + addChunk_zTXt(&outv, info.text_keys[i], info.text_strings[i], &state->encoder.zlibsettings); + } + else + { + addChunk_tEXt(&outv, info.text_keys[i], info.text_strings[i]); + } + } + /*LodePNG version id in text chunk*/ + if(state->encoder.add_id) + { + unsigned alread_added_id_text = 0; + for(i = 0; i != info.text_num; ++i) + { + if(!strcmp(info.text_keys[i], "LodePNG")) + { + alread_added_id_text = 1; + break; + } + } + if(alread_added_id_text == 0) + { + addChunk_tEXt(&outv, "LodePNG", LODEPNG_VERSION_STRING); /*it's shorter as tEXt than as zTXt chunk*/ + } + } + /*iTXt*/ + for(i = 0; i != info.itext_num; ++i) + { + if(strlen(info.itext_keys[i]) > 79) + { + state->error = 66; /*text chunk too large*/ + break; + } + if(strlen(info.itext_keys[i]) < 1) + { + state->error = 67; /*text chunk too small*/ + break; + } + addChunk_iTXt(&outv, state->encoder.text_compression, + info.itext_keys[i], info.itext_langtags[i], info.itext_transkeys[i], info.itext_strings[i], + &state->encoder.zlibsettings); + } + + /*unknown chunks between IDAT and IEND*/ + if(info.unknown_chunks_data[2]) + { + state->error = addUnknownChunks(&outv, info.unknown_chunks_data[2], info.unknown_chunks_size[2]); + if(state->error) break; + } +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + addChunk_IEND(&outv); + + break; /*this isn't really a while loop; no error happened so break out now!*/ + } + + lodepng_info_cleanup(&info); + lodepng_free(data); + /*instead of cleaning the vector up, give it to the output*/ + *out = outv.data; + *outsize = outv.size; + + return state->error; +} + +unsigned lodepng_encode_memory(unsigned char** out, size_t* outsize, const unsigned char* image, + unsigned w, unsigned h, LodePNGColorType colortype, unsigned bitdepth) +{ + unsigned error; + LodePNGState state; + lodepng_state_init(&state); + state.info_raw.colortype = colortype; + state.info_raw.bitdepth = bitdepth; + state.info_png.color.colortype = colortype; + state.info_png.color.bitdepth = bitdepth; + lodepng_encode(out, outsize, image, w, h, &state); + error = state.error; + lodepng_state_cleanup(&state); + return error; +} + +unsigned lodepng_encode32(unsigned char** out, size_t* outsize, const unsigned char* image, unsigned w, unsigned h) +{ + return lodepng_encode_memory(out, outsize, image, w, h, LCT_RGBA, 8); +} + +unsigned lodepng_encode24(unsigned char** out, size_t* outsize, const unsigned char* image, unsigned w, unsigned h) +{ + return lodepng_encode_memory(out, outsize, image, w, h, LCT_RGB, 8); +} + +#ifdef LODEPNG_COMPILE_DISK +unsigned lodepng_encode_file(const char* filename, const unsigned char* image, unsigned w, unsigned h, + LodePNGColorType colortype, unsigned bitdepth) +{ + unsigned char* buffer; + size_t buffersize; + unsigned error = lodepng_encode_memory(&buffer, &buffersize, image, w, h, colortype, bitdepth); + if(!error) error = lodepng_save_file(buffer, buffersize, filename); + lodepng_free(buffer); + return error; +} + +unsigned lodepng_encode32_file(const char* filename, const unsigned char* image, unsigned w, unsigned h) +{ + return lodepng_encode_file(filename, image, w, h, LCT_RGBA, 8); +} + +unsigned lodepng_encode24_file(const char* filename, const unsigned char* image, unsigned w, unsigned h) +{ + return lodepng_encode_file(filename, image, w, h, LCT_RGB, 8); +} +#endif /*LODEPNG_COMPILE_DISK*/ + +void lodepng_encoder_settings_init(LodePNGEncoderSettings* settings) +{ + lodepng_compress_settings_init(&settings->zlibsettings); + settings->filter_palette_zero = 1; + settings->filter_strategy = LFS_MINSUM; + settings->auto_convert = 1; + settings->force_palette = 0; + settings->predefined_filters = 0; +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + settings->add_id = 0; + settings->text_compression = 1; +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ +} + +#endif /*LODEPNG_COMPILE_ENCODER*/ +#endif /*LODEPNG_COMPILE_PNG*/ + +#ifdef LODEPNG_COMPILE_ERROR_TEXT +/* +This returns the description of a numerical error code in English. This is also +the documentation of all the error codes. +*/ +const char* lodepng_error_text(unsigned code) +{ + switch(code) + { + case 0: return "no error, everything went ok"; + case 1: return "nothing done yet"; /*the Encoder/Decoder has done nothing yet, error checking makes no sense yet*/ + case 10: return "end of input memory reached without huffman end code"; /*while huffman decoding*/ + case 11: return "error in code tree made it jump outside of huffman tree"; /*while huffman decoding*/ + case 13: return "problem while processing dynamic deflate block"; + case 14: return "problem while processing dynamic deflate block"; + case 15: return "problem while processing dynamic deflate block"; + case 16: return "unexisting code while processing dynamic deflate block"; + case 17: return "end of out buffer memory reached while inflating"; + case 18: return "invalid distance code while inflating"; + case 19: return "end of out buffer memory reached while inflating"; + case 20: return "invalid deflate block BTYPE encountered while decoding"; + case 21: return "NLEN is not ones complement of LEN in a deflate block"; + /*end of out buffer memory reached while inflating: + This can happen if the inflated deflate data is longer than the amount of bytes required to fill up + all the pixels of the image, given the color depth and image dimensions. Something that doesn't + happen in a normal, well encoded, PNG image.*/ + case 22: return "end of out buffer memory reached while inflating"; + case 23: return "end of in buffer memory reached while inflating"; + case 24: return "invalid FCHECK in zlib header"; + case 25: return "invalid compression method in zlib header"; + case 26: return "FDICT encountered in zlib header while it's not used for PNG"; + case 27: return "PNG file is smaller than a PNG header"; + /*Checks the magic file header, the first 8 bytes of the PNG file*/ + case 28: return "incorrect PNG signature, it's no PNG or corrupted"; + case 29: return "first chunk is not the header chunk"; + case 30: return "chunk length too large, chunk broken off at end of file"; + case 31: return "illegal PNG color type or bpp"; + case 32: return "illegal PNG compression method"; + case 33: return "illegal PNG filter method"; + case 34: return "illegal PNG interlace method"; + case 35: return "chunk length of a chunk is too large or the chunk too small"; + case 36: return "illegal PNG filter type encountered"; + case 37: return "illegal bit depth for this color type given"; + case 38: return "the palette is too big"; /*more than 256 colors*/ + case 39: return "more palette alpha values given in tRNS chunk than there are colors in the palette"; + case 40: return "tRNS chunk has wrong size for greyscale image"; + case 41: return "tRNS chunk has wrong size for RGB image"; + case 42: return "tRNS chunk appeared while it was not allowed for this color type"; + case 43: return "bKGD chunk has wrong size for palette image"; + case 44: return "bKGD chunk has wrong size for greyscale image"; + case 45: return "bKGD chunk has wrong size for RGB image"; + case 48: return "empty input buffer given to decoder. Maybe caused by non-existing file?"; + case 49: return "jumped past memory while generating dynamic huffman tree"; + case 50: return "jumped past memory while generating dynamic huffman tree"; + case 51: return "jumped past memory while inflating huffman block"; + case 52: return "jumped past memory while inflating"; + case 53: return "size of zlib data too small"; + case 54: return "repeat symbol in tree while there was no value symbol yet"; + /*jumped past tree while generating huffman tree, this could be when the + tree will have more leaves than symbols after generating it out of the + given lenghts. They call this an oversubscribed dynamic bit lengths tree in zlib.*/ + case 55: return "jumped past tree while generating huffman tree"; + case 56: return "given output image colortype or bitdepth not supported for color conversion"; + case 57: return "invalid CRC encountered (checking CRC can be disabled)"; + case 58: return "invalid ADLER32 encountered (checking ADLER32 can be disabled)"; + case 59: return "requested color conversion not supported"; + case 60: return "invalid window size given in the settings of the encoder (must be 0-32768)"; + case 61: return "invalid BTYPE given in the settings of the encoder (only 0, 1 and 2 are allowed)"; + /*LodePNG leaves the choice of RGB to greyscale conversion formula to the user.*/ + case 62: return "conversion from color to greyscale not supported"; + case 63: return "length of a chunk too long, max allowed for PNG is 2147483647 bytes per chunk"; /*(2^31-1)*/ + /*this would result in the inability of a deflated block to ever contain an end code. It must be at least 1.*/ + case 64: return "the length of the END symbol 256 in the Huffman tree is 0"; + case 66: return "the length of a text chunk keyword given to the encoder is longer than the maximum of 79 bytes"; + case 67: return "the length of a text chunk keyword given to the encoder is smaller than the minimum of 1 byte"; + case 68: return "tried to encode a PLTE chunk with a palette that has less than 1 or more than 256 colors"; + case 69: return "unknown chunk type with 'critical' flag encountered by the decoder"; + case 71: return "unexisting interlace mode given to encoder (must be 0 or 1)"; + case 72: return "while decoding, unexisting compression method encountering in zTXt or iTXt chunk (it must be 0)"; + case 73: return "invalid tIME chunk size"; + case 74: return "invalid pHYs chunk size"; + /*length could be wrong, or data chopped off*/ + case 75: return "no null termination char found while decoding text chunk"; + case 76: return "iTXt chunk too short to contain required bytes"; + case 77: return "integer overflow in buffer size"; + case 78: return "failed to open file for reading"; /*file doesn't exist or couldn't be opened for reading*/ + case 79: return "failed to open file for writing"; + case 80: return "tried creating a tree of 0 symbols"; + case 81: return "lazy matching at pos 0 is impossible"; + case 82: return "color conversion to palette requested while a color isn't in palette"; + case 83: return "memory allocation failed"; + case 84: return "given image too small to contain all pixels to be encoded"; + case 86: return "impossible offset in lz77 encoding (internal bug)"; + case 87: return "must provide custom zlib function pointer if LODEPNG_COMPILE_ZLIB is not defined"; + case 88: return "invalid filter strategy given for LodePNGEncoderSettings.filter_strategy"; + case 89: return "text chunk keyword too short or long: must have size 1-79"; + /*the windowsize in the LodePNGCompressSettings. Requiring POT(==> & instead of %) makes encoding 12% faster.*/ + case 90: return "windowsize must be a power of two"; + case 91: return "invalid decompressed idat size"; + case 92: return "too many pixels, not supported"; + case 93: return "zero width or height is invalid"; + case 94: return "header chunk must have a size of 13 bytes"; + } + return "unknown error code"; +} +#endif /*LODEPNG_COMPILE_ERROR_TEXT*/ + +/* ////////////////////////////////////////////////////////////////////////// */ +/* ////////////////////////////////////////////////////////////////////////// */ +/* // C++ Wrapper // */ +/* ////////////////////////////////////////////////////////////////////////// */ +/* ////////////////////////////////////////////////////////////////////////// */ + +#ifdef LODEPNG_COMPILE_CPP +namespace lodepng +{ + +#ifdef LODEPNG_COMPILE_DISK +unsigned load_file(std::vector<unsigned char>& buffer, const std::string& filename) +{ + long size = lodepng_filesize(filename.c_str()); + if(size < 0) return 78; + buffer.resize((size_t)size); + return size == 0 ? 0 : lodepng_buffer_file(&buffer[0], (size_t)size, filename.c_str()); +} + +/*write given buffer to the file, overwriting the file, it doesn't append to it.*/ +unsigned save_file(const std::vector<unsigned char>& buffer, const std::string& filename) +{ + return lodepng_save_file(buffer.empty() ? 0 : &buffer[0], buffer.size(), filename.c_str()); +} +#endif /* LODEPNG_COMPILE_DISK */ + +#ifdef LODEPNG_COMPILE_ZLIB +#ifdef LODEPNG_COMPILE_DECODER +unsigned decompress(std::vector<unsigned char>& out, const unsigned char* in, size_t insize, + const LodePNGDecompressSettings& settings) +{ + unsigned char* buffer = 0; + size_t buffersize = 0; + unsigned error = zlib_decompress(&buffer, &buffersize, in, insize, &settings); + if(buffer) + { + out.insert(out.end(), &buffer[0], &buffer[buffersize]); + lodepng_free(buffer); + } + return error; +} + +unsigned decompress(std::vector<unsigned char>& out, const std::vector<unsigned char>& in, + const LodePNGDecompressSettings& settings) +{ + return decompress(out, in.empty() ? 0 : &in[0], in.size(), settings); +} +#endif /* LODEPNG_COMPILE_DECODER */ + +#ifdef LODEPNG_COMPILE_ENCODER +unsigned compress(std::vector<unsigned char>& out, const unsigned char* in, size_t insize, + const LodePNGCompressSettings& settings) +{ + unsigned char* buffer = 0; + size_t buffersize = 0; + unsigned error = zlib_compress(&buffer, &buffersize, in, insize, &settings); + if(buffer) + { + out.insert(out.end(), &buffer[0], &buffer[buffersize]); + lodepng_free(buffer); + } + return error; +} + +unsigned compress(std::vector<unsigned char>& out, const std::vector<unsigned char>& in, + const LodePNGCompressSettings& settings) +{ + return compress(out, in.empty() ? 0 : &in[0], in.size(), settings); +} +#endif /* LODEPNG_COMPILE_ENCODER */ +#endif /* LODEPNG_COMPILE_ZLIB */ + + +#ifdef LODEPNG_COMPILE_PNG + +State::State() +{ + lodepng_state_init(this); +} + +State::State(const State& other) +{ + lodepng_state_init(this); + lodepng_state_copy(this, &other); +} + +State::~State() +{ + lodepng_state_cleanup(this); +} + +State& State::operator=(const State& other) +{ + lodepng_state_copy(this, &other); + return *this; +} + +#ifdef LODEPNG_COMPILE_DECODER + +unsigned decode(std::vector<unsigned char>& out, unsigned& w, unsigned& h, const unsigned char* in, + size_t insize, LodePNGColorType colortype, unsigned bitdepth) +{ + unsigned char* buffer; + unsigned error = lodepng_decode_memory(&buffer, &w, &h, in, insize, colortype, bitdepth); + if(buffer && !error) + { + State state; + state.info_raw.colortype = colortype; + state.info_raw.bitdepth = bitdepth; + size_t buffersize = lodepng_get_raw_size(w, h, &state.info_raw); + out.insert(out.end(), &buffer[0], &buffer[buffersize]); + lodepng_free(buffer); + } + return error; +} + +unsigned decode(std::vector<unsigned char>& out, unsigned& w, unsigned& h, + const std::vector<unsigned char>& in, LodePNGColorType colortype, unsigned bitdepth) +{ + return decode(out, w, h, in.empty() ? 0 : &in[0], (unsigned)in.size(), colortype, bitdepth); +} + +unsigned decode(std::vector<unsigned char>& out, unsigned& w, unsigned& h, + State& state, + const unsigned char* in, size_t insize) +{ + unsigned char* buffer = NULL; + unsigned error = lodepng_decode(&buffer, &w, &h, &state, in, insize); + if(buffer && !error) + { + size_t buffersize = lodepng_get_raw_size(w, h, &state.info_raw); + out.insert(out.end(), &buffer[0], &buffer[buffersize]); + } + lodepng_free(buffer); + return error; +} + +unsigned decode(std::vector<unsigned char>& out, unsigned& w, unsigned& h, + State& state, + const std::vector<unsigned char>& in) +{ + return decode(out, w, h, state, in.empty() ? 0 : &in[0], in.size()); +} + +#ifdef LODEPNG_COMPILE_DISK +unsigned decode(std::vector<unsigned char>& out, unsigned& w, unsigned& h, const std::string& filename, + LodePNGColorType colortype, unsigned bitdepth) +{ + std::vector<unsigned char> buffer; + unsigned error = load_file(buffer, filename); + if(error) return error; + return decode(out, w, h, buffer, colortype, bitdepth); +} +#endif /* LODEPNG_COMPILE_DECODER */ +#endif /* LODEPNG_COMPILE_DISK */ + +#ifdef LODEPNG_COMPILE_ENCODER +unsigned encode(std::vector<unsigned char>& out, const unsigned char* in, unsigned w, unsigned h, + LodePNGColorType colortype, unsigned bitdepth) +{ + unsigned char* buffer; + size_t buffersize; + unsigned error = lodepng_encode_memory(&buffer, &buffersize, in, w, h, colortype, bitdepth); + if(buffer) + { + out.insert(out.end(), &buffer[0], &buffer[buffersize]); + lodepng_free(buffer); + } + return error; +} + +unsigned encode(std::vector<unsigned char>& out, + const std::vector<unsigned char>& in, unsigned w, unsigned h, + LodePNGColorType colortype, unsigned bitdepth) +{ + if(lodepng_get_raw_size_lct(w, h, colortype, bitdepth) > in.size()) return 84; + return encode(out, in.empty() ? 0 : &in[0], w, h, colortype, bitdepth); +} + +unsigned encode(std::vector<unsigned char>& out, + const unsigned char* in, unsigned w, unsigned h, + State& state) +{ + unsigned char* buffer; + size_t buffersize; + unsigned error = lodepng_encode(&buffer, &buffersize, in, w, h, &state); + if(buffer) + { + out.insert(out.end(), &buffer[0], &buffer[buffersize]); + lodepng_free(buffer); + } + return error; +} + +unsigned encode(std::vector<unsigned char>& out, + const std::vector<unsigned char>& in, unsigned w, unsigned h, + State& state) +{ + if(lodepng_get_raw_size(w, h, &state.info_raw) > in.size()) return 84; + return encode(out, in.empty() ? 0 : &in[0], w, h, state); +} + +#ifdef LODEPNG_COMPILE_DISK +unsigned encode(const std::string& filename, + const unsigned char* in, unsigned w, unsigned h, + LodePNGColorType colortype, unsigned bitdepth) +{ + std::vector<unsigned char> buffer; + unsigned error = encode(buffer, in, w, h, colortype, bitdepth); + if(!error) error = save_file(buffer, filename); + return error; +} + +unsigned encode(const std::string& filename, + const std::vector<unsigned char>& in, unsigned w, unsigned h, + LodePNGColorType colortype, unsigned bitdepth) +{ + if(lodepng_get_raw_size_lct(w, h, colortype, bitdepth) > in.size()) return 84; + return encode(filename, in.empty() ? 0 : &in[0], w, h, colortype, bitdepth); +} +#endif /* LODEPNG_COMPILE_DISK */ +#endif /* LODEPNG_COMPILE_ENCODER */ +#endif /* LODEPNG_COMPILE_PNG */ +} /* namespace lodepng */ +#endif /*LODEPNG_COMPILE_CPP*/ diff --git a/lib/tinyxml2.cpp b/lib/tinyxml2.cpp new file mode 100644 index 0000000..7ab0c9a --- /dev/null +++ b/lib/tinyxml2.cpp @@ -0,0 +1,2467 @@ +/* +Original code by Lee Thomason (www.grinninglizard.com) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must +not claim that you wrote the original software. If you use this +software in a product, an acknowledgment in the product documentation +would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ + +#include "tinyxml2.h" + +#include <new> // yes, this one new style header, is in the Android SDK. +#if defined(ANDROID_NDK) || defined(__BORLANDC__) || defined(__QNXNTO__) +# include <stddef.h> +# include <stdarg.h> +#else +# include <cstddef> +# include <cstdarg> +#endif + +#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE) + // Microsoft Visual Studio, version 2005 and higher. Not WinCE. + /*int _snprintf_s( + char *buffer, + size_t sizeOfBuffer, + size_t count, + const char *format [, + argument] ... + );*/ + static inline int TIXML_SNPRINTF( char* buffer, size_t size, const char* format, ... ) + { + va_list va; + va_start( va, format ); + int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va ); + va_end( va ); + return result; + } + + static inline int TIXML_VSNPRINTF( char* buffer, size_t size, const char* format, va_list va ) + { + int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va ); + return result; + } + + #define TIXML_VSCPRINTF _vscprintf + #define TIXML_SSCANF sscanf_s +#elif defined _MSC_VER + // Microsoft Visual Studio 2003 and earlier or WinCE + #define TIXML_SNPRINTF _snprintf + #define TIXML_VSNPRINTF _vsnprintf + #define TIXML_SSCANF sscanf + #if (_MSC_VER < 1400 ) && (!defined WINCE) + // Microsoft Visual Studio 2003 and not WinCE. + #define TIXML_VSCPRINTF _vscprintf // VS2003's C runtime has this, but VC6 C runtime or WinCE SDK doesn't have. + #else + // Microsoft Visual Studio 2003 and earlier or WinCE. + static inline int TIXML_VSCPRINTF( const char* format, va_list va ) + { + int len = 512; + for (;;) { + len = len*2; + char* str = new char[len](); + const int required = _vsnprintf(str, len, format, va); + delete[] str; + if ( required != -1 ) { + TIXMLASSERT( required >= 0 ); + len = required; + break; + } + } + TIXMLASSERT( len >= 0 ); + return len; + } + #endif +#else + // GCC version 3 and higher + //#warning( "Using sn* functions." ) + #define TIXML_SNPRINTF snprintf + #define TIXML_VSNPRINTF vsnprintf + static inline int TIXML_VSCPRINTF( const char* format, va_list va ) + { + int len = vsnprintf( 0, 0, format, va ); + TIXMLASSERT( len >= 0 ); + return len; + } + #define TIXML_SSCANF sscanf +#endif + + +static const char LINE_FEED = (char)0x0a; // all line endings are normalized to LF +static const char LF = LINE_FEED; +static const char CARRIAGE_RETURN = (char)0x0d; // CR gets filtered out +static const char CR = CARRIAGE_RETURN; +static const char SINGLE_QUOTE = '\''; +static const char DOUBLE_QUOTE = '\"'; + +// Bunch of unicode info at: +// http://www.unicode.org/faq/utf_bom.html +// ef bb bf (Microsoft "lead bytes") - designates UTF-8 + +static const unsigned char TIXML_UTF_LEAD_0 = 0xefU; +static const unsigned char TIXML_UTF_LEAD_1 = 0xbbU; +static const unsigned char TIXML_UTF_LEAD_2 = 0xbfU; + +namespace tinyxml2 +{ + +struct Entity { + const char* pattern; + int length; + char value; +}; + +static const int NUM_ENTITIES = 5; +static const Entity entities[NUM_ENTITIES] = { + { "quot", 4, DOUBLE_QUOTE }, + { "amp", 3, '&' }, + { "apos", 4, SINGLE_QUOTE }, + { "lt", 2, '<' }, + { "gt", 2, '>' } +}; + + +StrPair::~StrPair() +{ + Reset(); +} + + +void StrPair::TransferTo( StrPair* other ) +{ + if ( this == other ) { + return; + } + // This in effect implements the assignment operator by "moving" + // ownership (as in auto_ptr). + + TIXMLASSERT( other->_flags == 0 ); + TIXMLASSERT( other->_start == 0 ); + TIXMLASSERT( other->_end == 0 ); + + other->Reset(); + + other->_flags = _flags; + other->_start = _start; + other->_end = _end; + + _flags = 0; + _start = 0; + _end = 0; +} + +void StrPair::Reset() +{ + if ( _flags & NEEDS_DELETE ) { + delete [] _start; + } + _flags = 0; + _start = 0; + _end = 0; +} + + +void StrPair::SetStr( const char* str, int flags ) +{ + TIXMLASSERT( str ); + Reset(); + size_t len = strlen( str ); + TIXMLASSERT( _start == 0 ); + _start = new char[ len+1 ]; + memcpy( _start, str, len+1 ); + _end = _start + len; + _flags = flags | NEEDS_DELETE; +} + + +char* StrPair::ParseText( char* p, const char* endTag, int strFlags ) +{ + TIXMLASSERT( endTag && *endTag ); + + char* start = p; + char endChar = *endTag; + size_t length = strlen( endTag ); + + // Inner loop of text parsing. + while ( *p ) { + if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) { + Set( start, p, strFlags ); + return p + length; + } + ++p; + } + return 0; +} + + +char* StrPair::ParseName( char* p ) +{ + if ( !p || !(*p) ) { + return 0; + } + if ( !XMLUtil::IsNameStartChar( *p ) ) { + return 0; + } + + char* const start = p; + ++p; + while ( *p && XMLUtil::IsNameChar( *p ) ) { + ++p; + } + + Set( start, p, 0 ); + return p; +} + + +void StrPair::CollapseWhitespace() +{ + // Adjusting _start would cause undefined behavior on delete[] + TIXMLASSERT( ( _flags & NEEDS_DELETE ) == 0 ); + // Trim leading space. + _start = XMLUtil::SkipWhiteSpace( _start ); + + if ( *_start ) { + char* p = _start; // the read pointer + char* q = _start; // the write pointer + + while( *p ) { + if ( XMLUtil::IsWhiteSpace( *p )) { + p = XMLUtil::SkipWhiteSpace( p ); + if ( *p == 0 ) { + break; // don't write to q; this trims the trailing space. + } + *q = ' '; + ++q; + } + *q = *p; + ++q; + ++p; + } + *q = 0; + } +} + + +const char* StrPair::GetStr() +{ + TIXMLASSERT( _start ); + TIXMLASSERT( _end ); + if ( _flags & NEEDS_FLUSH ) { + *_end = 0; + _flags ^= NEEDS_FLUSH; + + if ( _flags ) { + char* p = _start; // the read pointer + char* q = _start; // the write pointer + + while( p < _end ) { + if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) { + // CR-LF pair becomes LF + // CR alone becomes LF + // LF-CR becomes LF + if ( *(p+1) == LF ) { + p += 2; + } + else { + ++p; + } + *q++ = LF; + } + else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) { + if ( *(p+1) == CR ) { + p += 2; + } + else { + ++p; + } + *q++ = LF; + } + else if ( (_flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) { + // Entities handled by tinyXML2: + // - special entities in the entity table [in/out] + // - numeric character reference [in] + // 中 or 中 + + if ( *(p+1) == '#' ) { + const int buflen = 10; + char buf[buflen] = { 0 }; + int len = 0; + char* adjusted = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) ); + if ( adjusted == 0 ) { + *q = *p; + ++p; + ++q; + } + else { + TIXMLASSERT( 0 <= len && len <= buflen ); + TIXMLASSERT( q + len <= adjusted ); + p = adjusted; + memcpy( q, buf, len ); + q += len; + } + } + else { + bool entityFound = false; + for( int i = 0; i < NUM_ENTITIES; ++i ) { + const Entity& entity = entities[i]; + if ( strncmp( p + 1, entity.pattern, entity.length ) == 0 + && *( p + entity.length + 1 ) == ';' ) { + // Found an entity - convert. + *q = entity.value; + ++q; + p += entity.length + 2; + entityFound = true; + break; + } + } + if ( !entityFound ) { + // fixme: treat as error? + ++p; + ++q; + } + } + } + else { + *q = *p; + ++p; + ++q; + } + } + *q = 0; + } + // The loop below has plenty going on, and this + // is a less useful mode. Break it out. + if ( _flags & NEEDS_WHITESPACE_COLLAPSING ) { + CollapseWhitespace(); + } + _flags = (_flags & NEEDS_DELETE); + } + TIXMLASSERT( _start ); + return _start; +} + + + + +// --------- XMLUtil ----------- // + +const char* XMLUtil::ReadBOM( const char* p, bool* bom ) +{ + TIXMLASSERT( p ); + TIXMLASSERT( bom ); + *bom = false; + const unsigned char* pu = reinterpret_cast<const unsigned char*>(p); + // Check for BOM: + if ( *(pu+0) == TIXML_UTF_LEAD_0 + && *(pu+1) == TIXML_UTF_LEAD_1 + && *(pu+2) == TIXML_UTF_LEAD_2 ) { + *bom = true; + p += 3; + } + TIXMLASSERT( p ); + return p; +} + + +void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length ) +{ + const unsigned long BYTE_MASK = 0xBF; + const unsigned long BYTE_MARK = 0x80; + const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; + + if (input < 0x80) { + *length = 1; + } + else if ( input < 0x800 ) { + *length = 2; + } + else if ( input < 0x10000 ) { + *length = 3; + } + else if ( input < 0x200000 ) { + *length = 4; + } + else { + *length = 0; // This code won't convert this correctly anyway. + return; + } + + output += *length; + + // Scary scary fall throughs. + switch (*length) { + case 4: + --output; + *output = (char)((input | BYTE_MARK) & BYTE_MASK); + input >>= 6; + case 3: + --output; + *output = (char)((input | BYTE_MARK) & BYTE_MASK); + input >>= 6; + case 2: + --output; + *output = (char)((input | BYTE_MARK) & BYTE_MASK); + input >>= 6; + case 1: + --output; + *output = (char)(input | FIRST_BYTE_MARK[*length]); + break; + default: + TIXMLASSERT( false ); + } +} + + +const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length ) +{ + // Presume an entity, and pull it out. + *length = 0; + + if ( *(p+1) == '#' && *(p+2) ) { + unsigned long ucs = 0; + TIXMLASSERT( sizeof( ucs ) >= 4 ); + ptrdiff_t delta = 0; + unsigned mult = 1; + static const char SEMICOLON = ';'; + + if ( *(p+2) == 'x' ) { + // Hexadecimal. + const char* q = p+3; + if ( !(*q) ) { + return 0; + } + + q = strchr( q, SEMICOLON ); + + if ( !q ) { + return 0; + } + TIXMLASSERT( *q == SEMICOLON ); + + delta = q-p; + --q; + + while ( *q != 'x' ) { + unsigned int digit = 0; + + if ( *q >= '0' && *q <= '9' ) { + digit = *q - '0'; + } + else if ( *q >= 'a' && *q <= 'f' ) { + digit = *q - 'a' + 10; + } + else if ( *q >= 'A' && *q <= 'F' ) { + digit = *q - 'A' + 10; + } + else { + return 0; + } + TIXMLASSERT( digit < 16 ); + TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit ); + const unsigned int digitScaled = mult * digit; + TIXMLASSERT( ucs <= ULONG_MAX - digitScaled ); + ucs += digitScaled; + TIXMLASSERT( mult <= UINT_MAX / 16 ); + mult *= 16; + --q; + } + } + else { + // Decimal. + const char* q = p+2; + if ( !(*q) ) { + return 0; + } + + q = strchr( q, SEMICOLON ); + + if ( !q ) { + return 0; + } + TIXMLASSERT( *q == SEMICOLON ); + + delta = q-p; + --q; + + while ( *q != '#' ) { + if ( *q >= '0' && *q <= '9' ) { + const unsigned int digit = *q - '0'; + TIXMLASSERT( digit < 10 ); + TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit ); + const unsigned int digitScaled = mult * digit; + TIXMLASSERT( ucs <= ULONG_MAX - digitScaled ); + ucs += digitScaled; + } + else { + return 0; + } + TIXMLASSERT( mult <= UINT_MAX / 10 ); + mult *= 10; + --q; + } + } + // convert the UCS to UTF-8 + ConvertUTF32ToUTF8( ucs, value, length ); + return p + delta + 1; + } + return p+1; +} + + +void XMLUtil::ToStr( int v, char* buffer, int bufferSize ) +{ + TIXML_SNPRINTF( buffer, bufferSize, "%d", v ); +} + + +void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize ) +{ + TIXML_SNPRINTF( buffer, bufferSize, "%u", v ); +} + + +void XMLUtil::ToStr( bool v, char* buffer, int bufferSize ) +{ + TIXML_SNPRINTF( buffer, bufferSize, "%d", v ? 1 : 0 ); +} + +/* + ToStr() of a number is a very tricky topic. + https://github.com/leethomason/tinyxml2/issues/106 +*/ +void XMLUtil::ToStr( float v, char* buffer, int bufferSize ) +{ + TIXML_SNPRINTF( buffer, bufferSize, "%.8g", v ); +} + + +void XMLUtil::ToStr( double v, char* buffer, int bufferSize ) +{ + TIXML_SNPRINTF( buffer, bufferSize, "%.17g", v ); +} + + +bool XMLUtil::ToInt( const char* str, int* value ) +{ + if ( TIXML_SSCANF( str, "%d", value ) == 1 ) { + return true; + } + return false; +} + +bool XMLUtil::ToUnsigned( const char* str, unsigned *value ) +{ + if ( TIXML_SSCANF( str, "%u", value ) == 1 ) { + return true; + } + return false; +} + +bool XMLUtil::ToBool( const char* str, bool* value ) +{ + int ival = 0; + if ( ToInt( str, &ival )) { + *value = (ival==0) ? false : true; + return true; + } + if ( StringEqual( str, "true" ) ) { + *value = true; + return true; + } + else if ( StringEqual( str, "false" ) ) { + *value = false; + return true; + } + return false; +} + + +bool XMLUtil::ToFloat( const char* str, float* value ) +{ + if ( TIXML_SSCANF( str, "%f", value ) == 1 ) { + return true; + } + return false; +} + +bool XMLUtil::ToDouble( const char* str, double* value ) +{ + if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) { + return true; + } + return false; +} + + +char* XMLDocument::Identify( char* p, XMLNode** node ) +{ + TIXMLASSERT( node ); + TIXMLASSERT( p ); + char* const start = p; + p = XMLUtil::SkipWhiteSpace( p ); + if( !*p ) { + *node = 0; + TIXMLASSERT( p ); + return p; + } + + // These strings define the matching patterns: + static const char* xmlHeader = { "<?" }; + static const char* commentHeader = { "<!--" }; + static const char* cdataHeader = { "<![CDATA[" }; + static const char* dtdHeader = { "<!" }; + static const char* elementHeader = { "<" }; // and a header for everything else; check last. + + static const int xmlHeaderLen = 2; + static const int commentHeaderLen = 4; + static const int cdataHeaderLen = 9; + static const int dtdHeaderLen = 2; + static const int elementHeaderLen = 1; + + TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool + TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool + XMLNode* returnNode = 0; + if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) { + TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() ); + returnNode = new (_commentPool.Alloc()) XMLDeclaration( this ); + returnNode->_memPool = &_commentPool; + p += xmlHeaderLen; + } + else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) { + TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() ); + returnNode = new (_commentPool.Alloc()) XMLComment( this ); + returnNode->_memPool = &_commentPool; + p += commentHeaderLen; + } + else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) { + TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() ); + XMLText* text = new (_textPool.Alloc()) XMLText( this ); + returnNode = text; + returnNode->_memPool = &_textPool; + p += cdataHeaderLen; + text->SetCData( true ); + } + else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) { + TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() ); + returnNode = new (_commentPool.Alloc()) XMLUnknown( this ); + returnNode->_memPool = &_commentPool; + p += dtdHeaderLen; + } + else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) { + TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() ); + returnNode = new (_elementPool.Alloc()) XMLElement( this ); + returnNode->_memPool = &_elementPool; + p += elementHeaderLen; + } + else { + TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() ); + returnNode = new (_textPool.Alloc()) XMLText( this ); + returnNode->_memPool = &_textPool; + p = start; // Back it up, all the text counts. + } + + TIXMLASSERT( returnNode ); + TIXMLASSERT( p ); + *node = returnNode; + return p; +} + + +bool XMLDocument::Accept( XMLVisitor* visitor ) const +{ + TIXMLASSERT( visitor ); + if ( visitor->VisitEnter( *this ) ) { + for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) { + if ( !node->Accept( visitor ) ) { + break; + } + } + } + return visitor->VisitExit( *this ); +} + + +// --------- XMLNode ----------- // + +XMLNode::XMLNode( XMLDocument* doc ) : + _document( doc ), + _parent( 0 ), + _firstChild( 0 ), _lastChild( 0 ), + _prev( 0 ), _next( 0 ), + _memPool( 0 ) +{ +} + + +XMLNode::~XMLNode() +{ + DeleteChildren(); + if ( _parent ) { + _parent->Unlink( this ); + } +} + +const char* XMLNode::Value() const +{ + // Catch an edge case: XMLDocuments don't have a a Value. Carefully return nullptr. + if ( this->ToDocument() ) + return 0; + return _value.GetStr(); +} + +void XMLNode::SetValue( const char* str, bool staticMem ) +{ + if ( staticMem ) { + _value.SetInternedStr( str ); + } + else { + _value.SetStr( str ); + } +} + + +void XMLNode::DeleteChildren() +{ + while( _firstChild ) { + TIXMLASSERT( _lastChild ); + TIXMLASSERT( _firstChild->_document == _document ); + XMLNode* node = _firstChild; + Unlink( node ); + + DeleteNode( node ); + } + _firstChild = _lastChild = 0; +} + + +void XMLNode::Unlink( XMLNode* child ) +{ + TIXMLASSERT( child ); + TIXMLASSERT( child->_document == _document ); + TIXMLASSERT( child->_parent == this ); + if ( child == _firstChild ) { + _firstChild = _firstChild->_next; + } + if ( child == _lastChild ) { + _lastChild = _lastChild->_prev; + } + + if ( child->_prev ) { + child->_prev->_next = child->_next; + } + if ( child->_next ) { + child->_next->_prev = child->_prev; + } + child->_parent = 0; +} + + +void XMLNode::DeleteChild( XMLNode* node ) +{ + TIXMLASSERT( node ); + TIXMLASSERT( node->_document == _document ); + TIXMLASSERT( node->_parent == this ); + Unlink( node ); + DeleteNode( node ); +} + + +XMLNode* XMLNode::InsertEndChild( XMLNode* addThis ) +{ + TIXMLASSERT( addThis ); + if ( addThis->_document != _document ) { + TIXMLASSERT( false ); + return 0; + } + InsertChildPreamble( addThis ); + + if ( _lastChild ) { + TIXMLASSERT( _firstChild ); + TIXMLASSERT( _lastChild->_next == 0 ); + _lastChild->_next = addThis; + addThis->_prev = _lastChild; + _lastChild = addThis; + + addThis->_next = 0; + } + else { + TIXMLASSERT( _firstChild == 0 ); + _firstChild = _lastChild = addThis; + + addThis->_prev = 0; + addThis->_next = 0; + } + addThis->_parent = this; + return addThis; +} + + +XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis ) +{ + TIXMLASSERT( addThis ); + if ( addThis->_document != _document ) { + TIXMLASSERT( false ); + return 0; + } + InsertChildPreamble( addThis ); + + if ( _firstChild ) { + TIXMLASSERT( _lastChild ); + TIXMLASSERT( _firstChild->_prev == 0 ); + + _firstChild->_prev = addThis; + addThis->_next = _firstChild; + _firstChild = addThis; + + addThis->_prev = 0; + } + else { + TIXMLASSERT( _lastChild == 0 ); + _firstChild = _lastChild = addThis; + + addThis->_prev = 0; + addThis->_next = 0; + } + addThis->_parent = this; + return addThis; +} + + +XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis ) +{ + TIXMLASSERT( addThis ); + if ( addThis->_document != _document ) { + TIXMLASSERT( false ); + return 0; + } + + TIXMLASSERT( afterThis ); + + if ( afterThis->_parent != this ) { + TIXMLASSERT( false ); + return 0; + } + + if ( afterThis->_next == 0 ) { + // The last node or the only node. + return InsertEndChild( addThis ); + } + InsertChildPreamble( addThis ); + addThis->_prev = afterThis; + addThis->_next = afterThis->_next; + afterThis->_next->_prev = addThis; + afterThis->_next = addThis; + addThis->_parent = this; + return addThis; +} + + + + +const XMLElement* XMLNode::FirstChildElement( const char* name ) const +{ + for( const XMLNode* node = _firstChild; node; node = node->_next ) { + const XMLElement* element = node->ToElement(); + if ( element ) { + if ( !name || XMLUtil::StringEqual( element->Name(), name ) ) { + return element; + } + } + } + return 0; +} + + +const XMLElement* XMLNode::LastChildElement( const char* name ) const +{ + for( const XMLNode* node = _lastChild; node; node = node->_prev ) { + const XMLElement* element = node->ToElement(); + if ( element ) { + if ( !name || XMLUtil::StringEqual( element->Name(), name ) ) { + return element; + } + } + } + return 0; +} + + +const XMLElement* XMLNode::NextSiblingElement( const char* name ) const +{ + for( const XMLNode* node = _next; node; node = node->_next ) { + const XMLElement* element = node->ToElement(); + if ( element + && (!name || XMLUtil::StringEqual( name, element->Name() ))) { + return element; + } + } + return 0; +} + + +const XMLElement* XMLNode::PreviousSiblingElement( const char* name ) const +{ + for( const XMLNode* node = _prev; node; node = node->_prev ) { + const XMLElement* element = node->ToElement(); + if ( element + && (!name || XMLUtil::StringEqual( name, element->Name() ))) { + return element; + } + } + return 0; +} + + +char* XMLNode::ParseDeep( char* p, StrPair* parentEnd ) +{ + // This is a recursive method, but thinking about it "at the current level" + // it is a pretty simple flat list: + // <foo/> + // <!-- comment --> + // + // With a special case: + // <foo> + // </foo> + // <!-- comment --> + // + // Where the closing element (/foo) *must* be the next thing after the opening + // element, and the names must match. BUT the tricky bit is that the closing + // element will be read by the child. + // + // 'endTag' is the end tag for this node, it is returned by a call to a child. + // 'parentEnd' is the end tag for the parent, which is filled in and returned. + + while( p && *p ) { + XMLNode* node = 0; + + p = _document->Identify( p, &node ); + if ( node == 0 ) { + break; + } + + StrPair endTag; + p = node->ParseDeep( p, &endTag ); + if ( !p ) { + DeleteNode( node ); + if ( !_document->Error() ) { + _document->SetError( XML_ERROR_PARSING, 0, 0 ); + } + break; + } + + XMLDeclaration* decl = node->ToDeclaration(); + if ( decl ) { + // A declaration can only be the first child of a document. + // Set error, if document already has children. + if ( !_document->NoChildren() ) { + _document->SetError( XML_ERROR_PARSING_DECLARATION, decl->Value(), 0); + DeleteNode( decl ); + break; + } + } + + XMLElement* ele = node->ToElement(); + if ( ele ) { + // We read the end tag. Return it to the parent. + if ( ele->ClosingType() == XMLElement::CLOSING ) { + if ( parentEnd ) { + ele->_value.TransferTo( parentEnd ); + } + node->_memPool->SetTracked(); // created and then immediately deleted. + DeleteNode( node ); + return p; + } + + // Handle an end tag returned to this level. + // And handle a bunch of annoying errors. + bool mismatch = false; + if ( endTag.Empty() ) { + if ( ele->ClosingType() == XMLElement::OPEN ) { + mismatch = true; + } + } + else { + if ( ele->ClosingType() != XMLElement::OPEN ) { + mismatch = true; + } + else if ( !XMLUtil::StringEqual( endTag.GetStr(), ele->Name() ) ) { + mismatch = true; + } + } + if ( mismatch ) { + _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, ele->Name(), 0 ); + DeleteNode( node ); + break; + } + } + InsertEndChild( node ); + } + return 0; +} + +void XMLNode::DeleteNode( XMLNode* node ) +{ + if ( node == 0 ) { + return; + } + MemPool* pool = node->_memPool; + node->~XMLNode(); + pool->Free( node ); +} + +void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const +{ + TIXMLASSERT( insertThis ); + TIXMLASSERT( insertThis->_document == _document ); + + if ( insertThis->_parent ) + insertThis->_parent->Unlink( insertThis ); + else + insertThis->_memPool->SetTracked(); +} + +// --------- XMLText ---------- // +char* XMLText::ParseDeep( char* p, StrPair* ) +{ + const char* start = p; + if ( this->CData() ) { + p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION ); + if ( !p ) { + _document->SetError( XML_ERROR_PARSING_CDATA, start, 0 ); + } + return p; + } + else { + int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES; + if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) { + flags |= StrPair::NEEDS_WHITESPACE_COLLAPSING; + } + + p = _value.ParseText( p, "<", flags ); + if ( p && *p ) { + return p-1; + } + if ( !p ) { + _document->SetError( XML_ERROR_PARSING_TEXT, start, 0 ); + } + } + return 0; +} + + +XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const +{ + if ( !doc ) { + doc = _document; + } + XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern? + text->SetCData( this->CData() ); + return text; +} + + +bool XMLText::ShallowEqual( const XMLNode* compare ) const +{ + const XMLText* text = compare->ToText(); + return ( text && XMLUtil::StringEqual( text->Value(), Value() ) ); +} + + +bool XMLText::Accept( XMLVisitor* visitor ) const +{ + TIXMLASSERT( visitor ); + return visitor->Visit( *this ); +} + + +// --------- XMLComment ---------- // + +XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc ) +{ +} + + +XMLComment::~XMLComment() +{ +} + + +char* XMLComment::ParseDeep( char* p, StrPair* ) +{ + // Comment parses as text. + const char* start = p; + p = _value.ParseText( p, "-->", StrPair::COMMENT ); + if ( p == 0 ) { + _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 ); + } + return p; +} + + +XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const +{ + if ( !doc ) { + doc = _document; + } + XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern? + return comment; +} + + +bool XMLComment::ShallowEqual( const XMLNode* compare ) const +{ + TIXMLASSERT( compare ); + const XMLComment* comment = compare->ToComment(); + return ( comment && XMLUtil::StringEqual( comment->Value(), Value() )); +} + + +bool XMLComment::Accept( XMLVisitor* visitor ) const +{ + TIXMLASSERT( visitor ); + return visitor->Visit( *this ); +} + + +// --------- XMLDeclaration ---------- // + +XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc ) +{ +} + + +XMLDeclaration::~XMLDeclaration() +{ + //printf( "~XMLDeclaration\n" ); +} + + +char* XMLDeclaration::ParseDeep( char* p, StrPair* ) +{ + // Declaration parses as text. + const char* start = p; + p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION ); + if ( p == 0 ) { + _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 ); + } + return p; +} + + +XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const +{ + if ( !doc ) { + doc = _document; + } + XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern? + return dec; +} + + +bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const +{ + TIXMLASSERT( compare ); + const XMLDeclaration* declaration = compare->ToDeclaration(); + return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() )); +} + + + +bool XMLDeclaration::Accept( XMLVisitor* visitor ) const +{ + TIXMLASSERT( visitor ); + return visitor->Visit( *this ); +} + +// --------- XMLUnknown ---------- // + +XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc ) +{ +} + + +XMLUnknown::~XMLUnknown() +{ +} + + +char* XMLUnknown::ParseDeep( char* p, StrPair* ) +{ + // Unknown parses as text. + const char* start = p; + + p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION ); + if ( !p ) { + _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 ); + } + return p; +} + + +XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const +{ + if ( !doc ) { + doc = _document; + } + XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern? + return text; +} + + +bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const +{ + TIXMLASSERT( compare ); + const XMLUnknown* unknown = compare->ToUnknown(); + return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() )); +} + + +bool XMLUnknown::Accept( XMLVisitor* visitor ) const +{ + TIXMLASSERT( visitor ); + return visitor->Visit( *this ); +} + +// --------- XMLAttribute ---------- // + +const char* XMLAttribute::Name() const +{ + return _name.GetStr(); +} + +const char* XMLAttribute::Value() const +{ + return _value.GetStr(); +} + +char* XMLAttribute::ParseDeep( char* p, bool processEntities ) +{ + // Parse using the name rules: bug fix, was using ParseText before + p = _name.ParseName( p ); + if ( !p || !*p ) { + return 0; + } + + // Skip white space before = + p = XMLUtil::SkipWhiteSpace( p ); + if ( *p != '=' ) { + return 0; + } + + ++p; // move up to opening quote + p = XMLUtil::SkipWhiteSpace( p ); + if ( *p != '\"' && *p != '\'' ) { + return 0; + } + + char endTag[2] = { *p, 0 }; + ++p; // move past opening quote + + p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES ); + return p; +} + + +void XMLAttribute::SetName( const char* n ) +{ + _name.SetStr( n ); +} + + +XMLError XMLAttribute::QueryIntValue( int* value ) const +{ + if ( XMLUtil::ToInt( Value(), value )) { + return XML_NO_ERROR; + } + return XML_WRONG_ATTRIBUTE_TYPE; +} + + +XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const +{ + if ( XMLUtil::ToUnsigned( Value(), value )) { + return XML_NO_ERROR; + } + return XML_WRONG_ATTRIBUTE_TYPE; +} + + +XMLError XMLAttribute::QueryBoolValue( bool* value ) const +{ + if ( XMLUtil::ToBool( Value(), value )) { + return XML_NO_ERROR; + } + return XML_WRONG_ATTRIBUTE_TYPE; +} + + +XMLError XMLAttribute::QueryFloatValue( float* value ) const +{ + if ( XMLUtil::ToFloat( Value(), value )) { + return XML_NO_ERROR; + } + return XML_WRONG_ATTRIBUTE_TYPE; +} + + +XMLError XMLAttribute::QueryDoubleValue( double* value ) const +{ + if ( XMLUtil::ToDouble( Value(), value )) { + return XML_NO_ERROR; + } + return XML_WRONG_ATTRIBUTE_TYPE; +} + + +void XMLAttribute::SetAttribute( const char* v ) +{ + _value.SetStr( v ); +} + + +void XMLAttribute::SetAttribute( int v ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( v, buf, BUF_SIZE ); + _value.SetStr( buf ); +} + + +void XMLAttribute::SetAttribute( unsigned v ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( v, buf, BUF_SIZE ); + _value.SetStr( buf ); +} + + +void XMLAttribute::SetAttribute( bool v ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( v, buf, BUF_SIZE ); + _value.SetStr( buf ); +} + +void XMLAttribute::SetAttribute( double v ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( v, buf, BUF_SIZE ); + _value.SetStr( buf ); +} + +void XMLAttribute::SetAttribute( float v ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( v, buf, BUF_SIZE ); + _value.SetStr( buf ); +} + + +// --------- XMLElement ---------- // +XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ), + _closingType( 0 ), + _rootAttribute( 0 ) +{ +} + + +XMLElement::~XMLElement() +{ + while( _rootAttribute ) { + XMLAttribute* next = _rootAttribute->_next; + DeleteAttribute( _rootAttribute ); + _rootAttribute = next; + } +} + + +const XMLAttribute* XMLElement::FindAttribute( const char* name ) const +{ + for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) { + if ( XMLUtil::StringEqual( a->Name(), name ) ) { + return a; + } + } + return 0; +} + + +const char* XMLElement::Attribute( const char* name, const char* value ) const +{ + const XMLAttribute* a = FindAttribute( name ); + if ( !a ) { + return 0; + } + if ( !value || XMLUtil::StringEqual( a->Value(), value )) { + return a->Value(); + } + return 0; +} + + +const char* XMLElement::GetText() const +{ + if ( FirstChild() && FirstChild()->ToText() ) { + return FirstChild()->Value(); + } + return 0; +} + + +void XMLElement::SetText( const char* inText ) +{ + if ( FirstChild() && FirstChild()->ToText() ) + FirstChild()->SetValue( inText ); + else { + XMLText* theText = GetDocument()->NewText( inText ); + InsertFirstChild( theText ); + } +} + + +void XMLElement::SetText( int v ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( v, buf, BUF_SIZE ); + SetText( buf ); +} + + +void XMLElement::SetText( unsigned v ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( v, buf, BUF_SIZE ); + SetText( buf ); +} + + +void XMLElement::SetText( bool v ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( v, buf, BUF_SIZE ); + SetText( buf ); +} + + +void XMLElement::SetText( float v ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( v, buf, BUF_SIZE ); + SetText( buf ); +} + + +void XMLElement::SetText( double v ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( v, buf, BUF_SIZE ); + SetText( buf ); +} + + +XMLError XMLElement::QueryIntText( int* ival ) const +{ + if ( FirstChild() && FirstChild()->ToText() ) { + const char* t = FirstChild()->Value(); + if ( XMLUtil::ToInt( t, ival ) ) { + return XML_SUCCESS; + } + return XML_CAN_NOT_CONVERT_TEXT; + } + return XML_NO_TEXT_NODE; +} + + +XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const +{ + if ( FirstChild() && FirstChild()->ToText() ) { + const char* t = FirstChild()->Value(); + if ( XMLUtil::ToUnsigned( t, uval ) ) { + return XML_SUCCESS; + } + return XML_CAN_NOT_CONVERT_TEXT; + } + return XML_NO_TEXT_NODE; +} + + +XMLError XMLElement::QueryBoolText( bool* bval ) const +{ + if ( FirstChild() && FirstChild()->ToText() ) { + const char* t = FirstChild()->Value(); + if ( XMLUtil::ToBool( t, bval ) ) { + return XML_SUCCESS; + } + return XML_CAN_NOT_CONVERT_TEXT; + } + return XML_NO_TEXT_NODE; +} + + +XMLError XMLElement::QueryDoubleText( double* dval ) const +{ + if ( FirstChild() && FirstChild()->ToText() ) { + const char* t = FirstChild()->Value(); + if ( XMLUtil::ToDouble( t, dval ) ) { + return XML_SUCCESS; + } + return XML_CAN_NOT_CONVERT_TEXT; + } + return XML_NO_TEXT_NODE; +} + + +XMLError XMLElement::QueryFloatText( float* fval ) const +{ + if ( FirstChild() && FirstChild()->ToText() ) { + const char* t = FirstChild()->Value(); + if ( XMLUtil::ToFloat( t, fval ) ) { + return XML_SUCCESS; + } + return XML_CAN_NOT_CONVERT_TEXT; + } + return XML_NO_TEXT_NODE; +} + + + +XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name ) +{ + XMLAttribute* last = 0; + XMLAttribute* attrib = 0; + for( attrib = _rootAttribute; + attrib; + last = attrib, attrib = attrib->_next ) { + if ( XMLUtil::StringEqual( attrib->Name(), name ) ) { + break; + } + } + if ( !attrib ) { + TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() ); + attrib = new (_document->_attributePool.Alloc() ) XMLAttribute(); + attrib->_memPool = &_document->_attributePool; + if ( last ) { + last->_next = attrib; + } + else { + _rootAttribute = attrib; + } + attrib->SetName( name ); + attrib->_memPool->SetTracked(); // always created and linked. + } + return attrib; +} + + +void XMLElement::DeleteAttribute( const char* name ) +{ + XMLAttribute* prev = 0; + for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) { + if ( XMLUtil::StringEqual( name, a->Name() ) ) { + if ( prev ) { + prev->_next = a->_next; + } + else { + _rootAttribute = a->_next; + } + DeleteAttribute( a ); + break; + } + prev = a; + } +} + + +char* XMLElement::ParseAttributes( char* p ) +{ + const char* start = p; + XMLAttribute* prevAttribute = 0; + + // Read the attributes. + while( p ) { + p = XMLUtil::SkipWhiteSpace( p ); + if ( !(*p) ) { + _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() ); + return 0; + } + + // attribute. + if (XMLUtil::IsNameStartChar( *p ) ) { + TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() ); + XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute(); + attrib->_memPool = &_document->_attributePool; + attrib->_memPool->SetTracked(); + + p = attrib->ParseDeep( p, _document->ProcessEntities() ); + if ( !p || Attribute( attrib->Name() ) ) { + DeleteAttribute( attrib ); + _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p ); + return 0; + } + // There is a minor bug here: if the attribute in the source xml + // document is duplicated, it will not be detected and the + // attribute will be doubly added. However, tracking the 'prevAttribute' + // avoids re-scanning the attribute list. Preferring performance for + // now, may reconsider in the future. + if ( prevAttribute ) { + prevAttribute->_next = attrib; + } + else { + _rootAttribute = attrib; + } + prevAttribute = attrib; + } + // end of the tag + else if ( *p == '>' ) { + ++p; + break; + } + // end of the tag + else if ( *p == '/' && *(p+1) == '>' ) { + _closingType = CLOSED; + return p+2; // done; sealed element. + } + else { + _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p ); + return 0; + } + } + return p; +} + +void XMLElement::DeleteAttribute( XMLAttribute* attribute ) +{ + if ( attribute == 0 ) { + return; + } + MemPool* pool = attribute->_memPool; + attribute->~XMLAttribute(); + pool->Free( attribute ); +} + +// +// <ele></ele> +// <ele>foo<b>bar</b></ele> +// +char* XMLElement::ParseDeep( char* p, StrPair* strPair ) +{ + // Read the element name. + p = XMLUtil::SkipWhiteSpace( p ); + + // The closing element is the </element> form. It is + // parsed just like a regular element then deleted from + // the DOM. + if ( *p == '/' ) { + _closingType = CLOSING; + ++p; + } + + p = _value.ParseName( p ); + if ( _value.Empty() ) { + return 0; + } + + p = ParseAttributes( p ); + if ( !p || !*p || _closingType ) { + return p; + } + + p = XMLNode::ParseDeep( p, strPair ); + return p; +} + + + +XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const +{ + if ( !doc ) { + doc = _document; + } + XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern? + for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) { + element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern? + } + return element; +} + + +bool XMLElement::ShallowEqual( const XMLNode* compare ) const +{ + TIXMLASSERT( compare ); + const XMLElement* other = compare->ToElement(); + if ( other && XMLUtil::StringEqual( other->Name(), Name() )) { + + const XMLAttribute* a=FirstAttribute(); + const XMLAttribute* b=other->FirstAttribute(); + + while ( a && b ) { + if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) { + return false; + } + a = a->Next(); + b = b->Next(); + } + if ( a || b ) { + // different count + return false; + } + return true; + } + return false; +} + + +bool XMLElement::Accept( XMLVisitor* visitor ) const +{ + TIXMLASSERT( visitor ); + if ( visitor->VisitEnter( *this, _rootAttribute ) ) { + for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) { + if ( !node->Accept( visitor ) ) { + break; + } + } + } + return visitor->VisitExit( *this ); +} + + +// --------- XMLDocument ----------- // + +// Warning: List must match 'enum XMLError' +const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = { + "XML_SUCCESS", + "XML_NO_ATTRIBUTE", + "XML_WRONG_ATTRIBUTE_TYPE", + "XML_ERROR_FILE_NOT_FOUND", + "XML_ERROR_FILE_COULD_NOT_BE_OPENED", + "XML_ERROR_FILE_READ_ERROR", + "XML_ERROR_ELEMENT_MISMATCH", + "XML_ERROR_PARSING_ELEMENT", + "XML_ERROR_PARSING_ATTRIBUTE", + "XML_ERROR_IDENTIFYING_TAG", + "XML_ERROR_PARSING_TEXT", + "XML_ERROR_PARSING_CDATA", + "XML_ERROR_PARSING_COMMENT", + "XML_ERROR_PARSING_DECLARATION", + "XML_ERROR_PARSING_UNKNOWN", + "XML_ERROR_EMPTY_DOCUMENT", + "XML_ERROR_MISMATCHED_ELEMENT", + "XML_ERROR_PARSING", + "XML_CAN_NOT_CONVERT_TEXT", + "XML_NO_TEXT_NODE" +}; + + +XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) : + XMLNode( 0 ), + _writeBOM( false ), + _processEntities( processEntities ), + _errorID( XML_NO_ERROR ), + _whitespace( whitespace ), + _errorStr1( 0 ), + _errorStr2( 0 ), + _charBuffer( 0 ) +{ + // avoid VC++ C4355 warning about 'this' in initializer list (C4355 is off by default in VS2012+) + _document = this; +} + + +XMLDocument::~XMLDocument() +{ + Clear(); +} + + +void XMLDocument::Clear() +{ + DeleteChildren(); + +#ifdef DEBUG + const bool hadError = Error(); +#endif + _errorID = XML_NO_ERROR; + _errorStr1 = 0; + _errorStr2 = 0; + + delete [] _charBuffer; + _charBuffer = 0; + +#if 0 + _textPool.Trace( "text" ); + _elementPool.Trace( "element" ); + _commentPool.Trace( "comment" ); + _attributePool.Trace( "attribute" ); +#endif + +#ifdef DEBUG + if ( !hadError ) { + TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() ); + TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() ); + TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() ); + TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() ); + } +#endif +} + + +XMLElement* XMLDocument::NewElement( const char* name ) +{ + TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() ); + XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this ); + ele->_memPool = &_elementPool; + ele->SetName( name ); + return ele; +} + + +XMLComment* XMLDocument::NewComment( const char* str ) +{ + TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() ); + XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this ); + comment->_memPool = &_commentPool; + comment->SetValue( str ); + return comment; +} + + +XMLText* XMLDocument::NewText( const char* str ) +{ + TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() ); + XMLText* text = new (_textPool.Alloc()) XMLText( this ); + text->_memPool = &_textPool; + text->SetValue( str ); + return text; +} + + +XMLDeclaration* XMLDocument::NewDeclaration( const char* str ) +{ + TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() ); + XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this ); + dec->_memPool = &_commentPool; + dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" ); + return dec; +} + + +XMLUnknown* XMLDocument::NewUnknown( const char* str ) +{ + TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() ); + XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this ); + unk->_memPool = &_commentPool; + unk->SetValue( str ); + return unk; +} + +static FILE* callfopen( const char* filepath, const char* mode ) +{ + TIXMLASSERT( filepath ); + TIXMLASSERT( mode ); +#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE) + FILE* fp = 0; + errno_t err = fopen_s( &fp, filepath, mode ); + if ( err ) { + return 0; + } +#else + FILE* fp = fopen( filepath, mode ); +#endif + return fp; +} + +void XMLDocument::DeleteNode( XMLNode* node ) { + TIXMLASSERT( node ); + TIXMLASSERT(node->_document == this ); + if (node->_parent) { + node->_parent->DeleteChild( node ); + } + else { + // Isn't in the tree. + // Use the parent delete. + // Also, we need to mark it tracked: we 'know' + // it was never used. + node->_memPool->SetTracked(); + // Call the static XMLNode version: + XMLNode::DeleteNode(node); + } +} + + +XMLError XMLDocument::LoadFile( const char* filename ) +{ + Clear(); + FILE* fp = callfopen( filename, "rb" ); + if ( !fp ) { + SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 ); + return _errorID; + } + LoadFile( fp ); + fclose( fp ); + return _errorID; +} + +// This is likely overengineered template art to have a check that unsigned long value incremented +// by one still fits into size_t. If size_t type is larger than unsigned long type +// (x86_64-w64-mingw32 target) then the check is redundant and gcc and clang emit +// -Wtype-limits warning. This piece makes the compiler select code with a check when a check +// is useful and code with no check when a check is redundant depending on how size_t and unsigned long +// types sizes relate to each other. +template +<bool = (sizeof(unsigned long) >= sizeof(size_t))> +struct LongFitsIntoSizeTMinusOne { + static bool Fits( unsigned long value ) + { + return value < (size_t)-1; + } +}; + +template <> +bool LongFitsIntoSizeTMinusOne<false>::Fits( unsigned long /*value*/ ) +{ + return true; +} + +XMLError XMLDocument::LoadFile( FILE* fp ) +{ + Clear(); + + fseek( fp, 0, SEEK_SET ); + if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) { + SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 ); + return _errorID; + } + + fseek( fp, 0, SEEK_END ); + const long filelength = ftell( fp ); + fseek( fp, 0, SEEK_SET ); + if ( filelength == -1L ) { + SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 ); + return _errorID; + } + TIXMLASSERT( filelength >= 0 ); + + if ( !LongFitsIntoSizeTMinusOne<>::Fits( filelength ) ) { + // Cannot handle files which won't fit in buffer together with null terminator + SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 ); + return _errorID; + } + + if ( filelength == 0 ) { + SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 ); + return _errorID; + } + + const size_t size = filelength; + TIXMLASSERT( _charBuffer == 0 ); + _charBuffer = new char[size+1]; + size_t read = fread( _charBuffer, 1, size, fp ); + if ( read != size ) { + SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 ); + return _errorID; + } + + _charBuffer[size] = 0; + + Parse(); + return _errorID; +} + + +XMLError XMLDocument::SaveFile( const char* filename, bool compact ) +{ + FILE* fp = callfopen( filename, "w" ); + if ( !fp ) { + SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 ); + return _errorID; + } + SaveFile(fp, compact); + fclose( fp ); + return _errorID; +} + + +XMLError XMLDocument::SaveFile( FILE* fp, bool compact ) +{ + // Clear any error from the last save, otherwise it will get reported + // for *this* call. + SetError( XML_NO_ERROR, 0, 0 ); + XMLPrinter stream( fp, compact ); + Print( &stream ); + return _errorID; +} + + +XMLError XMLDocument::Parse( const char* p, size_t len ) +{ + Clear(); + + if ( len == 0 || !p || !*p ) { + SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 ); + return _errorID; + } + if ( len == (size_t)(-1) ) { + len = strlen( p ); + } + TIXMLASSERT( _charBuffer == 0 ); + _charBuffer = new char[ len+1 ]; + memcpy( _charBuffer, p, len ); + _charBuffer[len] = 0; + + Parse(); + if ( Error() ) { + // clean up now essentially dangling memory. + // and the parse fail can put objects in the + // pools that are dead and inaccessible. + DeleteChildren(); + _elementPool.Clear(); + _attributePool.Clear(); + _textPool.Clear(); + _commentPool.Clear(); + } + return _errorID; +} + + +void XMLDocument::Print( XMLPrinter* streamer ) const +{ + if ( streamer ) { + Accept( streamer ); + } + else { + XMLPrinter stdoutStreamer( stdout ); + Accept( &stdoutStreamer ); + } +} + + +void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 ) +{ + TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT ); + _errorID = error; + _errorStr1 = str1; + _errorStr2 = str2; +} + +const char* XMLDocument::ErrorName() const +{ + TIXMLASSERT( _errorID >= 0 && _errorID < XML_ERROR_COUNT ); + const char* errorName = _errorNames[_errorID]; + TIXMLASSERT( errorName && errorName[0] ); + return errorName; +} + +void XMLDocument::PrintError() const +{ + if ( Error() ) { + static const int LEN = 20; + char buf1[LEN] = { 0 }; + char buf2[LEN] = { 0 }; + + if ( _errorStr1 ) { + TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1 ); + } + if ( _errorStr2 ) { + TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2 ); + } + + // Should check INT_MIN <= _errorID && _errorId <= INT_MAX, but that + // causes a clang "always true" -Wtautological-constant-out-of-range-compare warning + TIXMLASSERT( 0 <= _errorID && XML_ERROR_COUNT - 1 <= INT_MAX ); + printf( "XMLDocument error id=%d '%s' str1=%s str2=%s\n", + static_cast<int>( _errorID ), ErrorName(), buf1, buf2 ); + } +} + +void XMLDocument::Parse() +{ + TIXMLASSERT( NoChildren() ); // Clear() must have been called previously + TIXMLASSERT( _charBuffer ); + char* p = _charBuffer; + p = XMLUtil::SkipWhiteSpace( p ); + p = const_cast<char*>( XMLUtil::ReadBOM( p, &_writeBOM ) ); + if ( !*p ) { + SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 ); + return; + } + ParseDeep(p, 0 ); +} + +XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) : + _elementJustOpened( false ), + _firstElement( true ), + _fp( file ), + _depth( depth ), + _textDepth( -1 ), + _processEntities( true ), + _compactMode( compact ) +{ + for( int i=0; i<ENTITY_RANGE; ++i ) { + _entityFlag[i] = false; + _restrictedEntityFlag[i] = false; + } + for( int i=0; i<NUM_ENTITIES; ++i ) { + const char entityValue = entities[i].value; + TIXMLASSERT( 0 <= entityValue && entityValue < ENTITY_RANGE ); + _entityFlag[ (unsigned char)entityValue ] = true; + } + _restrictedEntityFlag[(unsigned char)'&'] = true; + _restrictedEntityFlag[(unsigned char)'<'] = true; + _restrictedEntityFlag[(unsigned char)'>'] = true; // not required, but consistency is nice + _buffer.Push( 0 ); +} + + +void XMLPrinter::Print( const char* format, ... ) +{ + va_list va; + va_start( va, format ); + + if ( _fp ) { + vfprintf( _fp, format, va ); + } + else { + const int len = TIXML_VSCPRINTF( format, va ); + // Close out and re-start the va-args + va_end( va ); + TIXMLASSERT( len >= 0 ); + va_start( va, format ); + TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 ); + char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator. + TIXML_VSNPRINTF( p, len+1, format, va ); + } + va_end( va ); +} + + +void XMLPrinter::PrintSpace( int depth ) +{ + for( int i=0; i<depth; ++i ) { + Print( " " ); + } +} + + +void XMLPrinter::PrintString( const char* p, bool restricted ) +{ + // Look for runs of bytes between entities to print. + const char* q = p; + + if ( _processEntities ) { + const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag; + while ( *q ) { + TIXMLASSERT( p <= q ); + // Remember, char is sometimes signed. (How many times has that bitten me?) + if ( *q > 0 && *q < ENTITY_RANGE ) { + // Check for entities. If one is found, flush + // the stream up until the entity, write the + // entity, and keep looking. + if ( flag[(unsigned char)(*q)] ) { + while ( p < q ) { + const size_t delta = q - p; + // %.*s accepts type int as "precision" + const int toPrint = ( INT_MAX < delta ) ? INT_MAX : (int)delta; + Print( "%.*s", toPrint, p ); + p += toPrint; + } + bool entityPatternPrinted = false; + for( int i=0; i<NUM_ENTITIES; ++i ) { + if ( entities[i].value == *q ) { + Print( "&%s;", entities[i].pattern ); + entityPatternPrinted = true; + break; + } + } + if ( !entityPatternPrinted ) { + // TIXMLASSERT( entityPatternPrinted ) causes gcc -Wunused-but-set-variable in release + TIXMLASSERT( false ); + } + ++p; + } + } + ++q; + TIXMLASSERT( p <= q ); + } + } + // Flush the remaining string. This will be the entire + // string if an entity wasn't found. + TIXMLASSERT( p <= q ); + if ( !_processEntities || ( p < q ) ) { + Print( "%s", p ); + } +} + + +void XMLPrinter::PushHeader( bool writeBOM, bool writeDec ) +{ + if ( writeBOM ) { + static const unsigned char bom[] = { TIXML_UTF_LEAD_0, TIXML_UTF_LEAD_1, TIXML_UTF_LEAD_2, 0 }; + Print( "%s", bom ); + } + if ( writeDec ) { + PushDeclaration( "xml version=\"1.0\"" ); + } +} + + +void XMLPrinter::OpenElement( const char* name, bool compactMode ) +{ + SealElementIfJustOpened(); + _stack.Push( name ); + + if ( _textDepth < 0 && !_firstElement && !compactMode ) { + Print( "\n" ); + } + if ( !compactMode ) { + PrintSpace( _depth ); + } + + Print( "<%s", name ); + _elementJustOpened = true; + _firstElement = false; + ++_depth; +} + + +void XMLPrinter::PushAttribute( const char* name, const char* value ) +{ + TIXMLASSERT( _elementJustOpened ); + Print( " %s=\"", name ); + PrintString( value, false ); + Print( "\"" ); +} + + +void XMLPrinter::PushAttribute( const char* name, int v ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( v, buf, BUF_SIZE ); + PushAttribute( name, buf ); +} + + +void XMLPrinter::PushAttribute( const char* name, unsigned v ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( v, buf, BUF_SIZE ); + PushAttribute( name, buf ); +} + + +void XMLPrinter::PushAttribute( const char* name, bool v ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( v, buf, BUF_SIZE ); + PushAttribute( name, buf ); +} + + +void XMLPrinter::PushAttribute( const char* name, double v ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( v, buf, BUF_SIZE ); + PushAttribute( name, buf ); +} + + +void XMLPrinter::CloseElement( bool compactMode ) +{ + --_depth; + const char* name = _stack.Pop(); + + if ( _elementJustOpened ) { + Print( "/>" ); + } + else { + if ( _textDepth < 0 && !compactMode) { + Print( "\n" ); + PrintSpace( _depth ); + } + Print( "</%s>", name ); + } + + if ( _textDepth == _depth ) { + _textDepth = -1; + } + if ( _depth == 0 && !compactMode) { + Print( "\n" ); + } + _elementJustOpened = false; +} + + +void XMLPrinter::SealElementIfJustOpened() +{ + if ( !_elementJustOpened ) { + return; + } + _elementJustOpened = false; + Print( ">" ); +} + + +void XMLPrinter::PushText( const char* text, bool cdata ) +{ + _textDepth = _depth-1; + + SealElementIfJustOpened(); + if ( cdata ) { + Print( "<![CDATA[%s]]>", text ); + } + else { + PrintString( text, true ); + } +} + +void XMLPrinter::PushText( int value ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( value, buf, BUF_SIZE ); + PushText( buf, false ); +} + + +void XMLPrinter::PushText( unsigned value ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( value, buf, BUF_SIZE ); + PushText( buf, false ); +} + + +void XMLPrinter::PushText( bool value ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( value, buf, BUF_SIZE ); + PushText( buf, false ); +} + + +void XMLPrinter::PushText( float value ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( value, buf, BUF_SIZE ); + PushText( buf, false ); +} + + +void XMLPrinter::PushText( double value ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( value, buf, BUF_SIZE ); + PushText( buf, false ); +} + + +void XMLPrinter::PushComment( const char* comment ) +{ + SealElementIfJustOpened(); + if ( _textDepth < 0 && !_firstElement && !_compactMode) { + Print( "\n" ); + PrintSpace( _depth ); + } + _firstElement = false; + Print( "<!--%s-->", comment ); +} + + +void XMLPrinter::PushDeclaration( const char* value ) +{ + SealElementIfJustOpened(); + if ( _textDepth < 0 && !_firstElement && !_compactMode) { + Print( "\n" ); + PrintSpace( _depth ); + } + _firstElement = false; + Print( "<?%s?>", value ); +} + + +void XMLPrinter::PushUnknown( const char* value ) +{ + SealElementIfJustOpened(); + if ( _textDepth < 0 && !_firstElement && !_compactMode) { + Print( "\n" ); + PrintSpace( _depth ); + } + _firstElement = false; + Print( "<!%s>", value ); +} + + +bool XMLPrinter::VisitEnter( const XMLDocument& doc ) +{ + _processEntities = doc.ProcessEntities(); + if ( doc.HasBOM() ) { + PushHeader( true, false ); + } + return true; +} + + +bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute ) +{ + const XMLElement* parentElem = 0; + if ( element.Parent() ) { + parentElem = element.Parent()->ToElement(); + } + const bool compactMode = parentElem ? CompactMode( *parentElem ) : _compactMode; + OpenElement( element.Name(), compactMode ); + while ( attribute ) { + PushAttribute( attribute->Name(), attribute->Value() ); + attribute = attribute->Next(); + } + return true; +} + + +bool XMLPrinter::VisitExit( const XMLElement& element ) +{ + CloseElement( CompactMode(element) ); + return true; +} + + +bool XMLPrinter::Visit( const XMLText& text ) +{ + PushText( text.Value(), text.CData() ); + return true; +} + + +bool XMLPrinter::Visit( const XMLComment& comment ) +{ + PushComment( comment.Value() ); + return true; +} + +bool XMLPrinter::Visit( const XMLDeclaration& declaration ) +{ + PushDeclaration( declaration.Value() ); + return true; +} + + +bool XMLPrinter::Visit( const XMLUnknown& unknown ) +{ + PushUnknown( unknown.Value() ); + return true; +} + +} // namespace tinyxml2 + diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..ea55e32 --- /dev/null +++ b/main.cpp @@ -0,0 +1,754 @@ + +/* + * MULTI-CHANNEL SIGNED DISTANCE FIELD GENERATOR v1.0 (2016-04-24) - standalone console program + * -------------------------------------------------------------------------------------------- + * A utility by Viktor Chlumsky, (c) 2014 - 2016 + * + */ + +#ifdef MSDFGEN_STANDALONE + +#define _USE_MATH_DEFINES +#include <cstdio> +#include <cmath> +#include <cstring> + +#include "msdfgen.h" +#include "msdfgen-ext.h" + +#ifdef _WIN32 + #pragma warning(disable:4996) +#endif + +#define LARGE_VALUE 1e240 + +using namespace msdfgen; + +enum Format { + AUTO, + PNG, + BMP, + TEXT, + TEXT_FLOAT, + BINARY, + BINARY_FLOAT, + BINART_FLOAT_BE +}; + +static char toupper(char c) { + return c >= 'a' && c <= 'z' ? c-'a'+'A' : c; +} + +static bool parseUnsigned(unsigned &value, const char *arg) { + static char c; + return sscanf(arg, "%u%c", &value, &c) == 1; +} + +static bool parseUnsignedHex(unsigned &value, const char *arg) { + static char c; + return sscanf(arg, "%x%c", &value, &c) == 1; +} + +static bool parseDouble(double &value, const char *arg) { + static char c; + return sscanf(arg, "%lf%c", &value, &c) == 1; +} + +static bool parseUnicode(int &unicode, const char *arg) { + unsigned uuc; + if (parseUnsigned(uuc, arg)) { + unicode = uuc; + return true; + } + if (arg[0] == '0' && (arg[1] == 'x' || arg[1] == 'X') && parseUnsignedHex(uuc, arg+2)) { + unicode = uuc; + return true; + } + if (arg[0] == '\'' && arg[1] && arg[2] == '\'' && !arg[3]) { + unicode = arg[1]; + return true; + } + return false; +} + +static bool parseAngle(double &value, const char *arg) { + char c1, c2; + int result = sscanf(arg, "%lf%c%c", &value, &c1, &c2); + if (result == 1) + return true; + if (result == 2 && (c1 == 'd' || c1 == 'D')) { + value = M_PI*value/180; + } + return false; +} + +static void parseColoring(Shape &shape, const char *edgeAssignment) { + unsigned c = 0, e = 0; + if (shape.contours.size() < c) return; + Contour *contour = &shape.contours[c]; + bool change = false; + bool clear = true; + for (const char *in = edgeAssignment; *in; ++in) { + switch (*in) { + case ',': + if (change) + ++e; + if (clear) + while (e < contour->edges.size()) { + contour->edges[e]->color = WHITE; + ++e; + } + ++c, e = 0; + if (shape.contours.size() <= c) return; + contour = &shape.contours[c]; + change = false; + clear = true; + break; + case '?': + clear = false; + break; + case 'C': case 'M': case 'W': case 'Y': case 'c': case 'm': case 'w': case 'y': + if (change) { + ++e; + change = false; + } + if (e < contour->edges.size()) { + contour->edges[e]->color = EdgeColor( + (*in == 'C' || *in == 'c')*CYAN| + (*in == 'M' || *in == 'm')*MAGENTA| + (*in == 'Y' || *in == 'y')*YELLOW| + (*in == 'W' || *in == 'w')*WHITE); + change = true; + } + break; + } + } +} + +static bool writeTextBitmap(FILE *file, const float *values, int cols, int rows) { + for (int row = 0; row < rows; ++row) { + for (int col = 0; col < cols; ++col) { + int v = clamp(int((*values++)*0x100), 0xff); + fprintf(file, col ? " %02X" : "%02X", v); + } + fprintf(file, "\n"); + } + return true; +} + +static bool writeTextBitmapFloat(FILE *file, const float *values, int cols, int rows) { + for (int row = 0; row < rows; ++row) { + for (int col = 0; col < cols; ++col) { + fprintf(file, col ? " %g" : "%g", *values++); + } + fprintf(file, "\n"); + } + return true; +} + +static bool writeBinBitmap(FILE *file, const float *values, int count) { + for (int pos = 0; pos < count; ++pos) { + unsigned char v = clamp(int((*values++)*0x100), 0xff); + fwrite(&v, 1, 1, file); + } + return true; +} + +#ifdef __BIG_ENDIAN__ +static bool writeBinBitmapFloatBE(FILE *file, const float *values, int count) +#else +static bool writeBinBitmapFloat(FILE *file, const float *values, int count) +#endif +{ + return fwrite(values, sizeof(float), count, file) == count; +} + +#ifdef __BIG_ENDIAN__ +static bool writeBinBitmapFloat(FILE *file, const float *values, int count) +#else +static bool writeBinBitmapFloatBE(FILE *file, const float *values, int count) +#endif +{ + for (int pos = 0; pos < count; ++pos) { + const unsigned char *b = reinterpret_cast<const unsigned char *>(values++); + for (int i = sizeof(float)-1; i >= 0; --i) + fwrite(b+i, 1, 1, file); + } + return true; +} + +static bool cmpExtension(const char *path, const char *ext) { + for (const char *a = path+strlen(path)-1, *b = ext+strlen(ext)-1; b >= ext; --a, --b) + if (a < path || toupper(*a) != toupper(*b)) + return false; + return true; +} + +template <typename T> +static const char * writeOutput(const Bitmap<T> &bitmap, const char *filename, Format format) { + if (filename) { + if (format == AUTO) { + if (cmpExtension(filename, ".png")) format = PNG; + else if (cmpExtension(filename, ".bmp")) format = BMP; + else if (cmpExtension(filename, ".txt")) format = TEXT; + else if (cmpExtension(filename, ".bin")) format = BINARY; + else + return "Could not deduce format from output file name."; + } + switch (format) { + case PNG: return savePng(bitmap, filename) ? NULL : "Failed to write output PNG image."; + case BMP: return saveBmp(bitmap, filename) ? NULL : "Failed to write output BMP image."; + case TEXT: case TEXT_FLOAT: { + FILE *file = fopen(filename, "w"); + if (!file) return "Failed to write output text file."; + if (format == TEXT) + writeTextBitmap(file, reinterpret_cast<const float *>(&bitmap(0, 0)), sizeof(T)/sizeof(float)*bitmap.width(), bitmap.height()); + else if (format == TEXT_FLOAT) + writeTextBitmapFloat(file, reinterpret_cast<const float *>(&bitmap(0, 0)), sizeof(T)/sizeof(float)*bitmap.width(), bitmap.height()); + fclose(file); + return NULL; + } + case BINARY: case BINARY_FLOAT: case BINART_FLOAT_BE: { + FILE *file = fopen(filename, "wb"); + if (!file) return "Failed to write output binary file."; + if (format == BINARY) + writeBinBitmap(file, reinterpret_cast<const float *>(&bitmap(0, 0)), sizeof(T)/sizeof(float)*bitmap.width()*bitmap.height()); + else if (format == BINARY_FLOAT) + writeBinBitmapFloat(file, reinterpret_cast<const float *>(&bitmap(0, 0)), sizeof(T)/sizeof(float)*bitmap.width()*bitmap.height()); + else if (format == BINART_FLOAT_BE) + writeBinBitmapFloatBE(file, reinterpret_cast<const float *>(&bitmap(0, 0)), sizeof(T)/sizeof(float)*bitmap.width()*bitmap.height()); + fclose(file); + return NULL; + } + } + } else { + if (format == AUTO || format == TEXT) + writeTextBitmap(stdout, reinterpret_cast<const float *>(&bitmap(0, 0)), sizeof(T)/sizeof(float)*bitmap.width(), bitmap.height()); + else if (format == TEXT_FLOAT) + writeTextBitmapFloat(stdout, reinterpret_cast<const float *>(&bitmap(0, 0)), sizeof(T)/sizeof(float)*bitmap.width(), bitmap.height()); + else + return "Unsupported format for standard output."; + } + return NULL; +} + +static const char *helpText = + "\n" + "Multi-channel signed distance field generator by Viktor Chlumsky v" MSDFGEN_VERSION "\n" + "---------------------------------------------------------------------\n" + " Usage: msdfgen" + #ifdef _WIN32 + ".exe" + #endif + " <mode> <input specification> <options>\n" + "\n" + "MODES\n" + " sdf - Generate conventional monochrome signed distance field.\n" + " psdf - Generate monochrome signed pseudo-distance field.\n" + " msdf - Generate multi-channel signed distance field. This is used by default if no mode is specified.\n" + " metrics - Report shape metrics only.\n" + "\n" + "INPUT SPECIFICATION\n" + " -defineshape <definition>\n" + "\tDefines input shape using the ad-hoc text definition.\n" + " -font <filename.ttf> <character code>\n" + "\tLoads a single glyph from the specified font file. Format of character code is '?', 63 or 0x3F.\n" + " -shapedesc <filename.txt>\n" + "\tLoads text shape description from a file.\n" + " -stdin\n" + "\tReads text shape description from the standard input.\n" + " -svg <filename.svg>\n" + "\tLoads the first vector path encountered in the specified SVG file.\n" + "\n" + "OPTIONS\n" + " -angle <angle>\n" + "\tSpecifies the minimum angle between adjacent edges to be considered a corner. Append D for degrees.\n" + " -ascale <x scale> <y scale>\n" + "\tSets the scale used to convert shape units to pixels asymmetrically.\n" + " -autoframe\n" + "\tAutomatically scales (unless specified) and translates the shape to fit.\n" + " -edgecolors <sequence>\n" + "\tOverrides automatic edge coloring with the specified color sequence.\n" + " -errorcorrection <threshold>\n" + "\tChanges the threshold used to detect and correct potential artifacts. 0 disables error correction.\n" + " -exportshape <filename.txt>\n" + "\tSaves the shape description into a text file that can be edited and loaded using -shapedesc.\n" + " -format <png / bmp / text / textfloat / bin / binfloat / binfloatbe>\n" + "\tSpecifies the output format of the distance field. Otherwise it is chosen based on output file extension.\n" + " -help\n" + "\tDisplays this help.\n" + " -o <filename>\n" + "\tSets the output file name. The default value is \"output.png\".\n" + " -printmetrics\n" + "\tPrints relevant metrics of the shape to the standard output.\n" + " -pxrange <range>\n" + "\tSets the width of the range between the lowest and highest signed distance in pixels.\n" + " -range <range>\n" + "\tSets the width of the range between the lowest and highest signed distance in shape units.\n" + " -scale <scale>\n" + "\tSets the scale used to convert shape units to pixels.\n" + " -size <width> <height>\n" + "\tSets the dimensions of the output image.\n" + " -stdout\n" + "\tPrints the output instead of storing it in a file. Only text formats are supported.\n" + " -testrender <filename.png> <width> <height>\n" + "\tRenders an image preview using the generated distance field and saves it as a PNG file.\n" + " -testrendermulti <filename.png> <width> <height>\n" + "\tRenders an image preview without flattening the color channels.\n" + " -translate <x> <y>\n" + "\tSets the translation of the shape in shape units.\n" + " -yflip\n" + "\tInverts the Y axis in the output distance field. The default order is bottom to top.\n" + "\n"; + +int main(int argc, const char * const *argv) { + #define ABORT(msg) { puts(msg); return 0; } + + // Parse command line arguments + enum { + NONE, + SVG, + FONT, + DESCRIPTION_ARG, + DESCRIPTION_STDIN, + DESCRIPTION_FILE + } inputType = NONE; + enum { + SINGLE, + PSEUDO, + MULTI, + METRICS + } mode = MULTI; + Format format = AUTO; + const char *input = NULL; + const char *output = "output.png"; + const char *shapeExport = NULL; + const char *testRender = NULL; + const char *testRenderMulti = NULL; + bool outputSpecified = false; + int unicode = 0; + + int width = 64, height = 64; + int testWidth = 0, testHeight = 0; + int testWidthM = 0, testHeightM = 0; + bool autoFrame = false; + enum { + RANGE_UNIT, + RANGE_PX + } rangeMode = RANGE_PX; + double range = 1; + double pxRange = 2; + Vector2 translate; + Vector2 scale = 1; + bool scaleSpecified = false; + double angleThreshold = 3; + double edgeThreshold = 1.00000001; + bool defEdgeAssignment = true; + const char *edgeAssignment = NULL; + bool yFlip = false; + bool printMetrics = false; + bool skipColoring = false; + + int argPos = 1; + bool suggestHelp = false; + while (argPos < argc) { + const char *arg = argv[argPos]; + #define ARG_CASE(s, p) if (!strcmp(arg, s) && argPos+(p) < argc) + #define ARG_MODE(s, m) if (!strcmp(arg, s)) { mode = m; ++argPos; continue; } + #define SETFORMAT(fmt, ext) do { format = fmt; if (!outputSpecified) output = "output." ext; } while (false) + + ARG_MODE("sdf", SINGLE) + ARG_MODE("psdf", PSEUDO) + ARG_MODE("msdf", MULTI) + ARG_MODE("metrics", METRICS) + + ARG_CASE("-svg", 1) { + inputType = SVG; + input = argv[argPos+1]; + argPos += 2; + continue; + } + ARG_CASE("-font", 2) { + inputType = FONT; + input = argv[argPos+1]; + parseUnicode(unicode, argv[argPos+2]); + argPos += 3; + continue; + } + ARG_CASE("-defineshape", 1) { + inputType = DESCRIPTION_ARG; + input = argv[argPos+1]; + argPos += 2; + continue; + } + ARG_CASE("-stdin", 0) { + inputType = DESCRIPTION_STDIN; + input = "stdin"; + argPos += 1; + continue; + } + ARG_CASE("-shapedesc", 1) { + inputType = DESCRIPTION_FILE; + input = argv[argPos+1]; + argPos += 2; + continue; + } + ARG_CASE("-o", 1) { + output = argv[argPos+1]; + outputSpecified = true; + argPos += 2; + continue; + } + ARG_CASE("-stdout", 0) { + output = NULL; + argPos += 1; + continue; + } + ARG_CASE("-format", 1) { + if (!strcmp(argv[argPos+1], "auto")) format = AUTO; + else if (!strcmp(argv[argPos+1], "png")) SETFORMAT(PNG, "png"); + else if (!strcmp(argv[argPos+1], "bmp")) SETFORMAT(BMP, "bmp"); + else if (!strcmp(argv[argPos+1], "text") || !strcmp(argv[argPos+1], "txt")) SETFORMAT(TEXT, "txt"); + else if (!strcmp(argv[argPos+1], "textfloat") || !strcmp(argv[argPos+1], "txtfloat")) SETFORMAT(TEXT_FLOAT, "txt"); + else if (!strcmp(argv[argPos+1], "bin") || !strcmp(argv[argPos+1], "binary")) SETFORMAT(BINARY, "bin"); + else if (!strcmp(argv[argPos+1], "binfloat") || !strcmp(argv[argPos+1], "binfloatle")) SETFORMAT(BINARY_FLOAT, "bin"); + else if (!strcmp(argv[argPos+1], "binfloatbe")) SETFORMAT(BINART_FLOAT_BE, "bin"); + else + puts("Unknown format specified."); + argPos += 2; + continue; + } + ARG_CASE("-size", 2) { + unsigned w, h; + if (!parseUnsigned(w, argv[argPos+1]) || !parseUnsigned(h, argv[argPos+2]) || !w || !h) + ABORT("Invalid size arguments. Use -size <width> <height> with two positive integers."); + width = w, height = h; + argPos += 3; + continue; + } + ARG_CASE("-autoframe", 0) { + autoFrame = true; + argPos += 1; + continue; + } + ARG_CASE("-range", 1) { + double r; + if (!parseDouble(r, argv[argPos+1]) || r < 0) + ABORT("Invalid range argument. Use -range <range> with a positive real number."); + rangeMode = RANGE_UNIT; + range = r; + argPos += 2; + continue; + } + ARG_CASE("-pxrange", 1) { + double r; + if (!parseDouble(r, argv[argPos+1]) || r < 0) + ABORT("Invalid range argument. Use -pxrange <range> with a positive real number."); + rangeMode = RANGE_PX; + pxRange = r; + argPos += 2; + continue; + } + ARG_CASE("-scale", 1) { + double s; + if (!parseDouble(s, argv[argPos+1]) || s <= 0) + ABORT("Invalid scale argument. Use -scale <scale> with a positive real number."); + scale = s; + scaleSpecified = true; + argPos += 2; + continue; + } + ARG_CASE("-ascale", 2) { + double sx, sy; + if (!parseDouble(sx, argv[argPos+1]) || !parseDouble(sy, argv[argPos+2]) || sx <= 0 || sy <= 0) + ABORT("Invalid scale arguments. Use -ascale <x> <y> with two positive real numbers."); + scale.set(sx, sy); + scaleSpecified = true; + argPos += 3; + continue; + } + ARG_CASE("-translate", 2) { + double tx, ty; + if (!parseDouble(tx, argv[argPos+1]) || !parseDouble(ty, argv[argPos+2])) + ABORT("Invalid translate arguments. Use -translate <x> <y> with two real numbers."); + translate.set(tx, ty); + argPos += 3; + continue; + } + ARG_CASE("-angle", 1) { + double at; + if (!parseAngle(at, argv[argPos+1])) + ABORT("Invalid angle threshold. Use -angle <min angle> with a positive real number less than PI or a value in degrees followed by 'd' below 180d."); + angleThreshold = at; + argPos += 2; + continue; + } + ARG_CASE("-errorcorrection", 1) { + double et; + if (!parseDouble(et, argv[argPos+1]) || et < 0) + ABORT("Invalid error correction threshold. Use -errorcorrection <threshold> with a real number larger or equal to 1."); + edgeThreshold = et; + argPos += 2; + continue; + } + ARG_CASE("-edgecolors", 1) { + static const char *allowed = " ?,cmyCMY"; + for (int i = 0; argv[argPos+1][i]; ++i) { + for (int j = 0; allowed[j]; ++j) + if (argv[argPos+1][i] == allowed[j]) + goto ROLL_ARG; + ABORT("Invalid edge coloring sequence. Use -assign <color sequence> with only the colors C, M, and Y. Separate contours by commas and use ? to keep the default assigment for a contour."); + ROLL_ARG:; + } + edgeAssignment = argv[argPos+1]; + argPos += 2; + continue; + } + ARG_CASE("-exportshape", 1) { + shapeExport = argv[argPos+1]; + argPos += 2; + continue; + } + ARG_CASE("-testrender", 3) { + unsigned w, h; + if (!parseUnsigned(w, argv[argPos+2]) || !parseUnsigned(h, argv[argPos+3]) || !w || !h) + ABORT("Invalid arguments for test render. Use -testrender <output.png> <width> <height>."); + testRender = argv[argPos+1]; + testWidth = w, testHeight = h; + argPos += 4; + continue; + } + ARG_CASE("-testrendermulti", 3) { + unsigned w, h; + if (!parseUnsigned(w, argv[argPos+2]) || !parseUnsigned(h, argv[argPos+3]) || !w || !h) + ABORT("Invalid arguments for test render. Use -testrendermulti <output.png> <width> <height>."); + testRenderMulti = argv[argPos+1]; + testWidthM = w, testHeightM = h; + argPos += 4; + continue; + } + ARG_CASE("-yflip", 0) { + yFlip = true; + argPos += 1; + continue; + } + ARG_CASE("-printmetrics", 0) { + printMetrics = true; + argPos += 1; + continue; + } + ARG_CASE("-help", 0) + ABORT(helpText); + printf("Unknown setting or insufficient parameters: %s\n", arg); + suggestHelp = true; + ++argPos; + } + if (suggestHelp) + printf("Use -help for more information.\n"); + + // Load input + Vector2 svgDims; + double glyphAdvance = 0; + if (!inputType || !input) + ABORT("No input specified! Use either -svg <file.svg> or -font <file.ttf/otf> <character code>, or see -help."); + Shape shape; + switch (inputType) { + case SVG: { + if (!loadSvgShape(shape, input, &svgDims)) + ABORT("Failed to load shape from SVG file."); + break; + } + case FONT: { + if (!unicode) + ABORT("No character specified! Use -font <file.ttf/otf> <character code>. Character code can be a number (65, 0x41), or a character in apostrophes ('A')."); + FreetypeHandle *ft = initializeFreetype(); + if (!ft) return -1; + FontHandle *font = loadFont(ft, input); + if (!font) { + deinitializeFreetype(ft); + ABORT("Failed to load font file."); + } + if (!loadGlyph(shape, font, unicode, &glyphAdvance)) { + destroyFont(font); + deinitializeFreetype(ft); + ABORT("Failed to load glyph from font file."); + } + destroyFont(font); + deinitializeFreetype(ft); + break; + } + case DESCRIPTION_ARG: { + if (!readShapeDescription(input, shape, &skipColoring)) + ABORT("Parse error in shape description."); + break; + } + case DESCRIPTION_STDIN: { + if (!readShapeDescription(stdin, shape, &skipColoring)) + ABORT("Parse error in shape description."); + break; + } + case DESCRIPTION_FILE: { + FILE *file = fopen(input, "r"); + if (!file) + ABORT("Failed to load shape description file."); + if (!readShapeDescription(file, shape, &skipColoring)) + ABORT("Parse error in shape description."); + fclose(file); + break; + } + } + + // Validate and normalize shape + if (!shape.validate()) + ABORT("The geometry of the loaded shape is invalid."); + shape.normalize(); + if (yFlip) + shape.inverseYAxis = !shape.inverseYAxis; + + double avgScale = .5*(scale.x+scale.y); + struct { + double l, b, r, t; + } bounds = { + LARGE_VALUE, LARGE_VALUE, -LARGE_VALUE, -LARGE_VALUE + }; + if (autoFrame || mode == METRICS || printMetrics) + shape.bounds(bounds.l, bounds.b, bounds.r, bounds.t); + + // Auto-frame + if (autoFrame) { + double l = bounds.l, b = bounds.b, r = bounds.r, t = bounds.t; + Vector2 frame(width, height); + if (rangeMode == RANGE_UNIT) + l -= range, b -= range, r += range, t += range; + else if (!scaleSpecified) + frame -= 2*pxRange; + if (l >= r || b >= t) + l = 0, b = 0, r = 1, t = 1; + if (frame.x <= 0 || frame.y <= 0) + ABORT("Cannot fit the specified pixel range."); + Vector2 dims(r-l, t-b); + if (scaleSpecified) + translate = .5*(frame/scale-dims)-Vector2(l, b); + else { + if (dims.x*frame.y < dims.y*frame.x) { + translate.set(.5*(frame.x/frame.y*dims.y-dims.x)-l, -b); + scale = avgScale = frame.y/dims.y; + } else { + translate.set(-l, .5*(frame.y/frame.x*dims.x-dims.y)-b); + scale = avgScale = frame.x/dims.x; + } + } + if (rangeMode == RANGE_PX && !scaleSpecified) + translate += pxRange/scale; + } + + if (rangeMode == RANGE_PX) + range = pxRange/min(scale.x, scale.y); + + // Print metrics + if (mode == METRICS || printMetrics) { + FILE *out = stdout; + if (mode == METRICS && outputSpecified) + out = fopen(output, "w"); + if (!out) + ABORT("Failed to write output file."); + if (shape.inverseYAxis) + fprintf(out, "inverseY = true\n"); + if (bounds.r >= bounds.l && bounds.t >= bounds.b) + fprintf(out, "bounds = %.12g, %.12g, %.12g, %.12g\n", bounds.l, bounds.b, bounds.r, bounds.t); + if (svgDims.x != 0 && svgDims.y != 0) + fprintf(out, "dimensions = %.12g, %.12g\n", svgDims.x, svgDims.y); + if (glyphAdvance != 0) + fprintf(out, "advance = %.12g\n", glyphAdvance); + if (autoFrame) { + if (!scaleSpecified) + fprintf(out, "scale = %.12g\n", avgScale); + fprintf(out, "translate = %.12g, %.12g\n", translate.x, translate.y); + } + if (rangeMode == RANGE_PX) + fprintf(out, "range = %.12g\n", range); + if (mode == METRICS && outputSpecified) + fclose(out); + } + + // Compute output + Bitmap<float> sdf; + Bitmap<FloatRGB> msdf; + switch (mode) { + case SINGLE: { + sdf = Bitmap<float>(width, height); + generateSDF(sdf, shape, range, scale, translate); + break; + } + case PSEUDO: { + sdf = Bitmap<float>(width, height); + generatePseudoSDF(sdf, shape, range, scale, translate); + break; + } + case MULTI: { + if (!skipColoring) + edgeColoringSimple(shape, angleThreshold); + if (edgeAssignment) + parseColoring(shape, edgeAssignment); + msdf = Bitmap<FloatRGB>(width, height); + generateMSDF(msdf, shape, range, scale, translate, edgeThreshold); + break; + } + } + + // Save output + if (shapeExport) { + FILE *file = fopen(shapeExport, "w"); + if (file) { + writeShapeDescription(file, shape); + fclose(file); + } else + puts("Failed to write shape export file."); + } + const char *error = NULL; + switch (mode) { + case SINGLE: + case PSEUDO: + error = writeOutput(sdf, output, format); + if (error) + ABORT(error); + if (testRenderMulti || testRender) + simulate8bit(sdf); + if (testRenderMulti) { + Bitmap<FloatRGB> render(testWidthM, testHeightM); + renderSDF(render, sdf, avgScale*range); + if (!savePng(render, testRenderMulti)) + puts("Failed to write test render file."); + } + if (testRender) { + Bitmap<float> render(testWidth, testHeight); + renderSDF(render, sdf, avgScale*range); + if (!savePng(render, testRender)) + puts("Failed to write test render file."); + } + break; + case MULTI: + error = writeOutput(msdf, output, format); + if (error) + ABORT(error); + if (testRenderMulti || testRender) + simulate8bit(msdf); + if (testRenderMulti) { + Bitmap<FloatRGB> render(testWidthM, testHeightM); + renderSDF(render, msdf, avgScale*range); + if (!savePng(render, testRenderMulti)) + puts("Failed to write test render file."); + } + if (testRender) { + Bitmap<float> render(testWidth, testHeight); + renderSDF(render, msdf, avgScale*range); + if (!savePng(render, testRender)) + ABORT("Failed to write test render file."); + } + break; + } + + return 0; +} + +#endif diff --git a/msdfgen-ext.h b/msdfgen-ext.h new file mode 100644 index 0000000..4e6e976 --- /dev/null +++ b/msdfgen-ext.h @@ -0,0 +1,23 @@ + +#pragma once + +/* + * MULTI-CHANNEL SIGNED DISTANCE FIELD GENERATOR v1.0 (2016-04-24) - extensions + * ---------------------------------------------------------------------------- + * A utility by Viktor Chlumsky, (c) 2014 - 2016 + * + * The extension module provides ways to easily load input and save output using popular formats. + * + * Third party dependencies in extension module: + * - FreeType 2 + * (to load input font files) + * - TinyXML 2 by Lee Thomason + * (to aid in parsing input SVG files) + * - LodePNG by Lode Vandevenne + * (to save output PNG images) + * + */ + +#include "ext/save-png.h" +#include "ext/import-svg.h" +#include "ext/import-font.h" diff --git a/msdfgen.exe b/msdfgen.exe new file mode 100644 index 0000000000000000000000000000000000000000..f749c2153019ad843d07a41ecb559c9f92bb8053 GIT binary patch literal 335360 zcmeEvdwf*Ywf~vSBn&WcCK@zWlvJXPjSn=a;Gj+*lYnI~5%SVJv?7fZ6=5cT5(FoM z95%<&TfN2K)fQXsEp55g+ggnkbOM-!hY*BnP}FFto;0}{9)$!`=J#D|pEENF0loM4 z`sc@o%sFR2*K4n}_TKC4<G*XIVpkN!fxl=}Q5tZie_sAQ_mA7AC?m)GX{7S<(6_(c zV4ME-w`bKnurOo(f`@;w;NAx_?z{J)haL`OeE<H81;K|h9(X7t?~a)n4?aBm{%b~z z7?x=^y>>$Jtq00I4_bfsytVVexAA<>TP+Wk@pZ?8J8}KRcJG7l;rgef3G<rydfU7v zzTP^o57(jp*8N~Bt_R9*eo)|=l5{<nOG(=P;Ga2t6JJx3CeEYhJ0G~OhWZ?cVWCe^ zrrT1K8*(oxwes4PB-?P?NJXgur8Wa;{9FGoxVmw(oT%rO_eqM9f+zZCU6uLClDJ5- zE8Z1ckm^xozQ!(;sLZQ%D1~(Ml0(T@PB#Pod6N|*Ls1Ivb|~`)WF<aEknc@Q0GyK~ z=!vPZ`)dOCFAm^o)g0hMa1pK~6bb(_6y=_47R<gkaId2L(?5_wxSz ?>BF&kKTF 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%0D^AQ*Lmp^qpg*Jy04l}nb~Luh8+XJAF7 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�(yLzG^Y$mR&v9O0w<h44wi!DAcSuA#M!ZE3VWogv9F z$tbUQ6&Z!_gm_JyjATO>M=c)SSQ%W}O&ab`elup8_#$q+QlpGfMg3jnH4pdH3Z%T5 zwnMX8YOLud;l#RrX6W#!RE;to;vUy9DJ04;RmrIAqMuT)N{Q2(h_x63VHyPEnMpK+ z`P<A;8UIvgf5Ep&f7Qn(s<0q2c3W}Wk@e^y16x5BjD9ZjQ|TfT<Fvfn3Njz+%D!r) zPG{mHQ|e_dP5iuRErj|o2KA3a*Gr6yO*M%GU-D0g*V2e6n-DP@Bd#ofmSk**5b#__ z3jq_iRIq3vv@n-ijv6(}ihe`fg&>OTA{!PI($ZRZ(cOJoP)jhAS>vx@9UdEwpCF`Y zQ}DBH3D=f_wKa}nVHW7W;G!|8)fgvTuwpS_O`;ZH5r0*!f@$7I%8_m_ADn};Q~D`x z{Hz~cy2kZmJF+Q%-TBqN4PnK1`b2gmyAZYQkHJ<YWy_-9dDzYa`(gHzR%EGGy81+% zGaJ?8!w$WAPxu(l3iDMh3*VUP)aCO>`(xq{=`O~9eKV03C_>@!sNU-%k2r3)?flBg zW7^wS=5!l*W9=*p#;Z#6r1;ouyWP<PyAAJWVLocQb6wfospE=@&!f=NxBBH+`)>Ji zey8p$6vvm}YjwP2N$*xS=NGSZ{(7uECEDrI`QVR_?o)<d{OYT)gLZyazs9uReR9$_ zJAUtz`BwN!nq)8q*)9LB!-f^#O#R~HF)fB}d1+?ltcz*3Up}c-RIJD;P3ttLXCz8G zEMVY!2d6DQ<1?;G+2e}}FRACA#Ct!!t#21v(E78kx6~CcNKah{H|f&nXDBCV;$C>g zvCFj}%f5pz_5Y=JP~-=54}aFaX50#we%2ilG-EqyI#O*b2KG{XZ5fpK{KGRRSN8et z*o^4+`gyFsu;7tu)8xy^AFY?=PJX!Wz*o*IUkd!eQds0x{QLdV9+QGxBs=ciZ9A>4 zgU`hUGl!r3pkruVmtpS+XC1b_zB75_Jmr%e_Oq3^L0$D+*UXsWsj_Y>M`R4O`N%p> zyJxQ|Np`cO*GFrsW7=tK+O6$-ci`N%6aDudU;pE%Nek%_J?VETD<7B_=sUkD%&g5d z9Jug>!_JCpR}v+vfR|j7+gJV;U-Y)`#1n^C^`7$8wX?mi=dAhcTTGxR%(&89_iNL8 zF5Dk)8<JqT&$oD{Tb;l4bH8*6&3@!kd;gexW515sbI<Nx<`=iXO!H8>c50_o!-ls6 z;po`&?--fb^GHfKcM8<&@@vmQMvFxKv~3xB-*uG5vaw_@FU`{jM`i}#}K#YfCT z?o5oWSnr&)Aam|`NKn-8*B4K}EBSib%ICJF3DMj7$WD~)Ker%WzOhT-j$@a#YtMUm zx8E`TNa@_wZL7{@jZjRuCjaVTLULfQ>)+Utlt~9n`O2m&#O|~2dnu<bTij)K;r(TX zq-sCc6JxTy*I8K~9@%17cJ-kXKTRokbajiL+3nm{WllQh#FL92=2vaDYS&T`;W2N* z%nio}d0(3lA1~>CchJ-yr?xG0e*fG}mnApfJC*D)_W8|j-Nwj<ef{3a<ByhKICgpb z>jkk>KA9P}<qc1Jr@5o>^%KFnOYd<VG}AUm-1_p39=9+3zJ7bv?W-N`?uj0hmY(<G zNZ0&*Z(rWj(K_n>>G8AchqReJHO67*1;r7M7gAzB8aSt7|2Mzxj*FrtQq}!gX}^DS za>~y+vT+~PO?&?<+b5gNUir**T->UC&-dw4a`4NtGv!GKhn}>Xa{k?{wFf`U`Tiwm z$E4cUHt9JJ^wMr49zW;*<JT)9L#01`|9*Acxn3g^tMXp|GHXVU;e*x~TF!gv?V2%e z$qzLj{-kKtzNGFQJ8A8#yU(eMoqaMM9$x!)E8REq>#df$`R2wM`ntI;nf96VcDGVN zG4J4y5&6}#)61nlu0D2X|CBeRQ?`eep5FU=$bi@KEjo@0uo!+gu;V6Sf46G|0jZy) z9rifs_H9jFkNB5Ad}G)v<sDOxCng<8`FQ7#spBnHR<WT2A3~`)9i~oLQ1#JI6&?>i zNr*_EI5^`#b!gwqA(uT*gw&7j(Qf{<oKVA0y(Y&bcZl3^{pKv&KYoZCUOi|?wpGru zodbUJm2~TV!FPK3d%t%6YJEp}EbY{zo-Ekg-}3NFxj+AU_5Aox-qKyLsao^PgqYSJ zxBKGkwr#()d2g8R?V_<akG|h`)++fh$!}ZVmN~qba`KAL$->J$Mz))F<(uWRe*85# z<H%2+&Y0BS!fV1$KDOX1NH5)=WHV~!RiC`g{RVISG~v@@a?L!Kya&mJFO?oDi>a*3 z*&O3>`0K4x52;(NUAsys^q=9ieDApXLn|f)R$rLAzk8R5Hj74$n_d3px%mNCt=DY) z$RMP9R^ehaeu{TaOYd0jO^kB1D;&D)_peeM`g}9-@$mO=I=6H08_=qa#U~z~Ph56A zPEQW;U6;S1%1c*tcl7+#5&E|z-8){`y#3RDTO5ME%=~Kj4WGg9z5m6PD`rnl-78Bo zPtAT2+|52(6Ljb6iw9l5_8RtL-~nA}O#F=&IUh}|yK7Oh{_3Rc5j~~nzR)f8+f`wI z!oqQx_M;IOCsj|{^5gj5JGAWoS>WEQ=f1L?@N>kQuiV;syt^X$w6M6{C)W)>9KGA8 z|B^+N{i+VhQNRCsYOYsOc1?eW1<?Wb2lcy?e{V%=N!z%U0lFMXuW&_MGf&&}xktOZ zZG7?e;q%M$27Kq^9q{n1+A8BvzM0jv`9HrusYF>E@n!k>WtVRZ%2&qLuH5tC(YCYC z6lT)BVKhM7>Y?)vtn1VMzO8)hy%V2pO#Zaz-VLwKSbwyCqIAeYzqNbw+ZN@F9~f}> z>p|;w?|QN+X<+w&egluS9hvv`6YbE7u<w?>@8I)Cr=z3mE)Bb0wyb4bhm+==p4{0s za`RU^ixYma?y{FpqKYqz6pJd7>s-CgU7fqS|4(OZA}1zZ>X`G*=;<$<J$}*rg(sIr zAJ24Z+xzRXo;x~zXIawsXp0?3ZhkxF;!8GbkC<QFzhdI`0clf<SLB5BAMEqIWro9# z`<}FYTyG^wjg0wY=$YuGpsPD0uvie3xiOt=&B_X{T9ta}>@Udsef;UQwOf?eE=Inv z+p^cnkIrb7?>YZawA0Yap}T9>ZsD`r=CAiCdqcP2PWY8`M-KG864&CzW%*7&w|F=D zre<u%gbSJP8eY@CJoH1&{sB9(hVJ)qIkX~mv(x1^RDV(4g&(G$`M}k;qSH@l>-%~A zHpeS<>}$SX{FFNG`X4<$)Sj)ped37Kxeb|n)I!t`TQ82^sIkuZWZkH@^oN31Jf3zy zfAn;5zK<rdV%pIe+lJIUX{%OFEa`M%*Q#x6$KUxR=%<Gl=PrzF+4tlAm)G{7^aSY} zdtUaO`eO1A!#@4qYr?v+MXu`}Y|tNkSp5D^U1krfnzd<7#=Vx0Zl#~uR5*R)@uS}? z)yliAJr(a(ZRfb4L&D0qm#@06i1Hu)$*SinC4)meJLIkW&A<1aX}#w6JD*|5&PwxW zyZwS&mj8+PS1qfYK41$h!5mF!f%T82jbLWkS}?P+7tC5X3g#`I7tC8a3+8x>y@mA< z!NO*wU}5VoSlUj4=5D57X%{D0*%<_@)~^XxZL$O_$;Uzq$!4L2bg$6jxf4Rm=PHGk z_IHJrZLQ3#+d7(Aw{tVIZtrVm(>~P9ri0eZ#xdQ@)-l`6w&PAS+fJv<Y&-vA)~d6O zd8;nY=B>KY_z?xF#*8J!Dl+?ZGeO}a5z^jUjrsFeE8)n8crBIy9T#c0Of^qoLL@X> zdg!*ou<GOHFcvBjE}|BUyU$|odZXS-i5223#M86*2||j{kKXFfezV{s#xV^sLKp#k zni{$_CE`(DVh~abJDK$`lXgyxoTw0T1k5_PMZw<y9h@4j&?g}5pI!ea(rwHsaqs>Y zDVqsqW;BF=fF@=b>1TBP*UVf+M?4u{$^(9khsbm6_|Za~CR!Lfer#|kJZbxt3LNh} zUeG8taQ|!n$p}cRd>sN4jvepUCr%U9=UMKM`vR;S*$->{0-6u$_nwIvH@*t6uVB9w zCT6VU8r-u?%x{~R-!U=M*M~$tdFG8~eB`#lo%S8HNV5Tv{#KM%6=X3A@}h>jZ$jcI z>^p-J6CzbQ9USm`H_nIQ5hG68>Lb*H4#G}!CeKH3+vX$mDDx2pf#}zAwvVtZ$w$}< zN?ze390O^fgQxI+?B!u79NFn7MR+pr18oG6ncA{F$lOSjcQR8w(uEY-SG5Mw&`o8c zy&IL0>Vc5l2&uo5AGL+(M|>$Rp#(&Hv2bK=&jD%6LqzV~K@^rgB0_d=qutkNr=gDG zOftGpHsUlO@h4fMw5fiHPdrEl(t^5x5<!$#DhGv615utA8SynB`7Z{M{}K@Kfh@3H z=Q^YP6CmYp1BlZ597N%EfGB^*LF9i9ME;Jb6sn)dNS!bxc(mIvm<b0A4Hz|L{8--! zexn-tgxE)bE~31n8@Pylf!wJ-fCcp>7wQ*eR`qpvcLz>3XoNtVq69-vJ`K9f;8=q& zIx$X|tkjcVloA~g{tOXDM+St`aFamc6PY7;As!2dxQ0Y#!W*{He@Ck#aHf$ccxw}Z zsd($Q2Ba3e4Kc!Gl~$Ml1?%{PB*9M=N#UVuOr<!9%mBWK8yO2k{5WbW#HS&Yc+fCG zd<;71Xu(UbijQFD4d9tTCh!%Vh<}6GI}o3E0R;y3kBaJ_%J@X#=PC=tPez7R`~-jh z5%KXOc#oTm@mquR0x^;k2D1?!pR~t_9>wgja6vsla^irK+5A9A@uFa3$r$4|+BqLx zLkP}~&Qu!Rf-x%@z_-ywOsA0#Pme-1x{X7sl-JSV76A-|o#fgZQcg&A%GEfQM~+m- z-mu32CnFy9hY1*!P{qP{lsyUP2lq%I=Wk$Ki4RXF5wR&9vAkra^CL0cIM(NQnye{V z`f6i%p0)vHr4+?H(2O0AGSC^8n4g3OJI|MC2r-XM-Mmp^`UM#=5ZE8}6@|a4#`MWX z|6DN|kU#yCHMmeH9@1a%$Lt=De<P4rJ}9eD+it=X)SDpO`Vi+Up!=XY&|{GB5zbmb z)*va!5hMe-f`)+<pa4)1C>Rt13Im0MqCl}AHAoB6gHk~AK}$ecpw%D>pAE_Z<%04- zC7`3Aa!?hh8gvU(2eMn^%f@u77e|<7AQzB3Xc$NV@&^Th!a-V48fYab2b2#w3OWtC z2&w|z0^J8a23f8}8XyNy7myRk732vD0)>Gnd@N88N&{tqHh}U#hd>uWRiIlSVIA@Z z@&x_AAI(|K|G7Z_$^SL?d79lHGwfgeTY{Ob`M;*&7hz5m|6!T<kN%l*cui>hXO6k> zpZpW!%l>~a0%?n0TfAiH>&w#LSf24_=8Ctn-hSuZm8;%+fAt3+eza!ox{tFzS^w#V zjh}s<^Tn56ZTfoiH@V+#*_yX)`;PpbyT04KXYam(!lL4m{Ra*nI(+2&qsNY)C_Pzr z>hzhj=gKS2U$}Vb@|DV~*M6w_@%m5IH8*bF`uUgJwRi5`yZ`HN59%I1`u*`AxTj=h zZeeNFqNTNsZ7aLhZ6wm??AtoDYu~}KW2eqtx<21c*1bnhC+A+hUHZJx*VV0GfA;|c z2Mr!F^u=MrM|gO8jg%{t5jf0^j){$%Jx3j{Nzl$s)aeaL$tkJxW`yAzOX1J<e`WrH zR~P<om;Zk|{r|ZBy?uQBMvWfhKX%+p0fFNu;JfgXgQrZL77{w0*Z;Hq|F5Wj;WNxn zAi5)y4lDp!e~$SCln0`FGqphX9L$}d98eu7=nI%ZwII4<Lw9QwU()>=x>?iwJ`A~P zG1n(xB|x`b+^`OzbscE{;^89RjS+9v{QbQeTBXsd=2;w`o)2+%$nW%!Hi1&68#!Xi ze;1E57m-L?jhxS8d5B{xTCoJ2*Wc&=*?eeSrUOsP9hK0OGwnL~@9*+SD^$uUt%GST z7z?`!`Hg~2<Va;62zGzRi|cQ=uEsPj<>v3>rXod(8;$&kvBg^Y`}q7e7U`$NxRh&N z4}X_-3M)C66N)Xi^Rx3!=`_j+$tSI(Y1J&=3nNWb@;}ZC#f=0H+SBN<@^u3@st>*% zk7j*<_6A&rnzjrtqY7FzDtptrX{P!+y2a*(-larJbMQ9?Y0~XAN|oB2O7Z8qdph5y zC5}SANYWF)GXj58{!Ko-4SCH`*}3MA_JM!SmssE8-8_59n0KOTbevk{t&P)pkDol2 z={?Auj>(mYs>$qD4ep$g9)R4Rh42#EfN;6Z*N~Wqizz|M$T_%KF*b_nP$;e?h%mr6 zP^oR;Y~oH=dsO3<@v7j20N=5G2r5{9h5ZPq3&;gD8zpqZt}F<C^U(9$1Yhj^1hfwI zfR~s~g}Vo1|BDys!H0g-;sbh;#*T0zsV9J>nc(h}m>DQ-i!Uo<I?w|4EFk53HIVd2 zIY838<N`@Yln*2wQ2~&2E{A}mizx+?&ZHbjI+IEu=~k+NR8O@)(j(OYr9fe;FVneL z1F4Rrz_vg~paW0_YzK4!l1|4RNII=yz>Yu#kWP^Oft`UtK++Y30O`I!IPiI3EU+6; z3zPv<fZc&<z#hQCsN<f%bl9DMSwLstYG5y5Hn2A^2S^H=T;L19d|+Q-0ninA2<QeZ z1@;G)1BU`DfiD89fuujG1r7(+0Y?IbJYPW$um&oCQlK}`5lFi#8Ian_1xRh_4jcm< z1{@1i0LKCSfiD4rfFvIwzzM)`AjwWFa4Jv>Bsoa|P6ws|Y3H8~TnJQS{xyRDWWjC@ zTm!TK<^U~$B$HOaJlI<R3xF+wM}gMBa-a>6_Jpl~Rj}IuYk{qSkAZD~*4rQtKnI`{ zC<8tRB>A@olKi&?y29N7I1Jbh=m%^M3<5d=!+;%uvA|A1J+Lz{4cG<vCa^1THSl@h z24FW}E>H&C4eSm)1ndDk4eSZ51Udn40iA($z+OPh?T`nc6xavY1^5Ec1=trj80ZRA z0NsEg!2ZA};6R`jI2bq|I0Tpu912_sd=Z!p90uG391hF}jsTVbJ%FXak-&>UIj|b2 z0Nw|B1BD%s8=xJ~59kCO1#}0F26_U=0R4eufx*CWz;NJ8Ks7J`m;xLRTmqZ`%mM}h z*8nF0bAVHUdBADF0^oFDDNqHh1kM500@Xkv-&a@!v;&%90C5Cb0%@$ng(1NSb{n8O z&=%+kv;+DBrNCfdTVOcQ0jLJH2c`f!0ha)~0@natfjK}AU;%I>@F>t1SPq;6tOc6U zK(!P30NMdt0v&-iKqsIr&>d(8^aOSS`U5?H;lMdSHP8$L+I*lTFdf(uxDsds%m&&5 zHv#Q{`M^%V5}*gL6ljJ4uM%hpyaj9ttOMErEq5V4PztmIb^&$*x&S?Z3ZNMV#vq^# zFbrr5j0M^O^}tTRG@u7?HP8$LWe(5=m<O~4763Z|j{-e_RX{Tt<O*m56uv_^pdHWy z=m<1(LOy^tz`^7XRFFR~fc#yMAMyvrl0Q&S?ykrWxdY!Mci?JrcSrvucVI5L19y}A zVDwLN2c9N(U?sT^Lw%7QSVwkG)Yop<fl{EE0`*09pbMcN@=55Ad=dsApM*i^r$Ed3 z=%>I=Ks}IaXa%fSNCS&=0JzXkoQM6Hc9Gn<&XM*J^rL+V{b+Z>QDa0Nj-COaUo_TK z^ouoy=UQu=yBYb>I*)#|2B06!`SjBm`D%=It<kPEhNsm!{b*lAKU%NTPiI^k=!CgO zJ86(nR)pZl!_jJwesL%X{YckKKV3t4c)rw31C2glOgGw?&m?2{VzEA@pAt1jKb0{* z@y2{8Q3Ld&l_vdYRZqWIV|-et(r=D2{2U`c9ahcsGZ^{mjp@_6m3}eCbZB)*KUyKv zZw_jXe(??U!TsZn?lH#lQ9aK=I9gv*P0-qvYKr8+4Q=iXGs%RT;KSx(k_$Is6q5#$ z1zMxg+)DD`hS{6uWs(UpkAj)+TF0=p8_9wjW_Fs(Ngl{N31*TBH@HGXVK%_*4{bJ= z4RW8%%(NOGi}MdI6K<IKDZB=`BQwqaBpYs60gyY%2j!XglZ?2*L}5ry$V~i6RwykB zL-Io9rTml3xS{04M~B)VcPb0XjvI1-E(J5i4Q6pkhA3T%OL9c{ME65V#B++V4ylYj z?EH^pi+EB!&|a15llYU2xgk|ryO5lbnaWGDMm#B>ByVmALF*opIm#!UE|A=jc{=_E zz@|60Gs&UYUL=cd2u=AUe>a4t_Dx~s;^uiQJU5ffieX4@-5>#!Prf4^&FYinm-0sW ziD!8ZWO=3?oY*dW4;IMEPV!A_d6F5DaWc~ykK~-p#GhoH>aBTMNcP3Hi(vWZ=~7=1 z^FaMUG*h2wG;<lFd{W;K-Q!tXi20{><Yt{oT<SAaZxlC@<#`NRlKLLCBkv2mABnN4 zJk+14l|vCy>{rBvT33LC@lyJ*S|mB9zQpUD?wU~DQ62GqI98YlGw)Z>JHgD)e0V-c zS3#UZ;LiJ%535HSQ>lMacp67Z{-}O6tUO|$p)f(lHsd)Cf{UpP@jk%&t*M;(vNEc{ zk;+T;%lip$Zy#1)rfq2&UM&A8w(=LtIf}^wpL6_~obobzv;6Tg<9R%!$IHy?o|l>L zC3MDGr!ttP$MeU_Af_F}YC}vrfVC7)dos%hPdmVv9?1YtgQq>l*f*)pcpdZc#E11M z9eTrT`0!d5)9_<$%F_sBEib0Q#{x=&w>wV*>ra%GmyhRzbX?Sq-uT<Jjd*&z1;q3M zSzdU(jb)|fe1n)f=NrgcfY;m8`BE=xT8?1Wwwy1QS<cswmC2M>(>91_y{c&*CqQyV zc^+ppQyHhS{8BxVjklawu25rHc$-jP6zhw|c#1<lP2=#M$n)&O+Ci)f>Jz-5jbr)e zVS<e^N2z<WcHm(GSl<`RPWwyFhf6XK^Ag*4@-RWh{z`nX-)Kn7+oV0FFxlgAeN4g! znYd3hwk7f5qXtiRG8<92+27bM6lT0}ej#%Z%YWlqj%F3Ar$mPIhxWo$kF<w(1!fof zvXv9*Oz5`>_Htl8@I0^t_${y$m<_xLd<$3&JOR89JOdO;e1$TA9q<dFBXB3s30MMj z2VMkv0x2bb;89>Oa33%ncnC;3hdw|x>>mM_0OtVH;ocp%2KGp@Bfn<A9N1|N&I2w0 z765kuN#|n@EQg)iope5yz$(~j9;yW{1CkEN3iudy8b3)FM7kmC{l3C_pabx2pbSWT z*A=)GI1Km|kaP?*xB9`J0VEw#OJFeUq{ARxk~J_K_D_Lo;4xqda1(F|@Gvk7_zrLl za2GHKxF47Y%mWqx&jODEOM&G;n%}E{1;AS1DIn>rY=DnpKMAxx;454LIsnfBWxyjq zSKv0_Fkm6j4|p0F1l#}&1AYyR1zrK_f$sv-fR(^Ef!_gF1CIkY0Ivdbffs<gftP`Y zfEB>gzym<iLG=Vy!ma|6Zi#eHw_sNTNf*@%SO<G7kaTahK+A)?Pm!*vAM8@tbwJX| zwE}j5eI?KZxDhxQxEZJb(zp`<+zt!@?go<1h;&s^u%`n__w*vU!%jLQ((%~==fh6x z0n%;t2d2ZW2l~VA2wVyKH^6Kl&EupKYz^E5`vf5A(p-S~u+Ijj!QKs60=p7Oy2CcW zQrNL&V>(0$;3Dj+fYm@+6Idgj6nGzYnk%YdcLNHCd|B_dM*auDY6p7?FbMV$Ku6eL z14<G8IUwoC<Ul95zX2Q!oJ{_39|%;yPCJ|&gm(r8z#aq4hTRDm0(&$t3b+DDI>Ej` zE$s2Y`M|}%Sn%@#ro;X^Fa&lF;7Zt+00r3H0okyx1#SW+1M`6fU<q&v&=LIYfu*p& z2fPRj237;#2g=~z7I+`_OrSgX4h0H_ecAJ@F7S7N)eiQl<PUp0pd;+lfKI^G<PLlj zr~rNp3<Bl=har4>U^wg{<PUoXpc-~s@sTdl6PN<~Qs5Hc=fEsr5^xQ04KN7tIs$WG zpF#ex_W<U>9tA7_?gf?ti-DEETwpCQA1EC06}|^Zfd_#hh~Eh)gFOsLd;1@NuCNyY z{eXLbVZhJGANT<<9Pv5>--P``;A-GZpd-pL2)F_Ec|g*kDuB7LF9#}M9|kOdJq_p& z`*7e<*cSm~!M6*r9QK!iRX`0;3-_+TTG(d+T@Y^w@G<Q3fuyUJ0j<CH#SRbki15z? z9bgX!$`F1qA?)jb!+@^<^AWB$FbMWIU>Gm~7z?xjrU0)2(}7vQmB3Gc*}yHpO~5aK z`M}Y@5}+2y_d;}XDXtZiY@FhAb_5%fxH*c|6E~|^AK~UWHlK3yY?dc(p2Osuo7JqW zqB*r8Em}8;=_auL#KX)rai<-N7>0HqqM7dmdH7Ugo@sx@SMrf2Yk2O$|El3H?jcDh z;)a|NPp%8#S|Yv&qcci!r*%dIV$s=DV_dE;pw$W29nlFJ$q}XNhT5UF<+_6?HlOqL zFvS=5JCUqzxjX$8-RUH`(M)3l*Im$=AN4R=m(iXlhK+-KEv95+2scNtd~h?@c8O-n z6F2kxadR9?o115|HsEHB2_G%XD|hFb8g8c3IguxqA?`kpwLM?EQ45J{NjfzY&5>;W z<6-EGwb8vXJe?7W?);7<56|nJn`2m=a&s(eGj5J&^8z<(Se<e+*D#4@s&~=cn68$| z1b3%hq8P?t;+|xzH`-^ajAq)SQ!G)p5y#5T^+Q}^$aM@{OUCypTr<bbyuCy-tp~W7 z{)%RL7D6<~v$Y}Luk&=do`B0P*FW+5p<JIKy3^i{WE$fKIJ>dGWTyOc4JOyYD49HP z-4E9!l3vpdwMk{<`*1GD+|0F|{Je8E8(+A7h0dV44$uv~f%*y8Rq*_XItFedKhkT> zVP)pJlsRm?;kqNPspL8(uD#@X1um~#7es$aZ$tfrbLBfHt|cVhVWT_m-_+Onjx3(F zG1vLfUr`swHMLydz}t+Qxh9wE9>g%jllKR%!{K@0dOWV_<$AmbRz_~-nqP4b&wEOv zK7~tvqg~5tRMY`-Z86sYa*Z+9^YC=Jj)2P_H}iaQGySDK6X~zGcA4w(=#~cGbJEx+ z>ZxfDN_HNL`;$Jv)Sv98{<LT1sq^quJB@bINz$zX@)PBfMpM!=k!w?T(=nKb*Fnyn z7M{B|4NrPVu^z}QmYsBTbcce{;`%K<(~v%qO3Uk!-@Xyeq%-AOcdm2f?alS4^q1n& z*udL^>rCk;H|YVXoLVNMT#v;6nwHtr-Lwo`PnyKWIj-O2>GC}=^+oEL;`s*INrD^g zB<DPAEK8r8=_Z!wu48?TyX)CF&UL3e9pZ&wn$*wuFcQqPu%*>M=~AX(wd%yfu)per zm;vx^_M;D1(yvxN$da2x<hI7Y^(`CCCZ;sejJGf1ClN$s?gbY(f1tFEeBSaA5&mg# zSlECm9|yJdJ0%a<YTs?Z?QUL8`EsuGS9IstnE$5kqRrixn?$TN#;;vy#ylGF;qmtm zIJ_}L;kBqwl+C-=1yhy`nVojnxu9&wdl$`TKbAlE!12|OziO`-@@?|PyYueuv-a+{ zPd#rsFQ1qkm5EA3Ka}p`=jV1Vjh_2$YXx&b-LzIb80u@cy5n!F{xHU@lv}7$XaUH7 zIKCXv5j&_Z*e!vSos0z#{R`^rhZMzjUw>Y5xLz)ro)~$FwPCHWw!|AGKsb)&WQ<=c zUuZ7I8mZv5O5XyfpOk~Jx_}#2D>%|8DftgFB#3fEnbsyG3rbxaiL#)KOke`9o14f5 z-5944s%&#C=F2-jnCLdlir)TndHdRF8FDN4-=Emb8RmrtA}?>&u9SDZ`nFxl<Kgfh zxuW0s59OV-nsp~T5AhNTLLZcWoh|<ak0(uhp)>p=4?KAEsa*c+qB{{ot>J$=^!W~- z%P$0<kaybC9{vZ-vqpX?fBjVHp=o7!TalvJZP384<=y-$>MqPf{Oq&Z=Uj5-NkQMZ zWZZ*2{LZazYrd7Ao-+A)c_s2!p!%b8yRGt7F>hL?U3(G!`_p>An<u}wG2+;!61<Tp zt>$H&)pq&E3qI+2qPPS2jmu1)vqL^llWkvZ(FO6V#<x0~FMlmy{Lvo;lt<yzBX7_y z`H*QbgSB^tBL3&W+gE)jKR7<g>E$+kyoAac^IkW0%fJ7=-)ntN-t-i*)rEOJd*wBO znfD|=;_XM_v%j^<+$aA$dB^&VEAVzCndknG;tS-X9$oz<bJ0Mm&rKs+7s@x+F8+Sh z^5?yTQhhslexdwy{kwNMwlaf#g4L6WMe>4V7lqBHC!Rv({VwhgisasromwCK)!hp( z_mgN>7R#d&JEh8N(EqaYChPl@$Opf)d%w+bs*fj+oQ{;pC&pg)@s;)S65MU<4H5h0 zZXLeddg}_}3%_;hba%hJt#YJW=i74Fv)ZrEJRmRq;JwGLD}VOH4on>)J19REtcb{w z;SEwjUFuim9hC1M^meSP8OoP^JbJzSko@DG%U&-$AoCJxr`okSdPsgH`@|=CKcK!! zf4Y4o^sxNL%KCZcGAHDxY)rSB!*ZF^U3Hs5kPn4L#s<w1`NA1}cW$~l2=OQF-ywW2 z*L@ik5O*KxX&=tNp8mZ&F*~J4&wA9CqTj9`S{#+n-!tV{yYH#~)Th_JeN>*f>H5mi z+uL{vS#6cSKX**t>b=cxUl`oUOOXEYRp`gZ<T~}a-92AH{=#3K<kkMTyz1S4cjML$ zK>p1yx_)?EzU<DTtY2@!KWk-DNVgMmA*;iUo8PoV`WL#TeQ-h^``+CL3v@kD9-C1! zY)j<}ohSF4F$eWs{rih){-yE*_B(gJI~($t(|ziIWu@}X_x3F~uSEXxXLp@@pj1Av z&^>cp4a%EScC4blRGzl>&TnmoK;Bb|_V!ntlxOVf;Un`zezM{^zCZ7z{DUyJ?x}Yn z{~?>)=WRPFe|1TH#K;q<kNgqsF4UfsUuk34vtLMWFTvkuLYrP?@`v3vxJX}Z2Y%0e z77<Y<x9@1zuT!qQmr(9oFn4vCJoUwOo8pG!&0J}%k_yk1$@f`H_Fld*0`l<P=UeSg z$p@Bi@A$zx=+93Z&rRk7HZDvw&JRYctv=62G7&4&xLw48Zrm<n_TCB>Uc|JS+%95} z1-FYR`=XqM7qM~*w~Odfe~$T!82$~ni@16gw~JUR;dT+ziqEq6BIeBFb`eVlaJz`w zTW45!5v8AVyNE6-ZWmF}liNistvb!(ix~bHw~H7%hucN0bLDmsQ+_?g;)|HJi`zvM z7IV9Zb>q2R#FP%k_(s(JP{zw+#L6w)E@Jts+%BU3cy1Rlzbm(km<{<PIT10vnA=6v zzQ^q%hQx8Zi1~7E7ctwO+eH*=N*R9<%Zs>O#9<$ByNFU9w~MG9%k3f-^x}3AR}0)O zVr3r21N=lxOW<}9WiN2Mhy_*0S$Gk{KjwB3h3VWbVpeBv7t#IfF&1CMg7>*y#Gp`a z7qPMvw~HA5!%-Gr#M%wqE}}M`+eH-mbGwLX558ydMHC9SolvjT(6(Ao!XV;67-%^` zO9^t0RIx{6g=lpGd%<9|GJ>r!;uE4s6)dQu_|j=sB=?vVo2pH~>LVHf$Ui#K=%4B? z%t{>q(g?G#fFb?MER8BfuZ(VZk*5RPg77`wuE1bmC!imYbe8_WZb0jDuJe@wyThJ! zmg~?%;7_{uaG(UZ8t$~3$_82iW8qG^#T?k}ft!FbU@p)Om<Ob@gxx^W5tjf-r+F0E z5qKI%I`oS`M_?6@bi=oRq!Ydm>;ZfX><JXkah<s(&>2>1U@xE)i27yqjyh&Y!Lj~d z*mNx@r196jc?OS^=@SxU>I6*;&d_H030VOOLE1whr1b<jD+EO!g^=~ULa2RFA!LtK z2tf*kQ0l7?R^mOf;c&mV!@CJl*ye6&2pa^x+1(X_419yYH@6q(8w9>t;Hv=NT5pAL z5n&4uHVb)>Il&EKrS3eeFamZt_#j;FXoZlBhIUp*yMjb?CSh~#H(+3ltBe7xcsE0m zDpBv2>Kxf<CU=GCfrFq|KsIpmAhdCgB=oSgAt!<2xd8jX(L)CRp0>gQ_{*Fld3x$- zWPuqeAIzXjiV?I*{@z_wEz`v($3-!RSXEq1EaVu;<Mo_Tcwr^Io>Hbw(BW;ac&^=O zZ)li-?gNIp4<0~jav>3A9_#NniOggDyn`8z8t+FK6c9X$P(Nw>WWtD-#xQsNs1T%v zeP=MoI3w!E2D0#4|4`QN0urKBLF30zP<FOx4YV|pIgrQ<bg{x0fAQ`K_m;`7$~M33 znrQPu$CCJ#Z{44*9kMa9=F?SC>jtJ@XtN>zV(RlXXDZVx%HHoAu-#_Q{BK`v>6ZV~ z+g<l%MM-yby(`O|?LT+tz02Nvmn=AazSGUBOYsx8oxXo?>8Zt2SF76=<jjeh_b}p* zTZdK4Cxn?fRH$1-MtVse{o2|(^N>vA@v<~7pvpV^Oyb;_^(U(=Jja~2eCdy+t;^<Y zv)%Y8XWJ0<>McHJ4}W(-@o@L1AJpXo4PjSCooIdbVyM^2uQs_?^co>to|rcA+@bc$ z(tX?R=XLK{vUTbQt9G4`Y}}K-F5le6I^Am4mI}KAPBpE*T{b_V|8oJcAzyV>7J9iw zZ_o0+nABqK1+(3<vehq0&)j}v>9=#cZQI^rW7WQo2c6EZUVpe{%HW5BWJQk6dycEy zT>Y-~?1gS#@z(FFquw?Pi@bh+;+#1VN_CfVch%DILd4ylSG7>TveB$_;eG4Zrj<y3 zJy4OW3aZ&*e<Ocy#{Bf1kFRvS6fxHAe7k$|Pra!MIQ@Hwa!cUxiQ7i#h25WCbN}wN z_r@#Z&aEo<iZ402;rIJzPtC50^L<>Q89X{Y=Ihe@@bfx1OTQnxS`3;MVEg6a`K>Q` z&b12q(%ZbZRN89q>oU8;&f8+AZC#omvpF5T^W!Sz@iq@Hzr6ZzMV}t4OLOyb&K>OF zwKa56>%4v*VS9Fbt=?52Tb%#%_O1Iqw7a(5;={6U^~1-Ux$#YM+1hr!E?6#Ze^F=O zD)NUV9#Jbt&W>-LGkx~FRwvq2t*y6txA$hj_S<zW7x=v^sV)1|dRgpUv*(`_wTPQJ zE#krVF{-q=L)9IBYB5KX)cN$2%D$)Gm_F~k^ys)tF$q_8K74q4?+V|&J35?MksDt9 z>DjZdzI*bMlA`iqlkQ%ba3|)wlQGkFe|D+GHu+0KxA>p$+qyiUv+Xy(jk6dUKF`v- z_;&b}DOX~0Zm-Y`NZlJZ`pvD%?>jAy-kn{R;5_tN?4(u6c1JD7wEAvmd-ERsds$7{ z>#=LUORGIw-kF})*K+pOu+Qty6%9C1x-DZ}g=^Q%muKV_MSaxkZse^spUyVez8i1; zMGKoX@}X^RE{$oK*mjy=_1d_7s~qO#U)$XG+gFBl-fs8Nin4cF?>+P5j@uXKcfWF> z)#<WRulrm(eWz~grC814^WBcM-@9l=ubsbLP0me79<#&o`gH4b?QBW?5swzpVXe%b zt6!&jD{gZ{-KqLH%26lO?NhGVX8%&w`dsj0%kf29Eru(5#eDvteRyf$n7FYQk~Jg8 z%|5yL;`Fl>(XFm1YCXzdoV<DW7yH+JcX{E7En{lxx4Cz@yJyexqFqPa-`zU-vrqG! ztcI5Edbh>7V|}Jw4&E12(X-#Y=&kwVlqKe!V`r}HoAAPmdt2pwvcj&o^A)S<nYYc| zXlxLv`53_l2mB#-`q8*SKN>rT$Zi25f0{pAf@q+nIhN)@niIQ&27tUlO3)%uA;`=O zW{??}n1P8In3%NyAv1JGo$i;@9d9!k$Q`5rg$sZC1Ivc|k(u&nN|awy63Z+imBW-^ zWk2$#AMv6e@unZGAE>OfUZ5Y<rC1Lr4!fH`{Ak@kJZK$3=~EpMuQnj!Me7m8RelGh z2h9F3Q#e`=1Q^|W!yF7V#q$J(7|kPLZvGSNfx;4rWo}+h$|DiwnMjlcYDXeWkBlh) zM3jFb%0ChDC7x79kq_|@<5C<7N9Ch>Y73&Z5Utl}t=1FN7c>au0rCaWq!$UI$!sy` zQ&2JJ2aq`mmR5zc>~r%j4<1;22Tu6a$}6$vao?yA<{D^a30aHBNdjhKGOOVd1ETeX zCsw+i-RZ5@gfo0G^?J`>W?rW=XO6@>u}2DWR4UbLO1v7c4NlZyKKJS|pr3mWnMxCx z5QTZ(s|R~O4jL;N;i#VUk$yt<Om9IN>MdkV^A^&kcneyP4E8!D)=uz~!95#pqMtkL ze&K$2dA4^GlEO~Z++DP5y}gB8kh>4U5Q3_ZhT>&!p)$-{2%piIMlJ06h{iPjj<=Xb zt{l7-;6sGG$Y6H_pMM%(<fC{Ac?G2fAaA3+g@SS3!fBK_yI<2ar?}p{kG9N3de)JR zc@}y79f~{%Ylox$J-vndPpRMLe43X@=8HN6Rf2L+$CaQE@To-`)=o!R(57M=3aIN1 zf00IW-eTJB?%sj|l#P7mj^}wDj5ZYg{|-gIrGAi=QII)MILuifX9KNvA@eCl#Cnz- zXk8l#lg!zDU<lbcz#b#uzhE1P7o^9zMaC*M8kJgxmv7^(^Yk)uZ1f^kvgkOK8t-;i zY4}^uWf7^esd01gZe^KotlAK-o0BR_LNBp(`)~YgWwI$cJYG6N7O#tnMxy;xDJq#K zc8#i$GS4`T)}WW^w5rIsXnZ??R@`t+U?1ktjkL85#H*?%g9W0>++<^TmQ^ymcAY*C zfzV2|EIvV#5E+}85U+ZAN&6wbwi$yz$I<FkhNuL$rj<ldDch!L$NzoZ_LBwU+W|8C zH{f#vRKMa&>*JzjngrxHN=3fLa^o8vl#YtN6re*=lT_M-MAS;GQmblkPSB`R``Ox# z9Un9$ST;Fml<(NlV|~4Y$4(fJxNhJdhgWK`7@o|+b}u7sZTz^8%vjSbgaI4V7@0m+ zB~wPZ#U@0`@Je!eBRP1mXp|kd=mfm8-ZL7{9Bc5PZ$G_08Z85nN>oN-BabFP1KQdI zBq*bFG9_wW6QfqiV$`YHSXne0gRyTYAl`8fZp5sgY&83Jhb$pl)|4C7NN;&>SJ}`( zGRUHP%AnCKBdk<-jeDeNZc_9OiL=b}qEje(B{>9xXF|!-r1Id?4sjY=n@M=DxsDh3 z8F8pysHa5XlLfrmcs7z^OfrBiWn%^qAvzAP91-75PkT)^#TYcGDo6l6&%(HJIfujK zsbh>evz-t`jYvZ7ret;K$pG9Z8-pXeNFg4L6K{x@@jwwOeX>fWK?Bal_XSY5s;C$h z0w%~JSohGyMX{8XXefLICb6H)TdP%RqGW#Tb@NfG7<}wR#|p+ie}OKUBBM_yP_Ili znveyRo~O>dxHuyX*8dtr)BverNo(U$RBA|rE;XJ@Gv53Up{0@;^a;_4kRw|gZy4#@ zEl5jkOh_klF=*6yEn#Di=!0@b$@KK;7B$|OZ_EUfUZfu#r)O-b(ElHEZvswL_x=xW zWiDkZO>ztoMM#kj_lY7+G*FrhQ7Q8fjSiJcDvfB=pm{)p6lWieDrL-+%wvWlq$v5X zz4uZc-|zGL{om`o-s^hLl|JXQ?ls=)UTfWJ?X&k@=jHC@>&IgIx%vd4Wt}ogYqZ#- zN6Dd7RJn9vw0=;%QC!OQ1Km&${j*DG8LKZBCVO9B^r8<hbeBB+Mi&;FdMv)*MlW|4 zRERm6U1^o0zWEdWM?)^?$@S==^;9Ep2Ixq^pPIAKjOFC(@3tNdBR?IME;TJv@6_;P zp*kb8|63eWg&=A!zytg5V5H4|sneE!D5k&lyLlotIWcxlB|}woLhsCQ@}%s;)djub z0KMi2Rn8raU-Xrk5w!mdHM(r(B|9v(H&WOXma~U9`kx+b44{)jlqC`%>!$zj7eIe? zruyQaM(h>fPfhqZXEX&+eK26oWm%&@-#|C?Isx>a1T-nE+vw$oOr3sr3k!|xzD%fQ zp^3}YlXC3n8gF!U_eN75{nm}Gl+B>jR2VJv`a687di7a$|J>-A4o%*uPWUY&=ujwt zo~u=ucsfWKDs*<}S%RMac+!@Xu%VbAdZC89>lP>KWgmDp$4z895OoP{bA6Kw&XO7+ z-a*LJH=t2SL;w2G2UXN;NhM_>^$mV1#N8_py*`ER%Z=zHi~2rry+{4Sj7+-T|DTq_ zw3D6?=)#z3gUw7V{gnRyU^-#)LGM>$v1wJH`H4BR>#rmiH}r}X$_)JaG=;m>%>(%! zOcwqwDC|#9QM&7kgI**<z3l?&*bjL@)cimh9-3U4IhtjS)?Pf6=(P*YE52xr2=J!H zCbN2LqdCeSJxv46x_`}#G8R<b|ETs7Iv&c!lSS8$<?ZXb#SOh4?C-*iy)!g4|2aD7 zj`pJmKB}V=%7cYY3GrHj?C5VbXg}ruMO~;V5-Eta9?idKjP-d8%ruEzOJ)K2GfSg2 zgjzlNcTAs*T9N-T7La-e8q3!8?rv!Kq8FK=6Jln@w`Vy8p)rgi_v^2JYJ_sO{*G5K zU#bUC5@#=eH1$&pqQ4g!|J2qF?R_S%^Vn*>&>nqf`kv|`v`0mkI4BR1ibJ`3G%^F2 z(54QL(TDbjD5Tva#?_+3X}<#HLAe){{LdVUzI#!ewmT|4^~y4WT9K%9RKaLU?W+g% zm7pe9O6HFM*N^&2hto4EBkTK0pqZEYqaJtK7oQ5E!urRdzq`Bs4R=Q0``&|xr{X`J znhq*M+Yb#lgs3N&GjVG4Ir(k~px$GI7A;#eHPdna!?y9l8t8=&(6^wu6Zt?J(B>Ou z{MQXY-|2Y>71FO9W@_py2$%DZ`HIQk>2L1nH8t)m&j9M7tvW>CEXw5ixBmY%-vKl3 z|C}?W6UsSaa{i+iD(H`5`t(8v;wkTc&Q+Unz5eR?ANlnu`j3A`kFEcr;eI-xw2bQ7 zH|hq|_fPPjI`@_FSAvJ|-(m*j&N!+6)C1#^{&9k^BA8G%@>|iQg*FGK|C2J%n-P)w zhny5omW>tV{yVYo((8%VV%k|nUITh*Um%(i(S}OHMFV*<h_dvIbg7pfYSZr1U+;;k zVP8KD^sG=h*pI_i9gw!aqt{pIerjN$_lqHmrfP|NPGo;*lF_5b&0l|%R?wgFk(>J0 z_x$5xGUEunFbVC?(bkIcP5=0xSXtDrkDmHysUORHGHc;vdJVAGVWGzrqum&KLlSbw z{k_m*lqtom^YZYZmIdV7q0J`?sLE}2b@irm>GNvnGU=C+q2Z5IjWb}{@Ymy{8qse> z`J>Oi5$Z?pC8#9_IX=|Vht>Ia5kh-;+T;80D<NIp-^lceMU~m7xBvTc@M8DB6sAqD zFsM!aeK)F&l#ht8Z%*`c_4lXNJER*oPrrcm=xD-?+GA1bMvfht%#2wR{3Ho_9;DLJ zdhqZ<P63*E`(90{L$5hhdlq@2@O}p!t}e=S-@BqE7TFQC#4roB4z;bMitV@irgq*_ zy#CwndomT%&lSzZw2zCPo$Q2MVzg_bt|23ThFM?f&G?`FCRH7(K7Y5~e`bEBPXAXW z>!6dO{s#el8w)2q6|*KzpEeoo;0^RN=}ICC`xBp<4$zsdzps}!@>W?BHD+mOB10HZ z_rK=_sJ;Va{SF!a5sk2M@<k@kjP^hNMZaAUWpBR!nIEI4e(@N03Z2s<$6|vkI#}}e z-P-59;0+U#hIUQpHImAjFh}QYUeqy%KRw$1XqIum8Rwmf__sZQ)C)>kjM?^;im!|N zx!SW#&<;4jm9`^iFZ3{VKNQmcf;zsgj)9KX&lCP<TqJdJL3<N)0Eh*2e8v<18}fH0 z_>bfSvyT3aJFp#$Qqb=}sN*a8u;)M9+Hbb#i$XA77(wXJUJyds>!CR9QlV$u1)u{< zO0{UO8bF<3GDk?XY4=kei{8KeXPGz(<tQ`zfq(A<vxPSQYaDtHjGOmweaX0GxP`W8 z62W_gKUJrO?tpzDWkU4l%%qE9XZDDq-$`=OA9X7y7yb2pB4Osu$NhK~*wUYmFz&Sv z`d5Nw<={&PRA6}x9J%?WU%FN((YuE(E4AXV?-X+SO8NU;42OwxMrqGp_ET8`b7_pD zaQJA<RWQy($id$U^qJ3m=dMS{rM{aHM6fyfj{c}mImuuvMuN|9=6@jsgV5h#^d~al zPYm(?f7JE7{(owS_y3!Wc>h0L#QXmlAm0BEQS>Rtdg?<a^soN<^w<gmuWR+iWUzG> zmizP}^LwCP{JWsPziP+nxC7FYefjs{i*<kBBQ5Rn_xtL8-)F6(-uuDY;^u|+bJT83 zn>vZ6Uiis!aq@Rkrphowiw1s8CHk3{pFbV=r*I?OPe$fqtL3MvUp>lZ?4b)7elZ2x z2Oo1R@3R+z`zI@OOElGH#QTsyKei9<C#SzMcKwo^N`LN?Ngkgbd3?G`He5QW^Q8V1 z;BcVLe%u9Y=P$v!>BXX^7e@id2Q^>xw#V!H;B*Z2i2$l>^kK?F1vBOL^<Q8AN)v(^ z-M`Ir!Z_$hUa9)d;?yNm^l2SX&sM{}dNT5IQilG7;QGYDm{=k7Pm5G=PaEl;W=9&l zwu`G$d~M2vcbo1`f8(L+pvGa+Q+jqB<MbdBjr~64pmCQBe%^z1!bh*8F0rDIBkm6_ zn`w>!nD9P5_qC^$WaI<&`?o(C`GEUL{>%%l(3ids^)`gp1sB=^87o{MzWFu;E_&j1 zD{(g*ei_=EN`3%FZ?#l?`udk+IpRA>jp4ug>(gW3eIkAJF30^*j`d89Wa{$+ha*3Y z{=6ia@c;kmo2l0y{r}7TK7I3C-~BRu?MHXBP?K4|Pv89>eL*WOey+;su4WT@HIgYR z@t~mbE$r9Kmu%wsJ@wDd@enh4{N@e6TG)j0sCm7Y;^9T8>oUET3N~?0Z>vgGJakKM zi}<Bb$0ih|A6uv<fZd^y7oIsavC#tqB;D5~fYjyVc|nQgY$C@q;MnB^Sod+uw8qhh z*Npy^T$KR2Q9Yv<jX|7OcBxV|5hT*mRK(Q^*@Sa}$559<h}dv%@yJ)Gyd9&Q46h_Y zeZ!L@DPv36gws>*y6Qxb(j79_A+~`{NEc;As@;b*wu&qmp3WwW4%(6~_hHA*o$Z(5 zBb%7kBrCXbA9hVTBVN*m@*AZf#j3dvn!2X<%<jBn6W286E}8HEZjI)LSgGG<6Kjpr z_qsj+Q{}gZW#87b2|xFvPvRbc>+^NayL>X)#HUZ!T5BGF@9~=@Z@JIdgvGVt6V)HW z%FffC!WB7eLZc<aas5Lu$QL%;RLN%(53{OHUwsIZ-0t^E*gj_yO<pVVYafEe1%b}| znFVa(XtR!-#v`!b`0M2Xc~qW(`{u<P9zo~KN#|{!A^lDrE_?LaBPhu_E8$^O!zP|~ ztLM}`g2uz`(YLxX*hI$CyYds0V2r$dkx7|9n=t0wUa>I=CRclM3>?vY9Pzbk=dUNh zr|fZpuOcYFN1o$q>XYF2i5aaWcgxu5;T=)hnvc=^d-L2=@&%j7e;FO<_87`9Hq^+N z2-w7u`U%f(Jcge2N`;)>I5wem+)Vn*V{p3jrYJDw3!AWPYg?<84EH=H9%p~AWfLL# zGw*FmhFH;do7g#}Y$7^DN$6HGu=A(vzFvaj8xOm(tT7oZ{EzSyuH9gxSLeRJG3f~` z3UzbdW`p|w*oE_i`xA)&#bQlZf%0<_RkXkT1lDkxo;d70%O*NK7u;`p0zXsEp0<=o zVH0nM>J8U^3Qi>r!51f@`r688x_dkYw`CH|a1_~>%u}t5J5Rx`DpRYV`w^Q6G@Ps5 z@)YijJhWn!#RE1Wnl>p?Ck0j<W{ueFiQ><REb8z~LH8xyn0ROs()X)U+g0~cApgMF zJkhggylB*2c`itSO##XVk58idkF0sCt(yw@3fI415+M6pJR&2;I~7Ep)P#}Ym2Bef z!`osBsjzR*qv-7==suxQB0hm%Q^8^R_3G%>H*DgRxnhGJ4>TeNz3R>tViQ)04_Ev0 zAiMeQ><r;`$o`I-<|Ojqb;GUvoHW#*fm$h6?L0_~JMO8WhWe}gss8h+By78ON%ogv z5t~?b=&Gqd2_kmdv)uBKeLb%koAQ7JF~`K&%bZdD#!E%b{6@l3nG5@M4j_A5Cc30o ziw~L!OJ3B*<gy9<@*jIP^I`Js357)mQG0!VXAis02l=Ju@*w${P0T&ta<+*ND}y#< ztgq>06Ro0-Q?%1S{QHmn?W(AMOAi>n@<@Z%fubR|rI3BqhK4!aO#=s&a&!J~RKEL) zwL*e4IDGFcN90Bqn~2<=6*uJ>s9iT2)wcE<n^?24Ws&zYa2}VkLhDE`n`n=F^DF)t z+!(hr${~}-CZ4?VyZ7}Oe19VD{no#OO&r+xd%ga1NV=r<P{<C=SEUBqRsEiW?UD4Z z4U(w+A{9TY?>~o_B&EQF`>1~NbdKHXcn(&vqgM{?MD5r5VjVc`1vKyL(cwg*^0_S* zbGN*JMG~KC!rIYzd8~Y3e9{Z364^vP>}+QfzqU;5{{8~)MQ>{vse<~`t!4TrqnAJ& z0Oi!wZZ^R_`6_MeOR&6M;WfUh71?)K!<{ED;dzj&Mf!J?e^q_Lg`Y1W&$6p`SuwJY zbM1Oj>{nn{D^biHjr7sdu>Hi&R}go)MtApZG{4+aycETI1x0UroH)CYK12kMVtZe~ z)p5FU$4;f8`_3{l?r~njMR}<@Jw;T0<<!m>A+KT2bseWMwkUt)ggNEUUc))7lh^lm zp!q4g?7fh1I&|f~mPo3~W)u8P7d7XkgSGtc2e;GEeP&iebC-vu!}4g|&#s!Ny@wA6 zM7&Oi-<M9*NiIug6F1(Sc`g11K4zv}fdfBK|K3?4G4Bm1i`iHk&iKV9eorA6AAAGf zW-2zUxPsa<Z%t)v#v8CRb~VoX+J@wdKXyvJ1;KKU>m`n8K6RdXYpL~HFj(fIpm7!T zr{s#jq{z3B#kDUTEQIot|FJ+N=PkG-cYMCF6s33A2`A*<LDI5O=R|{0{8y`-rEK59 z<<)iDR71X_`Fr%6L#N(>Udk}JC?4wXghl&C6uyJ1K&QP5kCA@5uEt*(odG>xzK&fq z1GU$we8tRF8E`r^(q3at6`SB>94|VX0b}l@k87EO(%V@F1ea!j^3tg1+!d(2;m$JJ ztoLA^Xnahp0@*)bdPk+xdoa7pz8A0dlTFlZe{%u7Z+6m(FE?y0(fZ_3DCJu79!zaT zKZT1Sd#v$Vqp$G+L@ypDtcp<nS+N;nZXdw1Ctv!0J{lk8rCv2RKLG1f@rM{s)W0+C zuX@+?0U9I@?x<e-8qMD+SCVxyVYjK*m`%6Qc-4t_i1*F}y``=9W71IjAFsH0FEJCw z9Y6o&xjWKdd(^I^j!f{<2}&#(f#egWin@%=f^%U%<Wjd2CWHa&&W{CIAoDKRPWdI; zFFFf-P(6|bhgyZka5hMo5aWjqcgoHJ%bMYXu53em|C(3va@insD)!v;eNrZbSMfYK zyKI<uxSf^gEMh`v7<BB9&W0%uBmGNFQF{WL$H;!l2B${HjQj#*FP9xg-9z^cDLH+X zxa*4UvpY#zI69*H)~0li9=V<>PgO|$at@rFw$x*p0gAso>@rcC14|xmQ@kfgW)rOJ z@YadBP+6*wxWyjXC%;6#b8{|um)j3()EQzzT-_Qgb1xV68r|234ngB@e!wB~wp`fs zOYQ`F`%n`?Kb9RaEf1mw7d%gOLFJ9k8{QO@2lXmW3I{$RIj7rgT}mEYn{Z@R#|(6z zYNgD*w%$D0yhJ+J;t*QDv!>5JZT=BnUXU!g?STB9Y1fae-1iaEFCN$|qJ`pzXa1P_ z?js!1niS+V5v^Ydmi6kx^Wp7lUrG0^!X|`q_3Noi^I@CJV99-(deD6Ec+je-d`O7V z2&pMT_BT^m<lLux5Zk!t!tqxqzu<Isw^9KdIMZ${cNWR-B#iQNDS%;@6`H2TBmJj= zg!qjD*nU>o<Ea^%ui2*D<mLi6Jw$6%v_9(J%!bx|`h~D=;rp##mcva5yRJ;Xz(O#Z zKR)T88k&!UuN~i+QV8aCgWa$9BKyuvz8@!41YeJw(jI)}6I$<%+-R~Wf;T54ZdGhY z^KZRc>yn5fC<(u=Y4#4)KU!6|D7y$=cQ>XzABEO$LH)X5g<=5K_20X)k-fzoJ7Te> z7*ft%Q-4^A?$eBxkeG707-krpkmt`q{w7E*o6&%{*1I7`G*N!;(CIqm6ZDu(KdWqk z>KmXN_%PrT>|Yqucq$V0@2$;_6H`9H(URW#O|ocw8SF732bI8l?}LK}r42SAELF~K zvnl~K-p*x#)6o2vCp~mkWC@hr<la?qCfP*zd?lxX5*X`bF~~3(>DNwb)1mR7;l#3g z<4$iy^TCp`&~n$$uyBobQ<f|82h^?)T6O0$OszWq<<56BpH)2F)6?-8&UP$b=~a#N z@7Z)Uom~og+LBhCK_zTr{b`BRJ*6OGb?4EVYpA|^Us-?3D23*C#X;luqxRodRZ<&K z1_wQZw;d=%<L!hdD|$^CTnmk<-S`sOJE`&8@M;-sU9*utW;nVJ_@w;?VL=%TDP5Yq zZWx;XoOg=$jx7hVn1^b`w~&11-RxtWa<HC#IQgh1x)1e2PpgS*IT$aFUo(3(nvbg9 zrV-)gVBtCU{VaRrKa5kk{ON8voY6Fs_I@<lgwR}4zqqy>np*E~=Y9Q({M!ZOS=|cw zdMwE{OA)P)axN8%wpT#%)BJULdZ<0?doFB#RRM0+55j~r<xPmV`yQP#m2hah<eSzd z$llynmA9>_gz*__FVDJ3n-GCh?z`Nq1l|wD$L70H{Z3DOWBt7n0zy;tsy|bF@07>0 zt3X7S^<=cVq6v|-k9Fx-6}bI2*Bi11)n|^IsBA?Qthj0-zabZKn-jZ+>Q;lj*vy8n zHAw%8tTm^Ct6_Zj<r^M7sQ<>Ci+_+=4aaBI7#-Y-`oG-pl{>2jmX4hMp{5bt=RL$k z=Y>xVOmd9)DEtZOze_xg|GWl5U*}Fxo`&k%?R912$XW<4-kS8H4#ju7v-p`?Eo^yd z7?b!4=}Y9xnY`3maGAZN^zlq|pRK2R(pA|ya2~DYuiA|C5p-Y{XJZ|F+dKAYRw)|q zD?O}k@ajP1tCvk92g&1$?Z1quhsxlDOmZ-qf5e3L4E3ysfcII^a3ASo!m-VxU)RIR zISaKl)}s1I&t5iGxdDt<K6~qFg6?Zh`lhS6qXERStV@4gL-!%~Jba*4*Z>|ot;BM+ zqx^$^xY|tn0+YITuCyACc;(^;XO4e?Z)?3qt(%F);~)*0vF%?#GT^}!-wLG9Uzy0X z8ey;7+pN!eX#Nv<=kx7hBTNaq^{7Aw-Iu;S#m{ea6WH0Qe^UrX`Yu+@+Ptd?R>g?N zN{m6{^-QI3M|BfyF;kTKdF>;cnBKWxbzw8K9hYfUE=Kc*<alZMq-OAO_z@_hiu|dk zQN<N1Es&ECb7@I68c(4Ka<?N}VDo5`drIc0JlQ0(lY{`I_m?}IeT(L!fR{PXeFf0A zwLt#JRn-33fl1DF0{As?a*&KCvS+r+*u_&?f!~|v^UFumglLHHTJ7EnrJ6tEYL=;^ z^AAI(wws7chmBYug2q=q?3muz3O(_A&pj0gK=sJ%l`{~&%rBOE*dl=Fy;I)mAT*t> zx$|nX04B5UP9BHwgu<1=BTWKWc&L>tgz(Yfpb0*W0=V#!^{VuX0Hy@Jcb<nZeZTY1 z`waqU4tRcKEW(K^bCp8s1<=&!f2$hRd;89CeG7zdetmloS1SOA_GtaV2u;J5-CA2C zfM)>`N{_1r5TY1;XgERx|ME_kDghiG@@(bfN|c}UxMT^0%dOta*jETZe)I#EtK|YH z+<rIVYncFch@bvpj8LI<>5R})0hIPU_Iv$V0E439u1O+1^yFLK{1O3x(B7Znp9J83 zPG@X-u>cBIzMnc6;gRz*=dg<e@OJ%DYrjGPyqMRr_<Df=j%}-1@F`ya!lVpmD8lVq z=TDmXQ2@^`ZyL5SPXK~Ui-u#l0??kA^z><t04{kR+gq6}08Y<c3o(QjURM6r%o0GZ z&EUK9G6i5x)+}}VAb{ZXwXJ*K3t+@kv)!>70&v^mIyCv60K)d4KA8Dd0N=kpAgbR8 z;H1;O&7J82SU0lzohZT;HD{GaycU4bjNR_auLQ7OcH`|yF9i@UI<8{s3jt`(@{%-u zE`atBy@{sJ1Ry(J-<Xqz^xO*^4qpH&Rw2GAJONDK8*UJvg31}pd4A@J0IuW;D+WIn zfZ_CMoRyCRP<>i`lJ)}u1V(9;d{01jP!YWN$vpv-Sb87uzaxOJH}yl+Z=w2hcFoAT zE&#L9ZFhaHB75kCGRZ3f*s@>f&6$e=xE;E1liCFV)WuFsyK)xg>zDFw+-U&}b#B-f z5hVb-3lG}cPY6JKf{fJCV~F4Ql6~Wd0Lo5H;QWX{;ldYeO~VDCe{-_*j(q~iDmm+s zum{ECKH6LwA^=gL8RCP3k^NegaFlikAT8NOZt7M6M2v%-rdtGX>ipatv;2^~zYrb9 z_D1<R4AIr`5P<)l@-l@@sNX}y$9Anp{rIt`G<zMg-|<s5FF6VzW2D@7w>1K|zlX5U zTq%Hq`gU^Vb^^Fsv3~X8rKr8IbG(6#04fVV*<~+4b|IZQXuXvH0;HEJwar2HNWQ)i zU?u>)2kZ;2rUE!O@!c=ynW%r8cas^00@%OCt6JMY0K;q!Z4A>z`WX6gZvJEe#28Nt zRn!!KRnc*o)e}(vPX5q-R9OID;vY{S6$P+pn9`N1(E?Btf3dlDgaEi+PFrPV1)wE= z{mr;x0yz5+?8i$A;C=fmH3d;Lt{``!*dPJ4ylZu8>1lx<Gq&D;{JjNcjF6hKM9=~g zj@2zmuWbQ~dzY)ml(xXHWX^l5k1eoi6zl7<j25^*c(5+}c?&4%i*M>pZh<uK8@tZO zw}8Ur<OQRzwE(BiA<^qx3m9G;edyxx7Pz2sKl$!~7C3HaDIXQw0(G<5K`R4Vz;QK) z|6@}NXs)q*<>S}_Ll*2?_tLfn?#>JFZlBiz=JwBC{Dc;0Bvu%f8nnRJ+GXcYYqr3A zGl@*y@hzY}yZv0OYzw&CJ}qq!ZGogYx-LV1Hp6^-b3$Cu3|+>;drB&sfs=KXJdocE z7g`pC4u9JWs$X4Cd!#mllD5Ui%kj<7K6_bj!sTZ8u)Mn}>QpmmNnKoMd!QLIw%ru@ zvb`CGSG(ugdNzaPV(pM<$7V47H999@Ni*1;oE>p-b~AV_KkK()dNbI5t(!M^Vl#{~ zC3F2pH-mo0o)1qYn;}Hcp}XK`6R2tFk9gCB)(dXbr^BC{VA0b8am^1+aQaxKT@<eg z+|?|172R!uqQ*(n1?QXKtG|Uo;o&Bb&d8a30<AL-<HB=PJeyzy`)vO1HBGRiEVlm9 z0+eq0@kdW*Ho<hQmrX~tnjm$@$7wUrI`wvNoN<C!6U+^pf2r$RBlsB(m6fe-gs<<c zw7at#AyjSK$po?ynrEy&Tz|O{4(FTh(Am`pB9+=lZ!T|y$hE8e>~$N#c!~FAL-9uN zxahoXR@oP@>^9Kwd-w&ca<<-15B~xa2HpH@;_w9oBIc_<=zoE9>+2^1M7}`2N7@se zf(97*d*Q2&YYh;-ug>#XU<1sbe_i94MFWJiyN_8bkJj^BaVo5ediWZ3<8}7!dI&4t zIo&<59uyUOjq5q}Kp3txGL@(YwY{mV^;vb`s-fw={8Sxmo6Q*}v8oPET>G)fXM7#x z+Ys}@%4@+Q`9?bXVl8AW)|hv|u@-`g@?0Ip*Mb&nR&GLZ4V+OqyVUn&4Fm;_jXt`l z1~yk`sr8D~faLC_Q*J!1hSbYjgLZgTgU$KrEEnZ!kXgCa*DAXT9{s#@OD?zyj`ZXv zUel@q$z{c_>vAjMYe~EE{cV*{sFbz6W_%@_yQ{n3j$Z-$jTEhl)>gos`g^lxc9#SH zWJaL*v2u7j&(bhKy&QNNG9m$<Wsr~%swuy(6g)bwp4ocpGjtD5K9h2$1a2PMk(++< z6HHd&)h*s#42@HwhdpyH0vo%jKUruWBgR{Lprs`rq`WJe>rZ|JyAY=*cUAJ>$?#?F z<BsHjjZfpIaXDEa{(DHa{gd|~<1O8KW%3({k#$$eKkyvZ+223#?ertSk3Z@=4*y@U z74$qj6m*jP$jJ{hQ?4o`14>XnO2agTN!SWM-Q<Nt?;IzGTy<kV{*g|}`J+9Y|HxOW zoICzy$W>DG!bcs^6ZCU4Vh`m6{E=s#+#Ggs$9;0$jk{MXchb)}DQ}*<;g5W)Y`5P= zV;(uPQ`Bh9q*5w>)&Z%t?7s5-x4vAp;n+(uedFC3GhbKG^3M|v{*m`wy0!GT)O#{t zQDQ>-f@)g6No?aExxV06%+}Di@P20S`tz~$br+Vw=YzQXa##_lb|PbH8q87{v6-8K z>=Tt=@iO#}d|yQE>HB`S;qt{{n(NQd*NDq?J7?hh%VE*k$l%HI&XEbJ+^>m7O;mbr zLiv_I=>t~IaSagXkrs#aGdD*z)A`pf_y3b#`^W7qda+laSo@XTtP3raygb2iAC_mq z#|`$wloW51@vFaQMmf{hu~-Vu0e|E+Q|yPkUOYppPsqM}2>CTAJ*RW$eq27E;{85- z*IoVw;q>q?=}BBZ{7d;Hu0Q!N^(S%r;a}QMV*SCt=#RwuC;vtNB<?@*U;2;4{ZIZ& z|C88$;9u;A#P$dOVt*vIU-%dMC9(a(zt}&C#}E9=_#yH5gMS%+Bp$!;FXNZ|+tdH; zTkF8|RD5duWBY0ySUx4E#{VDrfcjH%YW)9^4`@G~KN|mk<OB3a$*J+5f)IUL2kM`e zqw)VoKA`_-IU4_e<OBMjmZR~H%P${jKeQZ;|3C5p_D9L7@sIN_A85anoEras(hsnI zI)60&|D+!<e(3zs_{Z|Bf#Z)(kH-HW`GE0D$*J*=%jZ+P->2`o>ffLN^T)vS1LvQC z<->sai;`3GS6}^L!2Cz2@7Ml;^Cu<muRj<t|I+#Q)BnKvo6f&q|G|LypO*LQe;BZS z(DHuv0|V9{THeq8V8HrC%lp|c3|RjtIko=b{%M5)>nA1eKYj+Tzm&ZH_#3!>)A{!s zzd$`3k@@ufc7tNfI>1HyMOqfhAa^!{d@&r3_6L-la}?up1_|V^Q{ns?dOah!cNydd zVw{C>D1)3rdR-*=S1|f8$OQ(8VGMFUH!}6P!ytDj#zhQrSeUmlzt!Tt#J|~!!RWyt ze-_4(404+qnEF0rkQ>7w;e*5HVvf$E=yr9{egHw_GRQ}MEEP`dW032Fk&VMgVeF`* z<8hE*OGW40!5GdUe*?xjI9!cEVlc)^+CL$<X$*3Z-%I7g4PlUQW{_`&xf+&>FvzK^ zVdB4Gkhskt|1jph403ESpMg;khYMj|OZ!piS@#(4F~~W|Ah8{XJ7R9hAXgi6d5k}+ z7(G-n$bEx(0)s>h<{?<_hQpU&oQY8lqZEVO&PpcVat4XF7$4y9^9=I$WA2A>Ek-Mh z1`P6*FdxDo@tyWF(E}MUW-`cm${_z5<|nW`1fwU$RaickLH;z%Rk2(KV=o?)%?xrr zG01&`!yjXQ70XXz+=I~%qcelt#S9X&FxSO$77mxj_~-X}lywdK<T!Qogu(aDB8y+= z+31{co8E-lQ}9XN&Se<PLHt;h^O%c}KRvHt^|6JBE5!;uy$ar+X85m-LGih(*WF)q z8zl1IrXCBKhxk<P!7uSpGj_^}D1}8R{tf5W8~0)M$`LvO8C}GGSZ{QF1oz;^p|(8~ zUo$mjbTS109^4%2h@P*>;TI&odI~GlUCru~Q2E@F3Saa)g4LI%s@~8+`SXW`7DVtt zbkGBtm*&*-S*IEwDM^C`{vNj?>`{EqJ&kRXo<o9)YtO}7=(-%?zrYS%2lqa5M(x6L zRDZ`vm%03xuyMM>uDq8M5f2hv5qk|kY8CCjgju8Vo_E_XNQc0A35#=Ao1^@1Z?Zl7 z2Bcf;viFZOK+j8^G*~zDEw~;fOQ#y@p!9d;^rbSOx$<B_%82=h=jV4>y$4P0i_exn zq}rz){$}?FXd5M!{Y`5&N`I<qc1k7~E?Ymb>%Jx8(<SnPvS5(Cta#^F^!&=m#0ekJ z^8#z0%o#pzFVb&oRp5}@*>HK6@DS-J^nBC!oX9xy99WarP#<sx$!(6`S^g;pOrM3T zeltMl(8LMe3ZGmk?Wi)#9*Oi7?=X9hXdZa{`Z@pN84L9M&ruiiPUk^f#vnh#_msY5 zDpzTLg!!iXhr8@X&(q|FZm1$Z!pfarOjZY2A?|l#*W!G5vB6knVmRtgX~8j#%6ym+ zxoeo3HG1ABksVy<QvjblbM@|pPe9Kb)!clLD1<FVZzCRypyz`+#;q_uTnJ@8I?H>b zSg5{k=()N@u;Eo_wdqsTAJV*AtF9M8exj4)>HQRc=a4hC81fHIE(%zI`or<f;VHag z*qu=ssTYXan`NruI`<PeDxH^@_Yk#DI%wFgtWUtolp6Oe9G#O(dp>crFM;17?@pyY zK>eqC^x(*f5~v)#M&$CHDM+r$irMfPgahhN*))$r{o5;5+4LE1hBr@kuSD@%r`>7v zDTRuYhsz~KqU%ze*}3;SOQBnSr1q-&9MnGl^9I|>fOWJe#M_gy$B6UpJ!NptElg+5 z26SD%b?dGhP!25zt?OjhqUW1VTz1HxTMnNjKLpK;n2Ge2X)`jd9O9P9G%is<{lQI8 z7Z<946**$zZ!RPK*3bK#!Kr|>oL!@f-=gaxbNx-$aVucfwsJ8ATlD<a=)<07B>Ek* zgNS?YCiHyZ*!yb)Jr&?nD73fK4B3}7D}5uo61K%@9`zrJ%IB_(RYm6;SLG9Rzr-&< z?U^?2+>v5(X|%QVH(`rZBEIUb=!jyH8<F_wc<<~~^w62`>eEH!w;mIsz;jqC!75um zL%E0yhOzujqfC)pI9%mMA-TKoP$nzIDwW_bCOvfv$x|Y8J=N3aq!N+ABF2vk$T^0y zFMRKqmP*9_GQ2vgfRq~5dZA+iCzasbtc!V<Pihg@KCYZJE0xGvTK{cXK6%Y|UIg(P zmCwmN+FSOKJozLtchNFH`2|jm+5D08t$U)!SDcZGo}jblLT4Unad&=>N4pV9Z?5dP zJCD@cs(;%4Y<UX7kqS?i&Lg#i>nE}|jX?25t9PHvCGCXM%tr>J{JkIk7%@4Q)H|kF zUg;^7O0*soANM4O)W2%tE_TuowJ-Kgn^g{Jed^(Fi6AYMKGL02luhdMubCEDp!UUE z=T39WCa>%{WbkUSGAbX8C4Od+apn@l?c0-3{>2e1BC^PfWkJ@HUz?-!9T6&uS>&u5 zxpZGQHqwXBuA2^-WZIIKtSuu<kp4_0c7=T)`M-MGuX;^K?f3X?bNf9h!8-DEj|<9= zYg!+jn?cS<KUV$zn@B2AzDjZRuXm);L$hI#do&Q={WDhm9hu~&)DW|39?Jje%4X}g zq|z&Au4fdgFL!q3oSkpTLGNuhtQ&{)A3Im#&W&`^c4eE(lLHG-{Zy{7KE5VR;>5FN zZ$j-Mg3}%ezb0Gq?L4@~sDC(*&N@zgMUG3`r7+>^R3zWrduQEC^0~?hF+=f%$Ub^Q z<4(RHJI;H{9ZyB}5vw`j(W~d=YVuTQe2y8aU(TkWu4km`^tsRWFP@o7IQkE2*M3Ht ztg(4kHCGqaZ|1THr!+Eq?4!&1k5PRI^-DFU_++P(wrX_gd?dG9J>)D&+BwH1?KVK= zaaxX@K<6uA!5@Deutn`5R@6KRN+F}t_6=5?hU|^g*?q9-2|0V%ms{`TDE+!wC9X{- zEem22yERb%a${#5&r2e0Z+=ht(Xt4oKYo+F=n?tWbo}6)n|et8CCBpB12V~awag3i zMr2QyPE0bpPmZeEU~DxOwTH7ZGaw~_jM{x(E^#NS54YsUb>nz);<9@U%6iD&xJNn; zd)^^a)@)hK)<pJ6Y%Jh;-6Yitc6?etj_S|Qw4R`Ar2f)-ZQ+InNN%g56MThy@A2}u zg&DFp?({gT(2L~!rDYCMW0AcQtd?nG&yfq;9%v^iQTDV=Z>L!lc|3mb{I7&1;?hz% z>yDC8WxYPR9*t+Bb%E04eWYK_@D&DDs66z<rxy}|q*}v!yC>@?{r<NPvp?YUGW!6| zZ;U+{e_{NIu^VF-#vd5JW9-EE4Pyt!c8qNpzhZ2~h^}8!wd0`cmNcU4l{7YCMAs>4 z{sm(LMs!`04zI&lixFLiq{FK*qU(<|uf$k^5nXqr!_oCd8cQ*L##n+8U1y}_#Te1` zMVd3`a0CZkU!-|HMs!_~=6M*=bw!GE(RD={(e*?cvoNCTi8M#o6KO=(6KTxAh^{Bn z{4K^e7}0e^I{Y=pR~XTCL^}KhMsyvK=Fc#uF-S-={m&nc_lX!e7zvF0VOWllgOR|< zm%?(49E=1;{!lE($iYZp<PX7ej2w&vM!qDLW8`2YF!Cj^93uxKfsrqc<rp~_35<L( zEXT;fNMPiPVmU?*Mgk*W1j{jUFcKK~!dQ-xgOR|<AB^P~IT#6y{6Scbk%N)I$QQzL zj2w&vMt<Kp07eeRzViXfHvaR&-Jxlt47N_Xoe~ntCP-dBX{rGzcIcN!ES5l=?|6X+ zU^sK=@{~8oA0iwt8^+CnuzMO##02C|p@%Ln+&mxhwa%v~IV1m#&>i_E+6J`5?@Vsm zhWuGV+GWs=rNEniW0^)7@}H4Ixx~Q^n&h3M4zwcwi11$f#LOPT^SXa`%uz?2FEvAb zH3WB*?R&Rq1|={5AmIRIcjh?jubGATkH*waM;IrY^l`na72@UH7dASBwSJ_+Tu1bL zej@hVq2hJmsvni)^ji<{*1WI<uAt8gB?m1*{wEQA@gQ$K%<7yv=8yyOhY61GS>27W zDrL96o2xbA@jXeG+@N%vo^PxORo~ddW%8S05BKt(50|wO=O@YTbBC1bu8jSwkUvjk zZC%{u0j3G#cPuxe>bL*nnay7C%v9Frb0YHhh`gE~p5CyHCFHSPiYnj#uI5A^koK7T zZRv01&k@8N#|j@fdSa)m(qKwoc{k3U_J!D;yNuTt%|YDebLmn)AhXLpsvoBE&ni=w z@`uUlt*1jvsPf|z{9pM)jcfLUMTa?5{H5u^0kGB^ybO*}`xEh($}_e=i_G%+8$i{E zEf&(Y1tx{5Mq1ia^_e@S_EsSHh?#Q_Jg3s{|83(M1iG?A)IS|V{waFXVcPhu@N&?@ z7e)knem^14HY(f-$_f*=o4lWkIP27dqubz#%VbNXG&98Wo=u;>9dgdKeVHRc<$vNC zPk09e@}}<BtE24e!N~=@9YFqAE4@OS>i=kVdEida9T$0Cc`v2^*rcs`yI_aPi+ev8 zQ}(1LHo9>aJZay2V7(Yszde(9SAyZJ!V~A+wv_!v9y6H21+7E#9p16E5NDsx_vgY# z(TqbuLn!+grk{|_g+TjEy9u)<A^z*ZVVw{NQkvvv_>9u8k*e3h5J+>)6`Wg7@zxzn z>O)|@h+paB0~BBO%xF$1oHdb_PwqzhNg}dc`BEr^f729?Dzij9UwT+?D5zQtE8HhV z*^Awno>jXcxFRagTn_#2mN1qUJl+kPyX*uV->LdMYO5Nt2fEu7etfj2^!Fp}lkXmo z_aW;HG^qW9&aV8-J#evcyh-Fz<o^@<HS#9!1;ZyluCItyMcjawcVI7=zb)C^^o)`_ zn-$jXg%@qN=O}tp`Y?M?Y90m}xAcQXZ#F@EkbHe?7-T$NZhK}7Wj_P`g^Z(b?`$FG zC%sw~dlC6h#97PC#al>MwS(^6V<~^5{BX{<05WUq`Me{)<{}=kAulF?+!68k_2mgx zh@Z&LGYKGhi7;5yVm{)n8Mzhy<Wh||9|>g^72iI4uRkffz-ULTES26R@V%x#dGpMc zGpb^gf9kHD{@#xa5xQX-zMJxgqSvSS_>miSeSdAZcOv42hRGxR$cR(ZMJ@--L44xr zd&$0Jz!shH6>}yd?tkdY8eg(@!NKQSLaY%_k%<=aB`>F+E*RoH2Jw3J@Hih5z0Fc( z+E1!I9U0rKd`Pdl+|PC5RQ$Zbo0`2z;p@YHUT>rLj(5wCA}*DFmp_H_AInu|PxB_N zdv9e<nM(22(Q6aENcqsAR=m5)h&xK@b$gP+@|R{Om{au=R}nJvBo73PmRze$@vP+^ z4tS8CyLj5#?~y-DMBk0hb|?2NdeGSBP5FB^>W-t`$z$KSGS6a=e^1o&)SNbxH}3Dh zwkTc(aigHx>zl~LRl|g(w2{9{7%howbtAWi-`#a{Jf+|C1x`k8<f<b@x3^hP{$SRI zG2D&hW_Ein$B62WxtFtEZy<LX?k+yoGy!q(-rd7DkRBWI^we)r{ywqYVEKCT_qj(_ zay^tkJ4&JQyeqjg+4{<p>$4Cy%8jUXA=@2Rr$mG<MBL_{fsP9~^7;MiW2RI6#ko}! zu#Su=75=W@K-t5OSKCva$*PCTo-I#B{xsn@Xsn1cS*~-!w|(bG#8<3ITHr*!pT6+r zd0(_&BC-l>PB@ZZ-_Lv%H;hW}UG*W!fxNM0*cUceo08jhTC62Mc04$Ba0XR=yy&R> z)nw{Hk;@sE=>GXO)pZrQ|MSypn@!Pv5<TgCUWYv?uP!c9qD|G$=J3khD@c#ug$8@A zsQm=T&{cLhIqt1>Pwb^BRDOz^F4~f39$3Y=_fYvo&T`XTMusf+8FDj#s!!}CXL1Qy zH*$wZy)mUvKF4m+ViI;(KI6Gi{po19|A{qe^x%U*VLR0y-1RF87m$~>MHHGDQvDk{ zOtI67^fpkLaIlNAf5$2La+YMS@i)om%c=Yw(|7C5CZ{Be$Q@Fq<eZ`j*0adu<XLSq zR46(3c~B9X4AA;AUBx8}U5DX5J1lQV4h|BxtS+P5bMKI~9+`O7dSd2Gv_B)bGL7;Y z<X)pCp9@b=?IC849-%<~);g%aCRc&t13%RLij?2TpTi($HiLvYgWOq|b1*k$kYmCi ze<tR}m>V(3HDr*Oj=2HmQ!&?LkfX~WUk7t-%qKC()nbs)#9RY&bq4ur402R4SH_%$ z`FIAoiVPCtFdu{YXa@NT401+dE|0k!<}wU&r5PlKV=jgHPzL#u400qe7sFhXK|+K< z?qJLZVNPJ)E6?;t4}+Xvn0I5|#USy6L2f7J-!N}ykkiH>zZG)<=FONlF-SBr$Zf#9 z9`jlTIW-LOt1z#`yqrO98G}SA<|UYa!n}w<P9cN*e9S*$p35LNhe0A6^GwV?Fv!nf zkn;}nH<+hm{)$2FO9qJ-m_NfjjX^%iAcu!}3g%B4B%UzHeT;b$<_|G{z#u=7K~4hZ z_b|W9AaRF5?k&u3Vt$=L&NT-4ahPAh{1WCD86;vE<eta;9Oh>j<eX-ZAB}kw<|i5C zo?wtTj`>l{BQd|s*d6~8gB*<9i#R+M+a*TM1%`9aWBEBO$H+O0!_VMwjGWU9=f+@p zG?ruJL}B?U9FCE55{I8)kbfM@F>;P!`B5y7#Bz+>BRKpp4#&tj#Bgo|mLJ4&jGS;R zKY+tAa`xl!eGKx$upA?2FP87Y^4(aDksFG`LvT1o4wvEFU@YH-<rq0Tarh1#j*+vS z;oNOlz7@+ca)Pit5X-kP$ic`Bz~TN35*Rst4Cne{xeu0O<apz7FC31M<H>NY2bQ~I zIY!QAEZ>B~F>>5+_(lf#8?YQBXFZm?Vz~>JW8|*G;m$Z5Bgcv1Tt_T-z;cY7wOGCe zhhyZd#^I|N<gdhXj2wF`UxDSzu^c1U4u{*~aEzQ~4CgMz@+DY~k+T?w+u(4F9BYPi z7h(BAEXT-MfaUYCd>(@wj9e=mK9@lPW8eBe&@brYeDqdvQ~QQ9M5_w5-yvd!h;&n( zl1J{#YpMMa#j{N}eL8r<S&Z7xP|qzXFpYV=)@s2RYQI9n3lpDBFTbDYwnv@X{}3Ao zb1O_Y)PBBTqd}+l7AC4qi)*zsvwzN}<b@(co$25n^~7;q)P9u+5+lBt>dbs`E+UHB z{}FQ~h-TBpTN|DR+@<#WM5`oMU@CHU-Nob(ZHh;Ta=w}_+4K406=Q1uLp&Dax0y=( z93sQpzL4UC1gFC^O#0F3cR#8965%Mx|7PkO`MvCfBDH@dqK6RQO)rW2yEHte<!Vyg zAEtRd6*E2*T2u0jVMMp7Sqf{><I}V}LYn*2^x3Af>braB^5kXtzf8-8x$ku@Q~Ou6 zW9Ixe6>)Sw?)!k&pZG|Auc`83LA|>lbv{AJ4~-?@R)$eprh+KNe-GsdLAW$4U&e!O zzxps@5FC1J>mRyUjgqez&L0FeZf1wKucgb6mgWuy%Pj?lU8nRZd9@5j7<}%!S9E$z zqWB=Wa$!)uqO-}cYYN3(<YPr3M|uG(^)Q`2Z-k>LG<y81ERdk%+bFQaV4Ag(%Y+yS zD*mZad@-on@7vn(6WzyxHeh48;-K|*?gpn=y1Z9oITCQo{K?tz8Fc^pDiV_L>6>3j zZsRN}y_OPR5{`|rT;_I<=9gHGL*T&t3m*?&r~BJig*6mvXL~0)`p8l77pRpFg<oyE z-gFkw`Z7?Dm4Za6rxhZ#bo@LG&M?Sq%v0ENj<%mXO=37`*tCiSzeV>6q8C<9;tz-Q z-wd85tfSlab0kL^e3lQ+_S{bGuZc2+NNEskFlU{2qs~u=&QYz>FiK`c(fng{{_<mN zWWaJ}!m#=!DwN!CY`hG_8hr?v%3eTmr*YD<Aa%pnB4_`6imz34lm&r<i0vCCy1!10 z=gY#gnZe7#E71ET(FR6|B?oz@WnQ(tL-zrq*GedJ<-jL;xt8i++8$L@vgF|6rew*` z)in23)s=@GR)#B8JL&#<t`;c|Ym>*;I?bL(<)^6LDi5vCOebsT(e*Xc;EVvd5aaWc z7SZ;5ZDQ;Q;OcF=^Mpgkm(wCf!olc-ufG%N@v?W4<46cRZfgJsgsA*}P3Dh;*@FAS zWq;H5JyS<o0o1ac(?SVZO3s_&tpFP|C$8GD!j$53^|BP;w&@1Dt{;jNFVNQ=1#;G< zX77K{>9q{FqrlnbsPL>GyQ%iRoK`*xLWbROy|xEkUq`P`Gvthh9jms7?$V<5Ic!Gk zX!spBy0$2p?oWT?*3n?OCcm=h0NsBYY@0EVvEAcofHJM`3X}LTz?IyxI+IW5cM+t= zLR>>`ZLy~?o&PNFvG8lV;XUP#bbV^g_+z1G?5)}h--c51q}i--@X#b6gY}*spGPdX z;~>LL{YINMb-qQo&n+JZ1>d}QJrQ(&_FCyGg4HrL!$*s0-Y`E>5wgw|zhAwVI$t9S z7q%*bu76gPPzi1SAFOT0gJh*f>KjG6{sD_)$HSH11`{}U>G^BRQbGx|?nwFscGLE~ z%hpi|=CkA~9;DLa@8EL25?JKec+NaT*#kFovNQ`C)?5_*l}ojsdr#Yl1#ey*wz_zn zmXkUgS<rfIT9?N=x_@(~M6;kclNBRgLEBTkZaNEYCtQ_{-%HmoN3WFykt$D;E97Y2 zqR&!>lxFVMI5l)VpWqHPK<B~j4zdz;<0<>%>P+J*!<vH~0X1`|^HQ$L^y|vt9<Dn6 zv(PleiFt;F$}sun)$u7u>G2(4B(4JS-<7wjs#c-?=U$p&qyimEL0MZ9sPjH<uJJ|{ za5k4KKF6o+H*aR73Iqt%C{`_@<mk>vz6$7v=a&TTq~-(eY|~a17?i=8_;Wg)J_J~* z(4lcQs^U6bUIb^ZDi};1xrdaZIQPS>AXNxhv{Os?FlGN-dGqV4pvm(!wD+aX%eZT1 z7pj8d;0T@hCiM9BokOUB=$&(KeYuo<aQPOxYB1GAuVwd2dVZFj>!=1BcN`RdVM6!U z2CGOlsQ6NHV^KS$4}zS>SA)F<uCYU&(c`^*e!Uv>R&C$IzDk{6b4?bGng9XzaW;W( zsr8Y2e$m_s@H9kDTk8`w|8NJ{1Wkb5TX{+rZ8{X!UK~3CR?isvV&;g+h!asuvL=B3 zvl%OYxzP3_yo^wXUH0>LC`pM?@%?Od)nWOIr>PAS>Goc?TcHl^OP)0yu%hcbe#L$y zSL6?ukfZH4%KouB4BoRLT|<_tA0fA@ULB<5XSb=WrR`rjXSf2{a#~;W%3HNmB>#|8 zHj*?fao+2ZOr6&e3v<bl<YV&OnF_gy6qm?5GLn2bPH5?sH0pXM@jTCAB$*;%`eIBz z9e>BiDI>`z*N1j}a9K#n4f1<OkQ<&Q$Q6vH&YOrY`I#d~{dh&6;<I`bKVNWR1nJ{6 z=C#cYbBZr6^cq1X6CYY8%$z~-K}9fvl&y0(sC$c+2No%fAPqK5m|ho0m#1DVkS7-& zJ3Djpehw8sx0sYCjc)4o&e~%}@!(HK<Vn330VB=c$x~dj#6g}s^z`l!`=38j5YH}| zB2Ts-KYV$zk})L@`rIo=X6t<1z4n<l#T834<;eDsSiz%@)OiyTUV2ZC6eHX6&J|iw zT)Qk-j(i|zyvD?uI*%bflv&G>s(}uhijL6bdzLH7k#Uh>6DQ4KQSzY`0$Eb~i`}jr z4vG}NUO~!|jf!SFUpUO7xOwFfS#rK|$@K_(x;`b94zi^D@M#5KWi2VWf7KLOvckOk z@IE!VyuzyCvSe$QYD@2(xs=?ax=e;VrQIZ19zyG1sOFvwnP3+q`0PpR=Xg!947u1= zdTpmaU7lL4wG1gEmn8apPaCC=#9Ad8@;R@$%q@dXnglk;yHwd|OwPvxIcM@o~N zw23{!vuJ(V)gO^2PhQQRK1PAIhlF}BY4W}3m)o(+=>D3~0Mev-Ky7zIf)16QY#1(0 z4&G()%g>mOAC^ZBC*KZ}XcoCPkCI1xbQn$^E?pq?-ip?5WPa~3(j=9$TX!UFe~|?j zhLKm*!gP8pe^T|0D1>3;&akOV-X5XPH^Yj`q)6o*ItKEYU6fp__<|H!{%Ft6(EYT0 z{3nniEmbyoNSdPGFQ5wsC1pd&Fs-t*yT`04{;MQ-D5)#Ox@3HT=JlVIhLRV~+|i$Z zfR3M4N)90xJHE&%6rt<?pv++iIpP{CZ^+8oRQglpy^`ec8|Bl5PSEzNRY6LUPs8rD zU5&S(<f4@hlBD>usc$cJ%%^yHWv>Kze4$Q4{w2CUA5~qDAUQvh9C}{S{S{sf668p| zv#U4S)==$PQBx*PKCin}=KYKAANAT`adPkLd5@!l==QbNDv6T?Ik#Vpxi*f<|4|*X z)}V65DI13xQrxIMSd3h7?)8>6qvlY&yIx6*jIoRUJoG7@{&52-N($XK6XkEA>+k!; zL6odpckx?o0$rX~W3LE#YMQ$Es5E-~l{a1xA$_uCyUMcZ^v9Y&gft#=bjjT~dOqPa zmkE<4hcBoN7opCxiKgaYVRG2~W1k0QYfyZ33%YwZB<tq(lg@Pe2MNjsld)}TbM9=R z?dPf>cra<z5NLFC2_4^}RcSD3`NLsT;$%%KePt^-h`c*#Q<GUSt^XZg9R`s@95;(p zhtT#d+tw>YPSEhZHq?x+@71;oLZn2>vJ=T;==O`YI|z|7vah-aS<?M|s=b#Wt5nCk zkr}E~{;ZA*1UWOjbZuc0J-)7Y06|Wl=s2(I1Z}UYzmUDWM{~_m$B&ps#dmD%{mpYM zZG57mN6&Aoo8UKZ@%2RUVI*C@WzE4oyw7aA+2ucJeavnlfAJP(CT=#irN?(Qy33O% zKjQpkjr)VB{L%%%KY5Qgo-BB8OWV)&R<fIC8*}MZdNe&g_I&N_;`vAJ8_cPv%U{t3 zUA$54Cr`#^()Ov=9{htBR(@bzemk9iQ#<*cx3w%=YDzS%-`gF%oxIm#{zD3u(fzye z8+7s-M$a1mPLtM8`8V<#Z(B|Ly3Ff~sQR4f?Cs!f59`X--bY<;A=uxcgJ&70$^{v^ ze&yeT+j&=aY6liI(46~&Y~u|LOxTmQiSEBqUA<p<i>rfr#l|a8>92ReS6*l8el2N9 z>iPg-&>h^$yI$RJP@;P>#l61;3wXOqc(&-Fu@oQG8Qj9ld!GI7bQ0Yj>F>QwywJU8 zdc7ah_Wk2~a3jy-vyt>qJvzUvAH5AcjZ5KIYdz@t$94tR^I~eN&$brR_OP+Lx0W}* zp~YU8PtR|xpTRY}j0-+5vc4!$<)#1Zt>WF;(qOjUl^zeezj`Zq6GkVV(|=93Fa1|= z1@A+g!kk;@>GdtPySI#2;238ztc+eSVt@9Q@ZSBDnPaj;lFE<!tG9?3P$su<KUa+6 zoSxo%Ud-JY)tC9S{kQh?=JJF-bU&SuHl2?DyElusS%EEC8$|a9@w@jOuWh%v&$1=- ze8m0T`<nOkN9EoM7g`^z-rh9cRawhI{sy{zoZj9fp2Nm0sR<%<eYm~7*LXvR9bUTh zAw9pKD*XM7e0<+IFZcztEO$9|_4!uQbq@||S=u}##b&u#nCs+|Oibo?3Doy#Q-9tt z8QBU+?;oGmbUMR!;s%<Yp4<v+#8)ld9qE&@H`ud&gn27?z6l&X?s8;`|K1U~@%F9Y z`XJy+rQacTY3FCn&EBn`&Q7Q-I~tLaekNeloPFrIjC&I2^TM3iyW3yAH9g-7)1351 z1<gIm9)6(9eZ|98kaQ}Ur*k!${oT@c(y@$I@UgBOSu#G7eJMLvzp1JfmTZ5ip<v8m zkInskZ~f0!*q*xRMe~`>DT`OhW(moCg&AjN&yaq3DkVeDou8`p6<)`=-<N;5IHg?s z#@*9qU*Y`pucyf=$5R#`j!TbT`4uE?wIpxigtE6U-pPLK`xOGh3zBC=hNOHs6k*gA z{uMS4kIGh+KAIBn&Z}|N<*!h^(Q5mGRfpMmtA+QJKm7_~ojTLPmd2#qOx~!sFYha` zT`m!xLg(3vMZZ*Rn!m!qr0s*E%Z{exM>y}FDcS}n_RI?jczuX{s$}O;E2TDQjyrK; z*NsrNk#m6OHlsH16?y$=S9}Z`t|nT4Slk9zIy!i^Y2ob8J1Sl0Y;J?122RY>)KGTF zx^ER_d)i>96hs&=IGs{as`TyL`8KeXy>qW#HjEuvRGbz3xD76kG0HEIoRu<UaP`%_ zIc<<P>(esJL6K~`DW*5>HMPNR)sJ(Azx82{NYa!1E!qy%p?W!+I>Oj`g$sUpE4RZA z;ZcX{&W5vlN4g}6v)duge)=9|jpOXE7mhi+v}=cn7K>K5tUj3X?uN19HJ^6mPn(fn zj8CPkFBI{(8_^Ca!ZGYaC(oyRzffcF=~_Efesjv7ULBB9b6xJa_VadluDQnWNALL* z6$9A?S4-RB>G@U}iQ;hfIPPuXIo<8h-euRNniZ9zrSn}`a%2Yt9n&4>*1k3+>bgzQ zH@yys-s({G`E^K&_5mkH@kJew$rT81J2RKPoKS3@wW$NPgu7(VKXI0w#ZG&8DXarp zog*JzPV-}z<`%SSUG4xoUUs|lyBM~H*7T3XWCv85HQkFc-^rHx+!K>n(g9P0Hl=)O zie_J%d~Qo(R|ixrx6hHde<H<fedeX&k>8-@c&gjpEk{y9t<Tv_GWZ6!*$IlgZQPXM z$JV^PviKXEu4xvW-FPUaSmWVzOD`lpt|&D5X$-sPbyS}0p>I&9czRXE$xycDvbmqd zZXvm)g~$T^Q|u%Q`*8I)-{4Z1Tgce?Z1!B`J0ra6zQLMWu5Q=WGi-^HEy)!konTpN zcgC#pc*<T|<M>@_op9;_XII+p<0-7?83q>SouGf<TmXA+M9Kse+fXCtPMA8*exJmn zGbw&I7UbE6bb^cN_t|%i9NEl$n4Mtjk|<~J`AiB~JS0Gt-w8v9^lq>_;F~gKj4L~_ ztP^hTXQSJKH>d15vAAnzZzpsP3!5;Uy+6g@p{YJV={v-1+aG4>8Is~35;ylWe21AI zUEPbWN2a{lU}o3o@EvkJ^p@MJMW(=-QfoKvcbGhKkmTd_(d>OfjehbMzr&Om;g-M= zds6h%bcLGJzQf0bBeNICUSK;f%ADR_`5ks`9r0w)8gI7j7}I4M!aqPO%ELMA|Fm~K z@HLhH|JfgmmR3~sl@=>vbk4cw-h1x7=iak145MKfhK*e|W}E$Cq>QMMZ_S@XMpG)4 zYLz6dQYk7TR4VmdC4Y)<t5nOs=lA}cdoOp#W)yv^pYz&h&wc)XKA-3Fe4fweInOy~ z%DnO>@5e2kbwic*v2^9mYvY!dKee%S*K4{}X-Bt2KRn~3qVhxYVwQZ8R;8``W#^Kr zw;wEDJZknQ8)sK(_7|r7^u~h4>Sv|xI(@UMO1rV=odbS2uuz>7^TJiq)++6ZuMbGW zKFlt+OuTaO(?3*c8TWtvP?OCw)wlWFONKQ4O>2EaV#i4zEiM1%tu19%>u=i2x4$rL z<M7etm-XHBUd-U%G+X5(3#as)P#)j=iwCFQ_M5hC=D(&4X|}X{U4wVCe<=M;llHzp z_m$ka<;9f`PoKNtH|^CQ$Cq`TGDU^Y-F)Q!-?YrQy#?<^6sYcRhTb|V^oS;X*kWk+ zLG#N^9eNyGA{^14wCuhuNm!^3y}|WdQ2!&^m(l<JEc522<%!P=O_ohMqP;!xt#@yK zZ;ATa@k#y1E<2)$$A4}7&XHnu@=rTn8~f%FZCl2^cjbBamOr&)@ZtyeAJL|59x88H ze!n_u&A)GI(D<kpv8OQZ=P#C&AHDLHwGWw&Y7IV~Aq*=VQEngf&A)R79o4=bx9;Wt zj4vtgHtgt+6Q&;3?5h%Pza=rhyhr`zLfIonwT?F>G~RJ+S^4(Ydlt9cd{mpUti$AO z&gp8ymLCs!<Hw^~PRUs9-Q&y3OZv|Id`a_T+UK$Hv)p0R)XCfU@F$~=X^q~#qr%!{ ziQ4mnfgOJseGKy}miH=}r@pYS{(^D$9@Aoy3S-MxjaSo)zuz7H;xX;B?gu`2FDPF< z^5)R~m;C3Lma}wvKgX_rmrt41pht%W$F-8llR8_=OUi$ob!o_5Hy_s~&RjbF*4U-x zcda<OyIJCKt-f{0$AO2YtBdY<=c=y@k8At?bLj5ZTh1+?DSZ~S_wnPJ^uoAw*1AMZ zULEk$^*fGhZ#1hc82ITtb@-B7P4^!=t_|tg?3OK$%q_oZ`Oi(e-grV=*mUx=Hf!!L z|3$ldU&r_p+P#|}FPydP4)u<>jYs=TKB0a2@6dN!eK=43w0Ols¡&2L+Bb?cI4 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 literal 0 HcmV?d00001 diff --git a/msdfgen.h b/msdfgen.h new file mode 100644 index 0000000..7906c61 --- /dev/null +++ b/msdfgen.h @@ -0,0 +1,40 @@ + +#pragma once + +/* + * MULTI-CHANNEL SIGNED DISTANCE FIELD GENERATOR v1.0 (2016-04-24) + * --------------------------------------------------------------- + * A utility by Viktor Chlumsky, (c) 2014 - 2016 + * + * The technique used to generate multi-channel distance fields in this code + * has been developed by Viktor Chlumsky in 2014 for his master's thesis, + * "Shape Decomposition for Multi-Channel Distance Fields". It provides improved + * quality of sharp corners in glyphs and other 2D shapes in comparison to monochrome + * distance fields. To reconstruct an image of the shape, apply the median of three + * operation on the triplet of sampled distance field values. + * + */ + +#include "core/arithmetics.hpp" +#include "core/Vector2.h" +#include "core/Shape.h" +#include "core/Bitmap.h" +#include "core/edge-coloring.h" +#include "core/render-sdf.h" +#include "core/save-bmp.h" +#include "core/shape-description.h" + +#define MSDFGEN_VERSION "1.0" + +namespace msdfgen { + +/// Generates a conventional single-channel signed distance field. +void generateSDF(Bitmap<float> &output, const Shape &shape, double range, const Vector2 &scale, const Vector2 &translate); + +/// Generates a single-channel signed pseudo-distance field. +void generatePseudoSDF(Bitmap<float> &output, const Shape &shape, double range, const Vector2 &scale, const Vector2 &translate); + +/// Generates a multi-channel signed distance field. Edge colors must be assigned first! (see edgeColoringSimple) +void generateMSDF(Bitmap<FloatRGB> &output, const Shape &shape, double range, const Vector2 &scale, const Vector2 &translate, double edgeThreshold = 1.00000001); + +} diff --git a/resource.h b/resource.h new file mode 100644 index 0000000000000000000000000000000000000000..791aa58ad4e1946edc623cfefacf400b9cf2d4c2 GIT binary patch literal 902 zcmb7?-Acni5QWdR;5!6*DYRC6ftd87*hDc+(W_w7Mk2*R)A)n<>gqRHu|L#e874b3 zoIQJHCSRW&b@YzKx>BZ4Jze8*6U7SDCrk8!9qR~eN1h^;%C*p36<%mbZA7h7t$WSL z0-a!<9yHYxzM#J3oKP#N<e+M@DS1I<M$}$=A%)AK$9e-3kxxK6zBYXMFWPjq8ZKk9 z*F02*c!me`6{}0_5bNrcJI1`~I)?eR>D6=>bX23;dVg-ZuBldJ1v6Q2nvxgJxyE`V z&cRk|d`@=>-tl?znSG+6(nh`QqmT9x9bB@7u({i!#{%xZ@7#d(L0jJg-NBOZjdVd} zK)h>S+0WY<cY3--Lnh-%xRVkE#2HF_7*gWxS=zkL{>^MVi7=nn!o9qn&S5rl+t}Xo nF5Pb9LsVP8`&4_d9>(n^X}j3ZYx7zCLoK#%8?(*1>2K!WqosWS literal 0 HcmV?d00001