quartz: Use proper alloc/free functions for COM objects.
[wine] / dlls / wineps.drv / 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include "config.h"
22 #include "wine/port.h"
23
24 #include <string.h>
25 #include <stdlib.h>
26 #include <stdarg.h>
27 #include <stdio.h>
28 #include <assert.h>
29 #include <locale.h>
30
31 #include "windef.h"
32 #include "winbase.h"
33 #include "winerror.h"
34 #include "wingdi.h"
35 #include "winspool.h"
36
37 #include "psdrv.h"
38 #include "wine/debug.h"
39
40 WINE_DEFAULT_DEBUG_CHANNEL(psdrv);
41
42
43 #define GET_BE_WORD(ptr)  MAKEWORD( ((BYTE *)(ptr))[1], ((BYTE *)(ptr))[0] )
44 #define GET_BE_DWORD(ptr) ((DWORD)MAKELONG( GET_BE_WORD(&((WORD *)(ptr))[1]), \
45                                             GET_BE_WORD(&((WORD *)(ptr))[0]) ))
46
47 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
48           ( ( (DWORD)_x4 << 24 ) |     \
49             ( (DWORD)_x3 << 16 ) |     \
50             ( (DWORD)_x2 <<  8 ) |     \
51               (DWORD)_x1         )
52
53 typedef struct {
54   DWORD MS_tag;
55   DWORD len, check;
56   BYTE *data;
57   BOOL write;
58 } OTTable;
59
60 static const OTTable tables_templ[] = {
61       { MS_MAKE_TAG('c','v','t',' '), 0, 0, NULL, TRUE },
62       { MS_MAKE_TAG('f','p','g','m'), 0, 0, NULL, TRUE },
63       { MS_MAKE_TAG('g','d','i','r'), 0, 0, NULL, TRUE },
64       { MS_MAKE_TAG('g','l','y','f'), 0, 0, NULL, FALSE },
65       { MS_MAKE_TAG('h','e','a','d'), 0, 0, NULL, TRUE },
66       { MS_MAKE_TAG('h','h','e','a'), 0, 0, NULL, TRUE },
67       { MS_MAKE_TAG('h','m','t','x'), 0, 0, NULL, TRUE },
68       { MS_MAKE_TAG('l','o','c','a'), 0, 0, NULL, TRUE },
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, maxp_tab;
78     int num_of_written_tables;
79     DWORD glyph_sent_size;
80     BOOL *glyph_sent;
81     DWORD emsize;
82     DWORD *glyf_blocks;
83 };
84
85 #define GLYPH_SENT_INC 128
86
87 #define FLIP_ORDER(x) \
88  ( ( ((x) & 0xff) << 24) | \
89    ( ((x) & 0xff00) << 8) | \
90    ( ((x) & 0xff0000) >> 8) | \
91    ( ((x) & 0xff000000) >> 24) )
92
93
94 /* Some flags for composite glyphs.  See glyf table in OT spec */
95 #define ARG_1_AND_2_ARE_WORDS    (1L << 0)
96 #define WE_HAVE_A_SCALE          (1L << 3)
97 #define MORE_COMPONENTS          (1L << 5)
98 #define WE_HAVE_AN_X_AND_Y_SCALE (1L << 6)
99 #define WE_HAVE_A_TWO_BY_TWO     (1L << 7)
100
101
102 static BOOL LoadTable(HDC hdc, OTTable *table)
103 {
104     unsigned int i;
105
106     if(table->MS_tag == MS_MAKE_TAG('g','d','i','r')) return TRUE;
107     table->len = GetFontData(hdc, table->MS_tag, 0, NULL, 0);
108     table->data = HeapAlloc(GetProcessHeap(), 0, (table->len + 3) & ~3 );
109     memset(table->data + ((table->len - 1) & ~3), 0, sizeof(DWORD));
110     GetFontData(hdc, table->MS_tag, 0, table->data, table->len);
111     table->check = 0;
112     for(i = 0; i < (table->len + 3) / 4; i++)
113         table->check += FLIP_ORDER(*((DWORD*)(table->data) + i));
114     return TRUE;
115 }
116
117 static BOOL get_glyf_pos(TYPE42 *t42, DWORD index, DWORD *start, DWORD *end)
118 {
119     WORD loca_format = GET_BE_WORD(t42->tables[t42->head_tab].data + 50);
120     TRACE("loca_format = %d\n", loca_format);
121     switch(loca_format) {
122     case 0:
123         *start = GET_BE_WORD(((WORD*)t42->tables[t42->loca_tab].data) + index);
124         *start <<= 1;
125         *end = GET_BE_WORD(((WORD*)t42->tables[t42->loca_tab].data) + index + 1);
126         *end <<= 1;
127         break;
128     case 1:
129         *start = GET_BE_DWORD(((DWORD*)t42->tables[t42->loca_tab].data) + index);
130         *end = GET_BE_DWORD(((DWORD*)t42->tables[t42->loca_tab].data) + index + 1);
131         break;
132     default:
133         ERR("Unknown loca_format %d\n", loca_format);
134         return FALSE;
135     }
136     return TRUE;
137 }
138
139 TYPE42 *T42_download_header(PSDRV_PDEVICE *physDev, char *ps_name,
140                             RECT *bbox, UINT emsize)
141 {
142     DWORD i, j, tablepos, nb_blocks, glyf_off = 0, loca_off = 0, cur_off;
143     WORD num_of_tables = sizeof(tables_templ) / sizeof(tables_templ[0]) - 1;
144     char *buf;
145     TYPE42 *t42;
146     static const char start[] = /* name, fontbbox */
147             "25 dict begin\n"
148             " /FontName /%s def\n"
149             " /Encoding 256 array 0 1 255{1 index exch /.notdef put} for\n"
150             " def\n"
151             " /PaintType 0 def\n"
152             " /FontMatrix [1 0 0 1 0 0] def\n"
153             " /FontBBox [%f %f %f %f] def\n"
154             " /FontType 42 def\n"
155             " /CharStrings 256 dict begin\n"
156             "  /.notdef 0 def\n"
157             " currentdict end def\n"
158             " /sfnts [\n";
159     static const char TT_offset_table[] = "<00010000%04x%04x%04x%04x\n";
160     static const char TT_table_dir_entry[] = "%08x%08x%08x%08x\n";
161     static const char storage[] ="]\nhavetype42gdir{pop}{{string} forall}ifelse\n";
162     static const char end[] = "] def\n"
163       "havetype42gdir{/GlyphDirectory 256 dict def\n"
164       " sfnts 0 get dup\n"
165       "  %d <6c6f6378000000000000000000000000> putinterval\n" /* replace loca entry with dummy locx */
166       "  %d <676c6678000000000000000000000000> putinterval\n" /* replace glyf entry with dummy glfx */
167       " }if\n"
168       "currentdict end dup /FontName get exch definefont pop\n";
169
170
171     t42 = HeapAlloc(GetProcessHeap(), 0, sizeof(*t42));
172     memcpy(t42->tables, tables_templ, sizeof(tables_templ));
173     t42->loca_tab = t42->glyf_tab = t42->head_tab = t42->hmtx_tab = -1;
174     t42->emsize = emsize;
175     t42->num_of_written_tables = 0;
176
177     for(i = 0; i < num_of_tables; i++) {
178         LoadTable(physDev->hdc, t42->tables + i);
179         if(t42->tables[i].len > 0xffff && t42->tables[i].write) break;
180         if(t42->tables[i].write) t42->num_of_written_tables++;
181         if(t42->tables[i].MS_tag == MS_MAKE_TAG('l','o','c','a'))
182             t42->loca_tab = i;
183         else if(t42->tables[i].MS_tag == MS_MAKE_TAG('g','l','y','f'))
184             t42->glyf_tab = i;
185         else if(t42->tables[i].MS_tag == MS_MAKE_TAG('h','e','a','d'))
186             t42->head_tab = i;
187         else if(t42->tables[i].MS_tag == MS_MAKE_TAG('h','m','t','x'))
188             t42->hmtx_tab = i;
189         else if(t42->tables[i].MS_tag == MS_MAKE_TAG('m','a','x','p'))
190             t42->maxp_tab = i;
191     }
192     if(i < num_of_tables) {
193         TRACE("Table %d has length %d.  Will use Type 1 font instead.\n", i, t42->tables[i].len);
194         T42_free(t42);
195         return NULL;
196     }
197
198     t42->glyph_sent_size = GLYPH_SENT_INC;
199     t42->glyph_sent = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
200                                 t42->glyph_sent_size *
201                                 sizeof(*(t42->glyph_sent)));
202
203     buf = HeapAlloc(GetProcessHeap(), 0, sizeof(start) + strlen(ps_name) +
204                     100);
205
206     push_lc_numeric("C");
207     sprintf(buf, start, ps_name,
208             (float)bbox->left / emsize, (float)bbox->bottom / emsize,
209             (float)bbox->right / emsize, (float)bbox->top / emsize);
210     pop_lc_numeric();
211
212     PSDRV_WriteSpool(physDev, buf, strlen(buf));
213
214     t42->num_of_written_tables++; /* explicitly add glyf */
215     sprintf(buf, TT_offset_table, t42->num_of_written_tables,
216             t42->num_of_written_tables, t42->num_of_written_tables, t42->num_of_written_tables);
217
218     PSDRV_WriteSpool(physDev, buf, strlen(buf));
219
220     tablepos = 12 + t42->num_of_written_tables * 16;
221     cur_off = 12;
222     for(i = 0; i < num_of_tables; i++) {
223         if(!t42->tables[i].write) continue;
224         sprintf(buf, TT_table_dir_entry, FLIP_ORDER(t42->tables[i].MS_tag),
225                 t42->tables[i].check, t42->tables[i].len ? tablepos : 0,
226                 t42->tables[i].len);
227         PSDRV_WriteSpool(physDev, buf, strlen(buf));
228         tablepos += ((t42->tables[i].len + 3) & ~3);
229         if(t42->tables[i].MS_tag == MS_MAKE_TAG('l','o','c','a'))
230             loca_off = cur_off;
231         cur_off += 16;
232     }
233     sprintf(buf, TT_table_dir_entry, FLIP_ORDER(t42->tables[t42->glyf_tab].MS_tag),
234             t42->tables[t42->glyf_tab].check, tablepos, t42->tables[t42->glyf_tab].len);
235     PSDRV_WriteSpool(physDev, buf, strlen(buf));
236     PSDRV_WriteSpool(physDev, "00>\n", 4); /* add an extra byte for old PostScript rips */
237     glyf_off = cur_off;
238
239     for(i = 0; i < num_of_tables; i++) {
240         if(t42->tables[i].len == 0 || !t42->tables[i].write) continue;
241         PSDRV_WriteSpool(physDev, "<", 1);
242         for(j = 0; j < ((t42->tables[i].len + 3) & ~3); j++) {
243             sprintf(buf, "%02x", t42->tables[i].data[j]);
244             PSDRV_WriteSpool(physDev, buf, strlen(buf));
245             if(j % 16 == 15) PSDRV_WriteSpool(physDev, "\n", 1);
246         }
247         PSDRV_WriteSpool(physDev, "00>\n", 4); /* add an extra byte for old PostScript rips */
248     }
249     
250     /* glyf_blocks is a 0 terminated list, holding the start offset of each block.  For simplicity
251        glyf_blocks[0] is 0 */
252     nb_blocks = 2;
253     t42->glyf_blocks = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (nb_blocks + 1) * sizeof(DWORD));
254     for(i = 0; i < GET_BE_WORD(t42->tables[t42->maxp_tab].data + 4); i++) {
255         DWORD start, end, size;
256         get_glyf_pos(t42, i, &start, &end);
257         size = end - t42->glyf_blocks[nb_blocks-2];
258         if(size > 0x2000 && t42->glyf_blocks[nb_blocks-1] % 4 == 0) {
259             nb_blocks++;
260             t42->glyf_blocks = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
261                                            t42->glyf_blocks, (nb_blocks + 1) * sizeof(DWORD));
262         }
263         t42->glyf_blocks[nb_blocks-1] = end;
264     }
265
266     PSDRV_WriteSpool(physDev, "[ ", 2);
267     for(i = 1; t42->glyf_blocks[i]; i++) {
268         sprintf(buf,"%d ", t42->glyf_blocks[i] - t42->glyf_blocks[i-1] + 1);
269         /* again add one byte for old PostScript rips */
270         PSDRV_WriteSpool(physDev, buf, strlen(buf));
271         if(i % 8 == 0)
272             PSDRV_WriteSpool(physDev, "\n", 1);
273     }
274     PSDRV_WriteSpool(physDev, storage, sizeof(storage) - 1);
275     sprintf(buf, end, loca_off, glyf_off);
276     PSDRV_WriteSpool(physDev, buf, strlen(buf));
277     HeapFree(GetProcessHeap(), 0, buf);
278     return t42;
279 }
280
281
282
283
284 BOOL T42_download_glyph(PSDRV_PDEVICE *physDev, DOWNLOAD *pdl, DWORD index,
285                         char *glyph_name)
286 {
287     DWORD start, end, i;
288     char *buf;
289     TYPE42 *t42;
290     WORD awidth;
291     short lsb;
292
293     const char glyph_def[] = 
294       "/%s findfont exch 1 index\n"
295       "havetype42gdir\n"
296       "{/GlyphDirectory get begin %d exch def end}\n"
297       "{/sfnts get 4 index get 3 index 2 index putinterval pop}\n"
298       "ifelse\n"
299       "/CharStrings get\n"
300       "begin\n"
301       " /%s %d def\n"
302       "end\n"
303       "pop pop\n";
304
305     TRACE("%d %s\n", index, glyph_name);
306     assert(pdl->type == Type42);
307     t42 = pdl->typeinfo.Type42;
308
309     if(index < t42->glyph_sent_size) {
310         if(t42->glyph_sent[index])
311             return TRUE;
312     } else {
313         t42->glyph_sent_size = (index / GLYPH_SENT_INC + 1) * GLYPH_SENT_INC;
314         t42->glyph_sent = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
315                                       t42->glyph_sent,
316                                       t42->glyph_sent_size * sizeof(*(t42->glyph_sent)));
317     }
318
319     buf = HeapAlloc(GetProcessHeap(), 0, sizeof(glyph_def) +
320                     strlen(pdl->ps_name) + 100);
321
322     if(!get_glyf_pos(t42, index, &start, &end)) return FALSE;
323     TRACE("start = %x end = %x\n", start, end);
324
325     awidth = GET_BE_WORD(t42->tables[t42->hmtx_tab].data + index * 4);
326     lsb = GET_BE_WORD(t42->tables[t42->hmtx_tab].data + index * 4 + 2);
327
328     if(GET_BE_WORD(t42->tables[t42->glyf_tab].data + start) == 0xffff) {
329       /* Composite glyph */
330         BYTE *sg_start = t42->tables[t42->glyf_tab].data + start + 10;
331         DWORD sg_flags, sg_index;
332         char sg_name[MAX_G_NAME + 1];
333
334         do {
335             sg_flags = GET_BE_WORD(sg_start);
336             sg_index = GET_BE_WORD(sg_start + 2);
337
338             TRACE("Sending subglyph %04x for glyph %04x\n", sg_index, index);
339             get_glyph_name(physDev->hdc, sg_index, sg_name);
340             T42_download_glyph(physDev, pdl, sg_index, sg_name);
341             sg_start += 4;
342             if(sg_flags & ARG_1_AND_2_ARE_WORDS)
343                 sg_start += 4;
344             else
345                 sg_start += 2;
346             if(sg_flags & WE_HAVE_A_SCALE)
347                 sg_start += 2;
348             else if(sg_flags & WE_HAVE_AN_X_AND_Y_SCALE)
349                 sg_start += 4;
350             else if(sg_flags & WE_HAVE_A_TWO_BY_TWO)
351                 sg_start += 8;
352         } while(sg_flags & MORE_COMPONENTS);
353     }
354
355     for(i = 1; t42->glyf_blocks[i]; i++)
356         if(start < t42->glyf_blocks[i]) break;
357     /* we don't have a string for the gdir and glyf tables, but we do have a 
358        string for the TT header.  So the offset we need is tables - 2 */
359     sprintf(buf, "%d %d\n", t42->num_of_written_tables - 2 + i, start - t42->glyf_blocks[i-1]);
360     PSDRV_WriteSpool(physDev, buf, strlen(buf));
361
362     PSDRV_WriteSpool(physDev, "<", 1);
363     for(i = start; i < end; i++) {
364         sprintf(buf, "%02x", *(t42->tables[t42->glyf_tab].data + i));
365         PSDRV_WriteSpool(physDev, buf, strlen(buf));
366         if((i - start) % 16 == 15)
367             PSDRV_WriteSpool(physDev, "\n", 1);
368     }
369     PSDRV_WriteSpool(physDev, ">\n", 2);
370     sprintf(buf, glyph_def, pdl->ps_name, index, glyph_name, index);
371     PSDRV_WriteSpool(physDev, buf, strlen(buf));
372
373     t42->glyph_sent[index] = TRUE;
374     HeapFree(GetProcessHeap(), 0, buf);
375     return TRUE;
376 }
377
378 void T42_free(TYPE42 *t42)
379 {
380     OTTable *table;
381     for(table = t42->tables; table->MS_tag; table++)
382         HeapFree(GetProcessHeap(), 0, table->data);
383     HeapFree(GetProcessHeap(), 0, t42->glyph_sent);
384     HeapFree(GetProcessHeap(), 0, t42->glyf_blocks);
385     HeapFree(GetProcessHeap(), 0, t42);
386     return;
387 }