fdopen: don't rewind the file after creating the FILE* handle. Added
[wine] / dlls / wineps / type42.c
1 /*
2  *      PostScript driver Type42 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
34 #define GET_BE_WORD(ptr)  MAKEWORD( ((BYTE *)(ptr))[1], ((BYTE *)(ptr))[0] )
35 #define GET_BE_DWORD(ptr) ((DWORD)MAKELONG( GET_BE_WORD(&((WORD *)(ptr))[1]), \
36                                             GET_BE_WORD(&((WORD *)(ptr))[0]) ))
37
38 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
39           ( ( (DWORD)_x4 << 24 ) |     \
40             ( (DWORD)_x3 << 16 ) |     \
41             ( (DWORD)_x2 <<  8 ) |     \
42               (DWORD)_x1         )
43
44 /* undef this to download the metrics in one go in the hmtx table.
45    Most printers seem unable to use incremental metrics unfortunately */
46 #define USE_SEPARATE_METRICS
47 #undef USE_SEPARATE_METRICS
48
49 typedef struct {
50   DWORD MS_tag;
51   DWORD len, check;
52   BYTE *data;
53   BOOL write;
54 } OTTable;
55
56 const OTTable tables_templ[] = {
57       { MS_MAKE_TAG('c','v','t',' '), 0, 0, NULL, TRUE },
58       { MS_MAKE_TAG('f','p','g','m'), 0, 0, NULL, TRUE },
59       { MS_MAKE_TAG('g','d','i','r'), 0, 0, NULL, TRUE },
60       { MS_MAKE_TAG('g','l','y','f'), 0, 0, NULL, FALSE },
61       { MS_MAKE_TAG('h','e','a','d'), 0, 0, NULL, TRUE },
62       { MS_MAKE_TAG('h','h','e','a'), 0, 0, NULL, TRUE },
63 #ifdef USE_SEPARATE_METRICS
64       { MS_MAKE_TAG('h','m','t','x'), 0, 0, NULL, FALSE },
65 #else
66       { MS_MAKE_TAG('h','m','t','x'), 0, 0, NULL, TRUE },
67 #endif
68       { MS_MAKE_TAG('l','o','c','a'), 0, 0, NULL, FALSE },
69       { MS_MAKE_TAG('m','a','x','p'), 0, 0, NULL, TRUE },
70       { MS_MAKE_TAG('p','r','e','p'), 0, 0, NULL, TRUE },
71       { 0, 0, 0, NULL, 0 }
72 };
73
74 struct tagTYPE42 {
75     OTTable tables[sizeof(tables_templ)/sizeof(tables_templ[0])];
76     int glyf_tab, loca_tab, head_tab; /* indices of glyf, loca and head tables */
77     int hmtx_tab;
78     DWORD glyph_sent_size;
79     BOOL *glyph_sent;
80     DWORD emsize;
81 };
82
83 #define GLYPH_SENT_INC 128
84
85 #define FLIP_ORDER(x) \
86  ( ( ((x) & 0xff) << 24) | \
87    ( ((x) & 0xff00) << 8) | \
88    ( ((x) & 0xff0000) >> 8) | \
89    ( ((x) & 0xff000000) >> 24) )
90
91
92 /* Some flags for composite glyphs.  See glyf table in OT spec */
93 #define ARG_1_AND_2_ARE_WORDS    (1L << 0)
94 #define WE_HAVE_A_SCALE          (1L << 3)
95 #define MORE_COMPONENTS          (1L << 5)
96 #define WE_HAVE_AN_X_AND_Y_SCALE (1L << 6)
97 #define WE_HAVE_A_TWO_BY_TWO     (1L << 7)
98
99
100 static BOOL LoadTable(HDC hdc, OTTable *table)
101 {
102     int i;
103
104     if(table->MS_tag == MS_MAKE_TAG('g','d','i','r')) return TRUE;
105     table->len = GetFontData(hdc, table->MS_tag, 0, NULL, 0);
106     table->data = HeapAlloc(GetProcessHeap(), 0, (table->len + 3) & ~3 );
107     memset(table->data + ((table->len - 1) & ~3), 0, sizeof(DWORD));
108     GetFontData(hdc, table->MS_tag, 0, table->data, table->len);
109     table->check = 0;
110     for(i = 0; i < (table->len + 3) / 4; i++)
111         table->check += FLIP_ORDER(*((DWORD*)(table->data) + i));
112     return TRUE;
113 }
114
115
116 TYPE42 *T42_download_header(PSDRV_PDEVICE *physDev, LPOUTLINETEXTMETRICA potm,
117                             char *ps_name)
118 {
119     DWORD i, j, tablepos;
120     WORD num_of_tables = sizeof(tables_templ) / sizeof(tables_templ[0]) - 1;
121     WORD num_of_write_tables = 0;
122     char *buf;
123     TYPE42 *t42;
124     char start[] = /* name, fontbbox */
125             "25 dict begin\n"
126             " /FontName /%s def\n"
127             " /Encoding 256 array 0 1 255{1 index exch /.notdef put} for\n"
128             " def\n"
129             " /PaintType 0 def\n"
130             " /FontMatrix [1 0 0 1 0 0] def\n"
131             " /FontBBox [%f %f %f %f] def\n"
132             " /FontType 42 def\n"
133             " /CharStrings 256 dict begin\n"
134             "  /.notdef 0 def\n"
135             " currentdict end def\n"
136             " /GlyphDirectory 256 dict def\n"
137 #ifdef USE_SEPARATE_METRICS
138             " /Metrics 256 dict def\n"
139 #endif
140             " /sfnts [\n";
141     char TT_offset_table[] = "<00010000%04x%04x%04x%04x\n";
142     char TT_table_dir_entry[] = "%08lx%08lx%08lx%08lx\n";
143     char end[] = "] def\n"
144       "currentdict end dup /FontName get exch definefont pop\n";
145
146
147     t42 = HeapAlloc(GetProcessHeap(), 0, sizeof(*t42));
148     memcpy(t42->tables, tables_templ, sizeof(tables_templ));
149     t42->loca_tab = t42->glyf_tab = t42->head_tab = t42->hmtx_tab = -1;
150     t42->emsize = potm->otmEMSquare;
151
152     for(i = 0; i < num_of_tables; i++) {
153         LoadTable(physDev->hdc, t42->tables + i);
154         if(t42->tables[i].len > 0xffff && t42->tables[i].write) break;
155         if(t42->tables[i].write) num_of_write_tables++;
156         if(t42->tables[i].MS_tag == MS_MAKE_TAG('l','o','c','a'))
157             t42->loca_tab = i;
158         else if(t42->tables[i].MS_tag == MS_MAKE_TAG('g','l','y','f'))
159             t42->glyf_tab = i;
160         else if(t42->tables[i].MS_tag == MS_MAKE_TAG('h','e','a','d'))
161             t42->head_tab = i;
162         else if(t42->tables[i].MS_tag == MS_MAKE_TAG('h','m','t','x'))
163             t42->hmtx_tab = i;
164     }
165     if(i < num_of_tables) {
166         TRACE("Table %ld has length %ld.  Will use Type 1 font instead.\n", i, t42->tables[i].len);
167         T42_free(t42);
168         return NULL;
169     }
170
171     t42->glyph_sent_size = GLYPH_SENT_INC;
172     t42->glyph_sent = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
173                                 t42->glyph_sent_size *
174                                 sizeof(*(t42->glyph_sent)));
175
176     buf = HeapAlloc(GetProcessHeap(), 0, sizeof(start) + strlen(ps_name) +
177                     100);
178
179     sprintf(buf, start, ps_name,
180             (float)potm->otmrcFontBox.left / potm->otmEMSquare,
181             (float)potm->otmrcFontBox.bottom / potm->otmEMSquare,
182             (float)potm->otmrcFontBox.right / potm->otmEMSquare,
183             (float)potm->otmrcFontBox.top / potm->otmEMSquare);
184
185     PSDRV_WriteSpool(physDev, buf, strlen(buf));
186
187     sprintf(buf, TT_offset_table, num_of_write_tables,
188             num_of_write_tables, num_of_write_tables, num_of_write_tables);
189
190     PSDRV_WriteSpool(physDev, buf, strlen(buf));
191
192     tablepos = 12 + num_of_write_tables * 16;
193     for(i = 0; i < num_of_tables; i++) {
194         if(!t42->tables[i].write) continue;
195         sprintf(buf, TT_table_dir_entry, FLIP_ORDER(t42->tables[i].MS_tag),
196                 t42->tables[i].check, t42->tables[i].len ? tablepos : 0,
197                 t42->tables[i].len);
198         PSDRV_WriteSpool(physDev, buf, strlen(buf));
199         tablepos += ((t42->tables[i].len + 3) & ~3);
200     }
201     PSDRV_WriteSpool(physDev, ">\n", 2);
202
203     for(i = 0; i < num_of_tables; i++) {
204         if(t42->tables[i].len == 0 || !t42->tables[i].write) continue;
205         PSDRV_WriteSpool(physDev, "<", 1);
206         for(j = 0; j < ((t42->tables[i].len + 3) & ~3); j++) {
207             sprintf(buf, "%02x", t42->tables[i].data[j]);
208             PSDRV_WriteSpool(physDev, buf, strlen(buf));
209             if(j % 16 == 15) PSDRV_WriteSpool(physDev, "\n", 1);
210         }
211         PSDRV_WriteSpool(physDev, ">\n", 2);
212     }
213
214     PSDRV_WriteSpool(physDev, end, sizeof(end) - 1);
215     HeapFree(GetProcessHeap(), 0, buf);
216     return t42;
217 }
218
219
220
221
222 BOOL T42_download_glyph(PSDRV_PDEVICE *physDev, DOWNLOAD *pdl, DWORD index,
223                         char *glyph_name)
224 {
225     DWORD start, end, i;
226     char *buf;
227     TYPE42 *t42;
228     WORD loca_format;
229     WORD awidth;
230     short lsb;
231
232 #ifdef USE_SEPARATE_METRICS
233     char glyph_with_Metrics_def[] = 
234       "/%s findfont exch 1 index /GlyphDirectory get\n"
235       "begin\n"
236       " %d exch def\n"
237       "end\n"
238       "dup /CharStrings get\n"
239       "begin\n"
240       " /%s %d def\n"
241       "end\n"
242       "/Metrics get\n"
243       "begin\n"
244       " /%s [%f %f] def\n"
245       "end\n";
246 #else
247     char glyph_def[] = 
248       "/%s findfont exch 1 index /GlyphDirectory get\n"
249       "begin\n"
250       " %d exch def\n"
251       "end\n"
252       "/CharStrings get\n"
253       "begin\n"
254       " /%s %d def\n"
255       "end\n";
256 #endif
257
258     TRACE("%ld %s\n", index, glyph_name);
259     assert(pdl->type == Type42);
260     t42 = pdl->typeinfo.Type42;
261
262     if(index < t42->glyph_sent_size) {
263         if(t42->glyph_sent[index])
264             return TRUE;
265     } else {
266         t42->glyph_sent_size = (index / GLYPH_SENT_INC + 1) * GLYPH_SENT_INC;
267         t42->glyph_sent = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
268                                       t42->glyph_sent,
269                                       t42->glyph_sent_size * sizeof(*(t42->glyph_sent)));
270     }
271
272     buf = HeapAlloc(GetProcessHeap(), 0, sizeof(glyph_def) +
273                     strlen(pdl->ps_name) + 100);
274
275     loca_format = GET_BE_WORD(t42->tables[t42->head_tab].data + 50);
276     TRACE("loca_format = %d\n", loca_format);
277     switch(loca_format) {
278     case 0:
279         start = GET_BE_WORD(((WORD*)t42->tables[t42->loca_tab].data) + index);
280         start <<= 1;
281         end = GET_BE_WORD(((WORD*)t42->tables[t42->loca_tab].data) + index + 1);
282         end <<= 1;
283         break;
284     case 1:
285         start = GET_BE_DWORD(((DWORD*)t42->tables[t42->loca_tab].data) + index);
286         end = GET_BE_DWORD(((DWORD*)t42->tables[t42->loca_tab].data) + index + 1);
287         break;
288     default:
289         ERR("Unknown loca_format %d\n", loca_format);
290         return FALSE;
291     }
292     TRACE("start = %lx end = %lx\n", start, end);
293
294     awidth = GET_BE_WORD(t42->tables[t42->hmtx_tab].data + index * 4);
295     lsb = GET_BE_WORD(t42->tables[t42->hmtx_tab].data + index * 4 + 2);
296
297     if(GET_BE_WORD(t42->tables[t42->glyf_tab].data + start) == 0xffff) {
298       /* Composite glyph */
299         char *sg_start = t42->tables[t42->glyf_tab].data + start + 10;
300         DWORD sg_flags, sg_index;
301         char sg_name[MAX_G_NAME + 1];
302
303         do {
304             sg_flags = GET_BE_WORD(sg_start);
305             sg_index = GET_BE_WORD(sg_start + 2);
306
307             TRACE("Sending subglyph %04lx for glyph %04lx\n", sg_index, index);
308             get_glyph_name(physDev->hdc, sg_index, sg_name);
309             T42_download_glyph(physDev, pdl, sg_index, sg_name);
310             sg_start += 4;
311             if(sg_flags & ARG_1_AND_2_ARE_WORDS)
312                 sg_start += 4;
313             else
314                 sg_start += 2;
315             if(sg_flags & WE_HAVE_A_SCALE)
316                 sg_start += 2;
317             else if(sg_flags & WE_HAVE_AN_X_AND_Y_SCALE)
318                 sg_start += 4;
319             else if(sg_flags & WE_HAVE_A_TWO_BY_TWO)
320                 sg_start += 8;
321         } while(sg_flags & MORE_COMPONENTS);
322     }
323
324     sprintf(buf, "%%%%glyph %04lx\n", index);
325     PSDRV_WriteSpool(physDev, buf, strlen(buf));
326     PSDRV_WriteSpool(physDev, "<", 1);
327     for(i = start; i < end; i++) {
328         sprintf(buf, "%02x", *(t42->tables[t42->glyf_tab].data + i));
329         PSDRV_WriteSpool(physDev, buf, strlen(buf));
330         if((i - start) % 16 == 15)
331             PSDRV_WriteSpool(physDev, "\n", 1);
332     }
333     PSDRV_WriteSpool(physDev, ">\n", 2);
334 #if USE_SEPARATE_METRICS
335     sprintf(buf, glyph_with_Metrics_def, pdl->ps_name, index, glyph_name, index,
336             glyph_name, (float)lsb / t42->emsize, (float)awidth / t42->emsize);
337 #else
338     sprintf(buf, glyph_def, pdl->ps_name, index, glyph_name, index);
339 #endif
340     PSDRV_WriteSpool(physDev, buf, strlen(buf));
341
342     t42->glyph_sent[index] = TRUE;
343     HeapFree(GetProcessHeap(), 0, buf);
344     return TRUE;
345 }
346
347 void T42_free(TYPE42 *t42)
348 {
349     OTTable *table;
350     for(table = t42->tables; table->MS_tag; table++)
351         if(table->data) HeapFree(GetProcessHeap(), 0, table->data);
352     if(t42->glyph_sent) HeapFree(GetProcessHeap(), 0, t42->glyph_sent);
353     HeapFree(GetProcessHeap(), 0, t42);
354     return;
355 }