From 2dfb5aca285baf50eed6c0a9520069614a2e5cf5 Mon Sep 17 00:00:00 2001 From: David Turner Date: Thu, 27 Jan 2000 14:02:04 +0000 Subject: [PATCH] added a new experimental Type 1 driver. This version sports several improvements compared to "src/type1". Briefly : - the postscript-like interpreter is now gone. We now perform pattern-matching to load our font content. The resultant code is much faster, smaller, and easier to maintain. For a more detailed description, see the comments at the start of "src/type1z/t1objs.c" - the glyph loader will be greatly simplified really soon, and the clumsy hinter will be ditched in favor of a more general auto-hinting module (when we get one). The goal is to strip down the Type1 driver to about 15-20 Kb. This is still an experimental version. It is added to the repository for archiving. You should not try to use it for now (it won't work because some crucial parts are _knowingly_ ignored for now !). Note that the "old" type1 driver will probably move to the "demos/src" directory, in order to show how one can replace one given font driver at runtime (and to provide the functionality of the "t1dump" program). --- src/type1z/module.mk | 6 + src/type1z/rules.mk | 168 +++++ src/type1z/t1config.h | 45 ++ src/type1z/t1driver.c | 271 +++++++ src/type1z/t1driver.h | 28 + src/type1z/t1encode.c | 332 +++++++++ src/type1z/t1encode.h | 98 +++ src/type1z/t1errors.h | 75 ++ src/type1z/t1gload.c | 1582 +++++++++++++++++++++++++++++++++++++++++ src/type1z/t1gload.h | 436 ++++++++++++ src/type1z/t1hinter.c | 1269 +++++++++++++++++++++++++++++++++ src/type1z/t1hinter.h | 380 ++++++++++ src/type1z/t1load.c | 741 +++++++++++++++++++ src/type1z/t1load.h | 56 ++ src/type1z/t1objs.c | 404 +++++++++++ src/type1z/t1objs.h | 302 ++++++++ src/type1z/t1parse.c | 901 +++++++++++++++++++++++ src/type1z/t1parse.h | 206 ++++++ src/type1z/t1tokens.h | 73 ++ src/type1z/type1z.c | 41 ++ 20 files changed, 7414 insertions(+) create mode 100644 src/type1z/module.mk create mode 100644 src/type1z/rules.mk create mode 100644 src/type1z/t1config.h create mode 100644 src/type1z/t1driver.c create mode 100644 src/type1z/t1driver.h create mode 100644 src/type1z/t1encode.c create mode 100644 src/type1z/t1encode.h create mode 100644 src/type1z/t1errors.h create mode 100644 src/type1z/t1gload.c create mode 100644 src/type1z/t1gload.h create mode 100644 src/type1z/t1hinter.c create mode 100644 src/type1z/t1hinter.h create mode 100644 src/type1z/t1load.c create mode 100644 src/type1z/t1load.h create mode 100644 src/type1z/t1objs.c create mode 100644 src/type1z/t1objs.h create mode 100644 src/type1z/t1parse.c create mode 100644 src/type1z/t1parse.h create mode 100644 src/type1z/t1tokens.h create mode 100644 src/type1z/type1z.c diff --git a/src/type1z/module.mk b/src/type1z/module.mk new file mode 100644 index 000000000..659cd3f00 --- /dev/null +++ b/src/type1z/module.mk @@ -0,0 +1,6 @@ +make_module_list: add_type1z_driver + +add_type1z_driver: + $(OPEN_DRIVER)t1z_driver_interface$(CLOSE_DRIVER) + $(ECHO_DRIVER)type1z $(ECHO_DRIVER_DESC) Postscript font files with extension *.pfa or *.pfb $(ECHO_DRIVER_DONE) + diff --git a/src/type1z/rules.mk b/src/type1z/rules.mk new file mode 100644 index 000000000..fb69d2105 --- /dev/null +++ b/src/type1z/rules.mk @@ -0,0 +1,168 @@ +#**************************************************************************** +#* * +#* Type1z driver Makefile * +#* * +#* Copyright 1996-1999 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 "Type1z" driver is an experimental replacement for the current * +#* Type 1 driver. It features a very different loading mechanism that * +#* is much faster than the one used by the "normal" driver, and also * +#* deals nicely with nearly broken Type 1 font files.. It is also * +#* much smaller.. * +#* * +#* Note that it may become a permanent replacement of the current * +#* "src/type1" driver in the future.. * +#* * +#**************************************************************************** + + +#**************************************************************************** +#* * +#* IMPORTANT NOTE: This Makefile is intended for GNU Make! * +#* If you provide Makefiles for other make utilities, * +#* please place them in `freetype/lib/arch/'. * +#* * +#* * +#* This file is to be included by the FreeType Makefile.lib, located in * +#* the `freetype/lib' directory. Here is the list of the variables that * +#* must be defined to use it: * +#* * +#* * +#* BASE_DIR: The location of the base layer's directory. This is * +#* usually `freetype/lib/base'. * +#* * +#* ARCH_DIR: The location of the architecture-dependent directory. * +#* This is usually `freetype/lib/arch/'. * +#* * +#* DRIVERS_DIR: The location of the font driver sub-dirs, usually * +#* `freetype/lib/drivers'. * +#* * +#* OBJ_DIR: The location where the compiled object(s) file will be * +#* placed. * +#* * +#* BASE_H: A list of pathnames to the base layer's header files on * +#* which the driver depends. * +#* * +#* FT_CFLAGS: A set of flags used for compilation of object files. * +#* This contains at least the include paths of the arch * +#* and base directories + optimization + warnings + ANSI * +#* compliance. * +#* * +#* FT_IFLAG: The flag used to specify an include path on the * +#* compiler command line. For example, with GCC, this is * +#* `-I', while some other compilers use `/i=' or `-J', * +#* etc. * +#* * +#* FT_OBJ: The suffix of an object file for the platform; can be * +#* `o', `obj', `coff', `tco', etc. depending on the * +#* platform. * +#* * +#* * +#* It also updates the following variables defined and used in the main * +#* Makefile: * +#* * +#* DRV_OBJ_S: The list of driver object files in * +#* single-object mode. * +#* * +#* DRV_OBJ_M: The list of driver object files in * +#* multiple-objects mode. * +#* * +#* FTINIT_DRIVER_PATHS: The list of include paths used to compile the * +#* `ftinit' component which registers all font * +#* drivers in the FT_Init_FreeType() function. * +#* * +#* FTINIT_DRIVER_H: The list of header dependencies used to * +#* compile the `ftinit' component. * +#* * +#* FTINIT_DRIVER_MACROS: The list of macros to be defined when * +#* compiling the `ftinit' component. * +#* * +#* `Single-object compilation' means that each font driver is compiled * +#* into a single object file. This is useful to get rid of all * +#* driver-specific entries. * +#* * +#**************************************************************************** + + +# Type1z driver directory +# +T1Z_DIR := $(SRC_)type1z +T1Z_DIR_ := $(T1Z_DIR)$(SEP) + + +# additional include flags used when compiling the driver +# +T1Z_INCLUDE := $(SHARED) $(T1Z_DIR) +T1Z_COMPILE := $(FT_COMPILE) $(T1Z_INCLUDE:%=$I%) + + +# Type1 driver sources (i.e., C files) +# +T1Z_DRV_SRC := $(T1Z_DIR_)t1parse.c \ + $(T1Z_DIR_)t1load.c +# $(T1Z_DIR_)t1parse.c \ +# $(T1Z_DIR_)t1tokens.c \ +# $(T1Z_DIR_)t1driver.c \ +# $(T1Z_DIR_)t1encode.c \ +# $(T1Z_DIR_)t1hinter.c \ +# $(T1Z_DIR_)t1gload.c + + +# Type1 driver headers +# +T1Z_DRV_H := $(T1Z_DIR_)t1errors.h \ + $(T1Z_DIR_)t1config.h \ + $(T1SHARED_H) \ + $(T1Z_DRV_SRC:%.c=%.h) + + +# driver object(s) +# +# T1Z_DRV_OBJ_M is used during `debug' builds +# T1Z_DRV_OBJ_S is used during `release' builds +# +T1Z_DRV_OBJ_M := $(T1Z_DRV_SRC:$(T1Z_DIR_)%.c=$(OBJ_)%.$O) \ + $(T1SHARED:$(T1SHARED_DIR_)%.c=$(OBJ_)%.$O) +T1Z_DRV_OBJ_S := $(OBJ_)type1z.$O + + + +# driver root source file(s) +# +T1Z_DRV_SRC_M := $(T1Z_DRV_SRC) $(T1SHARED_SRC) +T1Z_DRV_SRC_S := $(T1Z_DIR_)type1z.c + + +# driver - single object +# +# the driver is recompiled if any of the header or source files is changed +# +$(T1Z_DRV_OBJ_S): $(BASE_H) $(T1Z_DRV_H) $(T1Z_DRV_SRC) $(T1Z_DRV_SRC_S) + $(T1Z_COMPILE) $T$@ $(T1Z_DRV_SRC_S) + + + +# driver - multiple objects +# +# All objects are recompiled if any of the header files is changed +# +$(OBJ_)t1%.$O: $(T1Z_DIR_)t1%.c $(BASE_H) $(T1Z_DRV_H) + $(T1Z_COMPILE) $T$@ $< + +$(OBJ_)t1%.$O: $(T1SHARED_DIR_)t1%.c $(BASE_H) $(T1SHARED_H) + $(T1Z_COMPILE) $T$@ $< + + +# update main driver object lists +# +DRV_OBJS_S += $(T1Z_DRV_OBJ_S) +DRV_OBJS_M += $(T1Z_DRV_OBJ_M) + +# END diff --git a/src/type1z/t1config.h b/src/type1z/t1config.h new file mode 100644 index 000000000..a72b177b2 --- /dev/null +++ b/src/type1z/t1config.h @@ -0,0 +1,45 @@ +/******************************************************************* + * + * t1config.h + * + * Type 1 driver configuration file + * + * Copyright 1996-1998 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 T1CONFIG_H +#define T1CONFIG_H + +/* T1_MAX_STACK_DEPTH is the maximal depth of the token stack used */ +/* by the Type 1 parser (see t1load.c). A minimum of 16 is required */ +/* */ +#define T1_MAX_STACK_DEPTH 16 + +/* T1_MAX_DICT_DEPTH is the maximal depth of nest dictionaries and */ +/* arrays in the Type 1 stream (see t1load.c). A minimum of 4 is */ +/* required */ +#define T1_MAX_DICT_DEPTH 5 + +/* T1_MAX_SUBRS_CALLS details the maximum number of nested sub-routine */ +/* calls during glyph loading */ +#define T1_MAX_SUBRS_CALLS 8 + + +/* T1_MAX_CHARSTRING_OPERANDS is the charstring stack's capacity */ +#define T1_MAX_CHARSTRINGS_OPERANDS 32 + + +/* Define T1_CONFIG_OPTION_DISABLE_HINTER if you want to generate */ +/* a driver with no hinter. This can be useful to debug the parser */ +/* */ +#undef T1_CONFIG_OPTION_DISABLE_HINTER + +#endif /* T1CONFIG_H */ diff --git a/src/type1z/t1driver.c b/src/type1z/t1driver.c new file mode 100644 index 000000000..039ecd118 --- /dev/null +++ b/src/type1z/t1driver.c @@ -0,0 +1,271 @@ +/******************************************************************* + * + * t1driver.c + * + * High-level Type1 driver interface for FreeType 2.0 + * + * Copyright 1996-1998 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + ******************************************************************/ + +#include +#include + +#include +#include + +#undef FT_COMPONENT +#define FT_COMPONENT trace_t1driver + + /*************************************************************************/ + /* */ + /* */ + /* Get_Interface */ + /* */ + /* */ + /* Each driver can provide one or more extensions to the base */ + /* FreeType API. These can be used to access format specific */ + /* features (e.g., all TrueType/OpenType resources share a common */ + /* file structure and common tables which can be accessed through the */ + /* `sfnt' interface), or more simply generic ones (e.g., the */ + /* `postscript names' interface which can be used to retrieve the */ + /* PostScript name of a given glyph index). */ + /* */ + /* */ + /* driver :: A handle to a driver object. */ + /* */ + /* */ + /* interface :: A string designing the interface. Examples are */ + /* `sfnt', `post_names', `charmaps', etc. */ + /* */ + /* */ + /* A typeless pointer to the extension's interface (normally a table */ + /* of function pointers). Returns NULL if the requested extension */ + /* isn't available (i.e., wasn't compiled in the driver at build */ + /* time). */ + /* */ + static + void* Get_Interface( FT_Driver* driver, + const FT_String* interface ) + { + UNUSED(driver); + UNUSED(interface); + return 0; + } + + + /******************************************************************/ + /* */ + /* Set_Char_Sizes */ + /* */ + /* */ + /* A driver method used to reset a size's character sizes */ + /* (horizontal and vertical) expressed in fractional points. */ + /* */ + /* */ + /* size :: handle to target size object */ + /* char_width :: character width expressed in 26.6 points */ + /* char_height :: character height expressed in 26.6 points */ + /* */ + /* */ + /* FreeType error code. 0 means success */ + /* */ + static + T1_Error Set_Char_Sizes( T1_Size size, + T1_F26Dot6 char_width, + T1_F26Dot6 char_height, + T1_UInt horz_resolution, + T1_UInt vert_resolution ) + { + UNUSED(char_width); + UNUSED(horz_resolution); + UNUSED(vert_resolution); + + size->valid = FALSE; + return T1_Reset_Size( size ); + } + + + /******************************************************************/ + /* */ + /* Set_Pixel_Sizes */ + /* */ + /* */ + /* A driver method used to reset a size's character sizes */ + /* (horizontal and vertical) expressed in integer pixels. */ + /* */ + /* */ + /* size :: handle to target size object */ + /* */ + /* pixel_width :: character width expressed in 26.6 points */ + /* */ + /* pixel_height :: character height expressed in 26.6 points */ + /* */ + /* char_size :: the corresponding character size in points */ + /* This value is only sent to the TrueType */ + /* bytecode interpreter, even though 99% of */ + /* glyph programs will simply ignore it. A */ + /* safe value there is the maximum of the */ + /* pixel width and height (multiplied by */ + /* 64 to make it a 26.6 fixed float !) */ + /* */ + /* FreeType error code. 0 means success */ + /* */ + static + T1_Error Set_Pixel_Sizes( T1_Size size, + T1_Int pixel_width, + T1_Int pixel_height ) + { + UNUSED(pixel_width); + UNUSED(pixel_height); + + size->valid = FALSE; + return T1_Reset_Size(size); + } + + + /******************************************************************/ + /* */ + /* FT_DriverInterface */ + /* */ + /* */ + /* A structure used to hold a font driver's basic interface */ + /* used by the high-level parts of FreeType (or other apps) */ + /* */ + /* Most scalable drivers provide a specialized interface to */ + /* access format-specific features. It can be retrieved with */ + /* a call to the "get_format_interface", and should be defined */ + /* in each font driver header (e.g. ttdriver.h, t1driver.h,..) */ + /* */ + /* All fields are function pointers .. */ + /* */ + /* */ + /* */ + /* */ + /* new_engine :: */ + /* used to create and initialise a new driver object */ + /* */ + /* done_engine :: */ + /* used to finalise and destroy a given driver object */ + /* */ + /* get_format_interface :: */ + /* return a typeless pointer to the format-specific */ + /* driver interface. */ + /* */ + /* new_face :: */ + /* create a new face object from a resource */ + /* */ + /* done_face :: */ + /* discards a face object, as well as all child objects */ + /* ( sizes, charmaps, glyph slots ) */ + /* */ + /* get_face_properties :: */ + /* return generic face properties */ + /* */ + /* get_kerning :: */ + /* return the kerning vector corresponding to a pair */ + /* of glyphs, expressed in unscaled font units. */ + /* */ + /* new_size :: */ + /* create and initialise a new scalable size object. */ + /* */ + /* new_fixed_size :: */ + /* create and initialise a new fixed-size object. */ + /* */ + /* done_size :: */ + /* finalize a given face size object. */ + /* */ + /* set_size_resolutions :: */ + /* reset a scalable size object's output resolutions */ + /* */ + /* set_size_char_sizes :: */ + /* reset a scalable size object's character size */ + /* */ + /* set_pixel_sizes :: */ + /* reset a face size object's pixel dimensions. Applies */ + /* to both scalable and fixed faces. */ + /* */ + /* new_glyph_slot :: */ + /* create and initialise a new glyph slot */ + /* */ + /* done_glyph_slot :: */ + /* discard a given glyph slot */ + /* */ + /* load_glyph :: */ + /* load a given glyph into a given slot */ + /* */ + /* get_glyph_metrics :: */ + /* return a loaded glyph's metrics. */ + /* */ + + EXPORT_FUNC + const FT_DriverInterface t1_driver_interface = + { + sizeof( FT_DriverRec ), + sizeof( T1_FaceRec ), + sizeof( T1_SizeRec ), + sizeof( T1_GlyphSlotRec ), + + "type1", + 100, /* driver version == 1.0 */ + 200, /* requires FreeType 2.0 or above */ + + 0, /* format interface */ + + (FTDriver_initDriver) T1_Init_Driver, + (FTDriver_doneDriver) T1_Done_Driver, + (FTDriver_getInterface) Get_Interface, + + (FTDriver_initFace) T1_Init_Face, + (FTDriver_doneFace) T1_Done_Face, + (FTDriver_getKerning) 0, + + (FTDriver_initSize) T1_Init_Size, + (FTDriver_doneSize) T1_Done_Size, + (FTDriver_setCharSizes) Set_Char_Sizes, + (FTDriver_setPixelSizes) Set_Pixel_Sizes, + + (FTDriver_initGlyphSlot) T1_Init_GlyphSlot, + (FTDriver_doneGlyphSlot) T1_Done_GlyphSlot, + (FTDriver_loadGlyph) T1_Load_Glyph, + + (FTDriver_getCharIndex) 0, + }; + + /*************************************************************************/ + /* */ + /* */ + /* getDriverInterface */ + /* */ + /* */ + /* This function is used when compiling the font driver as a */ + /* shared library (`.DLL' or `.so'). It will be used by the */ + /* high-level library of FreeType to retrieve the address of the */ + /* driver's generic interface. */ + /* */ + /* It shouldn't be implemented in a static build, as each driver must */ + /* have the same function as an exported entry point. */ + /* */ + /* */ + /* The address of the TrueType's driver generic interface. The */ + /* format-specific interface can then be retrieved through the method */ + /* interface->get_format_interface. */ + /* */ +#ifdef FT_CONFIG_OPTION_DYNAMIC_DRIVERS + + EXPORT_FUNC + FT_DriverInterface* getDriverInterface( void ) + { + return &t1_driver_interface; + } + +#endif /* CONFIG_OPTION_DYNAMIC_DRIVERS */ + + diff --git a/src/type1z/t1driver.h b/src/type1z/t1driver.h new file mode 100644 index 000000000..a442035c3 --- /dev/null +++ b/src/type1z/t1driver.h @@ -0,0 +1,28 @@ +/******************************************************************* + * + * t1driver.h + * + * High-level Type1 driver interface for FreeType 2.0 + * + * Copyright 1996-1998 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 T1DRIVER_H +#define T1DRIVER_H + +#include +#include + + EXPORT_DEF + const FT_DriverInterface t1_driver_interface; + +#endif /* T1DRIVER_H */ + diff --git a/src/type1z/t1encode.c b/src/type1z/t1encode.c new file mode 100644 index 000000000..9c91027a7 --- /dev/null +++ b/src/type1z/t1encode.c @@ -0,0 +1,332 @@ +/***************************************************************************/ +/* */ +/* t1encode.c */ +/* */ +/* Type 1 standard encoding tables definitions (body). */ +/* */ +/* Copyright 1996-1999 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 is included by both the Type1 and Type2 driver. */ +/* It should never be compiled directly. */ +/* */ +/***************************************************************************/ + +#include +#include + + /*************************************************************************/ + /* */ + /* t1_standard_strings: */ + /* */ + /* This array contains the Adobe Standard Glyph Names ordered by */ + /* SID. It was taken from the CFF specification. */ + /* */ + LOCAL_FUNC + const T1_String* t1_standard_strings[] = + { + /* 0 */ + ".notdef", "space", "exclam", "quotedbl", "numbersign", + "dollar", "percent", "ampersand", "quoteright", "parenleft", + /* 10 */ + "parenright", "asterisk", "plus", "comma", "hyphen", + "period", "slash", "zero", "one", "two", + /* 20 */ + "three", "four", "five", "six", "seven", + "height", "nine", "colon", "semicolon", "less", + /* 30 */ + "equal", "greater", "question", "at", "A", + "B", "C", "D", "E", "F", + /* 40 */ + "G", "H", "I", "J", "K", + "L", "M", "N", "O", "P", + /* 50 */ + "Q", "R", "S", "T", "U", + "V", "W", "X", "Y", "Z", + /* 60 */ + "bracketleft", "backslash", "bracketright", "asciicircum", "underscore", + "quoteleft", "a", "b", "c", "d", + /* 70 */ + "e", "f", "g", "h", "i", + "j", "k", "l", "m", "n", + /* 80 */ + "o", "p", "q", "r", "s", + "t", "u", "v", "w", "x", + /* 90 */ + "y", "z", "braceleft", "bar", "braceright", + "asciitilde", "exclamdown", "cent", "sterling", "fraction", + /* 100 */ + "yen", "florin", "section", "currency", "quotesingle", + "quotedblleft", "quillemotleft", "guilsinglleft", "guilsinglright", "fi", + /* 110 */ + "fl", "endash", "dagger", "daggerdbl", "periodcenter", + "paragraph", "bullet", "quotesinglbase", "quotedblbase", "quotedblright", + /* 120 */ + "quillemotright", "ellipsis", "perthousand", "questiondown", "grave", + "acute", "circumflex", "tilde", "macron", "breve", + /* 130 */ + "dotaccent", "dieresis", "ring", "cedilla", "hungarumlaut", + "ogonek", "caron", "emdash", "AE", "ordfeminine", + /* 140 */ + "Lslash", "Oslash", "OE", "ordmasculine", "ae", + "dotlessi", "Islash", "oslash", "oe", "germandbls", + /* 150 */ + "onesuperior", "logicalnot", "mu", "trademark", "Eth", + "onehalf", "plusminus", "Thorn", "onequarter", "divide", + /* 160 */ + "brokenbar", "degree", "thorn", "threequarters", "twosuperior", + "regitered", "minus", "eth", "multiply", "threesuperior", + /* 170 */ + "copyright", "Aacute", "Acircumflex", "Adieresis", "Agrave", + "Aring", "Atilde", "Ccedilla", "Eacute", "Ecircumflex", + /* 180 */ + "Edieresis", "Egrave", "Iacute", "Icircumflex", "Idieresis", + "Igrave", "Ntilde", "Oacute", "Ocircumflex", "Odieresis", + /* 190 */ + "Ograve", "Otilde", "Scaron", "Uacute", "Ucircumflex", + "Udieresis", "Ugrave", "Yacute", "Ydieresis", "Zcaron", + /* 200 */ + "aacute", "acircumflex", "adieresis", "agrave", "aring", + "atilde", "ccedilla", "eacute", "ecircumflex", "edieresis", + /* 210 */ + "egrave", "iacute", "icircumflex", "idieresis", "igrave", + "ntilde", "oacute", "ocircumflex", "odieresis", "ograve", + /* 220 */ + "otilde", "scaron", "uacute", "ucircumflex", "udieresis", + "ugrave", "yacute", "ydieresis", "zcaron", "exclamsmall", + /* 230 */ + "Hungarumlautsmall", "dollaroldstyle", "dollarsuperior", "ampersandsmall", + "Acutesmall", + "parenleftsuperior", "parenrightsuperior", "twodotenleader", + "onedotenleader", "zerooldstyle", + /* 240 */ + "oneoldstyle", "twooldstyle", "threeoldstyle", "fouroldstyle", + "fiveoldstyle", + "sixoldstyle", "sevenoldstyle", "eightoldstyle", "nineoldstyle", + "commasuperior", + /* 250 */ + "threequartersemdash", "periodsuperior", "questionsmall", "asuperior", + "bsuperior", + "centsuperior", "dsuperior", "esuperior", "isuperior", "lsuperior", + /* 260 */ + "msuperior", "nsuperior", "osuperior", "rsuperior", "ssuperior", + "tsuperior", "ff", "ffi", "ffl", "parenleftinferior", + /* 270 */ + "parenrightinferior", "Circumflexsmall", "hyphensuperior", "Gravesmall", + "Asmall", + "Bsmall", "Csmall", "Dsmall", "Esmall", "Fsmall", + /* 280 */ + "Gsmall", "Hsmall", "Ismall", "Jsmall", "Ksmall", + "Lsmall", "Msmall", "Nsmall", "Osmall", "Psmall", + /* 290 */ + "Qsmall", "Rsmall", "Ssmall", "Tsmall", "Usmall", + "Vsmall", "Wsmall", "Xsmall", "Ysmall", "Zsmall", + /* 300 */ + "colonmonetary", "onefitted", "rupiah", "Tildesmall", "exclamdownsmall", + "centoldstyle", "Lslashsmall", "Scaronsmall", "Zcaronsmall", + "Dieresissmall", + /* 310 */ + "Brevesmall", "Caronsmall", "Dotaccentsmall", "Macronsmall", "figuredash", + "hypheninferior", "Ogoneksmall", "Ringsmall", "Cedillasmall", + "questiondownsmall", + /* 320 */ + "oneeighth", "threeeighths", "fiveeighths", "seveneighths", "onethird", + "twothirds", "zerosuperior", "foursuperior", "fivesuperior", + "sixsuperior", + /* 330 */ + "sevensuperior", "eightsuperior", "ninesuperior", "zeroinferior", + "oneinferior", + "twoinferior", "threeinferior", "fourinferior", "fiveinferior", + "sixinferior", + /* 340 */ + "seveninferior", "eightinferior", "nineinferior", "centinferior", + "dollarinferior", + "periodinferior", "commainferior", "Agravesmall", "Aacutesmall", + "Acircumflexsmall", + /* 350 */ + "Atildesmall", "Adieresissmall", "Aringsmall", "AEsmall", "Ccedillasmall", + "Egravesmall", "Eacutesmall", "Ecircumflexsmall", "Edieresissmall", + "Igravesmall", + /* 360 */ + "Iacutesmall", "Icircumflexsmall", "Idieresissmall", "Ethsmall", + "Ntildesmall", + "Ogravesmall", "Oacutesmall", "Ocircumflexsmall", "Otildesmall", + "Odieresissmall", + /* 370 */ + "OEsmall", "Oslashsmall", "Ugravesmall", "Uacautesmall", + "Ucircumflexsmall", + "Udieresissmall", "Yacutesmall", "Thornsmall", "Ydieresissmall", + "001.000", + /* 380 */ + "001.001", "001.002", "001.003", "Black", "Bold", + "Book", "Light", "Medium", "Regular", "Roman", + /* 390 */ + "Semibold" + }; + + + /*************************************************************************/ + /* */ + /* t1_standard_encoding: */ + /* */ + /* A simple table used to encode the Adobe StandardEncoding. The */ + /* table values are the SID of the standard glyphs; the table index */ + /* is the character code for the encoding. */ + /* */ + /* Example: */ + /* */ + /* t1_standard_encoding[33] == 2 */ + /* */ + /* which means that the glyph name for character code 32 is */ + /* */ + /* t1_standard_strings[2] == "exclam" */ + /* */ + /* (this correspond to the exclamation mark `!'). */ + /* */ + LOCAL_FUNC + T1_Short t1_standard_encoding[256] = + { + /* 0 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, + 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, + /* 50 */ + 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, + 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, + 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, + /* 100 */ + 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, + 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, + 89, 90, 91, 92, 93, 94, 95, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 150 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 96, 97, 98, 99, 100, 101, 102, 103, 104, + 105, 106, 107, 108, 109, 110, 0, 111, 112, 113, + 114, 0, 115, 116, 117, 118, 119, 120, 121, 122, + 0, 123, 0, 124, 125, 126, 127, 128, 129, 130, + /* 200 */ + 131, 0, 132, 133, 0, 134, 135, 136, 137, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 138, 0, 139, 0, 0, + 0, 0, 140, 141, 142, 143, 0, 0, 0, 0, + 0, 144, 0, 0, 0, 145, 0, 0, 146, 147, + /* 250 */ + 148, 149, 0, 0, 0, 0 + }; + + + /*************************************************************************/ + /* */ + /* t1_expert_encoding: */ + /* */ + /* A simple table used to encode the Adobe ExpertEncoding. The */ + /* table values are the SID of the standard glyphs; the table index */ + /* is the character code for the encoding. */ + /* */ + /* Example: */ + /* */ + /* t1_expert_encoding[33] == 229 */ + /* */ + /* which means that the glyph name for character code 32 is */ + /* */ + /* t1_standard_strings[229] == "exclamsmall" */ + /* */ + LOCAL_FUNC + T1_Short t1_expert_encoding[256] = + { + /* 0 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 229, 230, 0, 231, 232, 233, 234, + 235, 236, 237, 238, 13, 14, 15, 99, 239, 240, + /* 50 */ + 241, 242, 243, 244, 245, 246, 247, 248, 27, 28, + 249, 250, 251, 252, 0, 253, 254, 255, 256, 257, + 0, 0, 0, 258, 0, 0, 259, 260, 261, 262, + 0, 0, 263, 264, 265, 0, 266, 109, 110, 267, + 268, 269, 0, 270, 271, 272, 273, 274, 275, 276, + /* 100 */ + 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, + 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, + 297, 298, 299, 300, 301, 302, 303, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 150 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 304, 305, 306, 0, 0, 307, 308, 309, 310, + 311, 0, 312, 0, 0, 312, 0, 0, 314, 315, + 0, 0, 316, 317, 318, 0, 0, 0, 158, 155, + 163, 319, 320, 321, 322, 323, 324, 325, 0, 0, + /* 200 */ + 326, 150, 164, 169, 327, 328, 329, 330, 331, 332, + 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, + 343, 344, 345, 346, 347, 348, 349, 350, 351, 352, + 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, + 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, + /* 250 */ + 373, 374, 375, 376, 377, 378 + }; + + + /*************************************************************************/ + /* */ + /* t1_expert_subset_encoding: */ + /* */ + /* A simple table used to encode the Adobe ExpertEncoding subset */ + /* defined in the CFF specification. It will probably evolve into */ + /* another form sooner or later, as we deal with charsets */ + /* differently than with encodings. */ + /* */ + LOCAL_FUNC + FT_Short t1_expert_subset_encoding[256] = + { + /* 0 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 231, 232, 0, 0, + 235, 236, 237, 238, 13, 14, 15, 99, 239, 240, + /* 50 */ + 241, 242, 243, 244, 245, 246, 247, 248, 27, 28, + 249, 250, 251, 252, 0, 253, 254, 255, 256, 257, + 0, 0, 0, 258, 0, 0, 259, 260, 261, 262, + 0, 0, 263, 264, 265, 0, 266, 109, 110, 267, + 268, 269, 0, 270, 0, 272, 0, 0, 0, 0, + /* 100 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 300, 301, 302, 303, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 150 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 304, 305, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 314, 315, + 0, 0, 0, 0, 0, 0, 0, 0, 158, 155, + 163, 0, 320, 321, 322, 323, 324, 325, 0, 0, + /* 200 */ + 326, 150, 164, 169, 327, 328, 329, 330, 331, 332, + 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, + 343, 344, 345, 346, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 250 */ + 0, 0, 0, 0, 0, 0 + }; + + +/* END */ diff --git a/src/type1z/t1encode.h b/src/type1z/t1encode.h new file mode 100644 index 000000000..0f5c0d7c0 --- /dev/null +++ b/src/type1z/t1encode.h @@ -0,0 +1,98 @@ +/***************************************************************************/ +/* */ +/* t1encode.h */ +/* */ +/* Type 1 standard encoding tables definitions (specification). */ +/* */ +/* Copyright 1996-1999 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 is included by both the Type1 and Type2 driver. */ +/* It should never be compiled directly. */ +/* */ +/***************************************************************************/ + + +#ifndef T1ENCODE_H +#define T1ENCODE_H + +#include + + + /*************************************************************************/ + /* */ + /* t1_standard_strings: */ + /* */ + /* This array contains the Adobe Standard Glyph Names ordered by */ + /* SID. It was taken from the CFF specification. */ + /* */ + LOCAL_DEF + const T1_String* t1_standard_strings[]; + + + /*************************************************************************/ + /* */ + /* t1_standard_encoding: */ + /* */ + /* A simple table used to encode the Adobe StandardEncoding. The */ + /* table values are the SID of the standard glyphs; the table index */ + /* is the character code for the encoding. */ + /* */ + /* Example: */ + /* */ + /* t1_standard_encoding[33] == 2 */ + /* */ + /* which means that the glyph name for character code 33 is */ + /* */ + /* t1_standard_strings[2] == "exclam" */ + /* */ + /* (this correspond to the exclamation mark `!'). */ + /* */ + LOCAL_DEF + T1_Short t1_standard_encoding[256]; + + + /*************************************************************************/ + /* */ + /* t1_expert_encoding: */ + /* */ + /* A simple table used to encode the Adobe ExpertEncoding. The */ + /* table values are the SID of the standard glyphs; the table index */ + /* is the character code for the encoding. */ + /* */ + /* Example: */ + /* */ + /* t1_expert_encoding[33] == 229 */ + /* */ + /* which means that the glyph name for character code 33 is */ + /* */ + /* t1_standard_strings[229] == "exclamsmall" */ + /* */ + LOCAL_DEF + T1_Short t1_expert_encoding[256]; + + + /*************************************************************************/ + /* */ + /* t1_expert_subset_encoding: */ + /* */ + /* A simple table used to encode the Adobe ExpertEncoding subset */ + /* defined in the CFF specification. It will probably evolve into */ + /* another form sooner or later, as we deal with charsets */ + /* differently than with encodings. */ + /* */ + LOCAL_DEF + T1_Short t1_expert_subset_encoding[256]; + + +#endif /* T1ENCODE_H */ + + +/* END */ diff --git a/src/type1z/t1errors.h b/src/type1z/t1errors.h new file mode 100644 index 000000000..f268d8770 --- /dev/null +++ b/src/type1z/t1errors.h @@ -0,0 +1,75 @@ +/******************************************************************* + * + * t1errors.h + * + * Type1 Error ID definitions + * + * Copyright 1996-1998 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 T1ERRORS_H +#define T1ERRORS_H + +#include + + /************************ error codes declaration **************/ + + /* The error codes are grouped in 'classes' used to indicate the */ + /* 'level' at which the error happened. */ + /* The class is given by an error code's high byte. */ + + +/* ------------- Success is always 0 -------- */ + +#define T1_Err_Ok FT_Err_Ok + +/* ----------- high level API errors -------- */ + +#define T1_Err_Invalid_File_Format FT_Err_Invalid_File_Format +#define T1_Err_Invalid_Argument FT_Err_Invalid_Argument +#define T1_Err_Invalid_Driver_Handle FT_Err_Invalid_Driver_Handle +#define T1_Err_Invalid_Face_Handle FT_Err_Invalid_Face_Handle +#define T1_Err_Invalid_Size_Handle FT_Err_Invalid_Size_Handle +#define T1_Err_Invalid_Glyph_Handle FT_Err_Invalid_Slot_Handle +#define T1_Err_Invalid_CharMap_Handle FT_Err_Invalid_CharMap_Handle +#define T1_Err_Invalid_Glyph_Index FT_Err_Invalid_Glyph_Index + +#define T1_Err_Unimplemented_Feature FT_Err_Unimplemented_Feature +#define T1_Err_Unavailable_Outline FT_Err_Unavailable_Outline +#define T1_Err_Unavailable_Bitmap FT_Err_Unavailable_Bitmap +#define T1_Err_Unavailable_Pixmap FT_Err_Unavailable_Pixmap +#define T1_Err_File_Is_Not_Collection FT_Err_File_Is_Not_Collection + +#define T1_Err_Invalid_Engine FT_Err_Invalid_Driver_Handle + +/* ------------- internal errors ------------ */ + +#define T1_Err_Out_Of_Memory FT_Err_Out_Of_Memory +#define T1_Err_Unlisted_Object FT_Err_Unlisted_Object + +/* ------------ general glyph outline errors ------ */ + +#define T1_Err_Too_Many_Points FT_Err_Too_Many_Points +#define T1_Err_Too_Many_Contours FT_Err_Too_Many_Contours +#define T1_Err_Too_Many_Hints FT_Err_Too_Many_Hints +#define T1_Err_Invalid_Composite FT_Err_Invalid_Composite +#define T1_Err_Too_Many_Edges FT_Err_Too_Many_Edges +#define T1_Err_Too_Many_Strokes FT_Err_Too_Many_Strokes + + +#define T1_Err_Syntax_Error FT_Err_Invalid_File_Format +#define T1_Err_Stack_Underflow FT_Err_Invalid_File_Format +#define T1_Err_Stack_Overflow FT_Err_Invalid_File_Format + +#endif /* TDERRORS_H */ + + +/* END */ diff --git a/src/type1z/t1gload.c b/src/type1z/t1gload.c new file mode 100644 index 000000000..05cd0a26b --- /dev/null +++ b/src/type1z/t1gload.c @@ -0,0 +1,1582 @@ +/******************************************************************* + * + * t1gload.c 1.0 + * + * Type1 Glyph Loader. + * + * Copyright 1996-1999 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used + * modified and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + ******************************************************************/ + +#include +#include +#include +#include + +#ifndef T1_CONFIG_OPTION_DISABLE_HINTER +#include +#endif + + /**********************************************************************/ + /**********************************************************************/ + /**********************************************************************/ + /********** *********/ + /********** *********/ + /********** GENERIC CHARSTRINGS PARSING *********/ + /********** *********/ + /********** *********/ + /**********************************************************************/ + /**********************************************************************/ + /**********************************************************************/ + +/********************************************************************* + * + * + * T1_Init_Builder + * + * + * Initialise a given glyph builder. + * + * + * builder :: glyph builder to initialise + * face :: current face object + * size :: current size object + * glyph :: current glyph object + * funcs :: glyph builder functions (or "methods"). + * + *********************************************************************/ + + EXPORT_FUNC + void T1_Init_Builder( T1_Builder* builder, + T1_Face face, + T1_Size size, + T1_GlyphSlot glyph, + const T1_Builder_Funcs* funcs ) + { + builder->funcs = *funcs; + builder->path_begun = 0; + builder->load_points = 1; + + builder->face = face; + builder->size = size; + builder->glyph = glyph; + builder->memory = face->root.memory; + + if (glyph) + { + builder->base = glyph->root.outline; + builder->max_points = glyph->max_points; + builder->max_contours = glyph->max_contours; + } + + if (size) + { + builder->scale_x = size->root.metrics.x_scale; + builder->scale_y = size->root.metrics.y_scale; + } + + builder->pos_x = 0; + builder->pos_y = 0; + + builder->left_bearing.x = 0; + builder->left_bearing.y = 0; + builder->advance.x = 0; + builder->advance.y = 0; + + builder->base.n_points = 0; + builder->base.n_contours = 0; + builder->current = builder->base; + + builder->pass = 0; + builder->hint_point = 0; + } + + +/********************************************************************* + * + * + * T1_Done_Builder + * + * + * Finalise a given glyph builder. Its content can still be + * used after the call, but the function saves important information + * within the corresponding glyph slot. + * + * + * builder :: glyph builder to initialise + * + *********************************************************************/ + + EXPORT_FUNC + void T1_Done_Builder( T1_Builder* builder ) + { + T1_GlyphSlot glyph = builder->glyph; + + if (glyph) + { + glyph->root.outline = builder->base; + glyph->max_points = builder->max_points; + glyph->max_contours = builder->max_contours; + } + } + + + +/********************************************************************* + * + * + * T1_Init_Decoder + * + * + * Initialise a given Type 1 decoder for parsing + * + * + * decoder :: Type 1 decoder to initialise + * funcs :: hinter functions interface + * + *********************************************************************/ + + EXPORT_FUNC + void T1_Init_Decoder( T1_Decoder* decoder, + const T1_Hinter_Funcs* funcs ) + { + decoder->hinter = *funcs; /* copy hinter interface */ + decoder->top = 0; + decoder->zone = 0; + + decoder->flex_state = 0; + decoder->num_flex_vectors = 0; + + /* Clear loader */ + MEM_Set( &decoder->builder, 0, sizeof(decoder->builder) ); + } + + +/********************************************************************* + * + * + * lookup_glyph_by_stdcharcode + * + * + * Lookup a given glyph by its StandardEncoding charcode. Used + * to implement the SEAC Type 1 operator. + * + * + * face :: current face object + * charcode :: charcode to look for + * + * + * glyph index in font face. Returns -1 if the corresponding + * glyph wasn't found. + * + *********************************************************************/ + + static + T1_Int lookup_glyph_by_stdcharcode( T1_Face face, + T1_Int charcode ) + { + T1_Int n; + const T1_String* glyph_name; + + /* check range of standard char code */ + if (charcode < 0 || charcode > 255) + return -1; + + glyph_name = t1_standard_strings[t1_standard_encoding[charcode]]; + + for ( n = 0; n < face->type1.num_glyphs; n++ ) + { + T1_String* name = (T1_String*)face->type1.glyph_names[n]; + + if ( name && strcmp(name,glyph_name) == 0 ) + return n; + } + + return -1; + } + + +/********************************************************************* + * + * + * t1operator_seac + * + * + * Implements the "seac" Type 1 operator for a Type 1 decoder + * + * + * decoder :: current Type 1 decoder + * asb :: accent's side bearing + * adx :: horizontal position of accent + * ady :: vertical position of accent + * bchar :: base character's StandardEncoding charcode + * achar :: accent character's StandardEncoding charcode + * + * + * Error code. 0 means success. + * + *********************************************************************/ + + static + T1_Error t1operator_seac( T1_Decoder* decoder, + T1_Pos asb, + T1_Pos adx, + T1_Pos ady, + T1_Int bchar, + T1_Int achar ) + { + T1_Error error; + T1_Face face = decoder->builder.face; + T1_Int bchar_index, achar_index, n_base_points; + FT_Outline* cur = &decoder->builder.current; + FT_Outline* base = &decoder->builder.base; + T1_Vector left_bearing, advance; + T1_Font* type1 = &face->type1; + + bchar_index = lookup_glyph_by_stdcharcode( face, bchar ); + achar_index = lookup_glyph_by_stdcharcode( face, achar ); + + if (bchar_index < 0 || achar_index < 0) + { + FT_ERROR(( "T1.Parse_Seac : invalid seac character code arguments\n" )); + return T1_Err_Syntax_Error; + } + + /* First load "bchar" in builder */ + /* now load the unscaled outline */ + cur->n_points = 0; + cur->n_contours = 0; + cur->points = base->points + base->n_points; + cur->flags = base->flags + base->n_points; + cur->contours = base->contours + base->n_contours; + + error = T1_Parse_CharStrings( decoder, + type1->charstrings [bchar_index], + type1->charstrings_len[bchar_index], + type1->num_subrs, + type1->subrs, + type1->subrs_len ); + if (error) return error; + + n_base_points = cur->n_points; + + /* save the left bearing and width of the base character */ + /* as they will be erase by the next load.. */ + left_bearing = decoder->builder.left_bearing; + advance = decoder->builder.advance; + + decoder->builder.left_bearing.x = 0; + decoder->builder.left_bearing.y = 0; + + /* Now load "achar" on top of */ + /* the base outline */ + /* */ + cur->n_points = 0; + cur->n_contours = 0; + cur->points = base->points + base->n_points; + cur->flags = base->flags + base->n_points; + cur->contours = base->contours + base->n_contours; + + error = T1_Parse_CharStrings( decoder, + type1->charstrings [achar_index], + type1->charstrings_len[achar_index], + type1->num_subrs, + type1->subrs, + type1->subrs_len ); + if (error) return error; + + /* adjust contours in accented character outline */ + { + T1_Int n; + + for ( n = 0; n < cur->n_contours; n++ ) + cur->contours[n] += n_base_points; + } + + /* restore the left side bearing and */ + /* advance width of the base character */ + decoder->builder.left_bearing = left_bearing; + decoder->builder.advance = advance; + + /* Finally, move the accent */ + FT_Translate_Outline( cur, adx - asb, ady ); + + (void)asb; /* ignore this parameter */ + return T1_Err_Ok; + } + +/********************************************************************* + * + * + * t1operator_flex + * + * + * Implements the "flex" Type 1 operator for a Type 1 decoder + * + * + * decoder :: current Type 1 decoder + * threshold :: threshold + * end_x :: position of final flex point + * end_y :: position of final flex point + * + * + * Error code. 0 means success. + * + *********************************************************************/ + + static + T1_Error t1operator_flex( T1_Decoder* decoder, + T1_Pos threshold, + T1_Pos end_x, + T1_Pos end_y ) + { + T1_Vector vec; + T1_Vector* flex = decoder->flex_vectors; + T1_Int n; + + /* we don't even try to test the threshold in the non-hinting */ + /* builder, even if the flex operator is said to be a path */ + /* construction statement in the specification. This is better */ + /* left to the hinter.. */ + + flex = decoder->flex_vectors; + vec = *flex++; + + for ( n = 0; n < 6; n++ ) + { + flex->x += vec.x; + flex->y += vec.y; + + vec = *flex++; + } + + + (void)threshold; + (void)end_x; + (void)end_y; + + flex = decoder->flex_vectors; + + return decoder->builder.funcs.rcurve_to( &decoder->builder, + flex[0].x, flex[0].y, + flex[1].x, flex[1].y, + flex[2].x, flex[2].y ) || + + decoder->builder.funcs.rcurve_to( &decoder->builder, + flex[3].x, flex[3].y, + flex[4].x, flex[4].y, + flex[5].x, flex[5].y ); + } + + +/********************************************************************* + * + * + * T1_Parse_CharStrings + * + * + * Parses a given Type 1 charstrings program + * + * + * decoder :: current Type 1 decoder + * charstring_base :: base of the charstring stream + * charstring_len :: length in bytes of the charstring stream + * num_subrs :: number of sub-routines + * subrs_base :: array of sub-routines addresses + * subrs_len :: array of sub-routines lengths + * + * + * Error code. 0 means success. + * + *********************************************************************/ + + EXPORT_FUNC + T1_Error T1_Parse_CharStrings( T1_Decoder* decoder, + T1_Byte* charstring_base, + T1_Int charstring_len, + T1_Int num_subrs, + T1_Byte** subrs_base, + T1_Int* subrs_len ) + { + T1_Error error; + T1_Decoder_Zone* zone; + T1_Byte* ip; + T1_Byte* limit; + T1_Builder* builder = &decoder->builder; + T1_Builder_Funcs* builds = &builder->funcs; + T1_Hinter_Funcs* hints = &decoder->hinter; + + static const T1_Int args_count[ op_max ] = + { + 0, /* none */ + 0, /* endchar */ + 2, /* hsbw */ + 5, /* seac */ + 4, /* sbw */ + 0, /* closepath */ + 1, /* hlineto */ + 1, /* hmoveto */ + 4, /* hvcurveto */ + 2, /* rlineto */ + 2, /* rmoveto */ + 6, /* rrcurveto */ + 4, /* vhcurveto */ + 1, /* vlineto */ + 1, /* vmoveto */ + 0, /* dotsection */ + 2, /* hstem */ + 6, /* hstem3 */ + 2, /* vstem */ + 6, /* vstem3 */ + 2, /* div */ + -1, /* callothersubr */ + 1, /* callsubr */ + 0, /* pop */ + 0, /* return */ + 2 /* setcurrentpoint */ + }; + + /* First of all, initialise the decoder */ + decoder->top = decoder->stack; + decoder->zone = decoder->zones; + zone = decoder->zones; + + builder->path_begun = 0; + + zone->base = charstring_base; + limit = zone->limit = charstring_base + charstring_len; + ip = zone->cursor = zone->base; + + error = T1_Err_Ok; + + /* now, execute loop */ + while ( ip < limit ) + { + T1_Int* top = decoder->top; + T1_Operator op = op_none; + T1_Long value = 0; + + /* First of all, decompress operator or value */ + switch (*ip++) + { + case 1: op = op_hstem; break; + + case 3: op = op_vstem; break; + case 4: op = op_vmoveto; break; + case 5: op = op_rlineto; break; + case 6: op = op_hlineto; break; + case 7: op = op_vlineto; break; + case 8: op = op_rrcurveto; break; + case 9: op = op_closepath; break; + case 10: op = op_callsubr; break; + case 11: op = op_return; break; + + case 13: op = op_hsbw; break; + case 14: op = op_endchar; break; + + case 21: op = op_rmoveto; break; + case 22: op = op_hmoveto; break; + + case 30: op = op_vhcurveto; break; + case 31: op = op_hvcurveto; break; + + case 12: + { + if (ip > limit) + { + FT_ERROR(( "T1.Parse_CharStrings : invalid escape (12+EOF)\n" )); + goto Syntax_Error; + } + + switch (*ip++) + { + case 0: op = op_dotsection; break; + case 1: op = op_vstem3; break; + case 2: op = op_hstem3; break; + case 6: op = op_seac; break; + case 7: op = op_sbw; break; + case 12: op = op_div; break; + case 16: op = op_callothersubr; break; + case 17: op = op_pop; break; + case 33: op = op_setcurrentpoint; break; + + default: + FT_ERROR(( "T1.Parse_CharStrings : invalid escape (12+%d)\n", + ip[-1] )); + goto Syntax_Error; + } + } + break; + + case 255: /* four bytes integer */ + { + if (ip+4 > limit) + { + FT_ERROR(( "T1.Parse_CharStrings : unexpected EOF in integer\n" )); + goto Syntax_Error; + } + + value = ((long)ip[0] << 24) | + ((long)ip[1] << 16) | + ((long)ip[2] << 8) | + ip[3]; + ip += 4; + } + break; + + default: + if (ip[-1] >= 32) + { + if (ip[-1] < 247) + value = (long)ip[-1] - 139; + else + { + if (++ip > limit) + { + FT_ERROR(( "T1.Parse_CharStrings : unexpected EOF in integer\n" )); + goto Syntax_Error; + } + + if (ip[-2] < 251) + value = ((long)(ip[-2]-247) << 8) + ip[-1] + 108; + else + value = -((((long)ip[-2]-251) << 8) + ip[-1] + 108 ); + } + } + else + { + FT_ERROR(( "T1.Parse_CharStrings : invalid byte (%d)\n", + ip[-1] )); + goto Syntax_Error; + } + } + + /* push value if needed */ + if ( op == op_none ) + { + if ( top - decoder->stack >= T1_MAX_CHARSTRINGS_OPERANDS ) + { + FT_ERROR(( "T1.Parse_CharStrings : Stack overflow !!\n" )); + goto Syntax_Error; + } + + *top++ = value; + decoder->top = top; + } + + else if ( op == op_callothersubr ) /* check arguments differently */ + { + if ( top - decoder->stack < 2) + goto Stack_Underflow; + + top -= 2; + + switch (top[1]) + { + case 1: /* start flex feature ----------------------------- */ + { + if (top[0] != 0) goto Unexpected_OtherSubr; + + decoder->flex_state = 1; + decoder->num_flex_vectors = 0; + decoder->flex_vectors[0].x = 0; + decoder->flex_vectors[0].y = 0; + } + break; + + + case 2: /* add flex vector ------------------------------- */ + { + T1_Int index; + T1_Vector* flex; + + if (top[0] != 0) goto Unexpected_OtherSubr; + + top -= 2; + if (top < decoder->stack) goto Stack_Underflow; + + index = decoder->num_flex_vectors++; + if (index >= 7) + { + FT_ERROR(( "T1.Parse_CharStrings: too many flex vectors !\n" )); + goto Syntax_Error; + } + + flex = decoder->flex_vectors + index; + flex->x += top[0]; + flex->y += top[1]; + + } + break; + + + case 0: /* end flex feature ------------------------------ */ + { + if ( decoder->flex_state == 0 || + decoder->num_flex_vectors != 7 ) + { + FT_ERROR(( "T1.Parse_CharStrings: unexpected flex end\n" )); + goto Syntax_Error; + } + + if (top[0] != 3) goto Unexpected_OtherSubr; + + top -= 3; + if (top < decoder->stack) goto Stack_Underflow; + + /* now consume the remaining "pop pop setcurrentpoint" */ + if ( ip+6 > limit || + ip[0] != 12 || ip[1] != 17 || /* pop */ + ip[2] != 12 || ip[3] != 17 || /* pop */ + ip[4] != 12 || ip[5] != 33 ) /* setcurrentpoint */ + { + FT_ERROR(( "T1.Parse_CharStrings: invalid flex charstring\n" )); + goto Syntax_Error; + } + + decoder->flex_state = 0; + decoder->top = top; + + error = t1operator_flex( decoder, top[0], top[1], top[2] ); + } + break; + + + case 3: /* change hints ------------------------------------ */ + { + if (top[0] != 1) goto Unexpected_OtherSubr; + + /* eat the following "pop" */ + if (ip+2 > limit) + { + FT_ERROR(( "T1.Parse_CharStrings: invalid escape (12+%d)\n", + ip[-1] )); + goto Syntax_Error; + } + + if (ip[0] != 12 || ip[1] != 17) + { + FT_ERROR(( "T1.Parse_CharStrings: 'pop' expected, found (%d %d)\n", + ip[0], ip[1] )); + goto Syntax_Error; + } + + ip += 2; + error = hints->change_hints(builder); + } + break; + + + default: + /* invalid OtherSubrs call */ + Unexpected_OtherSubr: + FT_ERROR(( "T1.Parse_CharStrings: unexpected OtherSubrs [%d %d]\n", + top[0], top[1] )); + goto Syntax_Error; + } + decoder->top = top; + } + else + { + T1_Int num_args = args_count[op]; + + if ( top - decoder->stack < num_args ) + goto Stack_Underflow; + + top -= num_args; + + switch (op) + { + case op_endchar: + error = builds->end_char( builder ); + break; + + case op_hsbw: + error = builds->set_bearing_point( builder, top[0], 0, + top[1], 0 ); + break; + + case op_seac: + /* return immediately after the processing */ + return t1operator_seac( decoder, top[0], top[1], + top[2], top[3], top[4] ); + + case op_sbw: + error = builds->set_bearing_point( builder, top[0], top[1], + top[2], top[3] ); + break; + + case op_closepath: + error = builds->close_path( builder ); + break; + + case op_hlineto: + error = builds->rline_to( builder, top[0], 0 ); + break; + + case op_hmoveto: + error = builds->rmove_to( builder, top[0], 0 ); + break; + + case op_hvcurveto: + error = builds->rcurve_to( builder, top[0], 0, + top[1], top[2], + 0, top[3] ); + break; + + case op_rlineto: + error = builds->rline_to( builder, top[0], top[1] ); + break; + + case op_rmoveto: + /* ignore operator when in flex mode */ + if (decoder->flex_state == 0) + error = builds->rmove_to( builder, top[0], top[1] ); + else + top += 2; + break; + + case op_rrcurveto: + { + error = builds->rcurve_to( builder, top[0], top[1], + top[2], top[3], + top[4], top[5] ); + } + break; + + case op_vhcurveto: + error = builds->rcurve_to( builder, 0, top[0], + top[1], top[2], + top[3], 0 ); + break; + + case op_vlineto: + error = builds->rline_to( builder, 0, top[0] ); + break; + + case op_vmoveto: + error = builds->rmove_to( builder, 0, top[0] ); + break; + + case op_dotsection: + error = hints->dot_section( builder ); + break; + + case op_hstem: + error = hints->stem( builder, top[0], top[1], 0 ); + break; + + case op_hstem3: + error = hints->stem3( builder, top[0], top[1], top[2], + top[3], top[4], top[5], 0 ); + break; + + case op_vstem: + error = hints->stem( builder, top[0], top[1], 1 ); + break; + + case op_vstem3: + error = hints->stem3( builder, top[0], top[1], top[2], + top[3], top[4], top[5], 1 ); + break; + + case op_div: + if (top[1]) + *top++ = top[0] / top[1]; + else + { + FT_ERROR(( "T1.Parse_CHarStrings : division by 0\n" )); + goto Syntax_Error; + } + break; + + case op_callsubr: + { + T1_Int index = top[0]; + + if ( index < 0 || index >= num_subrs ) + { + FT_ERROR(( "T1.Parse_CharStrings : invalid subrs index\n" )); + goto Syntax_Error; + } + + if ( zone - decoder->zones >= T1_MAX_SUBRS_CALLS ) + { + FT_ERROR(( "T1.Parse_CharStrings : too many nested subrs\n" )); + goto Syntax_Error; + } + + zone->cursor = ip; /* save current instruction pointer */ + + zone++; + zone->base = subrs_base[index]; + zone->limit = zone->base + subrs_len[index]; + zone->cursor = zone->base; + + if (!zone->base) + { + FT_ERROR(( "T1.Parse_CharStrings : invoking empty subrs !!\n" )); + goto Syntax_Error; + } + + decoder->zone = zone; + ip = zone->base; + limit = zone->limit; + } + break; + + case op_pop: + FT_ERROR(( "T1.Parse_CharStrings : unexpected POP\n" )); + goto Syntax_Error; + + + case op_return: + if ( zone <= decoder->zones ) + { + FT_ERROR(( "T1.Parse_CharStrings : unexpected return\n" )); + goto Syntax_Error; + } + + zone--; + ip = zone->cursor; + limit = zone->limit; + decoder->zone = zone; + break; + + case op_setcurrentpoint: + FT_ERROR(( "T1.Parse_CharStrings : unexpected SETCURRENTPOINT\n" )); + goto Syntax_Error; + break; + + default: + FT_ERROR(( "T1.Parse_CharStrings : unhandled opcode %d\n", op )); + goto Syntax_Error; + } + + decoder->top = top; + } + } + + return error; + + Syntax_Error: + return T1_Err_Syntax_Error; + + Stack_Underflow: + return T1_Err_Stack_Underflow; + } + + + +/*************************************************************************/ +/* */ +/* T1_Add_Points */ +/* */ +/* */ +/* Checks that there is enough room in the current load glyph outline */ +/* to accept "num_points" additional outline points. If not, this */ +/* function grows the load outline's arrays accordingly.. */ +/* */ +/* */ +/* builder :: pointer to glyph builder object */ +/* num_points :: number of points that will be added later */ +/* */ +/* */ +/* Type1 error code. 0 means success */ +/* */ +/* */ +/* This function does NOT update the points count in the glyph builder*/ +/* This must be done by the caller itself, after this function is */ +/* invoked.. */ +/* */ + LOCAL_FUNC + T1_Error T1_Add_Points( T1_Builder* builder, + T1_Int num_points ) + { + T1_Int new_points; + + new_points = builder->base.n_points + + builder->current.n_points + + num_points; + + if ( new_points > builder->max_points ) + { + FT_Memory memory = builder->memory; + T1_Error error; + T1_Int increment = builder->current.points - builder->base.points; + T1_Int current = builder->max_points; + + while ( builder->max_points < new_points ) + builder->max_points += 16; + + if ( REALLOC_ARRAY( builder->base.points, + current, builder->max_points, T1_Vector ) || + + REALLOC_ARRAY( builder->base.flags, + current, builder->max_points, T1_Byte ) ) + return error; + + builder->current.points = builder->base.points + increment; + builder->current.flags = builder->base.flags + increment; + } + + return T1_Err_Ok; + } + +/*************************************************************************/ +/* */ +/* T1_Add_Contours */ +/* */ +/* */ +/* Checks that there is enough room in the current load glyph outline */ +/* to accept "num_contours" additional contours. If not, this func */ +/* the load outline's arrays accordingly.. */ +/* */ +/* */ +/* builder :: pointer to glyph builder object */ +/* num_contours :: number of contours that will be added later */ +/* */ +/* */ +/* Type1 error code. 0 means success */ +/* */ +/* */ +/* This function does NOT update the contours count in the load glyph */ +/* This must be done by the caller itself, after this function is */ +/* invoked.. */ +/* */ + LOCAL_FUNC + T1_Error T1_Add_Contours( T1_Builder* builder, + T1_Int num_contours ) + { + T1_Int new_contours; + + new_contours = builder->base.n_contours + + builder->current.n_contours + + num_contours; + + if ( new_contours > builder->max_contours && builder->load_points ) + { + T1_Error error; + FT_Memory memory = builder->memory; + T1_Int increment = builder->current.contours - builder->base.contours; + T1_Int current = builder->max_contours; + + while ( builder->max_contours < new_contours ) + builder->max_contours += 4; + + if ( REALLOC_ARRAY( builder->base.contours, + current, builder->max_contours, T1_Short ) ) + return error; + + builder->current.contours = builder->base.contours + increment; + } + + return T1_Err_Ok; + } + + + /**********************************************************************/ + /**********************************************************************/ + /**********************************************************************/ + /********** *********/ + /********** *********/ + /********** COMPUTE THE MAXIMUM ADVANCE WIDTH *********/ + /********** *********/ + /********** The following code is in charge of computing *********/ + /********** the maximum advance width of the font. It *********/ + /********** quickly process each glyph charstring to *********/ + /********** extract the value from either a "sbw" or "seac" *********/ + /********** operator. *********/ + /********** *********/ + /**********************************************************************/ + /**********************************************************************/ + /**********************************************************************/ + + + + static + T1_Error maxadv_sbw( T1_Decoder* decoder, + T1_Pos sbx, + T1_Pos sby, + T1_Pos wx, + T1_Pos wy ) + { + if (wx > decoder->builder.advance.x) + decoder->builder.advance.x = wx; + + (void)sbx; + (void)sby; + (void)wy; + return -1; /* return an error code to exit the Type 1 parser */ + /* immediately. */ + } + + + static + T1_Int maxadv_error( void ) + { + /* we should never reach this code, unless with a buggy font */ + return -2; + } + + /* the maxadv_gbuilder_interface is used when computing the maximum */ + /* advance width of all glyphs in a given font. We only process the */ + /* 'sbw' operator here, and return an error for all others.. */ + + /* Note that "seac" is processed by the T1_Decoder */ + static + const T1_Builder_Funcs maxadv_builder_interface = + { + (T1_Builder_EndChar) maxadv_error, + (T1_Builder_Sbw) maxadv_sbw, + (T1_Builder_ClosePath) maxadv_error, + (T1_Builder_RLineTo) maxadv_error, + (T1_Builder_RMoveTo) maxadv_error, + (T1_Builder_RCurveTo) maxadv_error + }; + + + /* the maxadv_interface is used when computing the maximum advance */ + /* with of the set of glyphs in a given font file. We only process */ + /* the "seac" operator and return immediately.. */ + static + const T1_Hinter_Funcs maxadv_hinter_interface = + { + (T1_Hinter_DotSection) maxadv_error, + (T1_Hinter_ChangeHints) maxadv_error, + (T1_Hinter_Stem) maxadv_error, + (T1_Hinter_Stem3) maxadv_error, + }; + + + + LOCAL_FUNC + T1_Error T1_Compute_Max_Advance( T1_Face face, + T1_Int *max_advance ) + { + T1_Error error; + T1_Decoder decoder; + T1_Int glyph_index; + T1_Font* type1 = &face->type1; + + *max_advance = 0; + + /* Initialise load decoder */ + T1_Init_Decoder( &decoder, &maxadv_hinter_interface ); + + T1_Init_Builder( &decoder.builder, face, 0, 0, + &maxadv_builder_interface ); + + /* For each glyph, parse the glyph charstring and extract */ + /* the advance width.. */ + for ( glyph_index = 0; glyph_index < type1->num_glyphs; glyph_index++ ) + { + /* now get load the unscaled outline */ + error = T1_Parse_CharStrings( &decoder, + type1->charstrings [glyph_index], + type1->charstrings_len[glyph_index], + type1->num_subrs, + type1->subrs, + type1->subrs_len ); + /* ignore the error if one occured - skip to next glyph */ + (void)error; + } + + *max_advance = decoder.builder.advance.x; + return T1_Err_Ok; + } + + + /**********************************************************************/ + /**********************************************************************/ + /**********************************************************************/ + /********** *********/ + /********** *********/ + /********** UNHINTED GLYPH LOADER *********/ + /********** *********/ + /********** The following code is in charge of loading a *********/ + /********** single outline. It completely ignores hinting *********/ + /********** and is used when FT_LOAD_NO_HINTING is set. *********/ + /********** *********/ + /********** The Type 1 hinter is located in "t1hint.c" *********/ + /********** *********/ + /**********************************************************************/ + /**********************************************************************/ + /**********************************************************************/ + + + + static + T1_Error close_open_path( T1_Builder* builder ) + { + T1_Error error; + FT_Outline* cur = &builder->current; + T1_Int num_points; + T1_Int first_point; + + /* Some fonts, like Hershey, are made of "open paths" which are */ + /* now managed directly by FreeType. In this case, it is necessary */ + /* to close the path by duplicating its points in reverse order, */ + /* which is precisely the purpose of this function */ + + /* first compute the number of points to duplicate.. */ + if (cur->n_contours > 1) + first_point = cur->contours[ cur->n_contours-2 ]+1; + else + first_point = 0; + + num_points = cur->n_points - first_point - 2; + if ( num_points > 0 ) + { + T1_Vector* source_point; + char* source_flags; + T1_Vector* point; + char* flags; + + error = T1_Add_Points( builder, num_points ); + if (error) return error; + + point = cur->points + cur->n_points; + flags = cur->flags + cur->n_points; + + source_point = point - 2; + source_flags = flags - 2; + + cur->n_points += num_points; + + if ( builder->load_points ) + do + { + *point++ = *source_point--; + *flags++ = *source_flags--; + num_points--; + } + while (num_points > 0); + } + + builder->path_begun = 0; + return T1_Err_Ok; + } + + + static + T1_Error gload_closepath( T1_Builder* builder ) + { + FT_Outline* cur = &builder->current; + + /* save current contour, if any */ + if ( cur->n_contours > 0 ) + cur->contours[cur->n_contours-1] = cur->n_points-1; + +#ifndef T1_CONFIG_OPTION_DISABLE_HINTER + /* hint latest points if needed - this is not strictly required */ + /* there, but it helps for debugging, and doesn't affect performance */ + if ( builder->pass == 1 ) + T1_Hint_Points( builder ); +#endif + + builder->path_begun = 0; + return T1_Err_Ok; + } + + + + static + T1_Error gload_endchar( T1_Builder* builder ) + { + FT_Outline* cur = &builder->current; + T1_Error error; + + /* close path if needed */ + if (builder->path_begun) + { + error = close_open_path( builder ); + if (error) return error; + } + + error = gload_closepath( builder ); + + builder->base.n_points += cur->n_points; + builder->base.n_contours += cur->n_contours; + + return error; + } + + + + static + T1_Error gload_sbw( T1_Builder* builder, + T1_Pos sbx, + T1_Pos sby, + T1_Pos wx, + T1_Pos wy ) + { + builder->left_bearing.x += sbx; + builder->left_bearing.y += sby; + builder->advance.x = wx; + builder->advance.y = wy; + + builder->last.x = sbx; + builder->last.y = sby; + return 0; + } + + + + + static + T1_Error gload_rlineto( T1_Builder* builder, + T1_Pos dx, + T1_Pos dy ) + { + T1_Error error; + FT_Outline* cur = &builder->current; + T1_Vector vec; + + /* grow buffer if necessary */ + error = T1_Add_Points ( builder, 1 ); + if (error) return error; + + if ( builder->load_points ) + { + /* save point */ + vec.x = builder->last.x + dx; + vec.y = builder->last.y + dy; + + cur->points[cur->n_points] = vec; + cur->flags [cur->n_points] = FT_Curve_Tag_On; + + builder->last = vec; + } + cur->n_points++; + + builder->path_begun = 1; + return T1_Err_Ok; + } + + + static + T1_Error gload_rmoveto( T1_Builder* builder, + T1_Pos dx, + T1_Pos dy ) + { + T1_Error error; + FT_Outline* cur = &builder->current; + T1_Vector vec; + + /* in the case where "path_begun" is set, we have a rmoveto */ + /* after some normal path definition. When the face's paint */ + /* type is set to 1, this means that we have an "open path", */ + /* also called a 'stroke'. The FreeType raster doesn't support */ + /* opened path, so we'll close it explicitely there.. */ + if ( builder->path_begun && builder->face->type1.paint_type == 1 ) + { + if ( builder->face->type1.paint_type == 1 ) + { + error = close_open_path( builder ); + if (error) return error; + } + } + + /* grow buffer if necessary */ + error = T1_Add_Contours( builder, 1 ) || + T1_Add_Points ( builder, 1 ); + if (error) return error; + + /* save current contour, if any */ + if ( cur->n_contours > 0 ) + cur->contours[cur->n_contours-1] = cur->n_points-1; + + if ( builder->load_points ) + { + /* save point */ + vec.x = builder->last.x + dx; + vec.y = builder->last.y + dy; + cur->points[cur->n_points] = vec; + cur->flags [cur->n_points] = FT_Curve_Tag_On; + + builder->last = vec; + } + + cur->n_contours++; + cur->n_points++; + + return T1_Err_Ok; + } + + + static + T1_Error gload_rrcurveto( T1_Builder* builder, + T1_Pos dx1, + T1_Pos dy1, + T1_Pos dx2, + T1_Pos dy2, + T1_Pos dx3, + T1_Pos dy3 ) + { + T1_Error error; + FT_Outline* cur = &builder->current; + T1_Vector vec; + T1_Vector* points; + char* flags; + + /* grow buffer if necessary */ + error = T1_Add_Points ( builder, 3 ); + if (error) return error; + + if ( builder->load_points ) + { + /* save point */ + points = cur->points + cur->n_points; + flags = cur->flags + cur->n_points; + + vec.x = builder->last.x + dx1; + vec.y = builder->last.y + dy1; + points[0] = vec; flags[0] = FT_Curve_Tag_Cubic; + + vec.x += dx2; + vec.y += dy2; + points[1] = vec; flags[1] = FT_Curve_Tag_Cubic; + + vec.x += dx3; + vec.y += dy3; + points[2] = vec; flags[2] = FT_Curve_Tag_On; + + builder->last = vec; + } + + cur->n_points += 3; + builder->path_begun = 1; + return T1_Err_Ok; + } + + + + + static + T1_Error gload_ignore( void ) + { + return 0; + } + + + static + const T1_Builder_Funcs gload_builder_interface = + { + gload_endchar, + gload_sbw, + gload_closepath, + gload_rlineto, + gload_rmoveto, + gload_rrcurveto + }; + + + static + const T1_Builder_Funcs gload_builder_interface_null = + { + (T1_Builder_EndChar) gload_ignore, + (T1_Builder_Sbw) gload_sbw, /* record left bearing */ + (T1_Builder_ClosePath) gload_ignore, + (T1_Builder_RLineTo) gload_ignore, + (T1_Builder_RMoveTo) gload_ignore, + (T1_Builder_RCurveTo) gload_ignore + }; + + + static + const T1_Hinter_Funcs gload_hinter_interface = + { + (T1_Hinter_DotSection) gload_ignore, /* dotsection */ + (T1_Hinter_ChangeHints) gload_ignore, /* changehints */ + (T1_Hinter_Stem) gload_ignore, /* hstem & vstem */ + (T1_Hinter_Stem3) gload_ignore, /* hstem3 & vestem3 */ + }; + + + + + LOCAL_FUNC + T1_Error T1_Load_Glyph( T1_GlyphSlot glyph, + T1_Size size, + T1_Int glyph_index, + T1_Int load_flags ) + { + T1_Error error; + T1_Decoder decoder; + T1_Face face = (T1_Face)glyph->root.face; + T1_Bool hinting; + T1_Font* type1 = &face->type1; + + glyph->x_scale = size->root.metrics.x_scale; + glyph->y_scale = size->root.metrics.y_scale; + + glyph->root.outline.n_points = 0; + glyph->root.outline.n_contours = 0; + + hinting = ( load_flags & FT_LOAD_NO_SCALE ) == 0 && + ( load_flags & FT_LOAD_NO_HINTING ) == 0; + + glyph->root.format = ft_glyph_format_none; + +#ifndef T1_CONFIG_OPTION_DISABLE_HINTER + /*****************************************************************/ + /* */ + /* Hinter overview : */ + /* */ + /* This is a two-pass hinter. On the first pass, the hints */ + /* are all recorded by the hinter, and no point is loaded */ + /* in the outline. */ + /* */ + /* When the first pass is finished, all stems hints are */ + /* grid-fitted at once. */ + /* */ + /* Then, a second pass is performed to load the outline */ + /* points as well as hint/scale them correctly. */ + /* */ + + if ( hinting ) + { + /* Pass 1 - don't record points, simply stem hints */ + T1_Init_Decoder( &decoder, &t1_hinter_funcs ); + T1_Init_Builder( &decoder.builder, face, size, glyph, + &gload_builder_interface_null ); + + glyph->hints->hori_stems.num_stems = 0; + glyph->hints->vert_stems.num_stems = 0; + + error = T1_Parse_CharStrings( &decoder, + type1->charstrings [glyph_index], + type1->charstrings_len[glyph_index], + type1->num_subrs, + type1->subrs, + type1->subrs_len ); + + /* All right, pass 1 is finished, now grid-fit all stem hints */ + T1_Hint_Stems( &decoder.builder ); + + /* Pass 2 - record and scale/hint the points */ + T1_Init_Decoder( &decoder, &t1_hinter_funcs ); + T1_Init_Builder( &decoder.builder, face, size, glyph, + &gload_builder_interface ); + + decoder.builder.pass = 1; + + error = T1_Parse_CharStrings( &decoder, + type1->charstrings [glyph_index], + type1->charstrings_len[glyph_index], + type1->num_subrs, + type1->subrs, + type1->subrs_len ); + + /* save new glyph tables */ + T1_Done_Builder( &decoder.builder ); + } + else +#endif + { + T1_Init_Decoder( &decoder, &gload_hinter_interface ); + + T1_Init_Builder( &decoder.builder, face, size, glyph, + &gload_builder_interface ); + + /* now load the unscaled outline */ + error = T1_Parse_CharStrings( &decoder, + type1->charstrings [glyph_index], + type1->charstrings_len[glyph_index], + type1->num_subrs, + type1->subrs, + type1->subrs_len ); + + /* save new glyph tables */ + T1_Done_Builder( &decoder.builder ); + } + + + /* Now, set the metrics.. - this is rather simple, as : */ + /* the left side bearing is the xMin, and the top side */ + /* bearing the yMax.. */ + if (!error) + { + FT_BBox cbox; + FT_Glyph_Metrics* metrics = &glyph->root.metrics; + + FT_Get_Outline_CBox( &glyph->root.outline, &cbox ); + + /* grid fit the bounding box if necessary */ + if (hinting) + { + cbox.xMin &= -64; + cbox.yMin &= -64; + cbox.xMax = ( cbox.xMax+63 ) & -64; + cbox.yMax = ( cbox.yMax+63 ) & -64; + } + + metrics->width = cbox.xMax - cbox.xMin; + metrics->height = cbox.yMax - cbox.yMin; + + metrics->horiBearingX = cbox.xMin; + metrics->horiBearingY = cbox.yMax; + + /* copy the _unscaled_ advance width */ + metrics->horiAdvance = decoder.builder.advance.x; + + /* make up vertical metrics */ + metrics->vertBearingX = 0; + metrics->vertBearingY = 0; + metrics->vertAdvance = 0; + + glyph->root.format = ft_glyph_format_outline; + + glyph->root.outline.second_pass = TRUE; + glyph->root.outline.high_precision = ( size->root.metrics.y_ppem < 24 ); + glyph->root.outline.dropout_mode = 2; + + if ( hinting ) + { + /* adjust the advance width */ + /* XXX : TODO : consider stem hints grid-fit */ + metrics->horiAdvance = FT_MulFix( metrics->horiAdvance, + glyph->x_scale ); + } + else if ( (load_flags & FT_LOAD_NO_SCALE) == 0 ) + { + /* scale the outline and the metrics */ + T1_Int n; + FT_Outline* cur = &decoder.builder.base; + T1_Vector* vec = cur->points; + T1_Fixed x_scale = glyph->x_scale; + T1_Fixed y_scale = glyph->y_scale; + + /* First of all, scale the points */ + for ( n = cur->n_points; n > 0; n--, vec++ ) + { + vec->x = FT_MulFix( vec->x, x_scale ); + vec->y = FT_MulFix( vec->y, y_scale ); + } + + /* Then scale the metrics */ + metrics->width = FT_MulFix( metrics->width, x_scale ); + metrics->height = FT_MulFix( metrics->height, y_scale ); + + metrics->horiBearingX = FT_MulFix( metrics->horiBearingX, x_scale ); + metrics->horiBearingY = FT_MulFix( metrics->horiBearingY, y_scale ); + metrics->horiAdvance = FT_MulFix( metrics->horiAdvance, x_scale ); + + metrics->vertBearingX = FT_MulFix( metrics->vertBearingX, x_scale ); + metrics->vertBearingY = FT_MulFix( metrics->vertBearingY, y_scale ); + metrics->vertAdvance = FT_MulFix( metrics->vertAdvance, x_scale ); + + } + } + + return error; + } + diff --git a/src/type1z/t1gload.h b/src/type1z/t1gload.h new file mode 100644 index 000000000..f635b8197 --- /dev/null +++ b/src/type1z/t1gload.h @@ -0,0 +1,436 @@ +/******************************************************************* + * + * t1gload.h 1.0 + * + * Type1 Glyph Loader. + * + * Copyright 1996-1998 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 Type 1 glyph loader uses three distinct objects to build + * scaled and hinted outlines from a charstrings program. These are : + * + * - a glyph builder, T1_Builder, used to store the built outline + * + * - a glyph hinter, T1_Hinter, used to record and apply the stem + * hints + * + * - a charstrings interpreter, T1_Decoder, used to parse the + * Type 1 charstrings stream, manage a stack and call the builder + * and/or hinter depending on the opcodes. + * + * Ideally, a Type 2 glyph loader would only need to have its own + * T2_Decoder object (assuming the hinter is able to manage all + * kinds of hints). + * + ******************************************************************/ + +#ifndef T1GLOAD_H +#define T1GLOAD_H + +#include + +#ifdef __cplusplus + extern "C" { +#endif + + +/*************************************************************************/ +/* */ +/* T1_Builder_Funcs */ +/* */ +/* */ +/* a structure used to store the address of various functions */ +/* used by a glyph builder to implement the outline's "path */ +/* construction". */ +/* */ +/* */ + typedef struct T1_Builder_ T1_Builder; + + typedef T1_Error (*T1_Builder_EndChar)( T1_Builder* loader ); + + typedef T1_Error (*T1_Builder_Sbw) ( T1_Builder* loader, + T1_Pos sbx, + T1_Pos sby, + T1_Pos wx, + T1_Pos wy ); + + typedef T1_Error (*T1_Builder_ClosePath)( T1_Builder* loader ); + + typedef T1_Error (*T1_Builder_RLineTo)( T1_Builder* loader, + T1_Pos dx, + T1_Pos dy ); + + typedef T1_Error (*T1_Builder_RMoveTo)( T1_Builder* loader, + T1_Pos dx, + T1_Pos dy ); + + typedef T1_Error (*T1_Builder_RCurveTo)( T1_Builder* loader, + T1_Pos dx1, + T1_Pos dy1, + T1_Pos dx2, + T1_Pos dy2, + T1_Pos dx3, + T1_Pos dy3 ); + + typedef struct T1_Builder_Funcs_ + { + T1_Builder_EndChar end_char; + T1_Builder_Sbw set_bearing_point; + T1_Builder_ClosePath close_path; + T1_Builder_RLineTo rline_to; + T1_Builder_RMoveTo rmove_to; + T1_Builder_RCurveTo rcurve_to; + + } T1_Builder_Funcs; + + + +/*************************************************************************/ +/* */ +/* T1_Builder */ +/* */ +/* */ +/* a structure used during glyph loading to store its outline. */ +/* */ +/* */ +/* system :: current system object */ +/* face :: current face object */ +/* size :: current size object */ +/* glyph :: current glyph slot */ +/* */ +/* current :: current glyph outline */ +/* base :: base glyph outline */ +/* */ +/* max_points :: maximum points in builder outline */ +/* max_contours :: maximum contours in builder outline */ +/* */ +/* last :: last point position */ +/* */ +/* scale_x :: horizontal scale ( FUnits to sub-pixels ) */ +/* scale_y :: vertical scale ( FUnits to sub-pixels ) */ +/* pos_x :: horizontal translation (composite glyphs) */ +/* pos_y :: vertical translation (composite glyph) */ +/* */ +/* left_bearing :: left side bearing point */ +/* advance :: horizontal advance vector */ +/* */ +/* path_begun :: flag, indicates that a new path has begun */ +/* load_points :: flag, if not set, no points are loaded */ +/* */ +/* pass :: pass number for multi-pass hinters */ +/* */ +/* funcs :: table of builder functions used to perform */ +/* the outline's path construction */ +/* */ +/* hint_point :: index of next point to hint.. */ +/* */ +/* */ +/* */ +/* */ + + struct T1_Builder_ + { + FT_Memory memory; + T1_Face face; + T1_Size size; + T1_GlyphSlot glyph; + + FT_Outline current; /* the current glyph outline */ + FT_Outline base; /* the composite glyph outline */ + + T1_Int max_points; /* capacity of base outline in points */ + T1_Int max_contours; /* capacity of base outline in contours */ + + T1_Vector last; + + T1_Fixed scale_x; + T1_Fixed scale_y; + + T1_Pos pos_x; + T1_Pos pos_y; + + T1_Vector left_bearing; + T1_Vector advance; + + T1_BBox bbox; /* bounding box */ + T1_Bool path_begun; + T1_Bool load_points; + + T1_Int pass; + T1_Int hint_point; + + /* path construction function interface */ + T1_Builder_Funcs funcs; + }; + + +/*************************************************************************/ +/* */ +/* T1_Hinter_Funcs */ +/* */ +/* */ +/* a structure used to store the address of various functions */ +/* used by a Type 1 hinter to perform outline hinting. */ +/* */ + + typedef T1_Error (*T1_Hinter_ChangeHints)( T1_Builder* builder ); + + typedef T1_Error (*T1_Hinter_DotSection)( T1_Builder* builder ); + + typedef T1_Error (*T1_Hinter_Stem)( T1_Builder* builder, + T1_Pos pos, + T1_Pos width, + T1_Bool vertical ); + + + typedef T1_Error (*T1_Hinter_Stem3)( T1_Builder* builder, + T1_Pos pos0, + T1_Pos width0, + T1_Pos pos1, + T1_Pos width1, + T1_Pos pos2, + T1_Pos width2, + T1_Bool vertical ); + + typedef struct T1_Hinter_Func_ + { + T1_Hinter_ChangeHints change_hints; + T1_Hinter_DotSection dot_section; + T1_Hinter_Stem stem; + T1_Hinter_Stem3 stem3; + + } T1_Hinter_Funcs; + + + + typedef enum T1_Operator_ + { + op_none = 0, + op_endchar, + op_hsbw, + op_seac, + op_sbw, + op_closepath, + op_hlineto, + op_hmoveto, + op_hvcurveto, + op_rlineto, + op_rmoveto, + op_rrcurveto, + op_vhcurveto, + op_vlineto, + op_vmoveto, + op_dotsection, + op_hstem, + op_hstem3, + op_vstem, + op_vstem3, + op_div, + op_callothersubr, + op_callsubr, + op_pop, + op_return, + op_setcurrentpoint, + + op_max /* never remove this one */ + + } T1_Operator; + + + + + /* execution context charstring zone */ + typedef struct T1_Decoder_Zone_ + { + T1_Byte* base; + T1_Byte* limit; + T1_Byte* cursor; + + } T1_Decoder_Zone; + + + typedef struct T1_Decoder_ + { + T1_Builder builder; + T1_Hinter_Funcs hinter; + + T1_Int stack[ T1_MAX_CHARSTRINGS_OPERANDS ]; + T1_Int* top; + + T1_Decoder_Zone zones[ T1_MAX_SUBRS_CALLS+1 ]; + T1_Decoder_Zone* zone; + + T1_Int flex_state; + T1_Int num_flex_vectors; + T1_Vector flex_vectors[7]; + + } T1_Decoder; + + + +/********************************************************************* + * + * + * T1_Init_Builder + * + * + * Initialise a given glyph builder. + * + * + * builder :: glyph builder to initialise + * face :: current face object + * size :: current size object + * glyph :: current glyph object + * funcs :: glyph builder functions (or "methods"). + * + * + * This function is exported for now because it is used by the + * "t1dump" utility. Later, it will be accessed through a + * format-specific extension + * + *********************************************************************/ + + EXPORT_DEF + void T1_Init_Builder( T1_Builder* builder, + T1_Face face, + T1_Size size, + T1_GlyphSlot glyph, + const T1_Builder_Funcs* funcs ); + +/********************************************************************* + * + * + * T1_Done_Builder + * + * + * Finalise a given glyph builder. Its content can still be + * used after the call, but the function saves important information + * within the corresponding glyph slot. + * + * + * builder :: glyph builder to initialise + * + * + * This function is exported for now because it is used by the + * "t1dump" utility. Later, it will be accessed through a + * format-specific extension + * + *********************************************************************/ + + EXPORT_DEF + void T1_Done_Builder( T1_Builder* builder ); + + +/********************************************************************* + * + * + * T1_Init_Decoder + * + * + * Initialise a given Type 1 decoder for parsing + * + * + * decoder :: Type 1 decoder to initialise + * funcs :: hinter functions interface + * + * + * This function is exported for now because it is used by the + * "t1dump" utility. Later, it will be accessed through a + * format-specific extension + * + *********************************************************************/ + + EXPORT_DEF + void T1_Init_Decoder( T1_Decoder* decoder, + const T1_Hinter_Funcs* funcs ); + + + + /* Compute the maximum advance width of a font through quick parsing */ + LOCAL_DEF + T1_Error T1_Compute_Max_Advance( T1_Face face, + T1_Int *max_advance ); + + + /* This function is exported, because it is used by the T1Dump utility */ + EXPORT_DEF + T1_Error T1_Parse_CharStrings( T1_Decoder* decoder, + T1_Byte* charstring_base, + T1_Int charstring_len, + T1_Int num_subrs, + T1_Byte** subrs_base, + T1_Int* subrs_len ); + + + +/*************************************************************************/ +/* */ +/* T1_Add_Points */ +/* */ +/* */ +/* Checks that there is enough room in the current load glyph outline */ +/* to accept "num_points" additional outline points. If not, this */ +/* function grows the load outline's arrays accordingly.. */ +/* */ +/* */ +/* builder :: pointer to glyph builder object */ +/* num_points :: number of points that will be added later */ +/* */ +/* */ +/* Type1 error code. 0 means success */ +/* */ +/* */ +/* This function does NOT update the points count in the glyph loader */ +/* This must be done by the caller itself, after this function is */ +/* invoked.. */ +/* */ + LOCAL_DEF + T1_Error T1_Add_Points( T1_Builder* builder, + T1_Int num_points ); + +/*************************************************************************/ +/* */ +/* T1_Add_Contours */ +/* */ +/* */ +/* Checks that there is enough room in the current load glyph outline */ +/* to accept "num_contours" additional contours. If not, this func */ +/* the load outline's arrays accordingly.. */ +/* */ +/* */ +/* builder :: pointer to glyph builder object */ +/* num_contours :: number of contours that will be added later */ +/* */ +/* */ +/* Type1 error code. 0 means success */ +/* */ +/* */ +/* This function does NOT update the contours count in the load glyph */ +/* This must be done by the caller itself, after this function is */ +/* invoked.. */ +/* */ + LOCAL_DEF + T1_Error T1_Add_Contours( T1_Builder* builder, + T1_Int num_contours ); + + + LOCAL_DEF + T1_Error T1_Load_Glyph( T1_GlyphSlot glyph, + T1_Size size, + T1_Int glyph_index, + T1_Int load_flags ); + + +#ifdef __cplusplus + } +#endif + +#endif /* T1GLOAD_H */ diff --git a/src/type1z/t1hinter.c b/src/type1z/t1hinter.c new file mode 100644 index 000000000..dc59441bd --- /dev/null +++ b/src/type1z/t1hinter.c @@ -0,0 +1,1269 @@ +/******************************************************************* + * + * t1hinter.c 1.2 + * + * Type1 hinter. + * + * Copyright 1996-1999 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 Hinter is in charge of fitting th scaled outline to the + * pixel grid in order to considerably improve the quality of + * the Type 1 font driver's output.. + * + ******************************************************************/ + +#include +#include +#include + +#undef FT_COMPONENT +#define FT_COMPONENT trace_t1hint /* for debugging/tracing */ + + +#undef ONE_PIXEL +#define ONE_PIXEL 64 + +#undef ROUND +#define ROUND(x) (( x + ONE_PIXEL/2 ) & -ONE_PIXEL) + +#undef SCALE +#define SCALE(val) FT_MulFix( val, scale ) + +/* various constants used to describe the alignment of a horizontal */ +/* stem with regards to the blue zones */ +#define T1_ALIGN_NONE 0 +#define T1_ALIGN_BOTTOM 1 +#define T1_ALIGN_TOP 2 +#define T1_ALIGN_BOTH 3 + + +/************************************************************************ + * + * + * t1_set_blue_zones + * + * + * Set a size object's blue zones during reset. This will compute + * the "snap" zone corresponding to each blue zone. + * + * + * size :: handle to target size object + * + * + * Error code. 0 means success + * + * + * This functions does the following : + * + * 1. It extracts the bottom and top blue zones from the + * face object. + * + * 2. Each zone is then grown by BlueFuzz, overlapping + * is eliminated by adjusting the zone edges appropriately + * + * 3. For each zone, we keep its original font units position, its + * original scaled position, as well as its grown/adjusted + * edges. + * + ************************************************************************/ + + /* ultra simple bubble sort (not a lot of elements, mostly */ + /* pre-sorted, no need for quicksort) */ + static + void t1_sort_blues( T1_Int* blues, + T1_Int count ) + { + T1_Int i, swap; + T1_Int* cur; + + for ( i = 2; i < count; i += 2 ) + { + cur = blues + i; + do + { + if ( cur[-1] < cur[0] ) + break; + + swap = cur[-2]; cur[-2] = cur[0]; cur[0] = swap; + swap = cur[-1]; cur[-1] = cur[1]; cur[1] = swap; + cur -= 2; + } + while ( cur > blues ); + } + } + + + static + T1_Error t1_set_blue_zones( T1_Size size ) + { + T1_Face face = (T1_Face)size->root.face; + T1_Font* priv = &face->type1; + T1_Int n; + T1_Int blues[24]; + T1_Int num_bottom; + T1_Int num_top; + T1_Int num_blues; + T1_Size_Hints* hints = size->hints; + T1_Snap_Zone* zone; + T1_Pos pix, orus; + T1_Pos min, max, threshold; + T1_Fixed scale; + T1_Bool is_bottom; + + /**********************************************************************/ + /* */ + /* COPY BOTTOM AND TOP BLUE ZONES IN LOCAL ARRAYS */ + /* */ + /* */ + + /* First of all, check the sizes of the /BlueValues and /OtherBlues */ + /* tables. They all must contain an even number of arguments */ + if ( priv->num_other_blues & 1 || + priv->num_blues & 1 ) + { + FT_ERROR(( "T1.Copy_Blues : odd number of blue values\n" )); + return T1_Err_Syntax_Error; + } + + /* copy the bottom blue zones from /OtherBlues */ + num_top = 0; + num_bottom = priv->num_other_blues; + + for ( n = 0; n < num_bottom; n ++ ) + blues[n] = priv->other_blues[n]; + + /* Add the first blue zone in /BlueValues to the table */ + num_top = priv->num_blues - 2; + if ( num_top >= 0 ) + { + blues[ num_bottom ] = priv->blue_values[0]; + blues[num_bottom+1] = priv->blue_values[1]; + + num_bottom += 2; + } + + /* sort the bottom blue zones */ + t1_sort_blues( blues, num_bottom ); + + hints->num_bottom_zones = num_bottom >> 1; + + /* now copy the /BlueValues to the top of the blues array */ + if ( num_top > 0 ) + { + for ( n = 0; n < num_top; n++ ) + blues[ num_bottom+n ] = priv->blue_values[n+2]; + + /* sort the top blue zones */ + t1_sort_blues( blues + num_bottom, num_top ); + } + else + num_top = 0; + + num_blues = num_top + num_bottom; + hints->num_blue_zones = ( num_blues ) >> 1; + + /**********************************************************************/ + /* */ + /* BUILD BLUE SNAP ZONES FROM THE LOCAL BLUES ARRAYS */ + /* */ + /* */ + + scale = size->root.metrics.y_scale; + zone = hints->blue_zones; + threshold = ONE_PIXEL/4; /* 0.25 pixels */ + + for ( n = 0; n < num_blues; n += 2, zone ++ ) + { + is_bottom = ( n < num_bottom ? 1 : 0 ); + + orus = blues[n+is_bottom]; /* get alignement coordinate */ + pix = SCALE( orus ); /* scale it */ + + min = SCALE( blues[ n ] - priv->blue_fuzz ); + max = SCALE( blues[n+1] + priv->blue_fuzz ); + + if ( min > pix - threshold ) min = pix - threshold; + if ( max < pix + threshold ) max = pix + threshold; + + zone->orus = orus; + zone->pix = pix; + zone->min = min; + zone->max = max; + } + + /* adjust edges in case of overlap */ + zone = hints->blue_zones; + for ( n = 0; n < num_blues-2; n += 2, zone ++ ) + { + if ( n != num_bottom-2 && + zone[0].max > zone[1].min ) + { + zone[0].max = zone[1].min = (zone[0].pix+zone[1].pix)/2; + } + } + + + /* Compare the current pixel size with the BlueScale value */ + /* to know wether to supress overshoots.. */ + + hints->supress_overshoots = + ( size->root.metrics.y_ppem < FT_MulFix(1000,priv->blue_scale) ); + + /* Now print the new blue values in tracing mode */ +#ifdef FT_DEBUG_LEVEL_TRACE + + FT_TRACE2(( "Blue Zones for size object at $%08lx :\n", (long)size )); + FT_TRACE2(( " orus pix min max\n" )); + FT_TRACE2(( "-------------------------------\n" )); + + zone = hints->blue_zones; + for ( n = 0; n < hints->num_blue_zones; n++ ) + { + FT_TRACE2(( " %3d %.2f %.2f %.2f\n", + zone->orus, + zone->pix/64.0, + zone->min/64.0, + zone->max/64.0 )); + zone++; + } + FT_TRACE2(( "\nOver shoots are %s\n\n", + hints->supress_overshoots ? "supressed" : "active" )); + +#endif /* DEBUG_LEVEL_TRACE */ + + return T1_Err_Ok; + } + + + +/************************************************************************ + * + * + * t1_set_snap_zones + * + * + * This function set a size object's stem snap zones. + * + * + * size :: handle to target size object + * + * + * Error code. 0 means success + * + * + * This function performs the following : + * + * 1. It reads and scales the stem snap widths from the parent face + * + * 2. A "snap zone" is computed for each snap width, by "growing" + * it with a threshold of a 1/2 pixel. Overlapping is avoided + * through proper edge adjustment. + * + * 3. Each width whose zone contain the scaled standard set width + * is removed from the table + * + * 4. Finally, the standard set width is scaled, and its correponding + * "snap zone" is inserted into the sorted snap zones table + * + ************************************************************************/ + + static + T1_Error t1_set_snap_zones( T1_Size size ) + { + T1_Int n, direction, n_zones, num_zones; + T1_Snap_Zone* zone; + T1_Snap_Zone* base_zone; + T1_Short* orgs; + T1_Pos standard_width; + T1_Fixed scale; + + T1_Face face = (T1_Face)size->root.face; + T1_Font* priv = &face->type1; + T1_Size_Hints* hints = size->hints; + + /* start with horizontal snap zones */ + direction = 0; + standard_width = priv->standard_width; + n_zones = priv->num_snap_widths; + base_zone = hints->snap_widths; + orgs = priv->stem_snap_widths; + scale = size->root.metrics.x_scale; + + while (direction < 2) + { + /*****************************************************************/ + /* */ + /* Read and scale stem snap widths table from the physical */ + /* font record. */ + /* */ + T1_Pos prev, orus, pix, min, max, threshold; + + threshold = ONE_PIXEL/4; + zone = base_zone; + + if ( n_zones > 0 ) + { + orus = *orgs++; + pix = SCALE( orus ); + min = pix-threshold; + max = pix+threshold; + + zone->orus = orus; + zone->pix = pix; + zone->min = min; + prev = pix; + + for ( n = 1; n < n_zones; n++ ) + { + orus = *orgs++; + pix = SCALE( orus ); + + if ( pix-prev < 2*threshold ) + { + min = max = (pix+prev)/2; + } + else + min = pix-threshold; + + zone->max = max; + zone++; + zone->orus = orus; + zone->pix = pix; + zone->min = min; + + max = pix+threshold; + prev = pix; + } + zone->max = max; + } + + /* print the scaled stem snap values in tracing modes */ +#ifdef FT_DEBUG_LEVEL_TRACE + + FT_TRACE2(( "Set_Snap_Zones : first %s pass\n", + direction ? "vertical" : "horizontal" )); + + FT_TRACE2(( "Scaled original stem snap zones :\n" )); + FT_TRACE2(( " orus pix min max\n" )); + FT_TRACE2(( "-----------------------------\n" )); + + zone = base_zone; + for ( n = 0; n < n_zones; n++, zone++ ) + FT_TRACE2(( " %3d %.2f %.2f %.2f\n", + zone->orus, + zone->pix/64.0, + zone->min/64.0, + zone->max/64.0 )); + FT_TRACE2(( "\n" )); + + FT_TRACE2(( "Standard width = %d\n", standard_width )); +#endif + + /*****************************************************************/ + /* */ + /* Now, each snap width which is in the range of the standard */ + /* set width will be removed from the list.. */ + /* */ + + if ( standard_width > 0 ) + { + T1_Snap_Zone* parent; + T1_Pos std_pix, std_min, std_max; + + std_pix = SCALE( standard_width ); + + std_min = std_pix-threshold; + std_max = std_pix+threshold; + + num_zones = 0; + zone = base_zone; + parent = base_zone; + + for ( n = 0; n < n_zones; n++ ) + { + if ( zone->pix >= std_min && zone->pix <= std_max ) + { + /* this zone must be removed from the list */ + if ( std_min > zone->min ) std_min = zone->min; + if ( std_max < zone->max ) std_max = zone->max; + } + else + { + *parent++ = *zone; + num_zones++; + } + zone++; + } + + /**********************************************/ + /* Now, insert the standard width zone */ + + zone = base_zone+num_zones; + while ( zone > base_zone && zone[-1].pix > std_max ) + { + zone[0] = zone[-1]; + zone --; + } + + /* check border zones */ + if ( zone > base_zone && zone[-1].max > std_min ) + zone[-1].max = std_min; + + if ( zone < base_zone+num_zones && zone[1].min < std_max ) + zone[1].min = std_max; + + zone->orus = standard_width; + zone->pix = std_pix; + zone->min = std_min; + zone->max = std_max; + + num_zones++; + } + else + num_zones = n_zones; + + /* save total number of stem snaps now */ + if (direction) hints->num_snap_heights = num_zones; + else hints->num_snap_widths = num_zones; + + /* print the scaled stem snap values in tracing modes */ +#ifdef FT_DEBUG_LEVEL_TRACE + + FT_TRACE2(( "Set_Snap_Zones : second %s pass\n", + direction ? "vertical" : "horizontal" )); + + FT_TRACE2(( "Scaled clipped stem snap zones :\n" )); + FT_TRACE2(( " orus pix min max\n" )); + FT_TRACE2(( "-----------------------------\n" )); + + zone = base_zone; + for ( n = 0; n < num_zones; n++, zone++ ) + FT_TRACE2(( " %3d %.2f %.2f %.2f\n", + zone->orus, + zone->pix/64.0, + zone->min/64.0, + zone->max/64.0 )); + FT_TRACE2(( "\n" )); + + FT_TRACE2(( "Standard width = %d\n", standard_width )); +#endif + + /* continue with vertical snap zone */ + direction++; + standard_width = priv->standard_height; + n_zones = priv->num_snap_heights; + base_zone = hints->snap_heights; + orgs = priv->stem_snap_heights; + scale = size->root.metrics.y_scale; + } + + return T1_Err_Ok; + } + + +/************************************************************************ + * + * + * T1_New_Size_Hinter + * + * + * Allocates a new hinter structure for a given size object + * + * + * size :: handle to target size object + * + * + * Error code. 0 means success + * + ************************************************************************/ + + LOCAL_FUNC + T1_Error T1_New_Size_Hinter( T1_Size size ) + { + FT_Memory memory = size->root.face->memory; + + return MEM_Alloc( size->hints, sizeof(*size->hints) ); + } + + +/************************************************************************ + * + * + * T1_Done_Size_Hinter + * + * + * Releases a given size object's hinter structure + * + * + * size :: handle to target size object + * + ************************************************************************/ + + LOCAL_FUNC + void T1_Done_Size_Hinter( T1_Size size ) + { + FT_Memory memory = size->root.face->memory; + + FREE( size->hints ); + } + + + +/************************************************************************ + * + * + * T1_Reset_Size_Hinter + * + * + * Recomputes hinting information when a given size object has + * changed its resolutions/char sizes/pixel sizes + * + * + * size :: handle to size object + * + * + * Error code. 0 means success + * + ************************************************************************/ + + LOCAL_FUNC + T1_Error T1_Reset_Size_Hinter( T1_Size size ) + { + return t1_set_blue_zones(size) || t1_set_snap_zones(size); + } + + + +/************************************************************************ + * + * + * T1_New_Glyph_Hinter + * + * + * Allocates a new hinter structure for a given glyph slot + * + * + * glyph :: handle to target glyph slot + * + * + * Error code. 0 means success + * + ************************************************************************/ + + LOCAL_FUNC + T1_Error T1_New_Glyph_Hinter( T1_GlyphSlot glyph ) + { + FT_Memory memory = glyph->root.face->memory; + + return MEM_Alloc( glyph->hints, sizeof(*glyph->hints) ); + } + + +/************************************************************************ + * + * + * T1_Done_Glyph_Hinter + * + * + * Releases a given glyph slot's hinter structure + * + * + * glyph :: handle to glyph slot + * + ************************************************************************/ + + LOCAL_FUNC + void T1_Done_Glyph_Hinter( T1_GlyphSlot glyph ) + { + FT_Memory memory = glyph->root.face->memory; + + FREE( glyph->hints ); + } + + + + /**********************************************************************/ + /**********************************************************************/ + /**********************************************************************/ + /********** *********/ + /********** *********/ + /********** HINTED GLYPH LOADER *********/ + /********** *********/ + /********** The following code is in charge of the first *********/ + /********** and second pass when loading a single outline *********/ + /********** *********/ + /**********************************************************************/ + /**********************************************************************/ + /**********************************************************************/ + + static + T1_Error t1_hinter_ignore( void ) + { + /* do nothing, used for "dotsection" which is unsupported for now */ + return 0; + } + + static + T1_Error t1_hinter_stem( T1_Builder* builder, + T1_Pos pos, + T1_Int width, + T1_Bool vertical ) + { + T1_Stem_Table* stem_table; + T1_Stem_Hint* stems; + T1_Stem_Hint* cur_stem; + T1_Int min, max, n, num_stems; + T1_Bool new_stem; + T1_Glyph_Hints* hinter = builder->glyph->hints; + + /* select the appropriate stem array */ + stem_table = vertical ? &hinter->vert_stems : &hinter->hori_stems; + stems = stem_table->stems; + num_stems = stem_table->num_stems; + + /* Compute minimum and maximum orus for the stem */ + min = pos + ( vertical + ? builder->left_bearing.x + : builder->left_bearing.y ); + + if ( width >= 0 ) + max = min + width; + else + { + /* a negative width indicates a ghost stem */ + if ( width == -21 ) + min += width; + + max = min; + } + + /* now scan the array. If we find a stem with the same borders */ + /* simply activate it.. */ + cur_stem = stems; + new_stem = 1; + + for ( n = 0; n < num_stems; n++, cur_stem++ ) + { + if ( cur_stem->min_edge.orus == min && + cur_stem->max_edge.orus == max ) + { + /* This stem is already in the table, simply activate it */ + if ( (cur_stem->hint_flags & T1_HINT_FLAG_ACTIVE) == 0) + { + cur_stem->hint_flags |= T1_HINT_FLAG_ACTIVE; + stem_table->num_active ++; + } + new_stem = 0; + break; + } + } + + /* add a new stem to the array when necessary */ + if (new_stem) + { + if (cur_stem >= stems + T1_HINTER_MAX_EDGES) + { + FT_ERROR(( "T1.Hinter : too many stems in glyph charstring\n" )); + return T1_Err_Syntax_Error; + } + + /* on the first pass, we record the stem, otherwise, this is */ + /* a bug in the glyph loader !! */ + if ( builder->pass == 0 ) + { + cur_stem->min_edge.orus = min; + cur_stem->max_edge.orus = max; + cur_stem->hint_flags = T1_HINT_FLAG_ACTIVE; + + stem_table->num_stems++; + stem_table->num_active++; + } + else + { + FT_ERROR(( "T1.Hinter : fatal glyph loader bug - pass2-stem\n" )); + return T1_Err_Syntax_Error; + } + } + + return T1_Err_Ok; + } + + + static + T1_Error t1_hinter_stem3( T1_Builder* builder, + T1_Pos pos0, + T1_Int width0, + T1_Pos pos1, + T1_Int width1, + T1_Pos pos2, + T1_Int width2, + T1_Bool vertical ) + { + /* For now, don't be elitist and simply call "stem" 3 times */ + return t1_hinter_stem( builder, pos0, width0, vertical ) || + t1_hinter_stem( builder, pos1, width1, vertical ) || + t1_hinter_stem( builder, pos2, width2, vertical ); + } + + + static + T1_Error t1_hinter_changehints( T1_Builder* builder ) + { + T1_Int dimension; + T1_Stem_Table* stem_table; + T1_Glyph_Hints* hinter = builder->glyph->hints; + + /* if we're in the second pass of glyph hinting, we must */ + /* call the function T1_Hint_Points on the builder in order */ + /* to force the fit the latest points to the pixel grid */ + if ( builder->pass == 1 ) + T1_Hint_Points( builder ); + + /* Simply de-activate all hints in all arrays */ + stem_table = &hinter->hori_stems; + + for ( dimension = 2; dimension > 0; dimension-- ) + { + T1_Stem_Hint* cur = stem_table->stems; + T1_Stem_Hint* limit = cur + stem_table->num_stems; + + for ( ; cur < limit; cur++ ) + cur->hint_flags &= ~T1_HINT_FLAG_ACTIVE; + + stem_table->num_active = 0; + stem_table = &hinter->vert_stems; + } + + return T1_Err_Ok; + } + + + LOCAL_FUNC + const T1_Hinter_Funcs t1_hinter_funcs = + { + (T1_Hinter_ChangeHints) t1_hinter_changehints, + (T1_Hinter_DotSection) t1_hinter_ignore, + (T1_Hinter_Stem) t1_hinter_stem, + (T1_Hinter_Stem3) t1_hinter_stem3 + }; + + + /**********************************************************************/ + /**********************************************************************/ + /**********************************************************************/ + /********** *********/ + /********** *********/ + /********** STEM HINTS MANAGEMENT *********/ + /********** *********/ + /********** The following code is in charge of computing *********/ + /********** the placement of each scaled stem hint.. *********/ + /********** *********/ + /**********************************************************************/ + /**********************************************************************/ + /**********************************************************************/ + +/************************************************************************ + * + * + * t1_sort_hints + * + * + * Sort the list of active stems in increasing order, through + * the "sort" indexing table + * + * + * table :: a stem hints table + * + ************************************************************************/ + + static + void t1_sort_hints( T1_Stem_Table* table ) + { + T1_Int num_stems = table->num_stems; + T1_Int num_active = 0; + T1_Int* sort = table->sort; + T1_Stem_Hint* stems = table->stems; + T1_Int n; + + /* record active stems in sort table */ + for ( n = 0; n < num_stems; n++ ) + { + if ( stems[n].hint_flags & T1_HINT_FLAG_ACTIVE ) + sort[num_active++] = n; + } + + /* now sort the indices. There are usually very few stems, */ + /* and they are pre-sorted in 90% cases, so we choose a */ + /* simple bubble sort (quicksort would be slower).. */ + for ( n = 1; n < num_active; n++ ) + { + T1_Int p = n-1; + T1_Stem_Hint* cur = stems + sort[n]; + + do + { + T1_Int swap; + T1_Stem_Hint* prev = stems + sort[p]; + + /* note that by definition, the active stems cannot overlap */ + /* so we simply compare their "min" to sort them.. */ + /* (we could compare their max, this wouldn't change anything) */ + if ( prev->min_edge.orus <= cur->min_edge.orus ) + break; + + /* swap elements */ + swap = sort[ p ]; + sort[ p ] = sort[p+1]; + sort[p+1] = swap; + p--; + } + while ( p >= 0 ); + } + + table->num_active = num_active; + } + + +/************************************************************************ + * + * + * t1_hint_horizontal_stems + * + * + * Compute the location of each scaled horizontal stem hint. + * This takes care of the blue zones and the horizontal stem + * snap table + * + * + * table :: the horizontal stem hints table + * hints :: the current size's hint structure + * blueShift :: the value of the /BlueShift as taken from the + * face object. + * scale :: the 16.16 scale used to convert outline + * units to 26.6 pixels + * + * + * For now, all stems are hinted independently from each other. + * It might be necessary, for better performance, to introduce + * the notion of "controlled" hints describing things like + * counter-stems, stem3 as well as overlapping stems control. + * + ************************************************************************/ + + static + void t1_hint_horizontal_stems( T1_Stem_Table* table, + T1_Size_Hints* hints, + T1_Pos blueShift, + T1_Fixed scale ) + { + T1_Stem_Hint* stem = table->stems; + T1_Stem_Hint* limit = stem + table->num_stems; + + /* first of all, scale the blueShift */ + blueShift = SCALE(blueShift); + + /* then scan the horizontal stem table */ + for ( ; stem < limit; stem++ ) + { + T1_Pos bottom_orus = stem->min_edge.orus; + T1_Pos top_orus = stem->max_edge.orus; + + T1_Pos top_pix = SCALE( top_orus ); + T1_Pos bottom_pix = SCALE( bottom_orus ); + T1_Pos width_pix = top_pix - bottom_pix; + + T1_Pos bottom = bottom_pix; + T1_Pos top = top_pix; + T1_Int align = T1_ALIGN_NONE; + + /******************************************************************/ + /* Snap pixel width if in stem snap range */ + { + T1_Snap_Zone* zone = hints->snap_heights; + T1_Snap_Zone* zone_limit = zone + hints->num_snap_heights; + + for ( ; zone < zone_limit; zone++ ) + { + if ( width_pix < zone->min ) + break; + + if ( width_pix <= zone->max ) + { + width_pix = zone->pix; + break; + } + } + } + + /******************************************************************/ + /* round width - minimum 1 pixel if this isn't a ghost stem */ + if ( width_pix > 0 ) + width_pix = ( width_pix < ONE_PIXEL ? ONE_PIXEL : ROUND(width_pix) ); + + + /******************************************************************/ + /* Now check for bottom blue zones alignement */ + { + T1_Int num_blues = hints->num_bottom_zones; + T1_Snap_Zone* blue = hints->blue_zones; + T1_Snap_Zone* blue_limit = blue + num_blues; + + for ( ; blue < blue_limit; blue++ ) + { + if ( bottom_pix < blue->min ) + break; + + if ( bottom_pix <= blue->max ) + { + align = T1_ALIGN_BOTTOM; + bottom = ROUND( blue->pix ); + + /* implements blue shift */ + if (!hints->supress_overshoots) + { + T1_Pos delta = blue->pix - bottom_pix; + + delta = ( delta < blueShift ? 0 : ROUND( delta ) ); + bottom -= delta; + } + } + } + } + + + /******************************************************************/ + /* Check for top blue zones alignement */ + { + T1_Int num_blues = hints->num_blue_zones - + hints->num_bottom_zones; + + T1_Snap_Zone* blue = hints->blue_zones + + hints->num_bottom_zones; + + T1_Snap_Zone* blue_limit = blue + num_blues; + + for ( ; blue < blue_limit; blue++ ) + { + if ( top_pix < blue->min ) + break; + + if ( top_pix <= blue->max ) + { + align |= T1_ALIGN_TOP; + top = ROUND( blue->pix ); + + /* implements blue shift */ + if (!hints->supress_overshoots) + { + T1_Pos delta = top - blue->pix; + + delta = ( delta < blueShift ? 0 : ROUND( delta ) ); + top += delta; + } + } + } + } + + + /******************************************************************/ + /* compute the hinted stem position, according to its alignment */ + switch (align) + { + case T1_ALIGN_BOTTOM: /* bottom zone alignement */ + bottom_pix = bottom; + top_pix = bottom + width_pix; + break; + + case T1_ALIGN_TOP: /* top zone alignement */ + top_pix = top; + bottom_pix = top - width_pix; + + break; + + case T1_ALIGN_BOTH: /* bottom+top zone alignement */ + bottom_pix = bottom; + top_pix = top; + break; + + default: /* no alignement */ + + /* XXXX : TODO : Add management of controlled stems */ + bottom = ( SCALE(bottom_orus+top_orus) - width_pix )/2; + + bottom_pix = ROUND(bottom); + top_pix = bottom_pix + width_pix; + } + + stem->min_edge.pix = bottom_pix; + stem->max_edge.pix = top_pix; + } + } + + + + +/************************************************************************ + * + * + * t1_hint_vertical_stems + * + * + * Compute the location of each scaled vertical stem hint. + * This takes care of the vertical stem snap table + * + * + * table :: the vertical stem hints table + * hints :: the current size's hint structure + * scale :: the 16.16 scale used to convert outline + * units to 26.6 pixels + * + * + * For now, all stems are hinted independently from each other. + * It might be necessary, for better performance, to introduce + * the notion of "controlled" hints describing things like + * counter-stems, stem3 as well as overlapping stems control. + * + ************************************************************************/ + + /* compute the location of each scaled vertical stem hint. */ + /* Take care of blue zones and stem snap table */ + static + void t1_hint_vertical_stems( T1_Stem_Table* table, + T1_Size_Hints* hints, + T1_Fixed scale ) + { + T1_Stem_Hint* stem = table->stems; + T1_Stem_Hint* limit = stem + table->num_stems; + + for ( ; stem < limit; stem++ ) + { + T1_Pos stem_left = stem->min_edge.orus; + T1_Pos stem_right = stem->max_edge.orus; + T1_Pos width_pix, left; + + width_pix = SCALE( stem_right - stem_left ); + + /* Snap pixel width if in stem snap range */ + { + T1_Snap_Zone* zone = hints->snap_widths; + T1_Snap_Zone* zone_limit = zone + hints->num_snap_widths; + + for ( ; zone < zone_limit; zone++ ) + { + if ( width_pix < zone->min ) + break; + + if ( width_pix <= zone->max ) + { + width_pix = zone->pix; + break; + } + } + } + + /* round width - minimum 1 pixel if this isn't a ghost stem */ + if ( width_pix > 0 ) + width_pix = ( width_pix < ONE_PIXEL ? ONE_PIXEL : + ROUND( width_pix ) ); + + /* now place the snapped and rounded stem */ + + /* XXXX : TODO : implement controlled stems for the overlapping */ + /* cases.. */ + + left = ( SCALE(stem_left+stem_right) - width_pix )/2; + + stem->min_edge.pix = ROUND(left); + stem->max_edge.pix = stem->min_edge.pix + width_pix; + } + } + + + + +/************************************************************************ + * + * + * t1_hint_point + * + * + * Grid-fit a coordinate with regards to a given stem hints table + * + * + * table :: the source stem hints table + * coord :: original coordinate, expressed in font units + * scale :: the 16.16 scale used to convert font units into + * 26.6 pixels + * + * + * the hinted/scaled value in 26.6 pixels + * + * + * For now, all stems are hinted independently from each other. + * It might be necessary, for better performance, to introduce + * the notion of "controlled" hints describing things like + * counter-stems, stem3 as well as overlapping stems control. + * + ************************************************************************/ + + static + T1_Pos t1_hint_point( T1_Stem_Table* table, + T1_Pos coord, + T1_Fixed scale ) + { + T1_Int num_active = table->num_active; + T1_Int n; + T1_Stem_Hint* prev = 0; + T1_Stem_Hint* cur = 0; + T1_Edge* min; + T1_Edge* max; + T1_Pos delta; + + /* only hint when there is at least one stem defined */ + if (num_active <= 0) + return SCALE(coord); + + /* scan the stem table to determine placement of coordinate */ + /* relative to the list of sorted and stems */ + for ( n = 0; n < num_active; n++, prev = cur ) + { + cur = table->stems + table->sort[n]; + + /* is it on the left of the current edge ? */ + delta = cur->min_edge.orus - coord; + if ( delta == 0 ) return cur->min_edge.pix; + + if (delta > 0) + { + /* if this is the left of the first edge, simply shift */ + if (!prev) return cur->min_edge.pix - SCALE(delta); + + /* otherwise, interpolate between the maximum of the */ + /* previous stem, and the minimum of the current one */ + min = &prev->max_edge; + max = &cur->min_edge; + goto Interpolate; + } + + /* is it within the current edge ? */ + delta = cur->max_edge.orus - coord; + if ( delta == 0 ) return cur->max_edge.pix; + + if (delta > 0) + { + /* interpolate within the stem */ + min = &cur->min_edge; + max = &cur->max_edge; + goto Interpolate; + } + } + + /* apparently, this coordinate is on the right of the last stem */ + delta = coord - cur->max_edge.orus; + return cur->max_edge.pix + SCALE(delta); + + Interpolate: + return min->pix + + FT_MulDiv( coord - min->orus, + max->pix - min->pix, + max->orus - min->orus ); + } + + + + + + +#if 1 + +/************************************************************************ + * + * + * T1_Hint_Points + * + * + * this function grid-fits several points in a given Type 1 builder + * at once. + * + * + * builder :: handle to target Type 1 builder + * first :: first point to hint in builder's current outline + * last :: last point to hint in builder's current outline + * + ************************************************************************/ + + LOCAL_FUNC + void T1_Hint_Points( T1_Builder* builder ) + { + T1_Int first = builder->hint_point; + T1_Int last = builder->current.n_points-1; + + T1_Size size = builder->size; + T1_Fixed scale_x = size->root.metrics.x_scale; + T1_Fixed scale_y = size->root.metrics.y_scale; + + T1_Glyph_Hints* hints = builder->glyph->hints; + T1_Stem_Table* hori_stems = &hints->hori_stems; + T1_Stem_Table* vert_stems = &hints->vert_stems; + + T1_Vector* cur = builder->current.points + first; + T1_Vector* limit = cur + last - first + 1; + + /* first of all, sort the active stem hints */ + t1_sort_hints( hori_stems ); + t1_sort_hints( vert_stems ); + + for ( ; cur < limit; cur++ ) + { + cur->x = t1_hint_point( vert_stems, cur->x, scale_x ); + cur->y = t1_hint_point( hori_stems, cur->y, scale_y ); + } + + builder->hint_point = builder->current.n_points; + } + + +/************************************************************************ + * + * + * T1_Hint_Stems + * + * + * This function is used to compute the location of each stem hint + * between the first and second passes of the glyph loader on the + * charstring. + * + * + * builder :: handle to target builder + * + ************************************************************************/ + + LOCAL_FUNC + void T1_Hint_Stems( T1_Builder* builder ) + { + T1_Glyph_Hints* hints = builder->glyph->hints; + T1_Font* priv = &builder->face->type1; + + T1_Size size = builder->size; + T1_Fixed scale_x = size->root.metrics.x_scale; + T1_Fixed scale_y = size->root.metrics.y_scale; + + t1_hint_horizontal_stems( &hints->hori_stems, + builder->size->hints, + priv->blue_shift, + scale_y ); + + t1_hint_vertical_stems( &hints->vert_stems, + builder->size->hints, + scale_x ); + } + +#endif diff --git a/src/type1z/t1hinter.h b/src/type1z/t1hinter.h new file mode 100644 index 000000000..4bf753af9 --- /dev/null +++ b/src/type1z/t1hinter.h @@ -0,0 +1,380 @@ +/******************************************************************* + * + * t1hinter.h 1.2 + * + * Type1 hinter. + * + * Copyright 1996-1999 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 Hinter is in charge of fitting th scaled outline to the + * pixel grid in order to considerably improve the quality of + * the Type 1 font driver's output.. + * + ******************************************************************/ + +#ifndef T1HINTER_H +#define T1HINTER_H + +#include +#include + +#ifdef __cplusplus + extern "C" { +#endif + + +/************************************************************************ + * + * + * T1_Snap_Zone + * + * + * A "snap zone" is used to model either a blue zone or a stem width + * at a given character size. It is made of a minimum and maximum + * edge, defined in 26.6 pixels, as well as one "original" and + * "scaled" position. + * + * the position corresponds to the stem width (for stem snap zones) + * or to the blue position (for blue zones) + * + * + * orus :: original position in font units + * pix :: current position in sub-pixel units + * min :: minimum boundary in sub-pixel units + * max :: maximim boundary in sub-pixel units + * + ************************************************************************/ + + typedef struct T1_Snap_Zone_ + { + T1_Pos orus; + T1_Pos pix; + T1_Pos min; + T1_Pos max; + + } T1_Snap_Zone; + + +/************************************************************************ + * + * + * T1_Edge + * + * + * A very simply structure used to model an stem edge + * + * + * orus :: original edge position in font units + * pix :: scaled edge position in sub-pixel units + * + ************************************************************************/ + + typedef struct T1_Edge_ + { + T1_Pos orus; + T1_Pos pix; + + } T1_Edge; + + +/************************************************************************ + * + * + * T1_Stem_Hint + * + * + * A simple structure used to model a stem hint + * + * + * min_edge :: the hint's minimum edge + * max_edge :: the hint's maximum edge + * hint_flags :: some flags describing the stem properties + * + * + * the min and max edges of a ghost stem have the same position, + * even if they're coded in a weird way in the charstrings + * + ************************************************************************/ + + typedef struct T1_Stem_Hint_ + { + T1_Edge min_edge; + T1_Edge max_edge; + T1_Int hint_flags; + + } T1_Stem_Hint; + + +#define T1_HINT_FLAG_ACTIVE 1 /* indicates an active stem */ +#define T1_HINT_FLAG_MIN_BORDER 2 /* unused for now.. */ +#define T1_HINT_FLAG_MAX_BORDER 4 /* unused for now.. */ + + +/* hinter's configuration constants */ +#define T1_HINTER_MAX_BLUES 24 /* maximum number of blue zones */ +#define T1_HINTER_MAX_SNAPS 16 /* maximum number of stem snap zones */ +#define T1_HINTER_MAX_EDGES 64 /* maximum number of stem hints */ + + +/************************************************************************ + * + * + * T1_Size_Hints + * + * + * A structure used to model the hinting information related to + * a size object + * + * + * supress_overshoots :: a boolean flag to tell when overshoot + * supression should occur. + * + * num_blue_zones :: the total number of blue zones (top+bottom) + * num_bottom_zones :: the number of bottom zones + * + * blue_zones :: the blue zones table. bottom zones are + * stored first in the table, followed by + * all top zones + * + * num_stem_snapH :: number of horizontal stem snap zones + * stem_snapH :: horizontal stem snap zones + * + * num_stem_snapV :: number of vertical stem snap zones + * stem_snapV :: vertical stem snap zones + * + ************************************************************************/ + + struct T1_Size_Hints_ + { + T1_Bool supress_overshoots; + + T1_Int num_blue_zones; + T1_Int num_bottom_zones; + T1_Snap_Zone blue_zones[ T1_HINTER_MAX_BLUES ]; + + T1_Int num_snap_widths; + T1_Snap_Zone snap_widths[ T1_HINTER_MAX_SNAPS ]; + + T1_Int num_snap_heights; + T1_Snap_Zone snap_heights[ T1_HINTER_MAX_SNAPS ]; + }; + + + +/************************************************************************ + * + * + * T1_Stem_Table + * + * + * A simple structure used to model a set of stem hints in a + * single direction during the loading of a given glyph outline. + * Not all stem hints are active at a time. Moreover, stems must + * be sorted regularly + * + * + * num_stems :: total number of stems in table + * num_active :: number of active stems in table + * + * stems :: the table of all stems + * sort :: a table of indices into the stems table, used + * to keep a sorted list of the active stems + * + ************************************************************************/ + + typedef struct T1_Stem_Table_ + { + T1_Int num_stems; + T1_Int num_active; + + T1_Stem_Hint stems[ T1_HINTER_MAX_EDGES ]; + T1_Int sort [ T1_HINTER_MAX_EDGES ]; + + } T1_Stem_Table; + + + +/************************************************************************ + * + * + * T1_Glyph_Hints + * + * + * A structure used to model the stem hints of a given glyph outline + * during glyph loading. + * + * + * hori_stems :: horizontal stem hints table + * vert_stems :: vertical stem hints table + * + ************************************************************************/ + + struct T1_Glyph_Hints_ + { + T1_Stem_Table hori_stems; + T1_Stem_Table vert_stems; + }; + + + +/************************************************************************ + * + * + * t1_hinter_funcs + * + * + * A table containing the address of various functions used during + * the loading of an hinted scaled outline + * + ************************************************************************/ + + LOCAL_DEF + const T1_Hinter_Funcs t1_hinter_funcs; + + +/************************************************************************ + * + * + * T1_New_Size_Hinter + * + * + * Allocates a new hinter structure for a given size object + * + * + * size :: handle to target size object + * + * + * Error code. 0 means success + * + ************************************************************************/ + + LOCAL_DEF + T1_Error T1_New_Size_Hinter( T1_Size size ); + + +/************************************************************************ + * + * + * T1_Done_Size_Hinter + * + * + * Releases a given size object's hinter structure + * + * + * size :: handle to target size object + * + ************************************************************************/ + + LOCAL_DEF + void T1_Done_Size_Hinter( T1_Size size ); + + +/************************************************************************ + * + * + * T1_Reset_Size_Hinter + * + * + * Recomputes hinting information when a given size object has + * changed its resolutions/char sizes/pixel sizes + * + * + * size :: handle to size object + * + * + * Error code. 0 means success + * + ************************************************************************/ + + LOCAL_DEF + T1_Error T1_Reset_Size_Hinter( T1_Size size ); + + +/************************************************************************ + * + * + * T1_New_Glyph_Hinter + * + * + * Allocates a new hinter structure for a given glyph slot + * + * + * glyph :: handle to target glyph slot + * + * + * Error code. 0 means success + * + ************************************************************************/ + + LOCAL_DEF + T1_Error T1_New_Glyph_Hinter( T1_GlyphSlot glyph ); + + +/************************************************************************ + * + * + * T1_Done_Glyph_Hinter + * + * + * Releases a given glyph slot's hinter structure + * + * + * glyph :: handle to glyph slot + * + ************************************************************************/ + + LOCAL_DEF + void T1_Done_Glyph_Hinter( T1_GlyphSlot glyph ); + + + + +/************************************************************************ + * + * + * T1_Hint_Points + * + * + * this function grid-fits several points in a given Type 1 builder + * at once. + * + * + * builder :: handle to target Type 1 builder + * + ************************************************************************/ + + LOCAL_DEF + void T1_Hint_Points( T1_Builder* builder ); + + +/************************************************************************ + * + * + * T1_Hint_Stems + * + * + * This function is used to compute the location of each stem hint + * between the first and second passes of the glyph loader on the + * charstring. + * + * + * builder :: handle to target builder + * + ************************************************************************/ + + LOCAL_DEF + void T1_Hint_Stems( T1_Builder* builder ); + +#ifdef __cplusplus + } +#endif + +#endif /* T1HINTER_H */ diff --git a/src/type1z/t1load.c b/src/type1z/t1load.c new file mode 100644 index 000000000..4acec0720 --- /dev/null +++ b/src/type1z/t1load.c @@ -0,0 +1,741 @@ +/******************************************************************* + * + * t1load.h 2.0 + * + * Type1 Loader. + * + * Copyright 1996-2000 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 is the new and improved Type 1 data loader for FreeType 2. + * The old loader has several problems: it is slow, complex, difficult + * to maintain, and contains incredible hacks to make it accept some + * ill-formed Type 1 fonts without hiccup-ing. Moreover, about 5% + * of the Type 1 fonts on my machine still aren't loaded correctly + * by it. + * + * This version is much simpler, much faster and also easier to + * read and maintain by a great order of magnitude. The idea behind + * it is to _not_ try to read the Type 1 token stream with a state + * machine (i.e. a Postscript-like interpreter) but rather to perform + * simple pattern-matching. + * + * Indeed, nearly all data definitions follow a simple pattern + * like : + * + * ..... /Field .... + * + * where can be a number, a boolean, a string, or an + * array of numbers. There are a few exceptions, namely the + * encoding, font name, charstrings and subrs and they are + * handled with a special pattern-matching routine. + * + * All other common cases are handled very simply. The matching + * rules are defined in the file "t1tokens.h" through the use + * of several macros calls PARSE_XXXX + * + * This file is included twice here, the first time to generate + * parsing callback functions, the second to generate a table + * of keywords (with pointers to the associated callback). + * + * The function "parse_dict" simply scans *linearly* a given + * dictionary (either the top-level or private one) and calls + * the appropriate callback when it encounters an immediate + * keyword. + * + * This is by far the fastest way one can find to parse and read + * all data :-) + * + * This led to tremendous code size reduction. Note that later, + * the glyph loader will also be _greatly_ simplified, and the + * automatic hinter will replace the clumsy "t1hinter".. + * + ******************************************************************/ + + #include + +#include +#include +#include +#include +#include + +#include + +#undef FT_COMPONENT +#define FT_COMPONENT trace_t1load + + typedef void (*T1_Parse_Func)( T1_Face face, T1_Loader* loader ); + + typedef struct T1_KeyWord_ + { + const char* name; + T1_Parse_Func parsing; + + } T1_KeyWord; + + /* some handy macros used to easily define parsing callback functions */ + /* each callback is in charge of loading a value and storing it in a */ + /* given field of the Type 1 face.. */ + +#define PARSE_(x) static void parse_##x##( T1_Face face, T1_Loader* loader ) + +#define PARSE_STRING(s,x) PARSE_(x) \ + { \ + FACE.##x = T1_ToString(&loader->parser); \ + FT_TRACE2(( "type1.parse_##x##: \"%s\"\n", FACE.##x )); \ + } + +#define PARSE_INT(s,x) PARSE_(x) \ + { \ + FACE.##x = T1_ToInt(&loader->parser); \ + FT_TRACE2(( "type1.parse_##x##: \"%d\"\n", FACE.##x )); \ + } + +#define PARSE_BOOL(s,x) PARSE_(x) \ + { \ + FACE.##x = T1_ToBool(&loader->parser); \ + FT_TRACE2(( "type1.parse_##x##: \"%s\"\n", \ + FACE.##x ? "true" : "false" )); \ + } + +#define PARSE_FIXED(s,x) PARSE_(x) \ + { \ + FACE.##x = T1_ToFixed(&loader->parser,3); \ + FT_TRACE2(( "type1.parse_##x##: \"%f\"\n", FACE.##x/65536.0 )); \ + } + +#define PARSE_COORDS(s,c,m,x) PARSE_(x) \ + { \ + FACE.##c = T1_ToCoordArray(&loader->parser, m, (T1_Short*)FACE.##x ); \ + FT_TRACE2(( "type1.parse_##x##\n" )); \ + } + +#define PARSE_FIXEDS(s,c,m,x) PARSE_(x) \ + { \ + FACE.##c = T1_ToFixedArray(&loader->parser, m, (T1_Fixed*)FACE.##x, 3 ); \ + FT_TRACE2(( "type1.parse_##x##\n" )); \ + } + + +#define PARSE_COORDS2(s,m,x) PARSE_(x) \ + { \ + (void)T1_ToCoordArray( &loader->parser, m, (T1_Short*)&FACE.##x ); \ + FT_TRACE2(( "type1.parse_##x##\n" )); \ + } + +#define PARSE_FIXEDS2(s,m,x) PARSE_(x) \ + { \ + (void)T1_ToFixedArray(&loader->parser, m, (T1_Fixed*)&FACE.##x, 3 ); \ + FT_TRACE2(( "type1.parse_##x##\n" )); \ + } + + +/* define all parsing callbacks */ +#include + + + static + int is_space( char c ) + { + return ( c == ' ' || c == '\t' || c == '\r' || c == '\n' ); + } + + static + int is_alpha( char c ) + { + return ( (c >= 'A' && c <= 'Z') || + (c >= 'a' && c <= 'z') || + (c >= '0' && c <= '9') || + (c == '.') || + (c == '_') ); + } + + static + void skip_whitespace( T1_Parser* parser ) + { + T1_Byte* cur = parser->cursor; + + while ( cur < parser->limit && is_space(*cur) ) + cur++; + + parser->cursor = cur; + } + + static + void skip_blackspace( T1_Parser* parser ) + { + T1_Byte* cur = parser->cursor; + + while ( cur < parser->limit && !is_space(*cur) ) + cur++; + + parser->cursor = cur; + } + + static + int read_binary_data( T1_Parser* parser, T1_Int *size, T1_Byte* *base ) + { + T1_Byte* cur; + T1_Byte* limit = parser->limit; + + /* the binary data has the following format */ + /* */ + /* "size" [white*] RD white ....... ND */ + /* */ + + skip_whitespace(parser); + cur = parser->cursor; + + if ( cur < limit && (T1_Byte)(*cur-'0') < 10 ) + { + *size = T1_ToInt(parser); + + skip_whitespace(parser); + skip_blackspace(parser); /* "RD" or "-|" or something else */ + + /* there is only one whitespace char after the */ + /* "RD" or "-|" token */ + *base = parser->cursor + 1; + + parser->cursor += *size+1; + return 1; + } + + FT_ERROR(( "type1.read_binary_data: invalid size field\n" )); + parser->error = FT_Err_Invalid_File_Format; + return 0; + } + + + /* we will now define the routines used to handle */ + /* the /Encoding, /Subrs and /CharStrings */ + /* dictionaries.. */ + + static + void parse_font_name( T1_Face face, T1_Loader* loader ) + { + T1_Parser* parser = &loader->parser; + FT_Error error; + FT_Memory memory = parser->memory; + T1_Int len; + T1_Byte* cur; + T1_Byte* cur2; + T1_Byte* limit; + + skip_whitespace(parser); + cur = parser->cursor; + limit = parser->limit; + if ( cur >= limit-1 || *cur != '/' ) return; + + cur++; + cur2 = cur; + while (cur2 < limit && is_alpha(*cur2)) cur2++; + len = cur2-cur; + if (len > 0) + { + if ( ALLOC( face->type1.font_name, len+1 ) ) + { + parser->error = error; + return; + } + + MEM_Copy( face->type1.font_name, cur, len ); + face->type1.font_name[len] = '\0'; + } + parser->cursor = cur2; + } + + static + void parse_font_bbox( T1_Face face, T1_Loader* loader ) + { + T1_Parser* parser = &loader->parser; + T1_Short temp[4]; + T1_BBox* bbox = &face->type1.font_bbox; + + (void)T1_ToCoordArray( parser, 4, temp ); + bbox->xMin = temp[0]; + bbox->yMin = temp[1]; + bbox->xMax = temp[2]; + bbox->yMax = temp[3]; + } + + static + void parse_encoding( T1_Face face, T1_Loader* loader ) + { + T1_Parser* parser = &loader->parser; + T1_Byte* cur = parser->cursor; + T1_Byte* limit = parser->limit; + + /* skip whitespace */ + while (is_space(*cur)) + { + cur++; + if (cur >= limit) + { + FT_ERROR(( "type1.parse_encoding: out of bounds !!\n" )); + parser->error = FT_Err_Invalid_File_Format; + return; + } + } + + /* if we have a number, then the encoding is an array, */ + /* and we must load it now */ + if ((T1_Byte)(*cur - '0') < 10) + { + T1_Encoding* encode = &face->type1.encoding; + T1_Int count, n; + T1_Table* char_table = &loader->encoding_table; + FT_Memory memory = parser->memory; + FT_Error error; + + /* read the number of entries in the encoding, should be 256 */ + count = T1_ToInt( parser ); + if (parser->error) return; + + /* we use a T1_Table to store our charnames */ + encode->num_chars = count; + if ( ALLOC_ARRAY( encode->char_index, count, T1_Short ) || + ALLOC_ARRAY( encode->char_name, count, T1_String* ) || + (error = T1_New_Table( char_table, count, memory )) != 0 ) + { + parser->error = error; + return; + } + + /* now, we will need to read a record of the form */ + /* ... charcode /charname ... for each entry in our table */ + /* */ + /* we simply look for a number followed by an immediate */ + /* name. Note that this ignores correctly the sequence */ + /* that is often seen in type1 fonts : */ + /* */ + /* 0 1 255 { 1 index exch /.notdef put } for dup */ + /* */ + /* used to clean the encoding array before anything else */ + /* */ + /* we stop when we encounter a "def" */ + /* */ + + cur = parser->cursor; + limit = parser->limit; + n = 0; + + for ( ; cur < limit; ) + { + T1_Byte c; + + c = *cur; + + /* we stop when we encounter a 'def' */ + if ( c == 'd' && cur+3 < limit ) + { + if ( cur[1] == 'e' && + cur[2] == 'f' && + is_space(cur[3]) ) + break; + } + + /* otherwise, we must find a number before anything else */ + if ( (T1_Byte)(c-'0') < 10 ) + { + T1_Int charcode; + + parser->cursor = cur; + charcode = T1_ToInt(parser); + cur = parser->cursor; + + /* skip whitespace */ + while (cur < limit && is_space(*cur)) cur++; + + if (cur < limit && *cur == '/') + { + /* bingo, we have an immediate name - it must be a */ + /* character name */ + FT_Byte* cur2 = cur+1; + T1_Int len; + + while (cur2 < limit && is_alpha(*cur2)) cur2++; + len = cur2-cur-1; + parser->error = T1_Add_Table( char_table, charcode, cur+1, len+1 ); + char_table->elements[charcode][len] = '\0'; + if (parser->error) return; + + cur = cur2; + } + } + else + cur++; + } + + face->type1.encoding_type = t1_encoding_array; + } + /* Otherwise, we should have either "StandardEncoding" or */ + /* "ExpertEncoding" */ + else + { + if ( cur+17 < limit && strncmp( cur, "StandardEncoding", 16 ) == 0 ) + face->type1.encoding_type = t1_encoding_standard; + + else if (cur+15 < limit && strncmp( cur, "ExpertEncoding", 14 ) == 0 ) + face->type1.encoding_type = t1_encoding_expert; + + else + { + FT_ERROR(( "type1.parse_encoding: invalid token !!\n" )); + parser->error = FT_Err_Invalid_File_Format; + } + } + } + + + static + void parse_subrs( T1_Face face, T1_Loader* loader ) + { + T1_Parser* parser = &loader->parser; + T1_Table* table = &loader->subrs; + FT_Memory memory = parser->memory; + FT_Error error; + T1_Int n; + + loader->num_subrs = T1_ToInt( parser ); + if (parser->error) return; + + /* initialise subrs array */ + error = T1_New_Table( table, loader->num_subrs, memory ); + if (error) goto Fail; + + /* the format is simple : */ + /* */ + /* "index" + binary data */ + /* */ + + for ( n = 0; n < loader->num_subrs; n++ ) + { + T1_Int index, size; + T1_Byte* base; + + index = T1_ToInt(parser); + if (!read_binary_data(parser,&size,&base)) return; + + error = T1_Add_Table( table, index, base, size ); + if (error) goto Fail; + } + return; + + Fail: + parser->error = error; + } + + + + + static + void parse_charstrings( T1_Face face, T1_Loader* loader ) + { + T1_Parser* parser = &loader->parser; + T1_Table* code_table = &loader->charstrings; + T1_Table* name_table = &loader->glyph_names; + FT_Memory memory = parser->memory; + FT_Error error; + + T1_Byte* cur; + T1_Byte* limit = parser->limit; + T1_Int n; + + loader->num_glyphs = T1_ToInt( parser ); + if (parser->error) return; + + /* initialise tables */ + error = T1_New_Table( code_table, loader->num_glyphs, memory ) || + T1_New_Table( name_table, loader->num_glyphs, memory ); + if (error) goto Fail; + + n = 0; + for ( ;; ) + { + T1_Int size; + T1_Byte* base; + + /* the format is simple : */ + /* "/glyphname" + binary data */ + /* */ + /* note that we stop when we find a "def" */ + /* */ + skip_whitespace(parser); + cur = parser->cursor; + if (cur >= limit) break; + + /* we stop when we find a "def" */ + if (*cur == 'd' && + cur+3 < limit && + cur[1] == 'e' && + cur[2] == 'f' ) + break; + + if (*cur != '/') + skip_blackspace(parser); + else + { + T1_Byte* cur2 = cur+1; + T1_Int len; + + while (cur2 < limit && is_alpha(*cur2)) cur2++; + len = cur2-cur-1; + error = T1_Add_Table( name_table, n, cur+1, len+1 ); + if (error) goto Fail; + + /* add a trailing zero to the name table */ + name_table->elements[n][len] = '\0'; + + parser->cursor = cur2; + if (!read_binary_data(parser,&size,&base)) return; + + error = T1_Add_Table( code_table, n, base, size ); + if (error) goto Fail; + + n++; + if (n >= loader->num_glyphs) + break; + } + } + return; + + Fail: + parser->error = error; + } + + +#undef PARSE_STRING +#undef PARSE_INT +#undef PARSE_BOOL +#undef PARSE_FIXED +#undef PARSE_COORDS +#undef PARSE_FIXEDS +#undef PARSE_COORDS2 +#undef PARSE_FIXEDS2 + +#undef PARSE_ +#define PARSE_(s,x) { s, parse_##x }, + +#define PARSE_STRING(s,x) PARSE_(s,x) +#define PARSE_INT(s,x) PARSE_(s,x) +#define PARSE_BOOL(s,x) PARSE_(s,x) +#define PARSE_FIXED(s,x) PARSE_(s,x) +#define PARSE_COORDS(s,c,m,x) PARSE_(s,x) +#define PARSE_FIXEDS(s,c,m,x) PARSE_(s,x) +#define PARSE_COORDS2(s,m,x) PARSE_(s,x) +#define PARSE_FIXEDS2(s,m,x) PARSE_(s,x) + + static + const T1_KeyWord t1_keywords[] = + { +#include + /* now add the special functions... */ + { "FontName", parse_font_name }, + { "FontBBox", parse_font_bbox }, + { "Encoding", parse_encoding }, + { "Subrs", parse_subrs }, + { "CharStrings", parse_charstrings }, + { 0, 0 } + }; + + + static + T1_Error parse_dict( T1_Face face, + T1_Loader* loader, + T1_Byte* base, + T1_Int size ) + { + T1_Parser* parser = &loader->parser; + + parser->cursor = base; + parser->limit = base + size; + parser->error = 0; + + { + T1_Byte* cur = base; + T1_Byte* limit = cur + size; + + for ( ;cur < limit; cur++ ) + { + /* look for immediates */ + if (*cur == '/' && cur+2 < limit) + { + T1_Byte* cur2; + T1_Int len; + + cur ++; + cur2 = cur; + while (cur2 < limit && is_alpha(*cur2)) cur2++; + len = cur2-cur; + + if (len > 0) + { + /* now, compare the immediate name to the keyword table */ + T1_KeyWord* keyword = (T1_KeyWord*)t1_keywords; + + for (;;) + { + T1_Byte* name; + + name = (T1_Byte*)keyword->name; + if (!name) break; + + if (cur[0] == name[0] && len == strlen(name) ) + { + T1_Int n; + for ( n = 1; n < len; n++ ) + if (cur[n] != name[n]) + break; + + if (n >= len) + { + /* we found it - run the parsing callback !! */ + parser->cursor = cur2; + skip_whitespace( parser ); + keyword->parsing( face, loader ); + if (parser->error) + return parser->error; + + cur = parser->cursor; + } + } + keyword++; + } + } + } + } + } + return parser->error; + } + + static + void t1_init_loader( T1_Loader* loader, T1_Face face ) + { + loader->num_glyphs = 0; + loader->num_chars = 0; + + loader->encoding_table.init = 0; + loader->charstrings.init = 0; + loader->glyph_names.init = 0; + loader->subrs.init = 0; + } + + static + void t1_done_loader( T1_Loader* loader ) + { + T1_Parser* parser = &loader->parser; + + /* finalize tables */ + T1_Release_Table( &loader->encoding_table ); + T1_Release_Table( &loader->charstrings ); + T1_Release_Table( &loader->glyph_names ); + T1_Release_Table( &loader->subrs ); + + /* finalize parser */ + T1_Done_Parser( parser ); + } + + LOCAL_FUNC + T1_Error T1_Open_Face( T1_Face face ) + { + T1_Loader loader; + T1_Parser* parser; + T1_Font* type1 = &face->type1; + FT_Error error; + + t1_init_loader( &loader, face ); + + /* default lenIV */ + type1->lenIV = 4; + + parser = &loader.parser; + error = T1_New_Parser( parser, face->root.stream, face->root.memory ); + if (error) goto Exit; + + error = parse_dict( face, &loader, parser->base_dict, parser->base_len ); + if (error) goto Exit; + + error = T1_Get_Private_Dict( parser ); + if (error) goto Exit; + + error = parse_dict( face, &loader, parser->private_dict, parser->private_len ); + if (error) goto Exit; + + /* now, propagate the subrs, charstrings and glyphnames tables */ + /* to the Type1 data */ + type1->num_glyphs = loader.num_glyphs; + + loader.subrs.init = 0; + type1->num_subrs = loader.num_subrs; + type1->subrs_block = loader.subrs.block; + type1->subrs = loader.subrs.elements; + type1->subrs_len = loader.subrs.lengths; + + loader.charstrings.init = 0; + type1->charstrings_block = loader.charstrings.block; + type1->charstrings = loader.charstrings.elements; + type1->charstrings_len = loader.charstrings.lengths; + + /* we copy the glyph names "block" and "elements" fields */ + /* but the "lengths" field must be released later.. */ + type1->glyph_names_block = loader.glyph_names.block; + type1->glyph_names = (T1_String**)loader.glyph_names.elements; + loader.glyph_names.block = 0; + loader.glyph_names.elements = 0; + + /* we must now build type1.encoding when we have a custom */ + /* array.. */ + if ( type1->encoding_type == t1_encoding_array ) + { + T1_Int charcode, index, min_char, max_char; + T1_Byte* char_name; + T1_Byte* glyph_name; + + /* OK, we do the following : for each element in the encoding */ + /* table, lookup the index of the glyph having the same name */ + /* the index is then stored in type1.encoding.char_index, and */ + /* a the name to type1.encoding.char_name */ + + min_char = +32000; + max_char = -32000; + + charcode = 0; + for ( ; charcode < loader.encoding_table.num_elems; charcode++ ) + { + type1->encoding.char_index[charcode] = 0; + type1->encoding.char_name [charcode] = ".notdef"; + + char_name = loader.encoding_table.elements[charcode]; + if (char_name) + for ( index = 0; index < type1->num_glyphs; index++ ) + { + glyph_name = type1->glyph_names[index]; + if ( strcmp( char_name, glyph_name ) == 0 ) + { + type1->encoding.char_index[charcode] = index; + type1->encoding.char_name [charcode] = glyph_name; + + if (charcode < min_char) min_char = charcode; + if (charcode > max_char) max_char = charcode; + break; + } + } + } + type1->encoding.code_first = min_char; + type1->encoding.code_last = max_char; + type1->encoding.num_chars = loader.num_chars; + } + + Exit: + t1_done_loader( &loader ); + return error; + } diff --git a/src/type1z/t1load.h b/src/type1z/t1load.h new file mode 100644 index 000000000..6a1a45c03 --- /dev/null +++ b/src/type1z/t1load.h @@ -0,0 +1,56 @@ +/******************************************************************* + * + * t1load.h 2.0 + * + * Type1 Loader. + * + * Copyright 1996-2000 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 T1LOAD_H +#define T1LOAD_H + +#include +#include + +#ifdef __cplusplus + extern "C" { +#endif + + typedef struct T1_Loader_ + { + T1_Parser parser; /* parser used to read the stream */ + + T1_Int num_chars; /* number of characters in encoding */ + T1_Table encoding_table; /* T1_Table used to store the */ + /* encoding character names */ + + T1_Int num_glyphs; + T1_Table glyph_names; + T1_Table charstrings; + + T1_Int num_subrs; + T1_Table subrs; + + } T1_Loader; + + LOCAL_DEF + T1_Error T1_Open_Face( T1_Face face ); + + +#ifdef __cplusplus + } +#endif + +#endif /* T1LOAD_H */ + + +/* END */ diff --git a/src/type1z/t1objs.c b/src/type1z/t1objs.c new file mode 100644 index 000000000..0d59b0f7c --- /dev/null +++ b/src/type1z/t1objs.c @@ -0,0 +1,404 @@ +/******************************************************************* + * + * t1objs.c 1.0 + * + * Type1 Objects manager. + * + * Copyright 1996-1998 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used + * modified and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + ******************************************************************/ + +#include +#include + +#include +#include + +#ifndef T1_CONFIG_OPTION_DISABLE_HINTER +#include +#endif + +/* Required by tracing mode */ +#undef FT_COMPONENT +#define FT_COMPONENT trace_t1objs + +/******************************************************************* + * * + * SIZE FUNCTIONS * + * * + * * + *******************************************************************/ + +/******************************************************************* + * + * T1_Done_Size + * + * + * The TrueDoc instance object destructor. Used to discard + * a given instance object.. + * + * + * instance :: handle to the target instance object + * + * + * TrueDoc error code. 0 means success + * + ******************************************************************/ + + LOCAL_FUNC + void T1_Done_Size( T1_Size size ) + { + if (size) + { +#ifndef T1_CONFIG_OPTION_DISABLE_HINTER + T1_Done_Size_Hinter( size ); +#endif + size->valid = 0; + } + } + + +/******************************************************************* + * + * T1_Init_Size + * + * + * The instance object constructor + * + * + * instance : handle to new instance object + * face : pointer to parent face object + * + * + * TrueDoc error code. 0 means success. + * + ******************************************************************/ + + LOCAL_DEF + T1_Error T1_Init_Size( T1_Size size ) + { + T1_Error error; + + size->valid = 0; + +#ifndef T1_CONFIG_OPTION_DISABLE_HINTER + error = T1_New_Size_Hinter( size ); + return error; +#else + (void)error; + return T1_Err_Ok; +#endif + } + + +/******************************************************************* + * + * T1_Reset_Size + * + * + * Resets an instance to a new pointsize/transform. + * This function is in charge of resetting the blue zones, + * As well as the stem snap tables for a given size.. + * + * + * instance the instance object to destroy + * + * + * Error code. + * + ******************************************************************/ + + LOCAL_FUNC + T1_Error T1_Reset_Size( T1_Size size ) + { +#ifndef T1_CONFIG_OPTION_DISABLE_HINTER + return T1_Reset_Size_Hinter( size ); +#else + (void)size; + return 0; +#endif + } + + +/******************************************************************* + * * + * FACE FUNCTIONS * + * * + * * + *******************************************************************/ + +/******************************************************************* + * + * T1_Done_Face + * + * + * The face object destructor. + * + * + * face :: typeless pointer to the face object to destroy + * + * + * Error code. + * + ******************************************************************/ + + LOCAL_FUNC + void T1_Done_Face( T1_Face face ) + { + FT_Memory memory; + + if (face) + { + memory = face->root.memory; + /* XXXX : TO DO */ + } + } + +/******************************************************************* + * + * T1_Init_Face + * + * + * The face object constructor. + * + * + * face :: face record to build + * Input :: input stream where to load font data + * + * + * Error code. + * + ******************************************************************/ + + LOCAL_FUNC + T1_Error T1_Init_Face( FT_Stream stream, + FT_Int face_index, + T1_Face face ) + { + T1_Error error; + + (void)face_index; + (void)face; + + face->root.num_faces = 1; + + /* open the tokenizer, this will also check the font format */ + error = T1_Open_Face( face ); + if (error) goto Exit; + + /* if we just wanted to check the format, leave successfully now */ + if (face_index < 0) + goto Exit; + + /* check the face index */ + if ( face_index != 0 ) + { + FT_ERROR(( "T1.Init_Face : invalid face index\n" )); + error = T1_Err_Invalid_Argument; + goto Exit; + } + + /* Now, load the font program into the face object */ + { + /* Init the face object fields */ + /* Now set up root face fields */ + { + FT_Face root = (FT_Face)&face->root; + + root->num_glyphs = face->type1.num_glyphs; + root->num_charmaps = 1; + + root->face_index = face_index; + root->face_flags = FT_FACE_FLAG_SCALABLE; + + root->face_flags |= FT_FACE_FLAG_HORIZONTAL; + + if ( face->type1.is_fixed_pitch ) + root->face_flags |= FT_FACE_FLAG_FIXED_WIDTH; + + /* XXX : TO DO - add kerning with .afm support */ + + /* get style name - be careful, some broken fonts only */ + /* have a /FontName dictionary entry .. !! */ + root->family_name = face->type1.family_name; + if (root->family_name) + { + char* full = face->type1.full_name; + char* family = root->family_name; + + while ( *family && *full == *family ) + { + family++; + full++; + } + + root->style_name = ( *full == ' ' ? full+1 : "Regular" ); + } + else + { + /* do we have a /FontName ?? */ + if (face->type1.font_name) + { + root->family_name = face->type1.font_name; + root->style_name = "Regular"; + } + } + + /* no embedded bitmap support */ + root->num_fixed_sizes = 0; + root->available_sizes = 0; + + root->bbox = face->type1.font_bbox; + root->units_per_EM = 1000; + root->ascender = (T1_Short)face->type1.font_bbox.yMax; + root->descender = -(T1_Short)face->type1.font_bbox.yMin; + root->height = ((root->ascender + root->descender)*12)/10; + + /* now compute the maximum advance width */ + + root->max_advance_width = face->type1.standard_width; + + /* compute max advance width for proportional fonts */ + if (!face->type1.is_fixed_pitch) + { + T1_Int max_advance; + + error = T1_Compute_Max_Advance( face, &max_advance ); + + /* in case of error, keep the standard width */ + if (!error) + root->max_advance_width = max_advance; + else + error = 0; /* clear error */ + } + + root->max_advance_height = root->height; + + root->underline_position = face->type1.underline_position; + root->underline_thickness = face->type1.underline_thickness; + + root->max_points = 0; + root->max_contours = 0; + } + } + + Exit: + return error; + } + + +/******************************************************************* + * + * Function : Glyph_Destroy + * + * Description : The glyph object destructor. + * + * Input : _glyph typeless pointer to the glyph record to destroy + * + * Output : Error code. + * + ******************************************************************/ + + LOCAL_FUNC + void T1_Done_GlyphSlot( T1_GlyphSlot glyph ) + { + FT_Memory memory = glyph->root.face->memory; + FT_Library library = glyph->root.face->driver->library; + +#ifndef T1_CONFIG_OPTION_DISABLE_HINTER + T1_Done_Glyph_Hinter( glyph ); +#endif + /* the bitmaps are created on demand */ + FREE( glyph->root.bitmap.buffer ); + FT_Done_Outline( library, &glyph->root.outline ); + return; + } + + +/******************************************************************* + * + * Function : Glyph_Create + * + * Description : The glyph object constructor. + * + * Input : glyph glyph record to build. + * face the glyph's parent face. + * + * Output : Error code. + * + ******************************************************************/ + + LOCAL_FUNC + T1_Error T1_Init_GlyphSlot( T1_GlyphSlot glyph ) + { + FT_Library library = glyph->root.face->driver->library; + T1_Error error; + + glyph->max_points = 0; + glyph->max_contours = 0; + glyph->root.bitmap.buffer = 0; + + error = FT_New_Outline( library, 0, 0, &glyph->root.outline ); + if (error) return error; + +#ifndef T1_CONFIG_OPTION_DISABLE_HINTER + error = T1_New_Glyph_Hinter( glyph ); + if (error) + FT_Done_Outline( library, &glyph->root.outline ); +#endif + + return error; + } + + +/******************************************************************* + * + * T1_Init_Driver + * + * + * Initialise a given Type 1 driver object + * + * + * driver :: handle to target driver object + * + * + * Error code. + * + ******************************************************************/ + + LOCAL_FUNC + T1_Error T1_Init_Driver( T1_Driver driver ) + { + (void)driver; + return T1_Err_Ok; + } + + + +/******************************************************************* + * + * T1_Done_Driver + * + * + * finalise a given Type 1 driver + * + * + * driver :: handle to target Type 1 driver + * + ******************************************************************/ + + LOCAL_DEF + void T1_Done_Driver( T1_Driver driver ) + { + (void)driver; + } + + +/* END */ diff --git a/src/type1z/t1objs.h b/src/type1z/t1objs.h new file mode 100644 index 000000000..417ae5380 --- /dev/null +++ b/src/type1z/t1objs.h @@ -0,0 +1,302 @@ +/******************************************************************* + * + * t1objs.h 1.0 + * + * Type1 objects definition. + * + * Copyright 1996-1999 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 T1OBJS_H +#define T1OBJS_H + +#include +#include +#include +#include + +#ifdef __cplusplus + extern "C" { +#endif + + /* The following structures must be defined by the hinter */ + typedef struct T1_Size_Hints_ T1_Size_Hints; + typedef struct T1_Glyph_Hints_ T1_Glyph_Hints; + + /***********************************************************************/ + /* */ + /* T1_Driver */ + /* */ + /* */ + /* A handle to a Type 1 driver object. */ + /* */ + typedef struct T1_DriverRec_ *T1_Driver; + + + /***********************************************************************/ + /* */ + /* T1_Size */ + /* */ + /* */ + /* A handle to a Type 1 size object. */ + /* */ + typedef struct T1_SizeRec_* T1_Size; + + + /***********************************************************************/ + /* */ + /* T1_GlyphSlot */ + /* */ + /* */ + /* A handle to a Type 1 glyph slot object. */ + /* */ + typedef struct T1_GlyphSlotRec_* T1_GlyphSlot; + + + /***********************************************************************/ + /* */ + /* T1_CharMap */ + /* */ + /* */ + /* A handle to a Type 1 character mapping object. */ + /* */ + /* */ + /* The Type 1 format doesn't use a charmap but an encoding table. */ + /* The driver is responsible for making up charmap objects */ + /* corresponding to these tables.. */ + /* */ + typedef struct T1_CharMapRec_* T1_CharMap; + + + + /**************************************************************************/ + /* */ + /* NOW BEGINS THE TYPE1 SPECIFIC STUFF .............................. */ + /* */ + /**************************************************************************/ + + + /***************************************************/ + /* */ + /* T1_Size : */ + /* */ + /* Type 1 size record.. */ + /* */ + + typedef struct T1_SizeRec_ + { + FT_SizeRec root; + T1_Bool valid; + T1_Size_Hints* hints; /* defined in the hinter. This allows */ + /* us to experiment with different */ + /* hinting schemes without having to */ + /* change 't1objs' each time.. */ + } T1_SizeRec; + + + + /***************************************************/ + /* */ + /* T1_GlyphSlot : */ + /* */ + /* TrueDoc glyph record.. */ + /* */ + + typedef struct T1_GlyphSlotRec_ + { + FT_GlyphSlotRec root; + + T1_Bool hint; + T1_Bool scaled; + + T1_Int max_points; + T1_Int max_contours; + + FT_Fixed x_scale; + FT_Fixed y_scale; + + T1_Glyph_Hints* hints; /* defined in the hinter */ + + } T1_GlyphSlotRec; + + +/******************************************************************* + * + * T1_Init_Face + * + * + * Initialise a given Type 1 face object + * + * + * face_index :: index of font face in resource + * resource :: source font resource + * face :: face record to build + * + * + * Error code. + * + ******************************************************************/ + + LOCAL_DEF + T1_Error T1_Init_Face( FT_Stream stream, + FT_Int face_index, + T1_Face face ); + + + +/******************************************************************* + * + * T1_Done_Face + * + * + * Finalise a given face object + * + * + * face :: handle to the face object to destroy + * + ******************************************************************/ + + LOCAL_DEF + void T1_Done_Face( T1_Face face ); + + + +/******************************************************************* + * + * T1_Init_Size + * + * + * Initialise a new Type 1 size object + * + * + * size :: handle to size object + * + * + * Type 1 error code. 0 means success. + * + ******************************************************************/ + + LOCAL_DEF + T1_Error T1_Init_Size( T1_Size size ); + + + +/******************************************************************* + * + * T1_Done_Size + * + * + * The Type 1 size object finaliser. + * + * + * size :: handle to the target size object. + * + ******************************************************************/ + + LOCAL_DEF + void T1_Done_Size( T1_Size size ); + + +/******************************************************************* + * + * T1_Reset_Size + * + * + * Reset a Type 1 size when resolutions and character dimensions + * have been changed.. + * + * + * size :: handle to the target size object. + * + ******************************************************************/ + + LOCAL_DEF + T1_Error T1_Reset_Size( T1_Size size ); + + + +/******************************************************************* + * + * T1_Init_GlyphSlot + * + * The TrueType glyph slot initialiser + * + * glyph :: glyph record to build. + * + * Error code. + * + ******************************************************************/ + + LOCAL_DEF + T1_Error T1_Init_GlyphSlot( T1_GlyphSlot slot ); + + + +/******************************************************************* + * + * T1_Done_GlyphSlot + * + * The Type 1 glyph slot finaliser + * + * glyph :: handle to glyph slot object + * + * Error code. + * + ******************************************************************/ + + LOCAL_DEF + void T1_Done_GlyphSlot( T1_GlyphSlot slot ); + + + +/******************************************************************* + * + * T1_Init_Driver + * + * + * Initialise a given Type 1 driver object + * + * + * driver :: handle to target driver object + * + * + * Error code. + * + ******************************************************************/ + + LOCAL_DEF + T1_Error T1_Init_Driver( T1_Driver driver ); + + + +/******************************************************************* + * + * T1_Done_Driver + * + * + * finalise a given Type 1 driver + * + * + * driver :: handle to target Type 1 driver + * + ******************************************************************/ + + LOCAL_DEF + void T1_Done_Driver( T1_Driver driver ); + +#ifdef __cplusplus + } +#endif + +#endif /* T1OBJS_H */ + + +/* END */ diff --git a/src/type1z/t1parse.c b/src/type1z/t1parse.c new file mode 100644 index 000000000..a326d3cf7 --- /dev/null +++ b/src/type1z/t1parse.c @@ -0,0 +1,901 @@ +/******************************************************************* + * + * t1parse.c 2.0 + * + * Type1 parser. + * + * Copyright 1996-1998 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 Type 1 parser is in charge of the following: + * + * - provide an implementation of a growing sequence of + * objects called a T1_Table (used to build various tables + * needed by the loader). + * + * - opening .pfb and .pfa files to extract their top-level + * and private dictionaries + * + * - read numbers, arrays & strings from any dictionary + * + * See "t1load.c" to see how data is loaded from the font file + * + ******************************************************************/ + +#include +#include +#include +#include +#include +#include + +#undef FT_COMPONENT +#define FT_COMPONENT trace_t1load + +/*************************************************************************/ +/* */ +/* T1_New_Table */ +/* */ +/* */ +/* Initialise a T1_Table. */ +/* */ +/* */ +/* table :: address of target table */ +/* count :: table size = maximum number of elements */ +/* memory :: memory object to use for all subsequent reallocations */ +/* */ +/* */ +/* Error code. 0 means success */ +/* */ + + LOCAL_FUNC + T1_Error T1_New_Table( T1_Table* table, + T1_Int count, + FT_Memory memory ) + { + T1_Error error; + + table->memory = memory; + if ( ALLOC_ARRAY( table->elements, count, T1_Byte* ) || + ALLOC_ARRAY( table->lengths, count, T1_Byte* ) ) + goto Exit; + + table->max_elems = count; + table->init = 0xdeadbeef; + table->num_elems = 0; + table->block = 0; + table->capacity = 0; + table->cursor = 0; + + Exit: + if (error) FREE(table->elements); + + return error; + } + + + +/*************************************************************************/ +/* */ +/* T1_Add_Table */ +/* */ +/* */ +/* Adds an object to a T1_Table, possibly growing its memory block */ +/* */ +/* */ +/* table :: target table */ +/* index :: index of object in table */ +/* object :: address of object to copy in memory */ +/* length :: length in bytes of source object */ +/* */ +/* */ +/* Error code. 0 means success. An error is returned when a */ +/* realloc failed.. */ +/* */ + + + static void shift_elements( T1_Table* table, T1_Byte* old_base ) + { + T1_Long delta = table->block - old_base; + T1_Byte** offset = table->elements; + T1_Byte** limit = offset + table->max_elems; + + if (delta) + for ( ; offset < limit; offset++ ) + { + if (offset[0]) + offset[0] += delta; + } + } + + static + T1_Error reallocate_t1_table( T1_Table* table, + T1_Int new_size ) + { + FT_Memory memory = table->memory; + T1_Byte* old_base = table->block; + T1_Error error; + + /* realloc the base block */ + if ( REALLOC( table->block, table->capacity, new_size ) ) + return error; + + table->capacity = new_size; + + /* shift all offsets when needed */ + if (old_base) + shift_elements( table, old_base ); + + return T1_Err_Ok; + } + + + + LOCAL_FUNC + T1_Error T1_Add_Table( T1_Table* table, + T1_Int index, + void* object, + T1_Int length ) + { + if (index < 0 || index > table->max_elems) + { + FT_ERROR(( "T1.Add_Table: invalid index\n" )); + return T1_Err_Syntax_Error; + } + + /* grow the base block if needed */ + if ( table->cursor + length > table->capacity ) + { + T1_Error error; + T1_Int new_size = table->capacity; + + while ( new_size < table->cursor+length ) + new_size += 1024; + + error = reallocate_t1_table( table, new_size ); + if (error) return error; + } + + /* add the object to the base block and adjust offset */ + table->elements[ index ] = table->block + table->cursor; + table->lengths [ index ] = length; + MEM_Copy( table->block + table->cursor, object, length ); + + table->cursor += length; + return T1_Err_Ok; + } + + +/*************************************************************************/ +/* */ +/* T1_Done_Table */ +/* */ +/* */ +/* Finalise a T1_Table. (realloc it to its current cursor). */ +/* */ +/* */ +/* table :: target table */ +/* */ +/* */ +/* This function does NOT release the heap's memory block. It is up */ +/* to the caller to clean it, or reference it in its own structures. */ +/* */ + LOCAL_FUNC + void T1_Done_Table( T1_Table* table ) + { + FT_Memory memory = table->memory; + T1_Error error; + T1_Byte* old_base; + + /* should never fail, as rec.cursor <= rec.size */ + old_base = table->block; + if (!old_base) + return; + + (void)REALLOC( table->block, table->capacity, table->cursor ); + table->capacity = table->cursor; + + if (old_base != table->block) + shift_elements( table, old_base ); + } + + + LOCAL_FUNC + void T1_Release_Table( T1_Table* table ) + { + FT_Memory memory = table->memory; + + if (table->init == 0xdeadbeef) + { + FREE( table->block ); + FREE( table->elements ); + FREE( table->lengths ); + table->init = 0; + } + } + + static + T1_Long t1_toint( T1_Byte* *cursor, + T1_Byte* limit ) + { + T1_Long result = 0; + T1_Byte* cur = *cursor; + T1_Byte c, d; + + for (; cur < limit; cur++) + { + c = *cur; + d = (T1_Byte)(c - '0'); + if (d < 10) break; + + if ( c=='-' ) + { + cur++; + break; + } + } + + if (cur < limit) + { + do + { + d = (T1_Byte)(cur[0] - '0'); + if (d >= 10) + break; + + result = result*10 + d; + cur++; + + } while (cur < limit); + + if (c == '-') + result = -result; + } + + *cursor = cur; + return result; + } + + + static + T1_Long t1_tofixed( T1_Byte* *cursor, + T1_Byte* limit, + T1_Long power_ten ) + { + T1_Byte* cur = *cursor; + T1_Long num, divider, result; + T1_Int sign = 0; + T1_Byte d; + + if (cur >= limit) return 0; + + /* first of all, read the integer part */ + result = t1_toint( &cur, limit ) << 16; + num = 0; + divider = 1; + + if (result < 0) + { + sign = 1; + result = -result; + } + if (cur >= limit) goto Exit; + + /* read decimal part, if any */ + if (*cur == '.' && cur+1 < limit) + { + cur++; + + for (;;) + { + d = (T1_Byte)(*cur - '0'); + if (d >= 10) break; + + if (divider < 10000000L) + { + num = num*10 + d; + divider *= 10; + } + cur++; + if (cur >= limit) break; + } + } + + /* read exponent, if any */ + if ( cur+1 < limit && (*cur == 'e' || *cur == 'E')) + { + cur++; + power_ten += t1_toint( &cur, limit ); + } + + Exit: + /* raise to power of ten if needed */ + while (power_ten > 0) + { + result = result*10; + num = num*10; + power_ten--; + } + + while (power_ten < 0) + { + result = result/10; + divider = divider*10; + power_ten++; + } + + if (num) + result += FT_DivFix( num, divider ); + + if (sign) + result = -result; + + *cursor = cur; + return result; + } + + + static + T1_Int t1_tocoordarray( T1_Byte* *cursor, + T1_Byte* limit, + T1_Int max_coords, + T1_Short* coords ) + { + T1_Byte* cur = *cursor; + T1_Int count = 0; + T1_Byte c, ender; + + if (cur >= limit) goto Exit; + + /* check for the beginning of an array. If not, only one number will be read */ + c = *cur; + ender = 0; + + if (c == '[') + ender = ']'; + + if (c == '{') + ender = '}'; + + if (ender) + cur++; + + /* now, read the coordinates */ + for ( ; cur < limit; cur++ ) + { + c = *cur; + if (count >= max_coords || c == ender) + break; + + coords[count] = (T1_Short)(t1_tofixed(&cur,limit,0) >> 16); + count++; + + if (!ender) + break; + } + + Exit: + *cursor = cur; + return count; + } + + + + static + T1_Int t1_tofixedarray( T1_Byte* *cursor, + T1_Byte* limit, + T1_Int max_values, + T1_Fixed* values, + T1_Int power_ten ) + { + T1_Byte* cur = *cursor; + T1_Int count = 0; + T1_Byte c, ender; + + if (cur >= limit) goto Exit; + + /* check for the beginning of an array. If not, only one number will be read */ + c = *cur; + ender = 0; + + if (c == '[') + ender = ']'; + + if (c == '{') + ender = '}'; + + if (ender) + cur++; + + /* now, read the values */ + for ( ; cur < limit; cur++ ) + { + c = *cur; + if (count >= max_values || c == ender) + break; + + values[count] = t1_tofixed(&cur,limit,power_ten); + count++; + + if (!ender) + break; + } + + Exit: + *cursor = cur; + return count; + } + + + static + T1_String* t1_tostring( T1_Byte* *cursor, T1_Byte* limit, FT_Memory memory ) + { + T1_Byte* cur = *cursor; + T1_Int len = 0; + T1_Int count; + T1_String* result; + FT_Error error; + + /* first of all, skip everything until we encounter a string */ + while ( cur < limit && *cur != '(' ) cur++; + cur++; + if (cur >= limit) return 0; + + *cursor = cur; + count = 0; + + /* then, count its length */ + for ( ; cur < limit; cur++ ) + { + if (*cur == '(') + count++; + + else if (*cur == ')') + { + count--; + if (count < 0) + break; + } + } + + len = cur - *cursor; + if (cur >= limit || ALLOC(result,len+1)) return 0; + + /* now copy the string */ + MEM_Copy( result, *cursor, len ); + result[len] = '\0'; + + return result; + } + + static + int t1_tobool( T1_Byte* *cursor, T1_Byte* limit ) + { + T1_Byte* cur = *cursor; + T1_Bool result = 0; + + /* return 1 if we find a "true", 0 otherwise */ + if ( cur+3 < limit && + cur[0] == 't' && + cur[1] == 'r' && + cur[2] == 'u' && + cur[3] == 'e' ) + { + result = 1; + cur += 5; + } + else if ( cur+4 < limit && + cur[0] == 'f' && + cur[1] == 'a' && + cur[2] == 'l' && + cur[3] == 's' && + cur[4] == 'e' ) + { + result = 0; + cur += 6; + } + *cursor = cur; + return result; + } + + + LOCAL_FUNC + T1_Long T1_ToInt ( T1_Parser* parser ) + { + return t1_toint( &parser->cursor, parser->limit ); + } + + + LOCAL_FUNC + T1_Long T1_ToFixed( T1_Parser* parser, T1_Int power_ten ) + { + return t1_tofixed( &parser->cursor, parser->limit, power_ten ); + } + + + LOCAL_FUNC + T1_Int T1_ToCoordArray( T1_Parser* parser, + T1_Int max_coords, + T1_Short* coords ) + { + return t1_tocoordarray( &parser->cursor, parser->limit, max_coords, coords ); + } + + + LOCAL_FUNC + T1_Int T1_ToFixedArray( T1_Parser* parser, + T1_Int max_values, + T1_Fixed* values, + T1_Int power_ten ) + { + return t1_tofixedarray( &parser->cursor, parser->limit, max_values, values, power_ten ); + } + + + LOCAL_FUNC + T1_String* T1_ToString( T1_Parser* parser ) + { + return t1_tostring( &parser->cursor, parser->limit, parser->memory ); + } + + + LOCAL_FUNC + T1_Bool T1_ToBool( T1_Parser* parser ) + { + return t1_tobool( &parser->cursor, parser->limit ); + } + + static + FT_Error read_pfb_tag( FT_Stream stream, T1_UShort *tag, T1_Long* size ) + { + FT_Error error; + + if (READ_UShort(*tag)) goto Exit; + if (*tag == 0x8001 || *tag == 0x8002) + { + FT_Long asize; + + if (READ_ULong(asize)) goto Exit; + + /* swap between big and little endianness */ + *size = ((asize & 0xFF000000) >> 24) | + ((asize & 0x00FF0000) >> 8 ) | + ((asize & 0x0000FF00) << 8 ) | + ((asize & 0x000000FF) << 24); + } + + Exit: + return error; + } + + + + LOCAL_FUNC + T1_Error T1_New_Parser( T1_Parser* parser, + FT_Stream stream, + FT_Memory memory ) + { + FT_Error error; + T1_UShort tag; + T1_Long size; + + parser->stream = stream; + parser->memory = memory; + parser->base_len = 0; + parser->base_dict = 0; + parser->private_len = 0; + parser->private_dict = 0; + parser->in_pfb = 0; + parser->in_memory = 0; + parser->single_block = 0; + + parser->cursor = 0; + parser->limit = 0; + + /******************************************************************/ + /* */ + /* Here's a short summary of what is going on : */ + /* */ + /* When creating a new Type 1 parser, we try to locate and */ + /* load the base dictionary when this is possible (i.e. for */ + /* .pfb files). Otherwise, we load the whole font in memory. */ + /* */ + /* When "loading" the base dictionary, we only setup pointers */ + /* in the case of a memory-based stream. Otherwise, we allocate */ + /* and load the base dict in it. */ + /* */ + /* parser->in_pfb is set when we are in a binary (".pfb") font */ + /* parser->in_memory is set when we have a memory stream. */ + /* */ + + /* try to compute the size of the base dictionary */ + /* look for a Postscript binary file tag, i.e 0x8001 */ + if ( FILE_Seek(0L) ) + goto Exit; + + error = read_pfb_tag( stream, &tag, &size ); + if (error) goto Exit; + + if (tag != 0x8001) + { + /* assume that this is a PFA file for now, an error will */ + /* be produced later when more things are checked */ + (void)FILE_Seek(0L); + size = stream->size; + } + else + parser->in_pfb = 1; + + /* now, try to load the "size" bytes of the "base" dictionary we */ + /* found previously */ + + /* if it's a memory-based resource, set up pointers */ + if ( !stream->read ) + { + parser->base_dict = (T1_Byte*)stream->base + stream->pos; + parser->base_len = size; + parser->in_memory = 1; + + /* check that the "size" field is valid */ + if ( FILE_Skip(size) ) goto Exit; + } + else + { + /* read segment in memory */ + if ( ALLOC( parser->base_dict, size ) || + FILE_Read( parser->base_dict, size ) ) + goto Exit; + } + + /* Now check font format, we must see a '%!PS-AdobeFont-1' */ + /* or a '%!FontType' */ + { + if ( size <= 16 || + ( strncmp( (const char*)parser->base_dict, "%!PS-AdobeFont-1", 16 ) && + strncmp( (const char*)parser->base_dict, "%!FontType", 10 ) ) ) + { + FT_TRACE2(( "Not a Type1 font\n" )); + error = T1_Err_Invalid_File_Format; + } + else + { + parser->cursor = parser->base_dict; + parser->limit = parser->cursor + parser->base_len; + } + } + + Exit: + if (error && !parser->in_memory) + FREE( parser->base_dict ); + + return error; + } + + + LOCAL_FUNC + void T1_Done_Parser( T1_Parser* parser ) + { + FT_Memory memory = parser->memory; + + /* always free the private dictionary */ + FREE( parser->private_dict ); + + /* free the base dictionary only when we have a disk stream */ + if (!parser->in_memory) + FREE( parser->base_dict ); + } + + + /* return the value of an hexadecimal digit */ + static + int hexa_value( char c ) + { + unsigned int d; + + d = (unsigned int)(c-'0'); + if ( d <= 9 ) return (int)d; + + d = (unsigned int)(c-'a'); + if ( d <= 5 ) return (int)(d+10); + + d = (unsigned int)(c-'A'); + if ( d <= 5 ) return (int)(d+10); + + return -1; + } + + + LOCAL_FUNC + void T1_Decrypt( T1_Byte* buffer, + T1_Int length, + T1_UShort seed ) + { + while ( length > 0 ) + { + T1_Byte plain; + + plain = (*buffer ^ (seed >> 8)); + seed = (*buffer+seed)*52845+22719; + *buffer++ = plain; + length--; + } + } + + + LOCAL_FUNC + T1_Error T1_Get_Private_Dict( T1_Parser* parser ) + { + FT_Stream stream = parser->stream; + FT_Memory memory = parser->memory; + FT_Error error = 0; + T1_Long size; + + if (parser->in_pfb) + { + /* in the case of the PFB format, the private dictionary can be */ + /* made of several segments. We thus first read the number of */ + /* segments to compute the total size of the private dictionary */ + /* then re-read them into memory.. */ + T1_Long start_pos = FILE_Pos(); + T1_UShort tag; + T1_Long size; + + parser->private_len = 0; + for (;;) + { + error = read_pfb_tag(stream, &tag, &size); + if (error) goto Fail; + + if (tag != 0x8002) + break; + + parser->private_len += size; + + if ( FILE_Skip(size) ) + goto Fail; + } + + /* Check that we have a private dictionary there */ + /* and allocate private dictionary buffer */ + if ( parser->private_len == 0 ) + { + FT_ERROR(( "T1.Open_Private: invalid private dictionary section\n" )); + error = T1_Err_Invalid_File_Format; + goto Fail; + } + + if ( FILE_Seek( start_pos ) || + ALLOC( parser->private_dict, parser->private_len ) ) + goto Fail; + + parser->private_len = 0; + for (;;) + { + error = read_pfb_tag( stream, &tag, &size ); + if (error || tag != 0x8002) { error = 0; break; } + + if ( FILE_Read( parser->private_dict + parser->private_len, size ) ) + goto Fail; + + parser->private_len += size; + } + } + else + { + /* we have already "loaded" the whole PFA font file in memory */ + /* if this is a memory resource, allocate a new block to hold */ + /* the private dict. Otherwise, simply overwrite into the */ + /* base dict block in the heap.. */ + + /* first of all, look at the "eexec" keyword */ + FT_Byte* cur = parser->base_dict; + FT_Byte* limit = cur + parser->base_len; + FT_Byte c; + + for (;;) + { + c = cur[0]; + if (c == 'e' && cur+9 < limit) /* 9 = 5 letters for 'eexec' + newline + 4 chars */ + { + if ( cur[1] == 'e' && cur[2] == 'x' && + cur[3] == 'e' && cur[4] == 'c' ) + { + cur += 6; /* we skip the newling after the "eexec" */ + break; + } + } + cur++; + if (cur >= limit) + { + FT_ERROR(("T1.Open_Private: could not find 'eexec' keyword\n")); + error = FT_Err_Invalid_File_Format; + goto Exit; + } + } + + /* now determine wether where to write the _encrypted_ binary private */ + /* dictionary. We overwrite the base dictionary for disk-based resources */ + /* and allocate a new block otherwise */ + + size = parser->base_len - (cur-parser->base_dict); + + if ( parser->in_memory ) + { + /* note that we allocate one more byte to put a terminating '0' */ + if (ALLOC( parser->private_dict, size+1 )) goto Fail; + parser->private_len = size; + } + else + { + parser->single_block = 1; + parser->private_dict = parser->base_dict; + parser->private_len = size; + parser->base_dict = 0; + parser->base_len = 0; + } + + /* now determine wether the private dictionary is encoded in binary */ + /* or hexadecimal ASCII format.. */ + /* and decode it accordingly */ + + /* we need to access the next 4 bytes (after the final \r following */ + /* the 'eexec' keyword..) if they all are hexadecimal digits, then */ + /*we have a case of ASCII storage.. */ + + if ( ( hexa_value( cur[0] ) | hexa_value( cur[1] ) | + hexa_value( cur[2] ) | hexa_value( cur[3] ) ) < 0 ) + { + /* binary encoding - "simply" copy the private dict */ + MEM_Copy( parser->private_dict, cur, size ); + } + else + { + /* ASCII hexadecimal encoding.. This blows goats !!.. */ + + T1_Byte* write; + T1_Int count; + + write = parser->private_dict; + count = 0; + + for ( ;cur < limit; cur++) + { + int hex1; + + /* check for newline */ + if (cur[0] == '\r' || cur[0] == '\n') + continue; + + /* exit if we have a non-hexadecimal digit that isn't a newline */ + hex1 = hexa_value(cur[0]); + if (hex1 < 0 || cur+1 >= limit) + break; + + /* otherwise, store byte */ + *write++ = (hex1 << 4) | hexa_value(cur[1]); + count++; + cur++; + } + + /* put a safeguard */ + parser->private_len = write - parser->private_dict; + *write++ = 0; + } + } + + /* we now decrypt the encoded binary private dictionary */ + T1_Decrypt( parser->private_dict, parser->private_len, 55665 ); + parser->cursor = parser->private_dict; + parser->limit = parser->cursor + parser->private_len; + + Fail: + Exit: + return error; + } + diff --git a/src/type1z/t1parse.h b/src/type1z/t1parse.h new file mode 100644 index 000000000..a34b079e3 --- /dev/null +++ b/src/type1z/t1parse.h @@ -0,0 +1,206 @@ +/******************************************************************* + * + * t1parse.h 2.0 + * + * Type1 parser. + * + * Copyright 1996-1998 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 Type 1 parser is in charge of the following: + * + * - provide an implementation of a growing sequence of + * objects called a T1_Table (used to build various tables + * needed by the loader). + * + * - opening .pfb and .pfa files to extract their top-level + * and private dictionaries + * + * - read numbers, arrays & strings from any dictionary + * + * See "t1load.c" to see how data is loaded from the font file + * + ******************************************************************/ + +#ifndef T1PARSE_H +#define T1PARSE_H + +#include + +#ifdef __cplusplus + extern "C" { +#endif + +/************************************************************************* + * + * T1_Table + * + * + * A T1_Table is a simple object used to store an array of objects + * in a single memory block. + * + * + * block :: address in memory of the growheap's block. This + * can change between two object adds, due to the use + * of 'realloc'. + * + * cursor :: current top of the grow heap within its block + * + * capacity :: current size of the heap block. Increments by 1 Kb + * + * init :: boolean. set when the table has been initialized + * (the table user should set this field) + * + * max_elems :: maximum number of elements in table + * num_elems :: current number of elements in table + * + * elements :: table of element addresses within the block + * lengths :: table of element sizes within the block + * + * memory :: memory object used for memory operations (alloc/realloc) + */ + + typedef struct T1_Table_ + { + T1_Byte* block; /* current memory block */ + T1_Int cursor; /* current cursor in memory block */ + T1_Int capacity; /* current size of memory block */ + T1_Long init; + + T1_Int max_elems; + T1_Int num_elems; + T1_Byte** elements; /* addresses of table elements */ + T1_Int* lengths; /* lengths of table elements */ + + FT_Memory memory; + + } T1_Table; + + +/************************************************************************* + * + * T1_Parser + * + * + * A T1_Parser is an object used to parse a Type 1 fonts very + * quickly. + * + * + * stream :: current input stream + * memory :: current memory object + * + * base_dict :: pointer to top-level dictionary + * base_len :: length in bytes of top dict + * + * private_dict :: pointer to private dictionary + * private_len :: length in bytes of private dict + * + * in_pfb :: boolean. Indicates that we're in a .pfb file + * in_memory :: boolean. Indicates a memory-based stream + * single_block :: boolean. Indicates that the private dict + * is stored in lieu of the base dict + * + * cursor :: current parser cursor + * limit :: current parser limit (first byte after current + * dictionary). + * + * error :: current parsing error + */ + typedef struct T1_Parser_ + { + FT_Stream stream; + FT_Memory memory; + + T1_Byte* base_dict; + T1_Int base_len; + + T1_Byte* private_dict; + T1_Int private_len; + + T1_Byte in_pfb; + T1_Byte in_memory; + T1_Byte single_block; + + T1_Byte* cursor; + T1_Byte* limit; + T1_Error error; + + } T1_Parser; + + + LOCAL_DEF + T1_Error T1_New_Table( T1_Table* table, + T1_Int count, + FT_Memory memory ); + + + LOCAL_DEF + T1_Error T1_Add_Table( T1_Table* table, + T1_Int index, + void* object, + T1_Int length ); + + + LOCAL_DEF + void T1_Done_Table( T1_Table* table ); + + LOCAL_DEF + void T1_Release_Table( T1_Table* table ); + + LOCAL_DEF + T1_Long T1_ToInt ( T1_Parser* parser ); + + LOCAL_DEF + T1_Long T1_ToFixed( T1_Parser* parser, T1_Int power_ten ); + + LOCAL_DEF + T1_Int T1_ToCoordArray( T1_Parser* parser, + T1_Int max_coords, + T1_Short* coords ); + + LOCAL_DEF + T1_Int T1_ToFixedArray( T1_Parser* parser, + T1_Int max_values, + T1_Fixed* values, + T1_Int power_ten ); + + LOCAL_DEF + T1_String* T1_ToString( T1_Parser* parser ); + + + LOCAL_DEF + T1_Bool T1_ToBool( T1_Parser* parser ); + + + LOCAL_DEF + T1_Int T1_ToImmediate( T1_Parser* parser ); + + + LOCAL_DEF + T1_Error T1_New_Parser( T1_Parser* parser, + FT_Stream stream, + FT_Memory memory ); + + LOCAL_DEF + T1_Error T1_Get_Private_Dict( T1_Parser* parser ); + + LOCAL_DEF + void T1_Decrypt( T1_Byte* buffer, + T1_Int length, + T1_UShort seed ); + +#ifdef __cplusplus + } +#endif + +#endif /* T1PARSE_H */ + + +/* END */ + diff --git a/src/type1z/t1tokens.h b/src/type1z/t1tokens.h new file mode 100644 index 000000000..4f251ed5f --- /dev/null +++ b/src/type1z/t1tokens.h @@ -0,0 +1,73 @@ +/******************************************************************* + * + * t1tokens.h + * + * Type 1 tokens definition + * + * Copyright 2000 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 only contains macros that are expanded when compiling + * the "t1load.c" source file. + * + ******************************************************************/ + +#undef FACE +#define FACE (face->type1) + + /* define the font info dictionary parsing callbacks */ + + PARSE_STRING("version",version) + PARSE_STRING("Notice",notice) + PARSE_STRING("FullName",full_name) + PARSE_STRING("FamilyName",family_name) + PARSE_STRING("Weight",weight) + + PARSE_INT("ItalicAngle",italic_angle) + PARSE_BOOL("isFixedPitch",is_fixed_pitch) + PARSE_INT("UnderlinePosition",underline_position) + PARSE_INT("UnderlineThickness",underline_thickness) + + /* define the private dict parsing callbacks */ + + PARSE_INT("UniqueID",unique_id) + PARSE_INT("lenIV",lenIV) + + PARSE_COORDS( "BlueValues", num_blues, 14, blue_values) + PARSE_COORDS( "OtherBlues", num_other_blues, 10, other_blues) + + PARSE_COORDS( "FamilyBlues", num_family_blues, 14, family_blues) + PARSE_COORDS( "FamilyOtherBlues", num_family_other_blues, 10, family_other_blues) + + PARSE_FIXED( "BlueScale", blue_scale) + PARSE_INT( "BlueShift", blue_shift) + + PARSE_INT( "BlueFuzz", blue_fuzz) + + PARSE_COORDS2( "StdHW", 1, standard_width ) + PARSE_COORDS2( "StdVW", 1, standard_height ) + + PARSE_COORDS( "StemSnapH", num_snap_widths, 12, stem_snap_widths ) + PARSE_COORDS( "StemSnapV", num_snap_heights, 12, stem_snap_heights ) + + PARSE_INT( "LanguageGroup", language_group ) + PARSE_INT( "password", password ) + PARSE_COORDS2( "MinFeature", 2, min_feature ) + + /* define the top-level dictionary parsing callbacks */ + +/* PARSE_STRING( "FontName", font_name ) -- handled by special routine */ + PARSE_INT( "PaintType", paint_type ) + PARSE_INT( "FontType", font_type ) + PARSE_FIXEDS2( "FontMatrix", 4, font_matrix ) +/* PARSE_COORDS2( "FontBBox", 4, font_bbox ) -- handled by special func */ + PARSE_INT( "StrokeWidth", stroke_width ) + +#undef FACE + + diff --git a/src/type1z/type1z.c b/src/type1z/type1z.c new file mode 100644 index 000000000..f2d28009b --- /dev/null +++ b/src/type1z/type1z.c @@ -0,0 +1,41 @@ +/***************************************************************************/ +/* */ +/* type1.c */ +/* */ +/* FreeType Type 1 driver component */ +/* */ +/* Copyright 1996-1998 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 is used to compile the FreeType Type 1 font driver. */ +/* It relies on all components included in the "base" layer (see */ +/* the file "ftbase.c"). Source code is located in "freetype/ttlib" */ +/* and contains : */ +/* */ +/* - a driver interface */ +/* - an object manager */ +/* - a table loader */ +/* - a glyph loader */ +/* - a glyph hinter */ +/* */ +/***************************************************************************/ + + + +#include +#include +#include +#include +/* +#include +#include +#include +*/ +