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