/*** ** ** 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 /* 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; jcnt_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; jcnt_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; iblue_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; jtop[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; ioblue_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; jbottom[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; inext) { 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-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 && ccwionoff, 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=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; nnext) { 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-1].x) ccw[ccwi++] = i+path->count-1; ccw[ccwi++] = i; } } for (j=1; jcount && ccwionoff, 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=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; n0) { 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=MAXIP) { pgm[(*pc)++] = op_loopcall; args[(*pcd)++] = TTFUN_SHP1; args[(*pcd)++] = (short)(cnt1/2); for (j=0; j=MAXIP) { pgm[(*pc)++] = op_loopcall; args[(*pcd)++] = TTFUN_SHP2; args[(*pcd)++] = (short)(cnt2/3); for (j=0; j=MAXIP) { pgm[(*pc)++] = op_loopcall; args[(*pcd)++] = TTFUN_SHPN; args[(*pcd)++] = num; for (j=0; j2) { 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; i3) { 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; i1) { pgm[(*pc)++] = op_loopcall; args[(*pcd)++] = TTFUN_SHPN; args[(*pcd)++] = num; } else { pgm[(*pc)++] = op_call; args[(*pcd)++] = TTFUN_SHPN; } for (i=0; i=MAXIP) { pgm[(*pc)++] = op_loopcall; args[(*pcd)++] = TTFUN_IP1; args[(*pcd)++] = (short)(cnt1/2); for (j=0; j=MAXIP) { pgm[(*pc)++] = op_loopcall; args[(*pcd)++] = TTFUN_IP2; args[(*pcd)++] = (short)(cnt2/3); for (j=0; j=MAXIP) { pgm[(*pc)++] = op_loopcall; args[(*pcd)++] = TTFUN_IPN; args[(*pcd)++] = num; for (j=0; j3) { 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; i4) { 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; i1) { pgm[(*pc)++] = op_loopcall; args[(*pcd)++] = TTFUN_IPN; args[(*pcd)++] = num; } else { pgm[(*pc)++] = op_call; args[(*pcd)++] = TTFUN_IPN; } for (i=0; i=0)) { bytes = 1; } else { bytes = 0; } for (i=0, j=0; 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=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