diff --git a/include/freetype/internal/internal.h b/include/freetype/internal/internal.h index 58003e900..a5a890ad0 100644 --- a/include/freetype/internal/internal.h +++ b/include/freetype/internal/internal.h @@ -40,8 +40,10 @@ #define FT_INTERNAL_CFF_TYPES_H #define FT_INTERNAL_FNT_TYPES_H -#define FT_INTERNAL_POSTSCRIPT_NAMES_H -#define FT_INTERNAL_POSTSCRIPT_AUX_H +#define FT_INTERNAL_POSTSCRIPT_NAMES_H +#define FT_INTERNAL_POSTSCRIPT_AUX_H +#define FT_INTERNAL_POSTSCRIPT_HINTS_H +#define FT_INTERNAL_POSTSCRIPT_GLOBALS_H #define FT_INTERNAL_AUTOHINT_H diff --git a/include/freetype/internal/psglobal.h b/include/freetype/internal/psglobal.h new file mode 100644 index 000000000..0749812bb --- /dev/null +++ b/include/freetype/internal/psglobal.h @@ -0,0 +1,139 @@ +#ifndef __PSGLOBALS_H__ +#define __PSGLOBALS_H__ + + /**********************************************************************/ + /**********************************************************************/ + /***** *****/ + /***** PUBLIC STRUCTURES & API *****/ + /***** *****/ + /**********************************************************************/ + /**********************************************************************/ + + /**************************************************************** + * + * @constant: PS_GLOBALS_MAX_BLUE_ZONES + * + * @description: + * the maximum number of blue zones in a font global hints + * structure. See @PS_Globals_BluesRec + */ +#define PS_GLOBALS_MAX_BLUE_ZONES 16 + + /**************************************************************** + * + * @constant: PS_GLOBALS_MAX_STD_WIDTHS + * + * @description: + * the maximum number of standard and snap widths in either the + * horizontal or vertical direction. See @PS_Globals_WidthsRec + */ +#define PS_GLOBALS_MAX_STD_WIDTHS 16 + + /**************************************************************** + * + * @type: PS_Globals + * + * @description: + * a handle to a @PS_GlobalsRec structure used to + * describe the global hints of a given font + */ + typedef struct PS_GlobalsRec_* PS_Globals; + + /**************************************************************** + * + * @struct: PS_Globals_BluesRec + * + * @description: + * a structure used to model the global blue zones of a given + * font + * + * @fields: + * count :: number of blue zones + * zones :: an array of (count*2) coordinates describing the zones + * + * count_family :: number of family blue zones + * zones_family :: an array of (count_family*2) coordinates describing + * the family blue zones + * + * scale :: the blue scale to be used (fixed float) + * shift :: the blue shift to be used + * fuzz :: the blue fuzz to be used + * + * @note: + * each blue zone is modeled by a (reference,overshoot) coordinate pair + * in the table. zones can be placed in any order.. + */ + typedef struct PS_Globals_BluesRec + { + FT_UInt count; + FT_Int16 zones[ 2*PS_GLOBALS_MAX_BLUE_ZONES ]; + + FT_UInt count_family; + FT_Int16 zones_family[ 2*PS_GLOBALS_MAX_BLUE_ZONES ]; + + FT_Fixed scale; + FT_Int16 shift; + FT_Int16 fuzz; + + } PS_Globals_BluesRec, *PS_Globals_Blues; + + + /**************************************************************** + * + * @type: PS_Global_Widths; + * + * @description: + * a handle to a @PS_Globals_WidthsRec structure used to model + * the global standard and snap widths in a given direction + */ + typedef struct PS_Globals_WidthsRec_* PS_Globals_Widths; + + + /**************************************************************** + * + * @struct: PS_Globals_WidthsRec + * + * @description: + * a structure used to model the global standard and snap widths + * in a given font + * + * @fields: + * count :: number of widths + * widths :: an array of 'count' widths in font units. + * + * @note: + * 'widths[0]' must be the standard width or height, while + * remaining elements of the array are snap widths or heights + */ + typedef struct PS_Globals_WidthsRec_ + { + FT_UInt count; + FT_Int16 widths[ PS_GLOBALS_MAX_STD_WIDTHS ]; + + } PS_Globals_WidthsRec; + + + /**************************************************************** + * + * @struct: PS_Globals_GlobalsRec + * + * @description: + * a structure used to model the global hints for a given font + * + * @fields: + * horizontal :: horizontal widths + * vertical :: vertical heights + * blues :: blue zones + */ + typedef struct PS_GlobalsRec_ + { + PS_Globals_WidthsRec horizontal; + PS_Globals_WidthsRec vertical; + PS_Globals_BluesRec blues; + + } PS_GlobalsRec; + + + /* */ + +#endif /* __PS_GLOBALS_H__ */ diff --git a/include/freetype/internal/pshints.h b/include/freetype/internal/pshints.h new file mode 100644 index 000000000..cc74f4d96 --- /dev/null +++ b/include/freetype/internal/pshints.h @@ -0,0 +1,419 @@ +/***************************************************************************/ +/* */ +/* pshints.h */ +/* */ +/* Interface to Postscript-specific (Type 1 and Type 2) hints */ +/* recorders. These are used to support native T1/T2 hints */ +/* in the "type1", "cid" and "cff" font drivers */ +/* */ +/* Copyright 2001 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 __PSHINTS_H__ +#define __PSHINTS_H__ + +FT_BEGIN_HEADER + + /**********************************************************************/ + /**********************************************************************/ + /***** *****/ + /***** PUBLIC TYPE 1 HINTS RECORDER *****/ + /***** *****/ + /**********************************************************************/ + /**********************************************************************/ + + /************************************************************************ + * + * @type: T1_Hints + * + * @description: + * this is a handle to an opaque structure used to record glyph + * hints from a Type 1 character glyph character string. + * + * the methods used to operate on this object are defined by the + * @T1_Hints_FuncsRec structure. Recording glyph hints is normally + * achieved through the following scheme: + * + * - open a new hint recording session by calling the "open" + * method. This will rewind the recorder and prepare it for + * new input + * + * - for each hint found in the glyph charstring, call the + * corresponding method ("stem", "stem3" or "reset"). + * note that these functions do not return an error code + * + * - close the recording session by calling the "close" method + * it will return an error code if the hints were invalid or + * something strange happened (e.g. memory shortage) + * + * the hints accumulated in the object can later be used by the + * Postscript hinter + */ + typedef struct T1_HintsRec_* T1_Hints; + + /************************************************************************ + * + * @type: T1_Hints_Funcs + * + * @description: + * a pointer to the @T1_Hints_FuncsRec structure that defines the + * API of a given @T1_Hints object + */ + typedef const struct T1_Hints_FuncsRec_* T1_Hints_Funcs; + + + /************************************************************************ + * + * @functype: T1_Hints_OpenFunc + * + * @description: + * a method of the @T1_Hints class used to prepare it for a new + * Type 1 hints recording session + * + * @input: + * hints :: handle to Type 1 hints recorder + * + * @note: + * You should always call the @T1_Hints_CloseFunc method in order + * to close an opened recording session + */ + typedef void (*T1_Hints_OpenFunc) ( T1_Hints hints ); + + /************************************************************************ + * + * @functype: T1_Hints_SetStemFunc + * + * @description: + * a method of the @T1_Hints class used to record a new horizontal or + * vertical stem. This corresponds to the Type 1 "hstem" and "vstem" + * operators + * + * @input: + * hints :: handle to Type 1 hints recorder + * dimension :: 0 for horizontal stems (hstem), 1 for vertical ones (vstem) + * coords :: array of 2 integers, used as (position,length) stem descriptor + * + * @note: + * use vertical coordinates (y) for horizontal stems (dim=0) + * use horizontal coordinates (x) for vertical stems (dim=1) + * + * "coords[0]" is the absolute stem position (lowest coordinate) + * "corods[1]" is the length. + * + * the length can be negative, in which case it must be either + * -20 or -21 in order and will be interpreted as a "ghost" stem, + * according to the Type 1 specification. + * + * if the length is -21 (corresponding to a bottom ghost stem), then + * the real stem position is "coords[0]+coords[1]" + */ + typedef void (*T1_Hints_SetStemFunc) ( T1_Hints hints, + FT_UInt dimension, + FT_Int* coords ); + + /************************************************************************ + * + * @functype: T1_Hints_SetStem3Func + * + * @description: + * a method of the @T1_Hints class used to record three counter-controlled + * horizontal or vertical stems at once + * + * @input: + * hints :: handle to Type 1 hints recorder + * dimension :: 0 for horizontal stems, 1 for vertical ones + * coords :: array of 6 integers, i.e. 3 (position,length) pairs + * for the counter-controlled stems + * + * @note: + * use vertical coordinates (y) for horizontal stems (dim=0) + * use horizontal coordinates (x) for vertical stems (dim=1) + * + * the lengths cannot be negative (ghost stems are never counter-controlled) + */ + typedef void (*T1_Hints_SetStem3Func) ( T1_Hints hints, + FT_UInt dimension, + FT_Int* coords ); + + /************************************************************************ + * + * @functype: T1_Hints_ResetStemsFunc + * + * @description: + * a method of the @T1_Hints class used to reset the stems hints + * in a recording session. This is equivalent to the Type 1 ... + * + * @input: + * hints :: handle to Type 1 hints recorder + * end_point :: index of last point in the input glyph in which + * the previously defined hints apply + */ + typedef void (*T1_Hints_ResetStemsFunc)( T1_Hints hints, + FT_UInt end_point ); + + /************************************************************************ + * + * @functype: T1_Hints_CloseFunc + * + * @description: + * a method of the @T1_Hints class used to close a hint recording + * session. + * + * @input: + * hints :: handle to Type 1 hints recorder + * end_point :: index of last point in the input glyph + * + * @return: + * error code. 0 means success + * + * @note: + * the error code will be set to indicate that an error occured + * during the recording session + */ + typedef FT_Error (*T1_Hint_RecordCloseFunc)( T1_Hints hints, + FT_UInt end_point ); + + /************************************************************************ + * + * @struct: T1_Hints_FuncsRec + * + * @description: + * the structure used to provide the API to @T1_Hints objects + * + * @fields: + * open :: open recording session + * close :: close recording session + * stem :: set simple stem + * stem3 :: set counter-controlled stems + * reset :: reset stem hints + */ + typedef struct T1_Hints_FuncsRec_ + { + T1_Hints_OpenFunc open; + T1_Hints_CloseFunc close; + T1_Hints_SetStemFunc stem; + T1_Hints_SetStem3Func stem3; + T1_Hints_ResetFunc reset; + + } T1_Hints_FuncsRec; + + + /**********************************************************************/ + /**********************************************************************/ + /***** *****/ + /***** PUBLIC TYPE 2 HINTS RECORDER *****/ + /***** *****/ + /**********************************************************************/ + /**********************************************************************/ + + + /************************************************************************ + * + * @type: T2_Hints + * + * @description: + * this is a handle to an opaque structure used to record glyph + * hints from a Type 2 character glyph character string. + * + * the methods used to operate on this object are defined by the + * @T2_Hints_FuncsRec structure. Recording glyph hints is normally + * achieved through the following scheme: + * + * - open a new hint recording session by calling the "open" + * method. This will rewind the recorder and prepare it for + * new input + * + * - for each hint found in the glyph charstring, call the + * corresponding method ("stems", "hintmask", "counters"). + * note that these functions do not return an error code + * + * - close the recording session by calling the "close" method + * it will return an error code if the hints were invalid or + * something strange happened (e.g. memory shortage) + * + * the hints accumulated in the object can later be used by the + * Postscript hinter + */ + typedef struct T2_HintsRec_* T2_Hints; + + /************************************************************************ + * + * @type: T2_Hints_Funcs + * + * @description: + * a pointer to the @T1_Hints_FuncsRec structure that defines the + * API of a given @T2_Hints object + */ + typedef const struct T2_Hints_FuncsRec_* T2_Hints_Funcs; + + /************************************************************************ + * + * @functype: T2_Hints_OpenFunc + * + * @description: + * a method of the @T2_Hints class used to prepare it for a new + * Type 2 hints recording session + * + * @input: + * hints :: handle to Type 2 hints recorder + * + * @note: + * You should always call the @T2_Hints_CloseFunc method in order + * to close an opened recording session + */ + typedef void (*T2_Hints_OpenFunc) ( T2_Hints hints ); + + + /************************************************************************ + * + * @functype: T2_Hints_StemsFunc + * + * @description: + * a method of the @T2_Hints class used to set the table of stems + * in either the vertical or horizontal dimension. Equivalent to the + * "hstem", "vstem", "hstemhm" and "vstemhm" Type 2 operators + * + * @input: + * hints :: handle to Type 2 hints recorder + * dimension :: 0 for horizontal stems (hstem), 1 for vertical ones (vstem) + * count :: number of stems + * coordinates :: an array of "count" (position,length) pairs + * + * @note: + * use vertical coordinates (y) for horizontal stems (dim=0) + * use horizontal coordinates (x) for vertical stems (dim=1) + * + * there are "2*count" elements in the "coordinates" array. Each + * even element is an absolute position in font units, each odd + * element is a length in font units + * + * a length can be negative, in which case it must be either + * -20 or -21 in order and will be interpreted as a "ghost" stem, + * according to the Type 1 specification. + */ + typedef void (*T2_Hints_StemsFunc) ( T2_Hints hints, + FT_UInt dimension, + FT_UInt count, + FT_Fixed* coordinates ); + + /************************************************************************ + * + * @functype: T2_Hints_MaskFunc + * + * @description: + * a method of the @T2_Hints class used to set a given hintmask + * (correspond to the "hintmask" Type 2 operator) + * + * @input: + * hints :: handle to Type 2 hints recorder + * end_point :: glyph index of the last point to which the previously + * defined/active hints apply. + * bit_count :: number of bits in the hint mask. + * bytes :: an array of bytes modelling the hint mask + * + * @note: + * if the hintmask starts the charstring (before any glyph point + * definition), the value of "end_point" should be 0 + * + * "bit_count" is the number of meaningful bits in the "bytes" array, + * and must be equal to the total number of hints defined so far + * (i.e. horizontal+verticals) + * + * the "bytes" array can come directly from the Type 2 charstring + * and respect the same format. + */ + typedef void (*T2_Hints_MaskFunc) ( T2_Hints hints, + FT_UInt end_point, + FT_UInt bit_count, + const FT_Byte* bytes ); + + /************************************************************************ + * + * @functype: T2_Hints_CounterFunc + * + * @description: + * a method of the @T2_Hints class used to set a given counter + * mask (correspond to the "hintmask" Type 2 operator) + * + * @input: + * hints :: handle to Type 2 hints recorder + * end_point :: glyph index of the last point to which the previously + * defined/active hints apply. + * bit_count :: number of bits in the hint mask. + * bytes :: an array of bytes modelling the hint mask + * + * @note: + * if the hintmask starts the charstring (before any glyph point + * definition), the value of "end_point" should be 0 + * + * "bit_count" is the number of meaningful bits in the "bytes" array, + * and must be equal to the total number of hints defined so far + * (i.e. horizontal+verticals) + * + * the "bytes" array can come directly from the Type 2 charstring + * and respect the same format. + */ + typedef void (*T2_Hints_CounterFunc)( T2_Hints hints, + FT_UInt bit_count, + const FT_Byte* bytes ); + + /************************************************************************ + * + * @functype: T2_Hints_CloseFunc + * + * @description: + * a method of the @T2_Hints class used to close a hint recording + * session. + * + * @input: + * hints :: handle to Type 2 hints recorder + * end_point :: index of last point in the input glyph + * + * @return: + * error code. 0 means success + * + * @note: + * the error code will be set to indicate that an error occured + * during the recording session + */ + typedef FT_Error (*T2_Hints_CloseFunc) ( T2_Hints hints, + FT_UInt end_point ); + + /************************************************************************ + * + * @struct: T2_Hints_FuncsRec + * + * @description: + * the structure used to provide the API to @T2_Hints objects + * + * @fields: + * open :: open recording session + * close :: close recording session + * stems :: set dimension's stems table + * hintmask :: set hint masks + * counter :: set counter masks + */ + typedef struct T2_Hints_FuncsRec_ + { + T2_Hints_OpenFunc open; + T2_Hints_CloseFunc close; + T2_Hints_StemsFunc stems; + T2_Hints_MaskFunc hintmask; + T2_Hints_CounterFunc counter; + + } T2_Hints_FuncsRec; + + /* */ + + +FT_END_HEADER + +#endif /* __PSHINTS_H__ */ diff --git a/src/pshinter/pshglob.c b/src/pshinter/pshglob.c new file mode 100644 index 000000000..c8b1ec429 --- /dev/null +++ b/src/pshinter/pshglob.c @@ -0,0 +1,277 @@ +#include "pshglob.h" + +/* "simple" ps hinter globals management, inspired from the new auto-hinter */ + + FT_LOCAL void + psh_globals_init( PSH_Globals globals, + FT_Memory memory ) + { + memset( globals, 0, sizeof(*globals) ); + globals->memory = memory; + globals->x_scale = 0x10000L; + globals->y_scale = 0x10000L; + } + + + /* reset the widths/heights table */ + static FT_Error + psh_globals_reset_widths( PSH_Globals globals, + FT_UInt direction, + PS_Globals_Widths widths ) + { + PSH_Dimension dim = &globals->dim[direction]; + FT_Memory memory = globals->memory; + FT_Error error = 0; + + /* simple copy of the original widths values - no sorting */ + { + FT_UInt count = widths->count; + PSH_Width write = dim->std.widths; + FT_Int16* read = widths->widths; + + dim->std.count = count; + for ( ; count > 0; count-- ) + { + write->org = read[0]; + write++; + read++; + } + } + + return error; + } + + + /* scale the widths/heights table */ + static void + psh_globals_scale_widths( PSH_Globals globals, + FT_UInt direction ) + { + PSH_Widths std = &globals->std[direction]; + FT_UInt count = std->count; + PSH_Width width = std->widths; + FT_Fixed scale = globals->scale[direction]; + + for ( ; count > 0; count--, width++ ) + { + width->cur = FT_MulFix( width->org, scale ); + width->fit = FT_RoundFix( width->cur ); + } + } + + + /* reset the blues table */ + static FT_Error + psh_globals_reset_blues( PSH_Globals globals, + PS_Globals_Blues blues ) + { + FT_Error error = 0; + FT_Memory memory = globals->memory; + + if ( !FT_REALLOC_ARRAY( globals->blues.zones, globals->blues.count, + blues->count, PSH_Blue_ZoneRec ) ) + { + FT_UInt count = 0; + + globals->blyes.count = blues->count; + + /* first of all, build a sorted table of blue zones */ + { + FT_Int16* read = blue->zones; + FT_UInt n, i, j; + FT_Pos reference, overshoot, delta; + + for ( n = 0; n < blues->count; n++, read++ ) + { + PSH_Blue_Zone zone; + + /* read new blue zone entry, find top and bottom coordinates */ + reference = read[0]; + overshoot = read[1]; + delta = overshoot - reference; + + /* now, insert in the blue zone table, sorted by reference position */ + zone = globals->blues.zones; + for ( i = 0; i < count; i++, zone++ ) + { + if ( reference > zone->org_ref ) + break; + + if ( reference == zone->org_ref ) + { + /* on the same reference coordinate, place bottom zones */ + /* before top zones.. */ + if ( delta < 0 || zone->org_delta >= 0 ) + break; + } + + for ( j = count - i; j > 0; j-- ) + zone[j+1] = zone[j]; + + zone->org_ref = reference; + zone->org_delta = delta; + + count++; + } + } + + /* now, get rid of blue zones located on the same reference position */ + /* (only keep the largest zone).. */ + { + PSH_Blue_Zone zone, limit; + + zone = globals->blues.zones; + limit = zone + count; + for ( ; zone+1 < limit; zone++ ) + { + if ( zone[0].org_ref == zone[1].org_ref ) + { + FT_Int delta0 = zone[0].org_delta; + FT_Int delta1 = zone[1].org_delta; + + /* these two zones are located on the same reference coordinate */ + /* we need to merge them when they're in the same direction.. */ + if ( ( delta0 < 0 ) ^ ( delta1 < 0 ) ) == 0 ) + { + /* ok, take the biggest one */ + if ( delta0 < 0 ) + { + if ( delta1 < delta0 ) + delta0 = delta1; + } + else + { + if ( delta1 > delta0 ) + delta0 = delta1; + } + + zone[0].org_delta = delta0; + + { + PSH_Blue_Zone cur = zone+1; + FT_UInt count2 = limit - cur; + + for ( ; count2 > 0; count2--, cur++ ) + { + cur[0].org_ref = cur[1].org_ref; + cur[0].org_delta = cur[1].org_delta; + } + } + count--; + limit--; + } + } + } + } + + globals->blues.count = count; + globals->blues.org_shift = blues->shift; + globals->blues.org_fuzz = blues->fuzz; + } + + return error; + } + + + static void + psh_globals_scale_blues( PSH_Globals globals, + PS_Globals_Blues blues ) + { + FT_Fixed y_scale = globals->scale[1]; + FT_Fixed y_delta = globals->delta[1]; + FT_Pos prev_top; + PSH_Blue_Zone zone, prev; + FT_UInt count; + + zone = globals->blues.zones; + prev = 0; + prev_top = 0; + for ( count = globals->blues.count; count > 0; count-- ) + { + FT_Pos ref, delta, top, bottom; + + ref = FT_MulFix( zone->org_ref, y_scale ) + y_delta; + delta = FT_MulFix( zone->org_delta, y_scale ); + ref = (ref+32) & -64; + + if ( delta < 0 ) + { + top = ref; + bottom = ref + delta; + } + else + { + bottom = ref; + top = ref + delta; + } + + zone->cur_ref = ref; + zone->cur_delta = delta; + zone->cur_top = top; + zone->cur_bottom = bottom; + + if + prev = zone; + zone++; + } + /* XXXX: test overshoot supression !! */ + } + + FT_LOCAL FT_Error + psh_globals_reset( PSH_Globals globals, + T1_Fitter_Globals public_globals ) + { + psh_globals_reset_widths( globals, 0, &public_globals->horizontal ); + psh_globals_scale_widths( globals, 0 ); + + psh_globals_reset_widths( globals, 1, &public_globals->vertical ); + psh_globals_scale_widths( globals, 1 ); + + psh_globals_reset_blues( globals, public_globals ); + psh_globals_scale_blues( globals ); + } + + + FT_LOCAL void + psh_globals_set_scale( PSH_Globals globals, + FT_Fixed x_scale, + FT_Fixed x_delta, + FT_Fixed y_scale, + FT_Fixed y_delta ) + { + FT_Memory memory = globals->memory; + + if ( x_scale != globals->scale[0] || + y_scale != globals->scale[1] || + x_delta != globals->delta[0] || + y_delta != globals->delta[1] ) + { + globals->scale[0] = x_scale; + globals->scale[1] = y_scale; + globals->delta[0] = x_delta; + globals->delta[1] = y_delta; + + psh_globals_scale_widths( globals, 0 ); + psh_globals_scale_widths( globals, 1 ); + psh_globals_scale_blues ( globals ); + } + } + + + FT_LOCAL void + psh_globals_done( PSH_Globals globals ) + { + if (globals) + { + FT_Memory memory = globals->memory; + + FT_FREE( globals->std[0].widths ); + globals->std[0].count = 0; + + FT_FREE( globals->std[1].widths ); + globals->std[1].count = 0; + + FT_FREE( globals->blues.zones ); + globals->blues.count = 0; + } + } diff --git a/src/pshinter/pshglob.h b/src/pshinter/pshglob.h new file mode 100644 index 000000000..c3594a71a --- /dev/null +++ b/src/pshinter/pshglob.h @@ -0,0 +1,108 @@ +#ifndef __PS_HINTER_GLOBALS_H__ +#define __PS_HINTER_GLOBALS_H__ + +FT_BEGIN_HEADER + + /**********************************************************************/ + /**********************************************************************/ + /***** *****/ + /***** GLOBAL HINTS INTERNALS *****/ + /***** *****/ + /**********************************************************************/ + /**********************************************************************/ + + /* blue zone descriptor */ + typedef struct PSH_Blue_ZoneRec_ + { + FT_Int org_ref; + FT_Int org_delta; + FT_Pos cur_ref; + FT_Pos cur_delta; + FT_Pos cur_bottom; + FT_Pos cur_top; + + } PSH_Blue_ZoneRec, *PSH_Blue_Zone; + + + /* blue zones table */ + typedef struct PSH_BluesRec_ + { + FT_UInt count; + PSH_Blue_ZoneRec zones[ PS_GLOBALS_MAX_BLUE_ZONES ]; + + FT_UInt count_family; + PSH_Blue_ZoneRec zones_family[ PS_GLOBALS_MAX_BLUE_ZONES ]; + + FT_Fixed scale; + FT_Int org_shift; + FT_Int org_fuzz; + FT_Pos cur_shift; + FT_Pos cur_fuzz; + + } PSH_BluesRec, *PSH_Blues; + + + /* standard and snap width */ + typedef struct PSH_WidthRec_ + { + FT_Int org; + FT_Pos cur; + FT_Pos fit; + + } PSH_WidthRec; + + + /* standard and snap widths table */ + typedef struct PSH_WidthsRec_ + { + FT_UInt count; + PSH_WidthRec widths[ PS_GLOBALS_MAX_STD_WIDTHS ]; + + } PSH_WidthsRec, *PSH_Widths; + + + typedef struct PSH_DimensionRec_ + { + PSH_WidthsRec std; + FT_Fixed scale_mult; + FT_Fixed scale_delta; + + } PSH_DimensionRec, *PSH_Dimension; + + /* font globals */ + typedef struct PSH_GlobalsRec_ + { + FT_Memory memory; + PSH_DimensionRec dimension[2]; + PSH_BluesRec blues; + + } PSH_GlobalsRec, *PSH_Globals; + + + /* initialise font globals */ + FT_LOCAL void + psh_globals_init( PSH_Globals globals, + FT_Memory memory ); + + /* reset font globals to new values */ + FT_LOCAL FT_Error + psh_globals_reset( PSH_Globals globals_hinter, + PS_Globals globals ); + + /* change current scale transform */ + FT_LOCAL void + psh_globals_set_scale( PSH_Globals globals_hinter, + FT_Fixed x_scale, + FT_Fixed x_delta, + FT_Fixed y_scale, + FT_Fixed y_delta ); + + /* finalize font globals */ + FT_LOCAL void + psh_globals_done( PSH_Globals globals ); + + /* */ + +FT_END_HEADER + +#endif __T1_FITTER_GLOBALS_H__ diff --git a/src/pshinter/psrecord.c b/src/pshinter/psrecord.c new file mode 100644 index 000000000..6d1b97f4f --- /dev/null +++ b/src/pshinter/psrecord.c @@ -0,0 +1,1067 @@ +#include "psrecord.h" + + /***********************************************************************/ + /***********************************************************************/ + /***** *****/ + /***** PS_HINT MANAGEMENT *****/ + /***** *****/ + /***********************************************************************/ + /***********************************************************************/ + + /* destroy hints table */ + static void + ps_hint_table_done( PS_Hint_Table table, + FT_Memory memory ) + { + FT_FREE( table->hints ); + table->num_hints = 0; + table->max_hints = 0; + } + + + /* ensure that a table can contain "count" elements */ + static FT_Error + ps_hint_table_ensure( PS_Hint_Table table, + FT_UInt count, + FT_Memory memory ) + { + FT_UInt old_max = table->max_hints; + FT_UInt new_max = count; + FT_Error error = 0; + + if ( new_max > old_max ) + { + /* try to grow the table */ + new_max = ( new_max + 7 ) & -8; + if ( !FT_REALLOC_ARRAY( table->hints, old_max, new_max, PS_HintRec ) ) + table->max_hints = new_max; + } + return error; + } + + + static FT_Error + ps_hint_table_alloc( PS_Hint_Table table, + FT_Memory memory, + PS_Hint *ahint ) + { + FT_Error error = 0; + FT_UInt count; + PS_Hint hint = 0; + + count = table->num_hints; + count++; + + if ( count >= table->max_hints ) + { + error = ps_hint_table_ensure( table, count, memory ); + if (error) goto Exit; + } + + hint = table->hints + count-1; + hint->org_pos = 0; + hint->org_len = 0; + hint->flags = 0; + + table->num_hints = count; + + Exit: + *ahint = hint; + return error; + } + + + /***********************************************************************/ + /***********************************************************************/ + /***** *****/ + /***** PS_MASK MANAGEMENT *****/ + /***** *****/ + /***********************************************************************/ + /***********************************************************************/ + + /* destroy mask */ + static void + ps_mask_done( PS_Mask mask, + FT_Memory memory ) + { + FT_FREE( mask->bytes ); + mask->num_bits = 0; + mask->max_bits = 0; + mask->end_point = 0; + } + + + /* ensure that a mask can contain "count" bits */ + static FT_Error + ps_mask_ensure( PS_Mask mask, + FT_UInt count, + FT_Memory memory ) + { + FT_UInt old_max = (mask->max_bits + 7) >> 3; + FT_UInt new_max = (count + 7) >> 3; + FT_Error error = 0; + + if ( new_max > old_max ) + { + new_max = ( new_max + 7 ) & -8; + if ( !FT_REALLOC_ARRAY( mask->bytes, old_max, new_max, FT_Byte ) ) + mask->max_bits = new_max*8; + } + return error; + } + + + + /* test a bit value in a given mask */ + static FT_Int + ps_mask_test_bit( PS_Mask mask, + FT_Int index ) + { + if ( index < 0 || index >= mask->num_bits ) + return 0; + + return mask->bytes[index >> 3] & (0x80 >> (index & 7)); + } + + + /* clear a given bit */ + static void + ps_mask_clear_bit( PS_Mask mask, + FT_Int index ) + { + FT_Byte* p; + + if ( index < 0 || index >= mask->num_bits ) + return; + + p = mask->bytes + (index >> 3); + p[0] = (FT_Byte)( p[0] & ~(0x80 >> (index & 7)) ); + } + + + /* set a given bit, eventually grow the mask */ + static FT_Error + ps_mask_set_bit( PS_Mask mask, + FT_Int index, + FT_Memory memory ) + { + FT_Error error = 0; + FT_Byte* p; + + if ( index < 0 ) + goto Exit; + + if ( index >= mask->num_bits ) + { + error = ps_mask_ensure( mask, index, memory ); + if (error) goto Exit; + } + + p = mask->bytes + (index >> 3); + p[0] = (FT_Byte)( p[0] | (0x80 >> (index & 7)) ); + + Exit: + return error; + } + + + /* destroy mask table */ + static void + ps_mask_table_done( PS_Mask_Table table, + FT_Memory memory ) + { + FT_UInt count = table->max_masks; + PS_Mask mask = table->masks; + + for ( ; count > 0; count--, mask++ ) + ps_mask_done( mask, memory ); + + FT_FREE( table->masks ); + table->num_masks = 0; + table->max_masks = 0; + } + + + /* ensure that a mask table can contain "count" masks */ + static FT_Error + ps_mask_table_ensure( PS_Mask_Table table, + FT_UInt count, + FT_Memory memory ) + { + FT_UInt old_max = table->max_masks; + FT_UInt new_max = count; + FT_Error error = 0; + + if ( new_max > old_max ) + { + new_max = (new_max+7) & -8; + if ( !FT_REALLOC_ARRAY( table->masks, old_max, new_max, PS_MaskRec ) ) + table->max_masks = new_max; + } + return error; + } + + + /* allocate a new mask in a table */ + static FT_Error + ps_mask_table_alloc( PS_Mask_Table table, + FT_Memory memory, + PS_Mask *amask ) + { + FT_UInt count; + FT_Error error = 0; + PS_Mask mask = 0; + + count = table->num_masks; + count++; + + if ( count >= table->max_masks ) + { + error = ps_mask_table_ensure( table, count, memory ); + if (error) goto Exit; + } + + mask = table->masks + count; + mask->num_bits = 0; + mask->end_point = 0; + table->num_masks = count; + + Exit: + *amask = mask; + return error; + } + + + /* return last hint mask in a table, create one if the table is empty */ + static FT_Error + ps_mask_table_last( PS_Mask_Table table, + FT_Memory memory, + PS_Mask *amask ) + { + FT_Error error; + FT_UInt count; + PS_Mask mask; + + count = table->num_masks; + if ( count == 0 ) + { + error = ps_mask_table_alloc( table, memory, &mask ); + if (error) goto Exit; + } + else + mask = table->masks + count-1; + + Exit: + *amask = mask; + return error; + } + + + /* set a new mask to a given bit range */ + static FT_Error + ps_mask_table_set_bits( PS_Mask_Table table, + FT_Byte* source, + FT_UInt bit_pos, + FT_UInt bit_count, + FT_Memory memory ) + { + FT_Error error = 0; + PS_Mask mask; + FT_UInt count; + + /* allocate new mask, and grow it to "bit_count" bits */ + error = ps_mask_table_alloc( table, memory, &mask ); + if (error) goto Exit; + + error = ps_mask_ensure( mask, bit_count, memory ); + if (error) goto Exit; + + mask->num_bits = bit_count; + + /* now, copy bits */ + { + FT_Byte* read = source + (bit_pos >> 3); + FT_Int rmask = 0x80 >> (bit_pos & 7); + FT_Byte* write = mask->bytes; + FT_Int wmask = 0x80; + FT_Int val; + + for ( ; source_bits > 0; source_bits-- ) + { + val = write[0] & ~wmask; + + if ( read[0] & rmask ) + val |= wmask; + + write[0] = (FT_Byte) val; + + rmask >>= 1; + if ( rmask == 0 ) + { + read++; + rmask = 0x80; + } + + wmask >>= 1; + if ( wmask == 0 ) + { + write++; + wmask = 0x80; + } + } + } + + Exit: + return error; + } + + + /* test wether two masks in a table intersect */ + static FT_Int + ps_mask_table_test_intersect( PS_Mask_Table table, + FT_Int index1, + FT_Int index2 ) + { + PS_Mask mask1 = table->masks + index1; + PS_Mask mask2 = table->masks + index2; + FT_Byte* p1 = mask1->bytes; + FT_Byte* p2 = mask2->bytes, + FT_UInt count1 = mask1->num_bits; + FT_UInt count2 = mask2->num_bits; + FT_UInt count; + + count = ( count1 <= count2 ) ? count1 : count2; + for ( ; count >= 8; count -= 8 ) + { + if ( p1[0] & p2[0] ) + return 1; + + p1++; + p2++; + } + + if ( count == 0 ) + return 0; + + return ( p1[0] & p2[0] ) & ~(0xFF >> count); + } + + + /* merge two masks, used by ps_mask_table_merge_all */ + static FT_Error + ps_mask_table_merge( PS_Mask_Table table, + FT_Int index1, + FT_Int index2, + FT_Memory memory ) + { + FT_UInt temp; + FT_Error error = 0; + + /* swap index1 and index2 so that index1 < index2 */ + if ( index1 > index2 ) + { + temp = index1; + index1 = index2; + index2 = index1; + } + + if ( index1 < index2 && index1 >= 0 && index2 < table->num_masks ) + { + /* we need to merge the bitsets of index1 and index2 with a */ + /* simple union.. */ + PS_Mask mask1 = table->masks + index1; + PS_Mask mask2 = table->masks + index2; + FT_UInt count1 = mask1->num_bits; + FT_UInt count2 = mask2->num_bits; + FT_Int delta; + + if ( count2 > 0 ) + { + FT_UInt pos; + FT_Byte* read; + FT_Byte* write; + + /* if "count2" is greater than "count1", we need to grow the */ + /* first bitset, and clear the highest bits.. */ + if ( count2 > count1 ) + { + error = ps_mask_ensure( mask1, count2, memory ); + if (error) goto Exit; + + for ( pos = count1; pos < count2; pos++ ) + ps_mask_clear_bit( mask1, pos ); + } + + /* merge (union) the bitsets */ + read = mask2->bytes; + write = mask1->bytes; + pos = (FT_UInt)((count2+7) >> 3); + for ( ; pos > 0; pos-- ) + { + write[0] = (FT_Byte)( write[0] | read[0] ); + write++; + read++; + } + } + + /* now, remove "mask2" from the list, we need to keep the masks */ + /* sorted in order of importance, so move table elements.. */ + mask2->num_bytes = 0; + mask2->end_point = 0; + + delta = table->num_masks-1 - index2; /* number of masks to move */ + if ( delta > 0 ) + { + /* move to end of table for reuse */ + PS_MaskRec dummy = *mask2; + + memmove( mask2, mask2+1, delta*sizeof(PS_MaskRec) ); + + mask2[delta] = dummy; + } + + table->num_masks--; + } + else + FT_ERROR(( "%s: ignoring invalid indices (%d,%d)\n", + index1, index2 )); + Exit: + return error; + } + + /* try to merge all masks in a given table, this is used to merge */ + /* all counter masks into independent counter "paths" */ + /* */ + static FT_Error + ps_mask_table_merge_all( PS_Mask_Table table, + FT_Memory memory ) + { + FT_Int index1, index2; + FT_Error error = 0; + + for ( index1 = table->num_masks-1; index1 > 0; index1-- ) + { + for ( index2 = index1-1; index2 >= 0; index2-- ) + { + if ( ps_mask_table_test_intersect( table, index1, index2 ) ) + { + error = ps_mask_table_merge( table, index2, index1, memory ) ); + if (error) goto Exit; + + break; + } + } + } + Exit: + return error; + } + + + /***********************************************************************/ + /***********************************************************************/ + /***** *****/ + /***** PS_DIMENSION MANAGEMENT *****/ + /***** *****/ + /***********************************************************************/ + /***********************************************************************/ + + + /* finalize a given dimension */ + static void + ps_dimension_done( PS_Dimension dimension, + FT_Memory memory ) + { + ps_mask_table_done( &dimension->counters, memory ); + ps_mask_table_done( &dimension->masks, memory ); + ps_hint_table_done( &dimension->hints, memory ); + } + + + /* initialise a given dimension */ + static void + ps_dimension_init( PS_Dimension dimension ) + { + dimension->hints.num_hints = 0; + dimension->masks.num_masks = 0; + dimension->counters.num_masks = 0; + } + + + /* set a bit at a given index in the current hint mask */ + static FT_Error + ps_dimension_set_mask_bit( PS_Dimension dim, + FT_UInt index, + FT_Memory memory ) + { + PS_Mask mask; + FT_Error error = 0; + + /* get last hint mask */ + error = ps_mask_table_last( &dim->masks, memory, &mask ); + if (error) goto Exit; + + error = ps_mask_set_bit( mask, index, memory ); + + Exit: + return error; + } + + + /* set the end point in a mask, called from "End" & "Reset" methods */ + static void + ps_dimension_end_mask( PS_Dimension dim, + FT_UInt end_point ) + { + FT_UInt count = dimension->masks.num_masks; + PS_Mask mask; + + if ( count > 0 ) + { + mask = dim->masks.masks + count-1; + mask->end_point = end_point; + } + } + + + /* set the end point in the current mask, then create a new empty one */ + /* (called by "Reset" method) */ + static FT_Error + ps_dimension_reset_mask( PS_Dimension dim, + FT_UInt end_point, + FT_Memory memory ) + { + PS_Mask mask; + + /* end current mask */ + ps_dimension_end_mask( dim, end_point ); + + /* allocate new one */ + return ps_mask_table_alloc( dim->masks, memory, &mask ); + } + + + /* set a new mask, called from the "T2Stem" method */ + static FT_Error + ps_dimension_set_mask_bits( PS_Dimension dim, + const FT_Byte* source, + FT_UInt source_pos, + FT_UInt source_bits, + FT_UInt end_point, + FT_Memory memory ) + { + FT_Error error = 0; + PS_Mask mask; + + /* reset current mask, if any */ + error = ps_dimension_reset_mask( dim, end_point, memory ); + if (error) goto Exit; + + /* set bits in new mask */ + error = ps_mask_table_set_bits( &dim->masks, (FT_Byte*)source, + source_pos, source_bits, memory ); + Exit: + return error; + } + + + + /* add a new single stem (called from "T1Stem" method) */ + static FT_Error + ps_dimension_add_t1stem( PS_Dimension dim, + FT_Int pos, + FT_Int len, + FT_Memory memory, + FT_Int *aindex ) + { + FT_Error error = 0; + FT_UInt flags = 0; + + /* detect ghost stem */ + if ( len < 0 ) + { + flags |= PS_HINT_FLAG_GHOST; + if ( len == -21 ) + { + flags |= PS_HINT_FLAG_BOTTOM; + pos += len; + } + } + + if (aindex) + *aindex = -1; + + /* now, lookup stem in the current hints table */ + { + PS_Mask mask; + FT_UInt index; + FT_UInt max = dim->hints.num_hints; + PS_Hint hint = dim->hints.hints; + + for ( index = 0; index < max; index++, hint++ ) + { + if ( hint->org_pos == pos && hint->org_len == len ) + break; + } + + /* we need to create a new hint in the table */ + if ( index >= max ) + { + error = ps_hint_table_alloc( &dim->hints, memory, &hint ); + if (error) goto Exit; + + hint->org_pos = pos; + hint->org_len = len; + hint->flags = flags; + } + + /* now, store the hint in the current mask */ + error = ps_mask_table_last( &dim->masks, memory, &mask ); + if (error) goto Exit; + + error = ps_mask_set_bit( mask, index, memory ); + if (error) goto Exit; + + if ( aindex ) + *aindex = (FT_Int)index; + } + Exit: + return error; + } + + + /* add a "hstem3/vstem3" counter to our dimension table */ + static FT_Error + ps_dimension_add_counter( PS_Dimension dim, + FT_Int hint1, + FT_Int hint2, + FT_Int hint3, + FT_Memory memory ) + { + FT_Error error = 0; + FT_UInt count = dim->counters.num_masks; + PS_Mask counter = dim->counters.masks; + + /* try to find an existing counter mask that already uses */ + /* one of these stems here.. */ + for ( ; count > 0; count--, counter++ ) + { + if ( ps_mask_test_bit( counter, hint1 ) || + ps_mask_test_bit( counter, hint2 ) || + ps_mask_test_bit( counter, hint3 ) ) + break; + } + + /* creat a new counter when needed */ + if ( count == 0 ) + { + error = ps_mask_table_alloc( &dim->counters, memory, &counter ); + if (error) goto Exit; + } + + /* now, set the bits for our hints in the counter mask */ + error = ps_mask_set_bit( counter, hint1, memory ); + if (error) goto Exit; + + error = ps_mask_set_bit( counter, hint2, memory ); + if (error) goto Exit; + + error = ps_mask_set_bit( counter, hint3, memory ); + if (error) goto Exit; + + Exit: + return error; + } + + + /* end of recording session for a given dimension */ + static FT_Error + ps_dimension_end( PS_Dimension dim, + FT_UInt end_point, + FT_Memory memory ) + { + /* end hint mask table */ + ps_dimension_end_mask( dim, end_point ); + + /* merge all counter masks into independent "paths" */ + return ps_mask_table_merge_all( &dim->counters, memory ); + } + + /***********************************************************************/ + /***********************************************************************/ + /***** *****/ + /***** PS_RECORDER MANAGEMENT *****/ + /***** *****/ + /***********************************************************************/ + /***********************************************************************/ + + + + /* destroy hints */ + static void + ps_hints_done( PS_Hints hints, + FT_Memory memory ) + { + ps_dimension_done( &hints->dimension[0], memory ); + ps_dimension_done( &hints->dimension[1], memory ); + hints->error = 0; + } + + + /* initialise a hints for a new session */ + static void + ps_hints_rewind( PS_Hints hints, + PS_Hint_Type hint_type ) + { + switch (hint_type) + { + case PS_Hint_Type_1: + case PS_Hint_Type_2: + { + hints->error = 0; + hints->hint_type = hint_type; + + ps_dimension_init( &hints->dimension[0] ); + ps_dimension_init( &hints->dimension[1] ); + } + break; + + default: + hints->error = FT_Err_Invalid_Argument; + hints->hint_type = hint_type; + + FT_ERROR(( "%s.init: invalid charstring type !!\n", "t1fitter.hints" )); + } + } + + + + /* add one or more stems to the current hints table */ + static void + ps_hints_stem( PS_Hints hints, + FT_Int dimension, + FT_UInt count, + FT_Int* stems ) + { + if ( !hints->error ) + { + /* limit "dimension" to 0..1 */ + if ( dimension < 0 || dimension > 1 ) + { + FT_ERROR(( "ps.hints.stem: invalid dimension (%d) used\n", + dimension )); + dimension = (dimension != 0); + } + + /* record the stems in the current hints/masks table */ + switch ( hints->hint_type ) + { + case PS_Hint_Type_1: /* Type 1 "hstem" or "vstem" operator */ + case PS_Hint_Type_2: /* Type 2 "hstem" or "vstem" operator */ + { + PS_Dimension dim = &hints->dimension[dimension]; + + for ( ; count > 0; count--, stems += 2 ) + { + FT_Error error; + + error = ps_dimension_add_t1stem( dim, stems[0], stems[1], + memory, NULL ); + if (error) + { + FT_ERROR(( "t1f.hints.stem: could not add stem" + " (%d,%d) to hints table\n", stems[0], stems[1] )); + + hints->error = error; + return; + }; + } + } + break; + + default: + FT_ERROR(( "t1f.hints.stem: called with invalid hint type (%d)\n", + hints->hint_type )); + ; + } + } + + + /* add one Type1 counter stem to the current hints table */ + static void + ps_hints_t1stem3( PS_Hints hints, + FT_Int dimension, + FT_Int* stems ) + { + if (!hints->error) + { + PS_Dimension dim; + FT_Memory memory = hints->memory; + FT_Int count; + FT_Int index[3]; + + /* limit "dimension" to 0..1 */ + if ( dimension < 0 || dimension > 1 ) + { + FT_ERROR(( "t1f.hints.stem: invalid dimension (%d) used\n", + dimension )); + dimension = (dimension != 0); + } + + dim = &hints->dimension[dimension]; + + /* there must be 6 elements in the 'stem' array */ + if ( hints->hint_type == PS_Hint_Type_1 ) + { + /* add the three stems to our hints/masks table */ + for ( count = 0; count < 3; count++, stems += 2 ) + { + error = ps_dimension_add_t1stem( dim, stems[0], stems[1], + &index[count], memory ); + if (error) goto Fail; + } + + /* now, add the hints to the counters table */ + error = ps_dimension_add_counter( dim, index[0], index[1], + index[2], memory ); + if (error) goto Fail; + } + else + { + FT_ERROR(( "t1f.hints.stem3: called with invalid hint type !!\n" )); + error = FT_Err_Invalid_Argument; + goto Fail; + } + } + + return; + + Fail: + FT_ERROR(( "t1f.hints.stem3: could not add counter stems to table\n" )); + hints->error = error; + } + + + + /* reset hints (only with Type 1 hints) */ + static void + ps_hints_t1reset( PS_Hints hints, + FT_UInt end_point ) + { + if ( !hints->error ) + { + FT_Memory memory = hints->memory; + + if ( hints->hint_type == PS_Hint_Type_1 ) + { + error = ps_dimension_reset_mask( &hints->dimension[0], + end_point, memory ); + if (error) goto Fail; + + error = ps_dimension_reset_mask( &hints->dimension[1], + end_point, memory ); + if (error) goto Fail; + } + else + { + /* invalid hint type */ + error = FT_Err_Invalid_Argument; + goto Fail; + } + } + return; + + Fail: + hints->error = error; + } + + + /* Type2 "hintmask" operator, add a new hintmask to each direction */ + static void + ps_hints_t2mask( PS_Hints hints, + FT_UInt end_point, + FT_UInt bit_count, + const FT_Byte* bytes ) + { + FT_Error error; + + if ( !hints->error ) + { + PS_Dimension dim = hints->dimension; + FT_Memory memory = hints->memory; + FT_UInt count1 = dim[0].hints.num_hints; + FT_UInt count2 = dim[1].hints.num_hints; + + /* check bit count, must be equal to current total hint count */ + if ( (FT_Int)bit_count != count1 + count2 ) + { + error = FT_Err_Invalid_Argument; + FT_ERROR(( "%s: called with invalid bitcount %d (instead of %d)\n", + bit_count, count1+count2 )); + goto Fail; + } + + /* set-up new horizontal and vertical hint mask now */ + error = ps_dimension_set_mask( &dim[0], mask, 0, count1, + end_point, memory ); + if (error) goto Fail; + + error = ps_dimension_set_mask( &dim[1], mask, count1, count2, + end_point, memory ); + if (error) goto Fail; + } + return; + + Fail: + hints->error = error; + } + + + static void + ps_hints_t2counter( PS_Hints hints, + FT_UInt bit_count, + const FT_Byte* mask ) + { + FT_Error error; + + if ( !hints->error ) + { + PS_Dimension dim = hints->dimension; + FT_Memory memory = hints->memory; + FT_UInt count1 = dim[0].hints.num_hints; + FT_UInt count2 = dim[1].hints.num_hints; + + /* check bit count, must be equal to current total hint count */ + if ( (FT_Int)bit_count != count1 + count2 ) + { + error = FT_Err_Invalid_Argument; + FT_ERROR(( "%s: called with invalid bitcount %d (instead of %d)\n", + bit_count, count1+count2 )); + goto Fail; + } + + /* set-up new horizontal and vertical hint mask now */ + error = ps_dimension_set_mask_bits( &dim[0], mask, 0, count1, + end_point, memory ); + if (error) goto Fail; + + error = ps_dimension_set_mask_bits( &dim[1], mask, count1, count2, + end_point, memory ); + if (error) goto Fail; + } + return; + + Fail: + hints->error = error; + } + + + + /* end recording session */ + static FT_Error + ps_hints_close( PS_Hints hints, + FT_UInt end_point ) + { + FT_Error error; + + error = hints->error; + if (!error) + { + FT_Error error; + FT_Memory memory = hints->memory; + PS_Dimension dim = hints->dimension; + + error = ps_dimension_end( &dim[0], end_point, memory ); + if (!error) + { + error = ps_dimension_end( &dim[1], end_point, memory ); + } + } + return error; + } + + /***********************************************************************/ + /***********************************************************************/ + /***** *****/ + /***** TYPE 1 HINTS RECORDING INTERFACE *****/ + /***** *****/ + /***********************************************************************/ + /***********************************************************************/ + + static void + t1_hints_open( T1_Hints hints ) + { + ps_hints_open( (PS_Hints)hints, ps_hints_type_1 ); + } + + static void + t1_hints_stem( T1_Hints hints, + FT_Int dimension, + FT_Int* coords ) + { + ps_hints_stem( (PS_Hints)hints, dimension, 1, coords ); + } + + + + static const T1_Hints_FuncsRec pshinter_t1_hints_funcs = + { + (T1_Hints_OpenFunc) t1_hints_open, + (T1_Hints_CloseFunc) ps_hints_close, + (T1_Hints_SetStemFunc) t1_hints_set_stem, + (T1_Hints_SetStem3Func) ps_hints_t1stem3, + (T1_Hints_ResetFunc) ps_hints_t1reset + }; + + + /***********************************************************************/ + /***********************************************************************/ + /***** *****/ + /***** TYPE 2 HINTS RECORDING INTERFACE *****/ + /***** *****/ + /***********************************************************************/ + /***********************************************************************/ + + static void + t2_hints_open( T2_Hints hints ) + { + ps_hints_open( (PS_Hints)hints, ps_hints_type_2 ); + } + + static void + t2_hints_stems( T2_Hints hints, + FT_Int dimension, + FT_Int count, + FT_Fixed* coords ) + { + FT_Int stems[32], n, total = count; + FT_Fixed* read; + + while (total > 0) + { + /* determine number of stems to write */ + count = total; + if ( count > 32 ) + count = 32; + + /* compute integer stem position in font units */ + for ( n = 0; n < count*2; n++ ) + stems[n] = (coords[n] + 0x8000) >> 16; + + /* add them to the current dimension */ + ps_hints_stem( (PS_Hints)hints, dimension, count, stems ); + + total -= (count >> 1); + } + } + + + static const T2_Hints_FuncsRec pshinter_t2_hints_funcs = + { + (T2_Hints_OpenFunc) t2_hints_open, + (T2_Hints_CloseFunc) ps_hints_close, + (T2_Hints_StemsFunc) t2_hints_stems, + (T2_Hints_MaskFunc) ps_hints_t2mask, + (T2_Hints_CounterFunc) ps_hints_t2counter + }; + + \ No newline at end of file diff --git a/src/pshinter/psrecord.h b/src/pshinter/psrecord.h new file mode 100644 index 000000000..06abd387e --- /dev/null +++ b/src/pshinter/psrecord.h @@ -0,0 +1,113 @@ +#ifndef __PSRECORD_H_ +#define __PSRECORD_H__ + +#include FT_INTERNAL_POSTSCRIPT_HINTS_H + +FT_BEGIN_HEADER + + /**********************************************************************/ + /**********************************************************************/ + /***** *****/ + /***** GLYPH HINTS RECORDER INTERNALS *****/ + /***** *****/ + /**********************************************************************/ + /**********************************************************************/ + + /* handle to hint record */ + typedef struct PS_HintRec_* PS_Hint; + + /* hint flags */ + typedef enum + { + PS_HINT_FLAG_ACTIVE = 1, + PS_HINT_FLAG_GHOST = 2, + PS_HINT_FLAG_BOTTOM = 4 + + } PS_Hint_Flags; + + /* hint descriptor */ + typedef struct PS_HintRec_ + { + FT_Int org_pos; + FT_Int org_len; + FT_UInt flags; + +#if 0 + FT_Pos cur_pos; + FT_Pos cur_len; + + PS_Hint parent; + + FT_Fixed interp_scale; + FT_Fixed interp_delta; +#endif + + } PS_HintRec; + + +#define ps_hint_is_active(x) ((x)->flags & PS_HINT_FLAG_ACTIVE) +#define ps_hint_is_ghost(x) ((x)->flags & PS_HINT_FLAG_GHOST) +#define ps_hint_is_bottom(x) ((x)->flags & PS_HINT_FLAG_BOTTOM) + + + /* hints table descriptor */ + typedef struct PS_Hint_TableRec_ + { + FT_UInt num_hints; + FT_UInt max_hints; + PS_Hint hints; + + } PS_Hint_TableRec, *PS_Hint_Table; + + + /* hint and counter mask descriptor */ + typedef struct PS_MaskRec_ + { + FT_UInt num_bits; + FT_UInt max_bits; + FT_Byte* bytes; + FT_UInt end_point; + + } PS_MaskRec, *PS_Mask; + + + /* masks and counters table descriptor */ + typedef struct PS_Mask_TableRec_ + { + FT_UInt num_masks; + FT_UInt max_masks; + PS_Mask masks; + + } PS_Mask_TableRec, *PS_Mask_Table; + + + /* dimension-specific hints descriptor */ + typedef struct PS_DimensionRec_ + { + PS_Hint_TableRec hints; + PS_Mask_TableRec masks; + PS_Mask_TableRec counters; + + } PS_DimensionRec, *PS_Dimension; + + + /* magic value used within PS_HintsRec */ +#define PS_HINTS_MAGIC 0x68696e74 /* "hint" */ + + + /* glyph hints descriptor */ + typedef struct PS_HintsRec_ + { + FT_Memory memory; + FT_Error error; + FT_UInt32 magic; + PS_Hint_Type hint_type; + PS_DimensionRec dimension[2]; + + } PS_HintsRec; + + /* */ + +FT_END_HEADER + +#endif /* __T1_FITTER_HINTS_H__ */