1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382
|
/* This is the low-level method which is used by any HP-GL or PCL Plotter
for rendering a single-font label in a PCL, PS, or Stick font. Note:
The `PCL 5' output by any PCL Plotter is simply a wrapped version of
HP-GL/2.
This method internally invokes _h_set_font to select the font. See
h_font.c for the font selection code.
Before HP-GL/2 (introduced c. 1990), HP-GL devices supported only Stick
fonts. In modern PCL5 printers, the suite of 45 PCL fonts is accessible
too. Only a few modern high-end PCL5/PS printers (e.g. LaserJet 4000
series laser printers) also support PS fonts in PCL mode. PS fonts are
supported by HP-GL/2 and PCL Plotters if the `--enable-ps-fonts-in-pcl'
option is specified at configure time.
Novel features of this driver include (1) the rightward shift that all
fonts need, when accessed through HP-GL, (2) the re-encoding that Stick
fonts need, (3) the compensation for the kerning used by full-featured
HP-GL devices when rendering variable-width Stick fonts, and (4) the
bizarre re-encoding that we apply to ISO-Latin-1 PCL fonts, due to HP's
idiosyncratic definition of ISO-Latin-1 ("ECMA-96 Latin 1"):
1. HP-GL rendering of a string is displaced leftward, relative to PS
rendering, by an amount equal to the distance between the bounding box
left edge and the left edge (`first ink') for the first character. This
is so that the first ink will be put on the page right where we start
rendering the string. This convention dates back to pen plotter days.
The offset[] arrays in g_fontdb.c hold the information that we need to
undo this leftward shift by a compensating initial rightward shift.
After rendering the string, we undo the shift.
2. On most devices, stick fonts are available only in HP's Roman-8
encoding. So we need to remap them, if they are to be ISO-Latin-1
fonts. There are a few characters missing, but we do our best.
3. Ideally, any HP-GL device kerns the variable-width Stick fonts that
it supports, if any. We compensate for this in g_alabel.c by using the
spacing tables in g_fontd2.c when computing label widths. The inclusion
of kerning in the label width computation affects the horizontal
positioning of the label, if it is centered or right-justifified rather
than left-justified.
4. PCL fonts (and the PS fonts available in PCL mode on a few high-end
devices) in principle support ISO-Latin-1 encoding, natively. However,
HP interprets ISO-Latin-1 in an idiosyncratic way. For example,
left-quote and right-quote show up as accents, and tilde shows up as a
tilde accent. For this reason, for ISO-Latin-1 PCL fonts we use HP's
Roman-8 encoding for the lower half, and HP's ISO-Latin-1 encoding for
the upper half. */
#include "sys-defines.h"
#include "extern.h"
#include "h_roman8.h"
/* for switching to upper half of font charset, and switching back */
#define SHIFT_OUT 14 /* i.e. ASCII 0x0e, i.e. ^N */
#define SHIFT_IN 15 /* i.e. ASCII 0x0f, i.e. ^O */
/* for DFA that keeps track of which half we're in */
typedef enum { LOWER_HALF, UPPER_HALF } state_type;
/* kludge, see comment in code */
#define HP_ROMAN_8_MINUS_CHAR 0366
double
#ifdef _HAVE_PROTOS
_h_paint_text_string (R___(Plotter *_plotter) const unsigned char *s, int h_just, int v_just)
#else
_h_paint_text_string (R___(_plotter) s, h_just, v_just)
S___(Plotter *_plotter;)
const unsigned char *s;
int h_just; /* horizontal justification: JUST_LEFT, CENTER, or RIGHT */
int v_just; /* vertical justification: JUST_TOP, HALF, BASE, BOTTOM */
#endif
{
bool created_temp_string = false;
bool reencode_iso_as_roman8 = false;
double hp_offset;
double theta, costheta, sintheta;
int master_font_index;
unsigned char *t;
unsigned char instruction_buf[4];
/* if empty string, nothing to do */
if (*s == (unsigned char)'\0')
return 0.0;
/* sanity checks: this routine supports only baseline positioning and
left-justification */
if (v_just != JUST_BASE || h_just != JUST_LEFT)
return 0.0;
/* sanity check, should be unnecessary */
#ifndef USE_PS_FONTS_IN_PCL
if (_plotter->drawstate->font_type != F_PCL
&& _plotter->drawstate->font_type != F_STICK)
return 0.0;
#else /* USE_PS_FONTS_IN_PCL */
if (_plotter->drawstate->font_type != F_POSTSCRIPT
&& _plotter->drawstate->font_type != F_PCL
&& _plotter->drawstate->font_type != F_STICK)
return 0.0;
#endif
/* Many HP-GL interpreters can't handle zero font size. So bail if the
font size we'll emit is zero. */
if (_plotter->drawstate->true_font_size == 0.0)
return 0.0;
/* Our font selection code in h_font.c will divide by zero if the
viewport in the device frame has zero area, i.e., if the HP-GL scaling
points P1,P2 have the same x or y coordinates. So bail now if that's
the case. */
if (_plotter->hpgl_p1.x == _plotter->hpgl_p2.x
|| _plotter->hpgl_p1.y == _plotter->hpgl_p2.y)
return _plotter->get_text_width (R___(_plotter) s);
/* compute index of font in master table in g_fontdb.c */
switch (_plotter->drawstate->font_type)
{
case F_PCL:
default:
master_font_index =
(_pcl_typeface_info[_plotter->drawstate->typeface_index].fonts)[_plotter->drawstate->font_index];
break;
case F_POSTSCRIPT:
master_font_index =
(_ps_typeface_info[_plotter->drawstate->typeface_index].fonts)[_plotter->drawstate->font_index];
break;
case F_STICK:
master_font_index =
(_stick_typeface_info[_plotter->drawstate->typeface_index].fonts)[_plotter->drawstate->font_index];
break;
}
/* label rotation angle in radians, in user frame */
theta = M_PI * _plotter->drawstate->text_rotation / 180.0;
sintheta = sin (theta);
costheta = cos (theta);
switch (_plotter->drawstate->font_type)
{
case F_PCL:
default:
if (_pcl_font_info[master_font_index].hpgl_symbol_set == PCL_ROMAN_8
&& _pcl_font_info[master_font_index].iso8859_1)
/* An ISO-Latin-1 PCL font, for which we use HP's Roman-8 for lower
half and HP's Latin-1 for upper half. Why? Because it's what
works best; see comments in the font retrieval code in h_font.c.
There is one exception to this: right here, we map the ASCII
minus character `-', in the lower half, to
HP_ROMAN_8_MINUS_CHAR, i.e., to 0366. This is a kludge, needed
to get a character whose width matches the width in the AFM
files that HP distributes. */
{
state_type dfa_state = LOWER_HALF;
unsigned const char *sptr = s;
unsigned char *tptr;
/* temp string for rewritten label */
t = (unsigned char *)_plot_xmalloc (3 * strlen ((const char *)s) + 1);
tptr = t;
created_temp_string = true;
/* SHIFT_OUT switches to alt. charset, SHIFT_IN back to standard */
while (*sptr)
{
unsigned char c;
c = *sptr++;
if (c < 0x80)
/* lower half of font, use standard font (HP Roman-8) */
{
if (c == '-') /* kludge, map to a char in upper half */
c = HP_ROMAN_8_MINUS_CHAR;
if (dfa_state == UPPER_HALF)
{
*tptr++ = SHIFT_IN;
dfa_state = LOWER_HALF;
}
*tptr++ = c;
}
else
/* upper half of font, use alt. font (HP ECMA-96 Latin-1) */
{
if (dfa_state == LOWER_HALF)
{
*tptr++ = SHIFT_OUT;
dfa_state = UPPER_HALF;
}
*tptr++ = c;
}
}
if (dfa_state == UPPER_HALF)
*tptr++ = SHIFT_IN;
*tptr = '\0'; /* end of rewritten label */
}
else
/* a non-ISO-Latin-1 PCL font, no need for reencoding */
t = (unsigned char *)s;
break;
case F_POSTSCRIPT:
/* no need for reencoding (HP's encoding of the font is good enough) */
t = (unsigned char *)s;
break;
case F_STICK:
if (_stick_font_info[master_font_index].hpgl_symbol_set == PCL_ROMAN_8
&& _stick_font_info[master_font_index].iso8859_1)
/* stick font uses HP's Roman-8 encoding for its upper half, so
must reencode ISO-Latin-1 as Roman-8 */
reencode_iso_as_roman8 = true;
if (_plotter->hpgl_version <= 1)
/* HP-GL version is no greater than "1.5", i.e. HP7550A; so in
h_font.c, we'll have made both lower and upper font halves
available as 7-bit fonts that can be switched between via SO/SI */
{
bool bogus_upper_half = false;
state_type dfa_state = LOWER_HALF;
unsigned const char *sptr = s;
unsigned char *tptr;
/* Check whether font is meant to be a pure 7-bit font with no
upper half; if so, we'll ignore all 8-bit characters. This
case is recognized by the charset number for the upper half
being -1 (see table in g_fontdb.c). */
if (_stick_font_info[master_font_index].hpgl_charset_upper < 0)
bogus_upper_half = true;
/* temp string for rewritten label */
t = (unsigned char *)_plot_xmalloc (3 * strlen ((const char *)s) + 1);
tptr = t;
created_temp_string = true;
/* do 7-bit reencoding, using SO/SI */
/* SHIFT_OUT switches to alt. charset, SHIFT_IN back to standard */
while (*sptr)
{
unsigned char c;
c = *sptr++;
if (c >= 0x80 && reencode_iso_as_roman8)
/* reencode upper half via lookup table in h_roman8.h */
c = _iso_to_roman8[c - 0x80];
if (c < 0x80)
/* lower half of font, pass through */
{
if (dfa_state == UPPER_HALF)
{
*tptr++ = SHIFT_IN;
dfa_state = LOWER_HALF;
}
*tptr++ = c;
}
else
/* upper half of font, move to lower half */
if (bogus_upper_half == false)
{
if (dfa_state == LOWER_HALF)
{
*tptr++ = SHIFT_OUT;
dfa_state = UPPER_HALF;
}
*tptr++ = c - 0x80;
}
}
/* ensure we switch back to standard font at end of label */
if (dfa_state == UPPER_HALF)
*tptr++ = SHIFT_IN;
*tptr = '\0'; /* end of rewritten label */
}
else
/* HP-GL version is "2", i.e. HP-GL/2, so the only Stick fonts we
have are 8-bit ones; no need for 7-bit reencoding via a DFA.
Will still need to map ISO-Latin-1 to Roman-8, though. */
{
unsigned const char *sptr = s;
unsigned char *tptr;
t = (unsigned char *)_plot_xmalloc (strlen ((const char *)s) + 1);
tptr = t;
created_temp_string = true;
while (*sptr)
{
if (*sptr < 0x80)
*tptr++ = *sptr++;
else
{
if (reencode_iso_as_roman8)
/* reencode upper half via lookup table in h_roman8.h */
*tptr++ = _iso_to_roman8[(*sptr++) - 0x80];
else
*tptr++ = *sptr++;
}
}
*tptr = '\0'; /* end of rewritten label */
}
break;
}
/* compute abovementioned HP-style rightward shift; depends on `offset'
for first character in label, i.e. its `first ink' */
switch (_plotter->drawstate->font_type)
{
case F_PCL:
default:
/* per-character offset expressed in units where font size = 1000 */
hp_offset = _pcl_font_info[master_font_index].offset[*((unsigned char *)s)] / 1000.0;
break;
case F_POSTSCRIPT:
/* per-character offset expressed in units where font size = 1000 */
hp_offset = _ps_font_info[master_font_index].offset[*((unsigned char *)s)] / 1000.0;
break;
case F_STICK:
/* Offset expressed in HP's abstract raster units, need to divide by
what the font size equals in raster units.
(Font size = 2 * raster width, by definition.) */
/* For Stick fonts that we've defined in such a way that the raster
width differs between lower and upper halves, not sure what to do
here. In particular ArcANK has JIS-ASCII encoding for lower half,
with raster width 42, and half-width Katakana encoding for upper
half, with raster width 45. For now, just use the raster width
for the lower half. */
hp_offset = (((double)(_stick_font_info[master_font_index].offset)) /
(2.0 * _stick_font_info[master_font_index].raster_width_lower));
break;
}
/* do the rightward shift */
_plotter->drawstate->pos.x +=
costheta * _plotter->drawstate->true_font_size * hp_offset;
_plotter->drawstate->pos.y +=
sintheta * _plotter->drawstate->true_font_size * hp_offset;
/* sync font and pen position */
_h_set_font (S___(_plotter));
_h_set_position (S___(_plotter));
/* Sync pen color. This may set the _plotter->hpgl_bad_pen flag (if optimal
pen is #0 [white] and we're not allowed to use pen #0 to draw with).
So we test _plotter->hpgl_bad_pen before drawing the label (see below). */
_h_set_pen_color (R___(_plotter) HPGL_OBJECT_LABEL);
if (t[0] != '\0' /* i.e. label nonempty */
&& _plotter->hpgl_bad_pen == false)
/* output the label via an `LB' instruction, including label
terminator; don't use sprintf to avoid having to escape % and \ */
{
strcpy (_plotter->data->page->point, "LB");
_update_buffer (_plotter->data->page);
strcpy (_plotter->data->page->point, (const char *)t);
_update_buffer (_plotter->data->page);
instruction_buf[0] = (unsigned char)3; /* ^C = default label terminator*/
instruction_buf[1] = ';';
instruction_buf[2] = '\0';
strcpy (_plotter->data->page->point, (const char *)instruction_buf);
_update_buffer (_plotter->data->page);
/* where is the plotter pen now located?? we don't know, exactly */
_plotter->hpgl_position_is_unknown = true;
}
if (created_temp_string)
/* created a temp string, so free it */
free (t);
/* Undo HP's rightward shift */
_plotter->drawstate->pos.x -=
costheta * _plotter->drawstate->true_font_size * hp_offset;
_plotter->drawstate->pos.y -=
sintheta * _plotter->drawstate->true_font_size * hp_offset;
return _plotter->get_text_width (R___(_plotter) s);
}
|