📄 type1.c
字号:
/* $XConsortium: type1.c,v 1.7 94/02/07 15:30:22 gildea Exp $ *//* Copyright International Business Machines, Corp. 1991 * All Rights Reserved * Copyright Lexmark International, Inc. 1991 * All Rights Reserved * Portions Copyright (c) 1990 Adobe Systems Incorporated. * All Rights Reserved * * License to use, copy, modify, and distribute this software and its * documentation for any purpose and without fee is hereby granted, * provided that the above copyright notice appear in all copies and that * both that copyright notice and this permission notice appear in * supporting documentation, and that the name of IBM or Lexmark or Adobe * not be used in advertising or publicity pertaining to distribution of * the software without specific, written prior permission. * * IBM, LEXMARK, AND ADOBE PROVIDE THIS SOFTWARE "AS IS", WITHOUT ANY * WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT * LIMITED TO ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * PARTICULAR PURPOSE, AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. THE * ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE, INCLUDING * ANY DUTY TO SUPPORT OR MAINTAIN, BELONGS TO THE LICENSEE. SHOULD ANY * PORTION OF THE SOFTWARE PROVE DEFECTIVE, THE LICENSEE (NOT IBM, * LEXMARK, OR ADOBE) ASSUMES THE ENTIRE COST OF ALL SERVICING, REPAIR AND * CORRECTION. IN NO EVENT SHALL IBM, LEXMARK, OR ADOBE BE LIABLE FOR ANY * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /*********************************************************************//* *//* Type 1 module - Converting fonts in Adobe Type 1 Font Format *//* to scaled and hinted paths for rasterization. *//* Files: type1.c, type1.h, and blues.h. *//* *//* Authors: Sten F. Andler, IBM Almaden Research Center *//* (Type 1 interpreter, stem & flex hints) *//* *//* Patrick A. Casey, Lexmark International, Inc. *//* (Font level hints & stem hints) *//* *//*********************************************************************/ /******************//* Include Files: *//******************/#include <stdio.h> /* a system-dependent include, usually */ #include "objects.h"#include "spaces.h"#include "paths.h"#include "fonts.h" /* understands about TEXTTYPEs */#include "pictures.h" /* understands about handles */ typedef struct xobject xobject;#include "util.h" /* PostScript objects */#include "blues.h" /* Blues structure for font-level hints */ /**********************************//* Type1 Constants and Structures *//**********************************/#define MAXSTACK 24 /* Adobe Type1 limit */#define MAXCALLSTACK 10 /* Adobe Type1 limit */#define MAXPSFAKESTACK 32 /* Max depth of fake PostScript stack (local) */#define MAXSTRLEN 512 /* Max length of a Type 1 string (local) */#define MAXLABEL 256 /* Maximum number of new hints */#define MAXSTEMS 128 /* Maximum number of VSTEM and HSTEM hints */#define EPS 0.001 /* Small number for comparisons */ /************************************//* Adobe Type 1 CharString commands *//************************************/#define HSTEM 1#define VSTEM 3#define VMOVETO 4#define RLINETO 5#define HLINETO 6#define VLINETO 7#define RRCURVETO 8#define CLOSEPATH 9#define CALLSUBR 10#define RETURN 11#define ESCAPE 12#define HSBW 13#define ENDCHAR 14#define RMOVETO 21#define HMOVETO 22#define VHCURVETO 30#define HVCURVETO 31 /*******************************************//* Adobe Type 1 CharString Escape commands *//*******************************************/#define DOTSECTION 0#define VSTEM3 1#define HSTEM3 2#define SEAC 6#define SBW 7#define DIV 12#define CALLOTHERSUBR 16#define POP 17#define SETCURRENTPOINT 33 /*****************//* Useful macros *//*****************/static double tmpx; /* Store macro argument in tmpx to avoid re-evaluation */static long tmpi; /* Store converted value in tmpi to avoid re-evaluation */ #define FABS(x) (((tmpx = (x)) < 0.0) ? -tmpx : tmpx) #define CEIL(x) (((tmpi = (long) (tmpx = (x))) < tmpx) ? ++tmpi : tmpi) #define FLOOR(x) (((tmpi = (long) (tmpx = (x))) > tmpx) ? --tmpi : tmpi) #define ROUND(x) FLOOR((x) + 0.5) #define ODD(x) (((int)(x)) & 01) #define Error {errflag = TRUE; return;}#define ErrorRet(ret) {errflag = TRUE; return (ret);} #define Error0(errmsg) {IfTrace0(TRUE, errmsg); Error;}#define Error0Ret(errmsg, ret) {IfTrace0(TRUE, errmsg); ErrorRet(ret);} #define Error1(errmsg,arg) {IfTrace1(TRUE, errmsg, arg); Error;} /********************//* global variables *//********************/struct stem { /* representation of a STEM hint */ int vertical; /* TRUE if vertical, FALSE otherwise */ double x, dx; /* interval of vertical stem */ double y, dy; /* interval of horizontal stem */ struct segment *lbhint, *lbrevhint; /* left or bottom hint adjustment */ struct segment *rthint, *rtrevhint; /* right or top hint adjustment */}; extern struct XYspace *IDENTITY; static double escapementX, escapementY;static double sidebearingX, sidebearingY;static double accentoffsetX, accentoffsetY; static struct segment *path;static int errflag; /*************************************************//* Global variables to hold Type1Char parameters *//*************************************************/static char *Environment;static struct XYspace *CharSpace;static psobj *CharStringP, *SubrsP, *OtherSubrsP;static int *ModeP; /************************//* Forward declarations *//************************/static double Div();static double PSFakePop();static DoCommand();static Escape();static HStem();static VStem();static RLineTo();static RRCurveTo();static DoClosePath();static CallSubr();static Return();static EndChar();static RMoveTo();static DotSection();static Seac();static Sbw();static CallOtherSubr();static SetCurrentPoint();/*****************************************//* statics for Flex procedures (FlxProc) *//*****************************************/static struct segment *FlxOldPath; /* save path before Flex feature */ /******************************************************//* statics for Font level hints (Blues) (see blues.h) *//******************************************************/static struct blues_struct *blues; /* the blues structure */static struct alignmentzone alignmentzones[MAXALIGNMENTZONES];static int numalignmentzones; /* total number of alignment zones */ /****************************************************************//* Subroutines for the Font level hints (Alignment zones, etc.) *//****************************************************************/ /******************************************//* Fill in the alignment zone structures. *//******************************************/static ComputeAlignmentZones(){ int i; double dummy, bluezonepixels, familyzonepixels; struct segment *p; numalignmentzones = 0; /* initialize total # of zones */ /* do the BlueValues zones */ for (i = 0; i < blues->numBlueValues; i +=2, ++numalignmentzones) { /* the 0th & 1st numbers in BlueValues are for a bottom zone */ /* the rest are topzones */ if (i == 0) /* bottom zone */ alignmentzones[numalignmentzones].topzone = FALSE; else /* top zone */ alignmentzones[numalignmentzones].topzone = TRUE; if (i < blues->numFamilyBlues) { /* we must consider FamilyBlues */ p = ILoc(CharSpace,0,blues->BlueValues[i] - blues->BlueValues[i+1]); QueryLoc(p, IDENTITY, &dummy, &bluezonepixels); Destroy(p); p = ILoc(CharSpace,0,blues->FamilyBlues[i]-blues->FamilyBlues[i+1]); QueryLoc(p, IDENTITY, &dummy, &familyzonepixels); Destroy(p); /* is the difference in size of the zones less than 1 pixel? */ if (FABS(bluezonepixels - familyzonepixels) < 1.0) { /* use the Family zones */ alignmentzones[numalignmentzones].bottomy = blues->FamilyBlues[i]; alignmentzones[numalignmentzones].topy = blues->FamilyBlues[i+1]; continue; } } /* use this font's Blue zones */ alignmentzones[numalignmentzones].bottomy = blues->BlueValues[i]; alignmentzones[numalignmentzones].topy = blues->BlueValues[i+1]; } /* do the OtherBlues zones */ for (i = 0; i < blues->numOtherBlues; i +=2, ++numalignmentzones) { /* all of the OtherBlues zones are bottom zones */ alignmentzones[numalignmentzones].topzone = FALSE; if (i < blues->numFamilyOtherBlues) {/* consider FamilyOtherBlues */ p = ILoc(CharSpace,0,blues->OtherBlues[i] - blues->OtherBlues[i+1]); QueryLoc(p, IDENTITY, &dummy, &bluezonepixels); Destroy(p); p = ILoc(CharSpace,0,blues->FamilyOtherBlues[i] - blues->FamilyOtherBlues[i+1]); QueryLoc(p, IDENTITY, &dummy, &familyzonepixels); Destroy(p); /* is the difference in size of the zones less than 1 pixel? */ if (FABS(bluezonepixels - familyzonepixels) < 1.0) { /* use the Family zones */ alignmentzones[numalignmentzones].bottomy = blues->FamilyOtherBlues[i]; alignmentzones[numalignmentzones].topy = blues->FamilyOtherBlues[i+1]; continue; } } /* use this font's Blue zones (as opposed to the Family Blues */ alignmentzones[numalignmentzones].bottomy = blues->OtherBlues[i]; alignmentzones[numalignmentzones].topy = blues->OtherBlues[i+1]; }} /**********************************************************************//* Subroutines and statics for handling of the VSTEM and HSTEM hints. *//**********************************************************************/static int InDotSection; /* DotSection flag */static struct stem stems[MAXSTEMS]; /* All STEM hints */static int numstems; /* Number of STEM hints */static int currstartstem; /* The current starting stem. */static int oldvert, oldhor; /* Remember hint in effect */static int oldhorhalf, oldverthalf; /* Remember which half of the stem */static double wsoffsetX, wsoffsetY; /* White space offset - for VSTEM3,HSTEM3 */static int wsset; /* Flag for whether we've set wsoffsetX,Y */ static InitStems() /* Initialize the STEM hint data structures */{ InDotSection = FALSE; currstartstem = numstems = 0; oldvert = oldhor = -1;} static FinitStems() /* Terminate the STEM hint data structures */{ int i; for (i = 0; i < numstems; i++) { Destroy(stems[i].lbhint); Destroy(stems[i].lbrevhint); Destroy(stems[i].rthint); Destroy(stems[i].rtrevhint); }} /*******************************************************************//* Compute the dislocation that a stemhint should cause for points *//* inside the stem. *//*******************************************************************/static ComputeStem(stemno)int stemno;{ int verticalondevice, idealwidth; double stemstart, stemwidth; struct segment *p; int i; double stembottom, stemtop, flatposition; double Xpixels, Ypixels; double unitpixels, onepixel; int suppressovershoot, enforceovershoot; double stemshift, flatpospixels, overshoot; double widthdiff; /* Number of character space units to adjust width */ double lbhintvalue, rthintvalue; double cxx, cyx, cxy, cyy; /* Transformation matrix */ int rotated; /* TRUE if character is on the side, FALSE if upright */ /************************************************/ /* DETERMINE ORIENTATION OF CHARACTER ON DEVICE */ /************************************************/ QuerySpace(CharSpace, &cxx, &cyx, &cxy, &cyy); /* Transformation matrix */ if (FABS(cxx) < 0.00001 || FABS(cyy) < 0.00001) rotated = TRUE; /* Char is on side (90 or 270 degrees), possibly oblique. */ else if (FABS(cyx) < 0.00001 || FABS(cxy) < 0.00001) rotated = FALSE; /* Char is upright (0 or 180 degrees), possibly oblique. */ else { stems[stemno].lbhint = NULL; /* Char is at non-axial angle, ignore hints. */ stems[stemno].lbrevhint = NULL; stems[stemno].rthint = NULL; stems[stemno].rtrevhint = NULL; return; } /* Determine orientation of stem */ if (stems[stemno].vertical) { verticalondevice = !rotated; stemstart = stems[stemno].x; stemwidth = stems[stemno].dx; } else { verticalondevice = rotated; stemstart = stems[stemno].y; stemwidth = stems[stemno].dy; } /* Determine how many pixels (non-negative) correspond to 1 character space unit (unitpixels), and how many character space units (non-negative) correspond to one pixel (onepixel). */ if (stems[stemno].vertical) p = ILoc(CharSpace, 1, 0); else p = ILoc(CharSpace, 0, 1); QueryLoc(p, IDENTITY, &Xpixels, &Ypixels); Destroy(p); if (verticalondevice) unitpixels = FABS(Xpixels); else unitpixels = FABS(Ypixels); onepixel = 1.0 / unitpixels; /**********************/ /* ADJUST STEM WIDTHS */ /**********************/ widthdiff = 0.0; /* Find standard stem with smallest width difference from this stem */ if (stems[stemno].vertical) { /* vertical stem */ if (blues->StdVW != 0) /* there is an entry for StdVW */ widthdiff = blues->StdVW - stemwidth; for (i = 0; i < blues->numStemSnapV; ++i) { /* now look at StemSnapV */ if (blues->StemSnapV[i] - stemwidth < widthdiff) /* this standard width is the best match so far for this stem */ widthdiff = blues->StemSnapV[i] - stemwidth; } } else { /* horizontal stem */ if (blues->StdHW != 0) /* there is an entry for StdHW */ widthdiff = blues->StdHW - stemwidth; for (i = 0; i < blues->numStemSnapH; ++i) { /* now look at StemSnapH */ if (blues->StemSnapH[i] - stemwidth < widthdiff) /* this standard width is the best match so far for this stem */ widthdiff = blues->StemSnapH[i] - stemwidth; } } /* Only expand or contract stems if they differ by less than 1 pixel from the closest standard width, otherwise make the width difference = 0. */ if (FABS(widthdiff) > onepixel) widthdiff = 0.0; /* Expand or contract stem to the nearest integral number of pixels. */ idealwidth = ROUND((stemwidth + widthdiff) * unitpixels); /* Ensure that all stems are at least one pixel wide. */ if (idealwidth == 0) idealwidth = 1; /* Apply ForceBold to vertical stems. */ if (blues->ForceBold && stems[stemno].vertical) /* Force this vertical stem to be at least DEFAULTBOLDSTEMWIDTH wide. */ if (idealwidth < DEFAULTBOLDSTEMWIDTH) idealwidth = DEFAULTBOLDSTEMWIDTH; /* Now compute the number of character space units necessary */ widthdiff = idealwidth * onepixel - stemwidth; /*********************************************************************/ /* ALIGNMENT ZONES AND OVERSHOOT SUPPRESSION - HORIZONTAL STEMS ONLY */ /*********************************************************************/ stemshift = 0.0; if (!stems[stemno].vertical) { /* Get bottom and top boundaries of the stem. */ stembottom = stemstart; stemtop = stemstart + stemwidth; /* Find out if this stem intersects an alignment zone (the BlueFuzz */ /* entry in the Private dictionary specifies the number of character */ /* units to extend (in both directions) the effect of an alignment */ /* zone on a horizontal stem. The default value of BlueFuzz is 1. */ for (i = 0; i < numalignmentzones; ++i) { if (alignmentzones[i].topzone) { if (stemtop >= alignmentzones[i].bottomy && stemtop <= alignmentzones[i].topy + blues->BlueFuzz) { break; /* We found a top-zone */ } } else { if (stembottom <= alignmentzones[i].topy && stembottom >= alignmentzones[i].bottomy - blues->BlueFuzz) { break; /* We found a bottom-zone */ } } } if (i < numalignmentzones) { /* We found an intersecting zone (number i). */ suppressovershoot = FALSE; enforceovershoot = FALSE; /* When 1 character space unit is rendered smaller than BlueScale device units (pixels), we must SUPPRESS overshoots. Otherwise, if the top (or bottom) of this stem is more than BlueShift character space units away from the flat position, we must ENFORCE overshoot. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -