1 /* Copyright (C) 1993, 2000 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: gdevxxf.c,v 1.9 2004/08/04 19:36:12 stefan Exp $ */
18 /* External font (xfont) implementation for X11. */
19 #include "math_.h"
20 #include "memory_.h"
21 #include "x_.h"
22 #include "gx.h"
23 #include "gxdevice.h"
24 #include "gdevx.h"
25 #include "gsstruct.h"
26 #include "gsutil.h"
27 #include "gserrors.h"
28 #include "gxxfont.h"
29
30 /* Define the smallest point size that we trust X to render reasonably well. */
31 #define min_X_font_size 6
32 /* Define the largest point size where X will do a better job than we can. */
33 #define max_X_font_size 35
34
35 extern gx_device_X gs_x11_device;
36
37 extern const byte gs_map_std_to_iso[256];
38 extern const byte gs_map_iso_to_std[256];
39
40 /* Declare the xfont procedures */
41 private xfont_proc_lookup_font(x_lookup_font);
42 private xfont_proc_char_xglyph(x_char_xglyph);
43 private xfont_proc_char_metrics(x_char_metrics);
44 private xfont_proc_render_char(x_render_char);
45 private xfont_proc_release(x_release);
46 private const gx_xfont_procs x_xfont_procs =
47 {
48 x_lookup_font,
49 x_char_xglyph,
50 x_char_metrics,
51 x_render_char,
52 x_release
53 };
54
55 /* Return the xfont procedure record. */
56 const gx_xfont_procs *
gdev_x_get_xfont_procs(gx_device * dev)57 gdev_x_get_xfont_procs(gx_device * dev)
58 {
59 return &x_xfont_procs;
60 }
61
62 /* Define a X11 xfont. */
63 typedef struct x_xfont_s x_xfont;
64 struct x_xfont_s {
65 gx_xfont_common common;
66 gx_device_X *xdev;
67 XFontStruct *font;
68 int encoding_index;
69 int My;
70 int angle;
71 };
72
73 gs_private_st_dev_ptrs1(st_x_xfont, x_xfont, "x_xfont",
74 x_xfont_enum_ptrs, x_xfont_reloc_ptrs, xdev);
75
76 /* ---------------- Utilities ---------------- */
77
78 /* Search one set of font maps for a font with a given name. */
79 private x11fontmap *
find_fontmap(x11fontmap * fmps,const byte * fname,uint len)80 find_fontmap(x11fontmap *fmps, const byte *fname, uint len)
81 {
82 x11fontmap *fmp = fmps;
83
84 while (fmp) {
85 if (len == strlen(fmp->ps_name) &&
86 strncmp(fmp->ps_name, (const char *)fname, len) == 0)
87 break;
88 fmp = fmp->next;
89 }
90 return fmp;
91 }
92
93 /* Find an X font with a given name, encoding, and size. */
94 private char *
find_x_font(gx_device_X * xdev,char x11template[256],x11fontmap * fmp,const char * encoding_name,x11fontlist * fls,int xheight,bool * scalable_font)95 find_x_font(gx_device_X *xdev, char x11template[256], x11fontmap *fmp,
96 const char *encoding_name, x11fontlist *fls, int xheight,
97 bool *scalable_font)
98 {
99 int i;
100 char *x11fontname = 0;
101 int len1 = strlen(fmp->x11_name) + 1;
102
103 if (fls->count == -1) {
104 sprintf(x11template, "%s-*-*-*-*-*-*-%s", fmp->x11_name,
105 encoding_name);
106 fls->names = XListFonts(xdev->dpy, x11template, 32, &fls->count);
107 }
108 *scalable_font = false;
109 for (i = 0; i < fls->count; i++) {
110 const char *szp = fls->names[i] + len1;
111 int size = 0;
112
113 while (*szp >= '0' && *szp <= '9')
114 size = size * 10 + *szp++ - '0';
115 if (size == 0) {
116 *scalable_font = true;
117 continue;
118 }
119 if (size == xheight)
120 return fls->names[i];
121 }
122 if (*scalable_font && xdev->useScalableFonts) {
123 sprintf(x11template, "%s-%d-0-0-0-*-0-%s", fmp->x11_name,
124 xheight, encoding_name);
125 x11fontname = x11template;
126 }
127 return x11fontname;
128 }
129
130 /* ---------------- xfont procedures ---------------- */
131
132 /* Look up a font. */
133 private gx_xfont *
x_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)134 x_lookup_font(gx_device * dev, const byte * fname, uint len,
135 int encoding_index, const gs_uid * puid, const gs_matrix * pmat,
136 gs_memory_t * mem)
137 {
138 gx_device_X *xdev = (gx_device_X *) dev;
139 x_xfont *xxf;
140 char x11template[256];
141 char *x11fontname = NULL;
142 XFontStruct *x11font;
143 x11fontmap *fmp;
144 double height;
145 int xwidth, xheight, angle;
146 Boolean My;
147 bool scalable_font;
148
149 if (!xdev->useXFonts)
150 return NULL;
151
152 if (pmat->xy == 0 && pmat->yx == 0) {
153 xwidth = fabs(pmat->xx * 1000) + 0.5;
154 xheight = fabs(pmat->yy * 1000) + 0.5;
155 height = fabs(pmat->yy * 1000);
156 angle = (pmat->xx > 0 ? 0 : 180);
157 My = (pmat->xx > 0 && pmat->yy > 0) || (pmat->xx < 0 && pmat->yy < 0);
158 } else if (pmat->xx == 0 && pmat->yy == 0) {
159 xwidth = fabs(pmat->xy * 1000) + 0.5;
160 xheight = fabs(pmat->yx * 1000) + 0.5;
161 height = fabs(pmat->yx * 1000);
162 angle = (pmat->yx < 0 ? 90 : 270);
163 My = (pmat->yx > 0 && pmat->xy < 0) || (pmat->yx < 0 && pmat->xy > 0);
164 } else {
165 return NULL;
166 }
167
168 /* Don't do very small fonts, where font metrics are way off */
169 /* due to rounding and the server does a very bad job of scaling, */
170 /* or very large fonts, where we can do just as good a job and */
171 /* the server may lock up the entire window system while rasterizing */
172 /* the whole font. */
173 if (xwidth < min_X_font_size || xwidth > max_X_font_size ||
174 xheight < min_X_font_size || xheight > max_X_font_size
175 )
176 return NULL;
177
178 if (!xdev->useFontExtensions && (My || angle != 0))
179 return NULL;
180
181 switch (encoding_index) {
182 case 0:
183 fmp = find_fontmap(xdev->regular_fonts, fname, len);
184 if (fmp == NULL)
185 return NULL;
186 x11fontname =
187 find_x_font(xdev, x11template, fmp, "Adobe-fontspecific",
188 &fmp->std, xheight, &scalable_font);
189 if (!x11fontname) {
190 x11fontname =
191 find_x_font(xdev, x11template, fmp, "ISO8859-1",
192 &fmp->iso, xheight, &scalable_font);
193 encoding_index = 1;
194 }
195 break;
196 case 1:
197 fmp = find_fontmap(xdev->regular_fonts, fname, len);
198 if (fmp == NULL)
199 return NULL;
200 x11fontname =
201 find_x_font(xdev, x11template, fmp, "ISO8859-1",
202 &fmp->iso, xheight, &scalable_font);
203 if (!x11fontname) {
204 x11fontname =
205 find_x_font(xdev, x11template, fmp, "Adobe-fontspecific",
206 &fmp->std, xheight, &scalable_font);
207 encoding_index = 0;
208 }
209 break;
210 case 2:
211 fmp = xdev->symbol_fonts;
212 goto sym;
213 case 3:
214 fmp = xdev->dingbat_fonts;
215 sym: fmp = find_fontmap(fmp, fname, len);
216 if (fmp == NULL)
217 return NULL;
218 x11fontname =
219 find_x_font(xdev, x11template, fmp, "Adobe-fontspecific",
220 &fmp->std, xheight, &scalable_font);
221 default:
222 return NULL;
223 }
224 if (!x11fontname)
225 return NULL;
226
227 if (xwidth != xheight || angle != 0 || My) {
228 if (!xdev->useScalableFonts || !scalable_font)
229 return NULL;
230 sprintf(x11template, "%s%s+%d-%d+%d-0-0-0-*-0-%s",
231 fmp->x11_name, (My ? "+My" : ""),
232 angle * 64, xheight, xwidth,
233 (encoding_index == 1 ? "ISO8859-1" : "Adobe-fontspecific"));
234 x11fontname = x11template;
235 }
236 x11font = XLoadQueryFont(xdev->dpy, x11fontname);
237 if (x11font == NULL)
238 return NULL;
239 /* Don't bother with 16-bit or 2 byte fonts yet */
240 if (x11font->min_byte1 || x11font->max_byte1) {
241 XFreeFont(xdev->dpy, x11font);
242 return NULL;
243 }
244 xxf = gs_alloc_struct(mem, x_xfont, &st_x_xfont, "x_lookup_font");
245 if (xxf == NULL)
246 return NULL;
247 xxf->common.procs = &x_xfont_procs;
248 xxf->xdev = xdev;
249 xxf->font = x11font;
250 xxf->encoding_index = encoding_index;
251 xxf->My = (My ? -1 : 1);
252 xxf->angle = angle;
253 if (xdev->logXFonts) {
254 dprintf3("Using %s\n for %s at %g pixels.\n", x11fontname,
255 fmp->ps_name, height);
256 dflush();
257 }
258 return (gx_xfont *) xxf;
259 }
260
261 /* Convert a character name or index to an xglyph code. */
262 private gx_xglyph
x_char_xglyph(gx_xfont * xf,gs_char chr,int encoding_index,gs_glyph glyph,const gs_const_string * glyph_name)263 x_char_xglyph(gx_xfont * xf, gs_char chr, int encoding_index,
264 gs_glyph glyph, const gs_const_string *glyph_name)
265 {
266 const x_xfont *xxf = (x_xfont *) xf;
267
268 if (chr == gs_no_char)
269 return gx_no_xglyph; /* can't look up names yet */
270 if (encoding_index != xxf->encoding_index) {
271 if (encoding_index == 0 && xxf->encoding_index == 1)
272 chr = gs_map_std_to_iso[chr];
273 else if (encoding_index == 1 && xxf->encoding_index == 0)
274 chr = gs_map_iso_to_std[chr];
275 else
276 return gx_no_xglyph;
277 if (chr == 0)
278 return gx_no_xglyph;
279 }
280 if (chr < xxf->font->min_char_or_byte2 ||
281 chr > xxf->font->max_char_or_byte2)
282 return gx_no_xglyph;
283 if (xxf->font->per_char) {
284 int i = chr - xxf->font->min_char_or_byte2;
285 const XCharStruct *xc = &xxf->font->per_char[i];
286
287 if ((xc->lbearing == 0) && (xc->rbearing == 0) &&
288 (xc->ascent == 0) && (xc->descent == 0))
289 return gx_no_xglyph;
290 }
291 return (gx_xglyph) chr;
292 }
293
294 /* Get the metrics for a character. */
295 private int
x_char_metrics(gx_xfont * xf,gx_xglyph xg,int wmode,gs_point * pwidth,gs_int_rect * pbbox)296 x_char_metrics(gx_xfont * xf, gx_xglyph xg, int wmode,
297 gs_point * pwidth, gs_int_rect * pbbox)
298 {
299 const x_xfont *xxf = (const x_xfont *) xf;
300 int width;
301
302 if (wmode != 0)
303 return gs_error_undefined;
304 if (xxf->font->per_char == NULL) {
305 width = xxf->font->max_bounds.width;
306 pbbox->p.x = xxf->font->max_bounds.lbearing;
307 pbbox->q.x = xxf->font->max_bounds.rbearing;
308 pbbox->p.y = -xxf->font->max_bounds.ascent;
309 pbbox->q.y = xxf->font->max_bounds.descent;
310 } else {
311 int i = xg - xxf->font->min_char_or_byte2;
312 const XCharStruct *xc = &xxf->font->per_char[i];
313
314 width = xc->width;
315 pbbox->p.x = xc->lbearing;
316 pbbox->q.x = xc->rbearing;
317 pbbox->p.y = -xc->ascent;
318 pbbox->q.y = xc->descent;
319 }
320 switch (xxf->angle) {
321 case 0:
322 pwidth->x = width, pwidth->y = 0; break;
323 case 90:
324 pwidth->x = 0, pwidth->y = -xxf->My * width; break;
325 case 180:
326 pwidth->x = -width, pwidth->y = 0; break;
327 case 270:
328 pwidth->x = 0, pwidth->y = xxf->My * width; break;
329 }
330 return 0;
331 }
332
333 /* Render a character. */
334 private int
x_render_char(gx_xfont * xf,gx_xglyph xg,gx_device * dev,int xo,int yo,gx_color_index color,int required)335 x_render_char(gx_xfont * xf, gx_xglyph xg, gx_device * dev,
336 int xo, int yo, gx_color_index color, int required)
337 {
338 x_xfont *xxf = (x_xfont *) xf;
339 char chr = (char)xg;
340 gs_point wxy;
341 gs_int_rect bbox;
342 int x, y, w, h;
343 int code;
344
345 if (dev->dname == gs_x11_device.dname && !((gx_device_X *)dev)->is_buffered) {
346 gx_device_X *xdev = (gx_device_X *)dev;
347
348 code = (*xf->common.procs->char_metrics) (xf, xg, 0, &wxy, &bbox);
349 if (code < 0)
350 return code;
351 /* Buffer text for more efficient X interaction. */
352 if (xdev->text.item_count == MAX_TEXT_ITEMS ||
353 xdev->text.char_count == MAX_TEXT_CHARS ||
354 (IN_TEXT(xdev) &&
355 (yo != xdev->text.origin.y || color != xdev->fore_color ||
356 xxf->font->fid != xdev->fid))
357 ) {
358 DRAW_TEXT(xdev);
359 xdev->text.item_count = xdev->text.char_count = 0;
360 }
361 if (xdev->text.item_count == 0) {
362 X_SET_FILL_STYLE(xdev, FillSolid);
363 X_SET_FORE_COLOR(xdev, color);
364 X_SET_FUNCTION(xdev, GXcopy);
365 xdev->text.origin.x = xdev->text.x = xo;
366 xdev->text.origin.y = yo;
367 xdev->text.items[0].font = xdev->fid = xxf->font->fid;
368 }
369 /*
370 * The following is wrong for rotated text, but it doesn't matter,
371 * because the next call of x_render_char will have a different Y.
372 */
373 {
374 int index = xdev->text.item_count;
375 XTextItem *item = &xdev->text.items[index];
376 char *pchar = &xdev->text.chars[xdev->text.char_count++];
377 int delta = xo - xdev->text.x;
378
379 *pchar = chr;
380 if (index > 0 && delta == 0) {
381 /* Continue the same item. */
382 item[-1].nchars++;
383 } else {
384 /* Start a new item. */
385 item->chars = pchar;
386 item->nchars = 1;
387 item->delta = delta;
388 if (index > 0)
389 item->font = None;
390 xdev->text.item_count++;
391 }
392 xdev->text.x = xo + wxy.x;
393 }
394 if (xdev->bpixmap != (Pixmap) 0) {
395 x = xo + bbox.p.x;
396 y = yo + bbox.p.y;
397 w = bbox.q.x - bbox.p.x;
398 h = bbox.q.y - bbox.p.y;
399 fit_fill(dev, x, y, w, h);
400 x_update_add(xdev, x, y, w, h);
401 }
402 return 0;
403 } else if (!required)
404 return -1; /* too hard */
405 else {
406 /* Display on an intermediate bitmap, then copy the bits. */
407 gx_device_X *xdev = xxf->xdev;
408 int wbm, raster;
409 int i;
410 XImage *xim;
411 Pixmap xpm;
412 GC fgc;
413 byte *bits;
414
415 dev_proc_copy_mono((*copy_mono)) = dev_proc(dev, copy_mono);
416
417 code = (*xf->common.procs->char_metrics) (xf, xg, 0, &wxy, &bbox);
418 if (code < 0)
419 return code;
420 w = bbox.q.x - bbox.p.x;
421 h = bbox.q.y - bbox.p.y;
422 wbm = ROUND_UP(w, align_bitmap_mod * 8);
423 raster = wbm >> 3;
424 bits = (byte *) gs_malloc(xdev->memory, h, raster, "x_render_char");
425 if (bits == 0)
426 return gs_error_limitcheck;
427 xpm = XCreatePixmap(xdev->dpy, xdev->win, w, h, 1);
428 fgc = XCreateGC(xdev->dpy, xpm, None, NULL);
429 XSetForeground(xdev->dpy, fgc, 0);
430 XFillRectangle(xdev->dpy, xpm, fgc, 0, 0, w, h);
431 XSetForeground(xdev->dpy, fgc, 1);
432 XSetFont(xdev->dpy, fgc, xxf->font->fid);
433 XDrawString(xdev->dpy, xpm, fgc, -bbox.p.x, -bbox.p.y, &chr, 1);
434 xim = XGetImage(xdev->dpy, xpm, 0, 0, w, h, 1, ZPixmap);
435 i = 0;
436 for (y = 0; y < h; y++) {
437 char b = 0;
438
439 for (x = 0; x < wbm; x++) {
440 b = b << 1;
441 if (x < w)
442 b += XGetPixel(xim, x, y);
443 if ((x & 7) == 7)
444 bits[i++] = b;
445 }
446 }
447 code = (*copy_mono) (dev, bits, 0, raster, gx_no_bitmap_id,
448 xo + bbox.p.x, yo + bbox.p.y, w, h,
449 gx_no_color_index, color);
450 gs_free(xdev->memory, (char *)bits, h, raster, "x_render_char");
451 XFreePixmap(xdev->dpy, xpm);
452 XFreeGC(xdev->dpy, fgc);
453 XDestroyImage(xim);
454 return (code < 0 ? code : 0);
455 }
456 }
457
458 /* Release an xfont. */
459 private int
x_release(gx_xfont * xf,gs_memory_t * mem)460 x_release(gx_xfont * xf, gs_memory_t * mem)
461 {
462 #if 0
463 /* The device may not be open. Cannot reliably free the font. */
464 x_xfont *xxf = (x_xfont *) xf;
465
466 XFreeFont(xxf->xdev->dpy, xxf->font);
467 #endif
468 if (mem != NULL)
469 gs_free_object(mem, xf, "x_release");
470 return 0;
471 }
472