1 /* Copyright (C) 1993, 1994, 1997, 1998, 1999 Aladdin Enterprises. All rights reserved.
2
3 This software is provided AS-IS with no warranty, either express or
4 implied.
5
6 This software is distributed under license and may not be copied,
7 modified or distributed except as expressly authorized under the terms
8 of the license contained in the file LICENSE in this distribution.
9
10 For more information about licensing, please refer to
11 http://www.ghostscript.com/licensing/. For information on
12 commercial licensing, go to http://www.artifex.com/licensing/ or
13 contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14 San Rafael, CA 94903, U.S.A., +1(415)492-9861.
15 */
16
17 /* $Id: gdevmsxf.c,v 1.8 2004/08/04 23:33:29 stefan Exp $ */
18 /* External font (xfont) implementation for Microsoft Windows. */
19 #include "ctype_.h"
20 #include "math_.h"
21 #include "memory_.h"
22 #include "string_.h"
23 #include "gdevmswn.h"
24 #include "gsutil.h"
25 #include "gxxfont.h"
26 #include "gsstruct.h"
27
28 /* Imported from gdevemap.c */
29 extern const byte gs_map_std_to_iso[256];
30
31 /* Declare the xfont procedures */
32 private xfont_proc_lookup_font(win_lookup_font);
33 private xfont_proc_char_xglyph(win_char_xglyph);
34 private xfont_proc_char_metrics(win_char_metrics);
35 private xfont_proc_render_char(win_render_char);
36 private xfont_proc_release(win_release);
37 private const gx_xfont_procs win_xfont_procs =
38 {
39 win_lookup_font,
40 win_char_xglyph,
41 win_char_metrics,
42 win_render_char,
43 win_release
44 };
45
46 /* Return the xfont procedure record. */
47 const gx_xfont_procs *
win_get_xfont_procs(gx_device * dev)48 win_get_xfont_procs(gx_device * dev)
49 {
50 return &win_xfont_procs;
51 }
52
53 /* Define a Windows xfont. */
54 typedef struct win_xfont_s win_xfont;
55 struct win_xfont_s {
56 gx_xfont_common common;
57 LOGFONT lf;
58 TEXTMETRIC tm;
59 HFONT hFont;
60 gx_device_win *dev; /* for GetDC */
61 int invert_y;
62 int y_offset;
63 };
64
65 gs_private_st_dev_ptrs1(st_win_xfont, win_xfont, "win_xfont",
66 win_xfont_enum_ptrs, win_xfont_reloc_ptrs, dev);
67 #define wxf ((win_xfont *)xf)
68
69 /* Forward references */
70 private HDC near win_get_dc(gx_device_win *);
71 private void near win_release_dc(gx_device_win *, HDC);
72 private int win_select_font(HDC, win_xfont *);
73
74 /* Map from PostScript to Windows character codes. */
75 /* (These tables were generated by winmaps.ps.) */
76
77 private const byte far_data gs_map_symbol_to_oem[256] =
78 {
79 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
80 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
81 32, 33, 0, 35, 0, 37, 38, 0, 40, 41, 0, 43, 44, 0, 46, 47,
82 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
83 0, 0, 0, 0, 0, 0, 231, 225, 0, 0, 0, 0, 0, 0, 0, 0,
84 226, 232, 0, 227, 0, 0, 0, 233, 0, 0, 0, 91, 0, 93, 0, 95,
85 0, 223, 224, 0, 234, 0, 236, 0, 0, 0, 0, 0, 0, 229, 0, 0,
86 0, 0, 0, 228, 230, 0, 0, 0, 0, 0, 0, 123, 124, 125, 0, 0,
87 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
88 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
89 0, 0, 0, 242, 0, 235, 0, 5, 4, 3, 6, 29, 27, 24, 26, 25,
90 247, 240, 0, 241, 0, 0, 0, 7, 245, 0, 239, 0, 0, 0, 0, 0,
91 0, 0, 0, 0, 0, 0, 0, 238, 0, 0, 0, 0, 0, 0, 237, 0,
92 0, 0, 0, 0, 0, 0, 250, 248, 169, 0, 0, 0, 0, 0, 0, 0,
93 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
94 0, 0, 0, 243, 0, 244, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
95 };
96
97 private const byte far_data gs_map_iso_to_oem[256] =
98 {
99 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
100 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
101 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 0, 46, 47,
102 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
103 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
104 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
105 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
106 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 0,
107 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
108 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
109 32, 172, 154, 155, 0, 156, 0, 21, 0, 0, 165, 173, 169, 45, 0, 0,
110 247, 240, 252, 0, 0, 229, 20, 249, 0, 0, 166, 174, 171, 170, 0, 167,
111 0, 0, 0, 0, 141, 142, 145, 128, 0, 143, 0, 0, 0, 0, 0, 0,
112 0, 164, 0, 0, 0, 0, 152, 0, 0, 0, 0, 0, 153, 0, 0, 0,
113 133, 159, 131, 0, 132, 134, 144, 135, 138, 130, 136, 137, 140, 160, 0, 139,
114 0, 163, 148, 161, 146, 0, 147, 245, 0, 150, 162, 149, 129, 0, 0, 151
115 };
116
117 /* Correlate PostScript font names with Windows font names. */
118 /* This table should be an external resource, like Fontmap, */
119 /* but that will have to wait till later. */
120
121 typedef struct font_entry_s {
122 const char *key;
123 const char *value;
124 uint pitchAndFamily;
125 } font_entry;
126
127 private const font_entry font_names[] =
128 {
129 {"Courier", "Courier New", FIXED_PITCH | FF_MODERN},
130 {"Helvetica", "Arial", VARIABLE_PITCH | FF_SWISS},
131 {"Helvetica", "Helv", VARIABLE_PITCH | FF_SWISS},
132 {"Times", "Times New Roman", VARIABLE_PITCH | FF_ROMAN},
133 {"Times", "Tms Rmn", VARIABLE_PITCH | FF_ROMAN}
134 };
135
136 /* Look up a font. */
137 private int /*bool */ map_logical_font(HDC, win_xfont *);
138 gx_xfont *
win_lookup_font(gx_device * dev,const byte * fname,uint len,int encoding_index,const gs_uid * puid,const gs_matrix * pmat,gs_memory_t * mem)139 win_lookup_font(gx_device * dev, const byte * fname, uint len,
140 int encoding_index, const gs_uid * puid, const gs_matrix * pmat,
141 gs_memory_t * mem)
142 {
143 win_xfont f;
144 win_xfont *wf;
145 uint name_len = min(len, LF_FACESIZE - 1);
146 const font_entry *pfe;
147 HDC hdc;
148
149 /* Only handle simple cases for now. */
150 if (pmat->xy != 0 || pmat->yx != 0 || pmat->xx <= 0 ||
151 fabs(fabs(pmat->yy) - pmat->xx) > 0.00002
152 )
153 return NULL;
154 f.lf.lfHeight = (long)(pmat->xx * 1000);
155 /* Don't trust Windows with very small sizes. */
156 if (f.lf.lfHeight < 6 || f.lf.lfHeight >= 36)
157 return NULL;
158 f.lf.lfWidth = 0;
159 f.lf.lfEscapement = 0;
160 f.lf.lfOrientation = 0;
161 f.lf.lfWeight =
162 (string_match(fname, len, "*Bold*", 6, NULL) ?
163 FW_BOLD : FW_REGULAR);
164 f.lf.lfItalic =
165 string_match(fname, len, "*Italic*", 8, NULL) ||
166 string_match(fname, len, "*Oblique*", 9, NULL);
167 f.lf.lfUnderline = 0;
168 f.lf.lfStrikeOut = 0;
169 f.lf.lfCharSet =
170 (encoding_index == 2 ? SYMBOL_CHARSET : ANSI_CHARSET);
171 f.lf.lfOutPrecision = OUT_CHARACTER_PRECIS;
172 f.lf.lfClipPrecision = CLIP_STROKE_PRECIS;
173 f.lf.lfQuality = PROOF_QUALITY;
174 f.hFont = 0;
175 f.invert_y = pmat->yy >= 0;
176 hdc = win_get_dc(wdev);
177 if (hdc == NULL)
178 return NULL;
179 for (pfe = font_names; pfe != &font_names[countof(font_names)]; pfe++)
180 if (!strncmp(pfe->key, fname, strlen(pfe->key))) { /* Found a match. */
181 strcpy(f.lf.lfFaceName, pfe->value);
182 f.lf.lfPitchAndFamily = pfe->pitchAndFamily;
183 if (map_logical_font(hdc, &f))
184 break;
185 }
186 if (f.hFont == 0) { /* No matches in the table, try with the given name. */
187 uint len;
188
189 memcpy(f.lf.lfFaceName, fname, name_len); /* default */
190 for (len = 0; len < name_len; len++)
191 if (!isalnum(fname[len]))
192 break;
193 f.lf.lfFaceName[len] = 0;
194 f.lf.lfPitchAndFamily = 0; /* default */
195 if (!map_logical_font(hdc, &f)) {
196 win_release_dc(wdev, hdc);
197 return NULL;
198 }
199 }
200 GetTextMetrics(hdc, &f.tm);
201 win_release_dc(wdev, hdc);
202 f.y_offset = (!f.invert_y ? f.tm.tmAscent : f.tm.tmDescent);
203 wf = gs_alloc_struct(mem, win_xfont, &st_win_xfont, "win_lookup_font");
204 if (wf == 0) {
205 DeleteObject(f.hFont);
206 return NULL;
207 }
208 f.common.procs = &win_xfont_procs;
209 f.dev = wdev;
210 *wf = f;
211 return (gx_xfont *) wf;
212 }
213 /* Map the logical font, and see if the result is satisfactory. */
214 private int /*bool */
map_logical_font(HDC hdc,win_xfont * xf)215 map_logical_font(HDC hdc, win_xfont * xf)
216 {
217 char szFaceName[LF_FACESIZE];
218
219 xf->hFont = CreateFontIndirect(&xf->lf);
220 if (xf->hFont == 0)
221 return 0;
222 /* Check the face name */
223 SelectObject(hdc, xf->hFont);
224 GetTextFace(hdc, sizeof(szFaceName), szFaceName);
225 if (!strncmp(xf->lf.lfFaceName, szFaceName, strlen(xf->lf.lfFaceName)))
226 return 1;
227 DeleteObject(xf->hFont);
228 xf->hFont = 0;
229 return 0;
230 }
231
232 /* Convert a character name or index to an xglyph code. */
233 gx_xglyph
win_char_xglyph(gx_xfont * xf,gs_char chr,int encoding_index,gs_glyph glyph,const gs_const_string * glyph_name)234 win_char_xglyph(gx_xfont * xf, gs_char chr, int encoding_index,
235 gs_glyph glyph, const gs_const_string *glyph_name)
236 {
237 if (chr == gs_no_char)
238 return gx_no_xglyph; /* can't look up names yet */
239 if (encoding_index == 0) { /* Map StandardEncoding to ISOLatin1Encoding. */
240 /* We lose a couple of characters that exist in both */
241 /* StandardEncoding and the Windows OEM encoding but not in */
242 /* the ISOLatin1Encoding; we won't worry about this */
243 /* for now. */
244 chr = gs_map_std_to_iso[chr];
245 encoding_index = 1;
246 }
247 if (wxf->hFont == NULL) { /* TEXTMETRICS not filled in yet */
248 HDC hdc = win_get_dc(wxf->dev);
249 int code;
250
251 if (hdc == NULL)
252 return gx_no_xglyph;
253 code = win_select_font(hdc, wxf);
254 win_release_dc(wxf->dev, hdc);
255 if (code < 0)
256 return gx_no_xglyph;
257 }
258 switch (wxf->tm.tmCharSet) {
259 case ANSI_CHARSET:
260 if (encoding_index == 1 && (chr < 0x7f || chr > 0x9f ||
261 chr == 0x91 || chr == 0x92)
262 )
263 break;
264 return gx_no_xglyph;
265 case OEM_CHARSET:
266 switch (encoding_index) {
267 case 1: /* ISOLatin1 */
268 chr = gs_map_iso_to_oem[chr];
269 break;
270 case 2: /* Symbol */
271 chr = gs_map_symbol_to_oem[chr];
272 break;
273 default:
274 return gx_no_xglyph;
275 }
276 break;
277 default:
278 return gx_no_xglyph;
279 }
280 return (chr != 0 && chr >= wxf->tm.tmFirstChar &&
281 chr <= wxf->tm.tmLastChar ?
282 (gx_xglyph) chr : gx_no_xglyph);
283 }
284
285 /* Get the metrics for a character. */
286 int
win_char_metrics(gx_xfont * xf,gx_xglyph xg,int wmode,gs_point * pwidth,gs_int_rect * pbbox)287 win_char_metrics(gx_xfont * xf, gx_xglyph xg, int wmode,
288 gs_point * pwidth, gs_int_rect * pbbox)
289 {
290 int code;
291 HDC hdc;
292 char chr = (char)xg;
293
294 if (wmode != 0)
295 return gs_error_undefined;
296 hdc = win_get_dc(wxf->dev);
297 if (hdc == NULL)
298 return gs_error_limitcheck;
299 if ((code = win_select_font(hdc, wxf)) < 0) {
300 win_release_dc(wxf->dev, hdc);
301 return code;
302 }
303 #ifdef __WIN32__
304 {
305 SIZE sz;
306
307 GetTextExtentPoint(hdc, &chr, 1, &sz);
308 pwidth->x = sz.cx;
309 }
310 #else
311 {
312 DWORD extent;
313
314 extent = GetTextExtent(hdc, &chr, 1);
315 pwidth->x = LOWORD(extent);
316 }
317 #endif
318 win_release_dc(wxf->dev, hdc);
319 pwidth->y = 0;
320 pbbox->p.x = 0;
321 pbbox->q.x = (int)pwidth->x;
322 if (wxf->invert_y) {
323 pbbox->p.y = -wxf->tm.tmDescent;
324 pbbox->q.y = wxf->tm.tmAscent;
325 } else {
326 pbbox->p.y = -wxf->tm.tmAscent;
327 pbbox->q.y = wxf->tm.tmDescent;
328 }
329 return 0;
330 }
331
332 /* Render a character. */
333 int
win_render_char(gx_xfont * xf,gx_xglyph xg,gx_device * dev,int xo,int yo,gx_color_index color,int required)334 win_render_char(gx_xfont * xf, gx_xglyph xg, gx_device * dev,
335 int xo, int yo, gx_color_index color, int required)
336 {
337 char chr = (char)xg;
338 int code;
339
340 #ifdef NOTUSED /* we don't own any windows so we can no longer do this */
341 if (dev->dname == gs_mswin_device.dname &&
342 wdev->hdctext != NULL && !wxf->invert_y
343 ) { /* Display the character directly */
344 HDC hdc = wdev->hdctext;
345 PALETTEENTRY *pal = &wdev->limgpalette->palPalEntry[color];
346
347 if ((code = win_select_font(hdc, wxf)) < 0)
348 return code;
349 SetTextColor(hdc, RGB(pal->peRed, pal->peGreen, pal->peBlue));
350 SetBkMode(hdc, TRANSPARENT);
351 TextOut(hdc, xo, yo - wxf->y_offset, &chr, 1);
352 } else
353 #endif
354 if (!required)
355 code = -1; /* too hard */
356 else { /* Display on an intermediate bitmap, then copy the bits. */
357 gs_point wxy;
358 gs_int_rect bbox;
359 int w, h, wbm, raster;
360 gx_device_win *fdev = wxf->dev;
361 HBITMAP hbm;
362 byte *bits;
363
364 code = (*xf->common.procs->char_metrics) (xf, xg, 0,
365 &wxy, &bbox);
366 if (code < 0)
367 return code;
368 w = bbox.q.x - bbox.p.x;
369 h = bbox.q.y - bbox.p.y;
370 wbm = ROUND_UP(w, align_bitmap_mod * 8);
371 raster = wbm >> 3;
372 bits = gs_malloc(dev->memory, h, raster, "win_render_char");
373 if (bits == 0)
374 return gs_error_limitcheck;
375 hbm = CreateBitmap(wbm, h, 1, 1, NULL);
376 if (hbm == NULL) {
377 code = gs_error_limitcheck;
378 } else {
379 HDC hdcwin = win_get_dc(fdev);
380 HDC hdcbit = CreateCompatibleDC(hdcwin);
381
382 dev_proc_copy_mono((*copy_mono)) =
383 dev_proc(dev, copy_mono);
384 int y = yo - wxf->y_offset;
385
386 SetMapMode(hdcbit, GetMapMode(hdcwin));
387 win_select_font(hdcbit, wxf);
388 SelectObject(hdcbit, hbm);
389 PatBlt(hdcbit, 0, 0, wbm, h, rop_write_0s);
390 SetTextColor(hdcbit, 0xffffffL); /* 1 */
391 SetBkMode(hdcbit, TRANSPARENT);
392 TextOut(hdcbit, 0, 0, &chr, 1);
393 GetBitmapBits(hbm, (DWORD) raster * h, bits);
394 DeleteDC(hdcbit);
395 win_release_dc(fdev, hdcwin);
396 DeleteObject(hbm);
397 if (!wxf->invert_y)
398 code = (*copy_mono) (dev, bits, 0,
399 raster, gx_no_bitmap_id,
400 xo, y, w, h,
401 gx_no_color_index, color);
402 else { /* Copy scan lines in reverse order. */
403 int i;
404
405 y += h - 1;
406 for (i = 0; i < h; i++)
407 (*copy_mono) (dev, bits + i * raster,
408 0, raster, gx_no_bitmap_id,
409 xo, y - i, w, 1,
410 gx_no_color_index, color);
411 }
412 }
413 gs_free(dev->memory, bits, h, raster, "win_render_char");
414 }
415 return (code < 0 ? code : 0);
416 }
417
418 /* Release an xfont. */
419 private int
win_release(gx_xfont * xf,gs_memory_t * mem)420 win_release(gx_xfont * xf, gs_memory_t * mem)
421 {
422 if (wxf->hFont) {
423 DeleteObject(wxf->hFont);
424 wxf->hFont = 0;
425 }
426 if (mem != NULL)
427 gs_free_object(mem, xf, "win_release");
428 return 0;
429 }
430
431 /* ------ Font utilities ------ */
432
433 #undef wdev
434 #undef wxf
435
436 /* Get a DC for the font's device. */
437 private HDC near
win_get_dc(gx_device_win * wdev)438 win_get_dc(gx_device_win * wdev)
439 {
440 /* Since we don't have a window, use the desktop */
441 /* Don't draw into it! */
442 return GetDC(HWND_DESKTOP);
443 }
444
445 /* Release a DC for the font's device. */
446 private void near
win_release_dc(gx_device_win * wdev,HDC hdc)447 win_release_dc(gx_device_win * wdev, HDC hdc)
448 {
449 ReleaseDC(HWND_DESKTOP, hdc);
450 }
451
452 /* Make an xfont current, possibly remapping it from a logical font. */
453 private int
win_select_font(HDC hdc,win_xfont * wxf)454 win_select_font(HDC hdc, win_xfont * wxf)
455 {
456 HFONT hFont = wxf->hFont;
457
458 if (hFont == NULL) { /* The font was released to free up resources. */
459 /* Re-acquire it now. */
460 wxf->hFont = CreateFontIndirect(&wxf->lf);
461 if (wxf->hFont == NULL)
462 return gs_error_limitcheck;
463 }
464 SelectObject(hdc, wxf->hFont);
465 return 0;
466 }
467