summaryrefslogtreecommitdiff
path: root/Build/source/libs/libttf/extend
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/libs/libttf/extend')
-rw-r--r--Build/source/libs/libttf/extend/ftxcmap.c348
-rw-r--r--Build/source/libs/libttf/extend/ftxcmap.h60
-rw-r--r--Build/source/libs/libttf/extend/ftxerr18.c241
-rw-r--r--Build/source/libs/libttf/extend/ftxerr18.h38
-rw-r--r--Build/source/libs/libttf/extend/ftxgasp.c70
-rw-r--r--Build/source/libs/libttf/extend/ftxgasp.h53
-rw-r--r--Build/source/libs/libttf/extend/ftxgdef.c1127
-rw-r--r--Build/source/libs/libttf/extend/ftxgdef.h216
-rw-r--r--Build/source/libs/libttf/extend/ftxgpos.c6169
-rw-r--r--Build/source/libs/libttf/extend/ftxgpos.h857
-rw-r--r--Build/source/libs/libttf/extend/ftxgsub.c4377
-rw-r--r--Build/source/libs/libttf/extend/ftxgsub.h592
-rw-r--r--Build/source/libs/libttf/extend/ftxkern.c603
-rw-r--r--Build/source/libs/libttf/extend/ftxkern.h181
-rw-r--r--Build/source/libs/libttf/extend/ftxopen.c1439
-rw-r--r--Build/source/libs/libttf/extend/ftxopen.h305
-rw-r--r--Build/source/libs/libttf/extend/ftxopenf.h143
-rw-r--r--Build/source/libs/libttf/extend/ftxpost.c523
-rw-r--r--Build/source/libs/libttf/extend/ftxpost.h107
-rw-r--r--Build/source/libs/libttf/extend/ftxsbit.c1391
-rw-r--r--Build/source/libs/libttf/extend/ftxsbit.h490
-rw-r--r--Build/source/libs/libttf/extend/ftxwidth.c186
-rw-r--r--Build/source/libs/libttf/extend/ftxwidth.h80
-rw-r--r--Build/source/libs/libttf/extend/readme.1st61
24 files changed, 19657 insertions, 0 deletions
diff --git a/Build/source/libs/libttf/extend/ftxcmap.c b/Build/source/libs/libttf/extend/ftxcmap.c
new file mode 100644
index 00000000000..09786b63d94
--- /dev/null
+++ b/Build/source/libs/libttf/extend/ftxcmap.c
@@ -0,0 +1,348 @@
+/*******************************************************************
+ *
+ * ftxcmap.h 1.0
+ *
+ * API extension for iterating over Cmaps
+ *
+ * Copyright 1996-1999 by Juliusz Chroboczek,
+ * 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 "ttconfig.h"
+#include "ftxcmap.h"
+
+#include "tttypes.h"
+#include "ttobjs.h"
+#include "tttables.h"
+
+static Long charmap_first4 ( PCMap4, UShort* );
+static Long charmap_next4 ( PCMap4, UShort, UShort* );
+static Long charmap_last4 ( PCMap4, UShort* );
+static UShort charmap_find_id4( PCMap4, UShort, TCMap4Segment*, UShort );
+
+
+/*******************************************************************
+ *
+ * Function : TT_CharMap_First
+ *
+ * Description : Returns the first valid character code in a
+ * given character map. Also returns the corresponding
+ * glyph index.
+ *
+ * Input : charMap handle to the target character map
+ * id address where the glyph index will be
+ * be returned in case of success
+ *
+ * Output : First valid character code. -1 in case of failure.
+ *
+ * Notes :
+ *
+ ******************************************************************/
+
+EXPORT_FUNC
+TT_Long TT_CharMap_First( TT_CharMap charMap,
+ TT_UShort* id )
+{
+ PCMapTable cmap;
+ UShort i, c;
+
+
+ if ( !( cmap = HANDLE_CharMap( charMap ) ) )
+ return -1;
+
+ switch ( cmap->format )
+ {
+ case 0:
+ if ( id )
+ *id = cmap->c.cmap0.glyphIdArray[0];
+ return 0;
+
+ case 4:
+ return charmap_first4( &cmap->c.cmap4, id );
+
+ case 6:
+ if ( cmap->c.cmap6.entryCount < 1 )
+ return -1;
+
+ if ( id )
+ *id = cmap->c.cmap6.glyphIdArray[0];
+ return cmap->c.cmap6.firstCode;
+
+ default:
+ /* Now loop from 0 to 65535. We can't use a simple "for' on */
+ /* 16-bits systems, hence the "strange" loop here.. */
+ i = 0;
+ do
+ {
+ c = TT_Char_Index( charMap, i );
+ if ( c > 0 )
+ {
+ if ( id )
+ *id = c;
+ return i;
+ }
+ i++;
+ } while ( i != 0 ); /* because i is UShort! */
+
+ return -1;
+ }
+}
+
+
+static Long charmap_first4( PCMap4 cmap4,
+ UShort* id )
+{
+ UShort firstCode;
+
+
+ if ( cmap4->segCountX2 / 2 < 1 )
+ return -1;
+
+ firstCode = cmap4->segments[0].startCount;
+
+ if ( id )
+ *id = charmap_find_id4( cmap4, firstCode, &(cmap4->segments[0]), 0 );
+
+ return firstCode;
+}
+
+
+/*******************************************************************
+ *
+ * Function : TT_CharMap_Next
+ *
+ * Description : Returns the next valid character code in a given
+ * charMap.
+ *
+ * Input : charMap handle to the target char. map
+ * index starting character code
+ * id address where the glyph index of the next
+ * character will be returned
+ *
+ * Output : Next valid character code after 'index'. -1 in case
+ * of failure.
+ *
+ * Notes :
+ *
+ ******************************************************************/
+
+EXPORT_FUNC
+TT_Long TT_CharMap_Next( TT_CharMap charMap,
+ TT_UShort index,
+ TT_UShort* id )
+{
+ PCMapTable cmap;
+ UShort i, c;
+
+
+ cmap = HANDLE_CharMap( charMap );
+ if ( !cmap )
+ return -1;
+
+ switch ( cmap->format )
+ {
+ case 0:
+ if ( index < 255 )
+ {
+ if ( id )
+ *id = cmap->c.cmap0.glyphIdArray[index + 1];
+ return index + 1;
+ }
+ else
+ return -1;
+
+ case 4:
+ return charmap_next4( &cmap->c.cmap4, index, id );
+
+ case 6:
+ {
+ UShort firstCode = cmap->c.cmap6.firstCode;
+
+
+ if ( index + 1 < firstCode + cmap->c.cmap6.entryCount )
+ {
+ if ( id )
+ *id = cmap->c.cmap6.glyphIdArray[index + 1 - firstCode];
+ return index + 1;
+ }
+ else
+ return -1;
+ }
+
+ default:
+ /* Now loop from 0 to 65535. We can't use a simple "for" on */
+ /* 16-bits systems, hence the "strange" loop here.. */
+ i = 0;
+ do
+ {
+ c = TT_Char_Index( charMap, i );
+ if ( c > 0 )
+ {
+ if ( id )
+ *id = c;
+ return i;
+ }
+ i++;
+ } while ( i != 0 ); /* because i is UShort! */
+
+ return -1;
+ }
+}
+
+
+static Long charmap_next4( PCMap4 cmap4,
+ UShort charCode,
+ UShort* id)
+{
+ UShort segCount, nextCode;
+ UShort i;
+ TCMap4Segment seg4;
+
+
+ if ( charCode == 0xFFFF )
+ return -1; /* get it out of the way now */
+
+ segCount = cmap4->segCountX2 / 2;
+
+ for ( i = 0; i < segCount; i++ )
+ if ( charCode < cmap4->segments[i].endCount )
+ break;
+
+ /* Safety check - even though the last endCount should be 0xFFFF */
+ if ( i >= segCount )
+ return -1;
+
+ seg4 = cmap4->segments[i];
+
+ if ( charCode < seg4.startCount )
+ nextCode = seg4.startCount;
+ else
+ nextCode = charCode + 1;
+
+ if ( id )
+ *id = charmap_find_id4( cmap4, nextCode, &seg4, i );
+
+ return nextCode;
+}
+
+
+static UShort
+charmap_find_id4( PCMap4 cmap4,
+ UShort charCode,
+ TCMap4Segment* seg4,
+ UShort i )
+{
+ UShort index1;
+
+
+ if ( seg4->idRangeOffset == 0 )
+ return (charCode + seg4->idDelta) & 0xFFFF;
+ else
+ {
+ index1 = seg4->idRangeOffset / 2 + charCode-seg4->startCount -
+ ( cmap4->segCountX2 / 2 - i );
+
+ if ( index1 >= cmap4->numGlyphId || cmap4->glyphIdArray[index1] == 0 )
+ return 0;
+ else
+ return (cmap4->glyphIdArray[index1] + seg4->idDelta) & 0xFFFF;
+ }
+}
+
+
+/*******************************************************************
+ *
+ * Function : TT_CharMap_Last
+ *
+ * Description : Returns the last valid character code in a
+ * given character map. Also returns the corresponding
+ * glyph index.
+ *
+ * Input : charMap handle to the target character map
+ * id address where the glyph index will be
+ * be returned in case of success
+ *
+ * Output : Last valid character code. -1 in case of failure.
+ *
+ * Notes :
+ *
+ ******************************************************************/
+
+EXPORT_FUNC
+TT_Long TT_CharMap_Last( TT_CharMap charMap,
+ TT_UShort* id )
+{
+ PCMapTable cmap;
+ UShort i, c;
+
+
+ if ( !( cmap = HANDLE_CharMap( charMap ) ) )
+ return -1;
+
+ switch ( cmap->format )
+ {
+ case 0:
+ if ( id )
+ *id = cmap->c.cmap0.glyphIdArray[255];
+ return 255;
+
+ case 4:
+ return charmap_last4( &cmap->c.cmap4, id );
+
+ case 6:
+ if ( cmap->c.cmap6.entryCount < 1 )
+ return -1;
+
+ if ( id )
+ *id = cmap->c.cmap6.glyphIdArray[cmap->c.cmap6.entryCount - 1];
+ return cmap->c.cmap6.firstCode + cmap->c.cmap6.entryCount - 1;
+
+ default:
+ i = 65535;
+ do
+ {
+ c = TT_Char_Index( charMap, i );
+ if ( c > 0 )
+ {
+ if ( id )
+ *id = c;
+ return i;
+ }
+ i--;
+ } while ( i != 0 );
+
+ return -1;
+ }
+}
+
+
+static Long charmap_last4( PCMap4 cmap4,
+ UShort* id )
+{
+ UShort lastCode;
+
+
+ if ( cmap4->segCountX2 / 2 < 1 )
+ return -1;
+
+ lastCode = cmap4->segments[cmap4->segCountX2 / 2 - 1].endCount;
+
+ if ( id )
+ *id = charmap_find_id4( cmap4,
+ lastCode,
+ &(cmap4->segments[cmap4->segCountX2 / 2 - 1]),
+ 0 );
+
+ return lastCode;
+}
+
+
+/* END */
diff --git a/Build/source/libs/libttf/extend/ftxcmap.h b/Build/source/libs/libttf/extend/ftxcmap.h
new file mode 100644
index 00000000000..38ed8e1d337
--- /dev/null
+++ b/Build/source/libs/libttf/extend/ftxcmap.h
@@ -0,0 +1,60 @@
+/*******************************************************************
+ *
+ * ftxcmap.h 1.0
+ *
+ * API extension for iterating over Cmaps
+ *
+ * Copyright 1996-1999 by Juliusz Chroboczek,
+ * 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 FTXCMAP_H
+#define FTXCMAP_H
+
+#include "freetype.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ /* Find the first entry of a Cmap. Its glyph index is returned */
+ /* in the "id" field, while the function returns the first valid */
+ /* character code in the Cmap. It returns -1 in case of failure. */
+
+ EXPORT_DEF
+ TT_Long TT_CharMap_First( TT_CharMap charMap,
+ TT_UShort* id );
+
+
+ /* Find the next entry of Cmap. Same return conventions. */
+
+ EXPORT_DEF
+ TT_Long TT_CharMap_Next( TT_CharMap charMap,
+ TT_UShort startId,
+ TT_UShort* id );
+
+ /* Find the last entry of a Cmap. Its glyph index is returned */
+ /* in the "id" field, while the function returns the last valid */
+ /* character code in the Cmap. It returns -1 in case of failure. */
+
+ EXPORT_DEF
+ TT_Long TT_CharMap_Last( TT_CharMap charMap,
+ TT_UShort* id );
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FTXCMAP_H */
+
+
+/* END */
diff --git a/Build/source/libs/libttf/extend/ftxerr18.c b/Build/source/libs/libttf/extend/ftxerr18.c
new file mode 100644
index 00000000000..ac8934a0165
--- /dev/null
+++ b/Build/source/libs/libttf/extend/ftxerr18.c
@@ -0,0 +1,241 @@
+/****************************************************************************/
+/* */
+/* Erwin Dieterich, 15. 10. 1997 */
+/* - 15. 08. 1999 */
+/* */
+/* TT_ErrToString: translate error codes to character strings */
+/* */
+/* This extension provides internationalized error strings from the */
+/* various error messages. It uses the "gettext" package if available */
+/* or returns English/American message strings if not. */
+/* */
+/* If you do not want to use it, or if you encounter some problems */
+/* compiling this file, try to disable nls support when invoking */
+/* ./configure (on Unix). */
+/* */
+/* */
+/****************************************************************************/
+
+#include "ttconfig.h"
+
+#include "ftxerr18.h"
+#include "ftxkern.h"
+#include "ftxpost.h"
+#include "ftxopen.h"
+
+#ifdef HAVE_LOCALE_H
+#include <locale.h>
+#endif
+
+#ifdef HAVE_LIBINTL_H
+#include <libintl.h>
+#undef _
+#define _( String ) dgettext( "freetype", String )
+#else
+#define _( String ) ( String )
+#endif
+
+
+EXPORT_FUNC
+TT_String* TT_ErrToString18( TT_Error error )
+{
+
+ switch ( error )
+ {
+ /* ----- high-level API error codes ----- */
+ case TT_Err_Ok:
+ return _( "Successful function call, no error." );
+
+ case TT_Err_Invalid_Face_Handle:
+ return _( "Invalid face handle." );
+ case TT_Err_Invalid_Instance_Handle:
+ return _( "Invalid instance handle." );
+ case TT_Err_Invalid_Glyph_Handle:
+ return _( "Invalid glyph handle." );
+ case TT_Err_Invalid_CharMap_Handle:
+ return _( "Invalid charmap handle." );
+ case TT_Err_Invalid_Result_Address:
+ return _( "Invalid result address." );
+ case TT_Err_Invalid_Glyph_Index:
+ return _( "Invalid glyph index." );
+ case TT_Err_Invalid_Argument:
+ return _( "Invalid argument." );
+ case TT_Err_Could_Not_Open_File:
+ return _( "Could not open file." );
+ case TT_Err_File_Is_Not_Collection:
+ return _( "File is not a TrueType collection." );
+
+ case TT_Err_Table_Missing:
+ return _( "Mandatory table missing." );
+ case TT_Err_Invalid_Horiz_Metrics:
+ return _( "Invalid horizontal metrics (hmtx table broken)." );
+ case TT_Err_Invalid_CharMap_Format:
+ return _( "Invalid charmap format." );
+ case TT_Err_Invalid_PPem:
+ return _( "Invalid ppem value." );
+ case TT_Err_Invalid_Vert_Metrics:
+ return _( "Invalid vertical metrics (vmtx table broken)." );
+
+ case TT_Err_Invalid_File_Format:
+ return _( "Invalid file format." );
+
+ case TT_Err_Invalid_Engine:
+ return _( "Invalid engine." );
+ case TT_Err_Too_Many_Extensions:
+ return _( "Too many extensions." );
+ case TT_Err_Extensions_Unsupported:
+ return _( "Extensions unsupported." );
+ case TT_Err_Invalid_Extension_Id:
+ return _( "Invalid extension id." );
+
+ case TT_Err_No_Vertical_Data:
+ return _( "No vertical data in font." );
+
+ case TT_Err_Max_Profile_Missing:
+ return _( "Maximum Profile (maxp) table missing." );
+ case TT_Err_Header_Table_Missing:
+ return _( "Font Header (head) table missing." );
+ case TT_Err_Horiz_Header_Missing:
+ return _( "Horizontal Header (hhea) table missing." );
+ case TT_Err_Locations_Missing:
+ return _( "Index to Location (loca) table missing." );
+ case TT_Err_Name_Table_Missing:
+ return _( "Naming (name) table missing." );
+ case TT_Err_CMap_Table_Missing:
+ return _( "Character to Glyph Index Mapping (cmap) tables missing." );
+ case TT_Err_Hmtx_Table_Missing:
+ return _( "Horizontal Metrics (hmtx) table missing." );
+ case TT_Err_OS2_Table_Missing:
+ return _( "OS/2 table missing." );
+ case TT_Err_Post_Table_Missing:
+ return _( "PostScript (post) table missing." );
+ case TT_Err_Glyf_Table_Missing:
+ return _( "Glyph (glyf) table missing." );
+
+
+ /* ----- memory component error codes ----- */
+ case TT_Err_Out_Of_Memory:
+ return _( "Out of memory." );
+
+
+ /* ----- file component error codes ----- */
+ case TT_Err_Invalid_File_Offset:
+ return _( "Invalid file offset." );
+ case TT_Err_Invalid_File_Read:
+ return _( "Invalid file read." );
+ case TT_Err_Invalid_Frame_Access:
+ return _( "Invalid frame access." );
+
+
+ /* ----- glyph loader error codes ----- */
+ case TT_Err_Too_Many_Points:
+ return _( "Too many points." );
+ case TT_Err_Too_Many_Contours:
+ return _( "Too many contours." );
+ case TT_Err_Invalid_Composite:
+ return _( "Invalid composite glyph." );
+ case TT_Err_Too_Many_Ins:
+ return _( "Too many instructions." );
+
+
+ /* ----- byte-code interpreter error codes ----- */
+ case TT_Err_Invalid_Opcode:
+ return _( "Invalid opcode." );
+ case TT_Err_Too_Few_Arguments:
+ return _( "Too few arguments." );
+ case TT_Err_Stack_Overflow:
+ return _( "Stack overflow." );
+ case TT_Err_Code_Overflow:
+ return _( "Code overflow." );
+ case TT_Err_Bad_Argument:
+ return _( "Bad argument." );
+ case TT_Err_Divide_By_Zero:
+ return _( "Divide by zero." );
+ case TT_Err_Storage_Overflow:
+ return _( "Storage overflow." );
+ case TT_Err_Cvt_Overflow:
+ return _( "Control Value (cvt) table overflow." );
+ case TT_Err_Invalid_Reference:
+ return _( "Invalid reference." );
+ case TT_Err_Invalid_Distance:
+ return _( "Invalid distance." );
+ case TT_Err_Interpolate_Twilight:
+ return _( "Interpolate twilight points." );
+ case TT_Err_Debug_OpCode:
+ return _( "`DEBUG' opcode found." );
+ case TT_Err_ENDF_In_Exec_Stream:
+ return _( "`ENDF' in byte-code stream." );
+ case TT_Err_Out_Of_CodeRanges:
+ return _( "Out of code ranges." );
+ case TT_Err_Nested_DEFS:
+ return _( "Nested function definitions." );
+ case TT_Err_Invalid_CodeRange:
+ return _( "Invalid code range." );
+ case TT_Err_Invalid_Displacement:
+ return _( "Invalid displacement." );
+ case TT_Err_Execution_Too_Long:
+ return _( "Endless loop encountered while executing instructions." );
+
+
+ /* ----- internal failure error codes ----- */
+ case TT_Err_Nested_Frame_Access:
+ return _( "Nested frame access." );
+ case TT_Err_Invalid_Cache_List:
+ return _( "Invalid cache list." );
+ case TT_Err_Could_Not_Find_Context:
+ return _( "Could not find context." );
+ case TT_Err_Unlisted_Object:
+ return _( "Unlisted object." );
+
+
+ /* ----- scan-line converter error codes ----- */
+ case TT_Err_Raster_Pool_Overflow:
+ return _( "Raster pool overflow." );
+ case TT_Err_Raster_Negative_Height:
+ return _( "Raster: negative height encountered." );
+ case TT_Err_Raster_Invalid_Value:
+ return _( "Raster: invalid value." );
+ case TT_Err_Raster_Not_Initialized:
+ return _( "Raster not initialized." );
+
+
+ /* ----- engine extensions error codes ----- */
+ case TT_Err_Invalid_Kerning_Table_Format:
+ return _( "Invalid kerning (kern) table format." );
+ case TT_Err_Invalid_Kerning_Table:
+ return _( "Invalid kerning (kern) table." );
+ case TT_Err_Invalid_Post_Table_Format:
+ return _( "Invalid PostScript (post) table format." );
+ case TT_Err_Invalid_Post_Table:
+ return _( "Invalid PostScript (post) table." );
+
+
+ /* ----- TrueType Open extension error codes ----- */
+
+ case TTO_Err_Invalid_SubTable_Format:
+ return _( "Invalid TrueType Open subtable format." );
+ case TTO_Err_Invalid_SubTable:
+ return _( "Invalid TrueType Open subtable." );
+ case TTO_Err_Not_Covered:
+ return _( "Glyph(s) not covered by lookup." );
+ case TTO_Err_Too_Many_Nested_Contexts:
+ return _( "Too many nested context substitutions." );
+ case TTO_Err_Invalid_GSUB_SubTable_Format:
+ return _( "Invalid glyph substitution (GSUB) table format." );
+ case TTO_Err_Invalid_GSUB_SubTable:
+ return _( "Invalid glyph substitution (GSUB) table." );
+ case TTO_Err_Invalid_GPOS_SubTable_Format:
+ return _( "Invalid glyph positioning (GPOS) table format." );
+ case TTO_Err_Invalid_GPOS_SubTable:
+ return _( "Invalid glyph positioning (GPOS) table." );
+
+
+ default:
+ ;
+ }
+
+ return _( "Invalid Error Number." );
+}
+
+
+/* END */
diff --git a/Build/source/libs/libttf/extend/ftxerr18.h b/Build/source/libs/libttf/extend/ftxerr18.h
new file mode 100644
index 00000000000..3ad060be359
--- /dev/null
+++ b/Build/source/libs/libttf/extend/ftxerr18.h
@@ -0,0 +1,38 @@
+/****************************************************************************/
+/* */
+/* Erwin Dieterich, 15. 10. 1997 */
+/* - 15. 08. 1999 */
+/* */
+/* TT_ErrToString: translate error codes to character strings */
+/* */
+/* This extension provides internationalized error strings from the */
+/* various error messages. It uses the "gettext" package where available */
+/* or returns english/american message strings if not. */
+/* */
+/* If you do not want to use it, or if you encounter some problems */
+/* compiling this file, try to disable nls support by configuring */
+/* FreeType with ./configure --disable-nls */
+/* */
+/* */
+/****************************************************************************/
+
+#ifndef FTXERR18_H
+#define FTXERR18_H
+
+#include "freetype.h"
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+ EXPORT_DEF
+ TT_String* TT_ErrToString18( TT_Error i );
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* FTXERR18_H */
+
+
+/* END */
diff --git a/Build/source/libs/libttf/extend/ftxgasp.c b/Build/source/libs/libttf/extend/ftxgasp.c
new file mode 100644
index 00000000000..aca43157d8d
--- /dev/null
+++ b/Build/source/libs/libttf/extend/ftxgasp.c
@@ -0,0 +1,70 @@
+/*******************************************************************
+ *
+ * ftxgasp.c 1.0
+ *
+ * Gasp table support API extension body
+ *
+ * Copyright 1996-1999 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.
+ *
+ *
+ * The gasp table is currently loaded by the core engine, but the
+ * standard API doesn't give access to it. This file is used to
+ * demonstrate the use of a simple API extension.
+ *
+ ******************************************************************/
+
+#include "ttconfig.h"
+#include "ftxgasp.h"
+
+#include "tttypes.h"
+#include "ttobjs.h"
+#include "tttables.h"
+
+
+ EXPORT_FUNC
+ TT_Error TT_Get_Face_Gasp_Flags( TT_Face face,
+ TT_UShort point_size,
+ TT_Bool* grid_fit,
+ TT_Bool* smooth_font )
+ {
+ PFace faze = HANDLE_Face( face );
+ UShort i, flag;
+
+
+ if ( !faze )
+ return TT_Err_Invalid_Face_Handle;
+
+ if ( faze->gasp.numRanges == 0 || !faze->gasp.gaspRanges )
+ return TT_Err_Table_Missing;
+
+ for ( i = 0; i < faze->gasp.numRanges; i++ )
+ {
+ if ( point_size <= faze->gasp.gaspRanges[i].maxPPEM )
+ {
+ flag = faze->gasp.gaspRanges[i].gaspFlag;
+
+ *grid_fit = ( (flag & GASP_GRIDFIT) != 0 );
+ *smooth_font = ( (flag & GASP_DOGRAY ) != 0 );
+
+ return TT_Err_Ok;
+ }
+ }
+
+ /* for very large fonts we enable font smoothing and discard */
+ /* grid fitting */
+
+ *grid_fit = 0;
+ *smooth_font = 1;
+
+ return TT_Err_Ok;
+ }
+
+
+/* END */
diff --git a/Build/source/libs/libttf/extend/ftxgasp.h b/Build/source/libs/libttf/extend/ftxgasp.h
new file mode 100644
index 00000000000..a0dde720c0f
--- /dev/null
+++ b/Build/source/libs/libttf/extend/ftxgasp.h
@@ -0,0 +1,53 @@
+/*******************************************************************
+ *
+ * ftxgasp.h 1.0
+ *
+ * Gasp table support API extension
+ *
+ * Copyright 1996-1999 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.
+ *
+ *
+ * The gasp table is currently loaded by the core engine, but the
+ * standard API doesn't give access to it. This file is used to
+ * demonstrate the use of a simple API extension.
+ *
+ ******************************************************************/
+
+#ifndef FTXGASP_H
+#define FTXGASP_H
+
+#include "freetype.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+ /* This function returns for a given 'point_size' the values of the */
+ /* gasp flags 'grid_fit' and 'smooth_font'. The returned values */
+ /* are booleans (where 0 = NO, and 1 = YES). */
+
+ /* Note that this function will return TT_Err_Table_Missing if */
+ /* the font file doesn't contain any gasp table. */
+
+ EXPORT_DEF
+ TT_Error TT_Get_Face_Gasp_Flags( TT_Face face,
+ TT_UShort point_size,
+ TT_Bool* grid_fit,
+ TT_Bool* smooth_font );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FTXGASP_H */
+
+
+/* END */
diff --git a/Build/source/libs/libttf/extend/ftxgdef.c b/Build/source/libs/libttf/extend/ftxgdef.c
new file mode 100644
index 00000000000..a4be21ecc90
--- /dev/null
+++ b/Build/source/libs/libttf/extend/ftxgdef.c
@@ -0,0 +1,1127 @@
+/*******************************************************************
+ *
+ * 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 "tttypes.h"
+#include "tttags.h"
+#include "ttload.h"
+#include "ttextend.h"
+#include "ttmemory.h"
+#include "ttfile.h"
+
+#include "ftxopen.h"
+#include "ftxopenf.h"
+
+
+#define GDEF_ID Build_Extension_ID( 'G', 'D', 'E', 'F' )
+
+
+ static TT_Error Load_AttachList( TTO_AttachList* al,
+ PFace input );
+ static TT_Error Load_LigCaretList( TTO_LigCaretList* lcl,
+ PFace input );
+
+ static void Free_AttachList( TTO_AttachList* al );
+ static void Free_LigCaretList( TTO_LigCaretList* lcl );
+
+ static void Free_NewGlyphClasses( TTO_GDEFHeader* gdef );
+
+
+
+ /**********************
+ * Extension Functions
+ **********************/
+
+
+ static TT_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 TT_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 );
+ Free_AttachList( &gdef->AttachList );
+ Free_ClassDefinition( &gdef->GlyphClassDef );
+ Free_ClassDefinition( &gdef->MarkAttachClassDef );
+
+ Free_NewGlyphClasses( gdef );
+ }
+
+ return TT_Err_Ok;
+ }
+
+
+ EXPORT_FUNC
+ TT_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 );
+ }
+
+
+ EXPORT_FUNC
+ TT_Error TT_Load_GDEF_Table( TT_Face face,
+ TTO_GDEFHeader* retptr )
+ {
+ ULong cur_offset, new_offset, base_offset;
+
+ TT_Error error;
+ TT_Stream stream;
+ TTO_GDEFHeader* gdef;
+
+ PFace faze = HANDLE_Face( face );
+
+
+ if ( !retptr )
+ return TT_Err_Invalid_Argument;
+
+ if ( !faze )
+ return TT_Err_Invalid_Face_Handle;
+
+ error = TT_Extension_Get( faze, GDEF_ID, (void**)&gdef );
+ if ( error )
+ return error;
+
+ if ( gdef->offset == 0 )
+ return TT_Err_Table_Missing; /* no GDEF table; nothing to do */
+
+ /* now access stream */
+
+ if ( USE_Stream( faze->stream, stream ) )
+ return error;
+
+ base_offset = gdef->offset;
+
+ /* skip version */
+
+ if ( FILE_Seek( base_offset + 4L ) ||
+ ACCESS_Frame( 2L ) )
+ return error;
+
+ 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,
+ faze ) ) != TT_Err_Ok )
+ return error;
+ (void)FILE_Seek( cur_offset );
+ }
+ else
+ gdef->GlyphClassDef.loaded = FALSE;
+
+ 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_AttachList( &gdef->AttachList,
+ faze ) ) != TT_Err_Ok )
+ goto Fail1;
+ (void)FILE_Seek( cur_offset );
+ }
+ else
+ gdef->AttachList.loaded = FALSE;
+
+ 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_LigCaretList( &gdef->LigCaretList,
+ faze ) ) != TT_Err_Ok )
+ goto Fail2;
+ (void)FILE_Seek( cur_offset );
+ }
+ else
+ gdef->LigCaretList.loaded = FALSE;
+
+ /* 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 current file offset. */
+
+ gdef->MarkAttachClassDef_offset = FILE_Pos();
+ gdef->MarkAttachClassDef.loaded = FALSE;
+
+ gdef->LastGlyph = 0;
+ gdef->NewGlyphClasses = NULL;
+ gdef->loaded = TRUE;
+
+ *retptr = *gdef;
+ DONE_Stream( stream );
+
+ return TT_Err_Ok;
+
+ Fail2:
+ Free_AttachList( &gdef->AttachList );
+
+ Fail1:
+ Free_ClassDefinition( &gdef->GlyphClassDef );
+
+ /* release stream */
+
+ DONE_Stream( stream );
+
+ return error;
+ }
+
+
+
+ /*******************************
+ * AttachList related functions
+ *******************************/
+
+
+ /* AttachPoint */
+
+ static TT_Error Load_AttachPoint( TTO_AttachPoint* ap,
+ PFace input )
+ {
+ DEFINE_LOAD_LOCALS( input->stream );
+
+ UShort n, count;
+ 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, 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 )
+ {
+ FREE( ap->PointIndex );
+ }
+
+
+ /* AttachList */
+
+ static TT_Error Load_AttachList( TTO_AttachList* al,
+ PFace input )
+ {
+ DEFINE_LOAD_LOCALS( input->stream );
+
+ UShort n, count;
+ 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, input ) ) != 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], input ) ) != TT_Err_Ok )
+ goto Fail1;
+ (void)FILE_Seek( cur_offset );
+ }
+
+ al->loaded = TRUE;
+
+ return TT_Err_Ok;
+
+ Fail1:
+ for ( n = 0; n < count; n++ )
+ Free_AttachPoint( &ap[n] );
+
+ FREE( ap );
+
+ Fail2:
+ Free_Coverage( &al->Coverage );
+ return error;
+ }
+
+
+ static void Free_AttachList( TTO_AttachList* al )
+ {
+ 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] );
+
+ FREE( ap );
+ }
+
+ Free_Coverage( &al->Coverage );
+ }
+
+
+
+ /*********************************
+ * LigCaretList related functions
+ *********************************/
+
+
+ /* CaretValueFormat1 */
+ /* CaretValueFormat2 */
+ /* CaretValueFormat3 */
+ /* CaretValueFormat4 */
+
+ static TT_Error Load_CaretValue( TTO_CaretValue* cv,
+ PFace input )
+ {
+ DEFINE_LOAD_LOCALS( input->stream );
+
+ 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,
+ input ) ) != 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 )
+ {
+ if ( cv->CaretValueFormat == 3 )
+ Free_Device( &cv->cvf.cvf3.Device );
+ }
+
+
+ /* LigGlyph */
+
+ static TT_Error Load_LigGlyph( TTO_LigGlyph* lg,
+ PFace input )
+ {
+ DEFINE_LOAD_LOCALS( input->stream );
+
+ UShort n, count;
+ 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], input ) ) != TT_Err_Ok )
+ goto Fail;
+ (void)FILE_Seek( cur_offset );
+ }
+
+ return TT_Err_Ok;
+
+ Fail:
+ for ( n = 0; n < count; n++ )
+ Free_CaretValue( &cv[n] );
+
+ FREE( cv );
+ return error;
+ }
+
+
+ static void Free_LigGlyph( TTO_LigGlyph* lg )
+ {
+ 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] );
+
+ FREE( cv );
+ }
+ }
+
+
+ /* LigCaretList */
+
+ static TT_Error Load_LigCaretList( TTO_LigCaretList* lcl,
+ PFace input )
+ {
+ DEFINE_LOAD_LOCALS( input->stream );
+
+ UShort n, count;
+ 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, input ) ) != 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], input ) ) != TT_Err_Ok )
+ goto Fail1;
+ (void)FILE_Seek( cur_offset );
+ }
+
+ lcl->loaded = TRUE;
+
+ return TT_Err_Ok;
+
+ Fail1:
+ for ( n = 0; n < count; n++ )
+ Free_LigGlyph( &lg[n] );
+
+ FREE( lg );
+
+ Fail2:
+ Free_Coverage( &lcl->Coverage );
+ return error;
+ }
+
+
+ static void Free_LigCaretList( TTO_LigCaretList* lcl )
+ {
+ 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] );
+
+ FREE( lg );
+ }
+
+ Free_Coverage( &lcl->Coverage );
+ }
+
+
+
+ /***********
+ * GDEF API
+ ***********/
+
+
+ static UShort Get_New_Class( TTO_GDEFHeader* gdef,
+ UShort glyphID,
+ UShort index )
+ {
+ UShort glyph_index, array_index;
+ UShort byte, bits;
+
+ TTO_ClassRangeRecord* gcrr;
+ UShort** ngc;
+
+
+ if ( glyphID >= gdef->LastGlyph )
+ return 0;
+
+ gcrr = gdef->GlyphClassDef.cd.cd2.ClassRangeRecord;
+ ngc = gdef->NewGlyphClasses;
+
+ if ( glyphID < gcrr[index].Start )
+ {
+ array_index = 0;
+ 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 + 1];
+ bits = byte >> ( 16 - ( glyph_index % 4 + 1 ) * 4 );
+
+ return bits & 0x000F;
+ }
+
+
+ EXPORT_FUNC
+ TT_Error TT_GDEF_Get_Glyph_Property( TTO_GDEFHeader* gdef,
+ TT_UShort glyphID,
+ TT_UShort* property )
+ {
+ UShort class, index;
+
+ TT_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 TT_Error Make_ClassRange( TTO_ClassDefinition* cd,
+ UShort start,
+ UShort end,
+ UShort class )
+ {
+ TT_Error error;
+ UShort index;
+
+ TTO_ClassDefFormat2* cdf2;
+ TTO_ClassRangeRecord* crr;
+
+
+ cdf2 = &cd->cd.cd2;
+
+ cdf2->ClassRangeCount++;
+
+ if ( REALLOC_ARRAY( cdf2->ClassRangeRecord, cdf2->ClassRangeCount,
+ TTO_ClassRangeRecord ) )
+ return error;
+
+ 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
+ TT_Error TT_GDEF_Build_ClassDefinition( TTO_GDEFHeader* gdef,
+ TT_UShort num_glyphs,
+ TT_UShort glyph_count,
+ TT_UShort* glyph_array,
+ TT_UShort* class_array )
+ {
+ UShort start, curr_glyph, curr_class;
+ UShort n, count;
+ TT_Error error;
+
+ TTO_ClassDefinition* gcd;
+ TTO_ClassRangeRecord* gcrr;
+ 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, 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 ) ) != 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 ) ) != 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 ) ) != 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, UShort* ) )
+ goto Fail2;
+
+ 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 ( gcrr[0].Start )
+ {
+ if ( ALLOC_ARRAY( ngc[0], gcrr[0].Start / 4 + 1, UShort ) )
+ goto Fail1;
+ }
+
+ 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 - 1 ) / 4 + 1,
+ UShort ) )
+ goto Fail1;
+ }
+
+ if ( gcrr[count - 1].End != num_glyphs - 1 )
+ {
+ if ( ALLOC_ARRAY( ngc[count],
+ ( num_glyphs - gcrr[count - 1].End - 1 ) / 4 + 1,
+ UShort ) )
+ goto Fail1;
+ }
+
+ gdef->LastGlyph = num_glyphs - 1;
+
+ gdef->MarkAttachClassDef_offset = 0L;
+ gdef->MarkAttachClassDef.loaded = FALSE;
+
+ return TT_Err_Ok;
+
+ Fail1:
+ for ( n = 0; n < count; n++ )
+ FREE( ngc[n] );
+
+ Fail2:
+ FREE( gdef->NewGlyphClasses );
+
+ Fail3:
+ FREE( gcd->cd.cd2.ClassRangeRecord );
+
+ Fail4:
+ FREE( gcd->Defined );
+ return error;
+ }
+
+
+ static void Free_NewGlyphClasses( TTO_GDEFHeader* gdef )
+ {
+ UShort** ngc;
+ 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 );
+ }
+ }
+
+
+ TT_Error Add_Glyph_Property( TTO_GDEFHeader* gdef,
+ UShort glyphID,
+ UShort property )
+ {
+ TT_Error error;
+ UShort class, new_class, index;
+ UShort byte, bits, mask;
+ UShort array_index, glyph_index;
+
+ TTO_ClassRangeRecord* gcrr;
+ 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;
+ }
+
+ gcrr = gdef->GlyphClassDef.cd.cd2.ClassRangeRecord;
+ ngc = gdef->NewGlyphClasses;
+
+ if ( glyphID < gcrr[index].Start )
+ {
+ array_index = 0;
+ 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 + 1];
+ 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 + 1] &= mask;
+ ngc[array_index][glyph_index / 4 + 1] |= bits;
+ }
+
+ return TT_Err_Ok;
+ }
+
+
+ TT_Error Check_Property( TTO_GDEFHeader* gdef,
+ UShort index,
+ UShort flags,
+ UShort* property )
+ {
+ TT_Error error;
+
+
+ if ( gdef )
+ {
+ error = TT_GDEF_Get_Glyph_Property( gdef, index, property );
+ if ( error )
+ return error;
+
+ /* This is OpenType 1.2 */
+
+ if ( flags & IGNORE_SPECIAL_MARKS )
+ if ( (flags & 0xFF00) != *property )
+ return TTO_Err_Not_Covered;
+
+ if ( flags & *property )
+ return TTO_Err_Not_Covered;
+ }
+
+ return TT_Err_Ok;
+ }
+
+
+/* END */
diff --git a/Build/source/libs/libttf/extend/ftxgdef.h b/Build/source/libs/libttf/extend/ftxgdef.h
new file mode 100644
index 00000000000..33872321f65
--- /dev/null
+++ b/Build/source/libs/libttf/extend/ftxgdef.h
@@ -0,0 +1,216 @@
+/*******************************************************************
+ *
+ * ftxgdef.h
+ *
+ * TrueType Open GDEF table support
+ *
+ * Copyright 1996-1999 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_
+ {
+ TT_UShort PointCount; /* size of the PointIndex array */
+ TT_UShort* PointIndex; /* array of contour points */
+ };
+
+ typedef struct TTO_AttachPoint_ TTO_AttachPoint;
+
+
+ struct TTO_AttachList_
+ {
+ TT_Bool loaded;
+
+ TTO_Coverage Coverage; /* Coverage table */
+ TT_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_
+ {
+ TT_Short Coordinate; /* x or y value (in design units) */
+ };
+
+ typedef struct TTO_CaretValueFormat1_ TTO_CaretValueFormat1;
+
+
+ struct TTO_CaretValueFormat2_
+ {
+ TT_UShort CaretValuePoint; /* contour point index on glyph */
+ };
+
+ typedef struct TTO_CaretValueFormat2_ TTO_CaretValueFormat2;
+
+
+ struct TTO_CaretValueFormat3_
+ {
+ TT_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_
+ {
+ TT_UShort IdCaretValue; /* metric ID */
+ };
+
+ typedef struct TTO_CaretValueFormat4_ TTO_CaretValueFormat4;
+
+
+ struct TTO_CaretValue_
+ {
+ TT_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_
+ {
+ TT_Bool loaded;
+
+ TT_UShort CaretCount; /* number of caret values */
+ TTO_CaretValue* CaretValue; /* array of caret values */
+ };
+
+ typedef struct TTO_LigGlyph_ TTO_LigGlyph;
+
+
+ struct TTO_LigCaretList_
+ {
+ TT_Bool loaded;
+
+ TTO_Coverage Coverage; /* Coverage table */
+ TT_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_
+ {
+ TT_Bool loaded;
+ TT_ULong offset;
+
+ TT_Fixed Version;
+
+ TTO_ClassDefinition GlyphClassDef;
+ TTO_AttachList AttachList;
+ TTO_LigCaretList LigCaretList;
+ TT_ULong MarkAttachClassDef_offset;
+ TTO_ClassDefinition MarkAttachClassDef; /* new in OT 1.2 */
+
+ TT_UShort LastGlyph;
+ TT_UShort** NewGlyphClasses;
+ };
+
+ typedef struct TTO_GDEFHeader_ TTO_GDEFHeader;
+
+
+ /* finally, the GDEF API */
+
+ EXPORT_DEF
+ TT_Error TT_Init_GDEF_Extension( TT_Engine engine );
+
+ EXPORT_DEF
+ TT_Error TT_Load_GDEF_Table( TT_Face face,
+ TTO_GDEFHeader* gdef );
+
+ EXPORT_DEF
+ TT_Error TT_GDEF_Get_Glyph_Property( TTO_GDEFHeader* gdef,
+ TT_UShort glyphID,
+ TT_UShort* property );
+ EXPORT_DEF
+ TT_Error TT_GDEF_Build_ClassDefinition( TTO_GDEFHeader* gdef,
+ TT_UShort num_glyphs,
+ TT_UShort glyph_count,
+ TT_UShort* glyph_array,
+ TT_UShort* class_array );
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FTXGDEF_H */
+
+
+/* END */
diff --git a/Build/source/libs/libttf/extend/ftxgpos.c b/Build/source/libs/libttf/extend/ftxgpos.c
new file mode 100644
index 00000000000..25eff3ade52
--- /dev/null
+++ b/Build/source/libs/libttf/extend/ftxgpos.c
@@ -0,0 +1,6169 @@
+/*******************************************************************
+ *
+ * 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.
+ *
+ ******************************************************************/
+
+/* 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 "tttypes.h"
+#include "tttags.h"
+#include "ttload.h"
+#include "ttextend.h"
+#include "ttmemory.h"
+#include "ttfile.h"
+
+#include "ftxopen.h"
+#include "ftxopenf.h"
+
+
+#define GPOS_ID Build_Extension_ID( 'G', 'P', 'O', 'S' )
+
+
+ struct GPOS_Instance_
+ {
+ TTO_GPOSHeader* gpos;
+ TT_Instance instance;
+ TT_Glyph glyph;
+ UShort load_flags; /* how the glyph should be loaded */
+ TT_Bool r2l;
+
+ UShort last; /* the last valid glyph -- used
+ with cursive positioning */
+ TT_Pos anchor_x; /* the coordinates of the anchor point */
+ TT_Pos anchor_y; /* of the last valid glyph */
+ };
+
+ typedef struct GPOS_Instance_ GPOS_Instance;
+
+
+ static TT_Error Do_Glyph_Lookup( GPOS_Instance* gpi,
+ UShort lookup_index,
+ TTO_GSUB_String* in,
+ TTO_GPOS_Data* out,
+ UShort context_length,
+ int nesting_level );
+
+
+
+ /**********************
+ * Extension Functions
+ **********************/
+
+ /* the client application must replace this with something more
+ meaningful if multiple master fonts are to be supported. */
+
+ static TT_Error default_mmfunc( TT_Instance instance,
+ TT_UShort metric_id,
+ TT_Pos* metric_value,
+ void* data )
+ {
+ return TTO_Err_No_MM_Interpreter;
+ }
+
+
+ static TT_Error GPOS_Create( void* ext,
+ PFace face )
+ {
+ DEFINE_LOAD_LOCALS( face->stream );
+
+ TTO_GPOSHeader* gpos = (TTO_GPOSHeader*)ext;
+ Long table;
+
+
+ /* by convention */
+
+ if ( !gpos )
+ return TT_Err_Ok;
+
+ /* a null offset indicates that there is no GPOS table */
+
+ gpos->offset = 0;
+
+ /* we store the start offset and the size of the subtable */
+
+ table = TT_LookUp_Table( face, TTAG_GPOS );
+ if ( table < 0 )
+ return TT_Err_Ok; /* The table is optional */
+
+ if ( FILE_Seek( face->dirTables[table].Offset ) ||
+ ACCESS_Frame( 4L ) )
+ return error;
+
+ gpos->offset = FILE_Pos() - 4L; /* undo ACCESS_Frame() */
+ gpos->Version = GET_ULong();
+
+ FORGET_Frame();
+
+ /* a default mmfunc() handler which just returns an error */
+
+ gpos->mmfunc = default_mmfunc;
+
+ /* the default glyph function is TT_Load_Glyph() */
+
+ gpos->gfunc = TT_Load_Glyph;
+
+ gpos->loaded = FALSE;
+
+ return TT_Err_Ok;
+ }
+
+
+ static TT_Error GPOS_Destroy( void* ext,
+ PFace face )
+ {
+ TTO_GPOSHeader* gpos = (TTO_GPOSHeader*)ext;
+
+
+ /* by convention */
+
+ if ( !gpos )
+ return TT_Err_Ok;
+
+ if ( gpos->loaded )
+ {
+ Free_LookupList( &gpos->LookupList, GPOS );
+ Free_FeatureList( &gpos->FeatureList );
+ Free_ScriptList( &gpos->ScriptList );
+ }
+
+ return TT_Err_Ok;
+ }
+
+
+ EXPORT_FUNC
+ TT_Error TT_Init_GPOS_Extension( TT_Engine engine )
+ {
+ PEngine_Instance _engine = HANDLE_Engine( engine );
+
+
+ if ( !_engine )
+ return TT_Err_Invalid_Engine;
+
+ return TT_Register_Extension( _engine,
+ GPOS_ID,
+ sizeof ( TTO_GPOSHeader ),
+ GPOS_Create,
+ GPOS_Destroy );
+ }
+
+
+ EXPORT_FUNC
+ TT_Error TT_Load_GPOS_Table( TT_Face face,
+ TTO_GPOSHeader* retptr,
+ TTO_GDEFHeader* gdef )
+ {
+ ULong cur_offset, new_offset, base_offset;
+
+ UShort i, num_lookups;
+ TT_Error error;
+ TT_Stream stream;
+ TTO_GPOSHeader* gpos;
+ TTO_Lookup* lo;
+
+ PFace faze = HANDLE_Face( face );
+
+
+ if ( !retptr )
+ return TT_Err_Invalid_Argument;
+
+ if ( !faze )
+ return TT_Err_Invalid_Face_Handle;
+
+ error = TT_Extension_Get( faze, GPOS_ID, (void**)&gpos );
+ if ( error )
+ return error;
+
+ if ( gpos->offset == 0 )
+ return TT_Err_Table_Missing; /* no GPOS table; nothing to do */
+
+ /* now access stream */
+
+ if ( USE_Stream( faze->stream, stream ) )
+ return error;
+
+ base_offset = gpos->offset;
+
+ /* skip version */
+
+ if ( FILE_Seek( base_offset + 4L ) ||
+ ACCESS_Frame( 2L ) )
+ return error;
+
+ new_offset = GET_UShort() + base_offset;
+
+ FORGET_Frame();
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = Load_ScriptList( &gpos->ScriptList,
+ faze ) ) != 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_FeatureList( &gpos->FeatureList,
+ faze ) ) != 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,
+ faze, 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 ) ||
+ ACCESS_Frame( 2L ) )
+ goto Fail1;
+
+ new_offset = GET_UShort();
+
+ FORGET_Frame();
+
+ if ( !new_offset )
+ return TTO_Err_Invalid_GDEF_SubTable;
+
+ new_offset += base_offset;
+
+ if ( FILE_Seek( new_offset ) ||
+ ( error = Load_ClassDefinition( &gdef->MarkAttachClassDef,
+ 256, faze ) ) != TT_Err_Ok )
+ goto Fail1;
+
+ break;
+ }
+ }
+ }
+
+ gpos->loaded = TRUE;
+ *retptr = *gpos;
+ DONE_Stream( stream );
+
+ return TT_Err_Ok;
+
+ Fail1:
+ Free_LookupList( &gpos->LookupList, GPOS );
+
+ Fail2:
+ Free_FeatureList( &gpos->FeatureList );
+
+ Fail3:
+ Free_ScriptList( &gpos->ScriptList );
+
+ /* release stream */
+
+ DONE_Stream( stream );
+
+ return error;
+ }
+
+
+
+ /*****************************
+ * 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 TT_Error Load_ValueRecord( TTO_ValueRecord* vr,
+ UShort format,
+ ULong base_offset,
+ PFace input )
+ {
+ DEFINE_LOAD_LOCALS( input->stream );
+
+ 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,
+ input ) ) != 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,
+ input ) ) != 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,
+ input ) ) != 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,
+ input ) ) != 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 );
+
+ Fail2:
+ Free_Device( &vr->XAdvanceDevice );
+
+ Fail3:
+ Free_Device( &vr->YPlacementDevice );
+ return error;
+ }
+
+
+ static void Free_ValueRecord( TTO_ValueRecord* vr,
+ UShort format )
+ {
+ if ( format & HAVE_Y_ADVANCE_DEVICE )
+ Free_Device( &vr->YAdvanceDevice );
+ if ( format & HAVE_X_ADVANCE_DEVICE )
+ Free_Device( &vr->XAdvanceDevice );
+ if ( format & HAVE_Y_PLACEMENT_DEVICE )
+ Free_Device( &vr->YPlacementDevice );
+ if ( format & HAVE_X_PLACEMENT_DEVICE )
+ Free_Device( &vr->XPlacementDevice );
+ }
+
+
+ static TT_Error Get_ValueRecord( GPOS_Instance* gpi,
+ TTO_ValueRecord* vr,
+ UShort format,
+ TTO_GPOS_Data* gd )
+ {
+ TT_Pos value;
+ Short pixel_value;
+ TT_Error error = TT_Err_Ok;
+ TTO_GPOSHeader* gpos = gpi->gpos;
+ PInstance ins;
+
+ UShort x_ppem, y_ppem;
+ Fixed x_scale, y_scale;
+
+
+ if ( !format )
+ return TT_Err_Ok;
+
+ ins = HANDLE_Instance( gpi->instance );
+
+ x_ppem = ins->metrics.x_ppem;
+ y_ppem = ins->metrics.y_ppem;
+ x_scale = TT_MulDiv( 0x10000,
+ ins->metrics.x_scale1,
+ ins->metrics.x_scale2 );
+ y_scale = TT_MulDiv( 0x10000,
+ ins->metrics.y_scale1,
+ ins->metrics.y_scale2 );
+
+ /* 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;
+
+ /* we use the device tables only if gpi->glyph.z is not NULL */
+
+ if ( gpi->glyph.z )
+ {
+ /* 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->instance, vr->XIdPlacement,
+ &value, gpos->data );
+ if ( error )
+ return error;
+ gd->x_pos += value;
+ }
+ if ( format & HAVE_Y_ID_PLACEMENT )
+ {
+ error = (gpos->mmfunc)( gpi->instance, vr->YIdPlacement,
+ &value, gpos->data );
+ if ( error )
+ return error;
+ gd->y_pos += value;
+ }
+ if ( format & HAVE_X_ID_ADVANCE )
+ {
+ error = (gpos->mmfunc)( gpi->instance, vr->XIdAdvance,
+ &value, gpos->data );
+ if ( error )
+ return error;
+ gd->x_advance += value;
+ }
+ if ( format & HAVE_Y_ID_ADVANCE )
+ {
+ error = (gpos->mmfunc)( gpi->instance, vr->YIdAdvance,
+ &value, gpos->data );
+ if ( error )
+ return error;
+ gd->y_advance += value;
+ }
+
+ return error;
+ }
+
+
+ /* AnchorFormat1 */
+ /* AnchorFormat2 */
+ /* AnchorFormat3 */
+ /* AnchorFormat4 */
+
+ static TT_Error Load_Anchor( TTO_Anchor* an,
+ PFace input )
+ {
+ DEFINE_LOAD_LOCALS( input->stream );
+
+ 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,
+ input ) ) != 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 = 0;
+ }
+
+ 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,
+ input ) ) != 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 = 0;
+ }
+ 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 );
+ return error;
+ }
+
+
+ static void Free_Anchor( TTO_Anchor* an )
+ {
+ if ( an->PosFormat == 3 )
+ {
+ Free_Device( &an->af.af3.YDeviceTable );
+ Free_Device( &an->af.af3.XDeviceTable );
+ }
+ }
+
+
+ static TT_Error Get_Anchor( GPOS_Instance* gpi,
+ TTO_Anchor* an,
+ TT_UShort glyph_index,
+ TT_Pos* x_value,
+ TT_Pos* y_value )
+ {
+ TT_Error error = TT_Err_Ok;
+
+ PInstance ins;
+ PGlyph glyph;
+ TTO_GPOSHeader* gpos = gpi->gpos;
+ UShort ap;
+
+ Short pixel_value;
+ UShort load_flags;
+
+ UShort x_ppem, y_ppem;
+ Fixed x_scale, y_scale;
+
+
+ ins = HANDLE_Instance( gpi->instance );
+
+ x_ppem = ins->metrics.x_ppem;
+ y_ppem = ins->metrics.y_ppem;
+ x_scale = TT_MulDiv( 0x10000,
+ ins->metrics.x_scale1,
+ ins->metrics.x_scale2 );
+ y_scale = TT_MulDiv( 0x10000,
+ ins->metrics.y_scale1,
+ ins->metrics.y_scale2 );
+
+ 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 | TTLOAD_SCALE_GLYPH;
+
+ /* we use the glyph contour point only if gpi->glyph.z is not NULL */
+
+ if ( gpi->glyph.z )
+ {
+ error = (gpos->gfunc)( gpi->instance, gpi->glyph,
+ glyph_index, load_flags );
+ if ( error )
+ return error;
+
+ glyph = HANDLE_Glyph( gpi->glyph );
+ ap = an->af.af2.AnchorPoint;
+
+ /* 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 ( !glyph->outline.n_points )
+ goto no_contour_point;
+
+ if ( ap >= glyph->outline.n_points )
+ return TTO_Err_Invalid_GPOS_SubTable;
+
+ *x_value = glyph->outline.points[ap].x;
+ *y_value = glyph->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:
+ /* we use the device tables only if gpi->glyph.z is not NULL */
+
+ if ( gpi->glyph.z )
+ {
+ 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->instance, an->af.af4.XIdAnchor,
+ x_value, gpos->data );
+ if ( error )
+ return error;
+
+ error = (gpos->mmfunc)( gpi->instance, an->af.af4.YIdAnchor,
+ y_value, gpos->data );
+ if ( error )
+ return error;
+ break;
+ }
+
+ return error;
+ }
+
+
+ /* MarkArray */
+
+ static TT_Error Load_MarkArray ( TTO_MarkArray* ma,
+ PFace input )
+ {
+ DEFINE_LOAD_LOCALS( input->stream );
+
+ UShort n, count;
+ 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, input ) ) != TT_Err_Ok )
+ goto Fail;
+ (void)FILE_Seek( cur_offset );
+ }
+
+ return TT_Err_Ok;
+
+ Fail:
+ for ( n = 0; n < count; n++ )
+ Free_Anchor( &mr[n].MarkAnchor );
+
+ FREE( mr );
+ return error;
+ }
+
+
+ static void Free_MarkArray( TTO_MarkArray* ma )
+ {
+ 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 );
+
+ FREE( mr );
+ }
+ }
+
+
+ /* LookupType 1 */
+
+ /* SinglePosFormat1 */
+ /* SinglePosFormat2 */
+
+ TT_Error Load_SinglePos( TTO_SinglePos* sp,
+ PFace input )
+ {
+ DEFINE_LOAD_LOCALS( input->stream );
+
+ UShort n, count, format;
+ 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, input ) ) != 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, input );
+ 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, input );
+ if ( error )
+ goto Fail1;
+ }
+ break;
+
+ default:
+ return TTO_Err_Invalid_GPOS_SubTable_Format;
+ }
+
+ return TT_Err_Ok;
+
+ Fail1:
+ for ( n = 0; n < count; n++ )
+ Free_ValueRecord( &vr[n], format );
+
+ FREE( vr );
+
+ Fail2:
+ Free_Coverage( &sp->Coverage );
+ return error;
+ }
+
+
+ void Free_SinglePos( TTO_SinglePos* sp )
+ {
+ UShort n, count, format;
+
+ TTO_ValueRecord* v;
+
+
+ format = sp->ValueFormat;
+
+ switch ( sp->PosFormat )
+ {
+ case 1:
+ Free_ValueRecord( &sp->spf.spf1.Value, format );
+ 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 );
+
+ FREE( v );
+ }
+ break;
+ }
+
+ Free_Coverage( &sp->Coverage );
+ }
+
+
+ static TT_Error Lookup_SinglePos( GPOS_Instance* gpi,
+ TTO_SinglePos* sp,
+ TTO_GSUB_String* in,
+ TTO_GPOS_Data* out,
+ UShort flags,
+ UShort context_length )
+ {
+ UShort index, property;
+ TT_Error error;
+ TTO_GPOSHeader* gpos = gpi->gpos;
+
+
+ if ( context_length != 0xFFFF && context_length < 1 )
+ return TTO_Err_Not_Covered;
+
+ if ( CHECK_Property( gpos->gdef, in->string[in->pos], flags, &property ) )
+ return error;
+
+ error = Coverage_Index( &sp->Coverage, in->string[in->pos], &index );
+ if ( error )
+ return error;
+
+ switch ( sp->PosFormat )
+ {
+ case 1:
+ error = Get_ValueRecord( gpi, &sp->spf.spf1.Value,
+ sp->ValueFormat, &out[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, &out[in->pos] );
+ if ( error )
+ return error;
+ break;
+
+ default:
+ return TTO_Err_Invalid_GPOS_SubTable;
+ }
+
+ (in->pos)++;
+
+ return TT_Err_Ok;
+ }
+
+
+ /* LookupType 2 */
+
+ /* PairSet */
+
+ static TT_Error Load_PairSet ( TTO_PairSet* ps,
+ UShort format1,
+ UShort format2,
+ PFace input )
+ {
+ DEFINE_LOAD_LOCALS( input->stream );
+
+ UShort n, count;
+ 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, input );
+ if ( error )
+ goto Fail;
+ }
+ if ( format2 )
+ {
+ error = Load_ValueRecord( &pvr[n].Value2, format2,
+ base_offset, input );
+ if ( error )
+ goto Fail;
+ }
+ }
+
+ return TT_Err_Ok;
+
+ Fail:
+ for ( n = 0; n < count; n++ )
+ {
+ if ( format1 )
+ Free_ValueRecord( &pvr[n].Value1, format1 );
+ if ( format2 )
+ Free_ValueRecord( &pvr[n].Value2, format2 );
+ }
+
+ FREE( pvr );
+ return error;
+ }
+
+
+ static void Free_PairSet( TTO_PairSet* ps,
+ UShort format1,
+ UShort format2 )
+ {
+ 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 );
+ if ( format2 )
+ Free_ValueRecord( &pvr[n].Value2, format2 );
+ }
+
+ FREE( pvr );
+ }
+ }
+
+
+ /* PairPosFormat1 */
+
+ static TT_Error Load_PairPos1( TTO_PairPosFormat1* ppf1,
+ UShort format1,
+ UShort format2,
+ PFace input )
+ {
+ DEFINE_LOAD_LOCALS( input->stream );
+
+ UShort n, count;
+ 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 ) )
+ goto Fail;
+
+ 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, input ) ) != TT_Err_Ok )
+ goto Fail;
+ (void)FILE_Seek( cur_offset );
+ }
+
+ return TT_Err_Ok;
+
+ Fail:
+ for ( n = 0; n < count; n++ )
+ Free_PairSet( &ps[n], format1, format2 );
+
+ FREE( ps );
+ return error;
+ }
+
+
+ static void Free_PairPos1( TTO_PairPosFormat1* ppf1,
+ UShort format1,
+ UShort format2 )
+ {
+ 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 );
+
+ FREE( ps );
+ }
+ }
+
+
+ /* PairPosFormat2 */
+
+ static TT_Error Load_PairPos2( TTO_PairPosFormat2* ppf2,
+ UShort format1,
+ UShort format2,
+ PFace input )
+ {
+ DEFINE_LOAD_LOCALS( input->stream );
+
+ UShort m, n, count1, count2;
+ 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,
+ input ) ) != TT_Err_Ok )
+ return error;
+ if ( FILE_Seek( new_offset2 ) ||
+ ( error = Load_ClassDefinition( &ppf2->ClassDef2, count2,
+ input ) ) != TT_Err_Ok )
+ goto Fail2;
+ (void)FILE_Seek( cur_offset );
+
+ ppf2->Class1Record = NULL;
+
+ if ( ALLOC_ARRAY( ppf2->Class1Record, count1, TTO_Class1Record ) )
+ goto Fail1;
+
+ 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, input );
+ if ( error )
+ goto Fail1;
+ }
+ if ( format2 )
+ {
+ error = Load_ValueRecord( &c2r[n].Value2, format2,
+ base_offset, input );
+ if ( error )
+ goto Fail1;
+ }
+ }
+ }
+
+ return TT_Err_Ok;
+
+ Fail1:
+ for ( m = 0; m < count1; m++ )
+ {
+ c2r = c1r[m].Class2Record;
+
+ for ( n = 0; n < count2; n++ )
+ {
+ if ( format1 )
+ Free_ValueRecord( &c2r[n].Value1, format1 );
+ if ( format2 )
+ Free_ValueRecord( &c2r[n].Value2, format2 );
+ }
+
+ FREE( c2r );
+ }
+
+ FREE( c1r );
+
+ Free_ClassDefinition( &ppf2->ClassDef2 );
+
+ Fail2:
+ Free_ClassDefinition( &ppf2->ClassDef1 );
+ return error;
+ }
+
+
+ static void Free_PairPos2( TTO_PairPosFormat2* ppf2,
+ UShort format1,
+ UShort format2 )
+ {
+ 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 );
+ if ( format2 )
+ Free_ValueRecord( &c2r[n].Value2, format2 );
+ }
+
+ FREE( c2r );
+ }
+
+ FREE( c1r );
+
+ Free_ClassDefinition( &ppf2->ClassDef2 );
+ Free_ClassDefinition( &ppf2->ClassDef1 );
+ }
+ }
+
+
+ TT_Error Load_PairPos( TTO_PairPos* pp,
+ PFace input )
+ {
+ DEFINE_LOAD_LOCALS( input->stream );
+
+ UShort format1, format2;
+ 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, input ) ) != TT_Err_Ok )
+ return error;
+ (void)FILE_Seek( cur_offset );
+
+ switch ( pp->PosFormat )
+ {
+ case 1:
+ error = Load_PairPos1( &pp->ppf.ppf1, format1, format2, input );
+ if ( error )
+ goto Fail;
+ break;
+
+ case 2:
+ error = Load_PairPos2( &pp->ppf.ppf2, format1, format2, input );
+ if ( error )
+ goto Fail;
+ break;
+
+ default:
+ return TTO_Err_Invalid_GPOS_SubTable_Format;
+ }
+
+ return TT_Err_Ok;
+
+ Fail:
+ Free_Coverage( &pp->Coverage );
+ return error;
+ }
+
+
+ void Free_PairPos( TTO_PairPos* pp )
+ {
+ UShort format1, format2;
+
+
+ format1 = pp->ValueFormat1;
+ format2 = pp->ValueFormat2;
+
+ switch ( pp->PosFormat )
+ {
+ case 1:
+ Free_PairPos1( &pp->ppf.ppf1, format1, format2 );
+ break;
+
+ case 2:
+ Free_PairPos2( &pp->ppf.ppf2, format1, format2 );
+ break;
+ }
+
+ Free_Coverage( &pp->Coverage );
+ }
+
+
+ static TT_Error Lookup_PairPos1( GPOS_Instance* gpi,
+ TTO_PairPosFormat1* ppf1,
+ TTO_GSUB_String* in,
+ TTO_GPOS_Data* out,
+ UShort first_pos,
+ UShort index,
+ UShort format1,
+ UShort format2 )
+ {
+ TT_Error error;
+ 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->string[in->pos];
+
+ for ( numpvr = ppf1->PairSet[index].PairValueCount;
+ numpvr;
+ numpvr--, pvr++ )
+ {
+ if ( glyph2 == pvr->SecondGlyph )
+ {
+ error = Get_ValueRecord( gpi, &pvr->Value1, format1,
+ &out[first_pos] );
+ if ( error )
+ return error;
+ return Get_ValueRecord( gpi, &pvr->Value2, format2,
+ &out[in->pos] );
+ }
+ }
+
+ return TTO_Err_Not_Covered;
+ }
+
+
+ static TT_Error Lookup_PairPos2( GPOS_Instance* gpi,
+ TTO_PairPosFormat2* ppf2,
+ TTO_GSUB_String* in,
+ TTO_GPOS_Data* out,
+ UShort first_pos,
+ UShort format1,
+ UShort format2 )
+ {
+ TT_Error error;
+ UShort cl1, cl2;
+
+ TTO_Class1Record* c1r;
+ TTO_Class2Record* c2r;
+
+
+ error = Get_Class( &ppf2->ClassDef1, in->string[first_pos],
+ &cl1, NULL );
+ if ( error )
+ return error;
+ error = Get_Class( &ppf2->ClassDef2, in->string[in->pos],
+ &cl2, NULL );
+ if ( error )
+ 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, &out[first_pos] );
+ if ( error )
+ return error;
+ return Get_ValueRecord( gpi, &c2r->Value2, format2, &out[in->pos] );
+ }
+
+
+ static TT_Error Lookup_PairPos( GPOS_Instance* gpi,
+ TTO_PairPos* pp,
+ TTO_GSUB_String* in,
+ TTO_GPOS_Data* out,
+ UShort flags,
+ UShort context_length )
+ {
+ TT_Error error;
+ UShort index, property, first_pos;
+ TTO_GPOSHeader* gpos = gpi->gpos;
+
+
+ if ( in->pos >= in->length )
+ return TTO_Err_Not_Covered; /* Not enough glyphs in input */
+
+ if ( context_length != 0xFFFF && context_length < 2 )
+ return TTO_Err_Not_Covered;
+
+ if ( CHECK_Property( gpos->gdef, in->string[in->pos], flags, &property ) )
+ return error;
+
+ error = Coverage_Index( &pp->Coverage, in->string[in->pos], &index );
+ if ( error )
+ return error;
+
+ /* second glyph */
+
+ first_pos = in->pos;
+ (in->pos)++;
+
+ while ( CHECK_Property( gpos->gdef, in->string[in->pos],
+ flags, &property ) )
+ {
+ if ( error && error != TTO_Err_Not_Covered )
+ return error;
+
+ if ( in->pos < in->length )
+ (in->pos)++;
+ else
+ break;
+ }
+
+ switch ( pp->PosFormat )
+ {
+ case 1:
+ error = Lookup_PairPos1( gpi, &pp->ppf.ppf1, in, out,
+ first_pos, index,
+ pp->ValueFormat1, pp->ValueFormat2 );
+ break;
+
+ case 2:
+ error = Lookup_PairPos2( gpi, &pp->ppf.ppf2, in, out, first_pos,
+ pp->ValueFormat1, pp->ValueFormat2 );
+ break;
+
+ default:
+ return TTO_Err_Invalid_GPOS_SubTable_Format;
+ }
+
+ /* adjusting the `next' glyph */
+
+ if ( pp->ValueFormat2 )
+ (in->pos)++;
+
+ return error;
+ }
+
+
+ /* LookupType 3 */
+
+ /* CursivePosFormat1 */
+
+ TT_Error Load_CursivePos( TTO_CursivePos* cp,
+ PFace input )
+ {
+ DEFINE_LOAD_LOCALS( input->stream );
+
+ UShort n, count;
+ 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, input ) ) != 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++ )
+ {
+ 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].EntryAnchor,
+ input ) ) != 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,
+ input ) ) != TT_Err_Ok )
+ goto Fail1;
+ (void)FILE_Seek( cur_offset );
+ }
+ else
+ eer[n].ExitAnchor.PosFormat = 0;
+ }
+
+ return TT_Err_Ok;
+
+ Fail1:
+ for ( n = 0; n < count; n++ )
+ {
+ Free_Anchor( &eer[n].EntryAnchor );
+ Free_Anchor( &eer[n].ExitAnchor );
+ }
+
+ FREE( eer );
+
+ Fail2:
+ Free_Coverage( &cp->Coverage );
+ return error;
+ }
+
+
+ void Free_CursivePos( TTO_CursivePos* cp )
+ {
+ 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 );
+ Free_Anchor( &eer[n].ExitAnchor );
+ }
+
+ FREE( eer );
+ }
+
+ Free_Coverage( &cp->Coverage );
+ }
+
+
+ static TT_Error Lookup_CursivePos( GPOS_Instance* gpi,
+ TTO_CursivePos* cp,
+ TTO_GSUB_String* in,
+ TTO_GPOS_Data* out,
+ UShort flags,
+ UShort context_length )
+ {
+ UShort index, property;
+ TT_Error error;
+ TTO_GPOSHeader* gpos = gpi->gpos;
+
+ TTO_EntryExitRecord* eer;
+ TT_Pos entry_x, entry_y;
+ TT_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->string[in->pos], 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->string[in->pos], &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 <andreib@microsoft.com> 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->string[in->pos],
+ &entry_x, &entry_y );
+ if ( error == TTO_Err_Not_Covered )
+ goto end;
+ if ( error )
+ return error;
+
+ if ( gpi->r2l )
+ {
+ out[in->pos].x_advance = entry_x - gpi->anchor_x;
+ out[in->pos].new_advance = TRUE;
+ }
+ else
+ {
+ out[gpi->last].x_advance = gpi->anchor_x - entry_x;
+ out[gpi->last].new_advance = TRUE;
+ }
+
+ out[in->pos].y_pos = gpi->anchor_y - entry_y + out[gpi->last].y_pos;
+
+ end:
+ error = Get_Anchor( gpi, &eer->ExitAnchor, in->string[in->pos],
+ &exit_x, &exit_y );
+ if ( error == TTO_Err_Not_Covered )
+ gpi->last = 0xFFFF;
+ else
+ {
+ gpi->last = in->pos;
+ gpi->anchor_x = exit_x;
+ gpi->anchor_y = exit_y;
+ }
+ if ( error )
+ return error;
+
+ (in->pos)++;
+
+ return TT_Err_Ok;
+ }
+
+
+ /* LookupType 4 */
+
+ /* BaseArray */
+
+ static TT_Error Load_BaseArray( TTO_BaseArray* ba,
+ UShort num_classes,
+ PFace input )
+ {
+ DEFINE_LOAD_LOCALS( input->stream );
+
+ UShort m, n, count;
+ 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 Fail;
+
+ new_offset = GET_UShort() + base_offset;
+
+ FORGET_Frame();
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = Load_Anchor( &ban[n], input ) ) != TT_Err_Ok )
+ goto Fail;
+ (void)FILE_Seek( cur_offset );
+ }
+ }
+
+ return TT_Err_Ok;
+
+ Fail:
+ for ( m = 0; m < count; m++ )
+ {
+ ban = br[m].BaseAnchor;
+
+ for ( n = 0; n < num_classes; n++ )
+ Free_Anchor( &ban[n] );
+
+ FREE( ban );
+ }
+
+ FREE( br );
+ return error;
+ }
+
+
+ static void Free_BaseArray( TTO_BaseArray* ba,
+ UShort num_classes )
+ {
+ 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] );
+
+ FREE( ban );
+ }
+
+ FREE( br );
+ }
+ }
+
+
+ /* MarkBasePosFormat1 */
+
+ TT_Error Load_MarkBasePos( TTO_MarkBasePos* mbp,
+ PFace input )
+ {
+ DEFINE_LOAD_LOCALS( input->stream );
+
+ 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();
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = Load_Coverage( &mbp->MarkCoverage, input ) ) != 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, input ) ) != 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, input ) ) != 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,
+ input ) ) != TT_Err_Ok )
+ goto Fail1;
+
+ return TT_Err_Ok;
+
+ Fail1:
+ Free_MarkArray( &mbp->MarkArray );
+
+ Fail2:
+ Free_Coverage( &mbp->BaseCoverage );
+
+ Fail3:
+ Free_Coverage( &mbp->MarkCoverage );
+ return error;
+ }
+
+
+ void Free_MarkBasePos( TTO_MarkBasePos* mbp )
+ {
+ Free_BaseArray( &mbp->BaseArray, mbp->ClassCount );
+ Free_MarkArray( &mbp->MarkArray );
+ Free_Coverage( &mbp->BaseCoverage );
+ Free_Coverage( &mbp->MarkCoverage );
+ }
+
+
+ static TT_Error Lookup_MarkBasePos( GPOS_Instance* gpi,
+ TTO_MarkBasePos* mbp,
+ TTO_GSUB_String* in,
+ TTO_GPOS_Data* out,
+ UShort flags,
+ UShort context_length )
+ {
+ UShort i, j, mark_index, base_index, property, class;
+ TT_Pos x_mark_value, y_mark_value, x_base_value, y_base_value;
+ TT_Error error;
+ TTO_GPOSHeader* gpos = gpi->gpos;
+
+ TTO_MarkArray* ma;
+ TTO_BaseArray* ba;
+ TTO_BaseRecord* br;
+ TTO_Anchor* mark_anchor;
+ TTO_Anchor* base_anchor;
+
+ TTO_GPOS_Data* 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->string[in->pos],
+ flags, &property ) )
+ return error;
+
+ error = Coverage_Index( &mbp->MarkCoverage, in->string[in->pos],
+ &mark_index );
+ if ( error )
+ return error;
+
+ /* now we search backwards for a base glyph */
+
+ i = 1;
+ j = in->pos - 1;
+
+ while ( i <= in->pos )
+ {
+ error = TT_GDEF_Get_Glyph_Property( gpos->gdef, in->string[j],
+ &property );
+ if ( error )
+ return error;
+
+ if ( property != TTO_MARK )
+ break;
+
+ i++;
+ j--;
+ }
+
+ if ( property != TTO_BASE_GLYPH )
+ return TTO_Err_Not_Covered;
+
+ if ( i > in->pos )
+ return TTO_Err_Not_Covered;
+
+ error = Coverage_Index( &mbp->BaseCoverage, in->string[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->string[in->pos],
+ &x_mark_value, &y_mark_value );
+ if ( error )
+ return error;
+ error = Get_Anchor( gpi, base_anchor, in->string[j],
+ &x_base_value, &y_base_value );
+ if ( error )
+ return error;
+
+ /* anchor points are not cumulative */
+
+ o = &out[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;
+
+ (in->pos)++;
+
+ return TT_Err_Ok;
+ }
+
+
+ /* LookupType 5 */
+
+ /* LigatureAttach */
+
+ static TT_Error Load_LigatureAttach( TTO_LigatureAttach* lat,
+ UShort num_classes,
+ PFace input )
+ {
+ DEFINE_LOAD_LOCALS( input->stream );
+
+ UShort m, n, count;
+ 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 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_Anchor( &lan[n], input ) ) != TT_Err_Ok )
+ goto Fail;
+ (void)FILE_Seek( cur_offset );
+ }
+ else
+ lan[n].PosFormat = 0;
+ }
+ }
+
+ return TT_Err_Ok;
+
+ Fail:
+ for ( m = 0; m < count; m++ )
+ {
+ lan = cr[m].LigatureAnchor;
+
+ for ( n = 0; n < num_classes; n++ )
+ Free_Anchor( &lan[n] );
+
+ FREE( lan );
+ }
+
+ FREE( cr );
+ return error;
+ }
+
+
+ static void Free_LigatureAttach( TTO_LigatureAttach* lat,
+ UShort num_classes )
+ {
+ 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] );
+
+ FREE( lan );
+ }
+
+ FREE( cr );
+ }
+ }
+
+
+ /* LigatureArray */
+
+ static TT_Error Load_LigatureArray( TTO_LigatureArray* la,
+ UShort num_classes,
+ PFace input )
+ {
+ DEFINE_LOAD_LOCALS( input->stream );
+
+ UShort n, count;
+ 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,
+ input ) ) != TT_Err_Ok )
+ goto Fail;
+ (void)FILE_Seek( cur_offset );
+ }
+
+ return TT_Err_Ok;
+
+ Fail:
+ for ( n = 0; n < count; n++ )
+ Free_LigatureAttach( &lat[n], num_classes );
+
+ FREE( lat );
+ return error;
+ }
+
+
+ static void Free_LigatureArray( TTO_LigatureArray* la,
+ UShort num_classes )
+ {
+ 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 );
+
+ FREE( lat );
+ }
+ }
+
+
+ /* MarkLigPosFormat1 */
+
+ TT_Error Load_MarkLigPos( TTO_MarkLigPos* mlp,
+ PFace input )
+ {
+ DEFINE_LOAD_LOCALS( input->stream );
+
+ 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, input ) ) != 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,
+ input ) ) != 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, input ) ) != 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,
+ input ) ) != TT_Err_Ok )
+ goto Fail1;
+
+ return TT_Err_Ok;
+
+ Fail1:
+ Free_MarkArray( &mlp->MarkArray );
+
+ Fail2:
+ Free_Coverage( &mlp->LigatureCoverage );
+
+ Fail3:
+ Free_Coverage( &mlp->MarkCoverage );
+ return error;
+ }
+
+
+ void Free_MarkLigPos( TTO_MarkLigPos* mlp )
+ {
+ Free_LigatureArray( &mlp->LigatureArray, mlp->ClassCount );
+ Free_MarkArray( &mlp->MarkArray );
+ Free_Coverage( &mlp->LigatureCoverage );
+ Free_Coverage( &mlp->MarkCoverage );
+ }
+
+
+ static TT_Error Lookup_MarkLigPos( GPOS_Instance* gpi,
+ TTO_MarkLigPos* mlp,
+ TTO_GSUB_String* in,
+ TTO_GPOS_Data* out,
+ UShort flags,
+ UShort context_length )
+ {
+ UShort i, j, mark_index, lig_index, property, class;
+ UShort mark_glyph;
+ TT_Pos x_mark_value, y_mark_value, x_lig_value, y_lig_value;
+ TT_Error error;
+ TTO_GPOSHeader* gpos = gpi->gpos;
+
+ TTO_MarkArray* ma;
+ TTO_LigatureArray* la;
+ TTO_LigatureAttach* lat;
+ TTO_ComponentRecord* cr;
+ UShort comp_index;
+ TTO_Anchor* mark_anchor;
+ TTO_Anchor* lig_anchor;
+
+ TTO_GPOS_Data* 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->string[in->pos];
+
+ if ( CHECK_Property( gpos->gdef, mark_glyph, flags, &property ) )
+ return error;
+
+ error = Coverage_Index( &mlp->MarkCoverage, mark_glyph, &mark_index );
+ if ( error )
+ return error;
+
+ /* now we search backwards for a ligature */
+
+ i = 1;
+ j = in->pos - 1;
+
+ while ( i <= in->pos )
+ {
+ error = TT_GDEF_Get_Glyph_Property( gpos->gdef, in->string[j],
+ &property );
+ if ( error )
+ return error;
+
+ if ( property != TTO_MARK )
+ break;
+
+ i++;
+ j--;
+ }
+
+ if ( property != TTO_LIGATURE )
+ return TTO_Err_Not_Covered;
+
+ if ( i > in->pos )
+ return TTO_Err_Not_Covered;
+
+ error = Coverage_Index( &mlp->LigatureCoverage, in->string[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->ligIDs && in->components &&
+ in->ligIDs[j] == in->ligIDs[in->pos] )
+ {
+ comp_index = in->components[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->string[in->pos],
+ &x_mark_value, &y_mark_value );
+ if ( error )
+ return error;
+ error = Get_Anchor( gpi, lig_anchor, in->string[j],
+ &x_lig_value, &y_lig_value );
+ if ( error )
+ return error;
+
+ /* anchor points are not cumulative */
+
+ o = &out[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;
+
+ (in->pos)++;
+
+ return TT_Err_Ok;
+ }
+
+
+ /* LookupType 6 */
+
+ /* Mark2Array */
+
+ static TT_Error Load_Mark2Array( TTO_Mark2Array* m2a,
+ UShort num_classes,
+ PFace input )
+ {
+ DEFINE_LOAD_LOCALS( input->stream );
+
+ UShort m, n, count;
+ 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 Fail;
+
+ new_offset = GET_UShort() + base_offset;
+
+ FORGET_Frame();
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = Load_Anchor( &m2an[n], input ) ) != TT_Err_Ok )
+ goto Fail;
+ (void)FILE_Seek( cur_offset );
+ }
+ }
+
+ return TT_Err_Ok;
+
+ Fail:
+ for ( m = 0; m < count; m++ )
+ {
+ m2an = m2r[m].Mark2Anchor;
+
+ for ( n = 0; n < num_classes; n++ )
+ Free_Anchor( &m2an[n] );
+
+ FREE( m2an );
+ }
+
+ FREE( m2r );
+ return error;
+ }
+
+
+ static void Free_Mark2Array( TTO_Mark2Array* m2a,
+ UShort num_classes )
+ {
+ 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] );
+
+ FREE( m2an );
+ }
+
+ FREE( m2r );
+ }
+ }
+
+
+ /* MarkMarkPosFormat1 */
+
+ TT_Error Load_MarkMarkPos( TTO_MarkMarkPos* mmp,
+ PFace input )
+ {
+ DEFINE_LOAD_LOCALS( input->stream );
+
+ 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,
+ input ) ) != 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,
+ input ) ) != 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, input ) ) != 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,
+ input ) ) != TT_Err_Ok )
+ goto Fail1;
+
+ return TT_Err_Ok;
+
+ Fail1:
+ Free_MarkArray( &mmp->Mark1Array );
+
+ Fail2:
+ Free_Coverage( &mmp->Mark2Coverage );
+
+ Fail3:
+ Free_Coverage( &mmp->Mark1Coverage );
+ return error;
+ }
+
+
+ void Free_MarkMarkPos( TTO_MarkMarkPos* mmp )
+ {
+ Free_Mark2Array( &mmp->Mark2Array, mmp->ClassCount );
+ Free_MarkArray( &mmp->Mark1Array );
+ Free_Coverage( &mmp->Mark2Coverage );
+ Free_Coverage( &mmp->Mark1Coverage );
+ }
+
+
+ static TT_Error Lookup_MarkMarkPos( GPOS_Instance* gpi,
+ TTO_MarkMarkPos* mmp,
+ TTO_GSUB_String* in,
+ TTO_GPOS_Data* out,
+ UShort flags,
+ UShort context_length )
+ {
+ UShort j, mark1_index, mark2_index, property, class;
+ TT_Pos x_mark1_value, y_mark1_value,
+ x_mark2_value, y_mark2_value;
+ TT_Error error;
+ TTO_GPOSHeader* gpos = gpi->gpos;
+
+ TTO_MarkArray* ma1;
+ TTO_Mark2Array* ma2;
+ TTO_Mark2Record* m2r;
+ TTO_Anchor* mark1_anchor;
+ TTO_Anchor* mark2_anchor;
+
+ TTO_GPOS_Data* 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->string[in->pos],
+ flags, &property ) )
+ return error;
+
+ error = Coverage_Index( &mmp->Mark1Coverage, in->string[in->pos],
+ &mark1_index );
+ if ( error )
+ return error;
+
+ /* now we check the preceding glyph whether it is a suitable
+ mark glyph */
+
+ if ( in->pos == 0 )
+ return TTO_Err_Not_Covered;
+
+ j = in->pos - 1;
+ error = TT_GDEF_Get_Glyph_Property( gpos->gdef, in->string[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->string[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->string[in->pos],
+ &x_mark1_value, &y_mark1_value );
+ if ( error )
+ return error;
+ error = Get_Anchor( gpi, mark2_anchor, in->string[j],
+ &x_mark2_value, &y_mark2_value );
+ if ( error )
+ return error;
+
+ /* anchor points are not cumulative */
+
+ o = &out[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;
+
+ (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 input
+ matches the subrule. */
+
+ static TT_Error Do_ContextPos( GPOS_Instance* gpi,
+ UShort GlyphCount,
+ UShort PosCount,
+ TTO_PosLookupRecord* pos,
+ TTO_GSUB_String* in,
+ TTO_GPOS_Data* out,
+ int nesting_level )
+ {
+ TT_Error error;
+ UShort i, old_pos;
+
+
+ i = 0;
+
+ while ( i < GlyphCount )
+ {
+ if ( PosCount && i == pos->SequenceIndex )
+ {
+ old_pos = in->pos;
+
+ /* Do a positioning */
+
+ error = Do_Glyph_Lookup( gpi, pos->LookupListIndex, in, out,
+ GlyphCount, nesting_level );
+
+ if ( error )
+ return error;
+
+ pos++;
+ PosCount--;
+ i += in->pos - old_pos;
+ }
+ else
+ {
+ i++;
+ (in->pos)++;
+ }
+ }
+
+ return TT_Err_Ok;
+ }
+
+
+ /* LookupType 7 */
+
+ /* PosRule */
+
+ static TT_Error Load_PosRule( TTO_PosRule* pr,
+ PFace input )
+ {
+ DEFINE_LOAD_LOCALS( input->stream );
+
+ UShort n, count;
+ 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, 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 )
+ {
+ FREE( pr->PosLookupRecord );
+ FREE( pr->Input );
+ }
+
+
+ /* PosRuleSet */
+
+ static TT_Error Load_PosRuleSet( TTO_PosRuleSet* prs,
+ PFace input )
+ {
+ DEFINE_LOAD_LOCALS( input->stream );
+
+ UShort n, count;
+ 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], input ) ) != TT_Err_Ok )
+ goto Fail;
+ (void)FILE_Seek( cur_offset );
+ }
+
+ return TT_Err_Ok;
+
+ Fail:
+ for ( n = 0; n < count; n++ )
+ Free_PosRule( &pr[n] );
+
+ FREE( pr );
+ return error;
+ }
+
+
+ static void Free_PosRuleSet( TTO_PosRuleSet* prs )
+ {
+ 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] );
+
+ FREE( pr );
+ }
+ }
+
+
+ /* ContextPosFormat1 */
+
+ static TT_Error Load_ContextPos1( TTO_ContextPosFormat1* cpf1,
+ PFace input )
+ {
+ DEFINE_LOAD_LOCALS( input->stream );
+
+ UShort n, count;
+ 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, input ) ) != 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], input ) ) != TT_Err_Ok )
+ goto Fail1;
+ (void)FILE_Seek( cur_offset );
+ }
+
+ return TT_Err_Ok;
+
+ Fail1:
+ for ( n = 0; n < count; n++ )
+ Free_PosRuleSet( &prs[n] );
+
+ FREE( prs );
+
+ Fail2:
+ Free_Coverage( &cpf1->Coverage );
+ return error;
+ }
+
+
+ static void Free_Context1( TTO_ContextPosFormat1* cpf1 )
+ {
+ 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] );
+
+ FREE( prs );
+ }
+
+ Free_Coverage( &cpf1->Coverage );
+ }
+
+
+ /* PosClassRule */
+
+ static TT_Error Load_PosClassRule( TTO_ContextPosFormat2* cpf2,
+ TTO_PosClassRule* pcr,
+ PFace input )
+ {
+ DEFINE_LOAD_LOCALS( input->stream );
+
+ UShort n, count;
+
+ UShort* c;
+ TTO_PosLookupRecord* plr;
+ 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, 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 )
+ {
+ FREE( pcr->PosLookupRecord );
+ FREE( pcr->Class );
+ }
+
+
+ /* PosClassSet */
+
+ static TT_Error Load_PosClassSet( TTO_ContextPosFormat2* cpf2,
+ TTO_PosClassSet* pcs,
+ PFace input )
+ {
+ DEFINE_LOAD_LOCALS( input->stream );
+
+ UShort n, count;
+ 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],
+ input ) ) != TT_Err_Ok )
+ goto Fail;
+ (void)FILE_Seek( cur_offset );
+ }
+
+ return TT_Err_Ok;
+
+ Fail:
+ for ( n = 0; n < count; n++ )
+ Free_PosClassRule( &pcr[n] );
+
+ FREE( pcr );
+ return error;
+ }
+
+
+ static void Free_PosClassSet( TTO_PosClassSet* pcs )
+ {
+ 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] );
+
+ FREE( pcr );
+ }
+ }
+
+
+ /* ContextPosFormat2 */
+
+ static TT_Error Load_ContextPos2( TTO_ContextPosFormat2* cpf2,
+ PFace input )
+ {
+ DEFINE_LOAD_LOCALS( input->stream );
+
+ UShort n, count;
+ 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, input ) ) != 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,
+ input ) ) != 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],
+ input ) ) != 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 ( n = 0; n < count; n++ )
+ Free_PosClassSet( &pcs[n] );
+
+ FREE( pcs );
+
+ Fail2:
+ Free_ClassDefinition( &cpf2->ClassDef );
+
+ Fail3:
+ Free_Coverage( &cpf2->Coverage );
+ return error;
+ }
+
+
+ static void Free_Context2( TTO_ContextPosFormat2* cpf2 )
+ {
+ 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] );
+
+ FREE( pcs );
+ }
+
+ Free_ClassDefinition( &cpf2->ClassDef );
+ Free_Coverage( &cpf2->Coverage );
+ }
+
+
+ /* ContextPosFormat3 */
+
+ static TT_Error Load_ContextPos3( TTO_ContextPosFormat3* cpf3,
+ PFace input )
+ {
+ DEFINE_LOAD_LOCALS( input->stream );
+
+ UShort n, count;
+ 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], input ) ) != 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] );
+
+ FREE( c );
+ return error;
+ }
+
+
+ static void Free_Context3( TTO_ContextPosFormat3* cpf3 )
+ {
+ 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] );
+
+ FREE( c );
+ }
+ }
+
+
+ /* ContextPos */
+
+ TT_Error Load_ContextPos( TTO_ContextPos* cp,
+ PFace input )
+ {
+ DEFINE_LOAD_LOCALS( input->stream );
+
+
+ if ( ACCESS_Frame( 2L ) )
+ return error;
+
+ cp->PosFormat = GET_UShort();
+
+ FORGET_Frame();
+
+ switch ( cp->PosFormat )
+ {
+ case 1:
+ return Load_ContextPos1( &cp->cpf.cpf1, input );
+
+ case 2:
+ return Load_ContextPos2( &cp->cpf.cpf2, input );
+
+ case 3:
+ return Load_ContextPos3( &cp->cpf.cpf3, input );
+
+ default:
+ return TTO_Err_Invalid_GPOS_SubTable_Format;
+ }
+
+ return TT_Err_Ok; /* never reached */
+ }
+
+
+ void Free_ContextPos( TTO_ContextPos* cp )
+ {
+ switch ( cp->PosFormat )
+ {
+ case 1:
+ Free_Context1( &cp->cpf.cpf1 );
+ break;
+
+ case 2:
+ Free_Context2( &cp->cpf.cpf2 );
+ break;
+
+ case 3:
+ Free_Context3( &cp->cpf.cpf3 );
+ break;
+ }
+ }
+
+
+ static TT_Error Lookup_ContextPos1( GPOS_Instance* gpi,
+ TTO_ContextPosFormat1* cpf1,
+ TTO_GSUB_String* in,
+ TTO_GPOS_Data* out,
+ UShort flags,
+ UShort context_length,
+ int nesting_level )
+ {
+ UShort index, property;
+ UShort i, j, k, numpr;
+ TT_Error error;
+ UShort* s_in;
+ TTO_GPOSHeader* gpos = gpi->gpos;
+
+ TTO_PosRule* pr;
+ TTO_GDEFHeader* gdef;
+
+
+ gdef = gpos->gdef;
+
+ if ( CHECK_Property( gdef, in->string[in->pos], flags, &property ) )
+ return error;
+
+ error = Coverage_Index( &cpf1->Coverage, in->string[in->pos], &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 )
+ continue;
+
+ if ( in->pos + pr[k].GlyphCount > in->length )
+ continue; /* context is too long */
+
+ s_in = &in->string[in->pos];
+
+ for ( i = 1, j = 1; i < pr[k].GlyphCount; i++, j++ )
+ {
+ while ( CHECK_Property( gdef, s_in[j], flags, &property ) )
+ {
+ if ( error && error != TTO_Err_Not_Covered )
+ return error;
+
+ if ( in->pos + j < in->length )
+ j++;
+ else
+ break;
+ }
+
+ if ( s_in[j] != pr[k].Input[i - 1] )
+ break;
+ }
+
+ if ( i == pr[k].GlyphCount )
+ return Do_ContextPos( gpi, pr[k].GlyphCount,
+ pr[k].PosCount, pr[k].PosLookupRecord,
+ in, out,
+ nesting_level );
+ }
+
+ return TTO_Err_Not_Covered;
+ }
+
+
+ static TT_Error Lookup_ContextPos2( GPOS_Instance* gpi,
+ TTO_ContextPosFormat2* cpf2,
+ TTO_GSUB_String* in,
+ TTO_GPOS_Data* out,
+ UShort flags,
+ UShort context_length,
+ int nesting_level )
+ {
+ UShort index, property;
+ TT_Error error;
+ UShort i, j, k, known_classes;
+
+ UShort* classes;
+ UShort* s_in;
+ UShort* cl;
+ TTO_GPOSHeader* gpos = gpi->gpos;
+
+ TTO_PosClassSet* pcs;
+ TTO_PosClassRule* pr;
+ TTO_GDEFHeader* gdef;
+
+
+ gdef = gpos->gdef;
+
+ if ( ALLOC_ARRAY( classes, cpf2->MaxContextLength, UShort ) )
+ return error;
+
+ if ( CHECK_Property( gdef, in->string[in->pos], 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->string[in->pos], &index );
+ if ( error )
+ goto End;
+
+ error = Get_Class( &cpf2->ClassDef, in->string[in->pos],
+ &classes[0], NULL );
+ if ( error )
+ 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 )
+ continue;
+
+ if ( in->pos + pr->GlyphCount > in->length )
+ continue; /* context is too long */
+
+ s_in = &in->string[in->pos];
+ cl = pr->Class;
+
+ /* Start at 1 because [0] is implied */
+
+ for ( i = 1, j = 1; i < pr->GlyphCount; i++, j++ )
+ {
+ while ( CHECK_Property( gdef, s_in[j], flags, &property ) )
+ {
+ if ( error && error != TTO_Err_Not_Covered )
+ return error;
+
+ if ( in->pos + j < in->length )
+ j++;
+ else
+ break;
+ }
+
+ if ( i > known_classes )
+ {
+ /* Keeps us from having to do this for each rule */
+
+ error = Get_Class( &cpf2->ClassDef, s_in[j], &classes[i], NULL );
+ if ( error && error != TTO_Err_Not_Covered )
+ return error;
+ known_classes = i;
+ }
+
+ if ( cl[i - 1] != classes[i] )
+ break;
+ }
+
+ if ( i == pr->GlyphCount )
+ {
+ error = Do_ContextPos( gpi, pr->GlyphCount,
+ pr->PosCount, pr->PosLookupRecord,
+ in, out,
+ nesting_level );
+ goto End;
+ }
+ }
+
+ error = TTO_Err_Not_Covered;
+
+ End:
+ FREE( classes );
+ return error;
+ }
+
+
+ static TT_Error Lookup_ContextPos3( GPOS_Instance* gpi,
+ TTO_ContextPosFormat3* cpf3,
+ TTO_GSUB_String* in,
+ TTO_GPOS_Data* out,
+ UShort flags,
+ UShort context_length,
+ int nesting_level )
+ {
+ TT_Error error;
+ UShort index, i, j, property;
+ UShort* s_in;
+ TTO_GPOSHeader* gpos = gpi->gpos;
+
+ TTO_Coverage* c;
+ TTO_GDEFHeader* gdef;
+
+
+ gdef = gpos->gdef;
+
+ if ( CHECK_Property( gdef, in->string[in->pos], flags, &property ) )
+ return error;
+
+ if ( context_length != 0xFFFF && context_length < cpf3->GlyphCount )
+ return TTO_Err_Not_Covered;
+
+ if ( in->pos + cpf3->GlyphCount > in->length )
+ return TTO_Err_Not_Covered; /* context is too long */
+
+ s_in = &in->string[in->pos];
+ c = cpf3->Coverage;
+
+ for ( i = 1, j = 1; i < cpf3->GlyphCount; i++, j++ )
+ {
+ while ( CHECK_Property( gdef, s_in[j], flags, &property ) )
+ {
+ if ( error && error != TTO_Err_Not_Covered )
+ return error;
+
+ if ( in->pos + j < in->length )
+ j++;
+ else
+ return TTO_Err_Not_Covered;
+ }
+
+ error = Coverage_Index( &c[i], s_in[j], &index );
+ if ( error )
+ return error;
+ }
+
+ return Do_ContextPos( gpi, cpf3->GlyphCount,
+ cpf3->PosCount, cpf3->PosLookupRecord,
+ in, out,
+ nesting_level );
+ }
+
+
+ static TT_Error Lookup_ContextPos( GPOS_Instance* gpi,
+ TTO_ContextPos* cp,
+ TTO_GSUB_String* in,
+ TTO_GPOS_Data* out,
+ UShort flags,
+ UShort context_length,
+ int nesting_level )
+ {
+ switch ( cp->PosFormat )
+ {
+ case 1:
+ return Lookup_ContextPos1( gpi, &cp->cpf.cpf1, in, out,
+ flags, context_length, nesting_level );
+
+ case 2:
+ return Lookup_ContextPos2( gpi, &cp->cpf.cpf2, in, out,
+ flags, context_length, nesting_level );
+
+ case 3:
+ return Lookup_ContextPos3( gpi, &cp->cpf.cpf3, in, out,
+ flags, context_length, nesting_level );
+
+ default:
+ return TTO_Err_Invalid_GPOS_SubTable_Format;
+ }
+
+ return TT_Err_Ok; /* never reached */
+ }
+
+
+ /* LookupType 8 */
+
+ /* ChainPosRule */
+
+ static TT_Error Load_ChainPosRule( TTO_ChainPosRule* cpr,
+ PFace input )
+ {
+ DEFINE_LOAD_LOCALS( input->stream );
+
+ UShort n, count;
+ UShort* b;
+ UShort* i;
+ 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, 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, 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, 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 )
+ {
+ FREE( cpr->PosLookupRecord );
+ FREE( cpr->Lookahead );
+ FREE( cpr->Input );
+ FREE( cpr->Backtrack );
+ }
+
+
+ /* ChainPosRuleSet */
+
+ static TT_Error Load_ChainPosRuleSet( TTO_ChainPosRuleSet* cprs,
+ PFace input )
+ {
+ DEFINE_LOAD_LOCALS( input->stream );
+
+ UShort n, count;
+ 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], input ) ) != TT_Err_Ok )
+ goto Fail;
+ (void)FILE_Seek( cur_offset );
+ }
+
+ return TT_Err_Ok;
+
+ Fail:
+ for ( n = 0; n < count; n++ )
+ Free_ChainPosRule( &cpr[n] );
+
+ FREE( cpr );
+ return error;
+ }
+
+
+ static void Free_ChainPosRuleSet( TTO_ChainPosRuleSet* cprs )
+ {
+ 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] );
+
+ FREE( cpr );
+ }
+ }
+
+
+ /* ChainContextPosFormat1 */
+
+ static TT_Error Load_ChainContextPos1( TTO_ChainContextPosFormat1* ccpf1,
+ PFace input )
+ {
+ DEFINE_LOAD_LOCALS( input->stream );
+
+ UShort n, count;
+ 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, input ) ) != 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], input ) ) != TT_Err_Ok )
+ goto Fail1;
+ (void)FILE_Seek( cur_offset );
+ }
+
+ return TT_Err_Ok;
+
+ Fail1:
+ for ( n = 0; n < count; n++ )
+ Free_ChainPosRuleSet( &cprs[n] );
+
+ FREE( cprs );
+
+ Fail2:
+ Free_Coverage( &ccpf1->Coverage );
+ return error;
+ }
+
+
+ static void Free_ChainContext1( TTO_ChainContextPosFormat1* ccpf1 )
+ {
+ 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] );
+
+ FREE( cprs );
+ }
+
+ Free_Coverage( &ccpf1->Coverage );
+ }
+
+
+ /* ChainPosClassRule */
+
+ static TT_Error Load_ChainPosClassRule(
+ TTO_ChainContextPosFormat2* ccpf2,
+ TTO_ChainPosClassRule* cpcr,
+ PFace input )
+ {
+ DEFINE_LOAD_LOCALS( input->stream );
+
+ UShort n, count;
+
+ UShort* b;
+ UShort* i;
+ UShort* l;
+ TTO_PosLookupRecord* plr;
+ 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, 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, 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, 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 )
+ {
+ FREE( cpcr->PosLookupRecord );
+ FREE( cpcr->Lookahead );
+ FREE( cpcr->Input );
+ FREE( cpcr->Backtrack );
+ }
+
+
+ /* PosClassSet */
+
+ static TT_Error Load_ChainPosClassSet(
+ TTO_ChainContextPosFormat2* ccpf2,
+ TTO_ChainPosClassSet* cpcs,
+ PFace input )
+ {
+ DEFINE_LOAD_LOCALS( input->stream );
+
+ UShort n, count;
+ 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],
+ input ) ) != TT_Err_Ok )
+ goto Fail;
+ (void)FILE_Seek( cur_offset );
+ }
+
+ return TT_Err_Ok;
+
+ Fail:
+ for ( n = 0; n < count; n++ )
+ Free_ChainPosClassRule( &cpcr[n] );
+
+ FREE( cpcr );
+ return error;
+ }
+
+
+ static void Free_ChainPosClassSet( TTO_ChainPosClassSet* cpcs )
+ {
+ 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] );
+
+ FREE( cpcr );
+ }
+ }
+
+
+ /* ChainContextPosFormat2 */
+
+ static TT_Error Load_ChainContextPos2( TTO_ChainContextPosFormat2* ccpf2,
+ PFace input )
+ {
+ DEFINE_LOAD_LOCALS( input->stream );
+
+ UShort n, count;
+ ULong cur_offset, new_offset, base_offset;
+ 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, input ) ) != TT_Err_Ok )
+ return error;
+ (void)FILE_Seek( cur_offset );
+
+ if ( ACCESS_Frame( 8L ) )
+ goto Fail5;
+
+ backtrack_offset = GET_UShort() + base_offset;
+ input_offset = GET_UShort() + base_offset;
+ lookahead_offset = GET_UShort() + base_offset;
+
+ /* `ChainPosClassSetCount' is the upper limit for input class values,
+ thus we read it now to make an additional safety check. */
+
+ count = ccpf2->ChainPosClassSetCount = GET_UShort();
+
+ FORGET_Frame();
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( backtrack_offset ) ||
+ ( error = Load_ClassDefinition( &ccpf2->BacktrackClassDef, count,
+ input ) ) != TT_Err_Ok )
+ goto Fail5;
+ if ( FILE_Seek( input_offset ) ||
+ ( error = Load_ClassDefinition( &ccpf2->InputClassDef, count,
+ input ) ) != TT_Err_Ok )
+ goto Fail4;
+ if ( FILE_Seek( lookahead_offset ) ||
+ ( error = Load_ClassDefinition( &ccpf2->LookaheadClassDef, count,
+ input ) ) != TT_Err_Ok )
+ goto Fail3;
+ (void)FILE_Seek( cur_offset );
+
+ 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],
+ input ) ) != 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 ( n = 0; n < count; n++ )
+ Free_ChainPosClassSet( &cpcs[n] );
+
+ FREE( cpcs );
+
+ Fail2:
+ Free_ClassDefinition( &ccpf2->LookaheadClassDef );
+
+ Fail3:
+ Free_ClassDefinition( &ccpf2->InputClassDef );
+
+ Fail4:
+ Free_ClassDefinition( &ccpf2->BacktrackClassDef );
+
+ Fail5:
+ Free_Coverage( &ccpf2->Coverage );
+ return error;
+ }
+
+
+ static void Free_ChainContext2( TTO_ChainContextPosFormat2* ccpf2 )
+ {
+ 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] );
+
+ FREE( cpcs );
+ }
+
+ Free_ClassDefinition( &ccpf2->LookaheadClassDef );
+ Free_ClassDefinition( &ccpf2->InputClassDef );
+ Free_ClassDefinition( &ccpf2->BacktrackClassDef );
+
+ Free_Coverage( &ccpf2->Coverage );
+ }
+
+
+ /* ChainContextPosFormat3 */
+
+ static TT_Error Load_ChainContextPos3( TTO_ChainContextPosFormat3* ccpf3,
+ PFace input )
+ {
+ DEFINE_LOAD_LOCALS( input->stream );
+
+ UShort n, count;
+ UShort backtrack_count, input_count, lookahead_count;
+ 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 ( n = 0; n < backtrack_count; n++ )
+ {
+ 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[n], input ) ) != 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 ( n = 0; n < input_count; n++ )
+ {
+ 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[n], input ) ) != 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 ( n = 0; n < lookahead_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( &l[n], input ) ) != 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 ( n = 0; n < lookahead_count; n++ )
+ Free_Coverage( &l[n] );
+
+ FREE( l );
+
+ Fail3:
+ for ( n = 0; n < input_count; n++ )
+ Free_Coverage( &i[n] );
+
+ FREE( i );
+
+ Fail4:
+ for ( n = 0; n < backtrack_count; n++ )
+ Free_Coverage( &b[n] );
+
+ FREE( b );
+ return error;
+ }
+
+
+ static void Free_ChainContext3( TTO_ChainContextPosFormat3* ccpf3 )
+ {
+ 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] );
+
+ FREE( c );
+ }
+
+ if ( ccpf3->InputCoverage )
+ {
+ count = ccpf3->InputGlyphCount;
+ c = ccpf3->InputCoverage;
+
+ for ( n = 0; n < count; n++ )
+ Free_Coverage( &c[n] );
+
+ FREE( c );
+ }
+
+ if ( ccpf3->BacktrackCoverage )
+ {
+ count = ccpf3->BacktrackGlyphCount;
+ c = ccpf3->BacktrackCoverage;
+
+ for ( n = 0; n < count; n++ )
+ Free_Coverage( &c[n] );
+
+ FREE( c );
+ }
+ }
+
+
+ /* ChainContextPos */
+
+ TT_Error Load_ChainContextPos( TTO_ChainContextPos* ccp,
+ PFace input )
+ {
+ DEFINE_LOAD_LOCALS( input->stream );
+
+
+ if ( ACCESS_Frame( 2L ) )
+ return error;
+
+ ccp->PosFormat = GET_UShort();
+
+ FORGET_Frame();
+
+ switch ( ccp->PosFormat )
+ {
+ case 1:
+ return Load_ChainContextPos1( &ccp->ccpf.ccpf1, input );
+
+ case 2:
+ return Load_ChainContextPos2( &ccp->ccpf.ccpf2, input );
+
+ case 3:
+ return Load_ChainContextPos3( &ccp->ccpf.ccpf3, input );
+
+ default:
+ return TTO_Err_Invalid_GPOS_SubTable_Format;
+ }
+
+ return TT_Err_Ok; /* never reached */
+ }
+
+
+ void Free_ChainContextPos( TTO_ChainContextPos* ccp )
+ {
+ switch ( ccp->PosFormat )
+ {
+ case 1:
+ Free_ChainContext1( &ccp->ccpf.ccpf1 );
+ break;
+
+ case 2:
+ Free_ChainContext2( &ccp->ccpf.ccpf2 );
+ break;
+
+ case 3:
+ Free_ChainContext3( &ccp->ccpf.ccpf3 );
+ break;
+ }
+ }
+
+
+ static TT_Error Lookup_ChainContextPos1(
+ GPOS_Instance* gpi,
+ TTO_ChainContextPosFormat1* ccpf1,
+ TTO_GSUB_String* in,
+ TTO_GPOS_Data* out,
+ UShort flags,
+ UShort context_length,
+ int nesting_level )
+ {
+ UShort index, property;
+ UShort i, j, k, num_cpr, curr_pos;
+ UShort bgc, igc, lgc;
+ TT_Error error;
+ UShort* s_in;
+ TTO_GPOSHeader* gpos = gpi->gpos;
+
+ TTO_ChainPosRule* cpr;
+ TTO_ChainPosRule curr_cpr;
+ TTO_GDEFHeader* gdef;
+
+
+ gdef = gpos->gdef;
+
+ if ( CHECK_Property( gdef, in->string[in->pos], flags, &property ) )
+ return error;
+
+ error = Coverage_Index( &ccpf1->Coverage, in->string[in->pos], &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 )
+ continue;
+
+ /* check whether context is too long; it is a first guess only */
+
+ if ( bgc > in->pos || in->pos + igc + lgc > in->length )
+ continue;
+
+ 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 */
+
+ curr_pos = 0;
+ s_in = &in->string[curr_pos];
+
+ for ( i = bgc, j = in->pos - 1; i > 0; i--, j-- )
+ {
+ while ( CHECK_Property( gdef, s_in[j], flags, &property ) )
+ {
+ if ( error && error != TTO_Err_Not_Covered )
+ return error;
+
+ if ( j > curr_pos )
+ j--;
+ else
+ break;
+ }
+
+ if ( s_in[j] != curr_cpr.Backtrack[i - 1] )
+ break;
+ }
+
+ if ( i != 0 )
+ continue;
+ }
+
+ curr_pos = in->pos;
+ s_in = &in->string[curr_pos];
+
+ /* Start at 1 because [0] is implied */
+
+ for ( i = 1, j = 1; i < igc; i++, j++ )
+ {
+ while ( CHECK_Property( gdef, s_in[j], flags, &property ) )
+ {
+ if ( error && error != TTO_Err_Not_Covered )
+ return error;
+
+ if ( curr_pos + j < in->length )
+ j++;
+ else
+ break;
+ }
+
+ if ( s_in[j] != curr_cpr.Input[i - 1] )
+ break;
+ }
+
+ if ( i != igc )
+ continue;
+
+ /* we are starting to check for lookahead glyphs right after the
+ last context glyph */
+
+ curr_pos = j;
+ s_in = &in->string[curr_pos];
+
+ for ( i = 0, j = 0; i < lgc; i++, j++ )
+ {
+ while ( CHECK_Property( gdef, s_in[j], flags, &property ) )
+ {
+ if ( error && error != TTO_Err_Not_Covered )
+ return error;
+
+ if ( curr_pos + j < in->length )
+ j++;
+ else
+ break;
+ }
+
+ if ( s_in[j] != curr_cpr.Lookahead[i] )
+ break;
+ }
+
+ if ( i == lgc )
+ return Do_ContextPos( gpi, igc,
+ curr_cpr.PosCount,
+ curr_cpr.PosLookupRecord,
+ in, out,
+ nesting_level );
+ }
+
+ return TTO_Err_Not_Covered;
+ }
+
+
+ static TT_Error Lookup_ChainContextPos2(
+ GPOS_Instance* gpi,
+ TTO_ChainContextPosFormat2* ccpf2,
+ TTO_GSUB_String* in,
+ TTO_GPOS_Data* out,
+ UShort flags,
+ UShort context_length,
+ int nesting_level )
+ {
+ UShort index, property;
+ TT_Error error;
+ UShort i, j, k, curr_pos;
+ UShort bgc, igc, lgc;
+ UShort known_backtrack_classes,
+ known_input_classes,
+ known_lookahead_classes;
+
+ UShort* backtrack_classes;
+ UShort* input_classes;
+ UShort* lookahead_classes;
+
+ UShort* s_in;
+
+ UShort* bc;
+ UShort* ic;
+ UShort* lc;
+ TTO_GPOSHeader* gpos = gpi->gpos;
+
+ TTO_ChainPosClassSet* cpcs;
+ TTO_ChainPosClassRule cpcr;
+ TTO_GDEFHeader* gdef;
+
+
+ gdef = gpos->gdef;
+
+ if ( CHECK_Property( gdef, in->string[in->pos], 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->string[in->pos], &index );
+ if ( error )
+ return error;
+
+ if ( ALLOC_ARRAY( backtrack_classes, ccpf2->MaxBacktrackLength, UShort ) )
+ return error;
+ known_backtrack_classes = 0;
+
+ if ( ALLOC_ARRAY( input_classes, ccpf2->MaxInputLength, UShort ) )
+ goto End3;
+ known_input_classes = 1;
+
+ if ( ALLOC_ARRAY( lookahead_classes, ccpf2->MaxLookaheadLength, UShort ) )
+ goto End2;
+ known_lookahead_classes = 0;
+
+ error = Get_Class( &ccpf2->InputClassDef, in->string[in->pos],
+ &input_classes[0], NULL );
+ if ( error )
+ 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 )
+ continue;
+
+ /* check whether context is too long; it is a first guess only */
+
+ if ( bgc > in->pos || in->pos + igc + lgc > in->length )
+ continue;
+
+ 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. */
+
+ curr_pos = 0;
+ s_in = &in->string[curr_pos];
+ bc = cpcr.Backtrack;
+
+ for ( i = 0, j = in->pos - 1; i < bgc; i++, j-- )
+ {
+ while ( CHECK_Property( gdef, s_in[j], flags, &property ) )
+ {
+ if ( error && error != TTO_Err_Not_Covered )
+ return error;
+
+ if ( j > curr_pos )
+ j--;
+ else
+ break;
+ }
+
+ if ( i >= known_backtrack_classes )
+ {
+ /* Keeps us from having to do this for each rule */
+
+ error = Get_Class( &ccpf2->BacktrackClassDef, s_in[j],
+ &backtrack_classes[i], NULL );
+ if ( error && error != TTO_Err_Not_Covered )
+ goto End1;
+ known_backtrack_classes = i;
+ }
+
+ if ( bc[bgc - 1 - i] != backtrack_classes[i] )
+ break;
+ }
+
+ if ( i != bgc )
+ continue;
+ }
+
+ curr_pos = in->pos;
+ s_in = &in->string[curr_pos];
+ ic = cpcr.Input;
+
+ /* Start at 1 because [0] is implied */
+
+ for ( i = 1, j = 1; i < igc; i++, j++ )
+ {
+ while ( CHECK_Property( gdef, s_in[j], flags, &property ) )
+ {
+ if ( error && error != TTO_Err_Not_Covered )
+ goto End1;
+
+ if ( curr_pos + j < in->length )
+ j++;
+ else
+ break;
+ }
+
+ if ( i >= known_input_classes )
+ {
+ error = Get_Class( &ccpf2->InputClassDef, s_in[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] )
+ break;
+ }
+
+ if ( i != igc )
+ continue;
+
+ /* we are starting to check for lookahead glyphs right after the
+ last context glyph */
+
+ curr_pos = j;
+ s_in = &in->string[curr_pos];
+ lc = cpcr.Lookahead;
+
+ for ( i = 0, j = 0; i < lgc; i++, j++ )
+ {
+ while ( CHECK_Property( gdef, s_in[j], flags, &property ) )
+ {
+ if ( error && error != TTO_Err_Not_Covered )
+ return error;
+
+ if ( curr_pos + j < in->length )
+ j++;
+ else
+ break;
+ }
+
+ if ( i >= known_lookahead_classes )
+ {
+ error = Get_Class( &ccpf2->LookaheadClassDef, s_in[j],
+ &lookahead_classes[i], NULL );
+ if ( error && error != TTO_Err_Not_Covered )
+ goto End1;
+ known_lookahead_classes = i;
+ }
+
+ if ( lc[i] != lookahead_classes[i] )
+ break;
+ }
+
+ if ( i == lgc )
+ {
+ error = Do_ContextPos( gpi, igc,
+ cpcr.PosCount,
+ cpcr.PosLookupRecord,
+ in, out,
+ nesting_level );
+ goto End1;
+ }
+ }
+
+ error = TTO_Err_Not_Covered;
+
+ End1:
+ FREE( lookahead_classes );
+
+ End2:
+ FREE( input_classes );
+
+ End3:
+ FREE( backtrack_classes );
+ return error;
+ }
+
+
+ static TT_Error Lookup_ChainContextPos3(
+ GPOS_Instance* gpi,
+ TTO_ChainContextPosFormat3* ccpf3,
+ TTO_GSUB_String* in,
+ TTO_GPOS_Data* out,
+ UShort flags,
+ UShort context_length,
+ int nesting_level )
+ {
+ UShort index, i, j, curr_pos, property;
+ UShort bgc, igc, lgc;
+ TT_Error error;
+ UShort* s_in;
+ 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->string[in->pos], 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 > in->pos || in->pos + igc + lgc > 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 */
+
+ curr_pos = 0;
+ s_in = &in->string[curr_pos];
+ bc = ccpf3->BacktrackCoverage;
+
+ for ( i = bgc, j = in->pos - 1; i > 0; i--, j-- )
+ {
+ while ( CHECK_Property( gdef, s_in[j], flags, &property ) )
+ {
+ if ( error && error != TTO_Err_Not_Covered )
+ return error;
+
+ if ( j > curr_pos )
+ j--;
+ else
+ return TTO_Err_Not_Covered;
+ }
+
+ error = Coverage_Index( &bc[i - 1], s_in[j], &index );
+ if ( error )
+ return error;
+ }
+ }
+
+ curr_pos = in->pos;
+ s_in = &in->string[curr_pos];
+ ic = ccpf3->InputCoverage;
+
+ /* Start at 1 because [0] is implied */
+
+ for ( i = 1, j = 1; i < igc; i++, j++ )
+ {
+ while ( CHECK_Property( gdef, s_in[j], flags, &property ) )
+ {
+ if ( error && error != TTO_Err_Not_Covered )
+ return error;
+
+ if ( curr_pos + j < in->length )
+ j++;
+ else
+ return TTO_Err_Not_Covered;
+ }
+
+ error = Coverage_Index( &ic[i], s_in[j], &index );
+ if ( error )
+ return error;
+ }
+
+ /* we are starting for lookahead glyphs right after the last context
+ glyph */
+
+ curr_pos = j;
+ s_in = &in->string[curr_pos];
+ lc = ccpf3->LookaheadCoverage;
+
+ for ( i = 0, j = 0; i < lgc; i++, j++ )
+ {
+ while ( CHECK_Property( gdef, s_in[j], flags, &property ) )
+ {
+ if ( error && error != TTO_Err_Not_Covered )
+ return error;
+
+ if ( curr_pos + j < in->length )
+ j++;
+ else
+ return TTO_Err_Not_Covered;
+ }
+
+ error = Coverage_Index( &lc[i], s_in[j], &index );
+ if ( error )
+ return error;
+ }
+
+ return Do_ContextPos( gpi, igc,
+ ccpf3->PosCount,
+ ccpf3->PosLookupRecord,
+ in, out,
+ nesting_level );
+ }
+
+
+ static TT_Error Lookup_ChainContextPos(
+ GPOS_Instance* gpi,
+ TTO_ChainContextPos* ccp,
+ TTO_GSUB_String* in,
+ TTO_GPOS_Data* out,
+ UShort flags,
+ UShort context_length,
+ int nesting_level )
+ {
+ switch ( ccp->PosFormat )
+ {
+ case 1:
+ return Lookup_ChainContextPos1( gpi, &ccp->ccpf.ccpf1, in, out,
+ flags, context_length,
+ nesting_level );
+
+ case 2:
+ return Lookup_ChainContextPos2( gpi, &ccp->ccpf.ccpf2, in, out,
+ flags, context_length,
+ nesting_level );
+
+ case 3:
+ return Lookup_ChainContextPos3( gpi, &ccp->ccpf.ccpf3, in, out,
+ flags, context_length,
+ nesting_level );
+
+ default:
+ return TTO_Err_Invalid_GPOS_SubTable_Format;
+ }
+
+ return TT_Err_Ok; /* never reached */
+ }
+
+
+
+ /***********
+ * GPOS API
+ ***********/
+
+
+ EXPORT_FUNC
+ TT_Error TT_GPOS_Select_Script( TTO_GPOSHeader* gpos,
+ TT_ULong script_tag,
+ TT_UShort* script_index )
+ {
+ 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
+ TT_Error TT_GPOS_Select_Language( TTO_GPOSHeader* gpos,
+ TT_ULong language_tag,
+ TT_UShort script_index,
+ TT_UShort* language_index,
+ TT_UShort* req_feature_index )
+ {
+ 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
+ TT_Error TT_GPOS_Select_Feature( TTO_GPOSHeader* gpos,
+ TT_ULong feature_tag,
+ TT_UShort script_index,
+ TT_UShort language_index,
+ TT_UShort* feature_index )
+ {
+ UShort n;
+
+ TTO_ScriptList* sl;
+ TTO_ScriptRecord* sr;
+ TTO_Script* s;
+ TTO_LangSysRecord* lsr;
+ TTO_LangSys* ls;
+ 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
+ TT_Error TT_GPOS_Query_Scripts( TTO_GPOSHeader* gpos,
+ TT_ULong** script_tag_list )
+ {
+ UShort n;
+ TT_Error error;
+ 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, 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
+ TT_Error TT_GPOS_Query_Languages( TTO_GPOSHeader* gpos,
+ TT_UShort script_index,
+ TT_ULong** language_tag_list )
+ {
+ UShort n;
+ TT_Error error;
+ 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, 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
+ TT_Error TT_GPOS_Query_Features( TTO_GPOSHeader* gpos,
+ TT_UShort script_index,
+ TT_UShort language_index,
+ TT_ULong** feature_tag_list )
+ {
+ UShort n;
+ TT_Error error;
+ ULong* ftl;
+
+ TTO_ScriptList* sl;
+ TTO_ScriptRecord* sr;
+ TTO_Script* s;
+ TTO_LangSysRecord* lsr;
+ TTO_LangSys* ls;
+ 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, 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;
+ }
+
+
+ /* Do an individual subtable lookup. Returns TT_Err_Ok if positioning
+ has been done, or TTO_Err_Not_Covered if not. */
+
+ static TT_Error Do_Glyph_Lookup( GPOS_Instance* gpi,
+ UShort lookup_index,
+ TTO_GSUB_String* in,
+ TTO_GPOS_Data* out,
+ UShort context_length,
+ int nesting_level )
+ {
+ TT_Error error = TT_Err_Ok;
+ UShort i, flags;
+ TTO_GPOSHeader* gpos = gpi->gpos;
+ TTO_Lookup* lo;
+
+
+ nesting_level++;
+
+ if ( nesting_level > TTO_MAX_NESTING_LEVEL )
+ return TTO_Err_Too_Many_Nested_Contexts;
+
+ lo = &gpos->LookupList.Lookup[lookup_index];
+ flags = lo->LookupFlag;
+
+ for ( i = 0; i < lo->SubTableCount; i++ )
+ {
+ switch ( lo->LookupType )
+ {
+ case GPOS_LOOKUP_SINGLE:
+ error = Lookup_SinglePos( gpi,
+ &lo->SubTable[i].st.gpos.single,
+ in, out,
+ flags, context_length );
+ break;
+
+ case GPOS_LOOKUP_PAIR:
+ error = Lookup_PairPos( gpi,
+ &lo->SubTable[i].st.gpos.pair,
+ in, out,
+ flags, context_length );
+ break;
+
+ case GPOS_LOOKUP_CURSIVE:
+ error = Lookup_CursivePos( gpi,
+ &lo->SubTable[i].st.gpos.cursive,
+ in, out,
+ flags, context_length );
+ break;
+
+ case GPOS_LOOKUP_MARKBASE:
+ error = Lookup_MarkBasePos( gpi,
+ &lo->SubTable[i].st.gpos.markbase,
+ in, out,
+ flags, context_length );
+ break;
+
+ case GPOS_LOOKUP_MARKLIG:
+ error = Lookup_MarkLigPos( gpi,
+ &lo->SubTable[i].st.gpos.marklig,
+ in, out,
+ flags, context_length );
+ break;
+
+ case GPOS_LOOKUP_MARKMARK:
+ error = Lookup_MarkMarkPos( gpi,
+ &lo->SubTable[i].st.gpos.markmark,
+ in, out,
+ flags, context_length );
+ break;
+
+ case GPOS_LOOKUP_CONTEXT:
+ error = Lookup_ContextPos( gpi,
+ &lo->SubTable[i].st.gpos.context,
+ in, out,
+ flags, context_length,
+ nesting_level );
+ break;
+
+ case GPOS_LOOKUP_CHAIN:
+ error = Lookup_ChainContextPos( gpi,
+ &lo->SubTable[i].st.gpos.chain,
+ in, out,
+ flags, context_length,
+ nesting_level );
+ break;
+ }
+
+ /* 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 TT_Error Do_String_Lookup( GPOS_Instance* gpi,
+ UShort lookup_index,
+ TTO_GSUB_String* in,
+ TTO_GPOS_Data* out )
+ {
+ TT_Error error = TTO_Err_Not_Covered;
+ TTO_GPOSHeader* gpos = gpi->gpos;
+
+ UShort* properties = gpos->LookupList.Properties;
+ UShort* p_in = in->properties;
+
+ int nesting_level = 0;
+
+
+ gpi->last = 0xFFFF; /* no last valid glyph for cursive pos. */
+
+ in->pos = 0;
+
+ while ( in->pos < in->length )
+ {
+ if ( ~p_in[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, in, out,
+ 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 )
+ (in->pos)++;
+ }
+
+ return error;
+ }
+
+
+ EXPORT_FUNC
+ TT_Error TT_GPOS_Add_Feature( TTO_GPOSHeader* gpos,
+ TT_UShort feature_index,
+ TT_UShort property )
+ {
+ UShort i;
+
+ TTO_Feature feature;
+ UShort* properties;
+ UShort* index;
+
+
+ if ( !gpos ||
+ feature_index >= gpos->FeatureList.FeatureCount )
+ return TT_Err_Invalid_Argument;
+
+ properties = gpos->LookupList.Properties;
+
+ feature = gpos->FeatureList.FeatureRecord[feature_index].Feature;
+ index = feature.LookupListIndex;
+
+ for ( i = 0; i < feature.LookupListCount; i++ )
+ properties[index[i]] |= property;
+
+ return TT_Err_Ok;
+ }
+
+
+ EXPORT_FUNC
+ TT_Error TT_GPOS_Clear_Features( TTO_GPOSHeader* gpos )
+ {
+ UShort i;
+
+ UShort* properties;
+
+
+ if ( !gpos )
+ return TT_Err_Invalid_Argument;
+
+ properties = gpos->LookupList.Properties;
+
+ for ( i = 0; i < gpos->LookupList.LookupCount; i++ )
+ properties[i] = 0;
+
+ return TT_Err_Ok;
+ }
+
+
+ EXPORT_FUNC
+ TT_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
+ TT_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
+ TT_Error TT_GPOS_Apply_String( TT_Instance instance,
+ TT_Glyph glyph,
+ TTO_GPOSHeader* gpos,
+ TT_UShort load_flags,
+ TTO_GSUB_String* in,
+ TTO_GPOS_Data** out,
+ TT_Bool dvi,
+ TT_Bool r2l )
+ {
+ TT_Error error = TTO_Err_Not_Covered;
+ GPOS_Instance gpi;
+
+ UShort j;
+
+ UShort* properties;
+
+
+ if ( !instance.z || !gpos ||
+ !in || in->length == 0 || in->pos >= in->length )
+ return TT_Err_Invalid_Argument;
+
+ properties = gpos->LookupList.Properties;
+
+ gpi.instance = instance;
+ if ( dvi )
+ gpi.glyph.z = NULL;
+ else
+ gpi.glyph = glyph;
+ gpi.gpos = gpos;
+ gpi.load_flags = load_flags;
+ gpi.r2l = r2l;
+
+ if ( *out )
+ FREE( *out );
+ if ( ALLOC_ARRAY( *out, in->length, TTO_GPOS_Data ) )
+ return error;
+
+ for ( j = 0; j < gpos->LookupList.LookupCount; j++ )
+ if ( !properties || properties[j] )
+ {
+ error = Do_String_Lookup( &gpi, j, in, *out );
+ if ( error && error != TTO_Err_Not_Covered )
+ return error;
+ }
+
+ return error;
+ }
+
+
+/* END */
diff --git a/Build/source/libs/libttf/extend/ftxgpos.h b/Build/source/libs/libttf/extend/ftxgpos.h
new file mode 100644
index 00000000000..af7ab39f2df
--- /dev/null
+++ b/Build/source/libs/libttf/extend/ftxgpos.h
@@ -0,0 +1,857 @@
+/*******************************************************************
+ *
+ * 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
+
+
+ /* 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 TT_Error (*TTO_GlyphFunction)(TT_Instance instance,
+ TT_Glyph glyph,
+ TT_UShort glyphIndex,
+ TT_UShort 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 TT_Error (*TTO_MMFunction)(TT_Instance instance,
+ TT_UShort metric_id,
+ TT_Pos* metric_value,
+ void* data );
+
+
+ struct TTO_GPOSHeader_
+ {
+ TT_Bool loaded;
+ TT_ULong offset;
+
+ TT_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;
+
+
+ /* shared tables */
+
+ struct TTO_ValueRecord_
+ {
+ TT_Short XPlacement; /* horizontal adjustment for
+ placement */
+ TT_Short YPlacement; /* vertical adjustment for
+ placement */
+ TT_Short XAdvance; /* horizontal adjustment for
+ advance */
+ TT_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 */
+ TT_UShort XIdPlacement; /* horizontal placement metric ID */
+ TT_UShort YIdPlacement; /* vertical placement metric ID */
+ TT_UShort XIdAdvance; /* horizontal advance metric ID */
+ TT_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_
+ {
+ TT_Short XCoordinate; /* horizontal value */
+ TT_Short YCoordinate; /* vertical value */
+ };
+
+ typedef struct TTO_AnchorFormat1_ TTO_AnchorFormat1;
+
+
+ struct TTO_AnchorFormat2_
+ {
+ TT_Short XCoordinate; /* horizontal value */
+ TT_Short YCoordinate; /* vertical value */
+ TT_UShort AnchorPoint; /* index to glyph contour point */
+ };
+
+ typedef struct TTO_AnchorFormat2_ TTO_AnchorFormat2;
+
+
+ struct TTO_AnchorFormat3_
+ {
+ TT_Short XCoordinate; /* horizontal value */
+ TT_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_
+ {
+ TT_UShort XIdAnchor; /* horizontal metric ID */
+ TT_UShort YIdAnchor; /* vertical metric ID */
+ };
+
+ typedef struct TTO_AnchorFormat4_ TTO_AnchorFormat4;
+
+
+ struct TTO_Anchor_
+ {
+ TT_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_
+ {
+ TT_UShort Class; /* mark class */
+ TTO_Anchor MarkAnchor; /* anchor table */
+ };
+
+ typedef struct TTO_MarkRecord_ TTO_MarkRecord;
+
+
+ struct TTO_MarkArray_
+ {
+ TT_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_
+ {
+ TT_UShort ValueCount; /* number of ValueRecord tables */
+ TTO_ValueRecord* Value; /* array of ValueRecord tables */
+ };
+
+ typedef struct TTO_SinglePosFormat2_ TTO_SinglePosFormat2;
+
+
+ struct TTO_SinglePos_
+ {
+ TT_UShort PosFormat; /* 1 or 2 */
+ TTO_Coverage Coverage; /* Coverage table */
+
+ TT_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_
+ {
+ TT_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_
+ {
+ TT_UShort PairValueCount;
+ /* number of PairValueRecord tables */
+ TTO_PairValueRecord* PairValueRecord;
+ /* array of PairValueRecord tables */
+ };
+
+ typedef struct TTO_PairSet_ TTO_PairSet;
+
+
+ struct TTO_PairPosFormat1_
+ {
+ TT_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 */
+ TT_UShort Class1Count; /* number of classes in ClassDef1
+ table */
+ TT_UShort Class2Count; /* number of classes in ClassDef2
+ table */
+ TTO_Class1Record* Class1Record; /* array of Class1Record tables */
+ };
+
+ typedef struct TTO_PairPosFormat2_ TTO_PairPosFormat2;
+
+
+ struct TTO_PairPos_
+ {
+ TT_UShort PosFormat; /* 1 or 2 */
+ TTO_Coverage Coverage; /* Coverage table */
+ TT_UShort ValueFormat1; /* format of ValueRecord table
+ for first glyph */
+ TT_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_
+ {
+ TT_UShort PosFormat; /* always 1 */
+ TTO_Coverage Coverage; /* Coverage table */
+ TT_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_
+ {
+ TT_UShort BaseCount; /* number of BaseRecord tables */
+ TTO_BaseRecord* BaseRecord; /* array of BaseRecord tables */
+ };
+
+ typedef struct TTO_BaseArray_ TTO_BaseArray;
+
+
+ struct TTO_MarkBasePos_
+ {
+ TT_UShort PosFormat; /* always 1 */
+ TTO_Coverage MarkCoverage; /* mark glyph coverage table */
+ TTO_Coverage BaseCoverage; /* base glyph coverage table */
+ TT_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_
+ {
+ TT_UShort ComponentCount;
+ /* number of ComponentRecord tables */
+ TTO_ComponentRecord* ComponentRecord;
+ /* array of ComponentRecord tables */
+ };
+
+ typedef struct TTO_LigatureAttach_ TTO_LigatureAttach;
+
+
+ struct TTO_LigatureArray_
+ {
+ TT_UShort LigatureCount; /* number of LigatureAttach tables */
+ TTO_LigatureAttach* LigatureAttach;
+ /* array of LigatureAttach tables */
+ };
+
+ typedef struct TTO_LigatureArray_ TTO_LigatureArray;
+
+
+ struct TTO_MarkLigPos_
+ {
+ TT_UShort PosFormat; /* always 1 */
+ TTO_Coverage MarkCoverage; /* mark glyph coverage table */
+ TTO_Coverage LigatureCoverage;
+ /* ligature glyph coverage table */
+ TT_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_
+ {
+ TT_UShort Mark2Count; /* number of Mark2Record tables */
+ TTO_Mark2Record* Mark2Record; /* array of Mark2Record tables */
+ };
+
+ typedef struct TTO_Mark2Array_ TTO_Mark2Array;
+
+
+ struct TTO_MarkMarkPos_
+ {
+ TT_UShort PosFormat; /* always 1 */
+ TTO_Coverage Mark1Coverage; /* first mark glyph coverage table */
+ TTO_Coverage Mark2Coverage; /* second mark glyph coverave table */
+ TT_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_
+ {
+ TT_UShort SequenceIndex; /* index into current
+ glyph sequence */
+ TT_UShort LookupListIndex; /* Lookup to apply to that pos. */
+ };
+
+ typedef struct TTO_PosLookupRecord_ TTO_PosLookupRecord;
+
+
+ /* LookupType 7 */
+
+ struct TTO_PosRule_
+ {
+ TT_UShort GlyphCount; /* total number of input glyphs */
+ TT_UShort PosCount; /* number of PosLookupRecord tables */
+ TT_UShort* Input; /* array of input glyph IDs */
+ TTO_PosLookupRecord* PosLookupRecord;
+ /* array of PosLookupRecord tables */
+ };
+
+ typedef struct TTO_PosRule_ TTO_PosRule;
+
+
+ struct TTO_PosRuleSet_
+ {
+ TT_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 */
+ TT_UShort PosRuleSetCount; /* number of PosRuleSet tables */
+ TTO_PosRuleSet* PosRuleSet; /* array of PosRuleSet tables */
+ };
+
+ typedef struct TTO_ContextPosFormat1_ TTO_ContextPosFormat1;
+
+
+ struct TTO_PosClassRule_
+ {
+ TT_UShort GlyphCount; /* total number of context classes */
+ TT_UShort PosCount; /* number of PosLookupRecord tables */
+ TT_UShort* Class; /* array of classes */
+ TTO_PosLookupRecord* PosLookupRecord;
+ /* array of PosLookupRecord tables */
+ };
+
+ typedef struct TTO_PosClassRule_ TTO_PosClassRule;
+
+
+ struct TTO_PosClassSet_
+ {
+ TT_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_
+ {
+ TT_UShort MaxContextLength;
+ /* maximal context length */
+ TTO_Coverage Coverage; /* Coverage table */
+ TTO_ClassDefinition ClassDef; /* ClassDef table */
+ TT_UShort PosClassSetCount;
+ /* number of PosClassSet tables */
+ TTO_PosClassSet* PosClassSet; /* array of PosClassSet tables */
+ };
+
+ typedef struct TTO_ContextPosFormat2_ TTO_ContextPosFormat2;
+
+
+ struct TTO_ContextPosFormat3_
+ {
+ TT_UShort GlyphCount; /* number of input glyphs */
+ TT_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_
+ {
+ TT_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_
+ {
+ TT_UShort BacktrackGlyphCount;
+ /* total number of backtrack glyphs */
+ TT_UShort* Backtrack; /* array of backtrack glyph IDs */
+ TT_UShort InputGlyphCount;
+ /* total number of input glyphs */
+ TT_UShort* Input; /* array of input glyph IDs */
+ TT_UShort LookaheadGlyphCount;
+ /* total number of lookahead glyphs */
+ TT_UShort* Lookahead; /* array of lookahead glyph IDs */
+ TT_UShort PosCount; /* number of PosLookupRecords */
+ TTO_PosLookupRecord* PosLookupRecord;
+ /* array of PosLookupRecords */
+ };
+
+ typedef struct TTO_ChainPosRule_ TTO_ChainPosRule;
+
+
+ struct TTO_ChainPosRuleSet_
+ {
+ TT_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 */
+ TT_UShort ChainPosRuleSetCount;
+ /* number of ChainPosRuleSet tables */
+ TTO_ChainPosRuleSet* ChainPosRuleSet;
+ /* array of ChainPosRuleSet tables */
+ };
+
+ typedef struct TTO_ChainContextPosFormat1_ TTO_ChainContextPosFormat1;
+
+
+ struct TTO_ChainPosClassRule_
+ {
+ TT_UShort BacktrackGlyphCount;
+ /* total number of backtrack
+ classes */
+ TT_UShort* Backtrack; /* array of backtrack classes */
+ TT_UShort InputGlyphCount;
+ /* total number of context classes */
+ TT_UShort* Input; /* array of context classes */
+ TT_UShort LookaheadGlyphCount;
+ /* total number of lookahead
+ classes */
+ TT_UShort* Lookahead; /* array of lookahead classes */
+ TT_UShort PosCount; /* number of PosLookupRecords */
+ TTO_PosLookupRecord* PosLookupRecord;
+ /* array of substitution lookups */
+ };
+
+ typedef struct TTO_ChainPosClassRule_ TTO_ChainPosClassRule;
+
+
+ struct TTO_ChainPosClassSet_
+ {
+ TT_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 */
+
+ TT_UShort MaxBacktrackLength;
+ /* maximal backtrack length */
+ TTO_ClassDefinition BacktrackClassDef;
+ /* BacktrackClassDef table */
+ TT_UShort MaxInputLength;
+ /* maximal input length */
+ TTO_ClassDefinition InputClassDef;
+ /* InputClassDef table */
+ TT_UShort MaxLookaheadLength;
+ /* maximal lookahead length */
+ TTO_ClassDefinition LookaheadClassDef;
+ /* LookaheadClassDef table */
+
+ TT_UShort ChainPosClassSetCount;
+ /* number of ChainPosClassSet
+ tables */
+ TTO_ChainPosClassSet* ChainPosClassSet;
+ /* array of ChainPosClassSet
+ tables */
+ };
+
+ typedef struct TTO_ChainContextPosFormat2_ TTO_ChainContextPosFormat2;
+
+
+ struct TTO_ChainContextPosFormat3_
+ {
+ TT_UShort BacktrackGlyphCount;
+ /* number of backtrack glyphs */
+ TTO_Coverage* BacktrackCoverage;
+ /* array of backtrack Coverage
+ tables */
+ TT_UShort InputGlyphCount;
+ /* number of input glyphs */
+ TTO_Coverage* InputCoverage;
+ /* array of input coverage
+ tables */
+ TT_UShort LookaheadGlyphCount;
+ /* number of lookahead glyphs */
+ TTO_Coverage* LookaheadCoverage;
+ /* array of lookahead coverage
+ tables */
+ TT_UShort PosCount; /* number of PosLookupRecords */
+ TTO_PosLookupRecord* PosLookupRecord;
+ /* array of substitution lookups */
+ };
+
+ typedef struct TTO_ChainContextPosFormat3_ TTO_ChainContextPosFormat3;
+
+
+ struct TTO_ChainContextPos_
+ {
+ TT_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;
+
+
+ /* This `string object' is much simpler compared to TTO_GSUB_String.
+ A call to TTO_GPOS_Apply_String() will allocate it. */
+
+ struct TTO_GPOS_Data_
+ {
+ TT_Pos x_pos;
+ TT_Pos y_pos;
+ TT_Pos x_advance;
+ TT_Pos y_advance;
+ TT_UShort back; /* number of glyphs to go back
+ for drawing current glyph */
+ TT_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. */
+ };
+
+ typedef struct TTO_GPOS_Data_ TTO_GPOS_Data;
+
+
+ /* finally, the GPOS API */
+
+ EXPORT_DEF
+ TT_Error TT_Init_GPOS_Extension( TT_Engine engine );
+
+ EXPORT_DEF
+ TT_Error TT_Load_GPOS_Table( TT_Face face,
+ TTO_GPOSHeader* gpos,
+ TTO_GDEFHeader* gdef );
+
+ EXPORT_DEF
+ TT_Error TT_GPOS_Select_Script( TTO_GPOSHeader* gpos,
+ TT_ULong script_tag,
+ TT_UShort* script_index );
+ EXPORT_DEF
+ TT_Error TT_GPOS_Select_Language( TTO_GPOSHeader* gpos,
+ TT_ULong language_tag,
+ TT_UShort script_index,
+ TT_UShort* language_index,
+ TT_UShort* req_feature_index );
+ EXPORT_DEF
+ TT_Error TT_GPOS_Select_Feature( TTO_GPOSHeader* gpos,
+ TT_ULong feature_tag,
+ TT_UShort script_index,
+ TT_UShort language_index,
+ TT_UShort* feature_index );
+
+ EXPORT_DEF
+ TT_Error TT_GPOS_Query_Scripts( TTO_GPOSHeader* gpos,
+ TT_ULong** script_tag_list );
+ EXPORT_DEF
+ TT_Error TT_GPOS_Query_Languages( TTO_GPOSHeader* gpos,
+ TT_UShort script_index,
+ TT_ULong** language_tag_list );
+ EXPORT_DEF
+ TT_Error TT_GPOS_Query_Features( TTO_GPOSHeader* gpos,
+ TT_UShort script_index,
+ TT_UShort language_index,
+ TT_ULong** feature_tag_list );
+
+ EXPORT_DEF
+ TT_Error TT_GPOS_Add_Feature( TTO_GPOSHeader* gpos,
+ TT_UShort feature_index,
+ TT_UShort property );
+ EXPORT_DEF
+ TT_Error TT_GPOS_Clear_Features( TTO_GPOSHeader* gpos );
+
+ EXPORT_DEF
+ TT_Error TT_GPOS_Register_Glyph_Function( TTO_GPOSHeader* gpos,
+ TTO_GlyphFunction gfunc );
+
+ EXPORT_DEF
+ TT_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
+ TT_Error TT_GPOS_Apply_String( TT_Instance instance,
+ TT_Glyph glyph,
+ TTO_GPOSHeader* gpos,
+ TT_UShort load_flags,
+ TTO_GSUB_String* in,
+ TTO_GPOS_Data** out,
+ TT_Bool dvi,
+ TT_Bool r2l );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FTXGPOS_H */
+
+
+/* END */
diff --git a/Build/source/libs/libttf/extend/ftxgsub.c b/Build/source/libs/libttf/extend/ftxgsub.c
new file mode 100644
index 00000000000..fbac7425d3c
--- /dev/null
+++ b/Build/source/libs/libttf/extend/ftxgsub.c
@@ -0,0 +1,4377 @@
+/*******************************************************************
+ *
+ * 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.
+ *
+ ******************************************************************/
+
+/* 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 :-) */
+
+#include "tttypes.h"
+#include "tttags.h"
+#include "ttload.h"
+#include "ttextend.h"
+#include "ttmemory.h"
+#include "ttfile.h"
+
+#include "ftxopen.h"
+#include "ftxopenf.h"
+
+
+#define GSUB_ID Build_Extension_ID( 'G', 'S', 'U', 'B' )
+
+
+#define ADD_String( in, num_in, out, num_out, glyph_data, component, ligID ) \
+ ( ( error = TT_GSUB_Add_String( (in), (num_in), \
+ (out), (num_out), \
+ (glyph_data), (component), (ligID) \
+ ) ) != TT_Err_Ok )
+
+
+ static TT_Error Do_Glyph_Lookup( TTO_GSUBHeader* gsub,
+ UShort lookup_index,
+ TTO_GSUB_String* in,
+ TTO_GSUB_String* out,
+ UShort context_length,
+ int nesting_level );
+
+
+
+ /**********************
+ * Auxiliary functions
+ **********************/
+
+
+ /* The following function copies `num_out' elements from `glyph_data'
+ to `out', advancing the array pointer in the `in' structure by
+ `num_in' elements, and in `out' by `num_out' elements. If the
+ string (resp. the properties) array in `out' is empty or too
+ small, it allocates resp. reallocates the string (and properties)
+ array. Finally, it sets the `length' field of `out' equal to
+ `pos' of the `out' structure.
+
+ If `component' is 0xFFFF, the value `in->component[in->pos]'
+ will be copied `num_out' times, otherwise `component' itself will
+ be used to fill `out->component'.
+
+ If `ligID' is 0xFFFF, the value `in->lig_IDs[in->pos]' will be
+ copied `num_out' times, otherwise `ligID' itself will be used to
+ fill `out->ligIDs'.
+
+ The properties (if defined) for all replaced glyphs are taken
+ from the glyph at position `in->pos'. */
+
+ EXPORT_FUNC
+ TT_Error TT_GSUB_Add_String( TTO_GSUB_String* in,
+ UShort num_in,
+ TTO_GSUB_String* out,
+ UShort num_out,
+ UShort* glyph_data,
+ UShort component,
+ UShort ligID )
+ {
+ TT_Error error;
+ UShort i;
+ UShort p_in;
+ UShort* p_out;
+
+
+ /* sanity check */
+
+ if ( !in || !out ||
+ in->length == 0 || in->pos >= in->length ||
+ in->length < in->pos + num_in )
+ return TT_Err_Invalid_Argument;
+
+ if ( out->pos + num_out >= out->allocated )
+ {
+ ULong size = out->pos + num_out + 256L;
+
+
+ /* The following works because all fields in `out' must be
+ initialized to zero (including the `string' field) for the
+ first use. */
+
+ if ( REALLOC_ARRAY( out->string, size, UShort ) )
+ return error;
+ if ( REALLOC_ARRAY( out->components, size, UShort ) )
+ return error;
+ if ( REALLOC_ARRAY( out->ligIDs, size, UShort ) )
+ return error;
+ if ( in->properties )
+ if ( REALLOC_ARRAY( out->properties, size, UShort ) )
+ return error;
+
+ out->allocated = size;
+ }
+
+ if ( num_out )
+ {
+ MEM_Copy( &out->string[out->pos], glyph_data,
+ num_out * sizeof ( UShort ) );
+
+ if ( component == 0xFFFF )
+ component = in->components[in->pos];
+
+ p_out = out->components;
+
+ for ( i = out->pos; i < out->pos + num_out; i++ )
+ p_out[i] = component;
+
+ p_out = out->ligIDs;
+
+ if ( ligID == 0xFFFF )
+ ligID = in->ligIDs[in->pos];
+
+ for ( i = out->pos; i < out->pos + num_out; i++ )
+ p_out[i] = ligID;
+
+ if ( in->properties )
+ {
+ p_in = in->properties[in->pos];
+ p_out = out->properties;
+
+ for ( i = out->pos; i < out->pos + num_out; i++ )
+ p_out[i] = p_in;
+ }
+ }
+
+ in->pos += num_in;
+ out->pos += num_out;
+
+ out->length = out->pos;
+
+ return TT_Err_Ok;
+ }
+
+
+
+ /**********************
+ * Extension Functions
+ **********************/
+
+
+ static TT_Error GSUB_Create( void* ext,
+ PFace face )
+ {
+ DEFINE_LOAD_LOCALS( face->stream );
+
+ TTO_GSUBHeader* gsub = (TTO_GSUBHeader*)ext;
+ Long table;
+
+
+ /* by convention */
+
+ if ( !gsub )
+ return TT_Err_Ok;
+
+ /* a null offset indicates that there is no GSUB table */
+
+ gsub->offset = 0;
+
+ /* we store the start offset and the size of the subtable */
+
+ table = TT_LookUp_Table( face, TTAG_GSUB );
+ if ( table < 0 )
+ return TT_Err_Ok; /* The table is optional */
+
+ if ( FILE_Seek( face->dirTables[table].Offset ) ||
+ ACCESS_Frame( 4L ) )
+ return error;
+
+ gsub->offset = FILE_Pos() - 4L; /* undo ACCESS_Frame() */
+ gsub->Version = GET_ULong();
+
+ FORGET_Frame();
+
+ gsub->loaded = FALSE;
+
+ return TT_Err_Ok;
+ }
+
+
+ static TT_Error GSUB_Destroy( void* ext,
+ PFace face )
+ {
+ TTO_GSUBHeader* gsub = (TTO_GSUBHeader*)ext;
+
+
+ /* by convention */
+
+ if ( !gsub )
+ return TT_Err_Ok;
+
+ if ( gsub->loaded )
+ {
+ Free_LookupList( &gsub->LookupList, GSUB );
+ Free_FeatureList( &gsub->FeatureList );
+ Free_ScriptList( &gsub->ScriptList );
+ }
+
+ return TT_Err_Ok;
+ }
+
+
+ EXPORT_FUNC
+ TT_Error TT_Init_GSUB_Extension( TT_Engine engine )
+ {
+ PEngine_Instance _engine = HANDLE_Engine( engine );
+
+
+ if ( !_engine )
+ return TT_Err_Invalid_Engine;
+
+ return TT_Register_Extension( _engine,
+ GSUB_ID,
+ sizeof ( TTO_GSUBHeader ),
+ GSUB_Create,
+ GSUB_Destroy );
+ }
+
+
+ EXPORT_FUNC
+ TT_Error TT_Load_GSUB_Table( TT_Face face,
+ TTO_GSUBHeader* retptr,
+ TTO_GDEFHeader* gdef )
+ {
+ ULong cur_offset, new_offset, base_offset;
+
+ UShort i, num_lookups;
+ TT_Error error;
+ TT_Stream stream;
+ TTO_GSUBHeader* gsub;
+ TTO_Lookup* lo;
+
+ PFace faze = HANDLE_Face( face );
+
+
+ if ( !retptr )
+ return TT_Err_Invalid_Argument;
+
+ if ( !faze )
+ return TT_Err_Invalid_Face_Handle;
+
+ error = TT_Extension_Get( faze, GSUB_ID, (void**)&gsub );
+ if ( error )
+ return error;
+
+ if ( gsub->offset == 0 )
+ return TT_Err_Table_Missing; /* no GSUB table; nothing to do */
+
+ /* now access stream */
+
+ if ( USE_Stream( faze->stream, stream ) )
+ return error;
+
+ base_offset = gsub->offset;
+
+ /* skip version */
+
+ if ( FILE_Seek( base_offset + 4L ) ||
+ ACCESS_Frame( 2L ) )
+ return error;
+
+ new_offset = GET_UShort() + base_offset;
+
+ FORGET_Frame();
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = Load_ScriptList( &gsub->ScriptList,
+ faze ) ) != 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_FeatureList( &gsub->FeatureList,
+ faze ) ) != 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,
+ faze, 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 ) ||
+ ACCESS_Frame( 2L ) )
+ goto Fail1;
+
+ new_offset = GET_UShort();
+
+ FORGET_Frame();
+
+ if ( !new_offset )
+ return TTO_Err_Invalid_GDEF_SubTable;
+
+ new_offset += base_offset;
+
+ if ( FILE_Seek( new_offset ) ||
+ ( error = Load_ClassDefinition( &gdef->MarkAttachClassDef,
+ 256, faze ) ) != TT_Err_Ok )
+ goto Fail1;
+
+ break;
+ }
+ }
+ }
+
+ gsub->loaded = TRUE;
+ *retptr = *gsub;
+ DONE_Stream( stream );
+
+ return TT_Err_Ok;
+
+ Fail1:
+ Free_LookupList( &gsub->LookupList, GSUB );
+
+ Fail2:
+ Free_FeatureList( &gsub->FeatureList );
+
+ Fail3:
+ Free_ScriptList( &gsub->ScriptList );
+
+ /* release stream */
+
+ DONE_Stream( stream );
+
+ return error;
+ }
+
+
+
+ /*****************************
+ * SubTable related functions
+ *****************************/
+
+
+ /* LookupType 1 */
+
+ /* SingleSubstFormat1 */
+ /* SingleSubstFormat2 */
+
+ TT_Error Load_SingleSubst( TTO_SingleSubst* ss,
+ PFace input )
+ {
+ DEFINE_LOAD_LOCALS( input->stream );
+
+ UShort n, count;
+ ULong cur_offset, new_offset, base_offset;
+
+ 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, input ) ) != 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, 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 );
+ return error;
+ }
+
+
+ void Free_SingleSubst( TTO_SingleSubst* ss )
+ {
+ switch ( ss->SubstFormat )
+ {
+ case 1:
+ break;
+
+ case 2:
+ FREE( ss->ssf.ssf2.Substitute );
+ break;
+ }
+
+ Free_Coverage( &ss->Coverage );
+ }
+
+
+ static TT_Error Lookup_SingleSubst( TTO_SingleSubst* ss,
+ TTO_GSUB_String* in,
+ TTO_GSUB_String* out,
+ UShort flags,
+ UShort context_length,
+ TTO_GDEFHeader* gdef )
+ {
+ UShort index, value[1], property;
+ TT_Error error;
+
+
+ if ( context_length != 0xFFFF && context_length < 1 )
+ return TTO_Err_Not_Covered;
+
+ if ( CHECK_Property( gdef, in->string[in->pos], flags, &property ) )
+ return error;
+
+ error = Coverage_Index( &ss->Coverage, in->string[in->pos], &index );
+ if ( error )
+ return error;
+
+ switch ( ss->SubstFormat )
+ {
+ case 1:
+ value[0] = ( in->string[in->pos] + ss->ssf.ssf1.DeltaGlyphID ) & 0xFFFF;
+ if ( ADD_String( in, 1, out, 1, value, 0xFFFF, 0xFFFF ) )
+ return error;
+ break;
+
+ case 2:
+ if ( index >= ss->ssf.ssf2.GlyphCount )
+ return TTO_Err_Invalid_GSUB_SubTable;
+ value[0] = ss->ssf.ssf2.Substitute[index];
+ if ( ADD_String( in, 1, out, 1, 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[0], property );
+ if ( error && error != TTO_Err_Not_Covered )
+ return error;
+ }
+
+ return TT_Err_Ok;
+ }
+
+
+ /* LookupType 2 */
+
+ /* Sequence */
+
+ static TT_Error Load_Sequence( TTO_Sequence* s,
+ PFace input )
+ {
+ DEFINE_LOAD_LOCALS( input->stream );
+
+ UShort n, count;
+ 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, 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 )
+ {
+ FREE( s->Substitute );
+ }
+
+
+ /* MultipleSubstFormat1 */
+
+ TT_Error Load_MultipleSubst( TTO_MultipleSubst* ms,
+ PFace input )
+ {
+ DEFINE_LOAD_LOCALS( input->stream );
+
+ UShort n, count;
+ 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, input ) ) != 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], input ) ) != TT_Err_Ok )
+ goto Fail1;
+ (void)FILE_Seek( cur_offset );
+ }
+
+ return TT_Err_Ok;
+
+ Fail1:
+ for ( n = 0; n < count; n++ )
+ Free_Sequence( &s[n] );
+
+ FREE( s );
+
+ Fail2:
+ Free_Coverage( &ms->Coverage );
+ return error;
+ }
+
+
+ void Free_MultipleSubst( TTO_MultipleSubst* ms )
+ {
+ 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] );
+
+ FREE( s );
+ }
+
+ Free_Coverage( &ms->Coverage );
+ }
+
+
+ static TT_Error Lookup_MultipleSubst( TTO_MultipleSubst* ms,
+ TTO_GSUB_String* in,
+ TTO_GSUB_String* out,
+ UShort flags,
+ UShort context_length,
+ TTO_GDEFHeader* gdef )
+ {
+ TT_Error error;
+ UShort index, property, n, count;
+ UShort* s;
+
+
+ if ( context_length != 0xFFFF && context_length < 1 )
+ return TTO_Err_Not_Covered;
+
+ if ( CHECK_Property( gdef, in->string[in->pos], flags, &property ) )
+ return error;
+
+ error = Coverage_Index( &ms->Coverage, in->string[in->pos], &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( in, 1, out, 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 TT_Error Load_AlternateSet( TTO_AlternateSet* as,
+ PFace input )
+ {
+ DEFINE_LOAD_LOCALS( input->stream );
+
+ UShort n, count;
+ UShort* a;
+
+
+ if ( ACCESS_Frame( 2L ) )
+ return error;
+
+ count = as->GlyphCount = GET_UShort();
+
+ FORGET_Frame();
+
+ as->Alternate = NULL;
+
+ if ( ALLOC_ARRAY( as->Alternate, count, 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 )
+ {
+ FREE( as->Alternate );
+ }
+
+
+ /* AlternateSubstFormat1 */
+
+ TT_Error Load_AlternateSubst( TTO_AlternateSubst* as,
+ PFace input )
+ {
+ DEFINE_LOAD_LOCALS( input->stream );
+
+ UShort n, count;
+ 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, input ) ) != 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], input ) ) != TT_Err_Ok )
+ goto Fail1;
+ (void)FILE_Seek( cur_offset );
+ }
+
+ return TT_Err_Ok;
+
+ Fail1:
+ for ( n = 0; n < count; n++ )
+ Free_AlternateSet( &aset[n] );
+
+ FREE( aset );
+
+ Fail2:
+ Free_Coverage( &as->Coverage );
+ return error;
+ }
+
+
+ void Free_AlternateSubst( TTO_AlternateSubst* as )
+ {
+ 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] );
+
+ FREE( aset );
+ }
+
+ Free_Coverage( &as->Coverage );
+ }
+
+
+ static TT_Error Lookup_AlternateSubst( TTO_GSUBHeader* gsub,
+ TTO_AlternateSubst* as,
+ TTO_GSUB_String* in,
+ TTO_GSUB_String* out,
+ UShort flags,
+ UShort context_length,
+ TTO_GDEFHeader* gdef )
+ {
+ TT_Error error;
+ UShort index, alt_index, property;
+
+ TTO_AlternateSet aset;
+
+
+ if ( context_length != 0xFFFF && context_length < 1 )
+ return TTO_Err_Not_Covered;
+
+ if ( CHECK_Property( gdef, in->string[in->pos], flags, &property ) )
+ return error;
+
+ error = Coverage_Index( &as->Coverage, in->string[in->pos], &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)( out->pos, in->string[in->pos],
+ aset.GlyphCount, aset.Alternate,
+ gsub->data );
+ else
+ alt_index = 0;
+
+ if ( ADD_String( in, 1, out, 1, &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 TT_Error Load_Ligature( TTO_Ligature* l,
+ PFace input )
+ {
+ DEFINE_LOAD_LOCALS( input->stream );
+
+ UShort n, count;
+ 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, 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 )
+ {
+ FREE( l->Component );
+ }
+
+
+ /* LigatureSet */
+
+ static TT_Error Load_LigatureSet( TTO_LigatureSet* ls,
+ PFace input )
+ {
+ DEFINE_LOAD_LOCALS( input->stream );
+
+ UShort n, count;
+ 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], input ) ) != TT_Err_Ok )
+ goto Fail;
+ (void)FILE_Seek( cur_offset );
+ }
+
+ return TT_Err_Ok;
+
+ Fail:
+ for ( n = 0; n < count; n++ )
+ Free_Ligature( &l[n] );
+
+ FREE( l );
+ return error;
+ }
+
+
+ static void Free_LigatureSet( TTO_LigatureSet* ls )
+ {
+ 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] );
+
+ FREE( l );
+ }
+ }
+
+
+ /* LigatureSubstFormat1 */
+
+ TT_Error Load_LigatureSubst( TTO_LigatureSubst* ls,
+ PFace input )
+ {
+ DEFINE_LOAD_LOCALS( input->stream );
+
+ UShort n, count;
+ 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, input ) ) != 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], input ) ) != TT_Err_Ok )
+ goto Fail1;
+ (void)FILE_Seek( cur_offset );
+ }
+
+ return TT_Err_Ok;
+
+ Fail1:
+ for ( n = 0; n < count; n++ )
+ Free_LigatureSet( &lset[n] );
+
+ FREE( lset );
+
+ Fail2:
+ Free_Coverage( &ls->Coverage );
+ return error;
+ }
+
+
+ void Free_LigatureSubst( TTO_LigatureSubst* ls )
+ {
+ 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] );
+
+ FREE( lset );
+ }
+
+ Free_Coverage( &ls->Coverage );
+ }
+
+
+ static TT_Error Lookup_LigatureSubst( TTO_LigatureSubst* ls,
+ TTO_GSUB_String* in,
+ TTO_GSUB_String* out,
+ UShort flags,
+ UShort context_length,
+ TTO_GDEFHeader* gdef )
+ {
+ UShort index, property;
+ TT_Error error;
+ UShort numlig, i, j, is_mark, first_is_mark = FALSE;
+ UShort* s_in;
+ UShort* c;
+
+ TTO_Ligature* lig;
+
+
+ if ( CHECK_Property( gdef, in->string[in->pos], flags, &property ) )
+ return error;
+
+ if ( property == TTO_MARK )
+ first_is_mark = TRUE;
+
+ error = Coverage_Index( &ls->Coverage, in->string[in->pos], &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 ( in->pos + lig->ComponentCount > in->length )
+ continue; /* Not enough glyphs in input */
+
+ s_in = &in->string[in->pos];
+ c = lig->Component;
+
+ is_mark = first_is_mark;
+
+ if ( context_length != 0xFFFF && context_length < lig->ComponentCount )
+ break;
+
+ for ( i = 1, j = 1; i < lig->ComponentCount; i++, j++ )
+ {
+ while ( CHECK_Property( gdef, s_in[j], flags, &property ) )
+ {
+ if ( error && error != TTO_Err_Not_Covered )
+ return error;
+
+ if ( in->pos + j < in->length )
+ j++;
+ else
+ break;
+ }
+
+ if ( property != TTO_MARK )
+ is_mark = FALSE;
+
+ if ( s_in[j] != c[i - 1] )
+ break;
+ }
+
+ if ( i == lig->ComponentCount )
+ {
+ 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 ( i == j )
+ {
+ /* We don't use a new ligature ID if there are no skipped
+ glyphs and the ligature already has an ID. */
+
+ if ( in->ligIDs[in->pos] )
+ {
+ if ( ADD_String( in, i, out, 1, &lig->LigGlyph,
+ 0xFFFF, 0xFFFF ) )
+ return error;
+ }
+ else
+ {
+ if ( ADD_String( in, i, out, 1, &lig->LigGlyph,
+ 0xFFFF, in->max_ligID ) )
+ return error;
+
+ (in->max_ligID)++;
+ }
+ }
+ else
+ {
+ if ( ADD_String( in, 1, out, 1, &lig->LigGlyph,
+ 0xFFFF, in->max_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->string[in->pos],
+ flags, &property ) )
+ if ( ADD_String( in, 1, out, 1, &in->string[in->pos],
+ i, in->max_ligID ) )
+ return error;
+
+ (in->pos)++;
+ }
+
+ (in->max_ligID)++;
+ }
+
+ return TT_Err_Ok;
+ }
+ }
+
+ 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 TT_Error Do_ContextSubst( TTO_GSUBHeader* gsub,
+ UShort GlyphCount,
+ UShort SubstCount,
+ TTO_SubstLookupRecord* subst,
+ TTO_GSUB_String* in,
+ TTO_GSUB_String* out,
+ int nesting_level )
+ {
+ TT_Error error;
+ UShort i, old_pos;
+
+
+ i = 0;
+
+ while ( i < GlyphCount )
+ {
+ if ( SubstCount && i == subst->SequenceIndex )
+ {
+ old_pos = in->pos;
+
+ /* Do a substitution */
+
+ error = Do_Glyph_Lookup( gsub, subst->LookupListIndex, in, out,
+ GlyphCount, nesting_level );
+
+ subst++;
+ SubstCount--;
+ i += in->pos - old_pos;
+
+ if ( error == TTO_Err_Not_Covered )
+ {
+ /* XXX "can't happen" -- but don't count on it */
+
+ if ( ADD_String( in, 1, out, 1, &in->string[in->pos],
+ 0xFFFF, 0xFFFF ) )
+ return error;
+ i++;
+ }
+ else if ( error )
+ return error;
+ }
+ else
+ {
+ /* No substitution for this index */
+
+ if ( ADD_String( in, 1, out, 1, &in->string[in->pos],
+ 0xFFFF, 0xFFFF ) )
+ return error;
+ i++;
+ }
+ }
+
+ return TT_Err_Ok;
+ }
+
+
+ /* LookupType 5 */
+
+ /* SubRule */
+
+ static TT_Error Load_SubRule( TTO_SubRule* sr,
+ PFace input )
+ {
+ DEFINE_LOAD_LOCALS( input->stream );
+
+ UShort n, count;
+ 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, 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 )
+ {
+ FREE( sr->SubstLookupRecord );
+ FREE( sr->Input );
+ }
+
+
+ /* SubRuleSet */
+
+ static TT_Error Load_SubRuleSet( TTO_SubRuleSet* srs,
+ PFace input )
+ {
+ DEFINE_LOAD_LOCALS( input->stream );
+
+ UShort n, count;
+ 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], input ) ) != TT_Err_Ok )
+ goto Fail;
+ (void)FILE_Seek( cur_offset );
+ }
+
+ return TT_Err_Ok;
+
+ Fail:
+ for ( n = 0; n < count; n++ )
+ Free_SubRule( &sr[n] );
+
+ FREE( sr );
+ return error;
+ }
+
+
+ static void Free_SubRuleSet( TTO_SubRuleSet* srs )
+ {
+ 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] );
+
+ FREE( sr );
+ }
+ }
+
+
+ /* ContextSubstFormat1 */
+
+ static TT_Error Load_ContextSubst1( TTO_ContextSubstFormat1* csf1,
+ PFace input )
+ {
+ DEFINE_LOAD_LOCALS( input->stream );
+
+ UShort n, count;
+ 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, input ) ) != 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], input ) ) != TT_Err_Ok )
+ goto Fail1;
+ (void)FILE_Seek( cur_offset );
+ }
+
+ return TT_Err_Ok;
+
+ Fail1:
+ for ( n = 0; n < count; n++ )
+ Free_SubRuleSet( &srs[n] );
+
+ FREE( srs );
+
+ Fail2:
+ Free_Coverage( &csf1->Coverage );
+ return error;
+ }
+
+
+ static void Free_Context1( TTO_ContextSubstFormat1* csf1 )
+ {
+ 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] );
+
+ FREE( srs );
+ }
+
+ Free_Coverage( &csf1->Coverage );
+ }
+
+
+ /* SubClassRule */
+
+ static TT_Error Load_SubClassRule( TTO_ContextSubstFormat2* csf2,
+ TTO_SubClassRule* scr,
+ PFace input )
+ {
+ DEFINE_LOAD_LOCALS( input->stream );
+
+ UShort n, count;
+
+ UShort* c;
+ TTO_SubstLookupRecord* slr;
+ 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, 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 )
+ {
+ FREE( scr->SubstLookupRecord );
+ FREE( scr->Class );
+ }
+
+
+ /* SubClassSet */
+
+ static TT_Error Load_SubClassSet( TTO_ContextSubstFormat2* csf2,
+ TTO_SubClassSet* scs,
+ PFace input )
+ {
+ DEFINE_LOAD_LOCALS( input->stream );
+
+ UShort n, count;
+ 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],
+ input ) ) != TT_Err_Ok )
+ goto Fail;
+ (void)FILE_Seek( cur_offset );
+ }
+
+ return TT_Err_Ok;
+
+ Fail:
+ for ( n = 0; n < count; n++ )
+ Free_SubClassRule( &scr[n] );
+
+ FREE( scr );
+ return error;
+ }
+
+
+ static void Free_SubClassSet( TTO_SubClassSet* scs )
+ {
+ 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] );
+
+ FREE( scr );
+ }
+ }
+
+
+ /* ContextSubstFormat2 */
+
+ static TT_Error Load_ContextSubst2( TTO_ContextSubstFormat2* csf2,
+ PFace input )
+ {
+ DEFINE_LOAD_LOCALS( input->stream );
+
+ UShort n, count;
+ 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, input ) ) != 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,
+ input ) ) != 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],
+ input ) ) != 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 ( n = 0; n < count; n++ )
+ Free_SubClassSet( &scs[n] );
+
+ FREE( scs );
+
+ Fail2:
+ Free_ClassDefinition( &csf2->ClassDef );
+
+ Fail3:
+ Free_Coverage( &csf2->Coverage );
+ return error;
+ }
+
+
+ static void Free_Context2( TTO_ContextSubstFormat2* csf2 )
+ {
+ 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] );
+
+ FREE( scs );
+ }
+
+ Free_ClassDefinition( &csf2->ClassDef );
+ Free_Coverage( &csf2->Coverage );
+ }
+
+
+ /* ContextSubstFormat3 */
+
+ static TT_Error Load_ContextSubst3( TTO_ContextSubstFormat3* csf3,
+ PFace input )
+ {
+ DEFINE_LOAD_LOCALS( input->stream );
+
+ UShort n, count;
+ 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], input ) ) != 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 ( n = 0; n < count; n++ )
+ Free_Coverage( &c[n] );
+
+ FREE( c );
+ return error;
+ }
+
+
+ static void Free_Context3( TTO_ContextSubstFormat3* csf3 )
+ {
+ 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] );
+
+ FREE( c );
+ }
+ }
+
+
+ /* ContextSubst */
+
+ TT_Error Load_ContextSubst( TTO_ContextSubst* cs,
+ PFace input )
+ {
+ DEFINE_LOAD_LOCALS( input->stream );
+
+
+ if ( ACCESS_Frame( 2L ) )
+ return error;
+
+ cs->SubstFormat = GET_UShort();
+
+ FORGET_Frame();
+
+ switch ( cs->SubstFormat )
+ {
+ case 1:
+ return Load_ContextSubst1( &cs->csf.csf1, input );
+
+ case 2:
+ return Load_ContextSubst2( &cs->csf.csf2, input );
+
+ case 3:
+ return Load_ContextSubst3( &cs->csf.csf3, input );
+
+ default:
+ return TTO_Err_Invalid_GSUB_SubTable_Format;
+ }
+
+ return TT_Err_Ok; /* never reached */
+ }
+
+
+ void Free_ContextSubst( TTO_ContextSubst* cs )
+ {
+ switch ( cs->SubstFormat )
+ {
+ case 1:
+ Free_Context1( &cs->csf.csf1 );
+ break;
+
+ case 2:
+ Free_Context2( &cs->csf.csf2 );
+ break;
+
+ case 3:
+ Free_Context3( &cs->csf.csf3 );
+ break;
+ }
+ }
+
+
+ static TT_Error Lookup_ContextSubst1(
+ TTO_GSUBHeader* gsub,
+ TTO_ContextSubstFormat1* csf1,
+ TTO_GSUB_String* in,
+ TTO_GSUB_String* out,
+ UShort flags,
+ UShort context_length,
+ int nesting_level )
+ {
+ UShort index, property;
+ UShort i, j, k, numsr;
+ TT_Error error;
+ UShort* s_in;
+
+ TTO_SubRule* sr;
+ TTO_GDEFHeader* gdef;
+
+
+ gdef = gsub->gdef;
+
+ if ( CHECK_Property( gdef, in->string[in->pos], flags, &property ) )
+ return error;
+
+ error = Coverage_Index( &csf1->Coverage, in->string[in->pos], &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 )
+ continue;
+
+ if ( in->pos + sr[k].GlyphCount > in->length )
+ continue; /* context is too long */
+
+ s_in = &in->string[in->pos];
+
+ for ( i = 1, j = 1; i < sr[k].GlyphCount; i++, j++ )
+ {
+ while ( CHECK_Property( gdef, s_in[j], flags, &property ) )
+ {
+ if ( error && error != TTO_Err_Not_Covered )
+ return error;
+
+ if ( in->pos + j < in->length )
+ j++;
+ else
+ break;
+ }
+
+ if ( s_in[j] != sr[k].Input[i - 1] )
+ break;
+ }
+
+ if ( i == sr[k].GlyphCount )
+ return Do_ContextSubst( gsub, sr[k].GlyphCount,
+ sr[k].SubstCount, sr[k].SubstLookupRecord,
+ in, out,
+ nesting_level );
+ }
+
+ return TTO_Err_Not_Covered;
+ }
+
+
+ static TT_Error Lookup_ContextSubst2(
+ TTO_GSUBHeader* gsub,
+ TTO_ContextSubstFormat2* csf2,
+ TTO_GSUB_String* in,
+ TTO_GSUB_String* out,
+ UShort flags,
+ UShort context_length,
+ int nesting_level )
+ {
+ UShort index, property;
+ TT_Error error;
+ UShort i, j, k, known_classes;
+
+ UShort* classes;
+ UShort* s_in;
+ UShort* cl;
+
+ TTO_SubClassSet* scs;
+ TTO_SubClassRule* sr;
+ TTO_GDEFHeader* gdef;
+
+
+ gdef = gsub->gdef;
+
+ if ( ALLOC_ARRAY( classes, csf2->MaxContextLength, UShort ) )
+ return error;
+
+ if ( CHECK_Property( gdef, in->string[in->pos], 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->string[in->pos], &index );
+ if ( error )
+ goto End;
+
+ error = Get_Class( &csf2->ClassDef, in->string[in->pos],
+ &classes[0], NULL );
+ if ( error )
+ 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 )
+ continue;
+
+ if ( in->pos + sr->GlyphCount > in->length )
+ continue; /* context is too long */
+
+ s_in = &in->string[in->pos];
+ cl = sr->Class;
+
+ /* Start at 1 because [0] is implied */
+
+ for ( i = 1, j = 1; i < sr->GlyphCount; i++, j++ )
+ {
+ while ( CHECK_Property( gdef, s_in[j], flags, &property ) )
+ {
+ if ( error && error != TTO_Err_Not_Covered )
+ return error;
+
+ if ( in->pos + j < in->length )
+ j++;
+ else
+ break;
+ }
+
+ if ( i > known_classes )
+ {
+ /* Keeps us from having to do this for each rule */
+
+ error = Get_Class( &csf2->ClassDef, s_in[j], &classes[i], NULL );
+ if ( error && error != TTO_Err_Not_Covered )
+ return error;
+ known_classes = i;
+ }
+
+ if ( cl[i - 1] != classes[i] )
+ break;
+ }
+
+ if ( i == sr->GlyphCount )
+ {
+ error = Do_ContextSubst( gsub, sr->GlyphCount,
+ sr->SubstCount, sr->SubstLookupRecord,
+ in, out,
+ nesting_level );
+ goto End;
+ }
+ }
+
+ error = TTO_Err_Not_Covered;
+
+ End:
+ FREE( classes );
+ return error;
+ }
+
+
+ static TT_Error Lookup_ContextSubst3(
+ TTO_GSUBHeader* gsub,
+ TTO_ContextSubstFormat3* csf3,
+ TTO_GSUB_String* in,
+ TTO_GSUB_String* out,
+ UShort flags,
+ UShort context_length,
+ int nesting_level )
+ {
+ TT_Error error;
+ UShort index, i, j, property;
+ UShort* s_in;
+
+ TTO_Coverage* c;
+ TTO_GDEFHeader* gdef;
+
+
+ gdef = gsub->gdef;
+
+ if ( CHECK_Property( gdef, in->string[in->pos], flags, &property ) )
+ return error;
+
+ if ( context_length != 0xFFFF && context_length < csf3->GlyphCount )
+ return TTO_Err_Not_Covered;
+
+ if ( in->pos + csf3->GlyphCount > in->length )
+ return TTO_Err_Not_Covered; /* context is too long */
+
+ s_in = &in->string[in->pos];
+ c = csf3->Coverage;
+
+ for ( i = 1, j = 1; i < csf3->GlyphCount; i++, j++ )
+ {
+ while ( CHECK_Property( gdef, s_in[j], flags, &property ) )
+ {
+ if ( error && error != TTO_Err_Not_Covered )
+ return error;
+
+ if ( in->pos + j < in->length )
+ j++;
+ else
+ return TTO_Err_Not_Covered;
+ }
+
+ error = Coverage_Index( &c[i], s_in[j], &index );
+ if ( error )
+ return error;
+ }
+
+ return Do_ContextSubst( gsub, csf3->GlyphCount,
+ csf3->SubstCount, csf3->SubstLookupRecord,
+ in, out,
+ nesting_level );
+ }
+
+
+ static TT_Error Lookup_ContextSubst( TTO_GSUBHeader* gsub,
+ TTO_ContextSubst* cs,
+ TTO_GSUB_String* in,
+ TTO_GSUB_String* out,
+ UShort flags,
+ UShort context_length,
+ int nesting_level )
+ {
+ switch ( cs->SubstFormat )
+ {
+ case 1:
+ return Lookup_ContextSubst1( gsub, &cs->csf.csf1, in, out,
+ flags, context_length, nesting_level );
+
+ case 2:
+ return Lookup_ContextSubst2( gsub, &cs->csf.csf2, in, out,
+ flags, context_length, nesting_level );
+
+ case 3:
+ return Lookup_ContextSubst3( gsub, &cs->csf.csf3, in, out,
+ flags, context_length, nesting_level );
+
+ default:
+ return TTO_Err_Invalid_GSUB_SubTable_Format;
+ }
+
+ return TT_Err_Ok; /* never reached */
+ }
+
+
+ /* LookupType 6 */
+
+ /* ChainSubRule */
+
+ static TT_Error Load_ChainSubRule( TTO_ChainSubRule* csr,
+ PFace input )
+ {
+ DEFINE_LOAD_LOCALS( input->stream );
+
+ UShort n, count;
+ UShort* b;
+ UShort* i;
+ 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, 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, 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, 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 )
+ {
+ FREE( csr->SubstLookupRecord );
+ FREE( csr->Lookahead );
+ FREE( csr->Input );
+ FREE( csr->Backtrack );
+ }
+
+
+ /* ChainSubRuleSet */
+
+ static TT_Error Load_ChainSubRuleSet( TTO_ChainSubRuleSet* csrs,
+ PFace input )
+ {
+ DEFINE_LOAD_LOCALS( input->stream );
+
+ UShort n, count;
+ 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], input ) ) != TT_Err_Ok )
+ goto Fail;
+ (void)FILE_Seek( cur_offset );
+ }
+
+ return TT_Err_Ok;
+
+ Fail:
+ for ( n = 0; n < count; n++ )
+ Free_ChainSubRule( &csr[n] );
+
+ FREE( csr );
+ return error;
+ }
+
+
+ static void Free_ChainSubRuleSet( TTO_ChainSubRuleSet* csrs )
+ {
+ 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] );
+
+ FREE( csr );
+ }
+ }
+
+
+ /* ChainContextSubstFormat1 */
+
+ static TT_Error Load_ChainContextSubst1(
+ TTO_ChainContextSubstFormat1* ccsf1,
+ PFace input )
+ {
+ DEFINE_LOAD_LOCALS( input->stream );
+
+ UShort n, count;
+ 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, input ) ) != 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], input ) ) != TT_Err_Ok )
+ goto Fail1;
+ (void)FILE_Seek( cur_offset );
+ }
+
+ return TT_Err_Ok;
+
+ Fail1:
+ for ( n = 0; n < count; n++ )
+ Free_ChainSubRuleSet( &csrs[n] );
+
+ FREE( csrs );
+
+ Fail2:
+ Free_Coverage( &ccsf1->Coverage );
+ return error;
+ }
+
+
+ static void Free_ChainContext1( TTO_ChainContextSubstFormat1* ccsf1 )
+ {
+ 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] );
+
+ FREE( csrs );
+ }
+
+ Free_Coverage( &ccsf1->Coverage );
+ }
+
+
+ /* ChainSubClassRule */
+
+ static TT_Error Load_ChainSubClassRule(
+ TTO_ChainContextSubstFormat2* ccsf2,
+ TTO_ChainSubClassRule* cscr,
+ PFace input )
+ {
+ DEFINE_LOAD_LOCALS( input->stream );
+
+ UShort n, count;
+
+ UShort* b;
+ UShort* i;
+ UShort* l;
+ TTO_SubstLookupRecord* slr;
+ 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, 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, 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, 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 )
+ {
+ FREE( cscr->SubstLookupRecord );
+ FREE( cscr->Lookahead );
+ FREE( cscr->Input );
+ FREE( cscr->Backtrack );
+ }
+
+
+ /* SubClassSet */
+
+ static TT_Error Load_ChainSubClassSet(
+ TTO_ChainContextSubstFormat2* ccsf2,
+ TTO_ChainSubClassSet* cscs,
+ PFace input )
+ {
+ DEFINE_LOAD_LOCALS( input->stream );
+
+ UShort n, count;
+ 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],
+ input ) ) != TT_Err_Ok )
+ goto Fail;
+ (void)FILE_Seek( cur_offset );
+ }
+
+ return TT_Err_Ok;
+
+ Fail:
+ for ( n = 0; n < count; n++ )
+ Free_ChainSubClassRule( &cscr[n] );
+
+ FREE( cscr );
+ return error;
+ }
+
+
+ static void Free_ChainSubClassSet( TTO_ChainSubClassSet* cscs )
+ {
+ 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] );
+
+ FREE( cscr );
+ }
+ }
+
+
+ /* ChainContextSubstFormat2 */
+
+ static TT_Error Load_ChainContextSubst2(
+ TTO_ChainContextSubstFormat2* ccsf2,
+ PFace input )
+ {
+ DEFINE_LOAD_LOCALS( input->stream );
+
+ UShort n, count;
+ ULong cur_offset, new_offset, base_offset;
+ 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, input ) ) != TT_Err_Ok )
+ return error;
+ (void)FILE_Seek( cur_offset );
+
+ if ( ACCESS_Frame( 8L ) )
+ goto Fail5;
+
+ backtrack_offset = GET_UShort() + base_offset;
+ input_offset = GET_UShort() + base_offset;
+ lookahead_offset = GET_UShort() + base_offset;
+
+ /* `ChainSubClassSetCount' is the upper limit for input class values,
+ thus we read it now to make an additional safety check. */
+
+ count = ccsf2->ChainSubClassSetCount = GET_UShort();
+
+ FORGET_Frame();
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( backtrack_offset ) ||
+ ( error = Load_ClassDefinition( &ccsf2->BacktrackClassDef, count,
+ input ) ) != TT_Err_Ok )
+ goto Fail5;
+ if ( FILE_Seek( input_offset ) ||
+ ( error = Load_ClassDefinition( &ccsf2->InputClassDef, count,
+ input ) ) != TT_Err_Ok )
+ goto Fail4;
+ if ( FILE_Seek( lookahead_offset ) ||
+ ( error = Load_ClassDefinition( &ccsf2->LookaheadClassDef, count,
+ input ) ) != TT_Err_Ok )
+ goto Fail3;
+ (void)FILE_Seek( cur_offset );
+
+ 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],
+ input ) ) != 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 ( n = 0; n < count; n++ )
+ Free_ChainSubClassSet( &cscs[n] );
+
+ FREE( cscs );
+
+ Fail2:
+ Free_ClassDefinition( &ccsf2->LookaheadClassDef );
+
+ Fail3:
+ Free_ClassDefinition( &ccsf2->InputClassDef );
+
+ Fail4:
+ Free_ClassDefinition( &ccsf2->BacktrackClassDef );
+
+ Fail5:
+ Free_Coverage( &ccsf2->Coverage );
+ return error;
+ }
+
+
+ static void Free_ChainContext2( TTO_ChainContextSubstFormat2* ccsf2 )
+ {
+ 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] );
+
+ FREE( cscs );
+ }
+
+ Free_ClassDefinition( &ccsf2->LookaheadClassDef );
+ Free_ClassDefinition( &ccsf2->InputClassDef );
+ Free_ClassDefinition( &ccsf2->BacktrackClassDef );
+
+ Free_Coverage( &ccsf2->Coverage );
+ }
+
+
+ /* ChainContextSubstFormat3 */
+
+ static TT_Error Load_ChainContextSubst3(
+ TTO_ChainContextSubstFormat3* ccsf3,
+ PFace input )
+ {
+ DEFINE_LOAD_LOCALS( input->stream );
+
+ UShort n, count;
+ UShort backtrack_count, input_count, lookahead_count;
+ 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 ( n = 0; n < backtrack_count; n++ )
+ {
+ 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[n], input ) ) != 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 ( n = 0; n < input_count; n++ )
+ {
+ 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[n], input ) ) != 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 ( n = 0; n < lookahead_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( &l[n], input ) ) != 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 ( n = 0; n < lookahead_count; n++ )
+ Free_Coverage( &l[n] );
+
+ FREE( l );
+
+ Fail3:
+ for ( n = 0; n < input_count; n++ )
+ Free_Coverage( &i[n] );
+
+ FREE( i );
+
+ Fail4:
+ for ( n = 0; n < backtrack_count; n++ )
+ Free_Coverage( &b[n] );
+
+ FREE( b );
+ return error;
+ }
+
+
+ static void Free_ChainContext3( TTO_ChainContextSubstFormat3* ccsf3 )
+ {
+ 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] );
+
+ FREE( c );
+ }
+
+ if ( ccsf3->InputCoverage )
+ {
+ count = ccsf3->InputGlyphCount;
+ c = ccsf3->InputCoverage;
+
+ for ( n = 0; n < count; n++ )
+ Free_Coverage( &c[n] );
+
+ FREE( c );
+ }
+
+ if ( ccsf3->BacktrackCoverage )
+ {
+ count = ccsf3->BacktrackGlyphCount;
+ c = ccsf3->BacktrackCoverage;
+
+ for ( n = 0; n < count; n++ )
+ Free_Coverage( &c[n] );
+
+ FREE( c );
+ }
+ }
+
+
+ /* ChainContextSubst */
+
+ TT_Error Load_ChainContextSubst( TTO_ChainContextSubst* ccs,
+ PFace input )
+ {
+ DEFINE_LOAD_LOCALS( input->stream );
+
+
+ if ( ACCESS_Frame( 2L ) )
+ return error;
+
+ ccs->SubstFormat = GET_UShort();
+
+ FORGET_Frame();
+
+ switch ( ccs->SubstFormat )
+ {
+ case 1:
+ return Load_ChainContextSubst1( &ccs->ccsf.ccsf1, input );
+
+ case 2:
+ return Load_ChainContextSubst2( &ccs->ccsf.ccsf2, input );
+
+ case 3:
+ return Load_ChainContextSubst3( &ccs->ccsf.ccsf3, input );
+
+ default:
+ return TTO_Err_Invalid_GSUB_SubTable_Format;
+ }
+
+ return TT_Err_Ok; /* never reached */
+ }
+
+
+ void Free_ChainContextSubst( TTO_ChainContextSubst* ccs )
+ {
+ switch ( ccs->SubstFormat )
+ {
+ case 1:
+ Free_ChainContext1( &ccs->ccsf.ccsf1 );
+ break;
+
+ case 2:
+ Free_ChainContext2( &ccs->ccsf.ccsf2 );
+ break;
+
+ case 3:
+ Free_ChainContext3( &ccs->ccsf.ccsf3 );
+ break;
+ }
+ }
+
+
+ static TT_Error Lookup_ChainContextSubst1(
+ TTO_GSUBHeader* gsub,
+ TTO_ChainContextSubstFormat1* ccsf1,
+ TTO_GSUB_String* in,
+ TTO_GSUB_String* out,
+ UShort flags,
+ UShort context_length,
+ int nesting_level )
+ {
+ UShort index, property;
+ UShort i, j, k, num_csr, curr_pos;
+ UShort bgc, igc, lgc;
+ TT_Error error;
+ UShort* s_in;
+
+ TTO_ChainSubRule* csr;
+ TTO_ChainSubRule curr_csr;
+ TTO_GDEFHeader* gdef;
+
+
+ gdef = gsub->gdef;
+
+ if ( CHECK_Property( gdef, in->string[in->pos], flags, &property ) )
+ return error;
+
+ error = Coverage_Index( &ccsf1->Coverage, in->string[in->pos], &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 )
+ continue;
+
+ /* check whether context is too long; it is a first guess only */
+
+ if ( bgc > in->pos || in->pos + igc + lgc > in->length )
+ continue;
+
+ 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 */
+
+ curr_pos = 0;
+ s_in = &in->string[curr_pos];
+
+ for ( i = bgc, j = in->pos - 1; i > 0; i--, j-- )
+ {
+ while ( CHECK_Property( gdef, s_in[j], flags, &property ) )
+ {
+ if ( error && error != TTO_Err_Not_Covered )
+ return error;
+
+ if ( j > curr_pos )
+ j--;
+ else
+ break;
+ }
+
+ if ( s_in[j] != curr_csr.Backtrack[i - 1] )
+ break;
+ }
+
+ if ( i != 0 )
+ continue;
+ }
+
+ curr_pos = in->pos;
+ s_in = &in->string[curr_pos];
+
+ /* Start at 1 because [0] is implied */
+
+ for ( i = 1, j = 1; i < igc; i++, j++ )
+ {
+ while ( CHECK_Property( gdef, s_in[j], flags, &property ) )
+ {
+ if ( error && error != TTO_Err_Not_Covered )
+ return error;
+
+ if ( curr_pos + j < in->length )
+ j++;
+ else
+ break;
+ }
+
+ if ( s_in[j] != curr_csr.Input[i - 1] )
+ break;
+ }
+
+ if ( i != igc )
+ continue;
+
+ /* we are starting to check for lookahead glyphs right after the
+ last context glyph */
+
+ curr_pos = j;
+ s_in = &in->string[curr_pos];
+
+ for ( i = 0, j = 0; i < lgc; i++, j++ )
+ {
+ while ( CHECK_Property( gdef, s_in[j], flags, &property ) )
+ {
+ if ( error && error != TTO_Err_Not_Covered )
+ return error;
+
+ if ( curr_pos + j < in->length )
+ j++;
+ else
+ break;
+ }
+
+ if ( s_in[j] != curr_csr.Lookahead[i] )
+ break;
+ }
+
+ if ( i == lgc )
+ return Do_ContextSubst( gsub, igc,
+ curr_csr.SubstCount,
+ curr_csr.SubstLookupRecord,
+ in, out,
+ nesting_level );
+ }
+
+ return TTO_Err_Not_Covered;
+ }
+
+
+ static TT_Error Lookup_ChainContextSubst2(
+ TTO_GSUBHeader* gsub,
+ TTO_ChainContextSubstFormat2* ccsf2,
+ TTO_GSUB_String* in,
+ TTO_GSUB_String* out,
+ UShort flags,
+ UShort context_length,
+ int nesting_level )
+ {
+ UShort index, property;
+ TT_Error error;
+ UShort i, j, k, curr_pos;
+ UShort bgc, igc, lgc;
+ UShort known_backtrack_classes,
+ known_input_classes,
+ known_lookahead_classes;
+
+ UShort* backtrack_classes;
+ UShort* input_classes;
+ UShort* lookahead_classes;
+
+ UShort* s_in;
+
+ UShort* bc;
+ UShort* ic;
+ UShort* lc;
+
+ TTO_ChainSubClassSet* cscs;
+ TTO_ChainSubClassRule ccsr;
+ TTO_GDEFHeader* gdef;
+
+
+ gdef = gsub->gdef;
+
+ if ( CHECK_Property( gdef, in->string[in->pos], 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->string[in->pos], &index );
+ if ( error )
+ return error;
+
+ if ( ALLOC_ARRAY( backtrack_classes, ccsf2->MaxBacktrackLength, UShort ) )
+ return error;
+ known_backtrack_classes = 0;
+
+ if ( ALLOC_ARRAY( input_classes, ccsf2->MaxInputLength, UShort ) )
+ goto End3;
+ known_input_classes = 1;
+
+ if ( ALLOC_ARRAY( lookahead_classes, ccsf2->MaxLookaheadLength, UShort ) )
+ goto End2;
+ known_lookahead_classes = 0;
+
+ error = Get_Class( &ccsf2->InputClassDef, in->string[in->pos],
+ &input_classes[0], NULL );
+ if ( error )
+ 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 )
+ continue;
+
+ /* check whether context is too long; it is a first guess only */
+
+ if ( bgc > in->pos || in->pos + igc + lgc > in->length )
+ continue;
+
+ 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. */
+
+ curr_pos = 0;
+ s_in = &in->string[curr_pos];
+ bc = ccsr.Backtrack;
+
+ for ( i = 0, j = in->pos - 1; i < bgc; i++, j-- )
+ {
+ while ( CHECK_Property( gdef, s_in[j], flags, &property ) )
+ {
+ if ( error && error != TTO_Err_Not_Covered )
+ return error;
+
+ if ( j > curr_pos )
+ j--;
+ else
+ break;
+ }
+
+ if ( i >= known_backtrack_classes )
+ {
+ /* Keeps us from having to do this for each rule */
+
+ error = Get_Class( &ccsf2->BacktrackClassDef, s_in[j],
+ &backtrack_classes[i], NULL );
+ if ( error && error != TTO_Err_Not_Covered )
+ goto End1;
+ known_backtrack_classes = i;
+ }
+
+ if ( bc[bgc - 1 - i] != backtrack_classes[i] )
+ break;
+ }
+
+ if ( i != bgc )
+ continue;
+ }
+
+ curr_pos = in->pos;
+ s_in = &in->string[curr_pos];
+ ic = ccsr.Input;
+
+ /* Start at 1 because [0] is implied */
+
+ for ( i = 1, j = 1; i < igc; i++, j++ )
+ {
+ while ( CHECK_Property( gdef, s_in[j], flags, &property ) )
+ {
+ if ( error && error != TTO_Err_Not_Covered )
+ goto End1;
+
+ if ( curr_pos + j < in->length )
+ j++;
+ else
+ break;
+ }
+
+ if ( i >= known_input_classes )
+ {
+ error = Get_Class( &ccsf2->InputClassDef, s_in[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] )
+ break;
+ }
+
+ if ( i != igc )
+ continue;
+
+ /* we are starting to check for lookahead glyphs right after the
+ last context glyph */
+
+ curr_pos = j;
+ s_in = &in->string[curr_pos];
+ lc = ccsr.Lookahead;
+
+ for ( i = 0, j = 0; i < lgc; i++, j++ )
+ {
+ while ( CHECK_Property( gdef, s_in[j], flags, &property ) )
+ {
+ if ( error && error != TTO_Err_Not_Covered )
+ return error;
+
+ if ( curr_pos + j < in->length )
+ j++;
+ else
+ break;
+ }
+
+ if ( i >= known_lookahead_classes )
+ {
+ error = Get_Class( &ccsf2->LookaheadClassDef, s_in[j],
+ &lookahead_classes[i], NULL );
+ if ( error && error != TTO_Err_Not_Covered )
+ goto End1;
+ known_lookahead_classes = i;
+ }
+
+ if ( lc[i] != lookahead_classes[i] )
+ break;
+ }
+
+ if ( i == lgc )
+ {
+ error = Do_ContextSubst( gsub, igc,
+ ccsr.SubstCount,
+ ccsr.SubstLookupRecord,
+ in, out,
+ nesting_level );
+ goto End1;
+ }
+ }
+
+ error = TTO_Err_Not_Covered;
+
+ End1:
+ FREE( lookahead_classes );
+
+ End2:
+ FREE( input_classes );
+
+ End3:
+ FREE( backtrack_classes );
+ return error;
+ }
+
+
+ static TT_Error Lookup_ChainContextSubst3(
+ TTO_GSUBHeader* gsub,
+ TTO_ChainContextSubstFormat3* ccsf3,
+ TTO_GSUB_String* in,
+ TTO_GSUB_String* out,
+ UShort flags,
+ UShort context_length,
+ int nesting_level )
+ {
+ UShort index, i, j, curr_pos, property;
+ UShort bgc, igc, lgc;
+ TT_Error error;
+ UShort* s_in;
+
+ TTO_Coverage* bc;
+ TTO_Coverage* ic;
+ TTO_Coverage* lc;
+ TTO_GDEFHeader* gdef;
+
+
+ gdef = gsub->gdef;
+
+ if ( CHECK_Property( gdef, in->string[in->pos], 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 > in->pos || in->pos + igc + lgc > 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 */
+
+ curr_pos = 0;
+ s_in = &in->string[curr_pos];
+ bc = ccsf3->BacktrackCoverage;
+
+ for ( i = bgc, j = in->pos - 1; i > 0; i--, j-- )
+ {
+ while ( CHECK_Property( gdef, s_in[j], flags, &property ) )
+ {
+ if ( error && error != TTO_Err_Not_Covered )
+ return error;
+
+ if ( j > curr_pos )
+ j--;
+ else
+ return TTO_Err_Not_Covered;
+ }
+
+ error = Coverage_Index( &bc[i - 1], s_in[j], &index );
+ if ( error )
+ return error;
+ }
+ }
+
+ curr_pos = in->pos;
+ s_in = &in->string[curr_pos];
+ ic = ccsf3->InputCoverage;
+
+ /* Start at 1 because [0] is implied */
+
+ for ( i = 1, j = 1; i < igc; i++, j++ )
+ {
+ while ( CHECK_Property( gdef, s_in[j], flags, &property ) )
+ {
+ if ( error && error != TTO_Err_Not_Covered )
+ return error;
+
+ if ( curr_pos + j < in->length )
+ j++;
+ else
+ return TTO_Err_Not_Covered;
+ }
+
+ error = Coverage_Index( &ic[i], s_in[j], &index );
+ if ( error )
+ return error;
+ }
+
+ /* we are starting for lookahead glyphs right after the last context
+ glyph */
+
+ curr_pos = j;
+ s_in = &in->string[curr_pos];
+ lc = ccsf3->LookaheadCoverage;
+
+ for ( i = 0, j = 0; i < lgc; i++, j++ )
+ {
+ while ( CHECK_Property( gdef, s_in[j], flags, &property ) )
+ {
+ if ( error && error != TTO_Err_Not_Covered )
+ return error;
+
+ if ( curr_pos + j < in->length )
+ j++;
+ else
+ return TTO_Err_Not_Covered;
+ }
+
+ error = Coverage_Index( &lc[i], s_in[j], &index );
+ if ( error )
+ return error;
+ }
+
+ return Do_ContextSubst( gsub, igc,
+ ccsf3->SubstCount,
+ ccsf3->SubstLookupRecord,
+ in, out,
+ nesting_level );
+ }
+
+
+ static TT_Error Lookup_ChainContextSubst(
+ TTO_GSUBHeader* gsub,
+ TTO_ChainContextSubst* ccs,
+ TTO_GSUB_String* in,
+ TTO_GSUB_String* out,
+ UShort flags,
+ UShort context_length,
+ int nesting_level )
+ {
+ switch ( ccs->SubstFormat )
+ {
+ case 1:
+ return Lookup_ChainContextSubst1( gsub, &ccs->ccsf.ccsf1, in, out,
+ flags, context_length,
+ nesting_level );
+
+ case 2:
+ return Lookup_ChainContextSubst2( gsub, &ccs->ccsf.ccsf2, in, out,
+ flags, context_length,
+ nesting_level );
+
+ case 3:
+ return Lookup_ChainContextSubst3( gsub, &ccs->ccsf.ccsf3, in, out,
+ flags, context_length,
+ nesting_level );
+
+ default:
+ return TTO_Err_Invalid_GSUB_SubTable_Format;
+ }
+
+ return TT_Err_Ok; /* never reached */
+ }
+
+
+
+ /***********
+ * GSUB API
+ ***********/
+
+
+ EXPORT_FUNC
+ TT_Error TT_GSUB_Select_Script( TTO_GSUBHeader* gsub,
+ TT_ULong script_tag,
+ TT_UShort* script_index )
+ {
+ 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
+ TT_Error TT_GSUB_Select_Language( TTO_GSUBHeader* gsub,
+ TT_ULong language_tag,
+ TT_UShort script_index,
+ TT_UShort* language_index,
+ TT_UShort* req_feature_index )
+ {
+ 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
+ TT_Error TT_GSUB_Select_Feature( TTO_GSUBHeader* gsub,
+ TT_ULong feature_tag,
+ TT_UShort script_index,
+ TT_UShort language_index,
+ TT_UShort* feature_index )
+ {
+ UShort n;
+
+ TTO_ScriptList* sl;
+ TTO_ScriptRecord* sr;
+ TTO_Script* s;
+ TTO_LangSysRecord* lsr;
+ TTO_LangSys* ls;
+ 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
+ TT_Error TT_GSUB_Query_Scripts( TTO_GSUBHeader* gsub,
+ TT_ULong** script_tag_list )
+ {
+ UShort n;
+ TT_Error error;
+ ULong* stl;
+
+ TTO_ScriptList* sl;
+ TTO_ScriptRecord* sr;
+
+
+ if ( !gsub || !script_tag_list )
+ return TT_Err_Invalid_Argument;
+
+ sl = &gsub->ScriptList;
+ sr = sl->ScriptRecord;
+
+ if ( ALLOC_ARRAY( stl, sl->ScriptCount + 1, 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
+ TT_Error TT_GSUB_Query_Languages( TTO_GSUBHeader* gsub,
+ TT_UShort script_index,
+ TT_ULong** language_tag_list )
+ {
+ UShort n;
+ TT_Error error;
+ ULong* ltl;
+
+ TTO_ScriptList* sl;
+ TTO_ScriptRecord* sr;
+ TTO_Script* s;
+ TTO_LangSysRecord* lsr;
+
+
+ if ( !gsub || !language_tag_list )
+ 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;
+
+ if ( ALLOC_ARRAY( ltl, s->LangSysCount + 1, 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
+ TT_Error TT_GSUB_Query_Features( TTO_GSUBHeader* gsub,
+ TT_UShort script_index,
+ TT_UShort language_index,
+ TT_ULong** feature_tag_list )
+ {
+ UShort n;
+ TT_Error error;
+ ULong* ftl;
+
+ TTO_ScriptList* sl;
+ TTO_ScriptRecord* sr;
+ TTO_Script* s;
+ TTO_LangSysRecord* lsr;
+ TTO_LangSys* ls;
+ UShort* fi;
+
+ TTO_FeatureList* fl;
+ TTO_FeatureRecord* fr;
+
+
+ if ( !gsub || !feature_tag_list )
+ 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;
+
+ if ( ALLOC_ARRAY( ftl, ls->FeatureCount + 1, 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;
+ }
+
+
+ /* Do an individual subtable lookup. Returns TT_Err_Ok if substitution
+ has been done, or TTO_Err_Not_Covered if not. */
+
+ static TT_Error Do_Glyph_Lookup( TTO_GSUBHeader* gsub,
+ UShort lookup_index,
+ TTO_GSUB_String* in,
+ TTO_GSUB_String* out,
+ UShort context_length,
+ int nesting_level )
+ {
+ TT_Error error = TT_Err_Ok;
+ UShort i, flags;
+ TTO_Lookup* lo;
+
+
+ nesting_level++;
+
+ if ( nesting_level > TTO_MAX_NESTING_LEVEL )
+ return TTO_Err_Too_Many_Nested_Contexts;
+
+ lo = &gsub->LookupList.Lookup[lookup_index];
+ flags = lo->LookupFlag;
+
+ for ( i = 0; i < lo->SubTableCount; i++ )
+ {
+ switch ( lo->LookupType )
+ {
+ case GSUB_LOOKUP_SINGLE:
+ error = Lookup_SingleSubst( &lo->SubTable[i].st.gsub.single,
+ in, out,
+ flags, context_length, gsub->gdef );
+ break;
+
+ case GSUB_LOOKUP_MULTIPLE:
+ error = Lookup_MultipleSubst( &lo->SubTable[i].st.gsub.multiple,
+ in, out,
+ flags, context_length, gsub->gdef );
+ break;
+
+ case GSUB_LOOKUP_ALTERNATE:
+ error = Lookup_AlternateSubst( gsub,
+ &lo->SubTable[i].st.gsub.alternate,
+ in, out,
+ flags, context_length, gsub->gdef );
+ break;
+
+ case GSUB_LOOKUP_LIGATURE:
+ error = Lookup_LigatureSubst( &lo->SubTable[i].st.gsub.ligature,
+ in, out,
+ flags, context_length, gsub->gdef );
+ break;
+
+ case GSUB_LOOKUP_CONTEXT:
+ error = Lookup_ContextSubst( gsub, &lo->SubTable[i].st.gsub.context,
+ in, out,
+ flags, context_length, nesting_level );
+ break;
+
+ case GSUB_LOOKUP_CHAIN:
+ error = Lookup_ChainContextSubst( gsub,
+ &lo->SubTable[i].st.gsub.chain,
+ in, out,
+ flags, context_length,
+ nesting_level );
+ break;
+ }
+
+ /* 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 TT_Error Do_String_Lookup( TTO_GSUBHeader* gsub,
+ UShort lookup_index,
+ TTO_GSUB_String* in,
+ TTO_GSUB_String* out )
+ {
+ TT_Error error = TTO_Err_Not_Covered;
+
+ UShort* properties = gsub->LookupList.Properties;
+ UShort* p_in = in->properties;
+ UShort* s_in = in->string;
+
+ int nesting_level = 0;
+
+
+ while ( in->pos < in->length )
+ {
+ if ( ~p_in[in->pos] & properties[lookup_index] )
+ {
+ /* 0xFFFF indicates that we don't have a context length yet */
+ error = Do_Glyph_Lookup( gsub, lookup_index, in, out,
+ 0xFFFF, nesting_level );
+ if ( error && error != TTO_Err_Not_Covered )
+ return error;
+ }
+ else
+ error = TTO_Err_Not_Covered;
+
+ if ( error == TTO_Err_Not_Covered )
+ if ( ADD_String( in, 1, out, 1, &s_in[in->pos], 0xFFFF, 0xFFFF ) )
+ return error;
+ }
+
+ return error;
+ }
+
+
+ EXPORT_FUNC
+ TT_Error TT_GSUB_Add_Feature( TTO_GSUBHeader* gsub,
+ TT_UShort feature_index,
+ TT_UShort property )
+ {
+ UShort i;
+
+ TTO_Feature feature;
+ UShort* properties;
+ UShort* index;
+
+
+ if ( !gsub ||
+ feature_index >= gsub->FeatureList.FeatureCount )
+ return TT_Err_Invalid_Argument;
+
+ properties = gsub->LookupList.Properties;
+
+ feature = gsub->FeatureList.FeatureRecord[feature_index].Feature;
+ index = feature.LookupListIndex;
+
+ for ( i = 0; i < feature.LookupListCount; i++ )
+ properties[index[i]] |= property;
+
+ return TT_Err_Ok;
+ }
+
+
+ EXPORT_FUNC
+ TT_Error TT_GSUB_Clear_Features( TTO_GSUBHeader* gsub )
+ {
+ UShort i;
+
+ UShort* properties;
+
+
+ if ( !gsub )
+ return TT_Err_Invalid_Argument;
+
+ properties = gsub->LookupList.Properties;
+
+ for ( i = 0; i < gsub->LookupList.LookupCount; i++ )
+ properties[i] = 0;
+
+ return TT_Err_Ok;
+ }
+
+
+ EXPORT_FUNC
+ TT_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
+ TT_Error TT_GSUB_Apply_String( TTO_GSUBHeader* gsub,
+ TTO_GSUB_String* in,
+ TTO_GSUB_String* out )
+ {
+ TT_Error error = TTO_Err_Not_Covered;
+ UShort j;
+
+ TTO_GSUB_String tmp1;
+ TTO_GSUB_String* ptmp1;
+ TTO_GSUB_String tmp2;
+ TTO_GSUB_String* ptmp2;
+ TTO_GSUB_String* t;
+
+ UShort* properties;
+
+
+ if ( !gsub ||
+ !in || !out || in->length == 0 || in->pos >= in->length )
+ return TT_Err_Invalid_Argument;
+
+ properties = gsub->LookupList.Properties;
+
+ tmp1.length = in->length;
+ tmp1.allocated = in->length;
+ tmp1.pos = in->pos;
+ tmp1.max_ligID = 1;
+
+ if ( ALLOC_ARRAY( tmp1.string, tmp1.length, UShort ) )
+ return error;
+ MEM_Copy( tmp1.string, in->string, in->length * sizeof ( UShort ) );
+
+ /* make sure that we always have a `properties', `components', and
+ `ligIDs' array in the string object */
+
+ if ( ALLOC_ARRAY( tmp1.components, tmp1.length, UShort ) )
+ return error;
+ if ( ALLOC_ARRAY( tmp1.ligIDs, tmp1.length, UShort ) )
+ return error;
+ if ( ALLOC_ARRAY( tmp1.properties, tmp1.length, UShort ) )
+ return error;
+ if ( in->properties )
+ MEM_Copy( tmp1.properties, in->properties,
+ in->length * sizeof( UShort ) );
+
+ tmp2.allocated = 0;
+ tmp2.pos = 0;
+ tmp2.string = NULL;
+ tmp2.properties = NULL;
+ tmp2.components = NULL;
+ tmp2.ligIDs = NULL;
+
+ ptmp1 = &tmp1;
+ ptmp2 = &tmp2;
+
+ for ( j = 0; j < gsub->LookupList.LookupCount; j++ )
+ if ( properties[j] )
+ {
+ error = Do_String_Lookup( gsub, j, ptmp1, ptmp2 );
+ if ( error && error != TTO_Err_Not_Covered )
+ return error;
+
+ /* flipping `in' and `out', preparing the next loop */
+
+ ptmp1->pos = in->pos;
+ ptmp2->length = ptmp2->pos;
+ ptmp2->pos = in->pos;
+ ptmp2->max_ligID = ptmp1->max_ligID;
+
+ t = ptmp2;
+ ptmp2 = ptmp1;
+ ptmp1 = t;
+ }
+
+ out->length = ptmp1->length;
+ out->pos = 0;
+ out->allocated = ptmp1->allocated;
+ out->string = ptmp1->string;
+ out->components = ptmp1->components;
+ out->ligIDs = ptmp1->ligIDs;
+
+ if ( in->properties )
+ out->properties = ptmp1->properties;
+ else
+ {
+ FREE( ptmp1->properties );
+ out->properties = NULL;
+ }
+
+ FREE( ptmp2->string );
+ FREE( ptmp2->properties );
+ FREE( ptmp2->components );
+ FREE( ptmp2->ligIDs );
+
+ return error;
+ }
+
+
+/* END */
diff --git a/Build/source/libs/libttf/extend/ftxgsub.h b/Build/source/libs/libttf/extend/ftxgsub.h
new file mode 100644
index 00000000000..463cd27240a
--- /dev/null
+++ b/Build/source/libs/libttf/extend/ftxgsub.h
@@ -0,0 +1,592 @@
+/*******************************************************************
+ *
+ * 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
+
+
+/* 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 TT_UShort (*TTO_AltFunction)(TT_ULong pos,
+ TT_UShort glyphID,
+ TT_UShort num_alternates,
+ TT_UShort* alternates,
+ void* data );
+
+
+ struct TTO_GSUBHeader_
+ {
+ TT_Bool loaded;
+ TT_ULong offset;
+
+ TT_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;
+
+
+ /* LookupType 1 */
+
+ struct TTO_SingleSubstFormat1_
+ {
+ TT_Short DeltaGlyphID; /* constant added to get
+ substitution glyph index */
+ };
+
+ typedef struct TTO_SingleSubstFormat1_ TTO_SingleSubstFormat1;
+
+
+ struct TTO_SingleSubstFormat2_
+ {
+ TT_UShort GlyphCount; /* number of glyph IDs in
+ Substitute array */
+ TT_UShort* Substitute; /* array of substitute glyph IDs */
+ };
+
+ typedef struct TTO_SingleSubstFormat2_ TTO_SingleSubstFormat2;
+
+
+ struct TTO_SingleSubst_
+ {
+ TT_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_
+ {
+ TT_UShort GlyphCount; /* number of glyph IDs in the
+ Substitute array */
+ TT_UShort* Substitute; /* string of glyph IDs to
+ substitute */
+ };
+
+ typedef struct TTO_Sequence_ TTO_Sequence;
+
+
+ struct TTO_MultipleSubst_
+ {
+ TT_UShort SubstFormat; /* always 1 */
+ TTO_Coverage Coverage; /* Coverage table */
+ TT_UShort SequenceCount; /* number of Sequence tables */
+ TTO_Sequence* Sequence; /* array of Sequence tables */
+ };
+
+ typedef struct TTO_MultipleSubst_ TTO_MultipleSubst;
+
+
+ /* LookupType 3 */
+
+ struct TTO_AlternateSet_
+ {
+ TT_UShort GlyphCount; /* number of glyph IDs in the
+ Alternate array */
+ TT_UShort* Alternate; /* array of alternate glyph IDs */
+ };
+
+ typedef struct TTO_AlternateSet_ TTO_AlternateSet;
+
+
+ struct TTO_AlternateSubst_
+ {
+ TT_UShort SubstFormat; /* always 1 */
+ TTO_Coverage Coverage; /* Coverage table */
+ TT_UShort AlternateSetCount;
+ /* number of AlternateSet tables */
+ TTO_AlternateSet* AlternateSet; /* array of AlternateSet tables */
+ };
+
+ typedef struct TTO_AlternateSubst_ TTO_AlternateSubst;
+
+
+ /* LookupType 4 */
+
+ struct TTO_Ligature_
+ {
+ TT_UShort LigGlyph; /* glyphID of ligature
+ to substitute */
+ TT_UShort ComponentCount; /* number of components in ligature */
+ TT_UShort* Component; /* array of component glyph IDs */
+ };
+
+ typedef struct TTO_Ligature_ TTO_Ligature;
+
+
+ struct TTO_LigatureSet_
+ {
+ TT_UShort LigatureCount; /* number of Ligature tables */
+ TTO_Ligature* Ligature; /* array of Ligature tables */
+ };
+
+ typedef struct TTO_LigatureSet_ TTO_LigatureSet;
+
+
+ struct TTO_LigatureSubst_
+ {
+ TT_UShort SubstFormat; /* always 1 */
+ TTO_Coverage Coverage; /* Coverage table */
+ TT_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_
+ {
+ TT_UShort SequenceIndex; /* index into current
+ glyph sequence */
+ TT_UShort LookupListIndex; /* Lookup to apply to that pos. */
+ };
+
+ typedef struct TTO_SubstLookupRecord_ TTO_SubstLookupRecord;
+
+
+ /* LookupType 5 */
+
+ struct TTO_SubRule_
+ {
+ TT_UShort GlyphCount; /* total number of input glyphs */
+ TT_UShort SubstCount; /* number of SubstLookupRecord
+ tables */
+ TT_UShort* Input; /* array of input glyph IDs */
+ TTO_SubstLookupRecord* SubstLookupRecord;
+ /* array of SubstLookupRecord
+ tables */
+ };
+
+ typedef struct TTO_SubRule_ TTO_SubRule;
+
+
+ struct TTO_SubRuleSet_
+ {
+ TT_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 */
+ TT_UShort SubRuleSetCount; /* number of SubRuleSet tables */
+ TTO_SubRuleSet* SubRuleSet; /* array of SubRuleSet tables */
+ };
+
+ typedef struct TTO_ContextSubstFormat1_ TTO_ContextSubstFormat1;
+
+
+ struct TTO_SubClassRule_
+ {
+ TT_UShort GlyphCount; /* total number of context classes */
+ TT_UShort SubstCount; /* number of SubstLookupRecord
+ tables */
+ TT_UShort* Class; /* array of classes */
+ TTO_SubstLookupRecord* SubstLookupRecord;
+ /* array of SubstLookupRecord
+ tables */
+ };
+
+ typedef struct TTO_SubClassRule_ TTO_SubClassRule;
+
+
+ struct TTO_SubClassSet_
+ {
+ TT_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_
+ {
+ TT_UShort MaxContextLength;
+ /* maximal context length */
+ TTO_Coverage Coverage; /* Coverage table */
+ TTO_ClassDefinition ClassDef; /* ClassDef table */
+ TT_UShort SubClassSetCount;
+ /* number of SubClassSet tables */
+ TTO_SubClassSet* SubClassSet; /* array of SubClassSet tables */
+ };
+
+ typedef struct TTO_ContextSubstFormat2_ TTO_ContextSubstFormat2;
+
+
+ struct TTO_ContextSubstFormat3_
+ {
+ TT_UShort GlyphCount; /* number of input glyphs */
+ TT_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_
+ {
+ TT_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_
+ {
+ TT_UShort BacktrackGlyphCount;
+ /* total number of backtrack glyphs */
+ TT_UShort* Backtrack; /* array of backtrack glyph IDs */
+ TT_UShort InputGlyphCount;
+ /* total number of input glyphs */
+ TT_UShort* Input; /* array of input glyph IDs */
+ TT_UShort LookaheadGlyphCount;
+ /* total number of lookahead glyphs */
+ TT_UShort* Lookahead; /* array of lookahead glyph IDs */
+ TT_UShort SubstCount; /* number of SubstLookupRecords */
+ TTO_SubstLookupRecord* SubstLookupRecord;
+ /* array of SubstLookupRecords */
+ };
+
+ typedef struct TTO_ChainSubRule_ TTO_ChainSubRule;
+
+
+ struct TTO_ChainSubRuleSet_
+ {
+ TT_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 */
+ TT_UShort ChainSubRuleSetCount;
+ /* number of ChainSubRuleSet tables */
+ TTO_ChainSubRuleSet* ChainSubRuleSet;
+ /* array of ChainSubRuleSet tables */
+ };
+
+ typedef struct TTO_ChainContextSubstFormat1_ TTO_ChainContextSubstFormat1;
+
+
+ struct TTO_ChainSubClassRule_
+ {
+ TT_UShort BacktrackGlyphCount;
+ /* total number of backtrack
+ classes */
+ TT_UShort* Backtrack; /* array of backtrack classes */
+ TT_UShort InputGlyphCount;
+ /* total number of context classes */
+ TT_UShort* Input; /* array of context classes */
+ TT_UShort LookaheadGlyphCount;
+ /* total number of lookahead
+ classes */
+ TT_UShort* Lookahead; /* array of lookahead classes */
+ TT_UShort SubstCount; /* number of SubstLookupRecords */
+ TTO_SubstLookupRecord* SubstLookupRecord;
+ /* array of substitution lookups */
+ };
+
+ typedef struct TTO_ChainSubClassRule_ TTO_ChainSubClassRule;
+
+
+ struct TTO_ChainSubClassSet_
+ {
+ TT_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 */
+
+ TT_UShort MaxBacktrackLength;
+ /* maximal backtrack length */
+ TTO_ClassDefinition BacktrackClassDef;
+ /* BacktrackClassDef table */
+ TT_UShort MaxInputLength;
+ /* maximal input length */
+ TTO_ClassDefinition InputClassDef;
+ /* InputClassDef table */
+ TT_UShort MaxLookaheadLength;
+ /* maximal lookahead length */
+ TTO_ClassDefinition LookaheadClassDef;
+ /* LookaheadClassDef table */
+
+ TT_UShort ChainSubClassSetCount;
+ /* number of ChainSubClassSet
+ tables */
+ TTO_ChainSubClassSet* ChainSubClassSet;
+ /* array of ChainSubClassSet
+ tables */
+ };
+
+ typedef struct TTO_ChainContextSubstFormat2_ TTO_ChainContextSubstFormat2;
+
+
+ struct TTO_ChainContextSubstFormat3_
+ {
+ TT_UShort BacktrackGlyphCount;
+ /* number of backtrack glyphs */
+ TTO_Coverage* BacktrackCoverage;
+ /* array of backtrack Coverage
+ tables */
+ TT_UShort InputGlyphCount;
+ /* number of input glyphs */
+ TTO_Coverage* InputCoverage;
+ /* array of input coverage
+ tables */
+ TT_UShort LookaheadGlyphCount;
+ /* number of lookahead glyphs */
+ TTO_Coverage* LookaheadCoverage;
+ /* array of lookahead coverage
+ tables */
+ TT_UShort SubstCount; /* number of SubstLookupRecords */
+ TTO_SubstLookupRecord* SubstLookupRecord;
+ /* array of substitution lookups */
+ };
+
+ typedef struct TTO_ChainContextSubstFormat3_ TTO_ChainContextSubstFormat3;
+
+
+ struct TTO_ChainContextSubst_
+ {
+ TT_UShort SubstFormat; /* 1, 2, or 3 */
+
+ union
+ {
+ TTO_ChainContextSubstFormat1 ccsf1;
+ TTO_ChainContextSubstFormat2 ccsf2;
+ TTO_ChainContextSubstFormat3 ccsf3;
+ } ccsf;
+ };
+
+ typedef struct TTO_ChainContextSubst_ TTO_ChainContextSubst;
+
+
+ union TTO_GSUB_SubTable_
+ {
+ TTO_SingleSubst single;
+ TTO_MultipleSubst multiple;
+ TTO_AlternateSubst alternate;
+ TTO_LigatureSubst ligature;
+ TTO_ContextSubst context;
+ TTO_ChainContextSubst chain;
+ };
+
+ 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. */
+
+ struct TTO_GSUB_String_
+ {
+ TT_ULong length;
+ TT_ULong pos;
+ TT_ULong allocated;
+ TT_UShort* string;
+ TT_UShort* properties;
+ TT_UShort* components;
+ TT_UShort max_ligID;
+ TT_UShort* ligIDs;
+ };
+
+ typedef struct TTO_GSUB_String_ TTO_GSUB_String;
+
+
+ /* finally, the GSUB API */
+
+ EXPORT_DEF
+ TT_Error TT_Init_GSUB_Extension( TT_Engine engine );
+
+ EXPORT_DEF
+ TT_Error TT_Load_GSUB_Table( TT_Face face,
+ TTO_GSUBHeader* gsub,
+ TTO_GDEFHeader* gdef );
+
+ EXPORT_DEF
+ TT_Error TT_GSUB_Select_Script( TTO_GSUBHeader* gsub,
+ TT_ULong script_tag,
+ TT_UShort* script_index );
+ EXPORT_DEF
+ TT_Error TT_GSUB_Select_Language( TTO_GSUBHeader* gsub,
+ TT_ULong language_tag,
+ TT_UShort script_index,
+ TT_UShort* language_index,
+ TT_UShort* req_feature_index );
+ EXPORT_DEF
+ TT_Error TT_GSUB_Select_Feature( TTO_GSUBHeader* gsub,
+ TT_ULong feature_tag,
+ TT_UShort script_index,
+ TT_UShort language_index,
+ TT_UShort* feature_index );
+
+ EXPORT_DEF
+ TT_Error TT_GSUB_Query_Scripts( TTO_GSUBHeader* gsub,
+ TT_ULong** script_tag_list );
+ EXPORT_DEF
+ TT_Error TT_GSUB_Query_Languages( TTO_GSUBHeader* gsub,
+ TT_UShort script_index,
+ TT_ULong** language_tag_list );
+ EXPORT_DEF
+ TT_Error TT_GSUB_Query_Features( TTO_GSUBHeader* gsub,
+ TT_UShort script_index,
+ TT_UShort language_index,
+ TT_ULong** feature_tag_list );
+
+ EXPORT_DEF
+ TT_Error TT_GSUB_Add_Feature( TTO_GSUBHeader* gsub,
+ TT_UShort feature_index,
+ TT_UShort property );
+ EXPORT_DEF
+ TT_Error TT_GSUB_Clear_Features( TTO_GSUBHeader* gsub );
+
+ EXPORT_DEF
+ TT_Error TT_GSUB_Register_Alternate_Function( TTO_GSUBHeader* gsub,
+ TTO_AltFunction altfunc,
+ void* data );
+
+ EXPORT_DEF
+ TT_Error TT_GSUB_Apply_String( TTO_GSUBHeader* gsub,
+ TTO_GSUB_String* in,
+ TTO_GSUB_String* out );
+
+ EXPORT_DEF
+ TT_Error TT_GSUB_Add_String( TTO_GSUB_String* in,
+ TT_UShort num_in,
+ TTO_GSUB_String* out,
+ TT_UShort num_out,
+ TT_UShort* glyph_data,
+ TT_UShort component,
+ TT_UShort ligID );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FTXGSUB_H */
+
+
+/* END */
diff --git a/Build/source/libs/libttf/extend/ftxkern.c b/Build/source/libs/libttf/extend/ftxkern.c
new file mode 100644
index 00000000000..94e10822816
--- /dev/null
+++ b/Build/source/libs/libttf/extend/ftxkern.c
@@ -0,0 +1,603 @@
+/*******************************************************************
+ *
+ * ftxkern.c 1.0
+ *
+ * Kerning support extension.
+ *
+ * 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.
+ *
+ *
+ * The kerning support is currently part of the engine extensions.
+ *
+ ******************************************************************/
+
+#include "ttconfig.h"
+#include "ftxkern.h"
+
+#include "ttextend.h"
+#include "tttypes.h"
+#include "ttdebug.h"
+#include "ttmemory.h"
+#include "ttfile.h"
+#include "ttobjs.h"
+#include "ttload.h" /* For the macros */
+#include "tttags.h"
+
+#include <stdlib.h> /* for qsort */
+
+/* Required by the tracing mode */
+#undef TT_COMPONENT
+#define TT_COMPONENT trace_any
+
+#define KERNING_ID Build_Extension_ID( 'k', 'e', 'r', 'n' )
+
+#undef KERN_INDEX
+#define KERN_INDEX(g1,g2) (((TT_ULong)g1 << 16) | g2)
+
+ /* compare two kerning pairs, for qsort() */
+ static
+ int __cdecl compare_kern_pairs( const void* a, const void* b )
+ {
+ TT_Kern_0_Pair* pair1 = (TT_Kern_0_Pair*)a;
+ TT_Kern_0_Pair* pair2 = (TT_Kern_0_Pair*)b;
+
+ TT_ULong index1 = KERN_INDEX( pair1->left, pair1->right );
+ TT_ULong index2 = KERN_INDEX( pair2->left, pair2->right );
+
+ return ( index1 < index2 ? -1 :
+ ( index1 > index2 ? 1 : 0 ));
+ }
+
+ /* check whether the kern table is sorted */
+ static
+ int is_sorted( TT_Kern_0_Pair* table, TT_ULong num_pairs )
+ {
+ TT_ULong i;
+
+ for ( i=1; i<num_pairs; i++ )
+ {
+ if ( compare_kern_pairs(&table[i-1], &table[i]) != -1 )
+ return 0;
+ }
+ return 1;
+ }
+
+
+/*******************************************************************
+ *
+ * Function : SubTable_Load_0
+ *
+ * Description : Loads a format 0 kerning subtable data.
+ *
+ * Input : kern0 pointer to the kerning subtable
+ *
+ * Output : error code
+ *
+ * Notes : - Assumes that the stream is already `used'
+ *
+ * - the file cursor must be set by the caller
+ *
+ * - in case of error, the function _must_ destroy
+ * the data it allocates!
+ *
+ ******************************************************************/
+
+ static TT_Error Subtable_Load_0( TT_Kern_0* kern0,
+ PFace input )
+ {
+ DEFINE_LOAD_LOCALS( input->stream );
+
+ UShort num_pairs, n;
+
+
+ if ( ACCESS_Frame( 8L ) )
+ return error;
+
+ num_pairs = GET_UShort();
+ kern0->nPairs = 0;
+ kern0->searchRange = GET_UShort();
+ kern0->entrySelector = GET_UShort();
+ kern0->rangeShift = GET_UShort();
+
+ /* we only set kern0->nPairs if the subtable has been loaded */
+
+ FORGET_Frame();
+
+ if ( ALLOC_ARRAY( kern0->pairs, num_pairs, TT_Kern_0_Pair ) )
+ return error;
+
+ if ( ACCESS_Frame( num_pairs * 6L ) )
+ goto Fail;
+
+ for ( n = 0; n < num_pairs; n++ )
+ {
+ kern0->pairs[n].left = GET_UShort();
+ kern0->pairs[n].right = GET_UShort();
+ kern0->pairs[n].value = GET_UShort();
+
+ if ( kern0->pairs[n].left >= input->numGlyphs ||
+ kern0->pairs[n].right >= input->numGlyphs )
+ {
+ FORGET_Frame();
+ error = TT_Err_Invalid_Kerning_Table;
+ goto Fail;
+ }
+ }
+
+ FORGET_Frame();
+
+ /* we're ok, set the pairs count */
+ kern0->nPairs = num_pairs;
+
+ /* the spec says that the kerning pairs must be sorted,
+ but some brain damaged font producers don't do that correctly.. (JvR 3/4/2000) */
+ if ( !is_sorted( kern0->pairs, num_pairs ) )
+ qsort( kern0->pairs, num_pairs, sizeof(TT_Kern_0_Pair), compare_kern_pairs );
+
+ return TT_Err_Ok;
+
+ Fail:
+ FREE( kern0->pairs );
+ return error;
+ }
+
+
+/*******************************************************************
+ *
+ * Function : SubTable_Load_2
+ *
+ * Description : Loads a format 2 kerning subtable data.
+ *
+ * Input : kern2 pointer to the kerning subtable
+ * length subtable length. This is required as
+ * the subheader doesn't give any indication
+ * of the size of the `array' table.
+ *
+ * Output : error code
+ *
+ * Notes : - Assumes that the stream is already `used'
+ *
+ * - the file cursor must be set by the caller
+ *
+ * - in case of error, the function _must_ destroy
+ * the data it allocates!
+ *
+ ******************************************************************/
+
+ static TT_Error Subtable_Load_2( TT_Kern_2* kern2,
+ PFace input )
+ {
+ DEFINE_LOAD_LOCALS( input->stream );
+
+ Long table_base;
+
+ UShort left_offset, right_offset, array_offset;
+ ULong array_size;
+ UShort left_max, right_max, n;
+
+
+ /* record the table offset */
+ table_base = FILE_Pos();
+
+ if ( ACCESS_Frame( 8L ) )
+ return error;
+
+ kern2->rowWidth = GET_UShort();
+ left_offset = GET_UShort();
+ right_offset = GET_UShort();
+ array_offset = GET_UShort();
+
+ FORGET_Frame();
+
+ /* first load left and right glyph classes */
+
+ if ( FILE_Seek( table_base + left_offset ) ||
+ ACCESS_Frame( 4L ) )
+ return error;
+
+ kern2->leftClass.firstGlyph = GET_UShort();
+ kern2->leftClass.nGlyphs = GET_UShort();
+
+ FORGET_Frame();
+
+ if ( ALLOC_ARRAY( kern2->leftClass.classes,
+ kern2->leftClass.nGlyphs,
+ UShort ) )
+ return error;
+
+ /* load left offsets */
+
+ if ( ACCESS_Frame( kern2->leftClass.nGlyphs * 2L ) )
+ goto Fail_Left;
+
+ for ( n = 0; n < kern2->leftClass.nGlyphs; n++ )
+ kern2->leftClass.classes[n] = GET_UShort();
+
+ FORGET_Frame();
+
+ /* right class */
+
+ if ( FILE_Seek( table_base + right_offset ) ||
+ ACCESS_Frame( 4L ) )
+ goto Fail_Left;
+
+ kern2->rightClass.firstGlyph = GET_UShort();
+ kern2->rightClass.nGlyphs = GET_UShort();
+
+ FORGET_Frame();
+
+ if ( ALLOC_ARRAY( kern2->rightClass.classes,
+ kern2->rightClass.nGlyphs,
+ UShort ) )
+ goto Fail_Left;
+
+ /* load right offsets */
+
+ if ( ACCESS_Frame( kern2->rightClass.nGlyphs * 2L ) )
+ goto Fail_Right;
+
+ for ( n = 0; n < kern2->rightClass.nGlyphs; n++ )
+ kern2->rightClass.classes[n] = GET_UShort();
+
+ FORGET_Frame();
+
+ /* Now load the kerning array. We don't have its size, we */
+ /* must compute it from what we know. */
+
+ /* We thus compute the maximum left and right offsets and */
+ /* add them to get the array size. */
+
+ left_max = right_max = 0;
+
+ for ( n = 0; n < kern2->leftClass.nGlyphs; n++ )
+ left_max = MAX( left_max, kern2->leftClass.classes[n] );
+
+ for ( n = 0; n < kern2->rightClass.nGlyphs; n++ )
+ right_max = MAX( right_max, kern2->leftClass.classes[n] );
+
+ array_size = left_max + right_max + 2;
+
+ if ( ALLOC( kern2->array, array_size ) )
+ goto Fail_Right;
+
+ if ( ACCESS_Frame( array_size ) )
+ goto Fail_Array;
+
+ for ( n = 0; n < array_size/2; n++ )
+ kern2->array[n] = GET_Short();
+
+ FORGET_Frame();
+
+ /* we're good now */
+
+ return TT_Err_Ok;
+
+ Fail_Array:
+ FREE( kern2->array );
+
+ Fail_Right:
+ FREE( kern2->rightClass.classes );
+ kern2->rightClass.nGlyphs = 0;
+
+ Fail_Left:
+ FREE( kern2->leftClass.classes );
+ kern2->leftClass.nGlyphs = 0;
+
+ return error;
+ }
+
+
+/*******************************************************************
+ *
+ * Function : Kerning_Create
+ *
+ * Description : Creates the kerning directory if a face is
+ * loaded. The tables however are loaded on
+ * demand to save space.
+ *
+ * Input : face pointer to the parent face object
+ * kern pointer to the extension's kerning field
+ *
+ * Output : error code
+ *
+ * Notes : as in all constructors, the memory allocated isn't
+ * released in case of failure. Rather, the task is left
+ * to the destructor (which is called if an error
+ * occurs during the loading of a face).
+ *
+ ******************************************************************/
+
+ static TT_Error Kerning_Create( void* ext,
+ PFace face )
+ {
+ DEFINE_LOAD_LOCALS( face->stream );
+
+ TT_Kerning* kern = (TT_Kerning*)ext;
+ UShort num_tables;
+ Long table;
+
+ TT_Kern_Subtable* sub;
+
+
+ /* by convention */
+ if ( !kern )
+ return TT_Err_Ok;
+
+ /* Now load the kerning directory. We're called from the face */
+ /* constructor. We thus need not use the stream. */
+
+ kern->version = 0;
+ kern->nTables = 0;
+ kern->tables = NULL;
+
+ table = TT_LookUp_Table( face, TTAG_kern );
+ if ( table < 0 )
+ return TT_Err_Ok; /* The table is optional */
+
+ if ( FILE_Seek( face->dirTables[table].Offset ) ||
+ ACCESS_Frame( 4L ) )
+ return error;
+
+ kern->version = GET_UShort();
+ num_tables = GET_UShort();
+
+ FORGET_Frame();
+
+ /* we don't set kern->nTables until we have allocated the array */
+
+ if ( ALLOC_ARRAY( kern->tables, num_tables, TT_Kern_Subtable ) )
+ return error;
+
+ kern->nTables = num_tables;
+
+ /* now load the directory entries, but do _not_ load the tables ! */
+
+ sub = kern->tables;
+
+ for ( table = 0; table < num_tables; table++ )
+ {
+ if ( ACCESS_Frame( 6L ) )
+ return error;
+
+ sub->loaded = FALSE; /* redundant, but good to see */
+ sub->version = GET_UShort();
+ sub->length = GET_UShort() - 6; /* substract header length */
+ sub->format = GET_Byte();
+ sub->coverage = GET_Byte();
+
+ FORGET_Frame();
+
+ sub->offset = FILE_Pos();
+
+ /* now skip to the next table */
+
+ if ( FILE_Skip( sub->length ) )
+ return error;
+
+ sub++;
+ }
+
+ /* that's fine, leave now */
+
+ return TT_Err_Ok;
+ }
+
+
+/*******************************************************************
+ *
+ * Function : Kerning_Destroy
+ *
+ * Description : Destroys all kerning information.
+ *
+ * Input : kern pointer to the extension's kerning field
+ *
+ * Output : error code
+ *
+ * Notes : This function is a destructor; it must be able
+ * to destroy partially built tables.
+ *
+ ******************************************************************/
+
+ static TT_Error Kerning_Destroy( void* ext,
+ PFace face )
+ {
+ TT_Kerning* kern = (TT_Kerning*)ext;
+ TT_Kern_Subtable* sub;
+ UShort n;
+
+
+ /* by convention */
+ if ( !kern )
+ return TT_Err_Ok;
+
+ if ( kern->nTables == 0 )
+ return TT_Err_Ok; /* no tables to release */
+
+ /* scan the table directory and release loaded entries */
+
+ sub = kern->tables;
+ for ( n = 0; n < kern->nTables; n++ )
+ {
+ if ( sub->loaded )
+ {
+ switch ( sub->format )
+ {
+ case 0:
+ FREE( sub->t.kern0.pairs );
+ sub->t.kern0.nPairs = 0;
+ sub->t.kern0.searchRange = 0;
+ sub->t.kern0.entrySelector = 0;
+ sub->t.kern0.rangeShift = 0;
+ break;
+
+ case 2:
+ FREE( sub->t.kern2.leftClass.classes );
+ sub->t.kern2.leftClass.firstGlyph = 0;
+ sub->t.kern2.leftClass.nGlyphs = 0;
+
+ FREE( sub->t.kern2.rightClass.classes );
+ sub->t.kern2.rightClass.firstGlyph = 0;
+ sub->t.kern2.rightClass.nGlyphs = 0;
+
+ FREE( sub->t.kern2.array );
+ sub->t.kern2.rowWidth = 0;
+ break;
+
+ default:
+ ; /* invalid subtable format - do nothing */
+ }
+
+ sub->loaded = FALSE;
+ sub->version = 0;
+ sub->offset = 0;
+ sub->length = 0;
+ sub->coverage = 0;
+ sub->format = 0;
+ }
+ sub++;
+ }
+
+ FREE( kern->tables );
+ kern->nTables = 0;
+
+ return TT_Err_Ok;
+ }
+
+
+/*******************************************************************
+ *
+ * Function : TT_Get_Kerning_Directory
+ *
+ * Description : Returns a given face's kerning directory.
+ *
+ * Input : face handle to the face object
+ * directory pointer to client's target directory
+ *
+ * Output : error code
+ *
+ * Notes : The kerning table directory is loaded with the face
+ * through the extension constructor. However, the kerning
+ * tables themselves are only loaded on demand, as they
+ * may represent a lot of data, unneeded by most uses of
+ * the engine.
+ *
+ ******************************************************************/
+
+ EXPORT_FUNC
+ TT_Error TT_Get_Kerning_Directory( TT_Face face,
+ TT_Kerning* directory )
+ {
+ PFace faze = HANDLE_Face( face );
+ TT_Error error;
+ TT_Kerning* kerning;
+
+
+ if ( !faze )
+ return TT_Err_Invalid_Face_Handle;
+
+ /* copy directory header */
+ error = TT_Extension_Get( faze, KERNING_ID, (void**)&kerning );
+ if ( !error )
+ *directory = *kerning;
+
+ return error;
+ }
+
+
+/*******************************************************************
+ *
+ * Function : TT_Load_Kerning_Table
+ *
+ * Description : Loads a kerning table intro memory.
+ *
+ * Input : face face handle
+ * kern_index index in the face's kerning directory
+ *
+ * Output : error code
+ *
+ * Notes :
+ *
+ ******************************************************************/
+
+ EXPORT_FUNC
+ TT_Error TT_Load_Kerning_Table( TT_Face face,
+ TT_UShort kern_index )
+ {
+ TT_Error error;
+ TT_Stream stream;
+
+ TT_Kerning* kern;
+ TT_Kern_Subtable* sub;
+
+
+ PFace faze = HANDLE_Face( face );
+
+ if ( !faze )
+ return TT_Err_Invalid_Face_Handle;
+
+ error = TT_Extension_Get( faze, KERNING_ID, (void**)&kern );
+ if ( error )
+ return error;
+
+ if ( kern->nTables == 0 )
+ return TT_Err_Table_Missing;
+
+ if ( kern_index >= kern->nTables )
+ return TT_Err_Invalid_Argument;
+
+ sub = kern->tables + kern_index;
+
+ if ( sub->format != 0 && sub->format != 2 )
+ return TT_Err_Invalid_Kerning_Table_Format;
+
+ /* now access stream */
+ if ( USE_Stream( faze->stream, stream ) )
+ return error;
+
+ if ( FILE_Seek( sub->offset ) )
+ goto Fail;
+
+ if ( sub->format == 0 )
+ error = Subtable_Load_0( &sub->t.kern0, faze );
+ else if ( sub->format == 2 )
+ error = Subtable_Load_2( &sub->t.kern2, faze );
+
+ if ( !error )
+ sub->loaded = TRUE;
+
+ Fail:
+ /* release stream */
+ DONE_Stream( stream );
+
+ return error;
+ }
+
+
+ EXPORT_FUNC
+ TT_Error TT_Init_Kerning_Extension( TT_Engine engine )
+ {
+ PEngine_Instance _engine = HANDLE_Engine( engine );
+
+ TT_Error error;
+
+
+ if ( !_engine )
+ return TT_Err_Invalid_Engine;
+
+ error = TT_Register_Extension( _engine,
+ KERNING_ID,
+ sizeof ( TT_Kerning ),
+ Kerning_Create,
+ Kerning_Destroy );
+ return error;
+ }
+
+
+/* END */
diff --git a/Build/source/libs/libttf/extend/ftxkern.h b/Build/source/libs/libttf/extend/ftxkern.h
new file mode 100644
index 00000000000..06e221e4be0
--- /dev/null
+++ b/Build/source/libs/libttf/extend/ftxkern.h
@@ -0,0 +1,181 @@
+/*******************************************************************
+ *
+ * ftxkern.h 1.0
+ *
+ * High-Level API Kerning extension
+ *
+ * Copyright 1996-1999 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.
+ *
+ *
+ * The kerning support is currently part of the engine extensions.
+ *
+ * This file should _not_ depend on engine internal types.
+ *
+ ******************************************************************/
+
+#ifndef FTXKERN_H
+#define FTXKERN_H
+
+#include "freetype.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ /* The kerning support in FreeType is minimal. This means that */
+ /* we do not try to interpret the kerning data in any way to */
+ /* `cook' it for a user application. This API lets you access */
+ /* directly the kerning tables found in the TrueType file; it's */
+ /* up to the client application to apply its own processing on */
+ /* these. */
+
+ /* The reason for this is that we generally do not encourage */
+ /* feature-bloat of the core engine. Moreover, not all */
+ /* libraries or font servers really need kerning data, or all */
+ /* formats of this data. */
+
+ /************** kerning error codes *****************************/
+
+ /* we choose the class 0x0A for our errors, this should not */
+ /* match with any error code class used in any other extension */
+
+#define TT_Err_Invalid_Kerning_Table_Format 0x0A00
+#define TT_Err_Invalid_Kerning_Table 0x0A01
+
+
+ /********** structures definitions ******************************/
+
+ /* Remember that all types and function are accessible by client */
+ /* applications in this section, and thus should have the `TT_' */
+ /* prefix. */
+
+ /* format 0 kerning pair */
+
+ struct TT_Kern_0_Pair_
+ {
+ TT_UShort left; /* index of left glyph in pair */
+ TT_UShort right; /* index of right glyph in pair */
+ TT_FWord value; /* kerning value */
+ };
+
+ typedef struct TT_Kern_0_Pair_ TT_Kern_0_Pair;
+
+
+ /* format 0 kerning subtable */
+
+ struct TT_Kern_0_
+ {
+ TT_UShort nPairs; /* number of kerning pairs */
+
+ TT_UShort searchRange; /* these values are defined by the TT spec */
+ TT_UShort entrySelector; /* for table searchs. */
+ TT_UShort rangeShift;
+
+ TT_Kern_0_Pair* pairs; /* a table of nPairs `pairs' */
+ };
+
+ typedef struct TT_Kern_0_ TT_Kern_0;
+
+
+ /* format 2 kerning glyph class */
+
+ struct TT_Kern_2_Class_
+ {
+ TT_UShort firstGlyph; /* first glyph in range */
+ TT_UShort nGlyphs; /* number of glyphs in range */
+ TT_UShort* classes; /* a table giving for each ranged glyph */
+ /* its class offset in the subtable pairs */
+ /* two-dimensional array */
+ };
+
+ typedef struct TT_Kern_2_Class_ TT_Kern_2_Class;
+
+
+ /* format 2 kerning subtable */
+
+ struct TT_Kern_2_
+ {
+ TT_UShort rowWidth; /* length of one row in bytes */
+ TT_Kern_2_Class leftClass; /* left class table */
+ TT_Kern_2_Class rightClass; /* right class table */
+ TT_FWord* array; /* 2-dimensional kerning values array */
+ };
+
+ typedef struct TT_Kern_2_ TT_Kern_2;
+
+
+ /* kerning subtable */
+
+ struct TT_Kern_Subtable_
+ {
+ TT_Bool loaded; /* boolean; indicates whether the table is */
+ /* loaded */
+ TT_UShort version; /* table version number */
+ TT_Long offset; /* file offset of table */
+ TT_UShort length; /* length of table, _excluding_ header */
+ TT_Byte coverage; /* lower 8 bit of the coverage table entry */
+ TT_Byte format; /* the subtable format, as found in the */
+ /* higher 8 bits of the coverage table entry */
+ union
+ {
+ TT_Kern_0 kern0;
+ TT_Kern_2 kern2;
+ } t;
+ };
+
+ typedef struct TT_Kern_Subtable_ TT_Kern_Subtable;
+
+
+ struct TT_Kerning_
+ {
+ TT_UShort version; /* kern table version number. starts at 0 */
+ TT_UShort nTables; /* number of tables */
+
+ TT_Kern_Subtable* tables; /* the kerning sub-tables */
+ };
+
+ typedef struct TT_Kerning_ TT_Kerning;
+
+
+
+ /***************** high-level API extension **************************/
+
+ /* Initialize Kerning extension, must be called after */
+ /* TT_Init_FreeType(). There is no need for a finalizer */
+ EXPORT_DEF
+ TT_Error TT_Init_Kerning_Extension( TT_Engine engine );
+
+ /* Note on the implemented mechanism: */
+
+ /* The kerning table directory is loaded with the face through the */
+ /* extension constructor. However, the tables will only be loaded */
+ /* on demand, as they may represent a lot of data, unnecessary to */
+ /* most applications. */
+
+ /* Queries a pointer to the kerning directory for the face object */
+ EXPORT_DEF
+ TT_Error TT_Get_Kerning_Directory( TT_Face face,
+ TT_Kerning* directory );
+
+ /* Load the kerning table number `kern_index' in the kerning */
+ /* directory. The table will stay in memory until the `face' */
+ /* face is destroyed. */
+ EXPORT_DEF
+ TT_Error TT_Load_Kerning_Table( TT_Face face,
+ TT_UShort kern_index );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FTXKERN_H */
+
+
+/* END */
diff --git a/Build/source/libs/libttf/extend/ftxopen.c b/Build/source/libs/libttf/extend/ftxopen.c
new file mode 100644
index 00000000000..bbf08bd1991
--- /dev/null
+++ b/Build/source/libs/libttf/extend/ftxopen.c
@@ -0,0 +1,1439 @@
+/*******************************************************************
+ *
+ * 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 "tttypes.h"
+#include "ttload.h"
+#include "ttextend.h"
+#include "ttmemory.h"
+#include "ttfile.h"
+
+#include "ftxopen.h"
+#include "ftxopenf.h"
+
+
+ /***************************
+ * Script related functions
+ ***************************/
+
+
+ /* LangSys */
+
+ static TT_Error Load_LangSys( TTO_LangSys* ls,
+ PFace input )
+ {
+ DEFINE_LOAD_LOCALS( input->stream );
+
+ UShort n, count;
+
+ 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, 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 )
+ {
+ FREE( ls->FeatureIndex );
+ }
+
+
+ /* Script */
+
+ static TT_Error Load_Script( TTO_Script* s,
+ PFace input )
+ {
+ DEFINE_LOAD_LOCALS( input->stream );
+
+ UShort n, count;
+ 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,
+ input ) ) != 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_Invalid_SubTable;
+ 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, input ) ) != TT_Err_Ok )
+ goto Fail1;
+ (void)FILE_Seek( cur_offset );
+ }
+
+ return TT_Err_Ok;
+
+ Fail1:
+ for ( n = 0; n < count; n++ )
+ Free_LangSys( &lsr[n].LangSys );
+
+ FREE( s->LangSysRecord );
+
+ Fail2:
+ Free_LangSys( &s->DefaultLangSys );
+ return error;
+ }
+
+
+ static void Free_Script( TTO_Script* s )
+ {
+ UShort n, count;
+
+ TTO_LangSysRecord* lsr;
+
+
+ Free_LangSys( &s->DefaultLangSys );
+
+ if ( s->LangSysRecord )
+ {
+ count = s->LangSysCount;
+ lsr = s->LangSysRecord;
+
+ for ( n = 0; n < count; n++ )
+ Free_LangSys( &lsr[n].LangSys );
+
+ FREE( lsr );
+ }
+ }
+
+
+ /* ScriptList */
+
+ TT_Error Load_ScriptList( TTO_ScriptList* sl,
+ PFace input )
+ {
+ DEFINE_LOAD_LOCALS( input->stream );
+
+ UShort n, count;
+ ULong cur_offset, new_offset, base_offset;
+
+ TTO_ScriptRecord* sr;
+
+
+ base_offset = FILE_Pos();
+
+ if ( ACCESS_Frame( 2L ) )
+ return error;
+
+ count = sl->ScriptCount = GET_UShort();
+
+ FORGET_Frame();
+
+ sl->ScriptRecord = NULL;
+
+ if ( ALLOC_ARRAY( sl->ScriptRecord, count, TTO_ScriptRecord ) )
+ return error;
+
+ sr = sl->ScriptRecord;
+
+ for ( n = 0; n < count; n++ )
+ {
+ if ( ACCESS_Frame( 6L ) )
+ goto Fail;
+
+ sr[n].ScriptTag = GET_ULong();
+ new_offset = GET_UShort() + base_offset;
+
+ FORGET_Frame();
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = Load_Script( &sr[n].Script, input ) ) != TT_Err_Ok )
+ goto Fail;
+ (void)FILE_Seek( cur_offset );
+ }
+
+ return TT_Err_Ok;
+
+ Fail:
+ for ( n = 0; n < count; n++ )
+ Free_Script( &sr[n].Script );
+
+ FREE( sl->ScriptRecord );
+ return error;
+ }
+
+
+ void Free_ScriptList( TTO_ScriptList* sl )
+ {
+ 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 );
+
+ FREE( sr );
+ }
+ }
+
+
+
+ /*********************************
+ * Feature List related functions
+ *********************************/
+
+
+ /* Feature */
+
+ static TT_Error Load_Feature( TTO_Feature* f,
+ PFace input )
+ {
+ DEFINE_LOAD_LOCALS( input->stream );
+
+ UShort n, count;
+
+ 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, 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 )
+ {
+ FREE( f->LookupListIndex );
+ }
+
+
+ /* FeatureList */
+
+ TT_Error Load_FeatureList( TTO_FeatureList* fl,
+ PFace input )
+ {
+ DEFINE_LOAD_LOCALS( input->stream );
+
+ UShort n, count;
+ 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;
+
+ fr = fl->FeatureRecord;
+
+ for ( n = 0; n < count; n++ )
+ {
+ if ( ACCESS_Frame( 6L ) )
+ goto Fail;
+
+ 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, input ) ) != TT_Err_Ok )
+ goto Fail;
+ (void)FILE_Seek( cur_offset );
+ }
+
+ return TT_Err_Ok;
+
+ Fail:
+ for ( n = 0; n < count; n++ )
+ Free_Feature( &fr[n].Feature );
+
+ FREE( fl->FeatureRecord );
+ return error;
+ }
+
+
+ void Free_FeatureList( TTO_FeatureList* fl )
+ {
+ 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 );
+
+ FREE( fr );
+ }
+ }
+
+
+
+ /********************************
+ * Lookup List related functions
+ ********************************/
+
+ /* the subroutines of the following two functions are defined in
+ ftxgsub.c and ftxgpos.c respectively */
+
+
+ /* SubTable */
+
+ static TT_Error Load_SubTable( TTO_SubTable* st,
+ PFace input,
+ TTO_Type table_type,
+ UShort lookup_type )
+ {
+ if ( table_type == GSUB )
+ switch ( lookup_type )
+ {
+ case GSUB_LOOKUP_SINGLE:
+ return Load_SingleSubst( &st->st.gsub.single, input );
+
+ case GSUB_LOOKUP_MULTIPLE:
+ return Load_MultipleSubst( &st->st.gsub.multiple, input );
+
+ case GSUB_LOOKUP_ALTERNATE:
+ return Load_AlternateSubst( &st->st.gsub.alternate, input );
+
+ case GSUB_LOOKUP_LIGATURE:
+ return Load_LigatureSubst( &st->st.gsub.ligature, input );
+
+ case GSUB_LOOKUP_CONTEXT:
+ return Load_ContextSubst( &st->st.gsub.context, input );
+
+ case GSUB_LOOKUP_CHAIN:
+ return Load_ChainContextSubst( &st->st.gsub.chain, input );
+
+ default:
+ return TTO_Err_Invalid_GSUB_SubTable_Format;
+ }
+ else
+ switch ( lookup_type )
+ {
+ case GPOS_LOOKUP_SINGLE:
+ return Load_SinglePos( &st->st.gpos.single, input );
+
+ case GPOS_LOOKUP_PAIR:
+ return Load_PairPos( &st->st.gpos.pair, input );
+
+ case GPOS_LOOKUP_CURSIVE:
+ return Load_CursivePos( &st->st.gpos.cursive, input );
+
+ case GPOS_LOOKUP_MARKBASE:
+ return Load_MarkBasePos( &st->st.gpos.markbase, input );
+
+ case GPOS_LOOKUP_MARKLIG:
+ return Load_MarkLigPos( &st->st.gpos.marklig, input );
+
+ case GPOS_LOOKUP_MARKMARK:
+ return Load_MarkMarkPos( &st->st.gpos.markmark, input );
+
+ case GPOS_LOOKUP_CONTEXT:
+ return Load_ContextPos( &st->st.gpos.context, input );
+
+ case GPOS_LOOKUP_CHAIN:
+ return Load_ChainContextPos( &st->st.gpos.chain, input );
+
+ 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,
+ UShort lookup_type )
+ {
+ if ( table_type == GSUB )
+ switch ( lookup_type )
+ {
+ case GSUB_LOOKUP_SINGLE:
+ Free_SingleSubst( &st->st.gsub.single );
+ break;
+
+ case GSUB_LOOKUP_MULTIPLE:
+ Free_MultipleSubst( &st->st.gsub.multiple );
+ break;
+
+ case GSUB_LOOKUP_ALTERNATE:
+ Free_AlternateSubst( &st->st.gsub.alternate );
+ break;
+
+ case GSUB_LOOKUP_LIGATURE:
+ Free_LigatureSubst( &st->st.gsub.ligature );
+ break;
+
+ case GSUB_LOOKUP_CONTEXT:
+ Free_ContextSubst( &st->st.gsub.context );
+ break;
+
+ case GSUB_LOOKUP_CHAIN:
+ Free_ChainContextSubst( &st->st.gsub.chain );
+ break;
+ }
+ else
+ switch ( lookup_type )
+ {
+ case GPOS_LOOKUP_SINGLE:
+ Free_SinglePos( &st->st.gpos.single );
+ break;
+
+ case GPOS_LOOKUP_PAIR:
+ Free_PairPos( &st->st.gpos.pair );
+ break;
+
+ case GPOS_LOOKUP_CURSIVE:
+ Free_CursivePos( &st->st.gpos.cursive );
+ break;
+
+ case GPOS_LOOKUP_MARKBASE:
+ Free_MarkBasePos( &st->st.gpos.markbase );
+ break;
+
+ case GPOS_LOOKUP_MARKLIG:
+ Free_MarkLigPos( &st->st.gpos.marklig );
+ break;
+
+ case GPOS_LOOKUP_MARKMARK:
+ Free_MarkMarkPos( &st->st.gpos.markmark );
+ break;
+
+ case GPOS_LOOKUP_CONTEXT:
+ Free_ContextPos( &st->st.gpos.context );
+ break;
+
+ case GPOS_LOOKUP_CHAIN:
+ Free_ChainContextPos ( &st->st.gpos.chain );
+ break;
+ }
+ }
+
+
+ /* Lookup */
+
+ static TT_Error Load_Lookup( TTO_Lookup* l,
+ PFace input,
+ TTO_Type type )
+ {
+ DEFINE_LOAD_LOCALS( input->stream );
+
+ UShort n, count;
+ ULong cur_offset, new_offset, base_offset;
+
+ TTO_SubTable* st;
+
+
+ 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;
+
+ 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_SubTable( &st[n], input,
+ type, l->LookupType ) ) != TT_Err_Ok )
+ goto Fail;
+ (void)FILE_Seek( cur_offset );
+ }
+
+ return TT_Err_Ok;
+
+ Fail:
+ for ( n = 0; n < count; n++ )
+ Free_SubTable( &st[n], type, l->LookupType );
+
+ FREE( l->SubTable );
+ return error;
+ }
+
+
+ static void Free_Lookup( TTO_Lookup* l,
+ TTO_Type type )
+ {
+ 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 );
+
+ FREE( st );
+ }
+ }
+
+
+ /* LookupList */
+
+ TT_Error Load_LookupList( TTO_LookupList* ll,
+ PFace input,
+ TTO_Type type )
+ {
+ DEFINE_LOAD_LOCALS( input->stream );
+
+ UShort n, count;
+ 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, UShort ) )
+ 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], input, type ) ) != TT_Err_Ok )
+ goto Fail1;
+ (void)FILE_Seek( cur_offset );
+ }
+
+ return TT_Err_Ok;
+
+ Fail1:
+ FREE( ll->Properties );
+
+ for ( n = 0; n < count; n++ )
+ Free_Lookup( &l[n], type );
+
+ Fail2:
+ FREE( ll->Lookup );
+ return error;
+ }
+
+
+ void Free_LookupList( TTO_LookupList* ll,
+ TTO_Type type )
+ {
+ 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 );
+
+ FREE( l );
+ }
+ }
+
+
+
+ /*****************************
+ * Coverage related functions
+ *****************************/
+
+
+ /* CoverageFormat1 */
+
+ static TT_Error Load_Coverage1( TTO_CoverageFormat1* cf1,
+ PFace input )
+ {
+ DEFINE_LOAD_LOCALS( input->stream );
+
+ UShort n, count;
+
+ UShort* ga;
+
+
+ if ( ACCESS_Frame( 2L ) )
+ return error;
+
+ count = cf1->GlyphCount = GET_UShort();
+
+ FORGET_Frame();
+
+ cf1->GlyphArray = NULL;
+
+ if ( ALLOC_ARRAY( cf1->GlyphArray, count, 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 )
+ {
+ FREE( cf1->GlyphArray );
+ }
+
+
+ /* CoverageFormat2 */
+
+ static TT_Error Load_Coverage2( TTO_CoverageFormat2* cf2,
+ PFace input )
+ {
+ DEFINE_LOAD_LOCALS( input->stream );
+
+ 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 )
+ {
+ FREE( cf2->RangeRecord );
+ }
+
+
+ TT_Error Load_Coverage( TTO_Coverage* c,
+ PFace input )
+ {
+ DEFINE_LOAD_LOCALS( input->stream );
+
+
+ if ( ACCESS_Frame( 2L ) )
+ return error;
+
+ c->CoverageFormat = GET_UShort();
+
+ FORGET_Frame();
+
+ switch ( c->CoverageFormat )
+ {
+ case 1:
+ return Load_Coverage1( &c->cf.cf1, input );
+
+ case 2:
+ return Load_Coverage2( &c->cf.cf2, input );
+
+ default:
+ return TTO_Err_Invalid_SubTable_Format;
+ }
+
+ return TT_Err_Ok; /* never reached */
+ }
+
+
+ void Free_Coverage( TTO_Coverage* c )
+ {
+ switch ( c->CoverageFormat )
+ {
+ case 1:
+ Free_Coverage1( &c->cf.cf1 );
+ break;
+
+ case 2:
+ Free_Coverage2( &c->cf.cf2 );
+ break;
+ }
+ }
+
+
+ static TT_Error Coverage_Index1( TTO_CoverageFormat1* cf1,
+ UShort glyphID,
+ UShort* index )
+ {
+ UShort min, max, new_min, new_max, middle;
+
+ UShort* array = cf1->GlyphArray;
+
+
+ /* binary search */
+
+ 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 TT_Error Coverage_Index2( TTO_CoverageFormat2* cf2,
+ UShort glyphID,
+ UShort* index )
+ {
+ UShort min, max, new_min, new_max, middle;
+
+ TTO_RangeRecord* rr = cf2->RangeRecord;
+
+
+ /* binary search */
+
+ 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;
+ }
+
+
+ TT_Error Coverage_Index( TTO_Coverage* c,
+ UShort glyphID,
+ 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 TT_Error Load_ClassDef1( TTO_ClassDefinition* cd,
+ UShort limit,
+ PFace input )
+ {
+ DEFINE_LOAD_LOCALS( input->stream );
+
+ UShort n, count;
+
+ UShort* cva;
+ 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, 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 )
+ {
+ FREE( cdf1->ClassValueArray );
+ }
+
+
+ /* ClassDefFormat2 */
+
+ static TT_Error Load_ClassDef2( TTO_ClassDefinition* cd,
+ UShort limit,
+ PFace input )
+ {
+ DEFINE_LOAD_LOCALS( input->stream );
+
+ UShort n, count;
+
+ TTO_ClassRangeRecord* crr;
+ 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 )
+ {
+ FREE( cdf2->ClassRangeRecord );
+ }
+
+
+ /* ClassDefinition */
+
+ TT_Error Load_ClassDefinition( TTO_ClassDefinition* cd,
+ UShort limit,
+ PFace input )
+ {
+ DEFINE_LOAD_LOCALS( input->stream );
+
+
+ if ( ALLOC_ARRAY( cd->Defined, limit, 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, input );
+ break;
+
+ case 2:
+ error = Load_ClassDef2( cd, limit, input );
+ 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;
+ }
+
+
+ void Free_ClassDefinition( TTO_ClassDefinition* cd )
+ {
+ if ( !cd->loaded )
+ return;
+
+ FREE( cd->Defined );
+
+ switch ( cd->ClassFormat )
+ {
+ case 1:
+ Free_ClassDef1( &cd->cd.cd1 );
+ break;
+
+ case 2:
+ Free_ClassDef2( &cd->cd.cd2 );
+ break;
+ }
+ }
+
+
+ static TT_Error Get_Class1( TTO_ClassDefFormat1* cdf1,
+ UShort glyphID,
+ UShort* class,
+ UShort* index )
+ {
+ UShort* cva = cdf1->ClassValueArray;
+
+
+ *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 TT_Error Get_Class2( TTO_ClassDefFormat2* cdf2,
+ UShort glyphID,
+ UShort* class,
+ UShort* index )
+ {
+ TT_Error error = TT_Err_Ok;
+ UShort min, max, new_min, new_max, middle;
+
+ TTO_ClassRangeRecord* crr = cdf2->ClassRangeRecord;
+
+
+ /* binary search */
+
+ 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;
+ }
+
+
+ TT_Error Get_Class( TTO_ClassDefinition* cd,
+ UShort glyphID,
+ UShort* class,
+ 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
+ ***************************/
+
+
+ TT_Error Load_Device( TTO_Device* d,
+ PFace input )
+ {
+ DEFINE_LOAD_LOCALS( input->stream );
+
+ UShort n, count;
+
+ 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, 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 )
+ {
+ 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 */
+
+ TT_Error Get_Device( TTO_Device* d,
+ UShort size,
+ Short* value )
+ {
+ UShort byte, bits, mask, f, s;
+
+
+ f = d->DeltaFormat;
+
+ if ( 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 = (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/Build/source/libs/libttf/extend/ftxopen.h b/Build/source/libs/libttf/extend/ftxopen.h
new file mode 100644
index 00000000000..0063527a614
--- /dev/null
+++ b/Build/source/libs/libttf/extend/ftxopen.h
@@ -0,0 +1,305 @@
+/*******************************************************************
+ *
+ * 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 "freetype.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#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
+
+
+ /* Script list related structures */
+
+ struct TTO_LangSys_
+ {
+ TT_UShort LookupOrderOffset; /* always 0 for TT Open 1.0 */
+ TT_UShort ReqFeatureIndex; /* required FeatureIndex */
+ TT_UShort FeatureCount; /* number of Feature indices */
+ TT_UShort* FeatureIndex; /* array of Feature indices */
+ };
+
+ typedef struct TTO_LangSys_ TTO_LangSys;
+
+
+ struct TTO_LangSysRecord_
+ {
+ TT_ULong LangSysTag; /* LangSysTag identifier */
+ TTO_LangSys LangSys; /* LangSys table */
+ };
+
+ typedef struct TTO_LangSysRecord_ TTO_LangSysRecord;
+
+
+ struct TTO_Script_
+ {
+ TTO_LangSys DefaultLangSys; /* DefaultLangSys table */
+ TT_UShort LangSysCount; /* number of LangSysRecords */
+ TTO_LangSysRecord* LangSysRecord; /* array of LangSysRecords */
+ };
+
+ typedef struct TTO_Script_ TTO_Script;
+
+
+ struct TTO_ScriptRecord_
+ {
+ TT_ULong ScriptTag; /* ScriptTag identifier */
+ TTO_Script Script; /* Script table */
+ };
+
+ typedef struct TTO_ScriptRecord_ TTO_ScriptRecord;
+
+
+ struct TTO_ScriptList_
+ {
+ TT_UShort ScriptCount; /* number of ScriptRecords */
+ TTO_ScriptRecord* ScriptRecord; /* array of ScriptRecords */
+ };
+
+ typedef struct TTO_ScriptList_ TTO_ScriptList;
+
+
+ /* Feature list related structures */
+
+ struct TTO_Feature_
+ {
+ TT_UShort FeatureParams; /* always 0 for TT Open 1.0 */
+ TT_UShort LookupListCount; /* number of LookupList indices */
+ TT_UShort* LookupListIndex; /* array of LookupList indices */
+ };
+
+ typedef struct TTO_Feature_ TTO_Feature;
+
+
+ struct TTO_FeatureRecord_
+ {
+ TT_ULong FeatureTag; /* FeatureTag identifier */
+ TTO_Feature Feature; /* Feature table */
+ };
+
+ typedef struct TTO_FeatureRecord_ TTO_FeatureRecord;
+
+
+ struct TTO_FeatureList_
+ {
+ TT_UShort FeatureCount; /* number of FeatureRecords */
+ TTO_FeatureRecord* FeatureRecord; /* array of FeatureRecords */
+ };
+
+ 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_
+ {
+ TT_UShort LookupType; /* Lookup type */
+ TT_UShort LookupFlag; /* Lookup qualifiers */
+ TT_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_
+ {
+ TT_UShort LookupCount; /* number of Lookups */
+ TTO_Lookup* Lookup; /* array of Lookup records */
+ TT_UShort* Properties; /* array of flags */
+ };
+
+ typedef struct TTO_LookupList_ TTO_LookupList;
+
+
+/* Possible LookupFlag bit masks. `IGNORE_SPECIAL_MARKS' comes from the
+ OpenType 1.2 specification. */
+
+#define IGNORE_BASE_GLYPHS 0x0002
+#define IGNORE_LIGATURES 0x0004
+#define IGNORE_MARKS 0x0008
+#define IGNORE_SPECIAL_MARKS 0xFF00
+
+
+ struct TTO_CoverageFormat1_
+ {
+ TT_UShort GlyphCount; /* number of glyphs in GlyphArray */
+ TT_UShort* GlyphArray; /* array of glyph IDs */
+ };
+
+ typedef struct TTO_CoverageFormat1_ TTO_CoverageFormat1;
+
+
+ struct TTO_RangeRecord_
+ {
+ TT_UShort Start; /* first glyph ID in the range */
+ TT_UShort End; /* last glyph ID in the range */
+ TT_UShort StartCoverageIndex; /* coverage index of first
+ glyph ID in the range */
+ };
+
+ typedef struct TTO_RangeRecord_ TTO_RangeRecord;
+
+
+ struct TTO_CoverageFormat2_
+ {
+ TT_UShort RangeCount; /* number of RangeRecords */
+ TTO_RangeRecord* RangeRecord; /* array of RangeRecords */
+ };
+
+ typedef struct TTO_CoverageFormat2_ TTO_CoverageFormat2;
+
+
+ struct TTO_Coverage_
+ {
+ TT_UShort CoverageFormat; /* 1 or 2 */
+
+ union
+ {
+ TTO_CoverageFormat1 cf1;
+ TTO_CoverageFormat2 cf2;
+ } cf;
+ };
+
+ typedef struct TTO_Coverage_ TTO_Coverage;
+
+
+ struct TTO_ClassDefFormat1_
+ {
+ TT_UShort StartGlyph; /* first glyph ID of the
+ ClassValueArray */
+ TT_UShort GlyphCount; /* size of the ClassValueArray */
+ TT_UShort* ClassValueArray; /* array of class values */
+ };
+
+ typedef struct TTO_ClassDefFormat1_ TTO_ClassDefFormat1;
+
+
+ struct TTO_ClassRangeRecord_
+ {
+ TT_UShort Start; /* first glyph ID in the range */
+ TT_UShort End; /* last glyph ID in the range */
+ TT_UShort Class; /* applied to all glyphs in range */
+ };
+
+ typedef struct TTO_ClassRangeRecord_ TTO_ClassRangeRecord;
+
+
+ struct TTO_ClassDefFormat2_
+ {
+ TT_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_
+ {
+ TT_Bool loaded;
+
+ TT_Bool* Defined; /* array of Booleans.
+ If Defined[n] is FALSE,
+ class n contains no glyphs. */
+ TT_UShort ClassFormat; /* 1 or 2 */
+
+ union
+ {
+ TTO_ClassDefFormat1 cd1;
+ TTO_ClassDefFormat2 cd2;
+ } cd;
+ };
+
+ typedef struct TTO_ClassDefinition_ TTO_ClassDefinition;
+
+
+ struct TTO_Device_
+ {
+ TT_UShort StartSize; /* smallest size to correct */
+ TT_UShort EndSize; /* largest size to correct */
+ TT_UShort DeltaFormat; /* DeltaValue array data format:
+ 1, 2, or 3 */
+ TT_UShort* DeltaValue; /* array of compressed data */
+ };
+
+ typedef struct TTO_Device_ TTO_Device;
+
+
+#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/Build/source/libs/libttf/extend/ftxopenf.h b/Build/source/libs/libttf/extend/ftxopenf.h
new file mode 100644
index 00000000000..df69a64b452
--- /dev/null
+++ b/Build/source/libs/libttf/extend/ftxopenf.h
@@ -0,0 +1,143 @@
+/*******************************************************************
+ *
+ * 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 */
+
+ TT_Error Load_ScriptList( TTO_ScriptList* sl,
+ PFace input );
+ TT_Error Load_FeatureList( TTO_FeatureList* fl,
+ PFace input );
+ TT_Error Load_LookupList( TTO_LookupList* ll,
+ PFace input,
+ TTO_Type type );
+
+ TT_Error Load_Coverage( TTO_Coverage* c,
+ PFace input );
+ TT_Error Load_ClassDefinition( TTO_ClassDefinition* cd,
+ UShort limit,
+ PFace input );
+ TT_Error Load_Device( TTO_Device* d,
+ PFace input );
+
+ void Free_ScriptList( TTO_ScriptList* sl );
+ void Free_FeatureList( TTO_FeatureList* fl );
+ void Free_LookupList( TTO_LookupList* ll,
+ TTO_Type type );
+
+ void Free_Coverage( TTO_Coverage* c );
+ void Free_ClassDefinition( TTO_ClassDefinition* cd );
+ void Free_Device( TTO_Device* d );
+
+
+ /* functions from ftxgsub.c */
+
+ TT_Error Load_SingleSubst( TTO_SingleSubst* ss,
+ PFace input );
+ TT_Error Load_MultipleSubst( TTO_MultipleSubst* ms,
+ PFace input );
+ TT_Error Load_AlternateSubst( TTO_AlternateSubst* as,
+ PFace input );
+ TT_Error Load_LigatureSubst( TTO_LigatureSubst* ls,
+ PFace input );
+ TT_Error Load_ContextSubst( TTO_ContextSubst* cs,
+ PFace input );
+ TT_Error Load_ChainContextSubst( TTO_ChainContextSubst* ccs,
+ PFace input );
+
+ void Free_SingleSubst( TTO_SingleSubst* ss );
+ void Free_MultipleSubst( TTO_MultipleSubst* ms );
+ void Free_AlternateSubst( TTO_AlternateSubst* as );
+ void Free_LigatureSubst( TTO_LigatureSubst* ls );
+ void Free_ContextSubst( TTO_ContextSubst* cs );
+ void Free_ChainContextSubst( TTO_ChainContextSubst* ccs );
+
+
+ /* functions from ftxgpos.c */
+
+ TT_Error Load_SinglePos( TTO_SinglePos* sp,
+ PFace input );
+ TT_Error Load_PairPos( TTO_PairPos* pp,
+ PFace input );
+ TT_Error Load_CursivePos( TTO_CursivePos* cp,
+ PFace input );
+ TT_Error Load_MarkBasePos( TTO_MarkBasePos* mbp,
+ PFace input );
+ TT_Error Load_MarkLigPos( TTO_MarkLigPos* mlp,
+ PFace input );
+ TT_Error Load_MarkMarkPos( TTO_MarkMarkPos* mmp,
+ PFace input );
+ TT_Error Load_ContextPos( TTO_ContextPos* cp,
+ PFace input );
+ TT_Error Load_ChainContextPos( TTO_ChainContextPos* ccp,
+ PFace input );
+
+ void Free_SinglePos( TTO_SinglePos* sp );
+ void Free_PairPos( TTO_PairPos* pp );
+ void Free_CursivePos( TTO_CursivePos* cp );
+ void Free_MarkBasePos( TTO_MarkBasePos* mbp );
+ void Free_MarkLigPos( TTO_MarkLigPos* mlp );
+ void Free_MarkMarkPos( TTO_MarkMarkPos* mmp );
+ void Free_ContextPos( TTO_ContextPos* cp );
+ void Free_ChainContextPos( TTO_ChainContextPos* ccp );
+
+
+ /* query functions */
+
+ TT_Error Coverage_Index( TTO_Coverage* c,
+ UShort glyphID,
+ UShort* index );
+ TT_Error Get_Class( TTO_ClassDefinition* cd,
+ UShort glyphID,
+ UShort* class,
+ UShort* index );
+ TT_Error Get_Device( TTO_Device* d,
+ UShort size,
+ Short* value );
+
+
+ /* functions from ftxgdef.c */
+
+ TT_Error Add_Glyph_Property( TTO_GDEFHeader* gdef,
+ UShort glyphID,
+ UShort property );
+
+ TT_Error Check_Property( TTO_GDEFHeader* gdef,
+ UShort index,
+ UShort flags,
+ 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/Build/source/libs/libttf/extend/ftxpost.c b/Build/source/libs/libttf/extend/ftxpost.c
new file mode 100644
index 00000000000..8b2ac5940c0
--- /dev/null
+++ b/Build/source/libs/libttf/extend/ftxpost.c
@@ -0,0 +1,523 @@
+/*******************************************************************
+ *
+ * ftxpost.c
+ *
+ * post table support API extension body
+ *
+ * Copyright 1996-1999 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.
+ *
+ *
+ * The post table is not completely loaded by the core engine. This
+ * file loads the missing PS glyph names and implements an API to
+ * access them.
+ *
+ ******************************************************************/
+
+#include "ttconfig.h"
+#include "ftxpost.h"
+
+#include "tttypes.h"
+#include "ttobjs.h"
+#include "tttables.h"
+#include "ttload.h" /* for the macros */
+#include "ttfile.h"
+#include "tttags.h"
+#include "ttmemory.h"
+#include "ttextend.h"
+
+
+#define POST_ID Build_Extension_ID( 'p', 'o', 's', 't' )
+
+
+ /* the 258 default Mac PS glyph names */
+
+ String* TT_Post_Default_Names[258] =
+ {
+ /* 0 */
+ ".notdef", ".null", "CR", "space", "exclam",
+ "quotedbl", "numbersign", "dollar", "percent", "ampersand",
+ /* 10 */
+ "quotesingle", "parenleft", "parenright", "asterisk", "plus",
+ "comma", "hyphen", "period", "slash", "zero",
+ /* 20 */
+ "one", "two", "three", "four", "five",
+ "six", "seven", "eight", "nine", "colon",
+ /* 30 */
+ "semicolon", "less", "equal", "greater", "question",
+ "at", "A", "B", "C", "D",
+ /* 40 */
+ "E", "F", "G", "H", "I",
+ "J", "K", "L", "M", "N",
+ /* 50 */
+ "O", "P", "Q", "R", "S",
+ "T", "U", "V", "W", "X",
+ /* 60 */
+ "Y", "Z", "bracketleft", "backslash", "bracketright",
+ "asciicircum", "underscore", "grave", "a", "b",
+ /* 70 */
+ "c", "d", "e", "f", "g",
+ "h", "i", "j", "k", "l",
+ /* 80 */
+ "m", "n", "o", "p", "q",
+ "r", "s", "t", "u", "v",
+ /* 90 */
+ "w", "x", "y", "z", "braceleft",
+ "bar", "braceright", "asciitilde", "Adieresis", "Aring",
+ /* 100 */
+ "Ccedilla", "Eacute", "Ntilde", "Odieresis", "Udieresis",
+ "aacute", "agrave", "acircumflex", "adieresis", "atilde",
+ /* 110 */
+ "aring", "ccedilla", "eacute", "egrave", "ecircumflex",
+ "edieresis", "iacute", "igrave", "icircumflex", "idieresis",
+ /* 120 */
+ "ntilde", "oacute", "ograve", "ocircumflex", "odieresis",
+ "otilde", "uacute", "ugrave", "ucircumflex", "udieresis",
+ /* 130 */
+ "dagger", "degree", "cent", "sterling", "section",
+ "bullet", "paragraph", "germandbls", "registered", "copyright",
+ /* 140 */
+ "trademark", "acute", "dieresis", "notequal", "AE",
+ "Oslash", "infinity", "plusminus", "lessequal", "greaterequal",
+ /* 150 */
+ "yen", "mu", "partialdiff", "summation", "product",
+ "pi", "integral", "ordfeminine", "ordmasculine", "Omega",
+ /* 160 */
+ "ae", "oslash", "questiondown", "exclamdown", "logicalnot",
+ "radical", "florin", "approxequal", "Delta", "guillemotleft",
+ /* 170 */
+ "guillemotright", "ellipsis", "nbspace", "Agrave", "Atilde",
+ "Otilde", "OE", "oe", "endash", "emdash",
+ /* 180 */
+ "quotedblleft", "quotedblright", "quoteleft", "quoteright", "divide",
+ "lozenge", "ydieresis", "Ydieresis", "fraction", "currency",
+ /* 190 */
+ "guilsinglleft", "guilsinglright", "fi", "fl", "daggerdbl",
+ "periodcentered", "quotesinglbase", "quotedblbase", "perthousand", "Acircumflex",
+ /* 200 */
+ "Ecircumflex", "Aacute", "Edieresis", "Egrave", "Iacute",
+ "Icircumflex", "Idieresis", "Igrave", "Oacute", "Ocircumflex",
+ /* 210 */
+ "apple", "Ograve", "Uacute", "Ucircumflex", "Ugrave",
+ "dotlessi", "circumflex", "tilde", "macron", "breve",
+ /* 220 */
+ "dotaccent", "ring", "cedilla", "hungarumlaut", "ogonek",
+ "caron", "Lslash", "lslash", "Scaron", "scaron",
+ /* 230 */
+ "Zcaron", "zcaron", "brokenbar", "Eth", "eth",
+ "Yacute", "yacute", "Thorn", "thorn", "minus",
+ /* 240 */
+ "multiply", "onesuperior", "twosuperior", "threesuperior", "onehalf",
+ "onequarter", "threequarters", "franc", "Gbreve", "gbreve",
+ /* 250 */
+ "Idot", "Scedilla", "scedilla", "Cacute", "cacute",
+ "Ccaron", "ccaron", "dmacron",
+ };
+
+
+
+ static TT_Error Load_Format_20( TT_Post_20* post20,
+ PFace input )
+ {
+ DEFINE_LOAD_LOCALS( input->stream );
+
+ UShort nameindex, n, num;
+ Byte len;
+
+
+ if ( ACCESS_Frame( 2L ) )
+ return error;
+
+ num = GET_UShort();
+
+ FORGET_Frame();
+
+ /* UNDOCUMENTED! The number of glyphs in this table can be smaller */
+ /* than the value in the maxp table (cf. cyberbit.ttf). */
+
+ /* There already exist fonts which have more than 32768 glyph names */
+ /* in this table, so the test for this threshold has been dropped. */
+ if ( num > input->numGlyphs )
+ return TT_Err_Invalid_Post_Table;
+
+ post20->numGlyphs = num;
+
+ if ( ALLOC_ARRAY( post20->glyphNameIndex, num, TT_UShort ) )
+ return error;
+
+ if ( ACCESS_Frame( num * 2L ) )
+ goto Fail;
+
+ for ( n = 0; n < num; n++ )
+ {
+ post20->glyphNameIndex[n] = GET_UShort();
+
+ if ( post20->glyphNameIndex[n] > 258 + num )
+ {
+ FORGET_Frame();
+ error = TT_Err_Invalid_Post_Table;
+ goto Fail;
+ }
+ }
+
+ FORGET_Frame();
+
+ if ( ALLOC_ARRAY( post20->glyphNames, num, Char* ) )
+ goto Fail;
+
+ /* We must initialize the glyphNames array for proper */
+ /* deallocation. */
+ for ( n = 0; n < num; n++ )
+ post20->glyphNames[n] = NULL;
+
+ /* Now we can read the glyph names which are stored in */
+ /* Pascal string format. */
+ for ( n = 0; n < num; n++ )
+ {
+ nameindex = post20->glyphNameIndex[n];
+
+ if ( nameindex < 258 )
+ ; /* default Mac glyph, do nothing */
+ else
+ {
+ if ( ACCESS_Frame( 1L ) )
+ goto Fail1;
+
+ len = GET_Byte();
+
+ FORGET_Frame();
+
+ if ( ALLOC_ARRAY( post20->glyphNames[nameindex - 258],
+ len + 1, Char ) ||
+ FILE_Read( post20->glyphNames[nameindex - 258], len ) )
+ goto Fail1;
+
+ /* we make a C string */
+ post20->glyphNames[nameindex - 258][len] = '\0';
+ }
+ }
+
+ return TT_Err_Ok;
+
+
+ Fail1:
+ for ( n = 0; n < num; n++ )
+ if ( post20->glyphNames[n] )
+ FREE( post20->glyphNames[n] );
+
+ FREE( post20->glyphNames );
+
+ Fail:
+ FREE( post20->glyphNameIndex );
+ return error;
+ }
+
+
+ static TT_Error Load_Format_25( TT_Post_25* post25,
+ PFace input )
+ {
+ DEFINE_LOAD_LOCALS( input->stream );
+
+ UShort n, num;
+
+
+ if ( ACCESS_Frame( 2L ) )
+ return error;
+
+ /* UNDOCUMENTED! This value appears only in the Apple TT specs. */
+ num = GET_UShort();
+
+ FORGET_Frame();
+
+ if ( num > input->numGlyphs || num > 258 )
+ return TT_Err_Invalid_Post_Table;
+
+ post25->numGlyphs = num;
+
+ if ( ALLOC_ARRAY( post25->offset, num, Char ) )
+ return error;
+
+ if ( ACCESS_Frame( num ) )
+ goto Fail;
+
+ for ( n = 0; n < num; n++ )
+ {
+ post25->offset[n] = GET_Char();
+
+ /* We add 128 to the tests to avoid problems with negative */
+ /* values for comparison. */
+ if ( n + ( post25->offset[n] + 128 ) > num + 128 ||
+ n + ( post25->offset[n] + 128 ) < 128 )
+ {
+ FORGET_Frame();
+ error = TT_Err_Invalid_Post_Table;
+ goto Fail;
+ }
+ }
+
+ FORGET_Frame();
+
+ return TT_Err_Ok;
+
+
+ Fail:
+ FREE( post25->offset );
+ return error;
+ }
+
+
+ static TT_Error Post_Create( void* ext,
+ PFace face )
+ {
+ TT_Post* post = (TT_Post*)ext;
+ Long table;
+
+
+ /* by convention */
+ if ( !post )
+ return TT_Err_Ok;
+
+ /* we store the start offset and the size of the subtable */
+ table = TT_LookUp_Table( face, TTAG_post );
+ post->offset = face->dirTables[table].Offset + 32L;
+ post->length = face->dirTables[table].Length - 32L;
+ post->loaded = FALSE;
+
+ return TT_Err_Ok;
+ }
+
+
+ static TT_Error Post_Destroy( void* ext,
+ PFace face )
+ {
+ TT_Post* post = (TT_Post*)ext;
+ UShort n;
+
+
+ /* by convention */
+ if ( !post )
+ return TT_Err_Ok;
+
+ if ( post->loaded )
+ {
+ switch ( face->postscript.FormatType )
+ {
+ case 0x00010000: /* nothing to do */
+ break;
+
+ case 0x00020000:
+ for ( n = 0; n < post->p.post20.numGlyphs; n++ )
+ if ( post->p.post20.glyphNames[n] )
+ FREE( post->p.post20.glyphNames[n] );
+ FREE( post->p.post20.glyphNames );
+ FREE( post->p.post20.glyphNameIndex );
+ break;
+
+ case 0x00028000:
+ FREE( post->p.post25.offset );
+ break;
+
+ case 0x00030000: /* nothing to do */
+ break;
+
+#if 0
+ case 0x00040000:
+ break;
+#endif
+
+ default:
+ ; /* invalid format, do nothing */
+ }
+ }
+
+ return TT_Err_Ok;
+ }
+
+
+ EXPORT_FUNC
+ TT_Error TT_Init_Post_Extension( TT_Engine engine )
+ {
+ PEngine_Instance _engine = HANDLE_Engine( engine );
+
+ TT_Error error;
+
+
+ if ( !_engine )
+ return TT_Err_Invalid_Engine;
+
+ error = TT_Register_Extension( _engine,
+ POST_ID,
+ sizeof ( TT_Post ),
+ Post_Create,
+ Post_Destroy );
+ return error;
+ }
+
+
+/*******************************************************************
+ *
+ * Function : TT_Load_PS_Names
+ *
+ * Description : Loads the PostScript Glyph Name subtable (if any).
+ *
+ * Output : error code
+ *
+ ******************************************************************/
+
+ EXPORT_FUNC
+ TT_Error TT_Load_PS_Names( TT_Face face,
+ TT_Post* ppost )
+ {
+ PFace faze = HANDLE_Face( face );
+ TT_Error error;
+ TT_Stream stream;
+ TT_Post* post;
+
+
+ if ( !faze )
+ return TT_Err_Invalid_Face_Handle;
+
+ error = TT_Extension_Get( faze, POST_ID, (void**)&post );
+ if ( error )
+ return error;
+
+ if ( USE_Stream( faze->stream, stream ) )
+ return error;
+
+
+ switch ( faze->postscript.FormatType )
+ {
+ case 0x00010000:
+ error = TT_Err_Ok; /* nothing to do */
+ break;
+
+ case 0x00020000:
+ if ( FILE_Seek( post->offset ) )
+ goto Fail;
+
+ error = Load_Format_20( &post->p.post20, faze );
+ break;
+
+ case 0x00028000: /* 2.5 in 16.16 format */
+ if ( FILE_Seek( post->offset ) )
+ goto Fail;
+
+ error = Load_Format_25( &post->p.post25, faze );
+ break;
+
+ case 0x00030000:
+ error = TT_Err_Ok; /* nothing to do */
+ break;
+
+#if 0
+ case 0x00040000:
+ break;
+#endif
+
+ default:
+ error = TT_Err_Invalid_Post_Table_Format;
+ break;
+ }
+
+ if ( !error )
+ {
+ post->loaded = TRUE;
+ *ppost = *post;
+ }
+
+
+ Fail:
+ DONE_Stream( stream );
+
+ return error;
+ }
+
+
+/*******************************************************************
+ *
+ * Function : TT_Get_PS_Name
+ *
+ * Description : Gets the PostScript Glyph Name of a glyph.
+ *
+ * Input : index glyph index
+ * PSname address of a string pointer.
+ * Will be NULL in case of error; otherwise it
+ * contains a pointer to the glyph name.
+ *
+ * You must not modify the returned string!
+ *
+ * Output : error code
+ *
+ ******************************************************************/
+
+ EXPORT_FUNC
+ TT_Error TT_Get_PS_Name( TT_Face face,
+ TT_UShort index,
+ TT_String** PSname )
+ {
+ PFace faze = HANDLE_Face( face );
+ TT_Error error;
+ TT_Post* post;
+ UShort nameindex;
+
+
+ if ( !faze )
+ return TT_Err_Invalid_Face_Handle;
+
+ if ( index >= faze->numGlyphs )
+ return TT_Err_Invalid_Glyph_Index;
+
+ error = TT_Extension_Get( faze, POST_ID, (void**)&post );
+ if ( error )
+ return error;
+
+
+ *PSname = TT_Post_Default_Names[0]; /* default value */
+
+ switch ( faze->postscript.FormatType )
+ {
+ case 0x00010000:
+ if ( index < 258 ) /* paranoid checking */
+ *PSname = TT_Post_Default_Names[index];
+ break;
+
+ case 0x00020000:
+ if ( index < post->p.post20.numGlyphs )
+ nameindex = post->p.post20.glyphNameIndex[index];
+ else
+ break;
+
+ if ( nameindex < 258 )
+ *PSname = TT_Post_Default_Names[nameindex];
+ else
+ *PSname = (String*)post->p.post20.glyphNames[nameindex - 258];
+ break;
+
+ case 0x00028000:
+ if ( index < post->p.post25.numGlyphs ) /* paranoid checking */
+ *PSname = TT_Post_Default_Names[index + post->p.post25.offset[index]];
+ break;
+
+ case 0x00030000:
+ break; /* nothing to do */
+
+#if 0
+ case 0x00040000:
+ break;
+#endif
+
+ default:
+ ; /* should never happen */
+ }
+
+ return TT_Err_Ok;
+ }
+
+
+/* END */
diff --git a/Build/source/libs/libttf/extend/ftxpost.h b/Build/source/libs/libttf/extend/ftxpost.h
new file mode 100644
index 00000000000..534b6080d30
--- /dev/null
+++ b/Build/source/libs/libttf/extend/ftxpost.h
@@ -0,0 +1,107 @@
+/*******************************************************************
+ *
+ * ftxpost.h
+ *
+ * post table support API extension
+ *
+ * Copyright 1996-1999 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.
+ *
+ *
+ * The post table is not completely loaded by the core engine. This
+ * file loads the missing PS glyph names and implements an API to
+ * access them.
+ *
+ ******************************************************************/
+
+#ifndef FTXPOST_H
+#define FTXPOST_H
+
+#include "freetype.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define TT_Err_Invalid_Post_Table_Format 0x0B00
+#define TT_Err_Invalid_Post_Table 0x0B01
+
+ /* the 258 standard Mac glyph names, used for format 1.0 and 2.5 */
+
+ extern TT_String* TT_Post_Default_Names[];
+
+
+ /* format 2.0 table */
+
+ struct TT_Post_20_
+ {
+ TT_UShort numGlyphs;
+ TT_UShort* glyphNameIndex;
+ TT_Char** glyphNames;
+ };
+
+ typedef struct TT_Post_20_ TT_Post_20;
+
+ struct TT_Post_25_
+ {
+ TT_UShort numGlyphs;
+ TT_Char* offset;
+ };
+
+ typedef struct TT_Post_25_ TT_Post_25;
+
+#if 0
+ /* format 4.0 table -- not implemented yet */
+
+ struct TT_Post_40_
+ {
+ };
+
+ typedef struct TT_Post_40_ TT_Post_40;
+#endif
+
+
+ struct TT_Post_
+ {
+ TT_Long offset;
+ TT_Long length;
+ TT_Bool loaded;
+
+ union
+ {
+ TT_Post_20 post20;
+ TT_Post_25 post25;
+#if 0
+ TT_Post_40 post40;
+#endif
+ } p;
+ };
+
+ typedef struct TT_Post_ TT_Post;
+
+
+ EXPORT_DEF
+ TT_Error TT_Init_Post_Extension( TT_Engine engine );
+
+ EXPORT_DEF
+ TT_Error TT_Load_PS_Names( TT_Face face,
+ TT_Post* post );
+ EXPORT_DEF
+ TT_Error TT_Get_PS_Name( TT_Face face,
+ TT_UShort index,
+ TT_String** PSname );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FTXPOST_H */
+
+
+/* END */
diff --git a/Build/source/libs/libttf/extend/ftxsbit.c b/Build/source/libs/libttf/extend/ftxsbit.c
new file mode 100644
index 00000000000..02162bd2e3f
--- /dev/null
+++ b/Build/source/libs/libttf/extend/ftxsbit.c
@@ -0,0 +1,1391 @@
+/*******************************************************************
+ *
+ * ftxsbit.c
+ *
+ * Embedded bitmap API extension
+ *
+ * Copyright 1996-1999 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 extension is used to load the embedded bitmaps present
+ * in certain TrueType files.
+ *
+ ******************************************************************/
+
+#include "ftxsbit.h"
+#include "ttobjs.h"
+#include "ttfile.h"
+#include "ttload.h"
+#include "ttmemory.h"
+#include "tttags.h"
+#include "ttextend.h"
+#include "ttdebug.h"
+
+
+#define SBIT_ID Build_Extension_ID( 's', 'b', 'i', 't' )
+
+
+/* Required by the tracing mode */
+#undef TT_COMPONENT
+#define TT_COMPONENT trace_bitmap
+
+/* In all functions, the stream is taken from the 'face' object */
+#define DEFINE_LOCALS DEFINE_LOAD_LOCALS( face->stream )
+#define DEFINE_LOCALS_WO_FRAME DEFINE_LOAD_LOCALS_WO_FRAME( face->stream )
+
+
+/***************************
+ *
+ * miscellaneous functions
+ *
+ ***************************/
+
+/*******************************************************************
+ *
+ * Function: Load_BitmapData
+ *
+ * Bit-aligned bitmap data -> Byte-aligned bitmap data when pad is 0
+ *
+ ******************************************************************/
+
+ static
+ TT_Error Load_BitmapData( TT_SBit_Image* image,
+ Int image_size,
+ Byte x_offset,
+ Byte y_offset,
+ UShort source_width,
+ UShort source_height,
+ Bool byte_padded )
+ {
+ DEFINE_LOCALS;
+
+ Int count; /* number of bits left in rows */
+ Int loaded; /* number of bits loaded in the accumulator */
+ UShort buff; /* accumulator */
+
+ PByte line; /* target write cursor */
+ PByte limit;
+
+
+ if ( ( y_offset + source_height > image->map.rows ) ||
+ ( x_offset + source_width > image->map.width ) )
+ return TT_Err_Invalid_Argument;
+
+ if ( ACCESS_Frame( image_size ) )
+ return error;
+
+ buff = 0;
+ loaded = 0;
+ line = (PByte)image->map.bitmap +
+ y_offset * image->map.cols;
+ limit = (PByte)image->map.bitmap +
+ ( y_offset + source_height ) * image->map.cols;
+
+ for ( ; line < limit; line += image->map.cols )
+ {
+ PByte ptr;
+
+
+ ptr = line + x_offset / 8;
+ count = source_width;
+
+ /* We may assume that `loaded' is less than 8 */
+ buff >>= x_offset % 8;
+ loaded += x_offset % 8;
+
+ /* first of all, read all consecutive bytes */
+ while ( count >= 8 )
+ {
+ if ( loaded < 8 )
+ {
+ buff |= ((UShort)GET_Byte()) << (8 - loaded);
+ loaded += 8;
+ }
+
+ *ptr++ |= (Byte)(buff >> 8);
+ buff <<= 8;
+ loaded -= 8;
+ count -= 8;
+ }
+
+ /* now write remaining bits (i.e. end of line with count < 8) */
+ if ( count > 0 )
+ {
+ if ( loaded < count )
+ {
+ buff |= ((UShort)GET_Byte()) << (8 - loaded);
+ loaded += 8;
+ }
+
+ *ptr |= ((Byte)(buff >> 8)) & ~(0xFF >> count);
+ buff <<= count;
+ loaded -= count;
+ }
+
+ if ( byte_padded )
+ {
+ buff = 0;
+ loaded = 0;
+ }
+ }
+
+ FORGET_Frame();
+ return TT_Err_Ok;
+ }
+
+
+/*******************************************************************
+ *
+ * Function: Crop_Bitmap
+ *
+ ******************************************************************/
+
+ static
+ void Crop_Bitmap( TT_SBit_Image* image )
+ {
+ /*******************************************************/
+ /* In the following situation, some bounding boxes of */
+ /* embedded bitmaps are too large. We need to crop it */
+ /* to a reasonable size. */
+ /* */
+ /* --------- */
+ /* | | ----- */
+ /* | *** | |***| */
+ /* | * | -----> | * | */
+ /* | * | | * | */
+ /* | * | | * | */
+ /* | * | | * | */
+ /* | *** | |***| */
+ /* --------- ----- */
+ /* */
+ /*******************************************************/
+
+ Int rows, count;
+ Long line_len;
+ PByte line;
+
+
+ /********************************************************************/
+ /* */
+ /* first of all, check the top-most lines of the bitmap and remove */
+ /* them if they're empty. */
+ /* */
+ {
+ line = (PByte)image->map.bitmap;
+ rows = image->map.rows;
+ line_len = image->map.cols;
+
+ for ( count = 0; count < rows; count++ )
+ {
+ PByte cur = line;
+ PByte limit = line + line_len;
+
+
+ for ( ; cur < limit; cur++ )
+ if ( cur[0] )
+ goto Found_Top;
+
+ /* the current line was empty -- skip to next one */
+ line = limit;
+ }
+
+ Found_Top:
+ /* check that we have at least one filled line */
+ if ( count >= rows )
+ goto Empty_Bitmap;
+
+ /* now, crop the empty upper lines */
+ if ( count > 0 )
+ {
+ line = (PByte)image->map.bitmap;
+
+ MEM_Move( line, line + count*line_len, (rows-count) * line_len );
+
+ image->metrics.bbox.yMax -= count;
+ image->metrics.vertBearingY -= count;
+ image->metrics.horiBearingY -= count;
+ image->map.rows -= count;
+ rows -= count;
+ }
+ }
+
+ /*******************************************************************/
+ /* */
+ /* second, crop the lower lines */
+ /* */
+ {
+ line = (PByte)image->map.bitmap + (rows-1) * line_len;
+
+ for ( count = 0; count < rows; count++ )
+ {
+ PByte cur = line;
+ PByte limit = line + line_len;
+
+
+ for ( ; cur < limit; cur++ )
+ if ( cur[0] )
+ goto Found_Bottom;
+
+ /* the current line was empty -- skip to previous one */
+ line -= line_len;
+ }
+
+ Found_Bottom:
+ if ( count > 0 )
+ {
+ image->metrics.bbox.yMin += count;
+ image->map.rows -= count;
+ rows -= count;
+ }
+ }
+
+ /*******************************************************************/
+ /* */
+ /* third, get rid of the space on the left side of the glyph */
+ /* */
+ do
+ {
+ PByte limit;
+
+
+ line = (PByte)image->map.bitmap;
+ limit = line + rows * line_len;
+
+ for ( ; line < limit; line += line_len )
+ if ( line[0] & 0x80 )
+ goto Found_Left;
+
+ /* shift the whole glyph one pixel to the left */
+ line = (PByte)image->map.bitmap;
+ limit = line + rows * line_len;
+
+ for ( ; line < limit; line += line_len )
+ {
+ Int n, width = image->map.width;
+ Byte old;
+ PByte cur = line;
+
+
+ old = cur[0] << 1;
+
+ for ( n = 8; n < width; n += 8 )
+ {
+ Byte val;
+
+
+ val = cur[1];
+ cur[0] = old | (val >> 7);
+ old = val << 1;
+ cur++;
+ }
+ cur[0] = old;
+ }
+
+ image->map.width--;
+ image->metrics.horiBearingX++;
+ image->metrics.vertBearingX++;
+ image->metrics.bbox.xMin++;
+
+ } while ( image->map.width > 0 );
+
+ Found_Left:
+
+ /*********************************************************************/
+ /* */
+ /* finally, crop the bitmap width to get rid of the space on the */
+ /* right side of the glyph. */
+ /* */
+ do
+ {
+ Int right = image->map.width-1;
+ PByte limit;
+ Byte mask;
+
+
+ line = (PByte)image->map.bitmap + (right >> 3);
+ limit = line + rows*line_len;
+ mask = 0x80 >> (right & 7);
+
+ for ( ; line < limit; line += line_len )
+ if ( line[0] & mask )
+ goto Found_Right;
+
+ /* crop the whole glyph on the right */
+ image->map.width--;
+ image->metrics.bbox.xMax--;
+
+ } while ( image->map.width > 0 );
+
+ Found_Right:
+ /* all right, the bitmap was cropped */
+ return;
+
+ Empty_Bitmap:
+ image->map.width = 0;
+ image->map.rows = 0;
+ image->map.cols = 0;
+ image->map.size = 0;
+ }
+
+/*************
+ *
+ * Main body
+ *
+ *************/
+
+
+ static
+ TT_Error Load_Range_Codes( TT_SBit_Range* range,
+ PFace face,
+ Bool load_offsets )
+ {
+ DEFINE_LOCALS;
+
+ ULong count, n, size;
+
+
+ (void)face;
+
+ /* read glyph count */
+ if ( ACCESS_Frame( 4L ) )
+ goto Exit;
+ count = GET_ULong();
+ FORGET_Frame();
+
+ range->num_glyphs = count;
+
+ /* Allocate glyph offsets table if needed */
+ if ( load_offsets )
+ {
+ if ( ALLOC_ARRAY( range->glyph_offsets, count, ULong ) )
+ goto Exit;
+
+ size = count * 4L;
+ }
+ else
+ size = count * 2L;
+
+ /* Allocate glyph codes table and access frame */
+ if ( ALLOC_ARRAY ( range->glyph_codes, count, UShort ) ||
+ ACCESS_Frame( size ) )
+ goto Exit;
+
+ for ( n = 0; n < count; n++ )
+ {
+ range->glyph_codes[n] = GET_UShort();
+
+ if ( load_offsets )
+ range->glyph_offsets[n] = (ULong)range->image_offset + GET_UShort();
+ }
+
+ FORGET_Frame();
+
+ Exit:
+ return error;
+ }
+
+
+ static
+ TT_Error Load_SBit_Range( TT_SBit_Strike* strike,
+ TT_SBit_Range* range,
+ PFace face )
+ {
+ DEFINE_LOCALS;
+
+ UShort format;
+
+
+ (void)face;
+ (void)strike;
+
+ format = range->index_format;
+ PTRACE6(( "Index Format: %d\n", format ));
+
+ switch( format )
+ {
+ case 1: /* variable metrics with 4-byte offsets */
+ case 3: /* variable metrics with 2-byte offsets */
+ {
+ UShort num_glyphs, size_elem;
+ Bool large = (format == 1);
+ ULong* cur;
+
+ num_glyphs = range->last_glyph - range->first_glyph + 1;
+ PTRACE5(( " num glyphs: %hu\n", num_glyphs ));
+
+ range->num_glyphs = num_glyphs;
+
+ num_glyphs++; /* BEWARE */
+
+ size_elem = large ? 4 : 2;
+
+ if ( ALLOC_ARRAY( range->glyph_offsets, num_glyphs, ULong ) ||
+ ACCESS_Frame( num_glyphs * size_elem ) )
+ return error;
+
+ cur = range->glyph_offsets;
+
+ while ( num_glyphs > 0 )
+ {
+ cur[0] = (TT_ULong)( range->image_offset +
+ (large ? GET_ULong() : GET_UShort()) );
+ PTRACE7(( " offset: %d\n", cur[0] ));
+ cur++;
+ num_glyphs--;
+ }
+
+ FORGET_Frame();
+ }
+ break;
+
+ case 2: /* all glyphs have identical metrics */
+ case 4:
+ case 5:
+ {
+ error = 0;
+
+ if ( format != 4 ) /* read constant metrics, formats 2 and 5 */
+ {
+ TT_SBit_Metrics* metrics;
+
+
+ if ( ACCESS_Frame( 12L ) )
+ return error;
+
+ range->image_size = GET_ULong();
+ metrics = &range->metrics;
+
+ metrics->height = GET_Byte();
+ metrics->width = GET_Byte();
+
+ metrics->horiBearingX = GET_Char();
+ metrics->horiBearingY = GET_Char();
+ metrics->horiAdvance = GET_Byte();
+
+ metrics->vertBearingX = GET_Char();
+ metrics->vertBearingY = GET_Char();
+ metrics->vertAdvance = GET_Byte();
+
+ FORGET_Frame();
+ }
+
+ if ( format != 2 ) /* load range codes, formats 4 and 5 */
+ error = Load_Range_Codes( range, face, (format == 4) );
+ }
+ break;
+
+ default:
+ error = TT_Err_Invalid_File_Format;
+ }
+
+ PTRACE3(( "Embedded Bitmap Location Tables loaded.\n" ));
+
+ return error;
+ }
+
+
+/*******************************************************************
+ *
+ * Function : Load_TrueType_Eblc
+ *
+ * Description : Loads the Eblc table directory into face table.
+ *
+ * Input : face face record to look for
+ *
+ * Output : Error code.
+ *
+ ******************************************************************/
+
+ static
+ TT_Error Load_TrueType_Eblc( PFace face,
+ TT_EBLC* eblc )
+ {
+ DEFINE_LOCALS;
+
+ ULong eblc_offset;
+ UShort i;
+ Long table;
+
+ TT_SBit_Strike* strike;
+
+
+ PTRACE2(( "Load_EBLC_Table( %08lx )\n", (long)face ));
+
+ eblc->version = 0;
+
+ /* Try to find the `EBLC' or `bloc' table in the font files. */
+ /* Both tags describe the same table; `EBLC' is for OpenType */
+ /* fonts while `bloc' is for TrueType GX fonts. Many fonts */
+ /* contain both tags pointing to the same table. */
+
+ table = TT_LookUp_Table( face, TTAG_EBLC );
+ if ( table < 0 )
+ table = TT_LookUp_Table( face, TTAG_bloc );
+
+ if ( table < 0 )
+ /* This table is optional */
+ return TT_Err_Ok;
+
+ eblc_offset = face->dirTables[table].Offset;
+
+ if ( FILE_Seek( eblc_offset ) ||
+ ACCESS_Frame( 8L ) )
+ return error;
+
+ eblc->version = GET_ULong();
+ eblc->num_strikes = GET_ULong();
+
+ FORGET_Frame();
+
+ PTRACE2(( "-- Tables count: %12u\n", eblc->num_strikes ));
+ PTRACE2(( "-- Format version: %08lx\n", eblc->version ));
+
+ if ( eblc->version != 0x00020000 )
+ {
+ PERROR(( "Invalid file format!\n" ));
+ return TT_Err_Invalid_File_Format;
+ }
+
+ if ( ALLOC_ARRAY( eblc->strikes, eblc->num_strikes, TT_SBit_Strike ) ||
+ ACCESS_Frame( 48L * eblc->num_strikes ) )
+ return error;
+
+ strike = eblc->strikes;
+
+ for ( i = 0; i < eblc->num_strikes; i++, strike++ )
+ { /* loop through the tables and get all entries */
+ ULong indexTablesSize;
+ TT_SBit_Line_Metrics* metrics;
+ Int count;
+
+
+ strike->ranges_offset = GET_ULong();
+ indexTablesSize = GET_ULong(); /* dont' save */
+
+ strike->num_ranges = GET_ULong();
+ strike->color_ref = GET_ULong();
+
+ /* load horizontal and vertical metrics */
+ metrics = &strike->hori;
+ for ( count = 2; count > 0; count-- )
+ {
+ metrics->ascender = GET_Char();
+ metrics->descender = GET_Char();
+ metrics->max_width = GET_Byte();
+
+ metrics->caret_slope_numerator = GET_Char();
+ metrics->caret_slope_denominator = GET_Char();
+ metrics->caret_offset = GET_Char();
+
+ metrics->min_origin_SB = GET_Char();
+ metrics->min_advance_SB = GET_Char();
+ metrics->max_before_BL = GET_Char();
+ metrics->min_after_BL = GET_Char();
+ metrics->pads[0] = GET_Char();
+ metrics->pads[1] = GET_Char();
+
+ metrics = &strike->vert;
+ }
+
+ strike->start_glyph = GET_UShort();
+ strike->end_glyph = GET_UShort();
+ strike->x_ppem = GET_Byte();
+ strike->y_ppem = GET_Byte();
+ strike->bit_depth = GET_Byte();
+ strike->flags = GET_Char();
+
+ PTRACE4(( " start - end - ppemX - ppemY\n" ));
+ PTRACE4(( " %04d - %04d - %3u - %3u\n",
+ strike->start_glyph,
+ strike->end_glyph,
+ strike->x_ppem,
+ strike->y_ppem ));
+ }
+
+ FORGET_Frame();
+
+ /* Load EBLC index ranges */
+ strike = eblc->strikes;
+
+ for ( i = 0; i < eblc->num_strikes; i++, strike++ )
+ {
+ TT_SBit_Range* range;
+ UShort count = strike->num_ranges;
+
+
+ /* loop through the tables and get all entries */
+ if ( ALLOC_ARRAY( strike->sbit_ranges,
+ strike->num_ranges,
+ TT_SBit_Range ) ||
+ FILE_Seek( eblc_offset + strike->ranges_offset ) ||
+ ACCESS_Frame( strike->num_ranges * 8L ) )
+ return error;
+
+ for ( range = strike->sbit_ranges; count > 0; count--, range++ )
+ {
+ range->first_glyph = GET_UShort();
+ range->last_glyph = GET_UShort();
+ range->table_offset = eblc_offset + strike->ranges_offset +
+ GET_ULong();
+ }
+ FORGET_Frame();
+
+ /* Now, read each index table */
+ range = strike->sbit_ranges;
+ for ( count = strike->num_ranges; count > 0; count--, range++ )
+ {
+ /* Read the header */
+ if ( FILE_Seek( range->table_offset ) ||
+ ACCESS_Frame( 8L ) )
+ return error;;
+
+ range->index_format = GET_UShort();
+ range->image_format = GET_UShort();
+ range->image_offset = GET_ULong();
+
+ FORGET_Frame();
+
+ error = Load_SBit_Range( strike, range, face );
+ if (error) return error;
+ }
+ }
+
+ return TT_Err_Ok;
+ }
+
+
+ static
+ void Free_TrueType_Eblc( TT_EBLC* eblc )
+ {
+ if ( eblc )
+ {
+ ULong i;
+ TT_SBit_Strike* strike = eblc->strikes;
+
+
+ strike = eblc->strikes;
+
+ for ( i = eblc->num_strikes; i > 0; i--, strike++ )
+ {
+ /* for each strike, release all glyph ranges */
+ TT_SBit_Range* range = strike->sbit_ranges;
+ Int n;
+
+
+ for ( n = strike->num_ranges; n > 0; n--, range++ )
+ {
+ /* release a range */
+ FREE( range->glyph_offsets );
+ FREE( range->glyph_codes );
+ }
+ FREE( strike->sbit_ranges );
+ strike->num_ranges = 0;
+ }
+ FREE( eblc->strikes );
+ eblc->num_strikes = 0;
+ eblc->version = 0;
+ }
+ }
+
+
+ static
+ TT_Error Load_SBit_Metrics( TT_Big_Glyph_Metrics* metrics,
+ TT_SBit_Range* range,
+ ULong ebdt_offset )
+ {
+ TT_Error error;
+ Byte height, width;
+
+
+ /* copy bitmap metrics for formats 2 and 5 */
+ if ( ( ( range->index_format == 2 ) || ( range->index_format == 5 ) ) &&
+ ( range->image_format == 5 ) )
+ /* metrics are taken from current image bitmap */
+ /* i.e. from `image.metrics' */
+ {
+ TT_SBit_Metrics* rmetrics = &range->metrics;
+
+
+ metrics->bbox.xMin = rmetrics->horiBearingX;
+ metrics->bbox.xMax = metrics->bbox.xMin + rmetrics->width;
+
+ metrics->bbox.yMax = rmetrics->horiBearingY;
+ metrics->bbox.yMin = metrics->bbox.yMax - rmetrics->height;
+
+ metrics->horiBearingX = rmetrics->horiBearingX;
+ metrics->horiBearingY = metrics->bbox.yMax;
+ metrics->horiAdvance = rmetrics->horiAdvance;
+
+ metrics->vertBearingX = rmetrics->vertBearingX;
+ metrics->vertBearingY = rmetrics->vertBearingY;
+ metrics->vertAdvance = rmetrics->vertAdvance;
+
+ return TT_Err_Ok;
+ }
+
+ switch ( range->image_format )
+ {
+ case 1:
+ case 2:
+ case 6:
+ case 7:
+ case 8:
+ case 9:
+ {
+ Long length = 5L;
+
+
+ if ( range->image_format == 8 )
+ length++;
+
+ /* read the small metrics */
+ if ( ACCESS_Frame( length ) )
+ return error;
+
+ height = GET_Byte();
+ width = GET_Byte();
+
+ metrics->horiBearingX = GET_Char();
+ metrics->horiBearingY = GET_Char();
+ metrics->horiAdvance = GET_Byte();
+
+ FORGET_Frame();
+
+ metrics->bbox.xMin = metrics->horiBearingX;
+ metrics->bbox.yMax = metrics->horiBearingY;
+ metrics->bbox.xMax = metrics->bbox.xMin + width;
+ metrics->bbox.yMin = metrics->bbox.yMax - height;
+
+ /* read the rest of the big metrics for the formats */
+ /* that support it. */
+ if ( ( range->image_format >= 6 ) && ( range->image_format != 8 ) )
+ {
+ if ( ACCESS_Frame( 3L ) )
+ return error;
+
+ metrics->vertBearingX = (Int)GET_Char();
+ metrics->vertBearingY = (Int)GET_Char();
+ metrics->vertAdvance = (Int)GET_Char();
+
+ FORGET_Frame();
+ }
+ else
+ {
+ /* XXX: How can we fill these when the information isn't */
+ /* available? */
+ metrics->vertBearingX = 0;
+ metrics->vertBearingY = 0;
+ metrics->vertAdvance = 0;
+ }
+ }
+ break;
+
+ case 5: /* metrics are taken from current image bitmap */
+ /* i.e. from 'image.metrics' */
+ break;
+
+ default:
+ PERROR(( "Unsupported embedded bitmap format!\n" ));
+ return TT_Err_Invalid_File_Format;
+ }
+
+ return TT_Err_Ok;
+ }
+
+
+ static
+ TT_Error Load_SBit_Image( TT_SBit_Strike strike,
+ UShort glyph_index,
+ Byte x_offset,
+ Byte y_offset,
+ ULong ebdt_offset,
+ TT_SBit_Image* image,
+ UShort component_depth )
+ {
+ TT_Error error;
+ Byte height, width;
+
+ ULong bitmap_offset;
+
+ TT_SBit_Range* range = 0;
+
+ TT_Big_Glyph_Metrics metrics;
+
+ /********************************************************************/
+ /* */
+ /* Scan the strike's range for the position/metrics of the source */
+ /* glyph. */
+ {
+ UShort count = strike.num_ranges;
+ TT_SBit_Range* cur = strike.sbit_ranges;
+
+ for ( ; count > 0; count--, cur++ )
+ {
+ /* look for the glyph in the current range */
+ switch ( cur->index_format )
+ {
+ case 1:
+ case 2:
+ case 3:
+ if ( glyph_index >= cur->first_glyph &&
+ glyph_index <= cur->last_glyph )
+ {
+ UShort delta = glyph_index - cur->first_glyph;
+
+
+ range = cur;
+ bitmap_offset = cur->index_format == 2
+ ? cur->image_offset + cur->image_size * delta
+ : cur->glyph_offsets[delta];
+ goto Found;
+ }
+ break;
+
+ case 4:
+ case 5:
+ {
+ UShort n;
+
+
+ for ( n = 0; n < cur->num_glyphs; n++ )
+ if ( cur->glyph_codes[n] == glyph_index )
+ {
+ range = cur;
+ bitmap_offset = cur->index_format == 4
+ ? cur->glyph_offsets[n]
+ : cur->image_offset + cur->image_size * n;
+ goto Found;
+ }
+ }
+ break;
+
+ default:
+ return TT_Err_Invalid_Glyph_Index;
+ }
+ }
+ /* Not found */
+ return TT_Err_Invalid_Glyph_Index;
+ }
+
+ Found:
+ if ( FILE_Seek( ebdt_offset + bitmap_offset ) )
+ return error;
+
+ /* First of all, load the metrics if needed */
+ error = Load_SBit_Metrics( &metrics, range, ebdt_offset );
+ if ( error )
+ return error;
+
+ width = metrics.bbox.xMax - metrics.bbox.xMin;
+ height = metrics.bbox.yMax - metrics.bbox.yMin;
+
+ if ( !component_depth )
+ {
+ image->metrics = metrics;
+
+ image->map.width = width;
+ image->map.rows = height;
+
+ image->map.cols = (width + 7) >> 3;
+ image->map.size = height * image->map.cols;
+
+ if ( REALLOC( image->map.bitmap, image->map.size ) )
+ return error;
+
+ MEM_Set( image->map.bitmap, 0, image->map.size );
+ }
+
+ /* Now, load the data as needed */
+ switch ( range->image_format )
+ {
+ case 1:
+ case 6: /* byte-aligned data */
+ error = Load_BitmapData( image,
+ height * (( width + 7 ) >> 3),
+ x_offset, y_offset,
+ width, height,
+ 1 );
+ if ( error )
+ return error;
+ break;
+
+ case 2:
+ case 5:
+ case 7:
+ error = Load_BitmapData( image,
+ (width * height + 7) >> 3,
+ x_offset, y_offset,
+ width, height, 0 );
+ if ( error )
+ return error;
+ break;
+
+ case 8:
+ case 9:
+ {
+ /* Now, load composite sbit glyphs */
+ /* This code is not sophisticated */
+
+ TT_SBit_Component* component_array;
+ UShort num_components;
+
+ Int i = 0;
+
+
+ if ( ACCESS_Frame( 2L ) )
+ return error;
+ num_components = GET_UShort();
+ FORGET_Frame();
+
+ MEM_Alloc( component_array,
+ sizeof ( TT_SBit_Component ) * num_components );
+
+ if ( ACCESS_Frame( 4L * num_components ) )
+ return error;
+
+ for ( i = 0; i < num_components; i++ )
+ {
+ component_array[i].glyph_code = GET_UShort();
+ component_array[i].x_offset = GET_Char();
+ component_array[i].y_offset = GET_Char();
+ }
+
+ FORGET_Frame();
+
+ component_depth++;
+
+ for ( i = 0; i < num_components; i++ )
+ {
+ error = Load_SBit_Image( strike, component_array[i].glyph_code,
+ component_array[i].x_offset,
+ component_array[i].y_offset,
+ ebdt_offset,
+ image,
+ component_depth );
+ if ( error )
+ return error;
+ }
+ FREE( component_array );
+ break;
+
+ default:
+ return TT_Err_Invalid_File_Format;
+ }
+ }
+
+ return TT_Err_Ok;
+ }
+
+
+/*******************************************************************
+ *
+ * Function: Load_TrueType_Ebdt
+ *
+ ******************************************************************/
+
+ static
+ TT_Error Load_TrueType_Ebdt( PFace face,
+ TT_SBit_Strike strike,
+ ULong glyph_index,
+ TT_SBit_Image* image )
+ {
+ DEFINE_LOCALS;
+
+ ULong ebdt_offset;
+ ULong version;
+ Long i;
+
+
+ /* Try to find the `EBDT' or `bdat' table in the font files. */
+ /* Both tags describe the same table, `EBDT' is for OpenType */
+ /* fonts, while `bdat' is for TrueType GX fonts. Many fonts */
+ /* contain both tags pointing to the same table */
+
+ i = TT_LookUp_Table( face, TTAG_EBDT );
+ if ( i < 0 )
+ i = TT_LookUp_Table( face, TTAG_bdat );
+
+ if ( i < 0 )
+ return TT_Err_Table_Missing;
+
+ ebdt_offset = face->dirTables[i].Offset;
+
+ if ( FILE_Seek( ebdt_offset ) ||
+ ACCESS_Frame( 4L ) ) /* read into frame */
+ return error;
+
+ version = GET_ULong();
+ FORGET_Frame();
+
+ PTRACE2(( "-- Format version : %08lx\n", version ));
+ if ( version != 0x00020000 )
+ {
+ PERROR(( "Invalid file format!\n" ));
+ return TT_Err_Invalid_File_Format;
+ }
+
+ /* This doesn't compile, I simply commented it out ?? - David */
+ /* PTRACE4(( "-- Format: %d\n", range->image_format )); */
+
+ error = Load_SBit_Image( strike,
+ glyph_index,
+ 0, 0,
+ ebdt_offset,
+ image,
+ 0 );
+ if ( error )
+ return error;
+
+ return TT_Err_Ok;
+ }
+
+
+ static TT_Error EBLC_Create( void* ext,
+ PFace face )
+ {
+ TT_EBLC* eblc = (TT_EBLC*)ext;
+
+
+ /* by convention */
+ if ( !eblc )
+ return TT_Err_Ok;
+
+ return Load_TrueType_Eblc( face, eblc );
+ }
+
+
+ static TT_Error EBLC_Destroy( void* ext,
+ PFace face )
+ {
+ TT_EBLC* eblc = (TT_EBLC*)ext;
+
+
+ (void)face;
+
+ if ( eblc )
+ Free_TrueType_Eblc( eblc );
+
+ return TT_Err_Ok;
+ }
+
+
+ /*************************************************************/
+ /* */
+ /* <Function> */
+ /* TT_Init_SBit_Extension */
+ /* */
+ /* <Description> */
+ /* Initialize the embedded bitmaps extension for the */
+ /* FreeType engine. */
+ /* */
+ /* <Input> */
+ /* engine :: handle to current FreeType library instance */
+ /* */
+ /* <Return> */
+ /* Error code. 0 means success. */
+ /* */
+ EXPORT_FUNC
+ TT_Error TT_Init_SBit_Extension( TT_Engine engine )
+ {
+ PEngine_Instance _engine = HANDLE_Engine( engine );
+
+ TT_Error error;
+
+
+ if ( !_engine )
+ return TT_Err_Invalid_Engine;
+
+ error = TT_Register_Extension( _engine,
+ SBIT_ID,
+ sizeof ( TT_EBLC ),
+ EBLC_Create,
+ EBLC_Destroy );
+
+ return error;
+ }
+
+
+ /*************************************************************/
+ /* */
+ /* <Function> */
+ /* TT_Get_Face_Bitmaps */
+ /* */
+ /* <Description> */
+ /* Loads the `EBLC' table from a font file, if any. */
+ /* */
+ /* <Input> */
+ /* face :: handle to the source TrueType font/face */
+ /* */
+ /* <Output> */
+ /* eblc_table :: a descriptor for the EBLC table */
+ /* */
+ /* <Return> */
+ /* Error code. 0 means success. */
+ /* */
+ /* <Note> */
+ /* This function returns TT_Err_Table_Missing if the */
+ /* font contains no embedded bitmaps. All fields in */
+ /* `eblc_table' will then be set to 0. */
+ /* */
+ EXPORT_FUNC
+ TT_Error TT_Get_Face_Bitmaps( TT_Face face,
+ TT_EBLC* eblc_table )
+ {
+ PFace faze = HANDLE_Face( face );
+ TT_EBLC* eblc;
+ TT_Error error;
+
+
+ error = TT_Extension_Get( faze, SBIT_ID, (void**)&eblc );
+ if ( !error )
+ {
+ if ( eblc->version )
+ {
+ *eblc_table = *eblc;
+ return TT_Err_Ok;
+ }
+ error = TT_Err_Table_Missing;
+ }
+
+ eblc_table->version = 0;
+ eblc_table->num_strikes = 0;
+ eblc_table->strikes = 0;
+
+ return error;
+ }
+
+
+/*******************************************************************
+ *
+ * <Function> TT_Get_SBit_Strike
+ *
+ * <Description>
+ * Loads suitable strike (bitmap sizetable) for given instance.
+ * This strike includes sbitLineMetrics.
+ *
+ * <Input>
+ * face :: the source face
+ * instance :: the current size instance
+ *
+ * <Output>
+ * strike :: the bitmap strike descriptor
+ *
+ * <Return>
+ * TrueType error code. 0 means success.
+ *
+ ******************************************************************/
+
+ EXPORT_FUNC
+ TT_Error TT_Get_SBit_Strike( TT_Face face,
+ TT_Instance instance,
+ TT_SBit_Strike* strike )
+ {
+ TT_Error error;
+ PFace faze = HANDLE_Face( face );
+ PInstance ins = HANDLE_Instance( instance );
+
+ TT_EBLC* eblc;
+ TT_Int x_ppem, y_ppem;
+
+
+ if ( !strike || !ins || ins->owner != faze )
+ return TT_Err_Invalid_Argument;
+
+ error = TT_Extension_Get( faze, SBIT_ID, (void**)&eblc );
+ if ( error )
+ goto Exit;
+
+ /********************************************************************/
+ /* */
+ /* Look for an sbit strike that matches the current x and y ppms */
+ /* */
+ {
+ UShort count = eblc->num_strikes;
+ TT_SBit_Strike* cur = eblc->strikes;
+
+
+ x_ppem = ins->metrics.x_ppem;
+ y_ppem = ins->metrics.y_ppem;
+
+ MEM_Set( strike, 0, sizeof ( TT_SBit_Strike ) );
+
+ for ( ; count > 0; count--, cur++ )
+ if ( cur->x_ppem == x_ppem &&
+ cur->y_ppem == y_ppem )
+ {
+ *strike = *cur;
+ break;
+ }
+
+ /* return immediately if we didn't find an appropriate strike */
+ if ( !strike->num_ranges )
+ error = TT_Err_Invalid_PPem;
+ }
+
+ Exit:
+ return error;
+ }
+
+
+ /*************************************************************/
+ /* */
+ /* <Function> */
+ /* TT_Load_Glyph_Bitmap */
+ /* */
+ /* <Description> */
+ /* Loads a given glyph embedded bitmap. */
+ /* */
+ /* <Input> */
+ /* face :: handle to the source TrueType font/face */
+ /* instance :: current size/transform instance */
+ /* glyph_index :: index of source glyph */
+ /* bitmap :: target embedded bitmap descriptor */
+ /* */
+ /* <Return> */
+ /* Error code. 0 means success. */
+ /* */
+ /* <Note> */
+ /* This function returns an error if there is no */
+ /* embedded bitmap for the glyph at the given */
+ /* instance. */
+ /* */
+ EXPORT_FUNC
+ TT_Error TT_Load_Glyph_Bitmap( TT_Face face,
+ TT_Instance instance,
+ TT_UShort glyph_index,
+ TT_SBit_Image* image )
+ {
+ TT_Stream stream;
+ TT_Error error;
+
+ PFace faze = HANDLE_Face( face );
+ PInstance ins = HANDLE_Instance( instance );
+
+ TT_SBit_Strike strike;
+
+
+ if ( ins->owner != faze )
+ {
+ error = TT_Err_Invalid_Argument;
+ goto Fail;
+ }
+
+ /********************************************************************/
+ /* */
+ /* Look for an sbit strike that matches the current x and y ppms */
+ /* */
+ error = TT_Get_SBit_Strike( face, instance, &strike );
+ if ( error )
+ goto Fail;
+
+ /* return immediately if the glyph index isn't in the strike extent */
+ if ( glyph_index < strike.start_glyph ||
+ glyph_index > strike.end_glyph )
+ {
+ error = TT_Err_Invalid_Glyph_Index;
+ goto Fail;
+ }
+
+ {
+ image->bit_depth = 1;
+
+ if ( !USE_Stream( faze->stream, stream ) )
+ {
+ error = Load_TrueType_Ebdt( faze, strike, glyph_index, image );
+
+ DONE_Stream( stream );
+
+ /* exit successfully if we can */
+ if ( !error )
+ {
+ image->map.flow = TT_Flow_Down;
+
+ Crop_Bitmap( image );
+
+ /* correct sbit metrics */
+ {
+ TT_Big_Glyph_Metrics* metrics = &image->metrics;
+
+
+ metrics->bbox.xMin *= 64;
+ metrics->bbox.xMax *= 64;
+
+ metrics->bbox.yMax *= 64;
+ metrics->bbox.yMin *= 64;
+
+ metrics->horiBearingX *= 64;
+ metrics->horiBearingY *= 64;
+ metrics->horiAdvance *= 64;
+
+ metrics->vertBearingX *= 64;
+ metrics->vertBearingY *= 64;
+ metrics->vertAdvance *= 64;
+ }
+
+ goto Exit;
+ }
+ }
+ }
+
+ Fail:
+ image->map.width = 0;
+ image->map.rows = 0;
+ image->map.cols = 0;
+ image->map.size = 0;
+ image->map.bitmap = 0;
+ image->map.flow = 0;
+ image->bit_depth = 0;
+
+ Exit:
+ return error;
+ }
+
+
+ /*************************************************************/
+ /* */
+ /* <Function> */
+ /* TT_New_SBit_Image */
+ /* */
+ /* <Description> */
+ /* Allocates a new embedded bitmap container. */
+ /* */
+ /* <Output> */
+ /* image :: sbit image */
+ /* */
+ /* <Return> */
+ /* Error code. 0 means success. */
+ /* */
+ EXPORT_FUNC
+ TT_Error TT_New_SBit_Image( TT_SBit_Image** image )
+ {
+ return MEM_Alloc( *image, sizeof ( **image ) );
+ }
+
+
+ /*************************************************************/
+ /* */
+ /* <Function> */
+ /* TT_Done_SBit_Image */
+ /* */
+ /* <Description> */
+ /* Releases an embedded bitmap container. */
+ /* */
+ /* <Input> */
+ /* image :: sbit image */
+ /* */
+ EXPORT_FUNC
+ void TT_Done_SBit_Image( TT_SBit_Image* image )
+ {
+ FREE( image->map.bitmap );
+ FREE( image );
+ }
+
+
+/* END */
diff --git a/Build/source/libs/libttf/extend/ftxsbit.h b/Build/source/libs/libttf/extend/ftxsbit.h
new file mode 100644
index 00000000000..05e7b1fc052
--- /dev/null
+++ b/Build/source/libs/libttf/extend/ftxsbit.h
@@ -0,0 +1,490 @@
+/*******************************************************************
+ *
+ * ftxsbit.h
+ *
+ * embedded bitmap support API extension
+ *
+ * Copyright 1996-1999 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 extension is used to load the embedded bitmaps present
+ * in certain TrueType files.
+ *
+ ******************************************************************/
+
+#ifndef FTXSBIT_H
+#define FTXSBIT_H
+
+#include "freetype.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ /*************************************************************/
+ /* */
+ /* <Struct> TT_SBit_Metrics */
+ /* */
+ /* <Description> */
+ /* A structure used to hold the big metrics of a given */
+ /* glyph bitmap in a TrueType or OpenType font. These */
+ /* are usually found in the `EBDT' table. */
+ /* */
+ /* <Fields> */
+ /* height :: glyph height in pixels */
+ /* width :: glyph width in pixels */
+ /* */
+ /* horiBearingX :: horizontal left bearing */
+ /* horiBearingY :: horizontal top bearing */
+ /* horiAdvance :: horizontal advance */
+ /* */
+ /* vertBearingX :: vertical left bearing */
+ /* vertBearingY :: vertical top bearing */
+ /* vertAdvance :: vertical advance */
+ /* */
+ typedef struct TT_SBit_Metrics_
+ {
+ TT_Byte height;
+ TT_Byte width;
+
+ TT_Char horiBearingX;
+ TT_Char horiBearingY;
+ TT_Byte horiAdvance;
+
+ TT_Char vertBearingX;
+ TT_Char vertBearingY;
+ TT_Byte vertAdvance;
+
+ } TT_SBit_Metrics;
+
+
+ /*************************************************************/
+ /* */
+ /* <Struct> TT_SBit_Small_Metrics */
+ /* */
+ /* <Description> */
+ /* A structure used to hold the small metrics of a given */
+ /* glyph bitmap in a TrueType or OpenType font. These */
+ /* are usually found in the `EBDT' table. */
+ /* */
+ /* <Fields> */
+ /* height :: glyph height in pixels */
+ /* width :: glyph width in pixels */
+ /* */
+ /* bearingX :: left-side bearing */
+ /* bearingY :: top-side bearing */
+ /* advance :: advance width or height */
+ /* */
+ typedef struct TT_SBit_Small_Metrics_
+ {
+ TT_Byte height;
+ TT_Byte width;
+
+ TT_Char bearingX;
+ TT_Char bearingY;
+ TT_Byte advance;
+
+ } TT_SBit_Small_Metrics;
+
+
+ /*************************************************************/
+ /* */
+ /* <Struct> TT_SBit_Line_Metrics */
+ /* */
+ /* <Description> */
+ /* A structure used to describe the text line metrics of */
+ /* a given bitmap strike, for either horizontal or */
+ /* vertical layout. */
+ /* */
+ /* <Fields> */
+ /* ascender :: ascender in pixels */
+ /* descender :: descender in pixels */
+ /* max_width :: maximum glyph width in pixels */
+ /* */
+ /* caret_slope_enumerator :: Rise of the caret slope, */
+ /* typically set to 1 for non-italic fonts. */
+ /* caret_slope_denominator :: Rise of the caret slope, */
+ /* typically set to 0 for non-italic fonts. */
+ /* caret_offset :: Offset in pixels */
+ /* to move the caret for proper positioning. */
+ /* */
+ /* min_origin_SB :: Minimum of horiBearingX */
+ /* (resp. vertBearingY) */
+ /* min_advance_SB :: Minimum of */
+ /* (hori. advance - ( horiBearingX + width )) */
+ /* (resp. vert. advance - ( vertBearingY + height )) */
+ /* max_before_BL :: Maximum of horiBearingY */
+ /* (resp. Maximum of vertBearingY) */
+ /* min_after_BL :: Minimum of ( horiBearingY - height ) */
+ /* (resp. vertBearingX - width ) */
+ /* */
+ typedef struct TT_SBit_Line_Metrics_
+ {
+ TT_Char ascender;
+ TT_Char descender;
+ TT_Byte max_width;
+ TT_Char caret_slope_numerator;
+ TT_Char caret_slope_denominator;
+ TT_Char caret_offset;
+ TT_Char min_origin_SB;
+ TT_Char min_advance_SB;
+ TT_Char max_before_BL;
+ TT_Char min_after_BL;
+ TT_Char pads[2];
+
+ } TT_SBit_Line_Metrics;
+
+
+ /*************************************************************/
+ /* */
+ /* <Struct> TT_SBit_Range */
+ /* */
+ /* <Description> */
+ /* A TrueType/OpenType subIndexTable as defined in the */
+ /* `EBLC' or `bloc' tables. */
+ /* */
+ /* <Fields> */
+ /* */
+ /* first_glyph :: first glyph index in range */
+ /* last_glyph :: last glyph index in range */
+ /* */
+ /* index_format :: format of index table. valid */
+ /* values are 1 to 5. */
+ /* */
+ /* image_format :: format of `EBDT' image data */
+ /* image_offset :: offset to image data in `EBDT' */
+ /* */
+ /* image_size :: for index formats 2 and 5. This is */
+ /* the size in bytes of each glyph bitmap */
+ /* glyph bitmap */
+ /* */
+ /* big_metrics :: for index formats 2 and 5. This is */
+ /* the big metrics for each glyph bitmap */
+ /* */
+ /* num_glyphs :: for index formats 4 and 5. This is */
+ /* the number of glyphs in the code */
+ /* array. */
+ /* */
+ /* glyph_offsets :: for index formats 1 and 3. */
+ /* glyph_codes :: for index formats 4 and 5. */
+ /* */
+ /* table_offset :: offset of index table in `EBLC' table */
+ /* -- only used during strike loading. */
+ /* */
+ typedef struct TT_SBit_Range
+ {
+ TT_UShort first_glyph;
+ TT_UShort last_glyph;
+
+ TT_UShort index_format;
+ TT_UShort image_format;
+ TT_ULong image_offset;
+
+ TT_ULong image_size;
+ TT_SBit_Metrics metrics;
+ TT_ULong num_glyphs;
+
+ TT_ULong* glyph_offsets;
+ TT_UShort* glyph_codes;
+
+ TT_ULong table_offset;
+
+ } TT_SBit_Range;
+
+
+ /*************************************************************/
+ /* */
+ /* <Struct> TT_SBit_Strike */
+ /* */
+ /* <Description> */
+ /* A structure used describe a given bitmap strike in the */
+ /* `EBLC' or `bloc' tables. */
+ /* */
+ /* <Fields> */
+ /* */
+ /* num_index_ranges :: number of index ranges */
+ /* index_ranges :: array of glyph index ranges */
+ /* */
+ /* color_ref :: unused. color reference? */
+ /* hori :: line metrics for horizontal layouts. */
+ /* vert :: line metrics for vertical layouts. */
+ /* */
+ /* start_glyph :: lowest glyph index for this strike. */
+ /* end_glyph :: higher glyph index for this strike. */
+ /* */
+ /* x_ppem :: horizontal pixels per EM */
+ /* y_ppem :: vertical pixels per EM */
+ /* bit_depth :: bit depth. valid values are 1, 2, 4 & 8 */
+ /* flags :: vertical or horizontal? */
+ /* */
+ typedef struct TT_SBit_Strike_
+ {
+ TT_Int num_ranges;
+ TT_SBit_Range* sbit_ranges;
+ TT_ULong ranges_offset;
+
+ TT_ULong color_ref;
+
+ TT_SBit_Line_Metrics hori;
+ TT_SBit_Line_Metrics vert;
+
+ TT_UShort start_glyph;
+ TT_UShort end_glyph;
+
+ TT_Byte x_ppem;
+ TT_Byte y_ppem;
+ TT_Byte bit_depth;
+ TT_Char flags;
+
+ } TT_SBit_Strike;
+
+
+ /*************************************************************/
+ /* */
+ /* <Struct> TT_SBit_Component */
+ /* */
+ /* <Description> */
+ /* A simple structure to describe a compound sbit element */
+ /* */
+ /* <Fields> */
+ /* glyph_code :: element's glyph index */
+ /* x_offset :: element's left bearing */
+ /* y_offset :: element's top bearing */
+ /* */
+ typedef struct TT_SBit_Component_
+ {
+ TT_UShort glyph_code;
+ TT_Char x_offset;
+ TT_Char y_offset;
+
+ } TT_SBit_Component;
+
+
+ /*************************************************************/
+ /* */
+ /* <Struct> TT_SBit_Scale */
+ /* */
+ /* <Description> */
+ /* A structure used describe a given bitmap scaling */
+ /* table, as defined for the `EBSC' table. */
+ /* */
+ /* <Fields> */
+ /* hori :: horizontal line metrics */
+ /* vert :: vertical line metrics */
+ /* */
+ /* x_ppem :: horizontal pixels per EM */
+ /* y_ppem :: vertical pixels per EM */
+ /* */
+ /* x_ppem_substitute :: substitution x_ppem */
+ /* y_ppem_substitute :: substitution y_ppem */
+ /* */
+ typedef struct TT_SBit_Scale_
+ {
+ TT_SBit_Line_Metrics hori;
+ TT_SBit_Line_Metrics vert;
+
+ TT_Byte x_ppem;
+ TT_Byte y_ppem;
+
+ TT_Byte x_ppem_substitute;
+ TT_Byte y_ppem_substitute;
+
+ } TT_SBit_Scale;
+
+
+ /*************************************************************/
+ /* */
+ /* <Struct> TT_SBit_Image */
+ /* */
+ /* <Description> */
+ /* A structure used to describe a given embedded bitmap */
+ /* image. */
+ /* */
+ /* <Fields> */
+ /* map :: bitmap descriptor */
+ /* bit_depth :: pixel bit depth */
+ /* metrics :: glyph metrics for the bitmap */
+ /* */
+ typedef struct TT_SBit_Image_
+ {
+ TT_Raster_Map map;
+ int bit_depth;
+ TT_Big_Glyph_Metrics metrics;
+
+ } TT_SBit_Image;
+
+
+ /*************************************************************/
+ /* */
+ /* <Struct> TT_EBLC */
+ /* */
+ /* <Description> */
+ /* A structure used to describe the `EBLC' table from */
+ /* a TrueType font. */
+ /* */
+ /* <Fields> */
+ /* version :: version number of the EBLC table */
+ /* */
+ /* num_strikes :: the number of strikes, i.e. bitmap */
+ /* sizes, present in this font */
+ /* */
+ /* strikes :: array of strikes */
+ /* */
+ typedef struct TT_EBLC_
+ {
+ TT_ULong version;
+ TT_ULong num_strikes;
+ TT_SBit_Strike* strikes;
+
+ } TT_EBLC;
+
+
+
+
+ /*************************************************************/
+ /* */
+ /* <Function> */
+ /* TT_Init_SBit_Extension */
+ /* */
+ /* <Description> */
+ /* Initializes the embedded bitmap extension for the */
+ /* FreeType engine. */
+ /* */
+ /* <Input> */
+ /* engine :: handle to current FreeType library instance */
+ /* */
+ /* <Return> */
+ /* Error code. 0 means success. */
+ /* */
+ EXPORT_DEF
+ TT_Error TT_Init_SBit_Extension( TT_Engine engine );
+
+
+ /*************************************************************/
+ /* */
+ /* <Function> */
+ /* TT_Get_Face_Bitmaps */
+ /* */
+ /* <Description> */
+ /* Loads the `EBLC' table from a font file, if any. */
+ /* */
+ /* <Input> */
+ /* face :: handle to the source TrueType font/face */
+ /* */
+ /* <Output> */
+ /* eblc_table :: a descriptor for the EBLC table */
+ /* */
+ /* <Return> */
+ /* Error code. 0 means success. */
+ /* */
+ /* <Note> */
+ /* This function returns TT_Err_Table_Missing if the */
+ /* font contains no embedded bitmaps. All fields in */
+ /* `eblc_table' will then be set to 0. */
+ /* */
+ EXPORT_DEF
+ TT_Error TT_Get_Face_Bitmaps( TT_Face face,
+ TT_EBLC* eblc_table );
+
+
+ /*************************************************************/
+ /* */
+ /* <Function> */
+ /* TT_New_SBit_Image */
+ /* */
+ /* <Description> */
+ /* Allocates a new embedded bitmap container. */
+ /* */
+ /* <Output> */
+ /* image :: sbit image */
+ /* */
+ /* <Return> */
+ /* Error code. 0 means success. */
+ /* */
+ EXPORT_DEF
+ TT_Error TT_New_SBit_Image( TT_SBit_Image** image );
+
+
+ /*************************************************************/
+ /* */
+ /* <Function> */
+ /* TT_Done_SBit_Image */
+ /* */
+ /* <Description> */
+ /* Releases an embedded bitmap container. */
+ /* */
+ /* <Input> */
+ /* image :: sbit image */
+ /* */
+ EXPORT_DEF
+ void TT_Done_SBit_Image( TT_SBit_Image* image );
+
+
+ /*************************************************************/
+ /* */
+ /* <Function> TT_Get_SBit_Strike */
+ /* */
+ /* <Description> */
+ /* Loads a suitable strike (bitmap sizetable) for the */
+ /* given instance. This strike includes */
+ /* sbitLineMetrics. */
+ /* */
+ /* <Input> */
+ /* face :: the source face */
+ /* instance :: the current size instance */
+ /* */
+ /* <Output> */
+ /* strike :: the bitmap strike descriptor */
+ /* */
+ /* <Return> */
+ /* Error code. 0 means success. */
+ /* */
+ EXPORT_DEF
+ TT_Error TT_Get_SBit_Strike( TT_Face face,
+ TT_Instance instance,
+ TT_SBit_Strike* strike );
+
+
+ /*************************************************************/
+ /* */
+ /* <Function> */
+ /* TT_Load_Glyph_Bitmap */
+ /* */
+ /* <Description> */
+ /* Loads a given glyph embedded bitmap. */
+ /* */
+ /* <Input> */
+ /* face :: handle to the source TrueType font/face */
+ /* instance :: current size/transform instance */
+ /* glyph_index :: index of source glyph */
+ /* bitmap :: target embedded bitmap descriptor */
+ /* */
+ /* <Return> */
+ /* Error code. 0 means success. */
+ /* */
+ /* <Note> */
+ /* This function returns an error if there is no */
+ /* embedded bitmap for the glyph at the given */
+ /* instance. */
+ /* */
+ EXPORT_DEF
+ TT_Error TT_Load_Glyph_Bitmap( TT_Face face,
+ TT_Instance instance,
+ TT_UShort glyph_index,
+ TT_SBit_Image* bitmap );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FTXSBIT_H */
+
+
+/* END */
diff --git a/Build/source/libs/libttf/extend/ftxwidth.c b/Build/source/libs/libttf/extend/ftxwidth.c
new file mode 100644
index 00000000000..bb3a258282b
--- /dev/null
+++ b/Build/source/libs/libttf/extend/ftxwidth.c
@@ -0,0 +1,186 @@
+/*******************************************************************
+ *
+ * ftxwidth.c 1.0
+ *
+ * Glyph Widths (and Heights) fast retrieval extension
+ *
+ * Copyright 1996-1999 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 extension is used to parse the "glyf" table of a TrueType
+ * file in order to extract the bbox of a given range of glyphs.
+ *
+ * The bbox is then used to build font unit widths and height
+ * that are returned in two parallel arrays.
+ *
+ * This extension is needed by the FreeType/2 OS/2 Font Driver.
+ *
+ ******************************************************************/
+
+
+#include "ttconfig.h"
+#include "ftxwidth.h"
+#include "ttdebug.h"
+#include "ttobjs.h"
+#include "ttfile.h"
+#include "tttags.h"
+#include "ttload.h"
+
+/* Required by the tracing mode */
+
+#undef TT_COMPONENT
+#define TT_COMPONENT trace_any
+
+
+ /******************************************************************/
+ /* */
+ /* Function: TT_Get_Face_Widths */
+ /* */
+ /* Description: Returns the widths and/or heights of a given */
+ /* range of glyphs for a face. */
+ /* */
+ /* Input: */
+ /* face :: face handle */
+ /* */
+ /* first_glyph :: first glyph in range */
+ /* */
+ /* last_glyph :: last glyph in range */
+ /* */
+ /* widths :: address of table receiving the widths */
+ /* expressed in font units (ushorts). Set */
+ /* this parameter to NULL if you're not */
+ /* interested by these values. */
+ /* */
+ /* heights :: address of table receiving the heights */
+ /* expressed in font units (ushorts). Set */
+ /* this parameter to NULL if you're not */
+ /* interested by these values. */
+ /* */
+ /* Returns: */
+ /* Error code */
+ /* */
+ /* */
+ /******************************************************************/
+
+ EXPORT_FUNC
+ TT_Error TT_Get_Face_Widths( TT_Face face,
+ TT_UShort first_glyph,
+ TT_UShort last_glyph,
+ TT_UShort* widths,
+ TT_UShort* heights )
+ {
+ DEFINE_ALL_LOCALS;
+
+ PFace faze = HANDLE_Face(face);
+ UShort n;
+ Long table;
+
+ ULong glyf_offset; /* offset of glyph table in file */
+ UShort zero_width = 0; /* width of glyph 0 */
+ UShort zero_height = 0; /* height of glyph 0 */
+
+ Bool zero_loaded = 0;
+
+#ifndef TT_HUGE_PTR
+ PStorage locations;
+#else
+ Storage TT_HUGE_PTR * locations;
+#endif
+ TT_BBox bbox;
+
+
+ if ( !faze )
+ return TT_Err_Invalid_Face_Handle;
+
+ if ( last_glyph >= faze->numGlyphs ||
+ first_glyph > last_glyph )
+ return TT_Err_Invalid_Argument;
+
+ /* find "glyf" table */
+ table = TT_LookUp_Table( faze, TTAG_glyf );
+ if ( table < 0 )
+ {
+ PERROR(( "ERROR: there is no glyph table in this font file!\n" ));
+ return TT_Err_Glyf_Table_Missing;
+ }
+ glyf_offset = faze->dirTables[table].Offset;
+
+ /* now access stream */
+ if ( USE_Stream( faze->stream, stream ) )
+ return error;
+
+ locations = faze->glyphLocations + first_glyph;
+
+ /* loop to load each glyph in the range */
+ for ( n = first_glyph; n <= last_glyph; n++ )
+ {
+ if ( n + 1 < faze->numGlyphs &&
+ locations[0] == locations[1] )
+ {
+ /* Note : Glyph 0 is always used to indicate a missing glyph */
+ /* in a range. We must thus return its width and height */
+ /* where appropriate when we find an undefined glyph. */
+ if ( zero_loaded == 0 )
+ {
+ if ( FILE_Seek( glyf_offset + faze->glyphLocations[0] ) ||
+ ACCESS_Frame( 10L ) )
+ goto Fail;
+
+ (void)GET_Short(); /* skip number of contours */
+
+ bbox.xMin = GET_Short();
+ bbox.yMin = GET_Short();
+ bbox.xMax = GET_Short();
+ bbox.yMax = GET_Short();
+
+ FORGET_Frame();
+
+ zero_width = (UShort)(bbox.xMax - bbox.xMin);
+ zero_height = (UShort)(bbox.yMax - bbox.yMin);
+ zero_loaded = 1;
+ }
+
+ if ( widths )
+ *widths++ = zero_width;
+
+ if ( heights )
+ *heights++ = zero_height;
+ }
+ else
+ {
+ /* normal glyph, read header */
+ if ( FILE_Seek( glyf_offset + locations[0] ) ||
+ ACCESS_Frame( 10L ) )
+ goto Fail;
+
+ (void)GET_Short(); /* skip number of contours */
+
+ bbox.xMin = GET_Short();
+ bbox.yMin = GET_Short();
+ bbox.xMax = GET_Short();
+ bbox.yMax = GET_Short();
+
+ FORGET_Frame();
+
+ if ( widths )
+ *widths++ = (UShort)(bbox.xMax - bbox.xMin);
+
+ if ( heights )
+ *heights++ = (UShort)(bbox.yMax - bbox.yMin);
+ }
+ }
+
+ Fail:
+ DONE_Stream( stream );
+ return error;
+ }
+
+
+/* END */
diff --git a/Build/source/libs/libttf/extend/ftxwidth.h b/Build/source/libs/libttf/extend/ftxwidth.h
new file mode 100644
index 00000000000..5ac72517927
--- /dev/null
+++ b/Build/source/libs/libttf/extend/ftxwidth.h
@@ -0,0 +1,80 @@
+/*******************************************************************
+ *
+ * ftxwidth.h
+ *
+ * Glyph Widths (and Heights) fast retrieval extension.
+ *
+ * Copyright 1996-1999 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 extension is used to parse the `glyf' table of a TrueType
+ * file in order to extract the bounding box of a given range of glyphs.
+ *
+ * The bounding box is then used to build font unit widths and heights
+ * that are returned in two parallel arrays.
+ *
+ * This extension is needed by the FreeType/2 OS/2 Font Driver.
+ *
+ ******************************************************************/
+
+#ifndef FTXWIDTH_H
+#define FTXWIDTH_H
+
+#include "freetype.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ /******************************************************************/
+ /* */
+ /* Function: TT_Get_Face_Widths */
+ /* */
+ /* Description: Returns the widths and/or heights of a given */
+ /* range of glyphs for a face. */
+ /* */
+ /* Input: */
+ /* face :: face handle */
+ /* */
+ /* first_glyph :: first glyph in range */
+ /* */
+ /* last_glyph :: last glyph in range */
+ /* */
+ /* widths :: address of table receiving the widths */
+ /* expressed in font units (ushorts). Set */
+ /* this parameter to NULL if you're not */
+ /* interested by these values. */
+ /* */
+ /* heights :: address of table receiving the heights */
+ /* expressed in font units (ushorts). Set */
+ /* this parameter to NULL if you're not */
+ /* interested by these values */
+ /* */
+ /* Returns: */
+ /* Error code */
+ /* */
+ /* */
+ /******************************************************************/
+
+ EXPORT_DEF
+ TT_Error TT_Get_Face_Widths( TT_Face face,
+ TT_UShort first_glyph,
+ TT_UShort last_glyph,
+ TT_UShort* widths,
+ TT_UShort* heights );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FTXWIDTH_H */
+
+
+/* END */
diff --git a/Build/source/libs/libttf/extend/readme.1st b/Build/source/libs/libttf/extend/readme.1st
new file mode 100644
index 00000000000..cce94cdfad1
--- /dev/null
+++ b/Build/source/libs/libttf/extend/readme.1st
@@ -0,0 +1,61 @@
+This directory contains several extensions to the core engine.
+
+An extension is a separately compilable unit which can be linked by
+a client application to add new functionalities to the engine.
+
+There are two kinds of extensions: an `API extension' provides
+clients with new APIs to access internal engine structures or data,
+while an `engine extension' implements new TrueType data or table
+management.
+
+This directory contains the following:
+
+ ftxcmap: An API extension to iterate over cmaps.
+
+ ftxgasp: A simple API extension which returns the TrueType `gasp'
+ table to client applications, when found in a font file.
+ Though this table is always loaded by the engine, there
+ is no function in the core API to access it. The reason
+ is simple: to demonstrate a simple API extension with
+ `ftxgasp'!
+
+ ftxkern: This engine extension is used to access kerning data,
+ when available in a font file. Note that it implements
+ on-the-fly loading and retrieving of kerning tables.
+ However, it doesn't interpret or process the data, and
+ client applications should use it according to the
+ TrueType specification.
+
+ ftxpost: An engine extension to load the PostScript glyph names
+ of the `post' table. See the `ftzoom' program for an
+ example how to use it.
+
+ ftxwidth: A simple extension used to load the widths and heights
+ of a given range of glyphs in a face. Results are
+ expressed in unscaled font units. This is required by
+ the latest version of the FreeType/2 DLL to speed up
+ font loading in the GRE (the OS/2 GRaphics Engine). It
+ can be used by other applications though...
+
+ ftxerr18: This extension simply converts a TrueType engine error
+ code into a corresponding string describing the error.
+ It is useful if you intend to write a package for end
+ users and want to give them not `Error code 135' but
+ `OS/2 table missing'. See docs/errstr.txt for a
+ description how to use it (really simple!). ftxerr18
+ supports localization of error strings (that is: error
+ strings are automatically translated into supported
+ languages) using gettext(). See docs/i18n.txt about
+ using gettext.
+
+ ftxsbit: Embedded bitmap support. This is an engine extension.
+ See e.g. the `ftstrtto' program for its usage.
+
+ ftxopen,
+ ftxgsub,
+ ftxgpos,
+ ftxgdef: This is experimental stuff for TrueType Open support!
+ Please ignore it or help debugging :-)
+
+
+--- END ---