diff options
Diffstat (limited to 'devices/gdevmsxf.c')
-rw-r--r-- | devices/gdevmsxf.c | 464 |
1 files changed, 464 insertions, 0 deletions
diff --git a/devices/gdevmsxf.c b/devices/gdevmsxf.c new file mode 100644 index 000000000..baebc302a --- /dev/null +++ b/devices/gdevmsxf.c @@ -0,0 +1,464 @@ +/* Copyright (C) 2001-2012 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 the license contained in the file LICENSE in this distribution. + + 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. +*/ + +/* External font (xfont) implementation for Microsoft Windows. */ +#include "ctype_.h" +#include "math_.h" +#include "memory_.h" +#include "string_.h" +#include "gdevmswn.h" +#include "gsutil.h" +#include "gxxfont.h" +#include "gsstruct.h" + +/* Imported from gdevemap.c */ +extern const byte gs_map_std_to_iso[256]; + +/* Declare the xfont procedures */ +static xfont_proc_lookup_font(win_lookup_font); +static xfont_proc_char_xglyph(win_char_xglyph); +static xfont_proc_char_metrics(win_char_metrics); +static xfont_proc_render_char(win_render_char); +static xfont_proc_release(win_release); +static const gx_xfont_procs win_xfont_procs = +{ + win_lookup_font, + win_char_xglyph, + win_char_metrics, + win_render_char, + win_release +}; + +/* Return the xfont procedure record. */ +const gx_xfont_procs * +win_get_xfont_procs(gx_device * dev) +{ + return &win_xfont_procs; +} + +/* Define a Windows xfont. */ +typedef struct win_xfont_s win_xfont; +struct win_xfont_s { + gx_xfont_common common; + LOGFONT lf; + TEXTMETRIC tm; + HFONT hFont; + gx_device_win *dev; /* for GetDC */ + int invert_y; + int y_offset; +}; + +gs_private_st_dev_ptrs1(st_win_xfont, win_xfont, "win_xfont", + win_xfont_enum_ptrs, win_xfont_reloc_ptrs, dev); +#define wxf ((win_xfont *)xf) + +/* Forward references */ +static HDC near win_get_dc(gx_device_win *); +static void near win_release_dc(gx_device_win *, HDC); +static int win_select_font(HDC, win_xfont *); + +/* Map from PostScript to Windows character codes. */ +/* (These tables were generated by winmaps.ps.) */ + +static const byte far_data gs_map_symbol_to_oem[256] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 32, 33, 0, 35, 0, 37, 38, 0, 40, 41, 0, 43, 44, 0, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 0, 0, 0, 0, 0, 0, 231, 225, 0, 0, 0, 0, 0, 0, 0, 0, + 226, 232, 0, 227, 0, 0, 0, 233, 0, 0, 0, 91, 0, 93, 0, 95, + 0, 223, 224, 0, 234, 0, 236, 0, 0, 0, 0, 0, 0, 229, 0, 0, + 0, 0, 0, 228, 230, 0, 0, 0, 0, 0, 0, 123, 124, 125, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 242, 0, 235, 0, 5, 4, 3, 6, 29, 27, 24, 26, 25, + 247, 240, 0, 241, 0, 0, 0, 7, 245, 0, 239, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 238, 0, 0, 0, 0, 0, 0, 237, 0, + 0, 0, 0, 0, 0, 0, 250, 248, 169, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 243, 0, 244, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +static const byte far_data gs_map_iso_to_oem[256] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 0, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, + 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, +112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 32, 172, 154, 155, 0, 156, 0, 21, 0, 0, 165, 173, 169, 45, 0, 0, + 247, 240, 252, 0, 0, 229, 20, 249, 0, 0, 166, 174, 171, 170, 0, 167, + 0, 0, 0, 0, 141, 142, 145, 128, 0, 143, 0, 0, 0, 0, 0, 0, + 0, 164, 0, 0, 0, 0, 152, 0, 0, 0, 0, 0, 153, 0, 0, 0, + 133, 159, 131, 0, 132, 134, 144, 135, 138, 130, 136, 137, 140, 160, 0, 139, + 0, 163, 148, 161, 146, 0, 147, 245, 0, 150, 162, 149, 129, 0, 0, 151 +}; + +/* Correlate PostScript font names with Windows font names. */ +/* This table should be an external resource, like Fontmap, */ +/* but that will have to wait till later. */ + +typedef struct font_entry_s { + const char *key; + const char *value; + uint pitchAndFamily; +} font_entry; + +static const font_entry font_names[] = +{ + {"Courier", "Courier New", FIXED_PITCH | FF_MODERN}, + {"Helvetica", "Arial", VARIABLE_PITCH | FF_SWISS}, + {"Helvetica", "Helv", VARIABLE_PITCH | FF_SWISS}, + {"Times", "Times New Roman", VARIABLE_PITCH | FF_ROMAN}, + {"Times", "Tms Rmn", VARIABLE_PITCH | FF_ROMAN} +}; + +/* Look up a font. */ +static int /*bool */ map_logical_font(HDC, win_xfont *); +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) +{ + win_xfont f; + win_xfont *wf; + uint name_len = min(len, LF_FACESIZE - 1); + const font_entry *pfe; + HDC hdc; + + /* Only handle simple cases for now. */ + if (pmat->xy != 0 || pmat->yx != 0 || pmat->xx <= 0 || + fabs(fabs(pmat->yy) - pmat->xx) > 0.00002 + ) + return NULL; + f.lf.lfHeight = (long)(pmat->xx * 1000); + /* Don't trust Windows with very small sizes. */ + if (f.lf.lfHeight < 6 || f.lf.lfHeight >= 36) + return NULL; + f.lf.lfWidth = 0; + f.lf.lfEscapement = 0; + f.lf.lfOrientation = 0; + f.lf.lfWeight = + (string_match(fname, len, "*Bold*", 6, NULL) ? + FW_BOLD : FW_REGULAR); + f.lf.lfItalic = + string_match(fname, len, "*Italic*", 8, NULL) || + string_match(fname, len, "*Oblique*", 9, NULL); + f.lf.lfUnderline = 0; + f.lf.lfStrikeOut = 0; + f.lf.lfCharSet = + (encoding_index == 2 ? SYMBOL_CHARSET : ANSI_CHARSET); + f.lf.lfOutPrecision = OUT_CHARACTER_PRECIS; + f.lf.lfClipPrecision = CLIP_STROKE_PRECIS; + f.lf.lfQuality = PROOF_QUALITY; + f.hFont = 0; + f.invert_y = pmat->yy >= 0; + hdc = win_get_dc(wdev); + if (hdc == NULL) + return NULL; + for (pfe = font_names; pfe != &font_names[countof(font_names)]; pfe++) + if (!strncmp(pfe->key, fname, strlen(pfe->key))) { /* Found a match. */ + strcpy(f.lf.lfFaceName, pfe->value); + f.lf.lfPitchAndFamily = pfe->pitchAndFamily; + if (map_logical_font(hdc, &f)) + break; + } + if (f.hFont == 0) { /* No matches in the table, try with the given name. */ + uint len; + + memcpy(f.lf.lfFaceName, fname, name_len); /* default */ + for (len = 0; len < name_len; len++) + if (!isalnum(fname[len])) + break; + f.lf.lfFaceName[len] = 0; + f.lf.lfPitchAndFamily = 0; /* default */ + if (!map_logical_font(hdc, &f)) { + win_release_dc(wdev, hdc); + return NULL; + } + } + GetTextMetrics(hdc, &f.tm); + win_release_dc(wdev, hdc); + f.y_offset = (!f.invert_y ? f.tm.tmAscent : f.tm.tmDescent); + wf = gs_alloc_struct(mem, win_xfont, &st_win_xfont, "win_lookup_font"); + if (wf == 0) { + DeleteObject(f.hFont); + return NULL; + } + f.common.procs = &win_xfont_procs; + f.dev = wdev; + *wf = f; + return (gx_xfont *) wf; +} +/* Map the logical font, and see if the result is satisfactory. */ +static int /*bool */ +map_logical_font(HDC hdc, win_xfont * xf) +{ + char szFaceName[LF_FACESIZE]; + + xf->hFont = CreateFontIndirect(&xf->lf); + if (xf->hFont == 0) + return 0; + /* Check the face name */ + SelectObject(hdc, xf->hFont); + GetTextFace(hdc, sizeof(szFaceName), szFaceName); + if (!strncmp(xf->lf.lfFaceName, szFaceName, strlen(xf->lf.lfFaceName))) + return 1; + DeleteObject(xf->hFont); + xf->hFont = 0; + return 0; +} + +/* Convert a character name or index to an xglyph code. */ +gx_xglyph +win_char_xglyph(gx_xfont * xf, gs_char chr, int encoding_index, + gs_glyph glyph, const gs_const_string *glyph_name) +{ + if (chr == gs_no_char) + return gx_no_xglyph; /* can't look up names yet */ + if (encoding_index == 0) { /* Map StandardEncoding to ISOLatin1Encoding. */ + /* We lose a couple of characters that exist in both */ + /* StandardEncoding and the Windows OEM encoding but not in */ + /* the ISOLatin1Encoding; we won't worry about this */ + /* for now. */ + chr = gs_map_std_to_iso[chr]; + encoding_index = 1; + } + if (wxf->hFont == NULL) { /* TEXTMETRICS not filled in yet */ + HDC hdc = win_get_dc(wxf->dev); + int code; + + if (hdc == NULL) + return gx_no_xglyph; + code = win_select_font(hdc, wxf); + win_release_dc(wxf->dev, hdc); + if (code < 0) + return gx_no_xglyph; + } + switch (wxf->tm.tmCharSet) { + case ANSI_CHARSET: + if (encoding_index == 1 && (chr < 0x7f || chr > 0x9f || + chr == 0x91 || chr == 0x92) + ) + break; + return gx_no_xglyph; + case OEM_CHARSET: + switch (encoding_index) { + case 1: /* ISOLatin1 */ + chr = gs_map_iso_to_oem[chr]; + break; + case 2: /* Symbol */ + chr = gs_map_symbol_to_oem[chr]; + break; + default: + return gx_no_xglyph; + } + break; + default: + return gx_no_xglyph; + } + return (chr != 0 && chr >= wxf->tm.tmFirstChar && + chr <= wxf->tm.tmLastChar ? + (gx_xglyph) chr : gx_no_xglyph); +} + +/* Get the metrics for a character. */ +int +win_char_metrics(gx_xfont * xf, gx_xglyph xg, int wmode, + gs_point * pwidth, gs_int_rect * pbbox) +{ + int code; + HDC hdc; + char chr = (char)xg; + + if (wmode != 0) + return gs_error_undefined; + hdc = win_get_dc(wxf->dev); + if (hdc == NULL) + return gs_error_limitcheck; + if ((code = win_select_font(hdc, wxf)) < 0) { + win_release_dc(wxf->dev, hdc); + return code; + } +#ifdef __WIN32__ + { + SIZE sz; + + GetTextExtentPoint(hdc, &chr, 1, &sz); + pwidth->x = sz.cx; + } +#else + { + DWORD extent; + + extent = GetTextExtent(hdc, &chr, 1); + pwidth->x = LOWORD(extent); + } +#endif + win_release_dc(wxf->dev, hdc); + pwidth->y = 0; + pbbox->p.x = 0; + pbbox->q.x = (int)pwidth->x; + if (wxf->invert_y) { + pbbox->p.y = -wxf->tm.tmDescent; + pbbox->q.y = wxf->tm.tmAscent; + } else { + pbbox->p.y = -wxf->tm.tmAscent; + pbbox->q.y = wxf->tm.tmDescent; + } + return 0; +} + +/* Render a character. */ +int +win_render_char(gx_xfont * xf, gx_xglyph xg, gx_device * dev, + int xo, int yo, gx_color_index color, int required) +{ + char chr = (char)xg; + int code; + +#ifdef NOTUSED /* we don't own any windows so we can no longer do this */ + if (dev->dname == gs_mswin_device.dname && + wdev->hdctext != NULL && !wxf->invert_y + ) { /* Display the character directly */ + HDC hdc = wdev->hdctext; + PALETTEENTRY *pal = &wdev->limgpalette->palPalEntry[color]; + + if ((code = win_select_font(hdc, wxf)) < 0) + return code; + SetTextColor(hdc, RGB(pal->peRed, pal->peGreen, pal->peBlue)); + SetBkMode(hdc, TRANSPARENT); + TextOut(hdc, xo, yo - wxf->y_offset, &chr, 1); + } else +#endif + if (!required) + code = -1; /* too hard */ + else { /* Display on an intermediate bitmap, then copy the bits. */ + gs_point wxy; + gs_int_rect bbox; + int w, h, wbm, raster; + gx_device_win *fdev = wxf->dev; + HBITMAP hbm; + byte *bits; + + 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 = gs_malloc(dev->memory, h, raster, "win_render_char"); + if (bits == 0) + return gs_error_limitcheck; + hbm = CreateBitmap(wbm, h, 1, 1, NULL); + if (hbm == NULL) { + code = gs_error_limitcheck; + } else { + HDC hdcwin = win_get_dc(fdev); + HDC hdcbit = CreateCompatibleDC(hdcwin); + + dev_proc_copy_mono((*copy_mono)) = + dev_proc(dev, copy_mono); + int y = yo - wxf->y_offset; + + SetMapMode(hdcbit, GetMapMode(hdcwin)); + win_select_font(hdcbit, wxf); + SelectObject(hdcbit, hbm); + PatBlt(hdcbit, 0, 0, wbm, h, rop_write_0s); + SetTextColor(hdcbit, 0xffffffL); /* 1 */ + SetBkMode(hdcbit, TRANSPARENT); + TextOut(hdcbit, 0, 0, &chr, 1); + GetBitmapBits(hbm, (DWORD) raster * h, bits); + DeleteDC(hdcbit); + win_release_dc(fdev, hdcwin); + DeleteObject(hbm); + if (!wxf->invert_y) + code = (*copy_mono) (dev, bits, 0, + raster, gx_no_bitmap_id, + xo, y, w, h, + gx_no_color_index, color); + else { /* Copy scan lines in reverse order. */ + int i; + + y += h - 1; + for (i = 0; i < h; i++) + (*copy_mono) (dev, bits + i * raster, + 0, raster, gx_no_bitmap_id, + xo, y - i, w, 1, + gx_no_color_index, color); + } + } + gs_free(dev->memory, bits, h, raster, "win_render_char"); + } + return (code < 0 ? code : 0); +} + +/* Release an xfont. */ +static int +win_release(gx_xfont * xf, gs_memory_t * mem) +{ + if (wxf->hFont) { + DeleteObject(wxf->hFont); + wxf->hFont = 0; + } + if (mem != NULL) + gs_free_object(mem, xf, "win_release"); + return 0; +} + +/* ------ Font utilities ------ */ + +#undef wdev +#undef wxf + +/* Get a DC for the font's device. */ +static HDC near +win_get_dc(gx_device_win * wdev) +{ + /* Since we don't have a window, use the desktop */ + /* Don't draw into it! */ + return GetDC(HWND_DESKTOP); +} + +/* Release a DC for the font's device. */ +static void near +win_release_dc(gx_device_win * wdev, HDC hdc) +{ + ReleaseDC(HWND_DESKTOP, hdc); +} + +/* Make an xfont current, possibly remapping it from a logical font. */ +static int +win_select_font(HDC hdc, win_xfont * wxf) +{ + HFONT hFont = wxf->hFont; + + if (hFont == NULL) { /* The font was released to free up resources. */ + /* Re-acquire it now. */ + wxf->hFont = CreateFontIndirect(&wxf->lf); + if (wxf->hFont == NULL) + return gs_error_limitcheck; + } + SelectObject(hdc, wxf->hFont); + return 0; +} |