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