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
22 #include "wine/port.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 ) | \
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
},
73 OTTable tables
[sizeof(tables_templ
)/sizeof(tables_templ
[0])];
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
;
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
)
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
);
110 for(i
= 0; i
< (table
->len
+ 3) / 4; i
++)
111 table
->check
+= FLIP_ORDER(*((DWORD
*)(table
->data
) + i
));
115 static BOOL
get_glyf_pos(TYPE42
*t42
, DWORD index
, DWORD
*start
, DWORD
*end
)
117 WORD loca_format
= GET_BE_WORD(t42
->tables
[t42
->head_tab
].data
+ 50);
118 TRACE("loca_format = %d\n", loca_format
);
119 switch(loca_format
) {
121 *start
= GET_BE_WORD(((WORD
*)t42
->tables
[t42
->loca_tab
].data
) + index
);
123 *end
= GET_BE_WORD(((WORD
*)t42
->tables
[t42
->loca_tab
].data
) + index
+ 1);
127 *start
= GET_BE_DWORD(((DWORD
*)t42
->tables
[t42
->loca_tab
].data
) + index
);
128 *end
= GET_BE_DWORD(((DWORD
*)t42
->tables
[t42
->loca_tab
].data
) + index
+ 1);
131 ERR("Unknown loca_format %d\n", loca_format
);
137 TYPE42
*T42_download_header(PSDRV_PDEVICE
*physDev
, char *ps_name
,
138 RECT
*bbox
, UINT emsize
)
140 DWORD i
, j
, tablepos
, nb_blocks
, glyf_off
= 0, loca_off
= 0, cur_off
;
141 WORD num_of_tables
= sizeof(tables_templ
) / sizeof(tables_templ
[0]) - 1;
144 static const char start
[] = /* name, fontbbox */
146 " /FontName /%s def\n"
147 " /Encoding 256 array 0 1 255{1 index exch /.notdef put} for\n"
149 " /PaintType 0 def\n"
150 " /FontMatrix [1 0 0 1 0 0] def\n"
151 " /FontBBox [%f %f %f %f] def\n"
152 " /FontType 42 def\n"
153 " /CharStrings 256 dict begin\n"
155 " currentdict end def\n"
157 static const char TT_offset_table
[] = "<00010000%04x%04x%04x%04x\n";
158 static const char TT_table_dir_entry
[] = "%08x%08x%08x%08x\n";
159 static const char storage
[] ="]\nhavetype42gdir{pop}{{string} forall}ifelse\n";
160 static const char end
[] = "] def\n"
161 "havetype42gdir{/GlyphDirectory 256 dict def\n"
163 " %d <6c6f6378000000000000000000000000> putinterval\n" /* replace loca entry with dummy locx */
164 " %d <676c6678000000000000000000000000> putinterval\n" /* replace glyf entry with dummy glfx */
166 "currentdict end dup /FontName get exch definefont pop\n";
169 t42
= HeapAlloc(GetProcessHeap(), 0, sizeof(*t42
));
170 memcpy(t42
->tables
, tables_templ
, sizeof(tables_templ
));
171 t42
->loca_tab
= t42
->glyf_tab
= t42
->head_tab
= t42
->hmtx_tab
= -1;
172 t42
->emsize
= emsize
;
173 t42
->num_of_written_tables
= 0;
175 for(i
= 0; i
< num_of_tables
; i
++) {
176 LoadTable(physDev
->hdc
, t42
->tables
+ i
);
177 if(t42
->tables
[i
].len
> 0xffff && t42
->tables
[i
].write
) break;
178 if(t42
->tables
[i
].write
) t42
->num_of_written_tables
++;
179 if(t42
->tables
[i
].MS_tag
== MS_MAKE_TAG('l','o','c','a'))
181 else if(t42
->tables
[i
].MS_tag
== MS_MAKE_TAG('g','l','y','f'))
183 else if(t42
->tables
[i
].MS_tag
== MS_MAKE_TAG('h','e','a','d'))
185 else if(t42
->tables
[i
].MS_tag
== MS_MAKE_TAG('h','m','t','x'))
187 else if(t42
->tables
[i
].MS_tag
== MS_MAKE_TAG('m','a','x','p'))
190 if(i
< num_of_tables
) {
191 TRACE("Table %d has length %d. Will use Type 1 font instead.\n", i
, t42
->tables
[i
].len
);
196 t42
->glyph_sent_size
= GLYPH_SENT_INC
;
197 t42
->glyph_sent
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
198 t42
->glyph_sent_size
*
199 sizeof(*(t42
->glyph_sent
)));
201 buf
= HeapAlloc(GetProcessHeap(), 0, sizeof(start
) + strlen(ps_name
) +
204 push_lc_numeric("C");
205 sprintf(buf
, start
, ps_name
,
206 (float)bbox
->left
/ emsize
, (float)bbox
->bottom
/ emsize
,
207 (float)bbox
->right
/ emsize
, (float)bbox
->top
/ emsize
);
210 PSDRV_WriteSpool(physDev
, buf
, strlen(buf
));
212 t42
->num_of_written_tables
++; /* explicitly add glyf */
213 sprintf(buf
, TT_offset_table
, t42
->num_of_written_tables
,
214 t42
->num_of_written_tables
, t42
->num_of_written_tables
, t42
->num_of_written_tables
);
216 PSDRV_WriteSpool(physDev
, buf
, strlen(buf
));
218 tablepos
= 12 + t42
->num_of_written_tables
* 16;
220 for(i
= 0; i
< num_of_tables
; i
++) {
221 if(!t42
->tables
[i
].write
) continue;
222 sprintf(buf
, TT_table_dir_entry
, FLIP_ORDER(t42
->tables
[i
].MS_tag
),
223 t42
->tables
[i
].check
, t42
->tables
[i
].len
? tablepos
: 0,
225 PSDRV_WriteSpool(physDev
, buf
, strlen(buf
));
226 tablepos
+= ((t42
->tables
[i
].len
+ 3) & ~3);
227 if(t42
->tables
[i
].MS_tag
== MS_MAKE_TAG('l','o','c','a'))
231 sprintf(buf
, TT_table_dir_entry
, FLIP_ORDER(t42
->tables
[t42
->glyf_tab
].MS_tag
),
232 t42
->tables
[t42
->glyf_tab
].check
, tablepos
, t42
->tables
[t42
->glyf_tab
].len
);
233 PSDRV_WriteSpool(physDev
, buf
, strlen(buf
));
234 PSDRV_WriteSpool(physDev
, "00>\n", 4); /* add an extra byte for old PostScript rips */
237 for(i
= 0; i
< num_of_tables
; i
++) {
238 if(t42
->tables
[i
].len
== 0 || !t42
->tables
[i
].write
) continue;
239 PSDRV_WriteSpool(physDev
, "<", 1);
240 for(j
= 0; j
< ((t42
->tables
[i
].len
+ 3) & ~3); j
++) {
241 sprintf(buf
, "%02x", t42
->tables
[i
].data
[j
]);
242 PSDRV_WriteSpool(physDev
, buf
, strlen(buf
));
243 if(j
% 16 == 15) PSDRV_WriteSpool(physDev
, "\n", 1);
245 PSDRV_WriteSpool(physDev
, "00>\n", 4); /* add an extra byte for old PostScript rips */
248 /* glyf_blocks is a 0 terminated list, holding the start offset of each block. For simplicity
249 glyf_blocks[0] is 0 */
251 t42
->glyf_blocks
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, (nb_blocks
+ 1) * sizeof(DWORD
));
252 for(i
= 0; i
< GET_BE_WORD(t42
->tables
[t42
->maxp_tab
].data
+ 4); i
++) {
253 DWORD start
, end
, size
;
254 get_glyf_pos(t42
, i
, &start
, &end
);
255 size
= end
- t42
->glyf_blocks
[nb_blocks
-2];
256 if(size
> 0x2000 && t42
->glyf_blocks
[nb_blocks
-1] % 4 == 0) {
258 t42
->glyf_blocks
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
259 t42
->glyf_blocks
, (nb_blocks
+ 1) * sizeof(DWORD
));
261 t42
->glyf_blocks
[nb_blocks
-1] = end
;
264 PSDRV_WriteSpool(physDev
, "[ ", 2);
265 for(i
= 1; t42
->glyf_blocks
[i
]; i
++) {
266 sprintf(buf
,"%d ", t42
->glyf_blocks
[i
] - t42
->glyf_blocks
[i
-1] + 1);
267 /* again add one byte for old PostScript rips */
268 PSDRV_WriteSpool(physDev
, buf
, strlen(buf
));
270 PSDRV_WriteSpool(physDev
, "\n", 1);
272 PSDRV_WriteSpool(physDev
, storage
, sizeof(storage
) - 1);
273 sprintf(buf
, end
, loca_off
, glyf_off
);
274 PSDRV_WriteSpool(physDev
, buf
, strlen(buf
));
275 HeapFree(GetProcessHeap(), 0, buf
);
282 BOOL
T42_download_glyph(PSDRV_PDEVICE
*physDev
, DOWNLOAD
*pdl
, DWORD index
,
291 const char glyph_def
[] =
292 "/%s findfont exch 1 index\n"
294 "{/GlyphDirectory get begin %d exch def end}\n"
295 "{/sfnts get 4 index get 3 index 2 index putinterval pop}\n"
303 TRACE("%d %s\n", index
, glyph_name
);
304 assert(pdl
->type
== Type42
);
305 t42
= pdl
->typeinfo
.Type42
;
307 if(index
< t42
->glyph_sent_size
) {
308 if(t42
->glyph_sent
[index
])
311 t42
->glyph_sent_size
= (index
/ GLYPH_SENT_INC
+ 1) * GLYPH_SENT_INC
;
312 t42
->glyph_sent
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
314 t42
->glyph_sent_size
* sizeof(*(t42
->glyph_sent
)));
317 buf
= HeapAlloc(GetProcessHeap(), 0, sizeof(glyph_def
) +
318 strlen(pdl
->ps_name
) + 100);
320 if(!get_glyf_pos(t42
, index
, &start
, &end
)) return FALSE
;
321 TRACE("start = %x end = %x\n", start
, end
);
323 awidth
= GET_BE_WORD(t42
->tables
[t42
->hmtx_tab
].data
+ index
* 4);
324 lsb
= GET_BE_WORD(t42
->tables
[t42
->hmtx_tab
].data
+ index
* 4 + 2);
326 if(GET_BE_WORD(t42
->tables
[t42
->glyf_tab
].data
+ start
) == 0xffff) {
327 /* Composite glyph */
328 BYTE
*sg_start
= t42
->tables
[t42
->glyf_tab
].data
+ start
+ 10;
329 DWORD sg_flags
, sg_index
;
330 char sg_name
[MAX_G_NAME
+ 1];
333 sg_flags
= GET_BE_WORD(sg_start
);
334 sg_index
= GET_BE_WORD(sg_start
+ 2);
336 TRACE("Sending subglyph %04x for glyph %04x\n", sg_index
, index
);
337 get_glyph_name(physDev
->hdc
, sg_index
, sg_name
);
338 T42_download_glyph(physDev
, pdl
, sg_index
, sg_name
);
340 if(sg_flags
& ARG_1_AND_2_ARE_WORDS
)
344 if(sg_flags
& WE_HAVE_A_SCALE
)
346 else if(sg_flags
& WE_HAVE_AN_X_AND_Y_SCALE
)
348 else if(sg_flags
& WE_HAVE_A_TWO_BY_TWO
)
350 } while(sg_flags
& MORE_COMPONENTS
);
353 for(i
= 1; t42
->glyf_blocks
[i
]; i
++)
354 if(start
< t42
->glyf_blocks
[i
]) break;
355 /* we don't have a string for the gdir and glyf tables, but we do have a
356 string for the TT header. So the offset we need is tables - 2 */
357 sprintf(buf
, "%d %d\n", t42
->num_of_written_tables
- 2 + i
, start
- t42
->glyf_blocks
[i
-1]);
358 PSDRV_WriteSpool(physDev
, buf
, strlen(buf
));
360 PSDRV_WriteSpool(physDev
, "<", 1);
361 for(i
= start
; i
< end
; i
++) {
362 sprintf(buf
, "%02x", *(t42
->tables
[t42
->glyf_tab
].data
+ i
));
363 PSDRV_WriteSpool(physDev
, buf
, strlen(buf
));
364 if((i
- start
) % 16 == 15)
365 PSDRV_WriteSpool(physDev
, "\n", 1);
367 PSDRV_WriteSpool(physDev
, ">\n", 2);
368 sprintf(buf
, glyph_def
, pdl
->ps_name
, index
, glyph_name
, index
);
369 PSDRV_WriteSpool(physDev
, buf
, strlen(buf
));
371 t42
->glyph_sent
[index
] = TRUE
;
372 HeapFree(GetProcessHeap(), 0, buf
);
376 void T42_free(TYPE42
*t42
)
379 for(table
= t42
->tables
; table
->MS_tag
; table
++)
380 HeapFree(GetProcessHeap(), 0, table
->data
);
381 HeapFree(GetProcessHeap(), 0, t42
->glyph_sent
);
382 HeapFree(GetProcessHeap(), 0, t42
->glyf_blocks
);
383 HeapFree(GetProcessHeap(), 0, t42
);