download.c 13.5 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
/*
 *	PostScript driver downloadable 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
 */
#include <string.h>
#include <stdlib.h>
#include <assert.h>
23
#include <math.h>
24
#include <stdarg.h>
25
#include <stdio.h>
26

27
#include "windef.h"
28 29
#include "winbase.h"
#include "wingdi.h"
30
#include "winnls.h"
31

32 33 34 35 36
#include "psdrv.h"
#include "wine/debug.h"

WINE_DEFAULT_DEBUG_CHANNEL(psdrv);

37 38 39 40 41 42 43 44 45
#define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
          ( ( (DWORD)_x4 << 24 ) |     \
            ( (DWORD)_x3 << 16 ) |     \
            ( (DWORD)_x2 <<  8 ) |     \
              (DWORD)_x1         )

#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]) ))
46 47 48 49

/****************************************************************************
 *  get_download_name
 */
50
static void get_download_name(PHYSDEV dev, LPOUTLINETEXTMETRICA potm, char **str)
51 52 53
{
    int len;
    char *p;
54 55
    DWORD size;

56
    size = GetFontData(dev->hdc, MS_MAKE_TAG('n','a','m','e'), 0, NULL, 0);
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
    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;

74
            GetFontData(dev->hdc, MS_MAKE_TAG('n','a','m','e'), 0, name, size);
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120
            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);
        }
    }

121 122 123
    len = strlen((char*)potm + (ptrdiff_t)potm->otmpFullName) + 1;
    *str = HeapAlloc(GetProcessHeap(),0,len);
    strcpy(*str, (char*)potm + (ptrdiff_t)potm->otmpFullName);
124

125 126 127 128 129 130 131 132 133 134 135 136 137
    p = *str;
    while((p = strchr(p, ' ')))
        *p = '_';

    return;
}

/****************************************************************************
 *  is_font_downloaded
 */
static DOWNLOAD *is_font_downloaded(PSDRV_PDEVICE *physDev, char *ps_name)
{
    DOWNLOAD *pdl;
138

139 140 141 142 143 144
    for(pdl = physDev->downloaded_fonts; pdl; pdl = pdl->next)
        if(!strcmp(pdl->ps_name, ps_name))
	    break;
    return pdl;
}

145 146 147 148 149 150 151 152 153
/****************************************************************************
 *  is_room_for_font
 */
static BOOL is_room_for_font(PSDRV_PDEVICE *physDev)
{
    DOWNLOAD *pdl;
    int count = 0;

    /* FIXME: should consider vm usage of each font and available printer memory.
154
       For now we allow up to two fonts to be downloaded at a time */
155 156 157 158 159 160 161 162
    for(pdl = physDev->downloaded_fonts; pdl; pdl = pdl->next)
        count++;

    if(count > 1)
        return FALSE;
    return TRUE;
}

163 164 165 166 167 168 169 170
/****************************************************************************
 *  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.
 */
171
static BOOL get_bbox(HDC hdc, RECT *rc, UINT *emsize)
172 173 174
{
    BYTE head[54]; /* the head table is 54 bytes long */

175 176
    if(GetFontData(hdc, MS_MAKE_TAG('h','e','a','d'), 0, head, sizeof(head)) == GDI_ERROR)
    {
177 178 179 180
        ERR("Can't retrieve head table\n");
        return FALSE;
    }
    *emsize = GET_BE_WORD(head + 18); /* unitsPerEm */
181 182 183 184 185 186 187
    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 */
    }
188 189 190
    return TRUE;
}

191 192 193 194 195 196
/****************************************************************************
 *  PSDRV_SelectDownloadFont
 *
 *  Set up physDev->font for a downloadable font
 *
 */
197
BOOL PSDRV_SelectDownloadFont(PHYSDEV dev)
198
{
199 200
    PSDRV_PDEVICE *physDev = get_psdrv_dev( dev );

201
    physDev->font.fontloc = Download;
202
    physDev->font.fontinfo.Download = NULL;
203 204 205 206

    return TRUE;
}

207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237
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);
}

238 239 240 241
static inline float ps_round(float f)
{
    return (f > 0) ? (f + 0.5) : (f - 0.5);
}
242 243 244 245 246 247
/****************************************************************************
 *  PSDRV_WriteSetDownloadFont
 *
 *  Write setfont for download font.
 *
 */
248
BOOL PSDRV_WriteSetDownloadFont(PHYSDEV dev)
249
{
250
    PSDRV_PDEVICE *physDev = get_psdrv_dev( dev );
251 252
    char *ps_name;
    LPOUTLINETEXTMETRICA potm;
253
    DWORD len = GetOutlineTextMetricsA(dev->hdc, 0, NULL);
254
    DOWNLOAD *pdl;
255 256
    LOGFONTW lf;
    UINT ppem;
257
    XFORM xform;
258 259 260

    assert(physDev->font.fontloc == Download);

261 262 263
    if (!GetObjectW( GetCurrentObject(dev->hdc, OBJ_FONT), sizeof(lf), &lf ))
        return FALSE;

264
    potm = HeapAlloc(GetProcessHeap(), 0, len);
265 266 267
    if (!potm)
        return FALSE;

268
    GetOutlineTextMetricsA(dev->hdc, len, potm);
269

270
    get_download_name(dev, potm, &ps_name);
271 272
    physDev->font.fontinfo.Download = is_font_downloaded(physDev, ps_name);

273
    ppem = calc_ppem_for_height(dev->hdc, lf.lfHeight);
274

275
    /* Retrieve the world -> device transform */
276
    GetTransform(dev->hdc, 0x204, &xform);
277

278
    if(GetGraphicsMode(dev->hdc) == GM_COMPATIBLE)
279
    {
280
        if (xform.eM22 < 0) physDev->font.escapement = -physDev->font.escapement;
281 282 283 284
        xform.eM11 = xform.eM22 = fabs(xform.eM22);
        xform.eM21 = xform.eM12 = 0;
    }

285 286
    physDev->font.size.xx = ps_round(ppem * xform.eM11);
    physDev->font.size.xy = ps_round(ppem * xform.eM12);
287 288
    physDev->font.size.yx = -ps_round(ppem * xform.eM21);
    physDev->font.size.yy = -ps_round(ppem * xform.eM22);
289

290 291 292 293 294
    physDev->font.underlineThickness = potm->otmsUnderscoreSize;
    physDev->font.underlinePosition = potm->otmsUnderscorePosition;
    physDev->font.strikeoutThickness = potm->otmsStrikeoutSize;
    physDev->font.strikeoutPosition = potm->otmsStrikeoutPosition;

295
    if(physDev->font.fontinfo.Download == NULL) {
296 297 298
        RECT bbox;
        UINT emsize;

299
        if (!get_bbox(dev->hdc, &bbox, &emsize)) {
300 301 302 303
	    HeapFree(GetProcessHeap(), 0, potm);
	    return FALSE;
	}
        if(!is_room_for_font(physDev))
304
            PSDRV_EmptyDownloadList(dev, TRUE);
305

306 307 308 309 310 311
        pdl = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*pdl));
	pdl->ps_name = HeapAlloc(GetProcessHeap(), 0, strlen(ps_name)+1);
	strcpy(pdl->ps_name, ps_name);
	pdl->next = NULL;

        if(physDev->pi->ppd->TTRasterizer == RO_Type42) {
312
	    pdl->typeinfo.Type42 = T42_download_header(dev, ps_name, &bbox, emsize);
313
	    pdl->type = Type42;
314 315
	}
	if(pdl->typeinfo.Type42 == NULL) {
316
	    pdl->typeinfo.Type1 = T1_download_header(dev, ps_name, &bbox, emsize);
317 318
	    pdl->type = Type1;
	}
319 320
	pdl->next = physDev->downloaded_fonts;
	physDev->downloaded_fonts = pdl;
321
	physDev->font.fontinfo.Download = pdl;
322 323 324

        if(pdl->type == Type42) {
            char g_name[MAX_G_NAME + 1];
325
            get_glyph_name(dev->hdc, 0, g_name);
326
            T42_download_glyph(dev, pdl, 0, g_name);
327
        }
328 329 330
    }


331
    PSDRV_WriteSetFont(dev, ps_name, physDev->font.size, physDev->font.escapement);
332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350

    HeapFree(GetProcessHeap(), 0, ps_name);
    HeapFree(GetProcessHeap(), 0, potm);
    return TRUE;
}

void get_glyph_name(HDC hdc, WORD index, char *name)
{
  /* FIXME */
    sprintf(name, "g%04x", index);
    return;
}

/****************************************************************************
 *  PSDRV_WriteDownloadGlyphShow
 *
 *  Download and write out a number of glyphs
 *
 */
351
BOOL PSDRV_WriteDownloadGlyphShow(PHYSDEV dev, WORD *glyphs,
352 353
				  UINT count)
{
354
    PSDRV_PDEVICE *physDev = get_psdrv_dev( dev );
355 356 357 358 359 360 361
    UINT i;
    char g_name[MAX_G_NAME + 1];
    assert(physDev->font.fontloc == Download);

    switch(physDev->font.fontinfo.Download->type) {
    case Type42:
    for(i = 0; i < count; i++) {
362
        get_glyph_name(dev->hdc, glyphs[i], g_name);
363 364
	T42_download_glyph(dev, physDev->font.fontinfo.Download, glyphs[i], g_name);
	PSDRV_WriteGlyphShow(dev, g_name);
365 366 367 368 369
    }
    break;

    case Type1:
    for(i = 0; i < count; i++) {
370
        get_glyph_name(dev->hdc, glyphs[i], g_name);
371 372
	T1_download_glyph(dev, physDev->font.fontinfo.Download, glyphs[i], g_name);
	PSDRV_WriteGlyphShow(dev, g_name);
373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388
    }
    break;

    default:
        ERR("Type = %d\n", physDev->font.fontinfo.Download->type);
	assert(0);
    }
    return TRUE;
}

/****************************************************************************
 *  PSDRV_EmptyDownloadList
 *
 *  Clear the list of downloaded fonts
 *
 */
389
BOOL PSDRV_EmptyDownloadList(PHYSDEV dev, BOOL write_undef)
390
{
391
    PSDRV_PDEVICE *physDev = get_psdrv_dev( dev );
392
    DOWNLOAD *pdl, *old;
393
    static const char undef[] = "/%s findfont 40 scalefont setfont /%s undefinefont\n";
394
    char buf[sizeof(undef) + 200];
395
    const char *default_font = physDev->pi->ppd->DefaultFont ?
396 397
        physDev->pi->ppd->DefaultFont : "Courier";

398 399 400 401 402 403 404 405
    if(physDev->font.fontloc == Download) {
        physDev->font.set = FALSE;
	physDev->font.fontinfo.Download = NULL;
    }

    pdl = physDev->downloaded_fonts;
    physDev->downloaded_fonts = NULL;
    while(pdl) {
406 407
        if(write_undef) {
            sprintf(buf, undef, default_font, pdl->ps_name);
408
            PSDRV_WriteSpool(dev, buf, strlen(buf));
409 410
        }

411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431
        switch(pdl->type) {
	case Type42:
	    T42_free(pdl->typeinfo.Type42);
	    break;

	case Type1:
	    T1_free(pdl->typeinfo.Type1);
	    break;

	default:
	    ERR("Type = %d\n", pdl->type);
	    assert(0);
	}

	HeapFree(GetProcessHeap(), 0, pdl->ps_name);
	old = pdl;
	pdl = pdl->next;
	HeapFree(GetProcessHeap(), 0, old);
    }
    return TRUE;
}