/* Copyright (C) 1993, 1994, 1997, 1998, 1999 artofcode LLC. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA, 02111-1307. */ /*$Id: gdevmsxf.c,v 1.2.6.1.2.1 2003/01/17 00:49:01 giles Exp $ */ /* 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 */ private xfont_proc_lookup_font(win_lookup_font); private xfont_proc_char_xglyph(win_char_xglyph); private xfont_proc_char_metrics(win_char_metrics); private xfont_proc_render_char(win_render_char); private xfont_proc_release(win_release); private 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 */ private HDC near win_get_dc(P1(gx_device_win *)); private void near win_release_dc(P2(gx_device_win *, HDC)); private int win_select_font(P2(HDC, win_xfont *)); /* Map from PostScript to Windows character codes. */ /* (These tables were generated by winmaps.ps.) */ private 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 }; private 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; private 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. */ private int /*bool */ map_logical_font(P2(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 = 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. */ private 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, gs_proc_glyph_name_t glyph_name_proc) { 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 = 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(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(bits, h, raster, "win_render_char"); } return (code < 0 ? code : 0); } /* Release an xfont. */ private 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. */ private 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. */ private 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. */ private 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; }