|  | /* | 
|  | *	PostScript driver Type1 font functions | 
|  | * | 
|  | *	Copyright 2002  Huw D M Davies for CodeWeavers | 
|  | * | 
|  | * This library is free software; you can redistribute it and/or | 
|  | * modify it under the terms of the GNU Lesser General Public | 
|  | * License as published by the Free Software Foundation; either | 
|  | * version 2.1 of the License, or (at your option) any later version. | 
|  | * | 
|  | * This library 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 | 
|  | * Lesser General Public License for more details. | 
|  | * | 
|  | * You should have received a copy of the GNU Lesser General Public | 
|  | * License along with this library; if not, write to the Free Software | 
|  | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA | 
|  | */ | 
|  |  | 
|  | #include "config.h" | 
|  | #include "wine/port.h" | 
|  |  | 
|  | #include <string.h> | 
|  | #include <stdlib.h> | 
|  | #include <stdarg.h> | 
|  | #include <stdio.h> | 
|  | #include <assert.h> | 
|  |  | 
|  | #include "windef.h" | 
|  | #include "winbase.h" | 
|  | #include "wingdi.h" | 
|  |  | 
|  | #include "psdrv.h" | 
|  | #include "wine/debug.h" | 
|  |  | 
|  | WINE_DEFAULT_DEBUG_CHANNEL(psdrv); | 
|  |  | 
|  | struct tagTYPE1 { | 
|  | DWORD glyph_sent_size; | 
|  | BOOL *glyph_sent; | 
|  | DWORD emsize; | 
|  | }; | 
|  |  | 
|  | #define GLYPH_SENT_INC 128 | 
|  |  | 
|  | /* Type 1 font commands */ | 
|  | enum t1_cmds { | 
|  | rlineto = 5, | 
|  | rrcurveto = 8, | 
|  | closepath = 9, | 
|  | hsbw = 13, | 
|  | endchar = 14, | 
|  | rmoveto = 21 | 
|  | }; | 
|  |  | 
|  |  | 
|  | TYPE1 *T1_download_header(PSDRV_PDEVICE *physDev, char *ps_name, RECT *bbox, UINT emsize) | 
|  | { | 
|  | char *buf; | 
|  | TYPE1 *t1; | 
|  |  | 
|  | char dict[] = /* name, emsquare, fontbbox */ | 
|  | "25 dict begin\n" | 
|  | " /FontName /%s def\n" | 
|  | " /Encoding 256 array 0 1 255{1 index exch /.notdef put} for def\n" | 
|  | " /PaintType 0 def\n" | 
|  | " /FontMatrix [1 %d div 0 0 1 %d div 0 0] def\n" | 
|  | " /FontBBox [%d %d %d %d] def\n" | 
|  | " /FontType 1 def\n" | 
|  | " /Private 7 dict begin\n" | 
|  | "  /RD {string currentfile exch readhexstring pop} def\n" | 
|  | "  /ND {def} def\n" | 
|  | "  /NP {put} def\n" | 
|  | "  /MinFeature {16 16} def\n" | 
|  | "  /BlueValues [] def\n" | 
|  | "  /password 5839 def\n" | 
|  | "  /lenIV -1 def\n" | 
|  | " currentdict end def\n" | 
|  | " currentdict dup /Private get begin\n" | 
|  | "  /CharStrings 256 dict begin\n" | 
|  | "   /.notdef 4 RD 8b8b0d0e ND\n" | 
|  | "  currentdict end put\n" | 
|  | " end\n" | 
|  | "currentdict end dup /FontName get exch definefont pop\n"; | 
|  |  | 
|  | t1 = HeapAlloc(GetProcessHeap(), 0, sizeof(*t1)); | 
|  | t1->emsize = emsize; | 
|  |  | 
|  | t1->glyph_sent_size = GLYPH_SENT_INC; | 
|  | t1->glyph_sent = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, | 
|  | t1->glyph_sent_size * | 
|  | sizeof(*(t1->glyph_sent))); | 
|  |  | 
|  | buf = HeapAlloc(GetProcessHeap(), 0, sizeof(dict) + strlen(ps_name) + | 
|  | 100); | 
|  |  | 
|  | sprintf(buf, dict, ps_name, t1->emsize, t1->emsize, | 
|  | bbox->left, bbox->bottom, bbox->right, bbox->top); | 
|  |  | 
|  | PSDRV_WriteSpool(physDev, buf, strlen(buf)); | 
|  |  | 
|  | HeapFree(GetProcessHeap(), 0, buf); | 
|  | return t1; | 
|  | } | 
|  |  | 
|  |  | 
|  | typedef struct { | 
|  | BYTE *str; | 
|  | int len, max_len; | 
|  | } STR; | 
|  |  | 
|  | static STR *str_init(int sz) | 
|  | { | 
|  | STR *str = HeapAlloc(GetProcessHeap(), 0, sizeof(*str)); | 
|  | str->max_len = sz; | 
|  | str->str = HeapAlloc(GetProcessHeap(), 0, str->max_len); | 
|  | str->len = 0; | 
|  | return str; | 
|  | } | 
|  |  | 
|  | static void str_free(STR *str) | 
|  | { | 
|  | HeapFree(GetProcessHeap(), 0, str->str); | 
|  | HeapFree(GetProcessHeap(), 0, str); | 
|  | } | 
|  |  | 
|  | static void str_add_byte(STR *str, BYTE b) | 
|  | { | 
|  | if(str->len == str->max_len) { | 
|  | str->max_len *= 2; | 
|  | str->str = HeapReAlloc(GetProcessHeap(), 0, str->str, str->max_len); | 
|  | } | 
|  | str->str[str->len++] = b; | 
|  | } | 
|  |  | 
|  | static void str_add_num(STR *str, int num) | 
|  | { | 
|  | if(num <= 107 && num >= -107) | 
|  | str_add_byte(str, num + 139); | 
|  | else if(num >= 108 && num <= 1131) { | 
|  | str_add_byte(str, ((num - 108) >> 8) + 247); | 
|  | str_add_byte(str, (num - 108) & 0xff); | 
|  | } else if(num <= -108 && num >= -1131) { | 
|  | num = -num; | 
|  | str_add_byte(str, ((num - 108) >> 8) + 251); | 
|  | str_add_byte(str, (num - 108) & 0xff); | 
|  | } else { | 
|  | str_add_byte(str, 0xff); | 
|  | str_add_byte(str, (num >> 24) & 0xff); | 
|  | str_add_byte(str, (num >> 16) & 0xff); | 
|  | str_add_byte(str, (num >> 8) & 0xff); | 
|  | str_add_byte(str, (num & 0xff)); | 
|  | } | 
|  | } | 
|  |  | 
|  | static void str_add_point(STR *str, POINTFX *pt, POINT *curpos) | 
|  | { | 
|  | POINT newpos; | 
|  | newpos.x = pt->x.value + ((pt->x.fract >> 15) & 0x1); | 
|  | newpos.y = pt->y.value + ((pt->y.fract >> 15) & 0x1); | 
|  |  | 
|  | str_add_num(str, newpos.x - curpos->x); | 
|  | str_add_num(str, newpos.y - curpos->y); | 
|  | *curpos = newpos; | 
|  | } | 
|  |  | 
|  | static void str_add_cmd(STR *str, enum t1_cmds cmd) | 
|  | { | 
|  | str_add_byte(str, (BYTE)cmd); | 
|  | } | 
|  |  | 
|  | static int str_get_bytes(STR *str, BYTE **b) | 
|  | { | 
|  | *b = str->str; | 
|  | return str->len; | 
|  | } | 
|  |  | 
|  | BOOL T1_download_glyph(PSDRV_PDEVICE *physDev, DOWNLOAD *pdl, DWORD index, | 
|  | char *glyph_name) | 
|  | { | 
|  | DWORD len, i; | 
|  | char *buf; | 
|  | TYPE1 *t1; | 
|  | STR *charstring; | 
|  | BYTE *bytes; | 
|  | HFONT old_font, unscaled_font; | 
|  | GLYPHMETRICS gm; | 
|  | char *glyph_buf; | 
|  | POINT curpos; | 
|  | TTPOLYGONHEADER *pph; | 
|  | TTPOLYCURVE *ppc; | 
|  | LOGFONTW lf; | 
|  | RECT rc; | 
|  | static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} }; | 
|  | static const char glyph_def_begin[] = | 
|  | "/%s findfont dup\n" | 
|  | "/Private get begin\n" | 
|  | "/CharStrings get begin\n" | 
|  | "/%s %d RD\n"; | 
|  | static const char glyph_def_end[] = | 
|  | "ND\n" | 
|  | "end end\n"; | 
|  |  | 
|  | TRACE("%d %s\n", index, glyph_name); | 
|  | assert(pdl->type == Type1); | 
|  | t1 = pdl->typeinfo.Type1; | 
|  |  | 
|  | if(index < t1->glyph_sent_size) { | 
|  | if(t1->glyph_sent[index]) | 
|  | return TRUE; | 
|  | } else { | 
|  | t1->glyph_sent_size = (index / GLYPH_SENT_INC + 1) * GLYPH_SENT_INC; | 
|  | t1->glyph_sent = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, | 
|  | t1->glyph_sent, | 
|  | t1->glyph_sent_size * sizeof(*(t1->glyph_sent))); | 
|  | } | 
|  |  | 
|  | GetObjectW(GetCurrentObject(physDev->hdc, OBJ_FONT), sizeof(lf), &lf); | 
|  | rc.left = rc.right = rc.bottom = 0; | 
|  | rc.top = t1->emsize; | 
|  | DPtoLP(physDev->hdc, (POINT*)&rc, 2); | 
|  | lf.lfHeight = -abs(rc.top - rc.bottom); | 
|  | lf.lfWidth = 0; | 
|  | lf.lfOrientation = lf.lfEscapement = 0; | 
|  | unscaled_font = CreateFontIndirectW(&lf); | 
|  | old_font = SelectObject(physDev->hdc, unscaled_font); | 
|  | len = GetGlyphOutlineW(physDev->hdc, index, GGO_GLYPH_INDEX | GGO_BEZIER, | 
|  | &gm, 0, NULL, &identity); | 
|  | if(len == GDI_ERROR) return FALSE; | 
|  | glyph_buf = HeapAlloc(GetProcessHeap(), 0, len); | 
|  | GetGlyphOutlineW(physDev->hdc, index, GGO_GLYPH_INDEX | GGO_BEZIER, | 
|  | &gm, len, glyph_buf, &identity); | 
|  |  | 
|  | SelectObject(physDev->hdc, old_font); | 
|  | DeleteObject(unscaled_font); | 
|  |  | 
|  | charstring = str_init(100); | 
|  |  | 
|  | curpos.x = gm.gmptGlyphOrigin.x; | 
|  | curpos.y = 0; | 
|  |  | 
|  | str_add_num(charstring, curpos.x); | 
|  | str_add_num(charstring, gm.gmCellIncX); | 
|  | str_add_cmd(charstring, hsbw); | 
|  |  | 
|  | pph = (TTPOLYGONHEADER*)glyph_buf; | 
|  | while((char*)pph < glyph_buf + len) { | 
|  | TRACE("contour len %d\n", pph->cb); | 
|  | ppc = (TTPOLYCURVE*)((char*)pph + sizeof(*pph)); | 
|  |  | 
|  | str_add_point(charstring, &pph->pfxStart, &curpos); | 
|  | str_add_cmd(charstring, rmoveto); | 
|  |  | 
|  | while((char*)ppc < (char*)pph + pph->cb) { | 
|  | TRACE("line type %d cpfx = %d\n", ppc->wType, ppc->cpfx); | 
|  | switch(ppc->wType) { | 
|  | case TT_PRIM_LINE: | 
|  | for(i = 0; i < ppc->cpfx; i++) { | 
|  | str_add_point(charstring, ppc->apfx + i, &curpos); | 
|  | str_add_cmd(charstring, rlineto); | 
|  | } | 
|  | break; | 
|  | case TT_PRIM_CSPLINE: | 
|  | for(i = 0; i < ppc->cpfx/3; i++) { | 
|  | str_add_point(charstring, ppc->apfx + 3 * i, &curpos); | 
|  | str_add_point(charstring, ppc->apfx + 3 * i + 1, &curpos); | 
|  | str_add_point(charstring, ppc->apfx + 3 * i + 2, &curpos); | 
|  | str_add_cmd(charstring, rrcurveto); | 
|  | } | 
|  | break; | 
|  | default: | 
|  | ERR("curve type = %d\n", ppc->wType); | 
|  | return FALSE; | 
|  | } | 
|  | ppc = (TTPOLYCURVE*)((char*)ppc + sizeof(*ppc) + | 
|  | (ppc->cpfx - 1) * sizeof(POINTFX)); | 
|  | } | 
|  | str_add_cmd(charstring, closepath); | 
|  | pph = (TTPOLYGONHEADER*)((char*)pph + pph->cb); | 
|  | } | 
|  | str_add_cmd(charstring, endchar); | 
|  |  | 
|  | buf = HeapAlloc(GetProcessHeap(), 0, sizeof(glyph_def_begin) + | 
|  | strlen(pdl->ps_name) + strlen(glyph_name) + 100); | 
|  |  | 
|  | sprintf(buf, "%%%%glyph %04x\n", index); | 
|  | PSDRV_WriteSpool(physDev, buf, strlen(buf)); | 
|  |  | 
|  | len = str_get_bytes(charstring, &bytes); | 
|  | sprintf(buf, glyph_def_begin, pdl->ps_name, glyph_name, len); | 
|  | PSDRV_WriteSpool(physDev, buf, strlen(buf)); | 
|  | PSDRV_WriteBytes(physDev, bytes, len); | 
|  | sprintf(buf, glyph_def_end); | 
|  | PSDRV_WriteSpool(physDev, buf, strlen(buf)); | 
|  | str_free(charstring); | 
|  |  | 
|  | t1->glyph_sent[index] = TRUE; | 
|  | HeapFree(GetProcessHeap(), 0, glyph_buf); | 
|  | HeapFree(GetProcessHeap(), 0, buf); | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  | void T1_free(TYPE1 *t1) | 
|  | { | 
|  | HeapFree(GetProcessHeap(), 0, t1->glyph_sent); | 
|  | HeapFree(GetProcessHeap(), 0, t1); | 
|  | return; | 
|  | } |