Huw Davies 5d275962eb Instead of trying to download the Type 42 glpyh metrics incrementally
(which most printers don't seem to understand), we'll download the
whole hmtx table in one go (sigh) unless it's larger than 64K in which
case we'll go back to using a Type 1 font.
2002-11-13 23:51:44 +00:00

356 lines
11 KiB
C

/*
* 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
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include "winspool.h"
#include "psdrv.h"
#include "wine/debug.h"
#include "winerror.h"
#include "config.h"
#include "wine/port.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 )
/* undef this to download the metrics in one go in the hmtx table.
Most printers seem unable to use incremental metrics unfortunately */
#define USE_SEPARATE_METRICS
#undef USE_SEPARATE_METRICS
typedef struct {
DWORD MS_tag;
DWORD len, check;
BYTE *data;
BOOL write;
} OTTable;
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 },
#ifdef USE_SEPARATE_METRICS
{ MS_MAKE_TAG('h','m','t','x'), 0, 0, NULL, FALSE },
#else
{ MS_MAKE_TAG('h','m','t','x'), 0, 0, NULL, TRUE },
#endif
{ MS_MAKE_TAG('l','o','c','a'), 0, 0, NULL, FALSE },
{ 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 */
int hmtx_tab;
DWORD glyph_sent_size;
BOOL *glyph_sent;
DWORD emsize;
};
#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)
static BOOL LoadTable(HDC hdc, OTTable *table)
{
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;
}
TYPE42 *T42_download_header(PSDRV_PDEVICE *physDev, LPOUTLINETEXTMETRICA potm,
char *ps_name)
{
DWORD i, j, tablepos;
WORD num_of_tables = sizeof(tables_templ) / sizeof(tables_templ[0]) - 1;
WORD num_of_write_tables = 0;
char *buf;
TYPE42 *t42;
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"
" /GlyphDirectory 256 dict def\n"
#ifdef USE_SEPARATE_METRICS
" /Metrics 256 dict def\n"
#endif
" /sfnts [\n";
char TT_offset_table[] = "<00010000%04x%04x%04x%04x\n";
char TT_table_dir_entry[] = "%08lx%08lx%08lx%08lx\n";
char end[] = "] def\n"
"currentdict end dup /FontName get exch definefont pop\n";
t42 = HeapAlloc(GetProcessHeap(), 0, 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 = potm->otmEMSquare;
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) num_of_write_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;
}
if(i < num_of_tables) {
TRACE("Table %ld has length %ld. 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);
sprintf(buf, start, ps_name,
(float)potm->otmrcFontBox.left / potm->otmEMSquare,
(float)potm->otmrcFontBox.bottom / potm->otmEMSquare,
(float)potm->otmrcFontBox.right / potm->otmEMSquare,
(float)potm->otmrcFontBox.top / potm->otmEMSquare);
PSDRV_WriteSpool(physDev, buf, strlen(buf));
sprintf(buf, TT_offset_table, num_of_write_tables,
num_of_write_tables, num_of_write_tables, num_of_write_tables);
PSDRV_WriteSpool(physDev, buf, strlen(buf));
tablepos = 12 + num_of_write_tables * 16;
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);
}
PSDRV_WriteSpool(physDev, ">\n", 2);
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, ">\n", 2);
}
PSDRV_WriteSpool(physDev, end, sizeof(end) - 1);
HeapFree(GetProcessHeap(), 0, buf);
return t42;
}
BOOL T42_download_glyph(PSDRV_PDEVICE *physDev, DOWNLOAD *pdl, DWORD index,
char *glyph_name)
{
DWORD start, end, i;
char *buf;
TYPE42 *t42;
WORD loca_format;
WORD awidth;
short lsb;
#ifdef USE_SEPARATE_METRICS
char glyph_with_Metrics_def[] =
"/%s findfont exch 1 index /GlyphDirectory get\n"
"begin\n"
" %d exch def\n"
"end\n"
"dup /CharStrings get\n"
"begin\n"
" /%s %d def\n"
"end\n"
"/Metrics get\n"
"begin\n"
" /%s [%f %f] def\n"
"end\n";
#else
char glyph_def[] =
"/%s findfont exch 1 index /GlyphDirectory get\n"
"begin\n"
" %d exch def\n"
"end\n"
"/CharStrings get\n"
"begin\n"
" /%s %d def\n"
"end\n";
#endif
TRACE("%ld %s\n", index, glyph_name);
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)));
}
buf = HeapAlloc(GetProcessHeap(), 0, sizeof(glyph_def) +
strlen(pdl->ps_name) + 100);
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;
}
TRACE("start = %lx end = %lx\n", start, end);
awidth = GET_BE_WORD(t42->tables[t42->hmtx_tab].data + index * 4);
lsb = GET_BE_WORD(t42->tables[t42->hmtx_tab].data + index * 4 + 2);
if(GET_BE_WORD(t42->tables[t42->glyf_tab].data + start) == 0xffff) {
/* Composite glyph */
char *sg_start = t42->tables[t42->glyf_tab].data + start + 10;
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);
TRACE("Sending subglyph %04lx for glyph %04lx\n", sg_index, index);
get_glyph_name(physDev->hdc, sg_index, sg_name);
T42_download_glyph(physDev, pdl, sg_index, sg_name);
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);
}
sprintf(buf, "%%%%glyph %04lx\n", index);
PSDRV_WriteSpool(physDev, buf, strlen(buf));
PSDRV_WriteSpool(physDev, "<", 1);
for(i = start; i < end; i++) {
sprintf(buf, "%02x", *(t42->tables[t42->glyf_tab].data + i));
PSDRV_WriteSpool(physDev, buf, strlen(buf));
if((i - start) % 16 == 15)
PSDRV_WriteSpool(physDev, "\n", 1);
}
PSDRV_WriteSpool(physDev, ">\n", 2);
#if USE_SEPARATE_METRICS
sprintf(buf, glyph_with_Metrics_def, pdl->ps_name, index, glyph_name, index,
glyph_name, (float)lsb / t42->emsize, (float)awidth / t42->emsize);
#else
sprintf(buf, glyph_def, pdl->ps_name, index, glyph_name, index);
#endif
PSDRV_WriteSpool(physDev, buf, strlen(buf));
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++)
if(table->data) HeapFree(GetProcessHeap(), 0, table->data);
if(t42->glyph_sent) HeapFree(GetProcessHeap(), 0, t42->glyph_sent);
HeapFree(GetProcessHeap(), 0, t42);
return;
}