1
/* Copyright (C) 2001-2006 Artifex Software, Inc.
4
This software is provided AS-IS with no warranty, either express or
7
This software is distributed under license and may not be copied, modified
8
or distributed except as expressly authorized under the terms of that
9
license. Refer to licensing information at http://www.artifex.com/
10
or contact Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134,
11
San Rafael, CA 94903, U.S.A., +1(415)492-9861, for further information.
14
/* $Id: gdevxxf.c 8250 2007-09-25 13:31:24Z giles $ */
15
/* External font (xfont) implementation for X11. */
27
/* Define the smallest point size that we trust X to render reasonably well. */
28
#define min_X_font_size 6
29
/* Define the largest point size where X will do a better job than we can. */
30
#define max_X_font_size 35
32
extern gx_device_X gs_x11_device;
34
extern const byte gs_map_std_to_iso[256];
35
extern const byte gs_map_iso_to_std[256];
37
/* Declare the xfont procedures */
38
static xfont_proc_lookup_font(x_lookup_font);
39
static xfont_proc_char_xglyph(x_char_xglyph);
40
static xfont_proc_char_metrics(x_char_metrics);
41
static xfont_proc_render_char(x_render_char);
42
static xfont_proc_release(x_release);
43
static const gx_xfont_procs x_xfont_procs =
52
/* Return the xfont procedure record. */
53
const gx_xfont_procs *
54
gdev_x_get_xfont_procs(gx_device * dev)
56
return &x_xfont_procs;
59
/* Define a X11 xfont. */
60
typedef struct x_xfont_s x_xfont;
62
gx_xfont_common common;
70
gs_private_st_dev_ptrs1(st_x_xfont, x_xfont, "x_xfont",
71
x_xfont_enum_ptrs, x_xfont_reloc_ptrs, xdev);
73
/* ---------------- Utilities ---------------- */
75
/* Search one set of font maps for a font with a given name. */
77
find_fontmap(x11fontmap *fmps, const byte *fname, uint len)
79
x11fontmap *fmp = fmps;
82
if (len == strlen(fmp->ps_name) &&
83
strncmp(fmp->ps_name, (const char *)fname, len) == 0)
90
/* Find an X font with a given name, encoding, and size. */
92
find_x_font(gx_device_X *xdev, char x11template[256], x11fontmap *fmp,
93
const char *encoding_name, x11fontlist *fls, int xheight,
97
char *x11fontname = 0;
98
int len1 = strlen(fmp->x11_name) + 1;
100
if (fls->count == -1) {
101
sprintf(x11template, "%s-*-*-*-*-*-*-%s", fmp->x11_name,
103
fls->names = XListFonts(xdev->dpy, x11template, 32, &fls->count);
105
*scalable_font = false;
106
for (i = 0; i < fls->count; i++) {
107
const char *szp = fls->names[i] + len1;
110
while (*szp >= '0' && *szp <= '9')
111
size = size * 10 + *szp++ - '0';
113
*scalable_font = true;
117
return fls->names[i];
119
if (*scalable_font && xdev->useScalableFonts) {
120
sprintf(x11template, "%s-%d-0-0-0-*-0-%s", fmp->x11_name,
121
xheight, encoding_name);
122
x11fontname = x11template;
127
/* ---------------- xfont procedures ---------------- */
129
/* Look up a font. */
131
x_lookup_font(gx_device * dev, const byte * fname, uint len,
132
int encoding_index, const gs_uid * puid, const gs_matrix * pmat,
135
gx_device_X *xdev = (gx_device_X *) dev;
137
char x11template[256];
138
char *x11fontname = NULL;
139
XFontStruct *x11font;
142
int xwidth, xheight, angle;
146
if (!xdev->useXFonts)
149
if (pmat->xy == 0 && pmat->yx == 0) {
150
xwidth = fabs(pmat->xx * 1000) + 0.5;
151
xheight = fabs(pmat->yy * 1000) + 0.5;
152
height = fabs(pmat->yy * 1000);
153
angle = (pmat->xx > 0 ? 0 : 180);
154
My = (pmat->xx > 0 && pmat->yy > 0) || (pmat->xx < 0 && pmat->yy < 0);
155
} else if (pmat->xx == 0 && pmat->yy == 0) {
156
xwidth = fabs(pmat->xy * 1000) + 0.5;
157
xheight = fabs(pmat->yx * 1000) + 0.5;
158
height = fabs(pmat->yx * 1000);
159
angle = (pmat->yx < 0 ? 90 : 270);
160
My = (pmat->yx > 0 && pmat->xy < 0) || (pmat->yx < 0 && pmat->xy > 0);
165
/* Don't do very small fonts, where font metrics are way off */
166
/* due to rounding and the server does a very bad job of scaling, */
167
/* or very large fonts, where we can do just as good a job and */
168
/* the server may lock up the entire window system while rasterizing */
169
/* the whole font. */
170
if (xwidth < min_X_font_size || xwidth > max_X_font_size ||
171
xheight < min_X_font_size || xheight > max_X_font_size
175
if (!xdev->useFontExtensions && (My || angle != 0))
178
switch (encoding_index) {
180
fmp = find_fontmap(xdev->regular_fonts, fname, len);
184
find_x_font(xdev, x11template, fmp, "Adobe-fontspecific",
185
&fmp->std, xheight, &scalable_font);
188
find_x_font(xdev, x11template, fmp, "ISO8859-1",
189
&fmp->iso, xheight, &scalable_font);
194
fmp = find_fontmap(xdev->regular_fonts, fname, len);
198
find_x_font(xdev, x11template, fmp, "ISO8859-1",
199
&fmp->iso, xheight, &scalable_font);
202
find_x_font(xdev, x11template, fmp, "Adobe-fontspecific",
203
&fmp->std, xheight, &scalable_font);
208
fmp = xdev->symbol_fonts;
211
fmp = xdev->dingbat_fonts;
212
sym: fmp = find_fontmap(fmp, fname, len);
216
find_x_font(xdev, x11template, fmp, "Adobe-fontspecific",
217
&fmp->std, xheight, &scalable_font);
224
if (xwidth != xheight || angle != 0 || My) {
225
if (!xdev->useScalableFonts || !scalable_font)
227
sprintf(x11template, "%s%s+%d-%d+%d-0-0-0-*-0-%s",
228
fmp->x11_name, (My ? "+My" : ""),
229
angle * 64, xheight, xwidth,
230
(encoding_index == 1 ? "ISO8859-1" : "Adobe-fontspecific"));
231
x11fontname = x11template;
233
x11font = XLoadQueryFont(xdev->dpy, x11fontname);
236
/* Don't bother with 16-bit or 2 byte fonts yet */
237
if (x11font->min_byte1 || x11font->max_byte1) {
238
XFreeFont(xdev->dpy, x11font);
241
xxf = gs_alloc_struct(mem, x_xfont, &st_x_xfont, "x_lookup_font");
244
xxf->common.procs = &x_xfont_procs;
247
xxf->encoding_index = encoding_index;
248
xxf->My = (My ? -1 : 1);
250
if (xdev->logXFonts) {
251
dprintf3("Using %s\n for %s at %g pixels.\n", x11fontname,
252
fmp->ps_name, height);
255
return (gx_xfont *) xxf;
258
/* Convert a character name or index to an xglyph code. */
260
x_char_xglyph(gx_xfont * xf, gs_char chr, int encoding_index,
261
gs_glyph glyph, const gs_const_string *glyph_name)
263
const x_xfont *xxf = (x_xfont *) xf;
265
if (chr == gs_no_char)
266
return gx_no_xglyph; /* can't look up names yet */
267
if (encoding_index != xxf->encoding_index) {
268
if (encoding_index == 0 && xxf->encoding_index == 1)
269
chr = gs_map_std_to_iso[chr];
270
else if (encoding_index == 1 && xxf->encoding_index == 0)
271
chr = gs_map_iso_to_std[chr];
277
if (chr < xxf->font->min_char_or_byte2 ||
278
chr > xxf->font->max_char_or_byte2)
280
if (xxf->font->per_char) {
281
int i = chr - xxf->font->min_char_or_byte2;
282
const XCharStruct *xc = &xxf->font->per_char[i];
284
if ((xc->lbearing == 0) && (xc->rbearing == 0) &&
285
(xc->ascent == 0) && (xc->descent == 0))
288
return (gx_xglyph) chr;
291
/* Get the metrics for a character. */
293
x_char_metrics(gx_xfont * xf, gx_xglyph xg, int wmode,
294
gs_point * pwidth, gs_int_rect * pbbox)
296
const x_xfont *xxf = (const x_xfont *) xf;
300
return gs_error_undefined;
301
if (xxf->font->per_char == NULL) {
302
width = xxf->font->max_bounds.width;
303
pbbox->p.x = xxf->font->max_bounds.lbearing;
304
pbbox->q.x = xxf->font->max_bounds.rbearing;
305
pbbox->p.y = -xxf->font->max_bounds.ascent;
306
pbbox->q.y = xxf->font->max_bounds.descent;
308
int i = xg - xxf->font->min_char_or_byte2;
309
const XCharStruct *xc = &xxf->font->per_char[i];
312
pbbox->p.x = xc->lbearing;
313
pbbox->q.x = xc->rbearing;
314
pbbox->p.y = -xc->ascent;
315
pbbox->q.y = xc->descent;
317
switch (xxf->angle) {
319
pwidth->x = width, pwidth->y = 0; break;
321
pwidth->x = 0, pwidth->y = -xxf->My * width; break;
323
pwidth->x = -width, pwidth->y = 0; break;
325
pwidth->x = 0, pwidth->y = xxf->My * width; break;
330
/* Render a character. */
332
x_render_char(gx_xfont * xf, gx_xglyph xg, gx_device * dev,
333
int xo, int yo, gx_color_index color, int required)
335
x_xfont *xxf = (x_xfont *) xf;
342
if (dev->dname == gs_x11_device.dname && !((gx_device_X *)dev)->is_buffered) {
343
gx_device_X *xdev = (gx_device_X *)dev;
345
code = (*xf->common.procs->char_metrics) (xf, xg, 0, &wxy, &bbox);
348
/* Buffer text for more efficient X interaction. */
349
if (xdev->text.item_count == MAX_TEXT_ITEMS ||
350
xdev->text.char_count == MAX_TEXT_CHARS ||
352
(yo != xdev->text.origin.y || color != xdev->fore_color ||
353
xxf->font->fid != xdev->fid))
356
xdev->text.item_count = xdev->text.char_count = 0;
358
if (xdev->text.item_count == 0) {
359
X_SET_FILL_STYLE(xdev, FillSolid);
360
X_SET_FORE_COLOR(xdev, color);
361
X_SET_FUNCTION(xdev, GXcopy);
362
xdev->text.origin.x = xdev->text.x = xo;
363
xdev->text.origin.y = yo;
364
xdev->text.items[0].font = xdev->fid = xxf->font->fid;
367
* The following is wrong for rotated text, but it doesn't matter,
368
* because the next call of x_render_char will have a different Y.
371
int index = xdev->text.item_count;
372
XTextItem *item = &xdev->text.items[index];
373
char *pchar = &xdev->text.chars[xdev->text.char_count++];
374
int delta = xo - xdev->text.x;
377
if (index > 0 && delta == 0) {
378
/* Continue the same item. */
381
/* Start a new item. */
387
xdev->text.item_count++;
389
xdev->text.x = xo + wxy.x;
391
if (xdev->bpixmap != (Pixmap) 0) {
394
w = bbox.q.x - bbox.p.x;
395
h = bbox.q.y - bbox.p.y;
396
fit_fill(dev, x, y, w, h);
397
x_update_add(xdev, x, y, w, h);
400
} else if (!required)
401
return -1; /* too hard */
403
/* Display on an intermediate bitmap, then copy the bits. */
404
gx_device_X *xdev = xxf->xdev;
412
dev_proc_copy_mono((*copy_mono)) = dev_proc(dev, copy_mono);
414
code = (*xf->common.procs->char_metrics) (xf, xg, 0, &wxy, &bbox);
417
w = bbox.q.x - bbox.p.x;
418
h = bbox.q.y - bbox.p.y;
419
wbm = ROUND_UP(w, align_bitmap_mod * 8);
421
bits = (byte *) gs_malloc(xdev->memory, h, raster, "x_render_char");
423
return gs_error_limitcheck;
424
xpm = XCreatePixmap(xdev->dpy, xdev->win, w, h, 1);
425
fgc = XCreateGC(xdev->dpy, xpm, None, NULL);
426
XSetForeground(xdev->dpy, fgc, 0);
427
XFillRectangle(xdev->dpy, xpm, fgc, 0, 0, w, h);
428
XSetForeground(xdev->dpy, fgc, 1);
429
XSetFont(xdev->dpy, fgc, xxf->font->fid);
430
XDrawString(xdev->dpy, xpm, fgc, -bbox.p.x, -bbox.p.y, &chr, 1);
431
xim = XGetImage(xdev->dpy, xpm, 0, 0, w, h, 1, ZPixmap);
433
for (y = 0; y < h; y++) {
436
for (x = 0; x < wbm; x++) {
439
b += XGetPixel(xim, x, y);
444
code = (*copy_mono) (dev, bits, 0, raster, gx_no_bitmap_id,
445
xo + bbox.p.x, yo + bbox.p.y, w, h,
446
gx_no_color_index, color);
447
gs_free(xdev->memory, (char *)bits, h, raster, "x_render_char");
448
XFreePixmap(xdev->dpy, xpm);
449
XFreeGC(xdev->dpy, fgc);
451
return (code < 0 ? code : 0);
455
/* Release an xfont. */
457
x_release(gx_xfont * xf, gs_memory_t * mem)
460
/* The device may not be open. Cannot reliably free the font. */
461
x_xfont *xxf = (x_xfont *) xf;
463
XFreeFont(xxf->xdev->dpy, xxf->font);
466
gs_free_object(mem, xf, "x_release");