summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKeith Packard <keithp@keithp.com>2004-12-04 22:06:52 +0000
committerKeith Packard <keithp@keithp.com>2004-12-04 22:06:52 +0000
commitdbf68dd5fe2f936af53891a240601c727bdcf09d (patch)
tree7217dee4eb5ef01ad9ddae04dbd440446ec5f34d
parent4f27c1c0a383e891890ab27c74226957ed7067aa (diff)
Fix typo.
Add detection for font capabilities (bug #105) reviewed by: Keith Packard <keithp@keithp.com>
-rw-r--r--ChangeLog13
-rw-r--r--doc/fontconfig-user.sgml1
-rw-r--r--fontconfig/fontconfig.h1
-rw-r--r--src/fcfreetype.c188
-rw-r--r--src/fcname.c1
5 files changed, 204 insertions, 0 deletions
diff --git a/ChangeLog b/ChangeLog
index 3d98cab..b89f20b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,16 @@
+2004-12-04 Daniel Glassey <danglassey@ntlworld.com>
+
+ reviewed by: Keith Packard <keithp@keithp.com>
+
+ * 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 <keithp@keithp.com>
* 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.
+ </para></refsect2>
<refsect2><title><sgmltag>patelt name="property"</></title><para>
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])