diff --git a/ChangeLog b/ChangeLog index 051ef3bda..1c57e55b0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,29 @@ +2013-08-25 Werner Lemberg + + [autofit] Introduce data file for blue strings. + + The idea is to have a central file which gets processed by a Perl + script to create proper `.c' and `.h' files using templates. There + are two other reasons to do that: + + . The data file should be easily readable. We use UTF-8 encoding + which then gets converted to single bytes. + + . Since the number of supported scripts will increase soon, the + current usage of blue string arrays is a waste of space. Using + the Perl script it is possible to imitate jagged arrays, + defining enumeration constants as offsets into the arrays. + + This commit only adds files without changing any functionality. + + * src/autofit/afblue.dat: New data file. + * src/tools/afblue.pl: New Perl script for processing `afblue.dat'. + + * src/autofit/afblue.cin, src/autofit/afblue.hin: New template files + for... + * src/autofit/afblue.c, src/autofit/afblue.c: New source files. + To avoid a dependency on Perl, we add them too. + 2013-08-19 Alexei Podtelezhnikov [base] Enable new algorithm for BBox_Cubic_Check. diff --git a/src/autofit/afblue.c b/src/autofit/afblue.c new file mode 100644 index 000000000..1c13b779c --- /dev/null +++ b/src/autofit/afblue.c @@ -0,0 +1,122 @@ +/* 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 "afblue.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 */ +#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_PROPERTY_LATIN_SMALL_TOP }, + { AF_BLUE_STRING_LATIN_SMALL, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_LATIN_SMALL, 0 }, + { AF_BLUE_STRING_LATIN_SMALL_MINOR, 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 000000000..ad47f980b --- /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 "afblue.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 000000000..5f391d3d9 --- /dev/null +++ b/src/autofit/afblue.dat @@ -0,0 +1,165 @@ +// 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_MINOR + "pqgjy" + +#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_PROPERTY_LATIN_SMALL_TOP } + { AF_BLUE_STRING_LATIN_SMALL, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_LATIN_SMALL, 0 } + { AF_BLUE_STRING_LATIN_SMALL_MINOR, 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 000000000..0699ae456 --- /dev/null +++ b/src/autofit/afblue.h @@ -0,0 +1,183 @@ +/* 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 = *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_MINOR = 34, + af_blue_1_1 = 39, +#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_SMALL_TOP ( 1 << 1 ) + +#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_2_1 = 7, +#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 000000000..071e7d97d --- /dev/null +++ b/src/autofit/afblue.hin @@ -0,0 +1,141 @@ +/***************************************************************************/ +/* */ +/* 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 = *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_SMALL_TOP ( 1 << 1 ) + +#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/tools/afblue.pl b/src/tools/afblue.pl new file mode 100644 index 000000000..774438f84 --- /dev/null +++ b/src/tools/afblue.pl @@ -0,0 +1,542 @@ +#! /usr/bin/perl -w +# -*- Perl -*- +# +# afblue.pl +# +# Process a blue zone character data file. +# +# 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. + +use strict; +use warnings; +use English '-no_match_vars'; +use open ':std', ':locale'; + + +my $prog = $PROGRAM_NAME; +$prog =~ s| .* / ||x; # Remove path. + +die "usage: $prog datafile < infile > outfile\n" if $#ARGV != 0; + + +my $datafile = $ARGV[0]; + +my %diversions; # The extracted and massaged data from `datafile'. +my @else_stack; # Booleans to track else-clauses. +my @name_stack; # Stack of integers used for names of aux. variables. + +my $curr_enum; # Name of the current enumeration. +my $curr_array; # Name of the current array. +my $curr_max; # Name of the current maximum value. + +my $curr_enum_element; # Name of the current enumeration element. +my $curr_offset; # The offset relative to current aux. variable. +my $curr_elem_size; # The size of the current string or block. + +my $have_sections = 0; # Boolean; set if start of a section has been seen. +my $have_strings; # Boolean; set if current section contains strings. +my $have_blocks; # Boolean; set if current section contains blocks. + +my $have_enum_element; # Boolean; set if we have an enumeration element. +my $in_string; # Boolean; set if a string has been parsed. + +my $num_sections = 0; # Number of sections seen so far. + +my $last_aux; # Name of last auxiliary variable. + + +# Regular expressions. + +# [] [] ':' [] '\n' +my $section_re = qr/ ^ \s* (\S+) \s+ (\S+) \s+ (\S+) \s* : \s* $ /x; + +# [] [] '\n' +my $enum_element_re = qr/ ^ \s* ( [A-Za-z0-9_]+ ) \s* $ /x; + +# '#' '\n' +my $preprocessor_re = qr/ ^ \# /x; + +# '/' '/' '\n' +my $comment_re = qr| ^ // |x; + +# empty line +my $whitespace_only_re = qr/ ^ \s* $ /x; + +# [] '"' '"' [] '\n' ( doesn't contain newlines) +my $string_re = qr/ ^ \s* + " ( (?: [^"\\]++ | \\. )*+ ) " + \s* $ /x; + +# [] '{' '}' [] '\n' ( can contain newlines) +my $block_start_re = qr/ ^ \s* \{ /x; + +# We need the capturing group for `split' to make it return the separator +# tokens (i.e., the opening and closing brace) also. +my $brace_re = qr/ ( [{}] ) /x; + + +sub Warn +{ + my $message = shift; + warn "$datafile:$INPUT_LINE_NUMBER: warning: $message\n"; +} + + +sub Die +{ + my $message = shift; + die "$datafile:$INPUT_LINE_NUMBER: error: $message\n"; +} + + +my $warned_before = 0; + +sub warn_before +{ + Warn("data before first section gets ignored") unless $warned_before; + $warned_before = 1; +} + + +sub strip_newline +{ + chomp; + s/ \x0D $ //x; +} + + +sub end_curr_string +{ + # Append final null byte to string. + if ($have_strings) + { + push @{$diversions{$curr_array}}, " '\\0',\n" if $in_string; + + $curr_offset++; + $in_string = 0; + } +} + + +sub update_max_elem_size +{ + if ($curr_elem_size) + { + my $max = pop @{$diversions{$curr_max}}; + $max = $curr_elem_size if $curr_elem_size > $max; + push @{$diversions{$curr_max}}, $max; + } +} + + +sub convert_non_ascii_char +{ + # A UTF-8 character outside of the printable ASCII range, with possibly a + # leading backslash character. + my $s = shift; + + # Here we count characters, not bytes. + $curr_elem_size += length $s; + + utf8::encode($s); + $s = uc unpack 'H*', $s; + + $curr_offset += $s =~ s/\G(..)/'\\x$1', /sg; + + return $s; +} + + +sub convert_ascii_chars +{ + # A series of ASCII characters in the printable range. + my $s = shift; + + my $count = $s =~ s/\G(.)/'$1', /g; + $curr_offset += $count; + $curr_elem_size += $count; + + return $s; +} + + +sub convert_literal +{ + my $s = shift; + my $orig = $s; + + # ASCII printables and space + my $safe_re = '\x20-\x7E'; + # ASCII printables and space, no backslash + my $safe_no_backslash_re = '\x20-\x5B\x5D-\x7E'; + + $s =~ s{ + (?: \\? ( [^$safe_re] ) + | ( (?: [$safe_no_backslash_re] + | \\ [$safe_re] )+ ) ) + } + { + defined($1) ? convert_non_ascii_char($1) + : convert_ascii_chars($2) + }egx; + + # We assume that `$orig' doesn't contain `*/' + return $s . " /* $orig */"; +} + + +sub aux_name +{ + return "af_blue_" . $num_sections. "_" . join('_', reverse @name_stack); +} + + +sub aux_name_next +{ + $name_stack[$#name_stack]++; + my $name = aux_name(); + $name_stack[$#name_stack]--; + + return $name; +} + + +sub enum_val_string +{ + # Build string which holds code to save the current offset in an + # enumeration element. + my $aux = shift; + + my $add = ($last_aux eq "af_blue_" . $num_sections . "_0" ) + ? "" + : "$last_aux + "; + + return " $aux = $add$curr_offset,\n"; +} + + + +# Process data file. + +open(DATA, $datafile) || die "$prog: can't open \`$datafile': $OS_ERROR\n"; + +while () +{ + strip_newline(); + + next if /$comment_re/; + next if /$whitespace_only_re/; + + if (/$section_re/) + { + Warn("previous section is empty") if ($have_sections + && !$have_strings + && !$have_blocks); + + end_curr_string(); + update_max_elem_size(); + + # Save captured groups from `section_re'. + $curr_enum = $1; + $curr_array = $2; + $curr_max = $3; + + $curr_enum_element = ""; + $curr_offset = 0; + + Warn("overwriting already defined enumeration \`$curr_enum'") + if exists($diversions{$curr_enum}); + Warn("overwriting already defined array \`$curr_array'") + if exists($diversions{$curr_array}); + Warn("overwriting already defined maximum value \`$curr_max'") + if exists($diversions{$curr_max}); + + $diversions{$curr_enum} = []; + $diversions{$curr_array} = []; + $diversions{$curr_max} = []; + + push @{$diversions{$curr_max}}, 0; + + @name_stack = (); + push @name_stack, 0; + + $have_sections = 1; + $have_strings = 0; + $have_blocks = 0; + + $have_enum_element = 0; + $in_string = 0; + + $num_sections++; + $curr_elem_size = 0; + + $last_aux = aux_name(); + + next; + } + + if (/$preprocessor_re/) + { + if ($have_sections) + { + # Having preprocessor conditionals complicates the computation of + # correct offset values. We have to introduce auxiliary enumeration + # elements with the name `af_blue____...' which store + # offsets to be used in conditional clauses. `' is the number of + # sections seen so far, `' is the number of `#if' and `#endif' + # conditionals seen so far in the topmost level, `' the number of + # `#if' and `#endif' conditionals seen so far one level deeper, etc. + # As a consequence, uneven values are used within a clause, and even + # values after a clause, since the C standard doesn't allow the + # redefinition of an enumeration value. For example, the name + # `af_blue_5_1_6' is used to construct enumeration values in the fifth + # section after the third (second-level) if-clause within the first + # (top-level) if-clause. After the first top-level clause has + # finished, `af_blue_5_2' is used. The current offset is then + # relative to the value stored in the current auxiliary element. + + if (/ ^ \# \s* if /x) + { + push @else_stack, 0; + + $name_stack[$#name_stack]++; + + push @{$diversions{$curr_enum}}, enum_val_string(aux_name()); + $last_aux = aux_name(); + + push @name_stack, 0; + + $curr_offset = 0; + } + elsif (/ ^ \# \s* elif /x) + { + Die("unbalanced #elif") unless @else_stack; + + pop @name_stack; + + push @{$diversions{$curr_enum}}, enum_val_string(aux_name_next()); + $last_aux = aux_name(); + + push @name_stack, 0; + + $curr_offset = 0; + } + elsif (/ ^ \# \s* else /x) + { + my $prev_else = pop @else_stack; + Die("unbalanced #else") unless defined($prev_else); + Die("#else already seen") if $prev_else; + push @else_stack, 1; + + pop @name_stack; + + push @{$diversions{$curr_enum}}, enum_val_string(aux_name_next()); + $last_aux = aux_name(); + + push @name_stack, 0; + + $curr_offset = 0; + } + elsif (/ ^ \# \s* endif /x) + { + my $prev_else = pop @else_stack; + Die("unbalanced #endif") unless defined($prev_else); + + pop @name_stack; + $name_stack[$#name_stack]++; + + # If there is no else-clause for an if-clause, we add one. This is + # necessary to have correct offsets. + if (!$prev_else) + { + push @{$diversions{$curr_enum}}, enum_val_string(aux_name()) + . "#else\n"; + + $curr_offset = 0; + } + + push @{$diversions{$curr_enum}}, enum_val_string(aux_name()); + $last_aux = aux_name(); + + $curr_offset = 0; + } + + # Handle (probably continued) preprocessor lines. + CONTINUED_LOOP: + { + do + { + strip_newline(); + + push @{$diversions{$curr_enum}}, $ARG . "\n"; + push @{$diversions{$curr_array}}, $ARG . "\n"; + + last CONTINUED_LOOP unless / \\ $ /x; + + } while (); + } + } + else + { + warn_before(); + } + + next; + } + + if (/$enum_element_re/) + { + end_curr_string(); + update_max_elem_size(); + + $curr_enum_element = $1; + $have_enum_element = 1; + $curr_elem_size = 0; + + next; + } + + if (/$string_re/) + { + if ($have_sections) + { + Die("strings and blocks can't be mixed in a section") if $have_blocks; + + # Save captured group from `string_re'. + my $string = $1; + + if ($have_enum_element) + { + push @{$diversions{$curr_enum}}, enum_val_string($curr_enum_element); + $have_enum_element = 0; + } + + $string = convert_literal($string); + + push @{$diversions{$curr_array}}, " $string\n"; + + $have_strings = 1; + $in_string = 1; + } + else + { + warn_before(); + } + + next; + } + + if (/$block_start_re/) + { + if ($have_sections) + { + Die("strings and blocks can't be mixed in a section") if $have_strings; + + my $depth = 0; + my $block = ""; + my $block_end = 0; + + # Count braces while getting the block. + BRACE_LOOP: + { + do + { + strip_newline(); + + foreach my $substring (split(/$brace_re/)) + { + if ($block_end) + { + Die("invalid data after last matching closing brace") + if $substring !~ /$whitespace_only_re/; + } + + $block .= $substring; + + if ($substring eq '{') + { + $depth++; + } + elsif ($substring eq '}') + { + $depth--; + + $block_end = 1 if $depth == 0; + } + } + + # If we are here, we have run out of substrings, so get next line + # or exit. + last BRACE_LOOP if $block_end; + + $block .= "\n"; + + } while (); + } + + if ($have_enum_element) + { + push @{$diversions{$curr_enum}}, enum_val_string($curr_enum_element); + $have_enum_element = 0; + } + + push @{$diversions{$curr_array}}, $block . ",\n"; + + $curr_offset++; + $curr_elem_size++; + + $have_blocks = 1; + } + else + { + warn_before(); + } + + next; + } + + # Garbage. We weren't able to parse the data. + Die("syntax error"); +} + +# Finalize data. +end_curr_string(); +update_max_elem_size(); + + +# Filter stdin to stdout, replacing `@...@' templates. + +sub emit_diversion +{ + my $diversion_name = shift; + return (exists($diversions{$1})) ? "@{$diversions{$1}}" + : "@" . $diversion_name . "@"; +} + + +$LIST_SEPARATOR = ''; + +my $s1 = "This file has been generated by the Perl script \`$prog',"; +my $s1len = length $s1; +my $s2 = "using data from file \`$datafile'."; +my $s2len = length $s2; +my $slen = ($s1len > $s2len) ? $s1len : $s2len; + +print "/* " . $s1 . " " x ($slen - $s1len) . " */\n" + . "/* " . $s2 . " " x ($slen - $s2len) . " */\n" + . "\n"; + +while () +{ + s/ @ ( [A-Za-z0-9_]+? ) @ / emit_diversion($1) /egx; + print; +} + +# EOF