Do not link against -lcups directly, but dynamically load it if
[wine] / dlls / wineps / type1.c
1 /*
2  *      PostScript driver Type1 font functions
3  *
4  *      Copyright 2002  Huw D M Davies for CodeWeavers
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20 #include <string.h>
21 #include <stdlib.h>
22 #include <stdio.h>
23 #include <assert.h>
24 #include "winspool.h"
25 #include "psdrv.h"
26 #include "wine/debug.h"
27 #include "winerror.h"
28 #include "config.h"
29 #include "wine/port.h"
30
31 WINE_DEFAULT_DEBUG_CHANNEL(psdrv);
32
33 struct tagTYPE1 {
34     DWORD glyph_sent_size;
35     BOOL *glyph_sent;
36     DWORD emsize;
37     HFONT unscaled_font;
38 };
39
40 #define GLYPH_SENT_INC 128
41
42 /* Type 1 font commands */
43 enum t1_cmds {
44     rlineto = 5,
45     rrcurveto = 8,
46     closepath = 9,
47     hsbw = 13,
48     endchar = 14,
49     rmoveto = 21
50 };
51
52
53 TYPE1 *T1_download_header(PSDRV_PDEVICE *physDev, LPOUTLINETEXTMETRICA potm,
54                           char *ps_name)
55 {
56     char *buf;
57     TYPE1 *t1;
58     LOGFONTW lf;
59     RECT rc;
60
61     char dict[] = /* name, emsquare, fontbbox */
62       "25 dict begin\n"
63       " /FontName /%s def\n"
64       " /Encoding 256 array 0 1 255{1 index exch /.notdef put} for def\n"
65       " /PaintType 0 def\n"
66       " /FontMatrix [1 %d div 0 0 1 %d div 0 0] def\n"
67       " /FontBBox [%d %d %d %d] def\n"
68       " /FontType 1 def\n"
69       " /Private 7 dict begin\n"
70       "  /RD {string currentfile exch readhexstring pop} def\n"
71       "  /ND {def} def\n"
72       "  /NP {put} def\n"
73       "  /MinFeature {16 16} def\n"
74       "  /BlueValues [] def\n"
75       "  /password 5839 def\n"
76       "  /lenIV -1 def\n"
77       " currentdict end def\n"
78       " currentdict dup /Private get begin\n"
79       "  /CharStrings 256 dict begin\n"
80       "   /.notdef 4 RD 8b8b0d0e ND\n"
81       "  currentdict end put\n"
82       " end\n"
83       "currentdict end dup /FontName get exch definefont pop\n";
84
85     t1 = HeapAlloc(GetProcessHeap(), 0, sizeof(*t1));
86     t1->emsize = potm->otmEMSquare;
87
88     GetObjectW(GetCurrentObject(physDev->hdc, OBJ_FONT), sizeof(lf), &lf);
89     rc.left = rc.right = rc.bottom = 0;
90     rc.top = t1->emsize;
91     DPtoLP(physDev->hdc, (POINT*)&rc, 2);
92     lf.lfHeight = -abs(rc.top - rc.bottom);
93     t1->unscaled_font = CreateFontIndirectW(&lf);
94     t1->glyph_sent_size = GLYPH_SENT_INC;
95     t1->glyph_sent = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
96                                t1->glyph_sent_size *
97                                sizeof(*(t1->glyph_sent)));
98
99     buf = HeapAlloc(GetProcessHeap(), 0, sizeof(dict) + strlen(ps_name) +
100                     100);
101
102     sprintf(buf, dict, ps_name, t1->emsize, t1->emsize,
103             potm->otmrcFontBox.left, potm->otmrcFontBox.bottom,
104             potm->otmrcFontBox.right, potm->otmrcFontBox.top);
105
106     PSDRV_WriteSpool(physDev, buf, strlen(buf));
107
108     HeapFree(GetProcessHeap(), 0, buf);
109     return t1;
110 }
111
112
113 typedef struct {
114   BYTE *str;
115   int len, max_len;
116 } STR;
117
118 static STR *str_init(int sz)
119 {
120   STR *str = HeapAlloc(GetProcessHeap(), 0, sizeof(*str));
121   str->max_len = sz;
122   str->str = HeapAlloc(GetProcessHeap(), 0, str->max_len);
123   str->len = 0;
124   return str;
125 }
126
127 static void str_free(STR *str)
128 {
129   HeapFree(GetProcessHeap(), 0, str->str);
130   HeapFree(GetProcessHeap(), 0, str);
131 }
132
133 static void str_add_byte(STR *str, BYTE b)
134 {
135     if(str->len == str->max_len) {
136         str->max_len *= 2;
137         str->str = HeapReAlloc(GetProcessHeap(), 0, str->str, str->max_len);
138     }
139     str->str[str->len++] = b;
140 }
141
142 static void str_add_num(STR *str, int num)
143 {
144     if(num <= 107 && num >= -107)
145         str_add_byte(str, num + 139);
146     else if(num >= 108 && num <= 1131) {
147         str_add_byte(str, ((num - 108) >> 8) + 247);
148         str_add_byte(str, (num - 108) & 0xff);
149     } else if(num <= -108 && num >= -1131) {
150         num = -num;
151         str_add_byte(str, ((num - 108) >> 8) + 251);
152         str_add_byte(str, (num - 108) & 0xff);
153     } else {
154         str_add_byte(str, 0xff);
155         str_add_byte(str, (num >> 24) & 0xff);
156         str_add_byte(str, (num >> 16) & 0xff);
157         str_add_byte(str, (num >> 8) & 0xff);
158         str_add_byte(str, (num & 0xff));
159     }
160 }
161
162 static void str_add_point(STR *str, POINTFX *pt, POINT *curpos)
163 {
164     POINT newpos;
165     newpos.x = pt->x.value + ((pt->x.fract >> 15) & 0x1);
166     newpos.y = pt->y.value + ((pt->y.fract >> 15) & 0x1);
167
168     str_add_num(str, newpos.x - curpos->x);
169     str_add_num(str, newpos.y - curpos->y);
170     *curpos = newpos;
171 }
172
173 static void str_add_cmd(STR *str, enum t1_cmds cmd)
174 {
175     str_add_byte(str, (BYTE)cmd);
176 }
177
178 static int str_get_bytes(STR *str, BYTE **b)
179 {
180   *b = str->str;
181   return str->len;
182 }
183
184 BOOL T1_download_glyph(PSDRV_PDEVICE *physDev, DOWNLOAD *pdl, DWORD index,
185                        char *glyph_name)
186 {
187     DWORD len, i;
188     char *buf;
189     TYPE1 *t1;
190     STR *charstring;
191     BYTE *bytes;
192     HFONT old_font;
193     GLYPHMETRICS gm;
194     char *glyph_buf;
195     POINT curpos;
196     TTPOLYGONHEADER *pph;
197     TTPOLYCURVE *ppc;
198     char glyph_def_begin[] =
199       "/%s findfont dup\n"
200       "/Private get begin\n"
201       "/CharStrings get begin\n"
202       "/%s %d RD\n";
203     char glyph_def_end[] =
204       "ND\n"
205       "end end\n";
206
207     TRACE("%ld %s\n", index, glyph_name);
208     assert(pdl->type == Type1);
209     t1 = pdl->typeinfo.Type1;
210
211     if(index < t1->glyph_sent_size) {
212         if(t1->glyph_sent[index])
213             return TRUE;
214     } else {
215         t1->glyph_sent_size = (index / GLYPH_SENT_INC + 1) * GLYPH_SENT_INC;
216         t1->glyph_sent = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
217                                       t1->glyph_sent,
218                                       t1->glyph_sent_size * sizeof(*(t1->glyph_sent)));
219     }
220
221     old_font = SelectObject(physDev->hdc, t1->unscaled_font);
222     len = GetGlyphOutlineW(physDev->hdc, index, GGO_GLYPH_INDEX | GGO_BEZIER,
223                            &gm, 0, NULL, NULL);
224     if(len == GDI_ERROR) return FALSE;
225     glyph_buf = HeapAlloc(GetProcessHeap(), 0, len);
226     GetGlyphOutlineW(physDev->hdc, index, GGO_GLYPH_INDEX | GGO_BEZIER,
227                      &gm, len, glyph_buf, NULL);
228
229     SelectObject(physDev->hdc, old_font);
230
231     charstring = str_init(100);
232
233     curpos.x = gm.gmptGlyphOrigin.x;
234     curpos.y = 0;
235
236     str_add_num(charstring, curpos.x);
237     str_add_num(charstring, gm.gmCellIncX);
238     str_add_cmd(charstring, hsbw);
239
240     pph = (TTPOLYGONHEADER*)glyph_buf;
241     while((char*)pph < glyph_buf + len) {
242         TRACE("contour len %ld\n", pph->cb);
243         ppc = (TTPOLYCURVE*)((char*)pph + sizeof(*pph));
244
245         str_add_point(charstring, &pph->pfxStart, &curpos);
246         str_add_cmd(charstring, rmoveto);
247
248         while((char*)ppc < (char*)pph + pph->cb) {
249             TRACE("line type %d cpfx = %d\n", ppc->wType, ppc->cpfx);
250             switch(ppc->wType) {
251             case TT_PRIM_LINE:
252                 for(i = 0; i < ppc->cpfx; i++) {
253                     str_add_point(charstring, ppc->apfx + i, &curpos);
254                     str_add_cmd(charstring, rlineto);
255                 }
256                 break;
257             case TT_PRIM_CSPLINE:
258                 for(i = 0; i < ppc->cpfx/3; i++) {
259                     str_add_point(charstring, ppc->apfx + 3 * i, &curpos);
260                     str_add_point(charstring, ppc->apfx + 3 * i + 1, &curpos);
261                     str_add_point(charstring, ppc->apfx + 3 * i + 2, &curpos);
262                     str_add_cmd(charstring, rrcurveto);
263                 }
264                 break;
265             default:
266                 ERR("curve type = %d\n", ppc->wType);
267                 return FALSE;
268             }
269             ppc = (TTPOLYCURVE*)((char*)ppc + sizeof(*ppc) +
270                                  (ppc->cpfx - 1) * sizeof(POINTFX));
271         }
272         str_add_cmd(charstring, closepath);
273         pph = (TTPOLYGONHEADER*)((char*)pph + pph->cb);
274     }
275     str_add_cmd(charstring, endchar);
276
277     buf = HeapAlloc(GetProcessHeap(), 0, sizeof(glyph_def_begin) +
278                     strlen(pdl->ps_name) + strlen(glyph_name) + 100);
279
280     sprintf(buf, "%%%%glyph %04lx\n", index);
281     PSDRV_WriteSpool(physDev, buf, strlen(buf));
282
283     len = str_get_bytes(charstring, &bytes);
284     sprintf(buf, glyph_def_begin, pdl->ps_name, glyph_name, len);
285     PSDRV_WriteSpool(physDev, buf, strlen(buf));
286     PSDRV_WriteBytes(physDev, bytes, len);
287     sprintf(buf, glyph_def_end);
288     PSDRV_WriteSpool(physDev, buf, strlen(buf));
289     str_free(charstring);
290
291     t1->glyph_sent[index] = TRUE;
292     HeapFree(GetProcessHeap(), 0, glyph_buf);
293     HeapFree(GetProcessHeap(), 0, buf);
294     return TRUE;
295 }
296
297 void T1_free(TYPE1 *t1)
298 {
299     HeapFree(GetProcessHeap(), 0, t1->glyph_sent);
300     DeleteObject(t1->unscaled_font);
301     HeapFree(GetProcessHeap(), 0, t1);
302     return;
303 }