From dbf68dd5fe2f936af53891a240601c727bdcf09d Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 4 Dec 2004 22:06:52 +0000 Subject: [PATCH] Fix typo. Add detection for font capabilities (bug #105) reviewed by: Keith Packard --- ChangeLog | 13 +++ doc/fontconfig-user.sgml | 1 + fontconfig/fontconfig.h | 1 + src/fcfreetype.c | 188 +++++++++++++++++++++++++++++++++++++++ src/fcname.c | 1 + 5 files changed, 204 insertions(+) diff --git a/ChangeLog b/ChangeLog index 3d98cab..b89f20b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,16 @@ +2004-12-04 Daniel Glassey + + reviewed by: Keith Packard + + * doc/fontconfig-user.sgml: + Fix typo. + + * fontconfig/fontconfig.h: + * src/fcfreetype.c: (FcFreeTypeQuery), (addtag), (compareulong), + (GetScriptTags), (FcFontCapabilities): + * src/fcname.c: + Add detection for font capabilities (bug #105) + 2004-12-04 Keith Packard * Makefile.am: diff --git a/doc/fontconfig-user.sgml b/doc/fontconfig-user.sgml index ca0f9b7..afe1c48 100644 --- a/doc/fontconfig-user.sgml +++ b/doc/fontconfig-user.sgml @@ -319,6 +319,7 @@ elements have a matching value, then the pattern matches the font. This can be used to select fonts based on attributes of the font (scalable, bold, etc), which is a more reliable mechanism than using file extensions. Pattern elements include patelt elements. + <sgmltag>patelt name="property"</> Patelt elements hold a single pattern element and list of values. They must have a 'name' attribute which indicates the pattern element name. Patelt diff --git a/fontconfig/fontconfig.h b/fontconfig/fontconfig.h index 645aebb..6758f27 100644 --- a/fontconfig/fontconfig.h +++ b/fontconfig/fontconfig.h @@ -93,6 +93,7 @@ typedef int FcBool; #define FC_FAMILYLANG "familylang" /* String RFC 3066 langs */ #define FC_STYLELANG "stylelang" /* String RFC 3066 langs */ #define FC_FULLNAMELANG "fullnamelang" /* String RFC 3066 langs */ +#define FC_CAPABILITY "capability" /* String */ #define FC_DIR_CACHE_FILE "fonts.cache-"FC_CACHE_VERSION #define FC_USER_CACHE_FILE ".fonts.cache-"FC_CACHE_VERSION diff --git a/src/fcfreetype.c b/src/fcfreetype.c index 9c2c385..0c2eafd 100644 --- a/src/fcfreetype.c +++ b/src/fcfreetype.c @@ -55,6 +55,9 @@ #include FT_SFNT_NAMES_H #include FT_TRUETYPE_IDS_H #include FT_TYPE1_TABLES_H +#include FT_INTERNAL_STREAM_H +#include FT_INTERNAL_SFNT_H +#include FT_INTERNAL_TRUETYPE_TYPES_H #if HAVE_FT_GET_BDF_PROPERTY #include FT_BDF_H @@ -551,6 +554,9 @@ static const FcMacRomanFake fcMacRomanFake[] = { { TT_MS_LANGID_ENGLISH_UNITED_STATES, "ASCII" }, }; +static FcChar8 * +FcFontCapabilities(FT_Face face); + #define NUM_FC_MAC_ROMAN_FAKE (sizeof (fcMacRomanFake) / sizeof (fcMacRomanFake[0])) #if HAVE_ICONV && HAVE_ICONV_H @@ -985,6 +991,7 @@ FcFreeTypeQuery (const FcChar8 *file, #if 0 FcChar8 *family = 0; #endif + FcChar8 *complex; const FcChar8 *foundry = 0; int spacing; TT_OS2 *os2; @@ -1366,6 +1373,15 @@ FcFreeTypeQuery (const FcChar8 *file, case 9: width = FC_WIDTH_ULTRAEXPANDED; break; } } + if (os2 && (complex = FcFontCapabilities(face))) + { + if (!FcPatternAddString (pat, FC_CAPABILITY, complex)) + { + free (complex); + goto bail1; + } + free (complex); + } /* * Type 1: Check for FontInfo dictionary information @@ -2604,3 +2620,175 @@ FcFreeTypeCharSet (FT_Face face, FcBlanks *blanks) return FcFreeTypeCharSetAndSpacing (face, blanks, &spacing); } + + +#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 + + +static void +addtag(FcChar8 *complex, FT_ULong tag) +{ + FcChar8 tagstring[15]; + sprintf (tagstring, "otlayout:%c%c%c%c ", + (unsigned char)(tag >> 24), + (unsigned char)((tag & 0xff0000) >> 16), + (unsigned char)((tag & 0xff00) >> 8), + (unsigned char)(tag & 0xff)); + strncat(complex, tagstring, 14); +} + +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; + TT_Face tt_face = (TT_Face)face; + FT_Stream stream = face->stream; + FT_Error error; + FT_UShort n, p; + FT_Memory memory = stream->memory; + + if ( !stream ) + return TT_Err_Invalid_Face_Handle; + + if (( error = tt_face->goto_table( tt_face, tabletag, stream, 0 ) )) + return error; + + base_offset = FT_STREAM_POS(); + + /* skip version */ + + if ( FT_STREAM_SEEK( base_offset + 4L ) || FT_FRAME_ENTER( 2L ) ) + return error; + + new_offset = FT_GET_USHORT() + base_offset; + + FT_FRAME_EXIT(); + + cur_offset = FT_STREAM_POS(); + + if ( FT_STREAM_SEEK( new_offset ) != TT_Err_Ok ) + return error; + + base_offset = FT_STREAM_POS(); + + if ( FT_FRAME_ENTER( 2L ) ) + return error; + + *script_count = FT_GET_USHORT(); + + FT_FRAME_EXIT(); + + if ( FT_SET_ERROR (FT_MEM_ALLOC_ARRAY( *stags, *script_count, FT_ULong )) ) + return error; + + p = 0; + for ( n = 0; n < *script_count; n++ ) + { + if ( FT_FRAME_ENTER( 6L ) ) + goto Fail; + + (*stags)[p] = FT_GET_ULONG(); + new_offset = FT_GET_USHORT() + base_offset; + + FT_FRAME_EXIT(); + + cur_offset = FT_STREAM_POS(); + + if ( FT_STREAM_SEEK( new_offset ) ) + goto Fail; + + if ( error == TT_Err_Ok ) + p++; + else if ( error != TTO_Err_Empty_Script ) + goto Fail; + + (void)FT_STREAM_SEEK( 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: + FT_FREE( *stags ); + 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, 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); + + err = GetScriptTags(face, TTAG_GPOS, &gpostags, &gpos_count); + err = GetScriptTags(face, TTAG_GSUB, &gsubtags, &gsub_count); + if (!issilgraphitefont && !gsub_count && !gpos_count) + { + goto bail; + } + + maxsize = ((gpos_count + gsub_count) * 15) + (issilgraphitefont ? 13 : 0); + complex = malloc (sizeof (FcChar8) * maxsize); + if (issilgraphitefont) + { + strcpy(complex, "ttable:Silf "); + } + else + { + strcpy(complex, ""); + } + + 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: + FT_FREE(gsubtags); + FT_FREE(gpostags); + return complex; +} diff --git a/src/fcname.c b/src/fcname.c index f40bf64..776fba8 100644 --- a/src/fcname.c +++ b/src/fcname.c @@ -67,6 +67,7 @@ static const FcObjectType _FcBaseObjectTypes[] = { { FC_CHARSET, FcTypeCharSet }, { FC_LANG, FcTypeLangSet }, { FC_FONTVERSION, FcTypeInteger }, + { FC_CAPABILITY, FcTypeString }, }; #define NUM_OBJECT_TYPES (sizeof _FcBaseObjectTypes / sizeof _FcBaseObjectTypes[0]) -- 2.39.5