From 19241347101203f873b47ddc0c17f7144373a986 Mon Sep 17 00:00:00 2001 From: Werner Lemberg Date: Sat, 21 Dec 2013 21:31:38 +0100 Subject: [PATCH] Introduce `coverages'. Coverages are the interface to the HarfBuzz library to access 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. --- ChangeLog | 65 +++++++++ builds/freetype.mk | 9 ++ devel/ftoption.h | 13 ++ include/config/ftoption.h | 13 ++ include/internal/fttrace.h | 1 + src/autofit/afcover.h | 66 +++++++++ src/autofit/afglobal.c | 37 ++--- src/autofit/afglobal.h | 10 +- src/autofit/afmodule.c | 37 ++++- src/autofit/afmodule.h | 2 +- src/autofit/afpic.c | 4 +- src/autofit/afranges.h | 2 +- src/autofit/afscript.h | 13 +- src/autofit/afstyles.h | 40 ++++-- src/autofit/aftypes.h | 91 ++++++++++++- src/autofit/afwrtsys.h | 3 +- src/autofit/autofit.c | 4 + src/autofit/hbshim.c | 269 +++++++++++++++++++++++++++++++++++++ src/autofit/hbshim.h | 47 +++++++ src/autofit/rules.mk | 4 +- 20 files changed, 678 insertions(+), 52 deletions(-) create mode 100644 src/autofit/afcover.h create mode 100644 src/autofit/hbshim.c create mode 100644 src/autofit/hbshim.h 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 \