From: Behdad Esfahbod Date: Fri, 31 Mar 2006 12:28:09 +0000 (+0000) Subject: Convert pango/opentype to the new project called HarfBuzz. X-Git-Tag: submit/2.0alpha-wayland/20121130.004132~9^2~1342 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=9f8da38cd108590514b71756b752d98952a9221f;p=profile%2Fivi%2Forg.tizen.video-player.git Convert pango/opentype to the new project called HarfBuzz. 2006-03-31 Behdad Esfahbod Convert pango/opentype to the new project called HarfBuzz. * pango/opentype/*: Restructured. * pango/pango-ot-*: Updated to use HarfBuzz symbol names. --- diff --git a/src/COPYING b/src/COPYING new file mode 100644 index 0000000..cde9101 --- /dev/null +++ b/src/COPYING @@ -0,0 +1,15 @@ +HarfBuzz is distributed under two mutually exclusive open-source licenses. +This means that *you* must choose *one* of the two licenses described +below, then obey all its terms and conditions when using HarfBuzz in +any of your projects or products. + + - The FreeType License, found in the file `COPYING.FTL', which is similar to + the original BSD license *with* an advertising clause that forces you to + explicitly cite the FreeType project in your product's documentation. + All details are in the license file. This license is suited to + products which don't use the GNU General Public License. + + - The GNU General Public License version 2, found in `COPYING.GPL' (any + later version can be used also), for programs which already use the GPL. + Note that the FTL is incompatible with the GPL due to its + advertisement clause. diff --git a/src/FTL.TXT b/src/COPYING.FTL similarity index 100% rename from src/FTL.TXT rename to src/COPYING.FTL diff --git a/src/COPYING.GPL b/src/COPYING.GPL new file mode 100644 index 0000000..14db8fc --- /dev/null +++ b/src/COPYING.GPL @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) 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 +this service 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 make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. 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. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the 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 a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE 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. + + 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 +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + 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 2 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, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision 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, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This 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 Library General +Public License instead of this License. diff --git a/src/FT-license.txt b/src/FT-license.txt deleted file mode 100644 index 102a03d..0000000 --- a/src/FT-license.txt +++ /dev/null @@ -1,28 +0,0 @@ - -The FreeType 2 font engine is copyrighted work and cannot be used -legally without a software license. In order to make this project -usable to a vast majority of developers, we distribute it under two -mutually exclusive open-source licenses. - -This means that *you* must choose *one* of the two licenses described -below, then obey all its terms and conditions when using FreeType 2 in -any of your projects or products. - - - The FreeType License, found in the file `FTL.TXT', which is similar - to the original BSD license *with* an advertising clause that forces - you to explicitly cite the FreeType project in your product's - documentation. All details are in the license file. This license - is suited to products which don't use the GNU General Public - License. - - - The GNU General Public License version 2, found in `GPL.TXT' (any - later version can be used also), for programs which already use the - GPL. Note that the FTL is incompatible with the GPL due to its - advertisement clause. - -The contributed PCF driver comes with a license similar to that of the X -Window System. It is compatible to the above two licenses (see file -src/pcf/readme). - - ---- end of LICENSE.TXT --- diff --git a/src/Makefile.am b/src/Makefile.am index 7c0ba69..8d65294 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,51 +1,58 @@ ## Process this file with automake to produce Makefile.in INCLUDES = \ - -DSYSCONFDIR=\"$(sysconfdir)\" \ - -DLIBDIR=\"$(libdir)\" \ - $(PANGO_DEBUG_FLAGS) \ - -I$(top_srcdir) \ - $(GLIB_CFLAGS) \ $(FREETYPE_CFLAGS) -noinst_LTLIBRARIES = libmini-harfbuzz.la - -libmini_harfbuzz_la_SOURCES = \ - ftglue.h \ - ftglue.c \ - ftxopen.c \ - ftxopen.h \ - ftxopenf.h \ - ftxgdef.c \ - ftxgdef.h \ - ftxgpos.c \ - ftxgpos.h \ - ftxgsub.c \ - ftxgsub.h \ - otlbuffer.c \ - otlbuffer.h - -libmini_harfbuzz_la_LIBADD = \ - $(x_ldflags) \ - $(x_libs) \ - $(GLIB_LIBS) \ - -lm - -if BUILD_OT_TESTS -noinst_PROGRAMS = ottest -endif - -ottest_SOURCES = \ - ottest.c \ - disasm.c \ - disasm.h - -ottest_LDADD = \ - libmini-harfbuzz.la \ +noinst_LTLIBRARIES = libharfbuzz-1.la + +SOURCES = \ + ftglue.c \ + harfbuzz-buffer.c \ + harfbuzz-dump.c \ + harfbuzz-gdef.c \ + harfbuzz-gpos.c \ + harfbuzz-gsub.c \ + harfbuzz-open.c + +EXTRA_SOURCES = harfbuzz.c + +PUBLICHEADERS = \ + harfbuzz.h \ + harfbuzz-buffer.h \ + harfbuzz-dump.h \ + harfbuzz-gdef.h \ + harfbuzz-gpos.h \ + harfbuzz-gsub.h \ + harfbuzz-open.h + +PRIVATEHEADERS = \ + ftglue.h \ + harfbuzz-impl.h \ + harfbuzz-gdef-private.h \ + harfbuzz-gpos-private.h \ + harfbuzz-gsub-private.h \ + harfbuzz-open-private.h + +libharfbuzz_1_la_SOURCES = \ + $(SOURCES) \ + $(PUBLICHEADERS) \ + $(PRIVATEHEADERS) + +libharfbuzz_1_la_LIBADD = \ $(FREETYPE_LIBS) +noinst_PROGRAMS = harfbuzz-dump + +harfbuzz_dump_SOURCES = \ + harfbuzz-dump-main.c + +harfbuzz_dump_LDADD = \ + libharfbuzz-1.la + EXTRA_DIST = \ README \ - FTL.TXT \ - FT-license.txt + COPYING.FTL \ + COPYING.GPL \ + COPYING \ + $(EXTRA_SOURCES) diff --git a/src/README b/src/README index 2003564..f7746ef 100644 --- a/src/README +++ b/src/README @@ -1,36 +1,18 @@ -This directory includes code for using OpenType Layout tables from -OpenType fonts with FreeType and +This is HarfBuzz, an OpenType Layout engine. -The table reading code in: +It was derived originally from the OpenType code in FreeType-1.x, ported to +FreeType2. (This code has been abandoned for FreeType2, but until something +better comes along, should serve our purposes.) In addition to porting to +FreeType-2, it has been modified in various other ways. - ftxopen.[ch] - ftxopenf.h - ftxgdef.[ch] - ftxgpos.[ch] - ftxgdef.[ch] +It also includes a partial XML dumper for OpenType Layout tables useful for +figuring out what is going on. Please extend to cover additional parts of the +tables as you encounter fonts using them. The dumper is written by Owen Taylor. -Is derived from the OpenType code in FreeType-1.x, ported to FreeType2. -(This code has been abandoned for FreeType2, but until something better -comes along, should serve our purposes.) +Bug reports on these files should be sent to the HarfBuzz mailing list as +listed on http://freedesktop.org/wiki/Software/harfbuzz -This code should be left following the FreeType indentation style and -coding conventions. +For license information, see the file COPYING. -In addition to porting to FreeType-2, it has been modified to -add support for PangoGlyphString's log_clusters, and in various -other ways. Bug reports on these files should be sent to -gtk-i18n-list@gtk.org, NOT to the freetype maintainers. - -The license for these files is in the file FT-license.txt. - - -Most of the additional files in this directory implement a high-level -interface to this that follows Pango conventions and integrates with -Pango. - -disasm.[ch] is a partial dumper for OpenType layout tables useful -in figuring out what is going on. Please extend to cover additional -parts of the tables as you encounter fonts using them. - -Owen Taylor -17 December 2000 +Behdad Esfahbod +April 1st, 2006 diff --git a/src/ftglue.c b/src/ftglue.c index b3fd5b2..5bb7274 100644 --- a/src/ftglue.c +++ b/src/ftglue.c @@ -8,15 +8,14 @@ * See ftglue.h for more information. */ -#include #include "ftglue.h" #if 0 #include -#define LOG(x) ftglue_log x +#define LOG(x) _hb_ftglue_log x static void -ftglue_log( const char* format, ... ) +_hb_ftglue_log( const char* format, ... ) { va_list ap; @@ -31,7 +30,7 @@ ftglue_log( const char* format, ... ) /* only used internally */ static FT_Pointer -ftglue_qalloc( FT_Memory memory, +_hb_ftglue_qalloc( FT_Memory memory, FT_ULong size, FT_Error *perror ) { @@ -50,11 +49,11 @@ ftglue_qalloc( FT_Memory memory, } #undef QALLOC /* just in case */ -#define QALLOC(ptr,size) ( (ptr) = ftglue_qalloc( memory, (size), &error ), error != 0 ) +#define QALLOC(ptr,size) ( (ptr) = _hb_ftglue_qalloc( memory, (size), &error ), error != 0 ) FTGLUE_APIDEF( FT_Pointer ) -ftglue_alloc( FT_Memory memory, +_hb_ftglue_alloc( FT_Memory memory, FT_ULong size, FT_Error *perror ) { @@ -76,7 +75,7 @@ ftglue_alloc( FT_Memory memory, FTGLUE_APIDEF( FT_Pointer ) -ftglue_realloc( FT_Memory memory, +_hb_ftglue_realloc( FT_Memory memory, FT_Pointer block, FT_ULong old_size, FT_ULong new_size, @@ -87,11 +86,11 @@ ftglue_realloc( FT_Memory memory, if ( old_size == 0 || block == NULL ) { - block2 = ftglue_alloc( memory, new_size, &error ); + block2 = _hb_ftglue_alloc( memory, new_size, &error ); } else if ( new_size == 0 ) { - ftglue_free( memory, block ); + _hb_ftglue_free( memory, block ); } else { @@ -111,7 +110,7 @@ ftglue_realloc( FT_Memory memory, FTGLUE_APIDEF( void ) -ftglue_free( FT_Memory memory, +_hb_ftglue_free( FT_Memory memory, FT_Pointer block ) { if ( block ) @@ -120,7 +119,7 @@ ftglue_free( FT_Memory memory, FTGLUE_APIDEF( FT_Long ) -ftglue_stream_pos( FT_Stream stream ) +_hb_ftglue_stream_pos( FT_Stream stream ) { LOG(( "ftglue:stream:pos() -> %ld\n", stream->pos )); return stream->pos; @@ -128,7 +127,7 @@ ftglue_stream_pos( FT_Stream stream ) FTGLUE_APIDEF( FT_Error ) -ftglue_stream_seek( FT_Stream stream, +_hb_ftglue_stream_seek( FT_Stream stream, FT_Long pos ) { FT_Error error = 0; @@ -136,7 +135,7 @@ ftglue_stream_seek( FT_Stream stream, stream->pos = pos; if ( stream->read ) { - if ( stream->read( stream, pos, 0, 0 ) ) + if ( stream->read( stream, pos, NULL, 0 ) ) error = FT_Err_Invalid_Stream_Operation; } else if ( pos > (FT_Long)stream->size ) @@ -148,7 +147,7 @@ ftglue_stream_seek( FT_Stream stream, FTGLUE_APIDEF( FT_Error ) -ftglue_stream_frame_enter( FT_Stream stream, +_hb_ftglue_stream_frame_enter( FT_Stream stream, FT_ULong count ) { FT_Error error = FT_Err_Ok; @@ -198,7 +197,7 @@ Exit: FTGLUE_APIDEF( void ) -ftglue_stream_frame_exit( FT_Stream stream ) +_hb_ftglue_stream_frame_exit( FT_Stream stream ) { if ( stream->read ) { @@ -206,68 +205,21 @@ ftglue_stream_frame_exit( FT_Stream stream ) FREE( stream->base ); } - stream->cursor = 0; - stream->limit = 0; + stream->cursor = NULL; + stream->limit = NULL; LOG(( "ftglue:stream:frame_exit()\n" )); } -FTGLUE_APIDEF( FT_Byte ) -ftglue_stream_get_byte( FT_Stream stream ) -{ - FT_Byte result = 0; - - if ( stream->cursor < stream->limit ) - result = *stream->cursor++; - - return result; -} - - -FTGLUE_APIDEF( FT_Short ) -ftglue_stream_get_short( FT_Stream stream ) -{ - FT_Byte* p; - FT_Short result = 0; - - p = stream->cursor; - if ( p + 2 <= stream->limit ) - { - result = (FT_Short)((p[0] << 8) | p[1]); - stream->cursor = p+2; - } - return result; -} - - -FTGLUE_APIDEF( FT_Long ) -ftglue_stream_get_long( FT_Stream stream ) -{ - FT_Byte* p; - FT_Long result = 0; - - p = stream->cursor; - if ( p + 4 <= stream->limit ) - { - result = (FT_Long)(((FT_Long)p[0] << 24) | - ((FT_Long)p[1] << 16) | - ((FT_Long)p[2] << 8) | - p[3] ); - stream->cursor = p+4; - } - return result; -} - - FTGLUE_APIDEF( FT_Error ) -ftglue_face_goto_table( FT_Face face, +_hb_ftglue_face_goto_table( FT_Face face, FT_ULong the_tag, FT_Stream stream ) { FT_Error error; - LOG(( "ftglue_face_goto_table( %p, %c%c%c%c, %p )\n", + LOG(( "_hb_ftglue_face_goto_table( %p, %c%c%c%c, %p )\n", face, (int)((the_tag >> 24) & 0xFF), (int)((the_tag >> 16) & 0xFF), @@ -331,11 +283,11 @@ ftglue_face_goto_table( FT_Face face, if ( tag == the_tag ) { LOG(( "TrueType table (start: %ld) (size: %ld)\n", start, size )); - error = ftglue_stream_seek( stream, offset+start ); + error = _hb_ftglue_stream_seek( stream, offset+start ); goto FoundIt; } } - error = TT_Err_Table_Missing; + error = FT_Err_Table_Missing; FoundIt: FORGET_Frame(); diff --git a/src/ftglue.h b/src/ftglue.h index 57c5ebe..84de7f3 100644 --- a/src/ftglue.h +++ b/src/ftglue.h @@ -1,4 +1,4 @@ -/* ftglue.c: Glue code for compiling the OpenType code from +/* ftglue.h: Glue code for compiling the OpenType code from * FreeType 1 using only the public API of FreeType 2 * * By David Turner, The FreeType Project (www.freetype.org) @@ -40,8 +40,8 @@ * * PS: This "glue" code is explicitely put in the public domain */ -#ifndef __OPENTYPE_FTGLUE_H__ -#define __OPENTYPE_FTGLUE_H__ +#ifndef FTGLUE_H +#define FTGLUE_H #include #include FT_FREETYPE_H @@ -50,10 +50,6 @@ FT_BEGIN_HEADER /* utility macros */ -#define TT_Err_Ok FT_Err_Ok -#define TT_Err_Invalid_Argument FT_Err_Invalid_Argument -#define TT_Err_Invalid_Face_Handle FT_Err_Invalid_Face_Handle -#define TT_Err_Table_Missing FT_Err_Table_Missing #define SET_ERR(c) ( (error = (c)) != 0 ) @@ -66,14 +62,23 @@ FT_BEGIN_HEADER #endif /* stream macros used by the OpenType parser */ -#define FILE_Pos() ftglue_stream_pos( stream ) -#define FILE_Seek(pos) SET_ERR( ftglue_stream_seek( stream, pos ) ) -#define ACCESS_Frame(size) SET_ERR( ftglue_stream_frame_enter( stream, size ) ) -#define FORGET_Frame() ftglue_stream_frame_exit( stream ) +#define FILE_Pos() _hb_ftglue_stream_pos( stream ) +#define FILE_Seek(pos) SET_ERR( _hb_ftglue_stream_seek( stream, pos ) ) +#define ACCESS_Frame(size) SET_ERR( _hb_ftglue_stream_frame_enter( stream, size ) ) +#define FORGET_Frame() _hb_ftglue_stream_frame_exit( stream ) + +#define GET_Byte() (*stream->cursor++) +#define GET_Short() (stream->cursor += 2, (FT_Short)( \ + (*(((FT_Byte*)stream->cursor)-2) << 8) | \ + *(((FT_Byte*)stream->cursor)-1) \ + )) +#define GET_Long() (stream->cursor += 4, (FT_Long)( \ + (*(((FT_Byte*)stream->cursor)-4) << 24) | \ + (*(((FT_Byte*)stream->cursor)-3) << 16) | \ + (*(((FT_Byte*)stream->cursor)-2) << 8) | \ + *(((FT_Byte*)stream->cursor)-1) \ + )) -#define GET_Byte() ftglue_stream_get_byte( stream ) -#define GET_Short() ftglue_stream_get_short( stream ) -#define GET_Long() ftglue_stream_get_long( stream ) #define GET_Char() ((FT_Char)GET_Byte()) #define GET_UShort() ((FT_UShort)GET_Short()) @@ -81,45 +86,36 @@ FT_BEGIN_HEADER #define GET_Tag4() GET_ULong() FTGLUE_API( FT_Long ) -ftglue_stream_pos( FT_Stream stream ); +_hb_ftglue_stream_pos( FT_Stream stream ); FTGLUE_API( FT_Error ) -ftglue_stream_seek( FT_Stream stream, +_hb_ftglue_stream_seek( FT_Stream stream, FT_Long pos ); FTGLUE_API( FT_Error ) -ftglue_stream_frame_enter( FT_Stream stream, +_hb_ftglue_stream_frame_enter( FT_Stream stream, FT_ULong size ); FTGLUE_API( void ) -ftglue_stream_frame_exit( FT_Stream stream ); - -FTGLUE_API( FT_Byte ) -ftglue_stream_get_byte( FT_Stream stream ); - -FTGLUE_API( FT_Short ) -ftglue_stream_get_short( FT_Stream stream ); - -FTGLUE_API( FT_Long ) -ftglue_stream_get_long( FT_Stream stream ); +_hb_ftglue_stream_frame_exit( FT_Stream stream ); FTGLUE_API( FT_Error ) -ftglue_face_goto_table( FT_Face face, +_hb_ftglue_face_goto_table( FT_Face face, FT_ULong tag, FT_Stream stream ); /* memory macros used by the OpenType parser */ #define ALLOC(_ptr,_size) \ - ( (_ptr) = ftglue_alloc( memory, _size, &error ), error != 0 ) + ( (_ptr) = _hb_ftglue_alloc( memory, _size, &error ), error != 0 ) #define REALLOC(_ptr,_oldsz,_newsz) \ - ( (_ptr) = ftglue_realloc( memory, (_ptr), (_oldsz), (_newsz), &error ), error != 0 ) + ( (_ptr) = _hb_ftglue_realloc( memory, (_ptr), (_oldsz), (_newsz), &error ), error != 0 ) #define FREE(_ptr) \ do { \ if ( (_ptr) ) \ { \ - ftglue_free( memory, _ptr ); \ + _hb_ftglue_free( memory, _ptr ); \ _ptr = NULL; \ } \ } while (0) @@ -134,23 +130,21 @@ ftglue_face_goto_table( FT_Face face, FTGLUE_API( FT_Pointer ) -ftglue_alloc( FT_Memory memory, +_hb_ftglue_alloc( FT_Memory memory, FT_ULong size, FT_Error *perror_ ); FTGLUE_API( FT_Pointer ) -ftglue_realloc( FT_Memory memory, +_hb_ftglue_realloc( FT_Memory memory, FT_Pointer block, FT_ULong old_size, FT_ULong new_size, FT_Error *perror_ ); FTGLUE_API( void ) -ftglue_free( FT_Memory memory, +_hb_ftglue_free( FT_Memory memory, FT_Pointer block ); -/* */ - FT_END_HEADER -#endif /* __OPENTYPE_FTGLUE_H__ */ +#endif /* FTGLUE_H */ diff --git a/src/ftxgdef.c b/src/ftxgdef.c deleted file mode 100644 index 8701b32..0000000 --- a/src/ftxgdef.c +++ /dev/null @@ -1,1225 +0,0 @@ -/******************************************************************* - * - * ftxgdef.c - * - * TrueType Open GDEF table support. - * - * Copyright 1996-2000 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. - * - ******************************************************************/ - -#include -#include "ftxopen.h" -#include "ftxopenf.h" - -#include "ftglue.h" - -#include FT_TRUETYPE_TAGS_H - -#define TTAG_GDEF FT_MAKE_TAG( 'G', 'D', 'E', 'F' ) - - static FT_Error Load_AttachList( TTO_AttachList* al, - FT_Stream stream ); - static FT_Error Load_LigCaretList( TTO_LigCaretList* lcl, - FT_Stream stream ); - - static void Free_AttachList( TTO_AttachList* al, - FT_Memory memory ); - static void Free_LigCaretList( TTO_LigCaretList* lcl, - FT_Memory memory ); - - static void Free_NewGlyphClasses( TTO_GDEFHeader* gdef, - FT_Memory memory ); - - - - /********************** - * Extension Functions - **********************/ - -#if 0 -#define GDEF_ID Build_Extension_ID( 'G', 'D', 'E', 'F' ) - - - static FT_Error GDEF_Create( void* ext, - PFace face ) - { - DEFINE_LOAD_LOCALS( face->stream ); - - TTO_GDEFHeader* gdef = (TTO_GDEFHeader*)ext; - Long table; - - - /* by convention */ - - if ( !gdef ) - return TT_Err_Ok; - - /* a null offset indicates that there is no GDEF table */ - - gdef->offset = 0; - - /* we store the start offset and the size of the subtable */ - - table = TT_LookUp_Table( face, TTAG_GDEF ); - if ( table < 0 ) - return TT_Err_Ok; /* The table is optional */ - - if ( FILE_Seek( face->dirTables[table].Offset ) || - ACCESS_Frame( 4L ) ) - return error; - - gdef->offset = FILE_Pos() - 4L; /* undo ACCESS_Frame() */ - gdef->Version = GET_ULong(); - - FORGET_Frame(); - - gdef->loaded = FALSE; - - return TT_Err_Ok; - } - - - static FT_Error GDEF_Destroy( void* ext, - PFace face ) - { - TTO_GDEFHeader* gdef = (TTO_GDEFHeader*)ext; - - - /* by convention */ - - if ( !gdef ) - return TT_Err_Ok; - - if ( gdef->loaded ) - { - Free_LigCaretList( &gdef->LigCaretList, memory ); - Free_AttachList( &gdef->AttachList, memory ); - Free_ClassDefinition( &gdef->GlyphClassDef, memory ); - Free_ClassDefinition( &gdef->MarkAttachClassDef, memory ); - - Free_NewGlyphClasses( gdef, memory ); - } - - return TT_Err_Ok; - } - - - EXPORT_FUNC - FT_Error TT_Init_GDEF_Extension( TT_Engine engine ) - { - PEngine_Instance _engine = HANDLE_Engine( engine ); - - - if ( !_engine ) - return TT_Err_Invalid_Engine; - - return TT_Register_Extension( _engine, - GDEF_ID, - sizeof ( TTO_GDEFHeader ), - GDEF_Create, - GDEF_Destroy ); - } -#endif - - EXPORT_FUNC - FT_Error TT_New_GDEF_Table( FT_Face face, - TTO_GDEFHeader** retptr ) - { - FT_Error error; - FT_Memory memory = face->memory; - - TTO_GDEFHeader* gdef; - - if ( !retptr ) - return TT_Err_Invalid_Argument; - - if ( ALLOC( gdef, sizeof( *gdef ) ) ) - return error; - - gdef->memory = face->memory; - - gdef->GlyphClassDef.loaded = FALSE; - gdef->AttachList.loaded = FALSE; - gdef->LigCaretList.loaded = FALSE; - gdef->MarkAttachClassDef_offset = 0; - gdef->MarkAttachClassDef.loaded = FALSE; - - gdef->LastGlyph = 0; - gdef->NewGlyphClasses = NULL; - - *retptr = gdef; - - return TT_Err_Ok; - } - - EXPORT_FUNC - FT_Error TT_Load_GDEF_Table( FT_Face face, - TTO_GDEFHeader** retptr ) - { - FT_Error error; - FT_Memory memory = face->memory; - FT_Stream stream = face->stream; - FT_ULong cur_offset, new_offset, base_offset; - - TTO_GDEFHeader* gdef; - - - if ( !retptr ) - return TT_Err_Invalid_Argument; - - if (( error = ftglue_face_goto_table( face, TTAG_GDEF, stream ) )) - return error; - - if (( error = TT_New_GDEF_Table ( face, &gdef ) )) - return error; - - base_offset = FILE_Pos(); - - /* skip version */ - - if ( FILE_Seek( base_offset + 4L ) || - ACCESS_Frame( 2L ) ) - goto Fail0; - - new_offset = GET_UShort(); - - FORGET_Frame(); - - /* all GDEF subtables are optional */ - - if ( new_offset ) - { - new_offset += base_offset; - - /* only classes 1-4 are allowed here */ - - cur_offset = FILE_Pos(); - if ( FILE_Seek( new_offset ) || - ( error = Load_ClassDefinition( &gdef->GlyphClassDef, 5, - stream ) ) != TT_Err_Ok ) - goto Fail0; - (void)FILE_Seek( cur_offset ); - } - - if ( ACCESS_Frame( 2L ) ) - goto Fail1; - - new_offset = GET_UShort(); - - FORGET_Frame(); - - if ( new_offset ) - { - new_offset += base_offset; - - cur_offset = FILE_Pos(); - if ( FILE_Seek( new_offset ) || - ( error = Load_AttachList( &gdef->AttachList, - stream ) ) != TT_Err_Ok ) - goto Fail1; - (void)FILE_Seek( cur_offset ); - } - - if ( ACCESS_Frame( 2L ) ) - goto Fail2; - - new_offset = GET_UShort(); - - FORGET_Frame(); - - if ( new_offset ) - { - new_offset += base_offset; - - cur_offset = FILE_Pos(); - if ( FILE_Seek( new_offset ) || - ( error = Load_LigCaretList( &gdef->LigCaretList, - stream ) ) != TT_Err_Ok ) - goto Fail2; - (void)FILE_Seek( cur_offset ); - } - - /* OpenType 1.2 has introduced the `MarkAttachClassDef' field. We - first have to scan the LookupFlag values to find out whether we - must load it or not. Here we only store the offset of the table. */ - - if ( ACCESS_Frame( 2L ) ) - goto Fail3; - - new_offset = GET_UShort(); - - FORGET_Frame(); - - if ( new_offset ) - gdef->MarkAttachClassDef_offset = new_offset + base_offset; - else - gdef->MarkAttachClassDef_offset = 0; - - *retptr = gdef; - - return TT_Err_Ok; - - Fail3: - Free_LigCaretList( &gdef->LigCaretList, memory ); - - Fail2: - Free_AttachList( &gdef->AttachList, memory ); - - Fail1: - Free_ClassDefinition( &gdef->GlyphClassDef, memory ); - - Fail0: - FREE( gdef ); - - return error; - } - - EXPORT_FUNC - FT_Error TT_Done_GDEF_Table ( TTO_GDEFHeader* gdef ) - { - FT_Memory memory = gdef->memory; - - Free_LigCaretList( &gdef->LigCaretList, memory ); - Free_AttachList( &gdef->AttachList, memory ); - Free_ClassDefinition( &gdef->GlyphClassDef, memory ); - Free_ClassDefinition( &gdef->MarkAttachClassDef, memory ); - - Free_NewGlyphClasses( gdef, memory ); - - FREE( gdef ); - - return TT_Err_Ok; - } - - - - - /******************************* - * AttachList related functions - *******************************/ - - - /* AttachPoint */ - - static FT_Error Load_AttachPoint( TTO_AttachPoint* ap, - FT_Stream stream ) - { - FT_Memory memory = stream->memory; - FT_Error error; - - FT_UShort n, count; - FT_UShort* pi; - - - if ( ACCESS_Frame( 2L ) ) - return error; - - count = ap->PointCount = GET_UShort(); - - FORGET_Frame(); - - ap->PointIndex = NULL; - - if ( count ) - { - if ( ALLOC_ARRAY( ap->PointIndex, count, FT_UShort ) ) - return error; - - pi = ap->PointIndex; - - if ( ACCESS_Frame( count * 2L ) ) - { - FREE( pi ); - return error; - } - - for ( n = 0; n < count; n++ ) - pi[n] = GET_UShort(); - - FORGET_Frame(); - } - - return TT_Err_Ok; - } - - - static void Free_AttachPoint( TTO_AttachPoint* ap, - FT_Memory memory ) - { - FREE( ap->PointIndex ); - } - - - /* AttachList */ - - static FT_Error Load_AttachList( TTO_AttachList* al, - FT_Stream stream ) - { - FT_Memory memory = stream->memory; - FT_Error error; - - FT_UShort n, m, count; - FT_ULong cur_offset, new_offset, base_offset; - - TTO_AttachPoint* ap; - - - base_offset = FILE_Pos(); - - if ( ACCESS_Frame( 2L ) ) - return error; - - new_offset = GET_UShort() + base_offset; - - FORGET_Frame(); - - cur_offset = FILE_Pos(); - if ( FILE_Seek( new_offset ) || - ( error = Load_Coverage( &al->Coverage, stream ) ) != TT_Err_Ok ) - return error; - (void)FILE_Seek( cur_offset ); - - if ( ACCESS_Frame( 2L ) ) - goto Fail2; - - count = al->GlyphCount = GET_UShort(); - - FORGET_Frame(); - - al->AttachPoint = NULL; - - if ( ALLOC_ARRAY( al->AttachPoint, count, TTO_AttachPoint ) ) - goto Fail2; - - ap = al->AttachPoint; - - for ( n = 0; n < count; n++ ) - { - if ( ACCESS_Frame( 2L ) ) - goto Fail1; - - new_offset = GET_UShort() + base_offset; - - FORGET_Frame(); - - cur_offset = FILE_Pos(); - if ( FILE_Seek( new_offset ) || - ( error = Load_AttachPoint( &ap[n], stream ) ) != TT_Err_Ok ) - goto Fail1; - (void)FILE_Seek( cur_offset ); - } - - al->loaded = TRUE; - - return TT_Err_Ok; - - Fail1: - for ( m = 0; m < n; m++ ) - Free_AttachPoint( &ap[m], memory ); - - FREE( ap ); - - Fail2: - Free_Coverage( &al->Coverage, memory ); - return error; - } - - - static void Free_AttachList( TTO_AttachList* al, - FT_Memory memory ) - { - FT_UShort n, count; - - TTO_AttachPoint* ap; - - - if ( !al->loaded ) - return; - - if ( al->AttachPoint ) - { - count = al->GlyphCount; - ap = al->AttachPoint; - - for ( n = 0; n < count; n++ ) - Free_AttachPoint( &ap[n], memory ); - - FREE( ap ); - } - - Free_Coverage( &al->Coverage, memory ); - } - - - - /********************************* - * LigCaretList related functions - *********************************/ - - - /* CaretValueFormat1 */ - /* CaretValueFormat2 */ - /* CaretValueFormat3 */ - /* CaretValueFormat4 */ - - static FT_Error Load_CaretValue( TTO_CaretValue* cv, - FT_Stream stream ) - { - FT_Error error; - - FT_ULong cur_offset, new_offset, base_offset; - - - base_offset = FILE_Pos(); - - if ( ACCESS_Frame( 2L ) ) - return error; - - cv->CaretValueFormat = GET_UShort(); - - FORGET_Frame(); - - switch ( cv->CaretValueFormat ) - { - case 1: - if ( ACCESS_Frame( 2L ) ) - return error; - - cv->cvf.cvf1.Coordinate = GET_Short(); - - FORGET_Frame(); - - break; - - case 2: - if ( ACCESS_Frame( 2L ) ) - return error; - - cv->cvf.cvf2.CaretValuePoint = GET_UShort(); - - FORGET_Frame(); - - break; - - case 3: - if ( ACCESS_Frame( 4L ) ) - return error; - - cv->cvf.cvf3.Coordinate = GET_Short(); - - new_offset = GET_UShort() + base_offset; - - FORGET_Frame(); - - cur_offset = FILE_Pos(); - if ( FILE_Seek( new_offset ) || - ( error = Load_Device( &cv->cvf.cvf3.Device, - stream ) ) != TT_Err_Ok ) - return error; - (void)FILE_Seek( cur_offset ); - - break; - - case 4: - if ( ACCESS_Frame( 2L ) ) - return error; - - cv->cvf.cvf4.IdCaretValue = GET_UShort(); - - FORGET_Frame(); - break; - - default: - return TTO_Err_Invalid_GDEF_SubTable_Format; - } - - return TT_Err_Ok; - } - - - static void Free_CaretValue( TTO_CaretValue* cv, - FT_Memory memory ) - { - if ( cv->CaretValueFormat == 3 ) - Free_Device( &cv->cvf.cvf3.Device, memory ); - } - - - /* LigGlyph */ - - static FT_Error Load_LigGlyph( TTO_LigGlyph* lg, - FT_Stream stream ) - { - FT_Memory memory = stream->memory; - FT_Error error; - - FT_UShort n, m, count; - FT_ULong cur_offset, new_offset, base_offset; - - TTO_CaretValue* cv; - - - base_offset = FILE_Pos(); - - if ( ACCESS_Frame( 2L ) ) - return error; - - count = lg->CaretCount = GET_UShort(); - - FORGET_Frame(); - - lg->CaretValue = NULL; - - if ( ALLOC_ARRAY( lg->CaretValue, count, TTO_CaretValue ) ) - return error; - - cv = lg->CaretValue; - - for ( n = 0; n < count; n++ ) - { - if ( ACCESS_Frame( 2L ) ) - goto Fail; - - new_offset = GET_UShort() + base_offset; - - FORGET_Frame(); - - cur_offset = FILE_Pos(); - if ( FILE_Seek( new_offset ) || - ( error = Load_CaretValue( &cv[n], stream ) ) != TT_Err_Ok ) - goto Fail; - (void)FILE_Seek( cur_offset ); - } - - return TT_Err_Ok; - - Fail: - for ( m = 0; m < n; m++ ) - Free_CaretValue( &cv[m], memory ); - - FREE( cv ); - return error; - } - - - static void Free_LigGlyph( TTO_LigGlyph* lg, - FT_Memory memory ) - { - FT_UShort n, count; - - TTO_CaretValue* cv; - - - if ( lg->CaretValue ) - { - count = lg->CaretCount; - cv = lg->CaretValue; - - for ( n = 0; n < count; n++ ) - Free_CaretValue( &cv[n], memory ); - - FREE( cv ); - } - } - - - /* LigCaretList */ - - static FT_Error Load_LigCaretList( TTO_LigCaretList* lcl, - FT_Stream stream ) - { - FT_Memory memory = stream->memory; - FT_Error error; - - FT_UShort m, n, count; - FT_ULong cur_offset, new_offset, base_offset; - - TTO_LigGlyph* lg; - - - base_offset = FILE_Pos(); - - if ( ACCESS_Frame( 2L ) ) - return error; - - new_offset = GET_UShort() + base_offset; - - FORGET_Frame(); - - cur_offset = FILE_Pos(); - if ( FILE_Seek( new_offset ) || - ( error = Load_Coverage( &lcl->Coverage, stream ) ) != TT_Err_Ok ) - return error; - (void)FILE_Seek( cur_offset ); - - if ( ACCESS_Frame( 2L ) ) - goto Fail2; - - count = lcl->LigGlyphCount = GET_UShort(); - - FORGET_Frame(); - - lcl->LigGlyph = NULL; - - if ( ALLOC_ARRAY( lcl->LigGlyph, count, TTO_LigGlyph ) ) - goto Fail2; - - lg = lcl->LigGlyph; - - for ( n = 0; n < count; n++ ) - { - if ( ACCESS_Frame( 2L ) ) - goto Fail1; - - new_offset = GET_UShort() + base_offset; - - FORGET_Frame(); - - cur_offset = FILE_Pos(); - if ( FILE_Seek( new_offset ) || - ( error = Load_LigGlyph( &lg[n], stream ) ) != TT_Err_Ok ) - goto Fail1; - (void)FILE_Seek( cur_offset ); - } - - lcl->loaded = TRUE; - - return TT_Err_Ok; - - Fail1: - for ( m = 0; m < n; m++ ) - Free_LigGlyph( &lg[m], memory ); - - FREE( lg ); - - Fail2: - Free_Coverage( &lcl->Coverage, memory ); - return error; - } - - - static void Free_LigCaretList( TTO_LigCaretList* lcl, - FT_Memory memory ) - { - FT_UShort n, count; - - TTO_LigGlyph* lg; - - - if ( !lcl->loaded ) - return; - - if ( lcl->LigGlyph ) - { - count = lcl->LigGlyphCount; - lg = lcl->LigGlyph; - - for ( n = 0; n < count; n++ ) - Free_LigGlyph( &lg[n], memory ); - - FREE( lg ); - } - - Free_Coverage( &lcl->Coverage, memory ); - } - - - - /*********** - * GDEF API - ***********/ - - - static FT_UShort Get_New_Class( TTO_GDEFHeader* gdef, - FT_UShort glyphID, - FT_UShort index ) - { - FT_UShort glyph_index, array_index, count; - FT_UShort byte, bits; - - TTO_ClassRangeRecord* gcrr; - FT_UShort** ngc; - - - if ( glyphID >= gdef->LastGlyph ) - return 0; - - count = gdef->GlyphClassDef.cd.cd2.ClassRangeCount; - gcrr = gdef->GlyphClassDef.cd.cd2.ClassRangeRecord; - ngc = gdef->NewGlyphClasses; - - if ( index < count && glyphID < gcrr[index].Start ) - { - array_index = index; - if ( index == 0 ) - glyph_index = glyphID; - else - glyph_index = glyphID - gcrr[index - 1].End - 1; - } - else - { - array_index = index + 1; - glyph_index = glyphID - gcrr[index].End - 1; - } - - byte = ngc[array_index][glyph_index / 4]; - bits = byte >> ( 16 - ( glyph_index % 4 + 1 ) * 4 ); - - return bits & 0x000F; - } - - - EXPORT_FUNC - FT_Error TT_GDEF_Get_Glyph_Property( TTO_GDEFHeader* gdef, - FT_UShort glyphID, - FT_UShort* property ) - { - FT_UShort class, index; - - FT_Error error; - - - if ( !gdef || !property ) - return TT_Err_Invalid_Argument; - - /* first, we check for mark attach classes */ - - if ( gdef->MarkAttachClassDef.loaded ) - { - error = Get_Class( &gdef->MarkAttachClassDef, glyphID, &class, &index ); - if ( error && error != TTO_Err_Not_Covered ) - return error; - if ( !error ) - { - *property = class << 8; - return TT_Err_Ok; - } - } - - error = Get_Class( &gdef->GlyphClassDef, glyphID, &class, &index ); - if ( error && error != TTO_Err_Not_Covered ) - return error; - - /* if we have a constructed class table, check whether additional - values have been assigned */ - - if ( error == TTO_Err_Not_Covered && gdef->NewGlyphClasses ) - class = Get_New_Class( gdef, glyphID, index ); - - switch ( class ) - { - case UNCLASSIFIED_GLYPH: - *property = 0; - break; - - case SIMPLE_GLYPH: - *property = TTO_BASE_GLYPH; - break; - - case LIGATURE_GLYPH: - *property = TTO_LIGATURE; - break; - - case MARK_GLYPH: - *property = TTO_MARK; - break; - - case COMPONENT_GLYPH: - *property = TTO_COMPONENT; - break; - } - - return TT_Err_Ok; - } - - - static FT_Error Make_ClassRange( TTO_ClassDefinition* cd, - FT_UShort start, - FT_UShort end, - FT_UShort class, - FT_Memory memory ) - { - FT_Error error; - FT_UShort index; - - TTO_ClassDefFormat2* cdf2; - TTO_ClassRangeRecord* crr; - - - cdf2 = &cd->cd.cd2; - - if ( REALLOC_ARRAY( cdf2->ClassRangeRecord, - cdf2->ClassRangeCount, - cdf2->ClassRangeCount + 1 , - TTO_ClassRangeRecord ) ) - return error; - - cdf2->ClassRangeCount++; - - crr = cdf2->ClassRangeRecord; - index = cdf2->ClassRangeCount - 1; - - crr[index].Start = start; - crr[index].End = end; - crr[index].Class = class; - - cd->Defined[class] = TRUE; - - return TT_Err_Ok; - } - - - EXPORT_FUNC - FT_Error TT_GDEF_Build_ClassDefinition( TTO_GDEFHeader* gdef, - FT_UShort num_glyphs, - FT_UShort glyph_count, - FT_UShort* glyph_array, - FT_UShort* class_array ) - { - FT_UShort start, curr_glyph, curr_class; - FT_UShort n, m, count; - FT_Error error; - FT_Memory memory = gdef->memory; - - TTO_ClassDefinition* gcd; - TTO_ClassRangeRecord* gcrr; - FT_UShort** ngc; - - - if ( !gdef || !glyph_array || !class_array ) - return TT_Err_Invalid_Argument; - - gcd = &gdef->GlyphClassDef; - - /* We build a format 2 table */ - - gcd->ClassFormat = 2; - - /* A GlyphClassDef table contains at most 5 different class values */ - - if ( ALLOC_ARRAY( gcd->Defined, 5, FT_Bool ) ) - return error; - - gcd->cd.cd2.ClassRangeCount = 0; - gcd->cd.cd2.ClassRangeRecord = NULL; - - start = glyph_array[0]; - curr_class = class_array[0]; - curr_glyph = start; - - if ( curr_class >= 5 ) - { - error = TT_Err_Invalid_Argument; - goto Fail4; - } - - glyph_count--; - - for ( n = 0; n <= glyph_count; n++ ) - { - if ( curr_glyph == glyph_array[n] && curr_class == class_array[n] ) - { - if ( n == glyph_count ) - { - if ( ( error = Make_ClassRange( gcd, start, - curr_glyph, - curr_class, - memory ) ) != TT_Err_Ok ) - goto Fail3; - } - else - { - if ( curr_glyph == 0xFFFF ) - { - error = TT_Err_Invalid_Argument; - goto Fail3; - } - else - curr_glyph++; - } - } - else - { - if ( ( error = Make_ClassRange( gcd, start, - curr_glyph - 1, - curr_class, - memory ) ) != TT_Err_Ok ) - goto Fail3; - - if ( curr_glyph > glyph_array[n] ) - { - error = TT_Err_Invalid_Argument; - goto Fail3; - } - - start = glyph_array[n]; - curr_class = class_array[n]; - curr_glyph = start; - - if ( curr_class >= 5 ) - { - error = TT_Err_Invalid_Argument; - goto Fail3; - } - - if ( n == glyph_count ) - { - if ( ( error = Make_ClassRange( gcd, start, - curr_glyph, - curr_class, - memory ) ) != TT_Err_Ok ) - goto Fail3; - } - else - { - if ( curr_glyph == 0xFFFF ) - { - error = TT_Err_Invalid_Argument; - goto Fail3; - } - else - curr_glyph++; - } - } - } - - /* now prepare the arrays for class values assigned during the lookup - process */ - - if ( ALLOC_ARRAY( gdef->NewGlyphClasses, - gcd->cd.cd2.ClassRangeCount + 1, FT_UShort* ) ) - goto Fail3; - - count = gcd->cd.cd2.ClassRangeCount; - gcrr = gcd->cd.cd2.ClassRangeRecord; - ngc = gdef->NewGlyphClasses; - - /* We allocate arrays for all glyphs not covered by the class range - records. Each element holds four class values. */ - - if ( count > 0 ) - { - if ( gcrr[0].Start ) - { - if ( ALLOC_ARRAY( ngc[0], ( gcrr[0].Start + 3 ) / 4, FT_UShort ) ) - goto Fail2; - } - - for ( n = 1; n < count; n++ ) - { - if ( gcrr[n].Start - gcrr[n - 1].End > 1 ) - if ( ALLOC_ARRAY( ngc[n], - ( gcrr[n].Start - gcrr[n - 1].End + 2 ) / 4, - FT_UShort ) ) - goto Fail1; - } - - if ( gcrr[count - 1].End != num_glyphs - 1 ) - { - if ( ALLOC_ARRAY( ngc[count], - ( num_glyphs - gcrr[count - 1].End + 2 ) / 4, - FT_UShort ) ) - goto Fail1; - } - } - else if ( num_glyphs > 0 ) - { - if ( ALLOC_ARRAY( ngc[count], - ( num_glyphs + 3 ) / 4, - FT_UShort ) ) - goto Fail2; - } - - gdef->LastGlyph = num_glyphs - 1; - - gdef->MarkAttachClassDef_offset = 0L; - gdef->MarkAttachClassDef.loaded = FALSE; - - gcd->loaded = TRUE; - - return TT_Err_Ok; - - Fail1: - for ( m = 0; m < n; m++ ) - FREE( ngc[m] ); - - Fail2: - FREE( gdef->NewGlyphClasses ); - - Fail3: - FREE( gcd->cd.cd2.ClassRangeRecord ); - - Fail4: - FREE( gcd->Defined ); - return error; - } - - - static void Free_NewGlyphClasses( TTO_GDEFHeader* gdef, - FT_Memory memory ) - { - FT_UShort** ngc; - FT_UShort n, count; - - - if ( gdef->NewGlyphClasses ) - { - count = gdef->GlyphClassDef.cd.cd2.ClassRangeCount + 1; - ngc = gdef->NewGlyphClasses; - - for ( n = 0; n < count; n++ ) - FREE( ngc[n] ); - - FREE( ngc ); - } - } - - - FT_Error Add_Glyph_Property( TTO_GDEFHeader* gdef, - FT_UShort glyphID, - FT_UShort property ) - { - FT_Error error; - FT_UShort class, new_class, index; - FT_UShort byte, bits, mask; - FT_UShort array_index, glyph_index, count; - - TTO_ClassRangeRecord* gcrr; - FT_UShort** ngc; - - - error = Get_Class( &gdef->GlyphClassDef, glyphID, &class, &index ); - if ( error && error != TTO_Err_Not_Covered ) - return error; - - /* we don't accept glyphs covered in `GlyphClassDef' */ - - if ( !error ) - return TTO_Err_Not_Covered; - - switch ( property ) - { - case 0: - new_class = UNCLASSIFIED_GLYPH; - break; - - case TTO_BASE_GLYPH: - new_class = SIMPLE_GLYPH; - break; - - case TTO_LIGATURE: - new_class = LIGATURE_GLYPH; - break; - - case TTO_MARK: - new_class = MARK_GLYPH; - break; - - case TTO_COMPONENT: - new_class = COMPONENT_GLYPH; - break; - - default: - return TT_Err_Invalid_Argument; - } - - count = gdef->GlyphClassDef.cd.cd2.ClassRangeCount; - gcrr = gdef->GlyphClassDef.cd.cd2.ClassRangeRecord; - ngc = gdef->NewGlyphClasses; - - if ( index < count && glyphID < gcrr[index].Start ) - { - array_index = index; - if ( index == 0 ) - glyph_index = glyphID; - else - glyph_index = glyphID - gcrr[index - 1].End - 1; - } - else - { - array_index = index + 1; - glyph_index = glyphID - gcrr[index].End - 1; - } - - byte = ngc[array_index][glyph_index / 4]; - bits = byte >> ( 16 - ( glyph_index % 4 + 1 ) * 4 ); - class = bits & 0x000F; - - /* we don't overwrite existing entries */ - - if ( !class ) - { - bits = new_class << ( 16 - ( glyph_index % 4 + 1 ) * 4 ); - mask = ~( 0x000F << ( 16 - ( glyph_index % 4 + 1 ) * 4 ) ); - - ngc[array_index][glyph_index / 4] &= mask; - ngc[array_index][glyph_index / 4] |= bits; - } - - return TT_Err_Ok; - } - - - FT_Error Check_Property( TTO_GDEFHeader* gdef, - OTL_GlyphItem gitem, - FT_UShort flags, - FT_UShort* property ) - { - FT_Error error; - - if ( gdef ) - { - FT_UShort basic_glyph_class; - FT_UShort desired_attachment_class; - - if ( gitem->gproperties == OTL_GLYPH_PROPERTIES_UNKNOWN ) - { - error = TT_GDEF_Get_Glyph_Property( gdef, gitem->gindex, &gitem->gproperties ); - if ( error ) - return error; - } - - *property = gitem->gproperties; - - /* If the glyph was found in the MarkAttachmentClass table, - * then that class value is the high byte of the result, - * otherwise the low byte contains the basic type of the glyph - * as defined by the GlyphClassDef table. - */ - if ( *property & IGNORE_SPECIAL_MARKS ) - basic_glyph_class = TTO_MARK; - else - basic_glyph_class = *property; - - /* Return Not_Covered, if, for example, basic_glyph_class - * is TTO_LIGATURE and LookFlags includes IGNORE_LIGATURES - */ - if ( flags & basic_glyph_class ) - return TTO_Err_Not_Covered; - - /* The high byte of LookupFlags has the meaning - * "ignore marks of attachment type different than - * the attachment type specified." - */ - desired_attachment_class = flags & IGNORE_SPECIAL_MARKS; - if ( desired_attachment_class ) - { - if ( basic_glyph_class == TTO_MARK && - *property != desired_attachment_class ) - return TTO_Err_Not_Covered; - } - } - - return TT_Err_Ok; - } - - -/* END */ diff --git a/src/ftxgdef.h b/src/ftxgdef.h deleted file mode 100644 index f22438e..0000000 --- a/src/ftxgdef.h +++ /dev/null @@ -1,224 +0,0 @@ -/******************************************************************* - * - * ftxgdef.h - * - * TrueType Open GDEF table support - * - * Copyright 1996-2000 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 FTXOPEN_H -#error "Don't include this file! Use ftxopen.h instead." -#endif - -#ifndef FTXGDEF_H -#define FTXGDEF_H - -#ifdef __cplusplus -extern "C" { -#endif - -#define TTO_Err_Invalid_GDEF_SubTable_Format 0x1030 -#define TTO_Err_Invalid_GDEF_SubTable 0x1031 - - -/* GDEF glyph classes */ - -#define UNCLASSIFIED_GLYPH 0 -#define SIMPLE_GLYPH 1 -#define LIGATURE_GLYPH 2 -#define MARK_GLYPH 3 -#define COMPONENT_GLYPH 4 - -/* GDEF glyph properties, corresponding to class values 1-4. Note that - TTO_COMPONENT has no corresponding flag in the LookupFlag field. */ - -#define TTO_BASE_GLYPH 0x0002 -#define TTO_LIGATURE 0x0004 -#define TTO_MARK 0x0008 -#define TTO_COMPONENT 0x0010 - - - /* Attachment related structures */ - - struct TTO_AttachPoint_ - { - FT_UShort PointCount; /* size of the PointIndex array */ - FT_UShort* PointIndex; /* array of contour points */ - }; - - typedef struct TTO_AttachPoint_ TTO_AttachPoint; - - - struct TTO_AttachList_ - { - FT_Bool loaded; - - TTO_Coverage Coverage; /* Coverage table */ - FT_UShort GlyphCount; /* number of glyphs with - attachments */ - TTO_AttachPoint* AttachPoint; /* array of AttachPoint tables */ - }; - - typedef struct TTO_AttachList_ TTO_AttachList; - - - /* Ligature Caret related structures */ - - struct TTO_CaretValueFormat1_ - { - FT_Short Coordinate; /* x or y value (in design units) */ - }; - - typedef struct TTO_CaretValueFormat1_ TTO_CaretValueFormat1; - - - struct TTO_CaretValueFormat2_ - { - FT_UShort CaretValuePoint; /* contour point index on glyph */ - }; - - typedef struct TTO_CaretValueFormat2_ TTO_CaretValueFormat2; - - - struct TTO_CaretValueFormat3_ - { - FT_Short Coordinate; /* x or y value (in design units) */ - TTO_Device Device; /* Device table for x or y value */ - }; - - typedef struct TTO_CaretValueFormat3_ TTO_CaretValueFormat3; - - - struct TTO_CaretValueFormat4_ - { - FT_UShort IdCaretValue; /* metric ID */ - }; - - typedef struct TTO_CaretValueFormat4_ TTO_CaretValueFormat4; - - - struct TTO_CaretValue_ - { - FT_UShort CaretValueFormat; /* 1, 2, 3, or 4 */ - - union - { - TTO_CaretValueFormat1 cvf1; - TTO_CaretValueFormat2 cvf2; - TTO_CaretValueFormat3 cvf3; - TTO_CaretValueFormat4 cvf4; - } cvf; - }; - - typedef struct TTO_CaretValue_ TTO_CaretValue; - - - struct TTO_LigGlyph_ - { - FT_Bool loaded; - - FT_UShort CaretCount; /* number of caret values */ - TTO_CaretValue* CaretValue; /* array of caret values */ - }; - - typedef struct TTO_LigGlyph_ TTO_LigGlyph; - - - struct TTO_LigCaretList_ - { - FT_Bool loaded; - - TTO_Coverage Coverage; /* Coverage table */ - FT_UShort LigGlyphCount; /* number of ligature glyphs */ - TTO_LigGlyph* LigGlyph; /* array of LigGlyph tables */ - }; - - typedef struct TTO_LigCaretList_ TTO_LigCaretList; - - - /* The `NewGlyphClasses' field is not defined in the TTO specification. - We use it for fonts with a constructed `GlyphClassDef' structure - (i.e., which don't have a GDEF table) to collect glyph classes - assigned during the lookup process. The number of arrays in this - pointer array is GlyphClassDef->cd.cd2.ClassRangeCount+1; the nth - array then contains the glyph class values of the glyphs not covered - by the ClassRangeRecords structures with index n-1 and n. We store - glyph class values for four glyphs in a single array element. - - `LastGlyph' is identical to the number of glyphs minus one in the - font; we need it only if `NewGlyphClasses' is not NULL (to have an - upper bound for the last array). - - Note that we first store the file offset to the `MarkAttachClassDef' - field (which has been introduced in OpenType 1.2) -- since the - `Version' field value hasn't been increased to indicate that we have - one more field for some obscure reason, we must parse the GSUB table - to find out whether class values refer to this table. Only then we - can finally load the MarkAttachClassDef structure if necessary. */ - - struct TTO_GDEFHeader_ - { - FT_Memory memory; - FT_ULong offset; - - FT_Fixed Version; - - TTO_ClassDefinition GlyphClassDef; - TTO_AttachList AttachList; - TTO_LigCaretList LigCaretList; - FT_ULong MarkAttachClassDef_offset; - TTO_ClassDefinition MarkAttachClassDef; /* new in OT 1.2 */ - - FT_UShort LastGlyph; - FT_UShort** NewGlyphClasses; - }; - - typedef struct TTO_GDEFHeader_ TTO_GDEFHeader; - typedef struct TTO_GDEFHeader_* TTO_GDEF; - - - /* finally, the GDEF API */ - - /* EXPORT_DEF - FT_Error TT_Init_GDEF_Extension( TT_Engine engine ); */ - - EXPORT_FUNC - FT_Error TT_New_GDEF_Table( FT_Face face, - TTO_GDEFHeader** retptr ); - - EXPORT_DEF - FT_Error TT_Load_GDEF_Table( FT_Face face, - TTO_GDEFHeader** gdef ); - - EXPORT_DEF - FT_Error TT_Done_GDEF_Table ( TTO_GDEFHeader* gdef ); - - EXPORT_DEF - FT_Error TT_GDEF_Get_Glyph_Property( TTO_GDEFHeader* gdef, - FT_UShort glyphID, - FT_UShort* property ); - EXPORT_DEF - FT_Error TT_GDEF_Build_ClassDefinition( TTO_GDEFHeader* gdef, - FT_UShort num_glyphs, - FT_UShort glyph_count, - FT_UShort* glyph_array, - FT_UShort* class_array ); - - -#ifdef __cplusplus -} -#endif - -#endif /* FTXGDEF_H */ - - -/* END */ diff --git a/src/ftxgpos.c b/src/ftxgpos.c deleted file mode 100644 index 69efd07..0000000 --- a/src/ftxgpos.c +++ /dev/null @@ -1,6199 +0,0 @@ -/******************************************************************* - * - * ftxgpos.c - * - * TrueType Open GPOS table support. - * - * Copyright 1996-2000 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. - * - ******************************************************************/ - -#include - -/* XXX There is *a lot* of duplicated code (cf. formats 7 and 8), but - I don't care currently. I believe that it would be possible to - save about 50% of TTO code by carefully designing the structures, - sharing as much as possible with extensive use of macros. This - is something for a volunteer :-) */ - -#include "ftxopen.h" -#include "ftxopenf.h" - -#include "ftglue.h" - -#include FT_TRUETYPE_TAGS_H - -#define TTAG_GPOS FT_MAKE_TAG( 'G', 'P', 'O', 'S' ) - - struct GPOS_Instance_ - { - TTO_GPOSHeader* gpos; - FT_Face face; - FT_Bool dvi; - FT_UShort load_flags; /* how the glyph should be loaded */ - FT_Bool r2l; - - FT_UShort last; /* the last valid glyph -- used - with cursive positioning */ - FT_Pos anchor_x; /* the coordinates of the anchor point */ - FT_Pos anchor_y; /* of the last valid glyph */ - }; - - typedef struct GPOS_Instance_ GPOS_Instance; - - - static FT_Error Do_Glyph_Lookup( GPOS_Instance* gpi, - FT_UShort lookup_index, - OTL_Buffer buffer, - FT_UShort context_length, - int nesting_level ); - - -#define IN_GLYPH( pos ) (buffer->in_string[(pos)].gindex) -#define IN_ITEM( pos ) (&buffer->in_string[(pos)]) -#define IN_CURGLYPH() (buffer->in_string[buffer->in_pos].gindex) -#define IN_CURITEM() (&buffer->in_string[buffer->in_pos]) -#define IN_PROPERTIES( pos ) (buffer->in_string[(pos)].properties) -#define IN_LIGID( pos ) (buffer->in_string[(pos)].ligID) -#define IN_COMPONENT( pos ) (buffer->in_string[(pos)].component) -#define POSITION( pos ) (&buffer->positions[(pos)]) - -/* the client application must replace this with something more - meaningful if multiple master fonts are to be supported. */ - - static FT_Error default_mmfunc( FT_Face face, - FT_UShort metric_id, - FT_Pos* metric_value, - void* data ) - { - return TTO_Err_No_MM_Interpreter; - } - - - EXPORT_FUNC - FT_Error TT_Load_GPOS_Table( FT_Face face, - TTO_GPOSHeader** retptr, - TTO_GDEFHeader* gdef ) - { - FT_ULong cur_offset, new_offset, base_offset; - - FT_UShort i, num_lookups; - TTO_GPOSHeader* gpos; - TTO_Lookup* lo; - - FT_Stream stream = face->stream; - FT_Error error; - FT_Memory memory = face->memory; - - - if ( !retptr ) - return TT_Err_Invalid_Argument; - - if ( !stream ) - return TT_Err_Invalid_Face_Handle; - - if (( error = ftglue_face_goto_table( face, TTAG_GPOS, stream ) )) - return error; - - base_offset = FILE_Pos(); - - if ( ALLOC ( gpos, sizeof( *gpos ) ) ) - return error; - - gpos->memory = memory; - gpos->gfunc = FT_Load_Glyph; - gpos->mmfunc = default_mmfunc; - - /* skip version */ - - if ( FILE_Seek( base_offset + 4L ) || - ACCESS_Frame( 2L ) ) - goto Fail4; - - new_offset = GET_UShort() + base_offset; - - FORGET_Frame(); - - cur_offset = FILE_Pos(); - if ( FILE_Seek( new_offset ) || - ( error = Load_ScriptList( &gpos->ScriptList, - stream ) ) != TT_Err_Ok ) - goto Fail4; - (void)FILE_Seek( cur_offset ); - - if ( ACCESS_Frame( 2L ) ) - goto Fail3; - - new_offset = GET_UShort() + base_offset; - - FORGET_Frame(); - - cur_offset = FILE_Pos(); - if ( FILE_Seek( new_offset ) || - ( error = Load_FeatureList( &gpos->FeatureList, - stream ) ) != TT_Err_Ok ) - goto Fail3; - (void)FILE_Seek( cur_offset ); - - if ( ACCESS_Frame( 2L ) ) - goto Fail2; - - new_offset = GET_UShort() + base_offset; - - FORGET_Frame(); - - cur_offset = FILE_Pos(); - if ( FILE_Seek( new_offset ) || - ( error = Load_LookupList( &gpos->LookupList, - stream, GPOS ) ) != TT_Err_Ok ) - goto Fail2; - - gpos->gdef = gdef; /* can be NULL */ - - /* We now check the LookupFlags for values larger than 0xFF to find - out whether we need to load the `MarkAttachClassDef' field of the - GDEF table -- this hack is necessary for OpenType 1.2 tables since - the version field of the GDEF table hasn't been incremented. - - For constructed GDEF tables, we only load it if - `MarkAttachClassDef_offset' is not zero (nevertheless, a build of - a constructed mark attach table is not supported currently). */ - - if ( gdef && - gdef->MarkAttachClassDef_offset && !gdef->MarkAttachClassDef.loaded ) - { - lo = gpos->LookupList.Lookup; - num_lookups = gpos->LookupList.LookupCount; - - for ( i = 0; i < num_lookups; i++ ) - { - if ( lo[i].LookupFlag & IGNORE_SPECIAL_MARKS ) - { - if ( FILE_Seek( gdef->MarkAttachClassDef_offset ) || - ( error = Load_ClassDefinition( &gdef->MarkAttachClassDef, - 256, stream ) ) != TT_Err_Ok ) - goto Fail1; - - break; - } - } - } - - *retptr = gpos; - - return TT_Err_Ok; - - Fail1: - Free_LookupList( &gpos->LookupList, GPOS, memory ); - - Fail2: - Free_FeatureList( &gpos->FeatureList, memory ); - - Fail3: - Free_ScriptList( &gpos->ScriptList, memory ); - - Fail4: - FREE( gpos ); - - return error; - } - - EXPORT_FUNC - FT_Error TT_Done_GPOS_Table( TTO_GPOSHeader* gpos ) - { - FT_Memory memory = gpos->memory; - - Free_LookupList( &gpos->LookupList, GPOS, memory ); - Free_FeatureList( &gpos->FeatureList, memory ); - Free_ScriptList( &gpos->ScriptList, memory ); - - return FT_Err_Ok; - } - - - /***************************** - * SubTable related functions - *****************************/ - - /* shared tables */ - - /* ValueRecord */ - - /* There is a subtle difference in the specs between a `table' and a - `record' -- offsets for device tables in ValueRecords are taken from - the parent table and not the parent record. */ - - static FT_Error Load_ValueRecord( TTO_ValueRecord* vr, - FT_UShort format, - FT_ULong base_offset, - FT_Stream stream ) - { - FT_Error error; - FT_Memory memory = stream->memory; - - FT_ULong cur_offset, new_offset; - - - if ( format & HAVE_X_PLACEMENT ) - { - if ( ACCESS_Frame( 2L ) ) - return error; - - vr->XPlacement = GET_Short(); - - FORGET_Frame(); - } - else - vr->XPlacement = 0; - - if ( format & HAVE_Y_PLACEMENT ) - { - if ( ACCESS_Frame( 2L ) ) - return error; - - vr->YPlacement = GET_Short(); - - FORGET_Frame(); - } - else - vr->YPlacement = 0; - - if ( format & HAVE_X_ADVANCE ) - { - if ( ACCESS_Frame( 2L ) ) - return error; - - vr->XAdvance = GET_Short(); - - FORGET_Frame(); - } - else - vr->XAdvance = 0; - - if ( format & HAVE_Y_ADVANCE ) - { - if ( ACCESS_Frame( 2L ) ) - return error; - - vr->YAdvance = GET_Short(); - - FORGET_Frame(); - } - else - vr->YAdvance = 0; - - if ( format & HAVE_X_PLACEMENT_DEVICE ) - { - if ( ACCESS_Frame( 2L ) ) - return error; - - new_offset = GET_UShort(); - - FORGET_Frame(); - - if ( new_offset ) - { - new_offset += base_offset; - - cur_offset = FILE_Pos(); - if ( FILE_Seek( new_offset ) || - ( error = Load_Device( &vr->XPlacementDevice, - stream ) ) != TT_Err_Ok ) - return error; - (void)FILE_Seek( cur_offset ); - } - else - goto empty1; - } - else - { - empty1: - vr->XPlacementDevice.StartSize = 0; - vr->XPlacementDevice.EndSize = 0; - vr->XPlacementDevice.DeltaValue = NULL; - } - - if ( format & HAVE_Y_PLACEMENT_DEVICE ) - { - if ( ACCESS_Frame( 2L ) ) - goto Fail3; - - new_offset = GET_UShort(); - - FORGET_Frame(); - - if ( new_offset ) - { - new_offset += base_offset; - - cur_offset = FILE_Pos(); - if ( FILE_Seek( new_offset ) || - ( error = Load_Device( &vr->YPlacementDevice, - stream ) ) != TT_Err_Ok ) - goto Fail3; - (void)FILE_Seek( cur_offset ); - } - else - goto empty2; - } - else - { - empty2: - vr->YPlacementDevice.StartSize = 0; - vr->YPlacementDevice.EndSize = 0; - vr->YPlacementDevice.DeltaValue = NULL; - } - - if ( format & HAVE_X_ADVANCE_DEVICE ) - { - if ( ACCESS_Frame( 2L ) ) - goto Fail2; - - new_offset = GET_UShort(); - - FORGET_Frame(); - - if ( new_offset ) - { - new_offset += base_offset; - - cur_offset = FILE_Pos(); - if ( FILE_Seek( new_offset ) || - ( error = Load_Device( &vr->XAdvanceDevice, - stream ) ) != TT_Err_Ok ) - goto Fail2; - (void)FILE_Seek( cur_offset ); - } - else - goto empty3; - } - else - { - empty3: - vr->XAdvanceDevice.StartSize = 0; - vr->XAdvanceDevice.EndSize = 0; - vr->XAdvanceDevice.DeltaValue = NULL; - } - - if ( format & HAVE_Y_ADVANCE_DEVICE ) - { - if ( ACCESS_Frame( 2L ) ) - goto Fail1; - - new_offset = GET_UShort(); - - FORGET_Frame(); - - if ( new_offset ) - { - new_offset += base_offset; - - cur_offset = FILE_Pos(); - if ( FILE_Seek( new_offset ) || - ( error = Load_Device( &vr->YAdvanceDevice, - stream ) ) != TT_Err_Ok ) - goto Fail1; - (void)FILE_Seek( cur_offset ); - } - else - goto empty4; - } - else - { - empty4: - vr->YAdvanceDevice.StartSize = 0; - vr->YAdvanceDevice.EndSize = 0; - vr->YAdvanceDevice.DeltaValue = NULL; - } - - if ( format & HAVE_X_ID_PLACEMENT ) - { - if ( ACCESS_Frame( 2L ) ) - goto Fail1; - - vr->XIdPlacement = GET_UShort(); - - FORGET_Frame(); - } - else - vr->XIdPlacement = 0; - - if ( format & HAVE_Y_ID_PLACEMENT ) - { - if ( ACCESS_Frame( 2L ) ) - goto Fail1; - - vr->YIdPlacement = GET_UShort(); - - FORGET_Frame(); - } - else - vr->YIdPlacement = 0; - - if ( format & HAVE_X_ID_ADVANCE ) - { - if ( ACCESS_Frame( 2L ) ) - goto Fail1; - - vr->XIdAdvance = GET_UShort(); - - FORGET_Frame(); - } - else - vr->XIdAdvance = 0; - - if ( format & HAVE_Y_ID_ADVANCE ) - { - if ( ACCESS_Frame( 2L ) ) - goto Fail1; - - vr->YIdAdvance = GET_UShort(); - - FORGET_Frame(); - } - else - vr->YIdAdvance = 0; - - return TT_Err_Ok; - - Fail1: - Free_Device( &vr->YAdvanceDevice, memory ); - - Fail2: - Free_Device( &vr->XAdvanceDevice, memory ); - - Fail3: - Free_Device( &vr->YPlacementDevice, memory ); - return error; - } - - - static void Free_ValueRecord( TTO_ValueRecord* vr, - FT_UShort format, - FT_Memory memory ) - { - if ( format & HAVE_Y_ADVANCE_DEVICE ) - Free_Device( &vr->YAdvanceDevice, memory ); - if ( format & HAVE_X_ADVANCE_DEVICE ) - Free_Device( &vr->XAdvanceDevice, memory ); - if ( format & HAVE_Y_PLACEMENT_DEVICE ) - Free_Device( &vr->YPlacementDevice, memory ); - if ( format & HAVE_X_PLACEMENT_DEVICE ) - Free_Device( &vr->XPlacementDevice, memory ); - } - - - static FT_Error Get_ValueRecord( GPOS_Instance* gpi, - TTO_ValueRecord* vr, - FT_UShort format, - OTL_Position gd ) - { - FT_Pos value; - FT_Short pixel_value; - FT_Error error = TT_Err_Ok; - TTO_GPOSHeader* gpos = gpi->gpos; - - FT_UShort x_ppem, y_ppem; - FT_Fixed x_scale, y_scale; - - - if ( !format ) - return TT_Err_Ok; - - x_ppem = gpi->face->size->metrics.x_ppem; - y_ppem = gpi->face->size->metrics.y_ppem; - x_scale = gpi->face->size->metrics.x_scale; - y_scale = gpi->face->size->metrics.y_scale; - - /* design units -> fractional pixel */ - - if ( format & HAVE_X_PLACEMENT ) - gd->x_pos += x_scale * vr->XPlacement / 0x10000; - if ( format & HAVE_Y_PLACEMENT ) - gd->y_pos += y_scale * vr->YPlacement / 0x10000; - if ( format & HAVE_X_ADVANCE ) - gd->x_advance += x_scale * vr->XAdvance / 0x10000; - if ( format & HAVE_Y_ADVANCE ) - gd->y_advance += y_scale * vr->YAdvance / 0x10000; - - if ( !gpi->dvi ) - { - /* pixel -> fractional pixel */ - - if ( format & HAVE_X_PLACEMENT_DEVICE ) - { - Get_Device( &vr->XPlacementDevice, x_ppem, &pixel_value ); - gd->x_pos += pixel_value << 6; - } - if ( format & HAVE_Y_PLACEMENT_DEVICE ) - { - Get_Device( &vr->YPlacementDevice, y_ppem, &pixel_value ); - gd->y_pos += pixel_value << 6; - } - if ( format & HAVE_X_ADVANCE_DEVICE ) - { - Get_Device( &vr->XAdvanceDevice, x_ppem, &pixel_value ); - gd->x_advance += pixel_value << 6; - } - if ( format & HAVE_Y_ADVANCE_DEVICE ) - { - Get_Device( &vr->YAdvanceDevice, y_ppem, &pixel_value ); - gd->y_advance += pixel_value << 6; - } - } - - /* values returned from mmfunc() are already in fractional pixels */ - - if ( format & HAVE_X_ID_PLACEMENT ) - { - error = (gpos->mmfunc)( gpi->face, vr->XIdPlacement, - &value, gpos->data ); - if ( error ) - return error; - gd->x_pos += value; - } - if ( format & HAVE_Y_ID_PLACEMENT ) - { - error = (gpos->mmfunc)( gpi->face, vr->YIdPlacement, - &value, gpos->data ); - if ( error ) - return error; - gd->y_pos += value; - } - if ( format & HAVE_X_ID_ADVANCE ) - { - error = (gpos->mmfunc)( gpi->face, vr->XIdAdvance, - &value, gpos->data ); - if ( error ) - return error; - gd->x_advance += value; - } - if ( format & HAVE_Y_ID_ADVANCE ) - { - error = (gpos->mmfunc)( gpi->face, vr->YIdAdvance, - &value, gpos->data ); - if ( error ) - return error; - gd->y_advance += value; - } - - return error; - } - - - /* AnchorFormat1 */ - /* AnchorFormat2 */ - /* AnchorFormat3 */ - /* AnchorFormat4 */ - - static FT_Error Load_Anchor( TTO_Anchor* an, - FT_Stream stream ) - { - FT_Error error; - FT_Memory memory = stream->memory; - - FT_ULong cur_offset, new_offset, base_offset; - - - base_offset = FILE_Pos(); - - if ( ACCESS_Frame( 2L ) ) - return error; - - an->PosFormat = GET_UShort(); - - FORGET_Frame(); - - switch ( an->PosFormat ) - { - case 1: - if ( ACCESS_Frame( 4L ) ) - return error; - - an->af.af1.XCoordinate = GET_Short(); - an->af.af1.YCoordinate = GET_Short(); - - FORGET_Frame(); - break; - - case 2: - if ( ACCESS_Frame( 6L ) ) - return error; - - an->af.af2.XCoordinate = GET_Short(); - an->af.af2.YCoordinate = GET_Short(); - an->af.af2.AnchorPoint = GET_UShort(); - - FORGET_Frame(); - break; - - case 3: - if ( ACCESS_Frame( 6L ) ) - return error; - - an->af.af3.XCoordinate = GET_Short(); - an->af.af3.YCoordinate = GET_Short(); - - new_offset = GET_UShort(); - - FORGET_Frame(); - - if ( new_offset ) - { - new_offset += base_offset; - - cur_offset = FILE_Pos(); - if ( FILE_Seek( new_offset ) || - ( error = Load_Device( &an->af.af3.XDeviceTable, - stream ) ) != TT_Err_Ok ) - return error; - (void)FILE_Seek( cur_offset ); - } - else - { - an->af.af3.XDeviceTable.StartSize = 0; - an->af.af3.XDeviceTable.EndSize = 0; - an->af.af3.XDeviceTable.DeltaValue = NULL; - } - - if ( ACCESS_Frame( 2L ) ) - goto Fail; - - new_offset = GET_UShort(); - - FORGET_Frame(); - - if ( new_offset ) - { - new_offset += base_offset; - - cur_offset = FILE_Pos(); - if ( FILE_Seek( new_offset ) || - ( error = Load_Device( &an->af.af3.YDeviceTable, - stream ) ) != TT_Err_Ok ) - goto Fail; - (void)FILE_Seek( cur_offset ); - } - else - { - an->af.af3.YDeviceTable.StartSize = 0; - an->af.af3.YDeviceTable.EndSize = 0; - an->af.af3.YDeviceTable.DeltaValue = NULL; - } - break; - - case 4: - if ( ACCESS_Frame( 4L ) ) - return error; - - an->af.af4.XIdAnchor = GET_UShort(); - an->af.af4.YIdAnchor = GET_UShort(); - - FORGET_Frame(); - break; - - default: - return TTO_Err_Invalid_GPOS_SubTable_Format; - } - - return TT_Err_Ok; - - Fail: - Free_Device( &an->af.af3.XDeviceTable, memory ); - return error; - } - - - static void Free_Anchor( TTO_Anchor* an, - FT_Memory memory) - { - if ( an->PosFormat == 3 ) - { - Free_Device( &an->af.af3.YDeviceTable, memory ); - Free_Device( &an->af.af3.XDeviceTable, memory ); - } - } - - - static FT_Error Get_Anchor( GPOS_Instance* gpi, - TTO_Anchor* an, - FT_UShort glyph_index, - FT_Pos* x_value, - FT_Pos* y_value ) - { - FT_Error error = TT_Err_Ok; - - FT_Outline outline; - TTO_GPOSHeader* gpos = gpi->gpos; - FT_UShort ap; - - FT_Short pixel_value; - FT_UShort load_flags; - - FT_UShort x_ppem, y_ppem; - FT_Fixed x_scale, y_scale; - - - x_ppem = gpi->face->size->metrics.x_ppem; - y_ppem = gpi->face->size->metrics.y_ppem; - x_scale = gpi->face->size->metrics.x_scale; - y_scale = gpi->face->size->metrics.y_scale; - - switch ( an->PosFormat ) - { - case 0: - /* The special case of an empty AnchorTable */ - - return TTO_Err_Not_Covered; - - case 1: - *x_value = x_scale * an->af.af1.XCoordinate / 0x10000; - *y_value = y_scale * an->af.af1.YCoordinate / 0x10000; - break; - - case 2: - /* glyphs must be scaled */ - - load_flags = gpi->load_flags & ~FT_LOAD_NO_SCALE; - - if ( !gpi->dvi ) - { - error = (gpos->gfunc)( gpi->face, glyph_index, load_flags ); - if ( error ) - return error; - - if ( gpi->face->glyph->format != ft_glyph_format_outline ) - return TTO_Err_Invalid_GPOS_SubTable; - - ap = an->af.af2.AnchorPoint; - - outline = gpi->face->glyph->outline; - - /* if outline.n_points is set to zero by gfunc(), we use the - design coordinate value pair. This can happen e.g. for - sbit glyphs */ - - if ( !outline.n_points ) - goto no_contour_point; - - if ( ap >= outline.n_points ) - return TTO_Err_Invalid_GPOS_SubTable; - - *x_value = outline.points[ap].x; - *y_value = outline.points[ap].y; - } - else - { - no_contour_point: - *x_value = x_scale * an->af.af3.XCoordinate / 0x10000; - *y_value = y_scale * an->af.af3.YCoordinate / 0x10000; - } - break; - - case 3: - if ( !gpi->dvi ) - { - Get_Device( &an->af.af3.XDeviceTable, x_ppem, &pixel_value ); - *x_value = pixel_value << 6; - Get_Device( &an->af.af3.YDeviceTable, y_ppem, &pixel_value ); - *y_value = pixel_value << 6; - } - else - *x_value = *y_value = 0; - - *x_value += x_scale * an->af.af3.XCoordinate / 0x10000; - *y_value += y_scale * an->af.af3.YCoordinate / 0x10000; - break; - - case 4: - error = (gpos->mmfunc)( gpi->face, an->af.af4.XIdAnchor, - x_value, gpos->data ); - if ( error ) - return error; - - error = (gpos->mmfunc)( gpi->face, an->af.af4.YIdAnchor, - y_value, gpos->data ); - if ( error ) - return error; - break; - } - - return error; - } - - - /* MarkArray */ - - static FT_Error Load_MarkArray ( TTO_MarkArray* ma, - FT_Stream stream ) - { - FT_Error error; - FT_Memory memory = stream->memory; - - FT_UShort n, m, count; - FT_ULong cur_offset, new_offset, base_offset; - - TTO_MarkRecord* mr; - - - base_offset = FILE_Pos(); - - if ( ACCESS_Frame( 2L ) ) - return error; - - count = ma->MarkCount = GET_UShort(); - - FORGET_Frame(); - - ma->MarkRecord = NULL; - - if ( ALLOC_ARRAY( ma->MarkRecord, count, TTO_MarkRecord ) ) - return error; - - mr = ma->MarkRecord; - - for ( n = 0; n < count; n++ ) - { - if ( ACCESS_Frame( 4L ) ) - goto Fail; - - mr[n].Class = GET_UShort(); - new_offset = GET_UShort() + base_offset; - - FORGET_Frame(); - - cur_offset = FILE_Pos(); - if ( FILE_Seek( new_offset ) || - ( error = Load_Anchor( &mr[n].MarkAnchor, stream ) ) != TT_Err_Ok ) - goto Fail; - (void)FILE_Seek( cur_offset ); - } - - return TT_Err_Ok; - - Fail: - for ( m = 0; m < n; m++ ) - Free_Anchor( &mr[m].MarkAnchor, memory ); - - FREE( mr ); - return error; - } - - - static void Free_MarkArray( TTO_MarkArray* ma, - FT_Memory memory ) - { - FT_UShort n, count; - - TTO_MarkRecord* mr; - - - if ( ma->MarkRecord ) - { - count = ma->MarkCount; - mr = ma->MarkRecord; - - for ( n = 0; n < count; n++ ) - Free_Anchor( &mr[n].MarkAnchor, memory ); - - FREE( mr ); - } - } - - - /* LookupType 1 */ - - /* SinglePosFormat1 */ - /* SinglePosFormat2 */ - - FT_Error Load_SinglePos( TTO_SinglePos* sp, - FT_Stream stream ) - { - FT_Error error; - FT_Memory memory = stream->memory; - - FT_UShort n, m, count, format; - FT_ULong cur_offset, new_offset, base_offset; - - TTO_ValueRecord* vr; - - - base_offset = FILE_Pos(); - - if ( ACCESS_Frame( 6L ) ) - return error; - - sp->PosFormat = GET_UShort(); - new_offset = GET_UShort() + base_offset; - - format = sp->ValueFormat = GET_UShort(); - - FORGET_Frame(); - - if ( !format ) - return TTO_Err_Invalid_GPOS_SubTable; - - cur_offset = FILE_Pos(); - if ( FILE_Seek( new_offset ) || - ( error = Load_Coverage( &sp->Coverage, stream ) ) != TT_Err_Ok ) - return error; - (void)FILE_Seek( cur_offset ); - - switch ( sp->PosFormat ) - { - case 1: - error = Load_ValueRecord( &sp->spf.spf1.Value, format, - base_offset, stream ); - if ( error ) - goto Fail2; - break; - - case 2: - if ( ACCESS_Frame( 2L ) ) - goto Fail2; - - count = sp->spf.spf2.ValueCount = GET_UShort(); - - FORGET_Frame(); - - sp->spf.spf2.Value = NULL; - - if ( ALLOC_ARRAY( sp->spf.spf2.Value, count, TTO_ValueRecord ) ) - goto Fail2; - - vr = sp->spf.spf2.Value; - - for ( n = 0; n < count; n++ ) - { - error = Load_ValueRecord( &vr[n], format, base_offset, stream ); - if ( error ) - goto Fail1; - } - break; - - default: - return TTO_Err_Invalid_GPOS_SubTable_Format; - } - - return TT_Err_Ok; - - Fail1: - for ( m = 0; m < n; m++ ) - Free_ValueRecord( &vr[m], format, memory ); - - FREE( vr ); - - Fail2: - Free_Coverage( &sp->Coverage, memory ); - return error; - } - - - void Free_SinglePos( TTO_SinglePos* sp, - FT_Memory memory ) - { - FT_UShort n, count, format; - - TTO_ValueRecord* v; - - - format = sp->ValueFormat; - - switch ( sp->PosFormat ) - { - case 1: - Free_ValueRecord( &sp->spf.spf1.Value, format, memory ); - break; - - case 2: - if ( sp->spf.spf2.Value ) - { - count = sp->spf.spf2.ValueCount; - v = sp->spf.spf2.Value; - - for ( n = 0; n < count; n++ ) - Free_ValueRecord( &v[n], format, memory ); - - FREE( v ); - } - break; - } - - Free_Coverage( &sp->Coverage, memory ); - } - - static FT_Error Lookup_DefaultPos( GPOS_Instance* gpi, - TTO_GPOS_SubTable* st, - OTL_Buffer buffer, - FT_UShort flags, - FT_UShort context_length, - int nesting_level ) - { - return TTO_Err_Not_Covered; - } - - static FT_Error Lookup_SinglePos( GPOS_Instance* gpi, - TTO_GPOS_SubTable* st, - OTL_Buffer buffer, - FT_UShort flags, - FT_UShort context_length, - int nesting_level ) - { - FT_UShort index, property; - FT_Error error; - TTO_GPOSHeader* gpos = gpi->gpos; - TTO_SinglePos* sp = &st->single; - - - if ( context_length != 0xFFFF && context_length < 1 ) - return TTO_Err_Not_Covered; - - if ( CHECK_Property( gpos->gdef, IN_CURITEM(), flags, &property ) ) - return error; - - error = Coverage_Index( &sp->Coverage, IN_CURGLYPH(), &index ); - if ( error ) - return error; - - switch ( sp->PosFormat ) - { - case 1: - error = Get_ValueRecord( gpi, &sp->spf.spf1.Value, - sp->ValueFormat, POSITION( buffer->in_pos ) ); - if ( error ) - return error; - break; - - case 2: - if ( index >= sp->spf.spf2.ValueCount ) - return TTO_Err_Invalid_GPOS_SubTable; - error = Get_ValueRecord( gpi, &sp->spf.spf2.Value[index], - sp->ValueFormat, POSITION( buffer->in_pos ) ); - if ( error ) - return error; - break; - - default: - return TTO_Err_Invalid_GPOS_SubTable; - } - - (buffer->in_pos)++; - - return TT_Err_Ok; - } - - - /* LookupType 2 */ - - /* PairSet */ - - static FT_Error Load_PairSet ( TTO_PairSet* ps, - FT_UShort format1, - FT_UShort format2, - FT_Stream stream ) - { - FT_Error error; - FT_Memory memory = stream->memory; - - FT_UShort n, m, count; - FT_ULong base_offset; - - TTO_PairValueRecord* pvr; - - - base_offset = FILE_Pos(); - - if ( ACCESS_Frame( 2L ) ) - return error; - - count = ps->PairValueCount = GET_UShort(); - - FORGET_Frame(); - - ps->PairValueRecord = NULL; - - if ( ALLOC_ARRAY( ps->PairValueRecord, count, TTO_PairValueRecord ) ) - return error; - - pvr = ps->PairValueRecord; - - for ( n = 0; n < count; n++ ) - { - if ( ACCESS_Frame( 2L ) ) - goto Fail; - - pvr[n].SecondGlyph = GET_UShort(); - - FORGET_Frame(); - - if ( format1 ) - { - error = Load_ValueRecord( &pvr[n].Value1, format1, - base_offset, stream ); - if ( error ) - goto Fail; - } - if ( format2 ) - { - error = Load_ValueRecord( &pvr[n].Value2, format2, - base_offset, stream ); - if ( error ) - { - if ( format1 ) - Free_ValueRecord( &pvr[n].Value1, format1, memory ); - goto Fail; - } - } - } - - return TT_Err_Ok; - - Fail: - for ( m = 0; m < n; m++ ) - { - if ( format1 ) - Free_ValueRecord( &pvr[m].Value1, format1, memory ); - if ( format2 ) - Free_ValueRecord( &pvr[m].Value2, format2, memory ); - } - - FREE( pvr ); - return error; - } - - - static void Free_PairSet( TTO_PairSet* ps, - FT_UShort format1, - FT_UShort format2, - FT_Memory memory ) - { - FT_UShort n, count; - - TTO_PairValueRecord* pvr; - - - if ( ps->PairValueRecord ) - { - count = ps->PairValueCount; - pvr = ps->PairValueRecord; - - for ( n = 0; n < count; n++ ) - { - if ( format1 ) - Free_ValueRecord( &pvr[n].Value1, format1, memory ); - if ( format2 ) - Free_ValueRecord( &pvr[n].Value2, format2, memory ); - } - - FREE( pvr ); - } - } - - - /* PairPosFormat1 */ - - static FT_Error Load_PairPos1( TTO_PairPosFormat1* ppf1, - FT_UShort format1, - FT_UShort format2, - FT_Stream stream ) - { - FT_Error error; - FT_Memory memory = stream->memory; - - FT_UShort n, m, count; - FT_ULong cur_offset, new_offset, base_offset; - - TTO_PairSet* ps; - - - base_offset = FILE_Pos() - 8L; - - if ( ACCESS_Frame( 2L ) ) - return error; - - count = ppf1->PairSetCount = GET_UShort(); - - FORGET_Frame(); - - ppf1->PairSet = NULL; - - if ( ALLOC_ARRAY( ppf1->PairSet, count, TTO_PairSet ) ) - return error; - - ps = ppf1->PairSet; - - for ( n = 0; n < count; n++ ) - { - if ( ACCESS_Frame( 2L ) ) - goto Fail; - - new_offset = GET_UShort() + base_offset; - - FORGET_Frame(); - - cur_offset = FILE_Pos(); - if ( FILE_Seek( new_offset ) || - ( error = Load_PairSet( &ps[n], format1, - format2, stream ) ) != TT_Err_Ok ) - goto Fail; - (void)FILE_Seek( cur_offset ); - } - - return TT_Err_Ok; - - Fail: - for ( m = 0; m < n; m++ ) - Free_PairSet( &ps[m], format1, format2, memory ); - - FREE( ps ); - return error; - } - - - static void Free_PairPos1( TTO_PairPosFormat1* ppf1, - FT_UShort format1, - FT_UShort format2, - FT_Memory memory ) - { - FT_UShort n, count; - - TTO_PairSet* ps; - - - if ( ppf1->PairSet ) - { - count = ppf1->PairSetCount; - ps = ppf1->PairSet; - - for ( n = 0; n < count; n++ ) - Free_PairSet( &ps[n], format1, format2, memory ); - - FREE( ps ); - } - } - - - /* PairPosFormat2 */ - - static FT_Error Load_PairPos2( TTO_PairPosFormat2* ppf2, - FT_UShort format1, - FT_UShort format2, - FT_Stream stream ) - { - FT_Error error; - FT_Memory memory = stream->memory; - - FT_UShort m, n, k, count1, count2; - FT_ULong cur_offset, new_offset1, new_offset2, base_offset; - - TTO_Class1Record* c1r; - TTO_Class2Record* c2r; - - - base_offset = FILE_Pos() - 8L; - - if ( ACCESS_Frame( 8L ) ) - return error; - - new_offset1 = GET_UShort() + base_offset; - new_offset2 = GET_UShort() + base_offset; - - /* `Class1Count' and `Class2Count' are the upper limits for class - values, thus we read it now to make additional safety checks. */ - - count1 = ppf2->Class1Count = GET_UShort(); - count2 = ppf2->Class2Count = GET_UShort(); - - FORGET_Frame(); - - cur_offset = FILE_Pos(); - if ( FILE_Seek( new_offset1 ) || - ( error = Load_ClassDefinition( &ppf2->ClassDef1, count1, - stream ) ) != TT_Err_Ok ) - return error; - if ( FILE_Seek( new_offset2 ) || - ( error = Load_ClassDefinition( &ppf2->ClassDef2, count2, - stream ) ) != TT_Err_Ok ) - goto Fail3; - (void)FILE_Seek( cur_offset ); - - ppf2->Class1Record = NULL; - - if ( ALLOC_ARRAY( ppf2->Class1Record, count1, TTO_Class1Record ) ) - goto Fail2; - - c1r = ppf2->Class1Record; - - for ( m = 0; m < count1; m++ ) - { - c1r[m].Class2Record = NULL; - - if ( ALLOC_ARRAY( c1r[m].Class2Record, count2, TTO_Class2Record ) ) - goto Fail1; - - c2r = c1r[m].Class2Record; - - for ( n = 0; n < count2; n++ ) - { - if ( format1 ) - { - error = Load_ValueRecord( &c2r[n].Value1, format1, - base_offset, stream ); - if ( error ) - goto Fail0; - } - if ( format2 ) - { - error = Load_ValueRecord( &c2r[n].Value2, format2, - base_offset, stream ); - if ( error ) - { - if ( format1 ) - Free_ValueRecord( &c2r[n].Value1, format1, memory ); - goto Fail0; - } - } - } - - continue; - - Fail0: - for ( k = 0; k < n; k++ ) - { - if ( format1 ) - Free_ValueRecord( &c2r[k].Value1, format1, memory ); - if ( format2 ) - Free_ValueRecord( &c2r[k].Value2, format2, memory ); - } - goto Fail1; - } - - return TT_Err_Ok; - - Fail1: - for ( k = 0; k < m; k++ ) - { - c2r = c1r[k].Class2Record; - - for ( n = 0; n < count2; n++ ) - { - if ( format1 ) - Free_ValueRecord( &c2r[n].Value1, format1, memory ); - if ( format2 ) - Free_ValueRecord( &c2r[n].Value2, format2, memory ); - } - - FREE( c2r ); - } - - FREE( c1r ); - Fail2: - - Free_ClassDefinition( &ppf2->ClassDef2, memory ); - - Fail3: - Free_ClassDefinition( &ppf2->ClassDef1, memory ); - return error; - } - - - static void Free_PairPos2( TTO_PairPosFormat2* ppf2, - FT_UShort format1, - FT_UShort format2, - FT_Memory memory ) - { - FT_UShort m, n, count1, count2; - - TTO_Class1Record* c1r; - TTO_Class2Record* c2r; - - - if ( ppf2->Class1Record ) - { - c1r = ppf2->Class1Record; - count1 = ppf2->Class1Count; - count2 = ppf2->Class2Count; - - for ( m = 0; m < count1; m++ ) - { - c2r = c1r[m].Class2Record; - - for ( n = 0; n < count2; n++ ) - { - if ( format1 ) - Free_ValueRecord( &c2r[n].Value1, format1, memory ); - if ( format2 ) - Free_ValueRecord( &c2r[n].Value2, format2, memory ); - } - - FREE( c2r ); - } - - FREE( c1r ); - - Free_ClassDefinition( &ppf2->ClassDef2, memory ); - Free_ClassDefinition( &ppf2->ClassDef1, memory ); - } - } - - - FT_Error Load_PairPos( TTO_PairPos* pp, - FT_Stream stream ) - { - FT_Error error; - FT_Memory memory = stream->memory; - - FT_UShort format1, format2; - FT_ULong cur_offset, new_offset, base_offset; - - - base_offset = FILE_Pos(); - - if ( ACCESS_Frame( 8L ) ) - return error; - - pp->PosFormat = GET_UShort(); - new_offset = GET_UShort() + base_offset; - - format1 = pp->ValueFormat1 = GET_UShort(); - format2 = pp->ValueFormat2 = GET_UShort(); - - FORGET_Frame(); - - cur_offset = FILE_Pos(); - if ( FILE_Seek( new_offset ) || - ( error = Load_Coverage( &pp->Coverage, stream ) ) != TT_Err_Ok ) - return error; - (void)FILE_Seek( cur_offset ); - - switch ( pp->PosFormat ) - { - case 1: - error = Load_PairPos1( &pp->ppf.ppf1, format1, format2, stream ); - if ( error ) - goto Fail; - break; - - case 2: - error = Load_PairPos2( &pp->ppf.ppf2, format1, format2, stream ); - if ( error ) - goto Fail; - break; - - default: - return TTO_Err_Invalid_GPOS_SubTable_Format; - } - - return TT_Err_Ok; - - Fail: - Free_Coverage( &pp->Coverage, memory ); - return error; - } - - - void Free_PairPos( TTO_PairPos* pp, - FT_Memory memory ) - { - FT_UShort format1, format2; - - - format1 = pp->ValueFormat1; - format2 = pp->ValueFormat2; - - switch ( pp->PosFormat ) - { - case 1: - Free_PairPos1( &pp->ppf.ppf1, format1, format2, memory ); - break; - - case 2: - Free_PairPos2( &pp->ppf.ppf2, format1, format2, memory ); - break; - } - - Free_Coverage( &pp->Coverage, memory ); - } - - - static FT_Error Lookup_PairPos1( GPOS_Instance* gpi, - TTO_PairPosFormat1* ppf1, - OTL_Buffer buffer, - FT_UShort first_pos, - FT_UShort index, - FT_UShort format1, - FT_UShort format2 ) - { - FT_Error error; - FT_UShort numpvr, glyph2; - - TTO_PairValueRecord* pvr; - - - if ( index >= ppf1->PairSetCount ) - return TTO_Err_Invalid_GPOS_SubTable; - - pvr = ppf1->PairSet[index].PairValueRecord; - if ( !pvr ) - return TTO_Err_Invalid_GPOS_SubTable; - - glyph2 = IN_CURGLYPH(); - - for ( numpvr = ppf1->PairSet[index].PairValueCount; - numpvr; - numpvr--, pvr++ ) - { - if ( glyph2 == pvr->SecondGlyph ) - { - error = Get_ValueRecord( gpi, &pvr->Value1, format1, - POSITION( first_pos ) ); - if ( error ) - return error; - return Get_ValueRecord( gpi, &pvr->Value2, format2, - POSITION( buffer->in_pos ) ); - } - } - - return TTO_Err_Not_Covered; - } - - - static FT_Error Lookup_PairPos2( GPOS_Instance* gpi, - TTO_PairPosFormat2* ppf2, - OTL_Buffer buffer, - FT_UShort first_pos, - FT_UShort format1, - FT_UShort format2 ) - { - FT_Error error; - FT_UShort cl1, cl2; - - TTO_Class1Record* c1r; - TTO_Class2Record* c2r; - - - error = Get_Class( &ppf2->ClassDef1, IN_GLYPH( first_pos ), - &cl1, NULL ); - if ( error && error != TTO_Err_Not_Covered ) - return error; - error = Get_Class( &ppf2->ClassDef2, IN_CURGLYPH(), - &cl2, NULL ); - if ( error && error != TTO_Err_Not_Covered ) - return error; - - c1r = &ppf2->Class1Record[cl1]; - if ( !c1r ) - return TTO_Err_Invalid_GPOS_SubTable; - c2r = &c1r->Class2Record[cl2]; - - error = Get_ValueRecord( gpi, &c2r->Value1, format1, POSITION( first_pos ) ); - if ( error ) - return error; - return Get_ValueRecord( gpi, &c2r->Value2, format2, POSITION( buffer->in_pos ) ); - } - - - static FT_Error Lookup_PairPos( GPOS_Instance* gpi, - TTO_GPOS_SubTable* st, - OTL_Buffer buffer, - FT_UShort flags, - FT_UShort context_length, - int nesting_level ) - { - FT_Error error; - FT_UShort index, property, first_pos; - TTO_GPOSHeader* gpos = gpi->gpos; - TTO_PairPos* pp = &st->pair; - - - if ( buffer->in_pos >= buffer->in_length - 1 ) - return TTO_Err_Not_Covered; /* Not enough glyphs in stream */ - - if ( context_length != 0xFFFF && context_length < 2 ) - return TTO_Err_Not_Covered; - - if ( CHECK_Property( gpos->gdef, IN_CURITEM(), flags, &property ) ) - return error; - - error = Coverage_Index( &pp->Coverage, IN_CURGLYPH(), &index ); - if ( error ) - return error; - - /* second glyph */ - - first_pos = buffer->in_pos; - (buffer->in_pos)++; - - while ( CHECK_Property( gpos->gdef, IN_CURITEM(), - flags, &property ) ) - { - if ( error && error != TTO_Err_Not_Covered ) - return error; - - if ( buffer->in_pos == buffer->in_length ) - return TTO_Err_Not_Covered; - (buffer->in_pos)++; - } - - switch ( pp->PosFormat ) - { - case 1: - error = Lookup_PairPos1( gpi, &pp->ppf.ppf1, buffer, - first_pos, index, - pp->ValueFormat1, pp->ValueFormat2 ); - break; - - case 2: - error = Lookup_PairPos2( gpi, &pp->ppf.ppf2, buffer, first_pos, - pp->ValueFormat1, pp->ValueFormat2 ); - break; - - default: - return TTO_Err_Invalid_GPOS_SubTable_Format; - } - - /* adjusting the `next' glyph */ - - if ( pp->ValueFormat2 ) - (buffer->in_pos)++; - - return error; - } - - - /* LookupType 3 */ - - /* CursivePosFormat1 */ - - FT_Error Load_CursivePos( TTO_CursivePos* cp, - FT_Stream stream ) - { - FT_Error error; - FT_Memory memory = stream->memory; - - FT_UShort n, m, count; - FT_ULong cur_offset, new_offset, base_offset; - - TTO_EntryExitRecord* eer; - - - base_offset = FILE_Pos(); - - if ( ACCESS_Frame( 4L ) ) - return error; - - cp->PosFormat = GET_UShort(); - new_offset = GET_UShort() + base_offset; - - FORGET_Frame(); - - cur_offset = FILE_Pos(); - if ( FILE_Seek( new_offset ) || - ( error = Load_Coverage( &cp->Coverage, stream ) ) != TT_Err_Ok ) - return error; - (void)FILE_Seek( cur_offset ); - - if ( ACCESS_Frame( 2L ) ) - goto Fail2; - - count = cp->EntryExitCount = GET_UShort(); - - FORGET_Frame(); - - cp->EntryExitRecord = NULL; - - if ( ALLOC_ARRAY( cp->EntryExitRecord, count, TTO_EntryExitRecord ) ) - goto Fail2; - - eer = cp->EntryExitRecord; - - for ( n = 0; n < count; n++ ) - { - FT_ULong entry_offset; - - if ( ACCESS_Frame( 2L ) ) - return error; - - entry_offset = new_offset = GET_UShort(); - - FORGET_Frame(); - - if ( new_offset ) - { - new_offset += base_offset; - - cur_offset = FILE_Pos(); - if ( FILE_Seek( new_offset ) || - ( error = Load_Anchor( &eer[n].EntryAnchor, - stream ) ) != TT_Err_Ok ) - goto Fail1; - (void)FILE_Seek( cur_offset ); - } - else - eer[n].EntryAnchor.PosFormat = 0; - - if ( ACCESS_Frame( 2L ) ) - return error; - - new_offset = GET_UShort(); - - FORGET_Frame(); - - if ( new_offset ) - { - new_offset += base_offset; - - cur_offset = FILE_Pos(); - if ( FILE_Seek( new_offset ) || - ( error = Load_Anchor( &eer[n].ExitAnchor, - stream ) ) != TT_Err_Ok ) - { - if ( entry_offset ) - Free_Anchor( &eer[n].EntryAnchor, memory ); - goto Fail1; - } - (void)FILE_Seek( cur_offset ); - } - else - eer[n].ExitAnchor.PosFormat = 0; - } - - return TT_Err_Ok; - - Fail1: - for ( m = 0; m < n; m++ ) - { - Free_Anchor( &eer[m].EntryAnchor, memory ); - Free_Anchor( &eer[m].ExitAnchor, memory ); - } - - FREE( eer ); - - Fail2: - Free_Coverage( &cp->Coverage, memory ); - return error; - } - - - void Free_CursivePos( TTO_CursivePos* cp, - FT_Memory memory ) - { - FT_UShort n, count; - - TTO_EntryExitRecord* eer; - - - if ( cp->EntryExitRecord ) - { - count = cp->EntryExitCount; - eer = cp->EntryExitRecord; - - for ( n = 0; n < count; n++ ) - { - Free_Anchor( &eer[n].EntryAnchor, memory ); - Free_Anchor( &eer[n].ExitAnchor, memory ); - } - - FREE( eer ); - } - - Free_Coverage( &cp->Coverage, memory ); - } - - - static FT_Error Lookup_CursivePos( GPOS_Instance* gpi, - TTO_GPOS_SubTable* st, - OTL_Buffer buffer, - FT_UShort flags, - FT_UShort context_length, - int nesting_level ) - { - FT_UShort index, property; - FT_Error error; - TTO_GPOSHeader* gpos = gpi->gpos; - TTO_CursivePos* cp = &st->cursive; - - TTO_EntryExitRecord* eer; - FT_Pos entry_x, entry_y; - FT_Pos exit_x, exit_y; - - - if ( context_length != 0xFFFF && context_length < 1 ) - { - gpi->last = 0xFFFF; - return TTO_Err_Not_Covered; - } - - /* Glyphs not having the right GDEF properties will be ignored, i.e., - gpi->last won't be reset (contrary to user defined properties). */ - - if ( CHECK_Property( gpos->gdef, IN_CURITEM(), flags, &property ) ) - return error; - - /* We don't handle mark glyphs here. According to Andrei, this isn't - possible, but who knows... */ - - if ( property == MARK_GLYPH ) - { - gpi->last = 0xFFFF; - return TTO_Err_Not_Covered; - } - - error = Coverage_Index( &cp->Coverage, IN_CURGLYPH(), &index ); - if ( error ) - { - gpi->last = 0xFFFF; - return error; - } - - if ( index >= cp->EntryExitCount ) - return TTO_Err_Invalid_GPOS_SubTable; - - eer = &cp->EntryExitRecord[index]; - - /* Now comes the messiest part of the whole OpenType - specification. At first glance, cursive connections seem easy - to understand, but there are pitfalls! The reason is that - the specs don't mention how to compute the advance values - resp. glyph offsets. I was told it would be an omission, to - be fixed in the next OpenType version... Again many thanks to - Andrei Burago for clarifications. - - Consider the following example: - - | xadv1 | - +---------+ - | | - +-----+--+ 1 | - | | .| | - | 0+--+------+ - | 2 | - | | - 0+--------+ - | xadv2 | - - glyph1: advance width = 12 - anchor point = (3,1) - - glyph2: advance width = 11 - anchor point = (9,4) - - LSB is 1 for both glyphs (so the boxes drawn above are glyph - bboxes). Writing direction is R2L; `0' denotes the glyph's - coordinate origin. - - Now the surprising part: The advance width of the *left* glyph - (resp. of the *bottom* glyph) will be modified, no matter - whether the writing direction is L2R or R2L (resp. T2B or - B2T)! This assymetry is caused by the fact that the glyph's - coordinate origin is always the lower left corner for all - writing directions. - - Continuing the above example, we can compute the new - (horizontal) advance width of glyph2 as - - 9 - 3 = 6 , - - and the new vertical offset of glyph2 as - - 1 - 4 = -3 . - - - Vertical writing direction is far more complicated: - - a) Assuming that we recompute the advance height of the lower glyph: - - -- - +---------+ - -- | | - +-----+--+ 1 | yadv1 - | | .| | - yadv2 | 0+--+------+ -- BSB1 -- - | 2 | -- -- y_offset - | | - BSB2 -- 0+--------+ -- - -- -- - - glyph1: advance height = 6 - anchor point = (3,1) - - glyph2: advance height = 7 - anchor point = (9,4) - - TSB is 1 for both glyphs; writing direction is T2B. - - - BSB1 = yadv1 - (TSB1 + ymax1) - BSB2 = yadv2 - (TSB2 + ymax2) - y_offset = y2 - y1 - - vertical advance width of glyph2 - = y_offset + BSB2 - BSB1 - = (y2 - y1) + (yadv2 - (TSB2 + ymax2)) - (yadv1 - (TSB1 + ymax1)) - = y2 - y1 + yadv2 - TSB2 - ymax2 - (yadv1 - TSB1 - ymax1) - = y2 - y1 + yadv2 - TSB2 - ymax2 - yadv1 + TSB1 + ymax1 - - - b) Assuming that we recompute the advance height of the upper glyph: - - -- -- - +---------+ -- TSB1 - -- -- | | - TSB2 -- +-----+--+ 1 | yadv1 ymax1 - | | .| | - yadv2 | 0+--+------+ -- -- - ymax2 | 2 | -- y_offset - | | - -- 0+--------+ -- - -- - - glyph1: advance height = 6 - anchor point = (3,1) - - glyph2: advance height = 7 - anchor point = (9,4) - - TSB is 1 for both glyphs; writing direction is T2B. - - y_offset = y2 - y1 - - vertical advance width of glyph2 - = TSB1 + ymax1 + y_offset - (TSB2 + ymax2) - = TSB1 + ymax1 + y2 - y1 - TSB2 - ymax2 - - - Comparing a) with b) shows that b) is easier to compute. I'll wait - for a reply from Andrei to see what should really be implemented... - - Since horizontal advance widths or vertical advance heights - can be used alone but not together, no ambiguity occurs. */ - - if ( gpi->last == 0xFFFF ) - goto end; - - /* Get_Anchor() returns TTO_Err_Not_Covered if there is no anchor - table. */ - - error = Get_Anchor( gpi, &eer->EntryAnchor, IN_CURGLYPH(), - &entry_x, &entry_y ); - if ( error == TTO_Err_Not_Covered ) - goto end; - if ( error ) - return error; - - if ( gpi->r2l ) - { - POSITION( buffer->in_pos )->x_advance = entry_x - gpi->anchor_x; - POSITION( buffer->in_pos )->new_advance = TRUE; - } - else - { - POSITION( gpi->last )->x_advance = gpi->anchor_x - entry_x; - POSITION( gpi->last )->new_advance = TRUE; - } - - if ( flags & RIGHT_TO_LEFT ) - { - POSITION( gpi->last )->cursive_chain = gpi->last - buffer->in_pos; - POSITION( gpi->last )->y_pos = entry_y - gpi->anchor_y; - } - else - { - POSITION( buffer->in_pos )->cursive_chain = buffer->in_pos - gpi->last; - POSITION( buffer->in_pos )->y_pos = gpi->anchor_y - entry_y; - } - - end: - error = Get_Anchor( gpi, &eer->ExitAnchor, IN_CURGLYPH(), - &exit_x, &exit_y ); - if ( error == TTO_Err_Not_Covered ) - gpi->last = 0xFFFF; - else - { - gpi->last = buffer->in_pos; - gpi->anchor_x = exit_x; - gpi->anchor_y = exit_y; - } - if ( error ) - return error; - - (buffer->in_pos)++; - - return TT_Err_Ok; - } - - - /* LookupType 4 */ - - /* BaseArray */ - - static FT_Error Load_BaseArray( TTO_BaseArray* ba, - FT_UShort num_classes, - FT_Stream stream ) - { - FT_Error error; - FT_Memory memory = stream->memory; - - FT_UShort m, n, k, count; - FT_ULong cur_offset, new_offset, base_offset; - - TTO_BaseRecord* br; - TTO_Anchor* ban; - - - base_offset = FILE_Pos(); - - if ( ACCESS_Frame( 2L ) ) - return error; - - count = ba->BaseCount = GET_UShort(); - - FORGET_Frame(); - - ba->BaseRecord = NULL; - - if ( ALLOC_ARRAY( ba->BaseRecord, count, TTO_BaseRecord ) ) - return error; - - br = ba->BaseRecord; - - for ( m = 0; m < count; m++ ) - { - br[m].BaseAnchor = NULL; - - if ( ALLOC_ARRAY( br[m].BaseAnchor, num_classes, TTO_Anchor ) ) - goto Fail; - - ban = br[m].BaseAnchor; - - for ( n = 0; n < num_classes; n++ ) - { - if ( ACCESS_Frame( 2L ) ) - goto Fail0; - - new_offset = GET_UShort() + base_offset; - - FORGET_Frame(); - - if (new_offset == base_offset) { - /* Doulos SIL Regular is buggy and has zer offsets here. Skip */ - ban[n].PosFormat = 0; - continue; - } - - cur_offset = FILE_Pos(); - if ( FILE_Seek( new_offset ) || - ( error = Load_Anchor( &ban[n], stream ) ) != TT_Err_Ok ) - goto Fail0; - (void)FILE_Seek( cur_offset ); - } - - continue; - Fail0: - for ( k = 0; k < n; k++ ) - Free_Anchor( &ban[k], memory ); - goto Fail; - } - - return TT_Err_Ok; - - Fail: - for ( k = 0; k < m; k++ ) - { - ban = br[k].BaseAnchor; - - for ( n = 0; n < num_classes; n++ ) - Free_Anchor( &ban[n], memory ); - - FREE( ban ); - } - - FREE( br ); - return error; - } - - - static void Free_BaseArray( TTO_BaseArray* ba, - FT_UShort num_classes, - FT_Memory memory ) - { - FT_UShort m, n, count; - - TTO_BaseRecord* br; - TTO_Anchor* ban; - - - if ( ba->BaseRecord ) - { - count = ba->BaseCount; - br = ba->BaseRecord; - - for ( m = 0; m < count; m++ ) - { - ban = br[m].BaseAnchor; - - for ( n = 0; n < num_classes; n++ ) - Free_Anchor( &ban[n], memory ); - - FREE( ban ); - } - - FREE( br ); - } - } - - - /* MarkBasePosFormat1 */ - - FT_Error Load_MarkBasePos( TTO_MarkBasePos* mbp, - FT_Stream stream ) - { - FT_Error error; - FT_Memory memory = stream->memory; - - FT_ULong cur_offset, new_offset, base_offset; - - - base_offset = FILE_Pos(); - - if ( ACCESS_Frame( 4L ) ) - return error; - - mbp->PosFormat = GET_UShort(); - new_offset = GET_UShort() + base_offset; - - FORGET_Frame(); - - if (mbp->PosFormat != 1) - return TTO_Err_Invalid_SubTable_Format; - - cur_offset = FILE_Pos(); - if ( FILE_Seek( new_offset ) || - ( error = Load_Coverage( &mbp->MarkCoverage, stream ) ) != TT_Err_Ok ) - return error; - (void)FILE_Seek( cur_offset ); - - if ( ACCESS_Frame( 2L ) ) - goto Fail3; - - new_offset = GET_UShort() + base_offset; - - FORGET_Frame(); - - cur_offset = FILE_Pos(); - if ( FILE_Seek( new_offset ) || - ( error = Load_Coverage( &mbp->BaseCoverage, stream ) ) != TT_Err_Ok ) - goto Fail3; - (void)FILE_Seek( cur_offset ); - - if ( ACCESS_Frame( 4L ) ) - goto Fail2; - - mbp->ClassCount = GET_UShort(); - new_offset = GET_UShort() + base_offset; - - FORGET_Frame(); - - cur_offset = FILE_Pos(); - if ( FILE_Seek( new_offset ) || - ( error = Load_MarkArray( &mbp->MarkArray, stream ) ) != TT_Err_Ok ) - goto Fail2; - (void)FILE_Seek( cur_offset ); - - if ( ACCESS_Frame( 2L ) ) - goto Fail1; - - new_offset = GET_UShort() + base_offset; - - FORGET_Frame(); - - cur_offset = FILE_Pos(); - if ( FILE_Seek( new_offset ) || - ( error = Load_BaseArray( &mbp->BaseArray, mbp->ClassCount, - stream ) ) != TT_Err_Ok ) - goto Fail1; - - return TT_Err_Ok; - - Fail1: - Free_MarkArray( &mbp->MarkArray, memory ); - - Fail2: - Free_Coverage( &mbp->BaseCoverage, memory ); - - Fail3: - Free_Coverage( &mbp->MarkCoverage, memory ); - return error; - } - - - void Free_MarkBasePos( TTO_MarkBasePos* mbp, - FT_Memory memory ) - { - Free_BaseArray( &mbp->BaseArray, mbp->ClassCount, memory ); - Free_MarkArray( &mbp->MarkArray, memory ); - Free_Coverage( &mbp->BaseCoverage, memory ); - Free_Coverage( &mbp->MarkCoverage, memory ); - } - - - static FT_Error Lookup_MarkBasePos( GPOS_Instance* gpi, - TTO_GPOS_SubTable* st, - OTL_Buffer buffer, - FT_UShort flags, - FT_UShort context_length, - int nesting_level ) - { - FT_UShort i, j, mark_index, base_index, property, class; - FT_Pos x_mark_value, y_mark_value, x_base_value, y_base_value; - FT_Error error; - TTO_GPOSHeader* gpos = gpi->gpos; - TTO_MarkBasePos* mbp = &st->markbase; - - TTO_MarkArray* ma; - TTO_BaseArray* ba; - TTO_BaseRecord* br; - TTO_Anchor* mark_anchor; - TTO_Anchor* base_anchor; - - OTL_Position o; - - - if ( context_length != 0xFFFF && context_length < 1 ) - return TTO_Err_Not_Covered; - - if ( flags & IGNORE_BASE_GLYPHS ) - return TTO_Err_Not_Covered; - - if ( CHECK_Property( gpos->gdef, IN_CURITEM(), - flags, &property ) ) - return error; - - error = Coverage_Index( &mbp->MarkCoverage, IN_CURGLYPH(), - &mark_index ); - if ( error ) - return error; - - /* now we search backwards for a non-mark glyph */ - - i = 1; - j = buffer->in_pos - 1; - - while ( i <= buffer->in_pos ) - { - error = TT_GDEF_Get_Glyph_Property( gpos->gdef, IN_GLYPH( j ), - &property ); - if ( error ) - return error; - - if ( !( property == TTO_MARK || property & IGNORE_SPECIAL_MARKS ) ) - break; - - i++; - j--; - } - - /* The following assertion is too strong -- at least for mangal.ttf. */ -#if 0 - if ( property != TTO_BASE_GLYPH ) - return TTO_Err_Not_Covered; -#endif - - if ( i > buffer->in_pos ) - return TTO_Err_Not_Covered; - - error = Coverage_Index( &mbp->BaseCoverage, IN_GLYPH( j ), - &base_index ); - if ( error ) - return error; - - ma = &mbp->MarkArray; - - if ( mark_index >= ma->MarkCount ) - return TTO_Err_Invalid_GPOS_SubTable; - - class = ma->MarkRecord[mark_index].Class; - mark_anchor = &ma->MarkRecord[mark_index].MarkAnchor; - - if ( class >= mbp->ClassCount ) - return TTO_Err_Invalid_GPOS_SubTable; - - ba = &mbp->BaseArray; - - if ( base_index >= ba->BaseCount ) - return TTO_Err_Invalid_GPOS_SubTable; - - br = &ba->BaseRecord[base_index]; - base_anchor = &br->BaseAnchor[class]; - - error = Get_Anchor( gpi, mark_anchor, IN_CURGLYPH(), - &x_mark_value, &y_mark_value ); - if ( error ) - return error; - - error = Get_Anchor( gpi, base_anchor, IN_GLYPH( j ), - &x_base_value, &y_base_value ); - if ( error ) - return error; - - /* anchor points are not cumulative */ - - o = POSITION( buffer->in_pos ); - - o->x_pos = x_base_value - x_mark_value; - o->y_pos = y_base_value - y_mark_value; - o->x_advance = 0; - o->y_advance = 0; - o->back = i; - - (buffer->in_pos)++; - - return TT_Err_Ok; - } - - - /* LookupType 5 */ - - /* LigatureAttach */ - - static FT_Error Load_LigatureAttach( TTO_LigatureAttach* lat, - FT_UShort num_classes, - FT_Stream stream ) - { - FT_Error error; - FT_Memory memory = stream->memory; - - FT_UShort m, n, k, count; - FT_ULong cur_offset, new_offset, base_offset; - - TTO_ComponentRecord* cr; - TTO_Anchor* lan; - - - base_offset = FILE_Pos(); - - if ( ACCESS_Frame( 2L ) ) - return error; - - count = lat->ComponentCount = GET_UShort(); - - FORGET_Frame(); - - lat->ComponentRecord = NULL; - - if ( ALLOC_ARRAY( lat->ComponentRecord, count, TTO_ComponentRecord ) ) - return error; - - cr = lat->ComponentRecord; - - for ( m = 0; m < count; m++ ) - { - cr[m].LigatureAnchor = NULL; - - if ( ALLOC_ARRAY( cr[m].LigatureAnchor, num_classes, TTO_Anchor ) ) - goto Fail; - - lan = cr[m].LigatureAnchor; - - for ( n = 0; n < num_classes; n++ ) - { - if ( ACCESS_Frame( 2L ) ) - goto Fail0; - - new_offset = GET_UShort(); - - FORGET_Frame(); - - if ( new_offset ) - { - new_offset += base_offset; - - cur_offset = FILE_Pos(); - if ( FILE_Seek( new_offset ) || - ( error = Load_Anchor( &lan[n], stream ) ) != TT_Err_Ok ) - goto Fail0; - (void)FILE_Seek( cur_offset ); - } - else - lan[n].PosFormat = 0; - } - - continue; - Fail0: - for ( k = 0; k < n; k++ ) - Free_Anchor( &lan[k], memory ); - goto Fail; - } - - return TT_Err_Ok; - - Fail: - for ( k = 0; k < m; k++ ) - { - lan = cr[k].LigatureAnchor; - - for ( n = 0; n < num_classes; n++ ) - Free_Anchor( &lan[n], memory ); - - FREE( lan ); - } - - FREE( cr ); - return error; - } - - - static void Free_LigatureAttach( TTO_LigatureAttach* lat, - FT_UShort num_classes, - FT_Memory memory ) - { - FT_UShort m, n, count; - - TTO_ComponentRecord* cr; - TTO_Anchor* lan; - - - if ( lat->ComponentRecord ) - { - count = lat->ComponentCount; - cr = lat->ComponentRecord; - - for ( m = 0; m < count; m++ ) - { - lan = cr[m].LigatureAnchor; - - for ( n = 0; n < num_classes; n++ ) - Free_Anchor( &lan[n], memory ); - - FREE( lan ); - } - - FREE( cr ); - } - } - - - /* LigatureArray */ - - static FT_Error Load_LigatureArray( TTO_LigatureArray* la, - FT_UShort num_classes, - FT_Stream stream ) - { - FT_Error error; - FT_Memory memory = stream->memory; - - FT_UShort n, m, count; - FT_ULong cur_offset, new_offset, base_offset; - - TTO_LigatureAttach* lat; - - - base_offset = FILE_Pos(); - - if ( ACCESS_Frame( 2L ) ) - return error; - - count = la->LigatureCount = GET_UShort(); - - FORGET_Frame(); - - la->LigatureAttach = NULL; - - if ( ALLOC_ARRAY( la->LigatureAttach, count, TTO_LigatureAttach ) ) - return error; - - lat = la->LigatureAttach; - - for ( n = 0; n < count; n++ ) - { - if ( ACCESS_Frame( 2L ) ) - goto Fail; - - new_offset = GET_UShort() + base_offset; - - FORGET_Frame(); - - cur_offset = FILE_Pos(); - if ( FILE_Seek( new_offset ) || - ( error = Load_LigatureAttach( &lat[n], num_classes, - stream ) ) != TT_Err_Ok ) - goto Fail; - (void)FILE_Seek( cur_offset ); - } - - return TT_Err_Ok; - - Fail: - for ( m = 0; m < n; m++ ) - Free_LigatureAttach( &lat[m], num_classes, memory ); - - FREE( lat ); - return error; - } - - - static void Free_LigatureArray( TTO_LigatureArray* la, - FT_UShort num_classes, - FT_Memory memory ) - { - FT_UShort n, count; - - TTO_LigatureAttach* lat; - - - if ( la->LigatureAttach ) - { - count = la->LigatureCount; - lat = la->LigatureAttach; - - for ( n = 0; n < count; n++ ) - Free_LigatureAttach( &lat[n], num_classes, memory ); - - FREE( lat ); - } - } - - - /* MarkLigPosFormat1 */ - - FT_Error Load_MarkLigPos( TTO_MarkLigPos* mlp, - FT_Stream stream ) - { - FT_Error error; - FT_Memory memory = stream->memory; - - FT_ULong cur_offset, new_offset, base_offset; - - - base_offset = FILE_Pos(); - - if ( ACCESS_Frame( 4L ) ) - return error; - - mlp->PosFormat = GET_UShort(); - new_offset = GET_UShort() + base_offset; - - FORGET_Frame(); - - cur_offset = FILE_Pos(); - if ( FILE_Seek( new_offset ) || - ( error = Load_Coverage( &mlp->MarkCoverage, stream ) ) != TT_Err_Ok ) - return error; - (void)FILE_Seek( cur_offset ); - - if ( ACCESS_Frame( 2L ) ) - goto Fail3; - - new_offset = GET_UShort() + base_offset; - - FORGET_Frame(); - - cur_offset = FILE_Pos(); - if ( FILE_Seek( new_offset ) || - ( error = Load_Coverage( &mlp->LigatureCoverage, - stream ) ) != TT_Err_Ok ) - goto Fail3; - (void)FILE_Seek( cur_offset ); - - if ( ACCESS_Frame( 4L ) ) - goto Fail2; - - mlp->ClassCount = GET_UShort(); - new_offset = GET_UShort() + base_offset; - - FORGET_Frame(); - - cur_offset = FILE_Pos(); - if ( FILE_Seek( new_offset ) || - ( error = Load_MarkArray( &mlp->MarkArray, stream ) ) != TT_Err_Ok ) - goto Fail2; - (void)FILE_Seek( cur_offset ); - - if ( ACCESS_Frame( 2L ) ) - goto Fail1; - - new_offset = GET_UShort() + base_offset; - - FORGET_Frame(); - - cur_offset = FILE_Pos(); - if ( FILE_Seek( new_offset ) || - ( error = Load_LigatureArray( &mlp->LigatureArray, mlp->ClassCount, - stream ) ) != TT_Err_Ok ) - goto Fail1; - - return TT_Err_Ok; - - Fail1: - Free_MarkArray( &mlp->MarkArray, memory ); - - Fail2: - Free_Coverage( &mlp->LigatureCoverage, memory ); - - Fail3: - Free_Coverage( &mlp->MarkCoverage, memory ); - return error; - } - - - void Free_MarkLigPos( TTO_MarkLigPos* mlp, - FT_Memory memory) - { - Free_LigatureArray( &mlp->LigatureArray, mlp->ClassCount, memory ); - Free_MarkArray( &mlp->MarkArray, memory ); - Free_Coverage( &mlp->LigatureCoverage, memory ); - Free_Coverage( &mlp->MarkCoverage, memory ); - } - - - static FT_Error Lookup_MarkLigPos( GPOS_Instance* gpi, - TTO_GPOS_SubTable* st, - OTL_Buffer buffer, - FT_UShort flags, - FT_UShort context_length, - int nesting_level ) - { - FT_UShort i, j, mark_index, lig_index, property, class; - FT_UShort mark_glyph; - FT_Pos x_mark_value, y_mark_value, x_lig_value, y_lig_value; - FT_Error error; - TTO_GPOSHeader* gpos = gpi->gpos; - TTO_MarkLigPos* mlp = &st->marklig; - - TTO_MarkArray* ma; - TTO_LigatureArray* la; - TTO_LigatureAttach* lat; - TTO_ComponentRecord* cr; - FT_UShort comp_index; - TTO_Anchor* mark_anchor; - TTO_Anchor* lig_anchor; - - OTL_Position o; - - - if ( context_length != 0xFFFF && context_length < 1 ) - return TTO_Err_Not_Covered; - - if ( flags & IGNORE_LIGATURES ) - return TTO_Err_Not_Covered; - - mark_glyph = IN_CURGLYPH(); - - if ( CHECK_Property( gpos->gdef, IN_CURITEM(), flags, &property ) ) - return error; - - error = Coverage_Index( &mlp->MarkCoverage, mark_glyph, &mark_index ); - if ( error ) - return error; - - /* now we search backwards for a non-mark glyph */ - - i = 1; - j = buffer->in_pos - 1; - - while ( i <= buffer->in_pos ) - { - error = TT_GDEF_Get_Glyph_Property( gpos->gdef, IN_GLYPH( j ), - &property ); - if ( error ) - return error; - - if ( !( property == TTO_MARK || property & IGNORE_SPECIAL_MARKS ) ) - break; - - i++; - j--; - } - - /* Similar to Lookup_MarkBasePos(), I suspect that this assertion is - too strong, thus it is commented out. */ -#if 0 - if ( property != TTO_LIGATURE ) - return TTO_Err_Not_Covered; -#endif - - if ( i > buffer->in_pos ) - return TTO_Err_Not_Covered; - - error = Coverage_Index( &mlp->LigatureCoverage, IN_GLYPH( j ), - &lig_index ); - if ( error ) - return error; - - ma = &mlp->MarkArray; - - if ( mark_index >= ma->MarkCount ) - return TTO_Err_Invalid_GPOS_SubTable; - - class = ma->MarkRecord[mark_index].Class; - mark_anchor = &ma->MarkRecord[mark_index].MarkAnchor; - - if ( class >= mlp->ClassCount ) - return TTO_Err_Invalid_GPOS_SubTable; - - la = &mlp->LigatureArray; - - if ( lig_index >= la->LigatureCount ) - return TTO_Err_Invalid_GPOS_SubTable; - - lat = &la->LigatureAttach[lig_index]; - - /* We must now check whether the ligature ID of the current mark glyph - is identical to the ligature ID of the found ligature. If yes, we - can directly use the component index. If not, we attach the mark - glyph to the last component of the ligature. */ - - if ( IN_LIGID( j ) == IN_LIGID( buffer->in_pos) ) - { - comp_index = IN_COMPONENT( buffer->in_pos ); - if ( comp_index >= lat->ComponentCount ) - return TTO_Err_Not_Covered; - } - else - comp_index = lat->ComponentCount - 1; - - cr = &lat->ComponentRecord[comp_index]; - lig_anchor = &cr->LigatureAnchor[class]; - - error = Get_Anchor( gpi, mark_anchor, IN_CURGLYPH(), - &x_mark_value, &y_mark_value ); - if ( error ) - return error; - error = Get_Anchor( gpi, lig_anchor, IN_GLYPH( j ), - &x_lig_value, &y_lig_value ); - if ( error ) - return error; - - /* anchor points are not cumulative */ - - o = POSITION( buffer->in_pos ); - - o->x_pos = x_lig_value - x_mark_value; - o->y_pos = y_lig_value - y_mark_value; - o->x_advance = 0; - o->y_advance = 0; - o->back = i; - - (buffer->in_pos)++; - - return TT_Err_Ok; - } - - - /* LookupType 6 */ - - /* Mark2Array */ - - static FT_Error Load_Mark2Array( TTO_Mark2Array* m2a, - FT_UShort num_classes, - FT_Stream stream ) - { - FT_Error error; - FT_Memory memory = stream->memory; - - FT_UShort k, m, n, count; - FT_ULong cur_offset, new_offset, base_offset; - - TTO_Mark2Record* m2r; - TTO_Anchor* m2an; - - - base_offset = FILE_Pos(); - - if ( ACCESS_Frame( 2L ) ) - return error; - - count = m2a->Mark2Count = GET_UShort(); - - FORGET_Frame(); - - m2a->Mark2Record = NULL; - - if ( ALLOC_ARRAY( m2a->Mark2Record, count, TTO_Mark2Record ) ) - return error; - - m2r = m2a->Mark2Record; - - for ( m = 0; m < count; m++ ) - { - m2r[m].Mark2Anchor = NULL; - - if ( ALLOC_ARRAY( m2r[m].Mark2Anchor, num_classes, TTO_Anchor ) ) - goto Fail; - - m2an = m2r[m].Mark2Anchor; - - for ( n = 0; n < num_classes; n++ ) - { - if ( ACCESS_Frame( 2L ) ) - goto Fail0; - - new_offset = GET_UShort() + base_offset; - - FORGET_Frame(); - - cur_offset = FILE_Pos(); - if ( FILE_Seek( new_offset ) || - ( error = Load_Anchor( &m2an[n], stream ) ) != TT_Err_Ok ) - goto Fail0; - (void)FILE_Seek( cur_offset ); - } - - continue; - Fail0: - for ( k = 0; k < n; k++ ) - Free_Anchor( &m2an[k], memory ); - goto Fail; - } - - return TT_Err_Ok; - - Fail: - for ( k = 0; k < m; k++ ) - { - m2an = m2r[k].Mark2Anchor; - - for ( n = 0; n < num_classes; n++ ) - Free_Anchor( &m2an[n], memory ); - - FREE( m2an ); - } - - FREE( m2r ); - return error; - } - - - static void Free_Mark2Array( TTO_Mark2Array* m2a, - FT_UShort num_classes, - FT_Memory memory ) - { - FT_UShort m, n, count; - - TTO_Mark2Record* m2r; - TTO_Anchor* m2an; - - - if ( m2a->Mark2Record ) - { - count = m2a->Mark2Count; - m2r = m2a->Mark2Record; - - for ( m = 0; m < count; m++ ) - { - m2an = m2r[m].Mark2Anchor; - - for ( n = 0; n < num_classes; n++ ) - Free_Anchor( &m2an[n], memory ); - - FREE( m2an ); - } - - FREE( m2r ); - } - } - - - /* MarkMarkPosFormat1 */ - - FT_Error Load_MarkMarkPos( TTO_MarkMarkPos* mmp, - FT_Stream stream ) - { - FT_Error error; - FT_Memory memory = stream->memory; - - FT_ULong cur_offset, new_offset, base_offset; - - - base_offset = FILE_Pos(); - - if ( ACCESS_Frame( 4L ) ) - return error; - - mmp->PosFormat = GET_UShort(); - new_offset = GET_UShort() + base_offset; - - FORGET_Frame(); - - cur_offset = FILE_Pos(); - if ( FILE_Seek( new_offset ) || - ( error = Load_Coverage( &mmp->Mark1Coverage, - stream ) ) != TT_Err_Ok ) - return error; - (void)FILE_Seek( cur_offset ); - - if ( ACCESS_Frame( 2L ) ) - goto Fail3; - - new_offset = GET_UShort() + base_offset; - - FORGET_Frame(); - - cur_offset = FILE_Pos(); - if ( FILE_Seek( new_offset ) || - ( error = Load_Coverage( &mmp->Mark2Coverage, - stream ) ) != TT_Err_Ok ) - goto Fail3; - (void)FILE_Seek( cur_offset ); - - if ( ACCESS_Frame( 4L ) ) - goto Fail2; - - mmp->ClassCount = GET_UShort(); - new_offset = GET_UShort() + base_offset; - - FORGET_Frame(); - - cur_offset = FILE_Pos(); - if ( FILE_Seek( new_offset ) || - ( error = Load_MarkArray( &mmp->Mark1Array, stream ) ) != TT_Err_Ok ) - goto Fail2; - (void)FILE_Seek( cur_offset ); - - if ( ACCESS_Frame( 2L ) ) - goto Fail1; - - new_offset = GET_UShort() + base_offset; - - FORGET_Frame(); - - cur_offset = FILE_Pos(); - if ( FILE_Seek( new_offset ) || - ( error = Load_Mark2Array( &mmp->Mark2Array, mmp->ClassCount, - stream ) ) != TT_Err_Ok ) - goto Fail1; - - return TT_Err_Ok; - - Fail1: - Free_MarkArray( &mmp->Mark1Array, memory ); - - Fail2: - Free_Coverage( &mmp->Mark2Coverage, memory ); - - Fail3: - Free_Coverage( &mmp->Mark1Coverage, memory ); - return error; - } - - - void Free_MarkMarkPos( TTO_MarkMarkPos* mmp, - FT_Memory memory) - { - Free_Mark2Array( &mmp->Mark2Array, mmp->ClassCount, memory ); - Free_MarkArray( &mmp->Mark1Array, memory ); - Free_Coverage( &mmp->Mark2Coverage, memory ); - Free_Coverage( &mmp->Mark1Coverage, memory ); - } - - - static FT_Error Lookup_MarkMarkPos( GPOS_Instance* gpi, - TTO_GPOS_SubTable* st, - OTL_Buffer buffer, - FT_UShort flags, - FT_UShort context_length, - int nesting_level ) - { - FT_UShort j, mark1_index, mark2_index, property, class; - FT_Pos x_mark1_value, y_mark1_value, - x_mark2_value, y_mark2_value; - FT_Error error; - TTO_GPOSHeader* gpos = gpi->gpos; - TTO_MarkMarkPos* mmp = &st->markmark; - - TTO_MarkArray* ma1; - TTO_Mark2Array* ma2; - TTO_Mark2Record* m2r; - TTO_Anchor* mark1_anchor; - TTO_Anchor* mark2_anchor; - - OTL_Position o; - - - if ( context_length != 0xFFFF && context_length < 1 ) - return TTO_Err_Not_Covered; - - if ( flags & IGNORE_MARKS ) - return TTO_Err_Not_Covered; - - if ( CHECK_Property( gpos->gdef, IN_CURITEM(), - flags, &property ) ) - return error; - - error = Coverage_Index( &mmp->Mark1Coverage, IN_CURGLYPH(), - &mark1_index ); - if ( error ) - return error; - - /* now we check the preceding glyph whether it is a suitable - mark glyph */ - - if ( buffer->in_pos == 0 ) - return TTO_Err_Not_Covered; - - j = buffer->in_pos - 1; - error = TT_GDEF_Get_Glyph_Property( gpos->gdef, IN_GLYPH( j ), - &property ); - if ( error ) - return error; - - if ( flags & IGNORE_SPECIAL_MARKS ) - { - if ( property != (flags & 0xFF00) ) - return TTO_Err_Not_Covered; - } - else - { - if ( property != TTO_MARK ) - return TTO_Err_Not_Covered; - } - - error = Coverage_Index( &mmp->Mark2Coverage, IN_GLYPH( j ), - &mark2_index ); - if ( error ) - return error; - - ma1 = &mmp->Mark1Array; - - if ( mark1_index >= ma1->MarkCount ) - return TTO_Err_Invalid_GPOS_SubTable; - - class = ma1->MarkRecord[mark1_index].Class; - mark1_anchor = &ma1->MarkRecord[mark1_index].MarkAnchor; - - if ( class >= mmp->ClassCount ) - return TTO_Err_Invalid_GPOS_SubTable; - - ma2 = &mmp->Mark2Array; - - if ( mark2_index >= ma2->Mark2Count ) - return TTO_Err_Invalid_GPOS_SubTable; - - m2r = &ma2->Mark2Record[mark2_index]; - mark2_anchor = &m2r->Mark2Anchor[class]; - - error = Get_Anchor( gpi, mark1_anchor, IN_CURGLYPH(), - &x_mark1_value, &y_mark1_value ); - if ( error ) - return error; - error = Get_Anchor( gpi, mark2_anchor, IN_GLYPH( j ), - &x_mark2_value, &y_mark2_value ); - if ( error ) - return error; - - /* anchor points are not cumulative */ - - o = POSITION( buffer->in_pos ); - - o->x_pos = x_mark2_value - x_mark1_value; - o->y_pos = y_mark2_value - y_mark1_value; - o->x_advance = 0; - o->y_advance = 0; - o->back = 1; - - (buffer->in_pos)++; - - return TT_Err_Ok; - } - - - /* Do the actual positioning for a context positioning (either format - 7 or 8). This is only called after we've determined that the stream - matches the subrule. */ - - static FT_Error Do_ContextPos( GPOS_Instance* gpi, - FT_UShort GlyphCount, - FT_UShort PosCount, - TTO_PosLookupRecord* pos, - OTL_Buffer buffer, - int nesting_level ) - { - FT_Error error; - FT_UShort i, old_pos; - - - i = 0; - - while ( i < GlyphCount ) - { - if ( PosCount && i == pos->SequenceIndex ) - { - old_pos = buffer->in_pos; - - /* Do a positioning */ - - error = Do_Glyph_Lookup( gpi, pos->LookupListIndex, buffer, - GlyphCount, nesting_level ); - - if ( error ) - return error; - - pos++; - PosCount--; - i += buffer->in_pos - old_pos; - } - else - { - i++; - (buffer->in_pos)++; - } - } - - return TT_Err_Ok; - } - - - /* LookupType 7 */ - - /* PosRule */ - - static FT_Error Load_PosRule( TTO_PosRule* pr, - FT_Stream stream ) - { - FT_Error error; - FT_Memory memory = stream->memory; - - FT_UShort n, count; - FT_UShort* i; - - TTO_PosLookupRecord* plr; - - - if ( ACCESS_Frame( 4L ) ) - return error; - - pr->GlyphCount = GET_UShort(); - pr->PosCount = GET_UShort(); - - FORGET_Frame(); - - pr->Input = NULL; - - count = pr->GlyphCount - 1; /* only GlyphCount - 1 elements */ - - if ( ALLOC_ARRAY( pr->Input, count, FT_UShort ) ) - return error; - - i = pr->Input; - - if ( ACCESS_Frame( count * 2L ) ) - goto Fail2; - - for ( n = 0; n < count; n++ ) - i[n] = GET_UShort(); - - FORGET_Frame(); - - pr->PosLookupRecord = NULL; - - count = pr->PosCount; - - if ( ALLOC_ARRAY( pr->PosLookupRecord, count, TTO_PosLookupRecord ) ) - goto Fail2; - - plr = pr->PosLookupRecord; - - if ( ACCESS_Frame( count * 4L ) ) - goto Fail1; - - for ( n = 0; n < count; n++ ) - { - plr[n].SequenceIndex = GET_UShort(); - plr[n].LookupListIndex = GET_UShort(); - } - - FORGET_Frame(); - - return TT_Err_Ok; - - Fail1: - FREE( plr ); - - Fail2: - FREE( i ); - return error; - } - - - static void Free_PosRule( TTO_PosRule* pr, - FT_Memory memory ) - { - FREE( pr->PosLookupRecord ); - FREE( pr->Input ); - } - - - /* PosRuleSet */ - - static FT_Error Load_PosRuleSet( TTO_PosRuleSet* prs, - FT_Stream stream ) - { - FT_Error error; - FT_Memory memory = stream->memory; - - FT_UShort n, m, count; - FT_ULong cur_offset, new_offset, base_offset; - - TTO_PosRule* pr; - - - base_offset = FILE_Pos(); - - if ( ACCESS_Frame( 2L ) ) - return error; - - count = prs->PosRuleCount = GET_UShort(); - - FORGET_Frame(); - - prs->PosRule = NULL; - - if ( ALLOC_ARRAY( prs->PosRule, count, TTO_PosRule ) ) - return error; - - pr = prs->PosRule; - - for ( n = 0; n < count; n++ ) - { - if ( ACCESS_Frame( 2L ) ) - goto Fail; - - new_offset = GET_UShort() + base_offset; - - FORGET_Frame(); - - cur_offset = FILE_Pos(); - if ( FILE_Seek( new_offset ) || - ( error = Load_PosRule( &pr[n], stream ) ) != TT_Err_Ok ) - goto Fail; - (void)FILE_Seek( cur_offset ); - } - - return TT_Err_Ok; - - Fail: - for ( m = 0; m < n; m++ ) - Free_PosRule( &pr[m], memory ); - - FREE( pr ); - return error; - } - - - static void Free_PosRuleSet( TTO_PosRuleSet* prs, - FT_Memory memory ) - { - FT_UShort n, count; - - TTO_PosRule* pr; - - - if ( prs->PosRule ) - { - count = prs->PosRuleCount; - pr = prs->PosRule; - - for ( n = 0; n < count; n++ ) - Free_PosRule( &pr[n], memory ); - - FREE( pr ); - } - } - - - /* ContextPosFormat1 */ - - static FT_Error Load_ContextPos1( TTO_ContextPosFormat1* cpf1, - FT_Stream stream ) - { - FT_Error error; - FT_Memory memory = stream->memory; - - FT_UShort n, m, count; - FT_ULong cur_offset, new_offset, base_offset; - - TTO_PosRuleSet* prs; - - - base_offset = FILE_Pos() - 2L; - - if ( ACCESS_Frame( 2L ) ) - return error; - - new_offset = GET_UShort() + base_offset; - - FORGET_Frame(); - - cur_offset = FILE_Pos(); - if ( FILE_Seek( new_offset ) || - ( error = Load_Coverage( &cpf1->Coverage, stream ) ) != TT_Err_Ok ) - return error; - (void)FILE_Seek( cur_offset ); - - if ( ACCESS_Frame( 2L ) ) - goto Fail2; - - count = cpf1->PosRuleSetCount = GET_UShort(); - - FORGET_Frame(); - - cpf1->PosRuleSet = NULL; - - if ( ALLOC_ARRAY( cpf1->PosRuleSet, count, TTO_PosRuleSet ) ) - goto Fail2; - - prs = cpf1->PosRuleSet; - - for ( n = 0; n < count; n++ ) - { - if ( ACCESS_Frame( 2L ) ) - goto Fail1; - - new_offset = GET_UShort() + base_offset; - - FORGET_Frame(); - - cur_offset = FILE_Pos(); - if ( FILE_Seek( new_offset ) || - ( error = Load_PosRuleSet( &prs[n], stream ) ) != TT_Err_Ok ) - goto Fail1; - (void)FILE_Seek( cur_offset ); - } - - return TT_Err_Ok; - - Fail1: - for ( m = 0; m < n; m++ ) - Free_PosRuleSet( &prs[m], memory ); - - FREE( prs ); - - Fail2: - Free_Coverage( &cpf1->Coverage, memory ); - return error; - } - - - static void Free_Context1( TTO_ContextPosFormat1* cpf1, - FT_Memory memory ) - { - FT_UShort n, count; - - TTO_PosRuleSet* prs; - - - if ( cpf1->PosRuleSet ) - { - count = cpf1->PosRuleSetCount; - prs = cpf1->PosRuleSet; - - for ( n = 0; n < count; n++ ) - Free_PosRuleSet( &prs[n], memory ); - - FREE( prs ); - } - - Free_Coverage( &cpf1->Coverage, memory ); - } - - - /* PosClassRule */ - - static FT_Error Load_PosClassRule( TTO_ContextPosFormat2* cpf2, - TTO_PosClassRule* pcr, - FT_Stream stream ) - { - FT_Error error; - FT_Memory memory = stream->memory; - - FT_UShort n, count; - - FT_UShort* c; - TTO_PosLookupRecord* plr; - FT_Bool* d; - - - if ( ACCESS_Frame( 4L ) ) - return error; - - pcr->GlyphCount = GET_UShort(); - pcr->PosCount = GET_UShort(); - - FORGET_Frame(); - - if ( pcr->GlyphCount > cpf2->MaxContextLength ) - cpf2->MaxContextLength = pcr->GlyphCount; - - pcr->Class = NULL; - - count = pcr->GlyphCount - 1; /* only GlyphCount - 1 elements */ - - if ( ALLOC_ARRAY( pcr->Class, count, FT_UShort ) ) - return error; - - c = pcr->Class; - d = cpf2->ClassDef.Defined; - - if ( ACCESS_Frame( count * 2L ) ) - goto Fail2; - - for ( n = 0; n < count; n++ ) - { - c[n] = GET_UShort(); - - /* We check whether the specific class is used at all. If not, - class 0 is used instead. */ - - if ( !d[c[n]] ) - c[n] = 0; - } - - FORGET_Frame(); - - pcr->PosLookupRecord = NULL; - - count = pcr->PosCount; - - if ( ALLOC_ARRAY( pcr->PosLookupRecord, count, TTO_PosLookupRecord ) ) - goto Fail2; - - plr = pcr->PosLookupRecord; - - if ( ACCESS_Frame( count * 4L ) ) - goto Fail1; - - for ( n = 0; n < count; n++ ) - { - plr[n].SequenceIndex = GET_UShort(); - plr[n].LookupListIndex = GET_UShort(); - } - - FORGET_Frame(); - - return TT_Err_Ok; - - Fail1: - FREE( plr ); - - Fail2: - FREE( c ); - return error; - } - - - static void Free_PosClassRule( TTO_PosClassRule* pcr, - FT_Memory memory ) - { - FREE( pcr->PosLookupRecord ); - FREE( pcr->Class ); - } - - - /* PosClassSet */ - - static FT_Error Load_PosClassSet( TTO_ContextPosFormat2* cpf2, - TTO_PosClassSet* pcs, - FT_Stream stream ) - { - FT_Error error; - FT_Memory memory = stream->memory; - - FT_UShort n, m, count; - FT_ULong cur_offset, new_offset, base_offset; - - TTO_PosClassRule* pcr; - - - base_offset = FILE_Pos(); - - if ( ACCESS_Frame( 2L ) ) - return error; - - count = pcs->PosClassRuleCount = GET_UShort(); - - FORGET_Frame(); - - pcs->PosClassRule = NULL; - - if ( ALLOC_ARRAY( pcs->PosClassRule, count, TTO_PosClassRule ) ) - return error; - - pcr = pcs->PosClassRule; - - for ( n = 0; n < count; n++ ) - { - if ( ACCESS_Frame( 2L ) ) - goto Fail; - - new_offset = GET_UShort() + base_offset; - - FORGET_Frame(); - - cur_offset = FILE_Pos(); - if ( FILE_Seek( new_offset ) || - ( error = Load_PosClassRule( cpf2, &pcr[n], - stream ) ) != TT_Err_Ok ) - goto Fail; - (void)FILE_Seek( cur_offset ); - } - - return TT_Err_Ok; - - Fail: - for ( m = 0; m < n; m++ ) - Free_PosClassRule( &pcr[m], memory ); - - FREE( pcr ); - return error; - } - - - static void Free_PosClassSet( TTO_PosClassSet* pcs, - FT_Memory memory ) - { - FT_UShort n, count; - - TTO_PosClassRule* pcr; - - - if ( pcs->PosClassRule ) - { - count = pcs->PosClassRuleCount; - pcr = pcs->PosClassRule; - - for ( n = 0; n < count; n++ ) - Free_PosClassRule( &pcr[n], memory ); - - FREE( pcr ); - } - } - - - /* ContextPosFormat2 */ - - static FT_Error Load_ContextPos2( TTO_ContextPosFormat2* cpf2, - FT_Stream stream ) - { - FT_Error error; - FT_Memory memory = stream->memory; - - FT_UShort n, m, count; - FT_ULong cur_offset, new_offset, base_offset; - - TTO_PosClassSet* pcs; - - - base_offset = FILE_Pos() - 2; - - if ( ACCESS_Frame( 2L ) ) - return error; - - new_offset = GET_UShort() + base_offset; - - FORGET_Frame(); - - cur_offset = FILE_Pos(); - if ( FILE_Seek( new_offset ) || - ( error = Load_Coverage( &cpf2->Coverage, stream ) ) != TT_Err_Ok ) - return error; - (void)FILE_Seek( cur_offset ); - - if ( ACCESS_Frame( 4L ) ) - goto Fail3; - - new_offset = GET_UShort() + base_offset; - - /* `PosClassSetCount' is the upper limit for class values, thus we - read it now to make an additional safety check. */ - - count = cpf2->PosClassSetCount = GET_UShort(); - - FORGET_Frame(); - - cur_offset = FILE_Pos(); - if ( FILE_Seek( new_offset ) || - ( error = Load_ClassDefinition( &cpf2->ClassDef, count, - stream ) ) != TT_Err_Ok ) - goto Fail3; - (void)FILE_Seek( cur_offset ); - - cpf2->PosClassSet = NULL; - cpf2->MaxContextLength = 0; - - if ( ALLOC_ARRAY( cpf2->PosClassSet, count, TTO_PosClassSet ) ) - goto Fail2; - - pcs = cpf2->PosClassSet; - - for ( n = 0; n < count; n++ ) - { - if ( ACCESS_Frame( 2L ) ) - goto Fail1; - - new_offset = GET_UShort() + base_offset; - - FORGET_Frame(); - - if ( new_offset != base_offset ) /* not a NULL offset */ - { - cur_offset = FILE_Pos(); - if ( FILE_Seek( new_offset ) || - ( error = Load_PosClassSet( cpf2, &pcs[n], - stream ) ) != TT_Err_Ok ) - goto Fail1; - (void)FILE_Seek( cur_offset ); - } - else - { - /* we create a PosClassSet table with no entries */ - - cpf2->PosClassSet[n].PosClassRuleCount = 0; - cpf2->PosClassSet[n].PosClassRule = NULL; - } - } - - return TT_Err_Ok; - - Fail1: - for ( m = 0; m < n; n++ ) - Free_PosClassSet( &pcs[m], memory ); - - FREE( pcs ); - - Fail2: - Free_ClassDefinition( &cpf2->ClassDef, memory ); - - Fail3: - Free_Coverage( &cpf2->Coverage, memory ); - return error; - } - - - static void Free_Context2( TTO_ContextPosFormat2* cpf2, - FT_Memory memory ) - { - FT_UShort n, count; - - TTO_PosClassSet* pcs; - - - if ( cpf2->PosClassSet ) - { - count = cpf2->PosClassSetCount; - pcs = cpf2->PosClassSet; - - for ( n = 0; n < count; n++ ) - Free_PosClassSet( &pcs[n], memory ); - - FREE( pcs ); - } - - Free_ClassDefinition( &cpf2->ClassDef, memory ); - Free_Coverage( &cpf2->Coverage, memory ); - } - - - /* ContextPosFormat3 */ - - static FT_Error Load_ContextPos3( TTO_ContextPosFormat3* cpf3, - FT_Stream stream ) - { - FT_Error error; - FT_Memory memory = stream->memory; - - FT_UShort n, count; - FT_ULong cur_offset, new_offset, base_offset; - - TTO_Coverage* c; - TTO_PosLookupRecord* plr; - - - base_offset = FILE_Pos() - 2L; - - if ( ACCESS_Frame( 4L ) ) - return error; - - cpf3->GlyphCount = GET_UShort(); - cpf3->PosCount = GET_UShort(); - - FORGET_Frame(); - - cpf3->Coverage = NULL; - - count = cpf3->GlyphCount; - - if ( ALLOC_ARRAY( cpf3->Coverage, count, TTO_Coverage ) ) - return error; - - c = cpf3->Coverage; - - for ( n = 0; n < count; n++ ) - { - if ( ACCESS_Frame( 2L ) ) - goto Fail2; - - new_offset = GET_UShort() + base_offset; - - FORGET_Frame(); - - cur_offset = FILE_Pos(); - if ( FILE_Seek( new_offset ) || - ( error = Load_Coverage( &c[n], stream ) ) != TT_Err_Ok ) - goto Fail2; - (void)FILE_Seek( cur_offset ); - } - - cpf3->PosLookupRecord = NULL; - - count = cpf3->PosCount; - - if ( ALLOC_ARRAY( cpf3->PosLookupRecord, count, TTO_PosLookupRecord ) ) - goto Fail2; - - plr = cpf3->PosLookupRecord; - - if ( ACCESS_Frame( count * 4L ) ) - goto Fail1; - - for ( n = 0; n < count; n++ ) - { - plr[n].SequenceIndex = GET_UShort(); - plr[n].LookupListIndex = GET_UShort(); - } - - FORGET_Frame(); - - return TT_Err_Ok; - - Fail1: - FREE( plr ); - - Fail2: - for ( n = 0; n < count; n++ ) - Free_Coverage( &c[n], memory ); - - FREE( c ); - return error; - } - - - static void Free_Context3( TTO_ContextPosFormat3* cpf3, - FT_Memory memory ) - { - FT_UShort n, count; - - TTO_Coverage* c; - - - FREE( cpf3->PosLookupRecord ); - - if ( cpf3->Coverage ) - { - count = cpf3->GlyphCount; - c = cpf3->Coverage; - - for ( n = 0; n < count; n++ ) - Free_Coverage( &c[n], memory ); - - FREE( c ); - } - } - - - /* ContextPos */ - - FT_Error Load_ContextPos( TTO_ContextPos* cp, - FT_Stream stream ) - { - FT_Error error; - - - if ( ACCESS_Frame( 2L ) ) - return error; - - cp->PosFormat = GET_UShort(); - - FORGET_Frame(); - - switch ( cp->PosFormat ) - { - case 1: - return Load_ContextPos1( &cp->cpf.cpf1, stream ); - - case 2: - return Load_ContextPos2( &cp->cpf.cpf2, stream ); - - case 3: - return Load_ContextPos3( &cp->cpf.cpf3, stream ); - - default: - return TTO_Err_Invalid_GPOS_SubTable_Format; - } - - return TT_Err_Ok; /* never reached */ - } - - - void Free_ContextPos( TTO_ContextPos* cp, - FT_Memory memory ) - { - switch ( cp->PosFormat ) - { - case 1: - Free_Context1( &cp->cpf.cpf1, memory ); - break; - - case 2: - Free_Context2( &cp->cpf.cpf2, memory ); - break; - - case 3: - Free_Context3( &cp->cpf.cpf3, memory ); - break; - } - } - - - static FT_Error Lookup_ContextPos1( GPOS_Instance* gpi, - TTO_ContextPosFormat1* cpf1, - OTL_Buffer buffer, - FT_UShort flags, - FT_UShort context_length, - int nesting_level ) - { - FT_UShort index, property; - FT_UShort i, j, k, numpr; - FT_Error error; - TTO_GPOSHeader* gpos = gpi->gpos; - - TTO_PosRule* pr; - TTO_GDEFHeader* gdef; - - - gdef = gpos->gdef; - - if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) ) - return error; - - error = Coverage_Index( &cpf1->Coverage, IN_CURGLYPH(), &index ); - if ( error ) - return error; - - pr = cpf1->PosRuleSet[index].PosRule; - numpr = cpf1->PosRuleSet[index].PosRuleCount; - - for ( k = 0; k < numpr; k++ ) - { - if ( context_length != 0xFFFF && context_length < pr[k].GlyphCount ) - goto next_posrule; - - if ( buffer->in_pos + pr[k].GlyphCount > buffer->in_length ) - goto next_posrule; /* context is too long */ - - for ( i = 1, j = buffer->in_pos + 1; i < pr[k].GlyphCount; i++, j++ ) - { - while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) - { - if ( error && error != TTO_Err_Not_Covered ) - return error; - - if ( j + pr[k].GlyphCount - i == buffer->in_length ) - goto next_posrule; - j++; - } - - if ( IN_GLYPH( j ) != pr[k].Input[i - 1] ) - goto next_posrule; - } - - return Do_ContextPos( gpi, pr[k].GlyphCount, - pr[k].PosCount, pr[k].PosLookupRecord, - buffer, - nesting_level ); - - next_posrule: - ; - } - - return TTO_Err_Not_Covered; - } - - - static FT_Error Lookup_ContextPos2( GPOS_Instance* gpi, - TTO_ContextPosFormat2* cpf2, - OTL_Buffer buffer, - FT_UShort flags, - FT_UShort context_length, - int nesting_level ) - { - FT_UShort index, property; - FT_Error error; - FT_Memory memory = gpi->face->memory; - FT_UShort i, j, k, known_classes; - - FT_UShort* classes; - FT_UShort* cl; - TTO_GPOSHeader* gpos = gpi->gpos; - - TTO_PosClassSet* pcs; - TTO_PosClassRule* pr; - TTO_GDEFHeader* gdef; - - - gdef = gpos->gdef; - - if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) ) - return error; - - /* Note: The coverage table in format 2 doesn't give an index into - anything. It just lets us know whether or not we need to - do any lookup at all. */ - - error = Coverage_Index( &cpf2->Coverage, IN_CURGLYPH(), &index ); - if ( error ) - return error; - - if ( ALLOC_ARRAY( classes, cpf2->MaxContextLength, FT_UShort ) ) - return error; - - error = Get_Class( &cpf2->ClassDef, IN_CURGLYPH(), - &classes[0], NULL ); - if ( error && error != TTO_Err_Not_Covered ) - goto End; - known_classes = 0; - - pcs = &cpf2->PosClassSet[classes[0]]; - if ( !pcs ) - { - error = TTO_Err_Invalid_GPOS_SubTable; - goto End; - } - - for ( k = 0; k < pcs->PosClassRuleCount; k++ ) - { - pr = &pcs->PosClassRule[k]; - - if ( context_length != 0xFFFF && context_length < pr->GlyphCount ) - goto next_posclassrule; - - if ( buffer->in_pos + pr->GlyphCount > buffer->in_length ) - goto next_posclassrule; /* context is too long */ - - cl = pr->Class; - - /* Start at 1 because [0] is implied */ - - for ( i = 1, j = buffer->in_pos + 1; i < pr->GlyphCount; i++, j++ ) - { - while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) - { - if ( error && error != TTO_Err_Not_Covered ) - goto End; - - if ( j + pr->GlyphCount - i == buffer->in_length ) - goto next_posclassrule; - j++; - } - - if ( i > known_classes ) - { - /* Keeps us from having to do this for each rule */ - - error = Get_Class( &cpf2->ClassDef, IN_GLYPH( j ), &classes[i], NULL ); - if ( error && error != TTO_Err_Not_Covered ) - goto End; - known_classes = i; - } - - if ( cl[i - 1] != classes[i] ) - goto next_posclassrule; - } - - error = Do_ContextPos( gpi, pr->GlyphCount, - pr->PosCount, pr->PosLookupRecord, - buffer, - nesting_level ); - goto End; - - next_posclassrule: - ; - } - - error = TTO_Err_Not_Covered; - - End: - FREE( classes ); - return error; - } - - - static FT_Error Lookup_ContextPos3( GPOS_Instance* gpi, - TTO_ContextPosFormat3* cpf3, - OTL_Buffer buffer, - FT_UShort flags, - FT_UShort context_length, - int nesting_level ) - { - FT_Error error; - FT_UShort index, i, j, property; - TTO_GPOSHeader* gpos = gpi->gpos; - - TTO_Coverage* c; - TTO_GDEFHeader* gdef; - - - gdef = gpos->gdef; - - if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) ) - return error; - - if ( context_length != 0xFFFF && context_length < cpf3->GlyphCount ) - return TTO_Err_Not_Covered; - - if ( buffer->in_pos + cpf3->GlyphCount > buffer->in_length ) - return TTO_Err_Not_Covered; /* context is too long */ - - c = cpf3->Coverage; - - for ( i = 1, j = 1; i < cpf3->GlyphCount; i++, j++ ) - { - while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) - { - if ( error && error != TTO_Err_Not_Covered ) - return error; - - if ( j + cpf3->GlyphCount - i == buffer->in_length ) - return TTO_Err_Not_Covered; - j++; - } - - error = Coverage_Index( &c[i], IN_GLYPH( j ), &index ); - if ( error ) - return error; - } - - return Do_ContextPos( gpi, cpf3->GlyphCount, - cpf3->PosCount, cpf3->PosLookupRecord, - buffer, - nesting_level ); - } - - - static FT_Error Lookup_ContextPos( GPOS_Instance* gpi, - TTO_GPOS_SubTable* st, - OTL_Buffer buffer, - FT_UShort flags, - FT_UShort context_length, - int nesting_level ) - { - TTO_ContextPos* cp = &st->context; - - switch ( cp->PosFormat ) - { - case 1: - return Lookup_ContextPos1( gpi, &cp->cpf.cpf1, buffer, - flags, context_length, nesting_level ); - - case 2: - return Lookup_ContextPos2( gpi, &cp->cpf.cpf2, buffer, - flags, context_length, nesting_level ); - - case 3: - return Lookup_ContextPos3( gpi, &cp->cpf.cpf3, buffer, - flags, context_length, nesting_level ); - - default: - return TTO_Err_Invalid_GPOS_SubTable_Format; - } - - return TT_Err_Ok; /* never reached */ - } - - - /* LookupType 8 */ - - /* ChainPosRule */ - - static FT_Error Load_ChainPosRule( TTO_ChainPosRule* cpr, - FT_Stream stream ) - { - FT_Error error; - FT_Memory memory = stream->memory; - - FT_UShort n, count; - FT_UShort* b; - FT_UShort* i; - FT_UShort* l; - - TTO_PosLookupRecord* plr; - - - if ( ACCESS_Frame( 2L ) ) - return error; - - cpr->BacktrackGlyphCount = GET_UShort(); - - FORGET_Frame(); - - cpr->Backtrack = NULL; - - count = cpr->BacktrackGlyphCount; - - if ( ALLOC_ARRAY( cpr->Backtrack, count, FT_UShort ) ) - return error; - - b = cpr->Backtrack; - - if ( ACCESS_Frame( count * 2L ) ) - goto Fail4; - - for ( n = 0; n < count; n++ ) - b[n] = GET_UShort(); - - FORGET_Frame(); - - if ( ACCESS_Frame( 2L ) ) - goto Fail4; - - cpr->InputGlyphCount = GET_UShort(); - - FORGET_Frame(); - - cpr->Input = NULL; - - count = cpr->InputGlyphCount - 1; /* only InputGlyphCount - 1 elements */ - - if ( ALLOC_ARRAY( cpr->Input, count, FT_UShort ) ) - goto Fail4; - - i = cpr->Input; - - if ( ACCESS_Frame( count * 2L ) ) - goto Fail3; - - for ( n = 0; n < count; n++ ) - i[n] = GET_UShort(); - - FORGET_Frame(); - - if ( ACCESS_Frame( 2L ) ) - goto Fail3; - - cpr->LookaheadGlyphCount = GET_UShort(); - - FORGET_Frame(); - - cpr->Lookahead = NULL; - - count = cpr->LookaheadGlyphCount; - - if ( ALLOC_ARRAY( cpr->Lookahead, count, FT_UShort ) ) - goto Fail3; - - l = cpr->Lookahead; - - if ( ACCESS_Frame( count * 2L ) ) - goto Fail2; - - for ( n = 0; n < count; n++ ) - l[n] = GET_UShort(); - - FORGET_Frame(); - - if ( ACCESS_Frame( 2L ) ) - goto Fail2; - - cpr->PosCount = GET_UShort(); - - FORGET_Frame(); - - cpr->PosLookupRecord = NULL; - - count = cpr->PosCount; - - if ( ALLOC_ARRAY( cpr->PosLookupRecord, count, TTO_PosLookupRecord ) ) - goto Fail2; - - plr = cpr->PosLookupRecord; - - if ( ACCESS_Frame( count * 4L ) ) - goto Fail1; - - for ( n = 0; n < count; n++ ) - { - plr[n].SequenceIndex = GET_UShort(); - plr[n].LookupListIndex = GET_UShort(); - } - - FORGET_Frame(); - - return TT_Err_Ok; - - Fail1: - FREE( plr ); - - Fail2: - FREE( l ); - - Fail3: - FREE( i ); - - Fail4: - FREE( b ); - return error; - } - - - static void Free_ChainPosRule( TTO_ChainPosRule* cpr, - FT_Memory memory ) - { - FREE( cpr->PosLookupRecord ); - FREE( cpr->Lookahead ); - FREE( cpr->Input ); - FREE( cpr->Backtrack ); - } - - - /* ChainPosRuleSet */ - - static FT_Error Load_ChainPosRuleSet( TTO_ChainPosRuleSet* cprs, - FT_Stream stream ) - { - FT_Error error; - FT_Memory memory = stream->memory; - - FT_UShort n, m, count; - FT_ULong cur_offset, new_offset, base_offset; - - TTO_ChainPosRule* cpr; - - - base_offset = FILE_Pos(); - - if ( ACCESS_Frame( 2L ) ) - return error; - - count = cprs->ChainPosRuleCount = GET_UShort(); - - FORGET_Frame(); - - cprs->ChainPosRule = NULL; - - if ( ALLOC_ARRAY( cprs->ChainPosRule, count, TTO_ChainPosRule ) ) - return error; - - cpr = cprs->ChainPosRule; - - for ( n = 0; n < count; n++ ) - { - if ( ACCESS_Frame( 2L ) ) - goto Fail; - - new_offset = GET_UShort() + base_offset; - - FORGET_Frame(); - - cur_offset = FILE_Pos(); - if ( FILE_Seek( new_offset ) || - ( error = Load_ChainPosRule( &cpr[n], stream ) ) != TT_Err_Ok ) - goto Fail; - (void)FILE_Seek( cur_offset ); - } - - return TT_Err_Ok; - - Fail: - for ( m = 0; m < n; m++ ) - Free_ChainPosRule( &cpr[m], memory ); - - FREE( cpr ); - return error; - } - - - static void Free_ChainPosRuleSet( TTO_ChainPosRuleSet* cprs, - FT_Memory memory ) - { - FT_UShort n, count; - - TTO_ChainPosRule* cpr; - - - if ( cprs->ChainPosRule ) - { - count = cprs->ChainPosRuleCount; - cpr = cprs->ChainPosRule; - - for ( n = 0; n < count; n++ ) - Free_ChainPosRule( &cpr[n], memory ); - - FREE( cpr ); - } - } - - - /* ChainContextPosFormat1 */ - - static FT_Error Load_ChainContextPos1( TTO_ChainContextPosFormat1* ccpf1, - FT_Stream stream ) - { - FT_Error error; - FT_Memory memory = stream->memory; - - FT_UShort n, m, count; - FT_ULong cur_offset, new_offset, base_offset; - - TTO_ChainPosRuleSet* cprs; - - - base_offset = FILE_Pos() - 2L; - - if ( ACCESS_Frame( 2L ) ) - return error; - - new_offset = GET_UShort() + base_offset; - - FORGET_Frame(); - - cur_offset = FILE_Pos(); - if ( FILE_Seek( new_offset ) || - ( error = Load_Coverage( &ccpf1->Coverage, stream ) ) != TT_Err_Ok ) - return error; - (void)FILE_Seek( cur_offset ); - - if ( ACCESS_Frame( 2L ) ) - goto Fail2; - - count = ccpf1->ChainPosRuleSetCount = GET_UShort(); - - FORGET_Frame(); - - ccpf1->ChainPosRuleSet = NULL; - - if ( ALLOC_ARRAY( ccpf1->ChainPosRuleSet, count, TTO_ChainPosRuleSet ) ) - goto Fail2; - - cprs = ccpf1->ChainPosRuleSet; - - for ( n = 0; n < count; n++ ) - { - if ( ACCESS_Frame( 2L ) ) - goto Fail1; - - new_offset = GET_UShort() + base_offset; - - FORGET_Frame(); - - cur_offset = FILE_Pos(); - if ( FILE_Seek( new_offset ) || - ( error = Load_ChainPosRuleSet( &cprs[n], stream ) ) != TT_Err_Ok ) - goto Fail1; - (void)FILE_Seek( cur_offset ); - } - - return TT_Err_Ok; - - Fail1: - for ( m = 0; m < n; m++ ) - Free_ChainPosRuleSet( &cprs[m], memory ); - - FREE( cprs ); - - Fail2: - Free_Coverage( &ccpf1->Coverage, memory ); - return error; - } - - - static void Free_ChainContext1( TTO_ChainContextPosFormat1* ccpf1, - FT_Memory memory ) - { - FT_UShort n, count; - - TTO_ChainPosRuleSet* cprs; - - - if ( ccpf1->ChainPosRuleSet ) - { - count = ccpf1->ChainPosRuleSetCount; - cprs = ccpf1->ChainPosRuleSet; - - for ( n = 0; n < count; n++ ) - Free_ChainPosRuleSet( &cprs[n], memory ); - - FREE( cprs ); - } - - Free_Coverage( &ccpf1->Coverage, memory ); - } - - - /* ChainPosClassRule */ - - static FT_Error Load_ChainPosClassRule( - TTO_ChainContextPosFormat2* ccpf2, - TTO_ChainPosClassRule* cpcr, - FT_Stream stream ) - { - FT_Error error; - FT_Memory memory = stream->memory; - - FT_UShort n, count; - - FT_UShort* b; - FT_UShort* i; - FT_UShort* l; - TTO_PosLookupRecord* plr; - FT_Bool* d; - - - if ( ACCESS_Frame( 2L ) ) - return error; - - cpcr->BacktrackGlyphCount = GET_UShort(); - - FORGET_Frame(); - - if ( cpcr->BacktrackGlyphCount > ccpf2->MaxBacktrackLength ) - ccpf2->MaxBacktrackLength = cpcr->BacktrackGlyphCount; - - cpcr->Backtrack = NULL; - - count = cpcr->BacktrackGlyphCount; - - if ( ALLOC_ARRAY( cpcr->Backtrack, count, FT_UShort ) ) - return error; - - b = cpcr->Backtrack; - d = ccpf2->BacktrackClassDef.Defined; - - if ( ACCESS_Frame( count * 2L ) ) - goto Fail4; - - for ( n = 0; n < count; n++ ) - { - b[n] = GET_UShort(); - - /* We check whether the specific class is used at all. If not, - class 0 is used instead. */ - - if ( !d[b[n]] ) - b[n] = 0; - } - - FORGET_Frame(); - - if ( ACCESS_Frame( 2L ) ) - goto Fail4; - - cpcr->InputGlyphCount = GET_UShort(); - - if ( cpcr->InputGlyphCount > ccpf2->MaxInputLength ) - ccpf2->MaxInputLength = cpcr->InputGlyphCount; - - FORGET_Frame(); - - cpcr->Input = NULL; - - count = cpcr->InputGlyphCount - 1; /* only InputGlyphCount - 1 elements */ - - if ( ALLOC_ARRAY( cpcr->Input, count, FT_UShort ) ) - goto Fail4; - - i = cpcr->Input; - d = ccpf2->InputClassDef.Defined; - - if ( ACCESS_Frame( count * 2L ) ) - goto Fail3; - - for ( n = 0; n < count; n++ ) - { - i[n] = GET_UShort(); - - if ( !d[i[n]] ) - i[n] = 0; - } - - FORGET_Frame(); - - if ( ACCESS_Frame( 2L ) ) - goto Fail3; - - cpcr->LookaheadGlyphCount = GET_UShort(); - - FORGET_Frame(); - - if ( cpcr->LookaheadGlyphCount > ccpf2->MaxLookaheadLength ) - ccpf2->MaxLookaheadLength = cpcr->LookaheadGlyphCount; - - cpcr->Lookahead = NULL; - - count = cpcr->LookaheadGlyphCount; - - if ( ALLOC_ARRAY( cpcr->Lookahead, count, FT_UShort ) ) - goto Fail3; - - l = cpcr->Lookahead; - d = ccpf2->LookaheadClassDef.Defined; - - if ( ACCESS_Frame( count * 2L ) ) - goto Fail2; - - for ( n = 0; n < count; n++ ) - { - l[n] = GET_UShort(); - - if ( !d[l[n]] ) - l[n] = 0; - } - - FORGET_Frame(); - - if ( ACCESS_Frame( 2L ) ) - goto Fail2; - - cpcr->PosCount = GET_UShort(); - - FORGET_Frame(); - - cpcr->PosLookupRecord = NULL; - - count = cpcr->PosCount; - - if ( ALLOC_ARRAY( cpcr->PosLookupRecord, count, TTO_PosLookupRecord ) ) - goto Fail2; - - plr = cpcr->PosLookupRecord; - - if ( ACCESS_Frame( count * 4L ) ) - goto Fail1; - - for ( n = 0; n < count; n++ ) - { - plr[n].SequenceIndex = GET_UShort(); - plr[n].LookupListIndex = GET_UShort(); - } - - FORGET_Frame(); - - return TT_Err_Ok; - - Fail1: - FREE( plr ); - - Fail2: - FREE( l ); - - Fail3: - FREE( i ); - - Fail4: - FREE( b ); - return error; - } - - - static void Free_ChainPosClassRule( TTO_ChainPosClassRule* cpcr, - FT_Memory memory ) - { - FREE( cpcr->PosLookupRecord ); - FREE( cpcr->Lookahead ); - FREE( cpcr->Input ); - FREE( cpcr->Backtrack ); - } - - - /* PosClassSet */ - - static FT_Error Load_ChainPosClassSet( - TTO_ChainContextPosFormat2* ccpf2, - TTO_ChainPosClassSet* cpcs, - FT_Stream stream ) - { - FT_Error error; - FT_Memory memory = stream->memory; - - FT_UShort n, m, count; - FT_ULong cur_offset, new_offset, base_offset; - - TTO_ChainPosClassRule* cpcr; - - - base_offset = FILE_Pos(); - - if ( ACCESS_Frame( 2L ) ) - return error; - - count = cpcs->ChainPosClassRuleCount = GET_UShort(); - - FORGET_Frame(); - - cpcs->ChainPosClassRule = NULL; - - if ( ALLOC_ARRAY( cpcs->ChainPosClassRule, count, - TTO_ChainPosClassRule ) ) - return error; - - cpcr = cpcs->ChainPosClassRule; - - for ( n = 0; n < count; n++ ) - { - if ( ACCESS_Frame( 2L ) ) - goto Fail; - - new_offset = GET_UShort() + base_offset; - - FORGET_Frame(); - - cur_offset = FILE_Pos(); - if ( FILE_Seek( new_offset ) || - ( error = Load_ChainPosClassRule( ccpf2, &cpcr[n], - stream ) ) != TT_Err_Ok ) - goto Fail; - (void)FILE_Seek( cur_offset ); - } - - return TT_Err_Ok; - - Fail: - for ( m = 0; m < n; m++ ) - Free_ChainPosClassRule( &cpcr[m], memory ); - - FREE( cpcr ); - return error; - } - - - static void Free_ChainPosClassSet( TTO_ChainPosClassSet* cpcs, - FT_Memory memory ) - { - FT_UShort n, count; - - TTO_ChainPosClassRule* cpcr; - - - if ( cpcs->ChainPosClassRule ) - { - count = cpcs->ChainPosClassRuleCount; - cpcr = cpcs->ChainPosClassRule; - - for ( n = 0; n < count; n++ ) - Free_ChainPosClassRule( &cpcr[n], memory ); - - FREE( cpcr ); - } - } - - - static FT_Error Load_EmptyOrClassDefinition( TTO_ClassDefinition* cd, - FT_UShort limit, - FT_ULong class_offset, - FT_ULong base_offset, - FT_Stream stream ) - { - FT_Error error; - FT_ULong cur_offset; - - cur_offset = FILE_Pos(); - - if ( class_offset ) - { - if ( !FILE_Seek( class_offset + base_offset ) ) - error = Load_ClassDefinition( cd, limit, stream ); - } - else - error = Load_EmptyClassDefinition ( cd, stream ); - - if (error == TT_Err_Ok) - (void)FILE_Seek( cur_offset ); /* Changes error as a side-effect */ - - return error; - } - - /* ChainContextPosFormat2 */ - - static FT_Error Load_ChainContextPos2( TTO_ChainContextPosFormat2* ccpf2, - FT_Stream stream ) - { - FT_Error error; - FT_Memory memory = stream->memory; - - FT_UShort n, m, count; - FT_ULong cur_offset, new_offset, base_offset; - FT_ULong backtrack_offset, input_offset, lookahead_offset; - - TTO_ChainPosClassSet* cpcs; - - - base_offset = FILE_Pos() - 2; - - if ( ACCESS_Frame( 2L ) ) - return error; - - new_offset = GET_UShort() + base_offset; - - FORGET_Frame(); - - cur_offset = FILE_Pos(); - if ( FILE_Seek( new_offset ) || - ( error = Load_Coverage( &ccpf2->Coverage, stream ) ) != TT_Err_Ok ) - return error; - (void)FILE_Seek( cur_offset ); - - if ( ACCESS_Frame( 8L ) ) - goto Fail5; - - backtrack_offset = GET_UShort(); - input_offset = GET_UShort(); - lookahead_offset = GET_UShort(); - - /* `ChainPosClassSetCount' is the upper limit for input class values, - thus we read it now to make an additional safety check. No limit - is known or needed for the other two class definitions */ - - count = ccpf2->ChainPosClassSetCount = GET_UShort(); - - FORGET_Frame(); - - if ( ( error = Load_EmptyOrClassDefinition( &ccpf2->BacktrackClassDef, 65535, - backtrack_offset, base_offset, - stream ) ) != TT_Err_Ok ) - goto Fail5; - if ( ( error = Load_EmptyOrClassDefinition( &ccpf2->InputClassDef, count, - input_offset, base_offset, - stream ) ) != TT_Err_Ok ) - goto Fail4; - if ( ( error = Load_EmptyOrClassDefinition( &ccpf2->LookaheadClassDef, 65535, - lookahead_offset, base_offset, - stream ) ) != TT_Err_Ok ) - goto Fail3; - - ccpf2->ChainPosClassSet = NULL; - ccpf2->MaxBacktrackLength = 0; - ccpf2->MaxInputLength = 0; - ccpf2->MaxLookaheadLength = 0; - - if ( ALLOC_ARRAY( ccpf2->ChainPosClassSet, count, TTO_ChainPosClassSet ) ) - goto Fail2; - - cpcs = ccpf2->ChainPosClassSet; - - for ( n = 0; n < count; n++ ) - { - if ( ACCESS_Frame( 2L ) ) - goto Fail1; - - new_offset = GET_UShort() + base_offset; - - FORGET_Frame(); - - if ( new_offset != base_offset ) /* not a NULL offset */ - { - cur_offset = FILE_Pos(); - if ( FILE_Seek( new_offset ) || - ( error = Load_ChainPosClassSet( ccpf2, &cpcs[n], - stream ) ) != TT_Err_Ok ) - goto Fail1; - (void)FILE_Seek( cur_offset ); - } - else - { - /* we create a ChainPosClassSet table with no entries */ - - ccpf2->ChainPosClassSet[n].ChainPosClassRuleCount = 0; - ccpf2->ChainPosClassSet[n].ChainPosClassRule = NULL; - } - } - - return TT_Err_Ok; - - Fail1: - for ( m = 0; m < n; m++ ) - Free_ChainPosClassSet( &cpcs[m], memory ); - - FREE( cpcs ); - - Fail2: - Free_ClassDefinition( &ccpf2->LookaheadClassDef, memory ); - - Fail3: - Free_ClassDefinition( &ccpf2->InputClassDef, memory ); - - Fail4: - Free_ClassDefinition( &ccpf2->BacktrackClassDef, memory ); - - Fail5: - Free_Coverage( &ccpf2->Coverage, memory ); - return error; - } - - - static void Free_ChainContext2( TTO_ChainContextPosFormat2* ccpf2, - FT_Memory memory ) - { - FT_UShort n, count; - - TTO_ChainPosClassSet* cpcs; - - - if ( ccpf2->ChainPosClassSet ) - { - count = ccpf2->ChainPosClassSetCount; - cpcs = ccpf2->ChainPosClassSet; - - for ( n = 0; n < count; n++ ) - Free_ChainPosClassSet( &cpcs[n], memory ); - - FREE( cpcs ); - } - - Free_ClassDefinition( &ccpf2->LookaheadClassDef, memory ); - Free_ClassDefinition( &ccpf2->InputClassDef, memory ); - Free_ClassDefinition( &ccpf2->BacktrackClassDef, memory ); - - Free_Coverage( &ccpf2->Coverage, memory ); - } - - - /* ChainContextPosFormat3 */ - - static FT_Error Load_ChainContextPos3( TTO_ChainContextPosFormat3* ccpf3, - FT_Stream stream ) - { - FT_Error error; - FT_Memory memory = stream->memory; - - FT_UShort n, nb, ni, nl, m, count; - FT_UShort backtrack_count, input_count, lookahead_count; - FT_ULong cur_offset, new_offset, base_offset; - - TTO_Coverage* b; - TTO_Coverage* i; - TTO_Coverage* l; - TTO_PosLookupRecord* plr; - - - base_offset = FILE_Pos() - 2L; - - if ( ACCESS_Frame( 2L ) ) - return error; - - ccpf3->BacktrackGlyphCount = GET_UShort(); - - FORGET_Frame(); - - ccpf3->BacktrackCoverage = NULL; - - backtrack_count = ccpf3->BacktrackGlyphCount; - - if ( ALLOC_ARRAY( ccpf3->BacktrackCoverage, backtrack_count, - TTO_Coverage ) ) - return error; - - b = ccpf3->BacktrackCoverage; - - for ( nb = 0; nb < backtrack_count; nb++ ) - { - if ( ACCESS_Frame( 2L ) ) - goto Fail4; - - new_offset = GET_UShort() + base_offset; - - FORGET_Frame(); - - cur_offset = FILE_Pos(); - if ( FILE_Seek( new_offset ) || - ( error = Load_Coverage( &b[nb], stream ) ) != TT_Err_Ok ) - goto Fail4; - (void)FILE_Seek( cur_offset ); - } - - if ( ACCESS_Frame( 2L ) ) - goto Fail4; - - ccpf3->InputGlyphCount = GET_UShort(); - - FORGET_Frame(); - - ccpf3->InputCoverage = NULL; - - input_count = ccpf3->InputGlyphCount; - - if ( ALLOC_ARRAY( ccpf3->InputCoverage, input_count, TTO_Coverage ) ) - goto Fail4; - - i = ccpf3->InputCoverage; - - for ( ni = 0; ni < input_count; ni++ ) - { - if ( ACCESS_Frame( 2L ) ) - goto Fail3; - - new_offset = GET_UShort() + base_offset; - - FORGET_Frame(); - - cur_offset = FILE_Pos(); - if ( FILE_Seek( new_offset ) || - ( error = Load_Coverage( &i[ni], stream ) ) != TT_Err_Ok ) - goto Fail3; - (void)FILE_Seek( cur_offset ); - } - - if ( ACCESS_Frame( 2L ) ) - goto Fail3; - - ccpf3->LookaheadGlyphCount = GET_UShort(); - - FORGET_Frame(); - - ccpf3->LookaheadCoverage = NULL; - - lookahead_count = ccpf3->LookaheadGlyphCount; - - if ( ALLOC_ARRAY( ccpf3->LookaheadCoverage, lookahead_count, - TTO_Coverage ) ) - goto Fail3; - - l = ccpf3->LookaheadCoverage; - - for ( nl = 0; nl < lookahead_count; nl++ ) - { - if ( ACCESS_Frame( 2L ) ) - goto Fail2; - - new_offset = GET_UShort() + base_offset; - - FORGET_Frame(); - - cur_offset = FILE_Pos(); - if ( FILE_Seek( new_offset ) || - ( error = Load_Coverage( &l[nl], stream ) ) != TT_Err_Ok ) - goto Fail2; - (void)FILE_Seek( cur_offset ); - } - - if ( ACCESS_Frame( 2L ) ) - goto Fail2; - - ccpf3->PosCount = GET_UShort(); - - FORGET_Frame(); - - ccpf3->PosLookupRecord = NULL; - - count = ccpf3->PosCount; - - if ( ALLOC_ARRAY( ccpf3->PosLookupRecord, count, TTO_PosLookupRecord ) ) - goto Fail2; - - plr = ccpf3->PosLookupRecord; - - if ( ACCESS_Frame( count * 4L ) ) - goto Fail1; - - for ( n = 0; n < count; n++ ) - { - plr[n].SequenceIndex = GET_UShort(); - plr[n].LookupListIndex = GET_UShort(); - } - - FORGET_Frame(); - - return TT_Err_Ok; - - Fail1: - FREE( plr ); - - Fail2: - for ( m = 0; m < nl; nl++ ) - Free_Coverage( &l[m], memory ); - - FREE( l ); - - Fail3: - for ( m = 0; m < ni; n++ ) - Free_Coverage( &i[m], memory ); - - FREE( i ); - - Fail4: - for ( m = 0; m < nb; n++ ) - Free_Coverage( &b[m], memory ); - - FREE( b ); - return error; - } - - - static void Free_ChainContext3( TTO_ChainContextPosFormat3* ccpf3, - FT_Memory memory ) - { - FT_UShort n, count; - - TTO_Coverage* c; - - - FREE( ccpf3->PosLookupRecord ); - - if ( ccpf3->LookaheadCoverage ) - { - count = ccpf3->LookaheadGlyphCount; - c = ccpf3->LookaheadCoverage; - - for ( n = 0; n < count; n++ ) - Free_Coverage( &c[n], memory ); - - FREE( c ); - } - - if ( ccpf3->InputCoverage ) - { - count = ccpf3->InputGlyphCount; - c = ccpf3->InputCoverage; - - for ( n = 0; n < count; n++ ) - Free_Coverage( &c[n], memory ); - - FREE( c ); - } - - if ( ccpf3->BacktrackCoverage ) - { - count = ccpf3->BacktrackGlyphCount; - c = ccpf3->BacktrackCoverage; - - for ( n = 0; n < count; n++ ) - Free_Coverage( &c[n], memory ); - - FREE( c ); - } - } - - - /* ChainContextPos */ - - FT_Error Load_ChainContextPos( TTO_ChainContextPos* ccp, - FT_Stream stream ) - { - FT_Error error; - - - if ( ACCESS_Frame( 2L ) ) - return error; - - ccp->PosFormat = GET_UShort(); - - FORGET_Frame(); - - switch ( ccp->PosFormat ) - { - case 1: - return Load_ChainContextPos1( &ccp->ccpf.ccpf1, stream ); - - case 2: - return Load_ChainContextPos2( &ccp->ccpf.ccpf2, stream ); - - case 3: - return Load_ChainContextPos3( &ccp->ccpf.ccpf3, stream ); - - default: - return TTO_Err_Invalid_GPOS_SubTable_Format; - } - - return TT_Err_Ok; /* never reached */ - } - - - void Free_ChainContextPos( TTO_ChainContextPos* ccp, - FT_Memory memory ) - { - switch ( ccp->PosFormat ) - { - case 1: - Free_ChainContext1( &ccp->ccpf.ccpf1, memory ); - break; - - case 2: - Free_ChainContext2( &ccp->ccpf.ccpf2, memory ); - break; - - case 3: - Free_ChainContext3( &ccp->ccpf.ccpf3, memory ); - break; - } - } - - - static FT_Error Lookup_ChainContextPos1( - GPOS_Instance* gpi, - TTO_ChainContextPosFormat1* ccpf1, - OTL_Buffer buffer, - FT_UShort flags, - FT_UShort context_length, - int nesting_level ) - { - FT_UShort index, property; - FT_UShort i, j, k, num_cpr; - FT_UShort bgc, igc, lgc; - FT_Error error; - TTO_GPOSHeader* gpos = gpi->gpos; - - TTO_ChainPosRule* cpr; - TTO_ChainPosRule curr_cpr; - TTO_GDEFHeader* gdef; - - - gdef = gpos->gdef; - - if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) ) - return error; - - error = Coverage_Index( &ccpf1->Coverage, IN_CURGLYPH(), &index ); - if ( error ) - return error; - - cpr = ccpf1->ChainPosRuleSet[index].ChainPosRule; - num_cpr = ccpf1->ChainPosRuleSet[index].ChainPosRuleCount; - - for ( k = 0; k < num_cpr; k++ ) - { - curr_cpr = cpr[k]; - bgc = curr_cpr.BacktrackGlyphCount; - igc = curr_cpr.InputGlyphCount; - lgc = curr_cpr.LookaheadGlyphCount; - - if ( context_length != 0xFFFF && context_length < igc ) - goto next_chainposrule; - - /* check whether context is too long; it is a first guess only */ - - if ( bgc > buffer->in_pos || buffer->in_pos + igc + lgc > buffer->in_length ) - goto next_chainposrule; - - if ( bgc ) - { - /* Since we don't know in advance the number of glyphs to inspect, - we search backwards for matches in the backtrack glyph array */ - - for ( i = 0, j = buffer->in_pos - 1; i < bgc; i++, j-- ) - { - while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) - { - if ( error && error != TTO_Err_Not_Covered ) - return error; - - if ( j + 1 == bgc - i ) - goto next_chainposrule; - j--; - } - - /* In OpenType 1.3, it is undefined whether the offsets of - backtrack glyphs is in logical order or not. Version 1.4 - will clarify this: - - Logical order - a b c d e f g h i j - i - Input offsets - 0 1 - Backtrack offsets - 3 2 1 0 - Lookahead offsets - 0 1 2 3 */ - - if ( IN_GLYPH( j ) != curr_cpr.Backtrack[i] ) - goto next_chainposrule; - } - } - - /* Start at 1 because [0] is implied */ - - for ( i = 1, j = buffer->in_pos + 1; i < igc; i++, j++ ) - { - while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) - { - if ( error && error != TTO_Err_Not_Covered ) - return error; - - if ( j + igc - i + lgc == buffer->in_length ) - goto next_chainposrule; - j++; - } - - if ( IN_GLYPH( j ) != curr_cpr.Input[i - 1] ) - goto next_chainposrule; - } - - /* we are starting to check for lookahead glyphs right after the - last context glyph */ - - for ( i = 0; i < lgc; i++, j++ ) - { - while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) - { - if ( error && error != TTO_Err_Not_Covered ) - return error; - - if ( j + lgc - i == buffer->in_length ) - goto next_chainposrule; - j++; - } - - if ( IN_GLYPH( j ) != curr_cpr.Lookahead[i] ) - goto next_chainposrule; - } - - return Do_ContextPos( gpi, igc, - curr_cpr.PosCount, - curr_cpr.PosLookupRecord, - buffer, - nesting_level ); - - next_chainposrule: - ; - } - - return TTO_Err_Not_Covered; - } - - - static FT_Error Lookup_ChainContextPos2( - GPOS_Instance* gpi, - TTO_ChainContextPosFormat2* ccpf2, - OTL_Buffer buffer, - FT_UShort flags, - FT_UShort context_length, - int nesting_level ) - { - FT_UShort index, property; - FT_Memory memory = gpi->face->memory; - FT_Error error; - FT_UShort i, j, k; - FT_UShort bgc, igc, lgc; - FT_UShort known_backtrack_classes, - known_input_classes, - known_lookahead_classes; - - FT_UShort* backtrack_classes; - FT_UShort* input_classes; - FT_UShort* lookahead_classes; - - FT_UShort* bc; - FT_UShort* ic; - FT_UShort* lc; - TTO_GPOSHeader* gpos = gpi->gpos; - - TTO_ChainPosClassSet* cpcs; - TTO_ChainPosClassRule cpcr; - TTO_GDEFHeader* gdef; - - - gdef = gpos->gdef; - - if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) ) - return error; - - /* Note: The coverage table in format 2 doesn't give an index into - anything. It just lets us know whether or not we need to - do any lookup at all. */ - - error = Coverage_Index( &ccpf2->Coverage, IN_CURGLYPH(), &index ); - if ( error ) - return error; - - if ( ALLOC_ARRAY( backtrack_classes, ccpf2->MaxBacktrackLength, FT_UShort ) ) - return error; - known_backtrack_classes = 0; - - if ( ALLOC_ARRAY( input_classes, ccpf2->MaxInputLength, FT_UShort ) ) - goto End3; - known_input_classes = 1; - - if ( ALLOC_ARRAY( lookahead_classes, ccpf2->MaxLookaheadLength, FT_UShort ) ) - goto End2; - known_lookahead_classes = 0; - - error = Get_Class( &ccpf2->InputClassDef, IN_CURGLYPH(), - &input_classes[0], NULL ); - if ( error && error != TTO_Err_Not_Covered ) - goto End1; - - cpcs = &ccpf2->ChainPosClassSet[input_classes[0]]; - if ( !cpcs ) - { - error = TTO_Err_Invalid_GPOS_SubTable; - goto End1; - } - - for ( k = 0; k < cpcs->ChainPosClassRuleCount; k++ ) - { - cpcr = cpcs->ChainPosClassRule[k]; - bgc = cpcr.BacktrackGlyphCount; - igc = cpcr.InputGlyphCount; - lgc = cpcr.LookaheadGlyphCount; - - if ( context_length != 0xFFFF && context_length < igc ) - goto next_chainposclassrule; - - /* check whether context is too long; it is a first guess only */ - - if ( bgc > buffer->in_pos || buffer->in_pos + igc + lgc > buffer->in_length ) - goto next_chainposclassrule; - - if ( bgc ) - { - /* Since we don't know in advance the number of glyphs to inspect, - we search backwards for matches in the backtrack glyph array. - Note that `known_backtrack_classes' starts at index 0. */ - - bc = cpcr.Backtrack; - - for ( i = 0, j = buffer->in_pos - 1; i < bgc; i++, j-- ) - { - while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) - { - if ( error && error != TTO_Err_Not_Covered ) - goto End1; - - if ( j + 1 == bgc - i ) - goto next_chainposclassrule; - j++; - } - - if ( i >= known_backtrack_classes ) - { - /* Keeps us from having to do this for each rule */ - - error = Get_Class( &ccpf2->BacktrackClassDef, IN_GLYPH( j ), - &backtrack_classes[i], NULL ); - if ( error && error != TTO_Err_Not_Covered ) - goto End1; - known_backtrack_classes = i; - } - - if ( bc[i] != backtrack_classes[i] ) - goto next_chainposclassrule; - } - } - - ic = cpcr.Input; - - /* Start at 1 because [0] is implied */ - - for ( i = 1, j = buffer->in_pos + 1; i < igc; i++, j++ ) - { - while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) - { - if ( error && error != TTO_Err_Not_Covered ) - goto End1; - - if ( j + igc - i + lgc == buffer->in_length ) - goto next_chainposclassrule; - j++; - } - - if ( i >= known_input_classes ) - { - error = Get_Class( &ccpf2->InputClassDef, IN_GLYPH( j ), - &input_classes[i], NULL ); - if ( error && error != TTO_Err_Not_Covered ) - goto End1; - known_input_classes = i; - } - - if ( ic[i - 1] != input_classes[i] ) - goto next_chainposclassrule; - } - - /* we are starting to check for lookahead glyphs right after the - last context glyph */ - - lc = cpcr.Lookahead; - - for ( i = 0; i < lgc; i++, j++ ) - { - while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) - { - if ( error && error != TTO_Err_Not_Covered ) - goto End1; - - if ( j + lgc - i == buffer->in_length ) - goto next_chainposclassrule; - j++; - } - - if ( i >= known_lookahead_classes ) - { - error = Get_Class( &ccpf2->LookaheadClassDef, IN_GLYPH( j ), - &lookahead_classes[i], NULL ); - if ( error && error != TTO_Err_Not_Covered ) - goto End1; - known_lookahead_classes = i; - } - - if ( lc[i] != lookahead_classes[i] ) - goto next_chainposclassrule; - } - - error = Do_ContextPos( gpi, igc, - cpcr.PosCount, - cpcr.PosLookupRecord, - buffer, - nesting_level ); - goto End1; - - next_chainposclassrule: - ; - } - - error = TTO_Err_Not_Covered; - - End1: - FREE( lookahead_classes ); - - End2: - FREE( input_classes ); - - End3: - FREE( backtrack_classes ); - return error; - } - - - static FT_Error Lookup_ChainContextPos3( - GPOS_Instance* gpi, - TTO_ChainContextPosFormat3* ccpf3, - OTL_Buffer buffer, - FT_UShort flags, - FT_UShort context_length, - int nesting_level ) - { - FT_UShort index, i, j, property; - FT_UShort bgc, igc, lgc; - FT_Error error; - TTO_GPOSHeader* gpos = gpi->gpos; - - TTO_Coverage* bc; - TTO_Coverage* ic; - TTO_Coverage* lc; - TTO_GDEFHeader* gdef; - - - gdef = gpos->gdef; - - if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) ) - return error; - - bgc = ccpf3->BacktrackGlyphCount; - igc = ccpf3->InputGlyphCount; - lgc = ccpf3->LookaheadGlyphCount; - - if ( context_length != 0xFFFF && context_length < igc ) - return TTO_Err_Not_Covered; - - /* check whether context is too long; it is a first guess only */ - - if ( bgc > buffer->in_pos || buffer->in_pos + igc + lgc > buffer->in_length ) - return TTO_Err_Not_Covered; - - if ( bgc ) - { - /* Since we don't know in advance the number of glyphs to inspect, - we search backwards for matches in the backtrack glyph array */ - - bc = ccpf3->BacktrackCoverage; - - for ( i = 0, j = buffer->in_pos - 1; i < bgc; i++, j-- ) - { - while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) - { - if ( error && error != TTO_Err_Not_Covered ) - return error; - - if ( j + 1 == bgc - i ) - return TTO_Err_Not_Covered; - j--; - } - - error = Coverage_Index( &bc[i], IN_GLYPH( j ), &index ); - if ( error ) - return error; - } - } - - ic = ccpf3->InputCoverage; - - for ( i = 0, j = buffer->in_pos; i < igc; i++, j++ ) - { - /* We already called CHECK_Property for IN_GLYPH ( buffer->in_pos ) */ - while ( j > buffer->in_pos && CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) - { - if ( error && error != TTO_Err_Not_Covered ) - return error; - - if ( j + igc - i + lgc == buffer->in_length ) - return TTO_Err_Not_Covered; - j++; - } - - error = Coverage_Index( &ic[i], IN_GLYPH( j ), &index ); - if ( error ) - return error; - } - - /* we are starting to check for lookahead glyphs right after the - last context glyph */ - - lc = ccpf3->LookaheadCoverage; - - for ( i = 0; i < lgc; i++, j++ ) - { - while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) - { - if ( error && error != TTO_Err_Not_Covered ) - return error; - - if ( j + lgc - i == buffer->in_length ) - return TTO_Err_Not_Covered; - j++; - } - - error = Coverage_Index( &lc[i], IN_GLYPH( j ), &index ); - if ( error ) - return error; - } - - return Do_ContextPos( gpi, igc, - ccpf3->PosCount, - ccpf3->PosLookupRecord, - buffer, - nesting_level ); - } - - - static FT_Error Lookup_ChainContextPos( - GPOS_Instance* gpi, - TTO_GPOS_SubTable* st, - OTL_Buffer buffer, - FT_UShort flags, - FT_UShort context_length, - int nesting_level ) - { - TTO_ChainContextPos* ccp = &st->chain; - - switch ( ccp->PosFormat ) - { - case 1: - return Lookup_ChainContextPos1( gpi, &ccp->ccpf.ccpf1, buffer, - flags, context_length, - nesting_level ); - - case 2: - return Lookup_ChainContextPos2( gpi, &ccp->ccpf.ccpf2, buffer, - flags, context_length, - nesting_level ); - - case 3: - return Lookup_ChainContextPos3( gpi, &ccp->ccpf.ccpf3, buffer, - flags, context_length, - nesting_level ); - - default: - return TTO_Err_Invalid_GPOS_SubTable_Format; - } - - return TT_Err_Ok; /* never reached */ - } - - - - /*********** - * GPOS API - ***********/ - - - EXPORT_FUNC - FT_Error TT_GPOS_Select_Script( TTO_GPOSHeader* gpos, - FT_ULong script_tag, - FT_UShort* script_index ) - { - FT_UShort n; - - TTO_ScriptList* sl; - TTO_ScriptRecord* sr; - - - if ( !gpos || !script_index ) - return TT_Err_Invalid_Argument; - - sl = &gpos->ScriptList; - sr = sl->ScriptRecord; - - for ( n = 0; n < sl->ScriptCount; n++ ) - if ( script_tag == sr[n].ScriptTag ) - { - *script_index = n; - - return TT_Err_Ok; - } - - return TTO_Err_Not_Covered; - } - - - EXPORT_FUNC - FT_Error TT_GPOS_Select_Language( TTO_GPOSHeader* gpos, - FT_ULong language_tag, - FT_UShort script_index, - FT_UShort* language_index, - FT_UShort* req_feature_index ) - { - FT_UShort n; - - TTO_ScriptList* sl; - TTO_ScriptRecord* sr; - TTO_Script* s; - TTO_LangSysRecord* lsr; - - - if ( !gpos || !language_index || !req_feature_index ) - return TT_Err_Invalid_Argument; - - sl = &gpos->ScriptList; - sr = sl->ScriptRecord; - - if ( script_index >= sl->ScriptCount ) - return TT_Err_Invalid_Argument; - - s = &sr[script_index].Script; - lsr = s->LangSysRecord; - - for ( n = 0; n < s->LangSysCount; n++ ) - if ( language_tag == lsr[n].LangSysTag ) - { - *language_index = n; - *req_feature_index = lsr[n].LangSys.ReqFeatureIndex; - - return TT_Err_Ok; - } - - return TTO_Err_Not_Covered; - } - - - /* selecting 0xFFFF for language_index asks for the values of the - default language (DefaultLangSys) */ - - EXPORT_FUNC - FT_Error TT_GPOS_Select_Feature( TTO_GPOSHeader* gpos, - FT_ULong feature_tag, - FT_UShort script_index, - FT_UShort language_index, - FT_UShort* feature_index ) - { - FT_UShort n; - - TTO_ScriptList* sl; - TTO_ScriptRecord* sr; - TTO_Script* s; - TTO_LangSysRecord* lsr; - TTO_LangSys* ls; - FT_UShort* fi; - - TTO_FeatureList* fl; - TTO_FeatureRecord* fr; - - - if ( !gpos || !feature_index ) - return TT_Err_Invalid_Argument; - - sl = &gpos->ScriptList; - sr = sl->ScriptRecord; - - fl = &gpos->FeatureList; - fr = fl->FeatureRecord; - - if ( script_index >= sl->ScriptCount ) - return TT_Err_Invalid_Argument; - - s = &sr[script_index].Script; - lsr = s->LangSysRecord; - - if ( language_index == 0xFFFF ) - ls = &s->DefaultLangSys; - else - { - if ( language_index >= s->LangSysCount ) - return TT_Err_Invalid_Argument; - - ls = &lsr[language_index].LangSys; - } - - fi = ls->FeatureIndex; - - for ( n = 0; n < ls->FeatureCount; n++ ) - { - if ( fi[n] >= fl->FeatureCount ) - return TTO_Err_Invalid_GPOS_SubTable_Format; - - if ( feature_tag == fr[fi[n]].FeatureTag ) - { - *feature_index = fi[n]; - - return TT_Err_Ok; - } - } - - return TTO_Err_Not_Covered; - } - - - /* The next three functions return a null-terminated list */ - - EXPORT_FUNC - FT_Error TT_GPOS_Query_Scripts( TTO_GPOSHeader* gpos, - FT_ULong** script_tag_list ) - { - FT_Error error; - FT_Memory memory = gpos->memory; - FT_UShort n; - FT_ULong* stl; - - TTO_ScriptList* sl; - TTO_ScriptRecord* sr; - - - if ( !gpos || !script_tag_list ) - return TT_Err_Invalid_Argument; - - sl = &gpos->ScriptList; - sr = sl->ScriptRecord; - - if ( ALLOC_ARRAY( stl, sl->ScriptCount + 1, FT_ULong ) ) - return error; - - for ( n = 0; n < sl->ScriptCount; n++ ) - stl[n] = sr[n].ScriptTag; - stl[n] = 0; - - *script_tag_list = stl; - - return TT_Err_Ok; - } - - - EXPORT_FUNC - FT_Error TT_GPOS_Query_Languages( TTO_GPOSHeader* gpos, - FT_UShort script_index, - FT_ULong** language_tag_list ) - { - FT_Error error; - FT_Memory memory = gpos->memory; - FT_UShort n; - FT_ULong* ltl; - - TTO_ScriptList* sl; - TTO_ScriptRecord* sr; - TTO_Script* s; - TTO_LangSysRecord* lsr; - - - if ( !gpos || !language_tag_list ) - return TT_Err_Invalid_Argument; - - sl = &gpos->ScriptList; - sr = sl->ScriptRecord; - - if ( script_index >= sl->ScriptCount ) - return TT_Err_Invalid_Argument; - - s = &sr[script_index].Script; - lsr = s->LangSysRecord; - - if ( ALLOC_ARRAY( ltl, s->LangSysCount + 1, FT_ULong ) ) - return error; - - for ( n = 0; n < s->LangSysCount; n++ ) - ltl[n] = lsr[n].LangSysTag; - ltl[n] = 0; - - *language_tag_list = ltl; - - return TT_Err_Ok; - } - - - /* selecting 0xFFFF for language_index asks for the values of the - default language (DefaultLangSys) */ - - EXPORT_FUNC - FT_Error TT_GPOS_Query_Features( TTO_GPOSHeader* gpos, - FT_UShort script_index, - FT_UShort language_index, - FT_ULong** feature_tag_list ) - { - FT_UShort n; - FT_Error error; - FT_Memory memory = gpos->memory; - FT_ULong* ftl; - - TTO_ScriptList* sl; - TTO_ScriptRecord* sr; - TTO_Script* s; - TTO_LangSysRecord* lsr; - TTO_LangSys* ls; - FT_UShort* fi; - - TTO_FeatureList* fl; - TTO_FeatureRecord* fr; - - - if ( !gpos || !feature_tag_list ) - return TT_Err_Invalid_Argument; - - sl = &gpos->ScriptList; - sr = sl->ScriptRecord; - - fl = &gpos->FeatureList; - fr = fl->FeatureRecord; - - if ( script_index >= sl->ScriptCount ) - return TT_Err_Invalid_Argument; - - s = &sr[script_index].Script; - lsr = s->LangSysRecord; - - if ( language_index == 0xFFFF ) - ls = &s->DefaultLangSys; - else - { - if ( language_index >= s->LangSysCount ) - return TT_Err_Invalid_Argument; - - ls = &lsr[language_index].LangSys; - } - - fi = ls->FeatureIndex; - - if ( ALLOC_ARRAY( ftl, ls->FeatureCount + 1, FT_ULong ) ) - return error; - - for ( n = 0; n < ls->FeatureCount; n++ ) - { - if ( fi[n] >= fl->FeatureCount ) - { - FREE( ftl ); - return TTO_Err_Invalid_GPOS_SubTable_Format; - } - ftl[n] = fr[fi[n]].FeatureTag; - } - ftl[n] = 0; - - *feature_tag_list = ftl; - - return TT_Err_Ok; - } - - - typedef FT_Error (*Lookup_Func_Type) ( GPOS_Instance* gpi, - TTO_GPOS_SubTable* st, - OTL_Buffer buffer, - FT_UShort flags, - FT_UShort context_length, - int nesting_level ); - static const Lookup_Func_Type Lookup_Call_Table[] = { - Lookup_DefaultPos, - Lookup_SinglePos, /* GPOS_LOOKUP_SINGLE 1 */ - Lookup_PairPos, /* GPOS_LOOKUP_PAIR 2 */ - Lookup_CursivePos, /* GPOS_LOOKUP_CURSIVE 3 */ - Lookup_MarkBasePos, /* GPOS_LOOKUP_MARKBASE 4 */ - Lookup_MarkLigPos, /* GPOS_LOOKUP_MARKLIG 5 */ - Lookup_MarkMarkPos, /* GPOS_LOOKUP_MARKMARK 6 */ - Lookup_ContextPos, /* GPOS_LOOKUP_CONTEXT 7 */ - Lookup_ChainContextPos, /* GPOS_LOOKUP_CHAIN 8 */ - Lookup_DefaultPos, /* GPOS_LOOKUP_EXTENSION 9 */ - }; - - /* Do an individual subtable lookup. Returns TT_Err_Ok if positioning - has been done, or TTO_Err_Not_Covered if not. */ - - static FT_Error Do_Glyph_Lookup( GPOS_Instance* gpi, - FT_UShort lookup_index, - OTL_Buffer buffer, - FT_UShort context_length, - int nesting_level ) - { - FT_Error error = TTO_Err_Not_Covered; - FT_UShort i, flags, lookup_count; - TTO_GPOSHeader* gpos = gpi->gpos; - TTO_Lookup* lo; - int lt; - Lookup_Func_Type Lookup_Func; - - - nesting_level++; - - if ( nesting_level > TTO_MAX_NESTING_LEVEL ) - return TTO_Err_Too_Many_Nested_Contexts; - - lookup_count = gpos->LookupList.LookupCount; - if (lookup_index >= lookup_count) - return error; - - lo = &gpos->LookupList.Lookup[lookup_index]; - flags = lo->LookupFlag; - lt = lo->LookupType; - if (lt >= sizeof Lookup_Call_Table / sizeof Lookup_Call_Table[0]) - lt = 0; - Lookup_Func = Lookup_Call_Table[lt]; - - for ( i = 0; i < lo->SubTableCount; i++ ) - { - error = Lookup_Func ( gpi, - &lo->SubTable[i].st.gpos, - buffer, - flags, context_length, - nesting_level ); - - /* Check whether we have a successful positioning or an error other - than TTO_Err_Not_Covered */ - - if ( error != TTO_Err_Not_Covered ) - return error; - } - - return TTO_Err_Not_Covered; - } - - - /* apply one lookup to the input string object */ - - static FT_Error Do_String_Lookup( GPOS_Instance* gpi, - FT_UShort lookup_index, - OTL_Buffer buffer ) - { - FT_Error error, retError = TTO_Err_Not_Covered; - TTO_GPOSHeader* gpos = gpi->gpos; - - FT_UInt* properties = gpos->LookupList.Properties; - - int nesting_level = 0; - - - gpi->last = 0xFFFF; /* no last valid glyph for cursive pos. */ - - buffer->in_pos = 0; - - while ( buffer->in_pos < buffer->in_length ) - { - if ( ~IN_PROPERTIES( buffer->in_pos ) & properties[lookup_index] ) - { - /* 0xFFFF indicates that we don't have a context length yet. */ - - /* Note that the connection between mark and base glyphs hold - exactly one (string) lookup. For example, it would be possible - that in the first lookup, mark glyph X is attached to base - glyph A, and in the next lookup it is attached to base glyph B. - It is up to the font designer to provide meaningful lookups and - lookup order. */ - - error = Do_Glyph_Lookup( gpi, lookup_index, buffer, - 0xFFFF, nesting_level ); - if ( error && error != TTO_Err_Not_Covered ) - return error; - } - else - { - /* Contrary to properties defined in GDEF, user-defined properties - will always stop a possible cursive positioning. */ - gpi->last = 0xFFFF; - - error = TTO_Err_Not_Covered; - } - - if ( error == TTO_Err_Not_Covered ) - (buffer->in_pos)++; - else - retError = error; - } - - return retError; - } - - - static FT_Error Position_CursiveChain ( OTL_Buffer buffer ) - { - FT_ULong i, j; - OTL_Position positions = buffer->positions; - - /* First handle all left-to-right connections */ - for (j = 0; j < buffer->in_length; j--) - { - if (positions[j].cursive_chain > 0) - positions[j].y_pos += positions[j - positions[j].cursive_chain].y_pos; - } - - /* Then handle all right-to-left connections */ - for (i = buffer->in_length; i > 0; i--) - { - j = i - 1; - - if (positions[j].cursive_chain < 0) - positions[j].y_pos += positions[j - positions[j].cursive_chain].y_pos; - } - - return TT_Err_Ok; - } - - EXPORT_FUNC - FT_Error TT_GPOS_Add_Feature( TTO_GPOSHeader* gpos, - FT_UShort feature_index, - FT_UInt property ) - { - FT_UShort i; - - TTO_Feature feature; - FT_UInt* properties; - FT_UShort* index; - FT_UShort lookup_count; - - /* Each feature can only be added once */ - - if ( !gpos || - feature_index >= gpos->FeatureList.FeatureCount || - gpos->FeatureList.ApplyCount == gpos->FeatureList.FeatureCount ) - return TT_Err_Invalid_Argument; - - gpos->FeatureList.ApplyOrder[gpos->FeatureList.ApplyCount++] = feature_index; - - properties = gpos->LookupList.Properties; - - feature = gpos->FeatureList.FeatureRecord[feature_index].Feature; - index = feature.LookupListIndex; - lookup_count = gpos->LookupList.LookupCount; - - for ( i = 0; i < feature.LookupListCount; i++ ) - { - FT_UShort lookup_index = index[i]; - if (lookup_index < lookup_count) - properties[lookup_index] |= property; - } - - return TT_Err_Ok; - } - - - EXPORT_FUNC - FT_Error TT_GPOS_Clear_Features( TTO_GPOSHeader* gpos ) - { - FT_UShort i; - - FT_UInt* properties; - - - if ( !gpos ) - return TT_Err_Invalid_Argument; - - gpos->FeatureList.ApplyCount = 0; - - properties = gpos->LookupList.Properties; - - for ( i = 0; i < gpos->LookupList.LookupCount; i++ ) - properties[i] = 0; - - return TT_Err_Ok; - } - - - EXPORT_FUNC - FT_Error TT_GPOS_Register_Glyph_Function( TTO_GPOSHeader* gpos, - TTO_GlyphFunction gfunc ) - { - if ( !gpos ) - return TT_Err_Invalid_Argument; - - gpos->gfunc = gfunc; - - return TT_Err_Ok; - } - - - EXPORT_FUNC - FT_Error TT_GPOS_Register_MM_Function( TTO_GPOSHeader* gpos, - TTO_MMFunction mmfunc, - void* data ) - { - if ( !gpos ) - return TT_Err_Invalid_Argument; - - gpos->mmfunc = mmfunc; - gpos->data = data; - - return TT_Err_Ok; - } - - /* If `dvi' is TRUE, glyph contour points for anchor points and device - tables are ignored -- you will get device independent values. */ - - EXPORT_FUNC - FT_Error TT_GPOS_Apply_String( FT_Face face, - TTO_GPOSHeader* gpos, - FT_UShort load_flags, - OTL_Buffer buffer, - FT_Bool dvi, - FT_Bool r2l ) - { - FT_Error error, retError = TTO_Err_Not_Covered; - GPOS_Instance gpi; - FT_UShort i, j, feature_index, lookup_count; - TTO_Feature feature; - - if ( !face || !gpos || - !buffer || buffer->in_length == 0 || buffer->in_pos >= buffer->in_length ) - return TT_Err_Invalid_Argument; - - gpi.face = face; - gpi.gpos = gpos; - gpi.load_flags = load_flags; - gpi.r2l = r2l; - gpi.dvi = dvi; - - lookup_count = gpos->LookupList.LookupCount; - - for ( i = 0; i < gpos->FeatureList.ApplyCount; i++ ) - { - /* index of i'th feature */ - feature_index = gpos->FeatureList.ApplyOrder[i]; - feature = gpos->FeatureList.FeatureRecord[feature_index].Feature; - - for ( j = 0; j < feature.LookupListCount; j++ ) - { - FT_UShort lookup_index = feature.LookupListIndex[j]; - - /* Skip nonexistant lookups */ - if (lookup_index >= lookup_count) - continue; - - error = Do_String_Lookup( &gpi, lookup_index, buffer ); - if ( error ) - { - if ( error != TTO_Err_Not_Covered ) - return error; - } - else - retError = error; - } - } - - error = Position_CursiveChain ( buffer ); - if ( error ) - return error; - - return retError; - } - -/* END */ diff --git a/src/ftxgpos.h b/src/ftxgpos.h deleted file mode 100644 index 28d1bae..0000000 --- a/src/ftxgpos.h +++ /dev/null @@ -1,838 +0,0 @@ -/******************************************************************* - * - * ftxgpos.h - * - * TrueType Open GPOS table support - * - * Copyright 1996-2000 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 FTXOPEN_H -#error "Don't include this file! Use ftxopen.h instead." -#endif - -#ifndef FTXGPOS_H -#define FTXGPOS_H - -#ifdef __cplusplus -extern "C" { -#endif - -#define TTO_Err_Invalid_GPOS_SubTable_Format 0x1020 -#define TTO_Err_Invalid_GPOS_SubTable 0x1021 - - -/* Lookup types for glyph positioning */ - -#define GPOS_LOOKUP_SINGLE 1 -#define GPOS_LOOKUP_PAIR 2 -#define GPOS_LOOKUP_CURSIVE 3 -#define GPOS_LOOKUP_MARKBASE 4 -#define GPOS_LOOKUP_MARKLIG 5 -#define GPOS_LOOKUP_MARKMARK 6 -#define GPOS_LOOKUP_CONTEXT 7 -#define GPOS_LOOKUP_CHAIN 8 -#define GPOS_LOOKUP_EXTENSION 9 - - - /* A pointer to a function which loads a glyph. Its parameters are - the same as in a call to TT_Load_Glyph() -- if no glyph loading - function will be registered with TTO_GPOS_Register_Glyph_Function(), - TT_Load_Glyph() will be called indeed. The purpose of this function - pointer is to provide a hook for caching glyph outlines and sbits - (using the instance's generic pointer to hold the data). - - If for some reason no outline data is available (e.g. for an - embedded bitmap glyph), _glyph->outline.n_points should be set to - zero. _glyph can be computed with - - _glyph = HANDLE_Glyph( glyph ) */ - - typedef FT_Error (*TTO_GlyphFunction)(FT_Face face, - FT_UInt glyphIndex, - FT_Int loadFlags ); - - - /* A pointer to a function which accesses the PostScript interpreter. - Multiple Master fonts need this interface to convert a metric ID - (as stored in an OpenType font version 1.2 or higher) `metric_id' - into a metric value (returned in `metric_value'). - - `data' points to the user-defined structure specified during a - call to TT_GPOS_Register_MM_Function(). - - `metric_value' must be returned as a scaled value (but shouldn't - be rounded). */ - - typedef FT_Error (*TTO_MMFunction)(FT_Face face, - FT_UShort metric_id, - FT_Pos* metric_value, - void* data ); - - - struct TTO_GPOSHeader_ - { - FT_Memory memory; - - FT_Fixed Version; - - TTO_ScriptList ScriptList; - TTO_FeatureList FeatureList; - TTO_LookupList LookupList; - - TTO_GDEFHeader* gdef; - - /* the next field is used for a callback function to get the - glyph outline. */ - - TTO_GlyphFunction gfunc; - - /* this is OpenType 1.2 -- Multiple Master fonts need this - callback function to get various metric values from the - PostScript interpreter. */ - - TTO_MMFunction mmfunc; - void* data; - }; - - typedef struct TTO_GPOSHeader_ TTO_GPOSHeader; - typedef struct TTO_GPOSHeader_* TTO_GPOS; - - - /* shared tables */ - - struct TTO_ValueRecord_ - { - FT_Short XPlacement; /* horizontal adjustment for - placement */ - FT_Short YPlacement; /* vertical adjustment for - placement */ - FT_Short XAdvance; /* horizontal adjustment for - advance */ - FT_Short YAdvance; /* vertical adjustment for - advance */ - TTO_Device XPlacementDevice; /* device table for horizontal - placement */ - TTO_Device YPlacementDevice; /* device table for vertical - placement */ - TTO_Device XAdvanceDevice; /* device table for horizontal - advance */ - TTO_Device YAdvanceDevice; /* device table for vertical - advance */ - FT_UShort XIdPlacement; /* horizontal placement metric ID */ - FT_UShort YIdPlacement; /* vertical placement metric ID */ - FT_UShort XIdAdvance; /* horizontal advance metric ID */ - FT_UShort YIdAdvance; /* vertical advance metric ID */ - }; - - typedef struct TTO_ValueRecord_ TTO_ValueRecord; - - -/* Mask values to scan the value format of the ValueRecord structure. - We always expand compressed ValueRecords of the font. */ - -#define HAVE_X_PLACEMENT 0x0001 -#define HAVE_Y_PLACEMENT 0x0002 -#define HAVE_X_ADVANCE 0x0004 -#define HAVE_Y_ADVANCE 0x0008 -#define HAVE_X_PLACEMENT_DEVICE 0x0010 -#define HAVE_Y_PLACEMENT_DEVICE 0x0020 -#define HAVE_X_ADVANCE_DEVICE 0x0040 -#define HAVE_Y_ADVANCE_DEVICE 0x0080 -#define HAVE_X_ID_PLACEMENT 0x0100 -#define HAVE_Y_ID_PLACEMENT 0x0200 -#define HAVE_X_ID_ADVANCE 0x0400 -#define HAVE_Y_ID_ADVANCE 0x0800 - - - struct TTO_AnchorFormat1_ - { - FT_Short XCoordinate; /* horizontal value */ - FT_Short YCoordinate; /* vertical value */ - }; - - typedef struct TTO_AnchorFormat1_ TTO_AnchorFormat1; - - - struct TTO_AnchorFormat2_ - { - FT_Short XCoordinate; /* horizontal value */ - FT_Short YCoordinate; /* vertical value */ - FT_UShort AnchorPoint; /* index to glyph contour point */ - }; - - typedef struct TTO_AnchorFormat2_ TTO_AnchorFormat2; - - - struct TTO_AnchorFormat3_ - { - FT_Short XCoordinate; /* horizontal value */ - FT_Short YCoordinate; /* vertical value */ - TTO_Device XDeviceTable; /* device table for X coordinate */ - TTO_Device YDeviceTable; /* device table for Y coordinate */ - }; - - typedef struct TTO_AnchorFormat3_ TTO_AnchorFormat3; - - - struct TTO_AnchorFormat4_ - { - FT_UShort XIdAnchor; /* horizontal metric ID */ - FT_UShort YIdAnchor; /* vertical metric ID */ - }; - - typedef struct TTO_AnchorFormat4_ TTO_AnchorFormat4; - - - struct TTO_Anchor_ - { - FT_UShort PosFormat; /* 1, 2, 3, or 4 -- 0 indicates - that there is no Anchor table */ - - union - { - TTO_AnchorFormat1 af1; - TTO_AnchorFormat2 af2; - TTO_AnchorFormat3 af3; - TTO_AnchorFormat4 af4; - } af; - }; - - typedef struct TTO_Anchor_ TTO_Anchor; - - - struct TTO_MarkRecord_ - { - FT_UShort Class; /* mark class */ - TTO_Anchor MarkAnchor; /* anchor table */ - }; - - typedef struct TTO_MarkRecord_ TTO_MarkRecord; - - - struct TTO_MarkArray_ - { - FT_UShort MarkCount; /* number of MarkRecord tables */ - TTO_MarkRecord* MarkRecord; /* array of MarkRecord tables */ - }; - - typedef struct TTO_MarkArray_ TTO_MarkArray; - - - /* LookupType 1 */ - - struct TTO_SinglePosFormat1_ - { - TTO_ValueRecord Value; /* ValueRecord for all covered - glyphs */ - }; - - typedef struct TTO_SinglePosFormat1_ TTO_SinglePosFormat1; - - - struct TTO_SinglePosFormat2_ - { - FT_UShort ValueCount; /* number of ValueRecord tables */ - TTO_ValueRecord* Value; /* array of ValueRecord tables */ - }; - - typedef struct TTO_SinglePosFormat2_ TTO_SinglePosFormat2; - - - struct TTO_SinglePos_ - { - FT_UShort PosFormat; /* 1 or 2 */ - TTO_Coverage Coverage; /* Coverage table */ - - FT_UShort ValueFormat; /* format of ValueRecord table */ - - union - { - TTO_SinglePosFormat1 spf1; - TTO_SinglePosFormat2 spf2; - } spf; - }; - - typedef struct TTO_SinglePos_ TTO_SinglePos; - - - /* LookupType 2 */ - - struct TTO_PairValueRecord_ - { - FT_UShort SecondGlyph; /* glyph ID for second glyph */ - TTO_ValueRecord Value1; /* pos. data for first glyph */ - TTO_ValueRecord Value2; /* pos. data for second glyph */ - }; - - typedef struct TTO_PairValueRecord_ TTO_PairValueRecord; - - - struct TTO_PairSet_ - { - FT_UShort PairValueCount; - /* number of PairValueRecord tables */ - TTO_PairValueRecord* PairValueRecord; - /* array of PairValueRecord tables */ - }; - - typedef struct TTO_PairSet_ TTO_PairSet; - - - struct TTO_PairPosFormat1_ - { - FT_UShort PairSetCount; /* number of PairSet tables */ - TTO_PairSet* PairSet; /* array of PairSet tables */ - }; - - typedef struct TTO_PairPosFormat1_ TTO_PairPosFormat1; - - - struct TTO_Class2Record_ - { - TTO_ValueRecord Value1; /* pos. data for first glyph */ - TTO_ValueRecord Value2; /* pos. data for second glyph */ - }; - - typedef struct TTO_Class2Record_ TTO_Class2Record; - - - struct TTO_Class1Record_ - { - TTO_Class2Record* Class2Record; /* array of Class2Record tables */ - }; - - typedef struct TTO_Class1Record_ TTO_Class1Record; - - - struct TTO_PairPosFormat2_ - { - TTO_ClassDefinition ClassDef1; /* class def. for first glyph */ - TTO_ClassDefinition ClassDef2; /* class def. for second glyph */ - FT_UShort Class1Count; /* number of classes in ClassDef1 - table */ - FT_UShort Class2Count; /* number of classes in ClassDef2 - table */ - TTO_Class1Record* Class1Record; /* array of Class1Record tables */ - }; - - typedef struct TTO_PairPosFormat2_ TTO_PairPosFormat2; - - - struct TTO_PairPos_ - { - FT_UShort PosFormat; /* 1 or 2 */ - TTO_Coverage Coverage; /* Coverage table */ - FT_UShort ValueFormat1; /* format of ValueRecord table - for first glyph */ - FT_UShort ValueFormat2; /* format of ValueRecord table - for second glyph */ - - union - { - TTO_PairPosFormat1 ppf1; - TTO_PairPosFormat2 ppf2; - } ppf; - }; - - typedef struct TTO_PairPos_ TTO_PairPos; - - - /* LookupType 3 */ - - struct TTO_EntryExitRecord_ - { - TTO_Anchor EntryAnchor; /* entry Anchor table */ - TTO_Anchor ExitAnchor; /* exit Anchor table */ - }; - - - typedef struct TTO_EntryExitRecord_ TTO_EntryExitRecord; - - struct TTO_CursivePos_ - { - FT_UShort PosFormat; /* always 1 */ - TTO_Coverage Coverage; /* Coverage table */ - FT_UShort EntryExitCount; - /* number of EntryExitRecord tables */ - TTO_EntryExitRecord* EntryExitRecord; - /* array of EntryExitRecord tables */ - }; - - typedef struct TTO_CursivePos_ TTO_CursivePos; - - - /* LookupType 4 */ - - struct TTO_BaseRecord_ - { - TTO_Anchor* BaseAnchor; /* array of base glyph anchor - tables */ - }; - - typedef struct TTO_BaseRecord_ TTO_BaseRecord; - - - struct TTO_BaseArray_ - { - FT_UShort BaseCount; /* number of BaseRecord tables */ - TTO_BaseRecord* BaseRecord; /* array of BaseRecord tables */ - }; - - typedef struct TTO_BaseArray_ TTO_BaseArray; - - - struct TTO_MarkBasePos_ - { - FT_UShort PosFormat; /* always 1 */ - TTO_Coverage MarkCoverage; /* mark glyph coverage table */ - TTO_Coverage BaseCoverage; /* base glyph coverage table */ - FT_UShort ClassCount; /* number of mark classes */ - TTO_MarkArray MarkArray; /* mark array table */ - TTO_BaseArray BaseArray; /* base array table */ - }; - - typedef struct TTO_MarkBasePos_ TTO_MarkBasePos; - - - /* LookupType 5 */ - - struct TTO_ComponentRecord_ - { - TTO_Anchor* LigatureAnchor; /* array of ligature glyph anchor - tables */ - }; - - typedef struct TTO_ComponentRecord_ TTO_ComponentRecord; - - - struct TTO_LigatureAttach_ - { - FT_UShort ComponentCount; - /* number of ComponentRecord tables */ - TTO_ComponentRecord* ComponentRecord; - /* array of ComponentRecord tables */ - }; - - typedef struct TTO_LigatureAttach_ TTO_LigatureAttach; - - - struct TTO_LigatureArray_ - { - FT_UShort LigatureCount; /* number of LigatureAttach tables */ - TTO_LigatureAttach* LigatureAttach; - /* array of LigatureAttach tables */ - }; - - typedef struct TTO_LigatureArray_ TTO_LigatureArray; - - - struct TTO_MarkLigPos_ - { - FT_UShort PosFormat; /* always 1 */ - TTO_Coverage MarkCoverage; /* mark glyph coverage table */ - TTO_Coverage LigatureCoverage; - /* ligature glyph coverage table */ - FT_UShort ClassCount; /* number of mark classes */ - TTO_MarkArray MarkArray; /* mark array table */ - TTO_LigatureArray LigatureArray; /* ligature array table */ - }; - - typedef struct TTO_MarkLigPos_ TTO_MarkLigPos; - - - /* LookupType 6 */ - - struct TTO_Mark2Record_ - { - TTO_Anchor* Mark2Anchor; /* array of mark glyph anchor - tables */ - }; - - typedef struct TTO_Mark2Record_ TTO_Mark2Record; - - - struct TTO_Mark2Array_ - { - FT_UShort Mark2Count; /* number of Mark2Record tables */ - TTO_Mark2Record* Mark2Record; /* array of Mark2Record tables */ - }; - - typedef struct TTO_Mark2Array_ TTO_Mark2Array; - - - struct TTO_MarkMarkPos_ - { - FT_UShort PosFormat; /* always 1 */ - TTO_Coverage Mark1Coverage; /* first mark glyph coverage table */ - TTO_Coverage Mark2Coverage; /* second mark glyph coverave table */ - FT_UShort ClassCount; /* number of combining mark classes */ - TTO_MarkArray Mark1Array; /* MarkArray table for first mark */ - TTO_Mark2Array Mark2Array; /* MarkArray table for second mark */ - }; - - typedef struct TTO_MarkMarkPos_ TTO_MarkMarkPos; - - - /* needed by both lookup type 7 and 8 */ - - struct TTO_PosLookupRecord_ - { - FT_UShort SequenceIndex; /* index into current - glyph sequence */ - FT_UShort LookupListIndex; /* Lookup to apply to that pos. */ - }; - - typedef struct TTO_PosLookupRecord_ TTO_PosLookupRecord; - - - /* LookupType 7 */ - - struct TTO_PosRule_ - { - FT_UShort GlyphCount; /* total number of input glyphs */ - FT_UShort PosCount; /* number of PosLookupRecord tables */ - FT_UShort* Input; /* array of input glyph IDs */ - TTO_PosLookupRecord* PosLookupRecord; - /* array of PosLookupRecord tables */ - }; - - typedef struct TTO_PosRule_ TTO_PosRule; - - - struct TTO_PosRuleSet_ - { - FT_UShort PosRuleCount; /* number of PosRule tables */ - TTO_PosRule* PosRule; /* array of PosRule tables */ - }; - - typedef struct TTO_PosRuleSet_ TTO_PosRuleSet; - - - struct TTO_ContextPosFormat1_ - { - TTO_Coverage Coverage; /* Coverage table */ - FT_UShort PosRuleSetCount; /* number of PosRuleSet tables */ - TTO_PosRuleSet* PosRuleSet; /* array of PosRuleSet tables */ - }; - - typedef struct TTO_ContextPosFormat1_ TTO_ContextPosFormat1; - - - struct TTO_PosClassRule_ - { - FT_UShort GlyphCount; /* total number of context classes */ - FT_UShort PosCount; /* number of PosLookupRecord tables */ - FT_UShort* Class; /* array of classes */ - TTO_PosLookupRecord* PosLookupRecord; - /* array of PosLookupRecord tables */ - }; - - typedef struct TTO_PosClassRule_ TTO_PosClassRule; - - - struct TTO_PosClassSet_ - { - FT_UShort PosClassRuleCount; - /* number of PosClassRule tables */ - TTO_PosClassRule* PosClassRule; /* array of PosClassRule tables */ - }; - - typedef struct TTO_PosClassSet_ TTO_PosClassSet; - - - /* The `MaxContextLength' field is not defined in the TTO specification - but simplifies the implementation of this format. It holds the - maximal context length used in the context rules. */ - - struct TTO_ContextPosFormat2_ - { - FT_UShort MaxContextLength; - /* maximal context length */ - TTO_Coverage Coverage; /* Coverage table */ - TTO_ClassDefinition ClassDef; /* ClassDef table */ - FT_UShort PosClassSetCount; - /* number of PosClassSet tables */ - TTO_PosClassSet* PosClassSet; /* array of PosClassSet tables */ - }; - - typedef struct TTO_ContextPosFormat2_ TTO_ContextPosFormat2; - - - struct TTO_ContextPosFormat3_ - { - FT_UShort GlyphCount; /* number of input glyphs */ - FT_UShort PosCount; /* number of PosLookupRecord tables */ - TTO_Coverage* Coverage; /* array of Coverage tables */ - TTO_PosLookupRecord* PosLookupRecord; - /* array of PosLookupRecord tables */ - }; - - typedef struct TTO_ContextPosFormat3_ TTO_ContextPosFormat3; - - - struct TTO_ContextPos_ - { - FT_UShort PosFormat; /* 1, 2, or 3 */ - - union - { - TTO_ContextPosFormat1 cpf1; - TTO_ContextPosFormat2 cpf2; - TTO_ContextPosFormat3 cpf3; - } cpf; - }; - - typedef struct TTO_ContextPos_ TTO_ContextPos; - - - /* LookupType 8 */ - - struct TTO_ChainPosRule_ - { - FT_UShort BacktrackGlyphCount; - /* total number of backtrack glyphs */ - FT_UShort* Backtrack; /* array of backtrack glyph IDs */ - FT_UShort InputGlyphCount; - /* total number of input glyphs */ - FT_UShort* Input; /* array of input glyph IDs */ - FT_UShort LookaheadGlyphCount; - /* total number of lookahead glyphs */ - FT_UShort* Lookahead; /* array of lookahead glyph IDs */ - FT_UShort PosCount; /* number of PosLookupRecords */ - TTO_PosLookupRecord* PosLookupRecord; - /* array of PosLookupRecords */ - }; - - typedef struct TTO_ChainPosRule_ TTO_ChainPosRule; - - - struct TTO_ChainPosRuleSet_ - { - FT_UShort ChainPosRuleCount; - /* number of ChainPosRule tables */ - TTO_ChainPosRule* ChainPosRule; /* array of ChainPosRule tables */ - }; - - typedef struct TTO_ChainPosRuleSet_ TTO_ChainPosRuleSet; - - - struct TTO_ChainContextPosFormat1_ - { - TTO_Coverage Coverage; /* Coverage table */ - FT_UShort ChainPosRuleSetCount; - /* number of ChainPosRuleSet tables */ - TTO_ChainPosRuleSet* ChainPosRuleSet; - /* array of ChainPosRuleSet tables */ - }; - - typedef struct TTO_ChainContextPosFormat1_ TTO_ChainContextPosFormat1; - - - struct TTO_ChainPosClassRule_ - { - FT_UShort BacktrackGlyphCount; - /* total number of backtrack - classes */ - FT_UShort* Backtrack; /* array of backtrack classes */ - FT_UShort InputGlyphCount; - /* total number of context classes */ - FT_UShort* Input; /* array of context classes */ - FT_UShort LookaheadGlyphCount; - /* total number of lookahead - classes */ - FT_UShort* Lookahead; /* array of lookahead classes */ - FT_UShort PosCount; /* number of PosLookupRecords */ - TTO_PosLookupRecord* PosLookupRecord; - /* array of substitution lookups */ - }; - - typedef struct TTO_ChainPosClassRule_ TTO_ChainPosClassRule; - - - struct TTO_ChainPosClassSet_ - { - FT_UShort ChainPosClassRuleCount; - /* number of ChainPosClassRule - tables */ - TTO_ChainPosClassRule* ChainPosClassRule; - /* array of ChainPosClassRule - tables */ - }; - - typedef struct TTO_ChainPosClassSet_ TTO_ChainPosClassSet; - - - /* The `MaxXXXLength' fields are not defined in the TTO specification - but simplifies the implementation of this format. It holds the - maximal context length used in the specific context rules. */ - - struct TTO_ChainContextPosFormat2_ - { - TTO_Coverage Coverage; /* Coverage table */ - - FT_UShort MaxBacktrackLength; - /* maximal backtrack length */ - TTO_ClassDefinition BacktrackClassDef; - /* BacktrackClassDef table */ - FT_UShort MaxInputLength; - /* maximal input length */ - TTO_ClassDefinition InputClassDef; - /* InputClassDef table */ - FT_UShort MaxLookaheadLength; - /* maximal lookahead length */ - TTO_ClassDefinition LookaheadClassDef; - /* LookaheadClassDef table */ - - FT_UShort ChainPosClassSetCount; - /* number of ChainPosClassSet - tables */ - TTO_ChainPosClassSet* ChainPosClassSet; - /* array of ChainPosClassSet - tables */ - }; - - typedef struct TTO_ChainContextPosFormat2_ TTO_ChainContextPosFormat2; - - - struct TTO_ChainContextPosFormat3_ - { - FT_UShort BacktrackGlyphCount; - /* number of backtrack glyphs */ - TTO_Coverage* BacktrackCoverage; - /* array of backtrack Coverage - tables */ - FT_UShort InputGlyphCount; - /* number of input glyphs */ - TTO_Coverage* InputCoverage; - /* array of input coverage - tables */ - FT_UShort LookaheadGlyphCount; - /* number of lookahead glyphs */ - TTO_Coverage* LookaheadCoverage; - /* array of lookahead coverage - tables */ - FT_UShort PosCount; /* number of PosLookupRecords */ - TTO_PosLookupRecord* PosLookupRecord; - /* array of substitution lookups */ - }; - - typedef struct TTO_ChainContextPosFormat3_ TTO_ChainContextPosFormat3; - - - struct TTO_ChainContextPos_ - { - FT_UShort PosFormat; /* 1, 2, or 3 */ - - union - { - TTO_ChainContextPosFormat1 ccpf1; - TTO_ChainContextPosFormat2 ccpf2; - TTO_ChainContextPosFormat3 ccpf3; - } ccpf; - }; - - typedef struct TTO_ChainContextPos_ TTO_ChainContextPos; - - - union TTO_GPOS_SubTable_ - { - TTO_SinglePos single; - TTO_PairPos pair; - TTO_CursivePos cursive; - TTO_MarkBasePos markbase; - TTO_MarkLigPos marklig; - TTO_MarkMarkPos markmark; - TTO_ContextPos context; - TTO_ChainContextPos chain; - }; - - typedef union TTO_GPOS_SubTable_ TTO_GPOS_SubTable; - - - /* finally, the GPOS API */ - - /* EXPORT_DEF - FT_Export ( FT_Error ) TT_Init_GPOS_Extension( TT_Engine engine ); */ - - EXPORT_DEF - FT_Error TT_Load_GPOS_Table( FT_Face face, - TTO_GPOSHeader** gpos, - TTO_GDEFHeader* gdef ); - - EXPORT_DEF - FT_Error TT_Done_GPOS_Table( TTO_GPOSHeader* gpos ); - - EXPORT_DEF - FT_Error TT_GPOS_Select_Script( TTO_GPOSHeader* gpos, - FT_ULong script_tag, - FT_UShort* script_index ); - EXPORT_DEF - FT_Error TT_GPOS_Select_Language( TTO_GPOSHeader* gpos, - FT_ULong language_tag, - FT_UShort script_index, - FT_UShort* language_index, - FT_UShort* req_feature_index ); - EXPORT_DEF - FT_Error TT_GPOS_Select_Feature( TTO_GPOSHeader* gpos, - FT_ULong feature_tag, - FT_UShort script_index, - FT_UShort language_index, - FT_UShort* feature_index ); - - EXPORT_DEF - FT_Error TT_GPOS_Query_Scripts( TTO_GPOSHeader* gpos, - FT_ULong** script_tag_list ); - EXPORT_DEF - FT_Error TT_GPOS_Query_Languages( TTO_GPOSHeader* gpos, - FT_UShort script_index, - FT_ULong** language_tag_list ); - EXPORT_DEF - FT_Error TT_GPOS_Query_Features( TTO_GPOSHeader* gpos, - FT_UShort script_index, - FT_UShort language_index, - FT_ULong** feature_tag_list ); - - EXPORT_DEF - FT_Error TT_GPOS_Add_Feature( TTO_GPOSHeader* gpos, - FT_UShort feature_index, - FT_UInt property ); - EXPORT_DEF - FT_Error TT_GPOS_Clear_Features( TTO_GPOSHeader* gpos ); - - EXPORT_DEF - FT_Error TT_GPOS_Register_Glyph_Function( TTO_GPOSHeader* gpos, - TTO_GlyphFunction gfunc ); - - EXPORT_DEF - FT_Error TT_GPOS_Register_MM_Function( TTO_GPOSHeader* gpos, - TTO_MMFunction mmfunc, - void* data ); - - /* If `dvi' is TRUE, glyph contour points for anchor points and device - tables are ignored -- you will get device independent values. */ - - EXPORT_DEF - FT_Error TT_GPOS_Apply_String( FT_Face face, - TTO_GPOSHeader* gpos, - FT_UShort load_flags, - OTL_Buffer buffer, - FT_Bool dvi, - FT_Bool r2l ); - -#ifdef __cplusplus -} -#endif - -#endif /* FTXGPOS_H */ - - -/* END */ diff --git a/src/ftxgsub.c b/src/ftxgsub.c deleted file mode 100644 index ce30697..0000000 --- a/src/ftxgsub.c +++ /dev/null @@ -1,4533 +0,0 @@ -/******************************************************************* - * - * ftxgsub.c - * - * TrueType Open GSUB table support. - * - * Copyright 1996-2000 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. - * - ******************************************************************/ - -#include - -/* XXX There is *a lot* of duplicated code (cf. formats 5 and 6), but - I don't care currently. I believe that it would be possible to - save about 50% of TTO code by carefully designing the structures, - sharing as much as possible with extensive use of macros. This - is something for a volunteer :-) */ - -#define EXPORT_FUNC - -#include "ftxopen.h" -#include "ftxopenf.h" - -#include "ftglue.h" - -#include FT_TRUETYPE_TAGS_H - -#define GSUB_ID Build_Extension_ID( 'G', 'S', 'U', 'B' ) - - -#define IN_GLYPH( pos ) buffer->in_string[(pos)].gindex -#define IN_ITEM( pos ) (&buffer->in_string[(pos)]) -#define IN_CURGLYPH() buffer->in_string[buffer->in_pos].gindex -#define IN_CURITEM() (&buffer->in_string[buffer->in_pos]) -#define IN_PROPERTIES( pos ) buffer->in_string[(pos)].properties -#define IN_LIGID( pos ) buffer->in_string[(pos)].ligID - -#define OUT_GLYPH( pos ) buffer->out_string[(pos)].gindex -#define OUT_ITEM( pos ) (&buffer->out_string[(pos)]) - -#define ADD_String( buffer, num_in, num_out, glyph_data, component, ligID ) \ - ( ( error = otl_buffer_add_output_glyphs( (buffer), \ - (num_in), (num_out), \ - (glyph_data), (component), (ligID) \ - ) ) != TT_Err_Ok ) -#define ADD_Glyph( buffer, glyph_index, component, ligID ) \ - ( ( error = otl_buffer_add_output_glyph( (buffer), \ - (glyph_index), (component), (ligID) \ - ) ) != TT_Err_Ok ) - - - static FT_Error Do_Glyph_Lookup( TTO_GSUBHeader* gsub, - FT_UShort lookup_index, - OTL_Buffer buffer, - FT_UShort context_length, - int nesting_level ); - - - - /********************** - * Auxiliary functions - **********************/ - - - EXPORT_FUNC - FT_Error TT_Load_GSUB_Table( FT_Face face, - TTO_GSUBHeader** retptr, - TTO_GDEFHeader* gdef ) - { - FT_Stream stream = face->stream; - FT_Memory memory = face->memory; - FT_Error error; - FT_ULong cur_offset, new_offset, base_offset; - - FT_UShort i, num_lookups; - TTO_GSUBHeader* gsub; - TTO_Lookup* lo; - - if ( !retptr ) - return TT_Err_Invalid_Argument; - - if (( error = ftglue_face_goto_table( face, TTAG_GSUB, stream ) )) - return error; - - base_offset = FILE_Pos(); - - if ( ALLOC ( gsub, sizeof( *gsub ) ) ) - return error; - - gsub->memory = memory; - - /* skip version */ - - if ( FILE_Seek( base_offset + 4L ) || - ACCESS_Frame( 2L ) ) - goto Fail4; - - new_offset = GET_UShort() + base_offset; - - FORGET_Frame(); - - cur_offset = FILE_Pos(); - if ( FILE_Seek( new_offset ) || - ( error = Load_ScriptList( &gsub->ScriptList, - stream ) ) != TT_Err_Ok ) - goto Fail4; - (void)FILE_Seek( cur_offset ); - - if ( ACCESS_Frame( 2L ) ) - goto Fail3; - - new_offset = GET_UShort() + base_offset; - - FORGET_Frame(); - - cur_offset = FILE_Pos(); - if ( FILE_Seek( new_offset ) || - ( error = Load_FeatureList( &gsub->FeatureList, - stream ) ) != TT_Err_Ok ) - goto Fail3; - (void)FILE_Seek( cur_offset ); - - if ( ACCESS_Frame( 2L ) ) - goto Fail2; - - new_offset = GET_UShort() + base_offset; - - FORGET_Frame(); - - cur_offset = FILE_Pos(); - if ( FILE_Seek( new_offset ) || - ( error = Load_LookupList( &gsub->LookupList, - stream, GSUB ) ) != TT_Err_Ok ) - goto Fail2; - - gsub->gdef = gdef; /* can be NULL */ - - /* We now check the LookupFlags for values larger than 0xFF to find - out whether we need to load the `MarkAttachClassDef' field of the - GDEF table -- this hack is necessary for OpenType 1.2 tables since - the version field of the GDEF table hasn't been incremented. - - For constructed GDEF tables, we only load it if - `MarkAttachClassDef_offset' is not zero (nevertheless, a build of - a constructed mark attach table is not supported currently). */ - - if ( gdef && - gdef->MarkAttachClassDef_offset && !gdef->MarkAttachClassDef.loaded ) - { - lo = gsub->LookupList.Lookup; - num_lookups = gsub->LookupList.LookupCount; - - for ( i = 0; i < num_lookups; i++ ) - { - - if ( lo[i].LookupFlag & IGNORE_SPECIAL_MARKS ) - { - if ( FILE_Seek( gdef->MarkAttachClassDef_offset ) || - ( error = Load_ClassDefinition( &gdef->MarkAttachClassDef, - 256, stream ) ) != TT_Err_Ok ) - goto Fail1; - - break; - } - } - } - - *retptr = gsub; - - return TT_Err_Ok; - - Fail1: - Free_LookupList( &gsub->LookupList, GSUB, memory ); - - Fail2: - Free_FeatureList( &gsub->FeatureList, memory ); - - Fail3: - Free_ScriptList( &gsub->ScriptList, memory ); - - Fail4: - FREE ( gsub ); - - - return error; - } - - EXPORT_FUNC - FT_Error TT_Done_GSUB_Table( TTO_GSUBHeader* gsub ) - { - FT_Memory memory = gsub->memory; - - Free_LookupList( &gsub->LookupList, GSUB, memory ); - Free_FeatureList( &gsub->FeatureList, memory ); - Free_ScriptList( &gsub->ScriptList, memory ); - - FREE( gsub ); - - return TT_Err_Ok; - } - - /***************************** - * SubTable related functions - *****************************/ - - static FT_Error Lookup_DefaultSubst( TTO_GSUBHeader* gsub, - TTO_GSUB_SubTable* st, - OTL_Buffer buffer, - FT_UShort flags, - FT_UShort context_length, - int nesting_level ) - { - return TTO_Err_Not_Covered; - } - - - /* LookupType 1 */ - - /* SingleSubstFormat1 */ - /* SingleSubstFormat2 */ - - FT_Error Load_SingleSubst( TTO_SingleSubst* ss, - FT_Stream stream ) - { - FT_Error error; - FT_Memory memory = stream->memory; - - FT_UShort n, count; - FT_ULong cur_offset, new_offset, base_offset; - - FT_UShort* s; - - - base_offset = FILE_Pos(); - - if ( ACCESS_Frame( 4L ) ) - return error; - - ss->SubstFormat = GET_UShort(); - new_offset = GET_UShort() + base_offset; - - FORGET_Frame(); - - cur_offset = FILE_Pos(); - if ( FILE_Seek( new_offset ) || - ( error = Load_Coverage( &ss->Coverage, stream ) ) != TT_Err_Ok ) - return error; - (void)FILE_Seek( cur_offset ); - - switch ( ss->SubstFormat ) - { - case 1: - if ( ACCESS_Frame( 2L ) ) - goto Fail2; - - ss->ssf.ssf1.DeltaGlyphID = GET_UShort(); - - FORGET_Frame(); - - break; - - case 2: - if ( ACCESS_Frame( 2L ) ) - goto Fail2; - - count = ss->ssf.ssf2.GlyphCount = GET_UShort(); - - FORGET_Frame(); - - ss->ssf.ssf2.Substitute = NULL; - - if ( ALLOC_ARRAY( ss->ssf.ssf2.Substitute, count, FT_UShort ) ) - goto Fail2; - - s = ss->ssf.ssf2.Substitute; - - if ( ACCESS_Frame( count * 2L ) ) - goto Fail1; - - for ( n = 0; n < count; n++ ) - s[n] = GET_UShort(); - - FORGET_Frame(); - - break; - - default: - return TTO_Err_Invalid_GSUB_SubTable_Format; - } - - return TT_Err_Ok; - - Fail1: - FREE( s ); - - Fail2: - Free_Coverage( &ss->Coverage, memory ); - return error; - } - - - void Free_SingleSubst( TTO_SingleSubst* ss, - FT_Memory memory ) - { - switch ( ss->SubstFormat ) - { - case 1: - break; - - case 2: - FREE( ss->ssf.ssf2.Substitute ); - break; - } - - Free_Coverage( &ss->Coverage, memory ); - } - - - static FT_Error Lookup_SingleSubst( TTO_GSUBHeader* gsub, - TTO_GSUB_SubTable* st, - OTL_Buffer buffer, - FT_UShort flags, - FT_UShort context_length, - int nesting_level ) - { - FT_UShort index, value, property; - FT_Error error; - TTO_SingleSubst* ss = &st->single; - TTO_GDEFHeader* gdef = gsub->gdef; - - - if ( context_length != 0xFFFF && context_length < 1 ) - return TTO_Err_Not_Covered; - - if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) ) - return error; - - error = Coverage_Index( &ss->Coverage, IN_CURGLYPH(), &index ); - if ( error ) - return error; - - switch ( ss->SubstFormat ) - { - case 1: - value = ( IN_CURGLYPH() + ss->ssf.ssf1.DeltaGlyphID ) & 0xFFFF; - if ( ADD_Glyph( buffer, value, 0xFFFF, 0xFFFF ) ) - return error; - break; - - case 2: - if ( index >= ss->ssf.ssf2.GlyphCount ) - return TTO_Err_Invalid_GSUB_SubTable; - value = ss->ssf.ssf2.Substitute[index]; - if ( ADD_Glyph( buffer, value, 0xFFFF, 0xFFFF ) ) - return error; - break; - - default: - return TTO_Err_Invalid_GSUB_SubTable; - } - - if ( gdef && gdef->NewGlyphClasses ) - { - /* we inherit the old glyph class to the substituted glyph */ - - error = Add_Glyph_Property( gdef, value, property ); - if ( error && error != TTO_Err_Not_Covered ) - return error; - } - - return TT_Err_Ok; - } - - - /* LookupType 2 */ - - /* Sequence */ - - static FT_Error Load_Sequence( TTO_Sequence* s, - FT_Stream stream ) - { - FT_Error error; - FT_Memory memory = stream->memory; - - FT_UShort n, count; - FT_UShort* sub; - - - if ( ACCESS_Frame( 2L ) ) - return error; - - count = s->GlyphCount = GET_UShort(); - - FORGET_Frame(); - - s->Substitute = NULL; - - if ( count ) - { - if ( ALLOC_ARRAY( s->Substitute, count, FT_UShort ) ) - return error; - - sub = s->Substitute; - - if ( ACCESS_Frame( count * 2L ) ) - { - FREE( sub ); - return error; - } - - for ( n = 0; n < count; n++ ) - sub[n] = GET_UShort(); - - FORGET_Frame(); - } - - return TT_Err_Ok; - } - - - static void Free_Sequence( TTO_Sequence* s, - FT_Memory memory ) - { - FREE( s->Substitute ); - } - - - /* MultipleSubstFormat1 */ - - FT_Error Load_MultipleSubst( TTO_MultipleSubst* ms, - FT_Stream stream ) - { - FT_Error error; - FT_Memory memory = stream->memory; - - FT_UShort n = 0, m, count; - FT_ULong cur_offset, new_offset, base_offset; - - TTO_Sequence* s; - - - base_offset = FILE_Pos(); - - if ( ACCESS_Frame( 4L ) ) - return error; - - ms->SubstFormat = GET_UShort(); /* should be 1 */ - new_offset = GET_UShort() + base_offset; - - FORGET_Frame(); - - cur_offset = FILE_Pos(); - if ( FILE_Seek( new_offset ) || - ( error = Load_Coverage( &ms->Coverage, stream ) ) != TT_Err_Ok ) - return error; - (void)FILE_Seek( cur_offset ); - - if ( ACCESS_Frame( 2L ) ) - goto Fail2; - - count = ms->SequenceCount = GET_UShort(); - - FORGET_Frame(); - - ms->Sequence = NULL; - - if ( ALLOC_ARRAY( ms->Sequence, count, TTO_Sequence ) ) - goto Fail2; - - s = ms->Sequence; - - for ( n = 0; n < count; n++ ) - { - if ( ACCESS_Frame( 2L ) ) - goto Fail1; - - new_offset = GET_UShort() + base_offset; - - FORGET_Frame(); - - cur_offset = FILE_Pos(); - if ( FILE_Seek( new_offset ) || - ( error = Load_Sequence( &s[n], stream ) ) != TT_Err_Ok ) - goto Fail1; - (void)FILE_Seek( cur_offset ); - } - - return TT_Err_Ok; - - Fail1: - for ( m = 0; m < n; m++ ) - Free_Sequence( &s[m], memory ); - - FREE( s ); - - Fail2: - Free_Coverage( &ms->Coverage, memory ); - return error; - } - - - void Free_MultipleSubst( TTO_MultipleSubst* ms, - FT_Memory memory ) - { - FT_UShort n, count; - - TTO_Sequence* s; - - - if ( ms->Sequence ) - { - count = ms->SequenceCount; - s = ms->Sequence; - - for ( n = 0; n < count; n++ ) - Free_Sequence( &s[n], memory ); - - FREE( s ); - } - - Free_Coverage( &ms->Coverage, memory ); - } - - - static FT_Error Lookup_MultipleSubst( TTO_GSUBHeader* gsub, - TTO_GSUB_SubTable* st, - OTL_Buffer buffer, - FT_UShort flags, - FT_UShort context_length, - int nesting_level ) - { - FT_Error error; - FT_UShort index, property, n, count; - FT_UShort*s; - TTO_MultipleSubst* ms = &st->multiple; - TTO_GDEFHeader* gdef = gsub->gdef; - - - if ( context_length != 0xFFFF && context_length < 1 ) - return TTO_Err_Not_Covered; - - if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) ) - return error; - - error = Coverage_Index( &ms->Coverage, IN_CURGLYPH(), &index ); - if ( error ) - return error; - - if ( index >= ms->SequenceCount ) - return TTO_Err_Invalid_GSUB_SubTable; - - count = ms->Sequence[index].GlyphCount; - s = ms->Sequence[index].Substitute; - - if ( ADD_String( buffer, 1, count, s, 0xFFFF, 0xFFFF ) ) - return error; - - if ( gdef && gdef->NewGlyphClasses ) - { - /* this is a guess only ... */ - - if ( property == TTO_LIGATURE ) - property = TTO_BASE_GLYPH; - - for ( n = 0; n < count; n++ ) - { - error = Add_Glyph_Property( gdef, s[n], property ); - if ( error && error != TTO_Err_Not_Covered ) - return error; - } - } - - return TT_Err_Ok; - } - - - /* LookupType 3 */ - - /* AlternateSet */ - - static FT_Error Load_AlternateSet( TTO_AlternateSet* as, - FT_Stream stream ) - { - FT_Error error; - FT_Memory memory = stream->memory; - - FT_UShort n, count; - FT_UShort* a; - - - if ( ACCESS_Frame( 2L ) ) - return error; - - count = as->GlyphCount = GET_UShort(); - - FORGET_Frame(); - - as->Alternate = NULL; - - if ( ALLOC_ARRAY( as->Alternate, count, FT_UShort ) ) - return error; - - a = as->Alternate; - - if ( ACCESS_Frame( count * 2L ) ) - { - FREE( a ); - return error; - } - - for ( n = 0; n < count; n++ ) - a[n] = GET_UShort(); - - FORGET_Frame(); - - return TT_Err_Ok; - } - - - static void Free_AlternateSet( TTO_AlternateSet* as, - FT_Memory memory ) - { - FREE( as->Alternate ); - } - - - /* AlternateSubstFormat1 */ - - FT_Error Load_AlternateSubst( TTO_AlternateSubst* as, - FT_Stream stream ) - { - FT_Error error; - FT_Memory memory = stream->memory; - - FT_UShort n = 0, m, count; - FT_ULong cur_offset, new_offset, base_offset; - - TTO_AlternateSet* aset; - - - base_offset = FILE_Pos(); - - if ( ACCESS_Frame( 4L ) ) - return error; - - as->SubstFormat = GET_UShort(); /* should be 1 */ - new_offset = GET_UShort() + base_offset; - - FORGET_Frame(); - - cur_offset = FILE_Pos(); - if ( FILE_Seek( new_offset ) || - ( error = Load_Coverage( &as->Coverage, stream ) ) != TT_Err_Ok ) - return error; - (void)FILE_Seek( cur_offset ); - - if ( ACCESS_Frame( 2L ) ) - goto Fail2; - - count = as->AlternateSetCount = GET_UShort(); - - FORGET_Frame(); - - as->AlternateSet = NULL; - - if ( ALLOC_ARRAY( as->AlternateSet, count, TTO_AlternateSet ) ) - goto Fail2; - - aset = as->AlternateSet; - - for ( n = 0; n < count; n++ ) - { - if ( ACCESS_Frame( 2L ) ) - goto Fail1; - - new_offset = GET_UShort() + base_offset; - - FORGET_Frame(); - - cur_offset = FILE_Pos(); - if ( FILE_Seek( new_offset ) || - ( error = Load_AlternateSet( &aset[n], stream ) ) != TT_Err_Ok ) - goto Fail1; - (void)FILE_Seek( cur_offset ); - } - - return TT_Err_Ok; - - Fail1: - for ( m = 0; m < n; m++ ) - Free_AlternateSet( &aset[m], memory ); - - FREE( aset ); - - Fail2: - Free_Coverage( &as->Coverage, memory ); - return error; - } - - - void Free_AlternateSubst( TTO_AlternateSubst* as, - FT_Memory memory ) - { - FT_UShort n, count; - - TTO_AlternateSet* aset; - - - if ( as->AlternateSet ) - { - count = as->AlternateSetCount; - aset = as->AlternateSet; - - for ( n = 0; n < count; n++ ) - Free_AlternateSet( &aset[n], memory ); - - FREE( aset ); - } - - Free_Coverage( &as->Coverage, memory ); - } - - - static FT_Error Lookup_AlternateSubst( TTO_GSUBHeader* gsub, - TTO_GSUB_SubTable* st, - OTL_Buffer buffer, - FT_UShort flags, - FT_UShort context_length, - int nesting_level ) - { - FT_Error error; - FT_UShort index, alt_index, property; - TTO_AlternateSubst* as = &st->alternate; - TTO_GDEFHeader* gdef = gsub->gdef; - - - TTO_AlternateSet aset; - - - if ( context_length != 0xFFFF && context_length < 1 ) - return TTO_Err_Not_Covered; - - if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) ) - return error; - - error = Coverage_Index( &as->Coverage, IN_CURGLYPH(), &index ); - if ( error ) - return error; - - aset = as->AlternateSet[index]; - - /* we use a user-defined callback function to get the alternate index */ - - if ( gsub->altfunc ) - alt_index = (gsub->altfunc)( buffer->out_pos, IN_CURGLYPH(), - aset.GlyphCount, aset.Alternate, - gsub->data ); - else - alt_index = 0; - - if ( ADD_Glyph( buffer, aset.Alternate[alt_index], - 0xFFFF, 0xFFFF ) ) - return error; - - if ( gdef && gdef->NewGlyphClasses ) - { - /* we inherit the old glyph class to the substituted glyph */ - - error = Add_Glyph_Property( gdef, aset.Alternate[alt_index], - property ); - if ( error && error != TTO_Err_Not_Covered ) - return error; - } - - return TT_Err_Ok; - } - - - /* LookupType 4 */ - - /* Ligature */ - - static FT_Error Load_Ligature( TTO_Ligature* l, - FT_Stream stream ) - { - FT_Error error; - FT_Memory memory = stream->memory; - - FT_UShort n, count; - FT_UShort* c; - - - if ( ACCESS_Frame( 4L ) ) - return error; - - l->LigGlyph = GET_UShort(); - l->ComponentCount = GET_UShort(); - - FORGET_Frame(); - - l->Component = NULL; - - count = l->ComponentCount - 1; /* only ComponentCount - 1 elements */ - - if ( ALLOC_ARRAY( l->Component, count, FT_UShort ) ) - return error; - - c = l->Component; - - if ( ACCESS_Frame( count * 2L ) ) - { - FREE( c ); - return error; - } - - for ( n = 0; n < count; n++ ) - c[n] = GET_UShort(); - - FORGET_Frame(); - - return TT_Err_Ok; - } - - - static void Free_Ligature( TTO_Ligature* l, - FT_Memory memory ) - { - FREE( l->Component ); - } - - - /* LigatureSet */ - - static FT_Error Load_LigatureSet( TTO_LigatureSet* ls, - FT_Stream stream ) - { - FT_Error error; - FT_Memory memory = stream->memory; - - FT_UShort n = 0, m, count; - FT_ULong cur_offset, new_offset, base_offset; - - TTO_Ligature* l; - - - base_offset = FILE_Pos(); - - if ( ACCESS_Frame( 2L ) ) - return error; - - count = ls->LigatureCount = GET_UShort(); - - FORGET_Frame(); - - ls->Ligature = NULL; - - if ( ALLOC_ARRAY( ls->Ligature, count, TTO_Ligature ) ) - return error; - - l = ls->Ligature; - - for ( n = 0; n < count; n++ ) - { - if ( ACCESS_Frame( 2L ) ) - goto Fail; - - new_offset = GET_UShort() + base_offset; - - FORGET_Frame(); - - cur_offset = FILE_Pos(); - if ( FILE_Seek( new_offset ) || - ( error = Load_Ligature( &l[n], stream ) ) != TT_Err_Ok ) - goto Fail; - (void)FILE_Seek( cur_offset ); - } - - return TT_Err_Ok; - - Fail: - for ( m = 0; m < n; m++ ) - Free_Ligature( &l[m], memory ); - - FREE( l ); - return error; - } - - - static void Free_LigatureSet( TTO_LigatureSet* ls, - FT_Memory memory ) - { - FT_UShort n, count; - - TTO_Ligature* l; - - - if ( ls->Ligature ) - { - count = ls->LigatureCount; - l = ls->Ligature; - - for ( n = 0; n < count; n++ ) - Free_Ligature( &l[n], memory ); - - FREE( l ); - } - } - - - /* LigatureSubstFormat1 */ - - FT_Error Load_LigatureSubst( TTO_LigatureSubst* ls, - FT_Stream stream ) - { - FT_Error error; - FT_Memory memory = stream->memory; - - FT_UShort n = 0, m, count; - FT_ULong cur_offset, new_offset, base_offset; - - TTO_LigatureSet* lset; - - - base_offset = FILE_Pos(); - - if ( ACCESS_Frame( 4L ) ) - return error; - - ls->SubstFormat = GET_UShort(); /* should be 1 */ - new_offset = GET_UShort() + base_offset; - - FORGET_Frame(); - - cur_offset = FILE_Pos(); - if ( FILE_Seek( new_offset ) || - ( error = Load_Coverage( &ls->Coverage, stream ) ) != TT_Err_Ok ) - return error; - (void)FILE_Seek( cur_offset ); - - if ( ACCESS_Frame( 2L ) ) - goto Fail2; - - count = ls->LigatureSetCount = GET_UShort(); - - FORGET_Frame(); - - ls->LigatureSet = NULL; - - if ( ALLOC_ARRAY( ls->LigatureSet, count, TTO_LigatureSet ) ) - goto Fail2; - - lset = ls->LigatureSet; - - for ( n = 0; n < count; n++ ) - { - if ( ACCESS_Frame( 2L ) ) - goto Fail1; - - new_offset = GET_UShort() + base_offset; - - FORGET_Frame(); - - cur_offset = FILE_Pos(); - if ( FILE_Seek( new_offset ) || - ( error = Load_LigatureSet( &lset[n], stream ) ) != TT_Err_Ok ) - goto Fail1; - (void)FILE_Seek( cur_offset ); - } - - return TT_Err_Ok; - - Fail1: - for ( m = 0; m < n; m++ ) - Free_LigatureSet( &lset[m], memory ); - - FREE( lset ); - - Fail2: - Free_Coverage( &ls->Coverage, memory ); - return error; - } - - - void Free_LigatureSubst( TTO_LigatureSubst* ls, - FT_Memory memory ) - { - FT_UShort n, count; - - TTO_LigatureSet* lset; - - - if ( ls->LigatureSet ) - { - count = ls->LigatureSetCount; - lset = ls->LigatureSet; - - for ( n = 0; n < count; n++ ) - Free_LigatureSet( &lset[n], memory ); - - FREE( lset ); - } - - Free_Coverage( &ls->Coverage, memory ); - } - - - static FT_Error Lookup_LigatureSubst( TTO_GSUBHeader* gsub, - TTO_GSUB_SubTable* st, - OTL_Buffer buffer, - FT_UShort flags, - FT_UShort context_length, - int nesting_level ) - { - FT_UShort index, property; - FT_Error error; - FT_UShort numlig, i, j, is_mark, first_is_mark = FALSE; - FT_UShort* c; - TTO_LigatureSubst* ls = &st->ligature; - TTO_GDEFHeader* gdef = gsub->gdef; - - TTO_Ligature* lig; - - - if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) ) - return error; - - if ( property == TTO_MARK || property & IGNORE_SPECIAL_MARKS ) - first_is_mark = TRUE; - - error = Coverage_Index( &ls->Coverage, IN_CURGLYPH(), &index ); - if ( error ) - return error; - - if ( index >= ls->LigatureSetCount ) - return TTO_Err_Invalid_GSUB_SubTable; - - lig = ls->LigatureSet[index].Ligature; - - for ( numlig = ls->LigatureSet[index].LigatureCount; - numlig; - numlig--, lig++ ) - { - if ( buffer->in_pos + lig->ComponentCount > buffer->in_length ) - goto next_ligature; /* Not enough glyphs in input */ - - c = lig->Component; - - is_mark = first_is_mark; - - if ( context_length != 0xFFFF && context_length < lig->ComponentCount ) - break; - - for ( i = 1, j = buffer->in_pos + 1; i < lig->ComponentCount; i++, j++ ) - { - while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) - { - if ( error && error != TTO_Err_Not_Covered ) - return error; - - if ( j + lig->ComponentCount - i == buffer->in_length ) - goto next_ligature; - j++; - } - - if ( !( property == TTO_MARK || property & IGNORE_SPECIAL_MARKS ) ) - is_mark = FALSE; - - if ( IN_GLYPH( j ) != c[i - 1] ) - goto next_ligature; - } - - if ( gdef && gdef->NewGlyphClasses ) - { - /* this is just a guess ... */ - - error = Add_Glyph_Property( gdef, lig->LigGlyph, - is_mark ? TTO_MARK : TTO_LIGATURE ); - if ( error && error != TTO_Err_Not_Covered ) - return error; - } - - if ( j == buffer->in_pos + i ) /* No input glyphs skipped */ - { - /* We don't use a new ligature ID if there are no skipped - glyphs and the ligature already has an ID. */ - - if ( IN_LIGID( buffer->in_pos ) ) - { - if ( ADD_String( buffer, i, 1, &lig->LigGlyph, - 0xFFFF, 0xFFFF ) ) - return error; - } - else - { - FT_UShort ligID = otl_buffer_allocate_ligid( buffer ); - if ( ADD_String( buffer, i, 1, &lig->LigGlyph, - 0xFFFF, ligID ) ) - return error; - } - } - else - { - FT_UShort ligID = otl_buffer_allocate_ligid( buffer ); - if ( ADD_Glyph( buffer, lig->LigGlyph, - 0xFFFF, ligID ) ) - return error; - - /* Now we must do a second loop to copy the skipped glyphs to - `out' and assign component values to it. We start with the - glyph after the first component. Glyphs between component - i and i+1 belong to component i. Together with the ligID - value it is later possible to check whether a specific - component value really belongs to a given ligature. */ - - for ( i = 0; i < lig->ComponentCount - 1; i++ ) - { - while ( CHECK_Property( gdef, IN_CURITEM(), - flags, &property ) ) - if ( ADD_Glyph( buffer, IN_CURGLYPH(), - i, ligID ) ) - return error; - - (buffer->in_pos)++; - } - } - - return TT_Err_Ok; - - next_ligature: - ; - } - - return TTO_Err_Not_Covered; - } - - - /* Do the actual substitution for a context substitution (either format - 5 or 6). This is only called after we've determined that the input - matches the subrule. */ - - static FT_Error Do_ContextSubst( TTO_GSUBHeader* gsub, - FT_UShort GlyphCount, - FT_UShort SubstCount, - TTO_SubstLookupRecord* subst, - OTL_Buffer buffer, - int nesting_level ) - { - FT_Error error; - FT_UShort i, old_pos; - - - i = 0; - - while ( i < GlyphCount ) - { - if ( SubstCount && i == subst->SequenceIndex ) - { - old_pos = buffer->in_pos; - - /* Do a substitution */ - - error = Do_Glyph_Lookup( gsub, subst->LookupListIndex, buffer, - GlyphCount, nesting_level ); - - subst++; - SubstCount--; - i += buffer->in_pos - old_pos; - - if ( error == TTO_Err_Not_Covered ) - { - /* XXX "can't happen" -- but don't count on it */ - - if ( ADD_Glyph( buffer, IN_CURGLYPH(), - 0xFFFF, 0xFFFF ) ) - return error; - i++; - } - else if ( error ) - return error; - } - else - { - /* No substitution for this index */ - - if ( ADD_Glyph( buffer, IN_CURGLYPH(), - 0xFFFF, 0xFFFF ) ) - return error; - i++; - } - } - - return TT_Err_Ok; - } - - - /* LookupType 5 */ - - /* SubRule */ - - static FT_Error Load_SubRule( TTO_SubRule* sr, - FT_Stream stream ) - { - FT_Error error; - FT_Memory memory = stream->memory; - - FT_UShort n, count; - FT_UShort* i; - - TTO_SubstLookupRecord* slr; - - - if ( ACCESS_Frame( 4L ) ) - return error; - - sr->GlyphCount = GET_UShort(); - sr->SubstCount = GET_UShort(); - - FORGET_Frame(); - - sr->Input = NULL; - - count = sr->GlyphCount - 1; /* only GlyphCount - 1 elements */ - - if ( ALLOC_ARRAY( sr->Input, count, FT_UShort ) ) - return error; - - i = sr->Input; - - if ( ACCESS_Frame( count * 2L ) ) - goto Fail2; - - for ( n = 0; n < count; n++ ) - i[n] = GET_UShort(); - - FORGET_Frame(); - - sr->SubstLookupRecord = NULL; - - count = sr->SubstCount; - - if ( ALLOC_ARRAY( sr->SubstLookupRecord, count, TTO_SubstLookupRecord ) ) - goto Fail2; - - slr = sr->SubstLookupRecord; - - if ( ACCESS_Frame( count * 4L ) ) - goto Fail1; - - for ( n = 0; n < count; n++ ) - { - slr[n].SequenceIndex = GET_UShort(); - slr[n].LookupListIndex = GET_UShort(); - } - - FORGET_Frame(); - - return TT_Err_Ok; - - Fail1: - FREE( slr ); - - Fail2: - FREE( i ); - return error; - } - - - static void Free_SubRule( TTO_SubRule* sr, - FT_Memory memory ) - { - FREE( sr->SubstLookupRecord ); - FREE( sr->Input ); - } - - - /* SubRuleSet */ - - static FT_Error Load_SubRuleSet( TTO_SubRuleSet* srs, - FT_Stream stream ) - { - FT_Error error; - FT_Memory memory = stream->memory; - - FT_UShort n = 0, m, count; - FT_ULong cur_offset, new_offset, base_offset; - - TTO_SubRule* sr; - - - base_offset = FILE_Pos(); - - if ( ACCESS_Frame( 2L ) ) - return error; - - count = srs->SubRuleCount = GET_UShort(); - - FORGET_Frame(); - - srs->SubRule = NULL; - - if ( ALLOC_ARRAY( srs->SubRule, count, TTO_SubRule ) ) - return error; - - sr = srs->SubRule; - - for ( n = 0; n < count; n++ ) - { - if ( ACCESS_Frame( 2L ) ) - goto Fail; - - new_offset = GET_UShort() + base_offset; - - FORGET_Frame(); - - cur_offset = FILE_Pos(); - if ( FILE_Seek( new_offset ) || - ( error = Load_SubRule( &sr[n], stream ) ) != TT_Err_Ok ) - goto Fail; - (void)FILE_Seek( cur_offset ); - } - - return TT_Err_Ok; - - Fail: - for ( m = 0; m < n; m++ ) - Free_SubRule( &sr[m], memory ); - - FREE( sr ); - return error; - } - - - static void Free_SubRuleSet( TTO_SubRuleSet* srs, - FT_Memory memory ) - { - FT_UShort n, count; - - TTO_SubRule* sr; - - - if ( srs->SubRule ) - { - count = srs->SubRuleCount; - sr = srs->SubRule; - - for ( n = 0; n < count; n++ ) - Free_SubRule( &sr[n], memory ); - - FREE( sr ); - } - } - - - /* ContextSubstFormat1 */ - - static FT_Error Load_ContextSubst1( TTO_ContextSubstFormat1* csf1, - FT_Stream stream ) - { - FT_Error error; - FT_Memory memory = stream->memory; - - FT_UShort n = 0, m, count; - FT_ULong cur_offset, new_offset, base_offset; - - TTO_SubRuleSet* srs; - - - base_offset = FILE_Pos() - 2L; - - if ( ACCESS_Frame( 2L ) ) - return error; - - new_offset = GET_UShort() + base_offset; - - FORGET_Frame(); - - cur_offset = FILE_Pos(); - if ( FILE_Seek( new_offset ) || - ( error = Load_Coverage( &csf1->Coverage, stream ) ) != TT_Err_Ok ) - return error; - (void)FILE_Seek( cur_offset ); - - if ( ACCESS_Frame( 2L ) ) - goto Fail2; - - count = csf1->SubRuleSetCount = GET_UShort(); - - FORGET_Frame(); - - csf1->SubRuleSet = NULL; - - if ( ALLOC_ARRAY( csf1->SubRuleSet, count, TTO_SubRuleSet ) ) - goto Fail2; - - srs = csf1->SubRuleSet; - - for ( n = 0; n < count; n++ ) - { - if ( ACCESS_Frame( 2L ) ) - goto Fail1; - - new_offset = GET_UShort() + base_offset; - - FORGET_Frame(); - - cur_offset = FILE_Pos(); - if ( FILE_Seek( new_offset ) || - ( error = Load_SubRuleSet( &srs[n], stream ) ) != TT_Err_Ok ) - goto Fail1; - (void)FILE_Seek( cur_offset ); - } - - return TT_Err_Ok; - - Fail1: - for ( m = 0; m < n; m++ ) - Free_SubRuleSet( &srs[m], memory ); - - FREE( srs ); - - Fail2: - Free_Coverage( &csf1->Coverage, memory ); - return error; - } - - - static void Free_Context1( TTO_ContextSubstFormat1* csf1, - FT_Memory memory ) - { - FT_UShort n, count; - - TTO_SubRuleSet* srs; - - - if ( csf1->SubRuleSet ) - { - count = csf1->SubRuleSetCount; - srs = csf1->SubRuleSet; - - for ( n = 0; n < count; n++ ) - Free_SubRuleSet( &srs[n], memory ); - - FREE( srs ); - } - - Free_Coverage( &csf1->Coverage, memory ); - } - - - /* SubClassRule */ - - static FT_Error Load_SubClassRule( TTO_ContextSubstFormat2* csf2, - TTO_SubClassRule* scr, - FT_Stream stream ) - { - FT_Error error; - FT_Memory memory = stream->memory; - - FT_UShort n, count; - - FT_UShort* c; - TTO_SubstLookupRecord* slr; - FT_Bool* d; - - - if ( ACCESS_Frame( 4L ) ) - return error; - - scr->GlyphCount = GET_UShort(); - scr->SubstCount = GET_UShort(); - - if ( scr->GlyphCount > csf2->MaxContextLength ) - csf2->MaxContextLength = scr->GlyphCount; - - FORGET_Frame(); - - scr->Class = NULL; - - count = scr->GlyphCount - 1; /* only GlyphCount - 1 elements */ - - if ( ALLOC_ARRAY( scr->Class, count, FT_UShort ) ) - return error; - - c = scr->Class; - d = csf2->ClassDef.Defined; - - if ( ACCESS_Frame( count * 2L ) ) - goto Fail2; - - for ( n = 0; n < count; n++ ) - { - c[n] = GET_UShort(); - - /* We check whether the specific class is used at all. If not, - class 0 is used instead. */ - if ( !d[c[n]] ) - c[n] = 0; - } - - FORGET_Frame(); - - scr->SubstLookupRecord = NULL; - - count = scr->SubstCount; - - if ( ALLOC_ARRAY( scr->SubstLookupRecord, count, TTO_SubstLookupRecord ) ) - goto Fail2; - - slr = scr->SubstLookupRecord; - - if ( ACCESS_Frame( count * 4L ) ) - goto Fail1; - - for ( n = 0; n < count; n++ ) - { - slr[n].SequenceIndex = GET_UShort(); - slr[n].LookupListIndex = GET_UShort(); - } - - FORGET_Frame(); - - return TT_Err_Ok; - - Fail1: - FREE( slr ); - - Fail2: - FREE( c ); - return error; - } - - - static void Free_SubClassRule( TTO_SubClassRule* scr, - FT_Memory memory ) - { - FREE( scr->SubstLookupRecord ); - FREE( scr->Class ); - } - - - /* SubClassSet */ - - static FT_Error Load_SubClassSet( TTO_ContextSubstFormat2* csf2, - TTO_SubClassSet* scs, - FT_Stream stream ) - { - FT_Error error; - FT_Memory memory = stream->memory; - - FT_UShort n = 0, m, count; - FT_ULong cur_offset, new_offset, base_offset; - - TTO_SubClassRule* scr; - - - base_offset = FILE_Pos(); - - if ( ACCESS_Frame( 2L ) ) - return error; - - count = scs->SubClassRuleCount = GET_UShort(); - - FORGET_Frame(); - - scs->SubClassRule = NULL; - - if ( ALLOC_ARRAY( scs->SubClassRule, count, TTO_SubClassRule ) ) - return error; - - scr = scs->SubClassRule; - - for ( n = 0; n < count; n++ ) - { - if ( ACCESS_Frame( 2L ) ) - goto Fail; - - new_offset = GET_UShort() + base_offset; - - FORGET_Frame(); - - cur_offset = FILE_Pos(); - if ( FILE_Seek( new_offset ) || - ( error = Load_SubClassRule( csf2, &scr[n], - stream ) ) != TT_Err_Ok ) - goto Fail; - (void)FILE_Seek( cur_offset ); - } - - return TT_Err_Ok; - - Fail: - for ( m = 0; m < n; m++ ) - Free_SubClassRule( &scr[m], memory ); - - FREE( scr ); - return error; - } - - - static void Free_SubClassSet( TTO_SubClassSet* scs, - FT_Memory memory ) - { - FT_UShort n, count; - - TTO_SubClassRule* scr; - - - if ( scs->SubClassRule ) - { - count = scs->SubClassRuleCount; - scr = scs->SubClassRule; - - for ( n = 0; n < count; n++ ) - Free_SubClassRule( &scr[n], memory ); - - FREE( scr ); - } - } - - - /* ContextSubstFormat2 */ - - static FT_Error Load_ContextSubst2( TTO_ContextSubstFormat2* csf2, - FT_Stream stream ) - { - FT_Error error; - FT_Memory memory = stream->memory; - - FT_UShort n = 0, m, count; - FT_ULong cur_offset, new_offset, base_offset; - - TTO_SubClassSet* scs; - - - base_offset = FILE_Pos() - 2; - - if ( ACCESS_Frame( 2L ) ) - return error; - - new_offset = GET_UShort() + base_offset; - - FORGET_Frame(); - - cur_offset = FILE_Pos(); - if ( FILE_Seek( new_offset ) || - ( error = Load_Coverage( &csf2->Coverage, stream ) ) != TT_Err_Ok ) - return error; - (void)FILE_Seek( cur_offset ); - - if ( ACCESS_Frame( 4L ) ) - goto Fail3; - - new_offset = GET_UShort() + base_offset; - - /* `SubClassSetCount' is the upper limit for class values, thus we - read it now to make an additional safety check. */ - - count = csf2->SubClassSetCount = GET_UShort(); - - FORGET_Frame(); - - cur_offset = FILE_Pos(); - if ( FILE_Seek( new_offset ) || - ( error = Load_ClassDefinition( &csf2->ClassDef, count, - stream ) ) != TT_Err_Ok ) - goto Fail3; - (void)FILE_Seek( cur_offset ); - - csf2->SubClassSet = NULL; - csf2->MaxContextLength = 0; - - if ( ALLOC_ARRAY( csf2->SubClassSet, count, TTO_SubClassSet ) ) - goto Fail2; - - scs = csf2->SubClassSet; - - for ( n = 0; n < count; n++ ) - { - if ( ACCESS_Frame( 2L ) ) - goto Fail1; - - new_offset = GET_UShort() + base_offset; - - FORGET_Frame(); - - if ( new_offset != base_offset ) /* not a NULL offset */ - { - cur_offset = FILE_Pos(); - if ( FILE_Seek( new_offset ) || - ( error = Load_SubClassSet( csf2, &scs[n], - stream ) ) != TT_Err_Ok ) - goto Fail1; - (void)FILE_Seek( cur_offset ); - } - else - { - /* we create a SubClassSet table with no entries */ - - csf2->SubClassSet[n].SubClassRuleCount = 0; - csf2->SubClassSet[n].SubClassRule = NULL; - } - } - - return TT_Err_Ok; - - Fail1: - for ( m = 0; m < n; m++ ) - Free_SubClassSet( &scs[m], memory ); - - FREE( scs ); - - Fail2: - Free_ClassDefinition( &csf2->ClassDef, memory ); - - Fail3: - Free_Coverage( &csf2->Coverage, memory ); - return error; - } - - - static void Free_Context2( TTO_ContextSubstFormat2* csf2, - FT_Memory memory ) - { - FT_UShort n, count; - - TTO_SubClassSet* scs; - - - if ( csf2->SubClassSet ) - { - count = csf2->SubClassSetCount; - scs = csf2->SubClassSet; - - for ( n = 0; n < count; n++ ) - Free_SubClassSet( &scs[n], memory ); - - FREE( scs ); - } - - Free_ClassDefinition( &csf2->ClassDef, memory ); - Free_Coverage( &csf2->Coverage, memory ); - } - - - /* ContextSubstFormat3 */ - - static FT_Error Load_ContextSubst3( TTO_ContextSubstFormat3* csf3, - FT_Stream stream ) - { - FT_Error error; - FT_Memory memory = stream->memory; - - FT_UShort n = 0, m, count; - FT_ULong cur_offset, new_offset, base_offset; - - TTO_Coverage* c; - TTO_SubstLookupRecord* slr; - - - base_offset = FILE_Pos() - 2L; - - if ( ACCESS_Frame( 4L ) ) - return error; - - csf3->GlyphCount = GET_UShort(); - csf3->SubstCount = GET_UShort(); - - FORGET_Frame(); - - csf3->Coverage = NULL; - - count = csf3->GlyphCount; - - if ( ALLOC_ARRAY( csf3->Coverage, count, TTO_Coverage ) ) - return error; - - c = csf3->Coverage; - - for ( n = 0; n < count; n++ ) - { - if ( ACCESS_Frame( 2L ) ) - goto Fail2; - - new_offset = GET_UShort() + base_offset; - - FORGET_Frame(); - - cur_offset = FILE_Pos(); - if ( FILE_Seek( new_offset ) || - ( error = Load_Coverage( &c[n], stream ) ) != TT_Err_Ok ) - goto Fail2; - (void)FILE_Seek( cur_offset ); - } - - csf3->SubstLookupRecord = NULL; - - count = csf3->SubstCount; - - if ( ALLOC_ARRAY( csf3->SubstLookupRecord, count, - TTO_SubstLookupRecord ) ) - goto Fail2; - - slr = csf3->SubstLookupRecord; - - if ( ACCESS_Frame( count * 4L ) ) - goto Fail1; - - for ( n = 0; n < count; n++ ) - { - slr[n].SequenceIndex = GET_UShort(); - slr[n].LookupListIndex = GET_UShort(); - } - - FORGET_Frame(); - - return TT_Err_Ok; - - Fail1: - FREE( slr ); - - Fail2: - for ( m = 0; m < n; m++ ) - Free_Coverage( &c[m], memory ); - - FREE( c ); - return error; - } - - - static void Free_Context3( TTO_ContextSubstFormat3* csf3, - FT_Memory memory ) - { - FT_UShort n, count; - - TTO_Coverage* c; - - - FREE( csf3->SubstLookupRecord ); - - if ( csf3->Coverage ) - { - count = csf3->GlyphCount; - c = csf3->Coverage; - - for ( n = 0; n < count; n++ ) - Free_Coverage( &c[n], memory ); - - FREE( c ); - } - } - - - /* ContextSubst */ - - FT_Error Load_ContextSubst( TTO_ContextSubst* cs, - FT_Stream stream ) - { - FT_Error error; - - - if ( ACCESS_Frame( 2L ) ) - return error; - - cs->SubstFormat = GET_UShort(); - - FORGET_Frame(); - - switch ( cs->SubstFormat ) - { - case 1: - return Load_ContextSubst1( &cs->csf.csf1, stream ); - - case 2: - return Load_ContextSubst2( &cs->csf.csf2, stream ); - - case 3: - return Load_ContextSubst3( &cs->csf.csf3, stream ); - - default: - return TTO_Err_Invalid_GSUB_SubTable_Format; - } - - return TT_Err_Ok; /* never reached */ - } - - - void Free_ContextSubst( TTO_ContextSubst* cs, - FT_Memory memory ) - { - switch ( cs->SubstFormat ) - { - case 1: - Free_Context1( &cs->csf.csf1, memory ); - break; - - case 2: - Free_Context2( &cs->csf.csf2, memory ); - break; - - case 3: - Free_Context3( &cs->csf.csf3, memory ); - break; - } - } - - - static FT_Error Lookup_ContextSubst1( TTO_GSUBHeader* gsub, - TTO_ContextSubstFormat1* csf1, - OTL_Buffer buffer, - FT_UShort flags, - FT_UShort context_length, - int nesting_level ) - { - FT_UShort index, property; - FT_UShort i, j, k, numsr; - FT_Error error; - - TTO_SubRule* sr; - TTO_GDEFHeader* gdef; - - - gdef = gsub->gdef; - - if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) ) - return error; - - error = Coverage_Index( &csf1->Coverage, IN_CURGLYPH(), &index ); - if ( error ) - return error; - - sr = csf1->SubRuleSet[index].SubRule; - numsr = csf1->SubRuleSet[index].SubRuleCount; - - for ( k = 0; k < numsr; k++ ) - { - if ( context_length != 0xFFFF && context_length < sr[k].GlyphCount ) - goto next_subrule; - - if ( buffer->in_pos + sr[k].GlyphCount > buffer->in_length ) - goto next_subrule; /* context is too long */ - - for ( i = 1, j = buffer->in_pos + 1; i < sr[k].GlyphCount; i++, j++ ) - { - while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) - { - if ( error && error != TTO_Err_Not_Covered ) - return error; - - if ( j + sr[k].GlyphCount - i == buffer->in_length ) - goto next_subrule; - j++; - } - - if ( IN_GLYPH( j ) != sr[k].Input[i - 1] ) - goto next_subrule; - } - - return Do_ContextSubst( gsub, sr[k].GlyphCount, - sr[k].SubstCount, sr[k].SubstLookupRecord, - buffer, - nesting_level ); - next_subrule: - ; - } - - return TTO_Err_Not_Covered; - } - - - static FT_Error Lookup_ContextSubst2( TTO_GSUBHeader* gsub, - TTO_ContextSubstFormat2* csf2, - OTL_Buffer buffer, - FT_UShort flags, - FT_UShort context_length, - int nesting_level ) - { - FT_UShort index, property; - FT_Error error; - FT_Memory memory = gsub->memory; - FT_UShort i, j, k, known_classes; - - FT_UShort* classes; - FT_UShort* cl; - - TTO_SubClassSet* scs; - TTO_SubClassRule* sr; - TTO_GDEFHeader* gdef; - - - gdef = gsub->gdef; - - if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) ) - return error; - - /* Note: The coverage table in format 2 doesn't give an index into - anything. It just lets us know whether or not we need to - do any lookup at all. */ - - error = Coverage_Index( &csf2->Coverage, IN_CURGLYPH(), &index ); - if ( error ) - return error; - - if ( ALLOC_ARRAY( classes, csf2->MaxContextLength, FT_UShort ) ) - return error; - - error = Get_Class( &csf2->ClassDef, IN_CURGLYPH(), - &classes[0], NULL ); - if ( error && error != TTO_Err_Not_Covered ) - goto End; - known_classes = 0; - - scs = &csf2->SubClassSet[classes[0]]; - if ( !scs ) - { - error = TTO_Err_Invalid_GSUB_SubTable; - goto End; - } - - for ( k = 0; k < scs->SubClassRuleCount; k++ ) - { - sr = &scs->SubClassRule[k]; - - if ( context_length != 0xFFFF && context_length < sr->GlyphCount ) - goto next_subclassrule; - - if ( buffer->in_pos + sr->GlyphCount > buffer->in_length ) - goto next_subclassrule; /* context is too long */ - - cl = sr->Class; - - /* Start at 1 because [0] is implied */ - - for ( i = 1, j = buffer->in_pos + 1; i < sr->GlyphCount; i++, j++ ) - { - while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) - { - if ( error && error != TTO_Err_Not_Covered ) - goto End; - - if ( j + sr->GlyphCount - i < buffer->in_length ) - goto next_subclassrule; - j++; - } - - if ( i > known_classes ) - { - /* Keeps us from having to do this for each rule */ - - error = Get_Class( &csf2->ClassDef, IN_GLYPH( j ), &classes[i], NULL ); - if ( error && error != TTO_Err_Not_Covered ) - goto End; - known_classes = i; - } - - if ( cl[i - 1] != classes[i] ) - goto next_subclassrule; - } - - error = Do_ContextSubst( gsub, sr->GlyphCount, - sr->SubstCount, sr->SubstLookupRecord, - buffer, - nesting_level ); - goto End; - - next_subclassrule: - ; - } - - error = TTO_Err_Not_Covered; - - End: - FREE( classes ); - return error; - } - - - static FT_Error Lookup_ContextSubst3( TTO_GSUBHeader* gsub, - TTO_ContextSubstFormat3* csf3, - OTL_Buffer buffer, - FT_UShort flags, - FT_UShort context_length, - int nesting_level ) - { - FT_Error error; - FT_UShort index, i, j, property; - - TTO_Coverage* c; - TTO_GDEFHeader* gdef; - - - gdef = gsub->gdef; - - if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) ) - return error; - - if ( context_length != 0xFFFF && context_length < csf3->GlyphCount ) - return TTO_Err_Not_Covered; - - if ( buffer->in_pos + csf3->GlyphCount > buffer->in_length ) - return TTO_Err_Not_Covered; /* context is too long */ - - c = csf3->Coverage; - - for ( i = 1, j = buffer->in_pos + 1; i < csf3->GlyphCount; i++, j++ ) - { - while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) - { - if ( error && error != TTO_Err_Not_Covered ) - return error; - - if ( j + csf3->GlyphCount - i == buffer->in_length ) - return TTO_Err_Not_Covered; - j++; - } - - error = Coverage_Index( &c[i], IN_GLYPH( j ), &index ); - if ( error ) - return error; - } - - return Do_ContextSubst( gsub, csf3->GlyphCount, - csf3->SubstCount, csf3->SubstLookupRecord, - buffer, - nesting_level ); - } - - - static FT_Error Lookup_ContextSubst( TTO_GSUBHeader* gsub, - TTO_GSUB_SubTable* st, - OTL_Buffer buffer, - FT_UShort flags, - FT_UShort context_length, - int nesting_level ) - { - TTO_ContextSubst* cs = &st->context; - - switch ( cs->SubstFormat ) - { - case 1: - return Lookup_ContextSubst1( gsub, &cs->csf.csf1, buffer, - flags, context_length, nesting_level ); - - case 2: - return Lookup_ContextSubst2( gsub, &cs->csf.csf2, buffer, - flags, context_length, nesting_level ); - - case 3: - return Lookup_ContextSubst3( gsub, &cs->csf.csf3, buffer, - flags, context_length, nesting_level ); - - default: - return TTO_Err_Invalid_GSUB_SubTable_Format; - } - - return TT_Err_Ok; /* never reached */ - } - - - /* LookupType 6 */ - - /* ChainSubRule */ - - static FT_Error Load_ChainSubRule( TTO_ChainSubRule* csr, - FT_Stream stream ) - { - FT_Error error; - FT_Memory memory = stream->memory; - - FT_UShort n, count; - FT_UShort* b; - FT_UShort* i; - FT_UShort* l; - - TTO_SubstLookupRecord* slr; - - - if ( ACCESS_Frame( 2L ) ) - return error; - - csr->BacktrackGlyphCount = GET_UShort(); - - FORGET_Frame(); - - csr->Backtrack = NULL; - - count = csr->BacktrackGlyphCount; - - if ( ALLOC_ARRAY( csr->Backtrack, count, FT_UShort ) ) - return error; - - b = csr->Backtrack; - - if ( ACCESS_Frame( count * 2L ) ) - goto Fail4; - - for ( n = 0; n < count; n++ ) - b[n] = GET_UShort(); - - FORGET_Frame(); - - if ( ACCESS_Frame( 2L ) ) - goto Fail4; - - csr->InputGlyphCount = GET_UShort(); - - FORGET_Frame(); - - csr->Input = NULL; - - count = csr->InputGlyphCount - 1; /* only InputGlyphCount - 1 elements */ - - if ( ALLOC_ARRAY( csr->Input, count, FT_UShort ) ) - goto Fail4; - - i = csr->Input; - - if ( ACCESS_Frame( count * 2L ) ) - goto Fail3; - - for ( n = 0; n < count; n++ ) - i[n] = GET_UShort(); - - FORGET_Frame(); - - if ( ACCESS_Frame( 2L ) ) - goto Fail3; - - csr->LookaheadGlyphCount = GET_UShort(); - - FORGET_Frame(); - - csr->Lookahead = NULL; - - count = csr->LookaheadGlyphCount; - - if ( ALLOC_ARRAY( csr->Lookahead, count, FT_UShort ) ) - goto Fail3; - - l = csr->Lookahead; - - if ( ACCESS_Frame( count * 2L ) ) - goto Fail2; - - for ( n = 0; n < count; n++ ) - l[n] = GET_UShort(); - - FORGET_Frame(); - - if ( ACCESS_Frame( 2L ) ) - goto Fail2; - - csr->SubstCount = GET_UShort(); - - FORGET_Frame(); - - csr->SubstLookupRecord = NULL; - - count = csr->SubstCount; - - if ( ALLOC_ARRAY( csr->SubstLookupRecord, count, TTO_SubstLookupRecord ) ) - goto Fail2; - - slr = csr->SubstLookupRecord; - - if ( ACCESS_Frame( count * 4L ) ) - goto Fail1; - - for ( n = 0; n < count; n++ ) - { - slr[n].SequenceIndex = GET_UShort(); - slr[n].LookupListIndex = GET_UShort(); - } - - FORGET_Frame(); - - return TT_Err_Ok; - - Fail1: - FREE( slr ); - - Fail2: - FREE( l ); - - Fail3: - FREE( i ); - - Fail4: - FREE( b ); - return error; - } - - - static void Free_ChainSubRule( TTO_ChainSubRule* csr, - FT_Memory memory ) - { - FREE( csr->SubstLookupRecord ); - FREE( csr->Lookahead ); - FREE( csr->Input ); - FREE( csr->Backtrack ); - } - - - /* ChainSubRuleSet */ - - static FT_Error Load_ChainSubRuleSet( TTO_ChainSubRuleSet* csrs, - FT_Stream stream ) - { - FT_Error error; - FT_Memory memory = stream->memory; - - FT_UShort n = 0, m, count; - FT_ULong cur_offset, new_offset, base_offset; - - TTO_ChainSubRule* csr; - - - base_offset = FILE_Pos(); - - if ( ACCESS_Frame( 2L ) ) - return error; - - count = csrs->ChainSubRuleCount = GET_UShort(); - - FORGET_Frame(); - - csrs->ChainSubRule = NULL; - - if ( ALLOC_ARRAY( csrs->ChainSubRule, count, TTO_ChainSubRule ) ) - return error; - - csr = csrs->ChainSubRule; - - for ( n = 0; n < count; n++ ) - { - if ( ACCESS_Frame( 2L ) ) - goto Fail; - - new_offset = GET_UShort() + base_offset; - - FORGET_Frame(); - - cur_offset = FILE_Pos(); - if ( FILE_Seek( new_offset ) || - ( error = Load_ChainSubRule( &csr[n], stream ) ) != TT_Err_Ok ) - goto Fail; - (void)FILE_Seek( cur_offset ); - } - - return TT_Err_Ok; - - Fail: - for ( m = 0; m < n; m++ ) - Free_ChainSubRule( &csr[m], memory ); - - FREE( csr ); - return error; - } - - - static void Free_ChainSubRuleSet( TTO_ChainSubRuleSet* csrs, - FT_Memory memory ) - { - FT_UShort n, count; - - TTO_ChainSubRule* csr; - - - if ( csrs->ChainSubRule ) - { - count = csrs->ChainSubRuleCount; - csr = csrs->ChainSubRule; - - for ( n = 0; n < count; n++ ) - Free_ChainSubRule( &csr[n], memory ); - - FREE( csr ); - } - } - - - /* ChainContextSubstFormat1 */ - - static FT_Error Load_ChainContextSubst1( - TTO_ChainContextSubstFormat1* ccsf1, - FT_Stream stream ) - { - FT_Error error; - FT_Memory memory = stream->memory; - - FT_UShort n = 0, m, count; - FT_ULong cur_offset, new_offset, base_offset; - - TTO_ChainSubRuleSet* csrs; - - - base_offset = FILE_Pos() - 2L; - - if ( ACCESS_Frame( 2L ) ) - return error; - - new_offset = GET_UShort() + base_offset; - - FORGET_Frame(); - - cur_offset = FILE_Pos(); - if ( FILE_Seek( new_offset ) || - ( error = Load_Coverage( &ccsf1->Coverage, stream ) ) != TT_Err_Ok ) - return error; - (void)FILE_Seek( cur_offset ); - - if ( ACCESS_Frame( 2L ) ) - goto Fail2; - - count = ccsf1->ChainSubRuleSetCount = GET_UShort(); - - FORGET_Frame(); - - ccsf1->ChainSubRuleSet = NULL; - - if ( ALLOC_ARRAY( ccsf1->ChainSubRuleSet, count, TTO_ChainSubRuleSet ) ) - goto Fail2; - - csrs = ccsf1->ChainSubRuleSet; - - for ( n = 0; n < count; n++ ) - { - if ( ACCESS_Frame( 2L ) ) - goto Fail1; - - new_offset = GET_UShort() + base_offset; - - FORGET_Frame(); - - cur_offset = FILE_Pos(); - if ( FILE_Seek( new_offset ) || - ( error = Load_ChainSubRuleSet( &csrs[n], stream ) ) != TT_Err_Ok ) - goto Fail1; - (void)FILE_Seek( cur_offset ); - } - - return TT_Err_Ok; - - Fail1: - for ( m = 0; m < n; m++ ) - Free_ChainSubRuleSet( &csrs[m], memory ); - - FREE( csrs ); - - Fail2: - Free_Coverage( &ccsf1->Coverage, memory ); - return error; - } - - - static void Free_ChainContext1( TTO_ChainContextSubstFormat1* ccsf1, - FT_Memory memory ) - { - FT_UShort n, count; - - TTO_ChainSubRuleSet* csrs; - - - if ( ccsf1->ChainSubRuleSet ) - { - count = ccsf1->ChainSubRuleSetCount; - csrs = ccsf1->ChainSubRuleSet; - - for ( n = 0; n < count; n++ ) - Free_ChainSubRuleSet( &csrs[n], memory ); - - FREE( csrs ); - } - - Free_Coverage( &ccsf1->Coverage, memory ); - } - - - /* ChainSubClassRule */ - - static FT_Error Load_ChainSubClassRule( - TTO_ChainContextSubstFormat2* ccsf2, - TTO_ChainSubClassRule* cscr, - FT_Stream stream ) - { - FT_Error error; - FT_Memory memory = stream->memory; - - FT_UShort n, count; - - FT_UShort* b; - FT_UShort* i; - FT_UShort* l; - TTO_SubstLookupRecord* slr; - FT_Bool* d; - - - if ( ACCESS_Frame( 2L ) ) - return error; - - cscr->BacktrackGlyphCount = GET_UShort(); - - FORGET_Frame(); - - if ( cscr->BacktrackGlyphCount > ccsf2->MaxBacktrackLength ) - ccsf2->MaxBacktrackLength = cscr->BacktrackGlyphCount; - - cscr->Backtrack = NULL; - - count = cscr->BacktrackGlyphCount; - - if ( ALLOC_ARRAY( cscr->Backtrack, count, FT_UShort ) ) - return error; - - b = cscr->Backtrack; - d = ccsf2->BacktrackClassDef.Defined; - - if ( ACCESS_Frame( count * 2L ) ) - goto Fail4; - - for ( n = 0; n < count; n++ ) - { - b[n] = GET_UShort(); - - /* We check whether the specific class is used at all. If not, - class 0 is used instead. */ - - if ( !d[b[n]] ) - b[n] = 0; - } - - FORGET_Frame(); - - if ( ACCESS_Frame( 2L ) ) - goto Fail4; - - cscr->InputGlyphCount = GET_UShort(); - - FORGET_Frame(); - - if ( cscr->InputGlyphCount > ccsf2->MaxInputLength ) - ccsf2->MaxInputLength = cscr->InputGlyphCount; - - cscr->Input = NULL; - - count = cscr->InputGlyphCount - 1; /* only InputGlyphCount - 1 elements */ - - if ( ALLOC_ARRAY( cscr->Input, count, FT_UShort ) ) - goto Fail4; - - i = cscr->Input; - d = ccsf2->InputClassDef.Defined; - - if ( ACCESS_Frame( count * 2L ) ) - goto Fail3; - - for ( n = 0; n < count; n++ ) - { - i[n] = GET_UShort(); - - if ( !d[i[n]] ) - i[n] = 0; - } - - FORGET_Frame(); - - if ( ACCESS_Frame( 2L ) ) - goto Fail3; - - cscr->LookaheadGlyphCount = GET_UShort(); - - FORGET_Frame(); - - if ( cscr->LookaheadGlyphCount > ccsf2->MaxLookaheadLength ) - ccsf2->MaxLookaheadLength = cscr->LookaheadGlyphCount; - - cscr->Lookahead = NULL; - - count = cscr->LookaheadGlyphCount; - - if ( ALLOC_ARRAY( cscr->Lookahead, count, FT_UShort ) ) - goto Fail3; - - l = cscr->Lookahead; - d = ccsf2->LookaheadClassDef.Defined; - - if ( ACCESS_Frame( count * 2L ) ) - goto Fail2; - - for ( n = 0; n < count; n++ ) - { - l[n] = GET_UShort(); - - if ( !d[l[n]] ) - l[n] = 0; - } - - FORGET_Frame(); - - if ( ACCESS_Frame( 2L ) ) - goto Fail2; - - cscr->SubstCount = GET_UShort(); - - FORGET_Frame(); - - cscr->SubstLookupRecord = NULL; - - count = cscr->SubstCount; - - if ( ALLOC_ARRAY( cscr->SubstLookupRecord, count, - TTO_SubstLookupRecord ) ) - goto Fail2; - - slr = cscr->SubstLookupRecord; - - if ( ACCESS_Frame( count * 4L ) ) - goto Fail1; - - for ( n = 0; n < count; n++ ) - { - slr[n].SequenceIndex = GET_UShort(); - slr[n].LookupListIndex = GET_UShort(); - } - - FORGET_Frame(); - - return TT_Err_Ok; - - Fail1: - FREE( slr ); - - Fail2: - FREE( l ); - - Fail3: - FREE( i ); - - Fail4: - FREE( b ); - return error; - } - - - static void Free_ChainSubClassRule( TTO_ChainSubClassRule* cscr, - FT_Memory memory ) - { - FREE( cscr->SubstLookupRecord ); - FREE( cscr->Lookahead ); - FREE( cscr->Input ); - FREE( cscr->Backtrack ); - } - - - /* SubClassSet */ - - static FT_Error Load_ChainSubClassSet( - TTO_ChainContextSubstFormat2* ccsf2, - TTO_ChainSubClassSet* cscs, - FT_Stream stream ) - { - FT_Error error; - FT_Memory memory = stream->memory; - - FT_UShort n = 0, m, count; - FT_ULong cur_offset, new_offset, base_offset; - - TTO_ChainSubClassRule* cscr; - - - base_offset = FILE_Pos(); - - if ( ACCESS_Frame( 2L ) ) - return error; - - count = cscs->ChainSubClassRuleCount = GET_UShort(); - - FORGET_Frame(); - - cscs->ChainSubClassRule = NULL; - - if ( ALLOC_ARRAY( cscs->ChainSubClassRule, count, - TTO_ChainSubClassRule ) ) - return error; - - cscr = cscs->ChainSubClassRule; - - for ( n = 0; n < count; n++ ) - { - if ( ACCESS_Frame( 2L ) ) - goto Fail; - - new_offset = GET_UShort() + base_offset; - - FORGET_Frame(); - - cur_offset = FILE_Pos(); - if ( FILE_Seek( new_offset ) || - ( error = Load_ChainSubClassRule( ccsf2, &cscr[n], - stream ) ) != TT_Err_Ok ) - goto Fail; - (void)FILE_Seek( cur_offset ); - } - - return TT_Err_Ok; - - Fail: - for ( m = 0; m < n; m++ ) - Free_ChainSubClassRule( &cscr[m], memory ); - - FREE( cscr ); - return error; - } - - - static void Free_ChainSubClassSet( TTO_ChainSubClassSet* cscs, - FT_Memory memory ) - { - FT_UShort n, count; - - TTO_ChainSubClassRule* cscr; - - - if ( cscs->ChainSubClassRule ) - { - count = cscs->ChainSubClassRuleCount; - cscr = cscs->ChainSubClassRule; - - for ( n = 0; n < count; n++ ) - Free_ChainSubClassRule( &cscr[n], memory ); - - FREE( cscr ); - } - } - - static FT_Error Load_EmptyOrClassDefinition( TTO_ClassDefinition* cd, - FT_UShort limit, - FT_ULong class_offset, - FT_ULong base_offset, - FT_Stream stream ) - { - FT_Error error; - FT_ULong cur_offset; - - cur_offset = FILE_Pos(); - - if ( class_offset ) - { - if ( !FILE_Seek( class_offset + base_offset ) ) - error = Load_ClassDefinition( cd, limit, stream ); - } - else - error = Load_EmptyClassDefinition ( cd, stream ); - - if (error == TT_Err_Ok) - (void)FILE_Seek( cur_offset ); /* Changes error as a side-effect */ - - return error; - } - - - /* ChainContextSubstFormat2 */ - - static FT_Error Load_ChainContextSubst2( - TTO_ChainContextSubstFormat2* ccsf2, - FT_Stream stream ) - { - FT_Error error; - FT_Memory memory = stream->memory; - - FT_UShort n = 0, m, count; - FT_ULong cur_offset, new_offset, base_offset; - FT_ULong backtrack_offset, input_offset, lookahead_offset; - - TTO_ChainSubClassSet* cscs; - - - base_offset = FILE_Pos() - 2; - - if ( ACCESS_Frame( 2L ) ) - return error; - - new_offset = GET_UShort() + base_offset; - - FORGET_Frame(); - - cur_offset = FILE_Pos(); - if ( FILE_Seek( new_offset ) || - ( error = Load_Coverage( &ccsf2->Coverage, stream ) ) != TT_Err_Ok ) - return error; - (void)FILE_Seek( cur_offset ); - - if ( ACCESS_Frame( 8L ) ) - goto Fail5; - - backtrack_offset = GET_UShort(); - input_offset = GET_UShort(); - lookahead_offset = GET_UShort(); - - /* `ChainSubClassSetCount' is the upper limit for input class values, - thus we read it now to make an additional safety check. No limit - is known or needed for the other two class definitions */ - - count = ccsf2->ChainSubClassSetCount = GET_UShort(); - - FORGET_Frame(); - - if ( ( error = Load_EmptyOrClassDefinition( &ccsf2->BacktrackClassDef, 65535, - backtrack_offset, base_offset, - stream ) ) != TT_Err_Ok ) - goto Fail5; - - if ( ( error = Load_EmptyOrClassDefinition( &ccsf2->InputClassDef, count, - input_offset, base_offset, - stream ) ) != TT_Err_Ok ) - goto Fail4; - if ( ( error = Load_EmptyOrClassDefinition( &ccsf2->LookaheadClassDef, 65535, - lookahead_offset, base_offset, - stream ) ) != TT_Err_Ok ) - goto Fail3; - - ccsf2->ChainSubClassSet = NULL; - ccsf2->MaxBacktrackLength = 0; - ccsf2->MaxInputLength = 0; - ccsf2->MaxLookaheadLength = 0; - - if ( ALLOC_ARRAY( ccsf2->ChainSubClassSet, count, TTO_ChainSubClassSet ) ) - goto Fail2; - - cscs = ccsf2->ChainSubClassSet; - - for ( n = 0; n < count; n++ ) - { - if ( ACCESS_Frame( 2L ) ) - goto Fail1; - - new_offset = GET_UShort() + base_offset; - - FORGET_Frame(); - - if ( new_offset != base_offset ) /* not a NULL offset */ - { - cur_offset = FILE_Pos(); - if ( FILE_Seek( new_offset ) || - ( error = Load_ChainSubClassSet( ccsf2, &cscs[n], - stream ) ) != TT_Err_Ok ) - goto Fail1; - (void)FILE_Seek( cur_offset ); - } - else - { - /* we create a ChainSubClassSet table with no entries */ - - ccsf2->ChainSubClassSet[n].ChainSubClassRuleCount = 0; - ccsf2->ChainSubClassSet[n].ChainSubClassRule = NULL; - } - } - - return TT_Err_Ok; - - Fail1: - for ( m = 0; m < n; m++ ) - Free_ChainSubClassSet( &cscs[m], memory ); - - FREE( cscs ); - - Fail2: - Free_ClassDefinition( &ccsf2->LookaheadClassDef, memory ); - - Fail3: - Free_ClassDefinition( &ccsf2->InputClassDef, memory ); - - Fail4: - Free_ClassDefinition( &ccsf2->BacktrackClassDef, memory ); - - Fail5: - Free_Coverage( &ccsf2->Coverage, memory ); - return error; - } - - - static void Free_ChainContext2( TTO_ChainContextSubstFormat2* ccsf2, - FT_Memory memory ) - { - FT_UShort n, count; - - TTO_ChainSubClassSet* cscs; - - - if ( ccsf2->ChainSubClassSet ) - { - count = ccsf2->ChainSubClassSetCount; - cscs = ccsf2->ChainSubClassSet; - - for ( n = 0; n < count; n++ ) - Free_ChainSubClassSet( &cscs[n], memory ); - - FREE( cscs ); - } - - Free_ClassDefinition( &ccsf2->LookaheadClassDef, memory ); - Free_ClassDefinition( &ccsf2->InputClassDef, memory ); - Free_ClassDefinition( &ccsf2->BacktrackClassDef, memory ); - - Free_Coverage( &ccsf2->Coverage, memory ); - } - - - /* ChainContextSubstFormat3 */ - - static FT_Error Load_ChainContextSubst3( - TTO_ChainContextSubstFormat3* ccsf3, - FT_Stream stream ) - { - FT_Error error; - FT_Memory memory = stream->memory; - - FT_UShort n, nb = 0, ni =0, nl = 0, m, count; - FT_UShort backtrack_count, input_count, lookahead_count; - FT_ULong cur_offset, new_offset, base_offset; - - TTO_Coverage* b; - TTO_Coverage* i; - TTO_Coverage* l; - TTO_SubstLookupRecord* slr; - - - base_offset = FILE_Pos() - 2L; - - if ( ACCESS_Frame( 2L ) ) - return error; - - ccsf3->BacktrackGlyphCount = GET_UShort(); - - FORGET_Frame(); - - ccsf3->BacktrackCoverage = NULL; - - backtrack_count = ccsf3->BacktrackGlyphCount; - - if ( ALLOC_ARRAY( ccsf3->BacktrackCoverage, backtrack_count, - TTO_Coverage ) ) - return error; - - b = ccsf3->BacktrackCoverage; - - for ( nb = 0; nb < backtrack_count; nb++ ) - { - if ( ACCESS_Frame( 2L ) ) - goto Fail4; - - new_offset = GET_UShort() + base_offset; - - FORGET_Frame(); - - cur_offset = FILE_Pos(); - if ( FILE_Seek( new_offset ) || - ( error = Load_Coverage( &b[nb], stream ) ) != TT_Err_Ok ) - goto Fail4; - (void)FILE_Seek( cur_offset ); - } - - if ( ACCESS_Frame( 2L ) ) - goto Fail4; - - ccsf3->InputGlyphCount = GET_UShort(); - - FORGET_Frame(); - - ccsf3->InputCoverage = NULL; - - input_count = ccsf3->InputGlyphCount; - - if ( ALLOC_ARRAY( ccsf3->InputCoverage, input_count, TTO_Coverage ) ) - goto Fail4; - - i = ccsf3->InputCoverage; - - for ( ni = 0; ni < input_count; ni++ ) - { - if ( ACCESS_Frame( 2L ) ) - goto Fail3; - - new_offset = GET_UShort() + base_offset; - - FORGET_Frame(); - - cur_offset = FILE_Pos(); - if ( FILE_Seek( new_offset ) || - ( error = Load_Coverage( &i[ni], stream ) ) != TT_Err_Ok ) - goto Fail3; - (void)FILE_Seek( cur_offset ); - } - - if ( ACCESS_Frame( 2L ) ) - goto Fail3; - - ccsf3->LookaheadGlyphCount = GET_UShort(); - - FORGET_Frame(); - - ccsf3->LookaheadCoverage = NULL; - - lookahead_count = ccsf3->LookaheadGlyphCount; - - if ( ALLOC_ARRAY( ccsf3->LookaheadCoverage, lookahead_count, - TTO_Coverage ) ) - goto Fail3; - - l = ccsf3->LookaheadCoverage; - - for ( nl = 0; nl < lookahead_count; nl++ ) - { - if ( ACCESS_Frame( 2L ) ) - goto Fail2; - - new_offset = GET_UShort() + base_offset; - - FORGET_Frame(); - - cur_offset = FILE_Pos(); - if ( FILE_Seek( new_offset ) || - ( error = Load_Coverage( &l[nl], stream ) ) != TT_Err_Ok ) - goto Fail2; - (void)FILE_Seek( cur_offset ); - } - - if ( ACCESS_Frame( 2L ) ) - goto Fail2; - - ccsf3->SubstCount = GET_UShort(); - - FORGET_Frame(); - - ccsf3->SubstLookupRecord = NULL; - - count = ccsf3->SubstCount; - - if ( ALLOC_ARRAY( ccsf3->SubstLookupRecord, count, - TTO_SubstLookupRecord ) ) - goto Fail2; - - slr = ccsf3->SubstLookupRecord; - - if ( ACCESS_Frame( count * 4L ) ) - goto Fail1; - - for ( n = 0; n < count; n++ ) - { - slr[n].SequenceIndex = GET_UShort(); - slr[n].LookupListIndex = GET_UShort(); - } - - FORGET_Frame(); - - return TT_Err_Ok; - - Fail1: - FREE( slr ); - - Fail2: - for ( m = 0; m < nl; m++ ) - Free_Coverage( &l[m], memory ); - - FREE( l ); - - Fail3: - for ( m = 0; m < ni; m++ ) - Free_Coverage( &i[m], memory ); - - FREE( i ); - - Fail4: - for ( m = 0; m < nb; m++ ) - Free_Coverage( &b[m], memory ); - - FREE( b ); - return error; - } - - - static void Free_ChainContext3( TTO_ChainContextSubstFormat3* ccsf3, - FT_Memory memory ) - { - FT_UShort n, count; - - TTO_Coverage* c; - - - FREE( ccsf3->SubstLookupRecord ); - - if ( ccsf3->LookaheadCoverage ) - { - count = ccsf3->LookaheadGlyphCount; - c = ccsf3->LookaheadCoverage; - - for ( n = 0; n < count; n++ ) - Free_Coverage( &c[n], memory ); - - FREE( c ); - } - - if ( ccsf3->InputCoverage ) - { - count = ccsf3->InputGlyphCount; - c = ccsf3->InputCoverage; - - for ( n = 0; n < count; n++ ) - Free_Coverage( &c[n], memory ); - - FREE( c ); - } - - if ( ccsf3->BacktrackCoverage ) - { - count = ccsf3->BacktrackGlyphCount; - c = ccsf3->BacktrackCoverage; - - for ( n = 0; n < count; n++ ) - Free_Coverage( &c[n], memory ); - - FREE( c ); - } - } - - - /* ChainContextSubst */ - - FT_Error Load_ChainContextSubst( TTO_ChainContextSubst* ccs, - FT_Stream stream ) - { - FT_Error error; - - - if ( ACCESS_Frame( 2L ) ) - return error; - - ccs->SubstFormat = GET_UShort(); - - FORGET_Frame(); - - switch ( ccs->SubstFormat ) - { - case 1: - return Load_ChainContextSubst1( &ccs->ccsf.ccsf1, stream ); - - case 2: - return Load_ChainContextSubst2( &ccs->ccsf.ccsf2, stream ); - - case 3: - return Load_ChainContextSubst3( &ccs->ccsf.ccsf3, stream ); - - default: - return TTO_Err_Invalid_GSUB_SubTable_Format; - } - - return TT_Err_Ok; /* never reached */ - } - - - void Free_ChainContextSubst( TTO_ChainContextSubst* ccs, - FT_Memory memory ) - { - switch ( ccs->SubstFormat ) - { - case 1: - Free_ChainContext1( &ccs->ccsf.ccsf1, memory ); - break; - - case 2: - Free_ChainContext2( &ccs->ccsf.ccsf2, memory ); - break; - - case 3: - Free_ChainContext3( &ccs->ccsf.ccsf3, memory ); - break; - } - } - - - static FT_Error Lookup_ChainContextSubst1( TTO_GSUBHeader* gsub, - TTO_ChainContextSubstFormat1* ccsf1, - OTL_Buffer buffer, - FT_UShort flags, - FT_UShort context_length, - int nesting_level ) - { - FT_UShort index, property; - FT_UShort i, j, k, num_csr; - FT_UShort bgc, igc, lgc; - FT_Error error; - - TTO_ChainSubRule* csr; - TTO_ChainSubRule curr_csr; - TTO_GDEFHeader* gdef; - - - gdef = gsub->gdef; - - if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) ) - return error; - - error = Coverage_Index( &ccsf1->Coverage, IN_CURGLYPH(), &index ); - if ( error ) - return error; - - csr = ccsf1->ChainSubRuleSet[index].ChainSubRule; - num_csr = ccsf1->ChainSubRuleSet[index].ChainSubRuleCount; - - for ( k = 0; k < num_csr; k++ ) - { - curr_csr = csr[k]; - bgc = curr_csr.BacktrackGlyphCount; - igc = curr_csr.InputGlyphCount; - lgc = curr_csr.LookaheadGlyphCount; - - if ( context_length != 0xFFFF && context_length < igc ) - goto next_chainsubrule; - - /* check whether context is too long; it is a first guess only */ - - if ( bgc > buffer->out_pos || buffer->in_pos + igc + lgc > buffer->in_length ) - goto next_chainsubrule; - - if ( bgc ) - { - /* since we don't know in advance the number of glyphs to inspect, - we search backwards for matches in the backtrack glyph array */ - - for ( i = 0, j = buffer->out_pos - 1; i < bgc; i++, j-- ) - { - while ( CHECK_Property( gdef, OUT_ITEM( j ), flags, &property ) ) - { - if ( error && error != TTO_Err_Not_Covered ) - return error; - - if ( j + 1 == bgc - i ) - goto next_chainsubrule; - j--; - } - - /* In OpenType 1.3, it is undefined whether the offsets of - backtrack glyphs is in logical order or not. Version 1.4 - will clarify this: - - Logical order - a b c d e f g h i j - i - Input offsets - 0 1 - Backtrack offsets - 3 2 1 0 - Lookahead offsets - 0 1 2 3 */ - - if ( OUT_GLYPH( j ) != curr_csr.Backtrack[i] ) - goto next_chainsubrule; - } - } - - /* Start at 1 because [0] is implied */ - - for ( i = 1, j = buffer->in_pos + 1; i < igc; i++, j++ ) - { - while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) - { - if ( error && error != TTO_Err_Not_Covered ) - return error; - - if ( j + igc - i + lgc == buffer->in_length ) - goto next_chainsubrule; - j++; - } - - if ( IN_GLYPH( j ) != curr_csr.Input[i - 1] ) - goto next_chainsubrule; - } - - /* we are starting to check for lookahead glyphs right after the - last context glyph */ - - for ( i = 0; i < lgc; i++, j++ ) - { - while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) - { - if ( error && error != TTO_Err_Not_Covered ) - return error; - - if ( j + lgc - i == buffer->in_length ) - goto next_chainsubrule; - j++; - } - - if ( IN_GLYPH( j ) != curr_csr.Lookahead[i] ) - goto next_chainsubrule; - } - - return Do_ContextSubst( gsub, igc, - curr_csr.SubstCount, - curr_csr.SubstLookupRecord, - buffer, - nesting_level ); - - next_chainsubrule: - ; - } - - return TTO_Err_Not_Covered; - } - - - static FT_Error Lookup_ChainContextSubst2( TTO_GSUBHeader* gsub, - TTO_ChainContextSubstFormat2* ccsf2, - OTL_Buffer buffer, - FT_UShort flags, - FT_UShort context_length, - int nesting_level ) - { - FT_UShort index, property; - FT_Memory memory; - FT_Error error; - FT_UShort i, j, k; - FT_UShort bgc, igc, lgc; - FT_UShort known_backtrack_classes, - known_input_classes, - known_lookahead_classes; - - FT_UShort* backtrack_classes; - FT_UShort* input_classes; - FT_UShort* lookahead_classes; - - FT_UShort* bc; - FT_UShort* ic; - FT_UShort* lc; - - TTO_ChainSubClassSet* cscs; - TTO_ChainSubClassRule ccsr; - TTO_GDEFHeader* gdef; - - - gdef = gsub->gdef; - memory = gsub->memory; - - if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) ) - return error; - - /* Note: The coverage table in format 2 doesn't give an index into - anything. It just lets us know whether or not we need to - do any lookup at all. */ - - error = Coverage_Index( &ccsf2->Coverage, IN_CURGLYPH(), &index ); - if ( error ) - return error; - - if ( ALLOC_ARRAY( backtrack_classes, ccsf2->MaxBacktrackLength, FT_UShort ) ) - return error; - known_backtrack_classes = 0; - - if ( ALLOC_ARRAY( input_classes, ccsf2->MaxInputLength, FT_UShort ) ) - goto End3; - known_input_classes = 1; - - if ( ALLOC_ARRAY( lookahead_classes, ccsf2->MaxLookaheadLength, FT_UShort ) ) - goto End2; - known_lookahead_classes = 0; - - error = Get_Class( &ccsf2->InputClassDef, IN_CURGLYPH(), - &input_classes[0], NULL ); - if ( error && error != TTO_Err_Not_Covered ) - goto End1; - - cscs = &ccsf2->ChainSubClassSet[input_classes[0]]; - if ( !cscs ) - { - error = TTO_Err_Invalid_GSUB_SubTable; - goto End1; - } - - for ( k = 0; k < cscs->ChainSubClassRuleCount; k++ ) - { - ccsr = cscs->ChainSubClassRule[k]; - bgc = ccsr.BacktrackGlyphCount; - igc = ccsr.InputGlyphCount; - lgc = ccsr.LookaheadGlyphCount; - - if ( context_length != 0xFFFF && context_length < igc ) - goto next_chainsubclassrule; - - /* check whether context is too long; it is a first guess only */ - - if ( bgc > buffer->out_pos || buffer->in_pos + igc + lgc > buffer->in_length ) - goto next_chainsubclassrule; - - if ( bgc ) - { - /* Since we don't know in advance the number of glyphs to inspect, - we search backwards for matches in the backtrack glyph array. - Note that `known_backtrack_classes' starts at index 0. */ - - bc = ccsr.Backtrack; - - for ( i = 0, j = buffer->out_pos - 1; i < bgc; i++, j-- ) - { - while ( CHECK_Property( gdef, OUT_ITEM( j ), flags, &property ) ) - { - if ( error && error != TTO_Err_Not_Covered ) - goto End1; - - if ( j + 1 == bgc - i ) - goto next_chainsubclassrule; - j--; - } - - if ( i >= known_backtrack_classes ) - { - /* Keeps us from having to do this for each rule */ - - error = Get_Class( &ccsf2->BacktrackClassDef, OUT_GLYPH( j ), - &backtrack_classes[i], NULL ); - if ( error && error != TTO_Err_Not_Covered ) - goto End1; - known_backtrack_classes = i; - } - - if ( bc[i] != backtrack_classes[i] ) - goto next_chainsubclassrule; - } - } - - ic = ccsr.Input; - - /* Start at 1 because [0] is implied */ - - for ( i = 1, j = buffer->in_pos + 1; i < igc; i++, j++ ) - { - while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) - { - if ( error && error != TTO_Err_Not_Covered ) - goto End1; - - if ( j + igc - i + lgc == buffer->in_length ) - goto next_chainsubclassrule; - j++; - } - - if ( i >= known_input_classes ) - { - error = Get_Class( &ccsf2->InputClassDef, IN_GLYPH( j ), - &input_classes[i], NULL ); - if ( error && error != TTO_Err_Not_Covered ) - goto End1; - known_input_classes = i; - } - - if ( ic[i - 1] != input_classes[i] ) - goto next_chainsubclassrule; - } - - /* we are starting to check for lookahead glyphs right after the - last context glyph */ - - lc = ccsr.Lookahead; - - for ( i = 0; i < lgc; i++, j++ ) - { - while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) - { - if ( error && error != TTO_Err_Not_Covered ) - goto End1; - - if ( j + lgc - i == buffer->in_length ) - goto next_chainsubclassrule; - j++; - } - - if ( i >= known_lookahead_classes ) - { - error = Get_Class( &ccsf2->LookaheadClassDef, IN_GLYPH( j ), - &lookahead_classes[i], NULL ); - if ( error && error != TTO_Err_Not_Covered ) - goto End1; - known_lookahead_classes = i; - } - - if ( lc[i] != lookahead_classes[i] ) - goto next_chainsubclassrule; - } - - error = Do_ContextSubst( gsub, igc, - ccsr.SubstCount, - ccsr.SubstLookupRecord, - buffer, - nesting_level ); - goto End1; - - next_chainsubclassrule: - ; - } - - error = TTO_Err_Not_Covered; - - End1: - FREE( lookahead_classes ); - - End2: - FREE( input_classes ); - - End3: - FREE( backtrack_classes ); - return error; - } - - - static FT_Error Lookup_ChainContextSubst3( TTO_GSUBHeader* gsub, - TTO_ChainContextSubstFormat3* ccsf3, - OTL_Buffer buffer, - FT_UShort flags, - FT_UShort context_length, - int nesting_level ) - { - FT_UShort index, i, j, property; - FT_UShort bgc, igc, lgc; - FT_Error error; - - TTO_Coverage* bc; - TTO_Coverage* ic; - TTO_Coverage* lc; - TTO_GDEFHeader* gdef; - - - gdef = gsub->gdef; - - if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) ) - return error; - - bgc = ccsf3->BacktrackGlyphCount; - igc = ccsf3->InputGlyphCount; - lgc = ccsf3->LookaheadGlyphCount; - - if ( context_length != 0xFFFF && context_length < igc ) - return TTO_Err_Not_Covered; - - /* check whether context is too long; it is a first guess only */ - - if ( bgc > buffer->out_pos || buffer->in_pos + igc + lgc > buffer->in_length ) - return TTO_Err_Not_Covered; - - if ( bgc ) - { - /* Since we don't know in advance the number of glyphs to inspect, - we search backwards for matches in the backtrack glyph array */ - - bc = ccsf3->BacktrackCoverage; - - for ( i = 0, j = buffer->out_pos - 1; i < bgc; i++, j-- ) - { - while ( CHECK_Property( gdef, OUT_ITEM( j ), flags, &property ) ) - { - if ( error && error != TTO_Err_Not_Covered ) - return error; - - if ( j + 1 == bgc - i ) - return TTO_Err_Not_Covered; - j--; - } - - error = Coverage_Index( &bc[i], OUT_GLYPH( j ), &index ); - if ( error ) - return error; - } - } - - ic = ccsf3->InputCoverage; - - for ( i = 0, j = buffer->in_pos; i < igc; i++, j++ ) - { - /* We already called CHECK_Property for IN_GLYPH( buffer->in_pos ) */ - while ( j > buffer->in_pos && CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) - { - if ( error && error != TTO_Err_Not_Covered ) - return error; - - if ( j + igc - i + lgc == buffer->in_length ) - return TTO_Err_Not_Covered; - j++; - } - - error = Coverage_Index( &ic[i], IN_GLYPH( j ), &index ); - if ( error ) - return error; - } - - /* we are starting for lookahead glyphs right after the last context - glyph */ - - lc = ccsf3->LookaheadCoverage; - - for ( i = 0; i < lgc; i++, j++ ) - { - while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) - { - if ( error && error != TTO_Err_Not_Covered ) - return error; - - if ( j + lgc - i == buffer->in_length ) - return TTO_Err_Not_Covered; - j++; - } - - error = Coverage_Index( &lc[i], IN_GLYPH( j ), &index ); - if ( error ) - return error; - } - - return Do_ContextSubst( gsub, igc, - ccsf3->SubstCount, - ccsf3->SubstLookupRecord, - buffer, - nesting_level ); - } - - - static FT_Error Lookup_ChainContextSubst( TTO_GSUBHeader* gsub, - TTO_GSUB_SubTable* st, - OTL_Buffer buffer, - FT_UShort flags, - FT_UShort context_length, - int nesting_level ) - { - TTO_ChainContextSubst* ccs = &st->chain; - - switch ( ccs->SubstFormat ) - { - case 1: - return Lookup_ChainContextSubst1( gsub, &ccs->ccsf.ccsf1, buffer, - flags, context_length, - nesting_level ); - - case 2: - return Lookup_ChainContextSubst2( gsub, &ccs->ccsf.ccsf2, buffer, - flags, context_length, - nesting_level ); - - case 3: - return Lookup_ChainContextSubst3( gsub, &ccs->ccsf.ccsf3, buffer, - flags, context_length, - nesting_level ); - - default: - return TTO_Err_Invalid_GSUB_SubTable_Format; - } - - return TT_Err_Ok; /* never reached */ - } - - - FT_Error Load_ReverseChainContextSubst( TTO_ReverseChainContextSubst* rccs, - FT_Stream stream ) - { - FT_Error error; - FT_Memory memory = stream->memory; - - FT_UShort m, count; - - FT_UShort nb = 0, nl = 0, n; - FT_UShort backtrack_count, lookahead_count; - FT_ULong cur_offset, new_offset, base_offset; - - TTO_Coverage* b; - TTO_Coverage* l; - FT_UShort* sub; - - base_offset = FILE_Pos(); - - if ( ACCESS_Frame( 2L ) ) - return error; - - rccs->SubstFormat = GET_UShort(); - - if ( rccs->SubstFormat != 1 ) - return TTO_Err_Invalid_GSUB_SubTable_Format; - - FORGET_Frame(); - - if ( ACCESS_Frame( 2L ) ) - return error; - - new_offset = GET_UShort() + base_offset; - - FORGET_Frame(); - - cur_offset = FILE_Pos(); - if ( FILE_Seek( new_offset ) || - ( error = Load_Coverage( &rccs->Coverage, stream ) ) != TT_Err_Ok ) - return error; - (void)FILE_Seek( cur_offset ); - - - if ( ACCESS_Frame( 2L ) ) - goto Fail4; - - rccs->BacktrackGlyphCount = GET_UShort(); - - FORGET_Frame(); - - rccs->BacktrackCoverage = NULL; - - backtrack_count = rccs->BacktrackGlyphCount; - - if ( ALLOC_ARRAY( rccs->BacktrackCoverage, backtrack_count, - TTO_Coverage ) ) - goto Fail4; - - b = rccs->BacktrackCoverage; - - for ( nb = 0; nb < backtrack_count; nb++ ) - { - if ( ACCESS_Frame( 2L ) ) - goto Fail3; - - new_offset = GET_UShort() + base_offset; - - FORGET_Frame(); - - cur_offset = FILE_Pos(); - if ( FILE_Seek( new_offset ) || - ( error = Load_Coverage( &b[nb], stream ) ) != TT_Err_Ok ) - goto Fail3; - (void)FILE_Seek( cur_offset ); - } - - - if ( ACCESS_Frame( 2L ) ) - goto Fail3; - - rccs->LookaheadGlyphCount = GET_UShort(); - - FORGET_Frame(); - - rccs->LookaheadCoverage = NULL; - - lookahead_count = rccs->LookaheadGlyphCount; - - if ( ALLOC_ARRAY( rccs->LookaheadCoverage, lookahead_count, - TTO_Coverage ) ) - goto Fail3; - - l = rccs->LookaheadCoverage; - - for ( nl = 0; nl < lookahead_count; nl++ ) - { - if ( ACCESS_Frame( 2L ) ) - goto Fail2; - - new_offset = GET_UShort() + base_offset; - - FORGET_Frame(); - - cur_offset = FILE_Pos(); - if ( FILE_Seek( new_offset ) || - ( error = Load_Coverage( &l[nl], stream ) ) != TT_Err_Ok ) - goto Fail2; - (void)FILE_Seek( cur_offset ); - } - - if ( ACCESS_Frame( 2L ) ) - goto Fail2; - - rccs->GlyphCount = GET_UShort(); - - FORGET_Frame(); - - rccs->Substitute = NULL; - - count = rccs->GlyphCount; - - if ( ALLOC_ARRAY( rccs->Substitute, count, - FT_UShort ) ) - goto Fail2; - - sub = rccs->Substitute; - - if ( ACCESS_Frame( count * 2L ) ) - goto Fail1; - - for ( n = 0; n < count; n++ ) - sub[n] = GET_UShort(); - - FORGET_Frame(); - - return TT_Err_Ok; - - Fail1: - FREE( sub ); - - Fail2: - for ( m = 0; m < nl; m++ ) - Free_Coverage( &l[m], memory ); - - FREE( l ); - - Fail3: - for ( m = 0; m < nb; m++ ) - Free_Coverage( &b[m], memory ); - - FREE( b ); - - Fail4: - Free_Coverage( &rccs->Coverage, memory ); - return error; - } - - - void Free_ReverseChainContextSubst( TTO_ReverseChainContextSubst* rccs, - FT_Memory memory ) - { - FT_UShort n, count; - - TTO_Coverage* c; - - Free_Coverage( &rccs->Coverage, memory ); - - if ( rccs->LookaheadCoverage ) - { - count = rccs->LookaheadGlyphCount; - c = rccs->LookaheadCoverage; - - for ( n = 0; n < count; n++ ) - Free_Coverage( &c[n], memory ); - - FREE( c ); - } - - if ( rccs->BacktrackCoverage ) - { - count = rccs->BacktrackGlyphCount; - c = rccs->BacktrackCoverage; - - for ( n = 0; n < count; n++ ) - Free_Coverage( &c[n], memory ); - - FREE( c ); - } - - FREE ( rccs->Substitute ); - } - - - static FT_Error Lookup_ReverseChainContextSubst( TTO_GSUBHeader* gsub, - TTO_GSUB_SubTable* st, - OTL_Buffer buffer, - FT_UShort flags, - /* note different signature here: */ FT_ULong string_index ) - { - FT_UShort index, input_index, i, j, property; - FT_UShort bgc, lgc; - FT_Error error; - - TTO_ReverseChainContextSubst* rccs = &st->reverse; - TTO_Coverage* bc; - TTO_Coverage* lc; - TTO_GDEFHeader* gdef; - - gdef = gsub->gdef; - - if ( CHECK_Property( gdef, IN_ITEM( string_index ), flags, &property ) ) - return error; - - bgc = rccs->BacktrackGlyphCount; - lgc = rccs->LookaheadGlyphCount; - - /* check whether context is too long; it is a first guess only */ - - if ( bgc > string_index || string_index + 1 + lgc > buffer->in_length ) - return TTO_Err_Not_Covered; - - if ( bgc ) - { - /* Since we don't know in advance the number of glyphs to inspect, - we search backwards for matches in the backtrack glyph array */ - - bc = rccs->BacktrackCoverage; - - for ( i = 0, j = string_index - 1; i < bgc; i++, j-- ) - { - while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) - { - if ( error && error != TTO_Err_Not_Covered ) - return error; - - if ( j + 1 == bgc - i ) - return TTO_Err_Not_Covered; - j--; - } - - error = Coverage_Index( &bc[i], IN_GLYPH( j ), &index ); - if ( error ) - return error; - } - } - - j = string_index; - - error = Coverage_Index( &rccs->Coverage, IN_GLYPH( j ), &input_index ); - if ( error ) - return error; - - /* we are starting for lookahead glyphs right after the last context - glyph */ - - j += 1; - - lc = rccs->LookaheadCoverage; - - for ( i = 0; i < lgc; i++, j++ ) - { - while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) - { - if ( error && error != TTO_Err_Not_Covered ) - return error; - - if ( j + lgc - i == buffer->in_length ) - return TTO_Err_Not_Covered; - j++; - } - - error = Coverage_Index( &lc[i], IN_GLYPH( j ), &index ); - if ( error ) - return error; - } - - IN_GLYPH( string_index ) = rccs->Substitute[input_index]; - - return error; - } - - - - /*********** - * GSUB API - ***********/ - - - EXPORT_FUNC - FT_Error TT_GSUB_Select_Script( TTO_GSUBHeader* gsub, - FT_ULong script_tag, - FT_UShort* script_index ) - { - FT_UShort n; - - TTO_ScriptList* sl; - TTO_ScriptRecord* sr; - - - if ( !gsub || !script_index ) - return TT_Err_Invalid_Argument; - - sl = &gsub->ScriptList; - sr = sl->ScriptRecord; - - for ( n = 0; n < sl->ScriptCount; n++ ) - if ( script_tag == sr[n].ScriptTag ) - { - *script_index = n; - - return TT_Err_Ok; - } - - return TTO_Err_Not_Covered; - } - - - EXPORT_FUNC - FT_Error TT_GSUB_Select_Language( TTO_GSUBHeader* gsub, - FT_ULong language_tag, - FT_UShort script_index, - FT_UShort* language_index, - FT_UShort* req_feature_index ) - { - FT_UShort n; - - TTO_ScriptList* sl; - TTO_ScriptRecord* sr; - TTO_Script* s; - TTO_LangSysRecord* lsr; - - - if ( !gsub || !language_index || !req_feature_index ) - return TT_Err_Invalid_Argument; - - sl = &gsub->ScriptList; - sr = sl->ScriptRecord; - - if ( script_index >= sl->ScriptCount ) - return TT_Err_Invalid_Argument; - - s = &sr[script_index].Script; - lsr = s->LangSysRecord; - - for ( n = 0; n < s->LangSysCount; n++ ) - if ( language_tag == lsr[n].LangSysTag ) - { - *language_index = n; - *req_feature_index = lsr[n].LangSys.ReqFeatureIndex; - - return TT_Err_Ok; - } - - return TTO_Err_Not_Covered; - } - - - /* selecting 0xFFFF for language_index asks for the values of the - default language (DefaultLangSys) */ - - EXPORT_FUNC - FT_Error TT_GSUB_Select_Feature( TTO_GSUBHeader* gsub, - FT_ULong feature_tag, - FT_UShort script_index, - FT_UShort language_index, - FT_UShort* feature_index ) - { - FT_UShort n; - - TTO_ScriptList* sl; - TTO_ScriptRecord* sr; - TTO_Script* s; - TTO_LangSysRecord* lsr; - TTO_LangSys* ls; - FT_UShort* fi; - - TTO_FeatureList* fl; - TTO_FeatureRecord* fr; - - - if ( !gsub || !feature_index ) - return TT_Err_Invalid_Argument; - - sl = &gsub->ScriptList; - sr = sl->ScriptRecord; - - fl = &gsub->FeatureList; - fr = fl->FeatureRecord; - - if ( script_index >= sl->ScriptCount ) - return TT_Err_Invalid_Argument; - - s = &sr[script_index].Script; - lsr = s->LangSysRecord; - - if ( language_index == 0xFFFF ) - ls = &s->DefaultLangSys; - else - { - if ( language_index >= s->LangSysCount ) - return TT_Err_Invalid_Argument; - - ls = &lsr[language_index].LangSys; - } - - fi = ls->FeatureIndex; - - for ( n = 0; n < ls->FeatureCount; n++ ) - { - if ( fi[n] >= fl->FeatureCount ) - return TTO_Err_Invalid_GSUB_SubTable_Format; - - if ( feature_tag == fr[fi[n]].FeatureTag ) - { - *feature_index = fi[n]; - - return TT_Err_Ok; - } - } - - return TTO_Err_Not_Covered; - } - - - /* The next three functions return a null-terminated list */ - - EXPORT_FUNC - FT_Error TT_GSUB_Query_Scripts( TTO_GSUBHeader* gsub, - FT_ULong** script_tag_list ) - { - FT_UShort n; - FT_Error error; - FT_Memory memory; - FT_ULong* stl; - - TTO_ScriptList* sl; - TTO_ScriptRecord* sr; - - - if ( !gsub || !script_tag_list ) - return TT_Err_Invalid_Argument; - - memory = gsub->memory; - - sl = &gsub->ScriptList; - sr = sl->ScriptRecord; - - if ( ALLOC_ARRAY( stl, sl->ScriptCount + 1, FT_ULong ) ) - return error; - - for ( n = 0; n < sl->ScriptCount; n++ ) - stl[n] = sr[n].ScriptTag; - stl[n] = 0; - - *script_tag_list = stl; - - return TT_Err_Ok; - } - - - EXPORT_FUNC - FT_Error TT_GSUB_Query_Languages( TTO_GSUBHeader* gsub, - FT_UShort script_index, - FT_ULong** language_tag_list ) - { - FT_UShort n; - FT_Error error; - FT_Memory memory; - FT_ULong* ltl; - - TTO_ScriptList* sl; - TTO_ScriptRecord* sr; - TTO_Script* s; - TTO_LangSysRecord* lsr; - - - if ( !gsub || !language_tag_list ) - return TT_Err_Invalid_Argument; - - memory = gsub->memory; - - sl = &gsub->ScriptList; - sr = sl->ScriptRecord; - - if ( script_index >= sl->ScriptCount ) - return TT_Err_Invalid_Argument; - - s = &sr[script_index].Script; - lsr = s->LangSysRecord; - - if ( ALLOC_ARRAY( ltl, s->LangSysCount + 1, FT_ULong ) ) - return error; - - for ( n = 0; n < s->LangSysCount; n++ ) - ltl[n] = lsr[n].LangSysTag; - ltl[n] = 0; - - *language_tag_list = ltl; - - return TT_Err_Ok; - } - - - /* selecting 0xFFFF for language_index asks for the values of the - default language (DefaultLangSys) */ - - EXPORT_FUNC - FT_Error TT_GSUB_Query_Features( TTO_GSUBHeader* gsub, - FT_UShort script_index, - FT_UShort language_index, - FT_ULong** feature_tag_list ) - { - FT_UShort n; - FT_Error error; - FT_Memory memory; - FT_ULong* ftl; - - TTO_ScriptList* sl; - TTO_ScriptRecord* sr; - TTO_Script* s; - TTO_LangSysRecord* lsr; - TTO_LangSys* ls; - FT_UShort* fi; - - TTO_FeatureList* fl; - TTO_FeatureRecord* fr; - - - if ( !gsub || !feature_tag_list ) - return TT_Err_Invalid_Argument; - - memory = gsub->memory; - - sl = &gsub->ScriptList; - sr = sl->ScriptRecord; - - fl = &gsub->FeatureList; - fr = fl->FeatureRecord; - - if ( script_index >= sl->ScriptCount ) - return TT_Err_Invalid_Argument; - - s = &sr[script_index].Script; - lsr = s->LangSysRecord; - - if ( language_index == 0xFFFF ) - ls = &s->DefaultLangSys; - else - { - if ( language_index >= s->LangSysCount ) - return TT_Err_Invalid_Argument; - - ls = &lsr[language_index].LangSys; - } - - fi = ls->FeatureIndex; - - if ( ALLOC_ARRAY( ftl, ls->FeatureCount + 1, FT_ULong ) ) - return error; - - for ( n = 0; n < ls->FeatureCount; n++ ) - { - if ( fi[n] >= fl->FeatureCount ) - { - FREE( ftl ); - return TTO_Err_Invalid_GSUB_SubTable_Format; - } - ftl[n] = fr[fi[n]].FeatureTag; - } - ftl[n] = 0; - - *feature_tag_list = ftl; - - return TT_Err_Ok; - } - - - typedef FT_Error (*Lookup_Func_Type)( TTO_GSUBHeader* gsub, - TTO_GSUB_SubTable* st, - OTL_Buffer buffer, - FT_UShort flags, - FT_UShort context_length, - int nesting_level ); - static const Lookup_Func_Type Lookup_Call_Table[] = { - Lookup_DefaultSubst, - Lookup_SingleSubst, /* GSUB_LOOKUP_SINGLE 1 */ - Lookup_MultipleSubst, /* GSUB_LOOKUP_MULTIPLE 2 */ - Lookup_AlternateSubst, /* GSUB_LOOKUP_ALTERNATE 3 */ - Lookup_LigatureSubst, /* GSUB_LOOKUP_LIGATURE 4 */ - Lookup_ContextSubst, /* GSUB_LOOKUP_CONTEXT 5 */ - Lookup_ChainContextSubst, /* GSUB_LOOKUP_CHAIN 6 */ - Lookup_DefaultSubst, /* GSUB_LOOKUP_EXTENSION 7 */ - }; - /* Note that the following lookup does not belong to the table above: - * Lookup_ReverseChainContextSubst, GSUB_LOOKUP_REVERSE_CHAIN 8 - * because it's invalid to happen where this table is used. It's - * signature is different too... - */ - - /* Do an individual subtable lookup. Returns TT_Err_Ok if substitution - has been done, or TTO_Err_Not_Covered if not. */ - - static FT_Error Do_Glyph_Lookup( TTO_GSUBHeader* gsub, - FT_UShort lookup_index, - OTL_Buffer buffer, - FT_UShort context_length, - int nesting_level ) - { - FT_Error error = TTO_Err_Not_Covered; - FT_UShort i, flags, lookup_count; - TTO_Lookup* lo; - int lt; - Lookup_Func_Type Lookup_Func; - - - nesting_level++; - - if ( nesting_level > TTO_MAX_NESTING_LEVEL ) - return TTO_Err_Too_Many_Nested_Contexts; - - lookup_count = gsub->LookupList.LookupCount; - if (lookup_index >= lookup_count) - return error; - - lo = &gsub->LookupList.Lookup[lookup_index]; - flags = lo->LookupFlag; - lt = lo->LookupType; - if (lt >= sizeof Lookup_Call_Table / sizeof Lookup_Call_Table[0]) - lt = 0; - Lookup_Func = Lookup_Call_Table[lt]; - - for ( i = 0; i < lo->SubTableCount; i++ ) - { - error = Lookup_Func ( gsub, - &lo->SubTable[i].st.gsub, - buffer, - flags, context_length, - nesting_level ); - - /* Check whether we have a successful substitution or an error other - than TTO_Err_Not_Covered */ - - if ( error != TTO_Err_Not_Covered ) - return error; - } - - return TTO_Err_Not_Covered; - } - - /* apply one lookup to the input string object */ - - static FT_Error Do_String_Lookup( TTO_GSUBHeader* gsub, - FT_UShort lookup_index, - OTL_Buffer buffer ) - { - FT_Error error, retError = TTO_Err_Not_Covered; - - FT_UInt* properties = gsub->LookupList.Properties; - - int nesting_level = 0; - - - while ( buffer->in_pos < buffer->in_length ) - { - if ( ~IN_PROPERTIES( buffer->in_pos ) & properties[lookup_index] ) - { - /* 0xFFFF indicates that we don't have a context length yet */ - error = Do_Glyph_Lookup( gsub, lookup_index, buffer, - 0xFFFF, nesting_level ); - if ( error ) - { - if ( error != TTO_Err_Not_Covered ) - return error; - } - else - retError = error; - } - else - error = TTO_Err_Not_Covered; - - if ( error == TTO_Err_Not_Covered ) - if ( otl_buffer_copy_output_glyph ( buffer ) ) - return error; - } - - return retError; - } - - - static FT_Error Apply_ReverseChainContextSubst( TTO_GSUBHeader* gsub, - FT_UShort lookup_index, - OTL_Buffer buffer ) - { - FT_UInt* properties = gsub->LookupList.Properties; - FT_Error error, retError = TTO_Err_Not_Covered; - FT_ULong subtable_Count, string_index; - FT_UShort flags; - TTO_Lookup* lo; - - if ( buffer->in_length == 0 ) - return TTO_Err_Not_Covered; - - lo = &gsub->LookupList.Lookup[lookup_index]; - flags = lo->LookupFlag; - - for ( subtable_Count = 0; subtable_Count < lo->SubTableCount; subtable_Count++ ) - { - string_index = buffer->in_length - 1; - do - { - if ( ~IN_PROPERTIES( buffer->in_pos ) & properties[lookup_index] ) - { - error = Lookup_ReverseChainContextSubst( gsub, &lo->SubTable[subtable_Count].st.gsub, - buffer, flags, string_index ); - if ( error ) - { - if ( error != TTO_Err_Not_Covered ) - return error; - } - else - retError = error; - } - } - while (string_index--); - } - - return retError; - } - - - EXPORT_FUNC - FT_Error TT_GSUB_Add_Feature( TTO_GSUBHeader* gsub, - FT_UShort feature_index, - FT_UInt property ) - { - FT_UShort i; - - TTO_Feature feature; - FT_UInt* properties; - FT_UShort* index; - FT_UShort lookup_count; - - /* Each feature can only be added once */ - - if ( !gsub || - feature_index >= gsub->FeatureList.FeatureCount || - gsub->FeatureList.ApplyCount == gsub->FeatureList.FeatureCount ) - return TT_Err_Invalid_Argument; - - gsub->FeatureList.ApplyOrder[gsub->FeatureList.ApplyCount++] = feature_index; - - properties = gsub->LookupList.Properties; - - feature = gsub->FeatureList.FeatureRecord[feature_index].Feature; - index = feature.LookupListIndex; - lookup_count = gsub->LookupList.LookupCount; - - for ( i = 0; i < feature.LookupListCount; i++ ) - { - FT_UShort lookup_index = index[i]; - if (lookup_index < lookup_count) - properties[lookup_index] |= property; - } - - return TT_Err_Ok; - } - - - EXPORT_FUNC - FT_Error TT_GSUB_Clear_Features( TTO_GSUBHeader* gsub ) - { - FT_UShort i; - - FT_UInt* properties; - - - if ( !gsub ) - return TT_Err_Invalid_Argument; - - gsub->FeatureList.ApplyCount = 0; - - properties = gsub->LookupList.Properties; - - for ( i = 0; i < gsub->LookupList.LookupCount; i++ ) - properties[i] = 0; - - return TT_Err_Ok; - } - - - EXPORT_FUNC - FT_Error TT_GSUB_Register_Alternate_Function( TTO_GSUBHeader* gsub, - TTO_AltFunction altfunc, - void* data ) - { - if ( !gsub ) - return TT_Err_Invalid_Argument; - - gsub->altfunc = altfunc; - gsub->data = data; - - return TT_Err_Ok; - } - - - EXPORT_FUNC - FT_Error TT_GSUB_Apply_String( TTO_GSUBHeader* gsub, - OTL_Buffer buffer ) - { - FT_Error error, retError = TTO_Err_Not_Covered; - FT_UShort i, j, lookup_count; - - if ( !gsub || - !buffer || buffer->in_length == 0 || buffer->in_pos >= buffer->in_length ) - return TT_Err_Invalid_Argument; - - lookup_count = gsub->LookupList.LookupCount; - - for ( i = 0; i < gsub->FeatureList.ApplyCount; i++) - { - FT_UShort feature_index; - TTO_Feature feature; - - feature_index = gsub->FeatureList.ApplyOrder[i]; - feature = gsub->FeatureList.FeatureRecord[feature_index].Feature; - - for ( j = 0; j < feature.LookupListCount; j++ ) - { - FT_UShort lookup_index; - TTO_Lookup* lookup; - FT_Bool need_swap; - - lookup_index = feature.LookupListIndex[j]; - - /* Skip nonexistant lookups */ - if (lookup_index >= lookup_count) - continue; - - lookup = &gsub->LookupList.Lookup[lookup_index]; - - if ( lookup->LookupType == GSUB_LOOKUP_REVERSE_CHAIN ) - { - error = Apply_ReverseChainContextSubst( gsub, lookup_index, buffer); - need_swap = FALSE; /* We do ReverseChainContextSubst in-place */ - } - else - { - error = Do_String_Lookup( gsub, lookup_index, buffer ); - need_swap = TRUE; - } - - if ( error ) - { - if ( error != TTO_Err_Not_Covered ) - goto End; - } - else - retError = error; - - if ( need_swap ) - { - error = otl_buffer_swap( buffer ); - if ( error ) - goto End; - } - } - } - - error = retError; - - End: - return error; - } - - -/* END */ diff --git a/src/ftxgsub.h b/src/ftxgsub.h deleted file mode 100644 index 53409d6..0000000 --- a/src/ftxgsub.h +++ /dev/null @@ -1,594 +0,0 @@ -/******************************************************************* - * - * ftxgsub.h - * - * TrueType Open GSUB table support - * - * Copyright 1996-2000 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 FTXOPEN_H -#error "Don't include this file! Use ftxopen.h instead." -#endif - -#ifndef FTXGSUB_H -#define FTXGSUB_H - -#ifdef __cplusplus -extern "C" { -#endif - -#define TTO_Err_Invalid_GSUB_SubTable_Format 0x1010 -#define TTO_Err_Invalid_GSUB_SubTable 0x1011 - - -/* Lookup types for glyph substitution */ - -#define GSUB_LOOKUP_SINGLE 1 -#define GSUB_LOOKUP_MULTIPLE 2 -#define GSUB_LOOKUP_ALTERNATE 3 -#define GSUB_LOOKUP_LIGATURE 4 -#define GSUB_LOOKUP_CONTEXT 5 -#define GSUB_LOOKUP_CHAIN 6 -#define GSUB_LOOKUP_EXTENSION 7 -#define GSUB_LOOKUP_REVERSE_CHAIN 8 - -/* Use this if a feature applies to all glyphs */ - -#define ALL_GLYPHS 0xFFFF - - - /* A pointer to a function which selects the alternate glyph. `pos' is - the position of the glyph with index `glyphID', `num_alternates' - gives the number of alternates in the `alternates' array. `data' - points to the user-defined structure specified during a call to - TT_GSUB_Register_Alternate_Function(). The function must return an - index into the `alternates' array. */ - - typedef FT_UShort (*TTO_AltFunction)(FT_ULong pos, - FT_UShort glyphID, - FT_UShort num_alternates, - FT_UShort* alternates, - void* data ); - - - struct TTO_GSUBHeader_ - { - FT_Memory memory; - - FT_ULong offset; - - FT_Fixed Version; - - TTO_ScriptList ScriptList; - TTO_FeatureList FeatureList; - TTO_LookupList LookupList; - - TTO_GDEFHeader* gdef; - - /* the next two fields are used for an alternate substitution callback - function to select the proper alternate glyph. */ - - TTO_AltFunction altfunc; - void* data; - }; - - typedef struct TTO_GSUBHeader_ TTO_GSUBHeader; - typedef struct TTO_GSUBHeader_* TTO_GSUB; - - - /* LookupType 1 */ - - struct TTO_SingleSubstFormat1_ - { - FT_Short DeltaGlyphID; /* constant added to get - substitution glyph index */ - }; - - typedef struct TTO_SingleSubstFormat1_ TTO_SingleSubstFormat1; - - - struct TTO_SingleSubstFormat2_ - { - FT_UShort GlyphCount; /* number of glyph IDs in - Substitute array */ - FT_UShort* Substitute; /* array of substitute glyph IDs */ - }; - - typedef struct TTO_SingleSubstFormat2_ TTO_SingleSubstFormat2; - - - struct TTO_SingleSubst_ - { - FT_UShort SubstFormat; /* 1 or 2 */ - TTO_Coverage Coverage; /* Coverage table */ - - union - { - TTO_SingleSubstFormat1 ssf1; - TTO_SingleSubstFormat2 ssf2; - } ssf; - }; - - typedef struct TTO_SingleSubst_ TTO_SingleSubst; - - - /* LookupType 2 */ - - struct TTO_Sequence_ - { - FT_UShort GlyphCount; /* number of glyph IDs in the - Substitute array */ - FT_UShort* Substitute; /* string of glyph IDs to - substitute */ - }; - - typedef struct TTO_Sequence_ TTO_Sequence; - - - struct TTO_MultipleSubst_ - { - FT_UShort SubstFormat; /* always 1 */ - TTO_Coverage Coverage; /* Coverage table */ - FT_UShort SequenceCount; /* number of Sequence tables */ - TTO_Sequence* Sequence; /* array of Sequence tables */ - }; - - typedef struct TTO_MultipleSubst_ TTO_MultipleSubst; - - - /* LookupType 3 */ - - struct TTO_AlternateSet_ - { - FT_UShort GlyphCount; /* number of glyph IDs in the - Alternate array */ - FT_UShort* Alternate; /* array of alternate glyph IDs */ - }; - - typedef struct TTO_AlternateSet_ TTO_AlternateSet; - - - struct TTO_AlternateSubst_ - { - FT_UShort SubstFormat; /* always 1 */ - TTO_Coverage Coverage; /* Coverage table */ - FT_UShort AlternateSetCount; - /* number of AlternateSet tables */ - TTO_AlternateSet* AlternateSet; /* array of AlternateSet tables */ - }; - - typedef struct TTO_AlternateSubst_ TTO_AlternateSubst; - - - /* LookupType 4 */ - - struct TTO_Ligature_ - { - FT_UShort LigGlyph; /* glyphID of ligature - to substitute */ - FT_UShort ComponentCount; /* number of components in ligature */ - FT_UShort* Component; /* array of component glyph IDs */ - }; - - typedef struct TTO_Ligature_ TTO_Ligature; - - - struct TTO_LigatureSet_ - { - FT_UShort LigatureCount; /* number of Ligature tables */ - TTO_Ligature* Ligature; /* array of Ligature tables */ - }; - - typedef struct TTO_LigatureSet_ TTO_LigatureSet; - - - struct TTO_LigatureSubst_ - { - FT_UShort SubstFormat; /* always 1 */ - TTO_Coverage Coverage; /* Coverage table */ - FT_UShort LigatureSetCount; /* number of LigatureSet tables */ - TTO_LigatureSet* LigatureSet; /* array of LigatureSet tables */ - }; - - typedef struct TTO_LigatureSubst_ TTO_LigatureSubst; - - - /* needed by both lookup type 5 and 6 */ - - struct TTO_SubstLookupRecord_ - { - FT_UShort SequenceIndex; /* index into current - glyph sequence */ - FT_UShort LookupListIndex; /* Lookup to apply to that pos. */ - }; - - typedef struct TTO_SubstLookupRecord_ TTO_SubstLookupRecord; - - - /* LookupType 5 */ - - struct TTO_SubRule_ - { - FT_UShort GlyphCount; /* total number of input glyphs */ - FT_UShort SubstCount; /* number of SubstLookupRecord - tables */ - FT_UShort* Input; /* array of input glyph IDs */ - TTO_SubstLookupRecord* SubstLookupRecord; - /* array of SubstLookupRecord - tables */ - }; - - typedef struct TTO_SubRule_ TTO_SubRule; - - - struct TTO_SubRuleSet_ - { - FT_UShort SubRuleCount; /* number of SubRule tables */ - TTO_SubRule* SubRule; /* array of SubRule tables */ - }; - - typedef struct TTO_SubRuleSet_ TTO_SubRuleSet; - - - struct TTO_ContextSubstFormat1_ - { - TTO_Coverage Coverage; /* Coverage table */ - FT_UShort SubRuleSetCount; /* number of SubRuleSet tables */ - TTO_SubRuleSet* SubRuleSet; /* array of SubRuleSet tables */ - }; - - typedef struct TTO_ContextSubstFormat1_ TTO_ContextSubstFormat1; - - - struct TTO_SubClassRule_ - { - FT_UShort GlyphCount; /* total number of context classes */ - FT_UShort SubstCount; /* number of SubstLookupRecord - tables */ - FT_UShort* Class; /* array of classes */ - TTO_SubstLookupRecord* SubstLookupRecord; - /* array of SubstLookupRecord - tables */ - }; - - typedef struct TTO_SubClassRule_ TTO_SubClassRule; - - - struct TTO_SubClassSet_ - { - FT_UShort SubClassRuleCount; - /* number of SubClassRule tables */ - TTO_SubClassRule* SubClassRule; /* array of SubClassRule tables */ - }; - - typedef struct TTO_SubClassSet_ TTO_SubClassSet; - - - /* The `MaxContextLength' field is not defined in the TTO specification - but simplifies the implementation of this format. It holds the - maximal context length used in the context rules. */ - - struct TTO_ContextSubstFormat2_ - { - FT_UShort MaxContextLength; - /* maximal context length */ - TTO_Coverage Coverage; /* Coverage table */ - TTO_ClassDefinition ClassDef; /* ClassDef table */ - FT_UShort SubClassSetCount; - /* number of SubClassSet tables */ - TTO_SubClassSet* SubClassSet; /* array of SubClassSet tables */ - }; - - typedef struct TTO_ContextSubstFormat2_ TTO_ContextSubstFormat2; - - - struct TTO_ContextSubstFormat3_ - { - FT_UShort GlyphCount; /* number of input glyphs */ - FT_UShort SubstCount; /* number of SubstLookupRecords */ - TTO_Coverage* Coverage; /* array of Coverage tables */ - TTO_SubstLookupRecord* SubstLookupRecord; - /* array of substitution lookups */ - }; - - typedef struct TTO_ContextSubstFormat3_ TTO_ContextSubstFormat3; - - - struct TTO_ContextSubst_ - { - FT_UShort SubstFormat; /* 1, 2, or 3 */ - - union - { - TTO_ContextSubstFormat1 csf1; - TTO_ContextSubstFormat2 csf2; - TTO_ContextSubstFormat3 csf3; - } csf; - }; - - typedef struct TTO_ContextSubst_ TTO_ContextSubst; - - - /* LookupType 6 */ - - struct TTO_ChainSubRule_ - { - FT_UShort BacktrackGlyphCount; - /* total number of backtrack glyphs */ - FT_UShort* Backtrack; /* array of backtrack glyph IDs */ - FT_UShort InputGlyphCount; - /* total number of input glyphs */ - FT_UShort* Input; /* array of input glyph IDs */ - FT_UShort LookaheadGlyphCount; - /* total number of lookahead glyphs */ - FT_UShort* Lookahead; /* array of lookahead glyph IDs */ - FT_UShort SubstCount; /* number of SubstLookupRecords */ - TTO_SubstLookupRecord* SubstLookupRecord; - /* array of SubstLookupRecords */ - }; - - typedef struct TTO_ChainSubRule_ TTO_ChainSubRule; - - - struct TTO_ChainSubRuleSet_ - { - FT_UShort ChainSubRuleCount; - /* number of ChainSubRule tables */ - TTO_ChainSubRule* ChainSubRule; /* array of ChainSubRule tables */ - }; - - typedef struct TTO_ChainSubRuleSet_ TTO_ChainSubRuleSet; - - - struct TTO_ChainContextSubstFormat1_ - { - TTO_Coverage Coverage; /* Coverage table */ - FT_UShort ChainSubRuleSetCount; - /* number of ChainSubRuleSet tables */ - TTO_ChainSubRuleSet* ChainSubRuleSet; - /* array of ChainSubRuleSet tables */ - }; - - typedef struct TTO_ChainContextSubstFormat1_ TTO_ChainContextSubstFormat1; - - - struct TTO_ChainSubClassRule_ - { - FT_UShort BacktrackGlyphCount; - /* total number of backtrack - classes */ - FT_UShort* Backtrack; /* array of backtrack classes */ - FT_UShort InputGlyphCount; - /* total number of context classes */ - FT_UShort* Input; /* array of context classes */ - FT_UShort LookaheadGlyphCount; - /* total number of lookahead - classes */ - FT_UShort* Lookahead; /* array of lookahead classes */ - FT_UShort SubstCount; /* number of SubstLookupRecords */ - TTO_SubstLookupRecord* SubstLookupRecord; - /* array of substitution lookups */ - }; - - typedef struct TTO_ChainSubClassRule_ TTO_ChainSubClassRule; - - - struct TTO_ChainSubClassSet_ - { - FT_UShort ChainSubClassRuleCount; - /* number of ChainSubClassRule - tables */ - TTO_ChainSubClassRule* ChainSubClassRule; - /* array of ChainSubClassRule - tables */ - }; - - typedef struct TTO_ChainSubClassSet_ TTO_ChainSubClassSet; - - - /* The `MaxXXXLength' fields are not defined in the TTO specification - but simplifies the implementation of this format. It holds the - maximal context length used in the specific context rules. */ - - struct TTO_ChainContextSubstFormat2_ - { - TTO_Coverage Coverage; /* Coverage table */ - - FT_UShort MaxBacktrackLength; - /* maximal backtrack length */ - TTO_ClassDefinition BacktrackClassDef; - /* BacktrackClassDef table */ - FT_UShort MaxInputLength; - /* maximal input length */ - TTO_ClassDefinition InputClassDef; - /* InputClassDef table */ - FT_UShort MaxLookaheadLength; - /* maximal lookahead length */ - TTO_ClassDefinition LookaheadClassDef; - /* LookaheadClassDef table */ - - FT_UShort ChainSubClassSetCount; - /* number of ChainSubClassSet - tables */ - TTO_ChainSubClassSet* ChainSubClassSet; - /* array of ChainSubClassSet - tables */ - }; - - typedef struct TTO_ChainContextSubstFormat2_ TTO_ChainContextSubstFormat2; - - - struct TTO_ChainContextSubstFormat3_ - { - FT_UShort BacktrackGlyphCount; - /* number of backtrack glyphs */ - TTO_Coverage* BacktrackCoverage; - /* array of backtrack Coverage - tables */ - FT_UShort InputGlyphCount; - /* number of input glyphs */ - TTO_Coverage* InputCoverage; - /* array of input coverage - tables */ - FT_UShort LookaheadGlyphCount; - /* number of lookahead glyphs */ - TTO_Coverage* LookaheadCoverage; - /* array of lookahead coverage - tables */ - FT_UShort SubstCount; /* number of SubstLookupRecords */ - TTO_SubstLookupRecord* SubstLookupRecord; - /* array of substitution lookups */ - }; - - typedef struct TTO_ChainContextSubstFormat3_ TTO_ChainContextSubstFormat3; - - - struct TTO_ChainContextSubst_ - { - FT_UShort SubstFormat; /* 1, 2, or 3 */ - - union - { - TTO_ChainContextSubstFormat1 ccsf1; - TTO_ChainContextSubstFormat2 ccsf2; - TTO_ChainContextSubstFormat3 ccsf3; - } ccsf; - }; - - typedef struct TTO_ChainContextSubst_ TTO_ChainContextSubst; - - - /* LookupType 8 */ - struct TTO_ReverseChainContextSubst_ - { - FT_UShort SubstFormat; /* always 1 */ - TTO_Coverage Coverage; /* coverage table for input glyphs */ - FT_UShort BacktrackGlyphCount; /* number of backtrack glyphs */ - TTO_Coverage* BacktrackCoverage; /* array of backtrack Coverage - tables */ - FT_UShort LookaheadGlyphCount; /* number of lookahead glyphs */ - TTO_Coverage* LookaheadCoverage; /* array of lookahead Coverage - tables */ - FT_UShort GlyphCount; /* number of Glyph IDs */ - FT_UShort* Substitute; /* array of substitute Glyph ID */ - }; - - typedef struct TTO_ReverseChainContextSubst_ TTO_ReverseChainContextSubst; - - - union TTO_GSUB_SubTable_ - { - TTO_SingleSubst single; - TTO_MultipleSubst multiple; - TTO_AlternateSubst alternate; - TTO_LigatureSubst ligature; - TTO_ContextSubst context; - TTO_ChainContextSubst chain; - TTO_ReverseChainContextSubst reverse; - }; - - typedef union TTO_GSUB_SubTable_ TTO_GSUB_SubTable; - - - /* A simple string object. It can both `send' and `receive' data. - In case of sending, `length' and `pos' will be used. In case of - receiving, `pos' points to the first free slot, and `allocated' - specifies the amount of allocated memory (and the `length' field - will be ignored). The routine TT_Add_String() will increase the - amount of memory if necessary. After end of receive, `length' - should be set to the value of `pos', and `pos' will be set to zero. - - `properties' (which is treated as a bit field) gives the glyph's - properties: If a certain bit is set for a glyph, the feature which - has the same bit set in its property value is applied. - - `components' is an internal array which tracks components of - ligatures. We need this for MarkToLigature Attachment Positioning - Subtables (in GPOS) together with `ligIDs' (which is used to mark - ligatures and the skipped glyphs during a ligature lookup). - `max_ligID' is increased after a successful ligature lookup. - - NEVER modify any elements of the structure! You should rather copy - its contents if necessary. - - TT_Add_String() will also handle allocation; you should use - free() in case you want to destroy the arrays in the object. */ - - - /* finally, the GSUB API */ - - /* EXPORT_DEF - TT_Error TT_Init_GSUB_Extension( TT_Engine engine ); */ - - EXPORT_DEF - FT_Error TT_Load_GSUB_Table( FT_Face face, - TTO_GSUBHeader** gsub, - TTO_GDEFHeader* gdef ); - - EXPORT_DEF - FT_Error TT_Done_GSUB_Table( TTO_GSUBHeader* gsub ); - - EXPORT_DEF - FT_Error TT_GSUB_Select_Script( TTO_GSUBHeader* gsub, - FT_ULong script_tag, - FT_UShort* script_index ); - EXPORT_DEF - FT_Error TT_GSUB_Select_Language( TTO_GSUBHeader* gsub, - FT_ULong language_tag, - FT_UShort script_index, - FT_UShort* language_index, - FT_UShort* req_feature_index ); - EXPORT_DEF - FT_Error TT_GSUB_Select_Feature( TTO_GSUBHeader* gsub, - FT_ULong feature_tag, - FT_UShort script_index, - FT_UShort language_index, - FT_UShort* feature_index ); - - EXPORT_DEF - FT_Error TT_GSUB_Query_Scripts( TTO_GSUBHeader* gsub, - FT_ULong** script_tag_list ); - EXPORT_DEF - FT_Error TT_GSUB_Query_Languages( TTO_GSUBHeader* gsub, - FT_UShort script_index, - FT_ULong** language_tag_list ); - EXPORT_DEF - FT_Error TT_GSUB_Query_Features( TTO_GSUBHeader* gsub, - FT_UShort script_index, - FT_UShort language_index, - FT_ULong** feature_tag_list ); - - EXPORT_DEF - FT_Error TT_GSUB_Add_Feature( TTO_GSUBHeader* gsub, - FT_UShort feature_index, - FT_UInt property ); - EXPORT_DEF - FT_Error TT_GSUB_Clear_Features( TTO_GSUBHeader* gsub ); - - EXPORT_DEF - FT_Error TT_GSUB_Register_Alternate_Function( TTO_GSUBHeader* gsub, - TTO_AltFunction altfunc, - void* data ); - - EXPORT_DEF - FT_Error TT_GSUB_Apply_String( TTO_GSUBHeader* gsub, - OTL_Buffer buffer ); - - -#ifdef __cplusplus -} -#endif - -#endif /* FTXGSUB_H */ - - -/* END */ diff --git a/src/ftxopen.c b/src/ftxopen.c deleted file mode 100644 index 8afb8f2..0000000 --- a/src/ftxopen.c +++ /dev/null @@ -1,1552 +0,0 @@ -/******************************************************************* - * - * ftxopen.c - * - * TrueType Open common table support. - * - * Copyright 1996-2000 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. - * - ******************************************************************/ - -#include - -#include "ftxopen.h" -#include "ftxopenf.h" - -#include "ftglue.h" - - - /*************************** - * Script related functions - ***************************/ - - - /* LangSys */ - - static FT_Error Load_LangSys( TTO_LangSys* ls, - FT_Stream stream ) - { - FT_Error error; - FT_Memory memory = stream->memory; - FT_UShort n, count; - FT_UShort* fi; - - - if ( ACCESS_Frame( 6L ) ) - return error; - - ls->LookupOrderOffset = GET_UShort(); /* should be 0 */ - ls->ReqFeatureIndex = GET_UShort(); - count = ls->FeatureCount = GET_UShort(); - - FORGET_Frame(); - - ls->FeatureIndex = NULL; - - if ( ALLOC_ARRAY( ls->FeatureIndex, count, FT_UShort ) ) - return error; - - if ( ACCESS_Frame( count * 2L ) ) - { - FREE( ls->FeatureIndex ); - return error; - } - - fi = ls->FeatureIndex; - - for ( n = 0; n < count; n++ ) - fi[n] = GET_UShort(); - - FORGET_Frame(); - - return TT_Err_Ok; - } - - - static void Free_LangSys( TTO_LangSys* ls, - FT_Memory memory ) - { - FREE( ls->FeatureIndex ); - } - - - /* Script */ - - static FT_Error Load_Script( TTO_Script* s, - FT_Stream stream ) - { - FT_Error error; - FT_Memory memory = stream->memory; - FT_UShort n, m, count; - FT_ULong cur_offset, new_offset, base_offset; - - TTO_LangSysRecord* lsr; - - - base_offset = FILE_Pos(); - - if ( ACCESS_Frame( 2L ) ) - return error; - - new_offset = GET_UShort() + base_offset; - - FORGET_Frame(); - - if ( new_offset != base_offset ) /* not a NULL offset */ - { - cur_offset = FILE_Pos(); - if ( FILE_Seek( new_offset ) || - ( error = Load_LangSys( &s->DefaultLangSys, - stream ) ) != TT_Err_Ok ) - return error; - (void)FILE_Seek( cur_offset ); - } - else - { - /* we create a DefaultLangSys table with no entries */ - - s->DefaultLangSys.LookupOrderOffset = 0; - s->DefaultLangSys.ReqFeatureIndex = 0xFFFF; - s->DefaultLangSys.FeatureCount = 0; - s->DefaultLangSys.FeatureIndex = NULL; - } - - if ( ACCESS_Frame( 2L ) ) - goto Fail2; - - count = s->LangSysCount = GET_UShort(); - - /* safety check; otherwise the official handling of TrueType Open - fonts won't work */ - - if ( s->LangSysCount == 0 && s->DefaultLangSys.FeatureCount == 0 ) - { - error = TTO_Err_Empty_Script; - goto Fail2; - } - - FORGET_Frame(); - - s->LangSysRecord = NULL; - - if ( ALLOC_ARRAY( s->LangSysRecord, count, TTO_LangSysRecord ) ) - goto Fail2; - - lsr = s->LangSysRecord; - - for ( n = 0; n < count; n++ ) - { - if ( ACCESS_Frame( 6L ) ) - goto Fail1; - - lsr[n].LangSysTag = GET_ULong(); - new_offset = GET_UShort() + base_offset; - - FORGET_Frame(); - - cur_offset = FILE_Pos(); - if ( FILE_Seek( new_offset ) || - ( error = Load_LangSys( &lsr[n].LangSys, stream ) ) != TT_Err_Ok ) - goto Fail1; - (void)FILE_Seek( cur_offset ); - } - - return TT_Err_Ok; - - Fail1: - for ( m = 0; m < n; m++ ) - Free_LangSys( &lsr[m].LangSys, memory ); - - FREE( s->LangSysRecord ); - - Fail2: - Free_LangSys( &s->DefaultLangSys, memory ); - return error; - } - - - static void Free_Script( TTO_Script* s, - FT_Memory memory ) - { - FT_UShort n, count; - - TTO_LangSysRecord* lsr; - - - Free_LangSys( &s->DefaultLangSys, memory ); - - if ( s->LangSysRecord ) - { - count = s->LangSysCount; - lsr = s->LangSysRecord; - - for ( n = 0; n < count; n++ ) - Free_LangSys( &lsr[n].LangSys, memory ); - - FREE( lsr ); - } - } - - - /* ScriptList */ - - FT_Error Load_ScriptList( TTO_ScriptList* sl, - FT_Stream stream ) - { - FT_Error error; - FT_Memory memory = stream->memory; - - FT_UShort n, script_count; - FT_ULong cur_offset, new_offset, base_offset; - - TTO_ScriptRecord* sr; - - - base_offset = FILE_Pos(); - - if ( ACCESS_Frame( 2L ) ) - return error; - - script_count = GET_UShort(); - - FORGET_Frame(); - - sl->ScriptRecord = NULL; - - if ( ALLOC_ARRAY( sl->ScriptRecord, script_count, TTO_ScriptRecord ) ) - return error; - - sr = sl->ScriptRecord; - - sl->ScriptCount= 0; - for ( n = 0; n < script_count; n++ ) - { - if ( ACCESS_Frame( 6L ) ) - goto Fail; - - sr[sl->ScriptCount].ScriptTag = GET_ULong(); - new_offset = GET_UShort() + base_offset; - - FORGET_Frame(); - - cur_offset = FILE_Pos(); - - if ( FILE_Seek( new_offset ) ) - goto Fail; - - error = Load_Script( &sr[sl->ScriptCount].Script, stream ); - if ( error == TT_Err_Ok ) - sl->ScriptCount += 1; - else if ( error != TTO_Err_Empty_Script ) - goto Fail; - - (void)FILE_Seek( cur_offset ); - } - - if ( sl->ScriptCount == 0 ) - { - error = TTO_Err_Invalid_SubTable; - goto Fail; - } - - return TT_Err_Ok; - - Fail: - for ( n = 0; n < sl->ScriptCount; n++ ) - Free_Script( &sr[n].Script, memory ); - - FREE( sl->ScriptRecord ); - return error; - } - - - void Free_ScriptList( TTO_ScriptList* sl, - FT_Memory memory ) - { - FT_UShort n, count; - - TTO_ScriptRecord* sr; - - - if ( sl->ScriptRecord ) - { - count = sl->ScriptCount; - sr = sl->ScriptRecord; - - for ( n = 0; n < count; n++ ) - Free_Script( &sr[n].Script, memory ); - - FREE( sr ); - } - } - - - - /********************************* - * Feature List related functions - *********************************/ - - - /* Feature */ - - static FT_Error Load_Feature( TTO_Feature* f, - FT_Stream stream ) - { - FT_Error error; - FT_Memory memory = stream->memory; - - FT_UShort n, count; - - FT_UShort* lli; - - - if ( ACCESS_Frame( 4L ) ) - return error; - - f->FeatureParams = GET_UShort(); /* should be 0 */ - count = f->LookupListCount = GET_UShort(); - - FORGET_Frame(); - - f->LookupListIndex = NULL; - - if ( ALLOC_ARRAY( f->LookupListIndex, count, FT_UShort ) ) - return error; - - lli = f->LookupListIndex; - - if ( ACCESS_Frame( count * 2L ) ) - { - FREE( f->LookupListIndex ); - return error; - } - - for ( n = 0; n < count; n++ ) - lli[n] = GET_UShort(); - - FORGET_Frame(); - - return TT_Err_Ok; - } - - - static void Free_Feature( TTO_Feature* f, - FT_Memory memory ) - { - FREE( f->LookupListIndex ); - } - - - /* FeatureList */ - - FT_Error Load_FeatureList( TTO_FeatureList* fl, - FT_Stream stream ) - { - FT_Error error; - FT_Memory memory = stream->memory; - - FT_UShort n, m, count; - FT_ULong cur_offset, new_offset, base_offset; - - TTO_FeatureRecord* fr; - - - base_offset = FILE_Pos(); - - if ( ACCESS_Frame( 2L ) ) - return error; - - count = fl->FeatureCount = GET_UShort(); - - FORGET_Frame(); - - fl->FeatureRecord = NULL; - - if ( ALLOC_ARRAY( fl->FeatureRecord, count, TTO_FeatureRecord ) ) - return error; - if ( ALLOC_ARRAY( fl->ApplyOrder, count, FT_UShort ) ) - goto Fail2; - - fl->ApplyCount = 0; - - fr = fl->FeatureRecord; - - for ( n = 0; n < count; n++ ) - { - if ( ACCESS_Frame( 6L ) ) - goto Fail1; - - fr[n].FeatureTag = GET_ULong(); - new_offset = GET_UShort() + base_offset; - - FORGET_Frame(); - - cur_offset = FILE_Pos(); - if ( FILE_Seek( new_offset ) || - ( error = Load_Feature( &fr[n].Feature, stream ) ) != TT_Err_Ok ) - goto Fail1; - (void)FILE_Seek( cur_offset ); - } - - return TT_Err_Ok; - - Fail1: - for ( m = 0; m < n; m++ ) - Free_Feature( &fr[m].Feature, memory ); - - FREE( fl->ApplyOrder ); - - Fail2: - FREE( fl->FeatureRecord ); - - return error; - } - - - void Free_FeatureList( TTO_FeatureList* fl, - FT_Memory memory) - { - FT_UShort n, count; - - TTO_FeatureRecord* fr; - - - if ( fl->FeatureRecord ) - { - count = fl->FeatureCount; - fr = fl->FeatureRecord; - - for ( n = 0; n < count; n++ ) - Free_Feature( &fr[n].Feature, memory ); - - FREE( fr ); - } - - FREE( fl->ApplyOrder ); - } - - - - /******************************** - * Lookup List related functions - ********************************/ - - /* the subroutines of the following two functions are defined in - ftxgsub.c and ftxgpos.c respectively */ - - - /* SubTable */ - - static FT_Error Load_SubTable( TTO_SubTable* st, - FT_Stream stream, - TTO_Type table_type, - FT_UShort lookup_type ) - { - if ( table_type == GSUB ) - switch ( lookup_type ) - { - case GSUB_LOOKUP_SINGLE: - return Load_SingleSubst( &st->st.gsub.single, stream ); - - case GSUB_LOOKUP_MULTIPLE: - return Load_MultipleSubst( &st->st.gsub.multiple, stream ); - - case GSUB_LOOKUP_ALTERNATE: - return Load_AlternateSubst( &st->st.gsub.alternate, stream ); - - case GSUB_LOOKUP_LIGATURE: - return Load_LigatureSubst( &st->st.gsub.ligature, stream ); - - case GSUB_LOOKUP_CONTEXT: - return Load_ContextSubst( &st->st.gsub.context, stream ); - - case GSUB_LOOKUP_CHAIN: - return Load_ChainContextSubst( &st->st.gsub.chain, stream ); - - case GSUB_LOOKUP_REVERSE_CHAIN: - return Load_ReverseChainContextSubst( &st->st.gsub.reverse, stream ); - - default: - return TTO_Err_Invalid_GSUB_SubTable_Format; - } - else - switch ( lookup_type ) - { - case GPOS_LOOKUP_SINGLE: - return Load_SinglePos( &st->st.gpos.single, stream ); - - case GPOS_LOOKUP_PAIR: - return Load_PairPos( &st->st.gpos.pair, stream ); - - case GPOS_LOOKUP_CURSIVE: - return Load_CursivePos( &st->st.gpos.cursive, stream ); - - case GPOS_LOOKUP_MARKBASE: - return Load_MarkBasePos( &st->st.gpos.markbase, stream ); - - case GPOS_LOOKUP_MARKLIG: - return Load_MarkLigPos( &st->st.gpos.marklig, stream ); - - case GPOS_LOOKUP_MARKMARK: - return Load_MarkMarkPos( &st->st.gpos.markmark, stream ); - - case GPOS_LOOKUP_CONTEXT: - return Load_ContextPos( &st->st.gpos.context, stream ); - - case GPOS_LOOKUP_CHAIN: - return Load_ChainContextPos( &st->st.gpos.chain, stream ); - - default: - return TTO_Err_Invalid_GPOS_SubTable_Format; - } - - return TT_Err_Ok; /* never reached */ - } - - - static void Free_SubTable( TTO_SubTable* st, - TTO_Type table_type, - FT_UShort lookup_type, - FT_Memory memory ) - { - if ( table_type == GSUB ) - switch ( lookup_type ) - { - case GSUB_LOOKUP_SINGLE: - Free_SingleSubst( &st->st.gsub.single, memory ); - break; - - case GSUB_LOOKUP_MULTIPLE: - Free_MultipleSubst( &st->st.gsub.multiple, memory ); - break; - - case GSUB_LOOKUP_ALTERNATE: - Free_AlternateSubst( &st->st.gsub.alternate, memory ); - break; - - case GSUB_LOOKUP_LIGATURE: - Free_LigatureSubst( &st->st.gsub.ligature, memory ); - break; - - case GSUB_LOOKUP_CONTEXT: - Free_ContextSubst( &st->st.gsub.context, memory ); - break; - - case GSUB_LOOKUP_REVERSE_CHAIN: - Free_ReverseChainContextSubst( &st->st.gsub.reverse, memory ); - break; - - case GSUB_LOOKUP_CHAIN: - Free_ChainContextSubst( &st->st.gsub.chain, memory ); - break; - } - else - switch ( lookup_type ) - { - case GPOS_LOOKUP_SINGLE: - Free_SinglePos( &st->st.gpos.single, memory ); - break; - - case GPOS_LOOKUP_PAIR: - Free_PairPos( &st->st.gpos.pair, memory ); - break; - - case GPOS_LOOKUP_CURSIVE: - Free_CursivePos( &st->st.gpos.cursive, memory ); - break; - - case GPOS_LOOKUP_MARKBASE: - Free_MarkBasePos( &st->st.gpos.markbase, memory ); - break; - - case GPOS_LOOKUP_MARKLIG: - Free_MarkLigPos( &st->st.gpos.marklig, memory ); - break; - - case GPOS_LOOKUP_MARKMARK: - Free_MarkMarkPos( &st->st.gpos.markmark, memory ); - break; - - case GPOS_LOOKUP_CONTEXT: - Free_ContextPos( &st->st.gpos.context, memory ); - break; - - case GPOS_LOOKUP_CHAIN: - Free_ChainContextPos ( &st->st.gpos.chain, memory ); - break; - } - } - - - /* Lookup */ - - static FT_Error Load_Lookup( TTO_Lookup* l, - FT_Stream stream, - TTO_Type type ) - { - FT_Error error; - FT_Memory memory = stream->memory; - - FT_UShort n, m, count; - FT_ULong cur_offset, new_offset, base_offset; - - TTO_SubTable* st; - - FT_Bool is_extension = FALSE; - - - base_offset = FILE_Pos(); - - if ( ACCESS_Frame( 6L ) ) - return error; - - l->LookupType = GET_UShort(); - l->LookupFlag = GET_UShort(); - count = l->SubTableCount = GET_UShort(); - - FORGET_Frame(); - - l->SubTable = NULL; - - if ( ALLOC_ARRAY( l->SubTable, count, TTO_SubTable ) ) - return error; - - st = l->SubTable; - - if ( ( type == GSUB && l->LookupType == GSUB_LOOKUP_EXTENSION ) || - ( type == GPOS && l->LookupType == GPOS_LOOKUP_EXTENSION ) ) - is_extension = TRUE; - - for ( n = 0; n < count; n++ ) - { - if ( ACCESS_Frame( 2L ) ) - goto Fail; - - new_offset = GET_UShort() + base_offset; - - FORGET_Frame(); - - cur_offset = FILE_Pos(); - - if ( is_extension ) - { - if ( FILE_Seek( new_offset ) || ACCESS_Frame( 8L ) ) - goto Fail; - - if (GET_UShort() != 1) /* format should be 1 */ - goto Fail; - - l->LookupType = GET_UShort(); - new_offset += GET_ULong(); - - FORGET_Frame(); - } - - if ( FILE_Seek( new_offset ) || - ( error = Load_SubTable( &st[n], stream, - type, l->LookupType ) ) != TT_Err_Ok ) - goto Fail; - (void)FILE_Seek( cur_offset ); - } - - return TT_Err_Ok; - - Fail: - for ( m = 0; m < n; m++ ) - Free_SubTable( &st[m], type, l->LookupType, memory ); - - FREE( l->SubTable ); - return error; - } - - - static void Free_Lookup( TTO_Lookup* l, - TTO_Type type, - FT_Memory memory) - { - FT_UShort n, count; - - TTO_SubTable* st; - - - if ( l->SubTable ) - { - count = l->SubTableCount; - st = l->SubTable; - - for ( n = 0; n < count; n++ ) - Free_SubTable( &st[n], type, l->LookupType, memory ); - - FREE( st ); - } - } - - - /* LookupList */ - - FT_Error Load_LookupList( TTO_LookupList* ll, - FT_Stream stream, - TTO_Type type ) - { - FT_Error error; - FT_Memory memory = stream->memory; - - FT_UShort n, m, count; - FT_ULong cur_offset, new_offset, base_offset; - - TTO_Lookup* l; - - - base_offset = FILE_Pos(); - - if ( ACCESS_Frame( 2L ) ) - return error; - - count = ll->LookupCount = GET_UShort(); - - FORGET_Frame(); - - ll->Lookup = NULL; - - if ( ALLOC_ARRAY( ll->Lookup, count, TTO_Lookup ) ) - return error; - if ( ALLOC_ARRAY( ll->Properties, count, FT_UInt ) ) - goto Fail2; - - l = ll->Lookup; - - for ( n = 0; n < count; n++ ) - { - if ( ACCESS_Frame( 2L ) ) - goto Fail1; - - new_offset = GET_UShort() + base_offset; - - FORGET_Frame(); - - cur_offset = FILE_Pos(); - if ( FILE_Seek( new_offset ) || - ( error = Load_Lookup( &l[n], stream, type ) ) != TT_Err_Ok ) - goto Fail1; - (void)FILE_Seek( cur_offset ); - } - - return TT_Err_Ok; - - Fail1: - FREE( ll->Properties ); - - for ( m = 0; m < n; m++ ) - Free_Lookup( &l[m], type, memory ); - - Fail2: - FREE( ll->Lookup ); - return error; - } - - - void Free_LookupList( TTO_LookupList* ll, - TTO_Type type, - FT_Memory memory ) - { - FT_UShort n, count; - - TTO_Lookup* l; - - - FREE( ll->Properties ); - - if ( ll->Lookup ) - { - count = ll->LookupCount; - l = ll->Lookup; - - for ( n = 0; n < count; n++ ) - Free_Lookup( &l[n], type, memory ); - - FREE( l ); - } - } - - - - /***************************** - * Coverage related functions - *****************************/ - - - /* CoverageFormat1 */ - - static FT_Error Load_Coverage1( TTO_CoverageFormat1* cf1, - FT_Stream stream ) - { - FT_Error error; - FT_Memory memory = stream->memory; - - FT_UShort n, count; - - FT_UShort* ga; - - - if ( ACCESS_Frame( 2L ) ) - return error; - - count = cf1->GlyphCount = GET_UShort(); - - FORGET_Frame(); - - cf1->GlyphArray = NULL; - - if ( ALLOC_ARRAY( cf1->GlyphArray, count, FT_UShort ) ) - return error; - - ga = cf1->GlyphArray; - - if ( ACCESS_Frame( count * 2L ) ) - { - FREE( cf1->GlyphArray ); - return error; - } - - for ( n = 0; n < count; n++ ) - ga[n] = GET_UShort(); - - FORGET_Frame(); - - return TT_Err_Ok; - } - - - static void Free_Coverage1( TTO_CoverageFormat1* cf1, - FT_Memory memory) - { - FREE( cf1->GlyphArray ); - } - - - /* CoverageFormat2 */ - - static FT_Error Load_Coverage2( TTO_CoverageFormat2* cf2, - FT_Stream stream ) - { - FT_Error error; - FT_Memory memory = stream->memory; - - FT_UShort n, count; - - TTO_RangeRecord* rr; - - - if ( ACCESS_Frame( 2L ) ) - return error; - - count = cf2->RangeCount = GET_UShort(); - - FORGET_Frame(); - - cf2->RangeRecord = NULL; - - if ( ALLOC_ARRAY( cf2->RangeRecord, count, TTO_RangeRecord ) ) - return error; - - rr = cf2->RangeRecord; - - if ( ACCESS_Frame( count * 6L ) ) - goto Fail; - - for ( n = 0; n < count; n++ ) - { - rr[n].Start = GET_UShort(); - rr[n].End = GET_UShort(); - rr[n].StartCoverageIndex = GET_UShort(); - - /* sanity check; we are limited to 16bit integers */ - if ( rr[n].Start > rr[n].End || - ( rr[n].End - rr[n].Start + (long)rr[n].StartCoverageIndex ) >= - 0x10000L ) - { - error = TTO_Err_Invalid_SubTable; - goto Fail; - } - } - - FORGET_Frame(); - - return TT_Err_Ok; - - Fail: - FREE( cf2->RangeRecord ); - return error; - } - - - static void Free_Coverage2( TTO_CoverageFormat2* cf2, - FT_Memory memory ) - { - FREE( cf2->RangeRecord ); - } - - - FT_Error Load_Coverage( TTO_Coverage* c, - FT_Stream stream ) - { - FT_Error error; - - if ( ACCESS_Frame( 2L ) ) - return error; - - c->CoverageFormat = GET_UShort(); - - FORGET_Frame(); - - switch ( c->CoverageFormat ) - { - case 1: - return Load_Coverage1( &c->cf.cf1, stream ); - - case 2: - return Load_Coverage2( &c->cf.cf2, stream ); - - default: - return TTO_Err_Invalid_SubTable_Format; - } - - return TT_Err_Ok; /* never reached */ - } - - - void Free_Coverage( TTO_Coverage* c, - FT_Memory memory ) - { - switch ( c->CoverageFormat ) - { - case 1: - Free_Coverage1( &c->cf.cf1, memory ); - break; - - case 2: - Free_Coverage2( &c->cf.cf2, memory ); - break; - } - } - - - static FT_Error Coverage_Index1( TTO_CoverageFormat1* cf1, - FT_UShort glyphID, - FT_UShort* index ) - { - FT_UShort min, max, new_min, new_max, middle; - - FT_UShort* array = cf1->GlyphArray; - - - /* binary search */ - - if ( cf1->GlyphCount == 0 ) - return TTO_Err_Not_Covered; - - new_min = 0; - new_max = cf1->GlyphCount - 1; - - do - { - min = new_min; - max = new_max; - - /* we use (min + max) / 2 = max - (max - min) / 2 to avoid - overflow and rounding errors */ - - middle = max - ( ( max - min ) >> 1 ); - - if ( glyphID == array[middle] ) - { - *index = middle; - return TT_Err_Ok; - } - else if ( glyphID < array[middle] ) - { - if ( middle == min ) - break; - new_max = middle - 1; - } - else - { - if ( middle == max ) - break; - new_min = middle + 1; - } - } while ( min < max ); - - return TTO_Err_Not_Covered; - } - - - static FT_Error Coverage_Index2( TTO_CoverageFormat2* cf2, - FT_UShort glyphID, - FT_UShort* index ) - { - FT_UShort min, max, new_min, new_max, middle; - - TTO_RangeRecord* rr = cf2->RangeRecord; - - - /* binary search */ - - if ( cf2->RangeCount == 0 ) - return TTO_Err_Not_Covered; - - new_min = 0; - new_max = cf2->RangeCount - 1; - - do - { - min = new_min; - max = new_max; - - /* we use (min + max) / 2 = max - (max - min) / 2 to avoid - overflow and rounding errors */ - - middle = max - ( ( max - min ) >> 1 ); - - if ( glyphID >= rr[middle].Start && glyphID <= rr[middle].End ) - { - *index = rr[middle].StartCoverageIndex + glyphID - rr[middle].Start; - return TT_Err_Ok; - } - else if ( glyphID < rr[middle].Start ) - { - if ( middle == min ) - break; - new_max = middle - 1; - } - else - { - if ( middle == max ) - break; - new_min = middle + 1; - } - } while ( min < max ); - - return TTO_Err_Not_Covered; - } - - - FT_Error Coverage_Index( TTO_Coverage* c, - FT_UShort glyphID, - FT_UShort* index ) - { - switch ( c->CoverageFormat ) - { - case 1: - return Coverage_Index1( &c->cf.cf1, glyphID, index ); - - case 2: - return Coverage_Index2( &c->cf.cf2, glyphID, index ); - - default: - return TTO_Err_Invalid_SubTable_Format; - } - - return TT_Err_Ok; /* never reached */ - } - - - - /************************************* - * Class Definition related functions - *************************************/ - - - /* ClassDefFormat1 */ - - static FT_Error Load_ClassDef1( TTO_ClassDefinition* cd, - FT_UShort limit, - FT_Stream stream ) - { - FT_Error error; - FT_Memory memory = stream->memory; - - FT_UShort n, count; - - FT_UShort* cva; - FT_Bool* d; - - TTO_ClassDefFormat1* cdf1; - - - cdf1 = &cd->cd.cd1; - - if ( ACCESS_Frame( 4L ) ) - return error; - - cdf1->StartGlyph = GET_UShort(); - count = cdf1->GlyphCount = GET_UShort(); - - FORGET_Frame(); - - /* sanity check; we are limited to 16bit integers */ - - if ( cdf1->StartGlyph + (long)count >= 0x10000L ) - return TTO_Err_Invalid_SubTable; - - cdf1->ClassValueArray = NULL; - - if ( ALLOC_ARRAY( cdf1->ClassValueArray, count, FT_UShort ) ) - return error; - - d = cd->Defined; - cva = cdf1->ClassValueArray; - - if ( ACCESS_Frame( count * 2L ) ) - goto Fail; - - for ( n = 0; n < count; n++ ) - { - cva[n] = GET_UShort(); - if ( cva[n] >= limit ) - { - error = TTO_Err_Invalid_SubTable; - goto Fail; - } - d[cva[n]] = TRUE; - } - - FORGET_Frame(); - - return TT_Err_Ok; - - Fail: - FREE( cva ); - - return error; - } - - - static void Free_ClassDef1( TTO_ClassDefFormat1* cdf1, - FT_Memory memory ) - { - FREE( cdf1->ClassValueArray ); - } - - - /* ClassDefFormat2 */ - - static FT_Error Load_ClassDef2( TTO_ClassDefinition* cd, - FT_UShort limit, - FT_Stream stream ) - { - FT_Error error; - FT_Memory memory = stream->memory; - - FT_UShort n, count; - - TTO_ClassRangeRecord* crr; - FT_Bool* d; - - TTO_ClassDefFormat2* cdf2; - - - cdf2 = &cd->cd.cd2; - - if ( ACCESS_Frame( 2L ) ) - return error; - - count = cdf2->ClassRangeCount = GET_UShort(); - - FORGET_Frame(); - - cdf2->ClassRangeRecord = NULL; - - if ( ALLOC_ARRAY( cdf2->ClassRangeRecord, count, TTO_ClassRangeRecord ) ) - return error; - - d = cd->Defined; - crr = cdf2->ClassRangeRecord; - - if ( ACCESS_Frame( count * 6L ) ) - goto Fail; - - for ( n = 0; n < count; n++ ) - { - crr[n].Start = GET_UShort(); - crr[n].End = GET_UShort(); - crr[n].Class = GET_UShort(); - - /* sanity check */ - - if ( crr[n].Start > crr[n].End || - crr[n].Class >= limit ) - { - error = TTO_Err_Invalid_SubTable; - goto Fail; - } - d[crr[n].Class] = TRUE; - } - - FORGET_Frame(); - - return TT_Err_Ok; - - Fail: - FREE( crr ); - - return error; - } - - - static void Free_ClassDef2( TTO_ClassDefFormat2* cdf2, - FT_Memory memory ) - { - FREE( cdf2->ClassRangeRecord ); - } - - - /* ClassDefinition */ - - FT_Error Load_ClassDefinition( TTO_ClassDefinition* cd, - FT_UShort limit, - FT_Stream stream ) - { - FT_Error error; - FT_Memory memory = stream->memory; - - - if ( ALLOC_ARRAY( cd->Defined, limit, FT_Bool ) ) - return error; - - if ( ACCESS_Frame( 2L ) ) - goto Fail; - - cd->ClassFormat = GET_UShort(); - - FORGET_Frame(); - - switch ( cd->ClassFormat ) - { - case 1: - error = Load_ClassDef1( cd, limit, stream ); - break; - - case 2: - error = Load_ClassDef2( cd, limit, stream ); - break; - - default: - error = TTO_Err_Invalid_SubTable_Format; - break; - } - - if ( error ) - goto Fail; - - cd->loaded = TRUE; - - return TT_Err_Ok; - - Fail: - FREE( cd->Defined ); - return error; - } - - - FT_Error Load_EmptyClassDefinition( TTO_ClassDefinition* cd, - FT_Stream stream ) - { - FT_Error error; - FT_Memory memory = stream->memory; - - - if ( ALLOC_ARRAY( cd->Defined, 1, FT_Bool ) ) - return error; - - cd->ClassFormat = 1; /* Meaningless */ - cd->Defined[0] = FALSE; - - if ( ALLOC_ARRAY( cd->cd.cd1.ClassValueArray, 1, FT_UShort ) ) - goto Fail; - - return TT_Err_Ok; - - Fail: - FREE( cd->Defined ); - return error; - } - - void Free_ClassDefinition( TTO_ClassDefinition* cd, - FT_Memory memory ) - { - if ( !cd->loaded ) - return; - - FREE( cd->Defined ); - - switch ( cd->ClassFormat ) - { - case 1: - Free_ClassDef1( &cd->cd.cd1, memory ); - break; - - case 2: - Free_ClassDef2( &cd->cd.cd2, memory ); - break; - } - } - - - static FT_Error Get_Class1( TTO_ClassDefFormat1* cdf1, - FT_UShort glyphID, - FT_UShort* class, - FT_UShort* index ) - { - FT_UShort* cva = cdf1->ClassValueArray; - - - if ( index ) - *index = 0; - - if ( glyphID >= cdf1->StartGlyph && - glyphID <= cdf1->StartGlyph + cdf1->GlyphCount ) - { - *class = cva[glyphID - cdf1->StartGlyph]; - return TT_Err_Ok; - } - else - { - *class = 0; - return TTO_Err_Not_Covered; - } - } - - - /* we need the index value of the last searched class range record - in case of failure for constructed GDEF tables */ - - static FT_Error Get_Class2( TTO_ClassDefFormat2* cdf2, - FT_UShort glyphID, - FT_UShort* class, - FT_UShort* index ) - { - FT_Error error = TT_Err_Ok; - FT_UShort min, max, new_min, new_max, middle; - - TTO_ClassRangeRecord* crr = cdf2->ClassRangeRecord; - - - /* binary search */ - - if ( cdf2->ClassRangeCount == 0 ) - { - *class = 0; - if ( index ) - *index = 0; - - return TTO_Err_Not_Covered; - } - - new_min = 0; - new_max = cdf2->ClassRangeCount - 1; - - do - { - min = new_min; - max = new_max; - - /* we use (min + max) / 2 = max - (max - min) / 2 to avoid - overflow and rounding errors */ - - middle = max - ( ( max - min ) >> 1 ); - - if ( glyphID >= crr[middle].Start && glyphID <= crr[middle].End ) - { - *class = crr[middle].Class; - error = TT_Err_Ok; - break; - } - else if ( glyphID < crr[middle].Start ) - { - if ( middle == min ) - { - *class = 0; - error = TTO_Err_Not_Covered; - break; - } - new_max = middle - 1; - } - else - { - if ( middle == max ) - { - *class = 0; - error = TTO_Err_Not_Covered; - break; - } - new_min = middle + 1; - } - } while ( min < max ); - - if ( index ) - *index = middle; - - return error; - } - - - FT_Error Get_Class( TTO_ClassDefinition* cd, - FT_UShort glyphID, - FT_UShort* class, - FT_UShort* index ) - { - switch ( cd->ClassFormat ) - { - case 1: - return Get_Class1( &cd->cd.cd1, glyphID, class, index ); - - case 2: - return Get_Class2( &cd->cd.cd2, glyphID, class, index ); - - default: - return TTO_Err_Invalid_SubTable_Format; - } - - return TT_Err_Ok; /* never reached */ - } - - - - /*************************** - * Device related functions - ***************************/ - - - FT_Error Load_Device( TTO_Device* d, - FT_Stream stream ) - { - FT_Error error; - FT_Memory memory = stream->memory; - - FT_UShort n, count; - - FT_UShort* dv; - - - if ( ACCESS_Frame( 6L ) ) - return error; - - d->StartSize = GET_UShort(); - d->EndSize = GET_UShort(); - d->DeltaFormat = GET_UShort(); - - FORGET_Frame(); - - if ( d->StartSize > d->EndSize || - d->DeltaFormat == 0 || d->DeltaFormat > 3 ) - return TTO_Err_Invalid_SubTable; - - d->DeltaValue = NULL; - - count = ( ( d->EndSize - d->StartSize + 1 ) >> - ( 4 - d->DeltaFormat ) ) + 1; - - if ( ALLOC_ARRAY( d->DeltaValue, count, FT_UShort ) ) - return error; - - if ( ACCESS_Frame( count * 2L ) ) - { - FREE( d->DeltaValue ); - return error; - } - - dv = d->DeltaValue; - - for ( n = 0; n < count; n++ ) - dv[n] = GET_UShort(); - - FORGET_Frame(); - - return TT_Err_Ok; - } - - - void Free_Device( TTO_Device* d, - FT_Memory memory ) - { - FREE( d->DeltaValue ); - } - - - /* Since we have the delta values stored in compressed form, we must - uncompress it now. To simplify the interface, the function always - returns a meaningful value in `value'; the error is just for - information. - | | - format = 1: 0011223344556677|8899101112131415|... - | | - byte 1 byte 2 - - 00: (byte >> 14) & mask - 11: (byte >> 12) & mask - ... - - mask = 0x0003 - | | - format = 2: 0000111122223333|4444555566667777|... - | | - byte 1 byte 2 - - 0000: (byte >> 12) & mask - 1111: (byte >> 8) & mask - ... - - mask = 0x000F - | | - format = 3: 0000000011111111|2222222233333333|... - | | - byte 1 byte 2 - - 00000000: (byte >> 8) & mask - 11111111: (byte >> 0) & mask - .... - - mask = 0x00FF */ - - FT_Error Get_Device( TTO_Device* d, - FT_UShort size, - FT_Short* value ) - { - FT_UShort byte, bits, mask, f, s; - - - f = d->DeltaFormat; - - if ( d->DeltaValue && size >= d->StartSize && size <= d->EndSize ) - { - s = size - d->StartSize; - byte = d->DeltaValue[s >> ( 4 - f )]; - bits = byte >> ( 16 - ( ( s % ( 1 << ( 4 - f ) ) + 1 ) << f ) ); - mask = 0xFFFF >> ( 16 - ( 1 << f ) ); - - *value = (FT_Short)( bits & mask ); - - /* conversion to a signed value */ - - if ( *value >= ( ( mask + 1 ) >> 1 ) ) - *value -= mask + 1; - - return TT_Err_Ok; - } - else - { - *value = 0; - return TTO_Err_Not_Covered; - } - } - - -/* END */ diff --git a/src/ftxopen.h b/src/ftxopen.h deleted file mode 100644 index 64d2820..0000000 --- a/src/ftxopen.h +++ /dev/null @@ -1,317 +0,0 @@ -/******************************************************************* - * - * ftxopen.h - * - * TrueType Open support. - * - * Copyright 1996-2000 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 should be included by the application. Nevertheless, - * the table specific APIs (and structures) are located in files like - * ftxgsub.h or ftxgpos.h; these header files are read by ftxopen.h . - * - ******************************************************************/ - -#ifndef FTXOPEN_H -#define FTXOPEN_H - -#include -#include FT_FREETYPE_H - -#ifdef __cplusplus -extern "C" { -#endif - -#define EXPORT_DEF -#define EXPORT_FUNC - -#define TTO_MAX_NESTING_LEVEL 100 - -#define TTO_Err_Invalid_SubTable_Format 0x1000 -#define TTO_Err_Invalid_SubTable 0x1001 -#define TTO_Err_Not_Covered 0x1002 -#define TTO_Err_Too_Many_Nested_Contexts 0x1003 -#define TTO_Err_No_MM_Interpreter 0x1004 -#define TTO_Err_Empty_Script 0x1005 - - - /* Script list related structures */ - - struct TTO_LangSys_ - { - FT_UShort LookupOrderOffset; /* always 0 for TT Open 1.0 */ - FT_UShort ReqFeatureIndex; /* required FeatureIndex */ - FT_UShort FeatureCount; /* number of Feature indices */ - FT_UShort* FeatureIndex; /* array of Feature indices */ - }; - - typedef struct TTO_LangSys_ TTO_LangSys; - - - struct TTO_LangSysRecord_ - { - FT_ULong LangSysTag; /* LangSysTag identifier */ - TTO_LangSys LangSys; /* LangSys table */ - }; - - typedef struct TTO_LangSysRecord_ TTO_LangSysRecord; - - - struct TTO_Script_ - { - TTO_LangSys DefaultLangSys; /* DefaultLangSys table */ - FT_UShort LangSysCount; /* number of LangSysRecords */ - TTO_LangSysRecord* LangSysRecord; /* array of LangSysRecords */ - }; - - typedef struct TTO_Script_ TTO_Script; - - - struct TTO_ScriptRecord_ - { - FT_ULong ScriptTag; /* ScriptTag identifier */ - TTO_Script Script; /* Script table */ - }; - - typedef struct TTO_ScriptRecord_ TTO_ScriptRecord; - - - struct TTO_ScriptList_ - { - FT_UShort ScriptCount; /* number of ScriptRecords */ - TTO_ScriptRecord* ScriptRecord; /* array of ScriptRecords */ - }; - - typedef struct TTO_ScriptList_ TTO_ScriptList; - - - /* Feature list related structures */ - - struct TTO_Feature_ - { - FT_UShort FeatureParams; /* always 0 for TT Open 1.0 */ - FT_UShort LookupListCount; /* number of LookupList indices */ - FT_UShort* LookupListIndex; /* array of LookupList indices */ - }; - - typedef struct TTO_Feature_ TTO_Feature; - - - struct TTO_FeatureRecord_ - { - FT_ULong FeatureTag; /* FeatureTag identifier */ - TTO_Feature Feature; /* Feature table */ - }; - - typedef struct TTO_FeatureRecord_ TTO_FeatureRecord; - - - struct TTO_FeatureList_ - { - FT_UShort FeatureCount; /* number of FeatureRecords */ - TTO_FeatureRecord* FeatureRecord; /* array of FeatureRecords */ - FT_UShort* ApplyOrder; /* order to apply features */ - FT_UShort ApplyCount; /* number of elements in ApplyOrder */ - }; - - typedef struct TTO_FeatureList_ TTO_FeatureList; - - - /* Lookup list related structures */ - - struct TTO_SubTable_; /* defined below after inclusion - of ftxgsub.h and ftxgpos.h */ - typedef struct TTO_SubTable_ TTO_SubTable; - - - struct TTO_Lookup_ - { - FT_UShort LookupType; /* Lookup type */ - FT_UShort LookupFlag; /* Lookup qualifiers */ - FT_UShort SubTableCount; /* number of SubTables */ - TTO_SubTable* SubTable; /* array of SubTables */ - }; - - typedef struct TTO_Lookup_ TTO_Lookup; - - - /* The `Properties' field is not defined in the TTO specification but - is needed for processing lookups. If properties[n] is > 0, the - functions TT_GSUB_Apply_String() resp. TT_GPOS_Apply_String() will - process Lookup[n] for glyphs which have the specific bit not set in - the `properties' field of the input string object. */ - - struct TTO_LookupList_ - { - FT_UShort LookupCount; /* number of Lookups */ - TTO_Lookup* Lookup; /* array of Lookup records */ - FT_UInt* Properties; /* array of flags */ - }; - - typedef struct TTO_LookupList_ TTO_LookupList; - - - /* Possible LookupFlag bit masks. `IGNORE_SPECIAL_MARKS' comes from the - OpenType 1.2 specification; RIGHT_TO_LEFT has been (re)introduced in - OpenType 1.3 -- if set, the last glyph in a cursive attachment - sequence has to be positioned on the baseline -- regardless of the - writing direction. */ - -#define RIGHT_TO_LEFT 0x0001 -#define IGNORE_BASE_GLYPHS 0x0002 -#define IGNORE_LIGATURES 0x0004 -#define IGNORE_MARKS 0x0008 -#define IGNORE_SPECIAL_MARKS 0xFF00 - - - struct TTO_CoverageFormat1_ - { - FT_UShort GlyphCount; /* number of glyphs in GlyphArray */ - FT_UShort* GlyphArray; /* array of glyph IDs */ - }; - - typedef struct TTO_CoverageFormat1_ TTO_CoverageFormat1; - - - struct TTO_RangeRecord_ - { - FT_UShort Start; /* first glyph ID in the range */ - FT_UShort End; /* last glyph ID in the range */ - FT_UShort StartCoverageIndex; /* coverage index of first - glyph ID in the range */ - }; - - typedef struct TTO_RangeRecord_ TTO_RangeRecord; - - - struct TTO_CoverageFormat2_ - { - FT_UShort RangeCount; /* number of RangeRecords */ - TTO_RangeRecord* RangeRecord; /* array of RangeRecords */ - }; - - typedef struct TTO_CoverageFormat2_ TTO_CoverageFormat2; - - - struct TTO_Coverage_ - { - FT_UShort CoverageFormat; /* 1 or 2 */ - - union - { - TTO_CoverageFormat1 cf1; - TTO_CoverageFormat2 cf2; - } cf; - }; - - typedef struct TTO_Coverage_ TTO_Coverage; - - - struct TTO_ClassDefFormat1_ - { - FT_UShort StartGlyph; /* first glyph ID of the - ClassValueArray */ - FT_UShort GlyphCount; /* size of the ClassValueArray */ - FT_UShort* ClassValueArray; /* array of class values */ - }; - - typedef struct TTO_ClassDefFormat1_ TTO_ClassDefFormat1; - - - struct TTO_ClassRangeRecord_ - { - FT_UShort Start; /* first glyph ID in the range */ - FT_UShort End; /* last glyph ID in the range */ - FT_UShort Class; /* applied to all glyphs in range */ - }; - - typedef struct TTO_ClassRangeRecord_ TTO_ClassRangeRecord; - - - struct TTO_ClassDefFormat2_ - { - FT_UShort ClassRangeCount; - /* number of ClassRangeRecords */ - TTO_ClassRangeRecord* ClassRangeRecord; - /* array of ClassRangeRecords */ - }; - - typedef struct TTO_ClassDefFormat2_ TTO_ClassDefFormat2; - - - /* The `Defined' field is not defined in the TTO specification but - apparently needed for processing fonts like trado.ttf: This font - refers to a class which contains not a single element. We map such - classes to class 0. */ - - struct TTO_ClassDefinition_ - { - FT_Bool loaded; - - FT_Bool* Defined; /* array of Booleans. - If Defined[n] is FALSE, - class n contains no glyphs. */ - FT_UShort ClassFormat; /* 1 or 2 */ - - union - { - TTO_ClassDefFormat1 cd1; - TTO_ClassDefFormat2 cd2; - } cd; - }; - - typedef struct TTO_ClassDefinition_ TTO_ClassDefinition; - - - struct TTO_Device_ - { - FT_UShort StartSize; /* smallest size to correct */ - FT_UShort EndSize; /* largest size to correct */ - FT_UShort DeltaFormat; /* DeltaValue array data format: - 1, 2, or 3 */ - FT_UShort* DeltaValue; /* array of compressed data */ - }; - - typedef struct TTO_Device_ TTO_Device; - - -#include "otlbuffer.h" -#include "ftxgdef.h" -#include "ftxgsub.h" -#include "ftxgpos.h" - - - struct TTO_SubTable_ - { - union - { - TTO_GSUB_SubTable gsub; - TTO_GPOS_SubTable gpos; - } st; - }; - - - enum TTO_Type_ - { - GSUB, - GPOS - }; - - typedef enum TTO_Type_ TTO_Type; - - -#ifdef __cplusplus -} -#endif - -#endif /* FTXOPEN_H */ - - -/* END */ diff --git a/src/ftxopenf.h b/src/ftxopenf.h deleted file mode 100644 index 2c274c3..0000000 --- a/src/ftxopenf.h +++ /dev/null @@ -1,166 +0,0 @@ -/******************************************************************* - * - * ftxopenf.h - * - * internal TrueType Open functions - * - * Copyright 1996-2000 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 FTXOPENF_H -#define FTXOPENF_H - -#include "ftxopen.h" - -#ifdef __cplusplus -extern "C" { -#endif - - /* functions from ftxopen.c */ - - FT_Error Load_ScriptList( TTO_ScriptList* sl, - FT_Stream stream ); - FT_Error Load_FeatureList( TTO_FeatureList* fl, - FT_Stream input ); - FT_Error Load_LookupList( TTO_LookupList* ll, - FT_Stream input, - TTO_Type type ); - - FT_Error Load_Coverage( TTO_Coverage* c, - FT_Stream input ); - FT_Error Load_ClassDefinition( TTO_ClassDefinition* cd, - FT_UShort limit, - FT_Stream input ); - FT_Error Load_EmptyClassDefinition( TTO_ClassDefinition* cd, - FT_Stream input ); - FT_Error Load_Device( TTO_Device* d, - FT_Stream input ); - - void Free_ScriptList( TTO_ScriptList* sl, - FT_Memory memory ); - void Free_FeatureList( TTO_FeatureList* fl, - FT_Memory memory ); - void Free_LookupList( TTO_LookupList* ll, - TTO_Type type, - FT_Memory memory ); - - void Free_Coverage( TTO_Coverage* c, - FT_Memory memory ); - void Free_ClassDefinition( TTO_ClassDefinition* cd, - FT_Memory memory ); - void Free_Device( TTO_Device* d, - FT_Memory memory ); - - - /* functions from ftxgsub.c */ - - FT_Error Load_SingleSubst( TTO_SingleSubst* ss, - FT_Stream input ); - FT_Error Load_MultipleSubst( TTO_MultipleSubst* ms, - FT_Stream input ); - FT_Error Load_AlternateSubst( TTO_AlternateSubst* as, - FT_Stream input ); - FT_Error Load_LigatureSubst( TTO_LigatureSubst* ls, - FT_Stream input ); - FT_Error Load_ContextSubst( TTO_ContextSubst* cs, - FT_Stream input ); - FT_Error Load_ChainContextSubst( TTO_ChainContextSubst* ccs, - FT_Stream input ); - FT_Error Load_ReverseChainContextSubst( TTO_ReverseChainContextSubst* rccs, - FT_Stream input ); - - void Free_SingleSubst( TTO_SingleSubst* ss, - FT_Memory memory ); - void Free_MultipleSubst( TTO_MultipleSubst* ms, - FT_Memory memory ); - void Free_AlternateSubst( TTO_AlternateSubst* as, - FT_Memory memory ); - void Free_LigatureSubst( TTO_LigatureSubst* ls, - FT_Memory memory ); - void Free_ContextSubst( TTO_ContextSubst* cs, - FT_Memory memory ); - void Free_ChainContextSubst( TTO_ChainContextSubst* ccs, - FT_Memory memory ); - void Free_ReverseChainContextSubst( TTO_ReverseChainContextSubst* rccs, - FT_Memory memory ); - - /* functions from ftxgpos.c */ - - FT_Error Load_SinglePos( TTO_SinglePos* sp, - FT_Stream input ); - FT_Error Load_PairPos( TTO_PairPos* pp, - FT_Stream input ); - FT_Error Load_CursivePos( TTO_CursivePos* cp, - FT_Stream input ); - FT_Error Load_MarkBasePos( TTO_MarkBasePos* mbp, - FT_Stream input ); - FT_Error Load_MarkLigPos( TTO_MarkLigPos* mlp, - FT_Stream input ); - FT_Error Load_MarkMarkPos( TTO_MarkMarkPos* mmp, - FT_Stream input ); - FT_Error Load_ContextPos( TTO_ContextPos* cp, - FT_Stream input ); - FT_Error Load_ChainContextPos( TTO_ChainContextPos* ccp, - FT_Stream input ); - - void Free_SinglePos( TTO_SinglePos* sp, - FT_Memory memory ); - void Free_PairPos( TTO_PairPos* pp, - FT_Memory memory ); - void Free_CursivePos( TTO_CursivePos* cp, - FT_Memory memory ); - void Free_MarkBasePos( TTO_MarkBasePos* mbp, - FT_Memory memory ); - void Free_MarkLigPos( TTO_MarkLigPos* mlp, - FT_Memory memory ); - void Free_MarkMarkPos( TTO_MarkMarkPos* mmp, - FT_Memory memory ); - void Free_ContextPos( TTO_ContextPos* cp, - FT_Memory memory ); - void Free_ChainContextPos( TTO_ChainContextPos* ccp, - FT_Memory memory ); - /* query functions */ - - FT_Error Coverage_Index( TTO_Coverage* c, - FT_UShort glyphID, - FT_UShort* index ); - FT_Error Get_Class( TTO_ClassDefinition* cd, - FT_UShort glyphID, - FT_UShort* class, - FT_UShort* index ); - FT_Error Get_Device( TTO_Device* d, - FT_UShort size, - FT_Short* value ); - - - /* functions from ftxgdef.c */ - - FT_Error Add_Glyph_Property( TTO_GDEFHeader* gdef, - FT_UShort glyphID, - FT_UShort property ); - - FT_Error Check_Property( TTO_GDEFHeader* gdef, - OTL_GlyphItem item, - FT_UShort flags, - FT_UShort* property ); - -#define CHECK_Property( gdef, index, flags, property ) \ - ( ( error = Check_Property( (gdef), (index), (flags), \ - (property) ) ) != TT_Err_Ok ) - -#ifdef __cplusplus -} -#endif - -#endif /* FTXOPENF_H */ - - -/* END */ diff --git a/src/harfbuzz-buffer.c b/src/harfbuzz-buffer.c new file mode 100644 index 0000000..3d233b4 --- /dev/null +++ b/src/harfbuzz-buffer.c @@ -0,0 +1,227 @@ +/* harfbuzz-buffer.c: Buffer of glyphs for substitution/positioning + * + * Copyright 2004 Red Hat Software + * + * Portions Copyright 1996-2000 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + */ + +#include "harfbuzz-impl.h" +#include "harfbuzz-buffer.h" +#include "harfbuzz-gsub-private.h" +#include "harfbuzz-gpos-private.h" + +static FT_Error +hb_buffer_ensure( HB_Buffer buffer, + FT_ULong size ) +{ + FT_Memory memory = buffer->memory; + FT_ULong new_allocated = buffer->allocated; + + if (size > new_allocated) + { + FT_Error error; + + while (size > new_allocated) + new_allocated += (new_allocated >> 1) + 8; + + if ( REALLOC_ARRAY( buffer->in_string, buffer->allocated, new_allocated, HB_GlyphItemRec ) ) + return error; + if ( REALLOC_ARRAY( buffer->out_string, buffer->allocated, new_allocated, HB_GlyphItemRec ) ) + return error; + if ( REALLOC_ARRAY( buffer->positions, buffer->allocated, new_allocated, HB_PositionRec ) ) + return error; + + buffer->allocated = new_allocated; + } + + return FT_Err_Ok; +} + +FT_Error +hb_buffer_new( FT_Memory memory, + HB_Buffer *buffer ) +{ + FT_Error error; + + if ( ALLOC( *buffer, sizeof( HB_BufferRec ) ) ) + return error; + + (*buffer)->memory = memory; + (*buffer)->in_length = 0; + (*buffer)->out_length = 0; + (*buffer)->allocated = 0; + (*buffer)->in_pos = 0; + (*buffer)->out_pos = 0; + + (*buffer)->in_string = NULL; + (*buffer)->out_string = NULL; + (*buffer)->positions = NULL; + (*buffer)->max_ligID = 0; + + return FT_Err_Ok; +} + +FT_Error +hb_buffer_swap( HB_Buffer buffer ) +{ + HB_GlyphItem tmp_string; + + tmp_string = buffer->in_string; + buffer->in_string = buffer->out_string; + buffer->out_string = tmp_string; + + buffer->in_length = buffer->out_length; + buffer->out_length = 0; + + buffer->in_pos = 0; + buffer->out_pos = 0; + + return FT_Err_Ok; +} + +FT_Error +hb_buffer_free( HB_Buffer buffer ) +{ + FT_Memory memory = buffer->memory; + + FREE( buffer->in_string ); + FREE( buffer->out_string ); + FREE( buffer->positions ); + FREE( buffer ); + + return FT_Err_Ok; +} + +FT_Error +hb_buffer_clear( HB_Buffer buffer ) +{ + buffer->in_length = 0; + buffer->out_length = 0; + buffer->in_pos = 0; + buffer->out_pos = 0; + + return FT_Err_Ok; +} + +FT_Error +hb_buffer_add_glyph( HB_Buffer buffer, + FT_UInt glyph_index, + FT_UInt properties, + FT_UInt cluster ) +{ + FT_Error error; + HB_GlyphItem glyph; + + error = hb_buffer_ensure( buffer, buffer->in_length + 1 ); + if ( error ) + return error; + + glyph = &buffer->in_string[buffer->in_length]; + glyph->gindex = glyph_index; + glyph->properties = properties; + glyph->cluster = cluster; + glyph->component = 0; + glyph->ligID = 0; + glyph->gproperties = HB_GLYPH_PROPERTIES_UNKNOWN; + + buffer->in_length++; + + return FT_Err_Ok; +} + +/* The following function copies `num_out' elements from `glyph_data' + to `buffer->out_string', advancing the in array pointer in the structure + by `num_in' elements, and the out array pointer by `num_out' elements. + Finally, it sets the `length' field of `out' equal to + `pos' of the `out' structure. + + If `component' is 0xFFFF, the component value from buffer->in_pos + will copied `num_out' times, otherwise `component' itself will + be used to fill the `component' fields. + + If `ligID' is 0xFFFF, the ligID value from buffer->in_pos + will copied `num_out' times, otherwise `ligID' itself will + be used to fill the `ligID' fields. + + The properties for all replacement glyphs are taken + from the glyph at position `buffer->in_pos'. + + The cluster value for the glyph at position buffer->in_pos is used + for all replacement glyphs */ +FT_Error +hb_buffer_add_output_glyphs( HB_Buffer buffer, + FT_UShort num_in, + FT_UShort num_out, + FT_UShort *glyph_data, + FT_UShort component, + FT_UShort ligID ) +{ + FT_Error error; + FT_UShort i; + FT_UInt properties; + FT_UInt cluster; + + error = hb_buffer_ensure( buffer, buffer->out_pos + num_out ); + if ( error ) + return error; + + properties = buffer->in_string[buffer->in_pos].properties; + cluster = buffer->in_string[buffer->in_pos].cluster; + if ( component == 0xFFFF ) + component = buffer->in_string[buffer->in_pos].component; + if ( ligID == 0xFFFF ) + ligID = buffer->in_string[buffer->in_pos].ligID; + + for ( i = 0; i < num_out; i++ ) + { + HB_GlyphItem item = &buffer->out_string[buffer->out_pos + i]; + + item->gindex = glyph_data[i]; + item->properties = properties; + item->cluster = cluster; + item->component = component; + item->ligID = ligID; + item->gproperties = HB_GLYPH_PROPERTIES_UNKNOWN; + } + + buffer->in_pos += num_in; + buffer->out_pos += num_out; + + buffer->out_length = buffer->out_pos; + + return FT_Err_Ok; +} + +FT_Error +hb_buffer_add_output_glyph( HB_Buffer buffer, + FT_UInt glyph_index, + FT_UShort component, + FT_UShort ligID ) +{ + FT_UShort glyph_data = glyph_index; + + return hb_buffer_add_output_glyphs ( buffer, 1, 1, + &glyph_data, component, ligID ); +} + +FT_Error +hb_buffer_copy_output_glyph ( HB_Buffer buffer ) +{ + FT_Error error; + + error = hb_buffer_ensure( buffer, buffer->out_pos + 1 ); + if ( error ) + return error; + + buffer->out_string[buffer->out_pos++] = buffer->in_string[buffer->in_pos++]; + buffer->out_length = buffer->out_pos; + + return FT_Err_Ok; +} + +FT_UShort +hb_buffer_allocate_ligid( HB_Buffer buffer ) +{ + return buffer->max_ligID++; +} diff --git a/src/harfbuzz-buffer.h b/src/harfbuzz-buffer.h new file mode 100644 index 0000000..c7478e3 --- /dev/null +++ b/src/harfbuzz-buffer.h @@ -0,0 +1,106 @@ +/* harfbuzz-buffer.h: Buffer of glyphs for substitution/positioning + * + * Copyrigh 2004 Red Hat Software + * + * Portions Copyright 1996-2000 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 HARFBUZZ_BUFFER_H +#define HARFBUZZ_BUFFER_H + +#include +#include FT_FREETYPE_H + +FT_BEGIN_HEADER + +#define HB_GLYPH_PROPERTIES_UNKNOWN 0xFFFF + +typedef struct HB_GlyphItemRec_ { + FT_UInt gindex; + FT_UInt properties; + FT_UInt cluster; + FT_UShort component; + FT_UShort ligID; + FT_UShort gproperties; +} HB_GlyphItemRec, *HB_GlyphItem; + +typedef struct HB_PositionRec_ { + FT_Pos x_pos; + FT_Pos y_pos; + FT_Pos x_advance; + FT_Pos y_advance; + FT_UShort back; /* number of glyphs to go back + for drawing current glyph */ + FT_Bool new_advance; /* if set, the advance width values are + absolute, i.e., they won't be + added to the original glyph's value + but rather replace them. */ + FT_Short cursive_chain; /* character to which this connects, + may be positive or negative; used + only internally */ +} HB_PositionRec, *HB_Position; + + +typedef struct HB_BufferRec_{ + FT_Memory memory; + FT_ULong allocated; + + FT_ULong in_length; + FT_ULong out_length; + FT_ULong in_pos; + FT_ULong out_pos; + + HB_GlyphItem in_string; + HB_GlyphItem out_string; + HB_Position positions; + FT_UShort max_ligID; +} HB_BufferRec, *HB_Buffer; + +FT_Error +hb_buffer_new( FT_Memory memory, + HB_Buffer *buffer ); + +FT_Error +hb_buffer_swap( HB_Buffer buffer ); + +FT_Error +hb_buffer_free( HB_Buffer buffer ); + +FT_Error +hb_buffer_clear( HB_Buffer buffer ); + +FT_Error +hb_buffer_add_glyph( HB_Buffer buffer, + FT_UInt glyph_index, + FT_UInt properties, + FT_UInt cluster ); + +FT_Error +hb_buffer_add_output_glyphs( HB_Buffer buffer, + FT_UShort num_in, + FT_UShort num_out, + FT_UShort *glyph_data, + FT_UShort component, + FT_UShort ligID ); + +FT_Error +hb_buffer_add_output_glyph ( HB_Buffer buffer, + FT_UInt glyph_index, + FT_UShort component, + FT_UShort ligID ); + +FT_Error +hb_buffer_copy_output_glyph ( HB_Buffer buffer ); + +FT_UShort +hb_buffer_allocate_ligid( HB_Buffer buffer ); + +FT_END_HEADER + +#endif /* HARFBUZZ_BUFFER_H */ diff --git a/src/ottest.c b/src/harfbuzz-dump-main.c similarity index 72% rename from src/ottest.c rename to src/harfbuzz-dump-main.c index b0f4fd6..81fecf4 100644 --- a/src/ottest.c +++ b/src/harfbuzz-dump-main.c @@ -1,5 +1,4 @@ -/* Pango - * otttest.c: Test program for OpenType +/* harfbuzz-dump-main.c: Test program for OpenType * * Copyright (C) 2000 Red Hat Software * @@ -19,13 +18,12 @@ * Boston, MA 02111-1307, USA. */ -#include #include #include -#include "ftxopen.h" +#include "harfbuzz-open.h" -#include "disasm.h" +#include "harfbuzz-dump.h" #define N_ELEMENTS(arr) (sizeof(arr)/ sizeof((arr)[0])) @@ -56,7 +54,7 @@ print_tag (FT_ULong tag) } static void -maybe_add_feature (TTO_GSUB gsub, +maybe_add_feature (HB_GSUB gsub, FT_UShort script_index, FT_ULong tag, FT_UShort property) @@ -65,22 +63,22 @@ maybe_add_feature (TTO_GSUB gsub, FT_UShort feature_index; /* 0xffff == default language system */ - error = TT_GSUB_Select_Feature (gsub, tag, script_index, 0xffff, &feature_index); + error = HB_GSUB_Select_Feature (gsub, tag, script_index, 0xffff, &feature_index); if (error) { - if (error == TTO_Err_Not_Covered) + if (error == HB_Err_Not_Covered) { print_tag (tag); fprintf (stderr, " not covered, ignored\n"); return; } - croak ("TT_GSUB_Select_Feature", error); + croak ("HB_GSUB_Select_Feature", error); } - if ((error = TT_GSUB_Add_Feature (gsub, feature_index, property))) - croak ("TT_GSUB_Add_Feature", error); + if ((error = HB_GSUB_Add_Feature (gsub, feature_index, property))) + croak ("HB_GSUB_Add_Feature", error); } static void @@ -122,23 +120,23 @@ select_cmap (FT_Face face) } static void -add_features (TTO_GSUB gsub) +add_features (HB_GSUB gsub) { FT_Error error; FT_ULong tag = FT_MAKE_TAG ('a', 'r', 'a', 'b'); FT_UShort script_index; - error = TT_GSUB_Select_Script (gsub, tag, &script_index); + error = HB_GSUB_Select_Script (gsub, tag, &script_index); if (error) { - if (error == TTO_Err_Not_Covered) + if (error == HB_Err_Not_Covered) { fprintf (stderr, "Arabic not covered, no features used\n"); return; } - croak ("TT_GSUB_Select_Script", error); + croak ("HB_GSUB_Select_Script", error); } maybe_add_feature (gsub, script_index, FT_MAKE_TAG ('i', 'n', 'i', 't'), I); @@ -150,7 +148,7 @@ add_features (TTO_GSUB gsub) #if 0 void -dump_string (TTO_GSUB_String *str) +dump_string (HB_GSUB_String *str) { FT_ULong i; @@ -173,20 +171,20 @@ FT_UShort arabic_props[] = { I|L, M|L, M|L, M|L, M|L, F|L, I|L, M|L void try_string (FT_Library library, FT_Face face, - TTO_GSUB gsub) + HB_GSUB gsub) { FT_Error error; - TTO_GSUB_String *in_str; - TTO_GSUB_String *out_str; + HB_GSUB_String *in_str; + HB_GSUB_String *out_str; FT_ULong i; - if ((error = TT_GSUB_String_New (face->memory, &in_str))) - croak ("TT_GSUB_String_New", error); - if ((error = TT_GSUB_String_New (face->memory, &out_str))) - croak ("TT_GSUB_String_New", error); + if ((error = HB_GSUB_String_New (face->memory, &in_str))) + croak ("HB_GSUB_String_New", error); + if ((error = HB_GSUB_String_New (face->memory, &out_str))) + croak ("HB_GSUB_String_New", error); - if ((error = TT_GSUB_String_Set_Length (in_str, N_ELEMENTS (arabic_str)))) - croak ("TT_GSUB_String_Set_Length", error); + if ((error = HB_GSUB_String_Set_Length (in_str, N_ELEMENTS (arabic_str)))) + croak ("HB_GSUB_String_Set_Length", error); for (i=0; i < N_ELEMENTS (arabic_str); i++) { @@ -196,16 +194,16 @@ try_string (FT_Library library, in_str->ligIDs[i] = i; } - if ((error = TT_GSUB_Apply_String (gsub, in_str, out_str))) - croak ("TT_GSUB_Apply_String", error); + if ((error = HB_GSUB_Apply_String (gsub, in_str, out_str))) + croak ("HB_GSUB_Apply_String", error); dump_string (in_str); dump_string (out_str); - if ((error = TT_GSUB_String_Done (in_str))) - croak ("TT_GSUB_String_New", error); - if ((error = TT_GSUB_String_Done (out_str))) - croak ("TT_GSUB_String_New", error); + if ((error = HB_GSUB_String_Done (in_str))) + croak ("HB_GSUB_String_New", error); + if ((error = HB_GSUB_String_Done (out_str))) + croak ("HB_GSUB_String_New", error); } #endif @@ -215,8 +213,8 @@ main (int argc, char **argv) FT_Error error; FT_Library library; FT_Face face; - TTO_GSUB gsub; - TTO_GPOS gpos; + HB_GSUB gsub; + HB_GPOS gpos; if (argc != 2) { @@ -233,25 +231,25 @@ main (int argc, char **argv) printf ("\n"); printf ("\n"); - if (!(error = TT_Load_GSUB_Table (face, &gsub, NULL))) + if (!(error = HB_Load_GSUB_Table (face, &gsub, NULL))) { - TT_Dump_GSUB_Table (gsub, stdout); + HB_Dump_GSUB_Table (gsub, stdout); - if ((error = TT_Done_GSUB_Table (gsub))) - croak ("FT_Done_GSUB_Table", error); + if ((error = HB_Done_GSUB_Table (gsub))) + croak ("HB_Done_GSUB_Table", error); } else if (error != FT_Err_Table_Missing) - fprintf (stderr, "TT_Load_GSUB_Table %x\n", error); + fprintf (stderr, "HB_Load_GSUB_Table %x\n", error); - if (!(error = TT_Load_GPOS_Table (face, &gpos, NULL))) + if (!(error = HB_Load_GPOS_Table (face, &gpos, NULL))) { - TT_Dump_GPOS_Table (gpos, stdout); + HB_Dump_GPOS_Table (gpos, stdout); - if ((error = TT_Done_GPOS_Table (gpos))) - croak ("FT_Done_GPOS_Table", error); + if ((error = HB_Done_GPOS_Table (gpos))) + croak ("HB_Done_GPOS_Table", error); } else if (error != FT_Err_Table_Missing) - fprintf (stderr, "TT_Load_GPOS_Table %x\n", error); + fprintf (stderr, "HB_Load_GPOS_Table %x\n", error); printf ("\n"); diff --git a/src/disasm.c b/src/harfbuzz-dump.c similarity index 74% rename from src/disasm.c rename to src/harfbuzz-dump.c index 50a0720..0500ff5 100644 --- a/src/disasm.c +++ b/src/harfbuzz-dump.c @@ -1,5 +1,4 @@ -/* Pango - * disasm.c: Dump OpenType layout tables +/* harfbuzz-dump.c: Dump OpenType layout tables * * Copyright (C) 2000 Red Hat Software * @@ -19,28 +18,29 @@ * Boston, MA 02111-1307, USA. */ -#include - -#include /* For G_HAVE_ISO_VARARGS */ +#include "harfbuzz-impl.h" +#include "harfbuzz-dump.h" +#include "harfbuzz-gdef-private.h" +#include "harfbuzz-gsub-private.h" +#include "harfbuzz-gpos-private.h" +#include "harfbuzz-open-private.h" #include -#include "disasm.h" +#define DUMP(format) dump (stream, indent, format) +#define DUMP1(format, arg1) dump (stream, indent, format, arg1) +#define DUMP2(format, arg1, arg2) dump (stream, indent, format, arg1, arg2) +#define DUMP3(format, arg1, arg2, arg3) dump (stream, indent, format, arg1, arg2, arg3) -#ifdef G_HAVE_ISO_VARARGS -#define DUMP(...) dump (stream, indent, __VA_ARGS__) -#elif defined (G_HAVE_GNUC_VARARGS) -#define DUMP(args...) dump (stream, indent, args) -#endif #define DUMP_FINT(strct,fld) dump (stream, indent, "<" #fld ">%d\n", (strct)->fld) #define DUMP_FUINT(strct,fld) dump (stream, indent, "<" #fld ">%u\n", (strct)->fld) #define DUMP_FGLYPH(strct,fld) dump (stream, indent, "<" #fld ">%#06x\n", (strct)->fld) #define DUMP_FGLYPH(strct,fld) dump (stream, indent, "<" #fld ">%#06x\n", (strct)->fld) #define DUMP_USHORT_ARRAY(strct,fld,cnt) Dump_UShort_Array ((strct)->fld, cnt, #fld, stream, indent); -#define DEF_DUMP(type) static void Dump_ ## type (TTO_ ## type *type, FILE *stream, int indent, FT_Bool G_GNUC_UNUSED is_gsub) -#define RECURSE(name, type, val) do { DUMP ("<" #name ">\n"); Dump_ ## type (val, stream, indent + 1, is_gsub); DUMP ("\n"); } while (0) -#define RECURSE_NUM(name, i, type, val) do { DUMP ("<" #name "> \n", i); Dump_ ## type (val, stream, indent + 1, is_gsub); DUMP ("\n"); } while (0) -#define DUMP_VALUE_RECORD(val, frmt) do { DUMP ("\n"); Dump_ValueRecord (val, stream, indent + 1, is_gsub, frmt); DUMP ("\n"); } while (0) +#define DEF_DUMP(type) static void Dump_ ## type (HB_ ## type *type, FILE *stream, int indent, HB_Type hb_type) +#define RECURSE(name, type, val) do { DUMP ("<" #name ">\n"); Dump_ ## type (val, stream, indent + 1, hb_type); DUMP ("\n"); } while (0) +#define RECURSE_NUM(name, i, type, val) do { DUMP1 ("<" #name "> \n", i); Dump_ ## type (val, stream, indent + 1, hb_type); DUMP ("\n"); } while (0) +#define DUMP_VALUE_RECORD(val, frmt) do { DUMP ("\n"); Dump_ValueRecord (val, stream, indent + 1, hb_type, frmt); DUMP ("\n"); } while (0) static void do_indent (FILE *stream, int indent) @@ -92,7 +92,7 @@ DEF_DUMP (LangSys) DUMP_FUINT (LangSys, FeatureCount); for (i=0; i < LangSys->FeatureCount; i++) - DUMP("%d\n", LangSys->FeatureIndex[i]); + DUMP1("%d\n", LangSys->FeatureIndex[i]); } DEF_DUMP (Script) @@ -137,13 +137,13 @@ DEF_DUMP (Feature) DUMP_FUINT (Feature, LookupListCount); for (i=0; i < Feature->LookupListCount; i++) - DUMP("%d\n", Feature->LookupListIndex[i]); + DUMP1("%d\n", Feature->LookupListIndex[i]); } DEF_DUMP (MarkRecord) { DUMP_FUINT (MarkRecord, Class); - DUMP("%d\n", MarkRecord->MarkAnchor.PosFormat ); + DUMP1("%d\n", MarkRecord->MarkAnchor.PosFormat ); } DEF_DUMP (MarkArray) @@ -182,8 +182,8 @@ DEF_DUMP (Coverage) DUMP_FUINT (&Coverage->cf.cf1, GlyphCount); for (i = 0; i < Coverage->cf.cf1.GlyphCount; i++) - DUMP("%#06x \n", - Coverage->cf.cf1.GlyphArray[i], i); + DUMP2("%#06x \n", + Coverage->cf.cf1.GlyphArray[i], i); } else { @@ -191,9 +191,9 @@ DEF_DUMP (Coverage) DUMP_FUINT (&Coverage->cf.cf2, RangeCount); for ( i = 0; i < Coverage->cf.cf2.RangeCount; i++ ) - DUMP("%#06x - %#06x \n", - Coverage->cf.cf2.RangeRecord[i].Start, - Coverage->cf.cf2.RangeRecord[i].End); + DUMP3("%#06x - %#06x \n", + Coverage->cf.cf2.RangeRecord[i].Start, + Coverage->cf.cf2.RangeRecord[i].End, i); } } @@ -212,18 +212,18 @@ DEF_DUMP (ClassDefinition) if (ClassDefinition->ClassFormat == 1) { int i; - TTO_ClassDefFormat1 *ClassDefFormat1 = &ClassDefinition->cd.cd1; + HB_ClassDefFormat1 *ClassDefFormat1 = &ClassDefinition->cd.cd1; DUMP("\n"); DUMP_FUINT (ClassDefFormat1, StartGlyph ); DUMP_FUINT (ClassDefFormat1, GlyphCount ); for (i = 0; i < ClassDefFormat1->GlyphCount; i++) - DUMP(" %d ", ClassDefFormat1->ClassValueArray[i], - ClassDefFormat1->StartGlyph+i ); + DUMP2(" %d ", ClassDefFormat1->ClassValueArray[i], + ClassDefFormat1->StartGlyph+i ); } else if (ClassDefinition->ClassFormat == 2) { int i; - TTO_ClassDefFormat2 *ClassDefFormat2 = &ClassDefinition->cd.cd2; + HB_ClassDefFormat2 *ClassDefFormat2 = &ClassDefinition->cd.cd2; DUMP_FUINT (ClassDefFormat2, ClassRangeCount); for (i = 0; i < ClassDefFormat2->ClassRangeCount; i++) @@ -263,9 +263,9 @@ DEF_DUMP (ChainSubClassSet) } static void -Dump_GSUB_Lookup_Single (TTO_SubTable *subtable, FILE *stream, int indent, FT_Bool is_gsub) +Dump_GSUB_Lookup_Single (HB_SubTable *subtable, FILE *stream, int indent, HB_Type hb_type) { - TTO_SingleSubst *SingleSubst = &subtable->st.gsub.single; + HB_SingleSubst *SingleSubst = &subtable->st.gsub.single; DUMP_FUINT (SingleSubst, SubstFormat); RECURSE (Coverage, Coverage, &SingleSubst->Coverage); @@ -280,7 +280,7 @@ Dump_GSUB_Lookup_Single (TTO_SubTable *subtable, FILE *stream, int indent, FT_Bo DUMP_FINT (&SingleSubst->ssf.ssf2, GlyphCount); for (i=0; i < SingleSubst->ssf.ssf2.GlyphCount; i++) - DUMP("%#06x \n", SingleSubst->ssf.ssf2.Substitute[i], i); + DUMP2("%#06x \n", SingleSubst->ssf.ssf2.Substitute[i], i); } } @@ -292,7 +292,7 @@ DEF_DUMP (Ligature) DUMP_FUINT (Ligature, ComponentCount); for (i=0; i < Ligature->ComponentCount - 1; i++) - DUMP("%#06x\n", Ligature->Component[i]); + DUMP1("%#06x\n", Ligature->Component[i]); } DEF_DUMP (LigatureSet) @@ -306,10 +306,10 @@ DEF_DUMP (LigatureSet) } static void -Dump_GSUB_Lookup_Ligature (TTO_SubTable *subtable, FILE *stream, int indent, FT_Bool is_gsub) +Dump_GSUB_Lookup_Ligature (HB_SubTable *subtable, FILE *stream, int indent, HB_Type hb_type) { int i; - TTO_LigatureSubst *LigatureSubst = &subtable->st.gsub.ligature; + HB_LigatureSubst *LigatureSubst = &subtable->st.gsub.ligature; DUMP_FUINT (LigatureSubst, SubstFormat); RECURSE (Coverage, Coverage, &LigatureSubst->Coverage); @@ -338,21 +338,21 @@ DEF_DUMP (ContextSubstFormat3) } static void -Dump_GSUB_Lookup_Context (TTO_SubTable *subtable, FILE *stream, int indent, FT_Bool is_gsub) +Dump_GSUB_Lookup_Context (HB_SubTable *subtable, FILE *stream, int indent, HB_Type hb_type) { - TTO_ContextSubst *ContextSubst = &subtable->st.gsub.context; + HB_ContextSubst *ContextSubst = &subtable->st.gsub.context; DUMP_FUINT (ContextSubst, SubstFormat); switch( ContextSubst->SubstFormat ) { case 1: - Dump_ContextSubstFormat1 (&ContextSubst->csf.csf1, stream, indent+2, is_gsub); + Dump_ContextSubstFormat1 (&ContextSubst->csf.csf1, stream, indent+2, hb_type); break; case 2: - Dump_ContextSubstFormat2 (&ContextSubst->csf.csf2, stream, indent+2, is_gsub); + Dump_ContextSubstFormat2 (&ContextSubst->csf.csf2, stream, indent+2, hb_type); break; case 3: - Dump_ContextSubstFormat3 (&ContextSubst->csf.csf3, stream, indent+2, is_gsub); + Dump_ContextSubstFormat3 (&ContextSubst->csf.csf3, stream, indent+2, hb_type); break; default: fprintf(stderr, "invalid subformat!!!!!\n"); @@ -401,21 +401,21 @@ DEF_DUMP (ChainContextSubstFormat3) } static void -Dump_GSUB_Lookup_Chain (TTO_SubTable *subtable, FILE *stream, int indent, FT_Bool is_gsub) +Dump_GSUB_Lookup_Chain (HB_SubTable *subtable, FILE *stream, int indent, HB_Type hb_type) { - TTO_ChainContextSubst *chain = &subtable->st.gsub.chain; + HB_ChainContextSubst *chain = &subtable->st.gsub.chain; DUMP_FUINT (chain, SubstFormat); switch (chain->SubstFormat) { case 1: - Dump_ChainContextSubstFormat1 (&chain->ccsf.ccsf1, stream, indent+2, is_gsub); + Dump_ChainContextSubstFormat1 (&chain->ccsf.ccsf1, stream, indent+2, hb_type); break; case 2: - Dump_ChainContextSubstFormat2 (&chain->ccsf.ccsf2, stream, indent+2, is_gsub); + Dump_ChainContextSubstFormat2 (&chain->ccsf.ccsf2, stream, indent+2, hb_type); break; case 3: - Dump_ChainContextSubstFormat3 (&chain->ccsf.ccsf3, stream, indent+2, is_gsub); + Dump_ChainContextSubstFormat3 (&chain->ccsf.ccsf3, stream, indent+2, hb_type); break; default: fprintf(stderr, "invalid subformat!!!!!\n"); @@ -423,7 +423,7 @@ Dump_GSUB_Lookup_Chain (TTO_SubTable *subtable, FILE *stream, int indent, FT_Boo } static void -Dump_Device (TTO_Device *Device, FILE *stream, int indent, FT_Bool is_gsub) +Dump_Device (HB_Device *Device, FILE *stream, int indent, HB_Type hb_type) { int i; int bits = 0; @@ -471,38 +471,38 @@ Dump_Device (TTO_Device *Device, FILE *stream, int indent, FT_Bool is_gsub) } static void -Dump_ValueRecord (TTO_ValueRecord *ValueRecord, FILE *stream, int indent, FT_Bool is_gsub, FT_UShort value_format) +Dump_ValueRecord (HB_ValueRecord *ValueRecord, FILE *stream, int indent, HB_Type hb_type, FT_UShort value_format) { - if (value_format & HAVE_X_PLACEMENT) + if (value_format & HB_GPOS_FORMAT_HAVE_X_PLACEMENT) DUMP_FINT (ValueRecord, XPlacement); - if (value_format & HAVE_Y_PLACEMENT) + if (value_format & HB_GPOS_FORMAT_HAVE_Y_PLACEMENT) DUMP_FINT (ValueRecord, YPlacement); - if (value_format & HAVE_X_ADVANCE) + if (value_format & HB_GPOS_FORMAT_HAVE_X_ADVANCE) DUMP_FINT (ValueRecord, XAdvance); - if (value_format & HAVE_Y_ADVANCE) + if (value_format & HB_GPOS_FORMAT_HAVE_Y_ADVANCE) DUMP_FINT (ValueRecord, XAdvance); - if (value_format & HAVE_X_PLACEMENT_DEVICE) + if (value_format & HB_GPOS_FORMAT_HAVE_X_PLACEMENT_DEVICE) RECURSE (Device, Device, &ValueRecord->XPlacementDevice); - if (value_format & HAVE_Y_PLACEMENT_DEVICE) + if (value_format & HB_GPOS_FORMAT_HAVE_Y_PLACEMENT_DEVICE) RECURSE (Device, Device, &ValueRecord->YPlacementDevice); - if (value_format & HAVE_X_ADVANCE_DEVICE) + if (value_format & HB_GPOS_FORMAT_HAVE_X_ADVANCE_DEVICE) RECURSE (Device, Device, &ValueRecord->XAdvanceDevice); - if (value_format & HAVE_Y_ADVANCE_DEVICE) + if (value_format & HB_GPOS_FORMAT_HAVE_Y_ADVANCE_DEVICE) RECURSE (Device, Device, &ValueRecord->YAdvanceDevice); - if (value_format & HAVE_X_ID_PLACEMENT) + if (value_format & HB_GPOS_FORMAT_HAVE_X_ID_PLACEMENT) DUMP_FUINT (ValueRecord, XIdPlacement); - if (value_format & HAVE_Y_ID_PLACEMENT) + if (value_format & HB_GPOS_FORMAT_HAVE_Y_ID_PLACEMENT) DUMP_FUINT (ValueRecord, YIdPlacement); - if (value_format & HAVE_X_ID_ADVANCE) + if (value_format & HB_GPOS_FORMAT_HAVE_X_ID_ADVANCE) DUMP_FUINT (ValueRecord, XIdAdvance); - if (value_format & HAVE_Y_ID_ADVANCE) + if (value_format & HB_GPOS_FORMAT_HAVE_Y_ID_ADVANCE) DUMP_FUINT (ValueRecord, XIdAdvance); } static void -Dump_GPOS_Lookup_Single (TTO_SubTable *subtable, FILE *stream, int indent, FT_Bool is_gsub) +Dump_GPOS_Lookup_Single (HB_SubTable *subtable, FILE *stream, int indent, HB_Type hb_type) { - TTO_SinglePos *SinglePos = &subtable->st.gpos.single; + HB_SinglePos *SinglePos = &subtable->st.gpos.single; DUMP_FUINT (SinglePos, PosFormat); RECURSE (Coverage, Coverage, &SinglePos->Coverage); @@ -524,7 +524,7 @@ Dump_GPOS_Lookup_Single (TTO_SubTable *subtable, FILE *stream, int indent, FT_Bo } static void -Dump_PairValueRecord (TTO_PairValueRecord *PairValueRecord, FILE *stream, int indent, FT_Bool is_gsub, FT_UShort ValueFormat1, FT_UShort ValueFormat2) +Dump_PairValueRecord (HB_PairValueRecord *PairValueRecord, FILE *stream, int indent, HB_Type hb_type, FT_UShort ValueFormat1, FT_UShort ValueFormat2) { DUMP_FUINT (PairValueRecord, SecondGlyph); DUMP_VALUE_RECORD (&PairValueRecord->Value1, ValueFormat1); @@ -532,7 +532,7 @@ Dump_PairValueRecord (TTO_PairValueRecord *PairValueRecord, FILE *stream, int in } static void -Dump_PairSet (TTO_PairSet *PairSet, FILE *stream, int indent, FT_Bool is_gsub, FT_UShort ValueFormat1, FT_UShort ValueFormat2) +Dump_PairSet (HB_PairSet *PairSet, FILE *stream, int indent, HB_Type hb_type, FT_UShort ValueFormat1, FT_UShort ValueFormat2) { int i; DUMP_FUINT (PairSet, PairValueCount); @@ -540,15 +540,15 @@ Dump_PairSet (TTO_PairSet *PairSet, FILE *stream, int indent, FT_Bool is_gsub, F for (i = 0; i < PairSet->PairValueCount; i++) { DUMP ("\n"); - Dump_PairValueRecord (&PairSet->PairValueRecord[i], stream, indent + 1, is_gsub, ValueFormat1, ValueFormat2); + Dump_PairValueRecord (&PairSet->PairValueRecord[i], stream, indent + 1, hb_type, ValueFormat1, ValueFormat2); DUMP ("\n"); } } static void -Dump_GPOS_Lookup_Pair (TTO_SubTable *subtable, FILE *stream, int indent, FT_Bool is_gsub) +Dump_GPOS_Lookup_Pair (HB_SubTable *subtable, FILE *stream, int indent, HB_Type hb_type) { - TTO_PairPos *PairPos = &subtable->st.gpos.pair; + HB_PairPos *PairPos = &subtable->st.gpos.pair; DUMP_FUINT (PairPos, PosFormat); RECURSE (Coverage, Coverage, &PairPos->Coverage); @@ -564,7 +564,7 @@ Dump_GPOS_Lookup_Pair (TTO_SubTable *subtable, FILE *stream, int indent, FT_Bool for (i = 0; i < PairPos->ppf.ppf1.PairSetCount; i++) { DUMP ("\n"); - Dump_PairSet (&PairPos->ppf.ppf1.PairSet[i], stream, indent + 1, is_gsub, PairPos->ValueFormat1, PairPos->ValueFormat2); + Dump_PairSet (&PairPos->ppf.ppf1.PairSet[i], stream, indent + 1, hb_type, PairPos->ValueFormat1, PairPos->ValueFormat2); DUMP ("\n"); } } @@ -574,10 +574,10 @@ Dump_GPOS_Lookup_Pair (TTO_SubTable *subtable, FILE *stream, int indent, FT_Bool } static void -Dump_GPOS_Lookup_Markbase (TTO_SubTable *subtable, FILE *stream, int indent, FT_Bool is_gsub) +Dump_GPOS_Lookup_Markbase (HB_SubTable *subtable, FILE *stream, int indent, HB_Type hb_type) { int i; - TTO_MarkBasePos *markbase = &subtable->st.gpos.markbase; + HB_MarkBasePos *markbase = &subtable->st.gpos.markbase; DUMP_FUINT (markbase, PosFormat); RECURSE (Coverage, Coverage, &markbase->MarkCoverage); @@ -592,10 +592,10 @@ Dump_GPOS_Lookup_Markbase (TTO_SubTable *subtable, FILE *stream, int indent, FT_ for (i = 0; i < markbase->BaseArray.BaseCount; i++) { int j; - TTO_BaseRecord *r = &markbase->BaseArray.BaseRecord[i]; - DUMP (" \n", i); + HB_BaseRecord *r = &markbase->BaseArray.BaseRecord[i]; + DUMP1 (" \n", i); for (j = 0; j < markbase->ClassCount; j++) - DUMP (" %d\n", r->BaseAnchor->PosFormat); + DUMP1 (" %d\n", r->BaseAnchor->PosFormat); DUMP ("\n"); } @@ -607,31 +607,31 @@ DEF_DUMP (Lookup) { int i; const char *lookup_name = NULL; - void (*lookup_func) (TTO_SubTable *subtable, FILE *stream, int indent, FT_Bool is_gsub) = NULL; + void (*lookup_func) (HB_SubTable *subtable, FILE *stream, int indent, HB_Type hb_type) = NULL; - if (is_gsub) + if (hb_type == HB_Type_GSUB) { switch (Lookup->LookupType) { - case GSUB_LOOKUP_SINGLE: + case HB_GSUB_LOOKUP_SINGLE: lookup_name = "SINGLE"; lookup_func = Dump_GSUB_Lookup_Single; break; - case GSUB_LOOKUP_MULTIPLE: + case HB_GSUB_LOOKUP_MULTIPLE: lookup_name = "MULTIPLE"; break; - case GSUB_LOOKUP_ALTERNATE: + case HB_GSUB_LOOKUP_ALTERNATE: lookup_name = "ALTERNATE"; break; - case GSUB_LOOKUP_LIGATURE: + case HB_GSUB_LOOKUP_LIGATURE: lookup_name = "LIGATURE"; lookup_func = Dump_GSUB_Lookup_Ligature; break; - case GSUB_LOOKUP_CONTEXT: + case HB_GSUB_LOOKUP_CONTEXT: lookup_name = "CONTEXT"; lookup_func = Dump_GSUB_Lookup_Context; break; - case GSUB_LOOKUP_CHAIN: + case HB_GSUB_LOOKUP_CHAIN: lookup_name = "CHAIN"; lookup_func = Dump_GSUB_Lookup_Chain; break; @@ -641,44 +641,44 @@ DEF_DUMP (Lookup) { switch (Lookup->LookupType) { - case GPOS_LOOKUP_SINGLE: + case HB_GPOS_LOOKUP_SINGLE: lookup_name = "SINGLE"; lookup_func = Dump_GPOS_Lookup_Single; break; - case GPOS_LOOKUP_PAIR: + case HB_GPOS_LOOKUP_PAIR: lookup_name = "PAIR"; lookup_func = Dump_GPOS_Lookup_Pair; break; - case GPOS_LOOKUP_CURSIVE: + case HB_GPOS_LOOKUP_CURSIVE: lookup_name = "CURSIVE"; break; - case GPOS_LOOKUP_MARKBASE: + case HB_GPOS_LOOKUP_MARKBASE: lookup_name = "MARKBASE"; lookup_func = Dump_GPOS_Lookup_Markbase; break; - case GPOS_LOOKUP_MARKLIG: + case HB_GPOS_LOOKUP_MARKLIG: lookup_name = "MARKLIG"; break; - case GPOS_LOOKUP_MARKMARK: + case HB_GPOS_LOOKUP_MARKMARK: lookup_name = "MARKMARK"; break; - case GPOS_LOOKUP_CONTEXT: + case HB_GPOS_LOOKUP_CONTEXT: lookup_name = "CONTEXT"; break; - case GPOS_LOOKUP_CHAIN: + case HB_GPOS_LOOKUP_CHAIN: lookup_name = "CHAIN"; break; } } - DUMP("%s \n", lookup_name, Lookup->LookupType); - DUMP("%#06x\n", Lookup->LookupFlag); + DUMP2("%s \n", lookup_name, Lookup->LookupType); + DUMP1("%#06x\n", Lookup->LookupFlag); for (i=0; i < Lookup->SubTableCount; i++) { DUMP ("\n"); if (lookup_func) - (*lookup_func) (&Lookup->SubTable[i], stream, indent + 1, is_gsub); + (*lookup_func) (&Lookup->SubTable[i], stream, indent + 1, hb_type); DUMP ("\n"); } } @@ -694,10 +694,10 @@ DEF_DUMP (LookupList) } void -TT_Dump_GSUB_Table (TTO_GSUB gsub, FILE *stream) +HB_Dump_GSUB_Table (HB_GSUB gsub, FILE *stream) { int indent = 1; - FT_Bool is_gsub = 1; + HB_Type hb_type = HB_Type_GSUB; do_indent (stream, indent); fprintf(stream, "\n"); @@ -707,10 +707,10 @@ TT_Dump_GSUB_Table (TTO_GSUB gsub, FILE *stream) } void -TT_Dump_GPOS_Table (TTO_GPOS gpos, FILE *stream) +HB_Dump_GPOS_Table (HB_GPOS gpos, FILE *stream) { int indent = 1; - FT_Bool is_gsub = 0; + HB_Type hb_type = HB_Type_GPOS; do_indent (stream, indent); fprintf(stream, "\n"); diff --git a/src/disasm.h b/src/harfbuzz-dump.h similarity index 71% rename from src/disasm.h rename to src/harfbuzz-dump.h index e7556d4..c41ca68 100644 --- a/src/disasm.h +++ b/src/harfbuzz-dump.h @@ -1,5 +1,4 @@ -/* Pango - * disasm.h: Dump OpenType layout tables +/* harfbuzz-dump.h: Dump OpenType layout tables * * Copyright (C) 2000 Red Hat Software * @@ -18,9 +17,18 @@ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ +#ifndef HARFBUZZ_DUMP_H +#define HARFBUZZ_DUMP_H #include -#include "ftxopen.h" +#include "harfbuzz-gsub.h" +#include "harfbuzz-gpos.h" -void TT_Dump_GSUB_Table (TTO_GSUB gsub, FILE *stream); -void TT_Dump_GPOS_Table (TTO_GPOS gpos, FILE *stream); +FT_BEGIN_HEADER + +void HB_Dump_GSUB_Table (HB_GSUB gsub, FILE *stream); +void HB_Dump_GPOS_Table (HB_GPOS gpos, FILE *stream); + +FT_END_HEADER + +#endif /* HARFBUZZ_DUMP_H */ diff --git a/src/harfbuzz-gdef-private.h b/src/harfbuzz-gdef-private.h new file mode 100644 index 0000000..e07e236 --- /dev/null +++ b/src/harfbuzz-gdef-private.h @@ -0,0 +1,101 @@ +/******************************************************************* + * + * Copyright 1996-2000 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * Copyright 2006 Behdad Esfahbod + * + * This is part of HarfBuzz, an OpenType Layout engine library. + * + * See the file name COPYING for licensing information. + * + ******************************************************************/ +#ifndef HARFBUZZ_GDEF_PRIVATE_H +#define HARFBUZZ_GDEF_PRIVATE_H + +#include "harfbuzz-gdef.h" +#include "harfbuzz-buffer.h" + +FT_BEGIN_HEADER + + +/* Attachment related structures */ + +struct HB_AttachPoint_ +{ + FT_UShort PointCount; /* size of the PointIndex array */ + FT_UShort* PointIndex; /* array of contour points */ +}; + +/* Ligature Caret related structures */ + +struct HB_CaretValueFormat1_ +{ + FT_Short Coordinate; /* x or y value (in design units) */ +}; + +typedef struct HB_CaretValueFormat1_ HB_CaretValueFormat1; + + +struct HB_CaretValueFormat2_ +{ + FT_UShort CaretValuePoint; /* contour point index on glyph */ +}; + +typedef struct HB_CaretValueFormat2_ HB_CaretValueFormat2; + + +struct HB_CaretValueFormat3_ +{ + FT_Short Coordinate; /* x or y value (in design units) */ + HB_Device Device; /* Device table for x or y value */ +}; + +typedef struct HB_CaretValueFormat3_ HB_CaretValueFormat3; + + +struct HB_CaretValueFormat4_ +{ + FT_UShort IdCaretValue; /* metric ID */ +}; + +typedef struct HB_CaretValueFormat4_ HB_CaretValueFormat4; + + +struct HB_CaretValue_ +{ + FT_UShort CaretValueFormat; /* 1, 2, 3, or 4 */ + + union + { + HB_CaretValueFormat1 cvf1; + HB_CaretValueFormat2 cvf2; + HB_CaretValueFormat3 cvf3; + HB_CaretValueFormat4 cvf4; + } cvf; +}; + +typedef struct HB_CaretValue_ HB_CaretValue; + + +struct HB_LigGlyph_ +{ + FT_Bool loaded; + + FT_UShort CaretCount; /* number of caret values */ + HB_CaretValue* CaretValue; /* array of caret values */ +}; + + +FT_Error _HB_GDEF_Add_Glyph_Property( HB_GDEFHeader* gdef, + FT_UShort glyphID, + FT_UShort property ); + +FT_Error _HB_GDEF_Check_Property( HB_GDEFHeader* gdef, + HB_GlyphItem item, + FT_UShort flags, + FT_UShort* property ); + +FT_END_HEADER + +#endif /* HARFBUZZ_GDEF_PRIVATE_H */ diff --git a/src/harfbuzz-gdef.c b/src/harfbuzz-gdef.c new file mode 100644 index 0000000..1564e88 --- /dev/null +++ b/src/harfbuzz-gdef.c @@ -0,0 +1,1228 @@ +/******************************************************************* + * + * Copyright 1996-2000 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * Copyright 2006 Behdad Esfahbod + * + * This is part of HarfBuzz, an OpenType Layout engine library. + * + * See the file name COPYING for licensing information. + * + ******************************************************************/ +#include "harfbuzz-impl.h" +#include "harfbuzz-gdef-private.h" +#include "harfbuzz-open-private.h" + +#include FT_TRUETYPE_TAGS_H + + +static FT_Error Load_AttachList( HB_AttachList* al, + FT_Stream stream ); +static FT_Error Load_LigCaretList( HB_LigCaretList* lcl, + FT_Stream stream ); + +static void Free_AttachList( HB_AttachList* al, + FT_Memory memory ); +static void Free_LigCaretList( HB_LigCaretList* lcl, + FT_Memory memory ); + +static void Free_NewGlyphClasses( HB_GDEFHeader* gdef, + FT_Memory memory ); + + + +/********************** + * Extension Functions + **********************/ + +#if 0 +#define GDEF_ID Build_Extension_ID( 'G', 'D', 'E', 'F' ) + + +static FT_Error GDEF_Create( void* ext, + PFace face ) +{ + DEFINE_LOAD_LOCALS( face->stream ); + + HB_GDEFHeader* gdef = (HB_GDEFHeader*)ext; + Long table; + + + /* by convention */ + + if ( !gdef ) + return FT_Err_Ok; + + /* a null offset indicates that there is no GDEF table */ + + gdef->offset = 0; + + /* we store the start offset and the size of the subtable */ + + table = HB_LookUp_Table( face, TTAG_GDEF ); + if ( table < 0 ) + return FT_Err_Ok; /* The table is optional */ + + if ( FILE_Seek( face->dirTables[table].Offset ) || + ACCESS_Frame( 4L ) ) + return error; + + gdef->offset = FILE_Pos() - 4L; /* undo ACCESS_Frame() */ + gdef->Version = GET_ULong(); + + FORGET_Frame(); + + gdef->loaded = FALSE; + + return FT_Err_Ok; +} + + +static FT_Error GDEF_Destroy( void* ext, + PFace face ) +{ + HB_GDEFHeader* gdef = (HB_GDEFHeader*)ext; + + + /* by convention */ + + if ( !gdef ) + return FT_Err_Ok; + + if ( gdef->loaded ) + { + Free_LigCaretList( &gdef->LigCaretList, memory ); + Free_AttachList( &gdef->AttachList, memory ); + _HB_OPEN_Free_ClassDefinition( &gdef->GlyphClassDef, memory ); + _HB_OPEN_Free_ClassDefinition( &gdef->MarkAttachClassDef, memory ); + + Free_NewGlyphClasses( gdef, memory ); + } + + return FT_Err_Ok; +} + + + +FT_Error HB_Init_GDEF_Extension( HB_Engine engine ) +{ + PEngine_Instance _engine = HANDLE_Engine( engine ); + + + if ( !_engine ) + return FT_Err_Invalid_Engine; + + return HB_Register_Extension( _engine, + GDEF_ID, + sizeof ( HB_GDEFHeader ), + GDEF_Create, + GDEF_Destroy ); +} +#endif +/* GDEF glyph classes */ + +#define UNCLASSIFIED_GLYPH 0 +#define SIMPLE_GLYPH 1 +#define LIGATURE_GLYPH 2 +#define MARK_GLYPH 3 +#define COMPONENT_GLYPH 4 + + + + + + +FT_Error HB_New_GDEF_Table( FT_Face face, + HB_GDEFHeader** retptr ) +{ + FT_Error error; + FT_Memory memory = face->memory; + + HB_GDEFHeader* gdef; + + if ( !retptr ) + return FT_Err_Invalid_Argument; + + if ( ALLOC( gdef, sizeof( *gdef ) ) ) + return error; + + gdef->memory = face->memory; + + gdef->GlyphClassDef.loaded = FALSE; + gdef->AttachList.loaded = FALSE; + gdef->LigCaretList.loaded = FALSE; + gdef->MarkAttachClassDef_offset = 0; + gdef->MarkAttachClassDef.loaded = FALSE; + + gdef->LastGlyph = 0; + gdef->NewGlyphClasses = NULL; + + *retptr = gdef; + + return FT_Err_Ok; +} + + +FT_Error HB_Load_GDEF_Table( FT_Face face, + HB_GDEFHeader** retptr ) +{ + FT_Error error; + FT_Memory memory = face->memory; + FT_Stream stream = face->stream; + FT_ULong cur_offset, new_offset, base_offset; + + HB_GDEFHeader* gdef; + + + if ( !retptr ) + return FT_Err_Invalid_Argument; + + if (( error = _hb_ftglue_face_goto_table( face, TTAG_GDEF, stream ) )) + return error; + + if (( error = HB_New_GDEF_Table ( face, &gdef ) )) + return error; + + base_offset = FILE_Pos(); + + /* skip version */ + + if ( FILE_Seek( base_offset + 4L ) || + ACCESS_Frame( 2L ) ) + goto Fail0; + + new_offset = GET_UShort(); + + FORGET_Frame(); + + /* all GDEF subtables are optional */ + + if ( new_offset ) + { + new_offset += base_offset; + + /* only classes 1-4 are allowed here */ + + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = _HB_OPEN_Load_ClassDefinition( &gdef->GlyphClassDef, 5, + stream ) ) != FT_Err_Ok ) + goto Fail0; + (void)FILE_Seek( cur_offset ); + } + + if ( ACCESS_Frame( 2L ) ) + goto Fail1; + + new_offset = GET_UShort(); + + FORGET_Frame(); + + if ( new_offset ) + { + new_offset += base_offset; + + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = Load_AttachList( &gdef->AttachList, + stream ) ) != FT_Err_Ok ) + goto Fail1; + (void)FILE_Seek( cur_offset ); + } + + if ( ACCESS_Frame( 2L ) ) + goto Fail2; + + new_offset = GET_UShort(); + + FORGET_Frame(); + + if ( new_offset ) + { + new_offset += base_offset; + + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = Load_LigCaretList( &gdef->LigCaretList, + stream ) ) != FT_Err_Ok ) + goto Fail2; + (void)FILE_Seek( cur_offset ); + } + + /* OpenType 1.2 has introduced the `MarkAttachClassDef' field. We + first have to scan the LookupFlag values to find out whether we + must load it or not. Here we only store the offset of the table. */ + + if ( ACCESS_Frame( 2L ) ) + goto Fail3; + + new_offset = GET_UShort(); + + FORGET_Frame(); + + if ( new_offset ) + gdef->MarkAttachClassDef_offset = new_offset + base_offset; + else + gdef->MarkAttachClassDef_offset = 0; + + *retptr = gdef; + + return FT_Err_Ok; + +Fail3: + Free_LigCaretList( &gdef->LigCaretList, memory ); + +Fail2: + Free_AttachList( &gdef->AttachList, memory ); + +Fail1: + _HB_OPEN_Free_ClassDefinition( &gdef->GlyphClassDef, memory ); + +Fail0: + FREE( gdef ); + + return error; +} + + +FT_Error HB_Done_GDEF_Table ( HB_GDEFHeader* gdef ) +{ + FT_Memory memory = gdef->memory; + + Free_LigCaretList( &gdef->LigCaretList, memory ); + Free_AttachList( &gdef->AttachList, memory ); + _HB_OPEN_Free_ClassDefinition( &gdef->GlyphClassDef, memory ); + _HB_OPEN_Free_ClassDefinition( &gdef->MarkAttachClassDef, memory ); + + Free_NewGlyphClasses( gdef, memory ); + + FREE( gdef ); + + return FT_Err_Ok; +} + + + + +/******************************* + * AttachList related functions + *******************************/ + + +/* AttachPoint */ + +static FT_Error Load_AttachPoint( HB_AttachPoint* ap, + FT_Stream stream ) +{ + FT_Memory memory = stream->memory; + FT_Error error; + + FT_UShort n, count; + FT_UShort* pi; + + + if ( ACCESS_Frame( 2L ) ) + return error; + + count = ap->PointCount = GET_UShort(); + + FORGET_Frame(); + + ap->PointIndex = NULL; + + if ( count ) + { + if ( ALLOC_ARRAY( ap->PointIndex, count, FT_UShort ) ) + return error; + + pi = ap->PointIndex; + + if ( ACCESS_Frame( count * 2L ) ) + { + FREE( pi ); + return error; + } + + for ( n = 0; n < count; n++ ) + pi[n] = GET_UShort(); + + FORGET_Frame(); + } + + return FT_Err_Ok; +} + + +static void Free_AttachPoint( HB_AttachPoint* ap, + FT_Memory memory ) +{ + FREE( ap->PointIndex ); +} + + +/* AttachList */ + +static FT_Error Load_AttachList( HB_AttachList* al, + FT_Stream stream ) +{ + FT_Memory memory = stream->memory; + FT_Error error; + + FT_UShort n, m, count; + FT_ULong cur_offset, new_offset, base_offset; + + HB_AttachPoint* ap; + + + base_offset = FILE_Pos(); + + if ( ACCESS_Frame( 2L ) ) + return error; + + new_offset = GET_UShort() + base_offset; + + FORGET_Frame(); + + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = _HB_OPEN_Load_Coverage( &al->Coverage, stream ) ) != FT_Err_Ok ) + return error; + (void)FILE_Seek( cur_offset ); + + if ( ACCESS_Frame( 2L ) ) + goto Fail2; + + count = al->GlyphCount = GET_UShort(); + + FORGET_Frame(); + + al->AttachPoint = NULL; + + if ( ALLOC_ARRAY( al->AttachPoint, count, HB_AttachPoint ) ) + goto Fail2; + + ap = al->AttachPoint; + + for ( n = 0; n < count; n++ ) + { + if ( ACCESS_Frame( 2L ) ) + goto Fail1; + + new_offset = GET_UShort() + base_offset; + + FORGET_Frame(); + + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = Load_AttachPoint( &ap[n], stream ) ) != FT_Err_Ok ) + goto Fail1; + (void)FILE_Seek( cur_offset ); + } + + al->loaded = TRUE; + + return FT_Err_Ok; + +Fail1: + for ( m = 0; m < n; m++ ) + Free_AttachPoint( &ap[m], memory ); + + FREE( ap ); + +Fail2: + _HB_OPEN_Free_Coverage( &al->Coverage, memory ); + return error; +} + + +static void Free_AttachList( HB_AttachList* al, + FT_Memory memory ) +{ + FT_UShort n, count; + + HB_AttachPoint* ap; + + + if ( !al->loaded ) + return; + + if ( al->AttachPoint ) + { + count = al->GlyphCount; + ap = al->AttachPoint; + + for ( n = 0; n < count; n++ ) + Free_AttachPoint( &ap[n], memory ); + + FREE( ap ); + } + + _HB_OPEN_Free_Coverage( &al->Coverage, memory ); +} + + + +/********************************* + * LigCaretList related functions + *********************************/ + + +/* CaretValueFormat1 */ +/* CaretValueFormat2 */ +/* CaretValueFormat3 */ +/* CaretValueFormat4 */ + +static FT_Error Load_CaretValue( HB_CaretValue* cv, + FT_Stream stream ) +{ + FT_Error error; + + FT_ULong cur_offset, new_offset, base_offset; + + + base_offset = FILE_Pos(); + + if ( ACCESS_Frame( 2L ) ) + return error; + + cv->CaretValueFormat = GET_UShort(); + + FORGET_Frame(); + + switch ( cv->CaretValueFormat ) + { + case 1: + if ( ACCESS_Frame( 2L ) ) + return error; + + cv->cvf.cvf1.Coordinate = GET_Short(); + + FORGET_Frame(); + + break; + + case 2: + if ( ACCESS_Frame( 2L ) ) + return error; + + cv->cvf.cvf2.CaretValuePoint = GET_UShort(); + + FORGET_Frame(); + + break; + + case 3: + if ( ACCESS_Frame( 4L ) ) + return error; + + cv->cvf.cvf3.Coordinate = GET_Short(); + + new_offset = GET_UShort() + base_offset; + + FORGET_Frame(); + + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = _HB_OPEN_Load_Device( &cv->cvf.cvf3.Device, + stream ) ) != FT_Err_Ok ) + return error; + (void)FILE_Seek( cur_offset ); + + break; + + case 4: + if ( ACCESS_Frame( 2L ) ) + return error; + + cv->cvf.cvf4.IdCaretValue = GET_UShort(); + + FORGET_Frame(); + break; + + default: + return HB_Err_Invalid_GDEF_SubTable_Format; + } + + return FT_Err_Ok; +} + + +static void Free_CaretValue( HB_CaretValue* cv, + FT_Memory memory ) +{ + if ( cv->CaretValueFormat == 3 ) + _HB_OPEN_Free_Device( &cv->cvf.cvf3.Device, memory ); +} + + +/* LigGlyph */ + +static FT_Error Load_LigGlyph( HB_LigGlyph* lg, + FT_Stream stream ) +{ + FT_Memory memory = stream->memory; + FT_Error error; + + FT_UShort n, m, count; + FT_ULong cur_offset, new_offset, base_offset; + + HB_CaretValue* cv; + + + base_offset = FILE_Pos(); + + if ( ACCESS_Frame( 2L ) ) + return error; + + count = lg->CaretCount = GET_UShort(); + + FORGET_Frame(); + + lg->CaretValue = NULL; + + if ( ALLOC_ARRAY( lg->CaretValue, count, HB_CaretValue ) ) + return error; + + cv = lg->CaretValue; + + for ( n = 0; n < count; n++ ) + { + if ( ACCESS_Frame( 2L ) ) + goto Fail; + + new_offset = GET_UShort() + base_offset; + + FORGET_Frame(); + + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = Load_CaretValue( &cv[n], stream ) ) != FT_Err_Ok ) + goto Fail; + (void)FILE_Seek( cur_offset ); + } + + return FT_Err_Ok; + +Fail: + for ( m = 0; m < n; m++ ) + Free_CaretValue( &cv[m], memory ); + + FREE( cv ); + return error; +} + + +static void Free_LigGlyph( HB_LigGlyph* lg, + FT_Memory memory ) +{ + FT_UShort n, count; + + HB_CaretValue* cv; + + + if ( lg->CaretValue ) + { + count = lg->CaretCount; + cv = lg->CaretValue; + + for ( n = 0; n < count; n++ ) + Free_CaretValue( &cv[n], memory ); + + FREE( cv ); + } +} + + +/* LigCaretList */ + +static FT_Error Load_LigCaretList( HB_LigCaretList* lcl, + FT_Stream stream ) +{ + FT_Memory memory = stream->memory; + FT_Error error; + + FT_UShort m, n, count; + FT_ULong cur_offset, new_offset, base_offset; + + HB_LigGlyph* lg; + + + base_offset = FILE_Pos(); + + if ( ACCESS_Frame( 2L ) ) + return error; + + new_offset = GET_UShort() + base_offset; + + FORGET_Frame(); + + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = _HB_OPEN_Load_Coverage( &lcl->Coverage, stream ) ) != FT_Err_Ok ) + return error; + (void)FILE_Seek( cur_offset ); + + if ( ACCESS_Frame( 2L ) ) + goto Fail2; + + count = lcl->LigGlyphCount = GET_UShort(); + + FORGET_Frame(); + + lcl->LigGlyph = NULL; + + if ( ALLOC_ARRAY( lcl->LigGlyph, count, HB_LigGlyph ) ) + goto Fail2; + + lg = lcl->LigGlyph; + + for ( n = 0; n < count; n++ ) + { + if ( ACCESS_Frame( 2L ) ) + goto Fail1; + + new_offset = GET_UShort() + base_offset; + + FORGET_Frame(); + + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = Load_LigGlyph( &lg[n], stream ) ) != FT_Err_Ok ) + goto Fail1; + (void)FILE_Seek( cur_offset ); + } + + lcl->loaded = TRUE; + + return FT_Err_Ok; + +Fail1: + for ( m = 0; m < n; m++ ) + Free_LigGlyph( &lg[m], memory ); + + FREE( lg ); + +Fail2: + _HB_OPEN_Free_Coverage( &lcl->Coverage, memory ); + return error; +} + + +static void Free_LigCaretList( HB_LigCaretList* lcl, + FT_Memory memory ) +{ + FT_UShort n, count; + + HB_LigGlyph* lg; + + + if ( !lcl->loaded ) + return; + + if ( lcl->LigGlyph ) + { + count = lcl->LigGlyphCount; + lg = lcl->LigGlyph; + + for ( n = 0; n < count; n++ ) + Free_LigGlyph( &lg[n], memory ); + + FREE( lg ); + } + + _HB_OPEN_Free_Coverage( &lcl->Coverage, memory ); +} + + + +/*********** + * GDEF API + ***********/ + + +static FT_UShort Get_New_Class( HB_GDEFHeader* gdef, + FT_UShort glyphID, + FT_UShort index ) +{ + FT_UShort glyph_index, array_index, count; + FT_UShort byte, bits; + + HB_ClassRangeRecord* gcrr; + FT_UShort** ngc; + + + if ( glyphID >= gdef->LastGlyph ) + return 0; + + count = gdef->GlyphClassDef.cd.cd2.ClassRangeCount; + gcrr = gdef->GlyphClassDef.cd.cd2.ClassRangeRecord; + ngc = gdef->NewGlyphClasses; + + if ( index < count && glyphID < gcrr[index].Start ) + { + array_index = index; + if ( index == 0 ) + glyph_index = glyphID; + else + glyph_index = glyphID - gcrr[index - 1].End - 1; + } + else + { + array_index = index + 1; + glyph_index = glyphID - gcrr[index].End - 1; + } + + byte = ngc[array_index][glyph_index / 4]; + bits = byte >> ( 16 - ( glyph_index % 4 + 1 ) * 4 ); + + return bits & 0x000F; +} + + + +FT_Error HB_GDEF_Get_Glyph_Property( HB_GDEFHeader* gdef, + FT_UShort glyphID, + FT_UShort* property ) +{ + FT_UShort class, index; + + FT_Error error; + + + if ( !gdef || !property ) + return FT_Err_Invalid_Argument; + + /* first, we check for mark attach classes */ + + if ( gdef->MarkAttachClassDef.loaded ) + { + error = _HB_OPEN_Get_Class( &gdef->MarkAttachClassDef, glyphID, &class, &index ); + if ( error && error != HB_Err_Not_Covered ) + return error; + if ( !error ) + { + *property = class << 8; + return FT_Err_Ok; + } + } + + error = _HB_OPEN_Get_Class( &gdef->GlyphClassDef, glyphID, &class, &index ); + if ( error && error != HB_Err_Not_Covered ) + return error; + + /* if we have a constructed class table, check whether additional + values have been assigned */ + + if ( error == HB_Err_Not_Covered && gdef->NewGlyphClasses ) + class = Get_New_Class( gdef, glyphID, index ); + + switch ( class ) + { + case UNCLASSIFIED_GLYPH: + *property = 0; + break; + + case SIMPLE_GLYPH: + *property = HB_GDEF_BASE_GLYPH; + break; + + case LIGATURE_GLYPH: + *property = HB_GDEF_LIGATURE; + break; + + case MARK_GLYPH: + *property = HB_GDEF_MARK; + break; + + case COMPONENT_GLYPH: + *property = HB_GDEF_COMPONENT; + break; + } + + return FT_Err_Ok; +} + + +static FT_Error Make_ClassRange( HB_ClassDefinition* cd, + FT_UShort start, + FT_UShort end, + FT_UShort class, + FT_Memory memory ) +{ + FT_Error error; + FT_UShort index; + + HB_ClassDefFormat2* cdf2; + HB_ClassRangeRecord* crr; + + + cdf2 = &cd->cd.cd2; + + if ( REALLOC_ARRAY( cdf2->ClassRangeRecord, + cdf2->ClassRangeCount, + cdf2->ClassRangeCount + 1 , + HB_ClassRangeRecord ) ) + return error; + + cdf2->ClassRangeCount++; + + crr = cdf2->ClassRangeRecord; + index = cdf2->ClassRangeCount - 1; + + crr[index].Start = start; + crr[index].End = end; + crr[index].Class = class; + + cd->Defined[class] = TRUE; + + return FT_Err_Ok; +} + + + +FT_Error HB_GDEF_Build_ClassDefinition( HB_GDEFHeader* gdef, + FT_UShort num_glyphs, + FT_UShort glyph_count, + FT_UShort* glyph_array, + FT_UShort* class_array ) +{ + FT_UShort start, curr_glyph, curr_class; + FT_UShort n, m, count; + FT_Error error; + FT_Memory memory = gdef->memory; + + HB_ClassDefinition* gcd; + HB_ClassRangeRecord* gcrr; + FT_UShort** ngc; + + + if ( !gdef || !glyph_array || !class_array ) + return FT_Err_Invalid_Argument; + + gcd = &gdef->GlyphClassDef; + + /* We build a format 2 table */ + + gcd->ClassFormat = 2; + + /* A GlyphClassDef table contains at most 5 different class values */ + + if ( ALLOC_ARRAY( gcd->Defined, 5, FT_Bool ) ) + return error; + + gcd->cd.cd2.ClassRangeCount = 0; + gcd->cd.cd2.ClassRangeRecord = NULL; + + start = glyph_array[0]; + curr_class = class_array[0]; + curr_glyph = start; + + if ( curr_class >= 5 ) + { + error = FT_Err_Invalid_Argument; + goto Fail4; + } + + glyph_count--; + + for ( n = 0; n <= glyph_count; n++ ) + { + if ( curr_glyph == glyph_array[n] && curr_class == class_array[n] ) + { + if ( n == glyph_count ) + { + if ( ( error = Make_ClassRange( gcd, start, + curr_glyph, + curr_class, + memory ) ) != FT_Err_Ok ) + goto Fail3; + } + else + { + if ( curr_glyph == 0xFFFF ) + { + error = FT_Err_Invalid_Argument; + goto Fail3; + } + else + curr_glyph++; + } + } + else + { + if ( ( error = Make_ClassRange( gcd, start, + curr_glyph - 1, + curr_class, + memory ) ) != FT_Err_Ok ) + goto Fail3; + + if ( curr_glyph > glyph_array[n] ) + { + error = FT_Err_Invalid_Argument; + goto Fail3; + } + + start = glyph_array[n]; + curr_class = class_array[n]; + curr_glyph = start; + + if ( curr_class >= 5 ) + { + error = FT_Err_Invalid_Argument; + goto Fail3; + } + + if ( n == glyph_count ) + { + if ( ( error = Make_ClassRange( gcd, start, + curr_glyph, + curr_class, + memory ) ) != FT_Err_Ok ) + goto Fail3; + } + else + { + if ( curr_glyph == 0xFFFF ) + { + error = FT_Err_Invalid_Argument; + goto Fail3; + } + else + curr_glyph++; + } + } + } + + /* now prepare the arrays for class values assigned during the lookup + process */ + + if ( ALLOC_ARRAY( gdef->NewGlyphClasses, + gcd->cd.cd2.ClassRangeCount + 1, FT_UShort* ) ) + goto Fail3; + + count = gcd->cd.cd2.ClassRangeCount; + gcrr = gcd->cd.cd2.ClassRangeRecord; + ngc = gdef->NewGlyphClasses; + + /* We allocate arrays for all glyphs not covered by the class range + records. Each element holds four class values. */ + + if ( count > 0 ) + { + if ( gcrr[0].Start ) + { + if ( ALLOC_ARRAY( ngc[0], ( gcrr[0].Start + 3 ) / 4, FT_UShort ) ) + goto Fail2; + } + + for ( n = 1; n < count; n++ ) + { + if ( gcrr[n].Start - gcrr[n - 1].End > 1 ) + if ( ALLOC_ARRAY( ngc[n], + ( gcrr[n].Start - gcrr[n - 1].End + 2 ) / 4, + FT_UShort ) ) + goto Fail1; + } + + if ( gcrr[count - 1].End != num_glyphs - 1 ) + { + if ( ALLOC_ARRAY( ngc[count], + ( num_glyphs - gcrr[count - 1].End + 2 ) / 4, + FT_UShort ) ) + goto Fail1; + } + } + else if ( num_glyphs > 0 ) + { + if ( ALLOC_ARRAY( ngc[count], + ( num_glyphs + 3 ) / 4, + FT_UShort ) ) + goto Fail2; + } + + gdef->LastGlyph = num_glyphs - 1; + + gdef->MarkAttachClassDef_offset = 0L; + gdef->MarkAttachClassDef.loaded = FALSE; + + gcd->loaded = TRUE; + + return FT_Err_Ok; + +Fail1: + for ( m = 0; m < n; m++ ) + FREE( ngc[m] ); + +Fail2: + FREE( gdef->NewGlyphClasses ); + +Fail3: + FREE( gcd->cd.cd2.ClassRangeRecord ); + +Fail4: + FREE( gcd->Defined ); + return error; +} + + +static void Free_NewGlyphClasses( HB_GDEFHeader* gdef, + FT_Memory memory ) +{ + FT_UShort** ngc; + FT_UShort n, count; + + + if ( gdef->NewGlyphClasses ) + { + count = gdef->GlyphClassDef.cd.cd2.ClassRangeCount + 1; + ngc = gdef->NewGlyphClasses; + + for ( n = 0; n < count; n++ ) + FREE( ngc[n] ); + + FREE( ngc ); + } +} + + +FT_Error _HB_GDEF_Add_Glyph_Property( HB_GDEFHeader* gdef, + FT_UShort glyphID, + FT_UShort property ) +{ + FT_Error error; + FT_UShort class, new_class, index; + FT_UShort byte, bits, mask; + FT_UShort array_index, glyph_index, count; + + HB_ClassRangeRecord* gcrr; + FT_UShort** ngc; + + + error = _HB_OPEN_Get_Class( &gdef->GlyphClassDef, glyphID, &class, &index ); + if ( error && error != HB_Err_Not_Covered ) + return error; + + /* we don't accept glyphs covered in `GlyphClassDef' */ + + if ( !error ) + return HB_Err_Not_Covered; + + switch ( property ) + { + case 0: + new_class = UNCLASSIFIED_GLYPH; + break; + + case HB_GDEF_BASE_GLYPH: + new_class = SIMPLE_GLYPH; + break; + + case HB_GDEF_LIGATURE: + new_class = LIGATURE_GLYPH; + break; + + case HB_GDEF_MARK: + new_class = MARK_GLYPH; + break; + + case HB_GDEF_COMPONENT: + new_class = COMPONENT_GLYPH; + break; + + default: + return FT_Err_Invalid_Argument; + } + + count = gdef->GlyphClassDef.cd.cd2.ClassRangeCount; + gcrr = gdef->GlyphClassDef.cd.cd2.ClassRangeRecord; + ngc = gdef->NewGlyphClasses; + + if ( index < count && glyphID < gcrr[index].Start ) + { + array_index = index; + if ( index == 0 ) + glyph_index = glyphID; + else + glyph_index = glyphID - gcrr[index - 1].End - 1; + } + else + { + array_index = index + 1; + glyph_index = glyphID - gcrr[index].End - 1; + } + + byte = ngc[array_index][glyph_index / 4]; + bits = byte >> ( 16 - ( glyph_index % 4 + 1 ) * 4 ); + class = bits & 0x000F; + + /* we don't overwrite existing entries */ + + if ( !class ) + { + bits = new_class << ( 16 - ( glyph_index % 4 + 1 ) * 4 ); + mask = ~( 0x000F << ( 16 - ( glyph_index % 4 + 1 ) * 4 ) ); + + ngc[array_index][glyph_index / 4] &= mask; + ngc[array_index][glyph_index / 4] |= bits; + } + + return FT_Err_Ok; +} + + +FT_Error _HB_GDEF_Check_Property( HB_GDEFHeader* gdef, + HB_GlyphItem gitem, + FT_UShort flags, + FT_UShort* property ) +{ + FT_Error error; + + if ( gdef ) + { + FT_UShort basic_glyph_class; + FT_UShort desired_attachment_class; + + if ( gitem->gproperties == HB_GLYPH_PROPERTIES_UNKNOWN ) + { + error = HB_GDEF_Get_Glyph_Property( gdef, gitem->gindex, &gitem->gproperties ); + if ( error ) + return error; + } + + *property = gitem->gproperties; + + /* If the glyph was found in the MarkAttachmentClass table, + * then that class value is the high byte of the result, + * otherwise the low byte contains the basic type of the glyph + * as defined by the GlyphClassDef table. + */ + if ( *property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS ) + basic_glyph_class = HB_GDEF_MARK; + else + basic_glyph_class = *property; + + /* Return Not_Covered, if, for example, basic_glyph_class + * is HB_GDEF_LIGATURE and LookFlags includes HB_LOOKUP_FLAG_IGNORE_LIGATURES + */ + if ( flags & basic_glyph_class ) + return HB_Err_Not_Covered; + + /* The high byte of LookupFlags has the meaning + * "ignore marks of attachment type different than + * the attachment type specified." + */ + desired_attachment_class = flags & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS; + if ( desired_attachment_class ) + { + if ( basic_glyph_class == HB_GDEF_MARK && + *property != desired_attachment_class ) + return HB_Err_Not_Covered; + } + } + + return FT_Err_Ok; +} + + +/* END */ diff --git a/src/harfbuzz-gdef.h b/src/harfbuzz-gdef.h new file mode 100644 index 0000000..e126e82 --- /dev/null +++ b/src/harfbuzz-gdef.h @@ -0,0 +1,127 @@ +/******************************************************************* + * + * Copyright 1996-2000 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * Copyright 2006 Behdad Esfahbod + * + * This is part of HarfBuzz, an OpenType Layout engine library. + * + * See the file name COPYING for licensing information. + * + ******************************************************************/ +#ifndef HARFBUZZ_GDEF_H +#define HARFBUZZ_GDEF_H + +#include "harfbuzz-open.h" + +FT_BEGIN_HEADER + +#define HB_Err_Invalid_GDEF_SubTable_Format 0x1030 +#define HB_Err_Invalid_GDEF_SubTable 0x1031 + + +/* GDEF glyph properties. Note that HB_GDEF_COMPONENT has no corresponding + * flag in the LookupFlag field. */ +#define HB_GDEF_BASE_GLYPH 0x0002 +#define HB_GDEF_LIGATURE 0x0004 +#define HB_GDEF_MARK 0x0008 +#define HB_GDEF_COMPONENT 0x0010 + + +typedef struct HB_AttachPoint_ HB_AttachPoint; + + +struct HB_AttachList_ +{ + FT_Bool loaded; + + HB_Coverage Coverage; /* Coverage table */ + FT_UShort GlyphCount; /* number of glyphs with + attachments */ + HB_AttachPoint* AttachPoint; /* array of AttachPoint tables */ +}; + +typedef struct HB_AttachList_ HB_AttachList; + +typedef struct HB_LigGlyph_ HB_LigGlyph; + +struct HB_LigCaretList_ +{ + FT_Bool loaded; + + HB_Coverage Coverage; /* Coverage table */ + FT_UShort LigGlyphCount; /* number of ligature glyphs */ + HB_LigGlyph* LigGlyph; /* array of LigGlyph tables */ +}; + +typedef struct HB_LigCaretList_ HB_LigCaretList; + + + +/* The `NewGlyphClasses' field is not defined in the TTO specification. + We use it for fonts with a constructed `GlyphClassDef' structure + (i.e., which don't have a GDEF table) to collect glyph classes + assigned during the lookup process. The number of arrays in this + pointer array is GlyphClassDef->cd.cd2.ClassRangeCount+1; the nth + array then contains the glyph class values of the glyphs not covered + by the ClassRangeRecords structures with index n-1 and n. We store + glyph class values for four glyphs in a single array element. + + `LastGlyph' is identical to the number of glyphs minus one in the + font; we need it only if `NewGlyphClasses' is not NULL (to have an + upper bound for the last array). + + Note that we first store the file offset to the `MarkAttachClassDef' + field (which has been introduced in OpenType 1.2) -- since the + `Version' field value hasn't been increased to indicate that we have + one more field for some obscure reason, we must parse the GSUB table + to find out whether class values refer to this table. Only then we + can finally load the MarkAttachClassDef structure if necessary. */ + +struct HB_GDEFHeader_ +{ + FT_Memory memory; + FT_ULong offset; + + FT_Fixed Version; + + HB_ClassDefinition GlyphClassDef; + HB_AttachList AttachList; + HB_LigCaretList LigCaretList; + FT_ULong MarkAttachClassDef_offset; + HB_ClassDefinition MarkAttachClassDef; /* new in OT 1.2 */ + + FT_UShort LastGlyph; + FT_UShort** NewGlyphClasses; +}; + +typedef struct HB_GDEFHeader_ HB_GDEFHeader; +typedef struct HB_GDEFHeader_* HB_GDEF; + + +FT_Error HB_New_GDEF_Table( FT_Face face, + HB_GDEFHeader** retptr ); + + +FT_Error HB_Load_GDEF_Table( FT_Face face, + HB_GDEFHeader** gdef ); + + +FT_Error HB_Done_GDEF_Table ( HB_GDEFHeader* gdef ); + + +FT_Error HB_GDEF_Get_Glyph_Property( HB_GDEFHeader* gdef, + FT_UShort glyphID, + FT_UShort* property ); + +FT_Error HB_GDEF_Build_ClassDefinition( HB_GDEFHeader* gdef, + FT_UShort num_glyphs, + FT_UShort glyph_count, + FT_UShort* glyph_array, + FT_UShort* class_array ); + + +FT_END_HEADER + +#endif /* HARFBUZZ_GDEF_H */ diff --git a/src/harfbuzz-gpos-private.h b/src/harfbuzz-gpos-private.h new file mode 100644 index 0000000..a04416f --- /dev/null +++ b/src/harfbuzz-gpos-private.h @@ -0,0 +1,683 @@ +/******************************************************************* + * + * Copyright 1996-2000 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * Copyright 2006 Behdad Esfahbod + * + * This is part of HarfBuzz, an OpenType Layout engine library. + * + * See the file name COPYING for licensing information. + * + ******************************************************************/ +#ifndef HARFBUZZ_GPOS_PRIVATE_H +#define HARFBUZZ_GPOS_PRIVATE_H + +#include "harfbuzz-gpos.h" + +FT_BEGIN_HEADER + + +/* shared tables */ + +struct HB_ValueRecord_ +{ + FT_Short XPlacement; /* horizontal adjustment for + placement */ + FT_Short YPlacement; /* vertical adjustment for + placement */ + FT_Short XAdvance; /* horizontal adjustment for + advance */ + FT_Short YAdvance; /* vertical adjustment for + advance */ + HB_Device XPlacementDevice; /* device table for horizontal + placement */ + HB_Device YPlacementDevice; /* device table for vertical + placement */ + HB_Device XAdvanceDevice; /* device table for horizontal + advance */ + HB_Device YAdvanceDevice; /* device table for vertical + advance */ + FT_UShort XIdPlacement; /* horizontal placement metric ID */ + FT_UShort YIdPlacement; /* vertical placement metric ID */ + FT_UShort XIdAdvance; /* horizontal advance metric ID */ + FT_UShort YIdAdvance; /* vertical advance metric ID */ +}; + +typedef struct HB_ValueRecord_ HB_ValueRecord; + + +/* Mask values to scan the value format of the ValueRecord structure. + We always expand compressed ValueRecords of the font. */ + +#define HB_GPOS_FORMAT_HAVE_X_PLACEMENT 0x0001 +#define HB_GPOS_FORMAT_HAVE_Y_PLACEMENT 0x0002 +#define HB_GPOS_FORMAT_HAVE_X_ADVANCE 0x0004 +#define HB_GPOS_FORMAT_HAVE_Y_ADVANCE 0x0008 +#define HB_GPOS_FORMAT_HAVE_X_PLACEMENT_DEVICE 0x0010 +#define HB_GPOS_FORMAT_HAVE_Y_PLACEMENT_DEVICE 0x0020 +#define HB_GPOS_FORMAT_HAVE_X_ADVANCE_DEVICE 0x0040 +#define HB_GPOS_FORMAT_HAVE_Y_ADVANCE_DEVICE 0x0080 +#define HB_GPOS_FORMAT_HAVE_X_ID_PLACEMENT 0x0100 +#define HB_GPOS_FORMAT_HAVE_Y_ID_PLACEMENT 0x0200 +#define HB_GPOS_FORMAT_HAVE_X_ID_ADVANCE 0x0400 +#define HB_GPOS_FORMAT_HAVE_Y_ID_ADVANCE 0x0800 + + +struct HB_AnchorFormat1_ +{ + FT_Short XCoordinate; /* horizontal value */ + FT_Short YCoordinate; /* vertical value */ +}; + +typedef struct HB_AnchorFormat1_ HB_AnchorFormat1; + + +struct HB_AnchorFormat2_ +{ + FT_Short XCoordinate; /* horizontal value */ + FT_Short YCoordinate; /* vertical value */ + FT_UShort AnchorPoint; /* index to glyph contour point */ +}; + +typedef struct HB_AnchorFormat2_ HB_AnchorFormat2; + + +struct HB_AnchorFormat3_ +{ + FT_Short XCoordinate; /* horizontal value */ + FT_Short YCoordinate; /* vertical value */ + HB_Device XDeviceTable; /* device table for X coordinate */ + HB_Device YDeviceTable; /* device table for Y coordinate */ +}; + +typedef struct HB_AnchorFormat3_ HB_AnchorFormat3; + + +struct HB_AnchorFormat4_ +{ + FT_UShort XIdAnchor; /* horizontal metric ID */ + FT_UShort YIdAnchor; /* vertical metric ID */ +}; + +typedef struct HB_AnchorFormat4_ HB_AnchorFormat4; + + +struct HB_Anchor_ +{ + FT_UShort PosFormat; /* 1, 2, 3, or 4 -- 0 indicates + that there is no Anchor table */ + + union + { + HB_AnchorFormat1 af1; + HB_AnchorFormat2 af2; + HB_AnchorFormat3 af3; + HB_AnchorFormat4 af4; + } af; +}; + +typedef struct HB_Anchor_ HB_Anchor; + + +struct HB_MarkRecord_ +{ + FT_UShort Class; /* mark class */ + HB_Anchor MarkAnchor; /* anchor table */ +}; + +typedef struct HB_MarkRecord_ HB_MarkRecord; + + +struct HB_MarkArray_ +{ + FT_UShort MarkCount; /* number of MarkRecord tables */ + HB_MarkRecord* MarkRecord; /* array of MarkRecord tables */ +}; + +typedef struct HB_MarkArray_ HB_MarkArray; + + +/* LookupType 1 */ + +struct HB_SinglePosFormat1_ +{ + HB_ValueRecord Value; /* ValueRecord for all covered + glyphs */ +}; + +typedef struct HB_SinglePosFormat1_ HB_SinglePosFormat1; + + +struct HB_SinglePosFormat2_ +{ + FT_UShort ValueCount; /* number of ValueRecord tables */ + HB_ValueRecord* Value; /* array of ValueRecord tables */ +}; + +typedef struct HB_SinglePosFormat2_ HB_SinglePosFormat2; + + +struct HB_SinglePos_ +{ + FT_UShort PosFormat; /* 1 or 2 */ + HB_Coverage Coverage; /* Coverage table */ + + FT_UShort ValueFormat; /* format of ValueRecord table */ + + union + { + HB_SinglePosFormat1 spf1; + HB_SinglePosFormat2 spf2; + } spf; +}; + +typedef struct HB_SinglePos_ HB_SinglePos; + + +/* LookupType 2 */ + +struct HB_PairValueRecord_ +{ + FT_UShort SecondGlyph; /* glyph ID for second glyph */ + HB_ValueRecord Value1; /* pos. data for first glyph */ + HB_ValueRecord Value2; /* pos. data for second glyph */ +}; + +typedef struct HB_PairValueRecord_ HB_PairValueRecord; + + +struct HB_PairSet_ +{ + FT_UShort PairValueCount; + /* number of PairValueRecord tables */ + HB_PairValueRecord* PairValueRecord; + /* array of PairValueRecord tables */ +}; + +typedef struct HB_PairSet_ HB_PairSet; + + +struct HB_PairPosFormat1_ +{ + FT_UShort PairSetCount; /* number of PairSet tables */ + HB_PairSet* PairSet; /* array of PairSet tables */ +}; + +typedef struct HB_PairPosFormat1_ HB_PairPosFormat1; + + +struct HB_Class2Record_ +{ + HB_ValueRecord Value1; /* pos. data for first glyph */ + HB_ValueRecord Value2; /* pos. data for second glyph */ +}; + +typedef struct HB_Class2Record_ HB_Class2Record; + + +struct HB_Class1Record_ +{ + HB_Class2Record* Class2Record; /* array of Class2Record tables */ +}; + +typedef struct HB_Class1Record_ HB_Class1Record; + + +struct HB_PairPosFormat2_ +{ + HB_ClassDefinition ClassDef1; /* class def. for first glyph */ + HB_ClassDefinition ClassDef2; /* class def. for second glyph */ + FT_UShort Class1Count; /* number of classes in ClassDef1 + table */ + FT_UShort Class2Count; /* number of classes in ClassDef2 + table */ + HB_Class1Record* Class1Record; /* array of Class1Record tables */ +}; + +typedef struct HB_PairPosFormat2_ HB_PairPosFormat2; + + +struct HB_PairPos_ +{ + FT_UShort PosFormat; /* 1 or 2 */ + HB_Coverage Coverage; /* Coverage table */ + FT_UShort ValueFormat1; /* format of ValueRecord table + for first glyph */ + FT_UShort ValueFormat2; /* format of ValueRecord table + for second glyph */ + + union + { + HB_PairPosFormat1 ppf1; + HB_PairPosFormat2 ppf2; + } ppf; +}; + +typedef struct HB_PairPos_ HB_PairPos; + + +/* LookupType 3 */ + +struct HB_EntryExitRecord_ +{ + HB_Anchor EntryAnchor; /* entry Anchor table */ + HB_Anchor ExitAnchor; /* exit Anchor table */ +}; + + +typedef struct HB_EntryExitRecord_ HB_EntryExitRecord; + +struct HB_CursivePos_ +{ + FT_UShort PosFormat; /* always 1 */ + HB_Coverage Coverage; /* Coverage table */ + FT_UShort EntryExitCount; + /* number of EntryExitRecord tables */ + HB_EntryExitRecord* EntryExitRecord; + /* array of EntryExitRecord tables */ +}; + +typedef struct HB_CursivePos_ HB_CursivePos; + + +/* LookupType 4 */ + +struct HB_BaseRecord_ +{ + HB_Anchor* BaseAnchor; /* array of base glyph anchor + tables */ +}; + +typedef struct HB_BaseRecord_ HB_BaseRecord; + + +struct HB_BaseArray_ +{ + FT_UShort BaseCount; /* number of BaseRecord tables */ + HB_BaseRecord* BaseRecord; /* array of BaseRecord tables */ +}; + +typedef struct HB_BaseArray_ HB_BaseArray; + + +struct HB_MarkBasePos_ +{ + FT_UShort PosFormat; /* always 1 */ + HB_Coverage MarkCoverage; /* mark glyph coverage table */ + HB_Coverage BaseCoverage; /* base glyph coverage table */ + FT_UShort ClassCount; /* number of mark classes */ + HB_MarkArray MarkArray; /* mark array table */ + HB_BaseArray BaseArray; /* base array table */ +}; + +typedef struct HB_MarkBasePos_ HB_MarkBasePos; + + +/* LookupType 5 */ + +struct HB_ComponentRecord_ +{ + HB_Anchor* LigatureAnchor; /* array of ligature glyph anchor + tables */ +}; + +typedef struct HB_ComponentRecord_ HB_ComponentRecord; + + +struct HB_LigatureAttach_ +{ + FT_UShort ComponentCount; + /* number of ComponentRecord tables */ + HB_ComponentRecord* ComponentRecord; + /* array of ComponentRecord tables */ +}; + +typedef struct HB_LigatureAttach_ HB_LigatureAttach; + + +struct HB_LigatureArray_ +{ + FT_UShort LigatureCount; /* number of LigatureAttach tables */ + HB_LigatureAttach* LigatureAttach; + /* array of LigatureAttach tables */ +}; + +typedef struct HB_LigatureArray_ HB_LigatureArray; + + +struct HB_MarkLigPos_ +{ + FT_UShort PosFormat; /* always 1 */ + HB_Coverage MarkCoverage; /* mark glyph coverage table */ + HB_Coverage LigatureCoverage; + /* ligature glyph coverage table */ + FT_UShort ClassCount; /* number of mark classes */ + HB_MarkArray MarkArray; /* mark array table */ + HB_LigatureArray LigatureArray; /* ligature array table */ +}; + +typedef struct HB_MarkLigPos_ HB_MarkLigPos; + + +/* LookupType 6 */ + +struct HB_Mark2Record_ +{ + HB_Anchor* Mark2Anchor; /* array of mark glyph anchor + tables */ +}; + +typedef struct HB_Mark2Record_ HB_Mark2Record; + + +struct HB_Mark2Array_ +{ + FT_UShort Mark2Count; /* number of Mark2Record tables */ + HB_Mark2Record* Mark2Record; /* array of Mark2Record tables */ +}; + +typedef struct HB_Mark2Array_ HB_Mark2Array; + + +struct HB_MarkMarkPos_ +{ + FT_UShort PosFormat; /* always 1 */ + HB_Coverage Mark1Coverage; /* first mark glyph coverage table */ + HB_Coverage Mark2Coverage; /* second mark glyph coverave table */ + FT_UShort ClassCount; /* number of combining mark classes */ + HB_MarkArray Mark1Array; /* MarkArray table for first mark */ + HB_Mark2Array Mark2Array; /* MarkArray table for second mark */ +}; + +typedef struct HB_MarkMarkPos_ HB_MarkMarkPos; + + +/* needed by both lookup type 7 and 8 */ + +struct HB_PosLookupRecord_ +{ + FT_UShort SequenceIndex; /* index into current + glyph sequence */ + FT_UShort LookupListIndex; /* Lookup to apply to that pos. */ +}; + +typedef struct HB_PosLookupRecord_ HB_PosLookupRecord; + + +/* LookupType 7 */ + +struct HB_PosRule_ +{ + FT_UShort GlyphCount; /* total number of input glyphs */ + FT_UShort PosCount; /* number of PosLookupRecord tables */ + FT_UShort* Input; /* array of input glyph IDs */ + HB_PosLookupRecord* PosLookupRecord; + /* array of PosLookupRecord tables */ +}; + +typedef struct HB_PosRule_ HB_PosRule; + + +struct HB_PosRuleSet_ +{ + FT_UShort PosRuleCount; /* number of PosRule tables */ + HB_PosRule* PosRule; /* array of PosRule tables */ +}; + +typedef struct HB_PosRuleSet_ HB_PosRuleSet; + + +struct HB_ContextPosFormat1_ +{ + HB_Coverage Coverage; /* Coverage table */ + FT_UShort PosRuleSetCount; /* number of PosRuleSet tables */ + HB_PosRuleSet* PosRuleSet; /* array of PosRuleSet tables */ +}; + +typedef struct HB_ContextPosFormat1_ HB_ContextPosFormat1; + + +struct HB_PosClassRule_ +{ + FT_UShort GlyphCount; /* total number of context classes */ + FT_UShort PosCount; /* number of PosLookupRecord tables */ + FT_UShort* Class; /* array of classes */ + HB_PosLookupRecord* PosLookupRecord; + /* array of PosLookupRecord tables */ +}; + +typedef struct HB_PosClassRule_ HB_PosClassRule; + + +struct HB_PosClassSet_ +{ + FT_UShort PosClassRuleCount; + /* number of PosClassRule tables */ + HB_PosClassRule* PosClassRule; /* array of PosClassRule tables */ +}; + +typedef struct HB_PosClassSet_ HB_PosClassSet; + + +/* The `MaxContextLength' field is not defined in the TTO specification + but simplifies the implementation of this format. It holds the + maximal context length used in the context rules. */ + +struct HB_ContextPosFormat2_ +{ + FT_UShort MaxContextLength; + /* maximal context length */ + HB_Coverage Coverage; /* Coverage table */ + HB_ClassDefinition ClassDef; /* ClassDef table */ + FT_UShort PosClassSetCount; + /* number of PosClassSet tables */ + HB_PosClassSet* PosClassSet; /* array of PosClassSet tables */ +}; + +typedef struct HB_ContextPosFormat2_ HB_ContextPosFormat2; + + +struct HB_ContextPosFormat3_ +{ + FT_UShort GlyphCount; /* number of input glyphs */ + FT_UShort PosCount; /* number of PosLookupRecord tables */ + HB_Coverage* Coverage; /* array of Coverage tables */ + HB_PosLookupRecord* PosLookupRecord; + /* array of PosLookupRecord tables */ +}; + +typedef struct HB_ContextPosFormat3_ HB_ContextPosFormat3; + + +struct HB_ContextPos_ +{ + FT_UShort PosFormat; /* 1, 2, or 3 */ + + union + { + HB_ContextPosFormat1 cpf1; + HB_ContextPosFormat2 cpf2; + HB_ContextPosFormat3 cpf3; + } cpf; +}; + +typedef struct HB_ContextPos_ HB_ContextPos; + + +/* LookupType 8 */ + +struct HB_ChainPosRule_ +{ + FT_UShort BacktrackGlyphCount; + /* total number of backtrack glyphs */ + FT_UShort* Backtrack; /* array of backtrack glyph IDs */ + FT_UShort InputGlyphCount; + /* total number of input glyphs */ + FT_UShort* Input; /* array of input glyph IDs */ + FT_UShort LookaheadGlyphCount; + /* total number of lookahead glyphs */ + FT_UShort* Lookahead; /* array of lookahead glyph IDs */ + FT_UShort PosCount; /* number of PosLookupRecords */ + HB_PosLookupRecord* PosLookupRecord; + /* array of PosLookupRecords */ +}; + +typedef struct HB_ChainPosRule_ HB_ChainPosRule; + + +struct HB_ChainPosRuleSet_ +{ + FT_UShort ChainPosRuleCount; + /* number of ChainPosRule tables */ + HB_ChainPosRule* ChainPosRule; /* array of ChainPosRule tables */ +}; + +typedef struct HB_ChainPosRuleSet_ HB_ChainPosRuleSet; + + +struct HB_ChainContextPosFormat1_ +{ + HB_Coverage Coverage; /* Coverage table */ + FT_UShort ChainPosRuleSetCount; + /* number of ChainPosRuleSet tables */ + HB_ChainPosRuleSet* ChainPosRuleSet; + /* array of ChainPosRuleSet tables */ +}; + +typedef struct HB_ChainContextPosFormat1_ HB_ChainContextPosFormat1; + + +struct HB_ChainPosClassRule_ +{ + FT_UShort BacktrackGlyphCount; + /* total number of backtrack + classes */ + FT_UShort* Backtrack; /* array of backtrack classes */ + FT_UShort InputGlyphCount; + /* total number of context classes */ + FT_UShort* Input; /* array of context classes */ + FT_UShort LookaheadGlyphCount; + /* total number of lookahead + classes */ + FT_UShort* Lookahead; /* array of lookahead classes */ + FT_UShort PosCount; /* number of PosLookupRecords */ + HB_PosLookupRecord* PosLookupRecord; + /* array of substitution lookups */ +}; + +typedef struct HB_ChainPosClassRule_ HB_ChainPosClassRule; + + +struct HB_ChainPosClassSet_ +{ + FT_UShort ChainPosClassRuleCount; + /* number of ChainPosClassRule + tables */ + HB_ChainPosClassRule* ChainPosClassRule; + /* array of ChainPosClassRule + tables */ +}; + +typedef struct HB_ChainPosClassSet_ HB_ChainPosClassSet; + + +/* The `MaxXXXLength' fields are not defined in the TTO specification + but simplifies the implementation of this format. It holds the + maximal context length used in the specific context rules. */ + +struct HB_ChainContextPosFormat2_ +{ + HB_Coverage Coverage; /* Coverage table */ + + FT_UShort MaxBacktrackLength; + /* maximal backtrack length */ + HB_ClassDefinition BacktrackClassDef; + /* BacktrackClassDef table */ + FT_UShort MaxInputLength; + /* maximal input length */ + HB_ClassDefinition InputClassDef; + /* InputClassDef table */ + FT_UShort MaxLookaheadLength; + /* maximal lookahead length */ + HB_ClassDefinition LookaheadClassDef; + /* LookaheadClassDef table */ + + FT_UShort ChainPosClassSetCount; + /* number of ChainPosClassSet + tables */ + HB_ChainPosClassSet* ChainPosClassSet; + /* array of ChainPosClassSet + tables */ +}; + +typedef struct HB_ChainContextPosFormat2_ HB_ChainContextPosFormat2; + + +struct HB_ChainContextPosFormat3_ +{ + FT_UShort BacktrackGlyphCount; + /* number of backtrack glyphs */ + HB_Coverage* BacktrackCoverage; + /* array of backtrack Coverage + tables */ + FT_UShort InputGlyphCount; + /* number of input glyphs */ + HB_Coverage* InputCoverage; + /* array of input coverage + tables */ + FT_UShort LookaheadGlyphCount; + /* number of lookahead glyphs */ + HB_Coverage* LookaheadCoverage; + /* array of lookahead coverage + tables */ + FT_UShort PosCount; /* number of PosLookupRecords */ + HB_PosLookupRecord* PosLookupRecord; + /* array of substitution lookups */ +}; + +typedef struct HB_ChainContextPosFormat3_ HB_ChainContextPosFormat3; + + +struct HB_ChainContextPos_ +{ + FT_UShort PosFormat; /* 1, 2, or 3 */ + + union + { + HB_ChainContextPosFormat1 ccpf1; + HB_ChainContextPosFormat2 ccpf2; + HB_ChainContextPosFormat3 ccpf3; + } ccpf; +}; + +typedef struct HB_ChainContextPos_ HB_ChainContextPos; + + +union HB_GPOS_SubTable_ +{ + HB_SinglePos single; + HB_PairPos pair; + HB_CursivePos cursive; + HB_MarkBasePos markbase; + HB_MarkLigPos marklig; + HB_MarkMarkPos markmark; + HB_ContextPos context; + HB_ChainContextPos chain; +}; + +typedef union HB_GPOS_SubTable_ HB_GPOS_SubTable; + + + +FT_Error _HB_GPOS_Load_SubTable( HB_GPOS_SubTable* st, + FT_Stream stream, + FT_UShort lookup_type ); + +void _HB_GPOS_Free_SubTable( HB_GPOS_SubTable* st, + FT_Memory memory, + FT_UShort lookup_type ); + +FT_END_HEADER + +#endif /* HARFBUZZ_GPOS_PRIVATE_H */ diff --git a/src/harfbuzz-gpos.c b/src/harfbuzz-gpos.c new file mode 100644 index 0000000..8143eac --- /dev/null +++ b/src/harfbuzz-gpos.c @@ -0,0 +1,6269 @@ +/******************************************************************* + * + * Copyright 1996-2000 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * Copyright 2006 Behdad Esfahbod + * + * This is part of HarfBuzz, an OpenType Layout engine library. + * + * See the file name COPYING for licensing information. + * + ******************************************************************/ +#include "harfbuzz-impl.h" +#include "harfbuzz-gpos-private.h" +#include "harfbuzz-open-private.h" +#include "harfbuzz-gdef-private.h" + +#include FT_TRUETYPE_TAGS_H + + +struct GPOS_Instance_ +{ + HB_GPOSHeader* gpos; + FT_Face face; + FT_Bool dvi; + FT_UShort load_flags; /* how the glyph should be loaded */ + FT_Bool r2l; + + FT_UShort last; /* the last valid glyph -- used + with cursive positioning */ + FT_Pos anchor_x; /* the coordinates of the anchor point */ + FT_Pos anchor_y; /* of the last valid glyph */ +}; + +typedef struct GPOS_Instance_ GPOS_Instance; + + +static FT_Error GPOS_Do_Glyph_Lookup( GPOS_Instance* gpi, + FT_UShort lookup_index, + HB_Buffer buffer, + FT_UShort context_length, + int nesting_level ); + + + +/* the client application must replace this with something more + meaningful if multiple master fonts are to be supported. */ + +static FT_Error default_mmfunc( FT_Face face, + FT_UShort metric_id, + FT_Pos* metric_value, + void* data ) +{ + return HB_Err_No_MM_Interpreter; +} + + + +FT_Error HB_Load_GPOS_Table( FT_Face face, + HB_GPOSHeader** retptr, + HB_GDEFHeader* gdef ) +{ + FT_ULong cur_offset, new_offset, base_offset; + + FT_UShort i, num_lookups; + HB_GPOSHeader* gpos; + HB_Lookup* lo; + + FT_Stream stream = face->stream; + FT_Error error; + FT_Memory memory = face->memory; + + + if ( !retptr ) + return FT_Err_Invalid_Argument; + + if ( !stream ) + return FT_Err_Invalid_Face_Handle; + + if (( error = _hb_ftglue_face_goto_table( face, TTAG_GPOS, stream ) )) + return error; + + base_offset = FILE_Pos(); + + if ( ALLOC ( gpos, sizeof( *gpos ) ) ) + return error; + + gpos->memory = memory; + gpos->gfunc = FT_Load_Glyph; + gpos->mmfunc = default_mmfunc; + + /* skip version */ + + if ( FILE_Seek( base_offset + 4L ) || + ACCESS_Frame( 2L ) ) + goto Fail4; + + new_offset = GET_UShort() + base_offset; + + FORGET_Frame(); + + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = _HB_OPEN_Load_ScriptList( &gpos->ScriptList, + stream ) ) != FT_Err_Ok ) + goto Fail4; + (void)FILE_Seek( cur_offset ); + + if ( ACCESS_Frame( 2L ) ) + goto Fail3; + + new_offset = GET_UShort() + base_offset; + + FORGET_Frame(); + + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = _HB_OPEN_Load_FeatureList( &gpos->FeatureList, + stream ) ) != FT_Err_Ok ) + goto Fail3; + (void)FILE_Seek( cur_offset ); + + if ( ACCESS_Frame( 2L ) ) + goto Fail2; + + new_offset = GET_UShort() + base_offset; + + FORGET_Frame(); + + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = _HB_OPEN_Load_LookupList( &gpos->LookupList, + stream, HB_Type_GPOS ) ) != FT_Err_Ok ) + goto Fail2; + + gpos->gdef = gdef; /* can be NULL */ + + /* We now check the LookupFlags for values larger than 0xFF to find + out whether we need to load the `MarkAttachClassDef' field of the + GDEF table -- this hack is necessary for OpenType 1.2 tables since + the version field of the GDEF table hasn't been incremented. + + For constructed GDEF tables, we only load it if + `MarkAttachClassDef_offset' is not zero (nevertheless, a build of + a constructed mark attach table is not supported currently). */ + + if ( gdef && + gdef->MarkAttachClassDef_offset && !gdef->MarkAttachClassDef.loaded ) + { + lo = gpos->LookupList.Lookup; + num_lookups = gpos->LookupList.LookupCount; + + for ( i = 0; i < num_lookups; i++ ) + { + if ( lo[i].LookupFlag & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS ) + { + if ( FILE_Seek( gdef->MarkAttachClassDef_offset ) || + ( error = _HB_OPEN_Load_ClassDefinition( &gdef->MarkAttachClassDef, + 256, stream ) ) != FT_Err_Ok ) + goto Fail1; + + break; + } + } + } + + *retptr = gpos; + + return FT_Err_Ok; + +Fail1: + _HB_OPEN_Free_LookupList( &gpos->LookupList, HB_Type_GPOS, memory ); + +Fail2: + _HB_OPEN_Free_FeatureList( &gpos->FeatureList, memory ); + +Fail3: + _HB_OPEN_Free_ScriptList( &gpos->ScriptList, memory ); + +Fail4: + FREE( gpos ); + + return error; +} + + +FT_Error HB_Done_GPOS_Table( HB_GPOSHeader* gpos ) +{ + FT_Memory memory = gpos->memory; + + _HB_OPEN_Free_LookupList( &gpos->LookupList, HB_Type_GPOS, memory ); + _HB_OPEN_Free_FeatureList( &gpos->FeatureList, memory ); + _HB_OPEN_Free_ScriptList( &gpos->ScriptList, memory ); + + return FT_Err_Ok; +} + + +/***************************** + * SubTable related functions + *****************************/ + +/* shared tables */ + +/* ValueRecord */ + +/* There is a subtle difference in the specs between a `table' and a + `record' -- offsets for device tables in ValueRecords are taken from + the parent table and not the parent record. */ + +static FT_Error Load_ValueRecord( HB_ValueRecord* vr, + FT_UShort format, + FT_ULong base_offset, + FT_Stream stream ) +{ + FT_Error error; + FT_Memory memory = stream->memory; + + FT_ULong cur_offset, new_offset; + + + if ( format & HB_GPOS_FORMAT_HAVE_X_PLACEMENT ) + { + if ( ACCESS_Frame( 2L ) ) + return error; + + vr->XPlacement = GET_Short(); + + FORGET_Frame(); + } + else + vr->XPlacement = 0; + + if ( format & HB_GPOS_FORMAT_HAVE_Y_PLACEMENT ) + { + if ( ACCESS_Frame( 2L ) ) + return error; + + vr->YPlacement = GET_Short(); + + FORGET_Frame(); + } + else + vr->YPlacement = 0; + + if ( format & HB_GPOS_FORMAT_HAVE_X_ADVANCE ) + { + if ( ACCESS_Frame( 2L ) ) + return error; + + vr->XAdvance = GET_Short(); + + FORGET_Frame(); + } + else + vr->XAdvance = 0; + + if ( format & HB_GPOS_FORMAT_HAVE_Y_ADVANCE ) + { + if ( ACCESS_Frame( 2L ) ) + return error; + + vr->YAdvance = GET_Short(); + + FORGET_Frame(); + } + else + vr->YAdvance = 0; + + if ( format & HB_GPOS_FORMAT_HAVE_X_PLACEMENT_DEVICE ) + { + if ( ACCESS_Frame( 2L ) ) + return error; + + new_offset = GET_UShort(); + + FORGET_Frame(); + + if ( new_offset ) + { + new_offset += base_offset; + + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = _HB_OPEN_Load_Device( &vr->XPlacementDevice, + stream ) ) != FT_Err_Ok ) + return error; + (void)FILE_Seek( cur_offset ); + } + else + goto empty1; + } + else + { + empty1: + vr->XPlacementDevice.StartSize = 0; + vr->XPlacementDevice.EndSize = 0; + vr->XPlacementDevice.DeltaValue = NULL; + } + + if ( format & HB_GPOS_FORMAT_HAVE_Y_PLACEMENT_DEVICE ) + { + if ( ACCESS_Frame( 2L ) ) + goto Fail3; + + new_offset = GET_UShort(); + + FORGET_Frame(); + + if ( new_offset ) + { + new_offset += base_offset; + + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = _HB_OPEN_Load_Device( &vr->YPlacementDevice, + stream ) ) != FT_Err_Ok ) + goto Fail3; + (void)FILE_Seek( cur_offset ); + } + else + goto empty2; + } + else + { + empty2: + vr->YPlacementDevice.StartSize = 0; + vr->YPlacementDevice.EndSize = 0; + vr->YPlacementDevice.DeltaValue = NULL; + } + + if ( format & HB_GPOS_FORMAT_HAVE_X_ADVANCE_DEVICE ) + { + if ( ACCESS_Frame( 2L ) ) + goto Fail2; + + new_offset = GET_UShort(); + + FORGET_Frame(); + + if ( new_offset ) + { + new_offset += base_offset; + + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = _HB_OPEN_Load_Device( &vr->XAdvanceDevice, + stream ) ) != FT_Err_Ok ) + goto Fail2; + (void)FILE_Seek( cur_offset ); + } + else + goto empty3; + } + else + { + empty3: + vr->XAdvanceDevice.StartSize = 0; + vr->XAdvanceDevice.EndSize = 0; + vr->XAdvanceDevice.DeltaValue = NULL; + } + + if ( format & HB_GPOS_FORMAT_HAVE_Y_ADVANCE_DEVICE ) + { + if ( ACCESS_Frame( 2L ) ) + goto Fail1; + + new_offset = GET_UShort(); + + FORGET_Frame(); + + if ( new_offset ) + { + new_offset += base_offset; + + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = _HB_OPEN_Load_Device( &vr->YAdvanceDevice, + stream ) ) != FT_Err_Ok ) + goto Fail1; + (void)FILE_Seek( cur_offset ); + } + else + goto empty4; + } + else + { + empty4: + vr->YAdvanceDevice.StartSize = 0; + vr->YAdvanceDevice.EndSize = 0; + vr->YAdvanceDevice.DeltaValue = NULL; + } + + if ( format & HB_GPOS_FORMAT_HAVE_X_ID_PLACEMENT ) + { + if ( ACCESS_Frame( 2L ) ) + goto Fail1; + + vr->XIdPlacement = GET_UShort(); + + FORGET_Frame(); + } + else + vr->XIdPlacement = 0; + + if ( format & HB_GPOS_FORMAT_HAVE_Y_ID_PLACEMENT ) + { + if ( ACCESS_Frame( 2L ) ) + goto Fail1; + + vr->YIdPlacement = GET_UShort(); + + FORGET_Frame(); + } + else + vr->YIdPlacement = 0; + + if ( format & HB_GPOS_FORMAT_HAVE_X_ID_ADVANCE ) + { + if ( ACCESS_Frame( 2L ) ) + goto Fail1; + + vr->XIdAdvance = GET_UShort(); + + FORGET_Frame(); + } + else + vr->XIdAdvance = 0; + + if ( format & HB_GPOS_FORMAT_HAVE_Y_ID_ADVANCE ) + { + if ( ACCESS_Frame( 2L ) ) + goto Fail1; + + vr->YIdAdvance = GET_UShort(); + + FORGET_Frame(); + } + else + vr->YIdAdvance = 0; + + return FT_Err_Ok; + +Fail1: + _HB_OPEN_Free_Device( &vr->YAdvanceDevice, memory ); + +Fail2: + _HB_OPEN_Free_Device( &vr->XAdvanceDevice, memory ); + +Fail3: + _HB_OPEN_Free_Device( &vr->YPlacementDevice, memory ); + return error; +} + + +static void Free_ValueRecord( HB_ValueRecord* vr, + FT_UShort format, + FT_Memory memory ) +{ + if ( format & HB_GPOS_FORMAT_HAVE_Y_ADVANCE_DEVICE ) + _HB_OPEN_Free_Device( &vr->YAdvanceDevice, memory ); + if ( format & HB_GPOS_FORMAT_HAVE_X_ADVANCE_DEVICE ) + _HB_OPEN_Free_Device( &vr->XAdvanceDevice, memory ); + if ( format & HB_GPOS_FORMAT_HAVE_Y_PLACEMENT_DEVICE ) + _HB_OPEN_Free_Device( &vr->YPlacementDevice, memory ); + if ( format & HB_GPOS_FORMAT_HAVE_X_PLACEMENT_DEVICE ) + _HB_OPEN_Free_Device( &vr->XPlacementDevice, memory ); +} + + +static FT_Error Get_ValueRecord( GPOS_Instance* gpi, + HB_ValueRecord* vr, + FT_UShort format, + HB_Position gd ) +{ + FT_Pos value; + FT_Short pixel_value; + FT_Error error = FT_Err_Ok; + HB_GPOSHeader* gpos = gpi->gpos; + + FT_UShort x_ppem, y_ppem; + FT_Fixed x_scale, y_scale; + + + if ( !format ) + return FT_Err_Ok; + + x_ppem = gpi->face->size->metrics.x_ppem; + y_ppem = gpi->face->size->metrics.y_ppem; + x_scale = gpi->face->size->metrics.x_scale; + y_scale = gpi->face->size->metrics.y_scale; + + /* design units -> fractional pixel */ + + if ( format & HB_GPOS_FORMAT_HAVE_X_PLACEMENT ) + gd->x_pos += x_scale * vr->XPlacement / 0x10000; + if ( format & HB_GPOS_FORMAT_HAVE_Y_PLACEMENT ) + gd->y_pos += y_scale * vr->YPlacement / 0x10000; + if ( format & HB_GPOS_FORMAT_HAVE_X_ADVANCE ) + gd->x_advance += x_scale * vr->XAdvance / 0x10000; + if ( format & HB_GPOS_FORMAT_HAVE_Y_ADVANCE ) + gd->y_advance += y_scale * vr->YAdvance / 0x10000; + + if ( !gpi->dvi ) + { + /* pixel -> fractional pixel */ + + if ( format & HB_GPOS_FORMAT_HAVE_X_PLACEMENT_DEVICE ) + { + _HB_OPEN_Get_Device( &vr->XPlacementDevice, x_ppem, &pixel_value ); + gd->x_pos += pixel_value << 6; + } + if ( format & HB_GPOS_FORMAT_HAVE_Y_PLACEMENT_DEVICE ) + { + _HB_OPEN_Get_Device( &vr->YPlacementDevice, y_ppem, &pixel_value ); + gd->y_pos += pixel_value << 6; + } + if ( format & HB_GPOS_FORMAT_HAVE_X_ADVANCE_DEVICE ) + { + _HB_OPEN_Get_Device( &vr->XAdvanceDevice, x_ppem, &pixel_value ); + gd->x_advance += pixel_value << 6; + } + if ( format & HB_GPOS_FORMAT_HAVE_Y_ADVANCE_DEVICE ) + { + _HB_OPEN_Get_Device( &vr->YAdvanceDevice, y_ppem, &pixel_value ); + gd->y_advance += pixel_value << 6; + } + } + + /* values returned from mmfunc() are already in fractional pixels */ + + if ( format & HB_GPOS_FORMAT_HAVE_X_ID_PLACEMENT ) + { + error = (gpos->mmfunc)( gpi->face, vr->XIdPlacement, + &value, gpos->data ); + if ( error ) + return error; + gd->x_pos += value; + } + if ( format & HB_GPOS_FORMAT_HAVE_Y_ID_PLACEMENT ) + { + error = (gpos->mmfunc)( gpi->face, vr->YIdPlacement, + &value, gpos->data ); + if ( error ) + return error; + gd->y_pos += value; + } + if ( format & HB_GPOS_FORMAT_HAVE_X_ID_ADVANCE ) + { + error = (gpos->mmfunc)( gpi->face, vr->XIdAdvance, + &value, gpos->data ); + if ( error ) + return error; + gd->x_advance += value; + } + if ( format & HB_GPOS_FORMAT_HAVE_Y_ID_ADVANCE ) + { + error = (gpos->mmfunc)( gpi->face, vr->YIdAdvance, + &value, gpos->data ); + if ( error ) + return error; + gd->y_advance += value; + } + + return error; +} + + +/* AnchorFormat1 */ +/* AnchorFormat2 */ +/* AnchorFormat3 */ +/* AnchorFormat4 */ + +static FT_Error Load_Anchor( HB_Anchor* an, + FT_Stream stream ) +{ + FT_Error error; + FT_Memory memory = stream->memory; + + FT_ULong cur_offset, new_offset, base_offset; + + + base_offset = FILE_Pos(); + + if ( ACCESS_Frame( 2L ) ) + return error; + + an->PosFormat = GET_UShort(); + + FORGET_Frame(); + + switch ( an->PosFormat ) + { + case 1: + if ( ACCESS_Frame( 4L ) ) + return error; + + an->af.af1.XCoordinate = GET_Short(); + an->af.af1.YCoordinate = GET_Short(); + + FORGET_Frame(); + break; + + case 2: + if ( ACCESS_Frame( 6L ) ) + return error; + + an->af.af2.XCoordinate = GET_Short(); + an->af.af2.YCoordinate = GET_Short(); + an->af.af2.AnchorPoint = GET_UShort(); + + FORGET_Frame(); + break; + + case 3: + if ( ACCESS_Frame( 6L ) ) + return error; + + an->af.af3.XCoordinate = GET_Short(); + an->af.af3.YCoordinate = GET_Short(); + + new_offset = GET_UShort(); + + FORGET_Frame(); + + if ( new_offset ) + { + new_offset += base_offset; + + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = _HB_OPEN_Load_Device( &an->af.af3.XDeviceTable, + stream ) ) != FT_Err_Ok ) + return error; + (void)FILE_Seek( cur_offset ); + } + else + { + an->af.af3.XDeviceTable.StartSize = 0; + an->af.af3.XDeviceTable.EndSize = 0; + an->af.af3.XDeviceTable.DeltaValue = NULL; + } + + if ( ACCESS_Frame( 2L ) ) + goto Fail; + + new_offset = GET_UShort(); + + FORGET_Frame(); + + if ( new_offset ) + { + new_offset += base_offset; + + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = _HB_OPEN_Load_Device( &an->af.af3.YDeviceTable, + stream ) ) != FT_Err_Ok ) + goto Fail; + (void)FILE_Seek( cur_offset ); + } + else + { + an->af.af3.YDeviceTable.StartSize = 0; + an->af.af3.YDeviceTable.EndSize = 0; + an->af.af3.YDeviceTable.DeltaValue = NULL; + } + break; + + case 4: + if ( ACCESS_Frame( 4L ) ) + return error; + + an->af.af4.XIdAnchor = GET_UShort(); + an->af.af4.YIdAnchor = GET_UShort(); + + FORGET_Frame(); + break; + + default: + return HB_Err_Invalid_GPOS_SubTable_Format; + } + + return FT_Err_Ok; + +Fail: + _HB_OPEN_Free_Device( &an->af.af3.XDeviceTable, memory ); + return error; +} + + +static void Free_Anchor( HB_Anchor* an, + FT_Memory memory) +{ + if ( an->PosFormat == 3 ) + { + _HB_OPEN_Free_Device( &an->af.af3.YDeviceTable, memory ); + _HB_OPEN_Free_Device( &an->af.af3.XDeviceTable, memory ); + } +} + + +static FT_Error Get_Anchor( GPOS_Instance* gpi, + HB_Anchor* an, + FT_UShort glyph_index, + FT_Pos* x_value, + FT_Pos* y_value ) +{ + FT_Error error = FT_Err_Ok; + + FT_Outline outline; + HB_GPOSHeader* gpos = gpi->gpos; + FT_UShort ap; + + FT_Short pixel_value; + FT_UShort load_flags; + + FT_UShort x_ppem, y_ppem; + FT_Fixed x_scale, y_scale; + + + x_ppem = gpi->face->size->metrics.x_ppem; + y_ppem = gpi->face->size->metrics.y_ppem; + x_scale = gpi->face->size->metrics.x_scale; + y_scale = gpi->face->size->metrics.y_scale; + + switch ( an->PosFormat ) + { + case 0: + /* The special case of an empty AnchorTable */ + + return HB_Err_Not_Covered; + + case 1: + *x_value = x_scale * an->af.af1.XCoordinate / 0x10000; + *y_value = y_scale * an->af.af1.YCoordinate / 0x10000; + break; + + case 2: + /* glyphs must be scaled */ + + load_flags = gpi->load_flags & ~FT_LOAD_NO_SCALE; + + if ( !gpi->dvi ) + { + error = (gpos->gfunc)( gpi->face, glyph_index, load_flags ); + if ( error ) + return error; + + if ( gpi->face->glyph->format != ft_glyph_format_outline ) + return HB_Err_Invalid_GPOS_SubTable; + + ap = an->af.af2.AnchorPoint; + + outline = gpi->face->glyph->outline; + + /* if outline.n_points is set to zero by gfunc(), we use the + design coordinate value pair. This can happen e.g. for + sbit glyphs */ + + if ( !outline.n_points ) + goto no_contour_point; + + if ( ap >= outline.n_points ) + return HB_Err_Invalid_GPOS_SubTable; + + *x_value = outline.points[ap].x; + *y_value = outline.points[ap].y; + } + else + { + no_contour_point: + *x_value = x_scale * an->af.af3.XCoordinate / 0x10000; + *y_value = y_scale * an->af.af3.YCoordinate / 0x10000; + } + break; + + case 3: + if ( !gpi->dvi ) + { + _HB_OPEN_Get_Device( &an->af.af3.XDeviceTable, x_ppem, &pixel_value ); + *x_value = pixel_value << 6; + _HB_OPEN_Get_Device( &an->af.af3.YDeviceTable, y_ppem, &pixel_value ); + *y_value = pixel_value << 6; + } + else + *x_value = *y_value = 0; + + *x_value += x_scale * an->af.af3.XCoordinate / 0x10000; + *y_value += y_scale * an->af.af3.YCoordinate / 0x10000; + break; + + case 4: + error = (gpos->mmfunc)( gpi->face, an->af.af4.XIdAnchor, + x_value, gpos->data ); + if ( error ) + return error; + + error = (gpos->mmfunc)( gpi->face, an->af.af4.YIdAnchor, + y_value, gpos->data ); + if ( error ) + return error; + break; + } + + return error; +} + + +/* MarkArray */ + +static FT_Error Load_MarkArray ( HB_MarkArray* ma, + FT_Stream stream ) +{ + FT_Error error; + FT_Memory memory = stream->memory; + + FT_UShort n, m, count; + FT_ULong cur_offset, new_offset, base_offset; + + HB_MarkRecord* mr; + + + base_offset = FILE_Pos(); + + if ( ACCESS_Frame( 2L ) ) + return error; + + count = ma->MarkCount = GET_UShort(); + + FORGET_Frame(); + + ma->MarkRecord = NULL; + + if ( ALLOC_ARRAY( ma->MarkRecord, count, HB_MarkRecord ) ) + return error; + + mr = ma->MarkRecord; + + for ( n = 0; n < count; n++ ) + { + if ( ACCESS_Frame( 4L ) ) + goto Fail; + + mr[n].Class = GET_UShort(); + new_offset = GET_UShort() + base_offset; + + FORGET_Frame(); + + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = Load_Anchor( &mr[n].MarkAnchor, stream ) ) != FT_Err_Ok ) + goto Fail; + (void)FILE_Seek( cur_offset ); + } + + return FT_Err_Ok; + +Fail: + for ( m = 0; m < n; m++ ) + Free_Anchor( &mr[m].MarkAnchor, memory ); + + FREE( mr ); + return error; +} + + +static void Free_MarkArray( HB_MarkArray* ma, + FT_Memory memory ) +{ + FT_UShort n, count; + + HB_MarkRecord* mr; + + + if ( ma->MarkRecord ) + { + count = ma->MarkCount; + mr = ma->MarkRecord; + + for ( n = 0; n < count; n++ ) + Free_Anchor( &mr[n].MarkAnchor, memory ); + + FREE( mr ); + } +} + + +/* LookupType 1 */ + +/* SinglePosFormat1 */ +/* SinglePosFormat2 */ + +static FT_Error Load_SinglePos( HB_GPOS_SubTable* st, + FT_Stream stream ) +{ + FT_Error error; + FT_Memory memory = stream->memory; + HB_SinglePos* sp = &st->single; + + FT_UShort n, m, count, format; + FT_ULong cur_offset, new_offset, base_offset; + + HB_ValueRecord* vr; + + + base_offset = FILE_Pos(); + + if ( ACCESS_Frame( 6L ) ) + return error; + + sp->PosFormat = GET_UShort(); + new_offset = GET_UShort() + base_offset; + + format = sp->ValueFormat = GET_UShort(); + + FORGET_Frame(); + + if ( !format ) + return HB_Err_Invalid_GPOS_SubTable; + + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = _HB_OPEN_Load_Coverage( &sp->Coverage, stream ) ) != FT_Err_Ok ) + return error; + (void)FILE_Seek( cur_offset ); + + switch ( sp->PosFormat ) + { + case 1: + error = Load_ValueRecord( &sp->spf.spf1.Value, format, + base_offset, stream ); + if ( error ) + goto Fail2; + break; + + case 2: + if ( ACCESS_Frame( 2L ) ) + goto Fail2; + + count = sp->spf.spf2.ValueCount = GET_UShort(); + + FORGET_Frame(); + + sp->spf.spf2.Value = NULL; + + if ( ALLOC_ARRAY( sp->spf.spf2.Value, count, HB_ValueRecord ) ) + goto Fail2; + + vr = sp->spf.spf2.Value; + + for ( n = 0; n < count; n++ ) + { + error = Load_ValueRecord( &vr[n], format, base_offset, stream ); + if ( error ) + goto Fail1; + } + break; + + default: + return HB_Err_Invalid_GPOS_SubTable_Format; + } + + return FT_Err_Ok; + +Fail1: + for ( m = 0; m < n; m++ ) + Free_ValueRecord( &vr[m], format, memory ); + + FREE( vr ); + +Fail2: + _HB_OPEN_Free_Coverage( &sp->Coverage, memory ); + return error; +} + + +static void Free_SinglePos( HB_GPOS_SubTable* st, + FT_Memory memory ) +{ + FT_UShort n, count, format; + HB_SinglePos* sp = &st->single; + + HB_ValueRecord* v; + + + format = sp->ValueFormat; + + switch ( sp->PosFormat ) + { + case 1: + Free_ValueRecord( &sp->spf.spf1.Value, format, memory ); + break; + + case 2: + if ( sp->spf.spf2.Value ) + { + count = sp->spf.spf2.ValueCount; + v = sp->spf.spf2.Value; + + for ( n = 0; n < count; n++ ) + Free_ValueRecord( &v[n], format, memory ); + + FREE( v ); + } + break; + } + + _HB_OPEN_Free_Coverage( &sp->Coverage, memory ); +} + +static FT_Error Lookup_DefaultPos( GPOS_Instance* gpi, + HB_GPOS_SubTable* st, + HB_Buffer buffer, + FT_UShort flags, + FT_UShort context_length, + int nesting_level ) +{ + return HB_Err_Not_Covered; +} + +static FT_Error Lookup_SinglePos( GPOS_Instance* gpi, + HB_GPOS_SubTable* st, + HB_Buffer buffer, + FT_UShort flags, + FT_UShort context_length, + int nesting_level ) +{ + FT_UShort index, property; + FT_Error error; + HB_GPOSHeader* gpos = gpi->gpos; + HB_SinglePos* sp = &st->single; + + + if ( context_length != 0xFFFF && context_length < 1 ) + return HB_Err_Not_Covered; + + if ( CHECK_Property( gpos->gdef, IN_CURITEM(), flags, &property ) ) + return error; + + error = _HB_OPEN_Coverage_Index( &sp->Coverage, IN_CURGLYPH(), &index ); + if ( error ) + return error; + + switch ( sp->PosFormat ) + { + case 1: + error = Get_ValueRecord( gpi, &sp->spf.spf1.Value, + sp->ValueFormat, POSITION( buffer->in_pos ) ); + if ( error ) + return error; + break; + + case 2: + if ( index >= sp->spf.spf2.ValueCount ) + return HB_Err_Invalid_GPOS_SubTable; + error = Get_ValueRecord( gpi, &sp->spf.spf2.Value[index], + sp->ValueFormat, POSITION( buffer->in_pos ) ); + if ( error ) + return error; + break; + + default: + return HB_Err_Invalid_GPOS_SubTable; + } + + (buffer->in_pos)++; + + return FT_Err_Ok; +} + + +/* LookupType 2 */ + +/* PairSet */ + +static FT_Error Load_PairSet ( HB_PairSet* ps, + FT_UShort format1, + FT_UShort format2, + FT_Stream stream ) +{ + FT_Error error; + FT_Memory memory = stream->memory; + + FT_UShort n, m, count; + FT_ULong base_offset; + + HB_PairValueRecord* pvr; + + + base_offset = FILE_Pos(); + + if ( ACCESS_Frame( 2L ) ) + return error; + + count = ps->PairValueCount = GET_UShort(); + + FORGET_Frame(); + + ps->PairValueRecord = NULL; + + if ( ALLOC_ARRAY( ps->PairValueRecord, count, HB_PairValueRecord ) ) + return error; + + pvr = ps->PairValueRecord; + + for ( n = 0; n < count; n++ ) + { + if ( ACCESS_Frame( 2L ) ) + goto Fail; + + pvr[n].SecondGlyph = GET_UShort(); + + FORGET_Frame(); + + if ( format1 ) + { + error = Load_ValueRecord( &pvr[n].Value1, format1, + base_offset, stream ); + if ( error ) + goto Fail; + } + if ( format2 ) + { + error = Load_ValueRecord( &pvr[n].Value2, format2, + base_offset, stream ); + if ( error ) + { + if ( format1 ) + Free_ValueRecord( &pvr[n].Value1, format1, memory ); + goto Fail; + } + } + } + + return FT_Err_Ok; + +Fail: + for ( m = 0; m < n; m++ ) + { + if ( format1 ) + Free_ValueRecord( &pvr[m].Value1, format1, memory ); + if ( format2 ) + Free_ValueRecord( &pvr[m].Value2, format2, memory ); + } + + FREE( pvr ); + return error; +} + + +static void Free_PairSet( HB_PairSet* ps, + FT_UShort format1, + FT_UShort format2, + FT_Memory memory ) +{ + FT_UShort n, count; + + HB_PairValueRecord* pvr; + + + if ( ps->PairValueRecord ) + { + count = ps->PairValueCount; + pvr = ps->PairValueRecord; + + for ( n = 0; n < count; n++ ) + { + if ( format1 ) + Free_ValueRecord( &pvr[n].Value1, format1, memory ); + if ( format2 ) + Free_ValueRecord( &pvr[n].Value2, format2, memory ); + } + + FREE( pvr ); + } +} + + +/* PairPosFormat1 */ + +static FT_Error Load_PairPos1( HB_PairPosFormat1* ppf1, + FT_UShort format1, + FT_UShort format2, + FT_Stream stream ) +{ + FT_Error error; + FT_Memory memory = stream->memory; + + FT_UShort n, m, count; + FT_ULong cur_offset, new_offset, base_offset; + + HB_PairSet* ps; + + + base_offset = FILE_Pos() - 8L; + + if ( ACCESS_Frame( 2L ) ) + return error; + + count = ppf1->PairSetCount = GET_UShort(); + + FORGET_Frame(); + + ppf1->PairSet = NULL; + + if ( ALLOC_ARRAY( ppf1->PairSet, count, HB_PairSet ) ) + return error; + + ps = ppf1->PairSet; + + for ( n = 0; n < count; n++ ) + { + if ( ACCESS_Frame( 2L ) ) + goto Fail; + + new_offset = GET_UShort() + base_offset; + + FORGET_Frame(); + + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = Load_PairSet( &ps[n], format1, + format2, stream ) ) != FT_Err_Ok ) + goto Fail; + (void)FILE_Seek( cur_offset ); + } + + return FT_Err_Ok; + +Fail: + for ( m = 0; m < n; m++ ) + Free_PairSet( &ps[m], format1, format2, memory ); + + FREE( ps ); + return error; +} + + +static void Free_PairPos1( HB_PairPosFormat1* ppf1, + FT_UShort format1, + FT_UShort format2, + FT_Memory memory ) +{ + FT_UShort n, count; + + HB_PairSet* ps; + + + if ( ppf1->PairSet ) + { + count = ppf1->PairSetCount; + ps = ppf1->PairSet; + + for ( n = 0; n < count; n++ ) + Free_PairSet( &ps[n], format1, format2, memory ); + + FREE( ps ); + } +} + + +/* PairPosFormat2 */ + +static FT_Error Load_PairPos2( HB_PairPosFormat2* ppf2, + FT_UShort format1, + FT_UShort format2, + FT_Stream stream ) +{ + FT_Error error; + FT_Memory memory = stream->memory; + + FT_UShort m, n, k, count1, count2; + FT_ULong cur_offset, new_offset1, new_offset2, base_offset; + + HB_Class1Record* c1r; + HB_Class2Record* c2r; + + + base_offset = FILE_Pos() - 8L; + + if ( ACCESS_Frame( 8L ) ) + return error; + + new_offset1 = GET_UShort() + base_offset; + new_offset2 = GET_UShort() + base_offset; + + /* `Class1Count' and `Class2Count' are the upper limits for class + values, thus we read it now to make additional safety checks. */ + + count1 = ppf2->Class1Count = GET_UShort(); + count2 = ppf2->Class2Count = GET_UShort(); + + FORGET_Frame(); + + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset1 ) || + ( error = _HB_OPEN_Load_ClassDefinition( &ppf2->ClassDef1, count1, + stream ) ) != FT_Err_Ok ) + return error; + if ( FILE_Seek( new_offset2 ) || + ( error = _HB_OPEN_Load_ClassDefinition( &ppf2->ClassDef2, count2, + stream ) ) != FT_Err_Ok ) + goto Fail3; + (void)FILE_Seek( cur_offset ); + + ppf2->Class1Record = NULL; + + if ( ALLOC_ARRAY( ppf2->Class1Record, count1, HB_Class1Record ) ) + goto Fail2; + + c1r = ppf2->Class1Record; + + for ( m = 0; m < count1; m++ ) + { + c1r[m].Class2Record = NULL; + + if ( ALLOC_ARRAY( c1r[m].Class2Record, count2, HB_Class2Record ) ) + goto Fail1; + + c2r = c1r[m].Class2Record; + + for ( n = 0; n < count2; n++ ) + { + if ( format1 ) + { + error = Load_ValueRecord( &c2r[n].Value1, format1, + base_offset, stream ); + if ( error ) + goto Fail0; + } + if ( format2 ) + { + error = Load_ValueRecord( &c2r[n].Value2, format2, + base_offset, stream ); + if ( error ) + { + if ( format1 ) + Free_ValueRecord( &c2r[n].Value1, format1, memory ); + goto Fail0; + } + } + } + + continue; + + Fail0: + for ( k = 0; k < n; k++ ) + { + if ( format1 ) + Free_ValueRecord( &c2r[k].Value1, format1, memory ); + if ( format2 ) + Free_ValueRecord( &c2r[k].Value2, format2, memory ); + } + goto Fail1; + } + + return FT_Err_Ok; + +Fail1: + for ( k = 0; k < m; k++ ) + { + c2r = c1r[k].Class2Record; + + for ( n = 0; n < count2; n++ ) + { + if ( format1 ) + Free_ValueRecord( &c2r[n].Value1, format1, memory ); + if ( format2 ) + Free_ValueRecord( &c2r[n].Value2, format2, memory ); + } + + FREE( c2r ); + } + + FREE( c1r ); +Fail2: + + _HB_OPEN_Free_ClassDefinition( &ppf2->ClassDef2, memory ); + +Fail3: + _HB_OPEN_Free_ClassDefinition( &ppf2->ClassDef1, memory ); + return error; +} + + +static void Free_PairPos2( HB_PairPosFormat2* ppf2, + FT_UShort format1, + FT_UShort format2, + FT_Memory memory ) +{ + FT_UShort m, n, count1, count2; + + HB_Class1Record* c1r; + HB_Class2Record* c2r; + + + if ( ppf2->Class1Record ) + { + c1r = ppf2->Class1Record; + count1 = ppf2->Class1Count; + count2 = ppf2->Class2Count; + + for ( m = 0; m < count1; m++ ) + { + c2r = c1r[m].Class2Record; + + for ( n = 0; n < count2; n++ ) + { + if ( format1 ) + Free_ValueRecord( &c2r[n].Value1, format1, memory ); + if ( format2 ) + Free_ValueRecord( &c2r[n].Value2, format2, memory ); + } + + FREE( c2r ); + } + + FREE( c1r ); + + _HB_OPEN_Free_ClassDefinition( &ppf2->ClassDef2, memory ); + _HB_OPEN_Free_ClassDefinition( &ppf2->ClassDef1, memory ); + } +} + + +static FT_Error Load_PairPos( HB_GPOS_SubTable* st, + FT_Stream stream ) +{ + FT_Error error; + FT_Memory memory = stream->memory; + HB_PairPos* pp = &st->pair; + + FT_UShort format1, format2; + FT_ULong cur_offset, new_offset, base_offset; + + + base_offset = FILE_Pos(); + + if ( ACCESS_Frame( 8L ) ) + return error; + + pp->PosFormat = GET_UShort(); + new_offset = GET_UShort() + base_offset; + + format1 = pp->ValueFormat1 = GET_UShort(); + format2 = pp->ValueFormat2 = GET_UShort(); + + FORGET_Frame(); + + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = _HB_OPEN_Load_Coverage( &pp->Coverage, stream ) ) != FT_Err_Ok ) + return error; + (void)FILE_Seek( cur_offset ); + + switch ( pp->PosFormat ) + { + case 1: + error = Load_PairPos1( &pp->ppf.ppf1, format1, format2, stream ); + if ( error ) + goto Fail; + break; + + case 2: + error = Load_PairPos2( &pp->ppf.ppf2, format1, format2, stream ); + if ( error ) + goto Fail; + break; + + default: + return HB_Err_Invalid_GPOS_SubTable_Format; + } + + return FT_Err_Ok; + +Fail: + _HB_OPEN_Free_Coverage( &pp->Coverage, memory ); + return error; +} + + +static void Free_PairPos( HB_GPOS_SubTable* st, + FT_Memory memory ) +{ + FT_UShort format1, format2; + HB_PairPos* pp = &st->pair; + + + format1 = pp->ValueFormat1; + format2 = pp->ValueFormat2; + + switch ( pp->PosFormat ) + { + case 1: + Free_PairPos1( &pp->ppf.ppf1, format1, format2, memory ); + break; + + case 2: + Free_PairPos2( &pp->ppf.ppf2, format1, format2, memory ); + break; + } + + _HB_OPEN_Free_Coverage( &pp->Coverage, memory ); +} + + +static FT_Error Lookup_PairPos1( GPOS_Instance* gpi, + HB_PairPosFormat1* ppf1, + HB_Buffer buffer, + FT_UShort first_pos, + FT_UShort index, + FT_UShort format1, + FT_UShort format2 ) +{ + FT_Error error; + FT_UShort numpvr, glyph2; + + HB_PairValueRecord* pvr; + + + if ( index >= ppf1->PairSetCount ) + return HB_Err_Invalid_GPOS_SubTable; + + pvr = ppf1->PairSet[index].PairValueRecord; + if ( !pvr ) + return HB_Err_Invalid_GPOS_SubTable; + + glyph2 = IN_CURGLYPH(); + + for ( numpvr = ppf1->PairSet[index].PairValueCount; + numpvr; + numpvr--, pvr++ ) + { + if ( glyph2 == pvr->SecondGlyph ) + { + error = Get_ValueRecord( gpi, &pvr->Value1, format1, + POSITION( first_pos ) ); + if ( error ) + return error; + return Get_ValueRecord( gpi, &pvr->Value2, format2, + POSITION( buffer->in_pos ) ); + } + } + + return HB_Err_Not_Covered; +} + + +static FT_Error Lookup_PairPos2( GPOS_Instance* gpi, + HB_PairPosFormat2* ppf2, + HB_Buffer buffer, + FT_UShort first_pos, + FT_UShort format1, + FT_UShort format2 ) +{ + FT_Error error; + FT_UShort cl1, cl2; + + HB_Class1Record* c1r; + HB_Class2Record* c2r; + + + error = _HB_OPEN_Get_Class( &ppf2->ClassDef1, IN_GLYPH( first_pos ), + &cl1, NULL ); + if ( error && error != HB_Err_Not_Covered ) + return error; + error = _HB_OPEN_Get_Class( &ppf2->ClassDef2, IN_CURGLYPH(), + &cl2, NULL ); + if ( error && error != HB_Err_Not_Covered ) + return error; + + c1r = &ppf2->Class1Record[cl1]; + if ( !c1r ) + return HB_Err_Invalid_GPOS_SubTable; + c2r = &c1r->Class2Record[cl2]; + + error = Get_ValueRecord( gpi, &c2r->Value1, format1, POSITION( first_pos ) ); + if ( error ) + return error; + return Get_ValueRecord( gpi, &c2r->Value2, format2, POSITION( buffer->in_pos ) ); +} + + +static FT_Error Lookup_PairPos( GPOS_Instance* gpi, + HB_GPOS_SubTable* st, + HB_Buffer buffer, + FT_UShort flags, + FT_UShort context_length, + int nesting_level ) +{ + FT_Error error; + FT_UShort index, property, first_pos; + HB_GPOSHeader* gpos = gpi->gpos; + HB_PairPos* pp = &st->pair; + + + if ( buffer->in_pos >= buffer->in_length - 1 ) + return HB_Err_Not_Covered; /* Not enough glyphs in stream */ + + if ( context_length != 0xFFFF && context_length < 2 ) + return HB_Err_Not_Covered; + + if ( CHECK_Property( gpos->gdef, IN_CURITEM(), flags, &property ) ) + return error; + + error = _HB_OPEN_Coverage_Index( &pp->Coverage, IN_CURGLYPH(), &index ); + if ( error ) + return error; + + /* second glyph */ + + first_pos = buffer->in_pos; + (buffer->in_pos)++; + + while ( CHECK_Property( gpos->gdef, IN_CURITEM(), + flags, &property ) ) + { + if ( error && error != HB_Err_Not_Covered ) + return error; + + if ( buffer->in_pos == buffer->in_length ) + return HB_Err_Not_Covered; + (buffer->in_pos)++; + } + + switch ( pp->PosFormat ) + { + case 1: + error = Lookup_PairPos1( gpi, &pp->ppf.ppf1, buffer, + first_pos, index, + pp->ValueFormat1, pp->ValueFormat2 ); + break; + + case 2: + error = Lookup_PairPos2( gpi, &pp->ppf.ppf2, buffer, first_pos, + pp->ValueFormat1, pp->ValueFormat2 ); + break; + + default: + return HB_Err_Invalid_GPOS_SubTable_Format; + } + + /* adjusting the `next' glyph */ + + if ( pp->ValueFormat2 ) + (buffer->in_pos)++; + + return error; +} + + +/* LookupType 3 */ + +/* CursivePosFormat1 */ + +static FT_Error Load_CursivePos( HB_GPOS_SubTable* st, + FT_Stream stream ) +{ + FT_Error error; + FT_Memory memory = stream->memory; + HB_CursivePos* cp = &st->cursive; + + FT_UShort n, m, count; + FT_ULong cur_offset, new_offset, base_offset; + + HB_EntryExitRecord* eer; + + + base_offset = FILE_Pos(); + + if ( ACCESS_Frame( 4L ) ) + return error; + + cp->PosFormat = GET_UShort(); + new_offset = GET_UShort() + base_offset; + + FORGET_Frame(); + + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = _HB_OPEN_Load_Coverage( &cp->Coverage, stream ) ) != FT_Err_Ok ) + return error; + (void)FILE_Seek( cur_offset ); + + if ( ACCESS_Frame( 2L ) ) + goto Fail2; + + count = cp->EntryExitCount = GET_UShort(); + + FORGET_Frame(); + + cp->EntryExitRecord = NULL; + + if ( ALLOC_ARRAY( cp->EntryExitRecord, count, HB_EntryExitRecord ) ) + goto Fail2; + + eer = cp->EntryExitRecord; + + for ( n = 0; n < count; n++ ) + { + FT_ULong entry_offset; + + if ( ACCESS_Frame( 2L ) ) + return error; + + entry_offset = new_offset = GET_UShort(); + + FORGET_Frame(); + + if ( new_offset ) + { + new_offset += base_offset; + + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = Load_Anchor( &eer[n].EntryAnchor, + stream ) ) != FT_Err_Ok ) + goto Fail1; + (void)FILE_Seek( cur_offset ); + } + else + eer[n].EntryAnchor.PosFormat = 0; + + if ( ACCESS_Frame( 2L ) ) + return error; + + new_offset = GET_UShort(); + + FORGET_Frame(); + + if ( new_offset ) + { + new_offset += base_offset; + + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = Load_Anchor( &eer[n].ExitAnchor, + stream ) ) != FT_Err_Ok ) + { + if ( entry_offset ) + Free_Anchor( &eer[n].EntryAnchor, memory ); + goto Fail1; + } + (void)FILE_Seek( cur_offset ); + } + else + eer[n].ExitAnchor.PosFormat = 0; + } + + return FT_Err_Ok; + +Fail1: + for ( m = 0; m < n; m++ ) + { + Free_Anchor( &eer[m].EntryAnchor, memory ); + Free_Anchor( &eer[m].ExitAnchor, memory ); + } + + FREE( eer ); + +Fail2: + _HB_OPEN_Free_Coverage( &cp->Coverage, memory ); + return error; +} + + +static void Free_CursivePos( HB_GPOS_SubTable* st, + FT_Memory memory ) +{ + FT_UShort n, count; + HB_CursivePos* cp = &st->cursive; + + HB_EntryExitRecord* eer; + + + if ( cp->EntryExitRecord ) + { + count = cp->EntryExitCount; + eer = cp->EntryExitRecord; + + for ( n = 0; n < count; n++ ) + { + Free_Anchor( &eer[n].EntryAnchor, memory ); + Free_Anchor( &eer[n].ExitAnchor, memory ); + } + + FREE( eer ); + } + + _HB_OPEN_Free_Coverage( &cp->Coverage, memory ); +} + + +static FT_Error Lookup_CursivePos( GPOS_Instance* gpi, + HB_GPOS_SubTable* st, + HB_Buffer buffer, + FT_UShort flags, + FT_UShort context_length, + int nesting_level ) +{ + FT_UShort index, property; + FT_Error error; + HB_GPOSHeader* gpos = gpi->gpos; + HB_CursivePos* cp = &st->cursive; + + HB_EntryExitRecord* eer; + FT_Pos entry_x, entry_y; + FT_Pos exit_x, exit_y; + + + if ( context_length != 0xFFFF && context_length < 1 ) + { + gpi->last = 0xFFFF; + return HB_Err_Not_Covered; + } + + /* Glyphs not having the right GDEF properties will be ignored, i.e., + gpi->last won't be reset (contrary to user defined properties). */ + + if ( CHECK_Property( gpos->gdef, IN_CURITEM(), flags, &property ) ) + return error; + + /* We don't handle mark glyphs here. According to Andrei, this isn't + possible, but who knows... */ + + if ( property == HB_GDEF_MARK ) + { + gpi->last = 0xFFFF; + return HB_Err_Not_Covered; + } + + error = _HB_OPEN_Coverage_Index( &cp->Coverage, IN_CURGLYPH(), &index ); + if ( error ) + { + gpi->last = 0xFFFF; + return error; + } + + if ( index >= cp->EntryExitCount ) + return HB_Err_Invalid_GPOS_SubTable; + + eer = &cp->EntryExitRecord[index]; + + /* Now comes the messiest part of the whole OpenType + specification. At first glance, cursive connections seem easy + to understand, but there are pitfalls! The reason is that + the specs don't mention how to compute the advance values + resp. glyph offsets. I was told it would be an omission, to + be fixed in the next OpenType version... Again many thanks to + Andrei Burago for clarifications. + + Consider the following example: + + | xadv1 | + +---------+ + | | + +-----+--+ 1 | + | | .| | + | 0+--+------+ + | 2 | + | | + 0+--------+ + | xadv2 | + + glyph1: advance width = 12 + anchor point = (3,1) + + glyph2: advance width = 11 + anchor point = (9,4) + + LSB is 1 for both glyphs (so the boxes drawn above are glyph + bboxes). Writing direction is R2L; `0' denotes the glyph's + coordinate origin. + + Now the surprising part: The advance width of the *left* glyph + (resp. of the *bottom* glyph) will be modified, no matter + whether the writing direction is L2R or R2L (resp. T2B or + B2T)! This assymetry is caused by the fact that the glyph's + coordinate origin is always the lower left corner for all + writing directions. + + Continuing the above example, we can compute the new + (horizontal) advance width of glyph2 as + + 9 - 3 = 6 , + + and the new vertical offset of glyph2 as + + 1 - 4 = -3 . + + + Vertical writing direction is far more complicated: + + a) Assuming that we recompute the advance height of the lower glyph: + + -- + +---------+ + -- | | + +-----+--+ 1 | yadv1 + | | .| | + yadv2 | 0+--+------+ -- BSB1 -- + | 2 | -- -- y_offset + | | + BSB2 -- 0+--------+ -- + -- -- + + glyph1: advance height = 6 + anchor point = (3,1) + + glyph2: advance height = 7 + anchor point = (9,4) + + TSB is 1 for both glyphs; writing direction is T2B. + + + BSB1 = yadv1 - (TSB1 + ymax1) + BSB2 = yadv2 - (TSB2 + ymax2) + y_offset = y2 - y1 + + vertical advance width of glyph2 + = y_offset + BSB2 - BSB1 + = (y2 - y1) + (yadv2 - (TSB2 + ymax2)) - (yadv1 - (TSB1 + ymax1)) + = y2 - y1 + yadv2 - TSB2 - ymax2 - (yadv1 - TSB1 - ymax1) + = y2 - y1 + yadv2 - TSB2 - ymax2 - yadv1 + TSB1 + ymax1 + + + b) Assuming that we recompute the advance height of the upper glyph: + + -- -- + +---------+ -- TSB1 + -- -- | | + TSB2 -- +-----+--+ 1 | yadv1 ymax1 + | | .| | + yadv2 | 0+--+------+ -- -- + ymax2 | 2 | -- y_offset + | | + -- 0+--------+ -- + -- + + glyph1: advance height = 6 + anchor point = (3,1) + + glyph2: advance height = 7 + anchor point = (9,4) + + TSB is 1 for both glyphs; writing direction is T2B. + + y_offset = y2 - y1 + + vertical advance width of glyph2 + = TSB1 + ymax1 + y_offset - (TSB2 + ymax2) + = TSB1 + ymax1 + y2 - y1 - TSB2 - ymax2 + + + Comparing a) with b) shows that b) is easier to compute. I'll wait + for a reply from Andrei to see what should really be implemented... + + Since horizontal advance widths or vertical advance heights + can be used alone but not together, no ambiguity occurs. */ + + if ( gpi->last == 0xFFFF ) + goto end; + + /* Get_Anchor() returns HB_Err_Not_Covered if there is no anchor + table. */ + + error = Get_Anchor( gpi, &eer->EntryAnchor, IN_CURGLYPH(), + &entry_x, &entry_y ); + if ( error == HB_Err_Not_Covered ) + goto end; + if ( error ) + return error; + + if ( gpi->r2l ) + { + POSITION( buffer->in_pos )->x_advance = entry_x - gpi->anchor_x; + POSITION( buffer->in_pos )->new_advance = TRUE; + } + else + { + POSITION( gpi->last )->x_advance = gpi->anchor_x - entry_x; + POSITION( gpi->last )->new_advance = TRUE; + } + + if ( flags & HB_LOOKUP_FLAG_RIGHT_TO_LEFT ) + { + POSITION( gpi->last )->cursive_chain = gpi->last - buffer->in_pos; + POSITION( gpi->last )->y_pos = entry_y - gpi->anchor_y; + } + else + { + POSITION( buffer->in_pos )->cursive_chain = buffer->in_pos - gpi->last; + POSITION( buffer->in_pos )->y_pos = gpi->anchor_y - entry_y; + } + +end: + error = Get_Anchor( gpi, &eer->ExitAnchor, IN_CURGLYPH(), + &exit_x, &exit_y ); + if ( error == HB_Err_Not_Covered ) + gpi->last = 0xFFFF; + else + { + gpi->last = buffer->in_pos; + gpi->anchor_x = exit_x; + gpi->anchor_y = exit_y; + } + if ( error ) + return error; + + (buffer->in_pos)++; + + return FT_Err_Ok; +} + + +/* LookupType 4 */ + +/* BaseArray */ + +static FT_Error Load_BaseArray( HB_BaseArray* ba, + FT_UShort num_classes, + FT_Stream stream ) +{ + FT_Error error; + FT_Memory memory = stream->memory; + + FT_UShort m, n, k, count; + FT_ULong cur_offset, new_offset, base_offset; + + HB_BaseRecord* br; + HB_Anchor* ban; + + + base_offset = FILE_Pos(); + + if ( ACCESS_Frame( 2L ) ) + return error; + + count = ba->BaseCount = GET_UShort(); + + FORGET_Frame(); + + ba->BaseRecord = NULL; + + if ( ALLOC_ARRAY( ba->BaseRecord, count, HB_BaseRecord ) ) + return error; + + br = ba->BaseRecord; + + for ( m = 0; m < count; m++ ) + { + br[m].BaseAnchor = NULL; + + if ( ALLOC_ARRAY( br[m].BaseAnchor, num_classes, HB_Anchor ) ) + goto Fail; + + ban = br[m].BaseAnchor; + + for ( n = 0; n < num_classes; n++ ) + { + if ( ACCESS_Frame( 2L ) ) + goto Fail0; + + new_offset = GET_UShort() + base_offset; + + FORGET_Frame(); + + if (new_offset == base_offset) { + /* Doulos SIL Regular is buggy and has zer offsets here. Skip */ + ban[n].PosFormat = 0; + continue; + } + + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = Load_Anchor( &ban[n], stream ) ) != FT_Err_Ok ) + goto Fail0; + (void)FILE_Seek( cur_offset ); + } + + continue; + Fail0: + for ( k = 0; k < n; k++ ) + Free_Anchor( &ban[k], memory ); + goto Fail; + } + + return FT_Err_Ok; + +Fail: + for ( k = 0; k < m; k++ ) + { + ban = br[k].BaseAnchor; + + for ( n = 0; n < num_classes; n++ ) + Free_Anchor( &ban[n], memory ); + + FREE( ban ); + } + + FREE( br ); + return error; +} + + +static void Free_BaseArray( HB_BaseArray* ba, + FT_UShort num_classes, + FT_Memory memory ) +{ + FT_UShort m, n, count; + + HB_BaseRecord* br; + HB_Anchor* ban; + + + if ( ba->BaseRecord ) + { + count = ba->BaseCount; + br = ba->BaseRecord; + + for ( m = 0; m < count; m++ ) + { + ban = br[m].BaseAnchor; + + for ( n = 0; n < num_classes; n++ ) + Free_Anchor( &ban[n], memory ); + + FREE( ban ); + } + + FREE( br ); + } +} + + +/* MarkBasePosFormat1 */ + +static FT_Error Load_MarkBasePos( HB_GPOS_SubTable* st, + FT_Stream stream ) +{ + FT_Error error; + FT_Memory memory = stream->memory; + HB_MarkBasePos* mbp = &st->markbase; + + FT_ULong cur_offset, new_offset, base_offset; + + + base_offset = FILE_Pos(); + + if ( ACCESS_Frame( 4L ) ) + return error; + + mbp->PosFormat = GET_UShort(); + new_offset = GET_UShort() + base_offset; + + FORGET_Frame(); + + if (mbp->PosFormat != 1) + return HB_Err_Invalid_SubTable_Format; + + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = _HB_OPEN_Load_Coverage( &mbp->MarkCoverage, stream ) ) != FT_Err_Ok ) + return error; + (void)FILE_Seek( cur_offset ); + + if ( ACCESS_Frame( 2L ) ) + goto Fail3; + + new_offset = GET_UShort() + base_offset; + + FORGET_Frame(); + + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = _HB_OPEN_Load_Coverage( &mbp->BaseCoverage, stream ) ) != FT_Err_Ok ) + goto Fail3; + (void)FILE_Seek( cur_offset ); + + if ( ACCESS_Frame( 4L ) ) + goto Fail2; + + mbp->ClassCount = GET_UShort(); + new_offset = GET_UShort() + base_offset; + + FORGET_Frame(); + + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = Load_MarkArray( &mbp->MarkArray, stream ) ) != FT_Err_Ok ) + goto Fail2; + (void)FILE_Seek( cur_offset ); + + if ( ACCESS_Frame( 2L ) ) + goto Fail1; + + new_offset = GET_UShort() + base_offset; + + FORGET_Frame(); + + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = Load_BaseArray( &mbp->BaseArray, mbp->ClassCount, + stream ) ) != FT_Err_Ok ) + goto Fail1; + + return FT_Err_Ok; + +Fail1: + Free_MarkArray( &mbp->MarkArray, memory ); + +Fail2: + _HB_OPEN_Free_Coverage( &mbp->BaseCoverage, memory ); + +Fail3: + _HB_OPEN_Free_Coverage( &mbp->MarkCoverage, memory ); + return error; +} + + +static void Free_MarkBasePos( HB_GPOS_SubTable* st, + FT_Memory memory ) +{ + HB_MarkBasePos* mbp = &st->markbase; + + Free_BaseArray( &mbp->BaseArray, mbp->ClassCount, memory ); + Free_MarkArray( &mbp->MarkArray, memory ); + _HB_OPEN_Free_Coverage( &mbp->BaseCoverage, memory ); + _HB_OPEN_Free_Coverage( &mbp->MarkCoverage, memory ); +} + + +static FT_Error Lookup_MarkBasePos( GPOS_Instance* gpi, + HB_GPOS_SubTable* st, + HB_Buffer buffer, + FT_UShort flags, + FT_UShort context_length, + int nesting_level ) +{ + FT_UShort i, j, mark_index, base_index, property, class; + FT_Pos x_mark_value, y_mark_value, x_base_value, y_base_value; + FT_Error error; + HB_GPOSHeader* gpos = gpi->gpos; + HB_MarkBasePos* mbp = &st->markbase; + + HB_MarkArray* ma; + HB_BaseArray* ba; + HB_BaseRecord* br; + HB_Anchor* mark_anchor; + HB_Anchor* base_anchor; + + HB_Position o; + + + if ( context_length != 0xFFFF && context_length < 1 ) + return HB_Err_Not_Covered; + + if ( flags & HB_LOOKUP_FLAG_IGNORE_BASE_GLYPHS ) + return HB_Err_Not_Covered; + + if ( CHECK_Property( gpos->gdef, IN_CURITEM(), + flags, &property ) ) + return error; + + error = _HB_OPEN_Coverage_Index( &mbp->MarkCoverage, IN_CURGLYPH(), + &mark_index ); + if ( error ) + return error; + + /* now we search backwards for a non-mark glyph */ + + i = 1; + j = buffer->in_pos - 1; + + while ( i <= buffer->in_pos ) + { + error = HB_GDEF_Get_Glyph_Property( gpos->gdef, IN_GLYPH( j ), + &property ); + if ( error ) + return error; + + if ( !( property == HB_GDEF_MARK || property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS ) ) + break; + + i++; + j--; + } + + /* The following assertion is too strong -- at least for mangal.ttf. */ +#if 0 + if ( property != HB_GDEF_BASE_GLYPH ) + return HB_Err_Not_Covered; +#endif + + if ( i > buffer->in_pos ) + return HB_Err_Not_Covered; + + error = _HB_OPEN_Coverage_Index( &mbp->BaseCoverage, IN_GLYPH( j ), + &base_index ); + if ( error ) + return error; + + ma = &mbp->MarkArray; + + if ( mark_index >= ma->MarkCount ) + return HB_Err_Invalid_GPOS_SubTable; + + class = ma->MarkRecord[mark_index].Class; + mark_anchor = &ma->MarkRecord[mark_index].MarkAnchor; + + if ( class >= mbp->ClassCount ) + return HB_Err_Invalid_GPOS_SubTable; + + ba = &mbp->BaseArray; + + if ( base_index >= ba->BaseCount ) + return HB_Err_Invalid_GPOS_SubTable; + + br = &ba->BaseRecord[base_index]; + base_anchor = &br->BaseAnchor[class]; + + error = Get_Anchor( gpi, mark_anchor, IN_CURGLYPH(), + &x_mark_value, &y_mark_value ); + if ( error ) + return error; + + error = Get_Anchor( gpi, base_anchor, IN_GLYPH( j ), + &x_base_value, &y_base_value ); + if ( error ) + return error; + + /* anchor points are not cumulative */ + + o = POSITION( buffer->in_pos ); + + o->x_pos = x_base_value - x_mark_value; + o->y_pos = y_base_value - y_mark_value; + o->x_advance = 0; + o->y_advance = 0; + o->back = i; + + (buffer->in_pos)++; + + return FT_Err_Ok; +} + + +/* LookupType 5 */ + +/* LigatureAttach */ + +static FT_Error Load_LigatureAttach( HB_LigatureAttach* lat, + FT_UShort num_classes, + FT_Stream stream ) +{ + FT_Error error; + FT_Memory memory = stream->memory; + + FT_UShort m, n, k, count; + FT_ULong cur_offset, new_offset, base_offset; + + HB_ComponentRecord* cr; + HB_Anchor* lan; + + + base_offset = FILE_Pos(); + + if ( ACCESS_Frame( 2L ) ) + return error; + + count = lat->ComponentCount = GET_UShort(); + + FORGET_Frame(); + + lat->ComponentRecord = NULL; + + if ( ALLOC_ARRAY( lat->ComponentRecord, count, HB_ComponentRecord ) ) + return error; + + cr = lat->ComponentRecord; + + for ( m = 0; m < count; m++ ) + { + cr[m].LigatureAnchor = NULL; + + if ( ALLOC_ARRAY( cr[m].LigatureAnchor, num_classes, HB_Anchor ) ) + goto Fail; + + lan = cr[m].LigatureAnchor; + + for ( n = 0; n < num_classes; n++ ) + { + if ( ACCESS_Frame( 2L ) ) + goto Fail0; + + new_offset = GET_UShort(); + + FORGET_Frame(); + + if ( new_offset ) + { + new_offset += base_offset; + + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = Load_Anchor( &lan[n], stream ) ) != FT_Err_Ok ) + goto Fail0; + (void)FILE_Seek( cur_offset ); + } + else + lan[n].PosFormat = 0; + } + + continue; + Fail0: + for ( k = 0; k < n; k++ ) + Free_Anchor( &lan[k], memory ); + goto Fail; + } + + return FT_Err_Ok; + +Fail: + for ( k = 0; k < m; k++ ) + { + lan = cr[k].LigatureAnchor; + + for ( n = 0; n < num_classes; n++ ) + Free_Anchor( &lan[n], memory ); + + FREE( lan ); + } + + FREE( cr ); + return error; +} + + +static void Free_LigatureAttach( HB_LigatureAttach* lat, + FT_UShort num_classes, + FT_Memory memory ) +{ + FT_UShort m, n, count; + + HB_ComponentRecord* cr; + HB_Anchor* lan; + + + if ( lat->ComponentRecord ) + { + count = lat->ComponentCount; + cr = lat->ComponentRecord; + + for ( m = 0; m < count; m++ ) + { + lan = cr[m].LigatureAnchor; + + for ( n = 0; n < num_classes; n++ ) + Free_Anchor( &lan[n], memory ); + + FREE( lan ); + } + + FREE( cr ); + } +} + + +/* LigatureArray */ + +static FT_Error Load_LigatureArray( HB_LigatureArray* la, + FT_UShort num_classes, + FT_Stream stream ) +{ + FT_Error error; + FT_Memory memory = stream->memory; + + FT_UShort n, m, count; + FT_ULong cur_offset, new_offset, base_offset; + + HB_LigatureAttach* lat; + + + base_offset = FILE_Pos(); + + if ( ACCESS_Frame( 2L ) ) + return error; + + count = la->LigatureCount = GET_UShort(); + + FORGET_Frame(); + + la->LigatureAttach = NULL; + + if ( ALLOC_ARRAY( la->LigatureAttach, count, HB_LigatureAttach ) ) + return error; + + lat = la->LigatureAttach; + + for ( n = 0; n < count; n++ ) + { + if ( ACCESS_Frame( 2L ) ) + goto Fail; + + new_offset = GET_UShort() + base_offset; + + FORGET_Frame(); + + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = Load_LigatureAttach( &lat[n], num_classes, + stream ) ) != FT_Err_Ok ) + goto Fail; + (void)FILE_Seek( cur_offset ); + } + + return FT_Err_Ok; + +Fail: + for ( m = 0; m < n; m++ ) + Free_LigatureAttach( &lat[m], num_classes, memory ); + + FREE( lat ); + return error; +} + + +static void Free_LigatureArray( HB_LigatureArray* la, + FT_UShort num_classes, + FT_Memory memory ) +{ + FT_UShort n, count; + + HB_LigatureAttach* lat; + + + if ( la->LigatureAttach ) + { + count = la->LigatureCount; + lat = la->LigatureAttach; + + for ( n = 0; n < count; n++ ) + Free_LigatureAttach( &lat[n], num_classes, memory ); + + FREE( lat ); + } +} + + +/* MarkLigPosFormat1 */ + +static FT_Error Load_MarkLigPos( HB_GPOS_SubTable* st, + FT_Stream stream ) +{ + FT_Error error; + FT_Memory memory = stream->memory; + HB_MarkLigPos* mlp = &st->marklig; + + FT_ULong cur_offset, new_offset, base_offset; + + + base_offset = FILE_Pos(); + + if ( ACCESS_Frame( 4L ) ) + return error; + + mlp->PosFormat = GET_UShort(); + new_offset = GET_UShort() + base_offset; + + FORGET_Frame(); + + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = _HB_OPEN_Load_Coverage( &mlp->MarkCoverage, stream ) ) != FT_Err_Ok ) + return error; + (void)FILE_Seek( cur_offset ); + + if ( ACCESS_Frame( 2L ) ) + goto Fail3; + + new_offset = GET_UShort() + base_offset; + + FORGET_Frame(); + + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = _HB_OPEN_Load_Coverage( &mlp->LigatureCoverage, + stream ) ) != FT_Err_Ok ) + goto Fail3; + (void)FILE_Seek( cur_offset ); + + if ( ACCESS_Frame( 4L ) ) + goto Fail2; + + mlp->ClassCount = GET_UShort(); + new_offset = GET_UShort() + base_offset; + + FORGET_Frame(); + + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = Load_MarkArray( &mlp->MarkArray, stream ) ) != FT_Err_Ok ) + goto Fail2; + (void)FILE_Seek( cur_offset ); + + if ( ACCESS_Frame( 2L ) ) + goto Fail1; + + new_offset = GET_UShort() + base_offset; + + FORGET_Frame(); + + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = Load_LigatureArray( &mlp->LigatureArray, mlp->ClassCount, + stream ) ) != FT_Err_Ok ) + goto Fail1; + + return FT_Err_Ok; + +Fail1: + Free_MarkArray( &mlp->MarkArray, memory ); + +Fail2: + _HB_OPEN_Free_Coverage( &mlp->LigatureCoverage, memory ); + +Fail3: + _HB_OPEN_Free_Coverage( &mlp->MarkCoverage, memory ); + return error; +} + + +static void Free_MarkLigPos( HB_GPOS_SubTable* st, + FT_Memory memory) +{ + HB_MarkLigPos* mlp = &st->marklig; + + Free_LigatureArray( &mlp->LigatureArray, mlp->ClassCount, memory ); + Free_MarkArray( &mlp->MarkArray, memory ); + _HB_OPEN_Free_Coverage( &mlp->LigatureCoverage, memory ); + _HB_OPEN_Free_Coverage( &mlp->MarkCoverage, memory ); +} + + +static FT_Error Lookup_MarkLigPos( GPOS_Instance* gpi, + HB_GPOS_SubTable* st, + HB_Buffer buffer, + FT_UShort flags, + FT_UShort context_length, + int nesting_level ) +{ + FT_UShort i, j, mark_index, lig_index, property, class; + FT_UShort mark_glyph; + FT_Pos x_mark_value, y_mark_value, x_lig_value, y_lig_value; + FT_Error error; + HB_GPOSHeader* gpos = gpi->gpos; + HB_MarkLigPos* mlp = &st->marklig; + + HB_MarkArray* ma; + HB_LigatureArray* la; + HB_LigatureAttach* lat; + HB_ComponentRecord* cr; + FT_UShort comp_index; + HB_Anchor* mark_anchor; + HB_Anchor* lig_anchor; + + HB_Position o; + + + if ( context_length != 0xFFFF && context_length < 1 ) + return HB_Err_Not_Covered; + + if ( flags & HB_LOOKUP_FLAG_IGNORE_LIGATURES ) + return HB_Err_Not_Covered; + + mark_glyph = IN_CURGLYPH(); + + if ( CHECK_Property( gpos->gdef, IN_CURITEM(), flags, &property ) ) + return error; + + error = _HB_OPEN_Coverage_Index( &mlp->MarkCoverage, mark_glyph, &mark_index ); + if ( error ) + return error; + + /* now we search backwards for a non-mark glyph */ + + i = 1; + j = buffer->in_pos - 1; + + while ( i <= buffer->in_pos ) + { + error = HB_GDEF_Get_Glyph_Property( gpos->gdef, IN_GLYPH( j ), + &property ); + if ( error ) + return error; + + if ( !( property == HB_GDEF_MARK || property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS ) ) + break; + + i++; + j--; + } + + /* Similar to Lookup_MarkBasePos(), I suspect that this assertion is + too strong, thus it is commented out. */ +#if 0 + if ( property != HB_GDEF_LIGATURE ) + return HB_Err_Not_Covered; +#endif + + if ( i > buffer->in_pos ) + return HB_Err_Not_Covered; + + error = _HB_OPEN_Coverage_Index( &mlp->LigatureCoverage, IN_GLYPH( j ), + &lig_index ); + if ( error ) + return error; + + ma = &mlp->MarkArray; + + if ( mark_index >= ma->MarkCount ) + return HB_Err_Invalid_GPOS_SubTable; + + class = ma->MarkRecord[mark_index].Class; + mark_anchor = &ma->MarkRecord[mark_index].MarkAnchor; + + if ( class >= mlp->ClassCount ) + return HB_Err_Invalid_GPOS_SubTable; + + la = &mlp->LigatureArray; + + if ( lig_index >= la->LigatureCount ) + return HB_Err_Invalid_GPOS_SubTable; + + lat = &la->LigatureAttach[lig_index]; + + /* We must now check whether the ligature ID of the current mark glyph + is identical to the ligature ID of the found ligature. If yes, we + can directly use the component index. If not, we attach the mark + glyph to the last component of the ligature. */ + + if ( IN_LIGID( j ) == IN_LIGID( buffer->in_pos) ) + { + comp_index = IN_COMPONENT( buffer->in_pos ); + if ( comp_index >= lat->ComponentCount ) + return HB_Err_Not_Covered; + } + else + comp_index = lat->ComponentCount - 1; + + cr = &lat->ComponentRecord[comp_index]; + lig_anchor = &cr->LigatureAnchor[class]; + + error = Get_Anchor( gpi, mark_anchor, IN_CURGLYPH(), + &x_mark_value, &y_mark_value ); + if ( error ) + return error; + error = Get_Anchor( gpi, lig_anchor, IN_GLYPH( j ), + &x_lig_value, &y_lig_value ); + if ( error ) + return error; + + /* anchor points are not cumulative */ + + o = POSITION( buffer->in_pos ); + + o->x_pos = x_lig_value - x_mark_value; + o->y_pos = y_lig_value - y_mark_value; + o->x_advance = 0; + o->y_advance = 0; + o->back = i; + + (buffer->in_pos)++; + + return FT_Err_Ok; +} + + +/* LookupType 6 */ + +/* Mark2Array */ + +static FT_Error Load_Mark2Array( HB_Mark2Array* m2a, + FT_UShort num_classes, + FT_Stream stream ) +{ + FT_Error error; + FT_Memory memory = stream->memory; + + FT_UShort k, m, n, count; + FT_ULong cur_offset, new_offset, base_offset; + + HB_Mark2Record* m2r; + HB_Anchor* m2an; + + + base_offset = FILE_Pos(); + + if ( ACCESS_Frame( 2L ) ) + return error; + + count = m2a->Mark2Count = GET_UShort(); + + FORGET_Frame(); + + m2a->Mark2Record = NULL; + + if ( ALLOC_ARRAY( m2a->Mark2Record, count, HB_Mark2Record ) ) + return error; + + m2r = m2a->Mark2Record; + + for ( m = 0; m < count; m++ ) + { + m2r[m].Mark2Anchor = NULL; + + if ( ALLOC_ARRAY( m2r[m].Mark2Anchor, num_classes, HB_Anchor ) ) + goto Fail; + + m2an = m2r[m].Mark2Anchor; + + for ( n = 0; n < num_classes; n++ ) + { + if ( ACCESS_Frame( 2L ) ) + goto Fail0; + + new_offset = GET_UShort() + base_offset; + + FORGET_Frame(); + + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = Load_Anchor( &m2an[n], stream ) ) != FT_Err_Ok ) + goto Fail0; + (void)FILE_Seek( cur_offset ); + } + + continue; + Fail0: + for ( k = 0; k < n; k++ ) + Free_Anchor( &m2an[k], memory ); + goto Fail; + } + + return FT_Err_Ok; + +Fail: + for ( k = 0; k < m; k++ ) + { + m2an = m2r[k].Mark2Anchor; + + for ( n = 0; n < num_classes; n++ ) + Free_Anchor( &m2an[n], memory ); + + FREE( m2an ); + } + + FREE( m2r ); + return error; +} + + +static void Free_Mark2Array( HB_Mark2Array* m2a, + FT_UShort num_classes, + FT_Memory memory ) +{ + FT_UShort m, n, count; + + HB_Mark2Record* m2r; + HB_Anchor* m2an; + + + if ( m2a->Mark2Record ) + { + count = m2a->Mark2Count; + m2r = m2a->Mark2Record; + + for ( m = 0; m < count; m++ ) + { + m2an = m2r[m].Mark2Anchor; + + for ( n = 0; n < num_classes; n++ ) + Free_Anchor( &m2an[n], memory ); + + FREE( m2an ); + } + + FREE( m2r ); + } +} + + +/* MarkMarkPosFormat1 */ + +static FT_Error Load_MarkMarkPos( HB_GPOS_SubTable* st, + FT_Stream stream ) +{ + FT_Error error; + FT_Memory memory = stream->memory; + HB_MarkMarkPos* mmp = &st->markmark; + + FT_ULong cur_offset, new_offset, base_offset; + + + base_offset = FILE_Pos(); + + if ( ACCESS_Frame( 4L ) ) + return error; + + mmp->PosFormat = GET_UShort(); + new_offset = GET_UShort() + base_offset; + + FORGET_Frame(); + + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = _HB_OPEN_Load_Coverage( &mmp->Mark1Coverage, + stream ) ) != FT_Err_Ok ) + return error; + (void)FILE_Seek( cur_offset ); + + if ( ACCESS_Frame( 2L ) ) + goto Fail3; + + new_offset = GET_UShort() + base_offset; + + FORGET_Frame(); + + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = _HB_OPEN_Load_Coverage( &mmp->Mark2Coverage, + stream ) ) != FT_Err_Ok ) + goto Fail3; + (void)FILE_Seek( cur_offset ); + + if ( ACCESS_Frame( 4L ) ) + goto Fail2; + + mmp->ClassCount = GET_UShort(); + new_offset = GET_UShort() + base_offset; + + FORGET_Frame(); + + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = Load_MarkArray( &mmp->Mark1Array, stream ) ) != FT_Err_Ok ) + goto Fail2; + (void)FILE_Seek( cur_offset ); + + if ( ACCESS_Frame( 2L ) ) + goto Fail1; + + new_offset = GET_UShort() + base_offset; + + FORGET_Frame(); + + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = Load_Mark2Array( &mmp->Mark2Array, mmp->ClassCount, + stream ) ) != FT_Err_Ok ) + goto Fail1; + + return FT_Err_Ok; + +Fail1: + Free_MarkArray( &mmp->Mark1Array, memory ); + +Fail2: + _HB_OPEN_Free_Coverage( &mmp->Mark2Coverage, memory ); + +Fail3: + _HB_OPEN_Free_Coverage( &mmp->Mark1Coverage, memory ); + return error; +} + + +static void Free_MarkMarkPos( HB_GPOS_SubTable* st, + FT_Memory memory) +{ + HB_MarkMarkPos* mmp = &st->markmark; + + Free_Mark2Array( &mmp->Mark2Array, mmp->ClassCount, memory ); + Free_MarkArray( &mmp->Mark1Array, memory ); + _HB_OPEN_Free_Coverage( &mmp->Mark2Coverage, memory ); + _HB_OPEN_Free_Coverage( &mmp->Mark1Coverage, memory ); +} + + +static FT_Error Lookup_MarkMarkPos( GPOS_Instance* gpi, + HB_GPOS_SubTable* st, + HB_Buffer buffer, + FT_UShort flags, + FT_UShort context_length, + int nesting_level ) +{ + FT_UShort j, mark1_index, mark2_index, property, class; + FT_Pos x_mark1_value, y_mark1_value, + x_mark2_value, y_mark2_value; + FT_Error error; + HB_GPOSHeader* gpos = gpi->gpos; + HB_MarkMarkPos* mmp = &st->markmark; + + HB_MarkArray* ma1; + HB_Mark2Array* ma2; + HB_Mark2Record* m2r; + HB_Anchor* mark1_anchor; + HB_Anchor* mark2_anchor; + + HB_Position o; + + + if ( context_length != 0xFFFF && context_length < 1 ) + return HB_Err_Not_Covered; + + if ( flags & HB_LOOKUP_FLAG_IGNORE_MARKS ) + return HB_Err_Not_Covered; + + if ( CHECK_Property( gpos->gdef, IN_CURITEM(), + flags, &property ) ) + return error; + + error = _HB_OPEN_Coverage_Index( &mmp->Mark1Coverage, IN_CURGLYPH(), + &mark1_index ); + if ( error ) + return error; + + /* now we check the preceding glyph whether it is a suitable + mark glyph */ + + if ( buffer->in_pos == 0 ) + return HB_Err_Not_Covered; + + j = buffer->in_pos - 1; + error = HB_GDEF_Get_Glyph_Property( gpos->gdef, IN_GLYPH( j ), + &property ); + if ( error ) + return error; + + if ( flags & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS ) + { + if ( property != (flags & 0xFF00) ) + return HB_Err_Not_Covered; + } + else + { + if ( property != HB_GDEF_MARK ) + return HB_Err_Not_Covered; + } + + error = _HB_OPEN_Coverage_Index( &mmp->Mark2Coverage, IN_GLYPH( j ), + &mark2_index ); + if ( error ) + return error; + + ma1 = &mmp->Mark1Array; + + if ( mark1_index >= ma1->MarkCount ) + return HB_Err_Invalid_GPOS_SubTable; + + class = ma1->MarkRecord[mark1_index].Class; + mark1_anchor = &ma1->MarkRecord[mark1_index].MarkAnchor; + + if ( class >= mmp->ClassCount ) + return HB_Err_Invalid_GPOS_SubTable; + + ma2 = &mmp->Mark2Array; + + if ( mark2_index >= ma2->Mark2Count ) + return HB_Err_Invalid_GPOS_SubTable; + + m2r = &ma2->Mark2Record[mark2_index]; + mark2_anchor = &m2r->Mark2Anchor[class]; + + error = Get_Anchor( gpi, mark1_anchor, IN_CURGLYPH(), + &x_mark1_value, &y_mark1_value ); + if ( error ) + return error; + error = Get_Anchor( gpi, mark2_anchor, IN_GLYPH( j ), + &x_mark2_value, &y_mark2_value ); + if ( error ) + return error; + + /* anchor points are not cumulative */ + + o = POSITION( buffer->in_pos ); + + o->x_pos = x_mark2_value - x_mark1_value; + o->y_pos = y_mark2_value - y_mark1_value; + o->x_advance = 0; + o->y_advance = 0; + o->back = 1; + + (buffer->in_pos)++; + + return FT_Err_Ok; +} + + +/* Do the actual positioning for a context positioning (either format + 7 or 8). This is only called after we've determined that the stream + matches the subrule. */ + +static FT_Error Do_ContextPos( GPOS_Instance* gpi, + FT_UShort GlyphCount, + FT_UShort PosCount, + HB_PosLookupRecord* pos, + HB_Buffer buffer, + int nesting_level ) +{ + FT_Error error; + FT_UShort i, old_pos; + + + i = 0; + + while ( i < GlyphCount ) + { + if ( PosCount && i == pos->SequenceIndex ) + { + old_pos = buffer->in_pos; + + /* Do a positioning */ + + error = GPOS_Do_Glyph_Lookup( gpi, pos->LookupListIndex, buffer, + GlyphCount, nesting_level ); + + if ( error ) + return error; + + pos++; + PosCount--; + i += buffer->in_pos - old_pos; + } + else + { + i++; + (buffer->in_pos)++; + } + } + + return FT_Err_Ok; +} + + +/* LookupType 7 */ + +/* PosRule */ + +static FT_Error Load_PosRule( HB_PosRule* pr, + FT_Stream stream ) +{ + FT_Error error; + FT_Memory memory = stream->memory; + + FT_UShort n, count; + FT_UShort* i; + + HB_PosLookupRecord* plr; + + + if ( ACCESS_Frame( 4L ) ) + return error; + + pr->GlyphCount = GET_UShort(); + pr->PosCount = GET_UShort(); + + FORGET_Frame(); + + pr->Input = NULL; + + count = pr->GlyphCount - 1; /* only GlyphCount - 1 elements */ + + if ( ALLOC_ARRAY( pr->Input, count, FT_UShort ) ) + return error; + + i = pr->Input; + + if ( ACCESS_Frame( count * 2L ) ) + goto Fail2; + + for ( n = 0; n < count; n++ ) + i[n] = GET_UShort(); + + FORGET_Frame(); + + pr->PosLookupRecord = NULL; + + count = pr->PosCount; + + if ( ALLOC_ARRAY( pr->PosLookupRecord, count, HB_PosLookupRecord ) ) + goto Fail2; + + plr = pr->PosLookupRecord; + + if ( ACCESS_Frame( count * 4L ) ) + goto Fail1; + + for ( n = 0; n < count; n++ ) + { + plr[n].SequenceIndex = GET_UShort(); + plr[n].LookupListIndex = GET_UShort(); + } + + FORGET_Frame(); + + return FT_Err_Ok; + +Fail1: + FREE( plr ); + +Fail2: + FREE( i ); + return error; +} + + +static void Free_PosRule( HB_PosRule* pr, + FT_Memory memory ) +{ + FREE( pr->PosLookupRecord ); + FREE( pr->Input ); +} + + +/* PosRuleSet */ + +static FT_Error Load_PosRuleSet( HB_PosRuleSet* prs, + FT_Stream stream ) +{ + FT_Error error; + FT_Memory memory = stream->memory; + + FT_UShort n, m, count; + FT_ULong cur_offset, new_offset, base_offset; + + HB_PosRule* pr; + + + base_offset = FILE_Pos(); + + if ( ACCESS_Frame( 2L ) ) + return error; + + count = prs->PosRuleCount = GET_UShort(); + + FORGET_Frame(); + + prs->PosRule = NULL; + + if ( ALLOC_ARRAY( prs->PosRule, count, HB_PosRule ) ) + return error; + + pr = prs->PosRule; + + for ( n = 0; n < count; n++ ) + { + if ( ACCESS_Frame( 2L ) ) + goto Fail; + + new_offset = GET_UShort() + base_offset; + + FORGET_Frame(); + + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = Load_PosRule( &pr[n], stream ) ) != FT_Err_Ok ) + goto Fail; + (void)FILE_Seek( cur_offset ); + } + + return FT_Err_Ok; + +Fail: + for ( m = 0; m < n; m++ ) + Free_PosRule( &pr[m], memory ); + + FREE( pr ); + return error; +} + + +static void Free_PosRuleSet( HB_PosRuleSet* prs, + FT_Memory memory ) +{ + FT_UShort n, count; + + HB_PosRule* pr; + + + if ( prs->PosRule ) + { + count = prs->PosRuleCount; + pr = prs->PosRule; + + for ( n = 0; n < count; n++ ) + Free_PosRule( &pr[n], memory ); + + FREE( pr ); + } +} + + +/* ContextPosFormat1 */ + +static FT_Error Load_ContextPos1( HB_ContextPosFormat1* cpf1, + FT_Stream stream ) +{ + FT_Error error; + FT_Memory memory = stream->memory; + + FT_UShort n, m, count; + FT_ULong cur_offset, new_offset, base_offset; + + HB_PosRuleSet* prs; + + + base_offset = FILE_Pos() - 2L; + + if ( ACCESS_Frame( 2L ) ) + return error; + + new_offset = GET_UShort() + base_offset; + + FORGET_Frame(); + + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = _HB_OPEN_Load_Coverage( &cpf1->Coverage, stream ) ) != FT_Err_Ok ) + return error; + (void)FILE_Seek( cur_offset ); + + if ( ACCESS_Frame( 2L ) ) + goto Fail2; + + count = cpf1->PosRuleSetCount = GET_UShort(); + + FORGET_Frame(); + + cpf1->PosRuleSet = NULL; + + if ( ALLOC_ARRAY( cpf1->PosRuleSet, count, HB_PosRuleSet ) ) + goto Fail2; + + prs = cpf1->PosRuleSet; + + for ( n = 0; n < count; n++ ) + { + if ( ACCESS_Frame( 2L ) ) + goto Fail1; + + new_offset = GET_UShort() + base_offset; + + FORGET_Frame(); + + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = Load_PosRuleSet( &prs[n], stream ) ) != FT_Err_Ok ) + goto Fail1; + (void)FILE_Seek( cur_offset ); + } + + return FT_Err_Ok; + +Fail1: + for ( m = 0; m < n; m++ ) + Free_PosRuleSet( &prs[m], memory ); + + FREE( prs ); + +Fail2: + _HB_OPEN_Free_Coverage( &cpf1->Coverage, memory ); + return error; +} + + +static void Free_ContextPos1( HB_ContextPosFormat1* cpf1, + FT_Memory memory ) +{ + FT_UShort n, count; + + HB_PosRuleSet* prs; + + + if ( cpf1->PosRuleSet ) + { + count = cpf1->PosRuleSetCount; + prs = cpf1->PosRuleSet; + + for ( n = 0; n < count; n++ ) + Free_PosRuleSet( &prs[n], memory ); + + FREE( prs ); + } + + _HB_OPEN_Free_Coverage( &cpf1->Coverage, memory ); +} + + +/* PosClassRule */ + +static FT_Error Load_PosClassRule( HB_ContextPosFormat2* cpf2, + HB_PosClassRule* pcr, + FT_Stream stream ) +{ + FT_Error error; + FT_Memory memory = stream->memory; + + FT_UShort n, count; + + FT_UShort* c; + HB_PosLookupRecord* plr; + FT_Bool* d; + + + if ( ACCESS_Frame( 4L ) ) + return error; + + pcr->GlyphCount = GET_UShort(); + pcr->PosCount = GET_UShort(); + + FORGET_Frame(); + + if ( pcr->GlyphCount > cpf2->MaxContextLength ) + cpf2->MaxContextLength = pcr->GlyphCount; + + pcr->Class = NULL; + + count = pcr->GlyphCount - 1; /* only GlyphCount - 1 elements */ + + if ( ALLOC_ARRAY( pcr->Class, count, FT_UShort ) ) + return error; + + c = pcr->Class; + d = cpf2->ClassDef.Defined; + + if ( ACCESS_Frame( count * 2L ) ) + goto Fail2; + + for ( n = 0; n < count; n++ ) + { + c[n] = GET_UShort(); + + /* We check whether the specific class is used at all. If not, + class 0 is used instead. */ + + if ( !d[c[n]] ) + c[n] = 0; + } + + FORGET_Frame(); + + pcr->PosLookupRecord = NULL; + + count = pcr->PosCount; + + if ( ALLOC_ARRAY( pcr->PosLookupRecord, count, HB_PosLookupRecord ) ) + goto Fail2; + + plr = pcr->PosLookupRecord; + + if ( ACCESS_Frame( count * 4L ) ) + goto Fail1; + + for ( n = 0; n < count; n++ ) + { + plr[n].SequenceIndex = GET_UShort(); + plr[n].LookupListIndex = GET_UShort(); + } + + FORGET_Frame(); + + return FT_Err_Ok; + +Fail1: + FREE( plr ); + +Fail2: + FREE( c ); + return error; +} + + +static void Free_PosClassRule( HB_PosClassRule* pcr, + FT_Memory memory ) +{ + FREE( pcr->PosLookupRecord ); + FREE( pcr->Class ); +} + + +/* PosClassSet */ + +static FT_Error Load_PosClassSet( HB_ContextPosFormat2* cpf2, + HB_PosClassSet* pcs, + FT_Stream stream ) +{ + FT_Error error; + FT_Memory memory = stream->memory; + + FT_UShort n, m, count; + FT_ULong cur_offset, new_offset, base_offset; + + HB_PosClassRule* pcr; + + + base_offset = FILE_Pos(); + + if ( ACCESS_Frame( 2L ) ) + return error; + + count = pcs->PosClassRuleCount = GET_UShort(); + + FORGET_Frame(); + + pcs->PosClassRule = NULL; + + if ( ALLOC_ARRAY( pcs->PosClassRule, count, HB_PosClassRule ) ) + return error; + + pcr = pcs->PosClassRule; + + for ( n = 0; n < count; n++ ) + { + if ( ACCESS_Frame( 2L ) ) + goto Fail; + + new_offset = GET_UShort() + base_offset; + + FORGET_Frame(); + + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = Load_PosClassRule( cpf2, &pcr[n], + stream ) ) != FT_Err_Ok ) + goto Fail; + (void)FILE_Seek( cur_offset ); + } + + return FT_Err_Ok; + +Fail: + for ( m = 0; m < n; m++ ) + Free_PosClassRule( &pcr[m], memory ); + + FREE( pcr ); + return error; +} + + +static void Free_PosClassSet( HB_PosClassSet* pcs, + FT_Memory memory ) +{ + FT_UShort n, count; + + HB_PosClassRule* pcr; + + + if ( pcs->PosClassRule ) + { + count = pcs->PosClassRuleCount; + pcr = pcs->PosClassRule; + + for ( n = 0; n < count; n++ ) + Free_PosClassRule( &pcr[n], memory ); + + FREE( pcr ); + } +} + + +/* ContextPosFormat2 */ + +static FT_Error Load_ContextPos2( HB_ContextPosFormat2* cpf2, + FT_Stream stream ) +{ + FT_Error error; + FT_Memory memory = stream->memory; + + FT_UShort n, m, count; + FT_ULong cur_offset, new_offset, base_offset; + + HB_PosClassSet* pcs; + + + base_offset = FILE_Pos() - 2; + + if ( ACCESS_Frame( 2L ) ) + return error; + + new_offset = GET_UShort() + base_offset; + + FORGET_Frame(); + + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = _HB_OPEN_Load_Coverage( &cpf2->Coverage, stream ) ) != FT_Err_Ok ) + return error; + (void)FILE_Seek( cur_offset ); + + if ( ACCESS_Frame( 4L ) ) + goto Fail3; + + new_offset = GET_UShort() + base_offset; + + /* `PosClassSetCount' is the upper limit for class values, thus we + read it now to make an additional safety check. */ + + count = cpf2->PosClassSetCount = GET_UShort(); + + FORGET_Frame(); + + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = _HB_OPEN_Load_ClassDefinition( &cpf2->ClassDef, count, + stream ) ) != FT_Err_Ok ) + goto Fail3; + (void)FILE_Seek( cur_offset ); + + cpf2->PosClassSet = NULL; + cpf2->MaxContextLength = 0; + + if ( ALLOC_ARRAY( cpf2->PosClassSet, count, HB_PosClassSet ) ) + goto Fail2; + + pcs = cpf2->PosClassSet; + + for ( n = 0; n < count; n++ ) + { + if ( ACCESS_Frame( 2L ) ) + goto Fail1; + + new_offset = GET_UShort() + base_offset; + + FORGET_Frame(); + + if ( new_offset != base_offset ) /* not a NULL offset */ + { + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = Load_PosClassSet( cpf2, &pcs[n], + stream ) ) != FT_Err_Ok ) + goto Fail1; + (void)FILE_Seek( cur_offset ); + } + else + { + /* we create a PosClassSet table with no entries */ + + cpf2->PosClassSet[n].PosClassRuleCount = 0; + cpf2->PosClassSet[n].PosClassRule = NULL; + } + } + + return FT_Err_Ok; + +Fail1: + for ( m = 0; m < n; n++ ) + Free_PosClassSet( &pcs[m], memory ); + + FREE( pcs ); + +Fail2: + _HB_OPEN_Free_ClassDefinition( &cpf2->ClassDef, memory ); + +Fail3: + _HB_OPEN_Free_Coverage( &cpf2->Coverage, memory ); + return error; +} + + +static void Free_ContextPos2( HB_ContextPosFormat2* cpf2, + FT_Memory memory ) +{ + FT_UShort n, count; + + HB_PosClassSet* pcs; + + + if ( cpf2->PosClassSet ) + { + count = cpf2->PosClassSetCount; + pcs = cpf2->PosClassSet; + + for ( n = 0; n < count; n++ ) + Free_PosClassSet( &pcs[n], memory ); + + FREE( pcs ); + } + + _HB_OPEN_Free_ClassDefinition( &cpf2->ClassDef, memory ); + _HB_OPEN_Free_Coverage( &cpf2->Coverage, memory ); +} + + +/* ContextPosFormat3 */ + +static FT_Error Load_ContextPos3( HB_ContextPosFormat3* cpf3, + FT_Stream stream ) +{ + FT_Error error; + FT_Memory memory = stream->memory; + + FT_UShort n, count; + FT_ULong cur_offset, new_offset, base_offset; + + HB_Coverage* c; + HB_PosLookupRecord* plr; + + + base_offset = FILE_Pos() - 2L; + + if ( ACCESS_Frame( 4L ) ) + return error; + + cpf3->GlyphCount = GET_UShort(); + cpf3->PosCount = GET_UShort(); + + FORGET_Frame(); + + cpf3->Coverage = NULL; + + count = cpf3->GlyphCount; + + if ( ALLOC_ARRAY( cpf3->Coverage, count, HB_Coverage ) ) + return error; + + c = cpf3->Coverage; + + for ( n = 0; n < count; n++ ) + { + if ( ACCESS_Frame( 2L ) ) + goto Fail2; + + new_offset = GET_UShort() + base_offset; + + FORGET_Frame(); + + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = _HB_OPEN_Load_Coverage( &c[n], stream ) ) != FT_Err_Ok ) + goto Fail2; + (void)FILE_Seek( cur_offset ); + } + + cpf3->PosLookupRecord = NULL; + + count = cpf3->PosCount; + + if ( ALLOC_ARRAY( cpf3->PosLookupRecord, count, HB_PosLookupRecord ) ) + goto Fail2; + + plr = cpf3->PosLookupRecord; + + if ( ACCESS_Frame( count * 4L ) ) + goto Fail1; + + for ( n = 0; n < count; n++ ) + { + plr[n].SequenceIndex = GET_UShort(); + plr[n].LookupListIndex = GET_UShort(); + } + + FORGET_Frame(); + + return FT_Err_Ok; + +Fail1: + FREE( plr ); + +Fail2: + for ( n = 0; n < count; n++ ) + _HB_OPEN_Free_Coverage( &c[n], memory ); + + FREE( c ); + return error; +} + + +static void Free_ContextPos3( HB_ContextPosFormat3* cpf3, + FT_Memory memory ) +{ + FT_UShort n, count; + + HB_Coverage* c; + + + FREE( cpf3->PosLookupRecord ); + + if ( cpf3->Coverage ) + { + count = cpf3->GlyphCount; + c = cpf3->Coverage; + + for ( n = 0; n < count; n++ ) + _HB_OPEN_Free_Coverage( &c[n], memory ); + + FREE( c ); + } +} + + +/* ContextPos */ + +static FT_Error Load_ContextPos( HB_GPOS_SubTable* st, + FT_Stream stream ) +{ + FT_Error error; + HB_ContextPos* cp = &st->context; + + + if ( ACCESS_Frame( 2L ) ) + return error; + + cp->PosFormat = GET_UShort(); + + FORGET_Frame(); + + switch ( cp->PosFormat ) + { + case 1: + return Load_ContextPos1( &cp->cpf.cpf1, stream ); + + case 2: + return Load_ContextPos2( &cp->cpf.cpf2, stream ); + + case 3: + return Load_ContextPos3( &cp->cpf.cpf3, stream ); + + default: + return HB_Err_Invalid_GPOS_SubTable_Format; + } + + return FT_Err_Ok; /* never reached */ +} + + +static void Free_ContextPos( HB_GPOS_SubTable* st, + FT_Memory memory ) +{ + HB_ContextPos* cp = &st->context; + + switch ( cp->PosFormat ) + { + case 1: + Free_ContextPos1( &cp->cpf.cpf1, memory ); + break; + + case 2: + Free_ContextPos2( &cp->cpf.cpf2, memory ); + break; + + case 3: + Free_ContextPos3( &cp->cpf.cpf3, memory ); + break; + } +} + + +static FT_Error Lookup_ContextPos1( GPOS_Instance* gpi, + HB_ContextPosFormat1* cpf1, + HB_Buffer buffer, + FT_UShort flags, + FT_UShort context_length, + int nesting_level ) +{ + FT_UShort index, property; + FT_UShort i, j, k, numpr; + FT_Error error; + HB_GPOSHeader* gpos = gpi->gpos; + + HB_PosRule* pr; + HB_GDEFHeader* gdef; + + + gdef = gpos->gdef; + + if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) ) + return error; + + error = _HB_OPEN_Coverage_Index( &cpf1->Coverage, IN_CURGLYPH(), &index ); + if ( error ) + return error; + + pr = cpf1->PosRuleSet[index].PosRule; + numpr = cpf1->PosRuleSet[index].PosRuleCount; + + for ( k = 0; k < numpr; k++ ) + { + if ( context_length != 0xFFFF && context_length < pr[k].GlyphCount ) + goto next_posrule; + + if ( buffer->in_pos + pr[k].GlyphCount > buffer->in_length ) + goto next_posrule; /* context is too long */ + + for ( i = 1, j = buffer->in_pos + 1; i < pr[k].GlyphCount; i++, j++ ) + { + while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) + { + if ( error && error != HB_Err_Not_Covered ) + return error; + + if ( j + pr[k].GlyphCount - i == buffer->in_length ) + goto next_posrule; + j++; + } + + if ( IN_GLYPH( j ) != pr[k].Input[i - 1] ) + goto next_posrule; + } + + return Do_ContextPos( gpi, pr[k].GlyphCount, + pr[k].PosCount, pr[k].PosLookupRecord, + buffer, + nesting_level ); + + next_posrule: + ; + } + + return HB_Err_Not_Covered; +} + + +static FT_Error Lookup_ContextPos2( GPOS_Instance* gpi, + HB_ContextPosFormat2* cpf2, + HB_Buffer buffer, + FT_UShort flags, + FT_UShort context_length, + int nesting_level ) +{ + FT_UShort index, property; + FT_Error error; + FT_Memory memory = gpi->face->memory; + FT_UShort i, j, k, known_classes; + + FT_UShort* classes; + FT_UShort* cl; + HB_GPOSHeader* gpos = gpi->gpos; + + HB_PosClassSet* pcs; + HB_PosClassRule* pr; + HB_GDEFHeader* gdef; + + + gdef = gpos->gdef; + + if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) ) + return error; + + /* Note: The coverage table in format 2 doesn't give an index into + anything. It just lets us know whether or not we need to + do any lookup at all. */ + + error = _HB_OPEN_Coverage_Index( &cpf2->Coverage, IN_CURGLYPH(), &index ); + if ( error ) + return error; + + if ( ALLOC_ARRAY( classes, cpf2->MaxContextLength, FT_UShort ) ) + return error; + + error = _HB_OPEN_Get_Class( &cpf2->ClassDef, IN_CURGLYPH(), + &classes[0], NULL ); + if ( error && error != HB_Err_Not_Covered ) + goto End; + known_classes = 0; + + pcs = &cpf2->PosClassSet[classes[0]]; + if ( !pcs ) + { + error = HB_Err_Invalid_GPOS_SubTable; + goto End; + } + + for ( k = 0; k < pcs->PosClassRuleCount; k++ ) + { + pr = &pcs->PosClassRule[k]; + + if ( context_length != 0xFFFF && context_length < pr->GlyphCount ) + goto next_posclassrule; + + if ( buffer->in_pos + pr->GlyphCount > buffer->in_length ) + goto next_posclassrule; /* context is too long */ + + cl = pr->Class; + + /* Start at 1 because [0] is implied */ + + for ( i = 1, j = buffer->in_pos + 1; i < pr->GlyphCount; i++, j++ ) + { + while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) + { + if ( error && error != HB_Err_Not_Covered ) + goto End; + + if ( j + pr->GlyphCount - i == buffer->in_length ) + goto next_posclassrule; + j++; + } + + if ( i > known_classes ) + { + /* Keeps us from having to do this for each rule */ + + error = _HB_OPEN_Get_Class( &cpf2->ClassDef, IN_GLYPH( j ), &classes[i], NULL ); + if ( error && error != HB_Err_Not_Covered ) + goto End; + known_classes = i; + } + + if ( cl[i - 1] != classes[i] ) + goto next_posclassrule; + } + + error = Do_ContextPos( gpi, pr->GlyphCount, + pr->PosCount, pr->PosLookupRecord, + buffer, + nesting_level ); + goto End; + + next_posclassrule: + ; + } + + error = HB_Err_Not_Covered; + +End: + FREE( classes ); + return error; +} + + +static FT_Error Lookup_ContextPos3( GPOS_Instance* gpi, + HB_ContextPosFormat3* cpf3, + HB_Buffer buffer, + FT_UShort flags, + FT_UShort context_length, + int nesting_level ) +{ + FT_Error error; + FT_UShort index, i, j, property; + HB_GPOSHeader* gpos = gpi->gpos; + + HB_Coverage* c; + HB_GDEFHeader* gdef; + + + gdef = gpos->gdef; + + if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) ) + return error; + + if ( context_length != 0xFFFF && context_length < cpf3->GlyphCount ) + return HB_Err_Not_Covered; + + if ( buffer->in_pos + cpf3->GlyphCount > buffer->in_length ) + return HB_Err_Not_Covered; /* context is too long */ + + c = cpf3->Coverage; + + for ( i = 1, j = 1; i < cpf3->GlyphCount; i++, j++ ) + { + while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) + { + if ( error && error != HB_Err_Not_Covered ) + return error; + + if ( j + cpf3->GlyphCount - i == buffer->in_length ) + return HB_Err_Not_Covered; + j++; + } + + error = _HB_OPEN_Coverage_Index( &c[i], IN_GLYPH( j ), &index ); + if ( error ) + return error; + } + + return Do_ContextPos( gpi, cpf3->GlyphCount, + cpf3->PosCount, cpf3->PosLookupRecord, + buffer, + nesting_level ); +} + + +static FT_Error Lookup_ContextPos( GPOS_Instance* gpi, + HB_GPOS_SubTable* st, + HB_Buffer buffer, + FT_UShort flags, + FT_UShort context_length, + int nesting_level ) +{ + HB_ContextPos* cp = &st->context; + + switch ( cp->PosFormat ) + { + case 1: + return Lookup_ContextPos1( gpi, &cp->cpf.cpf1, buffer, + flags, context_length, nesting_level ); + + case 2: + return Lookup_ContextPos2( gpi, &cp->cpf.cpf2, buffer, + flags, context_length, nesting_level ); + + case 3: + return Lookup_ContextPos3( gpi, &cp->cpf.cpf3, buffer, + flags, context_length, nesting_level ); + + default: + return HB_Err_Invalid_GPOS_SubTable_Format; + } + + return FT_Err_Ok; /* never reached */ +} + + +/* LookupType 8 */ + +/* ChainPosRule */ + +static FT_Error Load_ChainPosRule( HB_ChainPosRule* cpr, + FT_Stream stream ) +{ + FT_Error error; + FT_Memory memory = stream->memory; + + FT_UShort n, count; + FT_UShort* b; + FT_UShort* i; + FT_UShort* l; + + HB_PosLookupRecord* plr; + + + if ( ACCESS_Frame( 2L ) ) + return error; + + cpr->BacktrackGlyphCount = GET_UShort(); + + FORGET_Frame(); + + cpr->Backtrack = NULL; + + count = cpr->BacktrackGlyphCount; + + if ( ALLOC_ARRAY( cpr->Backtrack, count, FT_UShort ) ) + return error; + + b = cpr->Backtrack; + + if ( ACCESS_Frame( count * 2L ) ) + goto Fail4; + + for ( n = 0; n < count; n++ ) + b[n] = GET_UShort(); + + FORGET_Frame(); + + if ( ACCESS_Frame( 2L ) ) + goto Fail4; + + cpr->InputGlyphCount = GET_UShort(); + + FORGET_Frame(); + + cpr->Input = NULL; + + count = cpr->InputGlyphCount - 1; /* only InputGlyphCount - 1 elements */ + + if ( ALLOC_ARRAY( cpr->Input, count, FT_UShort ) ) + goto Fail4; + + i = cpr->Input; + + if ( ACCESS_Frame( count * 2L ) ) + goto Fail3; + + for ( n = 0; n < count; n++ ) + i[n] = GET_UShort(); + + FORGET_Frame(); + + if ( ACCESS_Frame( 2L ) ) + goto Fail3; + + cpr->LookaheadGlyphCount = GET_UShort(); + + FORGET_Frame(); + + cpr->Lookahead = NULL; + + count = cpr->LookaheadGlyphCount; + + if ( ALLOC_ARRAY( cpr->Lookahead, count, FT_UShort ) ) + goto Fail3; + + l = cpr->Lookahead; + + if ( ACCESS_Frame( count * 2L ) ) + goto Fail2; + + for ( n = 0; n < count; n++ ) + l[n] = GET_UShort(); + + FORGET_Frame(); + + if ( ACCESS_Frame( 2L ) ) + goto Fail2; + + cpr->PosCount = GET_UShort(); + + FORGET_Frame(); + + cpr->PosLookupRecord = NULL; + + count = cpr->PosCount; + + if ( ALLOC_ARRAY( cpr->PosLookupRecord, count, HB_PosLookupRecord ) ) + goto Fail2; + + plr = cpr->PosLookupRecord; + + if ( ACCESS_Frame( count * 4L ) ) + goto Fail1; + + for ( n = 0; n < count; n++ ) + { + plr[n].SequenceIndex = GET_UShort(); + plr[n].LookupListIndex = GET_UShort(); + } + + FORGET_Frame(); + + return FT_Err_Ok; + +Fail1: + FREE( plr ); + +Fail2: + FREE( l ); + +Fail3: + FREE( i ); + +Fail4: + FREE( b ); + return error; +} + + +static void Free_ChainPosRule( HB_ChainPosRule* cpr, + FT_Memory memory ) +{ + FREE( cpr->PosLookupRecord ); + FREE( cpr->Lookahead ); + FREE( cpr->Input ); + FREE( cpr->Backtrack ); +} + + +/* ChainPosRuleSet */ + +static FT_Error Load_ChainPosRuleSet( HB_ChainPosRuleSet* cprs, + FT_Stream stream ) +{ + FT_Error error; + FT_Memory memory = stream->memory; + + FT_UShort n, m, count; + FT_ULong cur_offset, new_offset, base_offset; + + HB_ChainPosRule* cpr; + + + base_offset = FILE_Pos(); + + if ( ACCESS_Frame( 2L ) ) + return error; + + count = cprs->ChainPosRuleCount = GET_UShort(); + + FORGET_Frame(); + + cprs->ChainPosRule = NULL; + + if ( ALLOC_ARRAY( cprs->ChainPosRule, count, HB_ChainPosRule ) ) + return error; + + cpr = cprs->ChainPosRule; + + for ( n = 0; n < count; n++ ) + { + if ( ACCESS_Frame( 2L ) ) + goto Fail; + + new_offset = GET_UShort() + base_offset; + + FORGET_Frame(); + + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = Load_ChainPosRule( &cpr[n], stream ) ) != FT_Err_Ok ) + goto Fail; + (void)FILE_Seek( cur_offset ); + } + + return FT_Err_Ok; + +Fail: + for ( m = 0; m < n; m++ ) + Free_ChainPosRule( &cpr[m], memory ); + + FREE( cpr ); + return error; +} + + +static void Free_ChainPosRuleSet( HB_ChainPosRuleSet* cprs, + FT_Memory memory ) +{ + FT_UShort n, count; + + HB_ChainPosRule* cpr; + + + if ( cprs->ChainPosRule ) + { + count = cprs->ChainPosRuleCount; + cpr = cprs->ChainPosRule; + + for ( n = 0; n < count; n++ ) + Free_ChainPosRule( &cpr[n], memory ); + + FREE( cpr ); + } +} + + +/* ChainContextPosFormat1 */ + +static FT_Error Load_ChainContextPos1( HB_ChainContextPosFormat1* ccpf1, + FT_Stream stream ) +{ + FT_Error error; + FT_Memory memory = stream->memory; + + FT_UShort n, m, count; + FT_ULong cur_offset, new_offset, base_offset; + + HB_ChainPosRuleSet* cprs; + + + base_offset = FILE_Pos() - 2L; + + if ( ACCESS_Frame( 2L ) ) + return error; + + new_offset = GET_UShort() + base_offset; + + FORGET_Frame(); + + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = _HB_OPEN_Load_Coverage( &ccpf1->Coverage, stream ) ) != FT_Err_Ok ) + return error; + (void)FILE_Seek( cur_offset ); + + if ( ACCESS_Frame( 2L ) ) + goto Fail2; + + count = ccpf1->ChainPosRuleSetCount = GET_UShort(); + + FORGET_Frame(); + + ccpf1->ChainPosRuleSet = NULL; + + if ( ALLOC_ARRAY( ccpf1->ChainPosRuleSet, count, HB_ChainPosRuleSet ) ) + goto Fail2; + + cprs = ccpf1->ChainPosRuleSet; + + for ( n = 0; n < count; n++ ) + { + if ( ACCESS_Frame( 2L ) ) + goto Fail1; + + new_offset = GET_UShort() + base_offset; + + FORGET_Frame(); + + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = Load_ChainPosRuleSet( &cprs[n], stream ) ) != FT_Err_Ok ) + goto Fail1; + (void)FILE_Seek( cur_offset ); + } + + return FT_Err_Ok; + +Fail1: + for ( m = 0; m < n; m++ ) + Free_ChainPosRuleSet( &cprs[m], memory ); + + FREE( cprs ); + +Fail2: + _HB_OPEN_Free_Coverage( &ccpf1->Coverage, memory ); + return error; +} + + +static void Free_ChainContextPos1( HB_ChainContextPosFormat1* ccpf1, + FT_Memory memory ) +{ + FT_UShort n, count; + + HB_ChainPosRuleSet* cprs; + + + if ( ccpf1->ChainPosRuleSet ) + { + count = ccpf1->ChainPosRuleSetCount; + cprs = ccpf1->ChainPosRuleSet; + + for ( n = 0; n < count; n++ ) + Free_ChainPosRuleSet( &cprs[n], memory ); + + FREE( cprs ); + } + + _HB_OPEN_Free_Coverage( &ccpf1->Coverage, memory ); +} + + +/* ChainPosClassRule */ + +static FT_Error Load_ChainPosClassRule( + HB_ChainContextPosFormat2* ccpf2, + HB_ChainPosClassRule* cpcr, + FT_Stream stream ) +{ + FT_Error error; + FT_Memory memory = stream->memory; + + FT_UShort n, count; + + FT_UShort* b; + FT_UShort* i; + FT_UShort* l; + HB_PosLookupRecord* plr; + FT_Bool* d; + + + if ( ACCESS_Frame( 2L ) ) + return error; + + cpcr->BacktrackGlyphCount = GET_UShort(); + + FORGET_Frame(); + + if ( cpcr->BacktrackGlyphCount > ccpf2->MaxBacktrackLength ) + ccpf2->MaxBacktrackLength = cpcr->BacktrackGlyphCount; + + cpcr->Backtrack = NULL; + + count = cpcr->BacktrackGlyphCount; + + if ( ALLOC_ARRAY( cpcr->Backtrack, count, FT_UShort ) ) + return error; + + b = cpcr->Backtrack; + d = ccpf2->BacktrackClassDef.Defined; + + if ( ACCESS_Frame( count * 2L ) ) + goto Fail4; + + for ( n = 0; n < count; n++ ) + { + b[n] = GET_UShort(); + + /* We check whether the specific class is used at all. If not, + class 0 is used instead. */ + + if ( !d[b[n]] ) + b[n] = 0; + } + + FORGET_Frame(); + + if ( ACCESS_Frame( 2L ) ) + goto Fail4; + + cpcr->InputGlyphCount = GET_UShort(); + + if ( cpcr->InputGlyphCount > ccpf2->MaxInputLength ) + ccpf2->MaxInputLength = cpcr->InputGlyphCount; + + FORGET_Frame(); + + cpcr->Input = NULL; + + count = cpcr->InputGlyphCount - 1; /* only InputGlyphCount - 1 elements */ + + if ( ALLOC_ARRAY( cpcr->Input, count, FT_UShort ) ) + goto Fail4; + + i = cpcr->Input; + d = ccpf2->InputClassDef.Defined; + + if ( ACCESS_Frame( count * 2L ) ) + goto Fail3; + + for ( n = 0; n < count; n++ ) + { + i[n] = GET_UShort(); + + if ( !d[i[n]] ) + i[n] = 0; + } + + FORGET_Frame(); + + if ( ACCESS_Frame( 2L ) ) + goto Fail3; + + cpcr->LookaheadGlyphCount = GET_UShort(); + + FORGET_Frame(); + + if ( cpcr->LookaheadGlyphCount > ccpf2->MaxLookaheadLength ) + ccpf2->MaxLookaheadLength = cpcr->LookaheadGlyphCount; + + cpcr->Lookahead = NULL; + + count = cpcr->LookaheadGlyphCount; + + if ( ALLOC_ARRAY( cpcr->Lookahead, count, FT_UShort ) ) + goto Fail3; + + l = cpcr->Lookahead; + d = ccpf2->LookaheadClassDef.Defined; + + if ( ACCESS_Frame( count * 2L ) ) + goto Fail2; + + for ( n = 0; n < count; n++ ) + { + l[n] = GET_UShort(); + + if ( !d[l[n]] ) + l[n] = 0; + } + + FORGET_Frame(); + + if ( ACCESS_Frame( 2L ) ) + goto Fail2; + + cpcr->PosCount = GET_UShort(); + + FORGET_Frame(); + + cpcr->PosLookupRecord = NULL; + + count = cpcr->PosCount; + + if ( ALLOC_ARRAY( cpcr->PosLookupRecord, count, HB_PosLookupRecord ) ) + goto Fail2; + + plr = cpcr->PosLookupRecord; + + if ( ACCESS_Frame( count * 4L ) ) + goto Fail1; + + for ( n = 0; n < count; n++ ) + { + plr[n].SequenceIndex = GET_UShort(); + plr[n].LookupListIndex = GET_UShort(); + } + + FORGET_Frame(); + + return FT_Err_Ok; + +Fail1: + FREE( plr ); + +Fail2: + FREE( l ); + +Fail3: + FREE( i ); + +Fail4: + FREE( b ); + return error; +} + + +static void Free_ChainPosClassRule( HB_ChainPosClassRule* cpcr, + FT_Memory memory ) +{ + FREE( cpcr->PosLookupRecord ); + FREE( cpcr->Lookahead ); + FREE( cpcr->Input ); + FREE( cpcr->Backtrack ); +} + + +/* PosClassSet */ + +static FT_Error Load_ChainPosClassSet( + HB_ChainContextPosFormat2* ccpf2, + HB_ChainPosClassSet* cpcs, + FT_Stream stream ) +{ + FT_Error error; + FT_Memory memory = stream->memory; + + FT_UShort n, m, count; + FT_ULong cur_offset, new_offset, base_offset; + + HB_ChainPosClassRule* cpcr; + + + base_offset = FILE_Pos(); + + if ( ACCESS_Frame( 2L ) ) + return error; + + count = cpcs->ChainPosClassRuleCount = GET_UShort(); + + FORGET_Frame(); + + cpcs->ChainPosClassRule = NULL; + + if ( ALLOC_ARRAY( cpcs->ChainPosClassRule, count, + HB_ChainPosClassRule ) ) + return error; + + cpcr = cpcs->ChainPosClassRule; + + for ( n = 0; n < count; n++ ) + { + if ( ACCESS_Frame( 2L ) ) + goto Fail; + + new_offset = GET_UShort() + base_offset; + + FORGET_Frame(); + + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = Load_ChainPosClassRule( ccpf2, &cpcr[n], + stream ) ) != FT_Err_Ok ) + goto Fail; + (void)FILE_Seek( cur_offset ); + } + + return FT_Err_Ok; + +Fail: + for ( m = 0; m < n; m++ ) + Free_ChainPosClassRule( &cpcr[m], memory ); + + FREE( cpcr ); + return error; +} + + +static void Free_ChainPosClassSet( HB_ChainPosClassSet* cpcs, + FT_Memory memory ) +{ + FT_UShort n, count; + + HB_ChainPosClassRule* cpcr; + + + if ( cpcs->ChainPosClassRule ) + { + count = cpcs->ChainPosClassRuleCount; + cpcr = cpcs->ChainPosClassRule; + + for ( n = 0; n < count; n++ ) + Free_ChainPosClassRule( &cpcr[n], memory ); + + FREE( cpcr ); + } +} + + +static FT_Error GPOS_Load_EmptyOrClassDefinition( HB_ClassDefinition* cd, + FT_UShort limit, + FT_ULong class_offset, + FT_ULong base_offset, + FT_Stream stream ) +{ + FT_Error error; + FT_ULong cur_offset; + + cur_offset = FILE_Pos(); + + if ( class_offset ) + { + if ( !FILE_Seek( class_offset + base_offset ) ) + error = _HB_OPEN_Load_ClassDefinition( cd, limit, stream ); + } + else + error = _HB_OPEN_Load_EmptyClassDefinition ( cd, stream ); + + if (error == FT_Err_Ok) + (void)FILE_Seek( cur_offset ); /* Changes error as a side-effect */ + + return error; +} + +/* ChainContextPosFormat2 */ + +static FT_Error Load_ChainContextPos2( HB_ChainContextPosFormat2* ccpf2, + FT_Stream stream ) +{ + FT_Error error; + FT_Memory memory = stream->memory; + + FT_UShort n, m, count; + FT_ULong cur_offset, new_offset, base_offset; + FT_ULong backtrack_offset, input_offset, lookahead_offset; + + HB_ChainPosClassSet* cpcs; + + + base_offset = FILE_Pos() - 2; + + if ( ACCESS_Frame( 2L ) ) + return error; + + new_offset = GET_UShort() + base_offset; + + FORGET_Frame(); + + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = _HB_OPEN_Load_Coverage( &ccpf2->Coverage, stream ) ) != FT_Err_Ok ) + return error; + (void)FILE_Seek( cur_offset ); + + if ( ACCESS_Frame( 8L ) ) + goto Fail5; + + backtrack_offset = GET_UShort(); + input_offset = GET_UShort(); + lookahead_offset = GET_UShort(); + + /* `ChainPosClassSetCount' is the upper limit for input class values, + thus we read it now to make an additional safety check. No limit + is known or needed for the other two class definitions */ + + count = ccpf2->ChainPosClassSetCount = GET_UShort(); + + FORGET_Frame(); + + if ( ( error = GPOS_Load_EmptyOrClassDefinition( &ccpf2->BacktrackClassDef, 65535, + backtrack_offset, base_offset, + stream ) ) != FT_Err_Ok ) + goto Fail5; + if ( ( error = GPOS_Load_EmptyOrClassDefinition( &ccpf2->InputClassDef, count, + input_offset, base_offset, + stream ) ) != FT_Err_Ok ) + goto Fail4; + if ( ( error = GPOS_Load_EmptyOrClassDefinition( &ccpf2->LookaheadClassDef, 65535, + lookahead_offset, base_offset, + stream ) ) != FT_Err_Ok ) + goto Fail3; + + ccpf2->ChainPosClassSet = NULL; + ccpf2->MaxBacktrackLength = 0; + ccpf2->MaxInputLength = 0; + ccpf2->MaxLookaheadLength = 0; + + if ( ALLOC_ARRAY( ccpf2->ChainPosClassSet, count, HB_ChainPosClassSet ) ) + goto Fail2; + + cpcs = ccpf2->ChainPosClassSet; + + for ( n = 0; n < count; n++ ) + { + if ( ACCESS_Frame( 2L ) ) + goto Fail1; + + new_offset = GET_UShort() + base_offset; + + FORGET_Frame(); + + if ( new_offset != base_offset ) /* not a NULL offset */ + { + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = Load_ChainPosClassSet( ccpf2, &cpcs[n], + stream ) ) != FT_Err_Ok ) + goto Fail1; + (void)FILE_Seek( cur_offset ); + } + else + { + /* we create a ChainPosClassSet table with no entries */ + + ccpf2->ChainPosClassSet[n].ChainPosClassRuleCount = 0; + ccpf2->ChainPosClassSet[n].ChainPosClassRule = NULL; + } + } + + return FT_Err_Ok; + +Fail1: + for ( m = 0; m < n; m++ ) + Free_ChainPosClassSet( &cpcs[m], memory ); + + FREE( cpcs ); + +Fail2: + _HB_OPEN_Free_ClassDefinition( &ccpf2->LookaheadClassDef, memory ); + +Fail3: + _HB_OPEN_Free_ClassDefinition( &ccpf2->InputClassDef, memory ); + +Fail4: + _HB_OPEN_Free_ClassDefinition( &ccpf2->BacktrackClassDef, memory ); + +Fail5: + _HB_OPEN_Free_Coverage( &ccpf2->Coverage, memory ); + return error; +} + + +static void Free_ChainContextPos2( HB_ChainContextPosFormat2* ccpf2, + FT_Memory memory ) +{ + FT_UShort n, count; + + HB_ChainPosClassSet* cpcs; + + + if ( ccpf2->ChainPosClassSet ) + { + count = ccpf2->ChainPosClassSetCount; + cpcs = ccpf2->ChainPosClassSet; + + for ( n = 0; n < count; n++ ) + Free_ChainPosClassSet( &cpcs[n], memory ); + + FREE( cpcs ); + } + + _HB_OPEN_Free_ClassDefinition( &ccpf2->LookaheadClassDef, memory ); + _HB_OPEN_Free_ClassDefinition( &ccpf2->InputClassDef, memory ); + _HB_OPEN_Free_ClassDefinition( &ccpf2->BacktrackClassDef, memory ); + + _HB_OPEN_Free_Coverage( &ccpf2->Coverage, memory ); +} + + +/* ChainContextPosFormat3 */ + +static FT_Error Load_ChainContextPos3( HB_ChainContextPosFormat3* ccpf3, + FT_Stream stream ) +{ + FT_Error error; + FT_Memory memory = stream->memory; + + FT_UShort n, nb, ni, nl, m, count; + FT_UShort backtrack_count, input_count, lookahead_count; + FT_ULong cur_offset, new_offset, base_offset; + + HB_Coverage* b; + HB_Coverage* i; + HB_Coverage* l; + HB_PosLookupRecord* plr; + + + base_offset = FILE_Pos() - 2L; + + if ( ACCESS_Frame( 2L ) ) + return error; + + ccpf3->BacktrackGlyphCount = GET_UShort(); + + FORGET_Frame(); + + ccpf3->BacktrackCoverage = NULL; + + backtrack_count = ccpf3->BacktrackGlyphCount; + + if ( ALLOC_ARRAY( ccpf3->BacktrackCoverage, backtrack_count, + HB_Coverage ) ) + return error; + + b = ccpf3->BacktrackCoverage; + + for ( nb = 0; nb < backtrack_count; nb++ ) + { + if ( ACCESS_Frame( 2L ) ) + goto Fail4; + + new_offset = GET_UShort() + base_offset; + + FORGET_Frame(); + + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = _HB_OPEN_Load_Coverage( &b[nb], stream ) ) != FT_Err_Ok ) + goto Fail4; + (void)FILE_Seek( cur_offset ); + } + + if ( ACCESS_Frame( 2L ) ) + goto Fail4; + + ccpf3->InputGlyphCount = GET_UShort(); + + FORGET_Frame(); + + ccpf3->InputCoverage = NULL; + + input_count = ccpf3->InputGlyphCount; + + if ( ALLOC_ARRAY( ccpf3->InputCoverage, input_count, HB_Coverage ) ) + goto Fail4; + + i = ccpf3->InputCoverage; + + for ( ni = 0; ni < input_count; ni++ ) + { + if ( ACCESS_Frame( 2L ) ) + goto Fail3; + + new_offset = GET_UShort() + base_offset; + + FORGET_Frame(); + + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = _HB_OPEN_Load_Coverage( &i[ni], stream ) ) != FT_Err_Ok ) + goto Fail3; + (void)FILE_Seek( cur_offset ); + } + + if ( ACCESS_Frame( 2L ) ) + goto Fail3; + + ccpf3->LookaheadGlyphCount = GET_UShort(); + + FORGET_Frame(); + + ccpf3->LookaheadCoverage = NULL; + + lookahead_count = ccpf3->LookaheadGlyphCount; + + if ( ALLOC_ARRAY( ccpf3->LookaheadCoverage, lookahead_count, + HB_Coverage ) ) + goto Fail3; + + l = ccpf3->LookaheadCoverage; + + for ( nl = 0; nl < lookahead_count; nl++ ) + { + if ( ACCESS_Frame( 2L ) ) + goto Fail2; + + new_offset = GET_UShort() + base_offset; + + FORGET_Frame(); + + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = _HB_OPEN_Load_Coverage( &l[nl], stream ) ) != FT_Err_Ok ) + goto Fail2; + (void)FILE_Seek( cur_offset ); + } + + if ( ACCESS_Frame( 2L ) ) + goto Fail2; + + ccpf3->PosCount = GET_UShort(); + + FORGET_Frame(); + + ccpf3->PosLookupRecord = NULL; + + count = ccpf3->PosCount; + + if ( ALLOC_ARRAY( ccpf3->PosLookupRecord, count, HB_PosLookupRecord ) ) + goto Fail2; + + plr = ccpf3->PosLookupRecord; + + if ( ACCESS_Frame( count * 4L ) ) + goto Fail1; + + for ( n = 0; n < count; n++ ) + { + plr[n].SequenceIndex = GET_UShort(); + plr[n].LookupListIndex = GET_UShort(); + } + + FORGET_Frame(); + + return FT_Err_Ok; + +Fail1: + FREE( plr ); + +Fail2: + for ( m = 0; m < nl; nl++ ) + _HB_OPEN_Free_Coverage( &l[m], memory ); + + FREE( l ); + +Fail3: + for ( m = 0; m < ni; n++ ) + _HB_OPEN_Free_Coverage( &i[m], memory ); + + FREE( i ); + +Fail4: + for ( m = 0; m < nb; n++ ) + _HB_OPEN_Free_Coverage( &b[m], memory ); + + FREE( b ); + return error; +} + + +static void Free_ChainContextPos3( HB_ChainContextPosFormat3* ccpf3, + FT_Memory memory ) +{ + FT_UShort n, count; + + HB_Coverage* c; + + + FREE( ccpf3->PosLookupRecord ); + + if ( ccpf3->LookaheadCoverage ) + { + count = ccpf3->LookaheadGlyphCount; + c = ccpf3->LookaheadCoverage; + + for ( n = 0; n < count; n++ ) + _HB_OPEN_Free_Coverage( &c[n], memory ); + + FREE( c ); + } + + if ( ccpf3->InputCoverage ) + { + count = ccpf3->InputGlyphCount; + c = ccpf3->InputCoverage; + + for ( n = 0; n < count; n++ ) + _HB_OPEN_Free_Coverage( &c[n], memory ); + + FREE( c ); + } + + if ( ccpf3->BacktrackCoverage ) + { + count = ccpf3->BacktrackGlyphCount; + c = ccpf3->BacktrackCoverage; + + for ( n = 0; n < count; n++ ) + _HB_OPEN_Free_Coverage( &c[n], memory ); + + FREE( c ); + } +} + + +/* ChainContextPos */ + +static FT_Error Load_ChainContextPos( HB_GPOS_SubTable* st, + FT_Stream stream ) +{ + FT_Error error; + HB_ChainContextPos* ccp = &st->chain; + + + if ( ACCESS_Frame( 2L ) ) + return error; + + ccp->PosFormat = GET_UShort(); + + FORGET_Frame(); + + switch ( ccp->PosFormat ) + { + case 1: + return Load_ChainContextPos1( &ccp->ccpf.ccpf1, stream ); + + case 2: + return Load_ChainContextPos2( &ccp->ccpf.ccpf2, stream ); + + case 3: + return Load_ChainContextPos3( &ccp->ccpf.ccpf3, stream ); + + default: + return HB_Err_Invalid_GPOS_SubTable_Format; + } + + return FT_Err_Ok; /* never reached */ +} + + +static void Free_ChainContextPos( HB_GPOS_SubTable* st, + FT_Memory memory ) +{ + HB_ChainContextPos* ccp = &st->chain; + + switch ( ccp->PosFormat ) + { + case 1: + Free_ChainContextPos1( &ccp->ccpf.ccpf1, memory ); + break; + + case 2: + Free_ChainContextPos2( &ccp->ccpf.ccpf2, memory ); + break; + + case 3: + Free_ChainContextPos3( &ccp->ccpf.ccpf3, memory ); + break; + } +} + + +static FT_Error Lookup_ChainContextPos1( + GPOS_Instance* gpi, + HB_ChainContextPosFormat1* ccpf1, + HB_Buffer buffer, + FT_UShort flags, + FT_UShort context_length, + int nesting_level ) +{ + FT_UShort index, property; + FT_UShort i, j, k, num_cpr; + FT_UShort bgc, igc, lgc; + FT_Error error; + HB_GPOSHeader* gpos = gpi->gpos; + + HB_ChainPosRule* cpr; + HB_ChainPosRule curr_cpr; + HB_GDEFHeader* gdef; + + + gdef = gpos->gdef; + + if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) ) + return error; + + error = _HB_OPEN_Coverage_Index( &ccpf1->Coverage, IN_CURGLYPH(), &index ); + if ( error ) + return error; + + cpr = ccpf1->ChainPosRuleSet[index].ChainPosRule; + num_cpr = ccpf1->ChainPosRuleSet[index].ChainPosRuleCount; + + for ( k = 0; k < num_cpr; k++ ) + { + curr_cpr = cpr[k]; + bgc = curr_cpr.BacktrackGlyphCount; + igc = curr_cpr.InputGlyphCount; + lgc = curr_cpr.LookaheadGlyphCount; + + if ( context_length != 0xFFFF && context_length < igc ) + goto next_chainposrule; + + /* check whether context is too long; it is a first guess only */ + + if ( bgc > buffer->in_pos || buffer->in_pos + igc + lgc > buffer->in_length ) + goto next_chainposrule; + + if ( bgc ) + { + /* Since we don't know in advance the number of glyphs to inspect, + we search backwards for matches in the backtrack glyph array */ + + for ( i = 0, j = buffer->in_pos - 1; i < bgc; i++, j-- ) + { + while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) + { + if ( error && error != HB_Err_Not_Covered ) + return error; + + if ( j + 1 == bgc - i ) + goto next_chainposrule; + j--; + } + + /* In OpenType 1.3, it is undefined whether the offsets of + backtrack glyphs is in logical order or not. Version 1.4 + will clarify this: + + Logical order - a b c d e f g h i j + i + Input offsets - 0 1 + Backtrack offsets - 3 2 1 0 + Lookahead offsets - 0 1 2 3 */ + + if ( IN_GLYPH( j ) != curr_cpr.Backtrack[i] ) + goto next_chainposrule; + } + } + + /* Start at 1 because [0] is implied */ + + for ( i = 1, j = buffer->in_pos + 1; i < igc; i++, j++ ) + { + while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) + { + if ( error && error != HB_Err_Not_Covered ) + return error; + + if ( j + igc - i + lgc == buffer->in_length ) + goto next_chainposrule; + j++; + } + + if ( IN_GLYPH( j ) != curr_cpr.Input[i - 1] ) + goto next_chainposrule; + } + + /* we are starting to check for lookahead glyphs right after the + last context glyph */ + + for ( i = 0; i < lgc; i++, j++ ) + { + while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) + { + if ( error && error != HB_Err_Not_Covered ) + return error; + + if ( j + lgc - i == buffer->in_length ) + goto next_chainposrule; + j++; + } + + if ( IN_GLYPH( j ) != curr_cpr.Lookahead[i] ) + goto next_chainposrule; + } + + return Do_ContextPos( gpi, igc, + curr_cpr.PosCount, + curr_cpr.PosLookupRecord, + buffer, + nesting_level ); + + next_chainposrule: + ; + } + + return HB_Err_Not_Covered; +} + + +static FT_Error Lookup_ChainContextPos2( + GPOS_Instance* gpi, + HB_ChainContextPosFormat2* ccpf2, + HB_Buffer buffer, + FT_UShort flags, + FT_UShort context_length, + int nesting_level ) +{ + FT_UShort index, property; + FT_Memory memory = gpi->face->memory; + FT_Error error; + FT_UShort i, j, k; + FT_UShort bgc, igc, lgc; + FT_UShort known_backtrack_classes, + known_input_classes, + known_lookahead_classes; + + FT_UShort* backtrack_classes; + FT_UShort* input_classes; + FT_UShort* lookahead_classes; + + FT_UShort* bc; + FT_UShort* ic; + FT_UShort* lc; + HB_GPOSHeader* gpos = gpi->gpos; + + HB_ChainPosClassSet* cpcs; + HB_ChainPosClassRule cpcr; + HB_GDEFHeader* gdef; + + + gdef = gpos->gdef; + + if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) ) + return error; + + /* Note: The coverage table in format 2 doesn't give an index into + anything. It just lets us know whether or not we need to + do any lookup at all. */ + + error = _HB_OPEN_Coverage_Index( &ccpf2->Coverage, IN_CURGLYPH(), &index ); + if ( error ) + return error; + + if ( ALLOC_ARRAY( backtrack_classes, ccpf2->MaxBacktrackLength, FT_UShort ) ) + return error; + known_backtrack_classes = 0; + + if ( ALLOC_ARRAY( input_classes, ccpf2->MaxInputLength, FT_UShort ) ) + goto End3; + known_input_classes = 1; + + if ( ALLOC_ARRAY( lookahead_classes, ccpf2->MaxLookaheadLength, FT_UShort ) ) + goto End2; + known_lookahead_classes = 0; + + error = _HB_OPEN_Get_Class( &ccpf2->InputClassDef, IN_CURGLYPH(), + &input_classes[0], NULL ); + if ( error && error != HB_Err_Not_Covered ) + goto End1; + + cpcs = &ccpf2->ChainPosClassSet[input_classes[0]]; + if ( !cpcs ) + { + error = HB_Err_Invalid_GPOS_SubTable; + goto End1; + } + + for ( k = 0; k < cpcs->ChainPosClassRuleCount; k++ ) + { + cpcr = cpcs->ChainPosClassRule[k]; + bgc = cpcr.BacktrackGlyphCount; + igc = cpcr.InputGlyphCount; + lgc = cpcr.LookaheadGlyphCount; + + if ( context_length != 0xFFFF && context_length < igc ) + goto next_chainposclassrule; + + /* check whether context is too long; it is a first guess only */ + + if ( bgc > buffer->in_pos || buffer->in_pos + igc + lgc > buffer->in_length ) + goto next_chainposclassrule; + + if ( bgc ) + { + /* Since we don't know in advance the number of glyphs to inspect, + we search backwards for matches in the backtrack glyph array. + Note that `known_backtrack_classes' starts at index 0. */ + + bc = cpcr.Backtrack; + + for ( i = 0, j = buffer->in_pos - 1; i < bgc; i++, j-- ) + { + while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) + { + if ( error && error != HB_Err_Not_Covered ) + goto End1; + + if ( j + 1 == bgc - i ) + goto next_chainposclassrule; + j++; + } + + if ( i >= known_backtrack_classes ) + { + /* Keeps us from having to do this for each rule */ + + error = _HB_OPEN_Get_Class( &ccpf2->BacktrackClassDef, IN_GLYPH( j ), + &backtrack_classes[i], NULL ); + if ( error && error != HB_Err_Not_Covered ) + goto End1; + known_backtrack_classes = i; + } + + if ( bc[i] != backtrack_classes[i] ) + goto next_chainposclassrule; + } + } + + ic = cpcr.Input; + + /* Start at 1 because [0] is implied */ + + for ( i = 1, j = buffer->in_pos + 1; i < igc; i++, j++ ) + { + while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) + { + if ( error && error != HB_Err_Not_Covered ) + goto End1; + + if ( j + igc - i + lgc == buffer->in_length ) + goto next_chainposclassrule; + j++; + } + + if ( i >= known_input_classes ) + { + error = _HB_OPEN_Get_Class( &ccpf2->InputClassDef, IN_GLYPH( j ), + &input_classes[i], NULL ); + if ( error && error != HB_Err_Not_Covered ) + goto End1; + known_input_classes = i; + } + + if ( ic[i - 1] != input_classes[i] ) + goto next_chainposclassrule; + } + + /* we are starting to check for lookahead glyphs right after the + last context glyph */ + + lc = cpcr.Lookahead; + + for ( i = 0; i < lgc; i++, j++ ) + { + while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) + { + if ( error && error != HB_Err_Not_Covered ) + goto End1; + + if ( j + lgc - i == buffer->in_length ) + goto next_chainposclassrule; + j++; + } + + if ( i >= known_lookahead_classes ) + { + error = _HB_OPEN_Get_Class( &ccpf2->LookaheadClassDef, IN_GLYPH( j ), + &lookahead_classes[i], NULL ); + if ( error && error != HB_Err_Not_Covered ) + goto End1; + known_lookahead_classes = i; + } + + if ( lc[i] != lookahead_classes[i] ) + goto next_chainposclassrule; + } + + error = Do_ContextPos( gpi, igc, + cpcr.PosCount, + cpcr.PosLookupRecord, + buffer, + nesting_level ); + goto End1; + + next_chainposclassrule: + ; + } + + error = HB_Err_Not_Covered; + +End1: + FREE( lookahead_classes ); + +End2: + FREE( input_classes ); + +End3: + FREE( backtrack_classes ); + return error; +} + + +static FT_Error Lookup_ChainContextPos3( + GPOS_Instance* gpi, + HB_ChainContextPosFormat3* ccpf3, + HB_Buffer buffer, + FT_UShort flags, + FT_UShort context_length, + int nesting_level ) +{ + FT_UShort index, i, j, property; + FT_UShort bgc, igc, lgc; + FT_Error error; + HB_GPOSHeader* gpos = gpi->gpos; + + HB_Coverage* bc; + HB_Coverage* ic; + HB_Coverage* lc; + HB_GDEFHeader* gdef; + + + gdef = gpos->gdef; + + if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) ) + return error; + + bgc = ccpf3->BacktrackGlyphCount; + igc = ccpf3->InputGlyphCount; + lgc = ccpf3->LookaheadGlyphCount; + + if ( context_length != 0xFFFF && context_length < igc ) + return HB_Err_Not_Covered; + + /* check whether context is too long; it is a first guess only */ + + if ( bgc > buffer->in_pos || buffer->in_pos + igc + lgc > buffer->in_length ) + return HB_Err_Not_Covered; + + if ( bgc ) + { + /* Since we don't know in advance the number of glyphs to inspect, + we search backwards for matches in the backtrack glyph array */ + + bc = ccpf3->BacktrackCoverage; + + for ( i = 0, j = buffer->in_pos - 1; i < bgc; i++, j-- ) + { + while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) + { + if ( error && error != HB_Err_Not_Covered ) + return error; + + if ( j + 1 == bgc - i ) + return HB_Err_Not_Covered; + j--; + } + + error = _HB_OPEN_Coverage_Index( &bc[i], IN_GLYPH( j ), &index ); + if ( error ) + return error; + } + } + + ic = ccpf3->InputCoverage; + + for ( i = 0, j = buffer->in_pos; i < igc; i++, j++ ) + { + /* We already called CHECK_Property for IN_GLYPH ( buffer->in_pos ) */ + while ( j > buffer->in_pos && CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) + { + if ( error && error != HB_Err_Not_Covered ) + return error; + + if ( j + igc - i + lgc == buffer->in_length ) + return HB_Err_Not_Covered; + j++; + } + + error = _HB_OPEN_Coverage_Index( &ic[i], IN_GLYPH( j ), &index ); + if ( error ) + return error; + } + + /* we are starting to check for lookahead glyphs right after the + last context glyph */ + + lc = ccpf3->LookaheadCoverage; + + for ( i = 0; i < lgc; i++, j++ ) + { + while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) + { + if ( error && error != HB_Err_Not_Covered ) + return error; + + if ( j + lgc - i == buffer->in_length ) + return HB_Err_Not_Covered; + j++; + } + + error = _HB_OPEN_Coverage_Index( &lc[i], IN_GLYPH( j ), &index ); + if ( error ) + return error; + } + + return Do_ContextPos( gpi, igc, + ccpf3->PosCount, + ccpf3->PosLookupRecord, + buffer, + nesting_level ); +} + + +static FT_Error Lookup_ChainContextPos( + GPOS_Instance* gpi, + HB_GPOS_SubTable* st, + HB_Buffer buffer, + FT_UShort flags, + FT_UShort context_length, + int nesting_level ) +{ + HB_ChainContextPos* ccp = &st->chain; + + switch ( ccp->PosFormat ) + { + case 1: + return Lookup_ChainContextPos1( gpi, &ccp->ccpf.ccpf1, buffer, + flags, context_length, + nesting_level ); + + case 2: + return Lookup_ChainContextPos2( gpi, &ccp->ccpf.ccpf2, buffer, + flags, context_length, + nesting_level ); + + case 3: + return Lookup_ChainContextPos3( gpi, &ccp->ccpf.ccpf3, buffer, + flags, context_length, + nesting_level ); + + default: + return HB_Err_Invalid_GPOS_SubTable_Format; + } + + return FT_Err_Ok; /* never reached */ +} + + + +/*********** + * GPOS API + ***********/ + + + +FT_Error HB_GPOS_Select_Script( HB_GPOSHeader* gpos, + FT_ULong script_tag, + FT_UShort* script_index ) +{ + FT_UShort n; + + HB_ScriptList* sl; + HB_ScriptRecord* sr; + + + if ( !gpos || !script_index ) + return FT_Err_Invalid_Argument; + + sl = &gpos->ScriptList; + sr = sl->ScriptRecord; + + for ( n = 0; n < sl->ScriptCount; n++ ) + if ( script_tag == sr[n].ScriptTag ) + { + *script_index = n; + + return FT_Err_Ok; + } + + return HB_Err_Not_Covered; +} + + + +FT_Error HB_GPOS_Select_Language( HB_GPOSHeader* gpos, + FT_ULong language_tag, + FT_UShort script_index, + FT_UShort* language_index, + FT_UShort* req_feature_index ) +{ + FT_UShort n; + + HB_ScriptList* sl; + HB_ScriptRecord* sr; + HB_Script* s; + HB_LangSysRecord* lsr; + + + if ( !gpos || !language_index || !req_feature_index ) + return FT_Err_Invalid_Argument; + + sl = &gpos->ScriptList; + sr = sl->ScriptRecord; + + if ( script_index >= sl->ScriptCount ) + return FT_Err_Invalid_Argument; + + s = &sr[script_index].Script; + lsr = s->LangSysRecord; + + for ( n = 0; n < s->LangSysCount; n++ ) + if ( language_tag == lsr[n].LangSysTag ) + { + *language_index = n; + *req_feature_index = lsr[n].LangSys.ReqFeatureIndex; + + return FT_Err_Ok; + } + + return HB_Err_Not_Covered; +} + + +/* selecting 0xFFFF for language_index asks for the values of the + default language (DefaultLangSys) */ + + +FT_Error HB_GPOS_Select_Feature( HB_GPOSHeader* gpos, + FT_ULong feature_tag, + FT_UShort script_index, + FT_UShort language_index, + FT_UShort* feature_index ) +{ + FT_UShort n; + + HB_ScriptList* sl; + HB_ScriptRecord* sr; + HB_Script* s; + HB_LangSysRecord* lsr; + HB_LangSys* ls; + FT_UShort* fi; + + HB_FeatureList* fl; + HB_FeatureRecord* fr; + + + if ( !gpos || !feature_index ) + return FT_Err_Invalid_Argument; + + sl = &gpos->ScriptList; + sr = sl->ScriptRecord; + + fl = &gpos->FeatureList; + fr = fl->FeatureRecord; + + if ( script_index >= sl->ScriptCount ) + return FT_Err_Invalid_Argument; + + s = &sr[script_index].Script; + lsr = s->LangSysRecord; + + if ( language_index == 0xFFFF ) + ls = &s->DefaultLangSys; + else + { + if ( language_index >= s->LangSysCount ) + return FT_Err_Invalid_Argument; + + ls = &lsr[language_index].LangSys; + } + + fi = ls->FeatureIndex; + + for ( n = 0; n < ls->FeatureCount; n++ ) + { + if ( fi[n] >= fl->FeatureCount ) + return HB_Err_Invalid_GPOS_SubTable_Format; + + if ( feature_tag == fr[fi[n]].FeatureTag ) + { + *feature_index = fi[n]; + + return FT_Err_Ok; + } + } + + return HB_Err_Not_Covered; +} + + +/* The next three functions return a null-terminated list */ + + +FT_Error HB_GPOS_Query_Scripts( HB_GPOSHeader* gpos, + FT_ULong** script_tag_list ) +{ + FT_Error error; + FT_Memory memory = gpos->memory; + FT_UShort n; + FT_ULong* stl; + + HB_ScriptList* sl; + HB_ScriptRecord* sr; + + + if ( !gpos || !script_tag_list ) + return FT_Err_Invalid_Argument; + + sl = &gpos->ScriptList; + sr = sl->ScriptRecord; + + if ( ALLOC_ARRAY( stl, sl->ScriptCount + 1, FT_ULong ) ) + return error; + + for ( n = 0; n < sl->ScriptCount; n++ ) + stl[n] = sr[n].ScriptTag; + stl[n] = 0; + + *script_tag_list = stl; + + return FT_Err_Ok; +} + + + +FT_Error HB_GPOS_Query_Languages( HB_GPOSHeader* gpos, + FT_UShort script_index, + FT_ULong** language_tag_list ) +{ + FT_Error error; + FT_Memory memory = gpos->memory; + FT_UShort n; + FT_ULong* ltl; + + HB_ScriptList* sl; + HB_ScriptRecord* sr; + HB_Script* s; + HB_LangSysRecord* lsr; + + + if ( !gpos || !language_tag_list ) + return FT_Err_Invalid_Argument; + + sl = &gpos->ScriptList; + sr = sl->ScriptRecord; + + if ( script_index >= sl->ScriptCount ) + return FT_Err_Invalid_Argument; + + s = &sr[script_index].Script; + lsr = s->LangSysRecord; + + if ( ALLOC_ARRAY( ltl, s->LangSysCount + 1, FT_ULong ) ) + return error; + + for ( n = 0; n < s->LangSysCount; n++ ) + ltl[n] = lsr[n].LangSysTag; + ltl[n] = 0; + + *language_tag_list = ltl; + + return FT_Err_Ok; +} + + +/* selecting 0xFFFF for language_index asks for the values of the + default language (DefaultLangSys) */ + + +FT_Error HB_GPOS_Query_Features( HB_GPOSHeader* gpos, + FT_UShort script_index, + FT_UShort language_index, + FT_ULong** feature_tag_list ) +{ + FT_UShort n; + FT_Error error; + FT_Memory memory = gpos->memory; + FT_ULong* ftl; + + HB_ScriptList* sl; + HB_ScriptRecord* sr; + HB_Script* s; + HB_LangSysRecord* lsr; + HB_LangSys* ls; + FT_UShort* fi; + + HB_FeatureList* fl; + HB_FeatureRecord* fr; + + + if ( !gpos || !feature_tag_list ) + return FT_Err_Invalid_Argument; + + sl = &gpos->ScriptList; + sr = sl->ScriptRecord; + + fl = &gpos->FeatureList; + fr = fl->FeatureRecord; + + if ( script_index >= sl->ScriptCount ) + return FT_Err_Invalid_Argument; + + s = &sr[script_index].Script; + lsr = s->LangSysRecord; + + if ( language_index == 0xFFFF ) + ls = &s->DefaultLangSys; + else + { + if ( language_index >= s->LangSysCount ) + return FT_Err_Invalid_Argument; + + ls = &lsr[language_index].LangSys; + } + + fi = ls->FeatureIndex; + + if ( ALLOC_ARRAY( ftl, ls->FeatureCount + 1, FT_ULong ) ) + return error; + + for ( n = 0; n < ls->FeatureCount; n++ ) + { + if ( fi[n] >= fl->FeatureCount ) + { + FREE( ftl ); + return HB_Err_Invalid_GPOS_SubTable_Format; + } + ftl[n] = fr[fi[n]].FeatureTag; + } + ftl[n] = 0; + + *feature_tag_list = ftl; + + return FT_Err_Ok; +} + + +typedef FT_Error (*Lookup_Pos_Func_Type) ( GPOS_Instance* gpi, + HB_GPOS_SubTable* st, + HB_Buffer buffer, + FT_UShort flags, + FT_UShort context_length, + int nesting_level ); +static const Lookup_Pos_Func_Type Lookup_Pos_Call_Table[] = { + Lookup_DefaultPos, + Lookup_SinglePos, /* HB_GPOS_LOOKUP_SINGLE 1 */ + Lookup_PairPos, /* HB_GPOS_LOOKUP_PAIR 2 */ + Lookup_CursivePos, /* HB_GPOS_LOOKUP_CURSIVE 3 */ + Lookup_MarkBasePos, /* HB_GPOS_LOOKUP_MARKBASE 4 */ + Lookup_MarkLigPos, /* HB_GPOS_LOOKUP_MARKLIG 5 */ + Lookup_MarkMarkPos, /* HB_GPOS_LOOKUP_MARKMARK 6 */ + Lookup_ContextPos, /* HB_GPOS_LOOKUP_CONTEXT 7 */ + Lookup_ChainContextPos, /* HB_GPOS_LOOKUP_CHAIN 8 */ + Lookup_DefaultPos, /* HB_GPOS_LOOKUP_EXTENSION 9 */ +}; + +/* Do an individual subtable lookup. Returns FT_Err_Ok if positioning + has been done, or HB_Err_Not_Covered if not. */ +static FT_Error GPOS_Do_Glyph_Lookup( GPOS_Instance* gpi, + FT_UShort lookup_index, + HB_Buffer buffer, + FT_UShort context_length, + int nesting_level ) +{ + FT_Error error = HB_Err_Not_Covered; + FT_UShort i, flags, lookup_count; + HB_GPOSHeader* gpos = gpi->gpos; + HB_Lookup* lo; + int lookup_type; + Lookup_Pos_Func_Type Func; + + + nesting_level++; + + if ( nesting_level > HB_MAX_NESTING_LEVEL ) + return HB_Err_Too_Many_Nested_Contexts; + + lookup_count = gpos->LookupList.LookupCount; + if (lookup_index >= lookup_count) + return error; + + lo = &gpos->LookupList.Lookup[lookup_index]; + flags = lo->LookupFlag; + lookup_type = lo->LookupType; + if (lookup_type >= ARRAY_LEN (Lookup_Pos_Call_Table)) + lookup_type = 0; + Func = Lookup_Pos_Call_Table[lookup_type]; + + for ( i = 0; i < lo->SubTableCount; i++ ) + { + error = Func ( gpi, + &lo->SubTable[i].st.gpos, + buffer, + flags, context_length, + nesting_level ); + + /* Check whether we have a successful positioning or an error other + than HB_Err_Not_Covered */ + + if ( error != HB_Err_Not_Covered ) + return error; + } + + return HB_Err_Not_Covered; +} + + +static FT_Error Load_DefaultPos( HB_GPOS_SubTable* st, + FT_Stream stream ) +{ + return HB_Err_Invalid_GPOS_SubTable_Format; +} + +typedef FT_Error (*Load_Pos_Func_Type)( HB_GPOS_SubTable* st, + FT_Stream stream ); +static const Load_Pos_Func_Type Load_Pos_Call_Table[] = { + Load_DefaultPos, + Load_SinglePos, /* HB_GPOS_LOOKUP_SINGLE 1 */ + Load_PairPos, /* HB_GPOS_LOOKUP_PAIR 2 */ + Load_CursivePos, /* HB_GPOS_LOOKUP_CURSIVE 3 */ + Load_MarkBasePos, /* HB_GPOS_LOOKUP_MARKBASE 4 */ + Load_MarkLigPos, /* HB_GPOS_LOOKUP_MARKLIG 5 */ + Load_MarkMarkPos, /* HB_GPOS_LOOKUP_MARKMARK 6 */ + Load_ContextPos, /* HB_GPOS_LOOKUP_CONTEXT 7 */ + Load_ChainContextPos, /* HB_GPOS_LOOKUP_CHAIN 8 */ + Load_DefaultPos, /* HB_GPOS_LOOKUP_EXTENSION 9 */ +}; + +FT_Error _HB_GPOS_Load_SubTable( HB_GPOS_SubTable* st, + FT_Stream stream, + FT_UShort lookup_type ) +{ + Load_Pos_Func_Type Func; + + if (lookup_type >= ARRAY_LEN (Load_Pos_Call_Table)) + lookup_type = 0; + + Func = Load_Pos_Call_Table[lookup_type]; + + return Func ( st, stream ); +} + + +static void Free_DefaultPos( HB_GPOS_SubTable* st, + FT_Memory memory ) +{ +} + +typedef void (*Free_Pos_Func_Type)( HB_GPOS_SubTable* st, + FT_Memory memory ); +static const Free_Pos_Func_Type Free_Pos_Call_Table[] = { + Free_DefaultPos, + Free_SinglePos, /* HB_GPOS_LOOKUP_SINGLE 1 */ + Free_PairPos, /* HB_GPOS_LOOKUP_PAIR 2 */ + Free_CursivePos, /* HB_GPOS_LOOKUP_CURSIVE 3 */ + Free_MarkBasePos, /* HB_GPOS_LOOKUP_MARKBASE 4 */ + Free_MarkLigPos, /* HB_GPOS_LOOKUP_MARKLIG 5 */ + Free_MarkMarkPos, /* HB_GPOS_LOOKUP_MARKMARK 6 */ + Free_ContextPos, /* HB_GPOS_LOOKUP_CONTEXT 7 */ + Free_ChainContextPos, /* HB_GPOS_LOOKUP_CHAIN 8 */ + Free_DefaultPos, /* HB_GPOS_LOOKUP_EXTENSION 9 */ +}; + +void _HB_GPOS_Free_SubTable( HB_GPOS_SubTable* st, + FT_Memory memory, + FT_UShort lookup_type ) +{ + Free_Pos_Func_Type Func; + + if (lookup_type >= ARRAY_LEN (Free_Pos_Call_Table)) + lookup_type = 0; + + Func = Free_Pos_Call_Table[lookup_type]; + + Func ( st, memory ); +} + + + +/* apply one lookup to the input string object */ + +static FT_Error GPOS_Do_String_Lookup( GPOS_Instance* gpi, + FT_UShort lookup_index, + HB_Buffer buffer ) +{ + FT_Error error, retError = HB_Err_Not_Covered; + HB_GPOSHeader* gpos = gpi->gpos; + + FT_UInt* properties = gpos->LookupList.Properties; + + int nesting_level = 0; + + + gpi->last = 0xFFFF; /* no last valid glyph for cursive pos. */ + + buffer->in_pos = 0; + + while ( buffer->in_pos < buffer->in_length ) + { + if ( ~IN_PROPERTIES( buffer->in_pos ) & properties[lookup_index] ) + { + /* 0xFFFF indicates that we don't have a context length yet. */ + + /* Note that the connection between mark and base glyphs hold + exactly one (string) lookup. For example, it would be possible + that in the first lookup, mark glyph X is attached to base + glyph A, and in the next lookup it is attached to base glyph B. + It is up to the font designer to provide meaningful lookups and + lookup order. */ + + error = GPOS_Do_Glyph_Lookup( gpi, lookup_index, buffer, + 0xFFFF, nesting_level ); + if ( error && error != HB_Err_Not_Covered ) + return error; + } + else + { + /* Contrary to properties defined in GDEF, user-defined properties + will always stop a possible cursive positioning. */ + gpi->last = 0xFFFF; + + error = HB_Err_Not_Covered; + } + + if ( error == HB_Err_Not_Covered ) + (buffer->in_pos)++; + else + retError = error; + } + + return retError; +} + + +static FT_Error Position_CursiveChain ( HB_Buffer buffer ) +{ + FT_ULong i, j; + HB_Position positions = buffer->positions; + + /* First handle all left-to-right connections */ + for (j = 0; j < buffer->in_length; j--) + { + if (positions[j].cursive_chain > 0) + positions[j].y_pos += positions[j - positions[j].cursive_chain].y_pos; + } + + /* Then handle all right-to-left connections */ + for (i = buffer->in_length; i > 0; i--) + { + j = i - 1; + + if (positions[j].cursive_chain < 0) + positions[j].y_pos += positions[j - positions[j].cursive_chain].y_pos; + } + + return FT_Err_Ok; +} + + +FT_Error HB_GPOS_Add_Feature( HB_GPOSHeader* gpos, + FT_UShort feature_index, + FT_UInt property ) +{ + FT_UShort i; + + HB_Feature feature; + FT_UInt* properties; + FT_UShort* index; + FT_UShort lookup_count; + + /* Each feature can only be added once */ + + if ( !gpos || + feature_index >= gpos->FeatureList.FeatureCount || + gpos->FeatureList.ApplyCount == gpos->FeatureList.FeatureCount ) + return FT_Err_Invalid_Argument; + + gpos->FeatureList.ApplyOrder[gpos->FeatureList.ApplyCount++] = feature_index; + + properties = gpos->LookupList.Properties; + + feature = gpos->FeatureList.FeatureRecord[feature_index].Feature; + index = feature.LookupListIndex; + lookup_count = gpos->LookupList.LookupCount; + + for ( i = 0; i < feature.LookupListCount; i++ ) + { + FT_UShort lookup_index = index[i]; + if (lookup_index < lookup_count) + properties[lookup_index] |= property; + } + + return FT_Err_Ok; +} + + + +FT_Error HB_GPOS_Clear_Features( HB_GPOSHeader* gpos ) +{ + FT_UShort i; + + FT_UInt* properties; + + + if ( !gpos ) + return FT_Err_Invalid_Argument; + + gpos->FeatureList.ApplyCount = 0; + + properties = gpos->LookupList.Properties; + + for ( i = 0; i < gpos->LookupList.LookupCount; i++ ) + properties[i] = 0; + + return FT_Err_Ok; +} + + + +FT_Error HB_GPOS_Register_Glyph_Function( HB_GPOSHeader* gpos, + HB_GlyphFunction gfunc ) +{ + if ( !gpos ) + return FT_Err_Invalid_Argument; + + gpos->gfunc = gfunc; + + return FT_Err_Ok; +} + + + +FT_Error HB_GPOS_Register_MM_Function( HB_GPOSHeader* gpos, + HB_MMFunction mmfunc, + void* data ) +{ + if ( !gpos ) + return FT_Err_Invalid_Argument; + + gpos->mmfunc = mmfunc; + gpos->data = data; + + return FT_Err_Ok; +} + +/* If `dvi' is TRUE, glyph contour points for anchor points and device + tables are ignored -- you will get device independent values. */ + + +FT_Error HB_GPOS_Apply_String( FT_Face face, + HB_GPOSHeader* gpos, + FT_UShort load_flags, + HB_Buffer buffer, + FT_Bool dvi, + FT_Bool r2l ) +{ + FT_Error error, retError = HB_Err_Not_Covered; + GPOS_Instance gpi; + FT_UShort i, j, feature_index, lookup_count; + HB_Feature feature; + + if ( !face || !gpos || + !buffer || buffer->in_length == 0 || buffer->in_pos >= buffer->in_length ) + return FT_Err_Invalid_Argument; + + gpi.face = face; + gpi.gpos = gpos; + gpi.load_flags = load_flags; + gpi.r2l = r2l; + gpi.dvi = dvi; + + lookup_count = gpos->LookupList.LookupCount; + + for ( i = 0; i < gpos->FeatureList.ApplyCount; i++ ) + { + /* index of i'th feature */ + feature_index = gpos->FeatureList.ApplyOrder[i]; + feature = gpos->FeatureList.FeatureRecord[feature_index].Feature; + + for ( j = 0; j < feature.LookupListCount; j++ ) + { + FT_UShort lookup_index = feature.LookupListIndex[j]; + + /* Skip nonexistant lookups */ + if (lookup_index >= lookup_count) + continue; + + error = GPOS_Do_String_Lookup( &gpi, lookup_index, buffer ); + if ( error ) + { + if ( error != HB_Err_Not_Covered ) + return error; + } + else + retError = error; + } + } + + error = Position_CursiveChain ( buffer ); + if ( error ) + return error; + + return retError; +} + +/* END */ diff --git a/src/harfbuzz-gpos.h b/src/harfbuzz-gpos.h new file mode 100644 index 0000000..1c67027 --- /dev/null +++ b/src/harfbuzz-gpos.h @@ -0,0 +1,168 @@ +/******************************************************************* + * + * Copyright 1996-2000 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * Copyright 2006 Behdad Esfahbod + * + * This is part of HarfBuzz, an OpenType Layout engine library. + * + * See the file name COPYING for licensing information. + * + ******************************************************************/ +#ifndef HARFBUZZ_GPOS_H +#define HARFBUZZ_GPOS_H + +#include "harfbuzz-gdef.h" +#include "harfbuzz-buffer.h" + +FT_BEGIN_HEADER + +#define HB_Err_Invalid_GPOS_SubTable_Format 0x1020 +#define HB_Err_Invalid_GPOS_SubTable 0x1021 + + +/* Lookup types for glyph positioning */ + +#define HB_GPOS_LOOKUP_SINGLE 1 +#define HB_GPOS_LOOKUP_PAIR 2 +#define HB_GPOS_LOOKUP_CURSIVE 3 +#define HB_GPOS_LOOKUP_MARKBASE 4 +#define HB_GPOS_LOOKUP_MARKLIG 5 +#define HB_GPOS_LOOKUP_MARKMARK 6 +#define HB_GPOS_LOOKUP_CONTEXT 7 +#define HB_GPOS_LOOKUP_CHAIN 8 +#define HB_GPOS_LOOKUP_EXTENSION 9 + + +/* A pointer to a function which loads a glyph. Its parameters are + the same as in a call to Load_Glyph() -- if no glyph loading + function will be registered with HB_GPOS_Register_Glyph_Function(), + Load_Glyph() will be called indeed. The purpose of this function + pointer is to provide a hook for caching glyph outlines and sbits + (using the instance's generic pointer to hold the data). + + If for some reason no outline data is available (e.g. for an + embedded bitmap glyph), _glyph->outline.n_points should be set to + zero. _glyph can be computed with + + _glyph = HANDLE_Glyph( glyph ) */ + +typedef FT_Error (*HB_GlyphFunction)(FT_Face face, + FT_UInt glyphIndex, + FT_Int loadFlags ); + + +/* A pointer to a function which accesses the PostScript interpreter. + Multiple Master fonts need this interface to convert a metric ID + (as stored in an OpenType font version 1.2 or higher) `metric_id' + into a metric value (returned in `metric_value'). + + `data' points to the user-defined structure specified during a + call to HB_GPOS_Register_MM_Function(). + + `metric_value' must be returned as a scaled value (but shouldn't + be rounded). */ + +typedef FT_Error (*HB_MMFunction)(FT_Face face, + FT_UShort metric_id, + FT_Pos* metric_value, + void* data ); + + +struct HB_GPOSHeader_ +{ + FT_Memory memory; + + FT_Fixed Version; + + HB_ScriptList ScriptList; + HB_FeatureList FeatureList; + HB_LookupList LookupList; + + HB_GDEFHeader* gdef; + + /* the next field is used for a callback function to get the + glyph outline. */ + + HB_GlyphFunction gfunc; + + /* this is OpenType 1.2 -- Multiple Master fonts need this + callback function to get various metric values from the + PostScript interpreter. */ + + HB_MMFunction mmfunc; + void* data; +}; + +typedef struct HB_GPOSHeader_ HB_GPOSHeader; +typedef HB_GPOSHeader* HB_GPOS; + + +FT_Error HB_Load_GPOS_Table( FT_Face face, + HB_GPOSHeader** gpos, + HB_GDEFHeader* gdef ); + + +FT_Error HB_Done_GPOS_Table( HB_GPOSHeader* gpos ); + + +FT_Error HB_GPOS_Select_Script( HB_GPOSHeader* gpos, + FT_ULong script_tag, + FT_UShort* script_index ); + +FT_Error HB_GPOS_Select_Language( HB_GPOSHeader* gpos, + FT_ULong language_tag, + FT_UShort script_index, + FT_UShort* language_index, + FT_UShort* req_feature_index ); + +FT_Error HB_GPOS_Select_Feature( HB_GPOSHeader* gpos, + FT_ULong feature_tag, + FT_UShort script_index, + FT_UShort language_index, + FT_UShort* feature_index ); + + +FT_Error HB_GPOS_Query_Scripts( HB_GPOSHeader* gpos, + FT_ULong** script_tag_list ); + +FT_Error HB_GPOS_Query_Languages( HB_GPOSHeader* gpos, + FT_UShort script_index, + FT_ULong** language_tag_list ); + +FT_Error HB_GPOS_Query_Features( HB_GPOSHeader* gpos, + FT_UShort script_index, + FT_UShort language_index, + FT_ULong** feature_tag_list ); + + +FT_Error HB_GPOS_Add_Feature( HB_GPOSHeader* gpos, + FT_UShort feature_index, + FT_UInt property ); + +FT_Error HB_GPOS_Clear_Features( HB_GPOSHeader* gpos ); + + +FT_Error HB_GPOS_Register_Glyph_Function( HB_GPOSHeader* gpos, + HB_GlyphFunction gfunc ); + + +FT_Error HB_GPOS_Register_MM_Function( HB_GPOSHeader* gpos, + HB_MMFunction mmfunc, + void* data ); + +/* If `dvi' is TRUE, glyph contour points for anchor points and device + tables are ignored -- you will get device independent values. */ + + +FT_Error HB_GPOS_Apply_String( FT_Face face, + HB_GPOSHeader* gpos, + FT_UShort load_flags, + HB_Buffer buffer, + FT_Bool dvi, + FT_Bool r2l ); + +FT_END_HEADER + +#endif /* HARFBUZZ_GPOS_H */ diff --git a/src/harfbuzz-gsub-private.h b/src/harfbuzz-gsub-private.h new file mode 100644 index 0000000..84c08df --- /dev/null +++ b/src/harfbuzz-gsub-private.h @@ -0,0 +1,448 @@ +/******************************************************************* + * + * Copyright 1996-2000 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * Copyright 2006 Behdad Esfahbod + * + * This is part of HarfBuzz, an OpenType Layout engine library. + * + * See the file name COPYING for licensing information. + * + ******************************************************************/ +#ifndef HARFBUZZ_GSUB_PRIVATE_H +#define HARFBUZZ_GSUB_PRIVATE_H + +#include "harfbuzz-gsub.h" + +FT_BEGIN_HEADER + + +typedef union HB_GSUB_SubTable_ HB_GSUB_SubTable; + +/* LookupType 1 */ + +struct HB_SingleSubstFormat1_ +{ + FT_Short DeltaGlyphID; /* constant added to get + substitution glyph index */ +}; + +typedef struct HB_SingleSubstFormat1_ HB_SingleSubstFormat1; + + +struct HB_SingleSubstFormat2_ +{ + FT_UShort GlyphCount; /* number of glyph IDs in + Substitute array */ + FT_UShort* Substitute; /* array of substitute glyph IDs */ +}; + +typedef struct HB_SingleSubstFormat2_ HB_SingleSubstFormat2; + + +struct HB_SingleSubst_ +{ + FT_UShort SubstFormat; /* 1 or 2 */ + HB_Coverage Coverage; /* Coverage table */ + + union + { + HB_SingleSubstFormat1 ssf1; + HB_SingleSubstFormat2 ssf2; + } ssf; +}; + +typedef struct HB_SingleSubst_ HB_SingleSubst; + + +/* LookupType 2 */ + +struct HB_Sequence_ +{ + FT_UShort GlyphCount; /* number of glyph IDs in the + Substitute array */ + FT_UShort* Substitute; /* string of glyph IDs to + substitute */ +}; + +typedef struct HB_Sequence_ HB_Sequence; + + +struct HB_MultipleSubst_ +{ + FT_UShort SubstFormat; /* always 1 */ + HB_Coverage Coverage; /* Coverage table */ + FT_UShort SequenceCount; /* number of Sequence tables */ + HB_Sequence* Sequence; /* array of Sequence tables */ +}; + +typedef struct HB_MultipleSubst_ HB_MultipleSubst; + + +/* LookupType 3 */ + +struct HB_AlternateSet_ +{ + FT_UShort GlyphCount; /* number of glyph IDs in the + Alternate array */ + FT_UShort* Alternate; /* array of alternate glyph IDs */ +}; + +typedef struct HB_AlternateSet_ HB_AlternateSet; + + +struct HB_AlternateSubst_ +{ + FT_UShort SubstFormat; /* always 1 */ + HB_Coverage Coverage; /* Coverage table */ + FT_UShort AlternateSetCount; + /* number of AlternateSet tables */ + HB_AlternateSet* AlternateSet; /* array of AlternateSet tables */ +}; + +typedef struct HB_AlternateSubst_ HB_AlternateSubst; + + +/* LookupType 4 */ + +struct HB_Ligature_ +{ + FT_UShort LigGlyph; /* glyphID of ligature + to substitute */ + FT_UShort ComponentCount; /* number of components in ligature */ + FT_UShort* Component; /* array of component glyph IDs */ +}; + +typedef struct HB_Ligature_ HB_Ligature; + + +struct HB_LigatureSet_ +{ + FT_UShort LigatureCount; /* number of Ligature tables */ + HB_Ligature* Ligature; /* array of Ligature tables */ +}; + +typedef struct HB_LigatureSet_ HB_LigatureSet; + + +struct HB_LigatureSubst_ +{ + FT_UShort SubstFormat; /* always 1 */ + HB_Coverage Coverage; /* Coverage table */ + FT_UShort LigatureSetCount; /* number of LigatureSet tables */ + HB_LigatureSet* LigatureSet; /* array of LigatureSet tables */ +}; + +typedef struct HB_LigatureSubst_ HB_LigatureSubst; + + +/* needed by both lookup type 5 and 6 */ + +struct HB_SubstLookupRecord_ +{ + FT_UShort SequenceIndex; /* index into current + glyph sequence */ + FT_UShort LookupListIndex; /* Lookup to apply to that pos. */ +}; + +typedef struct HB_SubstLookupRecord_ HB_SubstLookupRecord; + + +/* LookupType 5 */ + +struct HB_SubRule_ +{ + FT_UShort GlyphCount; /* total number of input glyphs */ + FT_UShort SubstCount; /* number of SubstLookupRecord + tables */ + FT_UShort* Input; /* array of input glyph IDs */ + HB_SubstLookupRecord* SubstLookupRecord; + /* array of SubstLookupRecord + tables */ +}; + +typedef struct HB_SubRule_ HB_SubRule; + + +struct HB_SubRuleSet_ +{ + FT_UShort SubRuleCount; /* number of SubRule tables */ + HB_SubRule* SubRule; /* array of SubRule tables */ +}; + +typedef struct HB_SubRuleSet_ HB_SubRuleSet; + + +struct HB_ContextSubstFormat1_ +{ + HB_Coverage Coverage; /* Coverage table */ + FT_UShort SubRuleSetCount; /* number of SubRuleSet tables */ + HB_SubRuleSet* SubRuleSet; /* array of SubRuleSet tables */ +}; + +typedef struct HB_ContextSubstFormat1_ HB_ContextSubstFormat1; + + +struct HB_SubClassRule_ +{ + FT_UShort GlyphCount; /* total number of context classes */ + FT_UShort SubstCount; /* number of SubstLookupRecord + tables */ + FT_UShort* Class; /* array of classes */ + HB_SubstLookupRecord* SubstLookupRecord; + /* array of SubstLookupRecord + tables */ +}; + +typedef struct HB_SubClassRule_ HB_SubClassRule; + + +struct HB_SubClassSet_ +{ + FT_UShort SubClassRuleCount; + /* number of SubClassRule tables */ + HB_SubClassRule* SubClassRule; /* array of SubClassRule tables */ +}; + +typedef struct HB_SubClassSet_ HB_SubClassSet; + + +/* The `MaxContextLength' field is not defined in the TTO specification + but simplifies the implementation of this format. It holds the + maximal context length used in the context rules. */ + +struct HB_ContextSubstFormat2_ +{ + FT_UShort MaxContextLength; + /* maximal context length */ + HB_Coverage Coverage; /* Coverage table */ + HB_ClassDefinition ClassDef; /* ClassDef table */ + FT_UShort SubClassSetCount; + /* number of SubClassSet tables */ + HB_SubClassSet* SubClassSet; /* array of SubClassSet tables */ +}; + +typedef struct HB_ContextSubstFormat2_ HB_ContextSubstFormat2; + + +struct HB_ContextSubstFormat3_ +{ + FT_UShort GlyphCount; /* number of input glyphs */ + FT_UShort SubstCount; /* number of SubstLookupRecords */ + HB_Coverage* Coverage; /* array of Coverage tables */ + HB_SubstLookupRecord* SubstLookupRecord; + /* array of substitution lookups */ +}; + +typedef struct HB_ContextSubstFormat3_ HB_ContextSubstFormat3; + + +struct HB_ContextSubst_ +{ + FT_UShort SubstFormat; /* 1, 2, or 3 */ + + union + { + HB_ContextSubstFormat1 csf1; + HB_ContextSubstFormat2 csf2; + HB_ContextSubstFormat3 csf3; + } csf; +}; + +typedef struct HB_ContextSubst_ HB_ContextSubst; + + +/* LookupType 6 */ + +struct HB_ChainSubRule_ +{ + FT_UShort BacktrackGlyphCount; + /* total number of backtrack glyphs */ + FT_UShort* Backtrack; /* array of backtrack glyph IDs */ + FT_UShort InputGlyphCount; + /* total number of input glyphs */ + FT_UShort* Input; /* array of input glyph IDs */ + FT_UShort LookaheadGlyphCount; + /* total number of lookahead glyphs */ + FT_UShort* Lookahead; /* array of lookahead glyph IDs */ + FT_UShort SubstCount; /* number of SubstLookupRecords */ + HB_SubstLookupRecord* SubstLookupRecord; + /* array of SubstLookupRecords */ +}; + +typedef struct HB_ChainSubRule_ HB_ChainSubRule; + + +struct HB_ChainSubRuleSet_ +{ + FT_UShort ChainSubRuleCount; + /* number of ChainSubRule tables */ + HB_ChainSubRule* ChainSubRule; /* array of ChainSubRule tables */ +}; + +typedef struct HB_ChainSubRuleSet_ HB_ChainSubRuleSet; + + +struct HB_ChainContextSubstFormat1_ +{ + HB_Coverage Coverage; /* Coverage table */ + FT_UShort ChainSubRuleSetCount; + /* number of ChainSubRuleSet tables */ + HB_ChainSubRuleSet* ChainSubRuleSet; + /* array of ChainSubRuleSet tables */ +}; + +typedef struct HB_ChainContextSubstFormat1_ HB_ChainContextSubstFormat1; + + +struct HB_ChainSubClassRule_ +{ + FT_UShort BacktrackGlyphCount; + /* total number of backtrack + classes */ + FT_UShort* Backtrack; /* array of backtrack classes */ + FT_UShort InputGlyphCount; + /* total number of context classes */ + FT_UShort* Input; /* array of context classes */ + FT_UShort LookaheadGlyphCount; + /* total number of lookahead + classes */ + FT_UShort* Lookahead; /* array of lookahead classes */ + FT_UShort SubstCount; /* number of SubstLookupRecords */ + HB_SubstLookupRecord* SubstLookupRecord; + /* array of substitution lookups */ +}; + +typedef struct HB_ChainSubClassRule_ HB_ChainSubClassRule; + + +struct HB_ChainSubClassSet_ +{ + FT_UShort ChainSubClassRuleCount; + /* number of ChainSubClassRule + tables */ + HB_ChainSubClassRule* ChainSubClassRule; + /* array of ChainSubClassRule + tables */ +}; + +typedef struct HB_ChainSubClassSet_ HB_ChainSubClassSet; + + +/* The `MaxXXXLength' fields are not defined in the TTO specification + but simplifies the implementation of this format. It holds the + maximal context length used in the specific context rules. */ + +struct HB_ChainContextSubstFormat2_ +{ + HB_Coverage Coverage; /* Coverage table */ + + FT_UShort MaxBacktrackLength; + /* maximal backtrack length */ + HB_ClassDefinition BacktrackClassDef; + /* BacktrackClassDef table */ + FT_UShort MaxInputLength; + /* maximal input length */ + HB_ClassDefinition InputClassDef; + /* InputClassDef table */ + FT_UShort MaxLookaheadLength; + /* maximal lookahead length */ + HB_ClassDefinition LookaheadClassDef; + /* LookaheadClassDef table */ + + FT_UShort ChainSubClassSetCount; + /* number of ChainSubClassSet + tables */ + HB_ChainSubClassSet* ChainSubClassSet; + /* array of ChainSubClassSet + tables */ +}; + +typedef struct HB_ChainContextSubstFormat2_ HB_ChainContextSubstFormat2; + + +struct HB_ChainContextSubstFormat3_ +{ + FT_UShort BacktrackGlyphCount; + /* number of backtrack glyphs */ + HB_Coverage* BacktrackCoverage; + /* array of backtrack Coverage + tables */ + FT_UShort InputGlyphCount; + /* number of input glyphs */ + HB_Coverage* InputCoverage; + /* array of input coverage + tables */ + FT_UShort LookaheadGlyphCount; + /* number of lookahead glyphs */ + HB_Coverage* LookaheadCoverage; + /* array of lookahead coverage + tables */ + FT_UShort SubstCount; /* number of SubstLookupRecords */ + HB_SubstLookupRecord* SubstLookupRecord; + /* array of substitution lookups */ +}; + +typedef struct HB_ChainContextSubstFormat3_ HB_ChainContextSubstFormat3; + + +struct HB_ChainContextSubst_ +{ + FT_UShort SubstFormat; /* 1, 2, or 3 */ + + union + { + HB_ChainContextSubstFormat1 ccsf1; + HB_ChainContextSubstFormat2 ccsf2; + HB_ChainContextSubstFormat3 ccsf3; + } ccsf; +}; + +typedef struct HB_ChainContextSubst_ HB_ChainContextSubst; + + +/* LookupType 8 */ +struct HB_ReverseChainContextSubst_ +{ + FT_UShort SubstFormat; /* always 1 */ + HB_Coverage Coverage; /* coverage table for input glyphs */ + FT_UShort BacktrackGlyphCount; /* number of backtrack glyphs */ + HB_Coverage* BacktrackCoverage; /* array of backtrack Coverage + tables */ + FT_UShort LookaheadGlyphCount; /* number of lookahead glyphs */ + HB_Coverage* LookaheadCoverage; /* array of lookahead Coverage + tables */ + FT_UShort GlyphCount; /* number of Glyph IDs */ + FT_UShort* Substitute; /* array of substitute Glyph ID */ +}; + +typedef struct HB_ReverseChainContextSubst_ HB_ReverseChainContextSubst; + + +union HB_GSUB_SubTable_ +{ + HB_SingleSubst single; + HB_MultipleSubst multiple; + HB_AlternateSubst alternate; + HB_LigatureSubst ligature; + HB_ContextSubst context; + HB_ChainContextSubst chain; + HB_ReverseChainContextSubst reverse; +}; + + + + + +FT_Error _HB_GSUB_Load_SubTable( HB_GSUB_SubTable* st, + FT_Stream stream, + FT_UShort lookup_type ); + +void _HB_GSUB_Free_SubTable( HB_GSUB_SubTable* st, + FT_Memory memory, + FT_UShort lookup_type ); + +FT_END_HEADER + +#endif /* HARFBUZZ_GSUB_PRIVATE_H */ diff --git a/src/harfbuzz-gsub.c b/src/harfbuzz-gsub.c new file mode 100644 index 0000000..0a69fa6 --- /dev/null +++ b/src/harfbuzz-gsub.c @@ -0,0 +1,4581 @@ +/******************************************************************* + * + * Copyright 1996-2000 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * Copyright 2006 Behdad Esfahbod + * + * This is part of HarfBuzz, an OpenType Layout engine library. + * + * See the file name COPYING for licensing information. + * + ******************************************************************/ +#include "harfbuzz-impl.h" +#include "harfbuzz-gsub-private.h" +#include "harfbuzz-open-private.h" +#include "harfbuzz-gdef-private.h" + +#include FT_TRUETYPE_TAGS_H + + +static FT_Error GSUB_Do_Glyph_Lookup( HB_GSUBHeader* gsub, + FT_UShort lookup_index, + HB_Buffer buffer, + FT_UShort context_length, + int nesting_level ); + + + +/********************** + * Auxiliary functions + **********************/ + + + +FT_Error HB_Load_GSUB_Table( FT_Face face, + HB_GSUBHeader** retptr, + HB_GDEFHeader* gdef ) +{ + FT_Stream stream = face->stream; + FT_Memory memory = face->memory; + FT_Error error; + FT_ULong cur_offset, new_offset, base_offset; + + FT_UShort i, num_lookups; + HB_GSUBHeader* gsub; + HB_Lookup* lo; + + if ( !retptr ) + return FT_Err_Invalid_Argument; + + if (( error = _hb_ftglue_face_goto_table( face, TTAG_GSUB, stream ) )) + return error; + + base_offset = FILE_Pos(); + + if ( ALLOC ( gsub, sizeof( *gsub ) ) ) + return error; + + gsub->memory = memory; + + /* skip version */ + + if ( FILE_Seek( base_offset + 4L ) || + ACCESS_Frame( 2L ) ) + goto Fail4; + + new_offset = GET_UShort() + base_offset; + + FORGET_Frame(); + + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = _HB_OPEN_Load_ScriptList( &gsub->ScriptList, + stream ) ) != FT_Err_Ok ) + goto Fail4; + (void)FILE_Seek( cur_offset ); + + if ( ACCESS_Frame( 2L ) ) + goto Fail3; + + new_offset = GET_UShort() + base_offset; + + FORGET_Frame(); + + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = _HB_OPEN_Load_FeatureList( &gsub->FeatureList, + stream ) ) != FT_Err_Ok ) + goto Fail3; + (void)FILE_Seek( cur_offset ); + + if ( ACCESS_Frame( 2L ) ) + goto Fail2; + + new_offset = GET_UShort() + base_offset; + + FORGET_Frame(); + + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = _HB_OPEN_Load_LookupList( &gsub->LookupList, + stream, HB_Type_GSUB ) ) != FT_Err_Ok ) + goto Fail2; + + gsub->gdef = gdef; /* can be NULL */ + + /* We now check the LookupFlags for values larger than 0xFF to find + out whether we need to load the `MarkAttachClassDef' field of the + GDEF table -- this hack is necessary for OpenType 1.2 tables since + the version field of the GDEF table hasn't been incremented. + + For constructed GDEF tables, we only load it if + `MarkAttachClassDef_offset' is not zero (nevertheless, a build of + a constructed mark attach table is not supported currently). */ + + if ( gdef && + gdef->MarkAttachClassDef_offset && !gdef->MarkAttachClassDef.loaded ) + { + lo = gsub->LookupList.Lookup; + num_lookups = gsub->LookupList.LookupCount; + + for ( i = 0; i < num_lookups; i++ ) + { + + if ( lo[i].LookupFlag & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS ) + { + if ( FILE_Seek( gdef->MarkAttachClassDef_offset ) || + ( error = _HB_OPEN_Load_ClassDefinition( &gdef->MarkAttachClassDef, + 256, stream ) ) != FT_Err_Ok ) + goto Fail1; + + break; + } + } + } + + *retptr = gsub; + + return FT_Err_Ok; + +Fail1: + _HB_OPEN_Free_LookupList( &gsub->LookupList, HB_Type_GSUB, memory ); + +Fail2: + _HB_OPEN_Free_FeatureList( &gsub->FeatureList, memory ); + +Fail3: + _HB_OPEN_Free_ScriptList( &gsub->ScriptList, memory ); + +Fail4: + FREE ( gsub ); + + + return error; +} + + +FT_Error HB_Done_GSUB_Table( HB_GSUBHeader* gsub ) +{ + FT_Memory memory = gsub->memory; + + _HB_OPEN_Free_LookupList( &gsub->LookupList, HB_Type_GSUB, memory ); + _HB_OPEN_Free_FeatureList( &gsub->FeatureList, memory ); + _HB_OPEN_Free_ScriptList( &gsub->ScriptList, memory ); + + FREE( gsub ); + + return FT_Err_Ok; +} + +/***************************** + * SubTable related functions + *****************************/ + +static FT_Error Lookup_DefaultSubst( HB_GSUBHeader* gsub, + HB_GSUB_SubTable* st, + HB_Buffer buffer, + FT_UShort flags, + FT_UShort context_length, + int nesting_level ) +{ + return HB_Err_Not_Covered; +} + + +/* LookupType 1 */ + +/* SingleSubstFormat1 */ +/* SingleSubstFormat2 */ + +static FT_Error Load_SingleSubst( HB_GSUB_SubTable* st, + FT_Stream stream ) +{ + FT_Error error; + FT_Memory memory = stream->memory; + HB_SingleSubst* ss = &st->single; + + FT_UShort n, count; + FT_ULong cur_offset, new_offset, base_offset; + + FT_UShort* s; + + + base_offset = FILE_Pos(); + + if ( ACCESS_Frame( 4L ) ) + return error; + + ss->SubstFormat = GET_UShort(); + new_offset = GET_UShort() + base_offset; + + FORGET_Frame(); + + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = _HB_OPEN_Load_Coverage( &ss->Coverage, stream ) ) != FT_Err_Ok ) + return error; + (void)FILE_Seek( cur_offset ); + + switch ( ss->SubstFormat ) + { + case 1: + if ( ACCESS_Frame( 2L ) ) + goto Fail2; + + ss->ssf.ssf1.DeltaGlyphID = GET_UShort(); + + FORGET_Frame(); + + break; + + case 2: + if ( ACCESS_Frame( 2L ) ) + goto Fail2; + + count = ss->ssf.ssf2.GlyphCount = GET_UShort(); + + FORGET_Frame(); + + ss->ssf.ssf2.Substitute = NULL; + + if ( ALLOC_ARRAY( ss->ssf.ssf2.Substitute, count, FT_UShort ) ) + goto Fail2; + + s = ss->ssf.ssf2.Substitute; + + if ( ACCESS_Frame( count * 2L ) ) + goto Fail1; + + for ( n = 0; n < count; n++ ) + s[n] = GET_UShort(); + + FORGET_Frame(); + + break; + + default: + return HB_Err_Invalid_GSUB_SubTable_Format; + } + + return FT_Err_Ok; + +Fail1: + FREE( s ); + +Fail2: + _HB_OPEN_Free_Coverage( &ss->Coverage, memory ); + return error; +} + + +static void Free_SingleSubst( HB_GSUB_SubTable* st, + FT_Memory memory ) +{ + HB_SingleSubst* ss = &st->single; + + switch ( ss->SubstFormat ) + { + case 1: + break; + + case 2: + FREE( ss->ssf.ssf2.Substitute ); + break; + } + + _HB_OPEN_Free_Coverage( &ss->Coverage, memory ); +} + + +static FT_Error Lookup_SingleSubst( HB_GSUBHeader* gsub, + HB_GSUB_SubTable* st, + HB_Buffer buffer, + FT_UShort flags, + FT_UShort context_length, + int nesting_level ) +{ + FT_UShort index, value, property; + FT_Error error; + HB_SingleSubst* ss = &st->single; + HB_GDEFHeader* gdef = gsub->gdef; + + + if ( context_length != 0xFFFF && context_length < 1 ) + return HB_Err_Not_Covered; + + if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) ) + return error; + + error = _HB_OPEN_Coverage_Index( &ss->Coverage, IN_CURGLYPH(), &index ); + if ( error ) + return error; + + switch ( ss->SubstFormat ) + { + case 1: + value = ( IN_CURGLYPH() + ss->ssf.ssf1.DeltaGlyphID ) & 0xFFFF; + if ( ADD_Glyph( buffer, value, 0xFFFF, 0xFFFF ) ) + return error; + break; + + case 2: + if ( index >= ss->ssf.ssf2.GlyphCount ) + return HB_Err_Invalid_GSUB_SubTable; + value = ss->ssf.ssf2.Substitute[index]; + if ( ADD_Glyph( buffer, value, 0xFFFF, 0xFFFF ) ) + return error; + break; + + default: + return HB_Err_Invalid_GSUB_SubTable; + } + + if ( gdef && gdef->NewGlyphClasses ) + { + /* we inherit the old glyph class to the substituted glyph */ + + error = _HB_GDEF_Add_Glyph_Property( gdef, value, property ); + if ( error && error != HB_Err_Not_Covered ) + return error; + } + + return FT_Err_Ok; +} + + +/* LookupType 2 */ + +/* Sequence */ + +static FT_Error Load_Sequence( HB_Sequence* s, + FT_Stream stream ) +{ + FT_Error error; + FT_Memory memory = stream->memory; + + FT_UShort n, count; + FT_UShort* sub; + + + if ( ACCESS_Frame( 2L ) ) + return error; + + count = s->GlyphCount = GET_UShort(); + + FORGET_Frame(); + + s->Substitute = NULL; + + if ( count ) + { + if ( ALLOC_ARRAY( s->Substitute, count, FT_UShort ) ) + return error; + + sub = s->Substitute; + + if ( ACCESS_Frame( count * 2L ) ) + { + FREE( sub ); + return error; + } + + for ( n = 0; n < count; n++ ) + sub[n] = GET_UShort(); + + FORGET_Frame(); + } + + return FT_Err_Ok; +} + + +static void Free_Sequence( HB_Sequence* s, + FT_Memory memory ) +{ + FREE( s->Substitute ); +} + + +/* MultipleSubstFormat1 */ + +static FT_Error Load_MultipleSubst( HB_GSUB_SubTable* st, + FT_Stream stream ) +{ + FT_Error error; + FT_Memory memory = stream->memory; + HB_MultipleSubst* ms = &st->multiple; + + FT_UShort n = 0, m, count; + FT_ULong cur_offset, new_offset, base_offset; + + HB_Sequence* s; + + + base_offset = FILE_Pos(); + + if ( ACCESS_Frame( 4L ) ) + return error; + + ms->SubstFormat = GET_UShort(); /* should be 1 */ + new_offset = GET_UShort() + base_offset; + + FORGET_Frame(); + + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = _HB_OPEN_Load_Coverage( &ms->Coverage, stream ) ) != FT_Err_Ok ) + return error; + (void)FILE_Seek( cur_offset ); + + if ( ACCESS_Frame( 2L ) ) + goto Fail2; + + count = ms->SequenceCount = GET_UShort(); + + FORGET_Frame(); + + ms->Sequence = NULL; + + if ( ALLOC_ARRAY( ms->Sequence, count, HB_Sequence ) ) + goto Fail2; + + s = ms->Sequence; + + for ( n = 0; n < count; n++ ) + { + if ( ACCESS_Frame( 2L ) ) + goto Fail1; + + new_offset = GET_UShort() + base_offset; + + FORGET_Frame(); + + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = Load_Sequence( &s[n], stream ) ) != FT_Err_Ok ) + goto Fail1; + (void)FILE_Seek( cur_offset ); + } + + return FT_Err_Ok; + +Fail1: + for ( m = 0; m < n; m++ ) + Free_Sequence( &s[m], memory ); + + FREE( s ); + +Fail2: + _HB_OPEN_Free_Coverage( &ms->Coverage, memory ); + return error; +} + + +static void Free_MultipleSubst( HB_GSUB_SubTable* st, + FT_Memory memory ) +{ + FT_UShort n, count; + HB_MultipleSubst* ms = &st->multiple; + + HB_Sequence* s; + + + if ( ms->Sequence ) + { + count = ms->SequenceCount; + s = ms->Sequence; + + for ( n = 0; n < count; n++ ) + Free_Sequence( &s[n], memory ); + + FREE( s ); + } + + _HB_OPEN_Free_Coverage( &ms->Coverage, memory ); +} + + +static FT_Error Lookup_MultipleSubst( HB_GSUBHeader* gsub, + HB_GSUB_SubTable* st, + HB_Buffer buffer, + FT_UShort flags, + FT_UShort context_length, + int nesting_level ) +{ + FT_Error error; + FT_UShort index, property, n, count; + FT_UShort*s; + HB_MultipleSubst* ms = &st->multiple; + HB_GDEFHeader* gdef = gsub->gdef; + + + if ( context_length != 0xFFFF && context_length < 1 ) + return HB_Err_Not_Covered; + + if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) ) + return error; + + error = _HB_OPEN_Coverage_Index( &ms->Coverage, IN_CURGLYPH(), &index ); + if ( error ) + return error; + + if ( index >= ms->SequenceCount ) + return HB_Err_Invalid_GSUB_SubTable; + + count = ms->Sequence[index].GlyphCount; + s = ms->Sequence[index].Substitute; + + if ( ADD_String( buffer, 1, count, s, 0xFFFF, 0xFFFF ) ) + return error; + + if ( gdef && gdef->NewGlyphClasses ) + { + /* this is a guess only ... */ + + if ( property == HB_GDEF_LIGATURE ) + property = HB_GDEF_BASE_GLYPH; + + for ( n = 0; n < count; n++ ) + { + error = _HB_GDEF_Add_Glyph_Property( gdef, s[n], property ); + if ( error && error != HB_Err_Not_Covered ) + return error; + } + } + + return FT_Err_Ok; +} + + +/* LookupType 3 */ + +/* AlternateSet */ + +static FT_Error Load_AlternateSet( HB_AlternateSet* as, + FT_Stream stream ) +{ + FT_Error error; + FT_Memory memory = stream->memory; + + FT_UShort n, count; + FT_UShort* a; + + + if ( ACCESS_Frame( 2L ) ) + return error; + + count = as->GlyphCount = GET_UShort(); + + FORGET_Frame(); + + as->Alternate = NULL; + + if ( ALLOC_ARRAY( as->Alternate, count, FT_UShort ) ) + return error; + + a = as->Alternate; + + if ( ACCESS_Frame( count * 2L ) ) + { + FREE( a ); + return error; + } + + for ( n = 0; n < count; n++ ) + a[n] = GET_UShort(); + + FORGET_Frame(); + + return FT_Err_Ok; +} + + +static void Free_AlternateSet( HB_AlternateSet* as, + FT_Memory memory ) +{ + FREE( as->Alternate ); +} + + +/* AlternateSubstFormat1 */ + +static FT_Error Load_AlternateSubst( HB_GSUB_SubTable* st, + FT_Stream stream ) +{ + FT_Error error; + FT_Memory memory = stream->memory; + HB_AlternateSubst* as = &st->alternate; + + FT_UShort n = 0, m, count; + FT_ULong cur_offset, new_offset, base_offset; + + HB_AlternateSet* aset; + + + base_offset = FILE_Pos(); + + if ( ACCESS_Frame( 4L ) ) + return error; + + as->SubstFormat = GET_UShort(); /* should be 1 */ + new_offset = GET_UShort() + base_offset; + + FORGET_Frame(); + + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = _HB_OPEN_Load_Coverage( &as->Coverage, stream ) ) != FT_Err_Ok ) + return error; + (void)FILE_Seek( cur_offset ); + + if ( ACCESS_Frame( 2L ) ) + goto Fail2; + + count = as->AlternateSetCount = GET_UShort(); + + FORGET_Frame(); + + as->AlternateSet = NULL; + + if ( ALLOC_ARRAY( as->AlternateSet, count, HB_AlternateSet ) ) + goto Fail2; + + aset = as->AlternateSet; + + for ( n = 0; n < count; n++ ) + { + if ( ACCESS_Frame( 2L ) ) + goto Fail1; + + new_offset = GET_UShort() + base_offset; + + FORGET_Frame(); + + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = Load_AlternateSet( &aset[n], stream ) ) != FT_Err_Ok ) + goto Fail1; + (void)FILE_Seek( cur_offset ); + } + + return FT_Err_Ok; + +Fail1: + for ( m = 0; m < n; m++ ) + Free_AlternateSet( &aset[m], memory ); + + FREE( aset ); + +Fail2: + _HB_OPEN_Free_Coverage( &as->Coverage, memory ); + return error; +} + + +static void Free_AlternateSubst( HB_GSUB_SubTable* st, + FT_Memory memory ) +{ + FT_UShort n, count; + HB_AlternateSubst* as = &st->alternate; + + HB_AlternateSet* aset; + + + if ( as->AlternateSet ) + { + count = as->AlternateSetCount; + aset = as->AlternateSet; + + for ( n = 0; n < count; n++ ) + Free_AlternateSet( &aset[n], memory ); + + FREE( aset ); + } + + _HB_OPEN_Free_Coverage( &as->Coverage, memory ); +} + + +static FT_Error Lookup_AlternateSubst( HB_GSUBHeader* gsub, + HB_GSUB_SubTable* st, + HB_Buffer buffer, + FT_UShort flags, + FT_UShort context_length, + int nesting_level ) +{ + FT_Error error; + FT_UShort index, alt_index, property; + HB_AlternateSubst* as = &st->alternate; + HB_GDEFHeader* gdef = gsub->gdef; + + + HB_AlternateSet aset; + + + if ( context_length != 0xFFFF && context_length < 1 ) + return HB_Err_Not_Covered; + + if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) ) + return error; + + error = _HB_OPEN_Coverage_Index( &as->Coverage, IN_CURGLYPH(), &index ); + if ( error ) + return error; + + aset = as->AlternateSet[index]; + + /* we use a user-defined callback function to get the alternate index */ + + if ( gsub->altfunc ) + alt_index = (gsub->altfunc)( buffer->out_pos, IN_CURGLYPH(), + aset.GlyphCount, aset.Alternate, + gsub->data ); + else + alt_index = 0; + + if ( ADD_Glyph( buffer, aset.Alternate[alt_index], + 0xFFFF, 0xFFFF ) ) + return error; + + if ( gdef && gdef->NewGlyphClasses ) + { + /* we inherit the old glyph class to the substituted glyph */ + + error = _HB_GDEF_Add_Glyph_Property( gdef, aset.Alternate[alt_index], + property ); + if ( error && error != HB_Err_Not_Covered ) + return error; + } + + return FT_Err_Ok; +} + + +/* LookupType 4 */ + +/* Ligature */ + +static FT_Error Load_Ligature( HB_Ligature* l, + FT_Stream stream ) +{ + FT_Error error; + FT_Memory memory = stream->memory; + + FT_UShort n, count; + FT_UShort* c; + + + if ( ACCESS_Frame( 4L ) ) + return error; + + l->LigGlyph = GET_UShort(); + l->ComponentCount = GET_UShort(); + + FORGET_Frame(); + + l->Component = NULL; + + count = l->ComponentCount - 1; /* only ComponentCount - 1 elements */ + + if ( ALLOC_ARRAY( l->Component, count, FT_UShort ) ) + return error; + + c = l->Component; + + if ( ACCESS_Frame( count * 2L ) ) + { + FREE( c ); + return error; + } + + for ( n = 0; n < count; n++ ) + c[n] = GET_UShort(); + + FORGET_Frame(); + + return FT_Err_Ok; +} + + +static void Free_Ligature( HB_Ligature* l, + FT_Memory memory ) +{ + FREE( l->Component ); +} + + +/* LigatureSet */ + +static FT_Error Load_LigatureSet( HB_LigatureSet* ls, + FT_Stream stream ) +{ + FT_Error error; + FT_Memory memory = stream->memory; + + FT_UShort n = 0, m, count; + FT_ULong cur_offset, new_offset, base_offset; + + HB_Ligature* l; + + + base_offset = FILE_Pos(); + + if ( ACCESS_Frame( 2L ) ) + return error; + + count = ls->LigatureCount = GET_UShort(); + + FORGET_Frame(); + + ls->Ligature = NULL; + + if ( ALLOC_ARRAY( ls->Ligature, count, HB_Ligature ) ) + return error; + + l = ls->Ligature; + + for ( n = 0; n < count; n++ ) + { + if ( ACCESS_Frame( 2L ) ) + goto Fail; + + new_offset = GET_UShort() + base_offset; + + FORGET_Frame(); + + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = Load_Ligature( &l[n], stream ) ) != FT_Err_Ok ) + goto Fail; + (void)FILE_Seek( cur_offset ); + } + + return FT_Err_Ok; + +Fail: + for ( m = 0; m < n; m++ ) + Free_Ligature( &l[m], memory ); + + FREE( l ); + return error; +} + + +static void Free_LigatureSet( HB_LigatureSet* ls, + FT_Memory memory ) +{ + FT_UShort n, count; + + HB_Ligature* l; + + + if ( ls->Ligature ) + { + count = ls->LigatureCount; + l = ls->Ligature; + + for ( n = 0; n < count; n++ ) + Free_Ligature( &l[n], memory ); + + FREE( l ); + } +} + + +/* LigatureSubstFormat1 */ + +static FT_Error Load_LigatureSubst( HB_GSUB_SubTable* st, + FT_Stream stream ) +{ + FT_Error error; + FT_Memory memory = stream->memory; + HB_LigatureSubst* ls = &st->ligature; + + FT_UShort n = 0, m, count; + FT_ULong cur_offset, new_offset, base_offset; + + HB_LigatureSet* lset; + + + base_offset = FILE_Pos(); + + if ( ACCESS_Frame( 4L ) ) + return error; + + ls->SubstFormat = GET_UShort(); /* should be 1 */ + new_offset = GET_UShort() + base_offset; + + FORGET_Frame(); + + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = _HB_OPEN_Load_Coverage( &ls->Coverage, stream ) ) != FT_Err_Ok ) + return error; + (void)FILE_Seek( cur_offset ); + + if ( ACCESS_Frame( 2L ) ) + goto Fail2; + + count = ls->LigatureSetCount = GET_UShort(); + + FORGET_Frame(); + + ls->LigatureSet = NULL; + + if ( ALLOC_ARRAY( ls->LigatureSet, count, HB_LigatureSet ) ) + goto Fail2; + + lset = ls->LigatureSet; + + for ( n = 0; n < count; n++ ) + { + if ( ACCESS_Frame( 2L ) ) + goto Fail1; + + new_offset = GET_UShort() + base_offset; + + FORGET_Frame(); + + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = Load_LigatureSet( &lset[n], stream ) ) != FT_Err_Ok ) + goto Fail1; + (void)FILE_Seek( cur_offset ); + } + + return FT_Err_Ok; + +Fail1: + for ( m = 0; m < n; m++ ) + Free_LigatureSet( &lset[m], memory ); + + FREE( lset ); + +Fail2: + _HB_OPEN_Free_Coverage( &ls->Coverage, memory ); + return error; +} + + +static void Free_LigatureSubst( HB_GSUB_SubTable* st, + FT_Memory memory ) +{ + FT_UShort n, count; + HB_LigatureSubst* ls = &st->ligature; + + HB_LigatureSet* lset; + + + if ( ls->LigatureSet ) + { + count = ls->LigatureSetCount; + lset = ls->LigatureSet; + + for ( n = 0; n < count; n++ ) + Free_LigatureSet( &lset[n], memory ); + + FREE( lset ); + } + + _HB_OPEN_Free_Coverage( &ls->Coverage, memory ); +} + + +static FT_Error Lookup_LigatureSubst( HB_GSUBHeader* gsub, + HB_GSUB_SubTable* st, + HB_Buffer buffer, + FT_UShort flags, + FT_UShort context_length, + int nesting_level ) +{ + FT_UShort index, property; + FT_Error error; + FT_UShort numlig, i, j, is_mark, first_is_mark = FALSE; + FT_UShort* c; + HB_LigatureSubst* ls = &st->ligature; + HB_GDEFHeader* gdef = gsub->gdef; + + HB_Ligature* lig; + + + if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) ) + return error; + + if ( property == HB_GDEF_MARK || property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS ) + first_is_mark = TRUE; + + error = _HB_OPEN_Coverage_Index( &ls->Coverage, IN_CURGLYPH(), &index ); + if ( error ) + return error; + + if ( index >= ls->LigatureSetCount ) + return HB_Err_Invalid_GSUB_SubTable; + + lig = ls->LigatureSet[index].Ligature; + + for ( numlig = ls->LigatureSet[index].LigatureCount; + numlig; + numlig--, lig++ ) + { + if ( buffer->in_pos + lig->ComponentCount > buffer->in_length ) + goto next_ligature; /* Not enough glyphs in input */ + + c = lig->Component; + + is_mark = first_is_mark; + + if ( context_length != 0xFFFF && context_length < lig->ComponentCount ) + break; + + for ( i = 1, j = buffer->in_pos + 1; i < lig->ComponentCount; i++, j++ ) + { + while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) + { + if ( error && error != HB_Err_Not_Covered ) + return error; + + if ( j + lig->ComponentCount - i == buffer->in_length ) + goto next_ligature; + j++; + } + + if ( !( property == HB_GDEF_MARK || property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS ) ) + is_mark = FALSE; + + if ( IN_GLYPH( j ) != c[i - 1] ) + goto next_ligature; + } + + if ( gdef && gdef->NewGlyphClasses ) + { + /* this is just a guess ... */ + + error = _HB_GDEF_Add_Glyph_Property( gdef, lig->LigGlyph, + is_mark ? HB_GDEF_MARK : HB_GDEF_LIGATURE ); + if ( error && error != HB_Err_Not_Covered ) + return error; + } + + if ( j == buffer->in_pos + i ) /* No input glyphs skipped */ + { + /* We don't use a new ligature ID if there are no skipped + glyphs and the ligature already has an ID. */ + + if ( IN_LIGID( buffer->in_pos ) ) + { + if ( ADD_String( buffer, i, 1, &lig->LigGlyph, + 0xFFFF, 0xFFFF ) ) + return error; + } + else + { + FT_UShort ligID = hb_buffer_allocate_ligid( buffer ); + if ( ADD_String( buffer, i, 1, &lig->LigGlyph, + 0xFFFF, ligID ) ) + return error; + } + } + else + { + FT_UShort ligID = hb_buffer_allocate_ligid( buffer ); + if ( ADD_Glyph( buffer, lig->LigGlyph, + 0xFFFF, ligID ) ) + return error; + + /* Now we must do a second loop to copy the skipped glyphs to + `out' and assign component values to it. We start with the + glyph after the first component. Glyphs between component + i and i+1 belong to component i. Together with the ligID + value it is later possible to check whether a specific + component value really belongs to a given ligature. */ + + for ( i = 0; i < lig->ComponentCount - 1; i++ ) + { + while ( CHECK_Property( gdef, IN_CURITEM(), + flags, &property ) ) + if ( ADD_Glyph( buffer, IN_CURGLYPH(), + i, ligID ) ) + return error; + + (buffer->in_pos)++; + } + } + + return FT_Err_Ok; + + next_ligature: + ; + } + + return HB_Err_Not_Covered; +} + + +/* Do the actual substitution for a context substitution (either format + 5 or 6). This is only called after we've determined that the input + matches the subrule. */ + +static FT_Error Do_ContextSubst( HB_GSUBHeader* gsub, + FT_UShort GlyphCount, + FT_UShort SubstCount, + HB_SubstLookupRecord* subst, + HB_Buffer buffer, + int nesting_level ) +{ + FT_Error error; + FT_UShort i, old_pos; + + + i = 0; + + while ( i < GlyphCount ) + { + if ( SubstCount && i == subst->SequenceIndex ) + { + old_pos = buffer->in_pos; + + /* Do a substitution */ + + error = GSUB_Do_Glyph_Lookup( gsub, subst->LookupListIndex, buffer, + GlyphCount, nesting_level ); + + subst++; + SubstCount--; + i += buffer->in_pos - old_pos; + + if ( error == HB_Err_Not_Covered ) + { + /* XXX "can't happen" -- but don't count on it */ + + if ( ADD_Glyph( buffer, IN_CURGLYPH(), + 0xFFFF, 0xFFFF ) ) + return error; + i++; + } + else if ( error ) + return error; + } + else + { + /* No substitution for this index */ + + if ( ADD_Glyph( buffer, IN_CURGLYPH(), + 0xFFFF, 0xFFFF ) ) + return error; + i++; + } + } + + return FT_Err_Ok; +} + + +/* LookupType 5 */ + +/* SubRule */ + +static FT_Error Load_SubRule( HB_SubRule* sr, + FT_Stream stream ) +{ + FT_Error error; + FT_Memory memory = stream->memory; + + FT_UShort n, count; + FT_UShort* i; + + HB_SubstLookupRecord* slr; + + + if ( ACCESS_Frame( 4L ) ) + return error; + + sr->GlyphCount = GET_UShort(); + sr->SubstCount = GET_UShort(); + + FORGET_Frame(); + + sr->Input = NULL; + + count = sr->GlyphCount - 1; /* only GlyphCount - 1 elements */ + + if ( ALLOC_ARRAY( sr->Input, count, FT_UShort ) ) + return error; + + i = sr->Input; + + if ( ACCESS_Frame( count * 2L ) ) + goto Fail2; + + for ( n = 0; n < count; n++ ) + i[n] = GET_UShort(); + + FORGET_Frame(); + + sr->SubstLookupRecord = NULL; + + count = sr->SubstCount; + + if ( ALLOC_ARRAY( sr->SubstLookupRecord, count, HB_SubstLookupRecord ) ) + goto Fail2; + + slr = sr->SubstLookupRecord; + + if ( ACCESS_Frame( count * 4L ) ) + goto Fail1; + + for ( n = 0; n < count; n++ ) + { + slr[n].SequenceIndex = GET_UShort(); + slr[n].LookupListIndex = GET_UShort(); + } + + FORGET_Frame(); + + return FT_Err_Ok; + +Fail1: + FREE( slr ); + +Fail2: + FREE( i ); + return error; +} + + +static void Free_SubRule( HB_SubRule* sr, + FT_Memory memory ) +{ + FREE( sr->SubstLookupRecord ); + FREE( sr->Input ); +} + + +/* SubRuleSet */ + +static FT_Error Load_SubRuleSet( HB_SubRuleSet* srs, + FT_Stream stream ) +{ + FT_Error error; + FT_Memory memory = stream->memory; + + FT_UShort n = 0, m, count; + FT_ULong cur_offset, new_offset, base_offset; + + HB_SubRule* sr; + + + base_offset = FILE_Pos(); + + if ( ACCESS_Frame( 2L ) ) + return error; + + count = srs->SubRuleCount = GET_UShort(); + + FORGET_Frame(); + + srs->SubRule = NULL; + + if ( ALLOC_ARRAY( srs->SubRule, count, HB_SubRule ) ) + return error; + + sr = srs->SubRule; + + for ( n = 0; n < count; n++ ) + { + if ( ACCESS_Frame( 2L ) ) + goto Fail; + + new_offset = GET_UShort() + base_offset; + + FORGET_Frame(); + + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = Load_SubRule( &sr[n], stream ) ) != FT_Err_Ok ) + goto Fail; + (void)FILE_Seek( cur_offset ); + } + + return FT_Err_Ok; + +Fail: + for ( m = 0; m < n; m++ ) + Free_SubRule( &sr[m], memory ); + + FREE( sr ); + return error; +} + + +static void Free_SubRuleSet( HB_SubRuleSet* srs, + FT_Memory memory ) +{ + FT_UShort n, count; + + HB_SubRule* sr; + + + if ( srs->SubRule ) + { + count = srs->SubRuleCount; + sr = srs->SubRule; + + for ( n = 0; n < count; n++ ) + Free_SubRule( &sr[n], memory ); + + FREE( sr ); + } +} + + +/* ContextSubstFormat1 */ + +static FT_Error Load_ContextSubst1( HB_ContextSubstFormat1* csf1, + FT_Stream stream ) +{ + FT_Error error; + FT_Memory memory = stream->memory; + + FT_UShort n = 0, m, count; + FT_ULong cur_offset, new_offset, base_offset; + + HB_SubRuleSet* srs; + + + base_offset = FILE_Pos() - 2L; + + if ( ACCESS_Frame( 2L ) ) + return error; + + new_offset = GET_UShort() + base_offset; + + FORGET_Frame(); + + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = _HB_OPEN_Load_Coverage( &csf1->Coverage, stream ) ) != FT_Err_Ok ) + return error; + (void)FILE_Seek( cur_offset ); + + if ( ACCESS_Frame( 2L ) ) + goto Fail2; + + count = csf1->SubRuleSetCount = GET_UShort(); + + FORGET_Frame(); + + csf1->SubRuleSet = NULL; + + if ( ALLOC_ARRAY( csf1->SubRuleSet, count, HB_SubRuleSet ) ) + goto Fail2; + + srs = csf1->SubRuleSet; + + for ( n = 0; n < count; n++ ) + { + if ( ACCESS_Frame( 2L ) ) + goto Fail1; + + new_offset = GET_UShort() + base_offset; + + FORGET_Frame(); + + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = Load_SubRuleSet( &srs[n], stream ) ) != FT_Err_Ok ) + goto Fail1; + (void)FILE_Seek( cur_offset ); + } + + return FT_Err_Ok; + +Fail1: + for ( m = 0; m < n; m++ ) + Free_SubRuleSet( &srs[m], memory ); + + FREE( srs ); + +Fail2: + _HB_OPEN_Free_Coverage( &csf1->Coverage, memory ); + return error; +} + + +static void Free_ContextSubst1( HB_ContextSubstFormat1* csf1, + FT_Memory memory ) +{ + FT_UShort n, count; + + HB_SubRuleSet* srs; + + + if ( csf1->SubRuleSet ) + { + count = csf1->SubRuleSetCount; + srs = csf1->SubRuleSet; + + for ( n = 0; n < count; n++ ) + Free_SubRuleSet( &srs[n], memory ); + + FREE( srs ); + } + + _HB_OPEN_Free_Coverage( &csf1->Coverage, memory ); +} + + +/* SubClassRule */ + +static FT_Error Load_SubClassRule( HB_ContextSubstFormat2* csf2, + HB_SubClassRule* scr, + FT_Stream stream ) +{ + FT_Error error; + FT_Memory memory = stream->memory; + + FT_UShort n, count; + + FT_UShort* c; + HB_SubstLookupRecord* slr; + FT_Bool* d; + + + if ( ACCESS_Frame( 4L ) ) + return error; + + scr->GlyphCount = GET_UShort(); + scr->SubstCount = GET_UShort(); + + if ( scr->GlyphCount > csf2->MaxContextLength ) + csf2->MaxContextLength = scr->GlyphCount; + + FORGET_Frame(); + + scr->Class = NULL; + + count = scr->GlyphCount - 1; /* only GlyphCount - 1 elements */ + + if ( ALLOC_ARRAY( scr->Class, count, FT_UShort ) ) + return error; + + c = scr->Class; + d = csf2->ClassDef.Defined; + + if ( ACCESS_Frame( count * 2L ) ) + goto Fail2; + + for ( n = 0; n < count; n++ ) + { + c[n] = GET_UShort(); + + /* We check whether the specific class is used at all. If not, + class 0 is used instead. */ + if ( !d[c[n]] ) + c[n] = 0; + } + + FORGET_Frame(); + + scr->SubstLookupRecord = NULL; + + count = scr->SubstCount; + + if ( ALLOC_ARRAY( scr->SubstLookupRecord, count, HB_SubstLookupRecord ) ) + goto Fail2; + + slr = scr->SubstLookupRecord; + + if ( ACCESS_Frame( count * 4L ) ) + goto Fail1; + + for ( n = 0; n < count; n++ ) + { + slr[n].SequenceIndex = GET_UShort(); + slr[n].LookupListIndex = GET_UShort(); + } + + FORGET_Frame(); + + return FT_Err_Ok; + +Fail1: + FREE( slr ); + +Fail2: + FREE( c ); + return error; +} + + +static void Free_SubClassRule( HB_SubClassRule* scr, + FT_Memory memory ) +{ + FREE( scr->SubstLookupRecord ); + FREE( scr->Class ); +} + + +/* SubClassSet */ + +static FT_Error Load_SubClassSet( HB_ContextSubstFormat2* csf2, + HB_SubClassSet* scs, + FT_Stream stream ) +{ + FT_Error error; + FT_Memory memory = stream->memory; + + FT_UShort n = 0, m, count; + FT_ULong cur_offset, new_offset, base_offset; + + HB_SubClassRule* scr; + + + base_offset = FILE_Pos(); + + if ( ACCESS_Frame( 2L ) ) + return error; + + count = scs->SubClassRuleCount = GET_UShort(); + + FORGET_Frame(); + + scs->SubClassRule = NULL; + + if ( ALLOC_ARRAY( scs->SubClassRule, count, HB_SubClassRule ) ) + return error; + + scr = scs->SubClassRule; + + for ( n = 0; n < count; n++ ) + { + if ( ACCESS_Frame( 2L ) ) + goto Fail; + + new_offset = GET_UShort() + base_offset; + + FORGET_Frame(); + + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = Load_SubClassRule( csf2, &scr[n], + stream ) ) != FT_Err_Ok ) + goto Fail; + (void)FILE_Seek( cur_offset ); + } + + return FT_Err_Ok; + +Fail: + for ( m = 0; m < n; m++ ) + Free_SubClassRule( &scr[m], memory ); + + FREE( scr ); + return error; +} + + +static void Free_SubClassSet( HB_SubClassSet* scs, + FT_Memory memory ) +{ + FT_UShort n, count; + + HB_SubClassRule* scr; + + + if ( scs->SubClassRule ) + { + count = scs->SubClassRuleCount; + scr = scs->SubClassRule; + + for ( n = 0; n < count; n++ ) + Free_SubClassRule( &scr[n], memory ); + + FREE( scr ); + } +} + + +/* ContextSubstFormat2 */ + +static FT_Error Load_ContextSubst2( HB_ContextSubstFormat2* csf2, + FT_Stream stream ) +{ + FT_Error error; + FT_Memory memory = stream->memory; + + FT_UShort n = 0, m, count; + FT_ULong cur_offset, new_offset, base_offset; + + HB_SubClassSet* scs; + + + base_offset = FILE_Pos() - 2; + + if ( ACCESS_Frame( 2L ) ) + return error; + + new_offset = GET_UShort() + base_offset; + + FORGET_Frame(); + + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = _HB_OPEN_Load_Coverage( &csf2->Coverage, stream ) ) != FT_Err_Ok ) + return error; + (void)FILE_Seek( cur_offset ); + + if ( ACCESS_Frame( 4L ) ) + goto Fail3; + + new_offset = GET_UShort() + base_offset; + + /* `SubClassSetCount' is the upper limit for class values, thus we + read it now to make an additional safety check. */ + + count = csf2->SubClassSetCount = GET_UShort(); + + FORGET_Frame(); + + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = _HB_OPEN_Load_ClassDefinition( &csf2->ClassDef, count, + stream ) ) != FT_Err_Ok ) + goto Fail3; + (void)FILE_Seek( cur_offset ); + + csf2->SubClassSet = NULL; + csf2->MaxContextLength = 0; + + if ( ALLOC_ARRAY( csf2->SubClassSet, count, HB_SubClassSet ) ) + goto Fail2; + + scs = csf2->SubClassSet; + + for ( n = 0; n < count; n++ ) + { + if ( ACCESS_Frame( 2L ) ) + goto Fail1; + + new_offset = GET_UShort() + base_offset; + + FORGET_Frame(); + + if ( new_offset != base_offset ) /* not a NULL offset */ + { + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = Load_SubClassSet( csf2, &scs[n], + stream ) ) != FT_Err_Ok ) + goto Fail1; + (void)FILE_Seek( cur_offset ); + } + else + { + /* we create a SubClassSet table with no entries */ + + csf2->SubClassSet[n].SubClassRuleCount = 0; + csf2->SubClassSet[n].SubClassRule = NULL; + } + } + + return FT_Err_Ok; + +Fail1: + for ( m = 0; m < n; m++ ) + Free_SubClassSet( &scs[m], memory ); + + FREE( scs ); + +Fail2: + _HB_OPEN_Free_ClassDefinition( &csf2->ClassDef, memory ); + +Fail3: + _HB_OPEN_Free_Coverage( &csf2->Coverage, memory ); + return error; +} + + +static void Free_ContextSubst2( HB_ContextSubstFormat2* csf2, + FT_Memory memory ) +{ + FT_UShort n, count; + + HB_SubClassSet* scs; + + + if ( csf2->SubClassSet ) + { + count = csf2->SubClassSetCount; + scs = csf2->SubClassSet; + + for ( n = 0; n < count; n++ ) + Free_SubClassSet( &scs[n], memory ); + + FREE( scs ); + } + + _HB_OPEN_Free_ClassDefinition( &csf2->ClassDef, memory ); + _HB_OPEN_Free_Coverage( &csf2->Coverage, memory ); +} + + +/* ContextSubstFormat3 */ + +static FT_Error Load_ContextSubst3( HB_ContextSubstFormat3* csf3, + FT_Stream stream ) +{ + FT_Error error; + FT_Memory memory = stream->memory; + + FT_UShort n = 0, m, count; + FT_ULong cur_offset, new_offset, base_offset; + + HB_Coverage* c; + HB_SubstLookupRecord* slr; + + + base_offset = FILE_Pos() - 2L; + + if ( ACCESS_Frame( 4L ) ) + return error; + + csf3->GlyphCount = GET_UShort(); + csf3->SubstCount = GET_UShort(); + + FORGET_Frame(); + + csf3->Coverage = NULL; + + count = csf3->GlyphCount; + + if ( ALLOC_ARRAY( csf3->Coverage, count, HB_Coverage ) ) + return error; + + c = csf3->Coverage; + + for ( n = 0; n < count; n++ ) + { + if ( ACCESS_Frame( 2L ) ) + goto Fail2; + + new_offset = GET_UShort() + base_offset; + + FORGET_Frame(); + + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = _HB_OPEN_Load_Coverage( &c[n], stream ) ) != FT_Err_Ok ) + goto Fail2; + (void)FILE_Seek( cur_offset ); + } + + csf3->SubstLookupRecord = NULL; + + count = csf3->SubstCount; + + if ( ALLOC_ARRAY( csf3->SubstLookupRecord, count, + HB_SubstLookupRecord ) ) + goto Fail2; + + slr = csf3->SubstLookupRecord; + + if ( ACCESS_Frame( count * 4L ) ) + goto Fail1; + + for ( n = 0; n < count; n++ ) + { + slr[n].SequenceIndex = GET_UShort(); + slr[n].LookupListIndex = GET_UShort(); + } + + FORGET_Frame(); + + return FT_Err_Ok; + +Fail1: + FREE( slr ); + +Fail2: + for ( m = 0; m < n; m++ ) + _HB_OPEN_Free_Coverage( &c[m], memory ); + + FREE( c ); + return error; +} + + +static void Free_ContextSubst3( HB_ContextSubstFormat3* csf3, + FT_Memory memory ) +{ + FT_UShort n, count; + + HB_Coverage* c; + + + FREE( csf3->SubstLookupRecord ); + + if ( csf3->Coverage ) + { + count = csf3->GlyphCount; + c = csf3->Coverage; + + for ( n = 0; n < count; n++ ) + _HB_OPEN_Free_Coverage( &c[n], memory ); + + FREE( c ); + } +} + + +/* ContextSubst */ + +static FT_Error Load_ContextSubst( HB_GSUB_SubTable* st, + FT_Stream stream ) +{ + FT_Error error; + HB_ContextSubst* cs = &st->context; + + + if ( ACCESS_Frame( 2L ) ) + return error; + + cs->SubstFormat = GET_UShort(); + + FORGET_Frame(); + + switch ( cs->SubstFormat ) + { + case 1: + return Load_ContextSubst1( &cs->csf.csf1, stream ); + + case 2: + return Load_ContextSubst2( &cs->csf.csf2, stream ); + + case 3: + return Load_ContextSubst3( &cs->csf.csf3, stream ); + + default: + return HB_Err_Invalid_GSUB_SubTable_Format; + } + + return FT_Err_Ok; /* never reached */ +} + + +static void Free_ContextSubst( HB_GSUB_SubTable* st, + FT_Memory memory ) +{ + HB_ContextSubst* cs = &st->context; + + switch ( cs->SubstFormat ) + { + case 1: + Free_ContextSubst1( &cs->csf.csf1, memory ); + break; + + case 2: + Free_ContextSubst2( &cs->csf.csf2, memory ); + break; + + case 3: + Free_ContextSubst3( &cs->csf.csf3, memory ); + break; + } +} + + +static FT_Error Lookup_ContextSubst1( HB_GSUBHeader* gsub, + HB_ContextSubstFormat1* csf1, + HB_Buffer buffer, + FT_UShort flags, + FT_UShort context_length, + int nesting_level ) +{ + FT_UShort index, property; + FT_UShort i, j, k, numsr; + FT_Error error; + + HB_SubRule* sr; + HB_GDEFHeader* gdef; + + + gdef = gsub->gdef; + + if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) ) + return error; + + error = _HB_OPEN_Coverage_Index( &csf1->Coverage, IN_CURGLYPH(), &index ); + if ( error ) + return error; + + sr = csf1->SubRuleSet[index].SubRule; + numsr = csf1->SubRuleSet[index].SubRuleCount; + + for ( k = 0; k < numsr; k++ ) + { + if ( context_length != 0xFFFF && context_length < sr[k].GlyphCount ) + goto next_subrule; + + if ( buffer->in_pos + sr[k].GlyphCount > buffer->in_length ) + goto next_subrule; /* context is too long */ + + for ( i = 1, j = buffer->in_pos + 1; i < sr[k].GlyphCount; i++, j++ ) + { + while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) + { + if ( error && error != HB_Err_Not_Covered ) + return error; + + if ( j + sr[k].GlyphCount - i == buffer->in_length ) + goto next_subrule; + j++; + } + + if ( IN_GLYPH( j ) != sr[k].Input[i - 1] ) + goto next_subrule; + } + + return Do_ContextSubst( gsub, sr[k].GlyphCount, + sr[k].SubstCount, sr[k].SubstLookupRecord, + buffer, + nesting_level ); + next_subrule: + ; + } + + return HB_Err_Not_Covered; +} + + +static FT_Error Lookup_ContextSubst2( HB_GSUBHeader* gsub, + HB_ContextSubstFormat2* csf2, + HB_Buffer buffer, + FT_UShort flags, + FT_UShort context_length, + int nesting_level ) +{ + FT_UShort index, property; + FT_Error error; + FT_Memory memory = gsub->memory; + FT_UShort i, j, k, known_classes; + + FT_UShort* classes; + FT_UShort* cl; + + HB_SubClassSet* scs; + HB_SubClassRule* sr; + HB_GDEFHeader* gdef; + + + gdef = gsub->gdef; + + if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) ) + return error; + + /* Note: The coverage table in format 2 doesn't give an index into + anything. It just lets us know whether or not we need to + do any lookup at all. */ + + error = _HB_OPEN_Coverage_Index( &csf2->Coverage, IN_CURGLYPH(), &index ); + if ( error ) + return error; + + if ( ALLOC_ARRAY( classes, csf2->MaxContextLength, FT_UShort ) ) + return error; + + error = _HB_OPEN_Get_Class( &csf2->ClassDef, IN_CURGLYPH(), + &classes[0], NULL ); + if ( error && error != HB_Err_Not_Covered ) + goto End; + known_classes = 0; + + scs = &csf2->SubClassSet[classes[0]]; + if ( !scs ) + { + error = HB_Err_Invalid_GSUB_SubTable; + goto End; + } + + for ( k = 0; k < scs->SubClassRuleCount; k++ ) + { + sr = &scs->SubClassRule[k]; + + if ( context_length != 0xFFFF && context_length < sr->GlyphCount ) + goto next_subclassrule; + + if ( buffer->in_pos + sr->GlyphCount > buffer->in_length ) + goto next_subclassrule; /* context is too long */ + + cl = sr->Class; + + /* Start at 1 because [0] is implied */ + + for ( i = 1, j = buffer->in_pos + 1; i < sr->GlyphCount; i++, j++ ) + { + while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) + { + if ( error && error != HB_Err_Not_Covered ) + goto End; + + if ( j + sr->GlyphCount - i < buffer->in_length ) + goto next_subclassrule; + j++; + } + + if ( i > known_classes ) + { + /* Keeps us from having to do this for each rule */ + + error = _HB_OPEN_Get_Class( &csf2->ClassDef, IN_GLYPH( j ), &classes[i], NULL ); + if ( error && error != HB_Err_Not_Covered ) + goto End; + known_classes = i; + } + + if ( cl[i - 1] != classes[i] ) + goto next_subclassrule; + } + + error = Do_ContextSubst( gsub, sr->GlyphCount, + sr->SubstCount, sr->SubstLookupRecord, + buffer, + nesting_level ); + goto End; + + next_subclassrule: + ; + } + + error = HB_Err_Not_Covered; + +End: + FREE( classes ); + return error; +} + + +static FT_Error Lookup_ContextSubst3( HB_GSUBHeader* gsub, + HB_ContextSubstFormat3* csf3, + HB_Buffer buffer, + FT_UShort flags, + FT_UShort context_length, + int nesting_level ) +{ + FT_Error error; + FT_UShort index, i, j, property; + + HB_Coverage* c; + HB_GDEFHeader* gdef; + + + gdef = gsub->gdef; + + if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) ) + return error; + + if ( context_length != 0xFFFF && context_length < csf3->GlyphCount ) + return HB_Err_Not_Covered; + + if ( buffer->in_pos + csf3->GlyphCount > buffer->in_length ) + return HB_Err_Not_Covered; /* context is too long */ + + c = csf3->Coverage; + + for ( i = 1, j = buffer->in_pos + 1; i < csf3->GlyphCount; i++, j++ ) + { + while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) + { + if ( error && error != HB_Err_Not_Covered ) + return error; + + if ( j + csf3->GlyphCount - i == buffer->in_length ) + return HB_Err_Not_Covered; + j++; + } + + error = _HB_OPEN_Coverage_Index( &c[i], IN_GLYPH( j ), &index ); + if ( error ) + return error; + } + + return Do_ContextSubst( gsub, csf3->GlyphCount, + csf3->SubstCount, csf3->SubstLookupRecord, + buffer, + nesting_level ); +} + + +static FT_Error Lookup_ContextSubst( HB_GSUBHeader* gsub, + HB_GSUB_SubTable* st, + HB_Buffer buffer, + FT_UShort flags, + FT_UShort context_length, + int nesting_level ) +{ + HB_ContextSubst* cs = &st->context; + + switch ( cs->SubstFormat ) + { + case 1: + return Lookup_ContextSubst1( gsub, &cs->csf.csf1, buffer, + flags, context_length, nesting_level ); + + case 2: + return Lookup_ContextSubst2( gsub, &cs->csf.csf2, buffer, + flags, context_length, nesting_level ); + + case 3: + return Lookup_ContextSubst3( gsub, &cs->csf.csf3, buffer, + flags, context_length, nesting_level ); + + default: + return HB_Err_Invalid_GSUB_SubTable_Format; + } + + return FT_Err_Ok; /* never reached */ +} + + +/* LookupType 6 */ + +/* ChainSubRule */ + +static FT_Error Load_ChainSubRule( HB_ChainSubRule* csr, + FT_Stream stream ) +{ + FT_Error error; + FT_Memory memory = stream->memory; + + FT_UShort n, count; + FT_UShort* b; + FT_UShort* i; + FT_UShort* l; + + HB_SubstLookupRecord* slr; + + + if ( ACCESS_Frame( 2L ) ) + return error; + + csr->BacktrackGlyphCount = GET_UShort(); + + FORGET_Frame(); + + csr->Backtrack = NULL; + + count = csr->BacktrackGlyphCount; + + if ( ALLOC_ARRAY( csr->Backtrack, count, FT_UShort ) ) + return error; + + b = csr->Backtrack; + + if ( ACCESS_Frame( count * 2L ) ) + goto Fail4; + + for ( n = 0; n < count; n++ ) + b[n] = GET_UShort(); + + FORGET_Frame(); + + if ( ACCESS_Frame( 2L ) ) + goto Fail4; + + csr->InputGlyphCount = GET_UShort(); + + FORGET_Frame(); + + csr->Input = NULL; + + count = csr->InputGlyphCount - 1; /* only InputGlyphCount - 1 elements */ + + if ( ALLOC_ARRAY( csr->Input, count, FT_UShort ) ) + goto Fail4; + + i = csr->Input; + + if ( ACCESS_Frame( count * 2L ) ) + goto Fail3; + + for ( n = 0; n < count; n++ ) + i[n] = GET_UShort(); + + FORGET_Frame(); + + if ( ACCESS_Frame( 2L ) ) + goto Fail3; + + csr->LookaheadGlyphCount = GET_UShort(); + + FORGET_Frame(); + + csr->Lookahead = NULL; + + count = csr->LookaheadGlyphCount; + + if ( ALLOC_ARRAY( csr->Lookahead, count, FT_UShort ) ) + goto Fail3; + + l = csr->Lookahead; + + if ( ACCESS_Frame( count * 2L ) ) + goto Fail2; + + for ( n = 0; n < count; n++ ) + l[n] = GET_UShort(); + + FORGET_Frame(); + + if ( ACCESS_Frame( 2L ) ) + goto Fail2; + + csr->SubstCount = GET_UShort(); + + FORGET_Frame(); + + csr->SubstLookupRecord = NULL; + + count = csr->SubstCount; + + if ( ALLOC_ARRAY( csr->SubstLookupRecord, count, HB_SubstLookupRecord ) ) + goto Fail2; + + slr = csr->SubstLookupRecord; + + if ( ACCESS_Frame( count * 4L ) ) + goto Fail1; + + for ( n = 0; n < count; n++ ) + { + slr[n].SequenceIndex = GET_UShort(); + slr[n].LookupListIndex = GET_UShort(); + } + + FORGET_Frame(); + + return FT_Err_Ok; + +Fail1: + FREE( slr ); + +Fail2: + FREE( l ); + +Fail3: + FREE( i ); + +Fail4: + FREE( b ); + return error; +} + + +static void Free_ChainSubRule( HB_ChainSubRule* csr, + FT_Memory memory ) +{ + FREE( csr->SubstLookupRecord ); + FREE( csr->Lookahead ); + FREE( csr->Input ); + FREE( csr->Backtrack ); +} + + +/* ChainSubRuleSet */ + +static FT_Error Load_ChainSubRuleSet( HB_ChainSubRuleSet* csrs, + FT_Stream stream ) +{ + FT_Error error; + FT_Memory memory = stream->memory; + + FT_UShort n = 0, m, count; + FT_ULong cur_offset, new_offset, base_offset; + + HB_ChainSubRule* csr; + + + base_offset = FILE_Pos(); + + if ( ACCESS_Frame( 2L ) ) + return error; + + count = csrs->ChainSubRuleCount = GET_UShort(); + + FORGET_Frame(); + + csrs->ChainSubRule = NULL; + + if ( ALLOC_ARRAY( csrs->ChainSubRule, count, HB_ChainSubRule ) ) + return error; + + csr = csrs->ChainSubRule; + + for ( n = 0; n < count; n++ ) + { + if ( ACCESS_Frame( 2L ) ) + goto Fail; + + new_offset = GET_UShort() + base_offset; + + FORGET_Frame(); + + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = Load_ChainSubRule( &csr[n], stream ) ) != FT_Err_Ok ) + goto Fail; + (void)FILE_Seek( cur_offset ); + } + + return FT_Err_Ok; + +Fail: + for ( m = 0; m < n; m++ ) + Free_ChainSubRule( &csr[m], memory ); + + FREE( csr ); + return error; +} + + +static void Free_ChainSubRuleSet( HB_ChainSubRuleSet* csrs, + FT_Memory memory ) +{ + FT_UShort n, count; + + HB_ChainSubRule* csr; + + + if ( csrs->ChainSubRule ) + { + count = csrs->ChainSubRuleCount; + csr = csrs->ChainSubRule; + + for ( n = 0; n < count; n++ ) + Free_ChainSubRule( &csr[n], memory ); + + FREE( csr ); + } +} + + +/* ChainContextSubstFormat1 */ + +static FT_Error Load_ChainContextSubst1( + HB_ChainContextSubstFormat1* ccsf1, + FT_Stream stream ) +{ + FT_Error error; + FT_Memory memory = stream->memory; + + FT_UShort n = 0, m, count; + FT_ULong cur_offset, new_offset, base_offset; + + HB_ChainSubRuleSet* csrs; + + + base_offset = FILE_Pos() - 2L; + + if ( ACCESS_Frame( 2L ) ) + return error; + + new_offset = GET_UShort() + base_offset; + + FORGET_Frame(); + + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = _HB_OPEN_Load_Coverage( &ccsf1->Coverage, stream ) ) != FT_Err_Ok ) + return error; + (void)FILE_Seek( cur_offset ); + + if ( ACCESS_Frame( 2L ) ) + goto Fail2; + + count = ccsf1->ChainSubRuleSetCount = GET_UShort(); + + FORGET_Frame(); + + ccsf1->ChainSubRuleSet = NULL; + + if ( ALLOC_ARRAY( ccsf1->ChainSubRuleSet, count, HB_ChainSubRuleSet ) ) + goto Fail2; + + csrs = ccsf1->ChainSubRuleSet; + + for ( n = 0; n < count; n++ ) + { + if ( ACCESS_Frame( 2L ) ) + goto Fail1; + + new_offset = GET_UShort() + base_offset; + + FORGET_Frame(); + + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = Load_ChainSubRuleSet( &csrs[n], stream ) ) != FT_Err_Ok ) + goto Fail1; + (void)FILE_Seek( cur_offset ); + } + + return FT_Err_Ok; + +Fail1: + for ( m = 0; m < n; m++ ) + Free_ChainSubRuleSet( &csrs[m], memory ); + + FREE( csrs ); + +Fail2: + _HB_OPEN_Free_Coverage( &ccsf1->Coverage, memory ); + return error; +} + + +static void Free_ChainContextSubst1( HB_ChainContextSubstFormat1* ccsf1, + FT_Memory memory ) +{ + FT_UShort n, count; + + HB_ChainSubRuleSet* csrs; + + + if ( ccsf1->ChainSubRuleSet ) + { + count = ccsf1->ChainSubRuleSetCount; + csrs = ccsf1->ChainSubRuleSet; + + for ( n = 0; n < count; n++ ) + Free_ChainSubRuleSet( &csrs[n], memory ); + + FREE( csrs ); + } + + _HB_OPEN_Free_Coverage( &ccsf1->Coverage, memory ); +} + + +/* ChainSubClassRule */ + +static FT_Error Load_ChainSubClassRule( + HB_ChainContextSubstFormat2* ccsf2, + HB_ChainSubClassRule* cscr, + FT_Stream stream ) +{ + FT_Error error; + FT_Memory memory = stream->memory; + + FT_UShort n, count; + + FT_UShort* b; + FT_UShort* i; + FT_UShort* l; + HB_SubstLookupRecord* slr; + FT_Bool* d; + + + if ( ACCESS_Frame( 2L ) ) + return error; + + cscr->BacktrackGlyphCount = GET_UShort(); + + FORGET_Frame(); + + if ( cscr->BacktrackGlyphCount > ccsf2->MaxBacktrackLength ) + ccsf2->MaxBacktrackLength = cscr->BacktrackGlyphCount; + + cscr->Backtrack = NULL; + + count = cscr->BacktrackGlyphCount; + + if ( ALLOC_ARRAY( cscr->Backtrack, count, FT_UShort ) ) + return error; + + b = cscr->Backtrack; + d = ccsf2->BacktrackClassDef.Defined; + + if ( ACCESS_Frame( count * 2L ) ) + goto Fail4; + + for ( n = 0; n < count; n++ ) + { + b[n] = GET_UShort(); + + /* We check whether the specific class is used at all. If not, + class 0 is used instead. */ + + if ( !d[b[n]] ) + b[n] = 0; + } + + FORGET_Frame(); + + if ( ACCESS_Frame( 2L ) ) + goto Fail4; + + cscr->InputGlyphCount = GET_UShort(); + + FORGET_Frame(); + + if ( cscr->InputGlyphCount > ccsf2->MaxInputLength ) + ccsf2->MaxInputLength = cscr->InputGlyphCount; + + cscr->Input = NULL; + + count = cscr->InputGlyphCount - 1; /* only InputGlyphCount - 1 elements */ + + if ( ALLOC_ARRAY( cscr->Input, count, FT_UShort ) ) + goto Fail4; + + i = cscr->Input; + d = ccsf2->InputClassDef.Defined; + + if ( ACCESS_Frame( count * 2L ) ) + goto Fail3; + + for ( n = 0; n < count; n++ ) + { + i[n] = GET_UShort(); + + if ( !d[i[n]] ) + i[n] = 0; + } + + FORGET_Frame(); + + if ( ACCESS_Frame( 2L ) ) + goto Fail3; + + cscr->LookaheadGlyphCount = GET_UShort(); + + FORGET_Frame(); + + if ( cscr->LookaheadGlyphCount > ccsf2->MaxLookaheadLength ) + ccsf2->MaxLookaheadLength = cscr->LookaheadGlyphCount; + + cscr->Lookahead = NULL; + + count = cscr->LookaheadGlyphCount; + + if ( ALLOC_ARRAY( cscr->Lookahead, count, FT_UShort ) ) + goto Fail3; + + l = cscr->Lookahead; + d = ccsf2->LookaheadClassDef.Defined; + + if ( ACCESS_Frame( count * 2L ) ) + goto Fail2; + + for ( n = 0; n < count; n++ ) + { + l[n] = GET_UShort(); + + if ( !d[l[n]] ) + l[n] = 0; + } + + FORGET_Frame(); + + if ( ACCESS_Frame( 2L ) ) + goto Fail2; + + cscr->SubstCount = GET_UShort(); + + FORGET_Frame(); + + cscr->SubstLookupRecord = NULL; + + count = cscr->SubstCount; + + if ( ALLOC_ARRAY( cscr->SubstLookupRecord, count, + HB_SubstLookupRecord ) ) + goto Fail2; + + slr = cscr->SubstLookupRecord; + + if ( ACCESS_Frame( count * 4L ) ) + goto Fail1; + + for ( n = 0; n < count; n++ ) + { + slr[n].SequenceIndex = GET_UShort(); + slr[n].LookupListIndex = GET_UShort(); + } + + FORGET_Frame(); + + return FT_Err_Ok; + +Fail1: + FREE( slr ); + +Fail2: + FREE( l ); + +Fail3: + FREE( i ); + +Fail4: + FREE( b ); + return error; +} + + +static void Free_ChainSubClassRule( HB_ChainSubClassRule* cscr, + FT_Memory memory ) +{ + FREE( cscr->SubstLookupRecord ); + FREE( cscr->Lookahead ); + FREE( cscr->Input ); + FREE( cscr->Backtrack ); +} + + +/* SubClassSet */ + +static FT_Error Load_ChainSubClassSet( + HB_ChainContextSubstFormat2* ccsf2, + HB_ChainSubClassSet* cscs, + FT_Stream stream ) +{ + FT_Error error; + FT_Memory memory = stream->memory; + + FT_UShort n = 0, m, count; + FT_ULong cur_offset, new_offset, base_offset; + + HB_ChainSubClassRule* cscr; + + + base_offset = FILE_Pos(); + + if ( ACCESS_Frame( 2L ) ) + return error; + + count = cscs->ChainSubClassRuleCount = GET_UShort(); + + FORGET_Frame(); + + cscs->ChainSubClassRule = NULL; + + if ( ALLOC_ARRAY( cscs->ChainSubClassRule, count, + HB_ChainSubClassRule ) ) + return error; + + cscr = cscs->ChainSubClassRule; + + for ( n = 0; n < count; n++ ) + { + if ( ACCESS_Frame( 2L ) ) + goto Fail; + + new_offset = GET_UShort() + base_offset; + + FORGET_Frame(); + + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = Load_ChainSubClassRule( ccsf2, &cscr[n], + stream ) ) != FT_Err_Ok ) + goto Fail; + (void)FILE_Seek( cur_offset ); + } + + return FT_Err_Ok; + +Fail: + for ( m = 0; m < n; m++ ) + Free_ChainSubClassRule( &cscr[m], memory ); + + FREE( cscr ); + return error; +} + + +static void Free_ChainSubClassSet( HB_ChainSubClassSet* cscs, + FT_Memory memory ) +{ + FT_UShort n, count; + + HB_ChainSubClassRule* cscr; + + + if ( cscs->ChainSubClassRule ) + { + count = cscs->ChainSubClassRuleCount; + cscr = cscs->ChainSubClassRule; + + for ( n = 0; n < count; n++ ) + Free_ChainSubClassRule( &cscr[n], memory ); + + FREE( cscr ); + } +} + +static FT_Error GSUB_Load_EmptyOrClassDefinition( HB_ClassDefinition* cd, + FT_UShort limit, + FT_ULong class_offset, + FT_ULong base_offset, + FT_Stream stream ) +{ + FT_Error error; + FT_ULong cur_offset; + + cur_offset = FILE_Pos(); + + if ( class_offset ) + { + if ( !FILE_Seek( class_offset + base_offset ) ) + error = _HB_OPEN_Load_ClassDefinition( cd, limit, stream ); + } + else + error = _HB_OPEN_Load_EmptyClassDefinition ( cd, stream ); + + if (error == FT_Err_Ok) + (void)FILE_Seek( cur_offset ); /* Changes error as a side-effect */ + + return error; +} + + +/* ChainContextSubstFormat2 */ + +static FT_Error Load_ChainContextSubst2( + HB_ChainContextSubstFormat2* ccsf2, + FT_Stream stream ) +{ + FT_Error error; + FT_Memory memory = stream->memory; + + FT_UShort n = 0, m, count; + FT_ULong cur_offset, new_offset, base_offset; + FT_ULong backtrack_offset, input_offset, lookahead_offset; + + HB_ChainSubClassSet* cscs; + + + base_offset = FILE_Pos() - 2; + + if ( ACCESS_Frame( 2L ) ) + return error; + + new_offset = GET_UShort() + base_offset; + + FORGET_Frame(); + + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = _HB_OPEN_Load_Coverage( &ccsf2->Coverage, stream ) ) != FT_Err_Ok ) + return error; + (void)FILE_Seek( cur_offset ); + + if ( ACCESS_Frame( 8L ) ) + goto Fail5; + + backtrack_offset = GET_UShort(); + input_offset = GET_UShort(); + lookahead_offset = GET_UShort(); + + /* `ChainSubClassSetCount' is the upper limit for input class values, + thus we read it now to make an additional safety check. No limit + is known or needed for the other two class definitions */ + + count = ccsf2->ChainSubClassSetCount = GET_UShort(); + + FORGET_Frame(); + + if ( ( error = GSUB_Load_EmptyOrClassDefinition( &ccsf2->BacktrackClassDef, 65535, + backtrack_offset, base_offset, + stream ) ) != FT_Err_Ok ) + goto Fail5; + + if ( ( error = GSUB_Load_EmptyOrClassDefinition( &ccsf2->InputClassDef, count, + input_offset, base_offset, + stream ) ) != FT_Err_Ok ) + goto Fail4; + if ( ( error = GSUB_Load_EmptyOrClassDefinition( &ccsf2->LookaheadClassDef, 65535, + lookahead_offset, base_offset, + stream ) ) != FT_Err_Ok ) + goto Fail3; + + ccsf2->ChainSubClassSet = NULL; + ccsf2->MaxBacktrackLength = 0; + ccsf2->MaxInputLength = 0; + ccsf2->MaxLookaheadLength = 0; + + if ( ALLOC_ARRAY( ccsf2->ChainSubClassSet, count, HB_ChainSubClassSet ) ) + goto Fail2; + + cscs = ccsf2->ChainSubClassSet; + + for ( n = 0; n < count; n++ ) + { + if ( ACCESS_Frame( 2L ) ) + goto Fail1; + + new_offset = GET_UShort() + base_offset; + + FORGET_Frame(); + + if ( new_offset != base_offset ) /* not a NULL offset */ + { + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = Load_ChainSubClassSet( ccsf2, &cscs[n], + stream ) ) != FT_Err_Ok ) + goto Fail1; + (void)FILE_Seek( cur_offset ); + } + else + { + /* we create a ChainSubClassSet table with no entries */ + + ccsf2->ChainSubClassSet[n].ChainSubClassRuleCount = 0; + ccsf2->ChainSubClassSet[n].ChainSubClassRule = NULL; + } + } + + return FT_Err_Ok; + +Fail1: + for ( m = 0; m < n; m++ ) + Free_ChainSubClassSet( &cscs[m], memory ); + + FREE( cscs ); + +Fail2: + _HB_OPEN_Free_ClassDefinition( &ccsf2->LookaheadClassDef, memory ); + +Fail3: + _HB_OPEN_Free_ClassDefinition( &ccsf2->InputClassDef, memory ); + +Fail4: + _HB_OPEN_Free_ClassDefinition( &ccsf2->BacktrackClassDef, memory ); + +Fail5: + _HB_OPEN_Free_Coverage( &ccsf2->Coverage, memory ); + return error; +} + + +static void Free_ChainContextSubst2( HB_ChainContextSubstFormat2* ccsf2, + FT_Memory memory ) +{ + FT_UShort n, count; + + HB_ChainSubClassSet* cscs; + + + if ( ccsf2->ChainSubClassSet ) + { + count = ccsf2->ChainSubClassSetCount; + cscs = ccsf2->ChainSubClassSet; + + for ( n = 0; n < count; n++ ) + Free_ChainSubClassSet( &cscs[n], memory ); + + FREE( cscs ); + } + + _HB_OPEN_Free_ClassDefinition( &ccsf2->LookaheadClassDef, memory ); + _HB_OPEN_Free_ClassDefinition( &ccsf2->InputClassDef, memory ); + _HB_OPEN_Free_ClassDefinition( &ccsf2->BacktrackClassDef, memory ); + + _HB_OPEN_Free_Coverage( &ccsf2->Coverage, memory ); +} + + +/* ChainContextSubstFormat3 */ + +static FT_Error Load_ChainContextSubst3( + HB_ChainContextSubstFormat3* ccsf3, + FT_Stream stream ) +{ + FT_Error error; + FT_Memory memory = stream->memory; + + FT_UShort n, nb = 0, ni =0, nl = 0, m, count; + FT_UShort backtrack_count, input_count, lookahead_count; + FT_ULong cur_offset, new_offset, base_offset; + + HB_Coverage* b; + HB_Coverage* i; + HB_Coverage* l; + HB_SubstLookupRecord* slr; + + + base_offset = FILE_Pos() - 2L; + + if ( ACCESS_Frame( 2L ) ) + return error; + + ccsf3->BacktrackGlyphCount = GET_UShort(); + + FORGET_Frame(); + + ccsf3->BacktrackCoverage = NULL; + + backtrack_count = ccsf3->BacktrackGlyphCount; + + if ( ALLOC_ARRAY( ccsf3->BacktrackCoverage, backtrack_count, + HB_Coverage ) ) + return error; + + b = ccsf3->BacktrackCoverage; + + for ( nb = 0; nb < backtrack_count; nb++ ) + { + if ( ACCESS_Frame( 2L ) ) + goto Fail4; + + new_offset = GET_UShort() + base_offset; + + FORGET_Frame(); + + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = _HB_OPEN_Load_Coverage( &b[nb], stream ) ) != FT_Err_Ok ) + goto Fail4; + (void)FILE_Seek( cur_offset ); + } + + if ( ACCESS_Frame( 2L ) ) + goto Fail4; + + ccsf3->InputGlyphCount = GET_UShort(); + + FORGET_Frame(); + + ccsf3->InputCoverage = NULL; + + input_count = ccsf3->InputGlyphCount; + + if ( ALLOC_ARRAY( ccsf3->InputCoverage, input_count, HB_Coverage ) ) + goto Fail4; + + i = ccsf3->InputCoverage; + + for ( ni = 0; ni < input_count; ni++ ) + { + if ( ACCESS_Frame( 2L ) ) + goto Fail3; + + new_offset = GET_UShort() + base_offset; + + FORGET_Frame(); + + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = _HB_OPEN_Load_Coverage( &i[ni], stream ) ) != FT_Err_Ok ) + goto Fail3; + (void)FILE_Seek( cur_offset ); + } + + if ( ACCESS_Frame( 2L ) ) + goto Fail3; + + ccsf3->LookaheadGlyphCount = GET_UShort(); + + FORGET_Frame(); + + ccsf3->LookaheadCoverage = NULL; + + lookahead_count = ccsf3->LookaheadGlyphCount; + + if ( ALLOC_ARRAY( ccsf3->LookaheadCoverage, lookahead_count, + HB_Coverage ) ) + goto Fail3; + + l = ccsf3->LookaheadCoverage; + + for ( nl = 0; nl < lookahead_count; nl++ ) + { + if ( ACCESS_Frame( 2L ) ) + goto Fail2; + + new_offset = GET_UShort() + base_offset; + + FORGET_Frame(); + + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = _HB_OPEN_Load_Coverage( &l[nl], stream ) ) != FT_Err_Ok ) + goto Fail2; + (void)FILE_Seek( cur_offset ); + } + + if ( ACCESS_Frame( 2L ) ) + goto Fail2; + + ccsf3->SubstCount = GET_UShort(); + + FORGET_Frame(); + + ccsf3->SubstLookupRecord = NULL; + + count = ccsf3->SubstCount; + + if ( ALLOC_ARRAY( ccsf3->SubstLookupRecord, count, + HB_SubstLookupRecord ) ) + goto Fail2; + + slr = ccsf3->SubstLookupRecord; + + if ( ACCESS_Frame( count * 4L ) ) + goto Fail1; + + for ( n = 0; n < count; n++ ) + { + slr[n].SequenceIndex = GET_UShort(); + slr[n].LookupListIndex = GET_UShort(); + } + + FORGET_Frame(); + + return FT_Err_Ok; + +Fail1: + FREE( slr ); + +Fail2: + for ( m = 0; m < nl; m++ ) + _HB_OPEN_Free_Coverage( &l[m], memory ); + + FREE( l ); + +Fail3: + for ( m = 0; m < ni; m++ ) + _HB_OPEN_Free_Coverage( &i[m], memory ); + + FREE( i ); + +Fail4: + for ( m = 0; m < nb; m++ ) + _HB_OPEN_Free_Coverage( &b[m], memory ); + + FREE( b ); + return error; +} + + +static void Free_ChainContextSubst3( HB_ChainContextSubstFormat3* ccsf3, + FT_Memory memory ) +{ + FT_UShort n, count; + + HB_Coverage* c; + + + FREE( ccsf3->SubstLookupRecord ); + + if ( ccsf3->LookaheadCoverage ) + { + count = ccsf3->LookaheadGlyphCount; + c = ccsf3->LookaheadCoverage; + + for ( n = 0; n < count; n++ ) + _HB_OPEN_Free_Coverage( &c[n], memory ); + + FREE( c ); + } + + if ( ccsf3->InputCoverage ) + { + count = ccsf3->InputGlyphCount; + c = ccsf3->InputCoverage; + + for ( n = 0; n < count; n++ ) + _HB_OPEN_Free_Coverage( &c[n], memory ); + + FREE( c ); + } + + if ( ccsf3->BacktrackCoverage ) + { + count = ccsf3->BacktrackGlyphCount; + c = ccsf3->BacktrackCoverage; + + for ( n = 0; n < count; n++ ) + _HB_OPEN_Free_Coverage( &c[n], memory ); + + FREE( c ); + } +} + + +/* ChainContextSubst */ + +static FT_Error Load_ChainContextSubst( HB_GSUB_SubTable* st, + FT_Stream stream ) +{ + FT_Error error; + HB_ChainContextSubst* ccs = &st->chain; + + if ( ACCESS_Frame( 2L ) ) + return error; + + ccs->SubstFormat = GET_UShort(); + + FORGET_Frame(); + + switch ( ccs->SubstFormat ) + { + case 1: + return Load_ChainContextSubst1( &ccs->ccsf.ccsf1, stream ); + + case 2: + return Load_ChainContextSubst2( &ccs->ccsf.ccsf2, stream ); + + case 3: + return Load_ChainContextSubst3( &ccs->ccsf.ccsf3, stream ); + + default: + return HB_Err_Invalid_GSUB_SubTable_Format; + } + + return FT_Err_Ok; /* never reached */ +} + + +static void Free_ChainContextSubst( HB_GSUB_SubTable* st, + FT_Memory memory ) +{ + HB_ChainContextSubst* ccs = &st->chain; + + switch ( ccs->SubstFormat ) + { + case 1: + Free_ChainContextSubst1( &ccs->ccsf.ccsf1, memory ); + break; + + case 2: + Free_ChainContextSubst2( &ccs->ccsf.ccsf2, memory ); + break; + + case 3: + Free_ChainContextSubst3( &ccs->ccsf.ccsf3, memory ); + break; + } +} + + +static FT_Error Lookup_ChainContextSubst1( HB_GSUBHeader* gsub, + HB_ChainContextSubstFormat1* ccsf1, + HB_Buffer buffer, + FT_UShort flags, + FT_UShort context_length, + int nesting_level ) +{ + FT_UShort index, property; + FT_UShort i, j, k, num_csr; + FT_UShort bgc, igc, lgc; + FT_Error error; + + HB_ChainSubRule* csr; + HB_ChainSubRule curr_csr; + HB_GDEFHeader* gdef; + + + gdef = gsub->gdef; + + if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) ) + return error; + + error = _HB_OPEN_Coverage_Index( &ccsf1->Coverage, IN_CURGLYPH(), &index ); + if ( error ) + return error; + + csr = ccsf1->ChainSubRuleSet[index].ChainSubRule; + num_csr = ccsf1->ChainSubRuleSet[index].ChainSubRuleCount; + + for ( k = 0; k < num_csr; k++ ) + { + curr_csr = csr[k]; + bgc = curr_csr.BacktrackGlyphCount; + igc = curr_csr.InputGlyphCount; + lgc = curr_csr.LookaheadGlyphCount; + + if ( context_length != 0xFFFF && context_length < igc ) + goto next_chainsubrule; + + /* check whether context is too long; it is a first guess only */ + + if ( bgc > buffer->out_pos || buffer->in_pos + igc + lgc > buffer->in_length ) + goto next_chainsubrule; + + if ( bgc ) + { + /* since we don't know in advance the number of glyphs to inspect, + we search backwards for matches in the backtrack glyph array */ + + for ( i = 0, j = buffer->out_pos - 1; i < bgc; i++, j-- ) + { + while ( CHECK_Property( gdef, OUT_ITEM( j ), flags, &property ) ) + { + if ( error && error != HB_Err_Not_Covered ) + return error; + + if ( j + 1 == bgc - i ) + goto next_chainsubrule; + j--; + } + + /* In OpenType 1.3, it is undefined whether the offsets of + backtrack glyphs is in logical order or not. Version 1.4 + will clarify this: + + Logical order - a b c d e f g h i j + i + Input offsets - 0 1 + Backtrack offsets - 3 2 1 0 + Lookahead offsets - 0 1 2 3 */ + + if ( OUT_GLYPH( j ) != curr_csr.Backtrack[i] ) + goto next_chainsubrule; + } + } + + /* Start at 1 because [0] is implied */ + + for ( i = 1, j = buffer->in_pos + 1; i < igc; i++, j++ ) + { + while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) + { + if ( error && error != HB_Err_Not_Covered ) + return error; + + if ( j + igc - i + lgc == buffer->in_length ) + goto next_chainsubrule; + j++; + } + + if ( IN_GLYPH( j ) != curr_csr.Input[i - 1] ) + goto next_chainsubrule; + } + + /* we are starting to check for lookahead glyphs right after the + last context glyph */ + + for ( i = 0; i < lgc; i++, j++ ) + { + while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) + { + if ( error && error != HB_Err_Not_Covered ) + return error; + + if ( j + lgc - i == buffer->in_length ) + goto next_chainsubrule; + j++; + } + + if ( IN_GLYPH( j ) != curr_csr.Lookahead[i] ) + goto next_chainsubrule; + } + + return Do_ContextSubst( gsub, igc, + curr_csr.SubstCount, + curr_csr.SubstLookupRecord, + buffer, + nesting_level ); + + next_chainsubrule: + ; + } + + return HB_Err_Not_Covered; +} + + +static FT_Error Lookup_ChainContextSubst2( HB_GSUBHeader* gsub, + HB_ChainContextSubstFormat2* ccsf2, + HB_Buffer buffer, + FT_UShort flags, + FT_UShort context_length, + int nesting_level ) +{ + FT_UShort index, property; + FT_Memory memory; + FT_Error error; + FT_UShort i, j, k; + FT_UShort bgc, igc, lgc; + FT_UShort known_backtrack_classes, + known_input_classes, + known_lookahead_classes; + + FT_UShort* backtrack_classes; + FT_UShort* input_classes; + FT_UShort* lookahead_classes; + + FT_UShort* bc; + FT_UShort* ic; + FT_UShort* lc; + + HB_ChainSubClassSet* cscs; + HB_ChainSubClassRule ccsr; + HB_GDEFHeader* gdef; + + + gdef = gsub->gdef; + memory = gsub->memory; + + if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) ) + return error; + + /* Note: The coverage table in format 2 doesn't give an index into + anything. It just lets us know whether or not we need to + do any lookup at all. */ + + error = _HB_OPEN_Coverage_Index( &ccsf2->Coverage, IN_CURGLYPH(), &index ); + if ( error ) + return error; + + if ( ALLOC_ARRAY( backtrack_classes, ccsf2->MaxBacktrackLength, FT_UShort ) ) + return error; + known_backtrack_classes = 0; + + if ( ALLOC_ARRAY( input_classes, ccsf2->MaxInputLength, FT_UShort ) ) + goto End3; + known_input_classes = 1; + + if ( ALLOC_ARRAY( lookahead_classes, ccsf2->MaxLookaheadLength, FT_UShort ) ) + goto End2; + known_lookahead_classes = 0; + + error = _HB_OPEN_Get_Class( &ccsf2->InputClassDef, IN_CURGLYPH(), + &input_classes[0], NULL ); + if ( error && error != HB_Err_Not_Covered ) + goto End1; + + cscs = &ccsf2->ChainSubClassSet[input_classes[0]]; + if ( !cscs ) + { + error = HB_Err_Invalid_GSUB_SubTable; + goto End1; + } + + for ( k = 0; k < cscs->ChainSubClassRuleCount; k++ ) + { + ccsr = cscs->ChainSubClassRule[k]; + bgc = ccsr.BacktrackGlyphCount; + igc = ccsr.InputGlyphCount; + lgc = ccsr.LookaheadGlyphCount; + + if ( context_length != 0xFFFF && context_length < igc ) + goto next_chainsubclassrule; + + /* check whether context is too long; it is a first guess only */ + + if ( bgc > buffer->out_pos || buffer->in_pos + igc + lgc > buffer->in_length ) + goto next_chainsubclassrule; + + if ( bgc ) + { + /* Since we don't know in advance the number of glyphs to inspect, + we search backwards for matches in the backtrack glyph array. + Note that `known_backtrack_classes' starts at index 0. */ + + bc = ccsr.Backtrack; + + for ( i = 0, j = buffer->out_pos - 1; i < bgc; i++, j-- ) + { + while ( CHECK_Property( gdef, OUT_ITEM( j ), flags, &property ) ) + { + if ( error && error != HB_Err_Not_Covered ) + goto End1; + + if ( j + 1 == bgc - i ) + goto next_chainsubclassrule; + j--; + } + + if ( i >= known_backtrack_classes ) + { + /* Keeps us from having to do this for each rule */ + + error = _HB_OPEN_Get_Class( &ccsf2->BacktrackClassDef, OUT_GLYPH( j ), + &backtrack_classes[i], NULL ); + if ( error && error != HB_Err_Not_Covered ) + goto End1; + known_backtrack_classes = i; + } + + if ( bc[i] != backtrack_classes[i] ) + goto next_chainsubclassrule; + } + } + + ic = ccsr.Input; + + /* Start at 1 because [0] is implied */ + + for ( i = 1, j = buffer->in_pos + 1; i < igc; i++, j++ ) + { + while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) + { + if ( error && error != HB_Err_Not_Covered ) + goto End1; + + if ( j + igc - i + lgc == buffer->in_length ) + goto next_chainsubclassrule; + j++; + } + + if ( i >= known_input_classes ) + { + error = _HB_OPEN_Get_Class( &ccsf2->InputClassDef, IN_GLYPH( j ), + &input_classes[i], NULL ); + if ( error && error != HB_Err_Not_Covered ) + goto End1; + known_input_classes = i; + } + + if ( ic[i - 1] != input_classes[i] ) + goto next_chainsubclassrule; + } + + /* we are starting to check for lookahead glyphs right after the + last context glyph */ + + lc = ccsr.Lookahead; + + for ( i = 0; i < lgc; i++, j++ ) + { + while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) + { + if ( error && error != HB_Err_Not_Covered ) + goto End1; + + if ( j + lgc - i == buffer->in_length ) + goto next_chainsubclassrule; + j++; + } + + if ( i >= known_lookahead_classes ) + { + error = _HB_OPEN_Get_Class( &ccsf2->LookaheadClassDef, IN_GLYPH( j ), + &lookahead_classes[i], NULL ); + if ( error && error != HB_Err_Not_Covered ) + goto End1; + known_lookahead_classes = i; + } + + if ( lc[i] != lookahead_classes[i] ) + goto next_chainsubclassrule; + } + + error = Do_ContextSubst( gsub, igc, + ccsr.SubstCount, + ccsr.SubstLookupRecord, + buffer, + nesting_level ); + goto End1; + + next_chainsubclassrule: + ; + } + + error = HB_Err_Not_Covered; + +End1: + FREE( lookahead_classes ); + +End2: + FREE( input_classes ); + +End3: + FREE( backtrack_classes ); + return error; +} + + +static FT_Error Lookup_ChainContextSubst3( HB_GSUBHeader* gsub, + HB_ChainContextSubstFormat3* ccsf3, + HB_Buffer buffer, + FT_UShort flags, + FT_UShort context_length, + int nesting_level ) +{ + FT_UShort index, i, j, property; + FT_UShort bgc, igc, lgc; + FT_Error error; + + HB_Coverage* bc; + HB_Coverage* ic; + HB_Coverage* lc; + HB_GDEFHeader* gdef; + + + gdef = gsub->gdef; + + if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) ) + return error; + + bgc = ccsf3->BacktrackGlyphCount; + igc = ccsf3->InputGlyphCount; + lgc = ccsf3->LookaheadGlyphCount; + + if ( context_length != 0xFFFF && context_length < igc ) + return HB_Err_Not_Covered; + + /* check whether context is too long; it is a first guess only */ + + if ( bgc > buffer->out_pos || buffer->in_pos + igc + lgc > buffer->in_length ) + return HB_Err_Not_Covered; + + if ( bgc ) + { + /* Since we don't know in advance the number of glyphs to inspect, + we search backwards for matches in the backtrack glyph array */ + + bc = ccsf3->BacktrackCoverage; + + for ( i = 0, j = buffer->out_pos - 1; i < bgc; i++, j-- ) + { + while ( CHECK_Property( gdef, OUT_ITEM( j ), flags, &property ) ) + { + if ( error && error != HB_Err_Not_Covered ) + return error; + + if ( j + 1 == bgc - i ) + return HB_Err_Not_Covered; + j--; + } + + error = _HB_OPEN_Coverage_Index( &bc[i], OUT_GLYPH( j ), &index ); + if ( error ) + return error; + } + } + + ic = ccsf3->InputCoverage; + + for ( i = 0, j = buffer->in_pos; i < igc; i++, j++ ) + { + /* We already called CHECK_Property for IN_GLYPH( buffer->in_pos ) */ + while ( j > buffer->in_pos && CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) + { + if ( error && error != HB_Err_Not_Covered ) + return error; + + if ( j + igc - i + lgc == buffer->in_length ) + return HB_Err_Not_Covered; + j++; + } + + error = _HB_OPEN_Coverage_Index( &ic[i], IN_GLYPH( j ), &index ); + if ( error ) + return error; + } + + /* we are starting for lookahead glyphs right after the last context + glyph */ + + lc = ccsf3->LookaheadCoverage; + + for ( i = 0; i < lgc; i++, j++ ) + { + while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) + { + if ( error && error != HB_Err_Not_Covered ) + return error; + + if ( j + lgc - i == buffer->in_length ) + return HB_Err_Not_Covered; + j++; + } + + error = _HB_OPEN_Coverage_Index( &lc[i], IN_GLYPH( j ), &index ); + if ( error ) + return error; + } + + return Do_ContextSubst( gsub, igc, + ccsf3->SubstCount, + ccsf3->SubstLookupRecord, + buffer, + nesting_level ); +} + + +static FT_Error Lookup_ChainContextSubst( HB_GSUBHeader* gsub, + HB_GSUB_SubTable* st, + HB_Buffer buffer, + FT_UShort flags, + FT_UShort context_length, + int nesting_level ) +{ + HB_ChainContextSubst* ccs = &st->chain; + + switch ( ccs->SubstFormat ) + { + case 1: + return Lookup_ChainContextSubst1( gsub, &ccs->ccsf.ccsf1, buffer, + flags, context_length, + nesting_level ); + + case 2: + return Lookup_ChainContextSubst2( gsub, &ccs->ccsf.ccsf2, buffer, + flags, context_length, + nesting_level ); + + case 3: + return Lookup_ChainContextSubst3( gsub, &ccs->ccsf.ccsf3, buffer, + flags, context_length, + nesting_level ); + + default: + return HB_Err_Invalid_GSUB_SubTable_Format; + } + + return FT_Err_Ok; /* never reached */ +} + + +static FT_Error Load_ReverseChainContextSubst( HB_GSUB_SubTable* st, + FT_Stream stream ) +{ + FT_Error error; + FT_Memory memory = stream->memory; + HB_ReverseChainContextSubst* rccs = &st->reverse; + + FT_UShort m, count; + + FT_UShort nb = 0, nl = 0, n; + FT_UShort backtrack_count, lookahead_count; + FT_ULong cur_offset, new_offset, base_offset; + + HB_Coverage* b; + HB_Coverage* l; + FT_UShort* sub; + + base_offset = FILE_Pos(); + + if ( ACCESS_Frame( 2L ) ) + return error; + + rccs->SubstFormat = GET_UShort(); + + if ( rccs->SubstFormat != 1 ) + return HB_Err_Invalid_GSUB_SubTable_Format; + + FORGET_Frame(); + + if ( ACCESS_Frame( 2L ) ) + return error; + + new_offset = GET_UShort() + base_offset; + + FORGET_Frame(); + + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = _HB_OPEN_Load_Coverage( &rccs->Coverage, stream ) ) != FT_Err_Ok ) + return error; + (void)FILE_Seek( cur_offset ); + + + if ( ACCESS_Frame( 2L ) ) + goto Fail4; + + rccs->BacktrackGlyphCount = GET_UShort(); + + FORGET_Frame(); + + rccs->BacktrackCoverage = NULL; + + backtrack_count = rccs->BacktrackGlyphCount; + + if ( ALLOC_ARRAY( rccs->BacktrackCoverage, backtrack_count, + HB_Coverage ) ) + goto Fail4; + + b = rccs->BacktrackCoverage; + + for ( nb = 0; nb < backtrack_count; nb++ ) + { + if ( ACCESS_Frame( 2L ) ) + goto Fail3; + + new_offset = GET_UShort() + base_offset; + + FORGET_Frame(); + + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = _HB_OPEN_Load_Coverage( &b[nb], stream ) ) != FT_Err_Ok ) + goto Fail3; + (void)FILE_Seek( cur_offset ); + } + + + if ( ACCESS_Frame( 2L ) ) + goto Fail3; + + rccs->LookaheadGlyphCount = GET_UShort(); + + FORGET_Frame(); + + rccs->LookaheadCoverage = NULL; + + lookahead_count = rccs->LookaheadGlyphCount; + + if ( ALLOC_ARRAY( rccs->LookaheadCoverage, lookahead_count, + HB_Coverage ) ) + goto Fail3; + + l = rccs->LookaheadCoverage; + + for ( nl = 0; nl < lookahead_count; nl++ ) + { + if ( ACCESS_Frame( 2L ) ) + goto Fail2; + + new_offset = GET_UShort() + base_offset; + + FORGET_Frame(); + + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = _HB_OPEN_Load_Coverage( &l[nl], stream ) ) != FT_Err_Ok ) + goto Fail2; + (void)FILE_Seek( cur_offset ); + } + + if ( ACCESS_Frame( 2L ) ) + goto Fail2; + + rccs->GlyphCount = GET_UShort(); + + FORGET_Frame(); + + rccs->Substitute = NULL; + + count = rccs->GlyphCount; + + if ( ALLOC_ARRAY( rccs->Substitute, count, + FT_UShort ) ) + goto Fail2; + + sub = rccs->Substitute; + + if ( ACCESS_Frame( count * 2L ) ) + goto Fail1; + + for ( n = 0; n < count; n++ ) + sub[n] = GET_UShort(); + + FORGET_Frame(); + + return FT_Err_Ok; + +Fail1: + FREE( sub ); + +Fail2: + for ( m = 0; m < nl; m++ ) + _HB_OPEN_Free_Coverage( &l[m], memory ); + + FREE( l ); + +Fail3: + for ( m = 0; m < nb; m++ ) + _HB_OPEN_Free_Coverage( &b[m], memory ); + + FREE( b ); + +Fail4: + _HB_OPEN_Free_Coverage( &rccs->Coverage, memory ); + return error; +} + + +static void Free_ReverseChainContextSubst( HB_GSUB_SubTable* st, + FT_Memory memory ) +{ + FT_UShort n, count; + HB_ReverseChainContextSubst* rccs = &st->reverse; + + HB_Coverage* c; + + _HB_OPEN_Free_Coverage( &rccs->Coverage, memory ); + + if ( rccs->LookaheadCoverage ) + { + count = rccs->LookaheadGlyphCount; + c = rccs->LookaheadCoverage; + + for ( n = 0; n < count; n++ ) + _HB_OPEN_Free_Coverage( &c[n], memory ); + + FREE( c ); + } + + if ( rccs->BacktrackCoverage ) + { + count = rccs->BacktrackGlyphCount; + c = rccs->BacktrackCoverage; + + for ( n = 0; n < count; n++ ) + _HB_OPEN_Free_Coverage( &c[n], memory ); + + FREE( c ); + } + + FREE ( rccs->Substitute ); +} + + +static FT_Error Lookup_ReverseChainContextSubst( HB_GSUBHeader* gsub, + HB_GSUB_SubTable* st, + HB_Buffer buffer, + FT_UShort flags, + /* note different signature here: */ FT_ULong string_index ) +{ + FT_UShort index, input_index, i, j, property; + FT_UShort bgc, lgc; + FT_Error error; + + HB_ReverseChainContextSubst* rccs = &st->reverse; + HB_Coverage* bc; + HB_Coverage* lc; + HB_GDEFHeader* gdef; + + gdef = gsub->gdef; + + if ( CHECK_Property( gdef, IN_ITEM( string_index ), flags, &property ) ) + return error; + + bgc = rccs->BacktrackGlyphCount; + lgc = rccs->LookaheadGlyphCount; + + /* check whether context is too long; it is a first guess only */ + + if ( bgc > string_index || string_index + 1 + lgc > buffer->in_length ) + return HB_Err_Not_Covered; + + if ( bgc ) + { + /* Since we don't know in advance the number of glyphs to inspect, + we search backwards for matches in the backtrack glyph array */ + + bc = rccs->BacktrackCoverage; + + for ( i = 0, j = string_index - 1; i < bgc; i++, j-- ) + { + while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) + { + if ( error && error != HB_Err_Not_Covered ) + return error; + + if ( j + 1 == bgc - i ) + return HB_Err_Not_Covered; + j--; + } + + error = _HB_OPEN_Coverage_Index( &bc[i], IN_GLYPH( j ), &index ); + if ( error ) + return error; + } + } + + j = string_index; + + error = _HB_OPEN_Coverage_Index( &rccs->Coverage, IN_GLYPH( j ), &input_index ); + if ( error ) + return error; + + /* we are starting for lookahead glyphs right after the last context + glyph */ + + j += 1; + + lc = rccs->LookaheadCoverage; + + for ( i = 0; i < lgc; i++, j++ ) + { + while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) + { + if ( error && error != HB_Err_Not_Covered ) + return error; + + if ( j + lgc - i == buffer->in_length ) + return HB_Err_Not_Covered; + j++; + } + + error = _HB_OPEN_Coverage_Index( &lc[i], IN_GLYPH( j ), &index ); + if ( error ) + return error; + } + + IN_GLYPH( string_index ) = rccs->Substitute[input_index]; + + return error; +} + + + +/*********** + * GSUB API + ***********/ + + + +FT_Error HB_GSUB_Select_Script( HB_GSUBHeader* gsub, + FT_ULong script_tag, + FT_UShort* script_index ) +{ + FT_UShort n; + + HB_ScriptList* sl; + HB_ScriptRecord* sr; + + + if ( !gsub || !script_index ) + return FT_Err_Invalid_Argument; + + sl = &gsub->ScriptList; + sr = sl->ScriptRecord; + + for ( n = 0; n < sl->ScriptCount; n++ ) + if ( script_tag == sr[n].ScriptTag ) + { + *script_index = n; + + return FT_Err_Ok; + } + + return HB_Err_Not_Covered; +} + + + +FT_Error HB_GSUB_Select_Language( HB_GSUBHeader* gsub, + FT_ULong language_tag, + FT_UShort script_index, + FT_UShort* language_index, + FT_UShort* req_feature_index ) +{ + FT_UShort n; + + HB_ScriptList* sl; + HB_ScriptRecord* sr; + HB_Script* s; + HB_LangSysRecord* lsr; + + + if ( !gsub || !language_index || !req_feature_index ) + return FT_Err_Invalid_Argument; + + sl = &gsub->ScriptList; + sr = sl->ScriptRecord; + + if ( script_index >= sl->ScriptCount ) + return FT_Err_Invalid_Argument; + + s = &sr[script_index].Script; + lsr = s->LangSysRecord; + + for ( n = 0; n < s->LangSysCount; n++ ) + if ( language_tag == lsr[n].LangSysTag ) + { + *language_index = n; + *req_feature_index = lsr[n].LangSys.ReqFeatureIndex; + + return FT_Err_Ok; + } + + return HB_Err_Not_Covered; +} + + +/* selecting 0xFFFF for language_index asks for the values of the + default language (DefaultLangSys) */ + + +FT_Error HB_GSUB_Select_Feature( HB_GSUBHeader* gsub, + FT_ULong feature_tag, + FT_UShort script_index, + FT_UShort language_index, + FT_UShort* feature_index ) +{ + FT_UShort n; + + HB_ScriptList* sl; + HB_ScriptRecord* sr; + HB_Script* s; + HB_LangSysRecord* lsr; + HB_LangSys* ls; + FT_UShort* fi; + + HB_FeatureList* fl; + HB_FeatureRecord* fr; + + + if ( !gsub || !feature_index ) + return FT_Err_Invalid_Argument; + + sl = &gsub->ScriptList; + sr = sl->ScriptRecord; + + fl = &gsub->FeatureList; + fr = fl->FeatureRecord; + + if ( script_index >= sl->ScriptCount ) + return FT_Err_Invalid_Argument; + + s = &sr[script_index].Script; + lsr = s->LangSysRecord; + + if ( language_index == 0xFFFF ) + ls = &s->DefaultLangSys; + else + { + if ( language_index >= s->LangSysCount ) + return FT_Err_Invalid_Argument; + + ls = &lsr[language_index].LangSys; + } + + fi = ls->FeatureIndex; + + for ( n = 0; n < ls->FeatureCount; n++ ) + { + if ( fi[n] >= fl->FeatureCount ) + return HB_Err_Invalid_GSUB_SubTable_Format; + + if ( feature_tag == fr[fi[n]].FeatureTag ) + { + *feature_index = fi[n]; + + return FT_Err_Ok; + } + } + + return HB_Err_Not_Covered; +} + + +/* The next three functions return a null-terminated list */ + + +FT_Error HB_GSUB_Query_Scripts( HB_GSUBHeader* gsub, + FT_ULong** script_tag_list ) +{ + FT_UShort n; + FT_Error error; + FT_Memory memory; + FT_ULong* stl; + + HB_ScriptList* sl; + HB_ScriptRecord* sr; + + + if ( !gsub || !script_tag_list ) + return FT_Err_Invalid_Argument; + + memory = gsub->memory; + + sl = &gsub->ScriptList; + sr = sl->ScriptRecord; + + if ( ALLOC_ARRAY( stl, sl->ScriptCount + 1, FT_ULong ) ) + return error; + + for ( n = 0; n < sl->ScriptCount; n++ ) + stl[n] = sr[n].ScriptTag; + stl[n] = 0; + + *script_tag_list = stl; + + return FT_Err_Ok; +} + + + +FT_Error HB_GSUB_Query_Languages( HB_GSUBHeader* gsub, + FT_UShort script_index, + FT_ULong** language_tag_list ) +{ + FT_UShort n; + FT_Error error; + FT_Memory memory; + FT_ULong* ltl; + + HB_ScriptList* sl; + HB_ScriptRecord* sr; + HB_Script* s; + HB_LangSysRecord* lsr; + + + if ( !gsub || !language_tag_list ) + return FT_Err_Invalid_Argument; + + memory = gsub->memory; + + sl = &gsub->ScriptList; + sr = sl->ScriptRecord; + + if ( script_index >= sl->ScriptCount ) + return FT_Err_Invalid_Argument; + + s = &sr[script_index].Script; + lsr = s->LangSysRecord; + + if ( ALLOC_ARRAY( ltl, s->LangSysCount + 1, FT_ULong ) ) + return error; + + for ( n = 0; n < s->LangSysCount; n++ ) + ltl[n] = lsr[n].LangSysTag; + ltl[n] = 0; + + *language_tag_list = ltl; + + return FT_Err_Ok; +} + + +/* selecting 0xFFFF for language_index asks for the values of the + default language (DefaultLangSys) */ + + +FT_Error HB_GSUB_Query_Features( HB_GSUBHeader* gsub, + FT_UShort script_index, + FT_UShort language_index, + FT_ULong** feature_tag_list ) +{ + FT_UShort n; + FT_Error error; + FT_Memory memory; + FT_ULong* ftl; + + HB_ScriptList* sl; + HB_ScriptRecord* sr; + HB_Script* s; + HB_LangSysRecord* lsr; + HB_LangSys* ls; + FT_UShort* fi; + + HB_FeatureList* fl; + HB_FeatureRecord* fr; + + + if ( !gsub || !feature_tag_list ) + return FT_Err_Invalid_Argument; + + memory = gsub->memory; + + sl = &gsub->ScriptList; + sr = sl->ScriptRecord; + + fl = &gsub->FeatureList; + fr = fl->FeatureRecord; + + if ( script_index >= sl->ScriptCount ) + return FT_Err_Invalid_Argument; + + s = &sr[script_index].Script; + lsr = s->LangSysRecord; + + if ( language_index == 0xFFFF ) + ls = &s->DefaultLangSys; + else + { + if ( language_index >= s->LangSysCount ) + return FT_Err_Invalid_Argument; + + ls = &lsr[language_index].LangSys; + } + + fi = ls->FeatureIndex; + + if ( ALLOC_ARRAY( ftl, ls->FeatureCount + 1, FT_ULong ) ) + return error; + + for ( n = 0; n < ls->FeatureCount; n++ ) + { + if ( fi[n] >= fl->FeatureCount ) + { + FREE( ftl ); + return HB_Err_Invalid_GSUB_SubTable_Format; + } + ftl[n] = fr[fi[n]].FeatureTag; + } + ftl[n] = 0; + + *feature_tag_list = ftl; + + return FT_Err_Ok; +} + + +typedef FT_Error (*Lookup_Subst_Func_Type)( HB_GSUBHeader* gsub, + HB_GSUB_SubTable* st, + HB_Buffer buffer, + FT_UShort flags, + FT_UShort context_length, + int nesting_level ); +static const Lookup_Subst_Func_Type Lookup_Subst_Call_Table[] = { + Lookup_DefaultSubst, + Lookup_SingleSubst, /* HB_GSUB_LOOKUP_SINGLE 1 */ + Lookup_MultipleSubst, /* HB_GSUB_LOOKUP_MULTIPLE 2 */ + Lookup_AlternateSubst, /* HB_GSUB_LOOKUP_ALTERNATE 3 */ + Lookup_LigatureSubst, /* HB_GSUB_LOOKUP_LIGATURE 4 */ + Lookup_ContextSubst, /* HB_GSUB_LOOKUP_CONTEXT 5 */ + Lookup_ChainContextSubst, /* HB_GSUB_LOOKUP_CHAIN 6 */ + Lookup_DefaultSubst /* HB_GSUB_LOOKUP_EXTENSION 7 */ +}; +/* Note that the following lookup does not belong to the table above: + * Lookup_ReverseChainContextSubst, HB_GSUB_LOOKUP_REVERSE_CHAIN 8 + * because it's invalid to happen where this table is used. It's + * signature is different too... + */ + +/* Do an individual subtable lookup. Returns FT_Err_Ok if substitution + has been done, or HB_Err_Not_Covered if not. */ +static FT_Error GSUB_Do_Glyph_Lookup( HB_GSUBHeader* gsub, + FT_UShort lookup_index, + HB_Buffer buffer, + FT_UShort context_length, + int nesting_level ) +{ + FT_Error error = HB_Err_Not_Covered; + FT_UShort i, flags, lookup_count; + HB_Lookup* lo; + int lookup_type; + Lookup_Subst_Func_Type Func; + + + nesting_level++; + + if ( nesting_level > HB_MAX_NESTING_LEVEL ) + return HB_Err_Too_Many_Nested_Contexts; + + lookup_count = gsub->LookupList.LookupCount; + if (lookup_index >= lookup_count) + return error; + + lo = &gsub->LookupList.Lookup[lookup_index]; + flags = lo->LookupFlag; + lookup_type = lo->LookupType; + + if (lookup_type >= ARRAY_LEN (Lookup_Subst_Call_Table)) + lookup_type = 0; + Func = Lookup_Subst_Call_Table[lookup_type]; + + for ( i = 0; i < lo->SubTableCount; i++ ) + { + error = Func ( gsub, + &lo->SubTable[i].st.gsub, + buffer, + flags, context_length, + nesting_level ); + + /* Check whether we have a successful substitution or an error other + than HB_Err_Not_Covered */ + + if ( error != HB_Err_Not_Covered ) + return error; + } + + return HB_Err_Not_Covered; +} + + +static FT_Error Load_DefaultSubst( HB_GSUB_SubTable* st, + FT_Stream stream ) +{ + return HB_Err_Invalid_GSUB_SubTable_Format; +} + +typedef FT_Error (*Load_Subst_Func_Type)( HB_GSUB_SubTable* st, + FT_Stream stream ); +static const Load_Subst_Func_Type Load_Subst_Call_Table[] = { + Load_DefaultSubst, + Load_SingleSubst, /* HB_GSUB_LOOKUP_SINGLE 1 */ + Load_MultipleSubst, /* HB_GSUB_LOOKUP_MULTIPLE 2 */ + Load_AlternateSubst, /* HB_GSUB_LOOKUP_ALTERNATE 3 */ + Load_LigatureSubst, /* HB_GSUB_LOOKUP_LIGATURE 4 */ + Load_ContextSubst, /* HB_GSUB_LOOKUP_CONTEXT 5 */ + Load_ChainContextSubst, /* HB_GSUB_LOOKUP_CHAIN 6 */ + Load_DefaultSubst, /* HB_GSUB_LOOKUP_EXTENSION 7 */ + Load_ReverseChainContextSubst /* HB_GSUB_LOOKUP_REVERSE_CHAIN 8 */ +}; + +FT_Error _HB_GSUB_Load_SubTable( HB_GSUB_SubTable* st, + FT_Stream stream, + FT_UShort lookup_type ) +{ + Load_Subst_Func_Type Func; + + if (lookup_type >= ARRAY_LEN (Load_Subst_Call_Table)) + lookup_type = 0; + + Func = Load_Subst_Call_Table[lookup_type]; + + return Func ( st, stream ); +} + + +static void Free_DefaultSubst( HB_GSUB_SubTable* st, + FT_Memory memory ) +{ +} + +typedef void (*Free_Subst_Func_Type)( HB_GSUB_SubTable* st, + FT_Memory memory ); +static const Free_Subst_Func_Type Free_Subst_Call_Table[] = { + Free_DefaultSubst, + Free_SingleSubst, /* HB_GSUB_LOOKUP_SINGLE 1 */ + Free_MultipleSubst, /* HB_GSUB_LOOKUP_MULTIPLE 2 */ + Free_AlternateSubst, /* HB_GSUB_LOOKUP_ALTERNATE 3 */ + Free_LigatureSubst, /* HB_GSUB_LOOKUP_LIGATURE 4 */ + Free_ContextSubst, /* HB_GSUB_LOOKUP_CONTEXT 5 */ + Free_ChainContextSubst, /* HB_GSUB_LOOKUP_CHAIN 6 */ + Free_DefaultSubst, /* HB_GSUB_LOOKUP_EXTENSION 7 */ + Free_ReverseChainContextSubst /* HB_GSUB_LOOKUP_REVERSE_CHAIN 8 */ +}; + +void _HB_GSUB_Free_SubTable( HB_GSUB_SubTable* st, + FT_Memory memory, + FT_UShort lookup_type ) +{ + Free_Subst_Func_Type Func; + + if (lookup_type >= ARRAY_LEN (Free_Subst_Call_Table)) + lookup_type = 0; + + Func = Free_Subst_Call_Table[lookup_type]; + + Func ( st, memory ); +} + + + +/* apply one lookup to the input string object */ + +static FT_Error GSUB_Do_String_Lookup( HB_GSUBHeader* gsub, + FT_UShort lookup_index, + HB_Buffer buffer ) +{ + FT_Error error, retError = HB_Err_Not_Covered; + + FT_UInt* properties = gsub->LookupList.Properties; + + int nesting_level = 0; + + + while ( buffer->in_pos < buffer->in_length ) + { + if ( ~IN_PROPERTIES( buffer->in_pos ) & properties[lookup_index] ) + { + /* 0xFFFF indicates that we don't have a context length yet */ + error = GSUB_Do_Glyph_Lookup( gsub, lookup_index, buffer, + 0xFFFF, nesting_level ); + if ( error ) + { + if ( error != HB_Err_Not_Covered ) + return error; + } + else + retError = error; + } + else + error = HB_Err_Not_Covered; + + if ( error == HB_Err_Not_Covered ) + if ( hb_buffer_copy_output_glyph ( buffer ) ) + return error; + } + + return retError; +} + + +static FT_Error Apply_ReverseChainContextSubst( HB_GSUBHeader* gsub, + FT_UShort lookup_index, + HB_Buffer buffer ) +{ + FT_UInt* properties = gsub->LookupList.Properties; + FT_Error error, retError = HB_Err_Not_Covered; + FT_ULong subtable_Count, string_index; + FT_UShort flags; + HB_Lookup* lo; + + if ( buffer->in_length == 0 ) + return HB_Err_Not_Covered; + + lo = &gsub->LookupList.Lookup[lookup_index]; + flags = lo->LookupFlag; + + for ( subtable_Count = 0; subtable_Count < lo->SubTableCount; subtable_Count++ ) + { + string_index = buffer->in_length - 1; + do + { + if ( ~IN_PROPERTIES( buffer->in_pos ) & properties[lookup_index] ) + { + error = Lookup_ReverseChainContextSubst( gsub, &lo->SubTable[subtable_Count].st.gsub, + buffer, flags, string_index ); + if ( error ) + { + if ( error != HB_Err_Not_Covered ) + return error; + } + else + retError = error; + } + } + while (string_index--); + } + + return retError; +} + + +FT_Error HB_GSUB_Add_Feature( HB_GSUBHeader* gsub, + FT_UShort feature_index, + FT_UInt property ) +{ + FT_UShort i; + + HB_Feature feature; + FT_UInt* properties; + FT_UShort* index; + FT_UShort lookup_count; + + /* Each feature can only be added once */ + + if ( !gsub || + feature_index >= gsub->FeatureList.FeatureCount || + gsub->FeatureList.ApplyCount == gsub->FeatureList.FeatureCount ) + return FT_Err_Invalid_Argument; + + gsub->FeatureList.ApplyOrder[gsub->FeatureList.ApplyCount++] = feature_index; + + properties = gsub->LookupList.Properties; + + feature = gsub->FeatureList.FeatureRecord[feature_index].Feature; + index = feature.LookupListIndex; + lookup_count = gsub->LookupList.LookupCount; + + for ( i = 0; i < feature.LookupListCount; i++ ) + { + FT_UShort lookup_index = index[i]; + if (lookup_index < lookup_count) + properties[lookup_index] |= property; + } + + return FT_Err_Ok; +} + + + +FT_Error HB_GSUB_Clear_Features( HB_GSUBHeader* gsub ) +{ + FT_UShort i; + + FT_UInt* properties; + + + if ( !gsub ) + return FT_Err_Invalid_Argument; + + gsub->FeatureList.ApplyCount = 0; + + properties = gsub->LookupList.Properties; + + for ( i = 0; i < gsub->LookupList.LookupCount; i++ ) + properties[i] = 0; + + return FT_Err_Ok; +} + + + +FT_Error HB_GSUB_Register_Alternate_Function( HB_GSUBHeader* gsub, + HB_AltFunction altfunc, + void* data ) +{ + if ( !gsub ) + return FT_Err_Invalid_Argument; + + gsub->altfunc = altfunc; + gsub->data = data; + + return FT_Err_Ok; +} + + + +FT_Error HB_GSUB_Apply_String( HB_GSUBHeader* gsub, + HB_Buffer buffer ) +{ + FT_Error error, retError = HB_Err_Not_Covered; + FT_UShort i, j, lookup_count; + + if ( !gsub || + !buffer || buffer->in_length == 0 || buffer->in_pos >= buffer->in_length ) + return FT_Err_Invalid_Argument; + + lookup_count = gsub->LookupList.LookupCount; + + for ( i = 0; i < gsub->FeatureList.ApplyCount; i++) + { + FT_UShort feature_index; + HB_Feature feature; + + feature_index = gsub->FeatureList.ApplyOrder[i]; + feature = gsub->FeatureList.FeatureRecord[feature_index].Feature; + + for ( j = 0; j < feature.LookupListCount; j++ ) + { + FT_UShort lookup_index; + HB_Lookup* lookup; + FT_Bool need_swap; + + lookup_index = feature.LookupListIndex[j]; + + /* Skip nonexistant lookups */ + if (lookup_index >= lookup_count) + continue; + + lookup = &gsub->LookupList.Lookup[lookup_index]; + + if ( lookup->LookupType == HB_GSUB_LOOKUP_REVERSE_CHAIN ) + { + error = Apply_ReverseChainContextSubst( gsub, lookup_index, buffer); + need_swap = FALSE; /* We do ReverseChainContextSubst in-place */ + } + else + { + error = GSUB_Do_String_Lookup( gsub, lookup_index, buffer ); + need_swap = TRUE; + } + + if ( error ) + { + if ( error != HB_Err_Not_Covered ) + goto End; + } + else + retError = error; + + if ( need_swap ) + { + error = hb_buffer_swap( buffer ); + if ( error ) + goto End; + } + } + } + + error = retError; + +End: + return error; +} + + +/* END */ diff --git a/src/harfbuzz-gsub.h b/src/harfbuzz-gsub.h new file mode 100644 index 0000000..09145ba --- /dev/null +++ b/src/harfbuzz-gsub.h @@ -0,0 +1,132 @@ +/******************************************************************* + * + * Copyright 1996-2000 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * Copyright 2006 Behdad Esfahbod + * + * This is part of HarfBuzz, an OpenType Layout engine library. + * + * See the file name COPYING for licensing information. + * + ******************************************************************/ +#ifndef HARFBUZZ_GSUB_H +#define HARFBUZZ_GSUB_H + +#include "harfbuzz-gdef.h" +#include "harfbuzz-buffer.h" + +FT_BEGIN_HEADER + +#define HB_Err_Invalid_GSUB_SubTable_Format 0x1010 +#define HB_Err_Invalid_GSUB_SubTable 0x1011 + + +/* Lookup types for glyph substitution */ + +#define HB_GSUB_LOOKUP_SINGLE 1 +#define HB_GSUB_LOOKUP_MULTIPLE 2 +#define HB_GSUB_LOOKUP_ALTERNATE 3 +#define HB_GSUB_LOOKUP_LIGATURE 4 +#define HB_GSUB_LOOKUP_CONTEXT 5 +#define HB_GSUB_LOOKUP_CHAIN 6 +#define HB_GSUB_LOOKUP_EXTENSION 7 +#define HB_GSUB_LOOKUP_REVERSE_CHAIN 8 + + +/* A pointer to a function which selects the alternate glyph. `pos' is + the position of the glyph with index `glyphID', `num_alternates' + gives the number of alternates in the `alternates' array. `data' + points to the user-defined structure specified during a call to + HB_GSUB_Register_Alternate_Function(). The function must return an + index into the `alternates' array. */ + +typedef FT_UShort (*HB_AltFunction)(FT_ULong pos, + FT_UShort glyphID, + FT_UShort num_alternates, + FT_UShort* alternates, + void* data ); + + +struct HB_GSUBHeader_ +{ + FT_Memory memory; + + FT_ULong offset; + + FT_Fixed Version; + + HB_ScriptList ScriptList; + HB_FeatureList FeatureList; + HB_LookupList LookupList; + + HB_GDEFHeader* gdef; + + /* the next two fields are used for an alternate substitution callback + function to select the proper alternate glyph. */ + + HB_AltFunction altfunc; + void* data; +}; + +typedef struct HB_GSUBHeader_ HB_GSUBHeader; +typedef HB_GSUBHeader* HB_GSUB; + + +FT_Error HB_Load_GSUB_Table( FT_Face face, + HB_GSUBHeader** gsub, + HB_GDEFHeader* gdef ); + + +FT_Error HB_Done_GSUB_Table( HB_GSUBHeader* gsub ); + + +FT_Error HB_GSUB_Select_Script( HB_GSUBHeader* gsub, + FT_ULong script_tag, + FT_UShort* script_index ); + +FT_Error HB_GSUB_Select_Language( HB_GSUBHeader* gsub, + FT_ULong language_tag, + FT_UShort script_index, + FT_UShort* language_index, + FT_UShort* req_feature_index ); + +FT_Error HB_GSUB_Select_Feature( HB_GSUBHeader* gsub, + FT_ULong feature_tag, + FT_UShort script_index, + FT_UShort language_index, + FT_UShort* feature_index ); + + +FT_Error HB_GSUB_Query_Scripts( HB_GSUBHeader* gsub, + FT_ULong** script_tag_list ); + +FT_Error HB_GSUB_Query_Languages( HB_GSUBHeader* gsub, + FT_UShort script_index, + FT_ULong** language_tag_list ); + +FT_Error HB_GSUB_Query_Features( HB_GSUBHeader* gsub, + FT_UShort script_index, + FT_UShort language_index, + FT_ULong** feature_tag_list ); + + +FT_Error HB_GSUB_Add_Feature( HB_GSUBHeader* gsub, + FT_UShort feature_index, + FT_UInt property ); + +FT_Error HB_GSUB_Clear_Features( HB_GSUBHeader* gsub ); + + +FT_Error HB_GSUB_Register_Alternate_Function( HB_GSUBHeader* gsub, + HB_AltFunction altfunc, + void* data ); + + +FT_Error HB_GSUB_Apply_String( HB_GSUBHeader* gsub, + HB_Buffer buffer ); + + +FT_END_HEADER + +#endif /* HARFBUZZ_GSUB_H */ diff --git a/src/harfbuzz-impl.h b/src/harfbuzz-impl.h new file mode 100644 index 0000000..2531014 --- /dev/null +++ b/src/harfbuzz-impl.h @@ -0,0 +1,64 @@ +/******************************************************************* + * + * Copyright 1996-2000 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * Copyright 2006 Behdad Esfahbod + * + * This is part of HarfBuzz, an OpenType Layout engine library. + * + * See the file name COPYING for licensing information. + * + ******************************************************************/ +#ifndef HARFBUZZ_IMPL_H +#define HARFBUZZ_IMPL_H + +#include +#include FT_FREETYPE_H + +FT_BEGIN_HEADER + +#include "ftglue.h" + +#ifndef FALSE +# define FALSE 0 +#endif + +#ifndef TRUE +# define TRUE 1 +#endif + +#define ARRAY_LEN(Array) ((int)(sizeof (Array) / sizeof (Array)[0])) + + + + +#define IN_GLYPH( pos ) (buffer->in_string[(pos)].gindex) +#define IN_ITEM( pos ) (&buffer->in_string[(pos)]) +#define IN_CURGLYPH() (buffer->in_string[buffer->in_pos].gindex) +#define IN_CURITEM() (&buffer->in_string[buffer->in_pos]) +#define IN_PROPERTIES( pos ) (buffer->in_string[(pos)].properties) +#define IN_LIGID( pos ) (buffer->in_string[(pos)].ligID) +#define IN_COMPONENT( pos ) (buffer->in_string[(pos)].component) +#define POSITION( pos ) (&buffer->positions[(pos)]) +#define OUT_GLYPH( pos ) (buffer->out_string[(pos)].gindex) +#define OUT_ITEM( pos ) (&buffer->out_string[(pos)]) + +#define CHECK_Property( gdef, index, flags, property ) \ + ( ( error = _HB_GDEF_Check_Property( (gdef), (index), (flags), \ + (property) ) ) != FT_Err_Ok ) + +#define ADD_String( buffer, num_in, num_out, glyph_data, component, ligID ) \ + ( ( error = hb_buffer_add_output_glyphs( (buffer), \ + (num_in), (num_out), \ + (glyph_data), (component), (ligID) \ + ) ) != FT_Err_Ok ) +#define ADD_Glyph( buffer, glyph_index, component, ligID ) \ + ( ( error = hb_buffer_add_output_glyph( (buffer), \ + (glyph_index), (component), (ligID) \ + ) ) != FT_Err_Ok ) + + +FT_END_HEADER + +#endif /* HARFBUZZ_IMPL_H */ diff --git a/src/harfbuzz-open-private.h b/src/harfbuzz-open-private.h new file mode 100644 index 0000000..be265af --- /dev/null +++ b/src/harfbuzz-open-private.h @@ -0,0 +1,81 @@ +/******************************************************************* + * + * Copyright 1996-2000 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * Copyright 2006 Behdad Esfahbod + * + * This is part of HarfBuzz, an OpenType Layout engine library. + * + * See the file name COPYING for licensing information. + * + ******************************************************************/ +#ifndef HARFBUZZ_OPEN_PRIVATE_H +#define HARFBUZZ_OPEN_PRIVATE_H + +#include "harfbuzz-open.h" +#include "harfbuzz-gsub-private.h" +#include "harfbuzz-gpos-private.h" + +FT_BEGIN_HEADER + + +struct HB_SubTable_ +{ + union + { + HB_GSUB_SubTable gsub; + HB_GPOS_SubTable gpos; + } st; +}; + + +FT_Error _HB_OPEN_Load_ScriptList( HB_ScriptList* sl, + FT_Stream stream ); +FT_Error _HB_OPEN_Load_FeatureList( HB_FeatureList* fl, + FT_Stream input ); +FT_Error _HB_OPEN_Load_LookupList( HB_LookupList* ll, + FT_Stream input, + HB_Type type ); + +FT_Error _HB_OPEN_Load_Coverage( HB_Coverage* c, + FT_Stream input ); +FT_Error _HB_OPEN_Load_ClassDefinition( HB_ClassDefinition* cd, + FT_UShort limit, + FT_Stream input ); +FT_Error _HB_OPEN_Load_EmptyClassDefinition( HB_ClassDefinition* cd, + FT_Stream input ); +FT_Error _HB_OPEN_Load_Device( HB_Device* d, + FT_Stream input ); + +void _HB_OPEN_Free_ScriptList( HB_ScriptList* sl, + FT_Memory memory ); +void _HB_OPEN_Free_FeatureList( HB_FeatureList* fl, + FT_Memory memory ); +void _HB_OPEN_Free_LookupList( HB_LookupList* ll, + HB_Type type, + FT_Memory memory ); + +void _HB_OPEN_Free_Coverage( HB_Coverage* c, + FT_Memory memory ); +void _HB_OPEN_Free_ClassDefinition( HB_ClassDefinition* cd, + FT_Memory memory ); +void _HB_OPEN_Free_Device( HB_Device* d, + FT_Memory memory ); + + + +FT_Error _HB_OPEN_Coverage_Index( HB_Coverage* c, + FT_UShort glyphID, + FT_UShort* index ); +FT_Error _HB_OPEN_Get_Class( HB_ClassDefinition* cd, + FT_UShort glyphID, + FT_UShort* class, + FT_UShort* index ); +FT_Error _HB_OPEN_Get_Device( HB_Device* d, + FT_UShort size, + FT_Short* value ); + +FT_END_HEADER + +#endif /* HARFBUZZ_OPEN_PRIVATE_H */ diff --git a/src/harfbuzz-open.c b/src/harfbuzz-open.c new file mode 100644 index 0000000..b3c1bcb --- /dev/null +++ b/src/harfbuzz-open.c @@ -0,0 +1,1426 @@ +/******************************************************************* + * + * Copyright 1996-2000 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * Copyright 2006 Behdad Esfahbod + * + * This is part of HarfBuzz, an OpenType Layout engine library. + * + * See the file name COPYING for licensing information. + * + ******************************************************************/ +#include "harfbuzz-impl.h" +#include "harfbuzz-open-private.h" + + +/*************************** + * Script related functions + ***************************/ + + +/* LangSys */ + +static FT_Error Load_LangSys( HB_LangSys* ls, + FT_Stream stream ) +{ + FT_Error error; + FT_Memory memory = stream->memory; + FT_UShort n, count; + FT_UShort* fi; + + + if ( ACCESS_Frame( 6L ) ) + return error; + + ls->LookupOrderOffset = GET_UShort(); /* should be 0 */ + ls->ReqFeatureIndex = GET_UShort(); + count = ls->FeatureCount = GET_UShort(); + + FORGET_Frame(); + + ls->FeatureIndex = NULL; + + if ( ALLOC_ARRAY( ls->FeatureIndex, count, FT_UShort ) ) + return error; + + if ( ACCESS_Frame( count * 2L ) ) + { + FREE( ls->FeatureIndex ); + return error; + } + + fi = ls->FeatureIndex; + + for ( n = 0; n < count; n++ ) + fi[n] = GET_UShort(); + + FORGET_Frame(); + + return FT_Err_Ok; +} + + +static void Free_LangSys( HB_LangSys* ls, + FT_Memory memory ) +{ + FREE( ls->FeatureIndex ); +} + + +/* Script */ + +static FT_Error Load_Script( HB_Script* s, + FT_Stream stream ) +{ + FT_Error error; + FT_Memory memory = stream->memory; + FT_UShort n, m, count; + FT_ULong cur_offset, new_offset, base_offset; + + HB_LangSysRecord* lsr; + + + base_offset = FILE_Pos(); + + if ( ACCESS_Frame( 2L ) ) + return error; + + new_offset = GET_UShort() + base_offset; + + FORGET_Frame(); + + if ( new_offset != base_offset ) /* not a NULL offset */ + { + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = Load_LangSys( &s->DefaultLangSys, + stream ) ) != FT_Err_Ok ) + return error; + (void)FILE_Seek( cur_offset ); + } + else + { + /* we create a DefaultLangSys table with no entries */ + + s->DefaultLangSys.LookupOrderOffset = 0; + s->DefaultLangSys.ReqFeatureIndex = 0xFFFF; + s->DefaultLangSys.FeatureCount = 0; + s->DefaultLangSys.FeatureIndex = NULL; + } + + if ( ACCESS_Frame( 2L ) ) + goto Fail2; + + count = s->LangSysCount = GET_UShort(); + + /* safety check; otherwise the official handling of TrueType Open + fonts won't work */ + + if ( s->LangSysCount == 0 && s->DefaultLangSys.FeatureCount == 0 ) + { + error = HB_Err_Empty_Script; + goto Fail2; + } + + FORGET_Frame(); + + s->LangSysRecord = NULL; + + if ( ALLOC_ARRAY( s->LangSysRecord, count, HB_LangSysRecord ) ) + goto Fail2; + + lsr = s->LangSysRecord; + + for ( n = 0; n < count; n++ ) + { + if ( ACCESS_Frame( 6L ) ) + goto Fail1; + + lsr[n].LangSysTag = GET_ULong(); + new_offset = GET_UShort() + base_offset; + + FORGET_Frame(); + + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = Load_LangSys( &lsr[n].LangSys, stream ) ) != FT_Err_Ok ) + goto Fail1; + (void)FILE_Seek( cur_offset ); + } + + return FT_Err_Ok; + +Fail1: + for ( m = 0; m < n; m++ ) + Free_LangSys( &lsr[m].LangSys, memory ); + + FREE( s->LangSysRecord ); + +Fail2: + Free_LangSys( &s->DefaultLangSys, memory ); + return error; +} + + +static void Free_Script( HB_Script* s, + FT_Memory memory ) +{ + FT_UShort n, count; + + HB_LangSysRecord* lsr; + + + Free_LangSys( &s->DefaultLangSys, memory ); + + if ( s->LangSysRecord ) + { + count = s->LangSysCount; + lsr = s->LangSysRecord; + + for ( n = 0; n < count; n++ ) + Free_LangSys( &lsr[n].LangSys, memory ); + + FREE( lsr ); + } +} + + +/* ScriptList */ + +FT_Error _HB_OPEN_Load_ScriptList( HB_ScriptList* sl, + FT_Stream stream ) +{ + FT_Error error; + FT_Memory memory = stream->memory; + + FT_UShort n, script_count; + FT_ULong cur_offset, new_offset, base_offset; + + HB_ScriptRecord* sr; + + + base_offset = FILE_Pos(); + + if ( ACCESS_Frame( 2L ) ) + return error; + + script_count = GET_UShort(); + + FORGET_Frame(); + + sl->ScriptRecord = NULL; + + if ( ALLOC_ARRAY( sl->ScriptRecord, script_count, HB_ScriptRecord ) ) + return error; + + sr = sl->ScriptRecord; + + sl->ScriptCount= 0; + for ( n = 0; n < script_count; n++ ) + { + if ( ACCESS_Frame( 6L ) ) + goto Fail; + + sr[sl->ScriptCount].ScriptTag = GET_ULong(); + new_offset = GET_UShort() + base_offset; + + FORGET_Frame(); + + cur_offset = FILE_Pos(); + + if ( FILE_Seek( new_offset ) ) + goto Fail; + + error = Load_Script( &sr[sl->ScriptCount].Script, stream ); + if ( error == FT_Err_Ok ) + sl->ScriptCount += 1; + else if ( error != HB_Err_Empty_Script ) + goto Fail; + + (void)FILE_Seek( cur_offset ); + } + + if ( sl->ScriptCount == 0 ) + { + error = HB_Err_Invalid_SubTable; + goto Fail; + } + + return FT_Err_Ok; + +Fail: + for ( n = 0; n < sl->ScriptCount; n++ ) + Free_Script( &sr[n].Script, memory ); + + FREE( sl->ScriptRecord ); + return error; +} + + +void _HB_OPEN_Free_ScriptList( HB_ScriptList* sl, + FT_Memory memory ) +{ + FT_UShort n, count; + + HB_ScriptRecord* sr; + + + if ( sl->ScriptRecord ) + { + count = sl->ScriptCount; + sr = sl->ScriptRecord; + + for ( n = 0; n < count; n++ ) + Free_Script( &sr[n].Script, memory ); + + FREE( sr ); + } +} + + + +/********************************* + * Feature List related functions + *********************************/ + + +/* Feature */ + +static FT_Error Load_Feature( HB_Feature* f, + FT_Stream stream ) +{ + FT_Error error; + FT_Memory memory = stream->memory; + + FT_UShort n, count; + + FT_UShort* lli; + + + if ( ACCESS_Frame( 4L ) ) + return error; + + f->FeatureParams = GET_UShort(); /* should be 0 */ + count = f->LookupListCount = GET_UShort(); + + FORGET_Frame(); + + f->LookupListIndex = NULL; + + if ( ALLOC_ARRAY( f->LookupListIndex, count, FT_UShort ) ) + return error; + + lli = f->LookupListIndex; + + if ( ACCESS_Frame( count * 2L ) ) + { + FREE( f->LookupListIndex ); + return error; + } + + for ( n = 0; n < count; n++ ) + lli[n] = GET_UShort(); + + FORGET_Frame(); + + return FT_Err_Ok; +} + + +static void Free_Feature( HB_Feature* f, + FT_Memory memory ) +{ + FREE( f->LookupListIndex ); +} + + +/* FeatureList */ + +FT_Error _HB_OPEN_Load_FeatureList( HB_FeatureList* fl, + FT_Stream stream ) +{ + FT_Error error; + FT_Memory memory = stream->memory; + + FT_UShort n, m, count; + FT_ULong cur_offset, new_offset, base_offset; + + HB_FeatureRecord* fr; + + + base_offset = FILE_Pos(); + + if ( ACCESS_Frame( 2L ) ) + return error; + + count = fl->FeatureCount = GET_UShort(); + + FORGET_Frame(); + + fl->FeatureRecord = NULL; + + if ( ALLOC_ARRAY( fl->FeatureRecord, count, HB_FeatureRecord ) ) + return error; + if ( ALLOC_ARRAY( fl->ApplyOrder, count, FT_UShort ) ) + goto Fail2; + + fl->ApplyCount = 0; + + fr = fl->FeatureRecord; + + for ( n = 0; n < count; n++ ) + { + if ( ACCESS_Frame( 6L ) ) + goto Fail1; + + fr[n].FeatureTag = GET_ULong(); + new_offset = GET_UShort() + base_offset; + + FORGET_Frame(); + + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = Load_Feature( &fr[n].Feature, stream ) ) != FT_Err_Ok ) + goto Fail1; + (void)FILE_Seek( cur_offset ); + } + + return FT_Err_Ok; + +Fail1: + for ( m = 0; m < n; m++ ) + Free_Feature( &fr[m].Feature, memory ); + + FREE( fl->ApplyOrder ); + +Fail2: + FREE( fl->FeatureRecord ); + + return error; +} + + +void _HB_OPEN_Free_FeatureList( HB_FeatureList* fl, + FT_Memory memory) +{ + FT_UShort n, count; + + HB_FeatureRecord* fr; + + + if ( fl->FeatureRecord ) + { + count = fl->FeatureCount; + fr = fl->FeatureRecord; + + for ( n = 0; n < count; n++ ) + Free_Feature( &fr[n].Feature, memory ); + + FREE( fr ); + } + + FREE( fl->ApplyOrder ); +} + + + +/******************************** + * Lookup List related functions + ********************************/ + +/* the subroutines of the following two functions are defined in + ftxgsub.c and ftxgpos.c respectively */ + + +/* SubTable */ + +static FT_Error Load_SubTable( HB_SubTable* st, + FT_Stream stream, + HB_Type table_type, + FT_UShort lookup_type ) +{ + if ( table_type == HB_Type_GSUB ) + return _HB_GSUB_Load_SubTable ( &st->st.gsub, stream, lookup_type ); + else + return _HB_GPOS_Load_SubTable ( &st->st.gpos, stream, lookup_type ); +} + + +static void Free_SubTable( HB_SubTable* st, + HB_Type table_type, + FT_UShort lookup_type, + FT_Memory memory ) +{ + if ( table_type == HB_Type_GSUB ) + _HB_GSUB_Free_SubTable ( &st->st.gsub, memory, lookup_type ); + else + _HB_GPOS_Free_SubTable ( &st->st.gpos, memory, lookup_type ); +} + + +/* Lookup */ + +static FT_Error Load_Lookup( HB_Lookup* l, + FT_Stream stream, + HB_Type type ) +{ + FT_Error error; + FT_Memory memory = stream->memory; + + FT_UShort n, m, count; + FT_ULong cur_offset, new_offset, base_offset; + + HB_SubTable* st; + + FT_Bool is_extension = FALSE; + + + base_offset = FILE_Pos(); + + if ( ACCESS_Frame( 6L ) ) + return error; + + l->LookupType = GET_UShort(); + l->LookupFlag = GET_UShort(); + count = l->SubTableCount = GET_UShort(); + + FORGET_Frame(); + + l->SubTable = NULL; + + if ( ALLOC_ARRAY( l->SubTable, count, HB_SubTable ) ) + return error; + + st = l->SubTable; + + if ( ( type == HB_Type_GSUB && l->LookupType == HB_GSUB_LOOKUP_EXTENSION ) || + ( type == HB_Type_GPOS && l->LookupType == HB_GPOS_LOOKUP_EXTENSION ) ) + is_extension = TRUE; + + for ( n = 0; n < count; n++ ) + { + if ( ACCESS_Frame( 2L ) ) + goto Fail; + + new_offset = GET_UShort() + base_offset; + + FORGET_Frame(); + + cur_offset = FILE_Pos(); + + if ( is_extension ) + { + if ( FILE_Seek( new_offset ) || ACCESS_Frame( 8L ) ) + goto Fail; + + if (GET_UShort() != 1) /* format should be 1 */ + goto Fail; + + l->LookupType = GET_UShort(); + new_offset += GET_ULong(); + + FORGET_Frame(); + } + + if ( FILE_Seek( new_offset ) || + ( error = Load_SubTable( &st[n], stream, + type, l->LookupType ) ) != FT_Err_Ok ) + goto Fail; + (void)FILE_Seek( cur_offset ); + } + + return FT_Err_Ok; + +Fail: + for ( m = 0; m < n; m++ ) + Free_SubTable( &st[m], type, l->LookupType, memory ); + + FREE( l->SubTable ); + return error; +} + + +static void Free_Lookup( HB_Lookup* l, + HB_Type type, + FT_Memory memory) +{ + FT_UShort n, count; + + HB_SubTable* st; + + + if ( l->SubTable ) + { + count = l->SubTableCount; + st = l->SubTable; + + for ( n = 0; n < count; n++ ) + Free_SubTable( &st[n], type, l->LookupType, memory ); + + FREE( st ); + } +} + + +/* LookupList */ + +FT_Error _HB_OPEN_Load_LookupList( HB_LookupList* ll, + FT_Stream stream, + HB_Type type ) +{ + FT_Error error; + FT_Memory memory = stream->memory; + + FT_UShort n, m, count; + FT_ULong cur_offset, new_offset, base_offset; + + HB_Lookup* l; + + + base_offset = FILE_Pos(); + + if ( ACCESS_Frame( 2L ) ) + return error; + + count = ll->LookupCount = GET_UShort(); + + FORGET_Frame(); + + ll->Lookup = NULL; + + if ( ALLOC_ARRAY( ll->Lookup, count, HB_Lookup ) ) + return error; + if ( ALLOC_ARRAY( ll->Properties, count, FT_UInt ) ) + goto Fail2; + + l = ll->Lookup; + + for ( n = 0; n < count; n++ ) + { + if ( ACCESS_Frame( 2L ) ) + goto Fail1; + + new_offset = GET_UShort() + base_offset; + + FORGET_Frame(); + + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = Load_Lookup( &l[n], stream, type ) ) != FT_Err_Ok ) + goto Fail1; + (void)FILE_Seek( cur_offset ); + } + + return FT_Err_Ok; + +Fail1: + FREE( ll->Properties ); + + for ( m = 0; m < n; m++ ) + Free_Lookup( &l[m], type, memory ); + +Fail2: + FREE( ll->Lookup ); + return error; +} + + +void _HB_OPEN_Free_LookupList( HB_LookupList* ll, + HB_Type type, + FT_Memory memory ) +{ + FT_UShort n, count; + + HB_Lookup* l; + + + FREE( ll->Properties ); + + if ( ll->Lookup ) + { + count = ll->LookupCount; + l = ll->Lookup; + + for ( n = 0; n < count; n++ ) + Free_Lookup( &l[n], type, memory ); + + FREE( l ); + } +} + + + +/***************************** + * Coverage related functions + *****************************/ + + +/* CoverageFormat1 */ + +static FT_Error Load_Coverage1( HB_CoverageFormat1* cf1, + FT_Stream stream ) +{ + FT_Error error; + FT_Memory memory = stream->memory; + + FT_UShort n, count; + + FT_UShort* ga; + + + if ( ACCESS_Frame( 2L ) ) + return error; + + count = cf1->GlyphCount = GET_UShort(); + + FORGET_Frame(); + + cf1->GlyphArray = NULL; + + if ( ALLOC_ARRAY( cf1->GlyphArray, count, FT_UShort ) ) + return error; + + ga = cf1->GlyphArray; + + if ( ACCESS_Frame( count * 2L ) ) + { + FREE( cf1->GlyphArray ); + return error; + } + + for ( n = 0; n < count; n++ ) + ga[n] = GET_UShort(); + + FORGET_Frame(); + + return FT_Err_Ok; +} + + +static void Free_Coverage1( HB_CoverageFormat1* cf1, + FT_Memory memory) +{ + FREE( cf1->GlyphArray ); +} + + +/* CoverageFormat2 */ + +static FT_Error Load_Coverage2( HB_CoverageFormat2* cf2, + FT_Stream stream ) +{ + FT_Error error; + FT_Memory memory = stream->memory; + + FT_UShort n, count; + + HB_RangeRecord* rr; + + + if ( ACCESS_Frame( 2L ) ) + return error; + + count = cf2->RangeCount = GET_UShort(); + + FORGET_Frame(); + + cf2->RangeRecord = NULL; + + if ( ALLOC_ARRAY( cf2->RangeRecord, count, HB_RangeRecord ) ) + return error; + + rr = cf2->RangeRecord; + + if ( ACCESS_Frame( count * 6L ) ) + goto Fail; + + for ( n = 0; n < count; n++ ) + { + rr[n].Start = GET_UShort(); + rr[n].End = GET_UShort(); + rr[n].StartCoverageIndex = GET_UShort(); + + /* sanity check; we are limited to 16bit integers */ + if ( rr[n].Start > rr[n].End || + ( rr[n].End - rr[n].Start + (long)rr[n].StartCoverageIndex ) >= + 0x10000L ) + { + error = HB_Err_Invalid_SubTable; + goto Fail; + } + } + + FORGET_Frame(); + + return FT_Err_Ok; + +Fail: + FREE( cf2->RangeRecord ); + return error; +} + + +static void Free_Coverage2( HB_CoverageFormat2* cf2, + FT_Memory memory ) +{ + FREE( cf2->RangeRecord ); +} + + +FT_Error _HB_OPEN_Load_Coverage( HB_Coverage* c, + FT_Stream stream ) +{ + FT_Error error; + + if ( ACCESS_Frame( 2L ) ) + return error; + + c->CoverageFormat = GET_UShort(); + + FORGET_Frame(); + + switch ( c->CoverageFormat ) + { + case 1: + return Load_Coverage1( &c->cf.cf1, stream ); + + case 2: + return Load_Coverage2( &c->cf.cf2, stream ); + + default: + return HB_Err_Invalid_SubTable_Format; + } + + return FT_Err_Ok; /* never reached */ +} + + +void _HB_OPEN_Free_Coverage( HB_Coverage* c, + FT_Memory memory ) +{ + switch ( c->CoverageFormat ) + { + case 1: + Free_Coverage1( &c->cf.cf1, memory ); + break; + + case 2: + Free_Coverage2( &c->cf.cf2, memory ); + break; + } +} + + +static FT_Error Coverage_Index1( HB_CoverageFormat1* cf1, + FT_UShort glyphID, + FT_UShort* index ) +{ + FT_UShort min, max, new_min, new_max, middle; + + FT_UShort* array = cf1->GlyphArray; + + + /* binary search */ + + if ( cf1->GlyphCount == 0 ) + return HB_Err_Not_Covered; + + new_min = 0; + new_max = cf1->GlyphCount - 1; + + do + { + min = new_min; + max = new_max; + + /* we use (min + max) / 2 = max - (max - min) / 2 to avoid + overflow and rounding errors */ + + middle = max - ( ( max - min ) >> 1 ); + + if ( glyphID == array[middle] ) + { + *index = middle; + return FT_Err_Ok; + } + else if ( glyphID < array[middle] ) + { + if ( middle == min ) + break; + new_max = middle - 1; + } + else + { + if ( middle == max ) + break; + new_min = middle + 1; + } + } while ( min < max ); + + return HB_Err_Not_Covered; +} + + +static FT_Error Coverage_Index2( HB_CoverageFormat2* cf2, + FT_UShort glyphID, + FT_UShort* index ) +{ + FT_UShort min, max, new_min, new_max, middle; + + HB_RangeRecord* rr = cf2->RangeRecord; + + + /* binary search */ + + if ( cf2->RangeCount == 0 ) + return HB_Err_Not_Covered; + + new_min = 0; + new_max = cf2->RangeCount - 1; + + do + { + min = new_min; + max = new_max; + + /* we use (min + max) / 2 = max - (max - min) / 2 to avoid + overflow and rounding errors */ + + middle = max - ( ( max - min ) >> 1 ); + + if ( glyphID >= rr[middle].Start && glyphID <= rr[middle].End ) + { + *index = rr[middle].StartCoverageIndex + glyphID - rr[middle].Start; + return FT_Err_Ok; + } + else if ( glyphID < rr[middle].Start ) + { + if ( middle == min ) + break; + new_max = middle - 1; + } + else + { + if ( middle == max ) + break; + new_min = middle + 1; + } + } while ( min < max ); + + return HB_Err_Not_Covered; +} + + +FT_Error _HB_OPEN_Coverage_Index( HB_Coverage* c, + FT_UShort glyphID, + FT_UShort* index ) +{ + switch ( c->CoverageFormat ) + { + case 1: + return Coverage_Index1( &c->cf.cf1, glyphID, index ); + + case 2: + return Coverage_Index2( &c->cf.cf2, glyphID, index ); + + default: + return HB_Err_Invalid_SubTable_Format; + } + + return FT_Err_Ok; /* never reached */ +} + + + +/************************************* + * Class Definition related functions + *************************************/ + + +/* ClassDefFormat1 */ + +static FT_Error Load_ClassDef1( HB_ClassDefinition* cd, + FT_UShort limit, + FT_Stream stream ) +{ + FT_Error error; + FT_Memory memory = stream->memory; + + FT_UShort n, count; + + FT_UShort* cva; + FT_Bool* d; + + HB_ClassDefFormat1* cdf1; + + + cdf1 = &cd->cd.cd1; + + if ( ACCESS_Frame( 4L ) ) + return error; + + cdf1->StartGlyph = GET_UShort(); + count = cdf1->GlyphCount = GET_UShort(); + + FORGET_Frame(); + + /* sanity check; we are limited to 16bit integers */ + + if ( cdf1->StartGlyph + (long)count >= 0x10000L ) + return HB_Err_Invalid_SubTable; + + cdf1->ClassValueArray = NULL; + + if ( ALLOC_ARRAY( cdf1->ClassValueArray, count, FT_UShort ) ) + return error; + + d = cd->Defined; + cva = cdf1->ClassValueArray; + + if ( ACCESS_Frame( count * 2L ) ) + goto Fail; + + for ( n = 0; n < count; n++ ) + { + cva[n] = GET_UShort(); + if ( cva[n] >= limit ) + { + error = HB_Err_Invalid_SubTable; + goto Fail; + } + d[cva[n]] = TRUE; + } + + FORGET_Frame(); + + return FT_Err_Ok; + +Fail: + FREE( cva ); + + return error; +} + + +static void Free_ClassDef1( HB_ClassDefFormat1* cdf1, + FT_Memory memory ) +{ + FREE( cdf1->ClassValueArray ); +} + + +/* ClassDefFormat2 */ + +static FT_Error Load_ClassDef2( HB_ClassDefinition* cd, + FT_UShort limit, + FT_Stream stream ) +{ + FT_Error error; + FT_Memory memory = stream->memory; + + FT_UShort n, count; + + HB_ClassRangeRecord* crr; + FT_Bool* d; + + HB_ClassDefFormat2* cdf2; + + + cdf2 = &cd->cd.cd2; + + if ( ACCESS_Frame( 2L ) ) + return error; + + count = cdf2->ClassRangeCount = GET_UShort(); + + FORGET_Frame(); + + cdf2->ClassRangeRecord = NULL; + + if ( ALLOC_ARRAY( cdf2->ClassRangeRecord, count, HB_ClassRangeRecord ) ) + return error; + + d = cd->Defined; + crr = cdf2->ClassRangeRecord; + + if ( ACCESS_Frame( count * 6L ) ) + goto Fail; + + for ( n = 0; n < count; n++ ) + { + crr[n].Start = GET_UShort(); + crr[n].End = GET_UShort(); + crr[n].Class = GET_UShort(); + + /* sanity check */ + + if ( crr[n].Start > crr[n].End || + crr[n].Class >= limit ) + { + error = HB_Err_Invalid_SubTable; + goto Fail; + } + d[crr[n].Class] = TRUE; + } + + FORGET_Frame(); + + return FT_Err_Ok; + +Fail: + FREE( crr ); + + return error; +} + + +static void Free_ClassDef2( HB_ClassDefFormat2* cdf2, + FT_Memory memory ) +{ + FREE( cdf2->ClassRangeRecord ); +} + + +/* ClassDefinition */ + +FT_Error _HB_OPEN_Load_ClassDefinition( HB_ClassDefinition* cd, + FT_UShort limit, + FT_Stream stream ) +{ + FT_Error error; + FT_Memory memory = stream->memory; + + + if ( ALLOC_ARRAY( cd->Defined, limit, FT_Bool ) ) + return error; + + if ( ACCESS_Frame( 2L ) ) + goto Fail; + + cd->ClassFormat = GET_UShort(); + + FORGET_Frame(); + + switch ( cd->ClassFormat ) + { + case 1: + error = Load_ClassDef1( cd, limit, stream ); + break; + + case 2: + error = Load_ClassDef2( cd, limit, stream ); + break; + + default: + error = HB_Err_Invalid_SubTable_Format; + break; + } + + if ( error ) + goto Fail; + + cd->loaded = TRUE; + + return FT_Err_Ok; + +Fail: + FREE( cd->Defined ); + return error; +} + + +FT_Error _HB_OPEN_Load_EmptyClassDefinition( HB_ClassDefinition* cd, + FT_Stream stream ) +{ + FT_Error error; + FT_Memory memory = stream->memory; + + + if ( ALLOC_ARRAY( cd->Defined, 1, FT_Bool ) ) + return error; + + cd->ClassFormat = 1; /* Meaningless */ + cd->Defined[0] = FALSE; + + if ( ALLOC_ARRAY( cd->cd.cd1.ClassValueArray, 1, FT_UShort ) ) + goto Fail; + + return FT_Err_Ok; + +Fail: + FREE( cd->Defined ); + return error; +} + +void _HB_OPEN_Free_ClassDefinition( HB_ClassDefinition* cd, + FT_Memory memory ) +{ + if ( !cd->loaded ) + return; + + FREE( cd->Defined ); + + switch ( cd->ClassFormat ) + { + case 1: + Free_ClassDef1( &cd->cd.cd1, memory ); + break; + + case 2: + Free_ClassDef2( &cd->cd.cd2, memory ); + break; + } +} + + +static FT_Error Get_Class1( HB_ClassDefFormat1* cdf1, + FT_UShort glyphID, + FT_UShort* class, + FT_UShort* index ) +{ + FT_UShort* cva = cdf1->ClassValueArray; + + + if ( index ) + *index = 0; + + if ( glyphID >= cdf1->StartGlyph && + glyphID <= cdf1->StartGlyph + cdf1->GlyphCount ) + { + *class = cva[glyphID - cdf1->StartGlyph]; + return FT_Err_Ok; + } + else + { + *class = 0; + return HB_Err_Not_Covered; + } +} + + +/* we need the index value of the last searched class range record + in case of failure for constructed GDEF tables */ + +static FT_Error Get_Class2( HB_ClassDefFormat2* cdf2, + FT_UShort glyphID, + FT_UShort* class, + FT_UShort* index ) +{ + FT_Error error = FT_Err_Ok; + FT_UShort min, max, new_min, new_max, middle; + + HB_ClassRangeRecord* crr = cdf2->ClassRangeRecord; + + + /* binary search */ + + if ( cdf2->ClassRangeCount == 0 ) + { + *class = 0; + if ( index ) + *index = 0; + + return HB_Err_Not_Covered; + } + + new_min = 0; + new_max = cdf2->ClassRangeCount - 1; + + do + { + min = new_min; + max = new_max; + + /* we use (min + max) / 2 = max - (max - min) / 2 to avoid + overflow and rounding errors */ + + middle = max - ( ( max - min ) >> 1 ); + + if ( glyphID >= crr[middle].Start && glyphID <= crr[middle].End ) + { + *class = crr[middle].Class; + error = FT_Err_Ok; + break; + } + else if ( glyphID < crr[middle].Start ) + { + if ( middle == min ) + { + *class = 0; + error = HB_Err_Not_Covered; + break; + } + new_max = middle - 1; + } + else + { + if ( middle == max ) + { + *class = 0; + error = HB_Err_Not_Covered; + break; + } + new_min = middle + 1; + } + } while ( min < max ); + + if ( index ) + *index = middle; + + return error; +} + + +FT_Error _HB_OPEN_Get_Class( HB_ClassDefinition* cd, + FT_UShort glyphID, + FT_UShort* class, + FT_UShort* index ) +{ + switch ( cd->ClassFormat ) + { + case 1: + return Get_Class1( &cd->cd.cd1, glyphID, class, index ); + + case 2: + return Get_Class2( &cd->cd.cd2, glyphID, class, index ); + + default: + return HB_Err_Invalid_SubTable_Format; + } + + return FT_Err_Ok; /* never reached */ +} + + + +/*************************** + * Device related functions + ***************************/ + + +FT_Error _HB_OPEN_Load_Device( HB_Device* d, + FT_Stream stream ) +{ + FT_Error error; + FT_Memory memory = stream->memory; + + FT_UShort n, count; + + FT_UShort* dv; + + + if ( ACCESS_Frame( 6L ) ) + return error; + + d->StartSize = GET_UShort(); + d->EndSize = GET_UShort(); + d->DeltaFormat = GET_UShort(); + + FORGET_Frame(); + + if ( d->StartSize > d->EndSize || + d->DeltaFormat == 0 || d->DeltaFormat > 3 ) + return HB_Err_Invalid_SubTable; + + d->DeltaValue = NULL; + + count = ( ( d->EndSize - d->StartSize + 1 ) >> + ( 4 - d->DeltaFormat ) ) + 1; + + if ( ALLOC_ARRAY( d->DeltaValue, count, FT_UShort ) ) + return error; + + if ( ACCESS_Frame( count * 2L ) ) + { + FREE( d->DeltaValue ); + return error; + } + + dv = d->DeltaValue; + + for ( n = 0; n < count; n++ ) + dv[n] = GET_UShort(); + + FORGET_Frame(); + + return FT_Err_Ok; +} + + +void _HB_OPEN_Free_Device( HB_Device* d, + FT_Memory memory ) +{ + FREE( d->DeltaValue ); +} + + +/* Since we have the delta values stored in compressed form, we must + uncompress it now. To simplify the interface, the function always + returns a meaningful value in `value'; the error is just for + information. + | | + format = 1: 0011223344556677|8899101112131415|... + | | + byte 1 byte 2 + + 00: (byte >> 14) & mask + 11: (byte >> 12) & mask + ... + + mask = 0x0003 + | | + format = 2: 0000111122223333|4444555566667777|... + | | + byte 1 byte 2 + + 0000: (byte >> 12) & mask + 1111: (byte >> 8) & mask + ... + + mask = 0x000F + | | + format = 3: 0000000011111111|2222222233333333|... + | | + byte 1 byte 2 + + 00000000: (byte >> 8) & mask + 11111111: (byte >> 0) & mask + .... + + mask = 0x00FF */ + +FT_Error _HB_OPEN_Get_Device( HB_Device* d, + FT_UShort size, + FT_Short* value ) +{ + FT_UShort byte, bits, mask, f, s; + + + f = d->DeltaFormat; + + if ( d->DeltaValue && size >= d->StartSize && size <= d->EndSize ) + { + s = size - d->StartSize; + byte = d->DeltaValue[s >> ( 4 - f )]; + bits = byte >> ( 16 - ( ( s % ( 1 << ( 4 - f ) ) + 1 ) << f ) ); + mask = 0xFFFF >> ( 16 - ( 1 << f ) ); + + *value = (FT_Short)( bits & mask ); + + /* conversion to a signed value */ + + if ( *value >= ( ( mask + 1 ) >> 1 ) ) + *value -= mask + 1; + + return FT_Err_Ok; + } + else + { + *value = 0; + return HB_Err_Not_Covered; + } +} + + +/* END */ diff --git a/src/harfbuzz-open.h b/src/harfbuzz-open.h new file mode 100644 index 0000000..17e1f29 --- /dev/null +++ b/src/harfbuzz-open.h @@ -0,0 +1,285 @@ +/******************************************************************* + * + * Copyright 1996-2000 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * Copyright 2006 Behdad Esfahbod + * + * This is part of HarfBuzz, an OpenType Layout engine library. + * + * See the file name COPYING for licensing information. + * + ******************************************************************/ +#ifndef HARFBUZZ_OPEN_H +#define HARFBUZZ_OPEN_H + +#include +#include FT_FREETYPE_H + +FT_BEGIN_HEADER + +/* Use this if a feature applies to all glyphs */ +#define HB_ALL_GLYPHS 0xFFFF + +#define HB_DEFAULT_LANGUAGE 0xFFFF + +#define HB_MAX_NESTING_LEVEL 100 + +#define HB_Err_Invalid_SubTable_Format 0x1000 +#define HB_Err_Invalid_SubTable 0x1001 +#define HB_Err_Not_Covered 0x1002 +#define HB_Err_Too_Many_Nested_Contexts 0x1003 +#define HB_Err_No_MM_Interpreter 0x1004 +#define HB_Err_Empty_Script 0x1005 + + +/* Script list related structures */ + +struct HB_LangSys_ +{ + FT_UShort LookupOrderOffset; /* always 0 for TT Open 1.0 */ + FT_UShort ReqFeatureIndex; /* required FeatureIndex */ + FT_UShort FeatureCount; /* number of Feature indices */ + FT_UShort* FeatureIndex; /* array of Feature indices */ +}; + +typedef struct HB_LangSys_ HB_LangSys; + + +struct HB_LangSysRecord_ +{ + FT_ULong LangSysTag; /* LangSysTag identifier */ + HB_LangSys LangSys; /* LangSys table */ +}; + +typedef struct HB_LangSysRecord_ HB_LangSysRecord; + + +struct HB_Script_ +{ + HB_LangSys DefaultLangSys; /* DefaultLangSys table */ + FT_UShort LangSysCount; /* number of LangSysRecords */ + HB_LangSysRecord* LangSysRecord; /* array of LangSysRecords */ +}; + +typedef struct HB_Script_ HB_Script; + + +struct HB_ScriptRecord_ +{ + FT_ULong ScriptTag; /* ScriptTag identifier */ + HB_Script Script; /* Script table */ +}; + +typedef struct HB_ScriptRecord_ HB_ScriptRecord; + + +struct HB_ScriptList_ +{ + FT_UShort ScriptCount; /* number of ScriptRecords */ + HB_ScriptRecord* ScriptRecord; /* array of ScriptRecords */ +}; + +typedef struct HB_ScriptList_ HB_ScriptList; + + +/* Feature list related structures */ + +struct HB_Feature_ +{ + FT_UShort FeatureParams; /* always 0 for TT Open 1.0 */ + FT_UShort LookupListCount; /* number of LookupList indices */ + FT_UShort* LookupListIndex; /* array of LookupList indices */ +}; + +typedef struct HB_Feature_ HB_Feature; + + +struct HB_FeatureRecord_ +{ + FT_ULong FeatureTag; /* FeatureTag identifier */ + HB_Feature Feature; /* Feature table */ +}; + +typedef struct HB_FeatureRecord_ HB_FeatureRecord; + + +struct HB_FeatureList_ +{ + FT_UShort FeatureCount; /* number of FeatureRecords */ + HB_FeatureRecord* FeatureRecord; /* array of FeatureRecords */ + FT_UShort* ApplyOrder; /* order to apply features */ + FT_UShort ApplyCount; /* number of elements in ApplyOrder */ +}; + +typedef struct HB_FeatureList_ HB_FeatureList; + + +/* Lookup list related structures */ + +typedef struct HB_SubTable_ HB_SubTable; + + +struct HB_Lookup_ +{ + FT_UShort LookupType; /* Lookup type */ + FT_UShort LookupFlag; /* Lookup qualifiers */ + FT_UShort SubTableCount; /* number of SubTables */ + HB_SubTable* SubTable; /* array of SubTables */ +}; + +typedef struct HB_Lookup_ HB_Lookup; + + +/* The `Properties' field is not defined in the OpenType specification but + is needed for processing lookups. If properties[n] is > 0, the + functions HB_GSUB_Apply_String() resp. HB_GPOS_Apply_String() will + process Lookup[n] for glyphs which have the specific bit not set in + the `properties' field of the input string object. */ + +struct HB_LookupList_ +{ + FT_UShort LookupCount; /* number of Lookups */ + HB_Lookup* Lookup; /* array of Lookup records */ + FT_UInt* Properties; /* array of flags */ +}; + +typedef struct HB_LookupList_ HB_LookupList; + + +/* Possible LookupFlag bit masks. `HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS' comes from the + OpenType 1.2 specification; HB_LOOKUP_FLAG_RIGHT_TO_LEFT has been (re)introduced in + OpenType 1.3 -- if set, the last glyph in a cursive attachment + sequence has to be positioned on the baseline -- regardless of the + writing direction. */ + +#define HB_LOOKUP_FLAG_RIGHT_TO_LEFT 0x0001 +#define HB_LOOKUP_FLAG_IGNORE_BASE_GLYPHS 0x0002 +#define HB_LOOKUP_FLAG_IGNORE_LIGATURES 0x0004 +#define HB_LOOKUP_FLAG_IGNORE_MARKS 0x0008 +#define HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS 0xFF00 + + +struct HB_CoverageFormat1_ +{ + FT_UShort GlyphCount; /* number of glyphs in GlyphArray */ + FT_UShort* GlyphArray; /* array of glyph IDs */ +}; + +typedef struct HB_CoverageFormat1_ HB_CoverageFormat1; + + +struct HB_RangeRecord_ +{ + FT_UShort Start; /* first glyph ID in the range */ + FT_UShort End; /* last glyph ID in the range */ + FT_UShort StartCoverageIndex; /* coverage index of first + glyph ID in the range */ +}; + +typedef struct HB_RangeRecord_ HB_RangeRecord; + + +struct HB_CoverageFormat2_ +{ + FT_UShort RangeCount; /* number of RangeRecords */ + HB_RangeRecord* RangeRecord; /* array of RangeRecords */ +}; + +typedef struct HB_CoverageFormat2_ HB_CoverageFormat2; + + +struct HB_Coverage_ +{ + FT_UShort CoverageFormat; /* 1 or 2 */ + + union + { + HB_CoverageFormat1 cf1; + HB_CoverageFormat2 cf2; + } cf; +}; + +typedef struct HB_Coverage_ HB_Coverage; + + +struct HB_ClassDefFormat1_ +{ + FT_UShort StartGlyph; /* first glyph ID of the + ClassValueArray */ + FT_UShort GlyphCount; /* size of the ClassValueArray */ + FT_UShort* ClassValueArray; /* array of class values */ +}; + +typedef struct HB_ClassDefFormat1_ HB_ClassDefFormat1; + + +struct HB_ClassRangeRecord_ +{ + FT_UShort Start; /* first glyph ID in the range */ + FT_UShort End; /* last glyph ID in the range */ + FT_UShort Class; /* applied to all glyphs in range */ +}; + +typedef struct HB_ClassRangeRecord_ HB_ClassRangeRecord; + + +struct HB_ClassDefFormat2_ +{ + FT_UShort ClassRangeCount; + /* number of ClassRangeRecords */ + HB_ClassRangeRecord* ClassRangeRecord; + /* array of ClassRangeRecords */ +}; + +typedef struct HB_ClassDefFormat2_ HB_ClassDefFormat2; + + +/* The `Defined' field is not defined in the OpenType specification but + apparently needed for processing fonts like trado.ttf: This font + refers to a class which contains not a single element. We map such + classes to class 0. */ + +struct HB_ClassDefinition_ +{ + FT_Bool loaded; + + FT_Bool* Defined; /* array of Booleans. + If Defined[n] is FALSE, + class n contains no glyphs. */ + FT_UShort ClassFormat; /* 1 or 2 */ + + union + { + HB_ClassDefFormat1 cd1; + HB_ClassDefFormat2 cd2; + } cd; +}; + +typedef struct HB_ClassDefinition_ HB_ClassDefinition; + + +struct HB_Device_ +{ + FT_UShort StartSize; /* smallest size to correct */ + FT_UShort EndSize; /* largest size to correct */ + FT_UShort DeltaFormat; /* DeltaValue array data format: + 1, 2, or 3 */ + FT_UShort* DeltaValue; /* array of compressed data */ +}; + +typedef struct HB_Device_ HB_Device; + + +enum HB_Type_ +{ + HB_Type_GSUB, + HB_Type_GPOS +}; + +typedef enum HB_Type_ HB_Type; + + +FT_END_HEADER + +#endif /* HARFBUZZ_OPEN_H */ diff --git a/src/harfbuzz.c b/src/harfbuzz.c new file mode 100644 index 0000000..4fd8bf9 --- /dev/null +++ b/src/harfbuzz.c @@ -0,0 +1,19 @@ +/******************************************************************* + * + * Copyright 1996-2000 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * Copyright 2006 Behdad Esfahbod + * + * This is part of HarfBuzz, an OpenType Layout engine library. + * + * See the file name COPYING for licensing information. + * + ******************************************************************/ +#include "ftglue.c" +#include "harfbuzz-open.c" +#include "harfbuzz-buffer.c" +#include "harfbuzz-gdef.c" +#include "harfbuzz-gsub.c" +#include "harfbuzz-gpos.c" +#include "harfbuzz-dump.c" diff --git a/src/harfbuzz.h b/src/harfbuzz.h new file mode 100644 index 0000000..e8e08a2 --- /dev/null +++ b/src/harfbuzz.h @@ -0,0 +1,23 @@ +/******************************************************************* + * + * Copyright 1996-2000 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * Copyright 2006 Behdad Esfahbod + * + * This is part of HarfBuzz, an OpenType Layout engine library. + * + * See the file name COPYING for licensing information. + * + ******************************************************************/ +#ifndef HARFBUZZ_H +#define HARFBUZZ_H + +#include "harfbuzz-open.h" +#include "harfbuzz-buffer.h" +#include "harfbuzz-gdef.h" +#include "harfbuzz-gsub.h" +#include "harfbuzz-gpos.h" +#include "harfbuzz-dump.h" + +#endif /* HARFBUZZ_OPEN_H */ diff --git a/src/otlbuffer.c b/src/otlbuffer.c deleted file mode 100644 index 5578f8e..0000000 --- a/src/otlbuffer.c +++ /dev/null @@ -1,238 +0,0 @@ -/* otlbuffer.c: Buffer of glyphs for substitution/positioning - * - * Copyright 2004 Red Hat Software - * - * Portions Copyright 1996-2000 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. - */ - -#include - -#include - -/* To get the gcc-3.3 strict-aliasing compatible versions - * FREE/REALLOC_ARRAY/etc. rather than the FT_* versions - * that - */ -#include "ftglue.h" - - static FT_Error - otl_buffer_ensure( OTL_Buffer buffer, - FT_ULong size ) - { - FT_Memory memory = buffer->memory; - FT_ULong new_allocated = buffer->allocated; - - if (size > new_allocated) - { - FT_Error error; - - while (size > new_allocated) - new_allocated += (new_allocated >> 1) + 8; - - if ( REALLOC_ARRAY( buffer->in_string, buffer->allocated, new_allocated, OTL_GlyphItemRec ) ) - return error; - if ( REALLOC_ARRAY( buffer->out_string, buffer->allocated, new_allocated, OTL_GlyphItemRec ) ) - return error; - if ( REALLOC_ARRAY( buffer->positions, buffer->allocated, new_allocated, OTL_PositionRec ) ) - return error; - - buffer->allocated = new_allocated; - } - - return FT_Err_Ok; - } - - FT_Error - otl_buffer_new( FT_Memory memory, - OTL_Buffer *buffer ) - { - FT_Error error; - - if ( ALLOC( *buffer, sizeof( OTL_BufferRec ) ) ) - return error; - - (*buffer)->memory = memory; - (*buffer)->in_length = 0; - (*buffer)->out_length = 0; - (*buffer)->allocated = 0; - (*buffer)->in_pos = 0; - (*buffer)->out_pos = 0; - - (*buffer)->in_string = NULL; - (*buffer)->out_string = NULL; - (*buffer)->positions = NULL; - (*buffer)->max_ligID = 0; - - return FT_Err_Ok; - } - - FT_Error - otl_buffer_swap( OTL_Buffer buffer ) - { - OTL_GlyphItem tmp_string; - - tmp_string = buffer->in_string; - buffer->in_string = buffer->out_string; - buffer->out_string = tmp_string; - - buffer->in_length = buffer->out_length; - buffer->out_length = 0; - - buffer->in_pos = 0; - buffer->out_pos = 0; - - return FT_Err_Ok; - } - - FT_Error - otl_buffer_free( OTL_Buffer buffer ) - { - FT_Memory memory = buffer->memory; - - FREE( buffer->in_string ); - FREE( buffer->out_string ); - FREE( buffer->positions ); - FREE( buffer ); - - return FT_Err_Ok; - } - - FT_Error - otl_buffer_clear( OTL_Buffer buffer ) - { - buffer->in_length = 0; - buffer->out_length = 0; - buffer->in_pos = 0; - buffer->out_pos = 0; - - return FT_Err_Ok; - } - - FT_Error - otl_buffer_add_glyph( OTL_Buffer buffer, - FT_UInt glyph_index, - FT_UInt properties, - FT_UInt cluster ) - { - FT_Error error; - OTL_GlyphItem glyph; - - error = otl_buffer_ensure( buffer, buffer->in_length + 1 ); - if ( error ) - return error; - - glyph = &buffer->in_string[buffer->in_length]; - glyph->gindex = glyph_index; - glyph->properties = properties; - glyph->cluster = cluster; - glyph->component = 0; - glyph->ligID = 0; - glyph->gproperties = OTL_GLYPH_PROPERTIES_UNKNOWN; - - buffer->in_length++; - - return FT_Err_Ok; - } - - /* The following function copies `num_out' elements from `glyph_data' - to `buffer->out_string', advancing the in array pointer in the structure - by `num_in' elements, and the out array pointer by `num_out' elements. - Finally, it sets the `length' field of `out' equal to - `pos' of the `out' structure. - - If `component' is 0xFFFF, the component value from buffer->in_pos - will copied `num_out' times, otherwise `component' itself will - be used to fill the `component' fields. - - If `ligID' is 0xFFFF, the ligID value from buffer->in_pos - will copied `num_out' times, otherwise `ligID' itself will - be used to fill the `ligID' fields. - - The properties for all replacement glyphs are taken - from the glyph at position `buffer->in_pos'. - - The cluster value for the glyph at position buffer->in_pos is used - for all replacement glyphs */ - FT_Error - otl_buffer_add_output_glyphs( OTL_Buffer buffer, - FT_UShort num_in, - FT_UShort num_out, - FT_UShort *glyph_data, - FT_UShort component, - FT_UShort ligID ) - { - FT_Error error; - FT_UShort i; - FT_UInt properties; - FT_UInt cluster; - - error = otl_buffer_ensure( buffer, buffer->out_pos + num_out ); - if ( error ) - return error; - - properties = buffer->in_string[buffer->in_pos].properties; - cluster = buffer->in_string[buffer->in_pos].cluster; - if ( component == 0xFFFF ) - component = buffer->in_string[buffer->in_pos].component; - if ( ligID == 0xFFFF ) - ligID = buffer->in_string[buffer->in_pos].ligID; - - for ( i = 0; i < num_out; i++ ) - { - OTL_GlyphItem item = &buffer->out_string[buffer->out_pos + i]; - - item->gindex = glyph_data[i]; - item->properties = properties; - item->cluster = cluster; - item->component = component; - item->ligID = ligID; - item->gproperties = OTL_GLYPH_PROPERTIES_UNKNOWN; - } - - buffer->in_pos += num_in; - buffer->out_pos += num_out; - - buffer->out_length = buffer->out_pos; - - return FT_Err_Ok; - } - - FT_Error - otl_buffer_add_output_glyph( OTL_Buffer buffer, - FT_UInt glyph_index, - FT_UShort component, - FT_UShort ligID ) - { - FT_UShort glyph_data = glyph_index; - - return otl_buffer_add_output_glyphs ( buffer, 1, 1, - &glyph_data, component, ligID ); - } - - FT_Error - otl_buffer_copy_output_glyph ( OTL_Buffer buffer ) - { - FT_Error error; - - error = otl_buffer_ensure( buffer, buffer->out_pos + 1 ); - if ( error ) - return error; - - buffer->out_string[buffer->out_pos++] = buffer->in_string[buffer->in_pos++]; - buffer->out_length = buffer->out_pos; - - return FT_Err_Ok; - } - - FT_UShort - otl_buffer_allocate_ligid( OTL_Buffer buffer ) - { - return buffer->max_ligID++; - } diff --git a/src/otlbuffer.h b/src/otlbuffer.h deleted file mode 100644 index bcb4e3e..0000000 --- a/src/otlbuffer.h +++ /dev/null @@ -1,103 +0,0 @@ -/* otlbuffer.h: Buffer of glyphs for substitution/positioning - * - * Copyrigh 2004 Red Hat Software - * - * Portions Copyright 1996-2000 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. - */ -#include -#include FT_FREETYPE_H - -#include - -G_BEGIN_DECLS - -#define OTL_GLYPH_PROPERTIES_UNKNOWN 0xFFFF - - typedef struct OTL_GlyphItemRec_ { - FT_UInt gindex; - FT_UInt properties; - FT_UInt cluster; - FT_UShort component; - FT_UShort ligID; - FT_UShort gproperties; - } OTL_GlyphItemRec, *OTL_GlyphItem; - - typedef struct OTL_PositionRec_ { - FT_Pos x_pos; - FT_Pos y_pos; - FT_Pos x_advance; - FT_Pos y_advance; - FT_UShort back; /* number of glyphs to go back - for drawing current glyph */ - FT_Bool new_advance; /* if set, the advance width values are - absolute, i.e., they won't be - added to the original glyph's value - but rather replace them. */ - FT_Short cursive_chain; /* character to which this connects, - may be positive or negative; used - only internally */ - } OTL_PositionRec, *OTL_Position; - - - typedef struct OTL_BufferRec_{ - FT_Memory memory; - FT_ULong allocated; - - FT_ULong in_length; - FT_ULong out_length; - FT_ULong in_pos; - FT_ULong out_pos; - - OTL_GlyphItem in_string; - OTL_GlyphItem out_string; - OTL_Position positions; - FT_UShort max_ligID; - } OTL_BufferRec, *OTL_Buffer; - - FT_Error - otl_buffer_new( FT_Memory memory, - OTL_Buffer *buffer ); - - FT_Error - otl_buffer_swap( OTL_Buffer buffer ); - - FT_Error - otl_buffer_free( OTL_Buffer buffer ); - - FT_Error - otl_buffer_clear( OTL_Buffer buffer ); - - FT_Error - otl_buffer_add_glyph( OTL_Buffer buffer, - FT_UInt glyph_index, - FT_UInt properties, - FT_UInt cluster ); - - FT_Error - otl_buffer_add_output_glyphs( OTL_Buffer buffer, - FT_UShort num_in, - FT_UShort num_out, - FT_UShort *glyph_data, - FT_UShort component, - FT_UShort ligID ); - - FT_Error - otl_buffer_add_output_glyph ( OTL_Buffer buffer, - FT_UInt glyph_index, - FT_UShort component, - FT_UShort ligID ); - - FT_Error - otl_buffer_copy_output_glyph ( OTL_Buffer buffer ); - - FT_UShort - otl_buffer_allocate_ligid( OTL_Buffer buffer ); - -G_END_DECLS