+
+
+#define TTAG_GPOS FT_MAKE_TAG( 'G', 'P', 'O', 'S' )
+#define TTAG_GSUB FT_MAKE_TAG( 'G', 'S', 'U', 'B' )
+#define TTAG_SILF FT_MAKE_TAG( 'S', 'i', 'l', 'f')
+#define TT_Err_Ok FT_Err_Ok
+#define TT_Err_Invalid_Face_Handle FT_Err_Invalid_Face_Handle
+#define TTO_Err_Empty_Script 0x1005
+#define TTO_Err_Invalid_SubTable 0x1001
+
+#define OTLAYOUT_HEAD "otlayout:"
+#define OTLAYOUT_HEAD_LEN 9
+#define OTLAYOUT_ID_LEN 4
+/* space + head + id */
+#define OTLAYOUT_LEN (1 + OTLAYOUT_HEAD_LEN + OTLAYOUT_ID_LEN)
+
+/*
+ * This is a bit generous; the registry has only lower case and space
+ * except for 'DFLT'.
+ */
+#define FcIsSpace(x) (040 == (x))
+#define FcIsValidScript(x) (FcIsLower(x) || FcIsUpper (x) || FcIsSpace(x))
+
+static void
+addtag(FcChar8 *complex, FT_ULong tag)
+{
+ FcChar8 tagstring[OTLAYOUT_ID_LEN + 1];
+
+ tagstring[0] = (FcChar8)(tag >> 24),
+ tagstring[1] = (FcChar8)(tag >> 16),
+ tagstring[2] = (FcChar8)(tag >> 8),
+ tagstring[3] = (FcChar8)(tag);
+ tagstring[4] = '\0';
+
+ /* skip tags which aren't alphabetic, under the assumption that
+ * they're probably broken
+ */
+ if (!FcIsValidScript(tagstring[0]) ||
+ !FcIsValidScript(tagstring[1]) ||
+ !FcIsValidScript(tagstring[2]) ||
+ !FcIsValidScript(tagstring[3]))
+ return;
+
+ if (*complex != '\0')
+ strcat ((char *) complex, " ");
+ strcat ((char *) complex, "otlayout:");
+ strcat ((char *) complex, (char *) tagstring);
+}
+
+static int
+compareulong (const void *a, const void *b)
+{
+ const FT_ULong *ua = (const FT_ULong *) a;
+ const FT_ULong *ub = (const FT_ULong *) b;
+ return *ua - *ub;
+}
+
+
+static FT_Error
+GetScriptTags(FT_Face face, FT_ULong tabletag, FT_ULong **stags, FT_UShort *script_count)
+{
+ FT_ULong cur_offset, new_offset, base_offset;
+ FT_Stream stream = face->stream;
+ FT_Error error;
+ FT_UShort n, p;
+ FT_Memory memory;
+
+ if ( !stream )
+ return TT_Err_Invalid_Face_Handle;
+
+ memory = stream->memory;
+
+ if (( error = ftglue_face_goto_table( face, tabletag, stream ) ))
+ return error;
+
+ base_offset = ftglue_stream_pos ( stream );
+
+ /* skip version */
+
+ if ( ftglue_stream_seek ( stream, base_offset + 4L ) || ftglue_stream_frame_enter( stream, 2L ) )
+ return error;
+
+ new_offset = GET_UShort() + base_offset;
+
+ ftglue_stream_frame_exit( stream );
+
+ cur_offset = ftglue_stream_pos( stream );
+
+ if ( ftglue_stream_seek( stream, new_offset ) != TT_Err_Ok )
+ return error;
+
+ base_offset = ftglue_stream_pos( stream );
+
+ if ( ftglue_stream_frame_enter( stream, 2L ) )
+ return error;
+
+ *script_count = GET_UShort ();
+
+ ftglue_stream_frame_exit( stream );
+
+ *stags = ftglue_alloc(memory, *script_count * sizeof( FT_ULong ), &error);
+
+ if (error)
+ return error;
+
+ p = 0;
+ for ( n = 0; n < *script_count; n++ )
+ {
+ if ( ftglue_stream_frame_enter( stream, 6L ) )
+ goto Fail;
+
+ (*stags)[p] = GET_ULong ();
+ new_offset = GET_UShort () + base_offset;
+
+ ftglue_stream_frame_exit( stream );
+
+ cur_offset = ftglue_stream_pos( stream );
+
+ error = ftglue_stream_seek( stream, new_offset );
+
+ if ( error == TT_Err_Ok )
+ p++;
+
+ (void)ftglue_stream_seek( stream, cur_offset );
+ }
+
+ if (!p)
+ {
+ error = TTO_Err_Invalid_SubTable;
+ goto Fail;
+ }
+
+ /* sort the tag list before returning it */
+ qsort(*stags, *script_count, sizeof(FT_ULong), compareulong);
+
+ return TT_Err_Ok;
+
+Fail:
+ *script_count = 0;
+ ftglue_free( memory, *stags );
+ *stags = NULL;
+ return error;
+}
+
+static FcChar8 *
+FcFontCapabilities(FT_Face face)
+{
+ FcBool issilgraphitefont = 0;
+ FT_Error err;
+ FT_ULong len = 0;
+ FT_ULong *gsubtags=NULL, *gpostags=NULL;
+ FT_UShort gsub_count=0, gpos_count=0;
+ FT_ULong maxsize;
+ FT_Memory memory = face->stream->memory;
+ FcChar8 *complex = NULL;
+ int indx1 = 0, indx2 = 0;
+
+ err = FT_Load_Sfnt_Table(face, TTAG_SILF, 0, 0, &len);
+ issilgraphitefont = ( err == FT_Err_Ok);
+
+ if (GetScriptTags(face, TTAG_GPOS, &gpostags, &gpos_count) != FT_Err_Ok)
+ gpos_count = 0;
+ if (GetScriptTags(face, TTAG_GSUB, &gsubtags, &gsub_count) != FT_Err_Ok)
+ gsub_count = 0;
+
+ if (!issilgraphitefont && !gsub_count && !gpos_count)
+ goto bail;
+
+ maxsize = (((FT_ULong) gpos_count + (FT_ULong) gsub_count) * OTLAYOUT_LEN +
+ (issilgraphitefont ? 13 : 0));
+ complex = malloc (sizeof (FcChar8) * maxsize);
+ if (!complex)
+ goto bail;
+
+ complex[0] = '\0';
+ if (issilgraphitefont)
+ strcpy((char *) complex, "ttable:Silf ");
+
+ while ((indx1 < gsub_count) || (indx2 < gpos_count)) {
+ if (indx1 == gsub_count) {
+ addtag(complex, gpostags[indx2]);
+ indx2++;
+ } else if ((indx2 == gpos_count) || (gsubtags[indx1] < gpostags[indx2])) {
+ addtag(complex, gsubtags[indx1]);
+ indx1++;
+ } else if (gsubtags[indx1] == gpostags[indx2]) {
+ addtag(complex, gsubtags[indx1]);
+ indx1++;
+ indx2++;
+ } else {
+ addtag(complex, gpostags[indx2]);
+ indx2++;
+ }
+ }
+ if (FcDebug () & FC_DBG_SCANV)
+ printf("complex features in this font: %s\n", complex);
+bail:
+ ftglue_free(memory, gsubtags);
+ ftglue_free(memory, gpostags);
+ return complex;
+}
+
+#define __fcfreetype__
+#include "fcaliastail.h"
+#undef __fcfreetype__