|
|
/***
** ** Module: ttprog ** ** Description: ** This is a module of the T1 to TT font converter. This is a ** sub-module of Hint module. This modules deals with the ** the font program fo the font. ** ** Author: Michael Jansson ** ** Created: 8/24/93 ** ***/
/**** INCLUDES */ /* General types and definitions. */ #include <limits.h>
/* Special types and definitions. */ #include "titott.h"
#include "types.h"
#include "safemem.h"
#include "metrics.h"
#include "t1msg.h"
/* Module dependent types and prototypes. */ /*#include "hints.h"*/ #include "ttprog.h"
/***** MACROS */ /*-none-*/
/***** CONSTANTS */ #define MAXIP 100
#define CURVEPHASE 6
#define MAXTHINPNTS 512
#define UNDEF -1
#define SMALL_LOWER 21L
#define SMALL_UPPER 50L
#define LARGE_LOWER 21L
#define LARGE_UPPER 21L
#define BUFSIZE 20
#define TTFUN_SET_ZONE 1
#define TTFUN_COPY_ZONE 2
#define TTFUN_STEM_SNAP_WIDTH 3
#define TTFUN_STEM_STD_WIDTH 4
#define TTFUN_SHIFT_BLUE_ZONE 5
#define TTFUN_ALIGN_BLUE_ZONE 6
#define TTFUN_COPY_FAMILY 7
#define TTFUN_WRITE_STEM 8
#define TTFUN_VERTICAL 9
#define TTFUN_HORIZONTAL 10
#define TTFUN_VCENTER 11
#define TTFUN_HCENTER 12
#define TTFUN_RELATIVE1V 13
#define TTFUN_RELATIVE2V 14
#define TTFUN_RELATIVE1H 15
#define TTFUN_RELATIVE2H 16
#define TTFUN_SIDE1 17
#define TTFUN_SIDE2 18
#define TTFUN_FLEX 19
#define TTFUN_SCALE3 20
#define TTFUN_SHIFT1 21
#define TTFUN_SHIFT2 22
#define TTFUN_IP1 23
#define TTFUN_IP2 24
#define TTFUN_IPN 25
#define TTFUN_SHP1 26
#define TTFUN_SHP2 27
#define TTFUN_SHPN 28
#define TTFUN_RANGE 29
#define TTFUN_OBLIQUE 30
#define TTFUN_NUM 31 /* 1..30 */
#define FDEF(name) op_pushb1, name, op_fdef,
#define ENDF op_endf,
#define CALL(name) op_pushb1, name, op_call
#define WCVT(name) op_pushb1, name, op_swap, op_wcvtf
#define PUSH1(v) op_pushb1, (v)
#define PUSH2(v1, v2) op_pushb1+1, (v1), (v2)
#define PUSH3(v1, v2, v3) op_pushb1+2, (v1), (v2), (v3)
#define PUSH4(v1, v2, v3, v4) op_pushb1+3, (v1), (v2), (v3), (v4)
#define PUSH5(v1,v2,v3,v4,v5) op_pushb1+4, (v1), (v2), (v3), (v4), (v5)
static const UBYTE FontProg[] = {
/******* SET ZONE FUNCTION
* * Args: flat_pos * */ FDEF(TTFUN_SET_ZONE) PUSH1(TMPPNT), op_swap, op_miap, PUSH1(TMPPNT), op_mdap | SUBOP_R, ENDF
/******* COPY ZONE FUNCTION
* * Args: from_cvt, to_cvt * */ FDEF(TTFUN_COPY_ZONE) op_rcvt, op_round, op_wcvtp, ENDF
/******* STEM SNAP WIDTH FUNCTION
* * Args: std_ci, std_cvt, snap_ci, snap_cvt, width, storage * */ FDEF(TTFUN_STEM_SNAP_WIDTH) op_mppem, op_gteq, op_if,
/* Use std */ op_rcvt, op_round, PUSH1(ONEPIXEL/2), op_max, op_swap, op_pop, op_swap, op_pop, op_swap, op_pop, CALL(TTFUN_WRITE_STEM), op_else, op_pop, op_mppem, op_gteq, op_if, /* Use snap */ op_rcvt, op_round, PUSH1(ONEPIXEL/2), op_max, op_swap, op_pop, CALL(TTFUN_WRITE_STEM), /* Use real width. */ op_else, op_pop, WCVT(TMPCVT), PUSH1(TMPCVT), op_rcvt, op_round, PUSH1(ONEPIXEL/2), op_max, CALL(TTFUN_WRITE_STEM), op_eif, op_eif, ENDF
/******* STEM STD WIDTH FUNCTION
* * Args: std_ci, std_cvt, width, storage * */ FDEF(TTFUN_STEM_STD_WIDTH) op_mppem, op_gteq, op_if, /* Use std */ op_rcvt, op_round, PUSH1(ONEPIXEL/2), op_max, op_swap, op_pop, CALL(TTFUN_WRITE_STEM), /* Use real width. */ op_else, op_pop, WCVT(TMPCVT), PUSH1(TMPCVT), op_rcvt, op_round, PUSH1(ONEPIXEL/2), op_max, CALL(TTFUN_WRITE_STEM), op_eif, ENDF
/******* SHIFT BLUE ZONE FUNCTION
* * Args: cvt * */ FDEF(TTFUN_SHIFT_BLUE_ZONE) PUSH5(TMPPNT1, TMPPNT1, TMPPNT, TMPPNT1, 5), op_cindex, op_miap, op_srp0, op_mdrp | SUBOP_mMRGR, op_gc, op_wcvtp, ENDF
/******* ALIGN BLUE ZONE FUNCTION
* * Args: cvt * */ FDEF(TTFUN_ALIGN_BLUE_ZONE) PUSH5(TMPPNT1, TMPPNT1, TMPPNT, TMPPNT1, 5), op_cindex, op_miap, op_srp0, op_mdrp | SUBOP_ROUND, op_gc, op_wcvtp, ENDF
/******* COPY FAMILY FUNCTION
* * Args: base_cvt * */ FDEF(TTFUN_COPY_FAMILY) op_dup, PUSH1(1), op_add, op_rcvt, op_wcvtp, ENDF
/******* WRITE STEM FUNCTION
* * Args: width, storage * */ FDEF(TTFUN_WRITE_STEM) op_dup, /* -| width, width, storage */ op_dup, /* -| width, width, width, storage */ op_add, /* -| 2*width, width, storage, */ op_odd, /* -| odd/even, width, storage */ PUSH2(1, 4), /* -| 4, 1, odd/even, width, storage */ op_cindex, /* -| storage, 1, odd/even, width, storage */ op_add, op_swap, /* -| odd/even, storage+1, width, storage */ op_ws, op_ws, ENDF
/******* VERTICAL FUNCTION
* * Args: -*none*- * */ FDEF(TTFUN_VERTICAL) op_svcta | SUBOP_X, PUSH1(TWILIGHT), op_szps, ENDF
/******* HORIZONTAL FUNCTION
* * Args: -*none*- * */ FDEF(TTFUN_HORIZONTAL) PUSH1(TWILIGHT), op_svcta, op_szps, ENDF
/******* CENTER VSTEM FUNCTION
* * Args: p1, p2, p3, p4, c, tz1, width * */ FDEF(TTFUN_VCENTER)
/* Set rounding state for the center. */ PUSH2(1, 8), op_cindex, op_add, op_rs, op_if, op_rthg, op_else, op_rtg, op_eif,
/* Create the stem in the twilight zone. */ WCVT(TMPCVT), PUSH2(TMPCVT, 6), op_cindex, op_swap, op_miap,
WCVT(TMPCVT), PUSH3(TMPCVT, 1, 6), op_cindex, op_add, op_swap, op_miap,
WCVT(TMPCVT), PUSH3(TMPCVT, 2, 5), op_cindex, op_add, op_swap, op_miap,
WCVT(TMPCVT), PUSH3(TMPCVT, 3, 4), op_cindex, op_add, op_swap, op_miap,
/* Move/round center. */ WCVT(TMPCVT), /* c */ PUSH2(TMPPNT, TMPCVT), op_miap| SUBOP_R, op_rtg,
/* Align all points to the center. */ op_dup, op_dup, PUSH1(1), op_add, op_alignrp, op_alignrp, /* tz1, tz1+1 */
/* Compute the width. */ op_swap, op_rs, PUSH1(CURVEPHASE), op_sub, op_swap,
/* -| tz1, width */ op_dup, op_dup, op_dup, op_srp0, PUSH1(4), op_cindex, op_neg, /* -| (-width/2), tz1, tz1, tz1, width */ op_shpix, PUSH1(2), op_add, op_alignrp, /* -| tz1+2, tz1, width */
/* Do the other side. */ /* -| tz1, width */ PUSH1(1), op_add, op_dup, op_dup, /* -| tz1+1, tz1+1, tz1+1, width */ op_srp0, op_roll, /* -| width, tz1+1, tz1+1 */ op_shpix, PUSH1(2), op_add, op_alignrp, /* -| tz1+3 */
/* Done. */ ENDF
/******* CENTER HSTEM FUNCTION
* * Args: p1, p2, c, tz1, width * */ FDEF(TTFUN_HCENTER)
/* Set,rounding state for the center. */ PUSH2(1, 6), op_cindex, op_add, op_rs, op_if, op_rthg, op_else, op_rtg, op_eif,
/* Create the stem in the twilight zone. */ WCVT(TMPCVT), PUSH2(TMPCVT, 4), op_cindex, op_swap, op_miap,
WCVT(TMPCVT), PUSH3(TMPCVT, 1, 4), op_cindex, op_add, op_swap, op_miap,
/* Move/round center. */ WCVT(TMPCVT), /* c */ PUSH2(TMPPNT, TMPCVT), op_miap| SUBOP_R, op_rtg,
/* Align all points to the center. */ op_dup, op_dup, PUSH1(1), op_add, op_alignrp, op_alignrp, /* tz1, tz1+1 */
/* Compute the width. */ op_swap, op_rs, PUSH1(CURVEPHASE), op_sub, op_swap,
/* -| tz1, width */ op_dup, PUSH1(3), op_cindex, op_neg, /* -| -width, tz1, tz1, width */ op_shpix,
/* Do the other side. */ /* -| tz1, width */ PUSH1(1), op_add, op_swap, /* -| width, tz1+1 */ op_shpix,
/* Done. */ ENDF
/******* RELATIVE1V STEM FUNCTION
* * Args: p1, p2, p3, p4, ref, tz1, width * */ FDEF(TTFUN_RELATIVE1V)
/* Create the stem in the twilight zone. */ WCVT(TMPCVT), PUSH2(TMPCVT, 6), op_cindex, op_swap, op_miap,
WCVT(TMPCVT), PUSH3(TMPCVT, 1, 6), op_cindex, op_add, op_swap, op_miap,
WCVT(TMPCVT), PUSH3(TMPCVT, 2, 5), op_cindex, op_add, op_swap, op_miap,
WCVT(TMPCVT), PUSH3(TMPCVT, 3, 4), op_cindex, op_add, op_swap, op_miap,
/* Move/round side. */ op_srp0, op_dup, op_mdrp | SUBOP_MmRGR,
/* Align points on the left side. */ op_dup, PUSH1(1), op_add, op_dup, op_dup, op_dup, PUSH1(1), op_add, /* -| tz1+2, tz1+1, tz1+1, tz+1, tz, width */ op_alignrp, op_alignrp,
/* Align right side */ op_srp0, /* -| tz1+1, tz1, width */ op_roll, op_rs, op_dup, op_add, /* -| width*2, tz1+1, tz1 */ op_shpix, PUSH1(3), op_add, op_alignrp, /* -| tz1+3 */
ENDF
/******* RELATIVE2V STEM FUNCTION
* * Args: p1, p2, p3, p4, ref, tz1, width * */ FDEF(TTFUN_RELATIVE2V)
/* Create the stem in the twilight zone. */ WCVT(TMPCVT), PUSH2(TMPCVT, 6), op_cindex, op_swap, op_miap,
WCVT(TMPCVT), PUSH3(TMPCVT, 1, 6), op_cindex, op_add, op_swap, op_miap,
WCVT(TMPCVT), PUSH3(TMPCVT, 2, 5), op_cindex, op_add, op_swap, op_miap,
WCVT(TMPCVT), PUSH3(TMPCVT, 3, 4), op_cindex, op_add, op_swap, op_miap,
/* Move/round side. */ op_srp0, op_dup, PUSH1(1), op_add, op_mdrp | SUBOP_MmRGR,
/* Align points on the left side. */ op_dup, op_dup, op_dup, op_dup, PUSH1(3), op_add, /* -| tz1+3, tz1, tz1, tz1, tz1, width */ op_alignrp, op_alignrp,
/* Align left side */ op_srp0, /* -| tz1, tz1, width */ op_roll, op_rs, op_dup, op_add, op_neg, op_shpix, /* -| -2*width, tz1, tz1 */ PUSH1(2), op_add, op_alignrp, /* -| tz1+2 */
ENDF
/******* RELATIVE1H STEM FUNCTION
* * Args: p1, p2, ref, tz1, width * */ FDEF(TTFUN_RELATIVE1H)
/* Create the stem in the twilight zone. */ WCVT(TMPCVT), PUSH2(TMPCVT, 4), op_cindex, op_swap, op_miap,
WCVT(TMPCVT), PUSH3(TMPCVT, 1, 4), op_cindex, op_add, op_swap, op_miap,
/* Move/round side. */ op_srp0, op_dup, op_mdrp | SUBOP_MmRGR,
/* Align all point to the lower side. */ PUSH1(1), op_add, op_dup, op_alignrp,
/* Align right side */ op_swap, op_rs, op_dup, op_add, op_shpix,
ENDF
/******* RELATIVE2H STEM FUNCTION
* * Args: p1, p2, ref, tz1, width * */ FDEF(TTFUN_RELATIVE2H)
/* Create the stem in the twilight zone. */ WCVT(TMPCVT), PUSH2(TMPCVT, 4), op_cindex, op_swap, op_miap,
WCVT(TMPCVT), PUSH3(TMPCVT, 1, 4), op_cindex, op_add, op_swap, op_miap,
/* Move/round side. */ op_srp0, op_dup, PUSH1(1), op_add, op_mdrp | SUBOP_MmRGR,
/* Align all points to the center. */ op_dup, op_alignrp,
/* Align left side */ op_swap, op_rs, op_dup, op_add, op_neg, op_shpix,
ENDF
/******* SIDE1 STEM FUNCTION
* * Args: p1, p2, zone, tz1, width * */ FDEF(TTFUN_SIDE1)
/* Create the stem in the twilight zone. */ WCVT(TMPCVT), PUSH2(TMPCVT, 4), op_cindex, op_swap, op_miap,
WCVT(TMPCVT), PUSH3(TMPCVT, 1, 4), op_cindex, op_add, op_swap, op_miap,
/* Move/round side. */ PUSH2(TMPPNT, TMPPNT), op_srp0, op_swap, op_miap | SUBOP_R,
/* Align all points to the side. */ op_dup, PUSH1(1), op_add, op_dup, op_roll, op_alignrp, op_alignrp,
/* Align first side */ op_swap, op_rs, op_dup, op_add, PUSH1(CURVEPHASE), op_sub, op_shpix,
ENDF
/******* SIDE2 STEM FUNCTION
* * Args: p1, p2, zone, tz1, width * */ FDEF(TTFUN_SIDE2)
/* Create the stem in the twilight zone. */ WCVT(TMPCVT), PUSH2(TMPCVT, 4), op_cindex, op_swap, op_miap,
WCVT(TMPCVT), PUSH3(TMPCVT, 1, 4), op_cindex, op_add, op_swap, op_miap,
/* Move/round side. */ PUSH2(TMPPNT, TMPPNT), op_srp0, op_swap, op_miap | SUBOP_R,
/* Align all points to the side. */ op_dup, op_dup, PUSH1(1), op_add, op_alignrp, op_alignrp,
/* Align second side */ op_swap, op_rs, op_dup, op_add, PUSH1(CURVEPHASE), op_sub, op_neg, op_shpix,
ENDF
/******* FLEX FUNCTION
* * Args on the stack: pnt_start, pnt_mid, ref_pos, pnt_mid, * pnt_start, pnt_mid, cnt, p1, p2, .... * */ FDEF(TTFUN_FLEX) op_srp0, op_alignrp, op_wcvtf, op_rcvt, op_shpix, op_srp1, op_srp2, op_sloop, op_ip, ENDF
/******* SCALE3 FUNCTION
* * Args: cnt, p1, p2, ... * */ FDEF(TTFUN_SCALE3) PUSH4(GLYPHZONE, TMPPNT1, TMPPNT, TMPPNT1), op_pushw1, HIBYTE(-31), LOBYTE(-31), PUSH3(TMPPNT, 0, TMPPNT1), op_pushw1, HIBYTE(1000), LOBYTE(1000), op_scfs, op_scfs, op_shpix, op_srp1, op_srp2, op_szp2, op_sloop, op_ip, ENDF
/******* SHIFT1 FUNCTION
* * Args: cnt reduction p1 p2 ... * */ FDEF(TTFUN_SHIFT1) op_sloop, op_rs, op_neg, op_shpix, ENDF
/******* SHIFT2 FUNCTION
* * Args: cnt reduction p1 p2 ... * */ FDEF(TTFUN_SHIFT2) op_sloop, op_rs, op_shpix, ENDF
/******* IP1 FUNCTION
* * Args: rp1, rp2, p1 * */ FDEF(TTFUN_IP1) op_srp1, op_srp2, op_ip, ENDF
/******* IP2 FUNCTION
* * Args: rp1, rp2, p1, p2 * */ FDEF(TTFUN_IP2) op_srp1, op_srp2, op_ip, op_ip, ENDF
/******* IPN FUNCTION
* * Args: rp1, rp2, cnt, p1, p2 * */ FDEF(TTFUN_IPN) op_srp1, op_srp2, op_sloop, op_ip, ENDF
/******* SHP1 FUNCTION
* * Args: rp, p * */ FDEF(TTFUN_SHP1) op_srp1, op_shp, ENDF
/******* SHP2 FUNCTION
* * Args: rp, p1, p2 * */ FDEF(TTFUN_SHP2) op_srp1, op_shp, op_shp, ENDF
/******* SHPN FUNCTION
* * Args: rp, cnt, p1, p2 * */ FDEF(TTFUN_SHPN) op_srp1, op_sloop, op_shp, ENDF
/******* RANGE FUNCTION
* * Args: p * */ FDEF(TTFUN_RANGE) op_dup, PUSH1(1), op_add, ENDF
/******* RANGE FUNCTION
* * Args: pos_x, pos_y, * */ FDEF(TTFUN_OBLIQUE) op_svcta | SUBOP_Y, PUSH1(TMPPNT1), op_swap, op_scfs, PUSH2(TMPPNT, 0), op_scfs, op_svcta | SUBOP_X, PUSH1(TMPPNT1), op_swap, op_scfs, PUSH2(TMPPNT, 0), op_scfs, PUSH2(TMPPNT, TMPPNT1), op_spvtl, ENDF
};
/***** LOCAL TYPES */
/***** STATIC FUNCTIONS */
/***
** Function: GetVStemWidth ** ** Description: ** This function allocates a storage entry for the ** width of a vertical stem; ***/ static short GetVStemWidth(WeightControl *weight, const funit width) { StemWidth *newwidths = NULL; short entry = 0; USHORT j;
if (weight->cnt_vw >= weight->max_vw) { newwidths = Realloc(weight->vwidths, sizeof(StemWidth)*(weight->max_vw+BUFSIZE)); if (newwidths == NULL) { entry = NOMEM; } else { weight->vwidths = newwidths; weight->max_vw += BUFSIZE; } }
if (entry != NOMEM) { for (j=0; j<weight->cnt_vw; j++) { if (weight->vwidths[j].width==width) { entry = (short)weight->vwidths[j].storage; break; } }
if (j==weight->cnt_vw) { weight->vwidths[weight->cnt_vw].storage = weight->storage; weight->vwidths[weight->cnt_vw].width = width; entry = (short)weight->storage; weight->storage += 2; weight->cnt_vw++; } }
return entry; }
/***
** Function: GetHStemWidth ** ** Description: ** This function allocates a storage entry for the ** width of a vertical stem; ***/ static short GetHStemWidth(WeightControl *weight, const funit width) { StemWidth *newwidths = NULL; short entry = 0; USHORT j;
if (weight->cnt_hw >= weight->max_hw) { newwidths = Realloc(weight->hwidths, sizeof(StemWidth)*(weight->max_hw+BUFSIZE)); if (newwidths == NULL) { entry = NOMEM; } else { weight->hwidths = newwidths; weight->max_hw += BUFSIZE; } }
if (entry != NOMEM) { for (j=0; j<weight->cnt_hw; j++) { if (weight->hwidths[j].width==width) { entry = (short)weight->hwidths[j].storage; break; } }
if (j==weight->cnt_hw) { weight->hwidths[weight->cnt_hw].storage = weight->storage; weight->hwidths[weight->cnt_hw].width = width; entry = (short)weight->storage; weight->storage += 2; weight->cnt_hw++; } }
return entry; }
/***** GLOBAL FUNCTIONS */
/***
** Function: SetZone ** ** Description: ** This function initiate an alignment zone ** by creating an appropriate point in the ** twilight zone. ***/ USHORT SetZone(UBYTE *prep, USHORT tp, const short cvt) { /* Set up the zone. */ if (cvt>255) { prep[tp++] = op_pushw1; prep[tp++] = HIBYTE(cvt); prep[tp++] = LOBYTE(cvt); prep[tp++] = op_pushb1; prep[tp++] = TTFUN_SET_ZONE; } else { prep[tp++] = op_pushb1 + 1; prep[tp++] = (UBYTE)cvt; prep[tp++] = TTFUN_SET_ZONE; } prep[tp++] = op_call;
return tp; }
/***
** Function: CopyZone ** ** Description: ** This function copies a cvt entry, representing an ** alignment zone, to the cvt used for a particular hstem. ***/ USHORT CopyZone(UBYTE *prep, short tp, short *args, const short ta) { args[0] = TTFUN_COPY_ZONE; args[1] = (short)((ta-2)/2); AssembleArgs(args, ta, prep, &tp); prep[tp++] = op_loopcall;
return (USHORT)tp; }
/***
** Function: CopyFamilyBlue ** ** Description: ** This function copies a cvt entry, representing a ** family blue zone, to the cvt used for a particular hstem. ***/ USHORT CopyFamilyBlue(UBYTE *prep, short tp, short *args, const short ta) { args[0] = TTFUN_COPY_FAMILY; args[1] = (short)(ta-2); AssembleArgs(args, ta, prep, &tp); prep[tp++] = op_loopcall;
return (USHORT)tp; }
/***
** Function: AlignFlat ** ** Description: ** This function creates a cvt entry for ** a particular hstem. ***/ USHORT AlignFlat(UBYTE *prep, short tp, short *args, const short ta) { args[0] = TTFUN_ALIGN_BLUE_ZONE; args[1] = (short)(ta-2); AssembleArgs(args, ta, prep, &tp); prep[tp++] = op_loopcall;
return (USHORT)tp; }
/***
** Function: AlignOvershoot ** ** Description: ** This function creates a cvt entry for ** a particular hstem. ***/ USHORT AlignOvershoot(UBYTE *prep, short tp, short *args, const short ta) { args[0] = TTFUN_SHIFT_BLUE_ZONE; args[1] = (short)(ta-2); AssembleArgs(args, ta, prep, &tp); prep[tp++] = op_loopcall;
return (USHORT)tp; }
/***
** Function: GetTopPos ** ** Description: ** This function allocates a cvt entry for the ** top side of a horizontal stem; ***/ short GetTopPos(const Blues *blues, AlignmentControl *align, const funit pos) { short entry = UNDEF; const funit *bluevals; short fuzz; USHORT i, j;
bluevals = &(blues->bluevalues[0]); fuzz = blues->blueFuzz;
/* Check if it is within a zone. */ for (i=0; i<blues->blue_cnt; i+=2) { if (((bluevals[i]-fuzz)<=pos) && ((bluevals[i+1]+fuzz)>=pos)) break; }
/* Record the position? */ if (i!=blues->blue_cnt) { i /= 2;
/* Is the position already mapped to a cvt entry? */ for (j=0; j<align->top[i].cnt; j++) { if (align->top[i].pos[j].y==pos) { entry = (short)align->top[i].pos[j].cvt; break; } }
if (j==align->top[i].cnt) {
/* Allocate the BlueZone cvt's */ if (align->top[i].cnt==0) { align->top[i].blue_cvt = align->cvt; align->cvt +=2; }
align->top[i].pos[align->top[i].cnt].cvt = align->cvt; align->top[i].pos[align->top[i].cnt].y = pos; entry = (short)align->cvt; align->cvt+=2; align->top[i].cnt++; } }
return entry; }
/***
** Function: GetBottomPos ** ** Description: ** This function allocates a cvt entry for the ** top side of a horizontal stem; ***/ short GetBottomPos(const Blues *blues, AlignmentControl *align, const funit pos) { short entry = UNDEF; const funit *bluevals; short fuzz; USHORT i, j;
bluevals = &(blues->otherblues[0]); fuzz = blues->blueFuzz;
/* Check if it is within a zone. */ for (i=0; i<blues->oblue_cnt; i+=2) { if (((bluevals[i]-fuzz)<=pos) && ((bluevals[i+1]+fuzz)>=pos)) break; }
/* Record the position? */ if (i!=blues->oblue_cnt) { i /= 2;
/* Is the position already mapped to a cvt entry? */ for (j=0; j<align->bottom[i].cnt; j++) { if (align->bottom[i].pos[j].y==pos) { entry = (short)align->bottom[i].pos[j].cvt; break; } }
if (j==align->bottom[i].cnt) {
/* Allocate the BlueZone and FamilyBlue cvt's */ if (align->bottom[i].cnt==0) { align->bottom[i].blue_cvt = align->cvt++; }
align->bottom[i].pos[align->bottom[i].cnt].cvt = align->cvt; align->bottom[i].pos[align->bottom[i].cnt].y = pos; entry = (short)align->cvt; align->cvt+=2; align->bottom[i].cnt++; } }
return entry; }
/***
** Function: CutInSize ** ** Description: ** This function computes the cut in size ** of a stem, given a master width and the ** width of the stem. This is done with the ** StdVW==2.0 pixel treshold and the thinn ** and wide cut in values. ***/ USHORT CutInSize(const funit width, const funit master, const USHORT tresh, const funit upem) { USHORT cis, ci1, ci2;
/*lint -e776 */ if (width > master) { ci1 = (USHORT)((long)upem * SMALL_UPPER / ONEPIXEL / (long)(width - master)); ci2 = (USHORT)((long)upem * LARGE_UPPER / ONEPIXEL / (long)(width - master)); } else if (width < master) { ci1 = (USHORT)((long)upem * SMALL_LOWER / ONEPIXEL / (long)(master - width)); ci2 = (USHORT)((long)upem * LARGE_LOWER / ONEPIXEL / (long)(master - width)); } else { ci1 = INFINITY; ci2 = INFINITY; } /*lint +e776 */
if (ci1 < tresh) { cis = ci1; } else if (ci2 < tresh) { cis = tresh; } else { cis = ci2; }
return cis; }
/***
** Function: SnapStemArgs ** ** Description: ** ***/ USHORT SnapStemArgs(short *args, USHORT ta, const funit width, const USHORT std_cvt, const USHORT snap_cvt, const USHORT std_ci, const USHORT snap_ci, const USHORT storage) { args[ta++] = (short)std_ci; args[ta++] = (short)std_cvt; args[ta++] = (short)snap_ci; args[ta++] = (short)snap_cvt; args[ta++] = (short)(width/2); args[ta++] = (short)storage;
return ta; }
/***
** Function: StdStemArgs ** ** Description: ** ***/ USHORT StdStemArgs(short *args, USHORT ta, const funit width, const USHORT std_cvt, const USHORT std_ci, const USHORT storage) { args[ta++] = (short)std_ci; args[ta++] = (short)std_cvt; args[ta++] = (short)(width/2); args[ta++] = (short)storage;
return ta; }
/***
** Function: CreateStdStems ** ** Description: ** ***/ USHORT CreateStdStems(UBYTE *prep, USHORT tp, const short cnt) { if (cnt>255) { prep[tp++] = op_pushw1; prep[tp++] = HIBYTE(cnt); prep[tp++] = LOBYTE(cnt); prep[tp++] = op_pushb1; prep[tp++] = TTFUN_STEM_STD_WIDTH; } else { prep[tp++] = op_pushb1 + 1; prep[tp++] = (UBYTE)cnt; prep[tp++] = TTFUN_STEM_STD_WIDTH; }
prep[tp++] = op_loopcall;
return tp; }
/***
** Function: CreateSnapStems ** ** Description: ** ***/ USHORT CreateSnapStems(UBYTE *prep, USHORT tp, const short cnt) { if (cnt>255) { prep[tp++] = op_pushw1; prep[tp++] = HIBYTE(cnt); prep[tp++] = LOBYTE(cnt); prep[tp++] = op_pushb1; prep[tp++] = TTFUN_STEM_SNAP_WIDTH; } else { prep[tp++] = op_pushb1 + 1; prep[tp++] = (UBYTE)cnt; prep[tp++] = TTFUN_STEM_SNAP_WIDTH; }
prep[tp++] = op_loopcall;
return tp; }
/***
** Function: tt_GetFontProg ** ** Description: ** This function returns the static font ** font program. ***/ const UBYTE *tt_GetFontProg(void) { return FontProg; }
/***
** Function: tt_GetFontProgSize ** ** Description: ** This function returns the size of the ** static font program. ***/ USHORT tt_GetFontProgSize(void) { return (USHORT)sizeof(FontProg); }
/***
** Function: tt_GetNumFuns ** ** Description: ** This function returns the number of functions ** defined in the static font program. ***/ USHORT tt_GetNumFuns(void) { return (USHORT)TTFUN_NUM; }
/***
** Function: EmitFlex ** ** Description: ** Convert a T1 flex hint into a TrueType IP[] ** intruction sequence that will reduce a flex ** that is flatter than a given height. ***/ errcode EmitFlex(short *args, short *pcd, const funit height, const short start, const short mid, const short last) { errcode status = SUCCESS; int i;
/* Enough space for the instructions? */ args[(*pcd)++] = TTFUN_FLEX; args[(*pcd)++] = start; args[(*pcd)++] = mid; args[(*pcd)++] = (short)height; args[(*pcd)++] = TMPCVT; args[(*pcd)++] = TMPCVT; args[(*pcd)++] = mid; args[(*pcd)++] = start; args[(*pcd)++] = mid;
/* Push the flex points onto the stack. */ args[(*pcd)++] = (short)(last-start-2); for (i=start+(short)1; i<last; i++) if (i!=mid) args[(*pcd)++] = (short)i;
return status; }
/***
** Function: ReduceDiagonals ** ** Description: ** This function generates the TT instructions ** that will shrink the outline, in order to ** control the width of diagonals. This implementation ** can probably be improved. ***/ short ReduceDiagonals(const Outline *paths, UBYTE *pgm, short *pc, short *args, short *pcd) { short cw[MAXTHINPNTS]; short ccw[MAXTHINPNTS]; short targ[MAXTHINPNTS]; const Outline *path; Point *pts; short i,j; short cwi = 0, ccwi = 0; short prev; short n,m; short prev_cw, prev_ccw; short ta;
/* Collect points on left and right side that are diagonals. */ i = 0; for (path = paths; path && ccwi<MAXTHINPNTS && cwi<MAXTHINPNTS; path=path->next) {
pts = &path->pts[0]; prev_cw = FALSE; prev_ccw = FALSE;
/* Are the first and last point coinciding? */ if (pts[path->count-1].x!=pts[0].x || pts[path->count-1].y!=pts[0].y) prev = (short)(path->count-(short)1); else prev = (short)(path->count-(short)2);
/* Special case the first point. */ if (!OnCurve(path->onoff, prev) || (pts[0].x != pts[prev].x && ABS(pts[0].x - pts[prev].x) < ABS(pts[0].y - pts[prev].y)*8)) { if (pts[0].y>pts[prev].y+20) { if (pts[prev].y<=pts[prev-1].y) cw[cwi++] = (short)(i+(short)path->count-1); cw[cwi++] = i; prev_cw = TRUE; prev_ccw = FALSE; } else if (pts[0].y<pts[prev].y-20) { if (pts[prev].y>=pts[prev-1].y) ccw[ccwi++] = (short)(i+(short)path->count-1); ccw[ccwi++] = i; prev_cw = FALSE; prev_ccw = TRUE; } }
for (j=1; j<(short)path->count && ccwi<MAXTHINPNTS && cwi<MAXTHINPNTS; j++) { i++; if (!OnCurve(path->onoff, j-1) || (pts[j].x != pts[j-1].x && ABS(pts[j].x - pts[j-1].x) < ABS(pts[j].y - pts[j-1].y)*8)) { if (pts[j].y>pts[j-1].y+20) { if (!prev_cw) cw[cwi++] = (short)(i-1); cw[cwi++] = i; prev_cw = TRUE; prev_ccw = FALSE; } else if (pts[j].y<pts[j-1].y-20) { if (!prev_ccw) ccw[ccwi++] = (short)(i-1); ccw[ccwi++] = i; prev_cw = FALSE; prev_ccw = TRUE; } else { prev_cw = FALSE; prev_ccw = FALSE; } } else { prev_cw = FALSE; prev_ccw = FALSE; } } i++; }
/* Did we get all points? */ if (ccwi>=MAXTHINPNTS || cwi>=MAXTHINPNTS) { LogError(MSG_WARNING, MSG_DIAG, NULL); }
/* Any points to shift? */ if (cwi || ccwi) { args[(*pcd)++] = STORAGE_DIAG; pgm[(*pc)++] = op_rs; pgm[(*pc)++] = op_if; pgm[(*pc)++] = op_svcta + SUBOP_X;
/* Switch over to GLYPHZONE */ pgm[(*pc)++] = op_szp2; args[(*pcd)++] = 1;
ta = 3;
/* Disable "cw[m] may not have been initialized".*/ /*lint -e644 */ for (n=0; n<cwi; n=m) { for (m=(short)(n+1); m<cwi && cw[m]==cw[m-1]+1; m++); /*lint +e644 */ if (m-n<=4) { for (i=n; i<m; i++) targ[ta++] = cw[i]; } else { targ[0] = TTFUN_RANGE; targ[1] = (short)(m-n-1); targ[2] = cw[n]; AssembleArgs(targ, ta, pgm, pc); pgm[(*pc)++] = op_loopcall; ta = 3; } } targ[0] = TTFUN_SHIFT1; targ[1] = cwi; targ[2] = STORAGE_DIAG; AssembleArgs(targ, ta, pgm, pc); pgm[(*pc)++] = op_call;
/************ Shift back the left side of the glyph. */
ta = 3;
/* Disable "ccw[m] may not have been initialized".*/ /*lint -e644 */ for (n=0; n<ccwi; n=m) { for (m=(short)(n+1); m<ccwi && ccw[m]==ccw[m-1]+1; m++); /*lint +e644 */ if (m-n<=4) { for (i=n; i<m; i++) targ[ta++] = ccw[i]; } else { targ[0] = TTFUN_RANGE; targ[1] = (short)(m-n-1); targ[2] = ccw[n]; AssembleArgs(targ, ta, pgm, pc); pgm[(*pc)++] = op_loopcall; ta = 3; } } targ[0] = TTFUN_SHIFT2; targ[1] = ccwi; targ[2] = STORAGE_DIAG; AssembleArgs(targ, ta, pgm, pc); pgm[(*pc)++] = op_call;
#ifdef SYMETRICAL_REDUCTION
/* The amount that the outline is shrunk is computed once at
each size, in the pre-program. The outline is shrunk symetrically by the amount: 1/16 + (12 Funits)*size/UPEm.
This approach yields more symmetrical results than shrinking the outline horizontally alone (see separate papers on the topic). */
/* Same thing for the height... */ i = 0; cwi = 0; ccwi = 0; for (path = paths; path && ccwi<MAXTHINPNTS && cwi<MAXTHINPNTS; path=path->next) {
pts = &path->pts[0];
/* Are the first and last point coinciding? */ if (pts[path->count-1].y!=pts[0].y || pts[path->count-1].x!=pts[0].x) prev = path->count-1; else prev = path->count-2;
if (!OnCurve(path->onoff, prev) || (pts[0].y != pts[prev].y && ABS(pts[0].y - pts[prev].y) < ABS(pts[0].x - pts[prev].x)*8)) { if (pts[0].x>pts[prev].x+20) { if (pts[prev].x<=pts[prev-1].x) cw[cwi++] = i+path->count-1; cw[cwi++] = i; } else if (pts[0].x<pts[prev].x-20) { if (pts[prev].x>=pts[prev-1].x) ccw[ccwi++] = i+path->count-1; ccw[ccwi++] = i; } }
for (j=1; j<path->count && ccwi<MAXTHINPNTS && cwi<MAXTHINPNTS; j++) { i++; if (!OnCurve(path->onoff, j-1) || (pts[j].y != pts[j-1].y && ABS(pts[j].y - pts[j-1].y) < ABS(pts[j].x - pts[j-1].x)*8)) { if (pts[j].x>pts[j-1].x+20) { if (!cwi || cw[cwi-1]!=i-1) cw[cwi++] = i-1; cw[cwi++] = i; } else if (pts[j].x<pts[j-1].x-20) { if (!ccwi || ccw[ccwi-1]!=i-1) ccw[ccwi++] = i-1; ccw[ccwi++] = i; } } } i++; }
if (ccwi>=MAXTHINPNTS || cwi>=MAXTHINPNTS) { LogError(MSG_WARNING, MSG_DIAG, NULL); }
/* Any points to shift? */ if (cwi || ccwi) { pgm[(*pc)++] = op_svcta + SUBOP_Y;
for (n=0; n<cwi; n=m) { for (m=n+1; m<cwi && cw[m]==cw[m-1]+1; m++); pgm[(*pc)++] = op_pushb1 + 2; pgm[(*pc)++] = cw[n]; pgm[(*pc)++] = (UBYTE)(m-n-1); pgm[(*pc)++] = TTFUN_RANGE; pgm[(*pc)++] = op_loopcall; } pgm[(*pc)++] = op_pushb1+2; pgm[(*pc)++] = STORAGE_DIAG; pgm[(*pc)++] = cwi; pgm[(*pc)++] = TTFUN_SHIFT2; pgm[(*pc)++] = op_call;
/************ Shift back the left side of the glyph. */
for (n=0; n<ccwi; n=m) { for (m=n+1; m<ccwi && ccw[m]==ccw[m-1]+1; m++); pgm[(*pc)++] = op_pushb1 + 2; pgm[(*pc)++] = (UBYTE)ccw[n]; pgm[(*pc)++] = (UBYTE)(m-n-1); pgm[(*pc)++] = TTFUN_RANGE; pgm[(*pc)++] = op_loopcall; } pgm[(*pc)++] = op_pushb1+2; pgm[(*pc)++] = STORAGE_DIAG; pgm[(*pc)++] = (UBYTE)ccwi; pgm[(*pc)++] = TTFUN_SHIFT1; pgm[(*pc)++] = op_call; } #endif
pgm[(*pc)++] = op_eif; }
/* Args + num of args + function number. */ return (short)(MAX(cwi, ccwi)+2); }
/***
** Function: ScaleDown3 ** ** Description: ** This function generates the TT instructions ** that will scale down points 3%. ***/ void ScaleDown3(const Extremas *extr, const short xcnt, UBYTE *pgm, short *pc, short *args, short *pcd) { short i,j,offset, opc, opcd;
/* Remember the state of the stacks. */ opc = (*pc); opcd = (*pcd);
args[(*pcd)++] = TTFUN_SCALE3;
offset = (*pcd)++; args[offset] = 0; for (i=0; i<xcnt; i++) { if ((extr[i].rp1==UNDEF || extr[i].rp2==UNDEF)) { for (j=0; j<extr[i].n; j++) { args[(*pcd)++] = extr[i].pts[j]; } args[offset] = (short)(args[offset] + extr[i].n); } } if (args[offset]>0) { pgm[(*pc)++] = op_call; } else { /* Back track. */ (*pc) = opc; (*pcd) = opcd; } }
/***
** Function: EmitIP ** ** Description: ** This function generates the TT instructions ** that will interpolate points that are either ** within or between stem sides. ***/ void EmitIP(const Extremas *extr, const short xcnt, UBYTE *pgm, short *pc, short *args, short *pcd, const short scale3offset) { short i,j,num; short ones[MAXIP], twoes[MAXIP], nths[MAXIP]; short cnt1, cnt2, cntn;
/*lint -e530 -e644 */ /* Shift extrems. */ cnt1 = 0; cnt2 = 0; cntn = 0; num = 0; for (i=0; i<xcnt; i++) { short rp;
/* Skip interpolations. */ if (extr[i].rp1!=UNDEF && extr[i].rp2!=UNDEF) continue;
/* Set the reference points. */ if (extr[i].rp1!=UNDEF) { rp = (short)(extr[i].rp1+scale3offset); } else { rp = (short)(extr[i].rp2+scale3offset); }
if (extr[i].n==1) { if ((cnt1+2)>=MAXIP) { pgm[(*pc)++] = op_loopcall; args[(*pcd)++] = TTFUN_SHP1; args[(*pcd)++] = (short)(cnt1/2); for (j=0; j<cnt1; j++) args[(*pcd)++] = (short)ones[j]; cnt1 = 0; } ones[cnt1++] = rp; ones[cnt1++] = extr[i].pts[0]; } else if (extr[i].n==2) { if ((cnt2+3)>=MAXIP) { pgm[(*pc)++] = op_loopcall; args[(*pcd)++] = TTFUN_SHP2; args[(*pcd)++] = (short)(cnt2/3); for (j=0; j<cnt2; j++) args[(*pcd)++] = (short)twoes[j]; cnt2 = 0; } twoes[cnt2++] = rp; twoes[cnt2++] = extr[i].pts[0]; twoes[cnt2++] = extr[i].pts[1]; } else { if ((cntn+2+extr[i].n)>=MAXIP) { pgm[(*pc)++] = op_loopcall; args[(*pcd)++] = TTFUN_SHPN; args[(*pcd)++] = num; for (j=0; j<cntn; j++) args[(*pcd)++] = (short)nths[j]; cntn = 0; num = 0; } nths[cntn++] = rp; nths[cntn++] = extr[i].n; for (j=0; j<extr[i].n; j++) { nths[cntn++] = extr[i].pts[j]; } num++; } }
if (cnt1) { if (cnt1>2) { pgm[(*pc)++] = op_loopcall; args[(*pcd)++] = TTFUN_SHP1; args[(*pcd)++] = (short)(cnt1/2); } else { pgm[(*pc)++] = op_call; args[(*pcd)++] = TTFUN_SHP1; } for (i=0; i<cnt1; i++) args[(*pcd)++] = ones[i]; } if (cnt2) { if (cnt2>3) { pgm[(*pc)++] = op_loopcall; args[(*pcd)++] = TTFUN_SHP2; args[(*pcd)++] = (short)(cnt2/3); } else { pgm[(*pc)++] = op_call; args[(*pcd)++] = TTFUN_SHP2; } for (i=0; i<cnt2; i++) args[(*pcd)++] = twoes[i]; } if (cntn) { if (num>1) { pgm[(*pc)++] = op_loopcall; args[(*pcd)++] = TTFUN_SHPN; args[(*pcd)++] = num; } else { pgm[(*pc)++] = op_call; args[(*pcd)++] = TTFUN_SHPN; } for (i=0; i<cntn; i++) args[(*pcd)++] = (short)nths[i]; }
/* Interpolate the extrems. */ cnt1 = 0; cnt2 = 0; cntn = 0; num = 0; for (i=0; i<xcnt; i++) {
/* Skip interpolations. */ if (extr[i].rp1==UNDEF || extr[i].rp2==UNDEF) continue;
if (extr[i].n==1) { if ((cnt1+3)>=MAXIP) { pgm[(*pc)++] = op_loopcall; args[(*pcd)++] = TTFUN_IP1; args[(*pcd)++] = (short)(cnt1/2); for (j=0; j<cnt1; j++) args[(*pcd)++] = (short)ones[j]; cnt1 = 0; } ones[cnt1++] = extr[i].rp1; ones[cnt1++] = extr[i].rp2; ones[cnt1++] = extr[i].pts[0]; } else if (extr[i].n==2) { if ((cnt2+4)>=MAXIP) { pgm[(*pc)++] = op_loopcall; args[(*pcd)++] = TTFUN_IP2; args[(*pcd)++] = (short)(cnt2/3); for (j=0; j<cnt2; j++) args[(*pcd)++] = (short)twoes[j]; cnt2 = 0; } twoes[cnt2++] = extr[i].rp1; twoes[cnt2++] = extr[i].rp2; twoes[cnt2++] = extr[i].pts[0]; twoes[cnt2++] = extr[i].pts[1]; } else { if ((cntn+3+extr[i].n)>=MAXIP) { pgm[(*pc)++] = op_loopcall; args[(*pcd)++] = TTFUN_IPN; args[(*pcd)++] = num; for (j=0; j<cntn; j++) args[(*pcd)++] = (short)nths[j]; cntn = 0; num = 0; } nths[cntn++] = extr[i].rp1; nths[cntn++] = extr[i].rp2; nths[cntn++] = extr[i].n; for (j=0; j<extr[i].n; j++) { nths[cntn++] = extr[i].pts[j]; } num++; } }
if (cnt1) { if (cnt1>3) { pgm[(*pc)++] = op_loopcall; args[(*pcd)++] = TTFUN_IP1; args[(*pcd)++] = (short)(cnt1/3); } else { pgm[(*pc)++] = op_call; args[(*pcd)++] = TTFUN_IP1; } for (i=0; i<cnt1; i++) args[(*pcd)++] = (short)ones[i]; } if (cnt2) { if (cnt2>4) { pgm[(*pc)++] = op_loopcall; args[(*pcd)++] = TTFUN_IP2; args[(*pcd)++] = (short)(cnt2/4); } else { pgm[(*pc)++] = op_call; args[(*pcd)++] = TTFUN_IP2; } for (i=0; i<cnt2; i++) args[(*pcd)++] = (short)twoes[i]; } if (cntn) { if (num>1) { pgm[(*pc)++] = op_loopcall; args[(*pcd)++] = TTFUN_IPN; args[(*pcd)++] = num; } else { pgm[(*pc)++] = op_call; args[(*pcd)++] = TTFUN_IPN; } for (i=0; i<cntn; i++) args[(*pcd)++] = (short)nths[i]; } /*lint +e530 +e644 */ }
/***
** Function: EmitVerticalStem ** ** Description: ** This function generates the code that ** will initiate the graphics state of the ** TrueType interpreter for the grid fitting ** of vertical stems. ***/ void EmitVerticalStems(UBYTE *pgm, short *pc, short *args, short *pcd) { pgm[(*pc)++] = op_call; args[(*pcd)++] = TTFUN_VERTICAL; }
/***
** Function: EmitHorizontalStem ** ** Description: ** This function generates the code that ** will initiate the graphics state of the ** TrueType interpreter for the grid fitting ** of vertical stems. ***/ void EmitHorizontalStems(UBYTE *pgm, short *pc, short *args, short *pcd) { pgm[(*pc)++] = op_call; args[(*pcd)++] = TTFUN_HORIZONTAL; }
/***
** Function: EmitVStem ** ** Description: ** This function generates the code that ** will create and grid fit points in the ** twilight zone, corresponding to a vstem. ***/ errcode EmitVStem(UBYTE *pgm, short *pc, short *args, short *pcd, struct T1Metrics *t1m, const funit width, const funit real_side1, const funit real_side2, const funit side1, const funit side2, const short rp, const enum aligntype align, const short ref) { errcode status = SUCCESS; short w_storage;
if ((w_storage = GetVStemWidth(GetWeight(t1m), width))==NOMEM) { SetError(status = NOMEM); } else {
pgm[(*pc)++] = op_call; switch (align) { case at_centered: args[(*pcd)++] = TTFUN_VCENTER; args[(*pcd)++] = (short)real_side1; args[(*pcd)++] = (short)real_side2; args[(*pcd)++] = (short)side1; args[(*pcd)++] = (short)side2; args[(*pcd)++] = (short)((side1+side2)/2); args[(*pcd)++] = rp; args[(*pcd)++] = w_storage; break;
case at_relative1: args[(*pcd)++] = TTFUN_RELATIVE1V; args[(*pcd)++] = (short)real_side1; args[(*pcd)++] = (short)real_side2; args[(*pcd)++] = (short)side1; args[(*pcd)++] = (short)side2; args[(*pcd)++] = ref; args[(*pcd)++] = rp; args[(*pcd)++] = w_storage; break;
case at_relative2: args[(*pcd)++] = TTFUN_RELATIVE2V; args[(*pcd)++] = (short)real_side1; args[(*pcd)++] = (short)real_side2; args[(*pcd)++] = (short)side1; args[(*pcd)++] = (short)side2; args[(*pcd)++] = ref; args[(*pcd)++] = rp; args[(*pcd)++] = w_storage; break;
case at_side1: case at_side2: LogError(MSG_WARNING, MSG_ALIGN, NULL); break; } }
return status; }
/***
** Function: EmitHStem ** ** Description: ** This function generates the code that ** will create and grid fit points in the ** twilight zone, corresponding to a hstem. ***/ errcode EmitHStem(UBYTE *pgm, short *pc, short *args, short *pcd, struct T1Metrics *t1m, const funit width, const funit side1, const funit side2, const short rp, const enum aligntype align, const short ref) { errcode status = SUCCESS; short w_storage;
if ((w_storage = GetHStemWidth(GetWeight(t1m), width))==NOMEM) { SetError(status = NOMEM); } else {
pgm[(*pc)++] = op_call; switch (align) {
case at_side1: args[(*pcd)++] = TTFUN_SIDE1; args[(*pcd)++] = (short)side1; args[(*pcd)++] = (short)side2; args[(*pcd)++] = ref; args[(*pcd)++] = rp; args[(*pcd)++] = w_storage; break;
case at_side2: args[(*pcd)++] = TTFUN_SIDE2; args[(*pcd)++] = (short)side1; args[(*pcd)++] = (short)side2; args[(*pcd)++] = ref; args[(*pcd)++] = rp; args[(*pcd)++] = w_storage; break;
case at_relative1: args[(*pcd)++] = TTFUN_RELATIVE1H; args[(*pcd)++] = (short)side1; args[(*pcd)++] = (short)side2; args[(*pcd)++] = ref; args[(*pcd)++] = rp; args[(*pcd)++] = w_storage; break;
case at_relative2: args[(*pcd)++] = TTFUN_RELATIVE2H; args[(*pcd)++] = (short)side1; args[(*pcd)++] = (short)side2; args[(*pcd)++] = ref; args[(*pcd)++] = rp; args[(*pcd)++] = w_storage; break;
case at_centered: default: args[(*pcd)++] = TTFUN_HCENTER; args[(*pcd)++] = (short)side1; args[(*pcd)++] = (short)side2; args[(*pcd)++] = (short)((side1+side2)/2); args[(*pcd)++] = rp; args[(*pcd)++] = w_storage; break; } }
return status; }
/***
** Function: FamilyCutIn ** ** Description: ** This function generates a branch in the ** pre-program. ***/ USHORT FamilyCutIn(UBYTE *prep, USHORT tp, const short cis) { prep[tp++] = op_mppem; if (cis<256) { prep[tp++] = op_pushb1; prep[tp++] = (UBYTE)cis; } else { prep[tp++] = op_pushw1; prep[tp++] = HIBYTE(cis); prep[tp++] = LOBYTE(cis); } prep[tp++] = op_lt; prep[tp++] = op_if;
return tp; }
/***
** Function: SetProjection ** ** Description: ** This function generates the TrueType code that ** changes the projection vector in oblique typefaces. ***/ void SetProjection(UBYTE *pgm, short *pc, short *args, short *pcd, const funit x, const funit y) { pgm[(*pc)++] = op_call; args[(*pcd)++] = TTFUN_OBLIQUE; args[(*pcd)++] = (short)y; args[(*pcd)++] = (short)x; }
/***
** Function: AssembleArgs ** ** Description: ** This function takes a sequence of arguments and ** assembles them into a sequence of PUSHB1[], PUSHW1[], ** NPUSHB[] and NPUSHW[] instructions. ***/ void AssembleArgs(short *args, const short pcd, UBYTE *is, short *cnt) { short bytes; short i,j;
if ((args[pcd-1] <= UCHAR_MAX && args[pcd-1]>=0)) { bytes = 1; } else { bytes = 0; }
for (i=0, j=0; j<pcd; i++) {
/* Pack a sequence of bytes? */ if (bytes) { if ((i-j)>=255 || i==pcd || (args[pcd-i-1]>UCHAR_MAX || args[pcd-i-1]<0)) { bytes = 0; if ((i-j)<=8) { is[(*cnt)++] = (UBYTE)(op_pushb1 + (i-j) - 1); } else { is[(*cnt)++] = op_npushb; is[(*cnt)++] = (UBYTE)(i-j); } while (j<i) is[(*cnt)++] = (UBYTE)args[pcd-1-j++]; }
/* Pack a sequence of words? */ } else { if ((i-j)>=255 || i==pcd || (args[pcd-i-1]<=UCHAR_MAX && args[pcd-i-1]>=0)) { bytes = 1; if ((i-j)<=8) { is[(*cnt)++] = (UBYTE)(op_pushw1 + (i-j) - 1); } else { is[(*cnt)++] = op_npushw; is[(*cnt)++] = (UBYTE)(i-j); } while (j<i) { is[(*cnt)++] = HIBYTE(args[pcd-j-1]); is[(*cnt)++] = LOBYTE(args[pcd-j-1]); j++; } } } } }
|