static UINT calc_ppem_for_height(HDC hdc, LONG height) { BYTE os2[78]; /* size of version 0 table */ BYTE hhea[8]; /* just enough to get the ascender and descender */ LONG ascent = 0, descent = 0; UINT emsize; if(height < 0) return -height; if(GetFontData(hdc, MS_MAKE_TAG('O','S','/','2'), 0, os2, sizeof(os2)) == sizeof(os2)) { ascent = GET_BE_WORD(os2 + 74); /* usWinAscent */ descent = GET_BE_WORD(os2 + 76); /* usWinDescent */ } if(ascent + descent == 0) { if(GetFontData(hdc, MS_MAKE_TAG('h','h','e','a'), 0, hhea, sizeof(hhea)) == sizeof(hhea)) { ascent = (signed short)GET_BE_WORD(hhea + 4); /* Ascender */ descent = -(signed short)GET_BE_WORD(hhea + 6); /* Descender */ } } if(ascent + descent == 0) return height; get_bbox(hdc, NULL, &emsize); return MulDiv(emsize, height, ascent + descent); }
static BOOL LoadTable(HDC hdc, OTTable *table) { unsigned int i; 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; }
static BOOL is_fake_italic( HDC hdc ) { TEXTMETRICW tm; BYTE head[54]; /* the head table is 54 bytes long */ WORD mac_style; GetTextMetricsW( hdc, &tm ); if (!tm.tmItalic) return FALSE; if (GetFontData( hdc, MS_MAKE_TAG('h','e','a','d'), 0, head, sizeof(head) ) == GDI_ERROR) return FALSE; mac_style = GET_BE_WORD( head + 44 ); TRACE( "mac style %04x\n", mac_style ); return !(mac_style & 2); }
/**************************************************************************** * get_bbox * * This retrieves the bounding box of the font in font units as well as * the size of the emsquare. To avoid having to worry about mapping mode and * the font size we'll get the data directly from the TrueType HEAD table rather * than using GetOutlineTextMetrics. */ static BOOL get_bbox(PSDRV_PDEVICE *physDev, RECT *rc, UINT *emsize) { BYTE head[54]; /* the head table is 54 bytes long */ if(GetFontData(physDev->hdc, MS_MAKE_TAG('h','e','a','d'), 0, head, sizeof(head)) == GDI_ERROR) { ERR("Can't retrieve head table\n"); return FALSE; } *emsize = GET_BE_WORD(head + 18); /* unitsPerEm */ rc->left = (signed short)GET_BE_WORD(head + 36); /* xMin */ rc->bottom = (signed short)GET_BE_WORD(head + 38); /* yMin */ rc->right = (signed short)GET_BE_WORD(head + 40); /* xMax */ rc->top = (signed short)GET_BE_WORD(head + 42); /* yMax */ return TRUE; }
/**************************************************************************** * get_bbox * * This retrieves the bounding box of the font in font units as well as * the size of the emsquare. To avoid having to worry about mapping mode and * the font size we'll get the data directly from the TrueType HEAD table rather * than using GetOutlineTextMetrics. */ static UINT get_bbox(HDC hdc, RECT *rc) { BYTE head[54]; /* the head table is 54 bytes long */ if(GetFontData(hdc, MS_MAKE_TAG('h','e','a','d'), 0, head, sizeof(head)) == GDI_ERROR) { ERR("Can't retrieve head table\n"); return 0; } if(rc) { rc->left = (signed short)GET_BE_WORD(head + 36); /* xMin */ rc->bottom = (signed short)GET_BE_WORD(head + 38); /* yMin */ rc->right = (signed short)GET_BE_WORD(head + 40); /* xMax */ rc->top = (signed short)GET_BE_WORD(head + 42); /* yMax */ } return GET_BE_WORD(head + 18); /* unitsPerEm */ }
TYPE42 *T42_download_header(PSDRV_PDEVICE *physDev, char *ps_name, RECT *bbox, UINT emsize) { DWORD i, j, tablepos, nb_blocks, glyf_off = 0, loca_off = 0, cur_off; WORD num_of_tables = sizeof(tables_templ) / sizeof(tables_templ[0]) - 1; char *buf; TYPE42 *t42; static const char start[] = /* name, fontbbox */ "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"; static const char TT_offset_table[] = "<00010000%04x%04x%04x%04x\n"; static const char TT_table_dir_entry[] = "%08x%08x%08x%08x\n"; static const char storage[] ="]\nhavetype42gdir{pop}{{string} forall}ifelse\n"; static const char end[] = "] def\n" "havetype42gdir{/GlyphDirectory 256 dict def\n" " 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" "currentdict end dup /FontName get exch definefont pop\n"; t42 = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*t42)); memcpy(t42->tables, tables_templ, sizeof(tables_templ)); t42->loca_tab = t42->glyf_tab = t42->head_tab = t42->hmtx_tab = -1; t42->emsize = emsize; t42->num_of_written_tables = 0; for(i = 0; i < num_of_tables; i++) { LoadTable(physDev->hdc, t42->tables + i); if(t42->tables[i].len > 0xffff && t42->tables[i].write) break; if(t42->tables[i].write) t42->num_of_written_tables++; 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; else if(t42->tables[i].MS_tag == MS_MAKE_TAG('m','a','x','p')) t42->maxp_tab = i; } if(i < num_of_tables) { TRACE("Table %d has length %d. Will use Type 1 font instead.\n", i, t42->tables[i].len); 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))); buf = HeapAlloc(GetProcessHeap(), 0, sizeof(start) + strlen(ps_name) + 100); push_lc_numeric("C"); sprintf(buf, start, ps_name, (float)bbox->left / emsize, (float)bbox->bottom / emsize, (float)bbox->right / emsize, (float)bbox->top / emsize); pop_lc_numeric(); PSDRV_WriteSpool(physDev, buf, strlen(buf)); 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); PSDRV_WriteSpool(physDev, buf, strlen(buf)); tablepos = 12 + t42->num_of_written_tables * 16; cur_off = 12; 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); PSDRV_WriteSpool(physDev, buf, strlen(buf)); tablepos += ((t42->tables[i].len + 3) & ~3); if(t42->tables[i].MS_tag == MS_MAKE_TAG('l','o','c','a')) loca_off = cur_off; cur_off += 16; } 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); PSDRV_WriteSpool(physDev, buf, strlen(buf)); PSDRV_WriteSpool(physDev, "00>\n", 4); /* add an extra byte for old PostScript rips */ glyf_off = cur_off; for(i = 0; i < num_of_tables; i++) { if(t42->tables[i].len == 0 || !t42->tables[i].write) continue; PSDRV_WriteSpool(physDev, "<", 1); for(j = 0; j < ((t42->tables[i].len + 3) & ~3); j++) { sprintf(buf, "%02x", t42->tables[i].data[j]); PSDRV_WriteSpool(physDev, buf, strlen(buf)); if(j % 16 == 15) PSDRV_WriteSpool(physDev, "\n", 1); } PSDRV_WriteSpool(physDev, "00>\n", 4); /* add an extra byte for old PostScript rips */ } /* 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; } PSDRV_WriteSpool(physDev, "[ ", 2); for(i = 1; t42->glyf_blocks[i]; i++) { sprintf(buf,"%d ", t42->glyf_blocks[i] - t42->glyf_blocks[i-1] + 1); /* again add one byte for old PostScript rips */ PSDRV_WriteSpool(physDev, buf, strlen(buf)); if(i % 8 == 0) PSDRV_WriteSpool(physDev, "\n", 1); } PSDRV_WriteSpool(physDev, storage, sizeof(storage) - 1); sprintf(buf, end, loca_off, glyf_off); PSDRV_WriteSpool(physDev, buf, strlen(buf)); HeapFree(GetProcessHeap(), 0, buf); return t42; }
#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; static const OTTable tables_templ[] = { { 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 }, { MS_MAKE_TAG('h','m','t','x'), 0, 0, NULL, TRUE }, { MS_MAKE_TAG('l','o','c','a'), 0, 0, NULL, TRUE }, { 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 */
/**************************************************************************** * get_download_name */ static void get_download_name(PHYSDEV dev, LPOUTLINETEXTMETRICA potm, char **str) { int len; char *p; DWORD size; size = GetFontData(dev->hdc, MS_MAKE_TAG('n','a','m','e'), 0, NULL, 0); if(size != 0 && size != GDI_ERROR) { BYTE *name = HeapAlloc(GetProcessHeap(), 0, size); if(name) { USHORT count, i; BYTE *strings; struct { USHORT platform_id; USHORT encoding_id; USHORT language_id; USHORT name_id; USHORT length; USHORT offset; } *name_record; GetFontData(dev->hdc, MS_MAKE_TAG('n','a','m','e'), 0, name, size); count = GET_BE_WORD(name + 2); strings = name + GET_BE_WORD(name + 4); name_record = (typeof(name_record))(name + 6); for(i = 0; i < count; i++, name_record++) { name_record->platform_id = GET_BE_WORD(&name_record->platform_id); name_record->encoding_id = GET_BE_WORD(&name_record->encoding_id); name_record->language_id = GET_BE_WORD(&name_record->language_id); name_record->name_id = GET_BE_WORD(&name_record->name_id); name_record->length = GET_BE_WORD(&name_record->length); name_record->offset = GET_BE_WORD(&name_record->offset); if(name_record->platform_id == 1 && name_record->encoding_id == 0 && name_record->language_id == 0 && name_record->name_id == 6) { TRACE("Got Mac PS name %s\n", debugstr_an((char*)strings + name_record->offset, name_record->length)); *str = HeapAlloc(GetProcessHeap(), 0, name_record->length + 1); memcpy(*str, strings + name_record->offset, name_record->length); *(*str + name_record->length) = '\0'; HeapFree(GetProcessHeap(), 0, name); return; } if(name_record->platform_id == 3 && name_record->encoding_id == 1 && name_record->language_id == 0x409 && name_record->name_id == 6) { WCHAR *unicode = HeapAlloc(GetProcessHeap(), 0, name_record->length + 2); DWORD len; int c; for(c = 0; c < name_record->length / 2; c++) unicode[c] = GET_BE_WORD(strings + name_record->offset + c * 2); unicode[c] = 0; TRACE("Got Windows PS name %s\n", debugstr_w(unicode)); len = WideCharToMultiByte(1252, 0, unicode, -1, NULL, 0, NULL, NULL); *str = HeapAlloc(GetProcessHeap(), 0, len); WideCharToMultiByte(1252, 0, unicode, -1, *str, len, NULL, NULL); HeapFree(GetProcessHeap(), 0, unicode); HeapFree(GetProcessHeap(), 0, name); return; } } TRACE("Unable to find PostScript name\n"); HeapFree(GetProcessHeap(), 0, name); } } len = strlen((char*)potm + (ptrdiff_t)potm->otmpFullName) + 1; *str = HeapAlloc(GetProcessHeap(),0,len); strcpy(*str, (char*)potm + (ptrdiff_t)potm->otmpFullName); p = *str; while((p = strchr(p, ' '))) *p = '_'; return; }