diff options
Diffstat (limited to 'gs/base/gdevxxf.c')
-rw-r--r-- | gs/base/gdevxxf.c | 468 |
1 files changed, 468 insertions, 0 deletions
diff --git a/gs/base/gdevxxf.c b/gs/base/gdevxxf.c new file mode 100644 index 000000000..7f002ca76 --- /dev/null +++ b/gs/base/gdevxxf.c @@ -0,0 +1,468 @@ +/* Copyright (C) 2001-2006 Artifex Software, Inc. + All Rights Reserved. + + This software is provided AS-IS with no warranty, either express or + implied. + + This software is distributed under license and may not be copied, modified + or distributed except as expressly authorized under the terms of that + license. Refer to licensing information at http://www.artifex.com/ + or contact Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134, + San Rafael, CA 94903, U.S.A., +1(415)492-9861, for further information. +*/ + +/* $Id$ */ +/* External font (xfont) implementation for X11. */ +#include "math_.h" +#include "memory_.h" +#include "x_.h" +#include "gx.h" +#include "gxdevice.h" +#include "gdevx.h" +#include "gsstruct.h" +#include "gsutil.h" +#include "gserrors.h" +#include "gxxfont.h" + +/* Define the smallest point size that we trust X to render reasonably well. */ +#define min_X_font_size 6 +/* Define the largest point size where X will do a better job than we can. */ +#define max_X_font_size 35 + +extern gx_device_X gs_x11_device; + +extern const byte gs_map_std_to_iso[256]; +extern const byte gs_map_iso_to_std[256]; + +/* Declare the xfont procedures */ +static xfont_proc_lookup_font(x_lookup_font); +static xfont_proc_char_xglyph(x_char_xglyph); +static xfont_proc_char_metrics(x_char_metrics); +static xfont_proc_render_char(x_render_char); +static xfont_proc_release(x_release); +static const gx_xfont_procs x_xfont_procs = +{ + x_lookup_font, + x_char_xglyph, + x_char_metrics, + x_render_char, + x_release +}; + +/* Return the xfont procedure record. */ +const gx_xfont_procs * +gdev_x_get_xfont_procs(gx_device * dev) +{ + return &x_xfont_procs; +} + +/* Define a X11 xfont. */ +typedef struct x_xfont_s x_xfont; +struct x_xfont_s { + gx_xfont_common common; + gx_device_X *xdev; + XFontStruct *font; + int encoding_index; + int My; + int angle; +}; + +gs_private_st_dev_ptrs1(st_x_xfont, x_xfont, "x_xfont", + x_xfont_enum_ptrs, x_xfont_reloc_ptrs, xdev); + +/* ---------------- Utilities ---------------- */ + +/* Search one set of font maps for a font with a given name. */ +static x11fontmap * +find_fontmap(x11fontmap *fmps, const byte *fname, uint len) +{ + x11fontmap *fmp = fmps; + + while (fmp) { + if (len == strlen(fmp->ps_name) && + strncmp(fmp->ps_name, (const char *)fname, len) == 0) + break; + fmp = fmp->next; + } + return fmp; +} + +/* Find an X font with a given name, encoding, and size. */ +static char * +find_x_font(gx_device_X *xdev, char x11template[256], x11fontmap *fmp, + const char *encoding_name, x11fontlist *fls, int xheight, + bool *scalable_font) +{ + int i; + char *x11fontname = 0; + int len1 = strlen(fmp->x11_name) + 1; + + if (fls->count == -1) { + sprintf(x11template, "%s-*-*-*-*-*-*-%s", fmp->x11_name, + encoding_name); + fls->names = XListFonts(xdev->dpy, x11template, 32, &fls->count); + } + *scalable_font = false; + for (i = 0; i < fls->count; i++) { + const char *szp = fls->names[i] + len1; + int size = 0; + + while (*szp >= '0' && *szp <= '9') + size = size * 10 + *szp++ - '0'; + if (size == 0) { + *scalable_font = true; + continue; + } + if (size == xheight) + return fls->names[i]; + } + if (*scalable_font && xdev->useScalableFonts) { + sprintf(x11template, "%s-%d-0-0-0-*-0-%s", fmp->x11_name, + xheight, encoding_name); + x11fontname = x11template; + } + return x11fontname; +} + +/* ---------------- xfont procedures ---------------- */ + +/* Look up a font. */ +static 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) +{ + gx_device_X *xdev = (gx_device_X *) dev; + x_xfont *xxf; + char x11template[256]; + char *x11fontname = NULL; + XFontStruct *x11font; + x11fontmap *fmp; + double height; + int xwidth, xheight, angle; + Boolean My; + bool scalable_font; + + if (!xdev->useXFonts) + return NULL; + + if (pmat->xy == 0 && pmat->yx == 0) { + xwidth = fabs(pmat->xx * 1000) + 0.5; + xheight = fabs(pmat->yy * 1000) + 0.5; + height = fabs(pmat->yy * 1000); + angle = (pmat->xx > 0 ? 0 : 180); + My = (pmat->xx > 0 && pmat->yy > 0) || (pmat->xx < 0 && pmat->yy < 0); + } else if (pmat->xx == 0 && pmat->yy == 0) { + xwidth = fabs(pmat->xy * 1000) + 0.5; + xheight = fabs(pmat->yx * 1000) + 0.5; + height = fabs(pmat->yx * 1000); + angle = (pmat->yx < 0 ? 90 : 270); + My = (pmat->yx > 0 && pmat->xy < 0) || (pmat->yx < 0 && pmat->xy > 0); + } else { + return NULL; + } + + /* Don't do very small fonts, where font metrics are way off */ + /* due to rounding and the server does a very bad job of scaling, */ + /* or very large fonts, where we can do just as good a job and */ + /* the server may lock up the entire window system while rasterizing */ + /* the whole font. */ + if (xwidth < min_X_font_size || xwidth > max_X_font_size || + xheight < min_X_font_size || xheight > max_X_font_size + ) + return NULL; + + if (!xdev->useFontExtensions && (My || angle != 0)) + return NULL; + + switch (encoding_index) { + case 0: + fmp = find_fontmap(xdev->regular_fonts, fname, len); + if (fmp == NULL) + return NULL; + x11fontname = + find_x_font(xdev, x11template, fmp, "Adobe-fontspecific", + &fmp->std, xheight, &scalable_font); + if (!x11fontname) { + x11fontname = + find_x_font(xdev, x11template, fmp, "ISO8859-1", + &fmp->iso, xheight, &scalable_font); + encoding_index = 1; + } + break; + case 1: + fmp = find_fontmap(xdev->regular_fonts, fname, len); + if (fmp == NULL) + return NULL; + x11fontname = + find_x_font(xdev, x11template, fmp, "ISO8859-1", + &fmp->iso, xheight, &scalable_font); + if (!x11fontname) { + x11fontname = + find_x_font(xdev, x11template, fmp, "Adobe-fontspecific", + &fmp->std, xheight, &scalable_font); + encoding_index = 0; + } + break; + case 2: + fmp = xdev->symbol_fonts; + goto sym; + case 3: + fmp = xdev->dingbat_fonts; +sym: fmp = find_fontmap(fmp, fname, len); + if (fmp == NULL) + return NULL; + x11fontname = + find_x_font(xdev, x11template, fmp, "Adobe-fontspecific", + &fmp->std, xheight, &scalable_font); + default: + return NULL; + } + if (!x11fontname) + return NULL; + + if (xwidth != xheight || angle != 0 || My) { + if (!xdev->useScalableFonts || !scalable_font) + return NULL; + sprintf(x11template, "%s%s+%d-%d+%d-0-0-0-*-0-%s", + fmp->x11_name, (My ? "+My" : ""), + angle * 64, xheight, xwidth, + (encoding_index == 1 ? "ISO8859-1" : "Adobe-fontspecific")); + x11fontname = x11template; + } + x11font = XLoadQueryFont(xdev->dpy, x11fontname); + if (x11font == NULL) + return NULL; + /* Don't bother with 16-bit or 2 byte fonts yet */ + if (x11font->min_byte1 || x11font->max_byte1) { + XFreeFont(xdev->dpy, x11font); + return NULL; + } + xxf = gs_alloc_struct(mem, x_xfont, &st_x_xfont, "x_lookup_font"); + if (xxf == NULL) + return NULL; + xxf->common.procs = &x_xfont_procs; + xxf->xdev = xdev; + xxf->font = x11font; + xxf->encoding_index = encoding_index; + xxf->My = (My ? -1 : 1); + xxf->angle = angle; + if (xdev->logXFonts) { + dprintf3("Using %s\n for %s at %g pixels.\n", x11fontname, + fmp->ps_name, height); + dflush(); + } + return (gx_xfont *) xxf; +} + +/* Convert a character name or index to an xglyph code. */ +static gx_xglyph +x_char_xglyph(gx_xfont * xf, gs_char chr, int encoding_index, + gs_glyph glyph, const gs_const_string *glyph_name) +{ + const x_xfont *xxf = (x_xfont *) xf; + + if (chr == gs_no_char) + return gx_no_xglyph; /* can't look up names yet */ + if (encoding_index != xxf->encoding_index) { + if (encoding_index == 0 && xxf->encoding_index == 1) + chr = gs_map_std_to_iso[chr]; + else if (encoding_index == 1 && xxf->encoding_index == 0) + chr = gs_map_iso_to_std[chr]; + else + return gx_no_xglyph; + if (chr == 0) + return gx_no_xglyph; + } + if (chr < xxf->font->min_char_or_byte2 || + chr > xxf->font->max_char_or_byte2) + return gx_no_xglyph; + if (xxf->font->per_char) { + int i = chr - xxf->font->min_char_or_byte2; + const XCharStruct *xc = &xxf->font->per_char[i]; + + if ((xc->lbearing == 0) && (xc->rbearing == 0) && + (xc->ascent == 0) && (xc->descent == 0)) + return gx_no_xglyph; + } + return (gx_xglyph) chr; +} + +/* Get the metrics for a character. */ +static int +x_char_metrics(gx_xfont * xf, gx_xglyph xg, int wmode, + gs_point * pwidth, gs_int_rect * pbbox) +{ + const x_xfont *xxf = (const x_xfont *) xf; + int width; + + if (wmode != 0) + return gs_error_undefined; + if (xxf->font->per_char == NULL) { + width = xxf->font->max_bounds.width; + pbbox->p.x = xxf->font->max_bounds.lbearing; + pbbox->q.x = xxf->font->max_bounds.rbearing; + pbbox->p.y = -xxf->font->max_bounds.ascent; + pbbox->q.y = xxf->font->max_bounds.descent; + } else { + int i = xg - xxf->font->min_char_or_byte2; + const XCharStruct *xc = &xxf->font->per_char[i]; + + width = xc->width; + pbbox->p.x = xc->lbearing; + pbbox->q.x = xc->rbearing; + pbbox->p.y = -xc->ascent; + pbbox->q.y = xc->descent; + } + switch (xxf->angle) { + case 0: + pwidth->x = width, pwidth->y = 0; break; + case 90: + pwidth->x = 0, pwidth->y = -xxf->My * width; break; + case 180: + pwidth->x = -width, pwidth->y = 0; break; + case 270: + pwidth->x = 0, pwidth->y = xxf->My * width; break; + } + return 0; +} + +/* Render a character. */ +static int +x_render_char(gx_xfont * xf, gx_xglyph xg, gx_device * dev, + int xo, int yo, gx_color_index color, int required) +{ + x_xfont *xxf = (x_xfont *) xf; + char chr = (char)xg; + gs_point wxy; + gs_int_rect bbox; + int x, y, w, h; + int code; + + if (dev->dname == gs_x11_device.dname && !((gx_device_X *)dev)->is_buffered) { + gx_device_X *xdev = (gx_device_X *)dev; + + code = (*xf->common.procs->char_metrics) (xf, xg, 0, &wxy, &bbox); + if (code < 0) + return code; + /* Buffer text for more efficient X interaction. */ + if (xdev->text.item_count == MAX_TEXT_ITEMS || + xdev->text.char_count == MAX_TEXT_CHARS || + (IN_TEXT(xdev) && + (yo != xdev->text.origin.y || color != xdev->fore_color || + xxf->font->fid != xdev->fid)) + ) { + DRAW_TEXT(xdev); + xdev->text.item_count = xdev->text.char_count = 0; + } + if (xdev->text.item_count == 0) { + X_SET_FILL_STYLE(xdev, FillSolid); + X_SET_FORE_COLOR(xdev, color); + X_SET_FUNCTION(xdev, GXcopy); + xdev->text.origin.x = xdev->text.x = xo; + xdev->text.origin.y = yo; + xdev->text.items[0].font = xdev->fid = xxf->font->fid; + } + /* + * The following is wrong for rotated text, but it doesn't matter, + * because the next call of x_render_char will have a different Y. + */ + { + int index = xdev->text.item_count; + XTextItem *item = &xdev->text.items[index]; + char *pchar = &xdev->text.chars[xdev->text.char_count++]; + int delta = xo - xdev->text.x; + + *pchar = chr; + if (index > 0 && delta == 0) { + /* Continue the same item. */ + item[-1].nchars++; + } else { + /* Start a new item. */ + item->chars = pchar; + item->nchars = 1; + item->delta = delta; + if (index > 0) + item->font = None; + xdev->text.item_count++; + } + xdev->text.x = xo + wxy.x; + } + if (xdev->bpixmap != (Pixmap) 0) { + x = xo + bbox.p.x; + y = yo + bbox.p.y; + w = bbox.q.x - bbox.p.x; + h = bbox.q.y - bbox.p.y; + fit_fill(dev, x, y, w, h); + x_update_add(xdev, x, y, w, h); + } + return 0; + } else if (!required) + return -1; /* too hard */ + else { + /* Display on an intermediate bitmap, then copy the bits. */ + gx_device_X *xdev = xxf->xdev; + int wbm, raster; + int i; + XImage *xim; + Pixmap xpm; + GC fgc; + byte *bits; + + dev_proc_copy_mono((*copy_mono)) = dev_proc(dev, copy_mono); + + code = (*xf->common.procs->char_metrics) (xf, xg, 0, &wxy, &bbox); + if (code < 0) + return code; + w = bbox.q.x - bbox.p.x; + h = bbox.q.y - bbox.p.y; + wbm = ROUND_UP(w, align_bitmap_mod * 8); + raster = wbm >> 3; + bits = (byte *) gs_malloc(xdev->memory, h, raster, "x_render_char"); + if (bits == 0) + return gs_error_limitcheck; + xpm = XCreatePixmap(xdev->dpy, xdev->win, w, h, 1); + fgc = XCreateGC(xdev->dpy, xpm, None, NULL); + XSetForeground(xdev->dpy, fgc, 0); + XFillRectangle(xdev->dpy, xpm, fgc, 0, 0, w, h); + XSetForeground(xdev->dpy, fgc, 1); + XSetFont(xdev->dpy, fgc, xxf->font->fid); + XDrawString(xdev->dpy, xpm, fgc, -bbox.p.x, -bbox.p.y, &chr, 1); + xim = XGetImage(xdev->dpy, xpm, 0, 0, w, h, 1, ZPixmap); + i = 0; + for (y = 0; y < h; y++) { + char b = 0; + + for (x = 0; x < wbm; x++) { + b = b << 1; + if (x < w) + b += XGetPixel(xim, x, y); + if ((x & 7) == 7) + bits[i++] = b; + } + } + code = (*copy_mono) (dev, bits, 0, raster, gx_no_bitmap_id, + xo + bbox.p.x, yo + bbox.p.y, w, h, + gx_no_color_index, color); + gs_free(xdev->memory, (char *)bits, h, raster, "x_render_char"); + XFreePixmap(xdev->dpy, xpm); + XFreeGC(xdev->dpy, fgc); + XDestroyImage(xim); + return (code < 0 ? code : 0); + } +} + +/* Release an xfont. */ +static int +x_release(gx_xfont * xf, gs_memory_t * mem) +{ +#if 0 + /* The device may not be open. Cannot reliably free the font. */ + x_xfont *xxf = (x_xfont *) xf; + + XFreeFont(xxf->xdev->dpy, xxf->font); +#endif + if (mem != NULL) + gs_free_object(mem, xf, "x_release"); + return 0; +} |