blob: 11523b69731f618d4341e6d5a3cdceb11e31a721 [file] [log] [blame]
/* Copyright (C) 1990 Aladdin Enterprises. All rights reserved.
Distributed by Free Software Foundation, Inc.
This file is part of Ghostscript.
Ghostscript is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY. No author or distributor accepts responsibility
to anyone for the consequences of using it or for whether it serves any
particular purpose or works at all, unless he says so in writing. Refer
to the Ghostscript General Public License for full details.
Everyone is granted permission to copy, modify and redistribute
Ghostscript, but only under the conditions described in the Ghostscript
General Public License. A copy of this license is supposed to have been
given to you along with Ghostscript so you can know your rights and
responsibilities. It should be in a file named COPYING. Among other
things, the copyright notice and this notice must be preserved on all
copies. */
/* gstype1.c */
/* Adobe Type 1 font routines for GhostScript library */
#include "math_.h"
#include "memory_.h"
#include "gx.h"
#include "gserrors.h"
#include "gxarith.h"
#include "gxfixed.h"
#include "gxmatrix.h"
#include "gzstate.h"
#include "gzdevice.h" /* for gxchar */
#include "gxdevmem.h" /* ditto */
#include "gzpath.h"
#include "gxchar.h"
#include "gxfont1.h"
#include "gxtype1.h"
/* Encrypt a string. */
int
gs_type1_encrypt(byte *dest, byte *src, uint len, crypt_state *pstate)
{ register crypt_state state = *pstate;
register byte *from = src;
register byte *to = dest;
register uint count = len;
while ( count )
{ encrypt_next(*from, state, *to);
from++, to++, count--;
}
*pstate = state;
return 0;
}
/* Decrypt a string. */
int
gs_type1_decrypt(byte *dest, byte *src, uint len, crypt_state *pstate)
{ register crypt_state state = *pstate;
register byte *from = src;
register byte *to = dest;
register uint count = len;
while ( count )
{ /* If from == to, we can't use the obvious */
/* decrypt_next(*from, state, *to); */
register byte ch = *from++;
decrypt_next(ch, state, *to);
to++, count--;
}
*pstate = state;
return 0;
}
/* Define the structures for the state of a Type 1 interpreter. */
/* This is the interpreter state that must be saved and restored */
/* when calling a CharString subroutine. */
typedef struct {
byte *ip;
crypt_state dstate;
} ip_state;
/* Define the fixed-point coefficient structure */
/* for avoiding floating point. */
#define max_coeff_bits 11 /* max coefficient in char space */
typedef struct {
long xx, xy, yx, yy;
int skewed;
int shift; /* see below */
fixed round; /* see below */
} fixed_coeff;
/* This is the full state of the Type 1 interpreter. */
struct gs_type1_state_s {
/* The following are set at initialization */
gs_show_enum *penum; /* show enumerator */
gs_state *pgs; /* graphics state */
gs_type1_data *pdata; /* font-specific data */
int charpath_flag; /* 0 for show, 1 for false */
/* charpath, 2 for true charpath */
int paint_type; /* 0 for fill, non-0 for stroke */
fixed_coeff fc; /* cached fixed coefficients */
/* The following are updated dynamically */
#define ostack_size 24
fixed ostack[ostack_size]; /* the Type 1 operand stack */
int os_count; /* # of occupied stack entries */
#define ipstack_size 10
ip_state ipstack[ipstack_size+1]; /* control stack */
int ips_count; /* # of occupied entries */
int ip_skip; /* # of bytes to skip */
gs_fixed_point lsb; /* left side bearing */
gs_fixed_point width; /* character width */
int seac_base; /* base character code for seac, */
/* or -1 */
};
/* Export the size of the structure */
int gs_type1_state_sizeof = sizeof(gs_type1_state);
/* Initialize the cached matrix in a Type 1 interpreter */
/* from the matrix in the graphics state. */
int
gs_type1_init_matrix(register gs_type1_state *pis)
{ gs_matrix ctm;
int scale = -10000;
int expt, shift;
ctm = ctm_only(pis->pgs);
pis->fc.skewed = 0;
if ( !is_fzero(ctm.xx) )
{ (void)frexp(ctm.xx, &scale);
}
if ( !is_fzero(ctm.xy) )
{ (void)frexp(ctm.xy, &expt);
if ( expt > scale ) scale = expt;
pis->fc.skewed = 1;
}
if ( !is_fzero(ctm.yx) )
{ (void)frexp(ctm.yx, &expt);
if ( expt > scale ) scale = expt;
pis->fc.skewed = 1;
}
if ( !is_fzero(ctm.yy) )
{ (void)frexp(ctm.yy, &expt);
if ( expt > scale ) scale = expt;
}
scale = 31 - max_coeff_bits - scale;
pis->fc.xx = (is_fzero(ctm.xx) ? 0 : (long)ldexp(ctm.xx, scale));
pis->fc.yy = (is_fzero(ctm.yy) ? 0 : (long)ldexp(ctm.yy, scale));
if ( pis->fc.skewed )
{ pis->fc.xy = (is_fzero(ctm.xy) ? 0 : (long)ldexp(ctm.xy, scale));
pis->fc.yx = (is_fzero(ctm.yx) ? 0 : (long)ldexp(ctm.yx, scale));
}
else
pis->fc.xy = pis->fc.yx = 0;
shift = scale - _fixed_shift;
pis->fc.shift = shift;
pis->fc.round = (shift > 0 ? (fixed)1 << (shift - 1) : 0);
#ifdef DEBUG
if ( gs_debug['1'] )
{ printf("[1]ctm: [%6g %6g %6g %6g ; %6g %6g] scale=%d\n",
ctm.xx, ctm.xy, ctm.yx, ctm.yy, ctm.tx, ctm.ty, scale);
printf(" fc: [%lx %lx %lx %lx] shift=%d\n",
pis->fc.xx, pis->fc.xy, pis->fc.yx, pis->fc.yy,
pis->fc.shift);
}
#endif
return 0;
}
/* Initialize a Type 1 interpreter */
int
gs_type1_init(register gs_type1_state *pis, gs_show_enum *penum,
int charpath_flag, int paint_type, byte *str, gs_type1_data *pdata)
{ gs_state *pgs = penum->pgs;
pis->penum = penum;
pis->pgs = pgs;
pis->pdata = pdata;
pis->charpath_flag = charpath_flag;
pis->paint_type = paint_type;
pis->os_count = 0;
pis->ipstack[0].ip = str;
pis->ipstack[0].dstate = crypt_charstring_seed;
pis->ips_count = 1;
pis->ip_skip = pdata->lenIV;
pis->seac_base = -1;
gs_type1_init_matrix(pis);
/* Set the current point of the path to the origin, */
/* in anticipation of the initial [h]sbw. */
{ gx_path *ppath = pgs->path;
ppath->position.x = pgs->ctm.tx_fixed;
ppath->position.y = pgs->ctm.ty_fixed;
}
return 0;
}
/* Tracing for type 1 interpreter */
#ifdef DEBUG
# define dc(str) type1_trace(cip, c, str);
private void
type1_trace(byte *cip, byte c, char *str)
{ if ( gs_debug['1'] )
printf("[1]%lx: %02x %s\n", (ulong)(cip - 1), c, str);
}
#else
# define dc(str)
#endif
/* Continue interpreting a Type 1 CharString. */
/* If str != 0, it is taken as the byte string to interpret. */
/* Return 0 on successful completion, <0 on error, */
/* (code<<1)+1 for seac, or (N+1)<<1 for callothersubr(N). */
int
gs_type1_interpret(register gs_type1_state *pis, byte *str)
{ gs_state *pgs = pis->pgs;
gx_path *ppath = pgs->path;
gs_type1_data *pdata = pis->pdata;
#define clear csp = cstack - 1
fixed cstack[ostack_size];
#define cs0 cstack[0]
#define cs1 cstack[1]
#define cs2 cstack[2]
#define cs3 cstack[3]
#define cs4 cstack[4]
#define cs5 cstack[5]
register fixed *csp;
ip_state *ipsp = &pis->ipstack[pis->ips_count - 1];
int skip = pis->ip_skip;
register byte *cip;
register crypt_state state; /* decryption state */
register int c;
int code;
fixed_coeff fc;
fixed ftx = pgs->ctm.tx_fixed,
fty = pgs->ctm.ty_fixed;
fixed ptx = ppath->position.x, pty = ppath->position.y;
fixed x1, y1, x2, y2;
fc = pis->fc;
#define c_fixed(d, c)\
(fc.shift >= 0 ? arith_rshift(fixed2int(d) * c + fc.round, fc.shift) :\
(fixed2int(d) * c) << -fc.shift)
/****** THE FOLLOWING ARE NOT ACCURATE FOR NON-INTEGER DELTAS. ******/
/* This probably doesn't make any difference in practice. */
#define accum_x(dx)\
ptx += c_fixed(dx, fc.xx);\
if ( fc.skewed ) pty += c_fixed(dx, fc.xy)
#define accum_y(dy)\
pty += c_fixed(dy, fc.yy);\
if ( fc.skewed ) ptx += c_fixed(dy, fc.yx)
#define accum_xy(dx,dy)\
ptx += c_fixed(dx, fc.xx);\
pty += c_fixed(dy, fc.yy);\
if ( fc.skewed ) pty += c_fixed(dx, fc.xy), ptx += c_fixed(dy, fc.yx)
/* Copy the operand stack out of the saved state. */
if ( pis->os_count == 0 )
{ clear;
}
else
{ memcpy(cstack, pis->ostack, pis->os_count * sizeof(fixed));
csp = &cstack[pis->os_count - 1];
}
if ( str != 0 )
ipsp->ip = str;
itop: cip = ipsp->ip;
state = ipsp->dstate;
top: /* Skip initial random bytes */
for ( ; skip > 0; --skip )
{ decrypt_next(*cip, state, c); ++cip;
}
while ( 1 )
{ decrypt_next(*cip, state, c); ++cip;
switch ( (char_command)c )
{
case c_hstem: dc("hstem") /* hint, ignore */
clear; break;
case c_vstem: dc("vstem") /* hint, ignore */
clear; break;
case c_vmoveto: dc("vmoveto")
accum_y(cs0);
goto mto;
case c_rlineto: dc("rlineto")
accum_xy(cs0, cs1);
lto: code = gx_path_add_line(ppath, ptx, pty);
moved: if ( code < 0 ) return code;
pp:
#ifdef DEBUG
if ( gs_debug['1'] )
printf("[1]pt=(%g,%g)\n", fixed2float(ptx), fixed2float(pty));
#endif
clear; break;
case c_hlineto: dc("hlineto")
accum_x(cs0);
goto lto;
case c_vlineto: dc("vlineto")
accum_y(cs0);
goto lto;
case c_rrcurveto: dc("rrcurveto")
accum_xy(cs0, cs1);
x1 = ptx, y1 = pty;
accum_xy(cs2, cs3);
x2 = ptx, y2 = pty;
accum_xy(cs4, cs5);
curve: code = gx_path_add_curve(ppath, x1, y1, x2, y2, ptx, pty);
goto moved;
case c_closepath: dc("closepath")
/* Note that this does NOT reset the current point! */
code = gx_path_close_subpath(ppath);
if ( code < 0 ) return code;
goto mto; /* put the point where it was */
case c_callsubr: dc("callsubr")
{ int index = fixed2int(*csp);
byte *nip;
code = (*pdata->subr_proc)(pdata, index, &nip);
if ( code < 0 ) return code;
--csp;
ipsp->ip = cip, ipsp->dstate = state;
++ipsp;
cip = nip;
}
state = crypt_charstring_seed;
skip = pis->pdata->lenIV;
goto top;
case c_return: dc("return")
--ipsp;
goto itop;
case c_escape: dc("escape:")
decrypt_next(*cip, state, c); ++cip;
switch ( (char_extended_command)c )
{
case ce_dotsection: dc(" dotsection") /* hint, ignore */
clear; break;
case ce_vstem3: dc(" vstem3") /* hint, ignore */
clear; break;
case ce_hstem3: dc(" hstem3") /* hint, ignore */
clear; break;
case ce_seac: dc(" seac")
/* Do the accent now. When it finishes */
/* (detected in endchar), do the base character. */
pis->seac_base = (int)(byte)fixed2int(cs3);
/* Adjust the origin of the coordinate system */
/* for the accent (endchar puts it back). */
ptx = ftx, pty = fty;
cs1 -= cs0; /* subtract off asb */
accum_xy(cs1, cs2);
ppath->position.x = ptx;
ppath->position.y = pty;
clear;
/* Give control back to the caller, who must */
/* re-invoke the interpreter with the seac string. */
state = crypt_charstring_seed;
skip = pis->pdata->lenIV;
return ((int)(byte)fixed2int(cs4) << 1) + 1;
case ce_sbw: dc(" sbw")
pis->lsb.x = cs0, pis->lsb.y = cs1;
pis->width.x = cs2, pis->width.y = cs3;
goto setp;
case ce_div: dc(" div")
csp[-1] = float2fixed((float)csp[-1] / (float)*csp);
--csp; break;
case ce_testadd: dc(" testadd")
/*
* NOTE: this opcode is not documented by Adobe.
*/
if ( csp[-2] > csp[-1] ) csp[-3] += *csp;
csp -= 3; break;
case ce_callothersubr: dc(" callothersubr")
{ int index = fixed2int(*csp);
int scount = csp - cstack;
/* Exit to caller */
ipsp->ip = cip, ipsp->dstate = state;
pis->os_count = scount;
pis->ips_count = ipsp - &pis->ipstack[0] + 1;
pis->ip_skip = 0;
if ( scount )
memcpy(pis->ostack, cstack,
scount * sizeof(fixed));
return (index + 1) << 1;
}
case ce_pop: dc(" pop")
++csp;
code = (*pdata->pop_proc)(pdata, csp);
if ( code < 0 ) return code;
goto pushed;
case ce_setcurrentpoint: dc(" setcurrentpoint")
ptx = ftx, pty = fty;
goto setp;
default:
return_error(gs_error_invalidfont);
}
break;
case c_hsbw: dc("hsbw")
pis->lsb.x = cs0, pis->lsb.y = 0;
pis->width.x = cs1, pis->width.y = 0;
cs1 = 0;
setp: accum_xy(cs0, cs1);
goto pp;
case c_endchar: dc("endchar")
if ( pis->seac_base >= 0 )
{ /* We just finished the accent of a seac. */
/* Do the base character. */
int base_code = pis->seac_base;
pis->seac_base = -1;
/* Restore the coordinate system origin */
ppath->position.x = pgs->ctm.tx_fixed;
ppath->position.y = pgs->ctm.ty_fixed;
clear;
/* Give control back to the caller, who must */
/* re-invoke the interpreter with the seac string. */
state = crypt_charstring_seed;
skip = pis->pdata->lenIV;
return (base_code << 1) + 1;
}
/* Set the current point to the character origin: */
/* the 'show' loop will take care of adding in */
/* the width we supply to setcharwidth/cachedevice. */
gx_path_add_point(ppath,
pgs->ctm.tx_fixed, pgs->ctm.ty_fixed);
if ( pis->charpath_flag )
{ code = gs_setcharwidth(pis->penum,
fixed2float(pis->width.x),
fixed2float(pis->width.y));
if ( code < 0 ) return code;
/* Merge the path into its parent */
code = gx_path_merge(ppath, pgs->saved->path);
}
else
{ gs_rect bbox;
code = gs_pathbbox(pgs, &bbox);
/* Restore the current point to where it was */
/* at the beginning of the character, so that */
/* the right thing will happen when we copy */
/* a just-cached character to the output. */
gx_path_add_point(ppath, ftx, fty);
if ( code < 0 ) /* must be a null path */
{ bbox.p.x = bbox.p.y = bbox.q.x = bbox.q.y = 0;
}
#ifdef DEBUG
if ( gs_debug['1'] )
printf("[1]bbox=(%g,%g),(%g,%g)\n",
bbox.p.x, bbox.p.y, bbox.q.x, bbox.q.y);
#endif
if ( pis->paint_type )
{ /* Expand the bounding box to encompass */
/* the width of the stroke, plus a little */
/* to overcome rounding problems. */
float adjust = gs_currentlinewidth(pgs);
if ( adjust == 0 ) adjust = 1;
bbox.p.x -= adjust;
bbox.p.y -= adjust;
bbox.q.x += adjust;
bbox.q.y += adjust;
}
code = gs_setcachedevice(pis->penum,
fixed2float(pis->width.x),
fixed2float(pis->width.y),
bbox.p.x, bbox.p.y,
bbox.q.x, bbox.q.y);
if ( code < 0 ) return code;
/* We've already constructed the path: */
/* translate it so it matches the cache device. */
gx_path_translate(pgs->path, pgs->ctm.tx_fixed - ftx,
pgs->ctm.ty_fixed - fty);
if ( code < 0 ) return code;
/******
****** The trim parameter is a hack to make
****** characters come out less bold, since we
****** don't look at the hints.
******/
code = (pis->paint_type ? gs_stroke(pgs) :
gs_fill_trim(pgs, float2fixed(0.2)));
}
return code;
case c_rmoveto: dc("rmoveto")
accum_xy(cs0, cs1);
mto: code = gx_path_add_point(ppath, ptx, pty);
goto moved;
case c_hmoveto: dc("hmoveto")
accum_x(cs0);
goto mto;
case c_vhcurveto: dc("vhcurveto")
accum_y(cs0);
x1 = ptx, y1 = pty;
accum_xy(cs1, cs2);
x2 = ptx, y2 = pty;
accum_x(cs3);
goto curve;
case c_hvcurveto: dc("hvcurveto")
accum_x(cs0);
x1 = ptx, y1 = pty;
accum_xy(cs1, cs2);
x2 = ptx, y2 = pty;
accum_y(cs3);
goto curve;
/* Fill up the dispatch up to 32 */
case c_undef0: case c_undef2:
case c_undef15:
case c_undef16: case c_undef17: case c_undef18: case c_undef19:
case c_undef20: case c_undef23:
case c_undef24: case c_undef25: case c_undef26: case c_undef27:
case c_undef28: case c_undef29:
return_error(gs_error_invalidfont);
default: /* a number */
csp++;
if ( c <= c_max_num1 )
*csp = int2fixed(c_value_num1(c));
else
{ byte c0;
decrypt_next(*cip, state, c0); ++cip;
if ( c <= c_max_num2 )
*csp = int2fixed(c_value_num2(c, (int)c0));
else if ( c <= c_max_num3 )
*csp = int2fixed(c_value_num3(c, (int)c0));
else /* c = 255 */
{ byte c1, c2;
long lw;
decrypt_next(*cip, state, c1); ++cip;
decrypt_next(*cip, state, c2); ++cip;
decrypt_next(*cip, state, lw); ++cip;
lw += (long)c0 << 24;
lw += (uint)c1 << 16;
lw += (uint)c2 << 8;
*csp = int2fixed(lw);
if ( lw != fixed2int(*csp) )
return_error(gs_error_rangecheck);
}
}
pushed:
#ifdef DEBUG
if ( gs_debug['1'] )
printf("[1]%d: (%d) %f\n", (int)(csp - cstack), c, fixed2float(*csp));
#endif
; /* in case no debug */
}
}
}
/* Pop a (fixed) number off the internal stack. */
/* The client uses this to get the arguments for an OtherSubr. */
int
gs_type1_pop(gs_type1_state *pis, fixed *pf)
{ *pf = pis->ostack[--(pis->os_count)];
return 0;
}