Rev 27236 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed
/* PAUL MURRELLThis is from the GNU plotutils libplot-2.3 distributionSeveral modifications have been made to use the R graphics enginefor output.All references to HAVE_PROTOS removedAll references to "plotter" replaced with references to "GEDevDesc"*//* This file contains the internal method _falabel_hershey(), which plots alabel using Hershey fonts. Each character in a Hershey font is asequence of pen motions, so this function simply calls fmoverel() andfcontrel() 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 MURRELLsys-defines.h not used*//* #include "sys-defines.h" *//* PAUL MURRELLextern.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 whichaccents are raised when placed over upper-case letters. RIGHT_SHIFT isapplied 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, unlikeKanji, are placed in the occidental array, at the very end.) */#define BEGINNING_OF_KANA 4195/* PAUL MURRELLStructure to contain vfont current position*/typedef struct {double currX;double currY;double angle;} vfontContext;/* forward references */static bool _composite_char (unsigned char *composite,unsigned char *character,unsigned char *accent);static void _draw_stroke (vfontContext *vc, R_GE_gcontext *gc,GEDevDesc *dd,bool pendown, double deltax, double deltay);static double _label_width_hershey (R_GE_gcontext *gc, GEDevDesc *dd,const unsigned short *label);static void _draw_hershey_string (vfontContext *vc, R_GE_gcontext *gc,GEDevDesc *dd,const unsigned short *string);/* _draw_hershey_stroke() draws a stroke, taking into account thetransformation from Hershey units to user units, and also the currenttransformation 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 inan absolute coordinate system because it does the rotation*/staticvoid _draw_hershey_stroke (vfontContext *vc, R_GE_gcontext *gc, GEDevDesc *dd,bool pendown, double deltax, double deltay){_draw_stroke(vc, gc, dd, pendown,fromDeviceWidth(HERSHEY_UNITS_TO_USER_UNITS (deltax),GE_INCHES, dd),fromDeviceHeight(HERSHEY_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, R_GE_gcontext *gc,GEDevDesc *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#endifstatic void _draw_stroke (vfontContext *vc, R_GE_gcontext *gc, GEDevDesc *dd,bool 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);elsemoverel(dx, dy, vc);}/* PAUL MURRELLRenamed 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 thecase when the current Plotter font is a Hershey font; called ing_flabelwidth () */static double R_VF_VStrWidth (const unsigned char *s,R_GE_gcontext *gc,GEDevDesc *dd){double label_width;unsigned short *codestring;/* PAUL MURRELL_controlify using R_alloc instead of xmalloc so need to dovmaxget() ... vmaxset() instead of free()*/char *vmax = vmaxget();/* convert string to a codestring, including annotations */codestring = _controlify (dd, s, gc->fontface, gc->fontfamily[0]);label_width = _label_width_hershey (gc, dd, codestring);vmaxset(vmax);/* free (codestring); */return label_width;}/* PAUL MURRELLAdded _label_height_hershey and GVStrHeight function*/static double _label_height_hershey (R_GE_gcontext *gc,GEDevDesc *dd,const unsigned short *label){return( HERSHEY_UNITS_TO_USER_UNITS(HERSHEY_LARGE_CAPHEIGHT) );}static double R_VF_VStrHeight (const unsigned char *s,R_GE_gcontext *gc,GEDevDesc *dd){double label_height;unsigned short *codestring;char *vmax = vmaxget();/* convert string to a codestring, including annotations */codestring = _controlify (dd, s, gc->fontface, gc->fontfamily[0]);label_height = _label_height_hershey (gc, dd, codestring);vmaxset(vmax);return label_height;}/* PAUL MURRELLThis guy is the entry point to the GNU codeRenamed from _g_falabel_hershey to GVTextReordered argumentsAdded x, y, rotation, and font specification argumentsRetyped x/y_justify from int to doubleRetyped s from "const unsigned char *" to char*Changed return value from double to void*//* this is the version of the falabel() method that is specificto the case when the current Plotter font is a Hershey font */static void R_VF_VText (double x, double y, char *s,double x_justify, double y_justify, double rotation,R_GE_gcontext *gc,GEDevDesc *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 dovmaxget() ... vmaxset() instead of free()*/char *vmax = vmaxget();/* PAUL MURRELLinitialise the local currX and currYwork 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 = 1;/* convert string to a codestring, including annotations */codestring = _controlify (dd, (unsigned char *)s, gc->fontface, gc->fontfamily[0]);/* PAUL MURRELLJustification changed from char (e.g., 'l', 'c', 'r') todouble (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;bool 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, andtransparent 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 MURRELLarguments now in INCHES because _draw_stroke does rotationso 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 (thestroker 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, freestorage. endpath() will be invoked in here automatically, flushingthe 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 MURRELLNo return value*//* return label_width; user units */}/* In addition to scaling the character sizes and the `width', we performthe following (dx, dy):enter subscript (dx, dy) = (-1/9, -1/2) * widthexit subscript (dx, dy) = (+1/6, +1/2) * widthenter superscript (dx, dy) = (-1/9, +1/2) * widthexit superscript (dx, dy) = (+1/6, -1/2) * widthFor clarity here, `width' refers to the width _before_ it ismultiplied 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 acontrolified character string to be rendered in a vector font, in userunits */static double _label_width_hershey (R_GE_gcontext *gc, GEDevDesc *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 thatcharacter is composite */if (glyphnum == ACC0 || glyphnum == ACC1 || glyphnum == ACC2){unsigned char composite, character, 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];elseglyphnum = UNDE; /* hope this won't happen */}/* could also be a glyph number displaced by KS, to indicatethat 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_UNITS_TO_USER_UNITS (width);}/* _draw_hershey_penup_stroke() draws a penup stroke, along a vectorspecified in Hershey units. Size scaling and obliquing (true/false) arespecified. This is used for repositioning during rendering ofcomposite (accented) characters. */staticvoid _draw_hershey_penup_stroke(vfontContext *vc, R_GE_gcontext *gc,GEDevDesc *dd,double dx, double dy,double charsize, bool 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 Hersheyglyph, specified by index in the occidental or oriental glyph arrays.Size scaling and obliquing (true/false) are specified. */staticvoid _draw_hershey_glyph (vfontContext *vc, R_GE_gcontext *gc, GEDevDesc *dd,int glyphnum,double charsize, int type, bool oblique){double xcurr, ycurr;double xfinal, yfinal;bool 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(). */staticvoid _draw_hershey_string (vfontContext *vc, R_GE_gcontext *gc, GEDevDesc *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 byglyph number, (2) an oriental Hershey glyph specified by glyphnumber, (3) a control code, and (4) an ordinary font character,which will be mapped to a Hershey glyph by one of the tables ing_fontdb.c. */if (c & RAW_HERSHEY_GLYPH){if (line_width_type != 1){gc->lwd = HERSHEY_UNITS_TO_USER_UNITS (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_UNITS_TO_USER_UNITS (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 bea composite (accented) character, could be a small Kana, orcould 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, accent;bool 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];elsechar_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];elseaccent_width = 0;/* draw the character */if (line_width_type != 1){gc->lwd = HERSHEY_UNITS_TO_USER_UNITS (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 ordinaryglyph from occidental+Kana array (could be a Kana, inparticular, 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 penupstroke in order to traverse the full width of anordinary Kana */_draw_hershey_penup_stroke (vc, gc, dd,shift * (double)kana_width,0.0, charsize, oblique);if (line_width_type != 2){gc->lwd = HERSHEY_UNITS_TO_USER_UNITS (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 confusinglyplaced in that array, at the end) */{if (glyphnum >= BEGINNING_OF_KANA){if (line_width_type != 2){gc->lwd = HERSHEY_UNITS_TO_USER_UNITS (HERSHEY_ORIENTAL_STROKE_WIDTH);line_width_type = 2;}}elseif (line_width_type != 1){gc->lwd = HERSHEY_UNITS_TO_USER_UNITS (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 ing_fontdb.c */static bool _composite_char (unsigned char *composite,unsigned char *character,unsigned char *accent){const struct plHersheyAccentedCharInfoStruct *compchar = _hershey_accented_char_info;bool 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;}void R_init_vfonts(DllInfo *dll){R_GE_setVFontRoutines(R_VF_VStrWidth, R_VF_VStrHeight, R_VF_VText);}