Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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 *
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 *
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 *
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 *
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
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
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
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
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
}