diff options
Diffstat (limited to 'src/autofit')
-rw-r--r-- | src/autofit/afblue.c | 166 | ||||
-rw-r--r-- | src/autofit/afblue.cin | 39 | ||||
-rw-r--r-- | src/autofit/afblue.dat | 218 | ||||
-rw-r--r-- | src/autofit/afblue.h | 199 | ||||
-rw-r--r-- | src/autofit/afblue.hin | 142 | ||||
-rw-r--r-- | src/autofit/afcjk.c | 614 | ||||
-rw-r--r-- | src/autofit/afcjk.h | 59 | ||||
-rw-r--r-- | src/autofit/afdummy.c | 39 | ||||
-rw-r--r-- | src/autofit/afdummy.h | 10 | ||||
-rw-r--r-- | src/autofit/afglobal.c | 147 | ||||
-rw-r--r-- | src/autofit/afglobal.h | 27 | ||||
-rw-r--r-- | src/autofit/afhints.c | 283 | ||||
-rw-r--r-- | src/autofit/afhints.h | 45 | ||||
-rw-r--r-- | src/autofit/afindic.c | 64 | ||||
-rw-r--r-- | src/autofit/afindic.h | 11 | ||||
-rw-r--r-- | src/autofit/aflatin.c | 486 | ||||
-rw-r--r-- | src/autofit/aflatin.h | 43 | ||||
-rw-r--r-- | src/autofit/aflatin2.c | 72 | ||||
-rw-r--r-- | src/autofit/aflatin2.h | 18 | ||||
-rw-r--r-- | src/autofit/afloader.c | 43 | ||||
-rw-r--r-- | src/autofit/afpic.c | 49 | ||||
-rw-r--r-- | src/autofit/afpic.h | 35 | ||||
-rw-r--r-- | src/autofit/afscript.h | 37 | ||||
-rw-r--r-- | src/autofit/aftypes.h | 287 | ||||
-rw-r--r-- | src/autofit/afwrtsys.h | 51 | ||||
-rw-r--r-- | src/autofit/autofit.c | 3 |
26 files changed, 2355 insertions, 832 deletions
diff --git a/src/autofit/afblue.c b/src/autofit/afblue.c new file mode 100644 index 0000000..22ef6d5 --- /dev/null +++ b/src/autofit/afblue.c @@ -0,0 +1,166 @@ +/* This file has been generated by the Perl script `afblue.pl', */ +/* using data from file `afblue.dat'. */ + +/***************************************************************************/ +/* */ +/* afblue.c */ +/* */ +/* Auto-fitter data for blue strings (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 "aftypes.h" + + + FT_LOCAL_ARRAY_DEF( char ) + af_blue_strings[] = + { + /* */ + 'T', 'H', 'E', 'Z', 'O', 'C', 'Q', 'S', /* THEZOCQS */ + '\0', + 'H', 'E', 'Z', 'L', 'O', 'C', 'U', 'S', /* HEZLOCUS */ + '\0', + 'f', 'i', 'j', 'k', 'd', 'b', 'h', /* fijkdbh */ + '\0', + 'x', 'z', 'r', 'o', 'e', 's', 'c', /* xzroesc */ + '\0', + 'p', 'q', 'g', 'j', 'y', /* pqgjy */ + '\0', + '\xCE', '\x93', '\xCE', '\x92', '\xCE', '\x95', '\xCE', '\x96', '\xCE', '\x98', '\xCE', '\x9F', '\xCE', '\xA9', /* ΓΒΕΖΘΟΩ */ + '\0', + '\xCE', '\x92', '\xCE', '\x94', '\xCE', '\x96', '\xCE', '\x9E', '\xCE', '\x98', '\xCE', '\x9F', /* ΒΔΖΞΘΟ */ + '\0', + '\xCE', '\xB2', '\xCE', '\xB8', '\xCE', '\xB4', '\xCE', '\xB6', '\xCE', '\xBB', '\xCE', '\xBE', /* βθδζλξ */ + '\0', + '\xCE', '\xB1', '\xCE', '\xB5', '\xCE', '\xB9', '\xCE', '\xBF', '\xCF', '\x80', '\xCF', '\x83', '\xCF', '\x84', '\xCF', '\x89', /* αειοπστω */ + '\0', + '\xCE', '\xB2', '\xCE', '\xB3', '\xCE', '\xB7', '\xCE', '\xBC', '\xCF', '\x81', '\xCF', '\x86', '\xCF', '\x87', '\xCF', '\x88', /* βγημρφχψ */ + '\0', + '\xD0', '\x91', '\xD0', '\x92', '\xD0', '\x95', '\xD0', '\x9F', '\xD0', '\x97', '\xD0', '\x9E', '\xD0', '\xA1', '\xD0', '\xAD', /* БВЕПЗОСЭ */ + '\0', + '\xD0', '\x91', '\xD0', '\x92', '\xD0', '\x95', '\xD0', '\xA8', '\xD0', '\x97', '\xD0', '\x9E', '\xD0', '\xA1', '\xD0', '\xAD', /* БВЕШЗОСЭ */ + '\0', + '\xD1', '\x85', '\xD0', '\xBF', '\xD0', '\xBD', '\xD1', '\x88', '\xD0', '\xB5', '\xD0', '\xB7', '\xD0', '\xBE', '\xD1', '\x81', /* хпншезос */ + '\0', + '\xD1', '\x80', '\xD1', '\x83', '\xD1', '\x84', /* руф */ + '\0', + '\xD7', '\x91', '\xD7', '\x93', '\xD7', '\x94', '\xD7', '\x97', '\xD7', '\x9A', '\xD7', '\x9B', '\xD7', '\x9D', '\xD7', '\xA1', /* בדהחךכםס */ + '\0', + '\xD7', '\x91', '\xD7', '\x98', '\xD7', '\x9B', '\xD7', '\x9D', '\xD7', '\xA1', '\xD7', '\xA6', /* בטכםסצ */ + '\0', + '\xD7', '\xA7', '\xD7', '\x9A', '\xD7', '\x9F', '\xD7', '\xA3', '\xD7', '\xA5', /* קךןףץ */ +#ifdef AF_CONFIG_OPTION_CJK + '\0', + '\xE4', '\xBB', '\x96', '\xE4', '\xBB', '\xAC', '\xE4', '\xBD', '\xA0', '\xE4', '\xBE', '\x86', '\xE5', '\x80', '\x91', '\xE5', '\x88', '\xB0', '\xE5', '\x92', '\x8C', '\xE5', '\x9C', '\xB0', /* 他们你來們到和地 */ + '\xE5', '\xAF', '\xB9', '\xE5', '\xB0', '\x8D', '\xE5', '\xB0', '\xB1', '\xE5', '\xB8', '\xAD', '\xE6', '\x88', '\x91', '\xE6', '\x97', '\xB6', '\xE6', '\x99', '\x82', '\xE6', '\x9C', '\x83', /* 对對就席我时時會 */ + '\xE6', '\x9D', '\xA5', '\xE7', '\x82', '\xBA', '\xE8', '\x83', '\xBD', '\xE8', '\x88', '\xB0', '\xE8', '\xAA', '\xAA', '\xE8', '\xAF', '\xB4', '\xE8', '\xBF', '\x99', '\xE9', '\x80', '\x99', /* 来為能舰說说这這 */ + '\xE9', '\xBD', '\x8A', /* 齊 */ + '\0', + '\xE5', '\x86', '\x9B', '\xE5', '\x90', '\x8C', '\xE5', '\xB7', '\xB2', '\xE6', '\x84', '\xBF', '\xE6', '\x97', '\xA2', '\xE6', '\x98', '\x9F', '\xE6', '\x98', '\xAF', '\xE6', '\x99', '\xAF', /* 军同已愿既星是景 */ + '\xE6', '\xB0', '\x91', '\xE7', '\x85', '\xA7', '\xE7', '\x8E', '\xB0', '\xE7', '\x8F', '\xBE', '\xE7', '\x90', '\x86', '\xE7', '\x94', '\xA8', '\xE7', '\xBD', '\xAE', '\xE8', '\xA6', '\x81', /* 民照现現理用置要 */ + '\xE8', '\xBB', '\x8D', '\xE9', '\x82', '\xA3', '\xE9', '\x85', '\x8D', '\xE9', '\x87', '\x8C', '\xE9', '\x96', '\x8B', '\xE9', '\x9B', '\xB7', '\xE9', '\x9C', '\xB2', '\xE9', '\x9D', '\xA2', /* 軍那配里開雷露面 */ + '\xE9', '\xA1', '\xBE', /* 顾 */ + '\0', + '\xE4', '\xB8', '\xAA', '\xE4', '\xB8', '\xBA', '\xE4', '\xBA', '\xBA', '\xE4', '\xBB', '\x96', '\xE4', '\xBB', '\xA5', '\xE4', '\xBB', '\xAC', '\xE4', '\xBD', '\xA0', '\xE4', '\xBE', '\x86', /* 个为人他以们你來 */ + '\xE5', '\x80', '\x8B', '\xE5', '\x80', '\x91', '\xE5', '\x88', '\xB0', '\xE5', '\x92', '\x8C', '\xE5', '\xA4', '\xA7', '\xE5', '\xAF', '\xB9', '\xE5', '\xB0', '\x8D', '\xE5', '\xB0', '\xB1', /* 個們到和大对對就 */ + '\xE6', '\x88', '\x91', '\xE6', '\x97', '\xB6', '\xE6', '\x99', '\x82', '\xE6', '\x9C', '\x89', '\xE6', '\x9D', '\xA5', '\xE7', '\x82', '\xBA', '\xE8', '\xA6', '\x81', '\xE8', '\xAA', '\xAA', /* 我时時有来為要說 */ + '\xE8', '\xAF', '\xB4', /* 说 */ + '\0', + '\xE4', '\xB8', '\xBB', '\xE4', '\xBA', '\x9B', '\xE5', '\x9B', '\xA0', '\xE5', '\xAE', '\x83', '\xE6', '\x83', '\xB3', '\xE6', '\x84', '\x8F', '\xE7', '\x90', '\x86', '\xE7', '\x94', '\x9F', /* 主些因它想意理生 */ + '\xE7', '\x95', '\xB6', '\xE7', '\x9C', '\x8B', '\xE7', '\x9D', '\x80', '\xE7', '\xBD', '\xAE', '\xE8', '\x80', '\x85', '\xE8', '\x87', '\xAA', '\xE8', '\x91', '\x97', '\xE8', '\xA3', '\xA1', /* 當看着置者自著裡 */ + '\xE8', '\xBF', '\x87', '\xE8', '\xBF', '\x98', '\xE8', '\xBF', '\x9B', '\xE9', '\x80', '\xB2', '\xE9', '\x81', '\x8E', '\xE9', '\x81', '\x93', '\xE9', '\x82', '\x84', '\xE9', '\x87', '\x8C', /* 过还进進過道還里 */ + '\xE9', '\x9D', '\xA2', /* 面 */ +#ifdef AF_CONFIG_OPTION_CJK_BLUE_HANI_VERT + '\0', + '\xE4', '\xBA', '\x9B', '\xE4', '\xBB', '\xAC', '\xE4', '\xBD', '\xA0', '\xE4', '\xBE', '\x86', '\xE5', '\x80', '\x91', '\xE5', '\x88', '\xB0', '\xE5', '\x92', '\x8C', '\xE5', '\x9C', '\xB0', /* 些们你來們到和地 */ + '\xE5', '\xA5', '\xB9', '\xE5', '\xB0', '\x86', '\xE5', '\xB0', '\x87', '\xE5', '\xB0', '\xB1', '\xE5', '\xB9', '\xB4', '\xE5', '\xBE', '\x97', '\xE6', '\x83', '\x85', '\xE6', '\x9C', '\x80', /* 她将將就年得情最 */ + '\xE6', '\xA0', '\xB7', '\xE6', '\xA8', '\xA3', '\xE7', '\x90', '\x86', '\xE8', '\x83', '\xBD', '\xE8', '\xAA', '\xAA', '\xE8', '\xAF', '\xB4', '\xE8', '\xBF', '\x99', '\xE9', '\x80', '\x99', /* 样樣理能說说这這 */ + '\xE9', '\x80', '\x9A', /* 通 */ + '\0', + '\xE5', '\x8D', '\xB3', '\xE5', '\x90', '\x97', '\xE5', '\x90', '\xA7', '\xE5', '\x90', '\xAC', '\xE5', '\x91', '\xA2', '\xE5', '\x93', '\x81', '\xE5', '\x93', '\x8D', '\xE5', '\x97', '\x8E', /* 即吗吧听呢品响嗎 */ + '\xE5', '\xB8', '\x88', '\xE5', '\xB8', '\xAB', '\xE6', '\x94', '\xB6', '\xE6', '\x96', '\xAD', '\xE6', '\x96', '\xB7', '\xE6', '\x98', '\x8E', '\xE7', '\x9C', '\xBC', '\xE9', '\x96', '\x93', /* 师師收断斷明眼間 */ + '\xE9', '\x97', '\xB4', '\xE9', '\x99', '\x85', '\xE9', '\x99', '\x88', '\xE9', '\x99', '\x90', '\xE9', '\x99', '\xA4', '\xE9', '\x99', '\xB3', '\xE9', '\x9A', '\x8F', '\xE9', '\x9A', '\x9B', /* 间际陈限除陳随際 */ + '\xE9', '\x9A', '\xA8', /* 隨 */ + '\0', + '\xE4', '\xBA', '\x8B', '\xE5', '\x89', '\x8D', '\xE5', '\xAD', '\xB8', '\xE5', '\xB0', '\x86', '\xE5', '\xB0', '\x87', '\xE6', '\x83', '\x85', '\xE6', '\x83', '\xB3', '\xE6', '\x88', '\x96', /* 事前學将將情想或 */ + '\xE6', '\x94', '\xBF', '\xE6', '\x96', '\xAF', '\xE6', '\x96', '\xB0', '\xE6', '\xA0', '\xB7', '\xE6', '\xA8', '\xA3', '\xE6', '\xB0', '\x91', '\xE6', '\xB2', '\x92', '\xE6', '\xB2', '\xA1', /* 政斯新样樣民沒没 */ + '\xE7', '\x84', '\xB6', '\xE7', '\x89', '\xB9', '\xE7', '\x8E', '\xB0', '\xE7', '\x8F', '\xBE', '\xE7', '\x90', '\x83', '\xE7', '\xAC', '\xAC', '\xE7', '\xB6', '\x93', '\xE8', '\xB0', '\x81', /* 然特现現球第經谁 */ + '\xE8', '\xB5', '\xB7', /* 起 */ + '\0', + '\xE4', '\xBE', '\x8B', '\xE5', '\x88', '\xA5', '\xE5', '\x88', '\xAB', '\xE5', '\x88', '\xB6', '\xE5', '\x8A', '\xA8', '\xE5', '\x8B', '\x95', '\xE5', '\x90', '\x97', '\xE5', '\x97', '\x8E', /* 例別别制动動吗嗎 */ + '\xE5', '\xA2', '\x9E', '\xE6', '\x8C', '\x87', '\xE6', '\x98', '\x8E', '\xE6', '\x9C', '\x9D', '\xE6', '\x9C', '\x9F', '\xE6', '\x9E', '\x84', '\xE7', '\x89', '\xA9', '\xE7', '\xA1', '\xAE', /* 增指明朝期构物确 */ + '\xE7', '\xA7', '\x8D', '\xE8', '\xAA', '\xBF', '\xE8', '\xB0', '\x83', '\xE8', '\xB2', '\xBB', '\xE8', '\xB4', '\xB9', '\xE9', '\x82', '\xA3', '\xE9', '\x83', '\xBD', '\xE9', '\x96', '\x93', /* 种調调費费那都間 */ + '\xE9', '\x97', '\xB4', /* 间 */ +#endif /* AF_CONFIG_OPTION_CJK_BLUE_HANI_VERT */ +#endif /* AF_CONFIG_OPTION_CJK */ + '\0', + + }; + + + /* stringsets are specific to scripts */ + FT_LOCAL_ARRAY_DEF( AF_Blue_StringRec ) + af_blue_stringsets[] = + { + /* */ + { AF_BLUE_STRING_LATIN_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_LATIN_CAPITAL_BOTTOM, 0 }, + { AF_BLUE_STRING_LATIN_SMALL_F_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_LATIN_SMALL, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, + { AF_BLUE_STRING_LATIN_SMALL, 0 }, + { AF_BLUE_STRING_LATIN_SMALL_DESCENDER, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_GREEK_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_GREEK_CAPITAL_BOTTOM, 0 }, + { AF_BLUE_STRING_GREEK_SMALL_BETA_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_GREEK_SMALL, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, + { AF_BLUE_STRING_GREEK_SMALL, 0 }, + { AF_BLUE_STRING_GREEK_SMALL_DESCENDER, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_CYRILLIC_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_CYRILLIC_CAPITAL_BOTTOM, 0 }, + { AF_BLUE_STRING_CYRILLIC_SMALL, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, + { AF_BLUE_STRING_CYRILLIC_SMALL, 0 }, + { AF_BLUE_STRING_CYRILLIC_SMALL_DESCENDER, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_HEBREW_TOP, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_LONG }, + { AF_BLUE_STRING_HEBREW_BOTTOM, 0 }, + { AF_BLUE_STRING_HEBREW_DESCENDER, 0 }, + { AF_BLUE_STRING_MAX, 0 }, +#ifdef AF_CONFIG_OPTION_CJK + { AF_BLUE_STRING_CJK_TOP_FILL, AF_BLUE_PROPERTY_CJK_TOP | + AF_BLUE_PROPERTY_CJK_FILL }, + { AF_BLUE_STRING_CJK_TOP_UNFILL, AF_BLUE_PROPERTY_CJK_TOP }, + { AF_BLUE_STRING_CJK_BOTTOM_FILL, AF_BLUE_PROPERTY_CJK_FILL }, + { AF_BLUE_STRING_CJK_BOTTOM_UNFILL, 0 }, +#ifdef AF_CONFIG_OPTION_CJK_BLUE_HANI_VERT + { AF_BLUE_STRING_CJK_LEFT_FILL, AF_BLUE_PROPERTY_CJK_HORIZ | + AF_BLUE_PROPERTY_CJK_FILL }, + { AF_BLUE_STRING_CJK_LEFT_UNFILL, AF_BLUE_PROPERTY_CJK_HORIZ }, + { AF_BLUE_STRING_CJK_RIGHT_FILL, AF_BLUE_PROPERTY_CJK_HORIZ | + AF_BLUE_PROPERTY_CJK_RIGHT | + AF_BLUE_PROPERTY_CJK_FILL }, + { AF_BLUE_STRING_CJK_RIGHT_UNFILL, AF_BLUE_PROPERTY_CJK_HORIZ | + AF_BLUE_PROPERTY_CJK_RIGHT }, +#endif /* AF_CONFIG_OPTION_CJK_BLUE_HANI_VERT */ + { AF_BLUE_STRING_MAX, 0 }, +#endif /* AF_CONFIG_OPTION_CJK */ + + }; + + +/* END */ diff --git a/src/autofit/afblue.cin b/src/autofit/afblue.cin new file mode 100644 index 0000000..c693d89 --- /dev/null +++ b/src/autofit/afblue.cin @@ -0,0 +1,39 @@ +/***************************************************************************/ +/* */ +/* afblue.c */ +/* */ +/* Auto-fitter data for blue strings (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 "aftypes.h" + + + FT_LOCAL_ARRAY_DEF( char ) + af_blue_strings[] = + { + /* */ +@AF_BLUE_STRINGS_ARRAY@ + }; + + + /* stringsets are specific to scripts */ + FT_LOCAL_ARRAY_DEF( AF_Blue_StringRec ) + af_blue_stringsets[] = + { + /* */ +@AF_BLUE_STRINGSETS_ARRAY@ + }; + + +/* END */ diff --git a/src/autofit/afblue.dat b/src/autofit/afblue.dat new file mode 100644 index 0000000..d488f3f --- /dev/null +++ b/src/autofit/afblue.dat @@ -0,0 +1,218 @@ +// afblue.dat +// +// Auto-fitter data for blue strings. +// +// 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 file contains data specific to blue zones. It gets processed by +// a script to simulate `jagged arrays', with enumeration values holding +// offsets into the arrays. +// +// The format of the file is rather simple: A section starts with three +// labels separated by whitespace and followed by a colon (everything in a +// single line); the first label gives the name of the enumeration template, +// the second the name of the array template, and the third the name of the +// `maximum' template, holding the size of the largest array element. The +// script then fills the corresponding templates (indicated by `@' +// characters around the name). +// +// A section contains one or more data records. Each data record consists +// of two or more lines. The first line holds the enumeration name, and the +// remaining lines the corresponding array data. +// +// There are two possible representations for array data. +// +// - A string of characters in UTF-8 encoding enclosed in double quotes, +// using C syntax. There can be only one string per line, thus the +// starting and ending double quote must be the first and last character +// in the line, respectively, ignoring whitespace before and after the +// string. If there are multiple strings (in multiple lines), they are +// concatenated to a single string. In the output, a string gets +// represented as a series of singles bytes, followed by a zero byte. The +// enumeration values simply hold byte offsets to the start of the +// corresponding strings. +// +// - Data blocks enclosed in balanced braces, which get copied verbatim and +// which can span multiple lines. The opening brace of a block must be +// the first character of a line (ignoring whitespace), and the closing +// brace the last (ignoring whitespace also). The script appends a comma +// character after each block and counts the number of blocks to set the +// enumeration values. +// +// A section can contain either strings only or data blocks only. +// +// A comment line starts with `//'; it gets removed. A preprocessor +// directive line (using the standard syntax of `cpp') starts with `#' and +// gets copied verbatim to both the enumeration and the array. Whitespace +// outside of a string is insignificant. +// +// Preprocessor directives are ignored while the script computes maximum +// values; this essentially means that the maximum values can easily be too +// large. Given that the purpose of those values is to create local +// fixed-size arrays at compile time for further processing of the blue zone +// data, this isn't a problem. Note the the final zero byte of a string is +// not counted. Note also that the count holds the number of UTF-8 encoded +// characters, not bytes. + + +AF_BLUE_STRING_ENUM AF_BLUE_STRINGS_ARRAY AF_BLUE_STRING_MAX_LEN: + + AF_BLUE_STRING_LATIN_CAPITAL_TOP + "THEZOCQS" + AF_BLUE_STRING_LATIN_CAPITAL_BOTTOM + "HEZLOCUS" + AF_BLUE_STRING_LATIN_SMALL_F_TOP + "fijkdbh" + AF_BLUE_STRING_LATIN_SMALL + "xzroesc" + AF_BLUE_STRING_LATIN_SMALL_DESCENDER + "pqgjy" + + AF_BLUE_STRING_GREEK_CAPITAL_TOP + "ΓΒΕΖΘΟΩ" + AF_BLUE_STRING_GREEK_CAPITAL_BOTTOM + "ΒΔΖΞΘΟ" + AF_BLUE_STRING_GREEK_SMALL_BETA_TOP + "βθδζλξ" + AF_BLUE_STRING_GREEK_SMALL + "αειοπστω" + AF_BLUE_STRING_GREEK_SMALL_DESCENDER + "βγημρφχψ" + + AF_BLUE_STRING_CYRILLIC_CAPITAL_TOP + "БВЕПЗОСЭ" + AF_BLUE_STRING_CYRILLIC_CAPITAL_BOTTOM + "БВЕШЗОСЭ" + AF_BLUE_STRING_CYRILLIC_SMALL + "хпншезос" + AF_BLUE_STRING_CYRILLIC_SMALL_DESCENDER + "руф" + + AF_BLUE_STRING_HEBREW_TOP + "בדהחךכםס" + AF_BLUE_STRING_HEBREW_BOTTOM + "בטכםסצ" + AF_BLUE_STRING_HEBREW_DESCENDER + "קךןףץ" + +#ifdef AF_CONFIG_OPTION_CJK + + AF_BLUE_STRING_CJK_TOP_FILL + "他们你來們到和地" + "对對就席我时時會" + "来為能舰說说这這" + "齊" + AF_BLUE_STRING_CJK_TOP_UNFILL + "军同已愿既星是景" + "民照现現理用置要" + "軍那配里開雷露面" + "顾" + AF_BLUE_STRING_CJK_BOTTOM_FILL + "个为人他以们你來" + "個們到和大对對就" + "我时時有来為要說" + "说" + AF_BLUE_STRING_CJK_BOTTOM_UNFILL + "主些因它想意理生" + "當看着置者自著裡" + "过还进進過道還里" + "面" + +#ifdef AF_CONFIG_OPTION_CJK_BLUE_HANI_VERT + + AF_BLUE_STRING_CJK_LEFT_FILL + "些们你來們到和地" + "她将將就年得情最" + "样樣理能說说这這" + "通" + AF_BLUE_STRING_CJK_LEFT_UNFILL + "即吗吧听呢品响嗎" + "师師收断斷明眼間" + "间际陈限除陳随際" + "隨" + AF_BLUE_STRING_CJK_RIGHT_FILL + "事前學将將情想或" + "政斯新样樣民沒没" + "然特现現球第經谁" + "起" + AF_BLUE_STRING_CJK_RIGHT_UNFILL + "例別别制动動吗嗎" + "增指明朝期构物确" + "种調调費费那都間" + "间" + +#endif /* AF_CONFIG_OPTION_CJK_BLUE_HANI_VERT */ + +#endif /* AF_CONFIG_OPTION_CJK */ + + +AF_BLUE_STRINGSET_ENUM AF_BLUE_STRINGSETS_ARRAY AF_BLUE_STRINGSET_MAX_LEN: + + AF_BLUE_STRINGSET_LATN + { AF_BLUE_STRING_LATIN_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_LATIN_CAPITAL_BOTTOM, 0 } + { AF_BLUE_STRING_LATIN_SMALL_F_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_LATIN_SMALL, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT } + { AF_BLUE_STRING_LATIN_SMALL, 0 } + { AF_BLUE_STRING_LATIN_SMALL_DESCENDER, 0 } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_GREK + { AF_BLUE_STRING_GREEK_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_GREEK_CAPITAL_BOTTOM, 0 } + { AF_BLUE_STRING_GREEK_SMALL_BETA_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_GREEK_SMALL, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT } + { AF_BLUE_STRING_GREEK_SMALL, 0 } + { AF_BLUE_STRING_GREEK_SMALL_DESCENDER, 0 } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_CYRL + { AF_BLUE_STRING_CYRILLIC_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_CYRILLIC_CAPITAL_BOTTOM, 0 } + { AF_BLUE_STRING_CYRILLIC_SMALL, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT } + { AF_BLUE_STRING_CYRILLIC_SMALL, 0 } + { AF_BLUE_STRING_CYRILLIC_SMALL_DESCENDER, 0 } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_HEBR + { AF_BLUE_STRING_HEBREW_TOP, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_LONG } + { AF_BLUE_STRING_HEBREW_BOTTOM, 0 } + { AF_BLUE_STRING_HEBREW_DESCENDER, 0 } + { AF_BLUE_STRING_MAX, 0 } + +#ifdef AF_CONFIG_OPTION_CJK + + AF_BLUE_STRINGSET_HANI + { AF_BLUE_STRING_CJK_TOP_FILL, AF_BLUE_PROPERTY_CJK_TOP | + AF_BLUE_PROPERTY_CJK_FILL } + { AF_BLUE_STRING_CJK_TOP_UNFILL, AF_BLUE_PROPERTY_CJK_TOP } + { AF_BLUE_STRING_CJK_BOTTOM_FILL, AF_BLUE_PROPERTY_CJK_FILL } + { AF_BLUE_STRING_CJK_BOTTOM_UNFILL, 0 } +#ifdef AF_CONFIG_OPTION_CJK_BLUE_HANI_VERT + { AF_BLUE_STRING_CJK_LEFT_FILL, AF_BLUE_PROPERTY_CJK_HORIZ | + AF_BLUE_PROPERTY_CJK_FILL } + { AF_BLUE_STRING_CJK_LEFT_UNFILL, AF_BLUE_PROPERTY_CJK_HORIZ } + { AF_BLUE_STRING_CJK_RIGHT_FILL, AF_BLUE_PROPERTY_CJK_HORIZ | + AF_BLUE_PROPERTY_CJK_RIGHT | + AF_BLUE_PROPERTY_CJK_FILL } + { AF_BLUE_STRING_CJK_RIGHT_UNFILL, AF_BLUE_PROPERTY_CJK_HORIZ | + AF_BLUE_PROPERTY_CJK_RIGHT } +#endif /* AF_CONFIG_OPTION_CJK_BLUE_HANI_VERT */ + { AF_BLUE_STRING_MAX, 0 } + +#endif /* AF_CONFIG_OPTION_CJK */ + + +// END diff --git a/src/autofit/afblue.h b/src/autofit/afblue.h new file mode 100644 index 0000000..86a3649 --- /dev/null +++ b/src/autofit/afblue.h @@ -0,0 +1,199 @@ +/* This file has been generated by the Perl script `afblue.pl', */ +/* using data from file `afblue.dat'. */ + +/***************************************************************************/ +/* */ +/* afblue.h */ +/* */ +/* Auto-fitter data for blue strings (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 __AFBLUE_H__ +#define __AFBLUE_H__ + + +FT_BEGIN_HEADER + + + /* an auxiliary macro to decode a UTF-8 character -- since we only use */ + /* hard-coded, self-converted data, no error checking is performed */ +#define GET_UTF8_CHAR( ch, p ) \ + ch = (unsigned char)*p++; \ + if ( ch >= 0x80 ) \ + { \ + FT_UInt len; \ + \ + \ + if ( ch < 0xE0 ) \ + { \ + len = 1; \ + ch &= 0x1F; \ + } \ + else if ( ch < 0xF0 ) \ + { \ + len = 2; \ + ch &= 0x0F; \ + } \ + else \ + { \ + len = 3; \ + ch &= 0x07; \ + } \ + \ + for ( ; len > 0; len-- ) \ + ch = ( ch << 6 ) | ( *p++ & 0x3F ); \ + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** B L U E S T R I N G S *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* At the bottommost level, we define strings for finding blue zones. */ + + +#define AF_BLUE_STRING_MAX_LEN 25 + + /* The AF_Blue_String enumeration values are offsets into the */ + /* `af_blue_strings' array. */ + + typedef enum AF_Blue_String_ + { + AF_BLUE_STRING_LATIN_CAPITAL_TOP = 0, + AF_BLUE_STRING_LATIN_CAPITAL_BOTTOM = 9, + AF_BLUE_STRING_LATIN_SMALL_F_TOP = 18, + AF_BLUE_STRING_LATIN_SMALL = 26, + AF_BLUE_STRING_LATIN_SMALL_DESCENDER = 34, + AF_BLUE_STRING_GREEK_CAPITAL_TOP = 40, + AF_BLUE_STRING_GREEK_CAPITAL_BOTTOM = 55, + AF_BLUE_STRING_GREEK_SMALL_BETA_TOP = 68, + AF_BLUE_STRING_GREEK_SMALL = 81, + AF_BLUE_STRING_GREEK_SMALL_DESCENDER = 98, + AF_BLUE_STRING_CYRILLIC_CAPITAL_TOP = 115, + AF_BLUE_STRING_CYRILLIC_CAPITAL_BOTTOM = 132, + AF_BLUE_STRING_CYRILLIC_SMALL = 149, + AF_BLUE_STRING_CYRILLIC_SMALL_DESCENDER = 166, + AF_BLUE_STRING_HEBREW_TOP = 173, + AF_BLUE_STRING_HEBREW_BOTTOM = 190, + AF_BLUE_STRING_HEBREW_DESCENDER = 203, + af_blue_1_1 = 213, +#ifdef AF_CONFIG_OPTION_CJK + AF_BLUE_STRING_CJK_TOP_FILL = af_blue_1_1 + 1, + AF_BLUE_STRING_CJK_TOP_UNFILL = af_blue_1_1 + 77, + AF_BLUE_STRING_CJK_BOTTOM_FILL = af_blue_1_1 + 153, + AF_BLUE_STRING_CJK_BOTTOM_UNFILL = af_blue_1_1 + 229, + af_blue_1_1_1 = af_blue_1_1 + 304, +#ifdef AF_CONFIG_OPTION_CJK_BLUE_HANI_VERT + AF_BLUE_STRING_CJK_LEFT_FILL = af_blue_1_1_1 + 1, + AF_BLUE_STRING_CJK_LEFT_UNFILL = af_blue_1_1_1 + 77, + AF_BLUE_STRING_CJK_RIGHT_FILL = af_blue_1_1_1 + 153, + AF_BLUE_STRING_CJK_RIGHT_UNFILL = af_blue_1_1_1 + 229, + af_blue_1_2_1 = af_blue_1_1_1 + 304, +#else + af_blue_1_2_1 = af_blue_1_1_1 + 0, +#endif /* AF_CONFIG_OPTION_CJK_BLUE_HANI_VERT */ + af_blue_1_2 = af_blue_1_2_1 + 0, +#else + af_blue_1_2 = af_blue_1_2_1 + 0, +#endif /* AF_CONFIG_OPTION_CJK */ + + + AF_BLUE_STRING_MAX /* do not remove */ + + } AF_Blue_String; + + + FT_LOCAL_ARRAY( char ) + af_blue_strings[]; + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** B L U E S T R I N G S E T S *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* The next level is to group blue strings into script-specific sets. */ + + + /* Properties are specific to a writing system. We assume that a given */ + /* blue string can't be used in more than a single writing system, which */ + /* is a safe bet. */ +#define AF_BLUE_PROPERTY_LATIN_TOP ( 1 << 0 ) +#define AF_BLUE_PROPERTY_LATIN_X_HEIGHT ( 1 << 1 ) +#define AF_BLUE_PROPERTY_LATIN_LONG ( 1 << 2 ) + +#define AF_BLUE_PROPERTY_CJK_HORIZ ( 1 << 0 ) +#define AF_BLUE_PROPERTY_CJK_TOP ( 1 << 1 ) +#define AF_BLUE_PROPERTY_CJK_FILL ( 1 << 2 ) +#define AF_BLUE_PROPERTY_CJK_RIGHT AF_BLUE_PROPERTY_CJK_TOP + + +#define AF_BLUE_STRINGSET_MAX_LEN 9 + + /* The AF_Blue_Stringset enumeration values are offsets into the */ + /* `af_blue_stringsets' array. */ + + typedef enum AF_Blue_Stringset_ + { + AF_BLUE_STRINGSET_LATN = 0, + AF_BLUE_STRINGSET_GREK = 7, + AF_BLUE_STRINGSET_CYRL = 14, + AF_BLUE_STRINGSET_HEBR = 20, + af_blue_2_1 = 24, +#ifdef AF_CONFIG_OPTION_CJK + AF_BLUE_STRINGSET_HANI = af_blue_2_1 + 0, + af_blue_2_1_1 = af_blue_2_1 + 4, +#ifdef AF_CONFIG_OPTION_CJK_BLUE_HANI_VERT + af_blue_2_2_1 = af_blue_2_1_1 + 4, +#else + af_blue_2_2_1 = af_blue_2_1_1 + 0, +#endif /* AF_CONFIG_OPTION_CJK_BLUE_HANI_VERT */ + af_blue_2_2 = af_blue_2_2_1 + 1, +#else + af_blue_2_2 = af_blue_2_2_1 + 0, +#endif /* AF_CONFIG_OPTION_CJK */ + + + AF_BLUE_STRINGSET_MAX /* do not remove */ + + } AF_Blue_Stringset; + + + typedef struct AF_Blue_StringRec_ + { + AF_Blue_String string; + FT_UShort properties; + + } AF_Blue_StringRec; + + + FT_LOCAL_ARRAY( AF_Blue_StringRec ) + af_blue_stringsets[]; + +/* */ + +FT_END_HEADER + + +#endif /* __AFBLUE_H__ */ + + +/* END */ diff --git a/src/autofit/afblue.hin b/src/autofit/afblue.hin new file mode 100644 index 0000000..00282c3 --- /dev/null +++ b/src/autofit/afblue.hin @@ -0,0 +1,142 @@ +/***************************************************************************/ +/* */ +/* afblue.h */ +/* */ +/* Auto-fitter data for blue strings (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 __AFBLUE_H__ +#define __AFBLUE_H__ + + +FT_BEGIN_HEADER + + + /* an auxiliary macro to decode a UTF-8 character -- since we only use */ + /* hard-coded, self-converted data, no error checking is performed */ +#define GET_UTF8_CHAR( ch, p ) \ + ch = (unsigned char)*p++; \ + if ( ch >= 0x80 ) \ + { \ + FT_UInt len; \ + \ + \ + if ( ch < 0xE0 ) \ + { \ + len = 1; \ + ch &= 0x1F; \ + } \ + else if ( ch < 0xF0 ) \ + { \ + len = 2; \ + ch &= 0x0F; \ + } \ + else \ + { \ + len = 3; \ + ch &= 0x07; \ + } \ + \ + for ( ; len > 0; len-- ) \ + ch = ( ch << 6 ) | ( *p++ & 0x3F ); \ + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** B L U E S T R I N G S *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* At the bottommost level, we define strings for finding blue zones. */ + + +#define AF_BLUE_STRING_MAX_LEN @AF_BLUE_STRING_MAX_LEN@ + + /* The AF_Blue_String enumeration values are offsets into the */ + /* `af_blue_strings' array. */ + + typedef enum AF_Blue_String_ + { +@AF_BLUE_STRING_ENUM@ + + AF_BLUE_STRING_MAX /* do not remove */ + + } AF_Blue_String; + + + FT_LOCAL_ARRAY( char ) + af_blue_strings[]; + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** B L U E S T R I N G S E T S *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* The next level is to group blue strings into script-specific sets. */ + + + /* Properties are specific to a writing system. We assume that a given */ + /* blue string can't be used in more than a single writing system, which */ + /* is a safe bet. */ +#define AF_BLUE_PROPERTY_LATIN_TOP ( 1 << 0 ) +#define AF_BLUE_PROPERTY_LATIN_X_HEIGHT ( 1 << 1 ) +#define AF_BLUE_PROPERTY_LATIN_LONG ( 1 << 2 ) + +#define AF_BLUE_PROPERTY_CJK_HORIZ ( 1 << 0 ) +#define AF_BLUE_PROPERTY_CJK_TOP ( 1 << 1 ) +#define AF_BLUE_PROPERTY_CJK_FILL ( 1 << 2 ) +#define AF_BLUE_PROPERTY_CJK_RIGHT AF_BLUE_PROPERTY_CJK_TOP + + +#define AF_BLUE_STRINGSET_MAX_LEN @AF_BLUE_STRINGSET_MAX_LEN@ + + /* The AF_Blue_Stringset enumeration values are offsets into the */ + /* `af_blue_stringsets' array. */ + + typedef enum AF_Blue_Stringset_ + { +@AF_BLUE_STRINGSET_ENUM@ + + AF_BLUE_STRINGSET_MAX /* do not remove */ + + } AF_Blue_Stringset; + + + typedef struct AF_Blue_StringRec_ + { + AF_Blue_String string; + FT_UShort properties; + + } AF_Blue_StringRec; + + + FT_LOCAL_ARRAY( AF_Blue_StringRec ) + af_blue_stringsets[]; + +/* */ + +FT_END_HEADER + + +#endif /* __AFBLUE_H__ */ + + +/* END */ diff --git a/src/autofit/afcjk.c b/src/autofit/afcjk.c index f69a528..7a6f835 100644 --- a/src/autofit/afcjk.c +++ b/src/autofit/afcjk.c @@ -26,7 +26,7 @@ #include FT_ADVANCES_H #include FT_INTERNAL_DEBUG_H -#include "aftypes.h" +#include "afglobal.h" #include "aflatin.h" @@ -73,6 +73,12 @@ AF_GlyphHintsRec hints[1]; + FT_TRACE5(( "\n" + "cjk standard widths computation (script `%s')\n" + "===============================================\n" + "\n", + af_script_names[metrics->root.script_class->script] )); + af_glyph_hints_init( hints, face->memory ); metrics->axis[AF_DIMENSION_HORZ].width_count = 0; @@ -86,11 +92,15 @@ AF_Scaler scaler = &dummy->root.scaler; - glyph_index = FT_Get_Char_Index( face, - metrics->root.clazz->standard_char ); + glyph_index = FT_Get_Char_Index( + face, + metrics->root.script_class->standard_char ); if ( glyph_index == 0 ) goto Exit; + FT_TRACE5(( "standard character: U+%04lX (glyph index %d)\n", + metrics->root.script_class->standard_char, glyph_index )); + error = FT_Load_Glyph( face, glyph_index, FT_LOAD_NO_SCALE ); if ( error || face->glyph->outline.n_points <= 0 ) goto Exit; @@ -122,11 +132,13 @@ FT_UInt num_widths = 0; - error = af_latin_hints_compute_segments( hints, (AF_Dimension)dim ); + error = af_latin_hints_compute_segments( hints, + (AF_Dimension)dim ); if ( error ) goto Exit; - af_latin_hints_link_segments( hints, (AF_Dimension)dim ); + af_latin_hints_link_segments( hints, + (AF_Dimension)dim ); seg = axhints->segments; limit = seg + axhints->num_segments; @@ -151,7 +163,7 @@ } /* this also replaces multiple almost identical stem widths */ - /* with a single one (the value 100 is heuristic) */ + /* with a single one (the value 100 is heuristic) */ af_sort_and_quantize_widths( &num_widths, axis->widths, dummy->units_per_em / 100 ); axis->width_count = num_widths; @@ -171,263 +183,201 @@ axis->edge_distance_threshold = stdw / 5; axis->standard_width = stdw; axis->extra_light = 0; - } - } - - af_glyph_hints_done( hints ); - } - - -#define AF_CJK_MAX_TEST_CHARACTERS 32 +#ifdef FT_DEBUG_LEVEL_TRACE + { + FT_UInt i; - /* Each blue zone has two types of fill and unfill, this is, */ - /* filling the entire glyph square or not. */ - enum - { - AF_CJK_BLUE_TYPE_FILL, - AF_CJK_BLUE_TYPE_UNFILL, - AF_CJK_BLUE_TYPE_MAX - }; + FT_TRACE5(( "%s widths:\n", + dim == AF_DIMENSION_VERT ? "horizontal" + : "vertical" )); + FT_TRACE5(( " %d (standard)", axis->standard_width )); + for ( i = 1; i < axis->width_count; i++ ) + FT_TRACE5(( " %d", axis->widths[i].org )); - /* Put some common and representative Han Ideographs characters here. */ - static const FT_ULong af_cjk_hani_blue_chars[AF_CJK_BLUE_MAX] - [AF_CJK_BLUE_TYPE_MAX] - [AF_CJK_MAX_TEST_CHARACTERS] = - { - { - { - 0x4ED6, 0x4EEC, 0x4F60, 0x4F86, 0x5011, 0x5230, 0x548C, 0x5730, - 0x5BF9, 0x5C0D, 0x5C31, 0x5E2D, 0x6211, 0x65F6, 0x6642, 0x6703, - 0x6765, 0x70BA, 0x80FD, 0x8230, 0x8AAA, 0x8BF4, 0x8FD9, 0x9019, - 0x9F4A /* top fill */ - }, - { - 0x519B, 0x540C, 0x5DF2, 0x613F, 0x65E2, 0x661F, 0x662F, 0x666F, - 0x6C11, 0x7167, 0x73B0, 0x73FE, 0x7406, 0x7528, 0x7F6E, 0x8981, - 0x8ECD, 0x90A3, 0x914D, 0x91CC, 0x958B, 0x96F7, 0x9732, 0x9762, - 0x987E /* top unfill */ - } - }, - { - { - 0x4E2A, 0x4E3A, 0x4EBA, 0x4ED6, 0x4EE5, 0x4EEC, 0x4F60, 0x4F86, - 0x500B, 0x5011, 0x5230, 0x548C, 0x5927, 0x5BF9, 0x5C0D, 0x5C31, - 0x6211, 0x65F6, 0x6642, 0x6709, 0x6765, 0x70BA, 0x8981, 0x8AAA, - 0x8BF4 /* bottom fill */ - }, - { - 0x4E3B, 0x4E9B, 0x56E0, 0x5B83, 0x60F3, 0x610F, 0x7406, 0x751F, - 0x7576, 0x770B, 0x7740, 0x7F6E, 0x8005, 0x81EA, 0x8457, 0x88E1, - 0x8FC7, 0x8FD8, 0x8FDB, 0x9032, 0x904E, 0x9053, 0x9084, 0x91CC, - 0x9762 /* bottom unfill */ - } - }, -#ifndef AF_CONFIG_OPTION_CJK_BLUE_HANI_VERT - { {0x0000}, {0x0000} }, - { {0x0000}, {0x0000} } -#else - { - { - 0x4E9B, 0x4EEC, 0x4F60, 0x4F86, 0x5011, 0x5230, 0x548C, 0x5730, - 0x5979, 0x5C06, 0x5C07, 0x5C31, 0x5E74, 0x5F97, 0x60C5, 0x6700, - 0x6837, 0x6A23, 0x7406, 0x80FD, 0x8AAA, 0x8BF4, 0x8FD9, 0x9019, - 0x901A /* left fill */ - }, - { - 0x5373, 0x5417, 0x5427, 0x542C, 0x5462, 0x54C1, 0x54CD, 0x55CE, - 0x5E08, 0x5E2B, 0x6536, 0x65AD, 0x65B7, 0x660E, 0x773C, 0x9593, - 0x95F4, 0x9645, 0x9648, 0x9650, 0x9664, 0x9673, 0x968F, 0x969B, - 0x96A8 /* left unfill */ - } - }, - { - { - 0x4E8B, 0x524D, 0x5B78, 0x5C06, 0x5C07, 0x60C5, 0x60F3, 0x6216, - 0x653F, 0x65AF, 0x65B0, 0x6837, 0x6A23, 0x6C11, 0x6C92, 0x6CA1, - 0x7136, 0x7279, 0x73B0, 0x73FE, 0x7403, 0x7B2C, 0x7D93, 0x8C01, - 0x8D77 /* right fill */ - }, - { - 0x4F8B, 0x5225, 0x522B, 0x5236, 0x52A8, 0x52D5, 0x5417, 0x55CE, - 0x589E, 0x6307, 0x660E, 0x671D, 0x671F, 0x6784, 0x7269, 0x786E, - 0x79CD, 0x8ABF, 0x8C03, 0x8CBB, 0x8D39, 0x90A3, 0x90FD, 0x9593, - 0x95F4 /* right unfill */ + FT_TRACE5(( "\n" )); + } +#endif } } -#endif /* AF_CONFIG_OPTION_CJK_BLUE_HANI_VERT */ - }; + FT_TRACE5(( "\n" )); + + af_glyph_hints_done( hints ); + } - /* Calculate blue zones for all the CJK_BLUE_XXX's. */ + + /* Find all blue zones. */ static void - af_cjk_metrics_init_blues( AF_CJKMetrics metrics, - FT_Face face, - const FT_ULong blue_chars - [AF_CJK_BLUE_MAX] - [AF_CJK_BLUE_TYPE_MAX] - [AF_CJK_MAX_TEST_CHARACTERS] ) + af_cjk_metrics_init_blues( AF_CJKMetrics metrics, + FT_Face face ) { - FT_Pos fills[AF_CJK_MAX_TEST_CHARACTERS]; - FT_Pos flats[AF_CJK_MAX_TEST_CHARACTERS]; + FT_Pos fills[AF_BLUE_STRING_MAX_LEN]; + FT_Pos flats[AF_BLUE_STRING_MAX_LEN]; - FT_Int num_fills; - FT_Int num_flats; + FT_Int num_fills; + FT_Int num_flats; - FT_Int bb; - AF_CJKBlue blue; - FT_Error error; - AF_CJKAxis axis; - FT_GlyphSlot glyph = face->glyph; + AF_CJKBlue blue; + FT_Error error; + AF_CJKAxis axis; + FT_Outline outline; + + AF_Blue_Stringset bss = metrics->root.script_class->blue_stringset; + const AF_Blue_StringRec* bs = &af_blue_stringsets[bss]; #ifdef FT_DEBUG_LEVEL_TRACE - FT_String* cjk_blue_name[AF_CJK_BLUE_MAX] = { - (FT_String*)"top", - (FT_String*)"bottom", - (FT_String*)"left", - (FT_String*)"right" + FT_String* cjk_blue_name[4] = + { + (FT_String*)"bottom", /* -- , -- */ + (FT_String*)"top", /* -- , TOP */ + (FT_String*)"left", /* HORIZ, -- */ + (FT_String*)"right" /* HORIZ, TOP */ }; - FT_String* cjk_blue_type_name[AF_CJK_BLUE_TYPE_MAX] = { - (FT_String*)"filled", - (FT_String*)"unfilled" + + FT_String* cjk_blue_type_name[2] = + { + (FT_String*)"unfilled", /* -- */ + (FT_String*)"filled" /* FILL */ }; #endif - /* We compute the blues simply by loading each character from the */ - /* `blue_chars[blues]' string, then computing its extreme points */ - /* (depending blue zone type etc.). */ + /* we walk over the blue character strings as specified in the */ + /* script's entry in the `af_blue_stringset' array, computing its */ + /* extremum points (depending on the string properties) */ - FT_TRACE5(( "cjk blue zones computation\n" )); - FT_TRACE5(( "------------------------------------------------\n" )); + FT_TRACE5(( "cjk blue zones computation\n" + "==========================\n" + "\n" )); - for ( bb = 0; bb < AF_CJK_BLUE_MAX; bb++ ) + for ( ; bs->string != AF_BLUE_STRING_MAX; bs++ ) { - FT_Int fill_type; - FT_Pos* blue_ref; - FT_Pos* blue_shoot; + const char* p = &af_blue_strings[bs->string]; + FT_Pos* blue_ref; + FT_Pos* blue_shoot; + + + if ( AF_CJK_IS_HORIZ_BLUE( bs ) ) + axis = &metrics->axis[AF_DIMENSION_HORZ]; + else + axis = &metrics->axis[AF_DIMENSION_VERT]; + FT_TRACE5(( "blue zone %d:\n", axis->blue_count )); num_fills = 0; num_flats = 0; - for ( fill_type = 0; fill_type < AF_CJK_BLUE_TYPE_MAX; fill_type++ ) + FT_TRACE5(( " cjk blue %s/%s\n", + cjk_blue_name[AF_CJK_IS_HORIZ_BLUE( bs ) | + AF_CJK_IS_TOP_BLUE( bs ) ], + cjk_blue_type_name[!!AF_CJK_IS_FILLED_BLUE( bs )] )); + + while ( *p ) { - const FT_ULong* p = blue_chars[bb][fill_type]; - const FT_ULong* limit = p + AF_CJK_MAX_TEST_CHARACTERS; - FT_Bool fill = FT_BOOL( - fill_type == AF_CJK_BLUE_TYPE_FILL ); + FT_ULong ch; + FT_UInt glyph_index; + FT_Pos best_pos; /* same as points.y or points.x, resp. */ + FT_Int best_point; + FT_Vector* points; - FT_TRACE5(( "cjk blue %s/%s\n", cjk_blue_name[bb], - cjk_blue_type_name[fill_type] )); + GET_UTF8_CHAR( ch, p ); + /* load the character in the face -- skip unknown or empty ones */ + glyph_index = FT_Get_Char_Index( face, ch ); + if ( glyph_index == 0 ) + { + FT_TRACE5(( " U+%04lX unavailable\n", ch )); + continue; + } - for ( ; p < limit && *p; p++ ) + error = FT_Load_Glyph( face, glyph_index, FT_LOAD_NO_SCALE ); + outline = face->glyph->outline; + if ( error || outline.n_points <= 0 ) { - FT_UInt glyph_index; - FT_Pos best_pos; /* same as points.y */ - FT_Int best_point; - FT_Vector* points; + FT_TRACE5(( " U+%04lX contains no outlines\n", ch )); + continue; + } + /* now compute min or max point indices and coordinates */ + points = outline.points; + best_point = -1; + best_pos = 0; /* make compiler happy */ - FT_TRACE5(( " U+%lX...", *p )); + { + FT_Int nn; + FT_Int first = 0; + FT_Int last = -1; - /* load the character in the face -- skip unknown or empty ones */ - glyph_index = FT_Get_Char_Index( face, *p ); - if ( glyph_index == 0 ) - { - FT_TRACE5(( "unavailable\n" )); - continue; - } - error = FT_Load_Glyph( face, glyph_index, FT_LOAD_NO_SCALE ); - if ( error || glyph->outline.n_points <= 0 ) + for ( nn = 0; nn < outline.n_contours; first = last + 1, nn++ ) { - FT_TRACE5(( "no outline\n" )); - continue; - } + FT_Int pp; - /* now compute min or max point indices and coordinates */ - points = glyph->outline.points; - best_point = -1; - best_pos = 0; /* make compiler happy */ - { - FT_Int nn; - FT_Int first = 0; - FT_Int last = -1; + last = outline.contours[nn]; + /* Avoid single-point contours since they are never rasterized. */ + /* In some fonts, they correspond to mark attachment points */ + /* which are way outside of the glyph's real outline. */ + if ( last <= first ) + continue; - for ( nn = 0; - nn < glyph->outline.n_contours; - first = last + 1, nn++ ) + if ( AF_CJK_IS_HORIZ_BLUE( bs ) ) { - FT_Int pp; - - - last = glyph->outline.contours[nn]; - - /* Avoid single-point contours since they are never */ - /* rasterized. In some fonts, they correspond to mark */ - /* attachment points which are way outside of the glyph's */ - /* real outline. */ - if ( last <= first ) - continue; - - switch ( bb ) + if ( AF_CJK_IS_RIGHT_BLUE( bs ) ) { - case AF_CJK_BLUE_TOP: for ( pp = first; pp <= last; pp++ ) - if ( best_point < 0 || points[pp].y > best_pos ) + if ( best_point < 0 || points[pp].x > best_pos ) { best_point = pp; - best_pos = points[pp].y; + best_pos = points[pp].x; } - break; - - case AF_CJK_BLUE_BOTTOM: + } + else + { for ( pp = first; pp <= last; pp++ ) - if ( best_point < 0 || points[pp].y < best_pos ) + if ( best_point < 0 || points[pp].x < best_pos ) { best_point = pp; - best_pos = points[pp].y; + best_pos = points[pp].x; } - break; - - case AF_CJK_BLUE_LEFT: + } + } + else + { + if ( AF_CJK_IS_TOP_BLUE( bs ) ) + { for ( pp = first; pp <= last; pp++ ) - if ( best_point < 0 || points[pp].x < best_pos ) + if ( best_point < 0 || points[pp].y > best_pos ) { best_point = pp; - best_pos = points[pp].x; + best_pos = points[pp].y; } - break; - - case AF_CJK_BLUE_RIGHT: + } + else + { for ( pp = first; pp <= last; pp++ ) - if ( best_point < 0 || points[pp].x > best_pos ) + if ( best_point < 0 || points[pp].y < best_pos ) { best_point = pp; - best_pos = points[pp].x; + best_pos = points[pp].y; } - break; - - default: - ; } } - FT_TRACE5(( "best_pos=%5ld\n", best_pos )); } - if ( fill ) - fills[num_fills++] = best_pos; - else - flats[num_flats++] = best_pos; + FT_TRACE5(( " U+%04lX: best_pos = %5ld\n", ch, best_pos )); } + + if ( AF_CJK_IS_FILLED_BLUE( bs ) ) + fills[num_fills++] = best_pos; + else + flats[num_flats++] = best_pos; } if ( num_flats == 0 && num_fills == 0 ) @@ -436,34 +386,30 @@ * we couldn't find a single glyph to compute this blue zone, * we will simply ignore it then */ - FT_TRACE5(( "empty\n" )); + FT_TRACE5(( " empty\n" )); continue; } /* we have computed the contents of the `fill' and `flats' tables, */ - /* now determine the reference position of the blue -- */ + /* now determine the reference position of the blue zone -- */ /* we simply take the median value after a simple sort */ af_sort_pos( num_flats, flats ); af_sort_pos( num_fills, fills ); - if ( AF_CJK_BLUE_TOP == bb || AF_CJK_BLUE_BOTTOM == bb ) - axis = &metrics->axis[AF_DIMENSION_VERT]; - else - axis = &metrics->axis[AF_DIMENSION_HORZ]; - - blue = & axis->blues[axis->blue_count]; - blue_ref = & blue->ref.org; - blue_shoot = & blue->shoot.org; + blue = &axis->blues[axis->blue_count]; + blue_ref = &blue->ref.org; + blue_shoot = &blue->shoot.org; axis->blue_count++; + if ( num_flats == 0 ) { - *blue_ref = fills[num_fills / 2]; + *blue_ref = *blue_shoot = fills[num_fills / 2]; } else if ( num_fills == 0 ) { - *blue_ref = flats[num_flats / 2]; + *blue_ref = *blue_shoot = flats[num_flats / 2]; } else @@ -481,26 +427,34 @@ FT_Bool under_ref = FT_BOOL( shoot < ref ); - if ( ( AF_CJK_BLUE_TOP == bb || - AF_CJK_BLUE_RIGHT == bb ) ^ under_ref ) - *blue_shoot = *blue_ref = ( shoot + ref ) / 2; + /* AF_CJK_IS_TOP_BLUE covers `right' and `top' */ + if ( AF_CJK_IS_TOP_BLUE( bs ) ^ under_ref ) + { + *blue_ref = + *blue_shoot = ( shoot + ref ) / 2; + + FT_TRACE5(( " [overshoot smaller than reference," + " taking mean value]\n" )); + } } blue->flags = 0; - if ( AF_CJK_BLUE_TOP == bb ) - blue->flags |= AF_CJK_BLUE_IS_TOP; - else if ( AF_CJK_BLUE_RIGHT == bb ) - blue->flags |= AF_CJK_BLUE_IS_RIGHT; + if ( AF_CJK_IS_TOP_BLUE( bs ) ) + blue->flags |= AF_CJK_BLUE_TOP; - FT_TRACE5(( "-- cjk %s bluezone ref = %ld shoot = %ld\n", - cjk_blue_name[bb], *blue_ref, *blue_shoot )); + FT_TRACE5(( " -> reference = %ld\n" + " overshoot = %ld\n", + *blue_ref, *blue_shoot )); } + FT_TRACE5(( "\n" )); + return; } /* Basically the Latin version with type AF_CJKMetrics for metrics. */ + FT_LOCAL_DEF( void ) af_cjk_metrics_check_digits( AF_CJKMetrics metrics, FT_Face face ) @@ -510,8 +464,7 @@ FT_Fixed advance, old_advance = 0; - /* check whether all ASCII digits have the same advance width; */ - /* digit `0' is 0x30 in all supported charmaps */ + /* digit `0' is 0x30 in all supported charmaps */ for ( i = 0x30; i <= 0x39; i++ ) { FT_UInt glyph_index; @@ -547,6 +500,8 @@ } + /* Initialize global metrics. */ + FT_LOCAL_DEF( FT_Error ) af_cjk_metrics_init( AF_CJKMetrics metrics, FT_Face face ) @@ -556,21 +511,21 @@ metrics->units_per_em = face->units_per_EM; - if ( FT_Select_Charmap( face, FT_ENCODING_UNICODE ) ) - face->charmap = NULL; - else + if ( !FT_Select_Charmap( face, FT_ENCODING_UNICODE ) ) { af_cjk_metrics_init_widths( metrics, face ); - af_cjk_metrics_init_blues( metrics, face, af_cjk_hani_blue_chars ); + af_cjk_metrics_init_blues( metrics, face ); af_cjk_metrics_check_digits( metrics, face ); } FT_Set_Charmap( face, oldmap ); - return FT_Err_Ok; } + /* Adjust scaling value, then scale and shift widths */ + /* and blue zones (if applicable) for given dimension. */ + static void af_cjk_metrics_scale_dim( AF_CJKMetrics metrics, AF_Scaler scaler, @@ -582,8 +537,6 @@ FT_UInt nn; - axis = &metrics->axis[dim]; - if ( dim == AF_DIMENSION_HORZ ) { scale = scaler->x_scale; @@ -595,6 +548,8 @@ delta = scaler->y_delta; } + axis = &metrics->axis[dim]; + if ( axis->org_scale == scale && axis->org_delta == delta ) return; @@ -650,12 +605,13 @@ blue->shoot.fit = blue->ref.fit - delta2; - FT_TRACE5(( ">> active cjk blue zone %c%d[%ld/%ld]: " - "ref: cur=%.2f fit=%.2f shoot: cur=%.2f fit=%.2f\n", - ( dim == AF_DIMENSION_HORZ ) ? 'H' : 'V', - nn, blue->ref.org, blue->shoot.org, - blue->ref.cur / 64.0, blue->ref.fit / 64.0, - blue->shoot.cur / 64.0, blue->shoot.fit / 64.0 )); + FT_TRACE5(( ">> active cjk blue zone %c%d[%ld/%ld]:\n" + " ref: cur=%.2f fit=%.2f\n" + " shoot: cur=%.2f fit=%.2f\n", + ( dim == AF_DIMENSION_HORZ ) ? 'H' : 'V', + nn, blue->ref.org, blue->shoot.org, + blue->ref.cur / 64.0, blue->ref.fit / 64.0, + blue->shoot.cur / 64.0, blue->shoot.fit / 64.0 )); blue->flags |= AF_CJK_BLUE_ACTIVE; } @@ -663,10 +619,14 @@ } + /* Scale global values in both directions. */ + FT_LOCAL_DEF( void ) af_cjk_metrics_scale( AF_CJKMetrics metrics, AF_Scaler scaler ) { + /* we copy the whole structure since the x and y scaling values */ + /* are not modified, contrary to e.g. the `latin' auto-hinter */ metrics->root.scaler = *scaler; af_cjk_metrics_scale_dim( metrics, scaler, AF_DIMENSION_HORZ ); @@ -682,6 +642,9 @@ /*************************************************************************/ /*************************************************************************/ + + /* Walk over all contours and compute its segments. */ + static FT_Error af_cjk_hints_compute_segments( AF_GlyphHints hints, AF_Dimension dim ) @@ -938,7 +901,7 @@ for ( seg = segments; seg < segment_limit; seg++ ) { - AF_Edge found = 0; + AF_Edge found = NULL; FT_Pos best = 0xFFFFU; FT_Int ee; @@ -1026,25 +989,26 @@ } } - /*********************************************************************/ - /* */ - /* Good, we now compute each edge's properties according to segments */ - /* found on its position. Basically, these are as follows. */ - /* */ - /* - edge's main direction */ - /* - stem edge, serif edge or both (which defaults to stem then) */ - /* - rounded edge, straight or both (which defaults to straight) */ - /* - link for edge */ - /* */ - /*********************************************************************/ - - /* first of all, set the `edge' field in each segment -- this is */ - /* required in order to compute edge links */ - /* */ - /* Note that removing this loop and setting the `edge' field of each */ - /* segment directly in the code above slows down execution speed for */ - /* some reasons on platforms like the Sun. */ + /******************************************************************/ + /* */ + /* Good, we now compute each edge's properties according to the */ + /* segments found on its position. Basically, these are */ + /* */ + /* - the edge's main direction */ + /* - stem edge, serif edge or both (which defaults to stem then) */ + /* - rounded edge, straight or both (which defaults to straight) */ + /* - link for edge */ + /* */ + /******************************************************************/ + + /* first of all, set the `edge' field in each segment -- this is */ + /* required in order to compute edge links */ + /* + * Note that removing this loop and setting the `edge' field of each + * segment directly in the code above slows down execution speed for + * some reasons on platforms like the Sun. + */ { AF_Edge edges = axis->edges; AF_Edge edge_limit = edges + axis->num_edges; @@ -1153,6 +1117,8 @@ } + /* Detect segments and edges for given dimension. */ + static FT_Error af_cjk_hints_detect_features( AF_GlyphHints hints, AF_Dimension dim ) @@ -1171,6 +1137,8 @@ } + /* Compute all edges which lie within blue zones. */ + FT_LOCAL_DEF( void ) af_cjk_hints_compute_blue_edges( AF_GlyphHints hints, AF_CJKMetrics metrics, @@ -1218,10 +1186,8 @@ /* zone, check for left edges */ /* */ /* of course, that's for TrueType */ - is_top_right_blue = - FT_BOOL( ( ( blue->flags & AF_CJK_BLUE_IS_TOP ) != 0 ) || - ( ( blue->flags & AF_CJK_BLUE_IS_RIGHT ) != 0 ) ); - is_major_dir = FT_BOOL( edge->dir == axis->major_dir ); + is_top_right_blue = FT_BOOL( blue->flags & AF_CJK_BLUE_TOP ); + is_major_dir = FT_BOOL( edge->dir == axis->major_dir ); /* if it is a top zone, the edge must be against the major */ /* direction; if it is a bottom zone, it must be in the major */ @@ -1258,6 +1224,8 @@ } + /* Initalize hinting engine. */ + FT_LOCAL_DEF( FT_Error ) af_cjk_hints_init( AF_GlyphHints hints, AF_CJKMetrics metrics ) @@ -1316,7 +1284,7 @@ hints->scaler_flags = scaler_flags; hints->other_flags = other_flags; - return 0; + return FT_Err_Ok; } @@ -1328,8 +1296,8 @@ /*************************************************************************/ /*************************************************************************/ - /* snap a given width in scaled coordinates to one of the */ - /* current standard widths */ + /* Snap a given width in scaled coordinates to one of the */ + /* current standard widths. */ static FT_Pos af_cjk_snap_width( AF_Width widths, @@ -1376,7 +1344,9 @@ } - /* compute the snapped width of a given stem */ + /* Compute the snapped width of a given stem. */ + /* There is a lot of voodoo in this function; changing the hard-coded */ + /* parameters influence the whole hinting process. */ static FT_Pos af_cjk_compute_stem_width( AF_GlyphHints hints, @@ -1385,8 +1355,8 @@ AF_Edge_Flags base_flags, AF_Edge_Flags stem_flags ) { - AF_CJKMetrics metrics = (AF_CJKMetrics) hints->metrics; - AF_CJKAxis axis = & metrics->axis[dim]; + AF_CJKMetrics metrics = (AF_CJKMetrics)hints->metrics; + AF_CJKAxis axis = &metrics->axis[dim]; FT_Pos dist = width; FT_Int sign = 0; FT_Bool vertical = FT_BOOL( dim == AF_DIMENSION_VERT ); @@ -1497,7 +1467,7 @@ } - /* align one stem edge relative to the previous stem edge */ + /* Align one stem edge relative to the previous stem edge. */ static void af_cjk_align_linked_edge( AF_GlyphHints hints, @@ -1517,6 +1487,9 @@ } + /* Shift the coordinates of the `serif' edge by the same amount */ + /* as the corresponding `base' edge has been moved already. */ + static void af_cjk_align_serif_edge( AF_GlyphHints hints, AF_Edge base, @@ -1670,6 +1643,8 @@ } + /* The main grid-fitting routine. */ + static void af_cjk_hint_edges( AF_GlyphHints hints, AF_Dimension dim ) @@ -1685,10 +1660,16 @@ FT_Bool has_last_stem = FALSE; FT_Pos last_stem_pos = 0; +#ifdef FT_DEBUG_LEVEL_TRACE + FT_UInt num_actions = 0; +#endif + + + FT_TRACE5(( "cjk %s edge hinting (script `%s')\n", + dim == AF_DIMENSION_VERT ? "horizontal" : "vertical", + af_script_names[hints->metrics->script_class->script] )); /* we begin by aligning all stems relative to the blue zone */ - FT_TRACE5(( "==== cjk hinting %s edges =====\n", - dim == AF_DIMENSION_HORZ ? "vertical" : "horizontal" )); if ( AF_HINTS_DO_BLUES( hints ) ) { @@ -1719,10 +1700,14 @@ if ( !edge1 ) continue; - FT_TRACE5(( "CJKBLUE: edge %d @%d (opos=%.2f) snapped to (%.2f), " - "was (%.2f)\n", - edge1-edges, edge1->fpos, edge1->opos / 64.0, blue->fit / 64.0, - edge1->pos / 64.0 )); +#ifdef FT_DEBUG_LEVEL_TRACE + FT_TRACE5(( " CJKBLUE: edge %d @%d (opos=%.2f) snapped to %.2f," + " was %.2f\n", + edge1 - edges, edge1->fpos, edge1->opos / 64.0, + blue->fit / 64.0, edge1->pos / 64.0 )); + + num_actions++; +#endif edge1->pos = blue->fit; edge1->flags |= AF_EDGE_DONE; @@ -1731,6 +1716,10 @@ { af_cjk_align_linked_edge( hints, dim, edge1, edge2 ); edge2->flags |= AF_EDGE_DONE; + +#ifdef FT_DEBUG_LEVEL_TRACE + num_actions++; +#endif } if ( !anchor ) @@ -1772,6 +1761,7 @@ } /* now align the stem */ + /* this should not happen, but it's better to be safe */ if ( edge2->blue_edge ) { @@ -1779,6 +1769,11 @@ af_cjk_align_linked_edge( hints, dim, edge2, edge ); edge->flags |= AF_EDGE_DONE; + +#ifdef FT_DEBUG_LEVEL_TRACE + num_actions++; +#endif + continue; } @@ -1786,6 +1781,11 @@ { af_cjk_align_linked_edge( hints, dim, edge2, edge ); edge->flags |= AF_EDGE_DONE; + +#ifdef FT_DEBUG_LEVEL_TRACE + num_actions++; +#endif + /* We rarely reaches here it seems; * usually the two edges belonging * to one stem are marked as DONE together @@ -1953,7 +1953,7 @@ } if ( !skipped ) - return; + goto Exit; /* * now hint the remaining edges (serifs and single) in order @@ -1973,7 +1973,7 @@ } if ( !skipped ) - return; + goto Exit; for ( edge = edges; edge < edge_limit; edge++ ) { @@ -2011,6 +2011,16 @@ } } } + + Exit: + +#ifdef FT_DEBUG_LEVEL_TRACE + if ( !num_actions ) + FT_TRACE5(( " (none)\n" )); + FT_TRACE5(( "\n" )); +#endif + + return; } @@ -2104,6 +2114,8 @@ } + /* Apply the complete hinting algorithm to a CJK glyph. */ + FT_LOCAL_DEF( FT_Error ) af_cjk_hints_apply( AF_GlyphHints hints, FT_Outline* outline, @@ -2191,9 +2203,28 @@ /*************************************************************************/ + AF_DEFINE_WRITING_SYSTEM_CLASS( + af_cjk_writing_system_class, + + AF_WRITING_SYSTEM_CJK, + + sizeof ( AF_CJKMetricsRec ), + + (AF_Script_InitMetricsFunc) af_cjk_metrics_init, + (AF_Script_ScaleMetricsFunc)af_cjk_metrics_scale, + (AF_Script_DoneMetricsFunc) NULL, + + (AF_Script_InitHintsFunc) af_cjk_hints_init, + (AF_Script_ApplyHintsFunc) af_cjk_hints_apply + ) + + /* this corresponds to Unicode 6.0 */ - static const AF_Script_UniRangeRec af_cjk_uniranges[] = + /* XXX: this should probably fine tuned to differentiate better between */ + /* scripts... */ + + static const AF_Script_UniRangeRec af_hani_uniranges[] = { AF_UNIRANGE_REC( 0x1100UL, 0x11FFUL ), /* Hangul Jamo */ AF_UNIRANGE_REC( 0x2E80UL, 0x2EFFUL ), /* CJK Radicals Supplement */ @@ -2231,45 +2262,42 @@ }; - AF_DEFINE_SCRIPT_CLASS( af_cjk_script_class, - AF_SCRIPT_CJK, - af_cjk_uniranges, - 0x7530, /* 田 */ +#else /* !AF_CONFIG_OPTION_CJK */ + + AF_DEFINE_WRITING_SYSTEM_CLASS( + af_cjk_writing_system_class, + + AF_WRITING_SYSTEM_CJK, sizeof ( AF_CJKMetricsRec ), - (AF_Script_InitMetricsFunc) af_cjk_metrics_init, - (AF_Script_ScaleMetricsFunc)af_cjk_metrics_scale, + (AF_Script_InitMetricsFunc) NULL, + (AF_Script_ScaleMetricsFunc)NULL, (AF_Script_DoneMetricsFunc) NULL, - (AF_Script_InitHintsFunc) af_cjk_hints_init, - (AF_Script_ApplyHintsFunc) af_cjk_hints_apply + (AF_Script_InitHintsFunc) NULL, + (AF_Script_ApplyHintsFunc) NULL ) -#else /* !AF_CONFIG_OPTION_CJK */ - static const AF_Script_UniRangeRec af_cjk_uniranges[] = + static const AF_Script_UniRangeRec af_hani_uniranges[] = { AF_UNIRANGE_REC( 0UL, 0UL ) }; +#endif /* !AF_CONFIG_OPTION_CJK */ - AF_DEFINE_SCRIPT_CLASS( af_cjk_script_class, - AF_SCRIPT_CJK, - af_cjk_uniranges, - 0, - sizeof ( AF_CJKMetricsRec ), + AF_DEFINE_SCRIPT_CLASS( + af_hani_script_class, - (AF_Script_InitMetricsFunc) NULL, - (AF_Script_ScaleMetricsFunc)NULL, - (AF_Script_DoneMetricsFunc) NULL, + AF_SCRIPT_HANI, + AF_BLUE_STRINGSET_HANI, + AF_WRITING_SYSTEM_CJK, - (AF_Script_InitHintsFunc) NULL, - (AF_Script_ApplyHintsFunc) NULL + af_hani_uniranges, + 0x7530 /* 田 */ ) -#endif /* !AF_CONFIG_OPTION_CJK */ - /* END */ diff --git a/src/autofit/afcjk.h b/src/autofit/afcjk.h index ab816f2..6f5bdc5 100644 --- a/src/autofit/afcjk.h +++ b/src/autofit/afcjk.h @@ -4,7 +4,7 @@ /* */ /* Auto-fitter hinting routines for CJK script (specification). */ /* */ -/* Copyright 2006, 2007, 2011, 2012 by */ +/* Copyright 2006, 2007, 2011-2013 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -26,39 +26,48 @@ FT_BEGIN_HEADER - /* the CJK-specific script class */ + /* the CJK-specific writing system */ - AF_DECLARE_SCRIPT_CLASS( af_cjk_script_class ) + AF_DECLARE_WRITING_SYSTEM_CLASS( af_cjk_writing_system_class ) + + + /* the CJK-specific script classes */ + + AF_DECLARE_SCRIPT_CLASS( af_hani_script_class ) + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** C J K G L O B A L M E T R I C S *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ - /* CJK (global) metrics management */ /* * CJK glyphs tend to fill the square. So we have both vertical and * horizontal blue zones. But some glyphs have flat bounding strokes that * leave some space between neighbour glyphs. */ - enum - { - AF_CJK_BLUE_TOP, - AF_CJK_BLUE_BOTTOM, - AF_CJK_BLUE_LEFT, - AF_CJK_BLUE_RIGHT, - - AF_CJK_BLUE_MAX - }; +#define AF_CJK_IS_TOP_BLUE( b ) \ + ( (b)->properties & AF_BLUE_PROPERTY_CJK_TOP ) +#define AF_CJK_IS_HORIZ_BLUE( b ) \ + ( (b)->properties & AF_BLUE_PROPERTY_CJK_HORIZ ) +#define AF_CJK_IS_FILLED_BLUE( b ) \ + ( (b)->properties & AF_BLUE_PROPERTY_CJK_FILL ) +#define AF_CJK_IS_RIGHT_BLUE AF_CJK_IS_TOP_BLUE #define AF_CJK_MAX_WIDTHS 16 -#define AF_CJK_MAX_BLUES AF_CJK_BLUE_MAX enum { - AF_CJK_BLUE_ACTIVE = 1 << 0, - AF_CJK_BLUE_IS_TOP = 1 << 1, - AF_CJK_BLUE_IS_RIGHT = 1 << 2, - AF_CJK_BLUE_ADJUSTMENT = 1 << 3, /* used for scale adjustment */ - /* optimization */ + AF_CJK_BLUE_ACTIVE = 1 << 0, /* set if zone height is <= 3/4px */ + AF_CJK_BLUE_TOP = 1 << 1, /* result of AF_CJK_IS_TOP_BLUE */ + AF_CJK_BLUE_ADJUSTMENT = 1 << 2, /* used for scale adjustment */ + /* optimization */ AF_CJK_BLUE_FLAG_MAX }; @@ -77,16 +86,16 @@ FT_BEGIN_HEADER FT_Fixed scale; FT_Pos delta; - FT_UInt width_count; - AF_WidthRec widths[AF_CJK_MAX_WIDTHS]; - FT_Pos edge_distance_threshold; - FT_Pos standard_width; - FT_Bool extra_light; + FT_UInt width_count; /* number of used widths */ + AF_WidthRec widths[AF_CJK_MAX_WIDTHS]; /* widths array */ + FT_Pos edge_distance_threshold; /* used for creating edges */ + FT_Pos standard_width; /* the default stem thickness */ + FT_Bool extra_light; /* is standard width very light? */ /* used for horizontal metrics too for CJK */ FT_Bool control_overshoot; FT_UInt blue_count; - AF_CJKBlueRec blues[AF_CJK_BLUE_MAX]; + AF_CJKBlueRec blues[AF_BLUE_STRINGSET_MAX]; FT_Fixed org_scale; FT_Pos org_delta; diff --git a/src/autofit/afdummy.c b/src/autofit/afdummy.c index 2294455..b2b3a20 100644 --- a/src/autofit/afdummy.c +++ b/src/autofit/afdummy.c @@ -26,8 +26,13 @@ af_dummy_hints_init( AF_GlyphHints hints, AF_ScriptMetrics metrics ) { - af_glyph_hints_rescale( hints, - metrics ); + af_glyph_hints_rescale( hints, metrics ); + + hints->x_scale = metrics->scaler.x_scale; + hints->y_scale = metrics->scaler.y_scale; + hints->x_delta = metrics->scaler.x_delta; + hints->y_delta = metrics->scaler.y_delta; + return FT_Err_Ok; } @@ -36,17 +41,21 @@ af_dummy_hints_apply( AF_GlyphHints hints, FT_Outline* outline ) { - FT_UNUSED( hints ); - FT_UNUSED( outline ); + FT_Error error; - return FT_Err_Ok; + + error = af_glyph_hints_reload( hints, outline ); + if ( !error ) + af_glyph_hints_save( hints, outline ); + + return error; } - AF_DEFINE_SCRIPT_CLASS( af_dummy_script_class, - AF_SCRIPT_DUMMY, - NULL, - 0, + AF_DEFINE_WRITING_SYSTEM_CLASS( + af_dummy_writing_system_class, + + AF_WRITING_SYSTEM_DUMMY, sizeof ( AF_ScriptMetricsRec ), @@ -59,4 +68,16 @@ ) + AF_DEFINE_SCRIPT_CLASS( + af_none_script_class, + + AF_SCRIPT_NONE, + (AF_Blue_Stringset)0, + AF_WRITING_SYSTEM_DUMMY, + + NULL, + '\0' + ) + + /* END */ diff --git a/src/autofit/afdummy.h b/src/autofit/afdummy.h index 95d8f8c..9a4d3c2 100644 --- a/src/autofit/afdummy.h +++ b/src/autofit/afdummy.h @@ -5,7 +5,7 @@ /* Auto-fitter dummy routines to be used if no hinting should be */ /* performed (specification). */ /* */ -/* Copyright 2003-2005, 2011 by */ +/* Copyright 2003-2005, 2011, 2013 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -25,11 +25,13 @@ FT_BEGIN_HEADER - /* A dummy script metrics class used when no hinting should - * be performed. This is the default for non-latin glyphs! + /* A dummy writing system and script class used when no hinting should be + * performed. */ - AF_DECLARE_SCRIPT_CLASS( af_dummy_script_class ) + AF_DECLARE_WRITING_SYSTEM_CLASS( af_dummy_writing_system_class ) + + AF_DECLARE_SCRIPT_CLASS( af_none_script_class ) /* */ diff --git a/src/autofit/afglobal.c b/src/autofit/afglobal.c index 3e41465..c2151af 100644 --- a/src/autofit/afglobal.c +++ b/src/autofit/afglobal.c @@ -17,39 +17,64 @@ #include "afglobal.h" -#include "afdummy.h" -#include "aflatin.h" -#include "afcjk.h" -#include "afindic.h" -#include "afpic.h" + + /* get writing system specific header files */ +#undef WRITING_SYSTEM +#define WRITING_SYSTEM( ws, WS ) /* empty */ +#include "afwrtsys.h" #include "aferrors.h" +#include "afpic.h" -#ifdef FT_OPTION_AUTOFIT2 -#include "aflatin2.h" -#endif #ifndef FT_CONFIG_OPTION_PIC - /* when updating this table, don't forget to update */ - /* AF_SCRIPT_CLASSES_COUNT and autofit_module_class_pic_init */ +#undef WRITING_SYSTEM +#define WRITING_SYSTEM( ws, WS ) \ + &af_ ## ws ## _writing_system_class, - /* populate this list when you add new scripts */ - static AF_ScriptClass const af_script_classes[] = + FT_LOCAL_ARRAY_DEF( AF_WritingSystemClass ) + af_writing_system_classes[] = { - &af_dummy_script_class, -#ifdef FT_OPTION_AUTOFIT2 - &af_latin2_script_class, -#endif - &af_latin_script_class, - &af_cjk_script_class, - &af_indic_script_class, + +#include "afwrtsys.h" + + NULL /* do not remove */ + }; + + +#undef SCRIPT +#define SCRIPT( s, S, d ) \ + &af_ ## s ## _script_class, + + FT_LOCAL_ARRAY_DEF( AF_ScriptClass ) + af_script_classes[] = + { + +#include "afscript.h" + NULL /* do not remove */ }; #endif /* !FT_CONFIG_OPTION_PIC */ +#ifdef FT_DEBUG_LEVEL_TRACE + +#undef SCRIPT +#define SCRIPT( s, S, d ) #s, + + FT_LOCAL_ARRAY_DEF( char* ) + af_script_names[] = + { + +#include "afscript.h" + + }; + +#endif /* FT_DEBUG_LEVEL_TRACE */ + + /* Compute the script index of each glyph within a given face. */ static FT_Error @@ -63,9 +88,9 @@ FT_UInt i; - /* the value AF_SCRIPT_NONE means `uncovered glyph' */ + /* the value AF_SCRIPT_UNASSIGNED means `uncovered glyph' */ FT_MEM_SET( globals->glyph_scripts, - AF_SCRIPT_NONE, + AF_SCRIPT_UNASSIGNED, globals->glyph_count ); error = FT_Select_Charmap( face, FT_ENCODING_UNICODE ); @@ -82,18 +107,20 @@ /* scan each script in a Unicode charmap */ for ( ss = 0; AF_SCRIPT_CLASSES_GET[ss]; ss++ ) { - AF_ScriptClass clazz = AF_SCRIPT_CLASSES_GET[ss]; + AF_ScriptClass script_class = AF_SCRIPT_CLASSES_GET[ss]; AF_Script_UniRange range; - if ( clazz->script_uni_ranges == NULL ) + if ( script_class->script_uni_ranges == NULL ) continue; /* * Scan all Unicode points in the range and set the corresponding * glyph script index. */ - for ( range = clazz->script_uni_ranges; range->first != 0; range++ ) + for ( range = script_class->script_uni_ranges; + range->first != 0; + range++ ) { FT_ULong charcode = range->first; FT_UInt gindex; @@ -101,9 +128,9 @@ gindex = FT_Get_Char_Index( face, charcode ); - if ( gindex != 0 && - gindex < (FT_ULong)globals->glyph_count && - gscripts[gindex] == AF_SCRIPT_NONE ) + if ( gindex != 0 && + gindex < (FT_ULong)globals->glyph_count && + gscripts[gindex] == AF_SCRIPT_UNASSIGNED ) gscripts[gindex] = (FT_Byte)ss; for (;;) @@ -113,8 +140,8 @@ if ( gindex == 0 || charcode > range->last ) break; - if ( gindex < (FT_ULong)globals->glyph_count && - gscripts[gindex] == AF_SCRIPT_NONE ) + if ( gindex < (FT_ULong)globals->glyph_count && + gscripts[gindex] == AF_SCRIPT_UNASSIGNED ) gscripts[gindex] = (FT_Byte)ss; } } @@ -135,16 +162,16 @@ * By default, all uncovered glyphs are set to the fallback script. * XXX: Shouldn't we disable hinting or do something similar? */ - if ( globals->module->fallback_script != AF_SCRIPT_NONE ) + if ( globals->module->fallback_script != AF_SCRIPT_UNASSIGNED ) { FT_Long nn; for ( nn = 0; nn < globals->glyph_count; nn++ ) { - if ( ( gscripts[nn] & ~AF_DIGIT ) == AF_SCRIPT_NONE ) + if ( ( gscripts[nn] & ~AF_DIGIT ) == AF_SCRIPT_UNASSIGNED ) { - gscripts[nn] &= ~AF_SCRIPT_NONE; + gscripts[nn] &= ~AF_SCRIPT_UNASSIGNED; gscripts[nn] |= globals->module->fallback_script; } } @@ -204,13 +231,14 @@ { if ( globals->metrics[nn] ) { - AF_ScriptClass clazz = AF_SCRIPT_CLASSES_GET[nn]; + AF_ScriptClass script_class = + AF_SCRIPT_CLASSES_GET[nn]; + AF_WritingSystemClass writing_system_class = + AF_WRITING_SYSTEM_CLASSES_GET[script_class->writing_system]; - FT_ASSERT( globals->metrics[nn]->clazz == clazz ); - - if ( clazz->script_metrics_done ) - clazz->script_metrics_done( globals->metrics[nn] ); + if ( writing_system_class->script_metrics_done ) + writing_system_class->script_metrics_done( globals->metrics[nn] ); FT_FREE( globals->metrics[nn] ); } @@ -232,12 +260,12 @@ AF_ScriptMetrics *ametrics ) { AF_ScriptMetrics metrics = NULL; - FT_UInt gidx; - AF_ScriptClass clazz; - FT_UInt script = options & 15; - const FT_Offset script_max = sizeof ( AF_SCRIPT_CLASSES_GET ) / - sizeof ( AF_SCRIPT_CLASSES_GET[0] ); - FT_Error error = FT_Err_Ok; + + AF_Script script = (AF_Script)( options & 15 ); + AF_WritingSystemClass writing_system_class; + AF_ScriptClass script_class; + + FT_Error error = FT_Err_Ok; if ( gindex >= (FT_ULong)globals->glyph_count ) @@ -246,41 +274,44 @@ goto Exit; } - gidx = script; - if ( gidx == 0 || gidx + 1 >= script_max ) - gidx = globals->glyph_scripts[gindex] & AF_SCRIPT_NONE; + /* if we have a forced script (via `options'), use it, */ + /* otherwise look into `glyph_scripts' array */ + if ( script == AF_SCRIPT_NONE || script + 1 >= AF_SCRIPT_MAX ) + script = (AF_Script)( globals->glyph_scripts[gindex] & + AF_SCRIPT_UNASSIGNED ); - clazz = AF_SCRIPT_CLASSES_GET[gidx]; - if ( script == 0 ) - script = clazz->script; + script_class = AF_SCRIPT_CLASSES_GET[script]; + writing_system_class = AF_WRITING_SYSTEM_CLASSES_GET + [script_class->writing_system]; - metrics = globals->metrics[clazz->script]; + metrics = globals->metrics[script]; if ( metrics == NULL ) { /* create the global metrics object if necessary */ FT_Memory memory = globals->face->memory; - if ( FT_ALLOC( metrics, clazz->script_metrics_size ) ) + if ( FT_ALLOC( metrics, writing_system_class->script_metrics_size ) ) goto Exit; - metrics->clazz = clazz; - metrics->globals = globals; + metrics->script_class = script_class; + metrics->globals = globals; - if ( clazz->script_metrics_init ) + if ( writing_system_class->script_metrics_init ) { - error = clazz->script_metrics_init( metrics, globals->face ); + error = writing_system_class->script_metrics_init( metrics, + globals->face ); if ( error ) { - if ( clazz->script_metrics_done ) - clazz->script_metrics_done( metrics ); + if ( writing_system_class->script_metrics_done ) + writing_system_class->script_metrics_done( metrics ); FT_FREE( metrics ); goto Exit; } } - globals->metrics[clazz->script] = metrics; + globals->metrics[script] = metrics; } Exit: diff --git a/src/autofit/afglobal.h b/src/autofit/afglobal.h index 2e24900..c01b474 100644 --- a/src/autofit/afglobal.h +++ b/src/autofit/afglobal.h @@ -5,7 +5,7 @@ /* Auto-fitter routines to compute global hinting values */ /* (specification). */ /* */ -/* Copyright 2003-2005, 2007, 2009, 2011-2012 by */ +/* Copyright 2003-2005, 2007, 2009, 2011-2013 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -28,17 +28,32 @@ FT_BEGIN_HEADER + FT_LOCAL_ARRAY( AF_WritingSystemClass ) + af_writing_system_classes[]; + + FT_LOCAL_ARRAY( AF_ScriptClass ) + af_script_classes[]; + +#ifdef FT_DEBUG_LEVEL_TRACE + FT_LOCAL_ARRAY( char* ) + af_script_names[]; +#endif + /* * Default values and flags for both autofitter globals (found in * AF_ModuleRec) and face globals (in AF_FaceGlobalsRec). */ /* index of fallback script in `af_script_classes' */ -#define AF_SCRIPT_FALLBACK 2 +#ifdef AF_CONFIG_OPTION_CJK +#define AF_SCRIPT_FALLBACK AF_SCRIPT_HANI +#else +#define AF_SCRIPT_FALLBACK AF_SCRIPT_NONE +#endif /* a bit mask indicating an uncovered glyph */ -#define AF_SCRIPT_NONE 0x7F +#define AF_SCRIPT_UNASSIGNED 0x7F /* if this flag is set, we have an ASCII digit */ -#define AF_DIGIT 0x80 +#define AF_DIGIT 0x80 /* `increase-x-height' property */ #define AF_PROP_INCREASE_X_HEIGHT_MIN 6 @@ -55,8 +70,8 @@ FT_BEGIN_HEADER /* - * Note that glyph_scripts[] is used to map each glyph into - * an index into the `af_script_classes' array. + * Note that glyph_scripts[] maps each glyph to an index into the + * `af_script_classes' array. * */ typedef struct AF_FaceGlobalsRec_ diff --git a/src/autofit/afhints.c b/src/autofit/afhints.c index e8defaa..ce504cc 100644 --- a/src/autofit/afhints.c +++ b/src/autofit/afhints.c @@ -144,6 +144,17 @@ #include FT_CONFIG_STANDARD_LIBRARY_H + /* The dump functions are used in the `ftgrid' demo program, too. */ +#define AF_DUMP( varformat ) \ + do \ + { \ + if ( to_stdout ) \ + printf varformat; \ + else \ + FT_TRACE7( varformat ); \ + } while ( 0 ) + + static const char* af_dir_str( AF_Direction dir ) { @@ -179,34 +190,35 @@ extern "C" { #endif void - af_glyph_hints_dump_points( AF_GlyphHints hints ) + af_glyph_hints_dump_points( AF_GlyphHints hints, + FT_Bool to_stdout ) { AF_Point points = hints->points; AF_Point limit = points + hints->num_points; AF_Point point; - FT_TRACE7(( "Table of points:\n" - " [ index | xorg | yorg | xscale | yscale" - " | xfit | yfit | flags ]\n" )); + AF_DUMP(( "Table of points:\n" + " [ index | xorg | yorg | xscale | yscale" + " | xfit | yfit | flags ]\n" )); for ( point = points; point < limit; point++ ) - FT_TRACE7(( " [ %5d | %5d | %5d | %6.2f | %6.2f" - " | %5.2f | %5.2f | %c%c%c%c%c%c ]\n", - point - points, - point->fx, - point->fy, - point->ox / 64.0, - point->oy / 64.0, - point->x / 64.0, - point->y / 64.0, - ( point->flags & AF_FLAG_WEAK_INTERPOLATION ) ? 'w' : ' ', - ( point->flags & AF_FLAG_INFLECTION ) ? 'i' : ' ', - ( point->flags & AF_FLAG_EXTREMA_X ) ? '<' : ' ', - ( point->flags & AF_FLAG_EXTREMA_Y ) ? 'v' : ' ', - ( point->flags & AF_FLAG_ROUND_X ) ? '(' : ' ', - ( point->flags & AF_FLAG_ROUND_Y ) ? 'u' : ' ')); - FT_TRACE7(( "\n" )); + AF_DUMP(( " [ %5d | %5d | %5d | %6.2f | %6.2f" + " | %5.2f | %5.2f | %c%c%c%c%c%c ]\n", + point - points, + point->fx, + point->fy, + point->ox / 64.0, + point->oy / 64.0, + point->x / 64.0, + point->y / 64.0, + ( point->flags & AF_FLAG_WEAK_INTERPOLATION ) ? 'w' : ' ', + ( point->flags & AF_FLAG_INFLECTION ) ? 'i' : ' ', + ( point->flags & AF_FLAG_EXTREMA_X ) ? '<' : ' ', + ( point->flags & AF_FLAG_EXTREMA_Y ) ? 'v' : ' ', + ( point->flags & AF_FLAG_ROUND_X ) ? '(' : ' ', + ( point->flags & AF_FLAG_ROUND_Y ) ? 'u' : ' ')); + AF_DUMP(( "\n" )); } #ifdef __cplusplus } @@ -247,7 +259,8 @@ extern "C" { #endif void - af_glyph_hints_dump_segments( AF_GlyphHints hints ) + af_glyph_hints_dump_segments( AF_GlyphHints hints, + FT_Bool to_stdout ) { FT_Int dimension; @@ -262,34 +275,34 @@ AF_Segment seg; - FT_TRACE7(( "Table of %s segments:\n", - dimension == AF_DIMENSION_HORZ ? "vertical" - : "horizontal" )); + AF_DUMP(( "Table of %s segments:\n", + dimension == AF_DIMENSION_HORZ ? "vertical" + : "horizontal" )); if ( axis->num_segments ) - FT_TRACE7(( " [ index | pos | dir | from" - " | to | link | serif | edge" - " | height | extra | flags ]\n" )); + AF_DUMP(( " [ index | pos | dir | from" + " | to | link | serif | edge" + " | height | extra | flags ]\n" )); else - FT_TRACE7(( " (none)\n" )); + AF_DUMP(( " (none)\n" )); for ( seg = segments; seg < limit; seg++ ) - FT_TRACE7(( " [ %5d | %5.2g | %5s | %4d" - " | %4d | %4d | %5d | %4d" - " | %6d | %5d | %11s ]\n", - seg - segments, - dimension == AF_DIMENSION_HORZ - ? (int)seg->first->ox / 64.0 - : (int)seg->first->oy / 64.0, - af_dir_str( (AF_Direction)seg->dir ), - AF_INDEX_NUM( seg->first, points ), - AF_INDEX_NUM( seg->last, points ), - AF_INDEX_NUM( seg->link, segments ), - AF_INDEX_NUM( seg->serif, segments ), - AF_INDEX_NUM( seg->edge, edges ), - seg->height, - seg->height - ( seg->max_coord - seg->min_coord ), - af_edge_flags_to_string( (AF_Edge_Flags)seg->flags ) )); - FT_TRACE7(( "\n" )); + AF_DUMP(( " [ %5d | %5.2g | %5s | %4d" + " | %4d | %4d | %5d | %4d" + " | %6d | %5d | %11s ]\n", + seg - segments, + dimension == AF_DIMENSION_HORZ + ? (int)seg->first->ox / 64.0 + : (int)seg->first->oy / 64.0, + af_dir_str( (AF_Direction)seg->dir ), + AF_INDEX_NUM( seg->first, points ), + AF_INDEX_NUM( seg->last, points ), + AF_INDEX_NUM( seg->link, segments ), + AF_INDEX_NUM( seg->serif, segments ), + AF_INDEX_NUM( seg->edge, edges ), + seg->height, + seg->height - ( seg->max_coord - seg->min_coord ), + af_edge_flags_to_string( (AF_Edge_Flags)seg->flags ) )); + AF_DUMP(( "\n" )); } } #ifdef __cplusplus @@ -366,7 +379,8 @@ extern "C" { #endif void - af_glyph_hints_dump_edges( AF_GlyphHints hints ) + af_glyph_hints_dump_edges( AF_GlyphHints hints, + FT_Bool to_stdout ) { FT_Int dimension; @@ -383,94 +397,35 @@ * note: AF_DIMENSION_HORZ corresponds to _vertical_ edges * since they have a constant X coordinate. */ - FT_TRACE7(( "Table of %s edges:\n", - dimension == AF_DIMENSION_HORZ ? "vertical" - : "horizontal" )); + AF_DUMP(( "Table of %s edges:\n", + dimension == AF_DIMENSION_HORZ ? "vertical" + : "horizontal" )); if ( axis->num_edges ) - FT_TRACE7(( " [ index | pos | dir | link" - " | serif | blue | opos | pos | flags ]\n" )); + AF_DUMP(( " [ index | pos | dir | link" + " | serif | blue | opos | pos | flags ]\n" )); else - FT_TRACE7(( " (none)\n" )); + AF_DUMP(( " (none)\n" )); for ( edge = edges; edge < limit; edge++ ) - FT_TRACE7(( " [ %5d | %5.2g | %5s | %4d" - " | %5d | %c | %5.2f | %5.2f | %11s ]\n", - edge - edges, - (int)edge->opos / 64.0, - af_dir_str( (AF_Direction)edge->dir ), - AF_INDEX_NUM( edge->link, edges ), - AF_INDEX_NUM( edge->serif, edges ), - edge->blue_edge ? 'y' : 'n', - edge->opos / 64.0, - edge->pos / 64.0, - af_edge_flags_to_string( (AF_Edge_Flags)edge->flags ) )); - FT_TRACE7(( "\n" )); + AF_DUMP(( " [ %5d | %5.2g | %5s | %4d" + " | %5d | %c | %5.2f | %5.2f | %11s ]\n", + edge - edges, + (int)edge->opos / 64.0, + af_dir_str( (AF_Direction)edge->dir ), + AF_INDEX_NUM( edge->link, edges ), + AF_INDEX_NUM( edge->serif, edges ), + edge->blue_edge ? 'y' : 'n', + edge->opos / 64.0, + edge->pos / 64.0, + af_edge_flags_to_string( (AF_Edge_Flags)edge->flags ) )); + AF_DUMP(( "\n" )); } } #ifdef __cplusplus } #endif -#else /* !FT_DEBUG_AUTOFIT */ - - /* these empty stubs are only used to link the `ftgrid' test program */ - /* if debugging is disabled */ - -#ifdef __cplusplus - extern "C" { -#endif - - void - af_glyph_hints_dump_points( AF_GlyphHints hints ) - { - FT_UNUSED( hints ); - } - - - void - af_glyph_hints_dump_segments( AF_GlyphHints hints ) - { - FT_UNUSED( hints ); - } - - - FT_Error - af_glyph_hints_get_num_segments( AF_GlyphHints hints, - FT_Int dimension, - FT_Int* num_segments ) - { - FT_UNUSED( hints ); - FT_UNUSED( dimension ); - FT_UNUSED( num_segments ); - - return 0; - } - - - FT_Error - af_glyph_hints_get_segment_offset( AF_GlyphHints hints, - FT_Int dimension, - FT_Int idx, - FT_Pos* offset ) - { - FT_UNUSED( hints ); - FT_UNUSED( dimension ); - FT_UNUSED( idx ); - FT_UNUSED( offset ); - - return 0; - } - - - void - af_glyph_hints_dump_edges( AF_GlyphHints hints ) - { - FT_UNUSED( hints ); - } - -#ifdef __cplusplus - } -#endif +#undef AF_DUMP #endif /* !FT_DEBUG_AUTOFIT */ @@ -740,6 +695,12 @@ FT_Pos in_y = 0; AF_Direction in_dir = AF_DIR_NONE; + FT_Pos last_good_in_x = 0; + FT_Pos last_good_in_y = 0; + + FT_UInt units_per_em = hints->metrics->scaler.face->units_per_EM; + FT_Int near_limit = 20 * units_per_em / 2048; + for ( point = points; point < point_limit; point++ ) { @@ -749,15 +710,59 @@ if ( point == first ) { - prev = first->prev; - in_x = first->fx - prev->fx; - in_y = first->fy - prev->fy; + prev = first->prev; + + in_x = first->fx - prev->fx; + in_y = first->fy - prev->fy; + + last_good_in_x = in_x; + last_good_in_y = in_y; + + if ( FT_ABS( in_x ) + FT_ABS( in_y ) < near_limit ) + { + /* search first non-near point to get a good `in_dir' value */ + + AF_Point point_ = prev; + + + while ( point_ != first ) + { + AF_Point prev_ = point_->prev; + + FT_Pos in_x_ = point_->fx - prev_->fx; + FT_Pos in_y_ = point_->fy - prev_->fy; + + + if ( FT_ABS( in_x_ ) + FT_ABS( in_y_ ) >= near_limit ) + { + last_good_in_x = in_x_; + last_good_in_y = in_y_; + + break; + } + + point_ = prev_; + } + } + in_dir = af_direction_compute( in_x, in_y ); first = prev + 1; } point->in_dir = (FT_Char)in_dir; + /* check whether the current point is near to the previous one */ + /* (value 20 in `near_limit' is heuristic; we use Taxicab */ + /* metrics for the test) */ + + if ( FT_ABS( in_x ) + FT_ABS( in_y ) < near_limit ) + point->flags |= AF_FLAG_NEAR; + else + { + last_good_in_x = in_x; + last_good_in_y = in_y; + } + next = point->next; out_x = next->fx - point->fx; out_y = next->fy - point->fy; @@ -765,23 +770,43 @@ in_dir = af_direction_compute( out_x, out_y ); point->out_dir = (FT_Char)in_dir; - /* check for weak points */ + /* Check for weak points. The remaining points not collected */ + /* in edges are then implicitly classified as strong points. */ if ( point->flags & AF_FLAG_CONTROL ) { + /* control points are always weak */ Is_Weak_Point: point->flags |= AF_FLAG_WEAK_INTERPOLATION; } else if ( point->out_dir == point->in_dir ) { if ( point->out_dir != AF_DIR_NONE ) + { + /* current point lies on a horizontal or */ + /* vertical segment (but doesn't start or end it) */ goto Is_Weak_Point; + } - if ( ft_corner_is_flat( in_x, in_y, out_x, out_y ) ) + /* test whether `in' and `out' direction is approximately */ + /* the same (and use the last good `in' vector in case */ + /* the current point is near to the previous one) */ + if ( ft_corner_is_flat( + point->flags & AF_FLAG_NEAR ? last_good_in_x : in_x, + point->flags & AF_FLAG_NEAR ? last_good_in_y : in_y, + out_x, + out_y ) ) + { + /* current point lies on a straight, diagonal line */ + /* (more or less) */ goto Is_Weak_Point; + } } else if ( point->in_dir == -point->out_dir ) + { + /* current point forms a spike */ goto Is_Weak_Point; + } in_x = out_x; in_y = out_y; diff --git a/src/autofit/afhints.h b/src/autofit/afhints.h index 776b3c8..ce52325 100644 --- a/src/autofit/afhints.h +++ b/src/autofit/afhints.h @@ -62,15 +62,19 @@ FT_BEGIN_HEADER * * by David Turner and Werner Lemberg * - * http://www.tug.org/TUGboat/Articles/tb24-3/lemberg.pdf + * http://www.tug.org/TUGboat/Articles/tb24-3/lemberg.pdf + * + * with appropriate updates. * * * Segments * * `af_{cjk,latin,...}_hints_compute_segments' are the functions to - * find segments in an outline. A segment is a series of consecutive - * points that are approximately aligned along a coordinate axis. The - * analysis to do so is specific to a script. + * find segments in an outline. + * + * A segment is a series of consecutive points that are approximately + * aligned along a coordinate axis. The analysis to do so is specific + * to a writing system. * * A segment must have at least two points, except in the case of * `fake' segments that are generated to hint metrics appropriately, @@ -79,16 +83,17 @@ FT_BEGIN_HEADER * * Edges * + * `af_{cjk,latin,...}_hints_compute_edges' are the functions to find + * edges. + * * As soon as segments are defined, the auto-hinter groups them into * edges. An edge corresponds to a single position on the main * dimension that collects one or more segments (allowing for a small * threshold). * - * The auto-hinter first tries to grid fit edges, then to align - * segments on the edges unless it detects that they form a serif. - * - * `af_{cjk,latin,...}_hints_compute_edges' are the functions to find - * edges; they are specific to a script. + * As an example, the `latin' writing system first tries to grid-fit + * edges, then to align segments on the edges unless it detects that + * they form a serif. * * * A H @@ -107,6 +112,8 @@ FT_BEGIN_HEADER * * Stems * + * Stems are detected by `af_{cjk,latin,...}_hint_edges'. + * * Segments need to be `linked' to other ones in order to detect stems. * A stem is made of two segments that face each other in opposite * directions and that are sufficiently close to each other. Using @@ -127,17 +134,21 @@ FT_BEGIN_HEADER * The best candidate is stored in field `link' in structure * `AF_Segment'. * - * Stems are detected by `af_{cjk,latin,...}_hint_edges'. - * * In the above ASCII drawing, the best candidate for both AB and CD is * GH, while the best candidate for GH is AB. Similarly, the best * candidate for EF and GH is AB, while the best candidate for AB is * GH. * + * The detection and handling of stems is dependent on the writing + * system. + * * * Serifs * - * On the opposite, a serif has + * Serifs are detected by `af_{cjk,latin,...}_hint_edges'. + * + * In comparison to a stem, a serif (as handled by the auto-hinter + * module which takes care of the `latin' writing system) has * * best segment_1 = segment_2 && best segment_2 != segment_1 * @@ -147,8 +158,6 @@ FT_BEGIN_HEADER * The best candidate is stored in field `serif' in structure * `AF_Segment' (and `link' is set to NULL). * - * Serifs are detected by `af_{cjk,latin,...}_hint_edges'. - * * * Touched points * @@ -178,7 +187,8 @@ FT_BEGIN_HEADER * differ greatly) * * - inflection points (i.e., where the `in' and `out' angles are the - * same, but the curvature changes sign) + * same, but the curvature changes sign) [currently, such points + * aren't handled in the auto-hinter] * * `af_glyph_hints_align_strong_points' is the function which takes * care of such situations; it is equivalent to the TrueType `IP' @@ -226,7 +236,10 @@ FT_BEGIN_HEADER AF_FLAG_WEAK_INTERPOLATION = 1 << 8, /* all inflection points in the outline have this flag set */ - AF_FLAG_INFLECTION = 1 << 9 + AF_FLAG_INFLECTION = 1 << 9, + + /* the current point is very near to another one */ + AF_FLAG_NEAR = 1 << 10 } AF_Flags; diff --git a/src/autofit/afindic.c b/src/autofit/afindic.c index 8c24972..ef8299f 100644 --- a/src/autofit/afindic.c +++ b/src/autofit/afindic.c @@ -97,26 +97,10 @@ /*************************************************************************/ - static const AF_Script_UniRangeRec af_indic_uniranges[] = - { -#if 0 - AF_UNIRANGE_REC( 0x0100UL, 0xFFFFUL ), /* why this? */ -#endif - AF_UNIRANGE_REC( 0x0900UL, 0x0DFFUL), /* Indic Range */ - AF_UNIRANGE_REC( 0x0F00UL, 0x0FFFUL), /* Tibetan */ - AF_UNIRANGE_REC( 0x1900UL, 0x194FUL), /* Limbu */ - AF_UNIRANGE_REC( 0x1B80UL, 0x1BBFUL), /* Sundanese */ - AF_UNIRANGE_REC( 0x1C80UL, 0x1CDFUL), /* Meetei Mayak */ - AF_UNIRANGE_REC( 0xA800UL, 0xA82FUL), /* Syloti Nagri */ - AF_UNIRANGE_REC( 0x11800UL, 0x118DFUL), /* Sharada */ - AF_UNIRANGE_REC( 0UL, 0UL) - }; - + AF_DEFINE_WRITING_SYSTEM_CLASS( + af_indic_writing_system_class, - AF_DEFINE_SCRIPT_CLASS( af_indic_script_class, - AF_SCRIPT_INDIC, - af_indic_uniranges, - 'o', /* XXX */ + AF_WRITING_SYSTEM_INDIC, sizeof ( AF_CJKMetricsRec ), @@ -128,18 +112,28 @@ (AF_Script_ApplyHintsFunc) af_indic_hints_apply ) -#else /* !AF_CONFIG_OPTION_INDIC */ + /* XXX: this should probably fine tuned to differentiate better between */ + /* scripts... */ - static const AF_Script_UniRangeRec af_indic_uniranges[] = + static const AF_Script_UniRangeRec af_deva_uniranges[] = { - { 0, 0 } + AF_UNIRANGE_REC( 0x0900UL, 0x0DFFUL ), /* Indic Range */ + AF_UNIRANGE_REC( 0x0F00UL, 0x0FFFUL ), /* Tibetan */ + AF_UNIRANGE_REC( 0x1900UL, 0x194FUL ), /* Limbu */ + AF_UNIRANGE_REC( 0x1B80UL, 0x1BBFUL ), /* Sundanese */ + AF_UNIRANGE_REC( 0x1C80UL, 0x1CDFUL ), /* Meetei Mayak */ + AF_UNIRANGE_REC( 0xA800UL, 0xA82FUL ), /* Syloti Nagri */ + AF_UNIRANGE_REC( 0x11800UL, 0x118DFUL ), /* Sharada */ + AF_UNIRANGE_REC( 0UL, 0UL ) }; - AF_DEFINE_SCRIPT_CLASS( af_indic_script_class, - AF_SCRIPT_INDIC, - af_indic_uniranges, - 0, +#else /* !AF_CONFIG_OPTION_INDIC */ + + AF_DEFINE_WRITING_SYSTEM_CLASS( + af_indic_writing_system_class, + + AF_WRITING_SYSTEM_INDIC, sizeof ( AF_CJKMetricsRec ), @@ -151,7 +145,25 @@ (AF_Script_ApplyHintsFunc) NULL ) + + static const AF_Script_UniRangeRec af_deva_uniranges[] = + { + AF_UNIRANGE_REC( 0UL, 0UL ) + }; + #endif /* !AF_CONFIG_OPTION_INDIC */ + AF_DEFINE_SCRIPT_CLASS( + af_deva_script_class, + + AF_SCRIPT_DEVA, + (AF_Blue_Stringset)0, /* XXX */ + AF_WRITING_SYSTEM_INDIC, + + af_deva_uniranges, + 'o' /* XXX */ + ) + + /* END */ diff --git a/src/autofit/afindic.h b/src/autofit/afindic.h index c252cf2..db38e96 100644 --- a/src/autofit/afindic.h +++ b/src/autofit/afindic.h @@ -4,7 +4,7 @@ /* */ /* Auto-fitter hinting routines for Indic scripts (specification). */ /* */ -/* Copyright 2007, 2012 by */ +/* Copyright 2007, 2012, 2013 by */ /* Rahul Bhalerao <rahul.bhalerao@redhat.com>, <b.rahul.pm@gmail.com>. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -25,9 +25,14 @@ FT_BEGIN_HEADER - /* the Indic-specific script class */ + /* the `indic' writing system */ - AF_DECLARE_SCRIPT_CLASS( af_indic_script_class ) + AF_DECLARE_WRITING_SYSTEM_CLASS( af_indic_writing_system_class ) + + + /* the indic-specific script classes */ + + AF_DECLARE_SCRIPT_CLASS( af_deva_script_class ) /* */ diff --git a/src/autofit/aflatin.c b/src/autofit/aflatin.c index ef0157a..15a241e 100644 --- a/src/autofit/aflatin.c +++ b/src/autofit/aflatin.c @@ -60,8 +60,11 @@ AF_GlyphHintsRec hints[1]; - FT_TRACE5(( "standard widths computation\n" - "===========================\n\n" )); + FT_TRACE5(( "\n" + "latin standard widths computation (script `%s')\n" + "=================================================\n" + "\n", + af_script_names[metrics->root.script_class->script] )); af_glyph_hints_init( hints, face->memory ); @@ -76,13 +79,14 @@ AF_Scaler scaler = &dummy->root.scaler; - glyph_index = FT_Get_Char_Index( face, - metrics->root.clazz->standard_char ); + glyph_index = FT_Get_Char_Index( + face, + metrics->root.script_class->standard_char ); if ( glyph_index == 0 ) goto Exit; - FT_TRACE5(( "standard character: 0x%X (glyph index %d)\n", - metrics->root.clazz->standard_char, glyph_index )); + FT_TRACE5(( "standard character: U+%04lX (glyph index %d)\n", + metrics->root.script_class->standard_char, glyph_index )); error = FT_Load_Glyph( face, glyph_index, FT_LOAD_NO_SCALE ); if ( error || face->glyph->outline.n_points <= 0 ) @@ -146,22 +150,21 @@ } /* this also replaces multiple almost identical stem widths */ - /* with a single one (the value 100 is heuristic) */ + /* with a single one (the value 100 is heuristic) */ af_sort_and_quantize_widths( &num_widths, axis->widths, dummy->units_per_em / 100 ); axis->width_count = num_widths; } - Exit: + Exit: for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ ) { AF_LatinAxis axis = &metrics->axis[dim]; FT_Pos stdw; - stdw = ( axis->width_count > 0 ) - ? axis->widths[0].org - : AF_LATIN_CONSTANT( metrics, 50 ); + stdw = ( axis->width_count > 0 ) ? axis->widths[0].org + : AF_LATIN_CONSTANT( metrics, 50 ); /* let's try 20% of the smallest width */ axis->edge_distance_threshold = stdw / 5; @@ -193,22 +196,6 @@ } - -#define AF_LATIN_MAX_TEST_CHARACTERS 12 - - - static const char af_latin_blue_chars[AF_LATIN_MAX_BLUES] - [AF_LATIN_MAX_TEST_CHARACTERS + 1] = - { - "THEZOCQS", - "HEZLOCUS", - "fijkdbh", - "xzroesc", - "xzroesc", - "pqgjy" - }; - - /* Find all blue zones. Flat segments give the reference points, */ /* round segments the overshoot positions. */ @@ -216,39 +203,80 @@ af_latin_metrics_init_blues( AF_LatinMetrics metrics, FT_Face face ) { - FT_Pos flats [AF_LATIN_MAX_TEST_CHARACTERS]; - FT_Pos rounds[AF_LATIN_MAX_TEST_CHARACTERS]; + FT_Pos flats [AF_BLUE_STRING_MAX_LEN]; + FT_Pos rounds[AF_BLUE_STRING_MAX_LEN]; + FT_Int num_flats; FT_Int num_rounds; - FT_Int bb; + AF_LatinBlue blue; FT_Error error; - AF_LatinAxis axis = &metrics->axis[AF_DIMENSION_VERT]; + AF_LatinAxis axis = &metrics->axis[AF_DIMENSION_VERT]; FT_Outline outline; + AF_Blue_Stringset bss = metrics->root.script_class->blue_stringset; + const AF_Blue_StringRec* bs = &af_blue_stringsets[bss]; + - /* we compute the blues simply by loading each character from the */ - /* `af_latin_blue_chars[blues]' string, then finding its top-most or */ - /* bottom-most points (depending on `AF_IS_TOP_BLUE') */ + /* we walk over the blue character strings as specified in the */ + /* script's entry in the `af_blue_stringset' array */ - FT_TRACE5(( "blue zones computation\n" - "======================\n\n" )); + FT_TRACE5(( "latin blue zones computation\n" + "============================\n" + "\n" )); - for ( bb = 0; bb < AF_LATIN_BLUE_MAX; bb++ ) + for ( ; bs->string != AF_BLUE_STRING_MAX; bs++ ) { - const char* p = af_latin_blue_chars[bb]; - const char* limit = p + AF_LATIN_MAX_TEST_CHARACTERS; + const char* p = &af_blue_strings[bs->string]; FT_Pos* blue_ref; FT_Pos* blue_shoot; - FT_TRACE5(( "blue zone %d:\n", bb )); +#ifdef FT_DEBUG_LEVEL_TRACE + { + FT_Bool have_flag = 0; + + + FT_TRACE5(( "blue zone %d", axis->blue_count )); + + if ( bs->properties ) + { + FT_TRACE5(( " (" )); + + if ( AF_LATIN_IS_TOP_BLUE( bs ) ) + { + FT_TRACE5(( "top" )); + have_flag = 1; + } + + if ( AF_LATIN_IS_X_HEIGHT_BLUE( bs ) ) + { + if ( have_flag ) + FT_TRACE5(( ", " )); + FT_TRACE5(( "small top" )); + have_flag = 1; + } + + if ( AF_LATIN_IS_LONG_BLUE( bs ) ) + { + if ( have_flag ) + FT_TRACE5(( ", " )); + FT_TRACE5(( "long" )); + } + + FT_TRACE5(( ")" )); + } + + FT_TRACE5(( ":\n" )); + } +#endif /* FT_DEBUG_LEVEL_TRACE */ num_flats = 0; num_rounds = 0; - for ( ; p < limit && *p; p++ ) + while ( *p ) { + FT_ULong ch; FT_UInt glyph_index; FT_Pos best_y; /* same as points.y */ FT_Int best_point, best_contour_first, best_contour_last; @@ -256,15 +284,23 @@ FT_Bool round = 0; + GET_UTF8_CHAR( ch, p ); + /* load the character in the face -- skip unknown or empty ones */ - glyph_index = FT_Get_Char_Index( face, (FT_UInt)*p ); + glyph_index = FT_Get_Char_Index( face, ch ); if ( glyph_index == 0 ) + { + FT_TRACE5(( " U+%04lX unavailable\n", ch )); continue; + } error = FT_Load_Glyph( face, glyph_index, FT_LOAD_NO_SCALE ); outline = face->glyph->outline; if ( error || outline.n_points <= 0 ) + { + FT_TRACE5(( " U+%04lX contains no outlines\n", ch )); continue; + } /* now compute min or max point indices and coordinates */ points = outline.points; @@ -289,11 +325,11 @@ /* Avoid single-point contours since they are never rasterized. */ /* In some fonts, they correspond to mark attachment points */ - /* which are way outside of the glyph's real outline. */ + /* that are way outside of the glyph's real outline. */ if ( last <= first ) continue; - if ( AF_LATIN_IS_TOP_BLUE( bb ) ) + if ( AF_LATIN_IS_TOP_BLUE( bs ) ) { for ( pp = first; pp <= last; pp++ ) if ( best_point < 0 || points[pp].y > best_y ) @@ -318,7 +354,6 @@ best_contour_last = last; } } - FT_TRACE5(( " %c %ld", *p, best_y )); } /* now check whether the point belongs to a straight or round */ @@ -328,10 +363,14 @@ { FT_Pos best_x = points[best_point].x; FT_Int prev, next; + FT_Int best_segment_first, best_segment_last; FT_Int best_on_point_first, best_on_point_last; FT_Pos dist; + best_segment_first = best_point; + best_segment_last = best_point; + if ( FT_CURVE_TAG( outline.tags[best_point] ) == FT_CURVE_TAG_ON ) { best_on_point_first = best_point; @@ -343,8 +382,9 @@ best_on_point_last = -1; } - /* look for the previous and next points that are not on the */ - /* same Y coordinate, then threshold the `closeness'... */ + /* look for the previous and next points on the contour */ + /* that are not on the same Y coordinate, then threshold */ + /* the `closeness'... */ prev = best_point; next = prev; @@ -362,6 +402,8 @@ if ( FT_ABS( points[prev].x - best_x ) <= 20 * dist ) break; + best_segment_first = prev; + if ( FT_CURVE_TAG( outline.tags[prev] ) == FT_CURVE_TAG_ON ) { best_on_point_first = prev; @@ -383,6 +425,8 @@ if ( FT_ABS( points[next].x - best_x ) <= 20 * dist ) break; + best_segment_last = next; + if ( FT_CURVE_TAG( outline.tags[next] ) == FT_CURVE_TAG_ON ) { best_on_point_last = next; @@ -392,8 +436,186 @@ } while ( next != best_point ); - /* now set the `round' flag depending on the segment's kind */ - /* (value 8 is heuristic) */ + if ( AF_LATIN_IS_LONG_BLUE( bs ) ) + { + /* If this flag is set, we have an additional constraint to */ + /* get the blue zone distance: Find a segment of the topmost */ + /* (or bottommost) contour that is longer than a heuristic */ + /* threshold. This ensures that small bumps in the outline */ + /* are ignored (for example, the `vertical serifs' found in */ + /* many Hebrew glyph designs). */ + + /* If this segment is long enough, we are done. Otherwise, */ + /* search the segment next to the extremum that is long */ + /* enough, has the same direction, and a not too large */ + /* vertical distance from the extremum. Note that the */ + /* algorithm doesn't check whether the found segment is */ + /* actually the one (vertically) nearest to the extremum. */ + + /* heuristic threshold value */ + FT_Pos length_threshold = metrics->units_per_em / 25; + + + dist = FT_ABS( points[best_segment_last].x - + points[best_segment_first].x ); + + if ( dist < length_threshold && + best_segment_last - best_segment_first + 2 <= + best_contour_last - best_contour_first ) + { + /* heuristic threshold value */ + FT_Pos height_threshold = metrics->units_per_em / 4; + + FT_Int first; + FT_Int last; + FT_Bool hit; + + FT_Bool left2right; + + + /* compute direction */ + prev = best_point; + + do + { + if ( prev > best_contour_first ) + prev--; + else + prev = best_contour_last; + + if ( points[prev].x != best_x ) + break; + + } while ( prev != best_point ); + + /* skip glyph for the degenerate case */ + if ( prev == best_point ) + continue; + + left2right = FT_BOOL( points[prev].x < points[best_point].x ); + + first = best_segment_last; + last = first; + hit = 0; + + do + { + FT_Bool l2r; + FT_Pos d; + FT_Int p_first, p_last; + + + if ( !hit ) + { + /* no hit; adjust first point */ + first = last; + + /* also adjust first and last on point */ + if ( FT_CURVE_TAG( outline.tags[first] ) == + FT_CURVE_TAG_ON ) + { + p_first = first; + p_last = first; + } + else + { + p_first = -1; + p_last = -1; + } + + hit = 1; + } + + if ( last < best_contour_last ) + last++; + else + last = best_contour_first; + + if ( FT_ABS( best_y - points[first].y ) > height_threshold ) + { + /* vertical distance too large */ + hit = 0; + continue; + } + + /* same test as above */ + dist = FT_ABS( points[last].y - points[first].y ); + if ( dist > 5 ) + if ( FT_ABS( points[last].x - points[first].x ) <= + 20 * dist ) + { + hit = 0; + continue; + } + + if ( FT_CURVE_TAG( outline.tags[last] ) == FT_CURVE_TAG_ON ) + { + p_last = last; + if ( p_first < 0 ) + p_first = last; + } + + l2r = FT_BOOL( points[first].x < points[last].x ); + d = FT_ABS( points[last].x - points[first].x ); + + if ( l2r == left2right && + d >= length_threshold ) + { + /* all constraints are met; update segment after finding */ + /* its end */ + do + { + if ( last < best_contour_last ) + last++; + else + last = best_contour_first; + + d = FT_ABS( points[last].y - points[first].y ); + if ( d > 5 ) + if ( FT_ABS( points[next].x - points[first].x ) <= + 20 * dist ) + { + last--; + break; + } + + p_last = last; + + if ( FT_CURVE_TAG( outline.tags[last] ) == + FT_CURVE_TAG_ON ) + { + p_last = last; + if ( p_first < 0 ) + p_first = last; + } + + } while ( last != best_segment_first ); + + best_y = points[first].y; + + best_segment_first = first; + best_segment_last = last; + + best_on_point_first = p_first; + best_on_point_last = p_last; + + break; + } + + } while ( last != best_segment_first ); + } + } + + FT_TRACE5(( " U+%04lX: best_y = %5ld", ch, best_y )); + + /* now set the `round' flag depending on the segment's kind: */ + /* */ + /* - if the horizontal distance between the first and last */ + /* `on' point is larger than upem/8 (value 8 is heuristic) */ + /* we have a flat segment */ + /* - if either the first or the last point of the segment is */ + /* an `off' point, the segment is round, otherwise it is */ + /* flat */ if ( best_on_point_first >= 0 && best_on_point_last >= 0 && (FT_UInt)( FT_ABS( points[best_on_point_last].x - @@ -402,8 +624,10 @@ round = 0; else round = FT_BOOL( - FT_CURVE_TAG( outline.tags[prev] ) != FT_CURVE_TAG_ON || - FT_CURVE_TAG( outline.tags[next] ) != FT_CURVE_TAG_ON ); + FT_CURVE_TAG( outline.tags[best_segment_first] ) != + FT_CURVE_TAG_ON || + FT_CURVE_TAG( outline.tags[best_segment_last] ) != + FT_CURVE_TAG_ON ); FT_TRACE5(( " (%s)\n", round ? "round" : "flat" )); } @@ -448,7 +672,7 @@ } else { - *blue_ref = flats[num_flats / 2]; + *blue_ref = flats [num_flats / 2]; *blue_shoot = rounds[num_rounds / 2]; } @@ -462,7 +686,7 @@ FT_Bool over_ref = FT_BOOL( shoot > ref ); - if ( AF_LATIN_IS_TOP_BLUE( bb ) ^ over_ref ) + if ( AF_LATIN_IS_TOP_BLUE( bs ) ^ over_ref ) { *blue_ref = *blue_shoot = ( shoot + ref ) / 2; @@ -473,7 +697,7 @@ } blue->flags = 0; - if ( AF_LATIN_IS_TOP_BLUE( bb ) ) + if ( AF_LATIN_IS_TOP_BLUE( bs ) ) blue->flags |= AF_LATIN_BLUE_TOP; /* @@ -481,7 +705,7 @@ * in order to optimize the pixel grid alignment of the top of small * letters. */ - if ( bb == AF_LATIN_BLUE_SMALL_TOP ) + if ( AF_LATIN_IS_X_HEIGHT_BLUE( bs ) ) blue->flags |= AF_LATIN_BLUE_ADJUSTMENT; FT_TRACE5(( " -> reference = %ld\n" @@ -650,7 +874,20 @@ else #endif if ( dim == AF_DIMENSION_VERT ) + { scale = FT_MulDiv( scale, fitted, scaled ); + + FT_TRACE5(( + "af_latin_metrics_scale_dim:" + " x height alignment (script `%s'):\n" + " " + " vertical scaling changed from %.4f to %.4f (by %d%%)\n" + "\n", + af_script_names[metrics->root.script_class->script], + axis->org_scale / 65536.0, + scale / 65536.0, + ( fitted - scaled ) * 100 / scaled )); + } } } } @@ -669,6 +906,10 @@ metrics->root.scaler.y_delta = delta; } + FT_TRACE5(( "%s widths (script `%s')\n", + dim == AF_DIMENSION_HORZ ? "horizontal" : "vertical", + af_script_names[metrics->root.script_class->script] )); + /* scale the widths */ for ( nn = 0; nn < axis->width_count; nn++ ) { @@ -677,15 +918,31 @@ width->cur = FT_MulFix( width->org, scale ); width->fit = width->cur; + + FT_TRACE5(( " %d scaled to %.2f\n", + width->org, + width->cur / 64.0 )); } + FT_TRACE5(( "\n" )); + /* an extra-light axis corresponds to a standard width that is */ /* smaller than 5/8 pixels */ axis->extra_light = (FT_Bool)( FT_MulFix( axis->standard_width, scale ) < 32 + 8 ); +#ifdef FT_DEBUG_LEVEL_TRACE + if ( axis->extra_light ) + FT_TRACE5(( "`%s' script is extra light (at current resolution)\n" + "\n", + af_script_names[metrics->root.script_class->script] )); +#endif + if ( dim == AF_DIMENSION_VERT ) { + FT_TRACE5(( "blue zones (script `%s')\n", + af_script_names[metrics->root.script_class->script] )); + /* scale the blue zones */ for ( nn = 0; nn < axis->blue_count; nn++ ) { @@ -757,6 +1014,19 @@ #endif blue->flags |= AF_LATIN_BLUE_ACTIVE; + + FT_TRACE5(( " reference %d: %d scaled to %.2f%s\n" + " overshoot %d: %d scaled to %.2f%s\n", + nn, + blue->ref.org, + blue->ref.fit / 64.0, + blue->flags & AF_LATIN_BLUE_ACTIVE ? "" + : " (inactive)", + nn, + blue->shoot.org, + blue->shoot.fit / 64.0, + blue->flags & AF_LATIN_BLUE_ACTIVE ? "" + : " (inactive)" )); } } } @@ -1654,8 +1924,8 @@ AF_Edge_Flags base_flags, AF_Edge_Flags stem_flags ) { - AF_LatinMetrics metrics = (AF_LatinMetrics) hints->metrics; - AF_LatinAxis axis = & metrics->axis[dim]; + AF_LatinMetrics metrics = (AF_LatinMetrics)hints->metrics; + AF_LatinAxis axis = &metrics->axis[dim]; FT_Pos dist = width; FT_Int sign = 0; FT_Int vertical = ( dim == AF_DIMENSION_VERT ); @@ -1878,8 +2148,9 @@ #endif - FT_TRACE5(( "%s edge hinting\n", - dim == AF_DIMENSION_VERT ? "horizontal" : "vertical" )); + FT_TRACE5(( "latin %s edge hinting (script `%s')\n", + dim == AF_DIMENSION_VERT ? "horizontal" : "vertical", + af_script_names[hints->metrics->script_class->script] )); /* we begin by aligning all stems relative to the blue zone */ /* if needed -- that's only for horizontal edges */ @@ -2414,6 +2685,7 @@ af_glyph_hints_align_weak_points( hints, (AF_Dimension)dim ); } } + af_glyph_hints_save( hints, outline ); Exit: @@ -2430,10 +2702,26 @@ /*************************************************************************/ + AF_DEFINE_WRITING_SYSTEM_CLASS( + af_latin_writing_system_class, + + AF_WRITING_SYSTEM_LATIN, + + sizeof ( AF_LatinMetricsRec ), + + (AF_Script_InitMetricsFunc) af_latin_metrics_init, + (AF_Script_ScaleMetricsFunc)af_latin_metrics_scale, + (AF_Script_DoneMetricsFunc) NULL, + + (AF_Script_InitHintsFunc) af_latin_hints_init, + (AF_Script_ApplyHintsFunc) af_latin_hints_apply + ) + + /* XXX: this should probably fine tuned to differentiate better between */ /* scripts... */ - static const AF_Script_UniRangeRec af_latin_uniranges[] = + static const AF_Script_UniRangeRec af_latn_uniranges[] = { AF_UNIRANGE_REC( 0x0020UL, 0x007FUL ), /* Basic Latin (no control chars) */ AF_UNIRANGE_REC( 0x00A0UL, 0x00FFUL ), /* Latin-1 Supplement (no control chars) */ @@ -2442,23 +2730,17 @@ AF_UNIRANGE_REC( 0x0250UL, 0x02AFUL ), /* IPA Extensions */ AF_UNIRANGE_REC( 0x02B0UL, 0x02FFUL ), /* Spacing Modifier Letters */ AF_UNIRANGE_REC( 0x0300UL, 0x036FUL ), /* Combining Diacritical Marks */ - AF_UNIRANGE_REC( 0x0370UL, 0x03FFUL ), /* Greek and Coptic */ - AF_UNIRANGE_REC( 0x0400UL, 0x04FFUL ), /* Cyrillic */ - AF_UNIRANGE_REC( 0x0500UL, 0x052FUL ), /* Cyrillic Supplement */ AF_UNIRANGE_REC( 0x1D00UL, 0x1D7FUL ), /* Phonetic Extensions */ AF_UNIRANGE_REC( 0x1D80UL, 0x1DBFUL ), /* Phonetic Extensions Supplement */ AF_UNIRANGE_REC( 0x1DC0UL, 0x1DFFUL ), /* Combining Diacritical Marks Supplement */ AF_UNIRANGE_REC( 0x1E00UL, 0x1EFFUL ), /* Latin Extended Additional */ - AF_UNIRANGE_REC( 0x1F00UL, 0x1FFFUL ), /* Greek Extended */ AF_UNIRANGE_REC( 0x2000UL, 0x206FUL ), /* General Punctuation */ AF_UNIRANGE_REC( 0x2070UL, 0x209FUL ), /* Superscripts and Subscripts */ AF_UNIRANGE_REC( 0x20A0UL, 0x20CFUL ), /* Currency Symbols */ AF_UNIRANGE_REC( 0x2150UL, 0x218FUL ), /* Number Forms */ AF_UNIRANGE_REC( 0x2460UL, 0x24FFUL ), /* Enclosed Alphanumerics */ AF_UNIRANGE_REC( 0x2C60UL, 0x2C7FUL ), /* Latin Extended-C */ - AF_UNIRANGE_REC( 0x2DE0UL, 0x2DFFUL ), /* Cyrillic Extended-A */ AF_UNIRANGE_REC( 0x2E00UL, 0x2E7FUL ), /* Supplemental Punctuation */ - AF_UNIRANGE_REC( 0xA640UL, 0xA69FUL ), /* Cyrillic Extended-B */ AF_UNIRANGE_REC( 0xA720UL, 0xA7FFUL ), /* Latin Extended-D */ AF_UNIRANGE_REC( 0xFB00UL, 0xFB06UL ), /* Alphab. Present. Forms (Latin Ligs) */ AF_UNIRANGE_REC( 0x1D400UL, 0x1D7FFUL ), /* Mathematical Alphanumeric Symbols */ @@ -2466,20 +2748,72 @@ AF_UNIRANGE_REC( 0UL, 0UL ) }; + static const AF_Script_UniRangeRec af_grek_uniranges[] = + { + AF_UNIRANGE_REC( 0x0370UL, 0x03FFUL ), /* Greek and Coptic */ + AF_UNIRANGE_REC( 0x1F00UL, 0x1FFFUL ), /* Greek Extended */ + AF_UNIRANGE_REC( 0UL, 0UL ) + }; - AF_DEFINE_SCRIPT_CLASS( af_latin_script_class, - AF_SCRIPT_LATIN, - af_latin_uniranges, - 'o', + static const AF_Script_UniRangeRec af_cyrl_uniranges[] = + { + AF_UNIRANGE_REC( 0x0400UL, 0x04FFUL ), /* Cyrillic */ + AF_UNIRANGE_REC( 0x0500UL, 0x052FUL ), /* Cyrillic Supplement */ + AF_UNIRANGE_REC( 0x2DE0UL, 0x2DFFUL ), /* Cyrillic Extended-A */ + AF_UNIRANGE_REC( 0xA640UL, 0xA69FUL ), /* Cyrillic Extended-B */ + AF_UNIRANGE_REC( 0UL, 0UL ) + }; - sizeof ( AF_LatinMetricsRec ), + static const AF_Script_UniRangeRec af_hebr_uniranges[] = + { + AF_UNIRANGE_REC( 0x0590UL, 0x05FFUL ), /* Hebrew */ + AF_UNIRANGE_REC( 0xFB1DUL, 0xFB4FUL ), /* Alphab. Present. Forms (Hebrew) */ + AF_UNIRANGE_REC( 0UL, 0UL ) + }; - (AF_Script_InitMetricsFunc) af_latin_metrics_init, - (AF_Script_ScaleMetricsFunc)af_latin_metrics_scale, - (AF_Script_DoneMetricsFunc) NULL, - (AF_Script_InitHintsFunc) af_latin_hints_init, - (AF_Script_ApplyHintsFunc) af_latin_hints_apply + AF_DEFINE_SCRIPT_CLASS( + af_latn_script_class, + + AF_SCRIPT_LATN, + AF_BLUE_STRINGSET_LATN, + AF_WRITING_SYSTEM_LATIN, + + af_latn_uniranges, + 'o' + ) + + AF_DEFINE_SCRIPT_CLASS( + af_grek_script_class, + + AF_SCRIPT_GREK, + AF_BLUE_STRINGSET_GREK, + AF_WRITING_SYSTEM_LATIN, + + af_grek_uniranges, + 0x3BF /* ο */ + ) + + AF_DEFINE_SCRIPT_CLASS( + af_cyrl_script_class, + + AF_SCRIPT_CYRL, + AF_BLUE_STRINGSET_CYRL, + AF_WRITING_SYSTEM_LATIN, + + af_cyrl_uniranges, + 0x43E /* о */ + ) + + AF_DEFINE_SCRIPT_CLASS( + af_hebr_script_class, + + AF_SCRIPT_HEBR, + AF_BLUE_STRINGSET_HEBR, + AF_WRITING_SYSTEM_LATIN, + + af_hebr_uniranges, + 0x5DD /* ם */ ) diff --git a/src/autofit/aflatin.h b/src/autofit/aflatin.h index d9170b3..c06cbd9 100644 --- a/src/autofit/aflatin.h +++ b/src/autofit/aflatin.h @@ -4,7 +4,7 @@ /* */ /* Auto-fitter hinting routines for latin script (specification). */ /* */ -/* Copyright 2003-2007, 2009, 2011-2012 by */ +/* Copyright 2003-2007, 2009, 2011-2013 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -24,10 +24,20 @@ FT_BEGIN_HEADER + /* the `latin' writing system */ - /* the latin-specific script class */ + AF_DECLARE_WRITING_SYSTEM_CLASS( af_latin_writing_system_class ) - AF_DECLARE_SCRIPT_CLASS( af_latin_script_class ) + + /* the latin-specific script classes */ + + AF_DECLARE_SCRIPT_CLASS( af_cyrl_script_class ) + AF_DECLARE_SCRIPT_CLASS( af_grek_script_class ) + AF_DECLARE_SCRIPT_CLASS( af_latn_script_class ) + AF_DECLARE_SCRIPT_CLASS( af_hebr_script_class ) +#if 0 + AF_DECLARE_SCRIPT_CLASS( af_armn_script_class ) +#endif /* constants are given with units_per_em == 2048 in mind */ @@ -51,27 +61,14 @@ FT_BEGIN_HEADER */ - /* Latin (global) metrics management */ - - enum - { - AF_LATIN_BLUE_CAPITAL_TOP, - AF_LATIN_BLUE_CAPITAL_BOTTOM, - AF_LATIN_BLUE_SMALL_F_TOP, - AF_LATIN_BLUE_SMALL_TOP, - AF_LATIN_BLUE_SMALL_BOTTOM, - AF_LATIN_BLUE_SMALL_MINOR, - - AF_LATIN_BLUE_MAX - }; - - -#define AF_LATIN_IS_TOP_BLUE( b ) ( (b) == AF_LATIN_BLUE_CAPITAL_TOP || \ - (b) == AF_LATIN_BLUE_SMALL_F_TOP || \ - (b) == AF_LATIN_BLUE_SMALL_TOP ) +#define AF_LATIN_IS_TOP_BLUE( b ) \ + ( (b)->properties & AF_BLUE_PROPERTY_LATIN_TOP ) +#define AF_LATIN_IS_X_HEIGHT_BLUE( b ) \ + ( (b)->properties & AF_BLUE_PROPERTY_LATIN_X_HEIGHT ) +#define AF_LATIN_IS_LONG_BLUE( b ) \ + ( (b)->properties & AF_BLUE_PROPERTY_LATIN_LONG ) #define AF_LATIN_MAX_WIDTHS 16 -#define AF_LATIN_MAX_BLUES AF_LATIN_BLUE_MAX enum @@ -106,7 +103,7 @@ FT_BEGIN_HEADER /* ignored for horizontal metrics */ FT_UInt blue_count; - AF_LatinBlueRec blues[AF_LATIN_BLUE_MAX]; + AF_LatinBlueRec blues[AF_BLUE_STRINGSET_MAX]; FT_Fixed org_scale; FT_Pos org_delta; diff --git a/src/autofit/aflatin2.c b/src/autofit/aflatin2.c index b1e9658..a6d564a 100644 --- a/src/autofit/aflatin2.c +++ b/src/autofit/aflatin2.c @@ -76,8 +76,9 @@ AF_Scaler scaler = &dummy->root.scaler; - glyph_index = FT_Get_Char_Index( face, - metrics->root.clazz->standard_char ); + glyph_index = FT_Get_Char_Index( + face, + metrics->root.script_class->standard_char ); if ( glyph_index == 0 ) goto Exit; @@ -409,11 +410,11 @@ blue->flags |= AF_LATIN_BLUE_TOP; /* - * The following flags is used later to adjust the y and x scales + * The following flag is used later to adjust the y and x scales * in order to optimize the pixel grid alignment of the top of small * letters. */ - if ( bb == AF_LATIN_BLUE_SMALL_TOP ) + if ( AF_LATIN_IS_X_HEIGHT_BLUE( bb ) ) blue->flags |= AF_LATIN_BLUE_ADJUSTMENT; FT_TRACE5(( " -> reference = %ld\n" @@ -2379,18 +2380,10 @@ /*************************************************************************/ - static const AF_Script_UniRangeRec af_latin2_uniranges[] = - { - AF_UNIRANGE_REC( 32UL, 127UL ), /* TODO: Add new Unicode ranges here! */ - AF_UNIRANGE_REC( 160UL, 255UL ), - AF_UNIRANGE_REC( 0UL, 0UL ) - }; + AF_DEFINE_WRITING_SYSTEM_CLASS( + af_latin2_writing_system_class, - - AF_DEFINE_SCRIPT_CLASS( af_latin2_script_class, - AF_SCRIPT_LATIN2, - af_latin2_uniranges, - 'o', + AF_WRITING_SYSTEM_LATIN2, sizeof ( AF_LatinMetricsRec ), @@ -2403,4 +2396,53 @@ ) + /* XXX: this should probably fine tuned to differentiate better between */ + /* scripts... */ + + static const AF_Script_UniRangeRec af_ltn2_uniranges[] = + { + AF_UNIRANGE_REC( 0x0020UL, 0x007FUL ), /* Basic Latin (no control chars) */ + AF_UNIRANGE_REC( 0x00A0UL, 0x00FFUL ), /* Latin-1 Supplement (no control chars) */ + AF_UNIRANGE_REC( 0x0100UL, 0x017FUL ), /* Latin Extended-A */ + AF_UNIRANGE_REC( 0x0180UL, 0x024FUL ), /* Latin Extended-B */ + AF_UNIRANGE_REC( 0x0250UL, 0x02AFUL ), /* IPA Extensions */ + AF_UNIRANGE_REC( 0x02B0UL, 0x02FFUL ), /* Spacing Modifier Letters */ + AF_UNIRANGE_REC( 0x0300UL, 0x036FUL ), /* Combining Diacritical Marks */ + AF_UNIRANGE_REC( 0x0370UL, 0x03FFUL ), /* Greek and Coptic */ + AF_UNIRANGE_REC( 0x0400UL, 0x04FFUL ), /* Cyrillic */ + AF_UNIRANGE_REC( 0x0500UL, 0x052FUL ), /* Cyrillic Supplement */ + AF_UNIRANGE_REC( 0x1D00UL, 0x1D7FUL ), /* Phonetic Extensions */ + AF_UNIRANGE_REC( 0x1D80UL, 0x1DBFUL ), /* Phonetic Extensions Supplement */ + AF_UNIRANGE_REC( 0x1DC0UL, 0x1DFFUL ), /* Combining Diacritical Marks Supplement */ + AF_UNIRANGE_REC( 0x1E00UL, 0x1EFFUL ), /* Latin Extended Additional */ + AF_UNIRANGE_REC( 0x1F00UL, 0x1FFFUL ), /* Greek Extended */ + AF_UNIRANGE_REC( 0x2000UL, 0x206FUL ), /* General Punctuation */ + AF_UNIRANGE_REC( 0x2070UL, 0x209FUL ), /* Superscripts and Subscripts */ + AF_UNIRANGE_REC( 0x20A0UL, 0x20CFUL ), /* Currency Symbols */ + AF_UNIRANGE_REC( 0x2150UL, 0x218FUL ), /* Number Forms */ + AF_UNIRANGE_REC( 0x2460UL, 0x24FFUL ), /* Enclosed Alphanumerics */ + AF_UNIRANGE_REC( 0x2C60UL, 0x2C7FUL ), /* Latin Extended-C */ + AF_UNIRANGE_REC( 0x2DE0UL, 0x2DFFUL ), /* Cyrillic Extended-A */ + AF_UNIRANGE_REC( 0x2E00UL, 0x2E7FUL ), /* Supplemental Punctuation */ + AF_UNIRANGE_REC( 0xA640UL, 0xA69FUL ), /* Cyrillic Extended-B */ + AF_UNIRANGE_REC( 0xA720UL, 0xA7FFUL ), /* Latin Extended-D */ + AF_UNIRANGE_REC( 0xFB00UL, 0xFB06UL ), /* Alphab. Present. Forms (Latin Ligs) */ + AF_UNIRANGE_REC( 0x1D400UL, 0x1D7FFUL ), /* Mathematical Alphanumeric Symbols */ + AF_UNIRANGE_REC( 0x1F100UL, 0x1F1FFUL ), /* Enclosed Alphanumeric Supplement */ + AF_UNIRANGE_REC( 0UL, 0UL ) + }; + + + AF_DEFINE_SCRIPT_CLASS( + af_ltn2_script_class, + + AF_SCRIPT_LTN2, + AF_BLUE_STRINGSET_LATN, + AF_WRITING_SYSTEM_LATIN2, + + af_ltn2_uniranges, + 'o' + ) + + /* END */ diff --git a/src/autofit/aflatin2.h b/src/autofit/aflatin2.h index cbfa395..f7f6d8d 100644 --- a/src/autofit/aflatin2.h +++ b/src/autofit/aflatin2.h @@ -4,7 +4,7 @@ /* */ /* Auto-fitter hinting routines for latin script (specification). */ /* */ -/* Copyright 2003-2007, 2012 by */ +/* Copyright 2003-2007, 2012, 2013 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -25,9 +25,21 @@ FT_BEGIN_HEADER - /* the latin-specific script class */ + /* the `latin' writing system */ + + AF_DECLARE_WRITING_SYSTEM_CLASS( af_latin2_writing_system_class ) + + + /* the latin-specific script classes */ + + AF_DECLARE_SCRIPT_CLASS( af_ltn2_script_class ) /* XXX */ +#if 0 + AF_DECLARE_SCRIPT_CLASS( af_arm2_script_class ) + AF_DECLARE_SCRIPT_CLASS( af_cyr2_script_class ) + AF_DECLARE_SCRIPT_CLASS( af_grk2_script_class ) + AF_DECLARE_SCRIPT_CLASS( af_hbr2_script_class ) +#endif - AF_DECLARE_SCRIPT_CLASS( af_latin2_script_class ) /* */ diff --git a/src/autofit/afloader.c b/src/autofit/afloader.c index 17a6fb7..400b01e 100644 --- a/src/autofit/afloader.c +++ b/src/autofit/afloader.c @@ -21,6 +21,7 @@ #include "afhints.h" #include "aferrors.h" #include "afmodule.h" +#include "afpic.h" /* Initialize glyph loader. */ @@ -180,10 +181,20 @@ /* now load the slot image into the auto-outline and run the */ /* automatic hinting process */ - if ( metrics->clazz->script_hints_apply ) - metrics->clazz->script_hints_apply( hints, - &gloader->current.outline, - metrics ); + { +#ifdef FT_CONFIG_OPTION_PIC + AF_FaceGlobals globals = loader->globals; +#endif + AF_WritingSystemClass writing_system_class = + AF_WRITING_SYSTEM_CLASSES_GET + [metrics->script_class->writing_system]; + + + if ( writing_system_class->script_hints_apply ) + writing_system_class->script_hints_apply( hints, + &gloader->current.outline, + metrics ); + } /* we now need to adjust the metrics according to the change in */ /* width/positioning that occurred during the hinting process */ @@ -519,33 +530,41 @@ if ( !error ) { AF_ScriptMetrics metrics; - FT_UInt options = 0; + FT_UInt options = AF_SCRIPT_NONE; #ifdef FT_OPTION_AUTOFIT2 - /* XXX: undocumented hook to activate the latin2 hinter */ + /* XXX: undocumented hook to activate the latin2 writing system */ if ( load_flags & ( 1UL << 20 ) ) - options = 2; + options = AF_SCRIPT_LTN2; #endif error = af_face_globals_get_metrics( loader->globals, gindex, options, &metrics ); if ( !error ) { +#ifdef FT_CONFIG_OPTION_PIC + AF_FaceGlobals globals = loader->globals; +#endif + AF_WritingSystemClass writing_system_class = + AF_WRITING_SYSTEM_CLASSES_GET + [metrics->script_class->writing_system]; + + loader->metrics = metrics; - if ( metrics->clazz->script_metrics_scale ) - metrics->clazz->script_metrics_scale( metrics, &scaler ); + if ( writing_system_class->script_metrics_scale ) + writing_system_class->script_metrics_scale( metrics, &scaler ); else metrics->scaler = scaler; load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_IGNORE_TRANSFORM; load_flags &= ~FT_LOAD_RENDER; - if ( metrics->clazz->script_hints_init ) + if ( writing_system_class->script_hints_init ) { - error = metrics->clazz->script_hints_init( &loader->hints, - metrics ); + error = writing_system_class->script_hints_init( &loader->hints, + metrics ); if ( error ) goto Exit; } diff --git a/src/autofit/afpic.c b/src/autofit/afpic.c index 45e1448..92d696d 100644 --- a/src/autofit/afpic.c +++ b/src/autofit/afpic.c @@ -43,13 +43,10 @@ /* forward declaration of PIC init functions from script classes */ -#include "aflatin.h" -#ifdef FT_OPTION_AUTOFIT2 -#include "aflatin2.h" -#endif -#include "afcjk.h" -#include "afdummy.h" -#include "afindic.h" +#undef WRITING_SYSTEM +#define WRITING_SYSTEM( ws, WS ) /* empty */ + +#include "afwrtsys.h" void @@ -100,27 +97,31 @@ FT_Init_Class_af_service_properties( &container->af_service_properties ); - for ( ss = 0 ; ss < AF_SCRIPT_CLASSES_REC_COUNT ; ss++ ) - { + for ( ss = 0; ss < AF_WRITING_SYSTEM_MAX - 1; ss++ ) + container->af_writing_system_classes[ss] = + &container->af_writing_system_classes_rec[ss]; + container->af_writing_system_classes[AF_WRITING_SYSTEM_MAX - 1] = NULL; + + for ( ss = 0; ss < AF_SCRIPT_MAX - 1; ss++ ) container->af_script_classes[ss] = &container->af_script_classes_rec[ss]; - } - container->af_script_classes[AF_SCRIPT_CLASSES_COUNT - 1] = NULL; + container->af_script_classes[AF_SCRIPT_MAX - 1] = NULL; + +#undef WRITING_SYSTEM +#define WRITING_SYSTEM( ws, WS ) \ + FT_Init_Class_af_ ## ws ## _writing_system_class( \ + &container->af_writing_system_classes_rec[ss++] ); + + ss = 0; +#include "afwrtsys.h" + +#undef SCRIPT +#define SCRIPT( s, S, d ) \ + FT_Init_Class_af_ ## s ## _script_class( \ + &container->af_script_classes_rec[ss++] ); - /* add call to initialization function when you add new scripts */ ss = 0; - FT_Init_Class_af_dummy_script_class( - &container->af_script_classes_rec[ss++] ); -#ifdef FT_OPTION_AUTOFIT2 - FT_Init_Class_af_latin2_script_class( - &container->af_script_classes_rec[ss++] ); -#endif - FT_Init_Class_af_latin_script_class( - &container->af_script_classes_rec[ss++] ); - FT_Init_Class_af_cjk_script_class( - &container->af_script_classes_rec[ss++] ); - FT_Init_Class_af_indic_script_class( - &container->af_script_classes_rec[ss++] ); +#include "afscript.h" FT_Init_Class_af_autofitter_interface( library, &container->af_autofitter_interface ); diff --git a/src/autofit/afpic.h b/src/autofit/afpic.h index 0acf803..09f8258 100644 --- a/src/autofit/afpic.h +++ b/src/autofit/afpic.h @@ -4,7 +4,7 @@ /* */ /* The FreeType position independent code services for autofit module. */ /* */ -/* Copyright 2009, 2011-2012 by */ +/* Copyright 2009, 2011-2013 by */ /* Oran Agra and Mickey Gabel. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -27,11 +27,12 @@ FT_BEGIN_HEADER #ifndef FT_CONFIG_OPTION_PIC -#define AF_SERVICES_GET af_services -#define AF_SERVICE_PROPERTIES_GET af_service_properties +#define AF_SERVICES_GET af_services +#define AF_SERVICE_PROPERTIES_GET af_service_properties -#define AF_SCRIPT_CLASSES_GET af_script_classes -#define AF_INTERFACE_GET af_autofitter_interface +#define AF_WRITING_SYSTEM_CLASSES_GET af_writing_system_classes +#define AF_SCRIPT_CLASSES_GET af_script_classes +#define AF_INTERFACE_GET af_autofitter_interface #else /* FT_CONFIG_OPTION_PIC */ @@ -40,24 +41,22 @@ FT_BEGIN_HEADER #include "aftypes.h" - /* increase these when you add new scripts, */ - /* and update autofit_module_class_pic_init */ -#ifdef FT_OPTION_AUTOFIT2 -#define AF_SCRIPT_CLASSES_COUNT 6 -#else -#define AF_SCRIPT_CLASSES_COUNT 5 -#endif - -#define AF_SCRIPT_CLASSES_REC_COUNT ( AF_SCRIPT_CLASSES_COUNT - 1 ) - typedef struct AFModulePIC_ { FT_ServiceDescRec* af_services; FT_Service_PropertiesRec af_service_properties; - AF_ScriptClass af_script_classes[AF_SCRIPT_CLASSES_COUNT]; - AF_ScriptClassRec af_script_classes_rec[AF_SCRIPT_CLASSES_REC_COUNT]; + AF_WritingSystemClass af_writing_system_classes + [AF_WRITING_SYSTEM_MAX]; + AF_WritingSystemClassRec af_writing_system_classes_rec + [AF_WRITING_SYSTEM_MAX - 1]; + + AF_ScriptClass af_script_classes + [AF_SCRIPT_MAX]; + AF_ScriptClassRec af_script_classes_rec + [AF_SCRIPT_MAX - 1]; + FT_AutoHinter_InterfaceRec af_autofitter_interface; } AFModulePIC; @@ -71,6 +70,8 @@ FT_BEGIN_HEADER #define AF_SERVICE_PROPERTIES_GET \ ( GET_PIC( library )->af_service_properties ) +#define AF_WRITING_SYSTEM_CLASSES_GET \ + ( GET_PIC( FT_FACE_LIBRARY( globals->face ) )->af_writing_system_classes ) #define AF_SCRIPT_CLASSES_GET \ ( GET_PIC( FT_FACE_LIBRARY( globals->face ) )->af_script_classes ) #define AF_INTERFACE_GET \ diff --git a/src/autofit/afscript.h b/src/autofit/afscript.h new file mode 100644 index 0000000..32ec2ca --- /dev/null +++ b/src/autofit/afscript.h @@ -0,0 +1,37 @@ +/***************************************************************************/ +/* */ +/* afscript.h */ +/* */ +/* Auto-fitter scripts (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. */ +/* */ +/***************************************************************************/ + + + /* The following part can be included multiple times. */ + /* Define `SCRIPT' as needed. */ + + + /* Add new scripts here. */ + + SCRIPT( cyrl, CYRL, "Cyrillic" ) + SCRIPT( deva, DEVA, "Indic scripts" ) + SCRIPT( none, NONE, "no script" ) + SCRIPT( grek, GREK, "Greek" ) + SCRIPT( hani, HANI, "CJKV ideographs" ) + SCRIPT( hebr, HEBR, "Hebrew" ) + SCRIPT( latn, LATN, "Latin" ) +#ifdef FT_OPTION_AUTOFIT2 + SCRIPT( ltn2, LTN2, "Latin 2" ) +#endif + + +/* END */ diff --git a/src/autofit/aftypes.h b/src/autofit/aftypes.h index 9acd7ad..cda1f89 100644 --- a/src/autofit/aftypes.h +++ b/src/autofit/aftypes.h @@ -4,7 +4,7 @@ /* */ /* Auto-fitter types (specification only). */ /* */ -/* Copyright 2003-2009, 2011-2012 by */ +/* Copyright 2003-2009, 2011-2013 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -20,15 +20,12 @@ * * The auto-fitter is a complete rewrite of the old auto-hinter. * Its main feature is the ability to differentiate between different - * scripts in order to apply language-specific rules. + * writing systems in order to apply script-specific rules. * * The code has also been compartmentized into several entities that * should make algorithmic experimentation easier than with the old * code. * - * Finally, we get rid of the Catharon license, since this code is - * released under the FreeType one. - * *************************************************************************/ @@ -42,6 +39,8 @@ #include FT_INTERNAL_OBJECTS_H #include FT_INTERNAL_DEBUG_H +#include "afblue.h" + FT_BEGIN_HEADER @@ -201,56 +200,21 @@ extern void* _af_debug_hints; /*************************************************************************/ /*************************************************************************/ /***** *****/ - /***** S C R I P T S *****/ + /***** S C R I P T M E T R I C S *****/ /***** *****/ /*************************************************************************/ /*************************************************************************/ - /* - * The list of known scripts. Each different script corresponds to the - * following information: - * - * - A set of Unicode ranges to test whether the face supports the - * script. - * - * - A specific global analyzer that will compute global metrics - * specific to the script. - * - * - A specific glyph analyzer that will compute segments and - * edges for each glyph covered by the script. - * - * - A specific grid-fitting algorithm that will distort the - * scaled glyph outline according to the results of the glyph - * analyzer. - * - * Note that a given analyzer and/or grid-fitting algorithm can be - * used by more than one script. - */ - - typedef enum AF_Script_ - { - AF_SCRIPT_DUMMY = 0, - AF_SCRIPT_LATIN = 1, - AF_SCRIPT_CJK = 2, - AF_SCRIPT_INDIC = 3, -#ifdef FT_OPTION_AUTOFIT2 - AF_SCRIPT_LATIN2 = 4, -#endif - - /* add new scripts here. Don't forget to update the list in */ - /* `afglobal.c'. */ - - AF_SCRIPT_MAX /* do not remove */ - - } AF_Script; + /* This is the main structure which combines writing systems and script */ + /* data (for a given face object, see below). */ - - typedef struct AF_ScriptClassRec_ const* AF_ScriptClass; - typedef struct AF_FaceGlobalsRec_* AF_FaceGlobals; + typedef struct AF_WritingSystemClassRec_ const* AF_WritingSystemClass; + typedef struct AF_ScriptClassRec_ const* AF_ScriptClass; + typedef struct AF_FaceGlobalsRec_* AF_FaceGlobals; typedef struct AF_ScriptMetricsRec_ { - AF_ScriptClass clazz; + AF_ScriptClass script_class; AF_ScalerRec scaler; FT_Bool digits_have_same_width; @@ -284,23 +248,54 @@ extern void* _af_debug_hints; AF_ScriptMetrics metrics ); - typedef struct AF_Script_UniRangeRec_ + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** W R I T I N G S Y S T E M S *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* + * In FreeType, a writing system consists of multiple scripts which can + * be handled similarly *in a typographical way*; the relationship is not + * based on history. For example, both the Greek and the unrelated + * Armenian scripts share the same features like ascender, descender, + * x-height, etc. Essentially, a writing system is covered by a + * submodule of the auto-fitter; it contains + * + * - a specific global analyzer which computes global metrics specific to + * the script (based on script-specific characters to identify ascender + * height, x-height, etc.), + * + * - a specific glyph analyzer that computes segments and edges for each + * glyph covered by the script, + * + * - a specific grid-fitting algorithm that distorts the scaled glyph + * outline according to the results of the glyph analyzer. + */ + +#define __AFWRTSYS_H__ /* don't load header files */ +#undef WRITING_SYSTEM +#define WRITING_SYSTEM( ws, WS ) \ + AF_WRITING_SYSTEM_ ## WS, + + /* The list of known writing systems. */ + typedef enum AF_WritingSystem_ { - FT_UInt32 first; - FT_UInt32 last; - } AF_Script_UniRangeRec; +#include "afwrtsys.h" -#define AF_UNIRANGE_REC( a, b ) { (FT_UInt32)(a), (FT_UInt32)(b) } + AF_WRITING_SYSTEM_MAX /* do not remove */ - typedef const AF_Script_UniRangeRec *AF_Script_UniRange; + } AF_WritingSystem; +#undef __AFWRTSYS_H__ - typedef struct AF_ScriptClassRec_ + + typedef struct AF_WritingSystemClassRec_ { - AF_Script script; - AF_Script_UniRange script_uni_ranges; /* last must be { 0, 0 } */ - FT_UInt32 standard_char; /* for default width and height */ + AF_WritingSystem writing_system; FT_Offset script_metrics_size; AF_Script_InitMetricsFunc script_metrics_init; @@ -310,59 +305,167 @@ extern void* _af_debug_hints; AF_Script_InitHintsFunc script_hints_init; AF_Script_ApplyHintsFunc script_hints_apply; + } AF_WritingSystemClassRec; + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** S C R I P T S *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* + * Each script is associated with a set of Unicode ranges which gets used + * to test whether the font face supports the script. It also references + * the writing system it belongs to. + * + * We use four-letter script tags from the OpenType specification. + */ + +#undef SCRIPT +#define SCRIPT( s, S, d ) \ + AF_SCRIPT_ ## S, + + /* The list of known scripts. */ + typedef enum AF_Script_ + { + +#include "afscript.h" + + AF_SCRIPT_MAX /* do not remove */ + + } AF_Script; + + + typedef struct AF_Script_UniRangeRec_ + { + FT_UInt32 first; + FT_UInt32 last; + + } AF_Script_UniRangeRec; + +#define AF_UNIRANGE_REC( a, b ) { (FT_UInt32)(a), (FT_UInt32)(b) } + + typedef const AF_Script_UniRangeRec* AF_Script_UniRange; + + + typedef struct AF_ScriptClassRec_ + { + AF_Script script; + AF_Blue_Stringset blue_stringset; + AF_WritingSystem writing_system; + + AF_Script_UniRange script_uni_ranges; /* last must be { 0, 0 } */ + FT_UInt32 standard_char; /* for default width and height */ + } AF_ScriptClassRec; /* Declare and define vtables for classes */ #ifndef FT_CONFIG_OPTION_PIC +#define AF_DECLARE_WRITING_SYSTEM_CLASS( writing_system_class ) \ + FT_CALLBACK_TABLE const AF_WritingSystemClassRec \ + writing_system_class; + +#define AF_DEFINE_WRITING_SYSTEM_CLASS( \ + writing_system_class, \ + system, \ + m_size, \ + m_init, \ + m_scale, \ + m_done, \ + h_init, \ + h_apply ) \ + FT_CALLBACK_TABLE_DEF \ + const AF_WritingSystemClassRec writing_system_class = \ + { \ + system, \ + \ + m_size, \ + \ + m_init, \ + m_scale, \ + m_done, \ + \ + h_init, \ + h_apply \ + }; + + #define AF_DECLARE_SCRIPT_CLASS( script_class ) \ FT_CALLBACK_TABLE const AF_ScriptClassRec \ script_class; -#define AF_DEFINE_SCRIPT_CLASS( script_class, script_, ranges, def_char, \ - m_size, \ - m_init, m_scale, m_done, h_init, h_apply ) \ - FT_CALLBACK_TABLE_DEF const AF_ScriptClassRec script_class = \ - { \ - script_, \ - ranges, \ - def_char, \ - \ - m_size, \ - \ - m_init, \ - m_scale, \ - m_done, \ - \ - h_init, \ - h_apply \ +#define AF_DEFINE_SCRIPT_CLASS( \ + script_class, \ + script_, \ + blue_stringset_, \ + writing_system_, \ + ranges, \ + std_char ) \ + FT_CALLBACK_TABLE_DEF \ + const AF_ScriptClassRec script_class = \ + { \ + script_, \ + blue_stringset_, \ + writing_system_, \ + ranges, \ + std_char \ }; #else /* FT_CONFIG_OPTION_PIC */ +#define AF_DECLARE_WRITING_SYSTEM_CLASS( writing_system_class ) \ + FT_LOCAL( void ) \ + FT_Init_Class_ ## writing_system_class( AF_WritingSystemClassRec* ac ); + +#define AF_DEFINE_WRITING_SYSTEM_CLASS( \ + writing_system_class, \ + system, \ + m_size, \ + m_init, \ + m_scale, \ + m_done, \ + h_init, \ + h_apply ) \ + FT_LOCAL_DEF( void ) \ + FT_Init_Class_ ## writing_system_class( AF_WritingSystemClassRec* ac ) \ + { \ + ac->writing_system = system; \ + \ + ac->script_metrics_size = m_size; \ + \ + ac->script_metrics_init = m_init; \ + ac->script_metrics_scale = m_scale; \ + ac->script_metrics_done = m_done; \ + \ + ac->script_hints_init = h_init; \ + ac->script_hints_apply = h_apply; \ + } + + #define AF_DECLARE_SCRIPT_CLASS( script_class ) \ FT_LOCAL( void ) \ FT_Init_Class_ ## script_class( AF_ScriptClassRec* ac ); -#define AF_DEFINE_SCRIPT_CLASS( script_class, script_, ranges, def_char, \ - m_size, \ - m_init, m_scale, m_done, h_init, h_apply ) \ - FT_LOCAL_DEF( void ) \ - FT_Init_Class_ ## script_class( AF_ScriptClassRec* ac ) \ - { \ - ac->script = script_; \ - ac->script_uni_ranges = ranges; \ - ac->default_char = def_char; \ - \ - ac->script_metrics_size = m_size; \ - \ - ac->script_metrics_init = m_init; \ - ac->script_metrics_scale = m_scale; \ - ac->script_metrics_done = m_done; \ - \ - ac->script_hints_init = h_init; \ - ac->script_hints_apply = h_apply; \ +#define AF_DEFINE_SCRIPT_CLASS( \ + script_class, \ + script_, \ + blue_string_set_, \ + writing_system_, \ + ranges, \ + std_char ) \ + FT_LOCAL_DEF( void ) \ + FT_Init_Class_ ## script_class( AF_ScriptClassRec* ac ) \ + { \ + ac->script = script_; \ + ac->blue_stringset = blue_stringset_; \ + ac->writing_system = writing_system_; \ + ac->script_uni_ranges = ranges; \ + ac->standard_char = std_char; \ } #endif /* FT_CONFIG_OPTION_PIC */ diff --git a/src/autofit/afwrtsys.h b/src/autofit/afwrtsys.h new file mode 100644 index 0000000..602c558 --- /dev/null +++ b/src/autofit/afwrtsys.h @@ -0,0 +1,51 @@ +/***************************************************************************/ +/* */ +/* afwrtsys.h */ +/* */ +/* Auto-fitter writing systems (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. */ +/* */ +/***************************************************************************/ + + +#ifndef __AFWRTSYS_H__ +#define __AFWRTSYS_H__ + + /* Since preprocessor directives can't create other preprocessor */ + /* directives, we have to include the header files manually. */ + +#include "afdummy.h" +#include "aflatin.h" +#include "afcjk.h" +#include "afindic.h" +#ifdef FT_OPTION_AUTOFIT2 +#include "aflatin2.h" +#endif + +#endif /* __AFWRTSYS_H__ */ + + + /* The following part can be included multiple times. */ + /* Define `WRITING_SYSTEM' as needed. */ + + + /* Add new writing systems here. */ + + WRITING_SYSTEM( dummy, DUMMY ) + WRITING_SYSTEM( latin, LATIN ) + WRITING_SYSTEM( cjk, CJK ) + WRITING_SYSTEM( indic, INDIC ) +#ifdef FT_OPTION_AUTOFIT2 + WRITING_SYSTEM( latin2, LATIN2 ) +#endif + + +/* END */ diff --git a/src/autofit/autofit.c b/src/autofit/autofit.c index 3883a0a..b23374a 100644 --- a/src/autofit/autofit.c +++ b/src/autofit/autofit.c @@ -4,7 +4,7 @@ /* */ /* Auto-fitter module (body). */ /* */ -/* Copyright 2003-2007, 2011 by */ +/* Copyright 2003-2007, 2011, 2013 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -20,6 +20,7 @@ #include <ft2build.h> #include "afpic.c" #include "afangles.c" +#include "afblue.c" #include "afglobal.c" #include "afhints.c" |