/* PAUL MURRELL This is from the GNU plotutils libplot-2.3 distribution Several modifications have been made to use the R graphics engine for output. All references to HAVE_PROTOS removed All references to "plotter" replaced with references to "GEDevDesc" */ /* This file contains the internal method _falabel_hershey(), which plots a label using Hershey fonts. Each character in a Hershey font is a sequence of pen motions, so this function simply calls fmoverel() and fcontrel() to `stroke' each character in the argument string. The width of the string in user units is returned. The internal method _flabelwidth_hershey() is similar, but does not actually plot the label. */ /* PAUL MURRELL sys-defines.h not used */ /* #include "sys-defines.h" */ /* PAUL MURRELL extern.h renamed g_extern.h */ #include "g_extern.h" #include "g_control.h" #include "g_her_metr.h" /* Shearing factor for oblique fonts, new_x = x + SHEAR * y */ #define SHEAR (2.0/7.0) /* Relative size of subscripts/superscripts (i.e. `indexical' size) */ #define SCRIPTSIZE (0.6) /* Positioning of subscripts/superscripts */ #define SUBSCRIPT_DX 0.0 #define SUBSCRIPT_DY (-0.25) #define SUPERSCRIPT_DX 0.0 #define SUPERSCRIPT_DY 0.4 /* Positioning of accents (in Hershey units). UP_SHIFT is amount by which accents are raised when placed over upper-case letters. RIGHT_SHIFT is applied as well, if the upper-case letter is italic. */ #define ACCENT_UP_SHIFT 7.0 #define ACCENT_RIGHT_SHIFT 2.0 /* Relative size of small Japanese Kana */ #define SMALL_KANA_SIZE 0.725 /* Hershey glyph arrays */ #define OCCIDENTAL 0 #define ORIENTAL 1 /* Location of first Kana in the occidental glyph arrays. (Kana, unlike Kanji, are placed in the occidental array, at the very end.) */ #define BEGINNING_OF_KANA 4195 /* PAUL MURRELL Structure to contain vfont current position */ typedef struct { double currX; double currY; double angle; } vfontContext; /* forward references */ static bool0 _composite_char (unsigned char *composite, unsigned char *character, unsigned char *accent); static void _draw_stroke (vfontContext *vc, const pGEcontext gc, pGEDevDesc dd, bool0 pendown, double deltax, double deltay); static double _label_width_hershey (const pGEcontext gc, pGEDevDesc dd, const unsigned short *label); static void _draw_hershey_string (vfontContext *vc, const pGEcontext gc, pGEDevDesc dd, const unsigned short *string); /* _draw_hershey_stroke() draws a stroke, taking into account the transformation from Hershey units to user units, and also the current transformation matrix (as set by the user). _draw_stroke is similar, but takes arguments in user units. */ /* PAUL MURRELL _draw_stroke now takes arguments in INCHES; it needs to work in an absolute coordinate system because it does the rotation */ static void _draw_hershey_stroke (vfontContext *vc, const pGEcontext gc, pGEDevDesc dd, bool0 pendown, double deltax, double deltay) { _draw_stroke(vc, gc, dd, pendown, fromDeviceWidth(HERSHEY_X_UNITS_TO_USER_UNITS (deltax), GE_INCHES, dd), fromDeviceHeight(HERSHEY_Y_UNITS_TO_USER_UNITS (deltay), GE_INCHES, dd)); } static void moverel(double dx, double dy, vfontContext *vc) { vc->currX += dx; vc->currY += dy; } static void linerel(double dx, double dy, vfontContext *vc, const pGEcontext gc, pGEDevDesc dd) { GELine(toDeviceX(vc->currX, GE_INCHES, dd), toDeviceY(vc->currY, GE_INCHES, dd), toDeviceX(vc->currX+dx, GE_INCHES, dd), toDeviceY(vc->currY+dy, GE_INCHES, dd), gc, dd); vc->currX += dx; vc->currY += dy; } /* e.g. for some Windows headers */ #ifndef M_PI #define M_PI 3.141592653589793238462643383279502884197169399375 #endif static void _draw_stroke (vfontContext *vc, const pGEcontext gc, pGEDevDesc dd, bool0 pendown, double deltax, double deltay) { double dx, dy; double theta; theta = M_PI * vc->angle / 180.0; dx = cos(theta) * deltax - sin(theta) * deltay; dy = sin(theta) * deltax + cos(theta) * deltay; if (pendown) linerel(dx, dy, vc, gc, dd); else moverel(dx, dy, vc); } /* PAUL MURRELL Renamed from _g_flabelwidth_hershey to GVStrWidth ... and added unit argument ... and rearranged order of arguments */ /* this is the version of the flabelwidth() method that is specific to the case when the current Plotter font is a Hershey font; called in g_flabelwidth () . Argument 'enc' is ignored: these are in their own encoding. */ attribute_hidden double R_GE_VStrWidth (const char *s, cetype_t enc, const pGEcontext gc, pGEDevDesc dd) { double label_width; unsigned short *codestring; /* PAUL MURRELL _controlify using R_alloc instead of xmalloc so need to do vmaxget() ... vmaxset() instead of free() */ const void *vmax = vmaxget(); /* convert string to a codestring, including annotations */ codestring = _controlify (dd, (const unsigned char *) s, gc->fontfamily[7] - 1, gc->fontface); label_width = _label_width_hershey (gc, dd, codestring); vmaxset(vmax); /* free (codestring); */ return label_width; } /* PAUL MURRELL Added _label_height_hershey and GVStrHeight function */ static double _label_height_hershey (const pGEcontext gc, pGEDevDesc dd, const unsigned short *label) { return( HERSHEY_Y_UNITS_TO_USER_UNITS(HERSHEY_LARGE_CAPHEIGHT) ); } attribute_hidden double R_GE_VStrHeight (const char *s, cetype_t enc, const pGEcontext gc, pGEDevDesc dd) { double label_height; unsigned short *codestring; const void *vmax = vmaxget(); /* convert string to a codestring, including annotations */ codestring = _controlify (dd, (const unsigned char *) s, gc->fontfamily[7] - 1, gc->fontface); label_height = _label_height_hershey (gc, dd, codestring); vmaxset(vmax); return label_height; } /* PAUL MURRELL This guy is the entry point to the GNU code Renamed from _g_falabel_hershey to GVText Reordered arguments Added x, y, rotation, and font specification arguments Re-typed x/y_justify from int to double Re-typed s from "unsigned char *" to char * Changed return value from double to void */ /* this is the version of the falabel() method that is specific to the case when the current Plotter font is a Hershey font */ attribute_hidden void R_GE_VText (double x, double y, const char *s, cetype_t enc, double x_justify, double y_justify, double rotation, const pGEcontext gc, pGEDevDesc dd) { unsigned short *codestring; double label_width, label_height; double x_offset, y_offset; /* double x_displacement; */ /* PAUL MURRELL _controlify using R_alloc instead of xmalloc so need to do vmaxget() ... vmaxset() instead of free() */ const void *vmax = vmaxget(); /* PAUL MURRELL initialise the local currX and currY work in INCHES because that is what moverel and linerel work in */ vfontContext vc; vc.currX = fromDeviceX(x, GE_INCHES, dd); vc.currY = fromDeviceY(y, GE_INCHES, dd); vc.angle = rotation; /* PAUL MURRELL * Override gc settings for lty and lwd */ gc->lty = LTY_SOLID; gc->lwd = HERSHEY_LINE_WIDTH_TO_LWD (HERSHEY_STROKE_WIDTH); gc->lend = GE_ROUND_CAP; gc->ljoin = GE_ROUND_JOIN; /* convert string to a codestring, including annotations */ codestring = _controlify (dd, (const unsigned char *)s, gc->fontfamily[7] - 1, gc->fontface); /* PAUL MURRELL Justification changed from char (e.g., 'l', 'c', 'r') to double (e.g., 0, .5, 1) Also added handling of NaN x_justify and y_justify ... and replaced HERSHEY_Y_UNITS_TO_USER_UNITS(HERSHEY_HEIGHT) with HERSHEY_Y_UNITS_TO_USER_UNITS(HERSHEY_LARGE_CAPHEIGHT) ... and replaced ((double)HERSHEY_ASCENT / (double)HERSHEY_HEIGHT) with 1.0 */ /* dimensions of the string, in user units */ label_width = _label_width_hershey (gc, dd, codestring); label_height = _label_height_hershey(gc, dd, codestring); if (!R_FINITE(x_justify)) x_justify = 0.5; if (!R_FINITE(y_justify)) y_justify = 0.5; x_offset = 0 - x_justify; /* x_displacement = 1 - 2 * x_justify; */ y_offset = 0 - y_justify * 1.0; /* save relevant drawing attributes, and restore them later */ { /* char *old_line_mode, *old_cap_mode, *old_join_mode; int old_fill_type; double oldposx, oldposy; bool0 old_dash_array_in_effect; old_line_mode = (char *)_plot_xmalloc (strlen (_plotter->drawstate->line_mode) + 1); old_cap_mode = (char *)_plot_xmalloc (strlen (_plotter->drawstate->cap_mode) + 1); old_join_mode = (char *)_plot_xmalloc (strlen (_plotter->drawstate->join_mode) + 1); oldposx = (_plotter->drawstate->pos).x; oldposy = (_plotter->drawstate->pos).y; strcpy (old_line_mode, _plotter->drawstate->line_mode); strcpy (old_cap_mode, _plotter->drawstate->cap_mode); strcpy (old_join_mode, _plotter->drawstate->join_mode); old_fill_type = _plotter->drawstate->fill_type; old_dash_array_in_effect = _plotter->drawstate->dash_array_in_effect; */ /* Our choices for rendering: solid lines, rounded capitals and joins, a line width equal to slightly more than 1 Hershey unit, and transparent filling. */ /* _plotter->linemod (R___(_plotter) "solid"); _plotter->capmod (R___(_plotter) "round"); _plotter->joinmod (R___(_plotter) "round"); _plotter->filltype (R___(_plotter) 0); */ /* move to take horizontal and vertical justification into account; arguments here are in user units */ /* PAUL MURRELL arguments now in INCHES because _draw_stroke does rotation so it needs to use absolute coordinates */ _draw_stroke (&vc, gc, dd, false_, fromDeviceWidth(x_offset * label_width, GE_INCHES, dd), fromDeviceHeight(y_offset * label_height, GE_INCHES, dd)); /* call stroker on the sequence of strokes obtained from each char (the stroker may manipulate the line width) */ /* _draw_hershey_stroke (dd, true_, 0, HERSHEY_EM); */ _draw_hershey_string (&vc, gc, dd, codestring); /* Restore original values of relevant drawing attributes, free storage. endpath() will be invoked in here automatically, flushing the created polyline object comprising the stroked text. */ /* _plotter->linemod (R___(_plotter) old_line_mode); _plotter->capmod (R___(_plotter) old_cap_mode); _plotter->joinmod (R___(_plotter) old_join_mode); _plotter->filltype (R___(_plotter) old_fill_type); _plotter->drawstate->dash_array_in_effect = old_dash_array_in_effect; free (old_line_mode); free (old_cap_mode); free (old_join_mode); */ /* return to original position */ /* _plotter->fmove (R___(_plotter) oldposx, oldposy); */ } /* amount by which to shift after printing label (user units) */ /* postdx = x_displacement * label_width; theta = M_PI * rotation / 180.0; dx = cos (theta) * postdx - sin (theta) * 0; dy = sin (theta) * postdx + cos (theta) * 0; moverel(dx, dy); */ vmaxset(vmax); /* free (codestring); */ /* PAUL MURRELL No return value */ /* return label_width; user units */ } /* In addition to scaling the character sizes and the `width', we perform the following (dx, dy): enter subscript (dx, dy) = (-1/9, -1/2) * width exit subscript (dx, dy) = (+1/6, +1/2) * width enter superscript (dx, dy) = (-1/9, +1/2) * width exit superscript (dx, dy) = (+1/6, -1/2) * width For clarity here, `width' refers to the width _before_ it is multiplied by a factor 2/3. [N.B. In Bob Beach's original UGS character stroke generator, the +1/6's here were +2/9 instead. Better?] */ /* _label_width_hershey() computes the width (total delta x) of a controlified character string to be rendered in a vector font, in user units */ static double _label_width_hershey (const pGEcontext gc, pGEDevDesc dd, const unsigned short *label) { const unsigned short *ptr = label; unsigned short c; double charsize = 1.0; /* relative char size, 1.0 means full size */ double saved_charsize = 1.0; double width = 0.0; /* label width */ double saved_width = 0.0; /* loop through unsigned shorts in label */ while ((c = (*ptr)) != (unsigned short)'\0') { int glyphnum; /* glyph in Hershey array */ const unsigned char *glyph; if (c & RAW_HERSHEY_GLYPH) /* glyph was spec'd via an escape, not as a char in a font */ { glyphnum = c & GLYPH_SPEC; glyph = (const unsigned char *)(_occidental_hershey_glyphs[glyphnum]); if (*glyph != '\0') /* nonempty glyph */ /* 1st two chars are bounds */ width += charsize * ((int)glyph[1] - (int)glyph[0]); } else if (c & RAW_ORIENTAL_HERSHEY_GLYPH) /* glyph was spec'd via an escape, not as a char in a font */ { glyphnum = c & GLYPH_SPEC; glyph = (const unsigned char *)_oriental_hershey_glyphs[glyphnum]; if (*glyph != '\0') /* nonempty glyph */ /* 1st two chars are bounds */ width += charsize * ((int)glyph[1] - (int)glyph[0]); } else if (c & CONTROL_CODE) /* parse control code */ { switch (c & ~CONTROL_CODE) { case C_BEGIN_SUBSCRIPT: case C_BEGIN_SUPERSCRIPT : charsize *= SCRIPTSIZE; break; case C_END_SUBSCRIPT: case C_END_SUPERSCRIPT: charsize /= SCRIPTSIZE; break; case C_PUSH_LOCATION: saved_width = width; saved_charsize = charsize; break; case C_POP_LOCATION: width = saved_width; charsize = saved_charsize; break; case C_RIGHT_ONE_EM: width += charsize * HERSHEY_EM; break; case C_RIGHT_HALF_EM: width += charsize * HERSHEY_EM / 2.0; break; case C_RIGHT_QUARTER_EM: width += charsize * HERSHEY_EM / 4.0; break; case C_RIGHT_SIXTH_EM: width += charsize * HERSHEY_EM / 6.0; break; case C_RIGHT_EIGHTH_EM: width += charsize * HERSHEY_EM / 8.0; break; case C_RIGHT_TWELFTH_EM: width += charsize * HERSHEY_EM / 12.0; break; case C_LEFT_ONE_EM: width -= charsize * HERSHEY_EM; break; case C_LEFT_HALF_EM: width -= charsize * HERSHEY_EM / 2.0; break; case C_LEFT_QUARTER_EM: width -= charsize * HERSHEY_EM / 4.0; break; case C_LEFT_SIXTH_EM: width -= charsize * HERSHEY_EM / 6.0; break; case C_LEFT_EIGHTH_EM: width -= charsize * HERSHEY_EM / 8.0; break; case C_LEFT_TWELFTH_EM: width -= charsize * HERSHEY_EM / 12.0; break; /* unrecognized control code */ default: break; } } else /* yow, an actual character */ { int raw_fontnum; /* compute index of font, in table in g_fontdb.c */ raw_fontnum = (c >> FONT_SHIFT) & ONE_BYTE; c &= ~FONT_SPEC; /* extract character proper */ glyphnum = (_hershey_font_info[raw_fontnum].chars)[c]; /* could be a pseudo glyph number, e.g. an indication that character is composite */ if (glyphnum == ACC0 || glyphnum == ACC1 || glyphnum == ACC2) { unsigned char composite, character = '\0' /* -Wall */, accent; /* if so, use 1st element of composite character */ composite = (unsigned char)c; if (_composite_char (&composite, &character, &accent)) glyphnum = (_hershey_font_info[raw_fontnum].chars)[character]; else glyphnum = UNDE; /* hope this won't happen */ } /* could also be a glyph number displaced by KS, to indicate that this is a small kana */ if (glyphnum & KS) glyphnum -= KS; glyph = (const unsigned char *)(_occidental_hershey_glyphs[glyphnum]); if (*glyph != '\0') /* nonempty glyph */ /* 1st two chars are bounds */ width += charsize * ((int)glyph[1] - (int)glyph[0]); } ptr++; /* bump pointer in string */ } return HERSHEY_X_UNITS_TO_USER_UNITS (width); } /* _draw_hershey_penup_stroke() draws a penup stroke, along a vector specified in Hershey units. Size scaling and obliquing (true/false) are specified. This is used for repositioning during rendering of composite (accented) characters. */ static void _draw_hershey_penup_stroke(vfontContext *vc, const pGEcontext gc, pGEDevDesc dd, double dx, double dy, double charsize, bool0 oblique) { double shear; shear = oblique ? (SHEAR) : 0.0; _draw_hershey_stroke (vc, gc, dd, false_, /* pen up */ charsize * (dx + shear * dy), charsize * dy); } /* _draw_hershey_glyph() invokes move() and cont() to draw a raw Hershey glyph, specified by index in the occidental or oriental glyph arrays. Size scaling and obliquing (true/false) are specified. */ static void _draw_hershey_glyph (vfontContext *vc, const pGEcontext gc, pGEDevDesc dd, int glyphnum, double charsize, int type, bool0 oblique) { double xcurr, ycurr; double xfinal, yfinal; bool0 pendown = false_; const unsigned char *glyph; double dx, dy; double shear; shear = oblique ? (SHEAR) : 0.0; switch (type) { case OCCIDENTAL: default: glyph = (const unsigned char *)(_occidental_hershey_glyphs[glyphnum]); break; case ORIENTAL: glyph = (const unsigned char *)(_oriental_hershey_glyphs[glyphnum]); break; } if (*glyph != '\0') /* nonempty glyph */ { xcurr = charsize * (double)glyph[0]; xfinal = charsize * (double)glyph[1]; ycurr = yfinal = 0.0; glyph += 2; while (*glyph) { int xnewint; xnewint = (int)glyph[0]; if (xnewint == (int)' ') pendown = false_; else { double xnew, ynew; xnew = (double)charsize * xnewint; ynew = (double)charsize * ((int)'R' - ((int)glyph[1] + (double)HERSHEY_BASELINE)); dx = xnew - xcurr; dy = ynew - ycurr; _draw_hershey_stroke (vc, gc, dd, pendown, dx + shear * dy, dy); xcurr = xnew, ycurr = ynew; pendown = true_; } glyph +=2; /* on to next pair */ } /* final penup stroke, to end where we should */ dx = xfinal - xcurr; dy = yfinal - ycurr; _draw_hershey_stroke (vc, gc, dd, false_, dx + shear * dy, dy); } } /* _draw_hershey_string() strokes a string beginning at present location, which is taken to be on the string's baseline. Besides invoking move() and cont(), it invokes linewidth(). */ static void _draw_hershey_string (vfontContext *vc, const pGEcontext gc, pGEDevDesc dd, const unsigned short *string) { unsigned short c; const unsigned short *ptr = string; double charsize = 1.0; int line_width_type = 0; /* 0,1,2 = unset,occidental,oriental */ while ((c = (*ptr++)) != '\0') { /* Check for the four possibilities: (1) a Hershey glyph specified by glyph number, (2) an oriental Hershey glyph specified by glyph number, (3) a control code, and (4) an ordinary font character, which will be mapped to a Hershey glyph by one of the tables in g_fontdb.c. */ if (c & RAW_HERSHEY_GLYPH) { if (line_width_type != 1) { gc->lwd = HERSHEY_LINE_WIDTH_TO_LWD (HERSHEY_STROKE_WIDTH); line_width_type = 1; } _draw_hershey_glyph (vc, gc, dd, c & GLYPH_SPEC, charsize, OCCIDENTAL, false_); } else if (c & RAW_ORIENTAL_HERSHEY_GLYPH) { if (line_width_type != 2) { gc->lwd = HERSHEY_LINE_WIDTH_TO_LWD (HERSHEY_STROKE_WIDTH); line_width_type = 2; } _draw_hershey_glyph (vc, gc, dd, c & GLYPH_SPEC, charsize, ORIENTAL, false_); } else if (c & CONTROL_CODE) switch (c & ~CONTROL_CODE) /* parse control codes */ { case C_BEGIN_SUPERSCRIPT : _draw_hershey_stroke (vc, gc, dd, false_, SUPERSCRIPT_DX * charsize * HERSHEY_EM, SUPERSCRIPT_DY * charsize * HERSHEY_EM); charsize *= SCRIPTSIZE; break; case C_END_SUPERSCRIPT: charsize /= SCRIPTSIZE; _draw_hershey_stroke (vc, gc, dd, false_, - SUPERSCRIPT_DX * charsize * HERSHEY_EM, - SUPERSCRIPT_DY * charsize * HERSHEY_EM); break; case C_BEGIN_SUBSCRIPT: _draw_hershey_stroke (vc, gc, dd, false_, SUBSCRIPT_DX * charsize * HERSHEY_EM, SUBSCRIPT_DY * charsize * HERSHEY_EM); charsize *= SCRIPTSIZE; break; case C_END_SUBSCRIPT: charsize /= SCRIPTSIZE; _draw_hershey_stroke (vc, gc, dd, false_, - SUBSCRIPT_DX * charsize * HERSHEY_EM, - SUBSCRIPT_DY * charsize * HERSHEY_EM); break; case C_PUSH_LOCATION: /* saved_charsize = charsize; saved_position_x = _plotter->drawstate->pos.x; saved_position_y = _plotter->drawstate->pos.y; */ break; case C_POP_LOCATION: /* charsize = saved_charsize; _plotter->fmove (R___(_plotter) saved_position_x, saved_position_y); */ break; case C_RIGHT_ONE_EM: _draw_hershey_stroke (vc, gc, dd, false_, charsize * HERSHEY_EM, 0.0); break; case C_RIGHT_HALF_EM: _draw_hershey_stroke (vc, gc, dd, false_, charsize * HERSHEY_EM / 2.0, 0.0); break; case C_RIGHT_QUARTER_EM: _draw_hershey_stroke (vc, gc, dd, false_, charsize * HERSHEY_EM / 4.0, 0.0); break; case C_RIGHT_SIXTH_EM: _draw_hershey_stroke (vc, gc, dd, false_, charsize * HERSHEY_EM / 6.0, 0.0); break; case C_RIGHT_EIGHTH_EM: _draw_hershey_stroke (vc, gc, dd, false_, charsize * HERSHEY_EM / 8.0, 0.0); break; case C_LEFT_ONE_EM: _draw_hershey_stroke (vc, gc, dd, false_, - charsize * HERSHEY_EM, 0.0); break; case C_LEFT_HALF_EM: _draw_hershey_stroke (vc, gc, dd, false_, - charsize * HERSHEY_EM / 2.0, 0.0); break; case C_LEFT_QUARTER_EM: _draw_hershey_stroke (vc, gc, dd, false_, - charsize * HERSHEY_EM / 4.0, 0.0); break; case C_LEFT_SIXTH_EM: _draw_hershey_stroke (vc, gc, dd, false_, - charsize * HERSHEY_EM / 6.0, 0.0); break; case C_LEFT_EIGHTH_EM: _draw_hershey_stroke (vc, gc, dd, false_, - charsize * HERSHEY_EM / 8.0, 0.0); break; /* unrecognized control code, punt */ default: break; } else /* yow, an actual font character! Several possibilities: could be a composite (accented) character, could be a small Kana, or could be a garden-variety character. */ { int raw_fontnum; int glyphnum; /* glyph in Hershey array */ int char_glyphnum, accent_glyphnum; /* for composite chars */ int char_width, accent_width; /* for composite chars */ const unsigned char *char_glyph, *accent_glyph; unsigned char composite, character = '\0', accent = '\0' /* -Wall */; bool0 oblique, small_kana = false_; /* compute index of font, in font table in g_fontdb.c */ raw_fontnum = (c >> FONT_SHIFT) & ONE_BYTE; /* shear font? (for HersheySans-Oblique, etc.) */ oblique = _hershey_font_info[raw_fontnum].obliquing; c &= ~FONT_SPEC; /* extract character proper */ glyphnum = (_hershey_font_info[raw_fontnum].chars)[c]; if (glyphnum & KS) /* a small kana? */ { glyphnum -= KS; small_kana = true_; } switch (glyphnum) { /* special case: this is a composite (accented) character; search font table in g_fontdb.c for it */ case ACC0: case ACC1: case ACC2: composite = (unsigned char)c; if (_composite_char (&composite, &character, &accent)) { char_glyphnum = (_hershey_font_info[raw_fontnum].chars)[character]; accent_glyphnum = (_hershey_font_info[raw_fontnum].chars)[accent]; } else { /* hope this won't happen */ char_glyphnum = UNDE; accent_glyphnum = 0; } char_glyph = (const unsigned char *)_occidental_hershey_glyphs[char_glyphnum]; accent_glyph = (const unsigned char *)_occidental_hershey_glyphs[accent_glyphnum]; if (*char_glyph != '\0') /* nonempty glyph */ /* 1st two chars are bounds, in Hershey units */ char_width = (int)char_glyph[1] - (int)char_glyph[0]; else char_width = 0; if (*accent_glyph != '\0') /* nonempty glyph */ /* 1st two chars are bounds, in Hershey units */ accent_width = (int)accent_glyph[1] - (int)accent_glyph[0]; else accent_width = 0; /* draw the character */ if (line_width_type != 1) { gc->lwd = HERSHEY_LINE_WIDTH_TO_LWD (HERSHEY_STROKE_WIDTH); line_width_type = 1; } _draw_hershey_glyph (vc, gc, dd, char_glyphnum, charsize, OCCIDENTAL, oblique); /* back up to draw accent */ _draw_hershey_penup_stroke (vc, gc, dd, -0.5 * (double)char_width -0.5 * (double)accent_width, 0.0, charsize, oblique); /* repositioning for uppercase and uppercase italic */ if (glyphnum == ACC1) _draw_hershey_penup_stroke (vc, gc, dd, 0.0, (double)(ACCENT_UP_SHIFT), charsize, oblique); else if (glyphnum == ACC2) _draw_hershey_penup_stroke (vc, gc, dd, (double)(ACCENT_RIGHT_SHIFT), (double)(ACCENT_UP_SHIFT), charsize, oblique); /* draw the accent */ _draw_hershey_glyph (vc, gc, dd, accent_glyphnum, charsize, OCCIDENTAL, oblique); /* undo special repositioning if any */ if (glyphnum == ACC1) _draw_hershey_penup_stroke (vc, gc, dd, 0.0, -(double)(ACCENT_UP_SHIFT), charsize, oblique); else if (glyphnum == ACC2) _draw_hershey_penup_stroke (vc, gc, dd, -(double)(ACCENT_RIGHT_SHIFT), -(double)(ACCENT_UP_SHIFT), charsize, oblique); /* move forward, to end composite char where we should */ _draw_hershey_penup_stroke (vc, gc, dd, 0.5 * (double)char_width -0.5 * (double)accent_width, 0.0, charsize, oblique); break; /* not a composite (accented) character; just an ordinary glyph from occidental+Kana array (could be a Kana, in particular, could be a small Kana) */ default: if (small_kana) { int kana_width; const unsigned char *kana_glyph; double shift = 0.5 * (1.0 - (SMALL_KANA_SIZE)); kana_glyph = (const unsigned char *)_occidental_hershey_glyphs[glyphnum]; kana_width = (int)kana_glyph[1] - (int)kana_glyph[0]; /* draw small Kana, preceded and followed by a penup stroke in order to traverse the full width of an ordinary Kana */ _draw_hershey_penup_stroke (vc, gc, dd, shift * (double)kana_width, 0.0, charsize, oblique); if (line_width_type != 2) { gc->lwd = HERSHEY_LINE_WIDTH_TO_LWD (HERSHEY_STROKE_WIDTH); line_width_type = 2; } _draw_hershey_glyph (vc, gc, dd, glyphnum, (SMALL_KANA_SIZE) * charsize, OCCIDENTAL, oblique); _draw_hershey_penup_stroke (vc, gc, dd, shift * (double)kana_width, 0.0, charsize, oblique); } else /* whew! just an ordinary glyph from the occidental array (could be a Kana however, since they're confusingly placed in that array, at the end) */ { if (glyphnum >= BEGINNING_OF_KANA) { if (line_width_type != 2) { gc->lwd = HERSHEY_LINE_WIDTH_TO_LWD (HERSHEY_ORIENTAL_STROKE_WIDTH); line_width_type = 2; } } else if (line_width_type != 1) { gc->lwd = HERSHEY_LINE_WIDTH_TO_LWD (HERSHEY_STROKE_WIDTH); line_width_type = 1; } _draw_hershey_glyph (vc, gc, dd, glyphnum, charsize, OCCIDENTAL, oblique); } break; } /* end of case statement that switches based on glyphnum */ } /* end of font character case */ } /* end of loop through unsigned shorts in the codestring */ return; } /* retrieve the two elements of a composite character from the table in g_fontdb.c */ static bool0 _composite_char (unsigned char *composite, unsigned char *character, unsigned char *accent) { const struct plHersheyAccentedCharInfoStruct *compchar = _hershey_accented_char_info; bool0 found = false_; unsigned char given = *composite; while (compchar->composite) { if (compchar->composite == given) { found = true_; /* return char and accent via pointers */ *character = compchar->character; *accent = compchar->accent; } compchar++; } return found; }