type42.c 13.2 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
/*
 *	PostScript driver Type42 font functions
 *
 *	Copyright 2002  Huw D M Davies for CodeWeavers
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * 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 22 23

#include "config.h"
#include "wine/port.h"

24 25
#include <string.h>
#include <stdlib.h>
26
#include <stdarg.h>
27 28
#include <stdio.h>
#include <assert.h>
29
#include <locale.h>
30

31
#include "windef.h"
32 33 34
#include "winbase.h"
#include "wingdi.h"

35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
#include "psdrv.h"
#include "wine/debug.h"

WINE_DEFAULT_DEBUG_CHANNEL(psdrv);


#define GET_BE_WORD(ptr)  MAKEWORD( ((BYTE *)(ptr))[1], ((BYTE *)(ptr))[0] )
#define GET_BE_DWORD(ptr) ((DWORD)MAKELONG( GET_BE_WORD(&((WORD *)(ptr))[1]), \
                                            GET_BE_WORD(&((WORD *)(ptr))[0]) ))

#define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
          ( ( (DWORD)_x4 << 24 ) |     \
            ( (DWORD)_x3 << 16 ) |     \
            ( (DWORD)_x2 <<  8 ) |     \
              (DWORD)_x1         )

typedef struct {
  DWORD MS_tag;
  DWORD len, check;
  BYTE *data;
  BOOL write;
} OTTable;

58
static const OTTable tables_templ[] = {
59 60 61 62 63 64
      { MS_MAKE_TAG('c','v','t',' '), 0, 0, NULL, TRUE },
      { MS_MAKE_TAG('f','p','g','m'), 0, 0, NULL, TRUE },
      { MS_MAKE_TAG('g','d','i','r'), 0, 0, NULL, TRUE },
      { MS_MAKE_TAG('g','l','y','f'), 0, 0, NULL, FALSE },
      { MS_MAKE_TAG('h','e','a','d'), 0, 0, NULL, TRUE },
      { 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 68 69 70 71 72 73 74
      { MS_MAKE_TAG('m','a','x','p'), 0, 0, NULL, TRUE },
      { MS_MAKE_TAG('p','r','e','p'), 0, 0, NULL, TRUE },
      { 0, 0, 0, NULL, 0 }
};

struct tagTYPE42 {
    OTTable tables[sizeof(tables_templ)/sizeof(tables_templ[0])];
    int glyf_tab, loca_tab, head_tab; /* indices of glyf, loca and head tables */
75 76
    int hmtx_tab, maxp_tab;
    int num_of_written_tables;
77 78 79
    DWORD glyph_sent_size;
    BOOL *glyph_sent;
    DWORD emsize;
80
    DWORD *glyf_blocks;
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
};

#define GLYPH_SENT_INC 128

#define FLIP_ORDER(x) \
 ( ( ((x) & 0xff) << 24) | \
   ( ((x) & 0xff00) << 8) | \
   ( ((x) & 0xff0000) >> 8) | \
   ( ((x) & 0xff000000) >> 24) )


/* Some flags for composite glyphs.  See glyf table in OT spec */
#define ARG_1_AND_2_ARE_WORDS    (1L << 0)
#define WE_HAVE_A_SCALE          (1L << 3)
#define MORE_COMPONENTS          (1L << 5)
#define WE_HAVE_AN_X_AND_Y_SCALE (1L << 6)
#define WE_HAVE_A_TWO_BY_TWO     (1L << 7)

99

100 101
static BOOL LoadTable(HDC hdc, OTTable *table)
{
102
    unsigned int i;
103 104 105 106 107 108 109 110 111 112 113 114

    if(table->MS_tag == MS_MAKE_TAG('g','d','i','r')) return TRUE;
    table->len = GetFontData(hdc, table->MS_tag, 0, NULL, 0);
    table->data = HeapAlloc(GetProcessHeap(), 0, (table->len + 3) & ~3 );
    memset(table->data + ((table->len - 1) & ~3), 0, sizeof(DWORD));
    GetFontData(hdc, table->MS_tag, 0, table->data, table->len);
    table->check = 0;
    for(i = 0; i < (table->len + 3) / 4; i++)
        table->check += FLIP_ORDER(*((DWORD*)(table->data) + i));
    return TRUE;
}

115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
static BOOL get_glyf_pos(TYPE42 *t42, DWORD index, DWORD *start, DWORD *end)
{
    WORD loca_format = GET_BE_WORD(t42->tables[t42->head_tab].data + 50);
    TRACE("loca_format = %d\n", loca_format);
    switch(loca_format) {
    case 0:
        *start = GET_BE_WORD(((WORD*)t42->tables[t42->loca_tab].data) + index);
        *start <<= 1;
        *end = GET_BE_WORD(((WORD*)t42->tables[t42->loca_tab].data) + index + 1);
        *end <<= 1;
        break;
    case 1:
        *start = GET_BE_DWORD(((DWORD*)t42->tables[t42->loca_tab].data) + index);
        *end = GET_BE_DWORD(((DWORD*)t42->tables[t42->loca_tab].data) + index + 1);
        break;
    default:
        ERR("Unknown loca_format %d\n", loca_format);
        return FALSE;
    }
    return TRUE;
}
136

137
TYPE42 *T42_download_header(PHYSDEV dev, char *ps_name,
138
                            RECT *bbox, UINT emsize)
139
{
140
    DWORD i, j, tablepos, nb_blocks, glyf_off = 0, loca_off = 0, cur_off;
141 142 143
    WORD num_of_tables = sizeof(tables_templ) / sizeof(tables_templ[0]) - 1;
    char *buf;
    TYPE42 *t42;
144
    static const char start[] = /* name, fontbbox */
145 146 147 148 149 150 151 152 153 154 155 156
            "25 dict begin\n"
	    " /FontName /%s def\n"
	    " /Encoding 256 array 0 1 255{1 index exch /.notdef put} for\n"
	    " def\n"
	    " /PaintType 0 def\n"
	    " /FontMatrix [1 0 0 1 0 0] def\n"
	    " /FontBBox [%f %f %f %f] def\n"
	    " /FontType 42 def\n"
	    " /CharStrings 256 dict begin\n"
	    "  /.notdef 0 def\n"
            " currentdict end def\n"
	    " /sfnts [\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 160
    static const char storage[] ="]\nhavetype42gdir{pop}{{string} forall}ifelse\n";
    static const char end[] = "] def\n"
161
      "havetype42gdir{/GlyphDirectory 256 dict def\n"
162 163 164 165
      " sfnts 0 get dup\n"
      "  %d <6c6f6378000000000000000000000000> putinterval\n" /* replace loca entry with dummy locx */
      "  %d <676c6678000000000000000000000000> putinterval\n" /* replace glyf entry with dummy glfx */
      " }if\n"
166 167 168
      "currentdict end dup /FontName get exch definefont pop\n";


169
    t42 = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*t42));
170 171
    memcpy(t42->tables, tables_templ, sizeof(tables_templ));
    t42->loca_tab = t42->glyf_tab = t42->head_tab = t42->hmtx_tab = -1;
172
    t42->emsize = emsize;
173
    t42->num_of_written_tables = 0;
174 175

    for(i = 0; i < num_of_tables; i++) {
176
        LoadTable(dev->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 180 181 182 183 184 185 186
	if(t42->tables[i].MS_tag == MS_MAKE_TAG('l','o','c','a'))
	    t42->loca_tab = i;
	else if(t42->tables[i].MS_tag == MS_MAKE_TAG('g','l','y','f'))
	    t42->glyf_tab = i;
	else if(t42->tables[i].MS_tag == MS_MAKE_TAG('h','e','a','d'))
	    t42->head_tab = i;
	else if(t42->tables[i].MS_tag == MS_MAKE_TAG('h','m','t','x'))
	    t42->hmtx_tab = i;
187 188
	else if(t42->tables[i].MS_tag == MS_MAKE_TAG('m','a','x','p'))
	    t42->maxp_tab = i;
189
    }
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);
192 193 194 195 196 197 198 199
        T42_free(t42);
	return NULL;
    }

    t42->glyph_sent_size = GLYPH_SENT_INC;
    t42->glyph_sent = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
				t42->glyph_sent_size *
				sizeof(*(t42->glyph_sent)));
200 201 202 203

    buf = HeapAlloc(GetProcessHeap(), 0, sizeof(start) + strlen(ps_name) +
		    100);

204
    push_lc_numeric("C");
205
    sprintf(buf, start, ps_name,
206 207
	    (float)bbox->left / emsize, (float)bbox->bottom / emsize,
	    (float)bbox->right / emsize, (float)bbox->top / emsize);
208
    pop_lc_numeric();
209

210
    PSDRV_WriteSpool(dev, buf, strlen(buf));
211

212 213 214
    t42->num_of_written_tables++; /* explicitly add glyf */
    sprintf(buf, TT_offset_table, t42->num_of_written_tables,
	    t42->num_of_written_tables, t42->num_of_written_tables, t42->num_of_written_tables);
215

216
    PSDRV_WriteSpool(dev, buf, strlen(buf));
217

218 219
    tablepos = 12 + t42->num_of_written_tables * 16;
    cur_off = 12;
220 221 222 223 224
    for(i = 0; i < num_of_tables; i++) {
        if(!t42->tables[i].write) continue;
        sprintf(buf, TT_table_dir_entry, FLIP_ORDER(t42->tables[i].MS_tag),
		t42->tables[i].check, t42->tables[i].len ? tablepos : 0,
		t42->tables[i].len);
225
	PSDRV_WriteSpool(dev, buf, strlen(buf));
226
	tablepos += ((t42->tables[i].len + 3) & ~3);
227 228 229
        if(t42->tables[i].MS_tag == MS_MAKE_TAG('l','o','c','a'))
            loca_off = cur_off;
        cur_off += 16;
230
    }
231 232
    sprintf(buf, TT_table_dir_entry, FLIP_ORDER(t42->tables[t42->glyf_tab].MS_tag),
            t42->tables[t42->glyf_tab].check, tablepos, t42->tables[t42->glyf_tab].len);
233 234
    PSDRV_WriteSpool(dev, buf, strlen(buf));
    PSDRV_WriteSpool(dev, "00>\n", 4); /* add an extra byte for old PostScript rips */
235
    glyf_off = cur_off;
236 237 238

    for(i = 0; i < num_of_tables; i++) {
        if(t42->tables[i].len == 0 || !t42->tables[i].write) continue;
239
	PSDRV_WriteSpool(dev, "<", 1);
240 241
	for(j = 0; j < ((t42->tables[i].len + 3) & ~3); j++) {
	    sprintf(buf, "%02x", t42->tables[i].data[j]);
242 243
	    PSDRV_WriteSpool(dev, buf, strlen(buf));
	    if(j % 16 == 15) PSDRV_WriteSpool(dev, "\n", 1);
244
	}
245
	PSDRV_WriteSpool(dev, "00>\n", 4); /* add an extra byte for old PostScript rips */
246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261
    }
    
    /* glyf_blocks is a 0 terminated list, holding the start offset of each block.  For simplicity
       glyf_blocks[0] is 0 */
    nb_blocks = 2;
    t42->glyf_blocks = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (nb_blocks + 1) * sizeof(DWORD));
    for(i = 0; i < GET_BE_WORD(t42->tables[t42->maxp_tab].data + 4); i++) {
        DWORD start, end, size;
        get_glyf_pos(t42, i, &start, &end);
        size = end - t42->glyf_blocks[nb_blocks-2];
        if(size > 0x2000 && t42->glyf_blocks[nb_blocks-1] % 4 == 0) {
            nb_blocks++;
            t42->glyf_blocks = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
                                           t42->glyf_blocks, (nb_blocks + 1) * sizeof(DWORD));
        }
        t42->glyf_blocks[nb_blocks-1] = end;
262 263
    }

264
    PSDRV_WriteSpool(dev, "[ ", 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(dev, buf, strlen(buf));
269
        if(i % 8 == 0)
270
            PSDRV_WriteSpool(dev, "\n", 1);
271
    }
272
    PSDRV_WriteSpool(dev, storage, sizeof(storage) - 1);
273
    sprintf(buf, end, loca_off, glyf_off);
274
    PSDRV_WriteSpool(dev, buf, strlen(buf));
275 276 277 278 279 280 281
    HeapFree(GetProcessHeap(), 0, buf);
    return t42;
}




282
BOOL T42_download_glyph(PHYSDEV dev, DOWNLOAD *pdl, DWORD index,
283 284 285 286 287
			char *glyph_name)
{
    DWORD start, end, i;
    char *buf;
    TYPE42 *t42;
288

Dmitry Timoshkov's avatar
Dmitry Timoshkov committed
289
    const char glyph_def[] = 
290 291
      "/%s findfont exch 1 index\n"
      "havetype42gdir\n"
292
      "{/GlyphDirectory get begin %d exch def end}\n"
293 294
      "{/sfnts get 4 index get 3 index 2 index putinterval pop}\n"
      "ifelse\n"
295 296
      "/CharStrings get\n"
      "begin\n"
297
      " /%s %d def\n"
298 299
      "end\n"
      "pop pop\n";
300

301
    TRACE("%d %s\n", index, glyph_name);
302 303 304 305 306 307 308 309 310 311 312 313 314
    assert(pdl->type == Type42);
    t42 = pdl->typeinfo.Type42;

    if(index < t42->glyph_sent_size) {
        if(t42->glyph_sent[index])
	    return TRUE;
    } else {
        t42->glyph_sent_size = (index / GLYPH_SENT_INC + 1) * GLYPH_SENT_INC;
	t42->glyph_sent = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
				      t42->glyph_sent,
				      t42->glyph_sent_size * sizeof(*(t42->glyph_sent)));
    }

315
    if(!get_glyf_pos(t42, index, &start, &end)) return FALSE;
316
    TRACE("start = %x end = %x\n", start, end);
317 318 319

    if(GET_BE_WORD(t42->tables[t42->glyf_tab].data + start) == 0xffff) {
      /* Composite glyph */
Mike McCormack's avatar
Mike McCormack committed
320
        BYTE *sg_start = t42->tables[t42->glyf_tab].data + start + 10;
321 322 323 324 325 326 327
	DWORD sg_flags, sg_index;
	char sg_name[MAX_G_NAME + 1];

	do {
	    sg_flags = GET_BE_WORD(sg_start);
	    sg_index = GET_BE_WORD(sg_start + 2);

328
	    TRACE("Sending subglyph %04x for glyph %04x\n", sg_index, index);
329 330
	    get_glyph_name(dev->hdc, sg_index, sg_name);
	    T42_download_glyph(dev, pdl, sg_index, sg_name);
331 332 333 334 335 336 337 338 339 340 341 342 343 344
	    sg_start += 4;
	    if(sg_flags & ARG_1_AND_2_ARE_WORDS)
	        sg_start += 4;
	    else
	        sg_start += 2;
	    if(sg_flags & WE_HAVE_A_SCALE)
	        sg_start += 2;
	    else if(sg_flags & WE_HAVE_AN_X_AND_Y_SCALE)
	        sg_start += 4;
	    else if(sg_flags & WE_HAVE_A_TWO_BY_TWO)
	        sg_start += 8;
	} while(sg_flags & MORE_COMPONENTS);
    }

345 346
    for(i = 1; t42->glyf_blocks[i]; i++)
        if(start < t42->glyf_blocks[i]) break;
347 348 349 350

    buf = HeapAlloc(GetProcessHeap(), 0, sizeof(glyph_def) +
		    strlen(pdl->ps_name) + 100);

351 352
    /* we don't have a string for the gdir and glyf tables, but we do have a 
       string for the TT header.  So the offset we need is tables - 2 */
353
    sprintf(buf, "%d %d\n", t42->num_of_written_tables - 2 + i, start - t42->glyf_blocks[i-1]);
354
    PSDRV_WriteSpool(dev, buf, strlen(buf));
355

356
    PSDRV_WriteSpool(dev, "<", 1);
357 358
    for(i = start; i < end; i++) {
        sprintf(buf, "%02x", *(t42->tables[t42->glyf_tab].data + i));
359
	PSDRV_WriteSpool(dev, buf, strlen(buf));
360
	if((i - start) % 16 == 15)
361
	    PSDRV_WriteSpool(dev, "\n", 1);
362
    }
363
    PSDRV_WriteSpool(dev, ">\n", 2);
364
    sprintf(buf, glyph_def, pdl->ps_name, index, glyph_name, index);
365
    PSDRV_WriteSpool(dev, buf, strlen(buf));
366 367 368 369 370 371 372 373 374 375

    t42->glyph_sent[index] = TRUE;
    HeapFree(GetProcessHeap(), 0, buf);
    return TRUE;
}

void T42_free(TYPE42 *t42)
{
    OTTable *table;
    for(table = t42->tables; table->MS_tag; table++)
376
        HeapFree(GetProcessHeap(), 0, table->data);
377 378
    HeapFree(GetProcessHeap(), 0, t42->glyph_sent);
    HeapFree(GetProcessHeap(), 0, t42->glyf_blocks);
379 380 381
    HeapFree(GetProcessHeap(), 0, t42);
    return;
}