blob: a92b3e6f4d9937ecfcd053f4e09a243cfc64c7b0 [file] [log] [blame]
Huw D M Daviesae4278e2002-06-24 23:44:18 +00001/*
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 */
Alexandre Julliardbb133bd2004-04-07 03:59:41 +000020
21#include "config.h"
22#include "wine/port.h"
23
Huw D M Daviesae4278e2002-06-24 23:44:18 +000024#include <string.h>
25#include <stdlib.h>
Alexandre Julliarde37c6e12003-09-05 23:08:26 +000026#include <stdarg.h>
Huw D M Daviesae4278e2002-06-24 23:44:18 +000027#include <stdio.h>
28#include <assert.h>
Marcus Meissner2f4b33c2004-10-05 22:31:14 +000029#include <locale.h>
Francois Gouget3efacb02003-01-07 23:09:22 +000030
Alexandre Julliarde37c6e12003-09-05 23:08:26 +000031#include "windef.h"
Francois Gouget3efacb02003-01-07 23:09:22 +000032#include "winbase.h"
33#include "winerror.h"
34#include "wingdi.h"
Huw D M Daviesae4278e2002-06-24 23:44:18 +000035#include "winspool.h"
Francois Gouget3efacb02003-01-07 23:09:22 +000036
Huw D M Daviesae4278e2002-06-24 23:44:18 +000037#include "psdrv.h"
38#include "wine/debug.h"
Huw D M Daviesae4278e2002-06-24 23:44:18 +000039
40WINE_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
53typedef struct {
54 DWORD MS_tag;
55 DWORD len, check;
56 BYTE *data;
57 BOOL write;
58} OTTable;
59
60const 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 },
Huw Davies5d275962002-11-13 23:51:44 +000067 { MS_MAKE_TAG('h','m','t','x'), 0, 0, NULL, TRUE },
Huw Davies14c90e82003-06-23 19:57:08 +000068 { MS_MAKE_TAG('l','o','c','a'), 0, 0, NULL, TRUE },
Huw D M Daviesae4278e2002-06-24 23:44:18 +000069 { 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
74struct 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 */
Huw Davies14c90e82003-06-23 19:57:08 +000077 int hmtx_tab, maxp_tab;
78 int num_of_written_tables;
Huw D M Daviesae4278e2002-06-24 23:44:18 +000079 DWORD glyph_sent_size;
80 BOOL *glyph_sent;
81 DWORD emsize;
Huw Davies14c90e82003-06-23 19:57:08 +000082 DWORD *glyf_blocks;
Huw D M Daviesae4278e2002-06-24 23:44:18 +000083};
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
Huw Davies5d275962002-11-13 23:51:44 +0000101
Huw D M Daviesae4278e2002-06-24 23:44:18 +0000102static BOOL LoadTable(HDC hdc, OTTable *table)
103{
Hans Leidekker719a7892004-09-22 02:46:38 +0000104 unsigned int i;
Huw D M Daviesae4278e2002-06-24 23:44:18 +0000105
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
Huw Davies14c90e82003-06-23 19:57:08 +0000117static 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}
Huw D M Daviesae4278e2002-06-24 23:44:18 +0000138
Huw Daviesef2ac7a2003-11-12 22:42:55 +0000139TYPE42 *T42_download_header(PSDRV_PDEVICE *physDev, char *ps_name,
140 RECT *bbox, UINT emsize)
Huw D M Daviesae4278e2002-06-24 23:44:18 +0000141{
Huw Davies14c90e82003-06-23 19:57:08 +0000142 DWORD i, j, tablepos, nb_blocks, glyf_off = 0, loca_off = 0, cur_off;
Huw D M Daviesae4278e2002-06-24 23:44:18 +0000143 WORD num_of_tables = sizeof(tables_templ) / sizeof(tables_templ[0]) - 1;
Huw D M Daviesae4278e2002-06-24 23:44:18 +0000144 char *buf;
145 TYPE42 *t42;
Francois Gougetcfc39432004-05-04 04:13:05 +0000146 static const char start[] = /* name, fontbbox */
Huw D M Daviesae4278e2002-06-24 23:44:18 +0000147 "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"
Huw D M Daviesae4278e2002-06-24 23:44:18 +0000158 " /sfnts [\n";
Francois Gougetcfc39432004-05-04 04:13:05 +0000159 static const char TT_offset_table[] = "<00010000%04x%04x%04x%04x\n";
160 static const char TT_table_dir_entry[] = "%08lx%08lx%08lx%08lx\n";
161 static const char storage[] ="]\nhavetype42gdir{pop}{{string} forall}ifelse\n";
162 static const char end[] = "] def\n"
Huw Davies14c90e82003-06-23 19:57:08 +0000163 "havetype42gdir{/GlyphDirectory 256 dict def\n"
Huw Daviesef2ac7a2003-11-12 22:42:55 +0000164 " sfnts 0 get dup %ld (locx) putinterval %ld (glfx) putinterval}if\n"
Huw D M Daviesae4278e2002-06-24 23:44:18 +0000165 "currentdict end dup /FontName get exch definefont pop\n";
166
167
168 t42 = HeapAlloc(GetProcessHeap(), 0, sizeof(*t42));
169 memcpy(t42->tables, tables_templ, sizeof(tables_templ));
170 t42->loca_tab = t42->glyf_tab = t42->head_tab = t42->hmtx_tab = -1;
Huw Daviesef2ac7a2003-11-12 22:42:55 +0000171 t42->emsize = emsize;
Huw Davies14c90e82003-06-23 19:57:08 +0000172 t42->num_of_written_tables = 0;
Huw D M Daviesae4278e2002-06-24 23:44:18 +0000173
174 for(i = 0; i < num_of_tables; i++) {
175 LoadTable(physDev->hdc, t42->tables + i);
Huw Davies5d275962002-11-13 23:51:44 +0000176 if(t42->tables[i].len > 0xffff && t42->tables[i].write) break;
Huw Davies14c90e82003-06-23 19:57:08 +0000177 if(t42->tables[i].write) t42->num_of_written_tables++;
Huw D M Daviesae4278e2002-06-24 23:44:18 +0000178 if(t42->tables[i].MS_tag == MS_MAKE_TAG('l','o','c','a'))
179 t42->loca_tab = i;
180 else if(t42->tables[i].MS_tag == MS_MAKE_TAG('g','l','y','f'))
181 t42->glyf_tab = i;
182 else if(t42->tables[i].MS_tag == MS_MAKE_TAG('h','e','a','d'))
183 t42->head_tab = i;
184 else if(t42->tables[i].MS_tag == MS_MAKE_TAG('h','m','t','x'))
185 t42->hmtx_tab = i;
Huw Davies14c90e82003-06-23 19:57:08 +0000186 else if(t42->tables[i].MS_tag == MS_MAKE_TAG('m','a','x','p'))
187 t42->maxp_tab = i;
Huw D M Daviesae4278e2002-06-24 23:44:18 +0000188 }
Huw Davies5d275962002-11-13 23:51:44 +0000189 if(i < num_of_tables) {
190 TRACE("Table %ld has length %ld. Will use Type 1 font instead.\n", i, t42->tables[i].len);
191 T42_free(t42);
192 return NULL;
193 }
194
195 t42->glyph_sent_size = GLYPH_SENT_INC;
196 t42->glyph_sent = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
197 t42->glyph_sent_size *
198 sizeof(*(t42->glyph_sent)));
Huw D M Daviesae4278e2002-06-24 23:44:18 +0000199
200 buf = HeapAlloc(GetProcessHeap(), 0, sizeof(start) + strlen(ps_name) +
201 100);
202
Marcus Meissner2f4b33c2004-10-05 22:31:14 +0000203 push_lc_numeric("C");
Huw D M Daviesae4278e2002-06-24 23:44:18 +0000204 sprintf(buf, start, ps_name,
Huw Daviesef2ac7a2003-11-12 22:42:55 +0000205 (float)bbox->left / emsize, (float)bbox->bottom / emsize,
206 (float)bbox->right / emsize, (float)bbox->top / emsize);
Marcus Meissner2f4b33c2004-10-05 22:31:14 +0000207 pop_lc_numeric();
Huw D M Daviesae4278e2002-06-24 23:44:18 +0000208
209 PSDRV_WriteSpool(physDev, buf, strlen(buf));
210
Huw Davies14c90e82003-06-23 19:57:08 +0000211 t42->num_of_written_tables++; /* explicitly add glyf */
212 sprintf(buf, TT_offset_table, t42->num_of_written_tables,
213 t42->num_of_written_tables, t42->num_of_written_tables, t42->num_of_written_tables);
Huw D M Daviesae4278e2002-06-24 23:44:18 +0000214
215 PSDRV_WriteSpool(physDev, buf, strlen(buf));
216
Huw Davies14c90e82003-06-23 19:57:08 +0000217 tablepos = 12 + t42->num_of_written_tables * 16;
218 cur_off = 12;
Huw D M Daviesae4278e2002-06-24 23:44:18 +0000219 for(i = 0; i < num_of_tables; i++) {
220 if(!t42->tables[i].write) continue;
221 sprintf(buf, TT_table_dir_entry, FLIP_ORDER(t42->tables[i].MS_tag),
222 t42->tables[i].check, t42->tables[i].len ? tablepos : 0,
223 t42->tables[i].len);
224 PSDRV_WriteSpool(physDev, buf, strlen(buf));
225 tablepos += ((t42->tables[i].len + 3) & ~3);
Huw Davies14c90e82003-06-23 19:57:08 +0000226 if(t42->tables[i].MS_tag == MS_MAKE_TAG('l','o','c','a'))
227 loca_off = cur_off;
228 cur_off += 16;
Huw D M Daviesae4278e2002-06-24 23:44:18 +0000229 }
Huw Davies14c90e82003-06-23 19:57:08 +0000230 sprintf(buf, TT_table_dir_entry, FLIP_ORDER(t42->tables[t42->glyf_tab].MS_tag),
231 t42->tables[t42->glyf_tab].check, tablepos, t42->tables[t42->glyf_tab].len);
232 PSDRV_WriteSpool(physDev, buf, strlen(buf));
233 PSDRV_WriteSpool(physDev, "00>\n", 4); /* add an extra byte for old PostScript rips */
234 glyf_off = cur_off;
Huw D M Daviesae4278e2002-06-24 23:44:18 +0000235
236 for(i = 0; i < num_of_tables; i++) {
237 if(t42->tables[i].len == 0 || !t42->tables[i].write) continue;
238 PSDRV_WriteSpool(physDev, "<", 1);
239 for(j = 0; j < ((t42->tables[i].len + 3) & ~3); j++) {
240 sprintf(buf, "%02x", t42->tables[i].data[j]);
241 PSDRV_WriteSpool(physDev, buf, strlen(buf));
242 if(j % 16 == 15) PSDRV_WriteSpool(physDev, "\n", 1);
243 }
Huw Davies14c90e82003-06-23 19:57:08 +0000244 PSDRV_WriteSpool(physDev, "00>\n", 4); /* add an extra byte for old PostScript rips */
245 }
246
247 /* glyf_blocks is a 0 terminated list, holding the start offset of each block. For simplicity
248 glyf_blocks[0] is 0 */
249 nb_blocks = 2;
250 t42->glyf_blocks = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (nb_blocks + 1) * sizeof(DWORD));
251 for(i = 0; i < GET_BE_WORD(t42->tables[t42->maxp_tab].data + 4); i++) {
252 DWORD start, end, size;
253 get_glyf_pos(t42, i, &start, &end);
254 size = end - t42->glyf_blocks[nb_blocks-2];
255 if(size > 0x2000 && t42->glyf_blocks[nb_blocks-1] % 4 == 0) {
256 nb_blocks++;
257 t42->glyf_blocks = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
258 t42->glyf_blocks, (nb_blocks + 1) * sizeof(DWORD));
259 }
260 t42->glyf_blocks[nb_blocks-1] = end;
Huw D M Daviesae4278e2002-06-24 23:44:18 +0000261 }
262
Huw Davies14c90e82003-06-23 19:57:08 +0000263 PSDRV_WriteSpool(physDev, "[ ", 2);
264 for(i = 1; t42->glyf_blocks[i]; i++) {
265 sprintf(buf,"%ld ", t42->glyf_blocks[i] - t42->glyf_blocks[i-1] + 1);
266 /* again add one byte for old PostScript rips */
267 PSDRV_WriteSpool(physDev, buf, strlen(buf));
268 if(i % 8 == 0)
269 PSDRV_WriteSpool(physDev, "\n", 1);
270 }
271 PSDRV_WriteSpool(physDev, storage, sizeof(storage) - 1);
272 sprintf(buf, end, loca_off, glyf_off);
273 PSDRV_WriteSpool(physDev, buf, strlen(buf));
Huw D M Daviesae4278e2002-06-24 23:44:18 +0000274 HeapFree(GetProcessHeap(), 0, buf);
275 return t42;
276}
277
278
279
280
281BOOL T42_download_glyph(PSDRV_PDEVICE *physDev, DOWNLOAD *pdl, DWORD index,
282 char *glyph_name)
283{
284 DWORD start, end, i;
285 char *buf;
286 TYPE42 *t42;
Huw D M Daviesae4278e2002-06-24 23:44:18 +0000287 WORD awidth;
288 short lsb;
Huw Davies5d275962002-11-13 23:51:44 +0000289
Dmitry Timoshkovb95693c2003-11-11 00:30:42 +0000290 const char glyph_def[] =
Huw Davies14c90e82003-06-23 19:57:08 +0000291 "/%s findfont exch 1 index\n"
292 "havetype42gdir\n"
Gerald Pfeifer149bb9e2003-11-11 20:40:27 +0000293 "{/GlyphDirectory get begin %ld exch def end}\n"
Huw Davies14c90e82003-06-23 19:57:08 +0000294 "{/sfnts get 4 index get 3 index 2 index putinterval pop}\n"
295 "ifelse\n"
Huw Davies5d275962002-11-13 23:51:44 +0000296 "/CharStrings get\n"
297 "begin\n"
Gerald Pfeifer149bb9e2003-11-11 20:40:27 +0000298 " /%s %ld def\n"
Huw Davies14c90e82003-06-23 19:57:08 +0000299 "end\n"
300 "pop pop\n";
Huw D M Daviesae4278e2002-06-24 23:44:18 +0000301
302 TRACE("%ld %s\n", index, glyph_name);
303 assert(pdl->type == Type42);
304 t42 = pdl->typeinfo.Type42;
305
306 if(index < t42->glyph_sent_size) {
307 if(t42->glyph_sent[index])
308 return TRUE;
309 } else {
310 t42->glyph_sent_size = (index / GLYPH_SENT_INC + 1) * GLYPH_SENT_INC;
311 t42->glyph_sent = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
312 t42->glyph_sent,
313 t42->glyph_sent_size * sizeof(*(t42->glyph_sent)));
314 }
315
316 buf = HeapAlloc(GetProcessHeap(), 0, sizeof(glyph_def) +
317 strlen(pdl->ps_name) + 100);
318
Huw Davies14c90e82003-06-23 19:57:08 +0000319 if(!get_glyf_pos(t42, index, &start, &end)) return FALSE;
Huw D M Daviesae4278e2002-06-24 23:44:18 +0000320 TRACE("start = %lx end = %lx\n", start, end);
321
322 awidth = GET_BE_WORD(t42->tables[t42->hmtx_tab].data + index * 4);
323 lsb = GET_BE_WORD(t42->tables[t42->hmtx_tab].data + index * 4 + 2);
324
325 if(GET_BE_WORD(t42->tables[t42->glyf_tab].data + start) == 0xffff) {
326 /* Composite glyph */
327 char *sg_start = t42->tables[t42->glyf_tab].data + start + 10;
328 DWORD sg_flags, sg_index;
329 char sg_name[MAX_G_NAME + 1];
330
331 do {
332 sg_flags = GET_BE_WORD(sg_start);
333 sg_index = GET_BE_WORD(sg_start + 2);
334
335 TRACE("Sending subglyph %04lx for glyph %04lx\n", sg_index, index);
336 get_glyph_name(physDev->hdc, sg_index, sg_name);
337 T42_download_glyph(physDev, pdl, sg_index, sg_name);
338 sg_start += 4;
339 if(sg_flags & ARG_1_AND_2_ARE_WORDS)
340 sg_start += 4;
341 else
342 sg_start += 2;
343 if(sg_flags & WE_HAVE_A_SCALE)
344 sg_start += 2;
345 else if(sg_flags & WE_HAVE_AN_X_AND_Y_SCALE)
346 sg_start += 4;
347 else if(sg_flags & WE_HAVE_A_TWO_BY_TWO)
348 sg_start += 8;
349 } while(sg_flags & MORE_COMPONENTS);
350 }
351
Huw Davies14c90e82003-06-23 19:57:08 +0000352 for(i = 1; t42->glyf_blocks[i]; i++)
353 if(start < t42->glyf_blocks[i]) break;
354 /* we don't have a string for the gdir and glyf tables, but we do have a
355 string for the TT header. So the offset we need is tables - 2 */
356 sprintf(buf, "%ld %ld\n", t42->num_of_written_tables - 2 + i, start - t42->glyf_blocks[i-1]);
Huw D M Daviesae4278e2002-06-24 23:44:18 +0000357 PSDRV_WriteSpool(physDev, buf, strlen(buf));
Huw Davies14c90e82003-06-23 19:57:08 +0000358
Huw D M Daviesae4278e2002-06-24 23:44:18 +0000359 PSDRV_WriteSpool(physDev, "<", 1);
360 for(i = start; i < end; i++) {
361 sprintf(buf, "%02x", *(t42->tables[t42->glyf_tab].data + i));
362 PSDRV_WriteSpool(physDev, buf, strlen(buf));
363 if((i - start) % 16 == 15)
364 PSDRV_WriteSpool(physDev, "\n", 1);
365 }
366 PSDRV_WriteSpool(physDev, ">\n", 2);
Huw Davies5d275962002-11-13 23:51:44 +0000367 sprintf(buf, glyph_def, pdl->ps_name, index, glyph_name, index);
Huw D M Daviesae4278e2002-06-24 23:44:18 +0000368 PSDRV_WriteSpool(physDev, buf, strlen(buf));
369
370 t42->glyph_sent[index] = TRUE;
371 HeapFree(GetProcessHeap(), 0, buf);
372 return TRUE;
373}
374
375void T42_free(TYPE42 *t42)
376{
377 OTTable *table;
378 for(table = t42->tables; table->MS_tag; table++)
Michael Stefaniuc15a308a2005-01-03 14:56:42 +0000379 HeapFree(GetProcessHeap(), 0, table->data);
Michael Stefaniuc5ad7d852004-12-23 17:06:43 +0000380 HeapFree(GetProcessHeap(), 0, t42->glyph_sent);
381 HeapFree(GetProcessHeap(), 0, t42->glyf_blocks);
Huw D M Daviesae4278e2002-06-24 23:44:18 +0000382 HeapFree(GetProcessHeap(), 0, t42);
383 return;
384}