xref: /plan9/sys/src/cmd/gs/src/gdevmsxf.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
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