diff --git a/CHANGES b/CHANGES index e7ffb2361..5c1b7ae4a 100644 --- a/CHANGES +++ b/CHANGES @@ -1,5 +1,14 @@ LATEST_CHANGES + - fixed potential "divide by zero" bugs in ftcalc.c.. my god.. + + - added source code for the OpenType/CFF driver (still incomplete though..) + + - modified the SFNT driver slightly to perform more robust header + checks in TT_Load_SFNT_Header. This prevents certain font files + (e.g. some Type 1 Multiple Masters) from being incorrectly "recognized" + as TrueType font files.. + - moved a lot of stuff from the TrueType driver to the SFNT module, this allows greater code re-use between font drivers (e.g. TrueType, OpenType, Compact-TrueType, etc..) diff --git a/src/base/ftcalc.c b/src/base/ftcalc.c index ddc694606..90d58e1e4 100644 --- a/src/base/ftcalc.c +++ b/src/base/ftcalc.c @@ -132,13 +132,13 @@ { FT_Int s; - s = 1; if ( a < 0 ) { a = -a; s = -s; } if ( b < 0 ) { b = -b; s = -s; } if ( c < 0 ) { c = -c; s = -s; } - return s * ( ( (FT_Int64)a * b + ( c >> 1 ) ) / c ); + return s * ( c > 0 ? ( ( (FT_Int64)a * b + ( c >> 1 ) ) / c ) + : 0x7FFFFFFF ); } @@ -344,21 +344,22 @@ s ^= b; b = ABS( b ); s ^= c; c = ABS( c ); - if ( a <= 46340 && b <= 46340 && c <= 176095L ) + if ( a <= 46340 && b <= 46340 && c <= 176095L && c > 0) { - a = ( a*b + (c >> 1) ) / c; + a = a*b + (c >> 1) ) / c; } - else + else if (c > 0) { FT_Int64 temp, temp2; - FT_MulTo64( a, b, &temp ); temp2.hi = (FT_Int32)(c >> 31); temp2.lo = (FT_Word32)(c / 2); FT_Add64( &temp, &temp2, &temp ); a = FT_Div64by32( &temp, c ); } + else + a = 0x7FFFFFFF; return ( s < 0 ) ? -a : a; } @@ -614,7 +615,6 @@ FT_Int32 s; FT_Word32 q, r, i, lo; - s = x->hi; if ( s < 0 ) { @@ -626,7 +626,9 @@ /* Shortcut */ if ( x->hi == 0 ) { - q = x->lo / y; + if (y > 0) q = x->lo / y; + else q = 0x7FFFFFFF; + return ( s < 0 ) ? -(FT_Int32)q : (FT_Int32)q; } diff --git a/src/cff/cff.c b/src/cff/cff.c new file mode 100644 index 000000000..b2581e973 --- /dev/null +++ b/src/cff/cff.c @@ -0,0 +1,49 @@ +/***************************************************************************/ +/* */ +/* cff.c */ +/* */ +/* FreeType OpenType driver component (body only). */ +/* */ +/* 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 used to compile the FreeType TrueType font driver. It */ + /* relies on all components included in the `base' layer (see the file */ + /* `ftbase.c'). The source code is located in `freetype/ttlib' and */ + /* contains: */ + /* */ + /* - a driver interface */ + /* - an object manager */ + /* - a table loader */ + /* - a glyph loader */ + /* - a glyph hinter/bytecode interpreter */ + /* - a charmap processor */ + /* - an extension manager (only used for some tools) */ + /* */ + /* Note that the engine extensions found in `freetype/ttlib/extend' are */ + /* reserved to specific tools and/or font servers; they're not part of */ + /* the `core' TrueType driver, even though they are separately linkable */ + /* to it. */ + /* */ + /*************************************************************************/ + + +#define FT_MAKE_OPTION_SINGLE_OBJECT + +#include /* driver interface */ +#include /* token parser */ +#include /* tables loader */ +#include /* object management */ + +/* END */ diff --git a/src/cff/module.mk b/src/cff/module.mk new file mode 100644 index 000000000..1e8b92539 --- /dev/null +++ b/src/cff/module.mk @@ -0,0 +1,7 @@ +make_module_list: add_cff_driver + +add_cff_driver: + $(OPEN_DRIVER)cff_driver_interface$(CLOSE_DRIVER) + $(ECHO_DRIVER)cff $(ECHO_DRIVER_DESC)OpenType fonts with extension *.otf$(ECHO_DRIVER_DONE) + +# EOF diff --git a/src/cff/rules.mk b/src/cff/rules.mk new file mode 100644 index 000000000..39e658da3 --- /dev/null +++ b/src/cff/rules.mk @@ -0,0 +1,112 @@ +# +# FreeType 2 OpenType/CFF driver configuration rules +# + + +# 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. + + +# Include the rules defined for the SFNT driver, which is heavily used +# by the TrueType one. +# +include $(SRC_)sfnt/rules.mk + + +# OpenType driver directory +# +T2_DIR := $(SRC_)cff +T2_DIR_ := $(T2_DIR)$(SEP) + + +# location of all extensions to the driver, if any +# +T2_EXT_DIR := $(T2_DIR_)extend +T2_EXT_DIR_ := $(T2_EXT_DIR)$(SEP) + +# additional include flags used when compiling the driver +# +T2_INCLUDE := $(SFNT_INCLUDE) $(T2_DIR) $(T2_EXT_DIR) + + +# compilation flags for the driver +# +T2_CFLAGS := $(T2_INCLUDE:%=$I%) +T2_COMPILE := $(FT_COMPILE) $(T2_CFLAGS) + + +# driver sources (i.e., C files) +# +T2_DRV_SRC := $(T2_DIR_)t2objs.c \ + $(T2_DIR_)t2load.c \ + $(T2_DIR_)t2gload.c \ + $(T2_DIR_)t2parse.c \ + $(T2_DIR_)t2driver.c + +# driver headers +# +T2_DRV_H := $(SFNT_H) \ + $(T2_DRV_SRC:%.c=%.h) + + +# default extensions headers +# +T2_EXT_H := $(T2_EXT_SRC:.c=.h) + + +# driver object(s) +# +# T2_DRV_OBJ_M is used during `debug' builds +# T2_DRV_OBJ_S is used during `release' builds +# +T2_DRV_OBJ_M := $(T2_DRV_SRC:$(T2_DIR_)%.c=$(OBJ_)%.$O) +T2_DRV_OBJ_S := $(OBJ_)cff.$O + + +# default extensions objects +# +T2_EXT_OBJ := $(T2_EXT_SRC:$(T2_EXT_DIR_)%.c=$(OBJ_)%.$O) + + +# driver source file(s) +# +T2_DRV_SRC_M := $(T2_DRV_SRC) $(SFNT_SRC) +T2_DRV_SRC_S := $(T2_DIR_)cff.c + + +# driver - single object +# +# the driver is recompiled if any of the header or source files is changed +# as well as any of the shared source files found in `shared/sfnt' +# +$(T2_DRV_OBJ_S): $(BASE_H) $(T2_DRV_H) $(T2_DRV_SRC) $(T2_DRV_SRC_S) + $(T2_COMPILE) $T$@ $(T2_DRV_SRC_S) + + + +# driver - multiple objects +# +# All objects are recompiled if any of the header files is changed +# +$(OBJ_)t2%.$O: $(T2_DIR_)t2%.c $(BASE_H) $(T2_DRV_H) + $(T2_COMPILE) $T$@ $< + +$(OBJ_)t2x%.$O: $(T2_EXT_DIR_)t2x%.c $(BASE_H) $(SFNT_H) $(T2_EXT_H) + $(T2_COMPILE) $T$@ $< + +$(OBJ_)t2%.$O: $(SFNT_DIR_)t2%.c $(BASE_H) $(SFNT_H) + $(T2_COMPILE) $T$@ $< + + +# update main driver object lists +# +DRV_OBJS_S += $(T2_DRV_OBJ_S) +DRV_OBJS_M += $(T2_DRV_OBJ_M) + +# EOF diff --git a/src/cff/t2driver.c b/src/cff/t2driver.c new file mode 100644 index 000000000..cac43ca44 --- /dev/null +++ b/src/cff/t2driver.c @@ -0,0 +1,444 @@ +/***************************************************************************/ +/* */ +/* t2driver.c */ +/* */ +/* OpenType font driver implementation (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. */ +/* */ +/***************************************************************************/ + + +#include +#include +#include +#include + +#include +#include + + +#undef FT_COMPONENT +#define FT_COMPONENT trace_ttdriver + + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** ****/ + /**** F A C E S ****/ + /**** ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + +#undef PAIR_TAG +#define PAIR_TAG( left, right ) ( ((TT_ULong)left << 16) | (TT_ULong)right ) + + /*************************************************************************/ + /* */ + /* */ + /* Get_Kerning */ + /* */ + /* */ + /* A driver method used to return the kerning vector between two */ + /* glyphs of the same face. */ + /* */ + /* */ + /* face :: A handle to the source face object. */ + /* */ + /* left_glyph :: The index of the left glyph in the kern pair. */ + /* */ + /* right_glyph :: The index of the right glyph in the kern pair. */ + /* */ + /* */ + /* kerning :: The kerning vector. This is in font units for */ + /* scalable formats, and in pixels for fixed-sizes */ + /* formats. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + /* */ + /* Only horizontal layouts (left-to-right & right-to-left) are */ + /* supported by this function. Other layouts, or more sophisticated */ + /* kernings are out of scope of this method (the basic driver */ + /* interface is meant to be simple). */ + /* */ + /* They can be implemented by format-specific interfaces. */ + /* */ + static + TT_Error Get_Kerning( TT_Face face, + TT_UInt left_glyph, + TT_UInt right_glyph, + TT_Vector* kerning ) + { + TT_Kern_0_Pair* pair; + + + if ( !face ) + return FT_Err_Invalid_Face_Handle; + + kerning->x = 0; + kerning->y = 0; + + if ( face->kern_pairs ) + { + /* there are some kerning pairs in this font file! */ + TT_ULong search_tag = PAIR_TAG( left_glyph, right_glyph ); + TT_Long left, right; + + + left = 0; + right = face->num_kern_pairs - 1; + + while ( left <= right ) + { + TT_Int middle = left + ((right-left) >> 1); + TT_ULong cur_pair; + + + pair = face->kern_pairs + middle; + cur_pair = PAIR_TAG( pair->left, pair->right ); + + if ( cur_pair == search_tag ) + goto Found; + + if ( cur_pair < search_tag ) + left = middle+1; + else + right = middle-1; + } + } + + Exit: + return FT_Err_Ok; + + Found: + kerning->x = pair->value; + goto Exit; + } + + +#undef PAIR_TAG + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** ****/ + /**** S I Z E S ****/ + /**** ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* */ + /* Set_Char_Sizes */ + /* */ + /* */ + /* A driver method used to reset a size's character sizes (horizontal */ + /* and vertical) expressed in fractional points. */ + /* */ + /* */ + /* char_width :: The character width expressed in 26.6 fractional */ + /* points. */ + /* char_height :: The character height expressed in 26.6 fractional */ + /* points. */ + /* */ + /* */ + /* size :: A handle to the target size object. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + static + TT_Error Set_Char_Sizes( T2_Size size, + FT_F26Dot6 char_width, + FT_F26Dot6 char_height, + FT_UInt horz_resolution, + FT_UInt vert_resolution ) + { + FT_Size_Metrics* metrics = &size->metrics; + T2_Face face = (T2_Face)size->face; + FT_Long dim_x, dim_y; + + /* This bit flag, when set, indicates that the pixel size must be */ + /* truncated to an integer. Nearly all TrueType fonts have this */ + /* bit set, as hinting won't work really well otherwise. */ + /* */ + /* However, for those rare fonts who do not set it, we override */ + /* the default computations performed by the base layer. I really */ + /* don't know if this is useful, but hey, that's the spec :-) */ + /* */ + if ( (face->header.Flags & 8) == 0 ) + { + /* Compute pixel sizes in 26.6 units */ + dim_x = (char_width * horz_resolution) / 72; + dim_y = (char_height * vert_resolution) / 72; + + metrics->x_scale = FT_DivFix( dim_x, face->root.units_per_EM ); + metrics->y_scale = FT_DivFix( dim_y, face->root.units_per_EM ); + + metrics->x_ppem = (TT_UShort)(dim_x >> 6); + metrics->y_ppem = (TT_UShort)(dim_y >> 6); + } + + return T2_Reset_Size( size ); + } + + + /*************************************************************************/ + /* */ + /* */ + /* Set_Pixel_Sizes */ + /* */ + /* */ + /* A driver method used to reset a size's character sizes (horizontal */ + /* and vertical) expressed in integer pixels. */ + /* */ + /* */ + /* pixel_width :: The character width expressed in integer pixels. */ + /* */ + /* pixel_height :: The character height expressed in integer pixels. */ + /* */ + /* */ + /* size :: A handle to the target size object. */ + /* */ + /* */ + /* FreeType error code. 0 means success */ + /* */ + static + FT_Error Set_Pixel_Sizes( T2_Size size, + FT_UInt pixel_width, + FT_UInt pixel_height ) + { + UNUSED(pixel_width); + UNUSED(pixel_height); + + return T2_Reset_Size( size ); + } + + + /*************************************************************************/ + /* */ + /* */ + /* Load_Glyph */ + /* */ + /* */ + /* A driver method used to load a glyph within a given glyph slot. */ + /* */ + /* */ + /* slot :: A handle to the target slot object where the glyph */ + /* will be loaded. */ + /* */ + /* size :: A handle to the source face size at which the glyph */ + /* must be scaled/loaded/etc. */ + /* */ + /* glyph_index :: The index of the glyph in the font file. */ + /* */ + /* load_flags :: A flag indicating what to load for this glyph. The */ + /* FTLOAD_??? constants can be used to control the */ + /* glyph loading process (e.g., whether the outline */ + /* should be scaled, whether to load bitmaps or not, */ + /* whether to hint the outline, etc). */ + /* */ + /* result :: A set of bit flags indicating the type of data that */ + /* was loaded in the glyph slot (outline, bitmap, */ + /* pixmap, etc). */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + static + FT_Error Load_Glyph( T2_GlyphSlot slot, + T2_Size size, + FT_UShort glyph_index, + FT_UInt load_flags ) + { + FT_Error error; + + + if ( !slot ) + return FT_Err_Invalid_Handle; + + /* check that we want a scaled outline or bitmap */ + if ( !size ) + load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING; + + if ( load_flags & FT_LOAD_NO_SCALE ) + size = NULL; + + /* reset the size object if necessary */ + if ( size ) + { + /* these two object must have the same parent */ + if ( size->face != slot->face ) + return FT_Err_Invalid_Face_Handle; + } + + /* now load the glyph outline if necessary */ +#if 1 /* XXXX: TODO */ + error = FT_Err_Unimplemented_Feature; +#else + error = T2_Load_Glyph( size, slot, glyph_index, load_flags ); +#endif + /* force drop-out mode to 2 - irrelevant now */ + /* slot->outline.dropout_mode = 2; */ + + return error; + } + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** ****/ + /**** C H A R A C T E R M A P P I N G S ****/ + /**** ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + /*************************************************************************/ + /* */ + /* */ + /* Get_Char_Index */ + /* */ + /* */ + /* Uses a charmap to return a given character code's glyph index. */ + /* */ + /* */ + /* charmap :: A handle to the source charmap object. */ + /* charcode :: The character code. */ + /* */ + /* */ + /* Glyph index. 0 means `undefined character code'. */ + /* */ + static + FT_UInt Get_Char_Index( TT_CharMap charmap, + FT_Long charcode ) + { + FT_Error error; + T2_Face face; + TT_CMapTable* cmap; + + cmap = &charmap->cmap; + face = (T2_Face)charmap->root.face; + + /* Load table if needed */ + if ( !cmap->loaded ) + { + SFNT_Interface* sfnt = (SFNT_Interface*)face->sfnt; + + error = sfnt->load_charmap( face, cmap, face->root.stream ); + if (error) return error; + + cmap->loaded = TRUE; + } + + return (cmap->get_index ? cmap->get_index( cmap, charcode ) : 0 ); + } + + + static + FTDriver_Interface t2_get_interface( T2_Driver driver, const char* interface ) + { + FT_Driver sfntd = FT_Get_Driver( driver->root.library, "sfnt" ); + SFNT_Interface* sfnt; + + /* only return the default interface from the SFNT module */ + if (sfntd) + { + sfnt = (SFNT_Interface*)(sfntd->interface.format_interface); + if (sfnt) + return sfnt->get_interface( (FT_Driver)driver, interface ); + } + return 0; + } + + + /* The FT_DriverInterface structure is defined in ftdriver.h. */ + + const FT_DriverInterface cff_driver_interface = + { + sizeof ( T2_DriverRec ), + sizeof ( TT_FaceRec ), + sizeof ( FT_SizeRec ), + sizeof ( FT_GlyphSlotRec ), + + "cff", /* driver name */ + 100, /* driver version == 1.0 */ + 200, /* driver requires FreeType 2.0 or above */ + + (void*)0, + + (FTDriver_initDriver) T2_Init_Driver, + (FTDriver_doneDriver) T2_Done_Driver, + (FTDriver_getInterface) t2_get_interface, + + (FTDriver_initFace) T2_Init_Face, + (FTDriver_doneFace) T2_Done_Face, + (FTDriver_getKerning) Get_Kerning, + + (FTDriver_initSize) T2_Init_Size, + (FTDriver_doneSize) T2_Done_Size, + (FTDriver_setCharSizes) Set_Char_Sizes, + (FTDriver_setPixelSizes) Set_Pixel_Sizes, + + (FTDriver_initGlyphSlot) T2_Init_GlyphSlot, + (FTDriver_doneGlyphSlot) T2_Done_GlyphSlot, + (FTDriver_loadGlyph) Load_Glyph, + + (FTDriver_getCharIndex) Get_Char_Index, + }; + + + + /*************************************************************************/ + /* */ + /* */ + /* getDriverInterface */ + /* */ + /* */ + /* This function is used when compiling the TrueType 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 &cff_driver_interface; + } + +#endif /* CONFIG_OPTION_DYNAMIC_DRIVERS */ + + +/* END */ diff --git a/src/cff/t2driver.h b/src/cff/t2driver.h new file mode 100644 index 000000000..129096ec8 --- /dev/null +++ b/src/cff/t2driver.h @@ -0,0 +1,34 @@ +/***************************************************************************/ +/* */ +/* t2driver.h */ +/* */ +/* High-level OpenType driver interface (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. */ +/* */ +/***************************************************************************/ + + +#ifndef T2DRIVER_H +#define T2DRIVER_H + +#include +#include +#include +#include + + + FT_EXPORT_VAR(const FT_DriverInterface) cff_driver_interface; + + +#endif /* T2DRIVER_H */ + + +/* END */ diff --git a/src/cff/t2errors.h b/src/cff/t2errors.h new file mode 100644 index 000000000..ab3d4e4b7 --- /dev/null +++ b/src/cff/t2errors.h @@ -0,0 +1,126 @@ +/***************************************************************************/ +/* */ +/* t2errors.h */ +/* */ +/* OpenType error ID definitions (specification only). */ +/* */ +/* 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 T2ERRORS_H +#define T2ERRORS_H + + /*************************************************************************/ + /* */ + /* 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 T2_Err_Ok FT_Err_Ok + + /* High level API errors. */ + +#define T2_Err_Invalid_File_Format FT_Err_Invalid_File_Format +#define T2_Err_Invalid_Argument FT_Err_Invalid_Argument +#define T2_Err_Invalid_Driver_Handle FT_Err_Invalid_Driver_Handle +#define T2_Err_Invalid_Face_Handle FT_Err_Invalid_Face_Handle +#define T2_Err_Invalid_Instance_Handle FT_Err_Invalid_Size_Handle +#define T2_Err_Invalid_Glyph_Handle FT_Err_Invalid_Slot_Handle +#define T2_Err_Invalid_CharMap_Handle FT_Err_Invalid_CharMap_Handle +#define T2_Err_Invalid_Glyph_Index FT_Err_Invalid_Glyph_Index + +#define T2_Err_Unimplemented_Feature FT_Err_Unimplemented_Feature +#define T2_Err_Unavailable_Outline FT_Err_Unavailable_Outline +#define T2_Err_Unavailable_Bitmap FT_Err_Unavailable_Bitmap +#define T2_Err_Unavailable_Pixmap FT_Err_Unavailable_Pixmap +#define T2_Err_File_Is_Not_Collection FT_Err_File_Is_Not_Collection + +#define T2_Err_Invalid_Engine FT_Err_Invalid_Driver_Handle + + /* Internal errors. */ + +#define T2_Err_Out_Of_Memory FT_Err_Out_Of_Memory +#define T2_Err_Unlisted_Object FT_Err_Unlisted_Object + + /* General glyph outline errors. */ + +#define T2_Err_Too_Many_Points FT_Err_Too_Many_Points +#define T2_Err_Too_Many_Contours FT_Err_Too_Many_Contours +#define T2_Err_Too_Many_Ins FT_Err_Too_Many_Hints +#define T2_Err_Invalid_Composite FT_Err_Invalid_Composite + + /* Bytecode interpreter error codes. */ + + /* These error codes are produced by the TrueType */ + /* bytecode interpreter. They usually indicate a */ + /* broken font file, a broken glyph within a font */ + /* file, or a bug in the interpreter! */ + +#define T2_Err_Invalid_Opcode 0x400 +#define T2_Err_Too_Few_Arguments 0x401 +#define T2_Err_Stack_Overflow 0x402 +#define T2_Err_Code_Overflow 0x403 +#define T2_Err_Bad_Argument 0x404 +#define T2_Err_Divide_By_Zero 0x405 +#define T2_Err_Storage_Overflow 0x406 +#define T2_Err_Cvt_Overflow 0x407 +#define T2_Err_Invalid_Reference 0x408 +#define T2_Err_Invalid_Distance 0x409 +#define T2_Err_Interpolate_Twilight 0x40A +#define T2_Err_Debug_OpCode 0x40B +#define T2_Err_ENDF_In_Exec_Stream 0x40C +#define T2_Err_Out_Of_CodeRanges 0x40D +#define T2_Err_Nested_DEFS 0x40E +#define T2_Err_Invalid_CodeRange 0x40F +#define T2_Err_Invalid_Displacement 0x410 +#define T2_Err_Execution_Too_Long 0x411 + +#define T2_Err_Too_Many_Instruction_Defs 0x412 +#define T2_Err_Too_Many_Function_Defs 0x412 + + /* Other TrueType specific error codes. */ + +#define T2_Err_Table_Missing 0x420 +#define T2_Err_Too_Many_Extensions 0x421 +#define T2_Err_Extensions_Unsupported 0x422 +#define T2_Err_Invalid_Extension_Id 0x423 + +#define T2_Err_No_Vertical_Data 0x424 + +#define T2_Err_Max_Profile_Missing 0x430 +#define T2_Err_Header_Table_Missing 0x431 +#define T2_Err_Horiz_Header_Missing 0x432 +#define T2_Err_Locations_Missing 0x433 +#define T2_Err_Name_Table_Missing 0x434 +#define T2_Err_CMap_Table_Missing 0x435 +#define T2_Err_Hmtx_Table_Missing 0x436 +#define T2_Err_OS2_Table_Missing 0x437 +#define T2_Err_Post_Table_Missing 0x438 + +#define T2_Err_Invalid_Horiz_Metrics 0x440 +#define T2_Err_Invalid_CharMap_Format 0x441 +#define T2_Err_Invalid_PPem 0x442 +#define T2_Err_Invalid_Vert_Metrics 0x443 + +#define T2_Err_Could_Not_Find_Context 0x450 + +#endif /* FTERRID_H */ + + +/* END */ diff --git a/src/cff/t2gload.c b/src/cff/t2gload.c new file mode 100644 index 000000000..a5caa756e --- /dev/null +++ b/src/cff/t2gload.c @@ -0,0 +1,1177 @@ +/***************************************************************************/ +/* */ +/* t2gload.c */ +/* */ +/* OpenType Glyph Loader (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. */ +/* */ +/***************************************************************************/ + + +#include +#include +#include +#include +#include + + +#include + + /* required for the tracing mode */ +#undef FT_COMPONENT +#define FT_COMPONENT trace_ttgload + + + /*************************************************************************/ + /* */ + /* Composite font flags. */ + /* */ +#define ARGS_ARE_WORDS 0x001 +#define ARGS_ARE_XY_VALUES 0x002 +#define ROUND_XY_TO_GRID 0x004 +#define WE_HAVE_A_SCALE 0x008 +/* reserved 0x010 */ +#define MORE_COMPONENTS 0x020 +#define WE_HAVE_AN_XY_SCALE 0x040 +#define WE_HAVE_A_2X2 0x080 +#define WE_HAVE_INSTR 0x100 +#define USE_MY_METRICS 0x200 + + + + /*************************************************************************/ + /* Returns the horizontal or vertical metrics in font units for a */ + /* given glyph. The metrics are the left side bearing (resp. top */ + /* side bearing) and advance width (resp. advance height). */ + /* */ + LOCAL_FUNC + void T2_Get_Metrics( TT_HoriHeader* header, + FT_UInt index, + FT_Short* bearing, + FT_UShort* advance ) + { + TT_LongMetrics* longs_m; + TT_UShort k = header->number_Of_HMetrics; + + + if ( index < k ) + { + longs_m = (TT_LongMetrics*)header->long_metrics + index; + *bearing = longs_m->bearing; + *advance = longs_m->advance; + } + else + { + *bearing = ((TT_ShortMetrics*)header->short_metrics)[index - k]; + *advance = ((TT_LongMetrics*)header->long_metrics)[k - 1].advance; + } + } + + + /*************************************************************************/ + /* Returns the horizontal metrics in font units for a given glyph. */ + /* If `check' is true, take care of monospaced fonts by returning the */ + /* advance width maximum. */ + /* */ + static + void Get_HMetrics( T2_Face face, + FT_UInt index, + FT_Bool check, + FT_Short* lsb, + FT_UShort* aw ) + { + T2_Get_Metrics( &face->horizontal, index, lsb, aw ); + + if ( check && face->postscript.isFixedPitch ) + *aw = face->horizontal.advance_Width_Max; + } + + + /*************************************************************************/ + /* Returns the advance width table for a given pixel size if it is */ + /* found in the font's `hdmx' table (if any). */ + /* */ + static + FT_Byte* Get_Advance_Widths( T2_Face face, + FT_UShort ppem ) + { + FT_UShort n; + + for ( n = 0; n < face->hdmx.num_records; n++ ) + if ( face->hdmx.records[n].ppem == ppem ) + return face->hdmx.records[n].widths; + + return NULL; + } + + +#define cur_to_org( n, zone ) \ + MEM_Copy( (zone)->org, (zone)->cur, n * sizeof ( TT_Vector ) ) + +#define org_to_cur( n, zone ) \ + MEM_Copy( (zone)->cur, (zone)->org, n * sizeof ( TT_Vector ) ) + + + /*************************************************************************/ + /* Translates an array of coordinates. */ + /* */ + static + void translate_array( FT_UInt n, + FT_Vector* coords, + FT_Pos delta_x, + FT_Pos delta_y ) + { + FT_UInt k; + + if ( delta_x ) + for ( k = 0; k < n; k++ ) + coords[k].x += delta_x; + + if ( delta_y ) + for ( k = 0; k < n; k++ ) + coords[k].y += delta_y; + } + + + + /*************************************************************************/ + /* Mounts one glyph zone on top of another. This is needed to */ + /* assemble composite glyphs. */ + /* */ + static + void mount_zone( FT_GlyphZone* source, + FT_GlyphZone* target ) + { + FT_UInt np; + FT_Int nc; + + np = source->n_points; + nc = source->n_contours; + + target->org = source->org + np; + target->cur = source->cur + np; + target->tags = source->tags + np; + + target->contours = source->contours + nc; + + target->n_points = 0; + target->n_contours = 0; + } + + +#undef IS_HINTED +#define IS_HINTED(flags) ((flags & FT_LOAD_NO_HINTING) == 0) + + /*************************************************************************/ + /* */ + /* */ + /* Load_Simple_Glyph */ + /* */ + /* */ + /* Loads a simple (i.e, non-composite) glyph. This function is used */ + /* for the `Load_Simple' state of TT_Load_Glyph(). All composite */ + /* glyphs elements will be loaded with routine. */ + /* */ + static + FT_Error Load_Simple( T2_Loader* load, + FT_UInt byte_count, + FT_Int n_contours, + FT_Bool debug ) + { + FT_Error error; + FT_Stream stream = load->stream; + FT_GlyphZone* zone = &load->zone; + T2_Face face = load->face; + + FT_UShort n_ins; + FT_Int n, n_points; + + /*********************************************************************/ + /* simple check */ + + if ( n_contours > load->left_contours ) + { + FT_TRACE0(( "ERROR: Glyph index %ld has %d contours > left %d\n", + load->glyph_index, + n_contours, + load->left_contours )); + return TT_Err_Too_Many_Contours; + } + + /* preparing the execution context */ + mount_zone( &load->base, zone ); + + /*********************************************************************/ + /* reading the contours endpoints */ + + if ( ACCESS_Frame( byte_count ) ) + return error; + + for ( n = 0; n < n_contours; n++ ) + zone->contours[n] = GET_UShort(); + + n_points = 0; + if ( n_contours > 0 ) + n_points = zone->contours[n_contours - 1] + 1; + + + /*********************************************************************/ + /* reading the bytecode instructions */ + + n_ins = GET_UShort(); + load->face->root.glyph->control_len = n_ins; + + if ( n_points > load->left_points ) + { + FT_TRACE0(( "ERROR: Too many points in glyph %ld\n", load->glyph_index )); + error = TT_Err_Too_Many_Points; + goto Fail; + } + + FT_TRACE4(( "Instructions size : %d\n", n_ins )); + + if ( n_ins > face->max_profile.maxSizeOfInstructions ) + { + FT_TRACE0(( "ERROR: Too many instructions!\n" )); + error = TT_Err_Too_Many_Ins; + goto Fail; + } + + if (stream->cursor + n_ins > stream->limit) + { + FT_TRACE0(( "ERROR: Instruction count mismatch!\n" )); + error = TT_Err_Too_Many_Ins; + goto Fail; + } + + stream->cursor += n_ins; + + /*********************************************************************/ + /* reading the point tags */ + + { + FT_Byte* flag = load->zone.tags; + FT_Byte* limit = flag + n_points; + FT_Byte c, count; + + for (; flag < limit; flag++) + { + *flag = c = GET_Byte(); + if ( c & 8 ) + { + for ( count = GET_Byte(); count > 0; count-- ) + *++flag = c; + } + } + } + + /*********************************************************************/ + /* reading the X coordinates */ + + { + FT_Vector* vec = zone->org; + FT_Vector* limit = vec + n_points; + FT_Byte* flag = zone->tags; + FT_Pos x = 0; + + for ( ; vec < limit; vec++, flag++ ) + { + FT_Pos y = 0; + + if ( *flag & 2 ) + { + y = GET_Byte(); + if ((*flag & 16) == 0) y = -y; + } + else if ((*flag & 16) == 0) + y = GET_Short(); + + x += y; + vec->x = x; + } + } + + /*********************************************************************/ + /* reading the Y coordinates */ + + { + FT_Vector* vec = zone->org; + FT_Vector* limit = vec + n_points; + FT_Byte* flag = zone->tags; + FT_Pos x = 0; + + for ( ; vec < limit; vec++, flag++ ) + { + FT_Pos y = 0; + + if ( *flag & 4 ) + { + y = GET_Byte(); + if ((*flag & 32) == 0) y = -y; + } + else if ((*flag & 32) == 0) + y = GET_Short(); + + x += y; + vec->y = x; + } + } + + FORGET_Frame(); + + /*********************************************************************/ + /* Add shadow points */ + + /* Now add the two shadow points at n and n + 1. */ + /* We need the left side bearing and advance width. */ + + { + FT_Vector* pp1; + FT_Vector* pp2; + + /* pp1 = xMin - lsb */ + pp1 = zone->org + n_points; + pp1->x = load->bbox.xMin - load->left_bearing; + pp1->y = 0; + + /* pp2 = pp1 + aw */ + pp2 = pp1 + 1; + pp2->x = pp1->x + load->advance; + pp2->y = 0; + + /* clear the touch tags */ + for ( n = 0; n < n_points; n++ ) + zone->tags[n] &= FT_Curve_Tag_On; + + zone->tags[n_points ] = 0; + zone->tags[n_points + 1] = 0; + } + /* Note that we return two more points that are not */ + /* part of the glyph outline. */ + + zone->n_points = n_points; + zone->n_contours = n_contours; + n_points += 2; + + /*******************************************/ + /* now eventually scale and hint the glyph */ + + if (load->load_flags & FT_LOAD_NO_SCALE) + { + /* no scaling, just copy the orig arrays into the cur ones */ + org_to_cur( n_points, zone ); + } + else + { + FT_Vector* vec = zone->org; + FT_Vector* limit = vec + n_points; + FT_Fixed x_scale = load->size->root.metrics.x_scale; + FT_Fixed y_scale = load->size->root.metrics.y_scale; + + /* first scale the glyph points */ + for (; vec < limit; vec++) + { + vec->x = FT_MulFix( vec->x, x_scale ); + vec->y = FT_MulFix( vec->y, y_scale ); + } + + /* if hinting, round pp1, and shift the glyph accordingly */ + if ( !IS_HINTED(load->load_flags) ) + { + org_to_cur( n_points, zone ); + } + else + { + FT_Pos x = zone->org[n_points-2].x; + x = ((x + 32) & -64) - x; + translate_array( n_points, zone->org, x, 0 ); + + org_to_cur( n_points, zone ); + + zone->cur[n_points-1].x = (zone->cur[n_points-1].x + 32) & -64; + + } + } + + /* save glyph phantom points */ + if ( !load->preserve_pps ) + { + load->pp1 = zone->cur[n_points - 2]; + load->pp2 = zone->cur[n_points - 1]; + } + + return FT_Err_Ok; + + Fail: + FORGET_Frame(); + return error; + } + + + + + + + /*************************************************************************/ + /* */ + /* */ + /* load_opentype_glyph */ + /* */ + /* */ + /* Loads a given truetype glyph. Handles composites and uses a */ + /* T2_Loader object.. */ + /* */ + static + FT_Error load_opentype_glyph( T2_Loader* loader, + FT_UInt glyph_index ) + { + FT_Stream stream = loader->stream; + FT_Error error; + T2_Face face = loader->face; + FT_ULong offset; + FT_Int num_subglyphs = 0, contours_count; + FT_UInt index, num_points, num_contours, count; + FT_Fixed x_scale, y_scale; + FT_ULong ins_offset; + + /* check glyph index */ + index = glyph_index; + if ( index >= (TT_UInt)face->root.num_glyphs ) + { + error = TT_Err_Invalid_Glyph_Index; + goto Fail; + } + + loader->glyph_index = glyph_index; + num_contours = 0; + num_points = 0; + ins_offset = 0; + + x_scale = 0x10000; + y_scale = 0x10000; + if ( (loader->load_flags & FT_LOAD_NO_SCALE)==0 ) + { + x_scale = loader->size->root.metrics.x_scale; + y_scale = loader->size->root.metrics.y_scale; + } + + /* get horizontal metrics */ + { + FT_Short left_bearing; + FT_UShort advance_width; + + Get_HMetrics( face, index, + (FT_Bool)!(loader->load_flags & + FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH), + &left_bearing, + &advance_width ); + + loader->left_bearing = left_bearing; + loader->advance = advance_width; + } + + /* load glyph header */ + offset = face->glyph_locations[index]; + count = 0; + if (index < (TT_UInt)face->num_locations-1) + count = face->glyph_locations[index+1] - offset; + + + if (count == 0) + { + /* as described by Frederic Loyer, these are spaces, and */ + /* not the unknown glyph. */ + loader->bbox.xMin = 0; + loader->bbox.xMax = 0; + loader->bbox.yMin = 0; + loader->bbox.yMax = 0; + + loader->pp1.x = 0; + loader->pp2.x = loader->advance; + + if ( (loader->load_flags & FT_LOAD_NO_SCALE)==0 ) + loader->pp2.x = FT_MulFix( loader->pp2.x, x_scale ); + + goto Load_End; + } + + offset = loader->glyf_offset + offset; + + /* read first glyph header */ + if ( FILE_Seek( offset ) || ACCESS_Frame( 10L ) ) + goto Fail; + + contours_count = GET_Short(); + + loader->bbox.xMin = GET_Short(); + loader->bbox.yMin = GET_Short(); + loader->bbox.xMax = GET_Short(); + loader->bbox.yMax = GET_Short(); + + FORGET_Frame(); + + FT_TRACE6(( "Glyph %ld\n", index )); + FT_TRACE6(( " # of contours : %d\n", num_contours )); + FT_TRACE6(( " xMin: %4d xMax: %4d\n", loader->bbox.xMin, + loader->bbox.xMax )); + FT_TRACE6(( " yMin: %4d yMax: %4d\n", loader->bbox.yMin, + loader->bbox.yMax )); + FT_TRACE6(( "-" )); + + count -= 10; + + if ( contours_count > loader->left_contours ) + { + FT_TRACE0(( "ERROR: Too many contours for glyph %ld\n", index )); + error = TT_Err_Too_Many_Contours; + goto Fail; + } + + loader->pp1.x = loader->bbox.xMin - loader->left_bearing; + loader->pp1.y = 0; + loader->pp2.x = loader->pp1.x + loader->advance; + loader->pp2.y = 0; + + if ((loader->load_flags & FT_LOAD_NO_SCALE)==0) + { + loader->pp1.x = FT_MulFix( loader->pp1.x, x_scale ); + loader->pp2.x = FT_MulFix( loader->pp2.x, x_scale ); + } + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + /**********************************************************************/ + /* if it is a simple glyph, load it */ + if (contours_count >= 0) + { + FT_UInt num_base_points; + + error = Load_Simple( loader, count, contours_count, 0 ); + if ( error ) goto Fail; + + /* Note: We could have put the simple loader source there */ + /* but the code is fat enough already :-) */ + num_points = loader->zone.n_points; + num_contours = loader->zone.n_contours; + + num_base_points = loader->base.n_points; + { + FT_UInt k; + for ( k = 0; k < num_contours; k++ ) + loader->zone.contours[k] += num_base_points; + } + + loader->base.n_points += num_points; + loader->base.n_contours += num_contours; + + loader->zone.n_points = 0; + loader->zone.n_contours = 0; + + loader->left_points -= num_points; + loader->left_contours -= num_contours; + } + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + /************************************************************************/ + else /* otherwise, load a composite !! */ + { + /* for each subglyph, read composite header */ + T2_GlyphSlot glyph = loader->glyph; + FT_SubGlyph* subglyph = glyph->subglyphs + glyph->num_subglyphs; + + if (ACCESS_Frame(count)) goto Fail; + + num_subglyphs = 0; + do + { + TT_Fixed xx, xy, yy, yx; + FT_UInt total_subglyphs; + + /* grow the 'glyph->subglyphs' table if necessary */ + total_subglyphs = glyph->num_subglyphs + num_subglyphs; + if ( total_subglyphs >= glyph->max_subglyphs ) + { + FT_UInt new_max = glyph->max_subglyphs; + FT_Memory memory = loader->face->root.memory; + + while (new_max <= total_subglyphs) + new_max += 4; + + if ( REALLOC_ARRAY( glyph->subglyphs, glyph->max_subglyphs, + new_max, FT_SubGlyph ) ) + goto Fail; + + glyph->max_subglyphs = new_max; + subglyph = glyph->subglyphs + glyph->num_subglyphs + num_subglyphs; + } + + subglyph->arg1 = subglyph->arg2 = 0; + + subglyph->flags = GET_UShort(); + subglyph->index = GET_UShort(); + + /* read arguments */ + if (subglyph->flags & ARGS_ARE_WORDS) + { + subglyph->arg1 = GET_Short(); + subglyph->arg2 = GET_Short(); + } + else + { + subglyph->arg1 = GET_Char(); + subglyph->arg2 = GET_Char(); + } + + /* read transform */ + xx = yy = 0x10000; + xy = yx = 0; + + if (subglyph->flags & WE_HAVE_A_SCALE) + { + xx = (TT_Fixed)GET_Short() << 2; + yy = xx; + } + else if (subglyph->flags & WE_HAVE_AN_XY_SCALE) + { + xx = (TT_Fixed)GET_Short() << 2; + yy = (TT_Fixed)GET_Short() << 2; + } + else if (subglyph->flags & WE_HAVE_A_2X2) + { + xx = (TT_Fixed)GET_Short() << 2; + xy = (TT_Fixed)GET_Short() << 2; + yx = (TT_Fixed)GET_Short() << 2; + yy = (TT_Fixed)GET_Short() << 2; + } + + subglyph->transform.xx = xx; + subglyph->transform.xy = xy; + subglyph->transform.yx = yx; + subglyph->transform.yy = yy; + + subglyph++; + num_subglyphs++; + } + while (subglyph[-1].flags & MORE_COMPONENTS); + + FORGET_Frame(); + + /* if the flag FT_LOAD_NO_RECURSE is set, we return the subglyph */ + /* "as is" in the glyph slot (the client application will be */ + /* responsible for interpreting this data..) */ + if ( loader->load_flags & FT_LOAD_NO_RECURSE ) + { + /* set up remaining glyph fields */ + glyph->num_subglyphs += num_subglyphs; + glyph->format = ft_glyph_format_composite; + goto Load_End; + } + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + /*********************************************************************/ + /* Now, read each subglyph independently.. */ + { + FT_Int n, num_base_points, num_new_points; + + subglyph = glyph->subglyphs + glyph->num_subglyphs; + glyph->num_subglyphs += num_subglyphs; + + for ( n = 0; n < num_subglyphs; n++, subglyph++ ) + { + FT_Vector pp1, pp2; + FT_Pos x, y; + + pp1 = loader->pp1; + pp2 = loader->pp2; + + num_base_points = loader->base.n_points; + + error = load_truetype_glyph( loader, subglyph->index ); + if (error) goto Fail; + + if ( subglyph->flags & USE_MY_METRICS ) + { + pp1 = loader->pp1; + pp2 = loader->pp2; + } + else + { + loader->pp1 = pp1; + loader->pp2 = pp2; + } + + num_points = loader->base.n_points; + num_contours = loader->base.n_contours; + + num_new_points = num_points - num_base_points; + + /********************************************************/ + /* now perform the transform required for this subglyph */ + + if ( subglyph->flags & ( WE_HAVE_A_SCALE | + WE_HAVE_AN_XY_SCALE | + WE_HAVE_A_2X2 ) ) + { + FT_Vector* cur = loader->zone.cur; + FT_Vector* org = loader->zone.org; + FT_Vector* limit = cur + num_new_points; + + for ( ; cur < limit; cur++, org++ ) + { + TT_Pos nx, ny; + + nx = FT_MulFix( cur->x, subglyph->transform.xx ) + + FT_MulFix( cur->y, subglyph->transform.yx ); + + ny = FT_MulFix( cur->x, subglyph->transform.xy ) + + FT_MulFix( cur->y, subglyph->transform.yy ); + + cur->x = nx; + cur->y = ny; + + nx = FT_MulFix( org->x, subglyph->transform.xx ) + + FT_MulFix( org->y, subglyph->transform.yx ); + + ny = FT_MulFix( org->x, subglyph->transform.xy ) + + FT_MulFix( org->y, subglyph->transform.yy ); + + org->x = nx; + org->y = ny; + } + } + + /* apply offset */ + + if ( !(subglyph->flags & ARGS_ARE_XY_VALUES) ) + { + FT_Int k = subglyph->arg1; + FT_UInt l = subglyph->arg2; + + if ( k >= num_base_points || + l >= (TT_UInt)num_new_points ) + { + error = TT_Err_Invalid_Composite; + goto Fail; + } + + l += num_base_points; + + x = loader->base.cur[k].x - loader->base.cur[l].x; + y = loader->base.cur[k].y - loader->base.cur[l].y; + } + else + { + x = subglyph->arg1; + y = subglyph->arg2; + + if (!(loader->load_flags & FT_LOAD_NO_SCALE)) + { + x = FT_MulFix( x, x_scale ); + y = FT_MulFix( y, y_scale ); + + if ( subglyph->flags & ROUND_XY_TO_GRID ) + { + x = (x + 32) & -64; + y = (y + 32) & -64; + } + } + } + + translate_array( num_new_points, loader->zone.cur, x, y ); + cur_to_org( num_new_points, &loader->zone ); + } + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + /* we have finished loading all sub-glyphs, now, look for */ + /* instructions for this composite !! */ + + } + /* end of composite loading */ + } + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + Load_End: + error = FT_Err_Ok; + + Fail: + return error; + } + + + + + + static + void compute_glyph_metrics( T2_Loader* loader, + FT_UInt glyph_index ) + { + FT_UInt num_points = loader->base.n_points; + FT_UInt num_contours = loader->base.n_contours; + FT_BBox bbox; + T2_Face face = loader->face; + FT_Fixed x_scale, y_scale; + T2_GlyphSlot glyph = loader->glyph; + T2_Size size = loader->size; + + /* when a simple glyph was loaded, the value of */ + /* "base.n_points" and "base.n_contours" is 0, we must */ + /* take those in the "zone" instead.. */ + if ( num_points == 0 && num_contours == 0 ) + { + num_points = loader->zone.n_points; + num_contours = loader->zone.n_contours; + } + + x_scale = 0x10000; + y_scale = 0x10000; + if ( (loader->load_flags & FT_LOAD_NO_SCALE) == 0) + { + x_scale = size->root.metrics.x_scale; + y_scale = size->root.metrics.y_scale; + } + + if ( glyph->format != ft_glyph_format_composite ) + { + FT_UInt u; + for ( u = 0; u < num_points + 2; u++ ) + { + glyph->outline.points[u] = loader->base.cur[u]; + glyph->outline.tags [u] = loader->base.tags[u]; + } + + for ( u = 0; u < num_contours; u++ ) + glyph->outline.contours[u] = loader->base.contours[u]; + + /* glyph->outline.second_pass = TRUE; */ + glyph->outline.flags &= ~ft_outline_single_pass; + glyph->outline.n_points = num_points; + glyph->outline.n_contours = num_contours; + + /* translate array so that (0,0) is the glyph's origin */ + translate_array( (TT_UShort)(num_points + 2), + glyph->outline.points, + -loader->pp1.x, + 0 ); + + FT_Outline_Get_CBox( &glyph->outline, &bbox ); + + if ( IS_HINTED(loader->load_flags) ) + { + /* grid-fit the bounding box */ + bbox.xMin &= -64; + bbox.yMin &= -64; + bbox.xMax = (bbox.xMax + 63) & -64; + bbox.yMax = (bbox.yMax + 63) & -64; + } + } + else + bbox = loader->bbox; + + /* get the device-independent scaled horizontal metrics */ + /* take care of fixed-pitch fonts... */ + { + FT_Pos left_bearing; + FT_Pos advance; + + left_bearing = loader->left_bearing; + advance = loader->advance; + + /* the flag FT_LOAD_NO_ADVANCE_CHECK was introduced to */ + /* correctly support DynaLab fonts, who have an incorrect */ + /* "advance_Width_Max" field !! It is used, to my knowledge */ + /* exclusively in the X-TrueType font server.. */ + /* */ + if ( face->postscript.isFixedPitch && + (loader->load_flags & FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH) == 0 ) + advance = face->horizontal.advance_Width_Max; + + if ( !(loader->load_flags & FT_LOAD_NO_SCALE) ) + { + left_bearing = FT_MulFix( left_bearing, x_scale ); + advance = FT_MulFix( advance, x_scale ); + } + + glyph->metrics2.horiBearingX = left_bearing; + glyph->metrics2.horiAdvance = advance; + } + + glyph->metrics.horiBearingX = bbox.xMin; + glyph->metrics.horiBearingY = bbox.yMax; + glyph->metrics.horiAdvance = loader->pp2.x - loader->pp1.x; + + /* Now take care of vertical metrics. In the case where there is */ + /* no vertical information within the font (relatively common), make */ + /* up some metrics by `hand'... */ + + { + FT_Short top_bearing; /* vertical top side bearing (EM units) */ + FT_UShort advance_height; /* vertical advance height (EM units) */ + + FT_Pos left; /* scaled vertical left side bearing */ + FT_Pos Top; /* scaled original vertical top side bearing */ + FT_Pos top; /* scaled vertical top side bearing */ + FT_Pos advance; /* scaled vertical advance height */ + + + /* Get the unscaled `tsb' and `ah' */ + if ( face->vertical_info && + face->vertical.number_Of_VMetrics > 0 ) + { + /* Don't assume that both the vertical header and vertical */ + /* metrics are present in the same font :-) */ + + T2_Get_Metrics( (TT_HoriHeader*)&face->vertical, + glyph_index, + &top_bearing, + &advance_height ); + } + else + { + /* Make up the distances from the horizontal header.. */ + + /* NOTE: The OS/2 values are the only `portable' ones, */ + /* which is why we use them, when there is an */ + /* OS/2 table in the font. Otherwise, we use the */ + /* values defined in the horizontal header.. */ + /* */ + /* NOTE2: The sTypoDescender is negative, which is why */ + /* we compute the baseline-to-baseline distance */ + /* here with: */ + /* ascender - descender + linegap */ + /* */ + if ( face->os2.version != 0xFFFF ) + { + top_bearing = face->os2.sTypoLineGap / 2; + advance_height = (TT_UShort)(face->os2.sTypoAscender - + face->os2.sTypoDescender + + face->os2.sTypoLineGap); + } + else + { + top_bearing = face->horizontal.Line_Gap / 2; + advance_height = (TT_UShort)(face->horizontal.Ascender + + face->horizontal.Descender + + face->horizontal.Line_Gap); + } + } + + /* We must adjust the top_bearing value from the bounding box given + in the glyph header to te bounding box calculated with + TT_Get_Outline_BBox() */ + + /* scale the metrics */ + if ( !(loader->load_flags & FT_LOAD_NO_SCALE) ) + { + Top = FT_MulFix( top_bearing, y_scale ); + top = FT_MulFix( top_bearing + loader->bbox.yMax, y_scale ) + - bbox.yMax; + advance = FT_MulFix( advance_height, y_scale ); + } + else + { + Top = top_bearing; + top = top_bearing + loader->bbox.yMax - bbox.yMax; + advance = advance_height; + } + + glyph->metrics2.vertBearingY = Top; + glyph->metrics2.vertAdvance = advance; + + /* XXX: for now, we have no better algorithm for the lsb, but it */ + /* should work fine. */ + /* */ + left = ( bbox.xMin - bbox.xMax ) / 2; + + /* grid-fit them if necessary */ + if ( IS_HINTED(loader->load_flags) ) + { + left &= -64; + top = (top + 63) & -64; + advance = (advance + 32) & -64; + } + + glyph->metrics.vertBearingX = left; + glyph->metrics.vertBearingY = top; + glyph->metrics.vertAdvance = advance; + } + + /* Adjust advance width to the value contained in the hdmx table. */ + if ( !face->postscript.isFixedPitch && size && + IS_HINTED(loader->load_flags) ) + { + FT_Byte* widths = Get_Advance_Widths( face, + size->root.metrics.x_ppem ); + if ( widths ) + glyph->metrics.horiAdvance = widths[glyph_index] << 6; + } + + /* set glyph dimensions */ + glyph->metrics.width = bbox.xMax - bbox.xMin; + glyph->metrics.height = bbox.yMax - bbox.yMin; + } + + + + + + + + + + + + + LOCAL_FUNC + FT_Error TT_Load_Glyph( T2_Size size, + T2_GlyphSlot glyph, + FT_UShort glyph_index, + FT_UInt load_flags ) + { + SFNT_Interface* sfnt; + T2_Face face; + FT_Stream stream; + FT_Memory memory; + FT_Error error; + T2_Loader loader; + FT_GlyphZone* zone; + + face = (TT_Face)glyph->face; + sfnt = (SFNT_Interface*)face->sfnt; + stream = face->root.stream; + memory = face->root.memory; + error = 0; + + if ( !size || (load_flags & FT_LOAD_NO_SCALE) || + (load_flags & FT_LOAD_NO_RECURSE )) + { + size = NULL; + load_flags |= FT_LOAD_NO_SCALE | + FT_LOAD_NO_HINTING | + FT_LOAD_NO_BITMAP; + } + + glyph->num_subglyphs = 0; + +#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS + /*********************************************************************/ + /* Try to load embedded bitmap if any */ + if ( size && (load_flags & FT_LOAD_NO_BITMAP) == 0 && sfnt->load_sbits ) + { + TT_SBit_Metrics metrics; + + error = sfnt->load_sbit_image( face, + size->root.metrics.x_ppem, + size->root.metrics.y_ppem, + glyph_index, + load_flags, + stream, + &glyph->bitmap, + &metrics ); + if ( !error ) + { + glyph->outline.n_points = 0; + glyph->outline.n_contours = 0; + + glyph->metrics.width = (FT_Pos)metrics.width << 6; + glyph->metrics.height = (FT_Pos)metrics.height << 6; + + glyph->metrics.horiBearingX = (FT_Pos)metrics.horiBearingX << 6; + glyph->metrics.horiBearingY = (FT_Pos)metrics.horiBearingY << 6; + glyph->metrics.horiAdvance = (FT_Pos)metrics.horiAdvance << 6; + + glyph->metrics.vertBearingX = (FT_Pos)metrics.vertBearingX << 6; + glyph->metrics.vertBearingY = (FT_Pos)metrics.vertBearingY << 6; + glyph->metrics.vertAdvance = (FT_Pos)metrics.vertAdvance << 6; + + glyph->format = ft_glyph_format_bitmap; + return error; + } + } +#endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */ + + if ( load_flags & FT_LOAD_NO_OUTLINE ) + return ( error ? error : TT_Err_Unavailable_Bitmap ); + + /* seek to the beginning of the glyph table. For Type 43 fonts */ + /* the table might be accessed from a Postscript stream or something */ + /* else... */ + error = face->goto_table( face, TTAG_glyf, stream, 0 ); + if (error) + { + FT_ERROR(( "TT.GLoad: could not access glyph table\n" )); + goto Exit; + } + + MEM_Set( &loader, 0, sizeof(loader) ); + + /* update the glyph zone bounds */ + zone = &((TT_Driver)face->root.driver)->zone; + error = FT_Update_GlyphZone( zone, + face->root.max_points, + face->root.max_contours ); + if (error) + { + FT_ERROR(( "TT.GLoad: could not update loader glyph zone\n" )); + goto Exit; + } + loader.base = *zone; + + loader.zone.n_points = 0; + loader.zone.n_contours = 0; + + /* clear all outline flags, except the "owner" one */ + glyph->outline.flags &= ft_outline_owner; + + if (size && size->root.metrics.y_ppem < 24 ) + glyph->outline.flags |= ft_outline_high_precision; + + /************************************************************************/ + /* let's initialise the rest of our loader now */ + loader.left_points = face->root.max_points; + loader.left_contours = face->root.max_contours; + loader.load_flags = load_flags; + + loader.face = face; + loader.size = size; + loader.glyph = glyph; + loader.stream = stream; + + loader.glyf_offset = FILE_Pos(); + + /* Main loading loop */ + glyph->format = ft_glyph_format_outline; + glyph->num_subglyphs = 0; + error = load_truetype_glyph( &loader, glyph_index ); + if (!error) + compute_glyph_metrics( &loader, glyph_index ); + + Exit: + return error; + } + + + +/* END */ diff --git a/src/cff/t2gload.h b/src/cff/t2gload.h new file mode 100644 index 000000000..012b7ac39 --- /dev/null +++ b/src/cff/t2gload.h @@ -0,0 +1,140 @@ +/***************************************************************************/ +/* */ +/* t2gload.h */ +/* */ +/* OpenType Glyph Loader (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. */ +/* */ +/***************************************************************************/ + + +#ifndef T2GLOAD_H +#define T2GLOAD_H + +#include + +#ifdef __cplusplus + extern "C" { +#endif + + typedef struct T2_Loader_ + { + T2_Face face; + T2_Size size; + T2_GlyphSlot glyph; + + FT_ULong load_flags; + FT_UInt glyph_index; + + FT_Stream stream; + FT_Int byte_len; + FT_Int left_points; + FT_Int left_contours; + + FT_BBox bbox; + FT_Int left_bearing; + FT_Int advance; + FT_Bool preserve_pps; + FT_Vector pp1; + FT_Vector pp2; + + FT_ULong glyf_offset; + + /* the zone where we load our glyphs */ + FT_GlyphZone base; + FT_GlyphZone zone; + + } T2_Loader; + + +#if 0 + /*************************************************************************/ + /* */ + /* */ + /* T2_Get_Metrics */ + /* */ + /* */ + /* Returns the horizontal or vertical metrics in font units for a */ + /* given glyph. The metrics are the left side bearing (resp. top */ + /* side bearing) and advance width (resp. advance height). */ + /* */ + /* */ + /* header :: A pointer to either the horizontal or vertical metrics */ + /* structure. */ + /* */ + /* index :: The glyph index. */ + /* */ + /* */ + /* bearing :: The bearing, either left side or top side. */ + /* */ + /* advance :: The advance width resp. advance height. */ + /* */ + /* */ + /* This function will much probably move to another component in the */ + /* near future, but I haven't decided which yet. */ + /* */ + LOCAL_DEF + void T2_Get_Metrics( TT_HoriHeader* header, + FT_UInt index, + FT_Short* bearing, + FT_UShort* advance ); + + + /*************************************************************************/ + /* */ + /* */ + /* T2_Load_Glyph */ + /* */ + /* */ + /* A function used to load a single glyph within a given glyph slot, */ + /* for a given size. */ + /* */ + /* */ + /* glyph :: A handle to a target slot object where the glyph */ + /* will be loaded. */ + /* */ + /* size :: A handle to the source face size at which the glyph */ + /* must be scaled/loaded. */ + /* */ + /* glyph_index :: The index of the glyph in the font file. */ + /* */ + /* load_flags :: A flag indicating what to load for this glyph. The */ + /* FT_LOAD_XXX constants can be used to control the */ + /* glyph loading process (e.g., whether the outline */ + /* should be scaled, whether to load bitmaps or not, */ + /* whether to hint the outline, etc). */ + /* */ + /* result :: A set of bit flags indicating the type of data that */ + /* was loaded in the glyph slot (outline or bitmap, */ + /* etc). */ + /* */ + /* You can set this field to 0 if you don't want this */ + /* information. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + LOCAL_DEF + FT_Error T2_Load_Glyph( T2_Size size, + T2_GlyphSlot glyph, + FT_UShort glyph_index, + FT_UInt load_flags ); +#endif + +#ifdef __cplusplus + } +#endif + + +#endif /* T2GLOAD_H */ + + +/* END */ diff --git a/src/cff/t2load.c b/src/cff/t2load.c new file mode 100644 index 000000000..b33aae587 --- /dev/null +++ b/src/cff/t2load.c @@ -0,0 +1,292 @@ +/***************************************************************************/ +/* */ +/* t2load.h */ +/* */ +/* TrueType glyph data/program tables loader (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. */ +/* */ +/***************************************************************************/ + + +#include +#include +#include + +#include +#include +#include +#include +#include + +#undef FT_COMPONENT +#define FT_COMPONENT trace_ttload + + /* read a CFF offset from memory */ + LOCAL_FUNC + FT_ULong T2_Get_Offset( FT_Byte* p, + FT_Byte off_size ) + { + FT_ULong result; + for ( result = 0; off_size > 0; off_size-- ) + result = (result <<= 8) | *p++; + return result; + } + + +#if 0 + /* read a CFF offset from a stream */ + LOCAL_FUNC + FT_ULong T2_Read_Offset( FT_Byte off_size, + FT_Stream stream ) + { + FT_Byte bytes[4]; + FT_Byte* p; + FT_ULong result; + + if (off_size > 4) + off_size = 4; + + /* first of all, read or access the bytes - this should really go */ + /* in "src/base/ftstream.c", but there are great chances that it will */ + /* never be used elsewhere, so.. */ + if (stream->read) + { + p = bytes; + if ( stream->read( stream, stream->pos, (char*)bytes, off_size ) != off_size ) + goto Fail; + } + else + { + p = (FT_Byte*)stream->base + stream->pos; + if (p+off_size-1 >= (FT_Byte*)stream->limit) + goto Fail; + } + + result = 0; + while (off_size > 0) + { + result = (result <<= 8) | *p++; + off_size--; + } + stream->pos += off_size; + return result; + + Fail: + FT_ERROR(( "T2_Read_Offset:" )); + FT_ERROR(( " invalid i/o, pos = 0x%lx, size = 0x%lx", + stream->pos, stream->size )); + return 0; + } +#endif + + /* return the memory address of a CFF index's element, when the index */ + /* is already loaded in memory.. */ + + LOCAL_FUNC + FT_Error T2_Access_Element( CFF_Index* cff_index, + FT_UInt element, + FT_Byte* *pbytes, + FT_ULong *pbyte_len ) + { + FT_Error error; + + if (cff_index && cff_index->bytes && element < (FT_UInt)cff_index->count) + { + FT_ULong off1, off2; + FT_Byte offsize = cff_index->off_size; + FT_Byte* p = cff_index->bytes + 3 + element*offsize; + FT_Byte* limit = cff_index->bytes + cff_index->data_offset; + + /* read element offset */ + off1 = T2_Get_Offset(p,offsize); + + /* a value of 0 indicates no object !! */ + if (off1) + { + /* compute offset of next element - skip empty elements */ + do + { + p += offsize; + off2 = T2_Get_Offset(p,offsize); + } + while (off2 == 0 && p < limit); + + if (p >= limit) + off1 = 0; + } + + *pbytes = 0; + *pbyte_len = 0; + if (off1) + { + *pbytes = cff_index->bytes + cff_index->data_offset + off1 - 1; + *pbyte_len = off2 - off1; + } + error = 0; + } + else + error = FT_Err_Invalid_Argument; + + return error; + } + + + LOCAL_FUNC + + LOCAL_FUNC + FT_Error T2_Read_CFF_Index( CFF_Index* index, + FT_Stream stream ) + { + FT_Error error; + FT_ULong data_size; + + MEM_Set( index, 0, sizeof(*index) ); + index->file_offset = FILE_Pos(); + if ( !READ_UShort( index->count ) && + index->count > 0 ) + { + FT_Byte* p; + FT_Byte offsize; + + /* there is at least one element, read the offset size */ + /* then access the offset table to compute the index's total size */ + if ( READ_Byte( offsize ) ) + goto Exit; + + index->off_size = offsize; + index->data_offset = ((FT_Long)index->count + 1)*offsize; + + if (ACCESS_Frame( index->data_offset )) + goto Exit; + + /* now read element offset limit */ + p = (FT_Byte*)stream->cursor + index->data_offset - offsize; + data_size = T2_Get_Offset( p, offsize ); + + FORGET_Frame(); + + index->data_offset += 3; + index->total_size = index->data_offset + data_size; + + /* skip the data */ + (void)FILE_Skip( data_size ); + } + Exit: + return error; + } + + + LOCAL_FUNC + FT_Error T2_Load_CFF_Index( CFF_Index* index, + FT_Stream stream ) + { + FT_Error error; + + /* we begin by reading the index's data */ + error = T2_Read_CFF_Index( index, stream ); + if (!error && index->total_size > 0) + { + /* OK, read it from the file */ + if ( FILE_Seek( index->file_offset ) || + EXTRACT_Frame( index->total_size, index->bytes ) ) + goto Exit; + + /* done !! */ + } + Exit: + return error; + } + + + LOCAL_FUNC + void T2_Done_CFF_Index( CFF_Index* index, + FT_Stream stream ) + { + if (index->bytes) + RELEASE_Frame( index->bytes ); + + MEM_Set( index, 0, sizeof(*index) ); + } + + + LOCAL_FUNC + FT_Error T2_Load_CFF_Font( FT_Stream stream, + CFF_Font* font ) + { + static const FT_Frame_Field cff_header_fields[] = { + FT_FRAME_START(4), + FT_FRAME_BYTE( CFF_Font, version_major ), + FT_FRAME_BYTE( CFF_Font, version_minor ), + FT_FRAME_BYTE( CFF_Font, header_size ), + FT_FRAME_BYTE( CFF_Font, absolute_offsize ), + FT_FRAME_END }; + + FT_Error error; + + MEM_Set( font, 0, sizeof(*font) ); + font->stream = stream; + font->memory = stream->memory; + + /* read CFF font header */ + if ( READ_Fields( cff_header_fields, font ) ) + goto Exit; + + /* check format */ + if ( font->version_major != 1 || + font->header_size < 4 || + font->absolute_offsize > 4 ) + { + FT_ERROR(( "incorrect CFF font header !!\n" )); + error = FT_Err_Unknown_File_Format; + goto Exit; + } + + /* skip the rest of the header */ + (void)FILE_Skip( font->header_size - 4 ); + + /* read the name, top dict, strong and global subrs index */ + error = T2_Load_CFF_Index( &font->name_index, stream ) || + T2_Load_CFF_Index( &font->top_dict_index, stream ) || + T2_Read_CFF_Index( &font->string_index, stream ) || + T2_Load_CFF_Index( &font->global_subrs_index, stream ); + if (error) goto Exit; + + /* well, we don't really forget the "disable" fonts.. */ + font->num_faces = font->name_index.count; + + Exit: + return error; + } + + LOCAL_FUNC + void T2_Done_CFF_Font( CFF_Font* font ) + { + FT_Stream stream = font->stream; + + T2_Done_CFF_Index( &font->global_subrs_index, stream ); + T2_Done_CFF_Index( &font->string_index, stream ); + T2_Done_CFF_Index( &font->top_dict_index, stream ); + T2_Done_CFF_Index( &font->name_index, stream ); + } + + + + /***********************************************************************/ + /***********************************************************************/ + /***********************************************************************/ + /***** *****/ + /***** TYPE 2 TABLES DECODING.. *****/ + /***** *****/ + /***********************************************************************/ + /***********************************************************************/ + /***********************************************************************/ + +/* END */ diff --git a/src/cff/t2load.h b/src/cff/t2load.h new file mode 100644 index 000000000..720f05f10 --- /dev/null +++ b/src/cff/t2load.h @@ -0,0 +1,36 @@ +/***************************************************************************/ +/* */ +/* t2load.h */ +/* */ +/* OpenType glyph data/program tables loader (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. */ +/* */ +/***************************************************************************/ + + +#ifndef T2LOAD_H +#define T2LOAD_H + +#include + +#ifdef __cplusplus + extern "C" { +#endif + +#ifdef __cplusplus + } +#endif + + +#endif /* T2LOAD_H */ + + +/* END */ diff --git a/src/cff/t2objs.c b/src/cff/t2objs.c new file mode 100644 index 000000000..10fc38ec5 --- /dev/null +++ b/src/cff/t2objs.c @@ -0,0 +1,333 @@ +/***************************************************************************/ +/* */ +/* ttobjs.c */ +/* */ +/* Objects manager (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. */ +/* */ +/***************************************************************************/ + + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +/* required by tracing mode */ +#undef FT_COMPONENT +#define FT_COMPONENT trace_ttobjs + + + /*************************************************************************/ + /* */ + /* GLYPH ZONE FUNCTIONS */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* */ + /* T2_Init_Face */ + /* */ + /* */ + /* Initializes a given TrueType face object. */ + /* */ + /* */ + /* resource :: The source font resource. */ + /* face_index :: The index of the font face in the resource. */ + /* face :: The newly built face object. */ + /* */ + /* */ + /* TrueType error code. 0 means success. */ + /* */ + LOCAL_DEF + FT_Error T2_Init_Face( FT_Stream stream, + T2_Face face, + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params ) + { + TT_Error error; + FT_Driver sfnt_driver; + SFNT_Interface* sfnt; + + sfnt_driver = FT_Get_Driver( face->root.driver->library, "sfnt" ); + if (!sfnt_driver) goto Bad_Format; + + sfnt = (SFNT_Interface*)(sfnt_driver->interface.format_interface); + if (!sfnt) goto Bad_Format; + + /* create input stream from resource */ + if ( FILE_Seek(0) ) + goto Exit; + + /* check that we have a valid TrueType file */ + error = sfnt->init_face( stream, face, face_index, num_params, params ); + if (error) goto Exit; + + /* We must also be able to accept Mac/GX fonts, as well as OT ones */ + if ( face->format_tag != 0x4f54544f ) /* OpenType/CFF font */ + { + FT_TRACE2(( "[not a valid OpenType/CFF font]" )); + goto Bad_Format; + } + + /* If we're performing a simple font format check, exit immediately */ + if ( face_index < 0 ) + return FT_Err_Ok; + + /* Load font directory */ + error = sfnt->load_face( stream, face, face_index, num_params, params ); + if ( error ) goto Exit; + + Exit: + return error; + Bad_Format: + error = FT_Err_Unknown_File_Format; + goto Exit; + } + + + + /*************************************************************************/ + /* */ + /* */ + /* T2_Done_Face */ + /* */ + /* */ + /* Finalizes a given face object. */ + /* */ + /* */ + /* face :: A pointer to the face object to destroy. */ + /* */ + LOCAL_DEF + void T2_Done_Face( T2_Face face ) + { +#if 0 + FT_Memory memory = face->root.memory; + FT_Stream stream = face->root.stream; +#endif + SFNT_Interface* sfnt = face->sfnt; + + if (sfnt) + sfnt->done_face(face); + + /* XXXXX: TO DO */ + } + + + /*************************************************************************/ + /* */ + /* SIZE FUNCTIONS */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* */ + /* T2_Init_Size */ + /* */ + /* */ + /* Initializes a new OpenType size object. */ + /* */ + /* */ + /* size :: A handle to the size object. */ + /* */ + /* */ + /* TrueType error code. 0 means success. */ + /* */ + LOCAL_DEF + FT_Error T2_Init_Size( T2_Size size ) + { + UNUSED(size); + return 0; + } + + + /*************************************************************************/ + /* */ + /* */ + /* T2_Done_Size */ + /* */ + /* */ + /* The OpenType size object finalizer. */ + /* */ + /* */ + /* size :: A handle to the target size object. */ + /* */ + LOCAL_FUNC + void T2_Done_Size( T2_Size size ) + { + UNUSED(size); + } + + + /*************************************************************************/ + /* */ + /* */ + /* T2_Reset_Size */ + /* */ + /* */ + /* Resets a OpenType size when resolutions and character dimensions */ + /* have been changed. */ + /* */ + /* */ + /* size :: A handle to the target size object. */ + /* */ + LOCAL_DEF + FT_Error T2_Reset_Size( T2_Size size ) + { + T2_Face face = (T2_Face)size->face; + FT_Size_Metrics* metrics = &size->metrics; + FT_Error error = FT_Err_Ok; + + if ( metrics->x_ppem < 1 || metrics->y_ppem < 1 ) + return FT_Err_Invalid_Argument; + + /* Compute root ascender, descender, test height, and max_advance */ + metrics->ascender = ( FT_MulFix( face->root.ascender, + metrics->y_scale ) + 32 ) & -64; + + metrics->descender = ( FT_MulFix( face->root.descender, + metrics->y_scale ) + 32 ) & -64; + + metrics->height = ( FT_MulFix( face->root.height, + metrics->y_scale ) + 32 ) & -64; + + metrics->max_advance = ( FT_MulFix( face->root.max_advance_width, + metrics->x_scale ) + 32 ) & -64; + return error; + } + + + /*************************************************************************/ + /* */ + /* */ + /* T2_Init_GlyphSlot */ + /* */ + /* */ + /* The OpenType glyph slot initializer. */ + /* */ + /* */ + /* slot :: The glyph record to build. */ + /* */ + /* */ + /* TrueType error code. 0 means success. */ + /* */ + LOCAL_FUNC + FT_Error T2_Init_GlyphSlot( T2_GlyphSlot slot ) + { + /* allocate the outline space */ + FT_Face face = slot->face; + FT_Library library = face->driver->library; + + FT_TRACE4(( "TT.Init_GlyphSlot: Creating outline maxp = %d, maxc = %d\n", + face->max_points, face->max_contours )); + + return FT_Outline_New( library, + face->max_points + 2, + face->max_contours, + &slot->outline ); + } + + + /*************************************************************************/ + /* */ + /* */ + /* TT_Done_GlyphSlot */ + /* */ + /* */ + /* The OpenType glyph slot finalizer. */ + /* */ + /* */ + /* slot :: A handle to the glyph slot object. */ + /* */ + LOCAL_FUNC + void T2_Done_GlyphSlot( T2_GlyphSlot slot ) + { + FT_Library library = slot->face->driver->library; + FT_Memory memory = library->memory; + + if (slot->flags & ft_glyph_own_bitmap) + FREE( slot->bitmap.buffer ); + + FT_Outline_Done( library, &slot->outline ); + return; + } + + + /*************************************************************************/ + /* */ + /* */ + /* T2_Init_Driver */ + /* */ + /* */ + /* Initializes a given OpenType driver object. */ + /* */ + /* */ + /* driver :: A handle to the target driver object. */ + /* */ + /* */ + /* TrueType error code. 0 means success. */ + /* */ + LOCAL_FUNC + FT_Error T2_Init_Driver( T2_Driver driver ) + { + FT_Memory memory = driver->root.memory; + FT_Error error; + + error = FT_New_GlyphZone( memory, 0, 0, &driver->zone ); + if (error) return error; + + /* init extension registry if needed */ +#ifdef T2_CONFIG_OPTION_EXTEND_ENGINE + return TT_Init_Extensions( driver ); +#else + return FT_Err_Ok; +#endif + } + + + /*************************************************************************/ + /* */ + /* */ + /* TT_Done_Driver */ + /* */ + /* */ + /* Finalizes a given TrueType driver. */ + /* */ + /* */ + /* driver :: A handle to the target TrueType driver. */ + /* */ + LOCAL_FUNC + void T2_Done_Driver( T2_Driver driver ) + { + /* destroy extensions registry if needed */ +#ifdef T2_CONFIG_OPTION_EXTEND_ENGINE + TT_Done_Extensions( driver ); +#endif + + /* remove the loading glyph zone */ + FT_Done_GlyphZone( &driver->zone ); + } + + +/* END */ diff --git a/src/cff/t2objs.h b/src/cff/t2objs.h new file mode 100644 index 000000000..aed60fc05 --- /dev/null +++ b/src/cff/t2objs.h @@ -0,0 +1,141 @@ +/***************************************************************************/ +/* */ +/* t2objs.h */ +/* */ +/* Objects manager (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. */ +/* */ +/***************************************************************************/ + + +#ifndef T2OBJS_H +#define T2OBJS_H + + +#include +#include +#include + + +#ifdef __cplusplus + extern "C" { +#endif + + + /*************************************************************************/ + /* */ + /* */ + /* T2_Driver */ + /* */ + /* */ + /* A handle to an OpenType driver object. */ + /* */ + typedef struct T2_DriverRec_* T2_Driver; + + typedef TT_Face T2_Face; + + /*************************************************************************/ + /* */ + /* */ + /* T2_Size */ + /* */ + /* */ + /* A handle to an OpenType size object. */ + /* */ + typedef FT_Size T2_Size; + + + /*************************************************************************/ + /* */ + /* */ + /* T2_GlyphSlot */ + /* */ + /* */ + /* A handle to an OpenType glyph slot object. */ + /* */ + /* */ + /* This is a direct typedef of FT_GlyphSlot, as there is nothing */ + /* specific about the OpenType glyph slot. */ + /* */ + typedef FT_GlyphSlot T2_GlyphSlot; + + + + /*************************************************************************/ + /* */ + /* Subglyph transformation record. */ + /* */ + typedef struct T2_Transform_ + { + FT_Fixed xx, xy; /* transformation matrix coefficients */ + FT_Fixed yx, yy; + FT_F26Dot6 ox, oy; /* offsets */ + + } T2_Transform; + + + /***********************************************************************/ + /* */ + /* TrueType driver class. */ + /* */ + typedef struct T2_DriverRec_ + { + FT_DriverRec root; + FT_GlyphZone zone; /* glyph loader points zone */ + + void* extension_component; + + } T2_DriverRec; + + + /*************************************************************************/ + /* Face Funcs */ + + LOCAL_DEF FT_Error T2_Init_Face( FT_Stream stream, + T2_Face face, + TT_Int face_index, + TT_Int num_params, + FT_Parameter* params ); + + LOCAL_DEF void T2_Done_Face( T2_Face face ); + + + /*************************************************************************/ + /* Size funcs */ + + LOCAL_DEF FT_Error T2_Init_Size ( T2_Size size ); + LOCAL_DEF void T2_Done_Size ( T2_Size size ); + LOCAL_DEF FT_Error T2_Reset_Size( T2_Size size ); + + + /*************************************************************************/ + /* GlyphSlot funcs */ + + LOCAL_DEF FT_Error T2_Init_GlyphSlot( T2_GlyphSlot slot ); + LOCAL_DEF void T2_Done_GlyphSlot( T2_GlyphSlot slot ); + + + /*************************************************************************/ + /* Driver funcs */ + + LOCAL_DEF FT_Error T2_Init_Driver( T2_Driver driver ); + LOCAL_DEF void T2_Done_Driver( T2_Driver driver ); + + +#ifdef __cplusplus + } +#endif + + +#endif /* T2OBJS_H */ + + +/* END */ diff --git a/src/cff/t2parse.c b/src/cff/t2parse.c new file mode 100644 index 000000000..752020959 --- /dev/null +++ b/src/cff/t2parse.c @@ -0,0 +1,514 @@ +#include +#include + +#define T2_Err_Stack_Underflow FT_Err_Invalid_Argument +#define T2_Err_Syntax_Error FT_Err_Invalid_Argument + + enum + { + t2_kind_none = 0, + t2_kind_num, + t2_kind_fixed, + t2_kind_string, + t2_kind_bool, + t2_kind_delta, + t2_kind_callback, + + t2_kind_max /* do not remove */ + }; + + + /* now generate handlers for the most simple fields */ + typedef FT_Error (*T2_Field_Reader)( T2_Parser* parser ); + + typedef struct T2_Field_Handler_ + { + int kind; + int code; + FT_UInt offset; + FT_Byte size; + T2_Field_Reader reader; + FT_UInt array_max; + FT_UInt count_offset; + + } T2_Field_Handler; + + + + + + LOCAL_FUNC + void T2_Parser_Init( T2_Parser* parser, FT_UInt code, void* object ) + { + MEM_Set(parser,0,sizeof(*parser)); + parser->top = parser->stack; + parser->object_code = code; + parser->object = object; + } + + + + + + + + /* reads an integer */ + static + FT_Long parse_t2_integer( FT_Byte* start, + FT_Byte* limit ) + { + FT_Byte* p = start; + FT_Int v = *p++; + FT_Long val = 0; + + if (v == 28) + { + if ( p+2 > limit ) goto Bad; + val = ((FT_Long)p[0] << 8) | p[1]; + p += 2; + } + else if (v == 29) + { + if ( p+4 > limit ) goto Bad; + val = ((FT_Long)p[0] << 24) | + ((FT_Long)p[1] << 16) | + ((FT_Long)p[2] << 8) | p[3]; + p += 4; + } + else if (v < 247) + { + val = v - 139; + } + else if (v < 251) + { + if (p+1 > limit) goto Bad; + val = (v-247)*256 + p[0]+108; + p ++; + } + else + { + if (p+1 > limit) goto Bad; + val = -(v-251)*256 - p[0]-108; + p ++; + } + + Exit: + return val; + + Bad: + val = 0; + goto Exit; + } + + + /* reads a real */ + static + FT_Fixed parse_t2_real( FT_Byte* start, + FT_Byte* limit, + FT_Int power_ten ) + { + FT_Byte* p = start; + FT_Long num, divider, result, exp; + FT_Int sign = 0, exp_sign = 0; + FT_Byte nib; + FT_Byte phase; + + result = 0; + num = 0; + divider = 1; + + /* first of all, read the integer part */ + phase = 4; + p--; + for (;;) + { + /* read one nibble at a time */ + if (phase && ++p >= limit) goto Bad; + nib = (p[0] >> phase) & 0xF; + phase = 4-phase; + + if (nib == 0xE) + sign = 1; + else if (nib > 9) + break; + else + result = result*10 + nib; + } + + /* read decimal part, if any */ + if (nib == 0xa) + for (;;) + { + /* read one nibble at a time */ + if (!phase && ++p >= limit) goto Bad; + phase = 4-phase; + nib = (p[0] >> phase) & 0xF; + + if (nib >= 10) + break; + + if (divider < 10000000L) + { + num = num*10 + nib; + divider *= 10; + } + } + + /* read exponent, if any */ + if (nib == 12) + { + exp_sign = 1; + nib = 11; + } + if (nib == 11) + { + exp = 0; + for (;;) + { + /* read one nibble at a time */ + if (!phase && ++p >= limit) goto Bad; + phase = 4-phase; + nib = (p[0] >> phase) & 0xF; + + if (nib >= 10) + break; + + exp = exp*10 + nib; + } + if (exp_sign) + exp = -exp; + + power_ten += exp; + } + + /* 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; + + Exit: + return result; + + Bad: + result = 0; + goto Exit; + } + + + /* reads a number, either integer or real */ + static + FT_Long t2_parse_num( FT_Byte** d ) + { + return ( **d == 30 ? (parse_t2_real ( d[0], d[1], 0 ) >> 16): + parse_t2_integer( d[0], d[1] ) ); + } + + /* reads a floating point number, either integer or real */ + static + FT_Fixed t2_parse_fixed( FT_Byte** d ) + { + return ( **d == 30 ? parse_t2_real( d[0], d[1], 0 ) : + parse_t2_integer( d[0], d[1] ) << 16 ); + } + + + + static + FT_Error parse_font_matrix( T2_Parser* parser ) + { + CFF_Top_Dict* dict = (CFF_Top_Dict*)parser->object; + FT_Matrix* matrix = &dict->font_matrix; + FT_Byte** data = parser->stack; + FT_Error error; + + error = T2_Err_Stack_Underflow; + if (parser->top >= parser->stack + 4) + { + matrix->xx = t2_parse_fixed( data++ ); + matrix->yx = t2_parse_fixed( data++ ); + matrix->xy = t2_parse_fixed( data++ ); + matrix->yy = t2_parse_fixed( data ); + error = 0; + } + return error; + } + + + static + FT_Error parse_font_bbox( T2_Parser* parser ) + { + CFF_Top_Dict* dict = (CFF_Top_Dict*)parser->object; + FT_BBox* bbox = &dict->font_bbox; + FT_Byte** data = parser->stack; + FT_Error error; + + error = T2_Err_Stack_Underflow; + if (parser->top >= parser->stack + 4) + { + bbox->xMin = t2_parse_fixed( data++ ); + bbox->yMin = t2_parse_fixed( data++ ); + bbox->xMax = t2_parse_fixed( data++ ); + bbox->yMax = t2_parse_fixed( data ); + error = 0; + } + return error; + } + + + static + FT_Error parse_private_dict( T2_Parser* parser ) + { + CFF_Top_Dict* dict = (CFF_Top_Dict*)parser->object; + FT_Byte** data = parser->stack; + FT_Error error; + + error = T2_Err_Stack_Underflow; + if (parser->top >= parser->stack + 2) + { + dict->private_offset = t2_parse_num( data++ ); + dict->private_size = t2_parse_num( data ); + error = 0; + } + return error; + } + + + static + FT_Error parse_cid_ros( T2_Parser* parser ) + { + CFF_Top_Dict* dict = (CFF_Top_Dict*)parser->object; + FT_Byte** data = parser->stack; + FT_Error error; + + error = T2_Err_Stack_Underflow; + if (parser->top >= parser->stack + 3) + { + dict->cid_registry = (FT_UInt)t2_parse_num( data++ ); + dict->cid_ordering = (FT_UInt)t2_parse_num( data++ ); + dict->cid_supplement = (FT_ULong)t2_parse_num( data ); + error = 0; + } + return error; + } + + + +#define T2_FIELD_NUM(code,name) T2_FIELD( code, name, t2_kind_num ) +#define T2_FIELD_FIXED(code,name) T2_FIELD( code, name, t2_kind_fixed ) +#define T2_FIELD_STRING(code,name) T2_FIELD( code, name, t2_kind_string ) +#define T2_FIELD_BOOL(code,name) T2_FIELD( code, name, t2_kind_bool ) +#define T2_FIELD_DELTA(code,name,max) T2_FIELD( code, name, t2_kind_delta ) + + +#define T2_REF(s,f) (((s*)0)->f) + +#define T2_FIELD_CALLBACK( code, name ) \ + { t2_kind_callback, code, 0, 0, parse_ ## name, 0, 0 }, + +#undef T2_FIELD +#define T2_FIELD( code, name, kind ) \ + { kind, code | T2CODE, \ + (FT_UInt)(char*)&T2_REF( T2TYPE, name ), \ + sizeof( T2_REF( T2TYPE, name ) ), \ + 0 }, + +#undef T2_FIELD_DELTA +#define T2_FIELD_DELTA( code, name, max ) \ + { t2_kind_delta, code | T2CODE, \ + (FT_UInt)(char*)&T2_REF( T2TYPE, name ), \ + sizeof( T2_REF( T2TYPE, name ) ), \ + 0, \ + max, (FT_UInt)(char*)&T2_REF( T2TYPE, num_ ## name ) }, + + +#define T2CODE_TOPDICT 0x1000 +#define T2CODE_PRIVATE 0x2000 + + static const T2_Field_Handler t2_field_handlers[] = + { + #include + { 0, 0, 0, 0, 0, 0, 0 } + }; + + + LOCAL_FUNC + FT_Error T2_Parser_Run( T2_Parser* parser, + FT_Byte* start, + FT_Byte* limit ) + { + FT_Byte* p; + FT_Error error = 0; + + parser->top = parser->stack; + parser->start = start; + parser->limit = limit; + parser->cursor = start; + + while (p < limit) + { + FT_Byte v = *p; + if ( v >= 27 || v != 31 ) + { + /* its a number, we'll push its position on the stack */ + if (parser->top - parser->stack >= T2_MAX_STACK_DEPTH) + goto Stack_Overflow; + + *parser->top ++ = p; + + /* now, skip it */ + if (v == 30) + { + /* skip real number */ + for (;;) + { + if (p >= limit) goto Syntax_Error; + v = p[0] >> 4; + if (v == 15) break; + v = p[0] & 0xF; + if (v == 15) break; + p++; + } + p++; + } + else if (v == 28) + p += 2; + else if (v == 29) + p += 4; + else if (v > 246) + p += 1; + } + else + { + /* this is not a number, hence it's an operator. Compute its code */ + /* and look for it in our current list.. */ + FT_UInt code; + FT_Int num_args = parser->top - parser->stack; + const T2_Field_Handler* field; + + /* first of all, a trivial check */ + if ( num_args < 1 ) goto Stack_Underflow; + + code = v; + if (v == 12) + { + /* two byte operator */ + p++; + code = 0x100 | p[0]; + } + code = code | parser->object_code; + + for ( field = t2_field_handlers; field->kind; field++ ) + { + if (field->code == code) + { + /* we found our field's handler, read it.. */ + FT_Long val; + FT_Byte* q = (FT_Byte*)parser->object + field->offset; + + switch (field->kind) + { + case t2_kind_bool: + case t2_kind_string: + case t2_kind_num: + val = t2_parse_num( parser->stack ); + goto Store_Number; + + case t2_kind_fixed: + val = t2_parse_fixed( parser->stack ); + + Store_Number: + switch (field->size) + { + case 1: *(FT_Byte*) q = (FT_Byte)val; break; + case 2: *(FT_Short*)q = (FT_Short)val; break; + default: *(FT_Long*)q = val; + } + break; + + + case t2_kind_delta: + { + FT_Byte* qcount = (FT_Byte*)parser->object + + field->count_offset; + + FT_Long val; + FT_Byte** data = parser->stack; + + if (num_args > field->array_max) + num_args = field->array_max; + + /* store count */ + *qcount = (FT_Byte)num_args; + + val = 0; + while (num_args > 0) + { + val += t2_parse_num( data++ ); + switch (field->size) + { + case 1: *(FT_Byte*) q = (FT_Byte)val; break; + case 2: *(FT_Short*)q = (FT_Short)val; break; + default: *(FT_Long*)q = val; + } + q += field->size; + num_args--; + } + } + break; + + default: /* callback */ + error = field->reader( parser ); + if (error) goto Exit; + } + /* clear stack */ + parser->top = parser->stack; + } + goto Found; /* exit loop */ + } + + /* this is an unknown operator, or it is unsupported, we will ignore */ + /* it for now... */ + + Found: + /* clear stack */ + parser->top = parser->stack; + } + p++; + } + Exit: + return error; + + Stack_Overflow: + error = FT_Err_Invalid_Argument; + goto Exit; + + Stack_Underflow: + error = FT_Err_Invalid_Argument; + goto Exit; + + Syntax_Error: + error = FT_Err_Invalid_Argument; + goto Exit; + + } + + + + + diff --git a/src/cff/t2parse.h b/src/cff/t2parse.h new file mode 100644 index 000000000..75aa48eb0 --- /dev/null +++ b/src/cff/t2parse.h @@ -0,0 +1,33 @@ +#ifndef T2PARSE_H +#define T2PARSE_H + +#include +#include + +#define T2_MAX_STACK_DEPTH 96 + + typedef struct T2_Parser_ + { + FT_Byte* start; + FT_Byte* limit; + FT_Byte* cursor; + + FT_Byte* stack[ T2_MAX_STACK_DEPTH+1 ]; + FT_Byte** top; + + FT_UInt object_code; + void* object; + + } T2_Parser; + + + LOCAL_DEF + void T2_Parser_Init( T2_Parser* parser, FT_UInt code, void* object ); + + + LOCAL_DEF + FT_Error T2_Parser_Run( T2_Parser* parser, + FT_Byte* start, + FT_Byte* limit ); + +#endif /* T2PARSE_H */ diff --git a/src/cff/t2tokens.h b/src/cff/t2tokens.h new file mode 100644 index 000000000..878f6c5cf --- /dev/null +++ b/src/cff/t2tokens.h @@ -0,0 +1,76 @@ + +#undef T2TYPE +#undef T2CODE +#define T2TYPE CFF_Top_Dict +#define T2CODE T2CODE_TOPDICT + + T2_FIELD_STRING ( 0, version ) + T2_FIELD_STRING ( 1, notice ) + T2_FIELD_STRING ( 0x100, copyright ) + T2_FIELD_STRING ( 2, full_name ) + T2_FIELD_STRING ( 3, family_name ) + T2_FIELD_STRING ( 4, weight ) + T2_FIELD_BOOL ( 0x101, is_fixed_pitch ) + T2_FIELD_FIXED ( 0x102, italic_angle ) + T2_FIELD_NUM ( 0x103, underline_position ) + T2_FIELD_NUM ( 0x104, underline_thickness ) + T2_FIELD_NUM ( 0x105, paint_type ) + T2_FIELD_NUM ( 0x106, charstring_type ) + T2_FIELD_CALLBACK( 0x107, font_matrix ) + T2_FIELD_NUM ( 13, unique_id ) + T2_FIELD_CALLBACK( 5, font_bbox ) + T2_FIELD_NUM ( 0x108, stroke_width ) + T2_FIELD_NUM ( 15, charset_offset ) + T2_FIELD_NUM ( 16, encoding_offset ) + T2_FIELD_NUM ( 17, charstrings_offset ) + T2_FIELD_CALLBACK( 18, private_dict ) + T2_FIELD_NUM ( 0x114, synthetic_base ) + T2_FIELD_STRING ( 0x115, postscript ) + T2_FIELD_STRING ( 0x116, base_font_name ) + +#if 0 + T2_FIELD_DELTA ( 0x117, base_font_blend, 16 ) + T2_FIELD_CALLBACK( 0x118, multiple_master ) + T2_FIELD_CALLBACK( 0x119, blend_axit_types ) +#endif + + T2_FIELD_CALLBACK( 0x11E, cid_ros ) + T2_FIELD_NUM ( 0x11F, cid_font_version ) + T2_FIELD_NUM ( 0x120, cid_font_revision ) + T2_FIELD_NUM ( 0x121, cid_font_type ) + T2_FIELD_NUM ( 0x122, cid_count ) + T2_FIELD_NUM ( 0x123, cid_uid_base ) + T2_FIELD_NUM ( 0x124, cid_fd_array_offset ) + T2_FIELD_NUM ( 0x125, cid_fd_select_offset ) + T2_FIELD_STRING ( 0x126, cid_font_name ) + +#if 0 + T2_FIELD_NUM ( 0x127, chameleon ) +#endif + +#undef T2TYPE +#undef T2CODE +#define T2TYPE CFF_Private +#define T2CODE T2CODE_PRIVATE + + T2_FIELD_DELTA( 6, blue_values, 14 ) + T2_FIELD_DELTA( 7, other_blues, 10 ) + T2_FIELD_DELTA( 8, family_blues, 14 ) + T2_FIELD_DELTA( 9, family_other_blues, 10 ) + T2_FIELD_FIXED( 0x109, blue_scale ) + T2_FIELD_NUM ( 0x10A, blue_shift ) + T2_FIELD_NUM ( 0x10B, blue_fuzz ) + T2_FIELD_NUM ( 10, standard_width ) + T2_FIELD_NUM ( 11, standard_height ) + T2_FIELD_DELTA( 0x10C, snap_widths, 13 ) + T2_FIELD_DELTA( 0x10D, snap_heights, 13 ) + T2_FIELD_BOOL ( 0x10E, force_bold ) + T2_FIELD_FIXED( 0x10F, force_bold_threshold ) + T2_FIELD_NUM ( 0x110, lenIV ) + T2_FIELD_NUM ( 0x111, language_group ) + T2_FIELD_FIXED( 0x112, expansion_factor ) + T2_FIELD_NUM ( 0x113, initial_random_seed ) + T2_FIELD_NUM ( 19, local_subrs_offset ) + T2_FIELD_NUM ( 20, default_width ) + T2_FIELD_NUM ( 21, nominal_width ) +