diff --git a/ChangeLog b/ChangeLog index 4a1f1ecae..db4b9760e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,68 @@ +2013-12-21 Werner Lemberg + + [autofit] Introduce `coverages'. + + Coverages are the interface to the HarfBuzz library to acces + OpenType features for handling glyphs not addressable by the cmap. + + Right now, compilation of HarfBuzz is only added to the development + build. A solution for standard build mode will be delayed until + HarfBuzz gets split into two libraries to avoid mutual dependencies + between FreeType and HarfBuzz. + + Note that this is only a first step in handling coverages, basically + providing the framework only. Code for handling selected OpenType + features (this is, actually using the data in `afcover.h') will + follow. + + * devel/ftoption.h, include/config/ftoption.h + (FT_CONFIG_OPTION_USE_HARFBUZZ): New macro. + + * src/autofit/hbshim.c, src/autofit/hbshim.h, src/autofit/afcover.h: + New files. + + * src/autofit/afscript.h: Add HarfBuzz script name tags. + + * src/autofit/afstyles.h: Add default coverage enumeration values. + + * src/autofit/aftypes.h: Update use of `SCRIPT' and `STYLE' macros. + (AF_Coverage): New enumeration (generated by `afcover.h'). + (AF_StyleClassRec): New member `coverage'. + (AF_DEFINE_STYLE_CLASS): Updated. + + * include/internal/fttrace.h: Add `afharfbuzz' for tracing coverage + data. + + * src/autofit/afglobal.h: Update use of `SCRIPT' and `STYLE' macros. + (AF_SCRIPT_FALLBACK): Renamed to ... + (AF_STYLE_FALLBACK): ... this. + + * src/autofit/afglobal.c: Include `hbshim.c'. + Update use of `SCRIPT' and `STYLE' macros. + (af_face_globals_compute_style_coverage) + [FT_CONFIG_OPTION_USE_HARFBUZZ]: Call `af_get_coverage'. + Update. + + * src/autofit/afmodule.h (AF_ModuleRec): + s/fallback_script/fallback_style/. + + * src/autofit/afmodule.c (af_property_set): Adapt handling of + `fallback-script' property to set a fallback style. + (af_property_get, af_autofitter_init): Updated. + + * src/autofit/afpic.c: Update use of `SCRIPT' and `STYLE' macros. + + * src/autofit/afranges.h: Update use of `SCRIPT' macro. + + * src/autofit/autofit.c [FT_CONFIG_OPTION_USE_HARFBUZZ]: Include + `hbshim.c'. + + * src/autofit/rules.mk (AUTOF_DRV_SRC): Add `hbshim.c'. + (AUTOF_DRV_H): Add `afcover.h'. + + * builds/freetype.mk (INCLUDE_FLAGS) [DEVEL_DIR]: Use pkg-config for + all libraries needed by FreeType. + 2013-12-21 Werner Lemberg Fix Savannah bug #40975 (sort of). diff --git a/builds/freetype.mk b/builds/freetype.mk index 68edfe505..bf372fd6c 100644 --- a/builds/freetype.mk +++ b/builds/freetype.mk @@ -126,6 +126,15 @@ INCLUDES := $(subst /,$(COMPILER_SEP),$(OBJ_DIR) \ INCLUDE_FLAGS := $(INCLUDES:%=$I%) +ifdef DEVEL_DIR + # We assume that all library dependencies for FreeType are fulfilled for a + # development build, so we directly access the necessary include directory + # information using `pkg-config'. + INCLUDE_FLAGS += $(shell pkg-config --cflags bzip2 \ + libpng \ + harfbuzz ) +endif + # C flags used for the compilation of an object file. This must include at # least the paths for the `base' and `builds/' directories; diff --git a/devel/ftoption.h b/devel/ftoption.h index 27d1bd9a5..d7b6a6301 100644 --- a/devel/ftoption.h +++ b/devel/ftoption.h @@ -217,6 +217,19 @@ FT_BEGIN_HEADER #define FT_CONFIG_OPTION_USE_PNG + /*************************************************************************/ + /* */ + /* HarfBuzz support. */ + /* */ + /* FreeType uses the HarfBuzz library to improve auto-hinting of */ + /* OpenType fonts. If available, many glyphs not directly addressable */ + /* by a font's character map will be hinted also. */ + /* */ + /* Define this macro if you want to enable this `feature'. */ + /* */ +#define FT_CONFIG_OPTION_USE_HARFBUZZ + + /*************************************************************************/ /* */ /* Define to disable the use of file stream functions and types, FILE, */ diff --git a/include/config/ftoption.h b/include/config/ftoption.h index fe2ba15b4..5b11f0e03 100644 --- a/include/config/ftoption.h +++ b/include/config/ftoption.h @@ -228,6 +228,19 @@ FT_BEGIN_HEADER /* #define FT_CONFIG_OPTION_USE_PNG */ + /*************************************************************************/ + /* */ + /* HarfBuzz support. */ + /* */ + /* FreeType uses the HarfBuzz library to improve auto-hinting of */ + /* OpenType fonts. If available, many glyphs not directly addressable */ + /* by a font's character map will be hinted also. */ + /* */ + /* Define this macro if you want to enable this `feature'. */ + /* */ +/* #define FT_CONFIG_OPTION_USE_HARFBUZZ */ + + /*************************************************************************/ /* */ /* DLL export compilation */ diff --git a/include/internal/fttrace.h b/include/internal/fttrace.h index a9d98b60a..29158c08f 100644 --- a/include/internal/fttrace.h +++ b/include/internal/fttrace.h @@ -148,5 +148,6 @@ FT_TRACE_DEF( afcjk ) FT_TRACE_DEF( aflatin ) FT_TRACE_DEF( aflatin2 ) FT_TRACE_DEF( afwarp ) +FT_TRACE_DEF( afharfbuzz ) /* END */ diff --git a/src/autofit/afcover.h b/src/autofit/afcover.h new file mode 100644 index 000000000..13dbecb21 --- /dev/null +++ b/src/autofit/afcover.h @@ -0,0 +1,66 @@ +/***************************************************************************/ +/* */ +/* afcover.h */ +/* */ +/* Auto-fitter coverages (specification only). */ +/* */ +/* Copyright 2013 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 header file can be included multiple times. */ + /* Define `COVERAGE_{1,2,3}' as needed. */ + + + /* Add new coverages here. The first and second arguments are the */ + /* coverage name in lowercase and uppercase, respectively, followed */ + /* by a description string. The remaining arguments the */ + /* corresponding OpenType features (with four characters a feature). */ + + COVERAGE_1( oldstyle_figures, OLDSTYLE_FIGURES, + "oldstyle figures", + 'o', 'n', 'u', 'm' ) /* Oldstyle Figures */ + + COVERAGE_2( petite_capitals, PETITE_CAPITALS, + "petite capitals", + 'c', '2', 'c', 'p', /* Petite Capitals from Capitals */ + 'p', 'c', 'a', 'p' ) /* Petite Capitals */ + + COVERAGE_2( small_capitals, SMALL_CAPITALS, + "small capitals", + 'c', '2', 's', 'c', /* Small Capitals from Capitals */ + 's', 'm', 'c', 'p' ) /* Small Capitals */ + + COVERAGE_1( titling, TITLING, + "titling", + 't', 'i', 't', 'l' ) /* Titling */ + + COVERAGE_2( sub_superscript_1, SUB_SUPERSCRIPT_1, + "sub- and superscripts group 1", + 's', 'u', 'b', 's', /* Subscript */ + 's', 'u', 'p', 's' ) /* Superscript */ + + COVERAGE_2( sub_superscript_2, SUB_SUPERSCRIPT_2, + "sub- and superscripts group 2", + 'o', 'r', 'd', 'n', /* Ordinals */ + 's', 'i', 'n', 'f' ) /* Scientific Inferiors */ + + COVERAGE_3( fractions, FRACTIONS, + "fractions", + 'd', 'n', 'o', 'm', /* Denominators */ + 'f', 'r', 'a', 'c', /* Fractions */ + 'n', 'u', 'm', 'r' ) /* Numerators */ + + COVERAGE_1( alternative_fractions, ALTERNATIVE_FRACTIONS, + "alternative fractions", + 'a', 'f', 'r', 'c' ) /* Alternative Fractions */ + +/* END */ diff --git a/src/autofit/afglobal.c b/src/autofit/afglobal.c index 1b4721c08..912a32fc3 100644 --- a/src/autofit/afglobal.c +++ b/src/autofit/afglobal.c @@ -18,6 +18,7 @@ #include "afglobal.h" #include "afranges.h" +#include "hbshim.h" /* get writing system specific header files */ #undef WRITING_SYSTEM @@ -29,7 +30,7 @@ #undef SCRIPT -#define SCRIPT( s, S, d, dc ) \ +#define SCRIPT( s, S, d, h, dc ) \ AF_DEFINE_SCRIPT_CLASS( \ af_ ## s ## _script_class, \ AF_SCRIPT_ ## S, \ @@ -40,13 +41,14 @@ #undef STYLE -#define STYLE( s, S, d, ws, sc, ss ) \ - AF_DEFINE_STYLE_CLASS( \ - af_ ## s ## _style_class, \ - AF_STYLE_ ## S, \ - ws, \ - sc, \ - ss ) +#define STYLE( s, S, d, ws, sc, ss, c ) \ + AF_DEFINE_STYLE_CLASS( \ + af_ ## s ## _style_class, \ + AF_STYLE_ ## S, \ + ws, \ + sc, \ + ss, \ + c ) #include "afstyles.h" @@ -68,7 +70,7 @@ #undef SCRIPT -#define SCRIPT( s, S, d, dc ) \ +#define SCRIPT( s, S, d, h, dc ) \ &af_ ## s ## _script_class, FT_LOCAL_ARRAY_DEF( AF_ScriptClass ) @@ -82,7 +84,7 @@ #undef STYLE -#define STYLE( s, S, d, ws, sc, ss ) \ +#define STYLE( s, S, d, ws, sc, ss, c ) \ &af_ ## s ## _style_class, FT_LOCAL_ARRAY_DEF( AF_StyleClass ) @@ -100,7 +102,7 @@ #ifdef FT_DEBUG_LEVEL_TRACE #undef STYLE -#define STYLE( s, S, d, ws, sc, ss ) #s, +#define STYLE( s, S, d, ws, sc, ss, c ) #s, FT_LOCAL_ARRAY_DEF( char* ) af_style_names[] = @@ -135,7 +137,7 @@ if ( error ) { /* - * Ignore this error; we simply use the fallback script. + * Ignore this error; we simply use the fallback style. * XXX: Shouldn't we rather disable hinting? */ error = FT_Err_Ok; @@ -186,6 +188,11 @@ gstyles[gindex] = (FT_Byte)ss; } } + +#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ + /* get glyphs not directly addressable by cmap */ + af_get_coverage( face, style_class, gstyles ); +#endif } /* mark ASCII digits */ @@ -200,10 +207,10 @@ Exit: /* - * By default, all uncovered glyphs are set to the fallback script. + * By default, all uncovered glyphs are set to the fallback style. * XXX: Shouldn't we disable hinting or do something similar? */ - if ( globals->module->fallback_script != AF_STYLE_UNASSIGNED ) + if ( globals->module->fallback_style != AF_STYLE_UNASSIGNED ) { FT_Long nn; @@ -213,7 +220,7 @@ if ( ( gstyles[nn] & ~AF_DIGIT ) == AF_STYLE_UNASSIGNED ) { gstyles[nn] &= ~AF_STYLE_UNASSIGNED; - gstyles[nn] |= globals->module->fallback_script; + gstyles[nn] |= globals->module->fallback_style; } } } diff --git a/src/autofit/afglobal.h b/src/autofit/afglobal.h index b0316e67e..43ce39472 100644 --- a/src/autofit/afglobal.h +++ b/src/autofit/afglobal.h @@ -33,7 +33,7 @@ FT_BEGIN_HEADER #undef SCRIPT -#define SCRIPT( s, S, d, dc ) \ +#define SCRIPT( s, S, d, h, dc ) \ AF_DECLARE_SCRIPT_CLASS( af_ ## s ## _script_class ) #include "afscript.h" @@ -43,7 +43,7 @@ FT_BEGIN_HEADER #undef STYLE -#define STYLE( s, S, d, ws, sc, ss ) \ +#define STYLE( s, S, d, ws, sc, ss, c ) \ AF_DECLARE_STYLE_CLASS( af_ ## s ## _style_class ) #include "afstyles.h" @@ -63,11 +63,11 @@ FT_BEGIN_HEADER * AF_ModuleRec) and face globals (in AF_FaceGlobalsRec). */ - /* index of fallback script in `af_style_classes' */ + /* index of fallback style in `af_style_classes' */ #ifdef AF_CONFIG_OPTION_CJK -#define AF_SCRIPT_FALLBACK AF_STYLE_HANI_DEFAULT +#define AF_STYLE_FALLBACK AF_STYLE_HANI_DEFAULT #else -#define AF_SCRIPT_FALLBACK AF_STYLE_NONE_DEFAULT +#define AF_STYLE_FALLBACK AF_STYLE_NONE_DEFAULT #endif /* a bit mask indicating an uncovered glyph */ #define AF_STYLE_UNASSIGNED 0x7F diff --git a/src/autofit/afmodule.c b/src/autofit/afmodule.c index 1ebe4a46e..d0316b3f7 100644 --- a/src/autofit/afmodule.c +++ b/src/autofit/afmodule.c @@ -92,8 +92,31 @@ { FT_UInt* fallback_script = (FT_UInt*)value; + FT_UInt ss; - module->fallback_script = *fallback_script; + + /* We translate the fallback script to a fallback style that uses */ + /* `fallback-script' as its script and `AF_COVERAGE_NONE' as its */ + /* coverage value. */ + for ( ss = 0; AF_STYLE_CLASSES_GET[ss]; ss++ ) + { + AF_StyleClass style_class = AF_STYLE_CLASSES_GET[ss]; + + + if ( style_class->script == *fallback_script && + style_class->coverage == AF_COVERAGE_DEFAULT ) + { + module->fallback_style = ss; + break; + } + } + + if ( !AF_STYLE_CLASSES_GET[ss] ) + { + FT_TRACE0(( "af_property_set: Invalid value %d for property `%s'\n", + fallback_script, property_name )); + return FT_THROW( Invalid_Argument ); + } return error; } @@ -121,9 +144,9 @@ const char* property_name, void* value ) { - FT_Error error = FT_Err_Ok; - AF_Module module = (AF_Module)ft_module; - FT_UInt fallback_script = module->fallback_script; + FT_Error error = FT_Err_Ok; + AF_Module module = (AF_Module)ft_module; + FT_UInt fallback_style = module->fallback_style; if ( !ft_strcmp( property_name, "glyph-to-script-map" ) ) @@ -142,8 +165,10 @@ { FT_UInt* val = (FT_UInt*)value; + AF_StyleClass style_class = AF_STYLE_CLASSES_GET[fallback_style]; - *val = fallback_script; + + *val = style_class->script; return error; } @@ -206,7 +231,7 @@ AF_Module module = (AF_Module)ft_module; - module->fallback_script = AF_SCRIPT_FALLBACK; + module->fallback_style = AF_STYLE_FALLBACK; return af_loader_init( module ); } diff --git a/src/autofit/afmodule.h b/src/autofit/afmodule.h index c4e8f8f66..d42c5c8ca 100644 --- a/src/autofit/afmodule.h +++ b/src/autofit/afmodule.h @@ -40,7 +40,7 @@ FT_BEGIN_HEADER { FT_ModuleRec root; - FT_UInt fallback_script; + FT_UInt fallback_style; AF_LoaderRec loader[1]; diff --git a/src/autofit/afpic.c b/src/autofit/afpic.c index eba6a8987..3980307f2 100644 --- a/src/autofit/afpic.c +++ b/src/autofit/afpic.c @@ -122,7 +122,7 @@ #include "afwrtsys.h" #undef SCRIPT -#define SCRIPT( s, S, d, dc ) \ +#define SCRIPT( s, S, d, h, dc ) \ FT_Init_Class_af_ ## s ## _script_class( \ &container->af_script_classes_rec[ss++] ); @@ -130,7 +130,7 @@ #include "afscript.h" #undef STYLE -#define STYLE( s, S, d, ws, sc, bss ) \ +#define STYLE( s, S, d, ws, sc, bss, c ) \ FT_Init_Class_af_ ## s ## _style_class( \ &container->af_style_classes_rec[ss++] ); diff --git a/src/autofit/afranges.h b/src/autofit/afranges.h index 8869695a7..cb04a3b9f 100644 --- a/src/autofit/afranges.h +++ b/src/autofit/afranges.h @@ -26,7 +26,7 @@ FT_BEGIN_HEADER #undef SCRIPT -#define SCRIPT( s, S, d, dc ) \ +#define SCRIPT( s, S, d, h, dc ) \ extern const AF_Script_UniRangeRec af_ ## s ## _uniranges[]; #include "afscript.h" diff --git a/src/autofit/afscript.h b/src/autofit/afscript.h index 063f2af21..a9def1838 100644 --- a/src/autofit/afscript.h +++ b/src/autofit/afscript.h @@ -20,34 +20,45 @@ /* Define `SCRIPT' as needed. */ - /* Add new scripts here. */ + /* Add new scripts here. The first and second arguments are the */ + /* script name in lowercase and uppercase, respectively, followed */ + /* by a description string. Then comes the corresponding HarfBuzz */ + /* script name tag, followed by the default character (to derive */ + /* the standard width and height of stems). */ SCRIPT( cyrl, CYRL, "Cyrillic", + HB_SCRIPT_CYRILLIC, 0x43E ) /* о */ SCRIPT( deva, DEVA, "Indic scripts", + HB_SCRIPT_DEVANAGARI, 'o' ) /* XXX */ SCRIPT( none, NONE, "no script", + HB_SCRIPT_INVALID, '\0' ) SCRIPT( grek, GREK, "Greek", + HB_SCRIPT_GREEK, 0x3BF ) /* ο */ SCRIPT( hani, HANI, "CJKV ideographs", + HB_SCRIPT_HAN, 0x7530 ) /* 田 */ SCRIPT( hebr, HEBR, "Hebrew", + HB_SCRIPT_HEBREW, 0x5DD ) /* ם */ SCRIPT( latn, LATN, "Latin", + HB_SCRIPT_LATIN, 'o' ) diff --git a/src/autofit/afstyles.h b/src/autofit/afstyles.h index ded804805..b5eb362ea 100644 --- a/src/autofit/afstyles.h +++ b/src/autofit/afstyles.h @@ -20,57 +20,69 @@ /* Define `STYLE' as needed. */ - /* Add new styles here. */ + /* Add new styles here. The first and second arguments are the */ + /* style name in lowercase and uppercase, respectively, followed */ + /* by a description string. The next arguments are the */ + /* corresponding writing system, script, blue stringset, and */ + /* coverage. */ STYLE( cyrl_default, CYRL_DEFAULT, "Cyrillic default style", AF_WRITING_SYSTEM_LATIN, AF_SCRIPT_CYRL, - AF_BLUE_STRINGSET_CYRL ) + AF_BLUE_STRINGSET_CYRL, + AF_COVERAGE_DEFAULT ) STYLE( deva_default, DEVA_DEFAULT, "Indic scripts default style", AF_WRITING_SYSTEM_INDIC, AF_SCRIPT_DEVA, - (AF_Blue_Stringset)0 ) /* XXX */ - - STYLE( none_default, NONE_DEFAULT, - "no style", - AF_WRITING_SYSTEM_DUMMY, - AF_SCRIPT_NONE, - (AF_Blue_Stringset)0 ) + (AF_Blue_Stringset)0, /* XXX */ + AF_COVERAGE_DEFAULT ) STYLE( grek_default, GREK_DEFAULT, "Greek default style", AF_WRITING_SYSTEM_LATIN, AF_SCRIPT_GREK, - AF_BLUE_STRINGSET_GREK ) + AF_BLUE_STRINGSET_GREK, + AF_COVERAGE_DEFAULT ) STYLE( hani_default, HANI_DEFAULT, "CJKV ideographs default style", AF_WRITING_SYSTEM_CJK, AF_SCRIPT_HANI, - AF_BLUE_STRINGSET_HANI ) + AF_BLUE_STRINGSET_HANI, + AF_COVERAGE_DEFAULT ) STYLE( hebr_default, HEBR_DEFAULT, "Hebrew default style", AF_WRITING_SYSTEM_LATIN, AF_SCRIPT_HEBR, - AF_BLUE_STRINGSET_HEBR ) + AF_BLUE_STRINGSET_HEBR, + AF_COVERAGE_DEFAULT ) STYLE( latn_default, LATN_DEFAULT, "Latin default style", AF_WRITING_SYSTEM_LATIN, AF_SCRIPT_LATN, - AF_BLUE_STRINGSET_LATN ) + AF_BLUE_STRINGSET_LATN, + AF_COVERAGE_DEFAULT ) #ifdef FT_OPTION_AUTOFIT2 STYLE( ltn2_default, LTN2_DEFAULT, "Latin 2 default style", AF_WRITING_SYSTEM_LATIN2, AF_SCRIPT_LATN, - AF_BLUE_STRINGSET_LATN ) + AF_BLUE_STRINGSET_LATN, + AF_COVERAGE_DEFAULT ) #endif + STYLE( none_default, NONE_DEFAULT, + "no style", + AF_WRITING_SYSTEM_DUMMY, + AF_SCRIPT_NONE, + (AF_Blue_Stringset)0, + AF_COVERAGE_DEFAULT ) + /* END */ diff --git a/src/autofit/aftypes.h b/src/autofit/aftypes.h index 70ddc7fff..b6a365b3e 100644 --- a/src/autofit/aftypes.h +++ b/src/autofit/aftypes.h @@ -303,7 +303,7 @@ extern void* _af_debug_hints; */ #undef SCRIPT -#define SCRIPT( s, S, d, dc ) \ +#define SCRIPT( s, S, d, h, dc ) \ AF_SCRIPT_ ## S, /* The list of known scripts. */ @@ -341,6 +341,82 @@ extern void* _af_debug_hints; typedef const AF_ScriptClassRec* AF_ScriptClass; + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** C O V E R A G E S *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* + * Usually, a font contains more glyphs than can be addressed by its + * character map. + * + * In the PostScript font world, encoding vectors specific to a given + * task are used to select such glyphs, and these glyphs can be often + * recognized by having a suffix in its glyph names. For example, a + * superscript glyph `A' might be called `A.sup'. Unfortunately, this + * naming scheme is not standardized and thus unusable for us. + * + * In the OpenType world, a better solution was invented, namely + * `features', which cleanly separate a character's input encoding from + * the corresponding glyph's appearance, and which don't use glyph names + * at all. For our purposes, and slightly generalized, an OpenType + * feature is a name of a mapping that maps character codes to + * non-standard glyph indices (features get used for other things also). + * For example, the `sups' feature provides superscript glyphs, thus + * mapping character codes like `A' or `B' to superscript glyph + * representation forms. How this mapping happens is completely + * uninteresting to us. + * + * For the auto-hinter, a `coverage' represents all glyphs of one or more + * OpenType features collected in a set (as listed below) that can be + * hinted together. To continue the above example, superscript glyphs + * must not be hinted together with normal glyphs because the blue zones + * completely differ. On the other hand, superscripts and subscripts + * don't overlap, so they can be combined into a single set. + * + * Note that FreeType itself doesn't compute coverages; it only provides + * the glyphs addressable by the default Unicode character map. Instead, + * we use the HarfBuzz library (if available), which has many functions + * exactly for this purpose. + * + * AF_COVERAGE_DEFAULT is special: It should cover everything that isn't + * listed separately (including the glyphs addressable by the character + * map). In case HarfBuzz isn't available, it exactly covers the glyphs + * addressable by the character map. + * + */ + +#undef COVERAGE_1 +#define COVERAGE_1( name, NAME, description, \ + tag_a1, tag_a2, tag_a3, tag_a4 ) \ + AF_COVERAGE_ ## NAME, + +#undef COVERAGE_2 +#define COVERAGE_2( name, NAME, description, \ + tag_a1, tag_a2, tag_a3, tag_a4, \ + tag_b1, tag_b2, tag_b3, tag_b4 ) \ + AF_COVERAGE_ ## NAME, + +#undef COVERAGE_3 +#define COVERAGE_3( name, NAME, description, \ + tag_a1, tag_a2, tag_a3, tag_a4, \ + tag_b1, tag_b2, tag_b3, tag_b4, \ + tag_c1, tag_c2, tag_c3, tag_c4 ) \ + AF_COVERAGE_ ## NAME, + + + typedef enum AF_Coverage_ + { +#include "afcover.h" + + AF_COVERAGE_DEFAULT + + } AF_Coverage; + + /*************************************************************************/ /*************************************************************************/ /***** *****/ @@ -355,7 +431,7 @@ extern void* _af_debug_hints; */ #undef STYLE -#define STYLE( s, S, d, ws, sc, ss ) \ +#define STYLE( s, S, d, ws, sc, ss, c ) \ AF_STYLE_ ## S, /* The list of known styles. */ @@ -376,6 +452,7 @@ extern void* _af_debug_hints; AF_WritingSystem writing_system; AF_Script script; AF_Blue_Stringset blue_stringset; + AF_Coverage coverage; } AF_StyleClassRec; @@ -466,14 +543,16 @@ extern void* _af_debug_hints; style, \ writing_system, \ script, \ - blue_stringset ) \ + blue_stringset, \ + coverage ) \ FT_CALLBACK_TABLE_DEF \ const AF_StyleClassRec style_class = \ { \ style, \ writing_system, \ script, \ - blue_stringset \ + blue_stringset, \ + coverage \ }; #else /* FT_CONFIG_OPTION_PIC */ @@ -534,7 +613,8 @@ extern void* _af_debug_hints; style_, \ writing_system_, \ script_, \ - blue_stringset_ ) \ + blue_stringset_, \ + coverage_ ) \ FT_LOCAL_DEF( void ) \ FT_Init_Class_ ## style_class( AF_StyleClassRec* ac ) \ { \ @@ -542,6 +622,7 @@ extern void* _af_debug_hints; ac->writing_system = writing_system_; \ ac->script = script_; \ ac->blue_stringset = blue_stringset_; \ + ac->coverage = coverage_; \ } #endif /* FT_CONFIG_OPTION_PIC */ diff --git a/src/autofit/afwrtsys.h b/src/autofit/afwrtsys.h index 602c55884..8aa2ed9e6 100644 --- a/src/autofit/afwrtsys.h +++ b/src/autofit/afwrtsys.h @@ -37,7 +37,8 @@ /* Define `WRITING_SYSTEM' as needed. */ - /* Add new writing systems here. */ + /* Add new writing systems here. The arguments are the writing system */ + /* name in lowercase and uppercase, respectively. */ WRITING_SYSTEM( dummy, DUMMY ) WRITING_SYSTEM( latin, LATIN ) diff --git a/src/autofit/autofit.c b/src/autofit/autofit.c index 930387c54..00c5af3de 100644 --- a/src/autofit/autofit.c +++ b/src/autofit/autofit.c @@ -34,6 +34,10 @@ #include "afcjk.c" #include "afindic.c" +#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ +#include "hbshim.c" +#endif + #include "afloader.c" #include "afmodule.c" diff --git a/src/autofit/hbshim.c b/src/autofit/hbshim.c new file mode 100644 index 000000000..b2731ad6d --- /dev/null +++ b/src/autofit/hbshim.c @@ -0,0 +1,269 @@ +/***************************************************************************/ +/* */ +/* hbshim.c */ +/* */ +/* HarfBuzz interface for accessing OpenType features (body). */ +/* */ +/* Copyright 2013 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#include +#include FT_FREETYPE_H + + +#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ + +#include +#include +#include + + + /*************************************************************************/ + /* */ + /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ + /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ + /* messages during execution. */ + /* */ +#undef FT_COMPONENT +#define FT_COMPONENT trace_afharfbuzz + + + /* + * We use `sets' (in the HarfBuzz sense, which comes quite near to the + * usual mathematical meaning) to manage both lookups and glyph indices. + * + * 1. For each coverage, collect lookup IDs in a set. Note that an + * auto-hinter `coverage' is represented by one or more `feature's, and + * a feature consists of an arbitrary number of (font specific) + * `lookup's that actually do the mapping job. Please check the + * OpenType specification for more details on features and lookups. + * + * 2. Create glyph ID sets from the corresponding lookup sets. + * + * 3. The glyph set corresponding to AF_COVERAGE_DEFAULT is computed + * with all lookups specific to the OpenType script activated. It + * relies on the order of AF_DEFINE_STYLE_CLASS entries so that + * special coverages (like `oldstyle figures') don't get overwritten. + * + */ + + + /* load coverage tags */ +#undef COVERAGE_1 +#define COVERAGE_1( name, NAME, description, \ + tag_a1, tag_a2, tag_a3, tag_a4 ) \ + static const hb_tag_t name ## _coverage[] = \ + { \ + HB_TAG( tag_a1, tag_a2, tag_a3, tag_a4 ), \ + HB_TAG_NONE \ + }; + +#undef COVERAGE_2 +#define COVERAGE_2( name, NAME, description, \ + tag_a1, tag_a2, tag_a3, tag_a4, \ + tag_b1, tag_b2, tag_b3, tag_b4 ) \ + static const hb_tag_t name ## _coverage[] = \ + { \ + HB_TAG( tag_a1, tag_a2, tag_a3, tag_a4 ), \ + HB_TAG( tag_b1, tag_b2, tag_b3, tag_b4 ), \ + HB_TAG_NONE \ + }; + +#undef COVERAGE_3 +#define COVERAGE_3( name, NAME, description, \ + tag_a1, tag_a2, tag_a3, tag_a4, \ + tag_b1, tag_b2, tag_b3, tag_b4, \ + tag_c1, tag_c2, tag_c3, tag_c4 ) \ + static const hb_tag_t name ## _coverage[] = \ + { \ + HB_TAG( tag_a1, tag_a2, tag_a3, tag_a4 ), \ + HB_TAG( tag_b1, tag_b2, tag_b3, tag_b4 ), \ + HB_TAG( tag_c1, tag_c2, tag_c3, tag_c4 ), \ + HB_TAG_NONE \ + }; + + +#include "afcover.h" + + + /* define mapping between coverage tags and AF_Coverage */ +#undef COVERAGE_1 +#define COVERAGE_1( name, NAME, description, \ + tag_a1, tag_a2, tag_a3, tag_a4 ) \ + name ## _coverage, + +#undef COVERAGE_2 +#define COVERAGE_2( name, NAME, description, \ + tag_a1, tag_a2, tag_a3, tag_a4, \ + tag_b1, tag_b2, tag_b3, tag_b4 ) \ + name ## _coverage, + +#undef COVERAGE_3 +#define COVERAGE_3( name, NAME, description, \ + tag_a1, tag_a2, tag_a3, tag_a4, \ + tag_b1, tag_b2, tag_b3, tag_b4, \ + tag_c1, tag_c2, tag_c3, tag_c4 ) \ + name ## _coverage, + + + static const hb_tag_t* coverages[] = + { +#include "afcover.h" + + NULL /* AF_COVERAGE_DEFAULT */ + }; + + + /* load HarfBuzz script tags */ +#undef SCRIPT +#define SCRIPT( s, S, d, h, dc ) h, + + + static const hb_tag_t scripts[] = + { +#include "afscript.h" + }; + + + FT_Error + af_get_coverage( FT_Face ft_face, + AF_StyleClass style_class, + FT_Byte* gstyles ) + { + hb_face_t* face; + + hb_set_t* lookups; /* lookups for a given script */ + hb_set_t* glyphs; /* glyphs covered by lookups */ + + hb_tag_t script; + const hb_tag_t* coverage_tags; + hb_tag_t script_tags[] = { HB_TAG_NONE, + HB_TAG_NONE, + HB_TAG_NONE }; + + hb_codepoint_t idx; +#ifdef FT_DEBUG_LEVEL_TRACE + int count; +#endif + + + if ( !ft_face || !style_class || !gstyles ) + return FT_THROW( Invalid_Argument ); + + face = hb_ft_face_create( ft_face, NULL ); + + lookups = hb_set_create(); + glyphs = hb_set_create(); + + coverage_tags = coverages[style_class->coverage]; + script = scripts[style_class->script]; + + /* Convert a HarfBuzz script tag into the corresponding OpenType */ + /* tag or tags -- some Indic scripts like Devanagari have an old */ + /* and a new set of features. */ + hb_ot_tags_from_script( script, + &script_tags[0], + &script_tags[1] ); + + /* `hb_ot_tags_from_script' usually returns HB_OT_TAG_DEFAULT_SCRIPT */ + /* as the second tag. We change that to HB_TAG_NONE since the */ + /* default script gets handled later on. */ + if ( script_tags[1] == HB_OT_TAG_DEFAULT_SCRIPT ) + script_tags[1] = HB_TAG_NONE; + + hb_ot_layout_collect_lookups( face, + HB_OT_TAG_GSUB, + script_tags, + NULL, + coverage_tags, + lookups ); + + FT_TRACE4(( "lookups (style `%s'):\n" + " ", + af_style_names[style_class->style] )); + +#ifdef FT_DEBUG_LEVEL_TRACE + count = 0; +#endif + + for ( idx = -1; hb_set_next( lookups, &idx ); ) + { +#ifdef FT_DEBUG_LEVEL_TRACE + FT_TRACE4(( " %d", idx )); + count++; +#endif + + hb_ot_layout_lookup_collect_glyphs( face, + HB_OT_TAG_GSUB, + idx, + NULL, + NULL, + NULL, + glyphs ); + } + +#ifdef FT_DEBUG_LEVEL_TRACE + if ( !count ) + FT_TRACE4(( " (none)" )); + FT_TRACE4(( "\n\n" )); + + FT_TRACE4(( " glyphs (`*' means already assigned)" )); + + count = 0; +#endif + + for ( idx = -1; hb_set_next( glyphs, &idx ); ) + { +#ifdef FT_DEBUG_LEVEL_TRACE + if ( !( count % 10 ) ) + FT_TRACE4(( "\n" + " " )); + + FT_TRACE4(( " %d", idx )); + count++; +#endif + + if ( gstyles[idx] == AF_STYLE_UNASSIGNED ) + gstyles[idx] = (FT_Byte)style_class->style; +#ifdef FT_DEBUG_LEVEL_TRACE + else + FT_TRACE4(( "*" )); +#endif + } + +#ifdef FT_DEBUG_LEVEL_TRACE + if ( !count ) + FT_TRACE4(( "\n" + " (none)" )); + FT_TRACE4(( "\n\n" )); +#endif + + hb_set_destroy( lookups ); + hb_set_destroy( glyphs ); + + hb_face_destroy( face ); + + return FT_Err_Ok; + } + + +#if 0 + /* to be always excluded */ + COVERAGE(nalt, 'n', 'a', 'l', 't'); /* Alternate Annotation Forms (?) */ + COVERAGE(ornm, 'o', 'r', 'n', 'm'); /* Ornaments (?) */ + /* COVERAGE(ruby, 'r', 'u', 'b', 'y') */ /* (only for Japanese) */ +#endif + +#endif /* FT_CONFIG_OPTION_USE_HARFBUZZ */ + + +/* END */ diff --git a/src/autofit/hbshim.h b/src/autofit/hbshim.h new file mode 100644 index 000000000..87a771e7a --- /dev/null +++ b/src/autofit/hbshim.h @@ -0,0 +1,47 @@ +/***************************************************************************/ +/* */ +/* hbshim.h */ +/* */ +/* HarfBuzz interface for accessing OpenType features (specification). */ +/* */ +/* Copyright 2013 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 __HBSHIM_H__ +#define __HBSHIM_H__ + + +#include +#include FT_FREETYPE_H + + +#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ + + +FT_BEGIN_HEADER + + FT_Error + af_get_coverage( FT_Face face, + AF_StyleClass style_class, + FT_Byte* gstyles ); + + /* */ + +FT_END_HEADER + + +#endif /* FT_CONFIG_OPTION_USE_HARFBUZZ */ + +#endif /* __HBSHIM_H__ */ + + +/* END */ diff --git a/src/autofit/rules.mk b/src/autofit/rules.mk index 5bf3893ca..658f04ea5 100644 --- a/src/autofit/rules.mk +++ b/src/autofit/rules.mk @@ -37,11 +37,13 @@ AUTOF_DRV_SRC := $(AUTOF_DIR)/afangles.c \ $(AUTOF_DIR)/afmodule.c \ $(AUTOF_DIR)/afpic.c \ $(AUTOF_DIR)/afranges.c \ - $(AUTOF_DIR)/afwarp.c + $(AUTOF_DIR)/afwarp.c \ + $(AUTOF_DIR)/hbshim.c # AUTOF driver headers # AUTOF_DRV_H := $(AUTOF_DRV_SRC:%c=%h) \ + $(AUTOF_DIR)/afcover.h \ $(AUTOF_DIR)/aferrors.h \ $(AUTOF_DIR)/afscript.h \ $(AUTOF_DIR)/afstyles.h \