1 /* This file is part of the GNU plotutils package. Copyright (C) 1995,
2 1996, 1997, 1998, 1999, 2000, 2005, 2008, Free Software Foundation, Inc.
3
4 The GNU plotutils package is free software. You may redistribute it
5 and/or modify it under the terms of the GNU General Public License as
6 published by the Free Software foundation; either version 2, or (at your
7 option) any later version.
8
9 The GNU plotutils package is distributed in the hope that it will be
10 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 General Public License for more details.
13
14 You should have received a copy of the GNU General Public License along
15 with the GNU plotutils package; see the file COPYING. If not, write to
16 the Free Software Foundation, Inc., 51 Franklin St., Fifth Floor,
17 Boston, MA 02110-1301, USA. */
18
19 /* This file contains the internal method _pl_g_alabel_hershey(), which
20 plots a label using Hershey fonts. Each character in a Hershey font is
21 a sequence of pen motions, so this function calls _API_fmoverel() and
22 _API_fcontrel() to `stroke' each character in the argument string.
23
24 The width of the string in user units is returned. The internal method
25 _pl_g_flabelwidth_hershey() is similar, but does not actually plot the
26 label. */
27
28 #include "sys-defines.h"
29 #include "extern.h"
30 #include "g_control.h"
31 #include "g_her_metr.h"
32
33 /* Shearing factor for oblique fonts, new_x = x + SHEAR * y */
34
35 #define SHEAR (2.0/7.0)
36
37 /* Relative size of subscripts/superscripts (i.e. `indexical' size) */
38
39 #define SCRIPTSIZE (0.6)
40
41 /* Positioning of subscripts/superscripts */
42
43 #define SUBSCRIPT_DX 0.0
44 #define SUBSCRIPT_DY (-0.25)
45 #define SUPERSCRIPT_DX 0.0
46 #define SUPERSCRIPT_DY 0.4
47
48 /* Positioning of accents (in Hershey units). UP_SHIFT is amount by which
49 accents are raised when placed over upper-case letters. RIGHT_SHIFT is
50 applied as well, if the upper-case letter is italic. */
51
52 #define ACCENT_UP_SHIFT 7.0
53 #define ACCENT_RIGHT_SHIFT 2.0
54
55 /* Relative size of small Japanese Kana */
56 #define SMALL_KANA_SIZE 0.725
57
58 /* Hershey glyph arrays */
59
60 #define OCCIDENTAL 0
61 #define ORIENTAL 1
62
63 /* Location of first Kana in the occidental glyph arrays. (Kana, unlike
64 Kanji, are placed in the occidental array, at the very end.) */
65 #define BEGINNING_OF_KANA 4195
66
67 /* forward references */
68 static bool composite_char (unsigned char *composite, unsigned char *character, unsigned char *accent);
69 static double label_width_hershey (const unsigned short *label);
70
71 /* An version of the alabel() method that is specific to the case when the
72 current Plotter font is a Hershey font. It handles escape sequences for
73 subscripts, superscripts, shifts among Hershey fonts, etc. */
74 double
_pl_g_alabel_hershey(R___ (Plotter * _plotter)const unsigned char * s,int x_justify,int y_justify)75 _pl_g_alabel_hershey (R___(Plotter *_plotter) const unsigned char *s, int x_justify, int y_justify)
76 {
77 unsigned short *codestring;
78 char x_justify_c, y_justify_c;
79 double label_width, label_height;
80 double x_offset, y_offset;
81 double x_displacement;
82 double postdx, dx, dy;
83 double theta;
84
85 /* convert string to a codestring, including annotations */
86 codestring = _pl_g_controlify (R___(_plotter) s);
87
88 /* dimensions of the string in user units */
89 label_width = HERSHEY_UNITS_TO_USER_UNITS(label_width_hershey (codestring));
90 label_height = HERSHEY_UNITS_TO_USER_UNITS(HERSHEY_HEIGHT);
91
92 x_justify_c = (char)x_justify;
93 y_justify_c = (char)y_justify;
94
95 switch (x_justify_c)
96 {
97 case 'l': /* left justified */
98 default:
99 x_offset = 0.0;
100 x_displacement = 1.0;
101 break;
102
103 case 'c': /* centered */
104 x_offset = -0.5;
105 x_displacement = 0.0;
106 break;
107
108 case 'r': /* right justified */
109 x_offset = -1.0;
110 x_displacement = -1.0;
111 break;
112 }
113
114 switch (y_justify_c)
115 {
116 case 'b': /* current point is at bottom */
117 y_offset = (double)HERSHEY_DESCENT / (double)HERSHEY_HEIGHT;
118 break;
119
120 case 'x': /* current point is on baseline */
121 default:
122 y_offset = 0.0;
123 break;
124
125 case 'c': /* current point midway between bottom, top */
126 y_offset = 0.5 * ((double)HERSHEY_DESCENT - (double)HERSHEY_ASCENT)
127 / (double)HERSHEY_HEIGHT;
128 break;
129
130 case 'C': /* current point is on cap line */
131 y_offset = - (double)HERSHEY_CAPHEIGHT / (double)HERSHEY_HEIGHT;
132 break;
133
134 case 't': /* current point is at top */
135 y_offset = - (double)HERSHEY_ASCENT / (double)HERSHEY_HEIGHT;
136 break;
137 }
138
139 /* save relevant drawing attributes, and restore them later */
140 {
141 char *old_line_mode, *old_cap_mode, *old_join_mode;
142 int old_fill_type;
143 double oldposx, oldposy;
144 bool old_dash_array_in_effect;
145
146 old_line_mode = (char *)_pl_xmalloc (strlen (_plotter->drawstate->line_mode) + 1);
147 old_cap_mode = (char *)_pl_xmalloc (strlen (_plotter->drawstate->cap_mode) + 1);
148 old_join_mode = (char *)_pl_xmalloc (strlen (_plotter->drawstate->join_mode) + 1);
149 oldposx = _plotter->drawstate->pos.x;
150 oldposy = _plotter->drawstate->pos.y;
151
152 strcpy (old_line_mode, _plotter->drawstate->line_mode);
153 strcpy (old_cap_mode, _plotter->drawstate->cap_mode);
154 strcpy (old_join_mode, _plotter->drawstate->join_mode);
155 old_fill_type = _plotter->drawstate->fill_type;
156 old_dash_array_in_effect = _plotter->drawstate->dash_array_in_effect;
157
158 /* Our choices for rendering: solid lines, rounded capitals and joins,
159 a line width equal to slightly more than 1 Hershey unit, and no
160 filling.
161
162 We don't set the pen type: we allow it to be 0, which will mean no
163 stroking at all. */
164 _API_linemod (R___(_plotter) "solid");
165 _API_capmod (R___(_plotter) "round");
166 _API_joinmod (R___(_plotter) "round");
167 _API_filltype (R___(_plotter) 0);
168
169 /* move to take horizontal and vertical justification into account */
170 {
171 double theta, deltax, deltay, dx_just, dy_just;
172
173 theta = M_PI * _plotter->drawstate->text_rotation / 180.0;
174
175 deltax = x_offset * label_width;
176 deltay = y_offset * label_height;
177 dx_just = cos(theta) * deltax - sin(theta) * deltay;
178 dy_just = sin(theta) * deltax + cos(theta) * deltay;
179
180 _API_fmoverel (R___(_plotter) dx_just, dy_just);
181 }
182
183 /* call stroker on the sequence of strokes obtained from each char (the
184 stroker may manipulate the line width) */
185 _pl_g_draw_hershey_string (R___(_plotter) codestring);
186
187 /* Restore original values of relevant drawing attributes, free
188 storage. endpath() will be invoked in here automatically, flushing
189 the created polyline object comprising the stroked text. */
190 _API_linemod (R___(_plotter) old_line_mode);
191 _API_capmod (R___(_plotter) old_cap_mode);
192 _API_joinmod (R___(_plotter) old_join_mode);
193 _API_filltype (R___(_plotter) old_fill_type);
194 _plotter->drawstate->dash_array_in_effect = old_dash_array_in_effect;
195
196 free (old_line_mode);
197 free (old_cap_mode);
198 free (old_join_mode);
199
200 /* return to original position */
201 _API_fmove (R___(_plotter) oldposx, oldposy);
202 }
203
204 /* amount by which to shift after printing label (user units) */
205 postdx = x_displacement * label_width;
206 theta = M_PI * _plotter->drawstate->text_rotation / 180.0;
207 dx = cos (theta) * postdx;
208 dy = sin (theta) * postdx;
209
210 _API_fmoverel (R___(_plotter) dx, dy);
211
212 free (codestring);
213
214 return label_width; /* user units */
215 }
216
217 /* A version of the flabelwidth() method that is specific to the case when
218 the current Plotter font is a Hershey font. */
219 double
_pl_g_flabelwidth_hershey(R___ (Plotter * _plotter)const unsigned char * s)220 _pl_g_flabelwidth_hershey (R___(Plotter *_plotter) const unsigned char *s)
221 {
222 double label_width;
223 unsigned short *codestring;
224
225 /* convert string to a codestring, including annotations */
226 codestring = _pl_g_controlify (R___(_plotter) s);
227
228 label_width = HERSHEY_UNITS_TO_USER_UNITS(label_width_hershey (codestring));
229 free (codestring);
230
231 return label_width;
232 }
233
234 /* _pl_g_draw_hershey_stroke() draws a stroke, taking into account the
235 transformation from Hershey units to user units, and also the angle in
236 user space at which the label should be plotted. */
237
238 void
_pl_g_draw_hershey_stroke(R___ (Plotter * _plotter)bool pendown,double deltax,double deltay)239 _pl_g_draw_hershey_stroke (R___(Plotter *_plotter) bool pendown, double deltax, double deltay)
240 {
241 double theta = M_PI * _plotter->drawstate->text_rotation / 180.0;
242 double dx, dy;
243
244 deltax = HERSHEY_UNITS_TO_USER_UNITS (deltax);
245 deltay = HERSHEY_UNITS_TO_USER_UNITS (deltay);
246
247 dx = cos(theta) * deltax - sin(theta) * deltay;
248 dy = sin(theta) * deltax + cos(theta) * deltay;
249
250 if (pendown)
251 _API_fcontrel (R___(_plotter) dx, dy);
252 else
253 _API_fmoverel (R___(_plotter) dx, dy);
254 }
255
256 /* label_width_hershey() computes the width (total delta x) of a
257 controlified character string to be rendered in a vector font, in
258 Hershey units. Parsing must take into account the many control
259 sequences which perform shifts, and initiate/terminate
260 subscripts/superscripts. */
261
262 /* In addition to scaling the character sizes and the `width', we perform
263 the following (dx, dy):
264
265 enter subscript (dx, dy) = (-1/9, -1/2) * width
266 exit subscript (dx, dy) = (+1/6, +1/2) * width
267
268 enter superscript (dx, dy) = (-1/9, +1/2) * width
269 exit superscript (dx, dy) = (+1/6, -1/2) * width
270
271 For clarity here, `width' refers to the width _before_ it is
272 multiplied by a factor 2/3.
273
274 [N.B. In Bob Beach's original UGS character stroke generator,
275 the +1/6's here were +2/9 instead. Better?] */
276
277 static double
label_width_hershey(const unsigned short * label)278 label_width_hershey (const unsigned short *label)
279 {
280 const unsigned short *ptr = label;
281 unsigned short c;
282 double charsize = 1.0; /* relative char size, 1.0 means full size */
283 double saved_charsize = 1.0;
284 double width = 0.0; /* label width */
285 double saved_width = 0.0;
286
287 /* loop through unsigned shorts in label */
288 while ((c = (*ptr)) != (unsigned short)'\0')
289 {
290 int glyphnum; /* glyph in Hershey array */
291 const unsigned char *glyph;
292
293 if (c & RAW_HERSHEY_GLYPH)
294 /* glyph was spec'd via an escape, not as a char in a font */
295 {
296 glyphnum = c & GLYPH_SPEC;
297 glyph = (const unsigned char *)(_pl_g_occidental_hershey_glyphs[glyphnum]);
298
299 if (*glyph != '\0') /* nonempty glyph */
300 /* 1st two chars are bounds */
301 width += charsize * ((int)glyph[1] - (int)glyph[0]);
302 }
303 else if (c & RAW_ORIENTAL_HERSHEY_GLYPH)
304 /* glyph was spec'd via an escape, not as a char in a font */
305 {
306 glyphnum = c & GLYPH_SPEC;
307 glyph = (const unsigned char *)_pl_g_oriental_hershey_glyphs[glyphnum];
308
309 if (*glyph != '\0') /* nonempty glyph */
310 /* 1st two chars are bounds */
311 width += charsize * ((int)glyph[1] - (int)glyph[0]);
312 }
313 else if (c & CONTROL_CODE) /* parse control code */
314 {
315 switch (c & ~CONTROL_CODE)
316 {
317 case C_BEGIN_SUBSCRIPT:
318 case C_BEGIN_SUPERSCRIPT :
319 charsize *= SCRIPTSIZE;
320 break;
321
322 case C_END_SUBSCRIPT:
323 case C_END_SUPERSCRIPT:
324 charsize /= SCRIPTSIZE;
325 break;
326
327 case C_PUSH_LOCATION:
328 saved_width = width;
329 saved_charsize = charsize;
330 break;
331
332 case C_POP_LOCATION:
333 width = saved_width;
334 charsize = saved_charsize;
335 break;
336
337 case C_RIGHT_ONE_EM:
338 width += charsize * HERSHEY_EM;
339 break;
340
341 case C_RIGHT_HALF_EM:
342 width += charsize * HERSHEY_EM / 2.0;
343 break;
344
345 case C_RIGHT_QUARTER_EM:
346 width += charsize * HERSHEY_EM / 4.0;
347 break;
348
349 case C_RIGHT_SIXTH_EM:
350 width += charsize * HERSHEY_EM / 6.0;
351 break;
352
353 case C_RIGHT_EIGHTH_EM:
354 width += charsize * HERSHEY_EM / 8.0;
355 break;
356
357 case C_RIGHT_TWELFTH_EM:
358 width += charsize * HERSHEY_EM / 12.0;
359 break;
360
361 case C_LEFT_ONE_EM:
362 width -= charsize * HERSHEY_EM;
363 break;
364
365 case C_LEFT_HALF_EM:
366 width -= charsize * HERSHEY_EM / 2.0;
367 break;
368
369 case C_LEFT_QUARTER_EM:
370 width -= charsize * HERSHEY_EM / 4.0;
371 break;
372
373 case C_LEFT_SIXTH_EM:
374 width -= charsize * HERSHEY_EM / 6.0;
375 break;
376
377 case C_LEFT_EIGHTH_EM:
378 width -= charsize * HERSHEY_EM / 8.0;
379 break;
380
381 case C_LEFT_TWELFTH_EM:
382 width -= charsize * HERSHEY_EM / 12.0;
383 break;
384
385 /* unrecognized control code */
386 default:
387 break;
388 }
389 }
390 else /* yow, an actual character */
391 {
392 int raw_fontnum;
393
394 /* compute index of font, in table in g_fontdb.c */
395 raw_fontnum = (c >> FONT_SHIFT) & ONE_BYTE;
396
397 c &= ~FONT_SPEC; /* extract character proper */
398 glyphnum = (_pl_g_hershey_font_info[raw_fontnum].chars)[c];
399
400 /* could be a pseudo glyph number, e.g. an indication that
401 character is composite */
402 if (glyphnum == ACC0 || glyphnum == ACC1 || glyphnum == ACC2)
403 {
404 unsigned char composite, character, accent;
405
406 /* if so, use 1st element of composite character */
407 composite = (unsigned char)c;
408 if (composite_char (&composite, &character, &accent))
409 glyphnum = (_pl_g_hershey_font_info[raw_fontnum].chars)[character];
410 else
411 glyphnum = UNDE; /* hope this won't happen */
412 }
413
414 /* could also be a glyph number displaced by KS, to indicate
415 that this is a small kana */
416 if (glyphnum & KS)
417 glyphnum -= KS;
418
419 glyph = (const unsigned char *)(_pl_g_occidental_hershey_glyphs[glyphnum]);
420 if (*glyph != '\0') /* nonempty glyph */
421 /* 1st two chars are bounds */
422 width += charsize * ((int)glyph[1] - (int)glyph[0]);
423 }
424
425 ptr++; /* bump pointer in string */
426 }
427
428 return width;
429 }
430
431 /* _pl_g_draw_hershey_penup_stroke() draws a penup stroke, along a vector
432 specified in Hershey units. Size scaling and obliquing (true/false) are
433 specified. This is used for repositioning during rendering of composite
434 (accented) characters. */
435 void
_pl_g_draw_hershey_penup_stroke(R___ (Plotter * _plotter)double dx,double dy,double charsize,bool oblique)436 _pl_g_draw_hershey_penup_stroke(R___(Plotter *_plotter) double dx, double dy, double charsize, bool oblique)
437 {
438 double shear;
439
440 shear = oblique ? (SHEAR) : 0.0;
441 _pl_g_draw_hershey_stroke (R___(_plotter)
442 false, /* pen up */
443 charsize * (dx + shear * dy),
444 charsize * dy);
445 }
446
447 /* _pl_g_draw_hershey_glyph() invokes move() and cont() to draw a raw
448 Hershey glyph, specified by index in the occidental or oriental glyph
449 arrays. Size scaling and obliquing (true/false) are specified. */
450 void
_pl_g_draw_hershey_glyph(R___ (Plotter * _plotter)int glyphnum,double charsize,int type,bool oblique)451 _pl_g_draw_hershey_glyph (R___(Plotter *_plotter) int glyphnum, double charsize, int type, bool oblique)
452 {
453 double xcurr, ycurr;
454 double xfinal, yfinal;
455 bool pendown = false;
456 const unsigned char *glyph;
457 double dx, dy;
458 double shear;
459
460 shear = oblique ? (SHEAR) : 0.0;
461 switch (type)
462 {
463 case OCCIDENTAL:
464 default:
465 glyph = (const unsigned char *)(_pl_g_occidental_hershey_glyphs[glyphnum]);
466 break;
467 case ORIENTAL:
468 glyph = (const unsigned char *)(_pl_g_oriental_hershey_glyphs[glyphnum]);
469 break;
470 }
471
472 if (*glyph != '\0') /* nonempty glyph */
473 {
474 xcurr = charsize * (double)glyph[0];
475 xfinal = charsize * (double)glyph[1];
476 ycurr = yfinal = 0.0;
477 glyph += 2;
478 while (*glyph)
479 {
480 int xnewint;
481
482 xnewint = (int)glyph[0];
483
484 if (xnewint == (int)' ')
485 pendown = false;
486 else
487 {
488 double xnew, ynew;
489
490 xnew = (double)charsize * xnewint;
491 ynew = (double)charsize
492 * ((int)'R'
493 - ((int)glyph[1] + (double)HERSHEY_BASELINE));
494 dx = xnew - xcurr;
495 dy = ynew - ycurr;
496 _pl_g_draw_hershey_stroke (R___(_plotter)
497 pendown, dx + shear * dy, dy);
498 xcurr = xnew, ycurr = ynew;
499 pendown = true;
500 }
501
502 glyph +=2; /* on to next pair */
503 }
504
505 /* final penup stroke, to end where we should */
506 dx = xfinal - xcurr;
507 dy = yfinal - ycurr;
508 _pl_g_draw_hershey_stroke (R___(_plotter) false, dx + shear * dy, dy);
509 }
510 }
511
512 /* _pl_g_draw_hershey_string() strokes a string beginning at present
513 location, which is taken to be on the string's baseline. Besides
514 invoking move() and cont(), it invokes linewidth(). */
515 void
_pl_g_draw_hershey_string(R___ (Plotter * _plotter)const unsigned short * string)516 _pl_g_draw_hershey_string (R___(Plotter *_plotter) const unsigned short *string)
517 {
518 unsigned short c;
519 const unsigned short *ptr = string;
520 double charsize = 1.0;
521 double saved_charsize = 1.0;
522 double saved_position_x = _plotter->drawstate->pos.x;
523 double saved_position_y = _plotter->drawstate->pos.y;
524 double old_line_width;
525 int line_width_type = 0; /* 0,1,2 = unset,occidental,oriental */
526
527 /* save line width (will restore at end) */
528 old_line_width = _plotter->drawstate->line_width;
529
530 while ((c = (*ptr++)) != '\0')
531 {
532 /* Check for the four possibilities: (1) a Hershey glyph specified by
533 glyph number, (2) an oriental Hershey glyph specified by glyph
534 number, (3) a control code, and (4) an ordinary font character,
535 which will be mapped to a Hershey glyph by one of the tables in
536 g_fontdb.c. */
537
538 if (c & RAW_HERSHEY_GLYPH)
539 {
540 if (line_width_type != 1)
541 {
542 _API_flinewidth (R___(_plotter)
543 HERSHEY_UNITS_TO_USER_UNITS (HERSHEY_STROKE_WIDTH));
544 line_width_type = 1;
545 }
546 _pl_g_draw_hershey_glyph (R___(_plotter)
547 c & GLYPH_SPEC, charsize, OCCIDENTAL, false);
548 }
549
550 else if (c & RAW_ORIENTAL_HERSHEY_GLYPH)
551 {
552 if (line_width_type != 2)
553 {
554 _API_flinewidth (R___(_plotter)
555 HERSHEY_UNITS_TO_USER_UNITS (HERSHEY_ORIENTAL_STROKE_WIDTH));
556 line_width_type = 2;
557 }
558 _pl_g_draw_hershey_glyph (R___(_plotter)
559 c & GLYPH_SPEC, charsize, ORIENTAL, false);
560 }
561
562 else if (c & CONTROL_CODE)
563 switch (c & ~CONTROL_CODE) /* parse control codes */
564 {
565 case C_BEGIN_SUPERSCRIPT :
566 _pl_g_draw_hershey_stroke (R___(_plotter)
567 false,
568 SUPERSCRIPT_DX * charsize * HERSHEY_EM,
569 SUPERSCRIPT_DY * charsize * HERSHEY_EM);
570 charsize *= SCRIPTSIZE;
571 break;
572
573 case C_END_SUPERSCRIPT:
574 charsize /= SCRIPTSIZE;
575 _pl_g_draw_hershey_stroke (R___(_plotter)
576 false,
577 - SUPERSCRIPT_DX * charsize * HERSHEY_EM,
578 - SUPERSCRIPT_DY * charsize * HERSHEY_EM);
579 break;
580
581 case C_BEGIN_SUBSCRIPT:
582 _pl_g_draw_hershey_stroke (R___(_plotter)
583 false,
584 SUBSCRIPT_DX * charsize * HERSHEY_EM,
585 SUBSCRIPT_DY * charsize * HERSHEY_EM);
586 charsize *= SCRIPTSIZE;
587 break;
588
589 case C_END_SUBSCRIPT:
590 charsize /= SCRIPTSIZE;
591 _pl_g_draw_hershey_stroke (R___(_plotter)
592 false,
593 - SUBSCRIPT_DX * charsize * HERSHEY_EM,
594 - SUBSCRIPT_DY * charsize * HERSHEY_EM);
595 break;
596
597 case C_PUSH_LOCATION:
598 saved_charsize = charsize;
599 saved_position_x = _plotter->drawstate->pos.x;
600 saved_position_y = _plotter->drawstate->pos.y;
601 break;
602
603 case C_POP_LOCATION:
604 charsize = saved_charsize;
605 _API_fmove (R___(_plotter)
606 saved_position_x, saved_position_y);
607 break;
608
609 case C_RIGHT_ONE_EM:
610 _pl_g_draw_hershey_stroke (R___(_plotter)
611 false, charsize * HERSHEY_EM, 0.0);
612 break;
613
614 case C_RIGHT_HALF_EM:
615 _pl_g_draw_hershey_stroke (R___(_plotter)
616 false, charsize * HERSHEY_EM / 2.0, 0.0);
617 break;
618
619 case C_RIGHT_QUARTER_EM:
620 _pl_g_draw_hershey_stroke (R___(_plotter)
621 false, charsize * HERSHEY_EM / 4.0, 0.0);
622 break;
623
624 case C_RIGHT_SIXTH_EM:
625 _pl_g_draw_hershey_stroke (R___(_plotter)
626 false, charsize * HERSHEY_EM / 6.0, 0.0);
627 break;
628
629 case C_RIGHT_EIGHTH_EM:
630 _pl_g_draw_hershey_stroke (R___(_plotter)
631 false, charsize * HERSHEY_EM / 8.0, 0.0);
632 break;
633
634 case C_RIGHT_TWELFTH_EM:
635 _pl_g_draw_hershey_stroke (R___(_plotter)
636 false, charsize * HERSHEY_EM / 12.0, 0.0);
637 break;
638
639 case C_LEFT_ONE_EM:
640 _pl_g_draw_hershey_stroke (R___(_plotter)
641 false, - charsize * HERSHEY_EM, 0.0);
642 break;
643
644 case C_LEFT_HALF_EM:
645 _pl_g_draw_hershey_stroke (R___(_plotter)
646 false, - charsize * HERSHEY_EM / 2.0, 0.0);
647 break;
648
649 case C_LEFT_QUARTER_EM:
650 _pl_g_draw_hershey_stroke (R___(_plotter)
651 false, - charsize * HERSHEY_EM / 4.0, 0.0);
652 break;
653
654 case C_LEFT_SIXTH_EM:
655 _pl_g_draw_hershey_stroke (R___(_plotter)
656 false, - charsize * HERSHEY_EM / 6.0, 0.0);
657 break;
658
659 case C_LEFT_EIGHTH_EM:
660 _pl_g_draw_hershey_stroke (R___(_plotter)
661 false, - charsize * HERSHEY_EM / 8.0, 0.0);
662 break;
663
664 case C_LEFT_TWELFTH_EM:
665 _pl_g_draw_hershey_stroke (R___(_plotter)
666 false, - charsize * HERSHEY_EM / 12.0, 0.0);
667 break;
668
669 /* unrecognized control code, punt */
670 default:
671 break;
672 }
673
674 else
675 /* yow, an actual font character! Several possibilities: could be
676 a composite (accented) character, could be a small Kana, or
677 could be a garden-variety character. */
678 {
679 int raw_fontnum;
680 int glyphnum; /* glyph in Hershey array */
681 int char_glyphnum, accent_glyphnum; /* for composite chars */
682 int char_width, accent_width; /* for composite chars */
683 const unsigned char *char_glyph, *accent_glyph;
684 unsigned char composite, character, accent;
685 bool oblique, small_kana = false;
686
687 /* compute index of font, in font table in g_fontdb.c */
688 raw_fontnum = (c >> FONT_SHIFT) & ONE_BYTE;
689 /* shear font? (for HersheySans-Oblique, etc.) */
690 oblique = _pl_g_hershey_font_info[raw_fontnum].obliquing;
691
692 c &= ~FONT_SPEC; /* extract character proper */
693 glyphnum = (_pl_g_hershey_font_info[raw_fontnum].chars)[c];
694
695 if (glyphnum & KS) /* a small kana? */
696 {
697 glyphnum -= KS;
698 small_kana = true;
699 }
700
701 switch (glyphnum)
702 {
703 /* special case: this is a composite (accented) character;
704 search font table in g_fontdb.c for it */
705 case ACC0:
706 case ACC1:
707 case ACC2:
708 composite = (unsigned char)c;
709 if (composite_char (&composite, &character, &accent))
710 {
711 char_glyphnum =
712 (_pl_g_hershey_font_info[raw_fontnum].chars)[character];
713 accent_glyphnum =
714 (_pl_g_hershey_font_info[raw_fontnum].chars)[accent];
715 }
716 else
717 { /* hope this won't happen */
718 char_glyphnum = UNDE;
719 accent_glyphnum = 0;
720 }
721 char_glyph =
722 (const unsigned char *)_pl_g_occidental_hershey_glyphs[char_glyphnum];
723 accent_glyph =
724 (const unsigned char *)_pl_g_occidental_hershey_glyphs[accent_glyphnum];
725
726 if (*char_glyph != '\0') /* nonempty glyph */
727 /* 1st two chars are bounds, in Hershey units */
728 char_width = (int)char_glyph[1] - (int)char_glyph[0];
729 else
730 char_width = 0;
731
732 if (*accent_glyph != '\0') /* nonempty glyph */
733 /* 1st two chars are bounds, in Hershey units */
734 accent_width = (int)accent_glyph[1] - (int)accent_glyph[0];
735 else
736 accent_width = 0;
737
738 /* draw the character */
739 if (line_width_type != 1)
740 {
741 _API_flinewidth (R___(_plotter)
742 HERSHEY_UNITS_TO_USER_UNITS (HERSHEY_STROKE_WIDTH));
743 line_width_type = 1;
744 }
745 _pl_g_draw_hershey_glyph (R___(_plotter)
746 char_glyphnum, charsize,
747 OCCIDENTAL, oblique);
748 /* back up to draw accent */
749 _pl_g_draw_hershey_penup_stroke (R___(_plotter)
750 -0.5 * (double)char_width
751 -0.5 * (double)accent_width,
752 0.0, charsize, oblique);
753
754 /* repositioning for uppercase and uppercase italic */
755 if (glyphnum == ACC1)
756 _pl_g_draw_hershey_penup_stroke (R___(_plotter)
757 0.0,
758 (double)(ACCENT_UP_SHIFT),
759 charsize, oblique);
760 else if (glyphnum == ACC2)
761 _pl_g_draw_hershey_penup_stroke (R___(_plotter)
762 (double)(ACCENT_RIGHT_SHIFT),
763 (double)(ACCENT_UP_SHIFT),
764 charsize, oblique);
765
766 /* draw the accent */
767 _pl_g_draw_hershey_glyph (R___(_plotter)
768 accent_glyphnum, charsize,
769 OCCIDENTAL, oblique);
770
771 /* undo special repositioning if any */
772 if (glyphnum == ACC1)
773 _pl_g_draw_hershey_penup_stroke (R___(_plotter)
774 0.0,
775 -(double)(ACCENT_UP_SHIFT),
776 charsize, oblique);
777 else if (glyphnum == ACC2)
778 _pl_g_draw_hershey_penup_stroke (R___(_plotter)
779 -(double)(ACCENT_RIGHT_SHIFT),
780 -(double)(ACCENT_UP_SHIFT),
781 charsize, oblique);
782
783 /* move forward, to end composite char where we should */
784 _pl_g_draw_hershey_penup_stroke (R___(_plotter)
785 0.5 * (double)char_width
786 -0.5 * (double)accent_width,
787 0.0, charsize, oblique);
788 break;
789
790 /* not a composite (accented) character; just an ordinary
791 glyph from occidental+Kana array (could be a Kana, in
792 particular, could be a small Kana) */
793 default:
794 if (small_kana)
795 {
796 int kana_width;
797 const unsigned char *kana_glyph;
798 double shift = 0.5 * (1.0 - (SMALL_KANA_SIZE));
799
800 kana_glyph =
801 (const unsigned char *)_pl_g_occidental_hershey_glyphs[glyphnum];
802 kana_width = (int)kana_glyph[1] - (int)kana_glyph[0];
803
804 /* draw small Kana, preceded and followed by a penup
805 stroke in order to traverse the full width of an
806 ordinary Kana */
807 _pl_g_draw_hershey_penup_stroke (R___(_plotter)
808 shift * (double)kana_width,
809 0.0, charsize, oblique);
810 if (line_width_type != 2)
811 {
812 _API_flinewidth (R___(_plotter)
813 HERSHEY_UNITS_TO_USER_UNITS (HERSHEY_ORIENTAL_STROKE_WIDTH));
814 line_width_type = 2;
815 }
816 _pl_g_draw_hershey_glyph (R___(_plotter)
817 glyphnum,
818 (SMALL_KANA_SIZE) * charsize,
819 OCCIDENTAL, oblique);
820 _pl_g_draw_hershey_penup_stroke (R___(_plotter)
821 shift * (double)kana_width,
822 0.0, charsize, oblique);
823 }
824 else
825 /* whew! just an ordinary glyph from the occidental array
826 (could be a Kana however, since they're confusingly
827 placed in that array, at the end) */
828 {
829 if (glyphnum >= BEGINNING_OF_KANA)
830 {
831 if (line_width_type != 2)
832 {
833 _API_flinewidth (R___(_plotter)
834 HERSHEY_UNITS_TO_USER_UNITS (HERSHEY_ORIENTAL_STROKE_WIDTH));
835 line_width_type = 2;
836 }
837 }
838 else
839 if (line_width_type != 1)
840 {
841 _API_flinewidth (R___(_plotter)
842 HERSHEY_UNITS_TO_USER_UNITS (HERSHEY_STROKE_WIDTH));
843 line_width_type = 1;
844 }
845 _pl_g_draw_hershey_glyph (R___(_plotter)
846 glyphnum, charsize,
847 OCCIDENTAL, oblique);
848 }
849 break;
850 } /* end of case statement that switches based on glyphnum */
851
852 } /* end of font character case */
853
854 } /* end of loop through unsigned shorts in the codestring */
855
856 if (line_width_type != 0)
857 /* must restore old line width */
858 _API_flinewidth (R___(_plotter) old_line_width);
859
860 return;
861 }
862
863 /* retrieve the two elements of a composite character from the table in
864 g_fontdb.c */
865 static bool
composite_char(unsigned char * composite,unsigned char * character,unsigned char * accent)866 composite_char (unsigned char *composite, unsigned char *character, unsigned char *accent)
867 {
868 const struct plHersheyAccentedCharInfoStruct *compchar = _pl_g_hershey_accented_char_info;
869 bool found = false;
870 unsigned char given = *composite;
871
872 while (compchar->composite)
873 {
874 if (compchar->composite == given)
875 {
876 found = true;
877 /* return char and accent via pointers */
878 *character = compchar->character;
879 *accent = compchar->accent;
880 }
881 compchar++;
882 }
883
884 return found;
885 }
886