/* PSparse.c */ #include #ifndef AIX #include #endif #include #include #include #include "defines.h" #include "myopen.h" #include "mymalloc.h" #include "ps2mf.h" #include "ps2mfutl.h" #include "PSparse.h" #ifdef MSDOS #include #endif float x_scale, y_scale; void write_MF_header () { int i; fprintf (mf_file, "%% %s\n", font_name); fprintf (mf_file, "mode_setup;\n"); fprintf (mf_file, "if unknown FontSize: FontSize := 10pt#; fi\n"); fprintf (mf_file, "FX# := FontSize * %.4f;\n", x_scale); fprintf (mf_file, "FY# := FontSize * %.4f;\n", y_scale); fprintf (mf_file, "bot_blues.n := %d;\n", num_of_other_blues + 1); fprintf (mf_file, "bot_blues1o := %d;\n", blue_values [0] . overshoot); fprintf (mf_file, "bot_blues1p := %d;\n", blue_values [0] . position); for (i = 0; i < num_of_other_blues; i ++) { fprintf (mf_file, "bot_blues%do := %d;\n", i + 2, other_blues [i] . overshoot); fprintf (mf_file, "bot_blues%dp := %d;\n", i + 2, other_blues [i] . position); } fprintf (mf_file, "top_blues.n := %d;\n", num_of_blue_values - 1); for (i = 1; i < num_of_blue_values; i ++) { fprintf (mf_file, "top_blues%do := %d;\n", i, blue_values [i] . overshoot); fprintf (mf_file, "top_blues%dp := %d;\n", i, blue_values [i] . position); } fprintf (mf_file, "blue_scale := %g;\n", blue_scale); fprintf (mf_file, "blue_shift := %d;\n", blue_shift); fprintf (mf_file, "blue_fuzz := %d;\n", blue_fuzz); fprintf (mf_file, "\ninput hints;\n"); } void write_MF_trailer () { fprintf (mf_file, "\nfont_slant := %.4f;\n", 1 - cos (italic_angle)); fprintf (mf_file, "font_normal_space := %d * FX#;\n", font_space); fprintf (mf_file, "font_normal_stretch := %d * FX#;\n", (int) (font_space / 2.0)); fprintf (mf_file, "font_normal_shrink := %d * FX#;\n", (int) (font_space / 3.0)); fprintf (mf_file, "font_x_height := %d * FY#;\n", (int) x_height); if (font_quad > 0) { fprintf (mf_file, "font_quad := %d * FX#;\n", font_quad); } else { fprintf (mf_file, "font_quad := %d * FX#;\n", (font_space * 3)); } fprintf (mf_file, "designsize := FontSize;\n"); fprintf (mf_file, "font_coding_scheme := \"%s\";\n", coding_scheme); fprintf (mf_file, "font_identifier := \"%s\";\n", font_name); fprintf (mf_file, "end.\n"); fprintf (mf_file, "%% That's all, Folks!\n"); } #ifdef __STDC__ void push (float fl) #else void push (fl) float fl; #endif { if (top_of_stack >= MAX_stack) error ("! stack overflow"); stack [top_of_stack] = fl; top_of_stack ++; } float pop () { top_of_stack --; if (top_of_stack < 0) error ("! stack underflow"); return (stack [top_of_stack]); } #ifdef __STDC__ void eat_this_character (char * s) #else void eat_this_character (s) char * s; #endif { char * this_param_string; do { get_token (ps_file); this_param_string = param_string (); } while (! (strequ (this_param_string, "ND") || strequ (this_param_string, "|-"))); } #ifdef __STDC__ bool ignore_this_character (char * s) # else bool ignore_this_character (s) char * s; # endif { ignore_info_tp * ii; for (ii = ignore_list; ii; ii = ii -> next) { if (strequ (ii -> AFM_name, s)) return (TRUE); } return (FALSE); } #ifdef __STDC__ int charstring_command (char * s) #else int charstring_command (s) char * s; #endif { char ** p; int n; if (s [0] == '/') { s ++; if (ignore_this_character (s) || ((strstr (obuffer, "seac") != NULL) && ! processing_seacs) || ((strstr (obuffer, "seac") == NULL) && processing_seacs)) { if (! have_found_seacs) have_found_seacs = TRUE; eat_this_character (s); return (not_a_charstring_command); } strcpy (current_char, s); return (charstring_command_char); } for (p = charstring_commands, n = 0; * p; p ++, n ++) if (strequ (s, * p)) return (n); if (sscanf (s, "%f", & numeric_val) == 1) return (charstring_command_numeric); if (strequ (s, "end")) return (charstring_commands_end); return (not_a_charstring_command); } #ifdef __STDC__ int PS_header_command () #else int PS_header_command () #endif { char ** p; int n; for (p = PS_header_commands, n = 0; * p; p ++, n ++) if (strstr (obuffer, * p) != NULL) return (n); return (not_a_PS_header_command); } /* Charstring Command Handling */ /* Commands for Starting and Finishing */ bool candidate_for_seac () { char ** p; for (p = seac_candidates; * p; p ++) if (strequ (current_char, * p)) return (TRUE); return (FALSE); } void do_endchar () { /* finishes a charstring outline definition and must be the last command in a character's outline (except for accented character defined using *seac*). When *endchar* is executed, Type 1 BuildChar performs several tasks. It executes a *setcachedevice* operation, using a bounding box it computes directly from the character outline and using the width information acquired from a previous *hsbw* or *sbw* operation. (Note that this is not the same order of events as in Type 3 Fonts.) BuildChar then calls a special version of *fill* or *stroke* depending on the value of *PaintType* in the font dictionary. The Type 1 font format supports only *PaintType* 0 (fill) and 2 (outline). Note that this single *fill* or *stroke* implies that there can be only one path (possibly containing several subpaths) that can be created to be filled or stroked by the *endchar* command. */ if (active_path) do_closepath (); if (candidate_for_seac ()) { fprintf (mf_file, "chp[%d]:=currentpicture;\n", current_AFM_num); } fprintf (mf_file, "endchar;\n"); } #ifdef __STDC__ void do_hsbw (float sbx, float wx) #else void do_hsbw (sbx, wx) float sbx, wx; #endif { /* sets the left sidebearing point at (sbx, 0) and sets the character width vector to (wx, 0) in character space. This command also sets the currentpoint to (sbx, 0), but does not place the point in the character path. Use *rmoveto* for the first point in the path. The name *hsbw* stands for horizontal sidebearing and width; horizontal indicates that the y component of both the sidebearing and width is 0. Either *sbw* or *hsbw* must be used once as the first command in a character outline definition. It must be used only once. In non-marking characters, such as the space character, the left sidebearing point should be (0, 0). */ do_sbw (sbx, 0.0, wx, 0.0); } #ifdef __STDC__ void do_seac (float asb, float adx, float ady, int bchar, int achar) #else void do_seac (asb, adx, ady, bchar, achar) float asb, adx, ady; int bchar, achar; #endif { /* for standard encoding accented character, makes an accented character from two other characters in its font program. The asb argument is the x component of the left sidebearing of the accent; this value must be the same as the sidebearing value given in the *hsbw* or *sbw* command in the accent's own charstring. The origin of the accent is placed at (adx, ady) relative to the origin of the base character. The bchar argument is the character code of the base character, and the achar argument is the the character code of the accent character. Both bchar and achar are codes that these characters are assigned in the Adobe StandardEncoding vector, given in an Appendix in the PostScript Language Reference Manual. Furthermore, the characters represented by achar and bchar must be in the same position in the font's encoding vector as the positions they occupy in the Adobe StandardEncoding vector. If the name of both components of an accented character do not appear in the Adobe StandardEncoding vector, the accented character cannot be build using the *seac* command. The *FontBBox* entry in the font dictionary must be large enough to accommodate both parts of the accented character. The *sbw* or *hsbw* command that begins the accented character must be the same as the corresponding command in the base character. Finally, *seac* is the last command in the charstring for the accented character because the accent and base characters' charstrings each already end with their own *endchar* commands. The use of this command saves space in a Type 1 font program, but its use is restricted to those characters whose parts are defined in the Adobe StandardEncoding vector. In situations where use of the *seac* command is not possible, use of *Subrs* subroutines is a more general means for creating accented characters. */ fprintf (mf_file, "seac(%d,%d,%g,%g)\n", achar, bchar, adx + current_point . x - asb, ady); fprintf (mf_file, "endchar;\n"); } #ifdef __STDC__ void do_sbw (float sbx, float sby, float wx, float wy) #else void do_sbw (sbx, sby, wx, wy) float sbx, sby, wx, wy; #endif { /* sets the left sidebearing point to (sbx, sby) and sets the character width vector to (wx, wy) in character space. This command also sets the current point to (sbx, sby), but does not place the point in the character path. Use *rmoveto* for the first point in the path. The name *sbw* stands for sidebearing and width; the x and y components of both the left sidebearing and width must be specified. If the y components of both the left sidebearing and the width are 0, then the *hsbw* command should be used. Either *sbw* or *hsbw* must be used once as the first command in a character outline definition. It must be used only once. */ current_point . x = sbx; current_point . y = sby; the_sbx = sbx; } /* Path Construction Commands */ void do_closepath () { /* *closepath* closes a subpath. Adobe strongly recommends that all character subpaths end with a *closepath* command, otherwise when an outline is stroked (by setting *PaintType* equal to 2) you may get unexpected behaviour where lines join. Note that, unlike the *closepath* command in the PostScript language, this command does not reposition the current point. Any subsequent *rmoveto* must be relative to the current point in force before the Type 1 format *closepath* command was given. Make sure that any subpath section formed by the *closepath* command intended to be zero length, is zero length. If not, the *closepath* command may cause a "spike" or "hangnail" (if the subpath doubles back onto itself) with unexpected results. */ fprintf (mf_file, " )cp\n"); active_path = FALSE; after_hint = FALSE; } #ifdef __STDC__ void do_hlineto (float dx) #else void do_hlineto (dx) float dx; #endif { /* for horizontal lineto. Equivalent to dx 0 *rlineto*. */ do_rlineto (dx, 0.0); } #ifdef __STDC__ void do_hmoveto (float dx) #else void do_hmoveto (dx) float dx; #endif { /* for horizontal lineto. Equivalent to dx 0 *rmoveto*. */ do_rmoveto (dx, 0.0); } #ifdef __STDC__ void do_hvcurveto (float dx1, float dx2, float dy2, float dy3) #else void do_hvcurveto (dx1, dx2, dy2, dy3) float dx1, dx2, dy2, dy3; #endif { /* for horizontal-vertical curveto. Equivalent to dx1 0 dx2 dy2 0 dy3 *rrcurveto*. This command eliminates two arguments from an *rrcurveto* call when the first B'ezier tangent is horizontal and the second B'ezier tangent is vertical. */ do_rrcurveto (dx1, 0.0, dx2, dy2, 0.0, dy3); } #ifdef __STDC__ void do_rlineto (float dx, float dy) #else void do_rlineto (dx, dy) float dx, dy; #endif { /* (relative *lineto*) appends a straight line segment to the current path in the same manner as *lineto*. However, the number pair is interpreted as a displacement relative to the current point (x, y) rather than as an absolute coordinate. That is, *rlineto* constructs a line from (x, y) to (x + dx, y + dy) and makes (x + dx, y + dy) the new current point. If the current point is undefined because the current path is empty, *rlineto* executes the error *nocurrentpoint*. */ current_point . x += dx; current_point . y += dy; fprintf (mf_file, "lt%s(%g,%g)\n", after_hint ? "h" : "", current_point . x, current_point . y); after_hint = FALSE; } #ifdef __STDC__ void do_rmoveto (float dx, float dy) #else void do_rmoveto (dx, dy) float dx, dy; #endif { /* (relative *moveto*) starts a new subpath of the current path in the same manner as *moveto*. However, the number pair is interpreted as a displacement relative to the current point (x, y) rather than as an absolute coordinate. That is, *rmoveto* makes (x + dx, y + dy) the new currentpoint, without connecting it to the previous point. If the current point is undefined because the current path is empty, *moveto* executes the error *nocurrentpoint*. */ current_point . x += dx; current_point . y += dy; if (active_path) do_closepath (); path_number ++; active_path = TRUE; if (after_hint) fprintf (mf_file, "ih\n"); fprintf (mf_file, "dr\n"); fprintf (mf_file, "ah((%g,%g)\n", current_point . x, current_point . y); after_hint = FALSE; } #ifdef __STDC__ void do_rrcurveto (float dx1, float dy1, float dx2, float dy2, float dx3, float dy3) #else void do_rrcurveto (dx1, dy1, dx2, dy2, dx3, dy3) float dx1, dy1, dx2, dy2, dx3, dy3; #endif { /* for relative *rcurveto*. Whereas the arguments to the *rcurveto* operator in the PostScript language are all relative to the current point, the arguments to *rrcurveto* are relative to each other. Equivalent to dx1 dy1 (dx1 + dx2) (dy1 + dy2) (dx1 + dx2 + dx3, dy1 + dy2 + dy3) *rcurveto*. */ do_rcurveto (dx1, dy1, dx1 + dx2, dy1 + dy2, dx1 + dx2 + dx3, dy1 + dy2 + dy3); } #ifdef __STDC__ void do_vhcurveto (float dy1, float dx2, float dy2, float dx3) #else void do_vhcurveto (dy1, dx2, dy2, dx3) float dy1, dx2, dy2, dx3; #endif { /* for vertical-horizontal curveto. Equivalent to 0 dy1 dx2 dy2 dx3 0 *rrcurveto*. This command eliminates two arguments from an *rrcurveto* call when the first B'ezier tangent is vertical and the second B'ezier tangent is horizontal. */ do_rrcurveto (0.0, dy1, dx2, dy2, dx3, 0.0); } #ifdef __STDC__ void do_vlineto (float dy) #else void do_vlineto (dy) float dy; #endif { /* for vertical lineto. This is equivalent to 0 dy *rlineto*. */ do_rlineto (0.0, dy); } #ifdef __STDC__ void do_vmoveto (float dy) #else void do_vmoveto (dy) float dy; #endif { /* for vertical moveto. This is equivalent to 0 dy *rmoveto*. */ do_rmoveto (0.0, dy); } void do_dotsection () { /* brackets an outline section for the dots in letters such as "i", "j" and "!". This is a hint command that indicates that a section of a charstring should be understood as describing such a feature, rather than as port of the main outline. */ } #ifdef __STDC__ void do_hstem (float y, float dy) #else void do_hstem (y, dy) float y, dy; #endif { /* declares the vertical range of a horizontal stem zone between the y coordinates y and y + dy, where y is relative to the y coordinate of the left sidebearing point. Horizontal stem zones within a set of stem hints for a single character may not overlap other horizontal stem zones. Use hint replacement to avoid stem hint overlaps. */ if (dy >= 0) fprintf (mf_file, "dh(\"hs(%g,%g)\")\n", y, y + dy); else fprintf (mf_file, "dh(\"hs(%g,%g)\")\n", y + dy, y); after_hint = TRUE; } #ifdef __STDC__ void do_hstem3 (float y0, float dy0, float y1, float dy1, float y2, float dy2) #else void do_hstem3 (y0, dy0, y1, dy1, y2, dy2) float y0, dy0, y1, dy1, y2, dy2; #endif { /* declares the vertical ranges of three horizontal stem zones between the y coordinates y0 and y0 + dy0, y1 and y1 + dy2, and between y2 and y2 + dy2, where y0, y1 and y2 are all relative to the y coordinate of the left sidebearing point. The *hstem3* command sorts these zones by the y values to obtain the lowest, middle and highest zones, called ymin, ymid and ymax respectively. The corresponding dy values are called dymin, dymid and dymax. These stems and the counters between them will all be controled. These coordinates must obey certain restrictions: . dymin = dymax . The distance from ymin + dymin/2 to ymid + dymid/2 must equal the distance from ymid + dymid/2 to ymax + dymax/2. In other words, the distance from the center of the bottom stem to the center of the middle stem must be the same as the distance from the center of the middle stem to the center of the top stem. If a charstring uses an *hstem3* command in the hints for a character, the charstring must not use *hstem* commands and it must use the same *hstem3* command consistently if hint replacement is performed. The *hstem3* command is especially suited for controlling the stems and counters of symbols with three horizontally oriented features with equal vertical widths and with equal white space between these features, such as the mathematical equivalence symbol or the division symbol. */ do_hstem (y0, dy0); do_hstem (y1, dy1); do_hstem (y2, dy2); fprintf (mf_file, "dh(\"hst\")\n"); } #ifdef __STDC__ void do_vstem (float x, float dx) # else void do_vstem (x, dx) float x, dx; # endif { /* declares the horizontal range of a vertical stem zone between the x coordinates x and x + dx, where x is relative to the x coordinate of the left sidebearing point. Vertical stem zones within a set of stem hints for a single character may not overlap other vertical stem zones. Use hint replacement to avoid stem hint overlap. */ if (dx >= 0) fprintf (mf_file, "dh(\"vs(%g,%g)\")\n", x + the_sbx, x + dx + the_sbx); else fprintf (mf_file, "dh(\"vs(%g,%g)\")\n", x + dx + the_sbx, x + the_sbx); after_hint = TRUE; } #ifdef __STDC__ void do_vstem3 (float x0, float dx0, float x1, float dx1, float x2, float dx2) #else void do_vstem3 (x0, dx0, x1, dx1, x2, dx2) float x0, dx0, x1, dx1, x2, dx2; #endif { /* declares the horizontal ranges of three vertical stem zones between the x coordinates x0 and x0 + dx0, x1 and x1 + dx2, and x2 and x2 + dx2, where x0, x1 and x2 are all relative to the x coordinate of the left sidebearing point. The *vstem3* command sorts these zones by the x values to obtain the leftmost, middle and rightmost zones, called xmin, xmid and xmax respectively. The corresponding dx values are called dxmin, dxmid and dxmax. These stems and the counters between them will all be controled. These coordinates must obey certain restrictions: . dxmin = dxmax . The distance from xmin + dxmin/2 to xmid + dxmid/2 must equal the distance from xmid + dxmid/2 to xmax + dxmax/2. In other words, the distance from the center of the left stem to the center of the middle stem must be the same as the distance from the center of the middle stem to the center of the right stem. If a charstring uses an *vstem3* command in the hints for a character, the charstring must not use *vstem* commands and it must use the same *vstem3* command consistently if hint replacement is performed. The *vstem3* command is especially suited for controlling the stems and counters of characters such as a lower case "m". */ do_vstem (x0, dx0); do_vstem (x1, dx1); do_vstem (x2, dx2); fprintf (mf_file, "dh(\"vst\")\n"); } #ifdef __STDC__ void do_rcurveto (float dx1, float dy1, float dx2, float dy2, float dx3, float dy3) #else void do_rcurveto (dx1, dy1, dx2, dy2, dx3, dy3) float dx1, dy1, dx2, dy2, dx3, dy3; #endif { /* (relative *curveto*) adds a B'ezier cubic section to the current path in the same manner as *curveto*. However, the three number pairs are interpreted as displacements relative to the current point (x0, y0) rather than as absolute coordinates. That is, *rcurveto* constructs a curve from (x0, y0) to (x0 + dx3, y0 + dy3), using (x0 + dx1, y0 + dy1) and (x0 + dx2, y0 + dy2) as B'ezier control points. */ fprintf (mf_file, "ct%s(%g,%g,%g,%g,%g,%g)\n", after_hint ? "h" : "", current_point . x + dx1, current_point . y + dy1, current_point . x + dx2, current_point . y + dy2, current_point . x + dx3, current_point . y + dy3); current_point . x += dx3; current_point . y += dy3; after_hint = FALSE; } /* Arithmetic Command */ #ifdef __STDC__ void do_div (float num1, float num2) #else void do_div (num1, num2) float num1, num2; #endif { /* divides num1 by num2, producing a result that is always a real even if both operands are integers */ push (num1 / num2); } /* Subroutine Commands */ #ifdef __STDC__ void do_moveto_for_flex (float dx, float dy) # else void do_moveto_for_flex (dx, dy) float dx, dy; #endif { current_point . x += dx; current_point . y += dy; flex . x [flex . n] = current_point . x; flex . y [flex . n] = current_point . y; } #ifdef __STDC__ void do_callothersubr (int othersubr, int n) #else void do_callothersubr (othersubr, n) int othersubr, n; #endif { /* is a mechanism used by Type 1 BuildChar to make calls on the PostScript interpreter. Arguments argn through arg1 are pushed onto the PostScript interpreter operand stack, and the PostScript language procedure in the othersubr# position in the *OtherSubrs* array in the *Private* dictionary (or a built-in function equivalent to this procedure) is executed. Note that the argument order will be reversed when pushed onto the PostScript interpreter operand stack. After the arguments are pushed onto the PostScript interpreter operand stack, the PostScript interpreter performs a *begin* operation on *systemdict* followed by a *begin* operation on the font dictionary prior to executing the *OtherSubrs* entry. When the *OtherSubrs* entry completes its execution, the PostScript interpreter performs two *end* operations prior to returning to Type 1 BuildChar charstring execution. Use *pop* commands to retrieve results from the PostScript operand stack back to the Type 1 BuildChar operand stack. */ float flex_h; switch (othersubr) { case 0: { (void) pop (); /* end point y */ (void) pop (); /* end point x */ flex_h = pop (); /* flex feature height */ if (! active_flex) error ("! othersub 1 required before Flex othersub 0\n"); if (flex . n != 7) error ("! seven calls to othersub 2 required before Flex othersub 0\n"); fprintf (mf_file, " fl%s(%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g)\n", after_hint ? "h" : "", flex . x [0], flex . y [0], flex . x [1], flex . y [1], flex . x [2], flex . y [2], flex . x [3], flex . y [3], flex . x [4], flex . y[4], flex . x [5], flex . y [5], flex . x [6], flex . y [6], flex_h); active_flex = after_hint = FALSE; } break; case 1: { active_flex = TRUE; flex . n = 0; } break; case 2: { flex . n ++; } break; case 3: { if (active_path && ! after_hint) fprintf (mf_file, " )\n"); } break; } } #ifdef __STDC__ void do_callsubr (int subr_no) #else void do_callsubr (subr_no) int subr_no; #endif { /* calls a charstring subroutine with index subr# form the *Subrs* array in the *private* dictionary. Each element of the *Subrs* array is a charstring encoded and encrypted like any other charstring. Arguments pushed on the Type 1 BuildChar operand stack prior to calling the subroutine, and results pushed on the stack by the subroutine, act according to the manner in which the subroutine is coded. These subroutines are generally used to encode sequences of path commands that are repeated throughout the font program, for example, serif outline sequences. Subroutine calls may be nested 10 deep. */ if (Subrs_entries [subr_no] == NULL) { error ("! Undefined subroutine called"); } processing_Subr = TRUE; current_Subr ++; Subrs_stack [current_Subr] = Subrs_entries [subr_no]; } float do_pop () { /* removes a number from the top of the PostScript interpreter operand stack and pushes that number onto the Type1 BuildChar operand stack. This command is used only to retrieve a result from an *OtherSubrs* procedure. */ return (0.0); } void do_return () { /* returns from a *Subrs* array charstring subroutine (that had been called with a *callsubr* command) and continues execution in the calling charstring. */ current_Subr --; if (current_Subr < 0) processing_Subr = FALSE; } #ifdef __STDC__ void do_setcurrentpoint (float x, float y) #else void do_setcurrentpoint (x, y) float x, y; #endif { /* sets the current point in the Type 1 format *BuildChar* to (x, y) in absolute character space coordinates without performing a charstring *moveto* command. This establishes the current point for a subsequent relative path building command. The *setcurrentpoint* command is used only in conjunction with results from *OtherSubrs* procedures. */ current_point . x = x; current_point . y = y; } void process_hstem () /* hstem: |- y dy hstem (1) |- */ { float y, dy; dy = pop (); y = pop (); do_hstem (y, dy); } void process_vstem () /* vstem: |- x dx vstem (3) |- */ { float x, dx; dx = pop (); x = pop (); do_vstem (x, dx); } void process_vmoveto () /* vmoveto: |- dy vmoveto (4) |- */ { float dy; dy = pop (); if (active_flex) do_moveto_for_flex (0.0, dy); else do_vmoveto (dy); } void process_rlineto () /* rlineto: |- dx dy rlineto (5) |- */ { float dx, dy; dy = pop (); dx = pop (); do_rlineto (dx, dy); } void process_hlineto () /* hlineto: |- dx hlineto (6) |- */ { float dx; dx = pop (); do_hlineto (dx); } void process_vlineto () /* vlineto: |- dy vlineto (7) |- */ { do_vlineto (pop ()); } void process_rrcurveto () /* rrcurveto: |- dx1 dy1 dx2 dy2 dx3 dy3 rrcurveto (8) |- */ { float dx1, dy1, dx2, dy2, dx3, dy3; dy3 = pop (); dx3 = pop (); dy2 = pop (); dx2 = pop (); dy1 = pop (); dx1 = pop (); do_rrcurveto (dx1, dy1, dx2, dy2, dx3, dy3); } void process_closepath () /* - closepath (9) |- */ { do_closepath (); } void process_callsubr () /* subr# callsubr */ { do_callsubr ((int) pop ()); } void process_return () /* - return (11) - */ { /* returns from a *Subrs* array charstring subroutine (that had been called with a *callsubr* command) and continues execution in the calling charstring. */ do_return (); } void process_escape () /* escape (12) */ { /* skip */; } void process_hsbw () /* |- sbx wx hsbw (13) |- */ { float sbx, wx; wx = pop (); sbx = pop (); do_hsbw (sbx, wx); } void process_endchar () /* - endchar (14) |- */ { do_endchar (); } void process_rmoveto () /* |- dx dy rmoveto (21) |- */ { float dx, dy; dy = pop (); dx = pop (); if (active_flex) do_moveto_for_flex (dx, dy); else do_rmoveto (dx, dy); } void process_hmoveto () /* |- dx hmoveto (22) |- */ { float dx; dx = pop (); if (active_flex) do_moveto_for_flex (dx, 0.0); else do_hmoveto (dx); } void process_vhcurveto () /* |- dy1 dx2 dy2 dx3 vhcurveto (30) |- */ { float dy1, dx2, dy2, dx3; dx3 = pop (); dy2 = pop (); dx2 = pop (); dy1 = pop (); do_vhcurveto (dy1, dx2, dy2, dx3); } void process_hvcurveto () /* |- dx1 dx2 dy2 dy3 hvcurveto (31) |- */ { float dx1, dx2, dy2, dy3; dy3 = pop (); dy2 = pop (); dx2 = pop (); dx1 = pop (); do_hvcurveto (dx1, dx2, dy2, dy3); } void process_dotsection () /* - dotsection (12 0) |- */ { do_dotsection (); } void process_vstem3 () /* |- x0 dx0 x1 dx1 x2 dx2 vstem3 (12 1) |- */ { float x0, dx0, x1, dx1, x2, dx2; dx2 = pop (); x2 = pop (); dx1 = pop (); x1 = pop (); dx0 = pop (); x0 = pop (); do_vstem3 (x0, dx0, x1, dx1, x2, dx2); } void process_hstem3 () /* |- y0 dy0 y1 dy1 y2 dy2 hstem3 (12 2) |- */ { float y0, dy0, y1, dy1, y2, dy2; dy2 = pop (); y2 = pop (); dy1 = pop (); y1 = pop (); dy0 = pop (); y0 = pop (); do_hstem3 (y0, dy0, y1, dy1, y2, dy2); } void process_seac () /* |- asb adx ady bchar achar seac (12 6) |- */ { float asb, adx, ady; int bchar, achar; achar = (int) pop (); bchar = (int) pop (); ady = pop (); adx = pop (); asb = pop (); do_seac (asb, adx, ady, bchar, achar); } void process_sbw () /* |- sbx sby wx wy sbw (12 7) |- */ { float sbx, sby, wx, wy; wy = pop (); wx = pop (); sby = pop (); sbx = pop (); do_sbw (sbx, sby, wx, wy); } void process_div () /* num1 num2 div (12 12) quotient */ { float num1, num2; num2 = pop (); num1 = pop (); do_div (num1, num2); } void process_callothersubr () /* arg1 ... argn n othersubr# callothersubr (12 16) - */ { int othersubr, n; othersubr = (int) pop (); n = (int) pop (); do_callothersubr (othersubr, n); } float process_pop () { return (do_pop ()); } void process_setcurrentpoint () /* |- x y setcurrentpoint (12 33) |- */ { float x, y; y = pop (); x = pop (); do_setcurrentpoint (x, y); } #ifdef __STDC__ void start_char (char * name) #else void start_char (name) char * name; #endif { AFM_info_tp * ai; ai = find_AFM_info_for (name); if (ai == NULL || ai -> TeX_num == -1) { /* fprintf (stderr, "No TeX coding found for character %s\n", name); */ eat_this_character (name); return; } if (first_time_generating) { fprintf (stderr, "Generating MF code for %s", name); linepos = strlen ("Generating MF code for "); linepos += strlen (name); first_time_generating = FALSE; } else { if (linepos + strlen (name) + 3 < 79) { fprintf (stderr, ", %s", name); linepos += strlen (name) + 3; } else { fprintf (stderr, ",\n %s", name); linepos = strlen (name) + 2; } } fprintf (mf_file, "\nbeginchar(%d,%d*FX#,%d*FY#,%d*FY#);\n", ai -> TeX_num, ai -> width, ai -> bbox_ury, (ai -> bbox_lly == 0) ? 0 : -ai -> bbox_lly); fprintf (mf_file, "\"%s\";\n", ai -> AFM_name); path_number = 0; active_path = FALSE; ai -> in_MF_file = TRUE; current_AFM_num = ai -> AFM_num; } Subrs_entry_tp * new_Subrs_entry () { Subrs_entry_tp * nse; nse = (Subrs_entry_tp *) my_malloc (sizeof (Subrs_entry_tp)); nse -> token = NULL; nse -> next = NULL; return (nse); } void process_one_Subrs_entry () { Subrs_entry_tp * se, * nse, * lse; char * p; int n; bool stop; stop = FALSE; expect ("dup"); n = param_num (); if (n >= MAX_Subrs_entries) error ("! Too many Subrs"); se = new_Subrs_entry (); lse = se; while (! stop) { nse = new_Subrs_entry (); nse -> token = param_new_string (); if (strequ (nse -> token, "return")) stop = TRUE; lse -> next = nse; lse = nse; if (! * param) get_line (ps_file); } Subrs_entries [n] = se; } void process_Subrs_entries () { int i; while (get_line (ps_file)) { if (strstr (obuffer, "dup") == NULL) return; else process_one_Subrs_entry (); } } void get_paint_type () { char * dummy_string; int dummy_int; dummy_string = param_string (); dummy_int = param_num (); if (dummy_int != 0) error ("! Can only handle outlinefonts"); } void get_font_type () { char * dummy_string; int dummy_int; dummy_string = param_string (); dummy_int = param_num (); if (dummy_int != 1) error ("! Can only translate Type 1 fonts"); } void get_font_matrix () { char * dummy_string; float dummy_float; dummy_string = param_string (); if (* param == '[') { param ++; while (* param == ' ') param ++; } x_scale = param_float (); dummy_float = param_float (); dummy_float = param_float (); y_scale = param_float (); } void get_italic_angle () { char * dummy_string; float dummy_float; dummy_string = param_string (); if (italic_angle != param_float ()) { error ("! PS en AFM do not match"); } } void get_is_fixed_pitch () { char * dummy_string; dummy_string = param_string (); if (fixed_pitch != ((* param == 't' || * param == 'T') ? TRUE : FALSE)) { error ("! PS en AFM do not match"); } } void get_blue_scale () { char * dummy_string; float dummy_float; int dummy_int; dummy_string = param_string (); blue_scale = param_float (); } void get_blue_shift () { char * dummy_string; float dummy_float; int dummy_int; dummy_string = param_string (); blue_shift = param_num (); } void get_blue_fuzz () { char * dummy_string; float dummy_float; int dummy_int; dummy_string = param_string (); blue_fuzz = param_num (); } void get_blue_values () { char * dummy_string; num_of_blue_values = 0; dummy_string = param_string (); if (* param == '[') { param ++; while (* param == ' ') param ++; } while (isdigit (* param) || * param == '-') /* added ILH */ { if (num_of_blue_values == 0) { blue_values [num_of_blue_values] . overshoot = param_num (); blue_values [num_of_blue_values] . position = param_num (); } else { blue_values [num_of_blue_values] . position = param_num (); blue_values [num_of_blue_values] . overshoot = param_num (); } num_of_blue_values ++; /* if (num_of_blue_values >= MAX_blue_values) */ } } void get_other_blues () { char * dummy_string; float dummy_float; int dummy_int; num_of_other_blues = 0; dummy_string = param_string (); if (* param == '[') { param ++; while (* param == ' ') param ++; } while (isdigit (* param) || * param == '-') /* added ILH */ { other_blues [num_of_other_blues] . overshoot = param_num (); other_blues [num_of_other_blues] . position = param_num (); num_of_other_blues ++; /* if (num_of_other_blues >= MAX_other_blues) */ } } void parse_PS_header () { /* Skip PS file until FontInfo entry -- the FontInfo case below will not be called because we eat it now */ while (get_line (ps_file) && PS_header_command () != FontInfo) /* skip */; while (get_line (ps_file)) { switch (PS_header_command ()) { case FontInfo: break; case FontName: break; case Encoding: break; case PaintType: { get_paint_type (); } break; case FontType: { get_font_type (); } break; case FontMatrix: { get_font_matrix (); } break; case FontBBox: break; case UniqueID: break; case Metrics: break; case StrokeWidth: break; case Private: break; case CharStrings: { get_line (ps_file); return; } case FID: break; case version: break; case Notice: break; case FullName: break; case FamilyName: break; case Weight: break; case ItalicAngle: { get_italic_angle (); } break; case isFixedPitch: { get_is_fixed_pitch (); } break; case UnderlinePosition: break; case UnderlineThickness: break; case BlueFuzz: { get_blue_fuzz (); } break; case BlueScale: { get_blue_scale (); } break; case BlueShift: { get_blue_shift (); } break; case BlueValues: { get_blue_values (); } break; case ExpansionFactor: break; case FamilyBlues: break; case FamilyOtherBlues: break; case ForceBold: break; case LanguageGroup: break; case lenIV: break; case MinFeature: break; case ND: break; case NP: break; case OtherSubrs: break; case OtherBlues: { get_other_blues (); } break; case password: break; case RD: break; case RndStemUp: break; case StdHW: break; case StdVW: break; case StemSnapH: break; case StemSnapV: break; case Subrs: { process_Subrs_entries (); } break; case not_a_PS_header_command: break; default: break; } } } char * next_param_string () { if (! processing_Subr) return (param_string ()); Subrs_stack [current_Subr] = Subrs_stack [current_Subr] -> next; return (Subrs_stack [current_Subr] -> token); } void parse_charstrings_dictionary () { float dummy; processing_Subr = FALSE; current_Subr = -1; while (get_token (ps_file)) { switch (charstring_command (next_param_string ())) { case hstem: process_hstem (); break; case vstem: process_vstem (); break; case vmoveto: process_vmoveto (); break; case rlineto: process_rlineto (); break; case hlineto: process_hlineto (); break; case vlineto: process_vlineto (); break; case rrcurveto: process_rrcurveto (); break; case closepath: process_closepath (); break; case callsubr: process_callsubr (); break; case return_command: process_return (); break; case escape: process_escape (); break; case hsbw: process_hsbw (); break; case endchar: process_endchar (); break; case rmoveto: process_rmoveto (); break; case hmoveto: process_hmoveto (); break; case vhcurveto: process_vhcurveto (); break; case hvcurveto: process_hvcurveto (); break; case dotsection: process_dotsection (); break; case vstem3: process_vstem3 (); break; case hstem3: process_hstem3 (); break; case seac: process_seac (); break; case sbw: process_sbw (); break; case div: process_div (); break; case callothersubr: process_callothersubr (); break; case pop_command: dummy = process_pop (); break; case charstring_command_numeric: push (numeric_val); break; case charstring_command_char: start_char (current_char); break; case charstring_commands_end: return; default: break; } } } void parse_PS () { top_of_stack = 0; x_scale = 1000; y_scale = 1000; have_found_seacs = FALSE; after_hint = FALSE; the_sbx = 0.0; blue_scale = 0.039625; blue_shift = 7; blue_fuzz = 1; first_time_generating = TRUE; parse_PS_header (); write_MF_header (); charstring_position = ftell (ps_file); processing_seacs = FALSE; parse_charstrings_dictionary (); if (have_found_seacs) { fseek (ps_file, charstring_position, 0); processing_seacs = TRUE; parse_charstrings_dictionary (); } fprintf (stderr, ".\n"); process_ligatures_and_kerns (); write_MF_trailer (); }