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 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442
|
/* This file contains a low-level method for adjusting the font of an HP-GL
or PCL device to agree with an HPGL or PCL Plotter's notion of what it
should be, prior to plotting a label. Note: The `PCL 5' output by any
PCL Plotter is simply a wrapped version of HP-GL/2.
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.
After selecting the font, this method invokes the HP-GL DR/SR/SL
instructions to size and slant the font, as needed.
The font selection itself is accomplished in either of two ways.
1. In versions of HP-GL prior to HP-GL/2, 7-bit font halves are selected
with `CS' and `CA' instructions. They must be switched between when the
label is plotted via SO/SI; see h_text.c. The HP-GL device will usually
supply the upper font half in the Roman-8 encoding, and that too will
need to be taken into account when the label is plotted.
2. In HP-GL/2, a single 8-bit font is selected with the HP-GL/2 `SD'
instruction. In principle, no switching between 7-bit font halves is
needed.
In practice, it's more complicated than that. For ISO-Latin-1 PCL
fonts, the SD instruction allegedly allows the ISO-Latin-1 encoding to
be requested. But it doesn't work! One or two characters in the lower
half (!) don't come out right. So instead, we use the `SD' instruction
to retrieve an 8-bit version that uses the Roman-8 encoding, and the
`AD' instruction to retrieve an alternative 8-bit version that uses the
ISO-Latin-1 encoding. We'll use the former for characters in the lower
half, and the latter for characters in the upper half. This is bizarre,
but it works. See additional comments in h_text.c. */
/* NOTE: This code assumes that P1 and P2 have different x coordinates, and
different y coordinates. If that isn't the case, it'll divide by zero.
So we check for that possibility in _h_paint_text_string() before
calling this function. See comment in h_text.c. */
#include "sys-defines.h"
#include "extern.h"
/* Shearing factor for oblique fonts, new_x = x + SHEAR * y */
#define SHEAR (2.0/7.0)
void
#ifdef _HAVE_PROTOS
_h_set_font (S___(Plotter *_plotter))
#else
_h_set_font (S___(_plotter))
S___(Plotter *_plotter;)
#endif
{
bool font_changed = false;
bool oblique;
double cos_slant = 1.0, sin_slant = 0.0;
double new_relative_label_run, new_relative_label_rise;
double theta, sintheta, costheta;
plVector base, up, base_native, up_native;
double base_native_len, up_native_len, tan_slant;
/* sanity check, should be unnecessary */
if (_plotter->drawstate->font_type == F_HERSHEY)
return;
if (_plotter->drawstate->font_type == F_STICK)
/* check whether obliquing of this font is called for */
{
int master_font_index;
/* compute index of font in master table of fonts, in g_fontdb.c */
master_font_index =
(_stick_typeface_info[_plotter->drawstate->typeface_index].fonts)[_plotter->drawstate->font_index];
oblique = _stick_font_info[master_font_index].obliquing;
}
else
oblique = false;
/* label rotation angle in radians, in user frame */
theta = M_PI * _plotter->drawstate->text_rotation / 180.0;
costheta = cos (theta);
sintheta = sin (theta);
/* compute in the device frame a `base vector' which is (in the user
frame) directed along the label, with length equal to the font size) */
base.x = _plotter->drawstate->true_font_size * XDV(costheta,sintheta);
base.y = _plotter->drawstate->true_font_size * YDV(costheta,sintheta);
/* Compute rise and run, relative to x-distance and y-distance between
scaling points P1,P2. (Either rise or run can be negative; overall
normalization, e.g. the `100', is irrelevant. We include the `100' to
express them as percentages.) */
new_relative_label_run = 100 * base.x / (HPGL_SCALED_DEVICE_RIGHT - HPGL_SCALED_DEVICE_LEFT);
new_relative_label_rise = 100 * base.y / (HPGL_SCALED_DEVICE_TOP - HPGL_SCALED_DEVICE_BOTTOM);
if (new_relative_label_run != 0.0 || new_relative_label_rise != 0.0)
/* (will always be true except when the font size is so small
there's really no point in printing the label) */
{
/* update device-frame label rotation angle if needed */
if (_plotter->hpgl_rel_label_run != new_relative_label_run
|| _plotter->hpgl_rel_label_rise != new_relative_label_rise)
{
sprintf (_plotter->data->page->point, "DR%.3f,%.3f;",
new_relative_label_run, new_relative_label_rise);
_update_buffer (_plotter->data->page);
_plotter->hpgl_rel_label_run = new_relative_label_run;
_plotter->hpgl_rel_label_rise = new_relative_label_rise;
}
}
/* emit command to select new font, if needed (see below) */
if (_plotter->hpgl_version == 2)
font_changed = _hpgl2_maybe_update_font (S___(_plotter));
else /* 0 or 1, i.e. generic HP-GL or HP7550A */
font_changed = _hpgl_maybe_update_font (S___(_plotter));
/* Compute image, in the device frame, of a so-called `up vector': a
vector which in the user frame is perpendicular to the above `base'
vector, and has the same length. Some fonts are specially obliqued,
so we take font obliquing (if any) into account here. */
up.x = _plotter->drawstate->true_font_size * XDV(-sintheta,costheta);
up.y = _plotter->drawstate->true_font_size * YDV(-sintheta,costheta);
up.x += (oblique ? SHEAR : 0.0) * base.x;
up.y += (oblique ? SHEAR : 0.0) * base.y;
/* Our `device frame' base and up vectors are really vectors in the
normalized device frame, in which the viewport has a fixed size. See
h_defplot.c. E.g., the viewport corners (0,0) and (1,1) in the NDC
frame are respectively mapped to
(HPGL_SCALED_DEVICE_LEFT,HPGL_SCALED_DEVICE_BOTTOM) and
(HPGL_SCALED_DEVICE_RIGHT,HPGL_SCALED_DEVICE_TOP) in the normalized
device frame. The further mapping to native HP-GL coordinates is
accomplished by an `SC' scaling instruction emitted at the head of the
output file; see h_openpl.c. This further mapping depends on the
PAGESIZE parameter.
Unfortunately, when dealing with anamorphically transformed fonts we
need to manipulate not just vectors in the normalized device frame,
but also vectors in the true device frame, i.e., in native HP-GL
units. */
/* These vectors use native HP-GL units. */
base_native.x = base.x * (_plotter->hpgl_p2.x - _plotter->hpgl_p1.x) / (HPGL_SCALED_DEVICE_RIGHT - HPGL_SCALED_DEVICE_LEFT);
base_native.y = base.y * (_plotter->hpgl_p2.y - _plotter->hpgl_p1.y) / (HPGL_SCALED_DEVICE_TOP - HPGL_SCALED_DEVICE_BOTTOM);
up_native.x = up.x * (_plotter->hpgl_p2.x - _plotter->hpgl_p1.x) / (HPGL_SCALED_DEVICE_RIGHT - HPGL_SCALED_DEVICE_LEFT);
up_native.y = up.y * (_plotter->hpgl_p2.y - _plotter->hpgl_p1.y) / (HPGL_SCALED_DEVICE_TOP - HPGL_SCALED_DEVICE_BOTTOM);
base_native_len = sqrt (base_native.x * base_native.x + base_native.y * base_native.y);
up_native_len = sqrt (up_native.x * up_native.x + up_native.y * up_native.y);
/* compute character slant angle (in the true device frame, NOT in the
normalized device frame) */
if (base_native_len == 0.0 || up_native_len == 0.0) /* a bad situation */
tan_slant = 0.0;
else
{
sin_slant = ((base_native.x * up_native.x + base_native.y * up_native.y)
/ (base_native_len * up_native_len));
cos_slant = sqrt (1 - sin_slant * sin_slant);
tan_slant = sin_slant / cos_slant;
}
/* Compute nominal horizontal and vertical character sizes as percentages
of the horizontal and vertical distances between scaling points P1 and
P2, and specify them with the SR instruction.
The two arguments of the SR instruction (the horizontal and vertical
character sizes) should apparently be 0.5 times the font size, and 0.7
times the font size.
Why? The 0.5 and 0.7 = 1.4 * 0.5 factors are undocumented HP magic.
This convention must have been introduced by HP to adapt the SR
instruction, which dates back to fixed-width plotter fonts (i.e., the
original Stick font), to modern outline fonts. Fixed-width plotter
fonts did not have a font size in the modern sense: they had a
character width and a character height. (The former being the width
of the character proper, which occupied the left 2/3 of a character
cell, and the latter being what we would nowadays call a cap height.)
The convention probably arose because Stick fonts look best if the
aspect ratio is 1.4 (= 0.7/0.5), i.e. if the `character height' is 1.4
times the `character width'. I am not sure where the 0.5 came from.
Possibly back in stick font days, the nominal font size was defined to
be 4/3 times the width of a character cell, or equivalently the width
of a character cell was chosen to be 3/4 times the nominal font size.
This would make the maximum character width (2/3)x(3/4) = (1/2) times
the nominal font size. */
{
double fractional_char_width = 0.5;
double fractional_char_height = 1.4 * 0.5;
double new_relative_char_width, new_relative_char_height;
/* If, in the physical device frame, the font is reflected, we must
flip the sign of HP-GL's `character height', as used in the SR
instruction. To determine whether this sign-flipping is needed, we
use the fact that the user_frame->physical_device_frame map is the
product of the user_frame->normalized_device_frame map and the
normalized_device_frame->physical_device_frame map. Whether the
first includes a reflection is precomputed and stored in the drawing
state. The second will include a reflection only if exactly one of
the xsize,ysize fields of PAGESIZE is negative. We can easily check
for that by comparing the x,y coordinates of the HP-GL scaling
points P1,P2. */
int orientation = _plotter->drawstate->transform.nonreflection ? 1 : -1;
if ((_plotter->hpgl_p2.x - _plotter->hpgl_p1.x) / (HPGL_SCALED_DEVICE_RIGHT - HPGL_SCALED_DEVICE_LEFT) < 0.0)
orientation *= -1;
if ((_plotter->hpgl_p2.y - _plotter->hpgl_p1.y) / (HPGL_SCALED_DEVICE_TOP - HPGL_SCALED_DEVICE_BOTTOM) < 0.0)
orientation *= -1;
new_relative_char_width = fractional_char_width * 100 * base_native_len / (_plotter->hpgl_p2.x - _plotter->hpgl_p1.x);
new_relative_char_height =
fractional_char_height * 100 * orientation * cos_slant * up_native_len / (_plotter->hpgl_p2.y - _plotter->hpgl_p1.y);
/* emit SR instruction only if font was changed or if current
size was wrong */
if (font_changed ||
(new_relative_char_width != _plotter->hpgl_rel_char_width
|| new_relative_char_height != _plotter->hpgl_rel_char_height))
{
sprintf (_plotter->data->page->point, "SR%.3f,%.3f;",
new_relative_char_width, new_relative_char_height);
_update_buffer (_plotter->data->page);
_plotter->hpgl_rel_char_width = new_relative_char_width;
_plotter->hpgl_rel_char_height = new_relative_char_height;
}
}
/* update slant angle if necessary */
if (tan_slant != _plotter->hpgl_tan_char_slant)
{
sprintf (_plotter->data->page->point, "SL%.3f;", tan_slant);
_update_buffer (_plotter->data->page);
_plotter->hpgl_tan_char_slant = tan_slant;
}
}
/* If needed, emit a new-style (HP-GL/2) `SD' font-selection command.
Return value indicates whether font was changed. */
bool
#ifdef _HAVE_PROTOS
_hpgl2_maybe_update_font (S___(Plotter *_plotter))
#else
_hpgl2_maybe_update_font (S___(_plotter))
S___(Plotter *_plotter;)
#endif
{
bool font_change = false;
bool font_is_iso_latin_1;
int master_font_index;
int symbol_set, spacing, posture, stroke_weight, typeface;
/* PCL, PS, and Stick fonts are handled separately here only because the
font information for them is stored in different tables in g_fontdb.c.
We compute parameters we'll need for the HP-GL/2 `SD' font-selection
command. */
switch (_plotter->drawstate->font_type)
{
case F_PCL:
default:
/* compute index of font in master table of fonts, in g_fontdb.c */
master_font_index =
(_pcl_typeface_info[_plotter->drawstate->typeface_index].fonts)[_plotter->drawstate->font_index];
/* #1: symbol set */
symbol_set = _pcl_font_info[master_font_index].hpgl_symbol_set;
/* #2: spacing */
spacing = _pcl_font_info[master_font_index].hpgl_spacing;
/* #3, #4 are pitch and height (we use defaults) */
/* #5: posture */
posture = _pcl_font_info[master_font_index].hpgl_posture;
/* #6: stroke weight */
stroke_weight = _pcl_font_info[master_font_index].hpgl_stroke_weight;
/* #7: typeface */
typeface = _pcl_font_info[master_font_index].pcl_typeface;
/* ISO-Latin-1 after reencoding (if any)? */
font_is_iso_latin_1 = _pcl_font_info[master_font_index].iso8859_1;
break;
case F_POSTSCRIPT:
/* compute index of font in master table of fonts, in g_fontdb.c */
master_font_index =
(_ps_typeface_info[_plotter->drawstate->typeface_index].fonts)[_plotter->drawstate->font_index];
/* #1: symbol set */
symbol_set = _ps_font_info[master_font_index].hpgl_symbol_set;
/* #2: spacing */
spacing = _ps_font_info[master_font_index].hpgl_spacing;
/* #3, #4 are pitch and height (we use defaults) */
/* #5: posture */
posture = _ps_font_info[master_font_index].hpgl_posture;
/* #6: stroke weight */
stroke_weight = _ps_font_info[master_font_index].hpgl_stroke_weight;
/* #7: typeface */
typeface = _ps_font_info[master_font_index].pcl_typeface;
/* ISO-Latin-1 after reencoding (if any)? */
font_is_iso_latin_1 = _ps_font_info[master_font_index].iso8859_1;
break;
case F_STICK:
/* compute index of font in master table of fonts, in g_fontdb.c */
master_font_index =
(_stick_typeface_info[_plotter->drawstate->typeface_index].fonts)[_plotter->drawstate->font_index];
/* #1: symbol set */
symbol_set = _stick_font_info[master_font_index].hpgl_symbol_set;
/* #2: spacing */
spacing = _stick_font_info[master_font_index].hpgl_spacing;
/* #3, #4 are pitch and height (we use defaults) */
/* #5: posture */
posture = _stick_font_info[master_font_index].hpgl_posture;
/* #6: stroke weight */
stroke_weight = _stick_font_info[master_font_index].hpgl_stroke_weight;
/* #7: typeface */
typeface = _stick_font_info[master_font_index].pcl_typeface;
/* ISO-Latin-1 after reencoding (if any)? */
font_is_iso_latin_1 = _stick_font_info[master_font_index].iso8859_1;
break;
}
if (symbol_set != _plotter->hpgl_symbol_set
|| spacing != _plotter->hpgl_spacing
|| posture != _plotter->hpgl_posture
|| stroke_weight != _plotter->hpgl_stroke_weight
|| typeface != _plotter->hpgl_pcl_typeface)
font_change = true;
if (font_change)
{
if (spacing == FIXED_SPACING)
/* fixed-width font */
sprintf (_plotter->data->page->point,
/* #4 (nominal point size) not needed but included anyway */
"SD1,%d,2,%d,3,%.3f,4,%.3f,5,%d,6,%d,7,%d;",
symbol_set, spacing,
(double)NOMINAL_CHARS_PER_INCH, (double)NOMINAL_POINT_SIZE,
posture, stroke_weight, typeface);
else
/* variable-width font */
sprintf (_plotter->data->page->point,
/* #3 (nominal chars per inch) not needed but incl'd anyway */
"SD1,%d,2,%d,3,%.3f,4,%.3f,5,%d,6,%d,7,%d;",
symbol_set, spacing,
(double)NOMINAL_CHARS_PER_INCH, (double)NOMINAL_POINT_SIZE,
posture, stroke_weight, typeface);
_update_buffer (_plotter->data->page);
/* A hack. Due to HP's idiosyncratic definition of `ISO-Latin-1
encoding' for PCL fonts, when plotting a label in an ISO-Latin-1
PCL font we'll map characters in the lower half into HP's Roman-8
encoding, and characters in the upper half into HP's ISO-Latin-1
encoding. We implement this by using two fonts: standard and
alternative. See h_text.c for the DFA that switches back and
forth (if necessary) when the label is rendered. */
if (_plotter->drawstate->font_type == F_PCL
&& font_is_iso_latin_1
&& symbol_set == PCL_ROMAN_8)
{
if (spacing == FIXED_SPACING)
/* fixed-width font */
sprintf (_plotter->data->page->point,
/* #4 (nominal point size) not needed but included anyway */
"AD1,%d,2,%d,3,%.3f,4,%.3f,5,%d,6,%d,7,%d;",
PCL_ISO_8859_1, spacing,
(double)NOMINAL_CHARS_PER_INCH, (double)NOMINAL_POINT_SIZE,
posture, stroke_weight, typeface);
else
/* variable-width font */
sprintf (_plotter->data->page->point,
/* #3 (nominal chars per inch) not needed but included anyway */
"AD1,%d,2,%d,3,%.3f,4,%.3f,5,%d,6,%d,7,%d;",
PCL_ISO_8859_1, spacing,
(double)NOMINAL_CHARS_PER_INCH, (double)NOMINAL_POINT_SIZE,
posture, stroke_weight, typeface);
_update_buffer (_plotter->data->page);
}
_plotter->hpgl_symbol_set = symbol_set;
_plotter->hpgl_spacing = spacing;
_plotter->hpgl_posture = posture;
_plotter->hpgl_stroke_weight = stroke_weight;
_plotter->hpgl_pcl_typeface = typeface;
}
return font_change; /* was font changed? */
}
/* If needed, emit an old-style (pre-HP-GL/2) `CS' font-selection command,
and also a `CA' font-change command to make the upper half of the
selected font available via SO/SI. Return value indicates whether font
was changed. (This is used only for Stick fonts, which is all that
pre-HP/GL-2 HP-GL devices had.) */
bool
#ifdef _HAVE_PROTOS
_hpgl_maybe_update_font (S___(Plotter *_plotter))
#else
_hpgl_maybe_update_font (S___(_plotter))
S___(Plotter *_plotter;)
#endif
{
bool font_change = false;
int new_hpgl_charset_lower, new_hpgl_charset_upper, master_font_index;
/* compute index of font in master table of fonts, in g_fontdb.c */
master_font_index =
(_stick_typeface_info[_plotter->drawstate->typeface_index].fonts)[_plotter->drawstate->font_index];
/* determine HP character set numbers (old style, pre-HP-GL/2) */
new_hpgl_charset_lower = _stick_font_info[master_font_index].hpgl_charset_lower;
new_hpgl_charset_upper = _stick_font_info[master_font_index].hpgl_charset_upper;
/* using `CS', select charset for lower half of font */
if (new_hpgl_charset_lower != _plotter->hpgl_charset_lower)
{
sprintf (_plotter->data->page->point, "CS%d;", new_hpgl_charset_lower);
_update_buffer (_plotter->data->page);
_plotter->hpgl_charset_lower = new_hpgl_charset_lower;
font_change = true;
}
/* using `CA', select charset for upper half, if we have a genuine one (a
negative value for the upper charset is our way of flagging that this
is a 7-bit font; see comment in h_text.c) */
if (new_hpgl_charset_upper >= 0
&& new_hpgl_charset_upper != _plotter->hpgl_charset_upper)
{
sprintf (_plotter->data->page->point, "CA%d;", new_hpgl_charset_upper);
_update_buffer (_plotter->data->page);
_plotter->hpgl_charset_upper = new_hpgl_charset_upper;
font_change = true;
}
return font_change;
}
|