objects.c 16.8 KB
Newer Older
Alexandre Julliard's avatar
Alexandre Julliard committed
1 2 3 4
/*
 * GDI objects
 *
 * Copyright 1993 Alexandre Julliard
5 6 7 8 9 10 11 12 13 14 15 16 17
 *
 * 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
Alexandre Julliard's avatar
Alexandre Julliard committed
19 20 21 22
 */

#include <stdlib.h>
#include <stdio.h>
23
#include <string.h>
24
#include <stdarg.h>
25

26 27 28
#include "windef.h"
#include "winbase.h"
#include "wingdi.h"
Michael Stefaniuc's avatar
Michael Stefaniuc committed
29
#include "wownt32.h"
30
#include "mfdrv/metafiledrv.h"
31
#include "gdi_private.h"
32
#include "wine/debug.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
33

34
WINE_DEFAULT_DEBUG_CHANNEL(metafile);
35

36 37 38 39 40 41
/******************************************************************
 *         MFDRV_AddHandle
 */
UINT MFDRV_AddHandle( PHYSDEV dev, HGDIOBJ obj )
{
    METAFILEDRV_PDEVICE *physDev = (METAFILEDRV_PDEVICE *)dev;
42
    UINT16 index;
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60

    for(index = 0; index < physDev->handles_size; index++)
        if(physDev->handles[index] == 0) break; 
    if(index == physDev->handles_size) {
        physDev->handles_size += HANDLE_LIST_INC;
        physDev->handles = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
                                       physDev->handles,
                                       physDev->handles_size * sizeof(physDev->handles[0]));
    }
    physDev->handles[index] = obj;

    physDev->cur_handles++; 
    if(physDev->cur_handles > physDev->mh->mtNoObjects)
        physDev->mh->mtNoObjects++;

    return index ; /* index 0 is not reserved for metafiles */
}

61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
/******************************************************************
 *         MFDRV_RemoveHandle
 */
BOOL MFDRV_RemoveHandle( PHYSDEV dev, UINT index )
{
    METAFILEDRV_PDEVICE *physDev = (METAFILEDRV_PDEVICE *)dev;
    BOOL ret = FALSE;

    if (index < physDev->handles_size && physDev->handles[index])
    {
        physDev->handles[index] = 0;
        physDev->cur_handles--;
        ret = TRUE;
    }
    return ret;
}

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 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
/******************************************************************
 *         MFDRV_FindObject
 */
static INT16 MFDRV_FindObject( PHYSDEV dev, HGDIOBJ obj )
{
    METAFILEDRV_PDEVICE *physDev = (METAFILEDRV_PDEVICE *)dev;
    INT16 index;

    for(index = 0; index < physDev->handles_size; index++)
        if(physDev->handles[index] == obj) break;

    if(index == physDev->handles_size) return -1;

    return index ;
}


/******************************************************************
 *         MFDRV_DeleteObject
 */
BOOL MFDRV_DeleteObject( PHYSDEV dev, HGDIOBJ obj )
{   
    METARECORD mr;
    METAFILEDRV_PDEVICE *physDev = (METAFILEDRV_PDEVICE *)dev;
    INT16 index;
    BOOL ret = TRUE;

    index = MFDRV_FindObject(dev, obj);
    if( index < 0 )
        return 0;

    mr.rdSize = sizeof mr / 2;
    mr.rdFunction = META_DELETEOBJECT;
    mr.rdParm[0] = index;

    if(!MFDRV_WriteRecord( dev, &mr, mr.rdSize*2 ))
        ret = FALSE;

    physDev->handles[index] = 0;
    physDev->cur_handles--;
    return ret;
}


/***********************************************************************
 *           MFDRV_SelectObject
 */
static BOOL MFDRV_SelectObject( PHYSDEV dev, INT16 index)
{
    METARECORD mr;

    mr.rdSize = sizeof mr / 2;
    mr.rdFunction = META_SELECTOBJECT;
    mr.rdParm[0] = index;

    return MFDRV_WriteRecord( dev, &mr, mr.rdSize*2 );
}

136

Alexandre Julliard's avatar
Alexandre Julliard committed
137
/***********************************************************************
138
 *           MFDRV_SelectBitmap
Alexandre Julliard's avatar
Alexandre Julliard committed
139
 */
140
HBITMAP MFDRV_SelectBitmap( PHYSDEV dev, HBITMAP hbitmap )
Alexandre Julliard's avatar
Alexandre Julliard committed
141 142 143 144
{
    return 0;
}

145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206
/***********************************************************************
 * Internal helper for MFDRV_CreateBrushIndirect():
 * Change the padding of a bitmap from 16 (BMP) to 32 (DIB) bits.
 */
static inline void MFDRV_PadTo32(LPBYTE lpRows, int height, int width)
{
    int bytes16 = 2 * ((width + 15) / 16);
    int bytes32 = 4 * ((width + 31) / 32);
    LPBYTE lpSrc, lpDst;
    int i;

    if (!height)
        return;

    height = abs(height) - 1;
    lpSrc = lpRows + height * bytes16;
    lpDst = lpRows + height * bytes32;

    /* Note that we work backwards so we can re-pad in place */
    while (height >= 0)
    {
        for (i = bytes32; i > bytes16; i--)
            lpDst[i - 1] = 0; /* Zero the padding bytes */
        for (; i > 0; i--)
            lpDst[i - 1] = lpSrc[i - 1]; /* Move image bytes into alignment */
        lpSrc -= bytes16;
        lpDst -= bytes32;
        height--;
    }
}

/***********************************************************************
 * Internal helper for MFDRV_CreateBrushIndirect():
 * Reverse order of bitmap rows in going from BMP to DIB.
 */
static inline void MFDRV_Reverse(LPBYTE lpRows, int height, int width)
{
    int bytes = 4 * ((width + 31) / 32);
    LPBYTE lpSrc, lpDst;
    BYTE temp;
    int i;

    if (!height)
        return;

    lpSrc = lpRows;
    lpDst = lpRows + (height-1) * bytes;
    height = height/2;

    while (height > 0)
    {
        for (i = 0; i < bytes; i++)
        {
            temp = lpDst[i];
            lpDst[i] = lpSrc[i];
            lpSrc[i] = temp;
        }
        lpSrc += bytes;
        lpDst -= bytes;
        height--;
    }
}
Alexandre Julliard's avatar
Alexandre Julliard committed
207

208 209 210 211
/******************************************************************
 *         MFDRV_CreateBrushIndirect
 */

212
INT16 MFDRV_CreateBrushIndirect(PHYSDEV dev, HBRUSH hBrush )
213
{
214
    DWORD size;
215
    METARECORD *mr;
216
    LOGBRUSH logbrush;
217
    METAFILEDRV_PDEVICE *physDev = (METAFILEDRV_PDEVICE *)dev;
218
    BOOL r;
219 220 221 222 223

    if (!GetObjectA( hBrush, sizeof(logbrush), &logbrush )) return -1;

    switch(logbrush.lbStyle)
    {
224 225 226 227 228 229
    case BS_SOLID:
    case BS_NULL:
    case BS_HATCHED:
        {
	    LOGBRUSH16 lb16;

230 231 232
	    lb16.lbStyle = logbrush.lbStyle;
	    lb16.lbColor = logbrush.lbColor;
	    lb16.lbHatch = logbrush.lbHatch;
233
	    size = sizeof(METARECORD) + sizeof(LOGBRUSH16) - 2;
234
	    mr = HeapAlloc( GetProcessHeap(), 0, size );
235 236
	    mr->rdSize = size / 2;
	    mr->rdFunction = META_CREATEBRUSHINDIRECT;
237
	    memcpy( mr->rdParm, &lb16, sizeof(LOGBRUSH16));
238 239
	    break;
	}
240 241 242
    case BS_PATTERN:
        {
	    BITMAP bm;
243 244
	    BITMAPINFO *info;
	    DWORD bmSize;
245
	    COLORREF cref;
246

Michael Stefaniuc's avatar
Michael Stefaniuc committed
247
	    GetObjectA((HANDLE)logbrush.lbHatch, sizeof(bm), &bm);
248
	    if(bm.bmBitsPixel != 1 || bm.bmPlanes != 1) {
249
	        FIXME("Trying to store a colour pattern brush\n");
250
		goto done;
251 252
	    }

Jon Griffiths's avatar
Jon Griffiths committed
253
	    bmSize = DIB_GetDIBImageBytes(bm.bmWidth, bm.bmHeight, DIB_PAL_COLORS);
254

255
	    size = sizeof(METARECORD) + sizeof(WORD) + sizeof(BITMAPINFO) +
256
	      sizeof(RGBQUAD) + bmSize;
257

258
	    mr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
259
	    if(!mr) goto done;
260
	    mr->rdFunction = META_DIBCREATEPATTERNBRUSH;
261
	    mr->rdSize = size / 2;
262 263 264 265 266 267 268 269 270
	    mr->rdParm[0] = BS_PATTERN;
	    mr->rdParm[1] = DIB_RGB_COLORS;
	    info = (BITMAPINFO *)(mr->rdParm + 2);

	    info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
	    info->bmiHeader.biWidth = bm.bmWidth;
	    info->bmiHeader.biHeight = bm.bmHeight;
	    info->bmiHeader.biPlanes = 1;
	    info->bmiHeader.biBitCount = 1;
271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294
	    info->bmiHeader.biSizeImage = bmSize;

	    GetBitmapBits((HANDLE)logbrush.lbHatch,
		      bm.bmHeight * BITMAP_GetWidthBytes (bm.bmWidth, bm.bmBitsPixel),
		      (LPBYTE)info + sizeof(BITMAPINFO) + sizeof(RGBQUAD));

	    /* Change the padding to be DIB compatible if needed */
	    if(bm.bmWidth & 31)
	        MFDRV_PadTo32((LPBYTE)info + sizeof(BITMAPINFO) + sizeof(RGBQUAD),
		      bm.bmWidth, bm.bmHeight);
	    /* BMP and DIB have opposite row order conventions */
            MFDRV_Reverse((LPBYTE)info + sizeof(BITMAPINFO) + sizeof(RGBQUAD),
		      bm.bmWidth, bm.bmHeight);

	    cref = GetTextColor(physDev->hdc);
	    info->bmiColors[0].rgbRed = GetRValue(cref);
	    info->bmiColors[0].rgbGreen = GetGValue(cref);
	    info->bmiColors[0].rgbBlue = GetBValue(cref);
	    info->bmiColors[0].rgbReserved = 0;
	    cref = GetBkColor(physDev->hdc);
	    info->bmiColors[1].rgbRed = GetRValue(cref);
	    info->bmiColors[1].rgbGreen = GetGValue(cref);
	    info->bmiColors[1].rgbBlue = GetBValue(cref);
	    info->bmiColors[1].rgbReserved = 0;
295 296 297 298
	    break;
	}

    case BS_DIBPATTERN:
299 300 301 302
        {
	      BITMAPINFO *info;
	      DWORD bmSize, biSize;

303
	      info = GlobalLock16((HGLOBAL16)logbrush.lbHatch);
304 305 306 307 308 309
	      if (info->bmiHeader.biCompression)
		  bmSize = info->bmiHeader.biSizeImage;
	      else
		  bmSize = DIB_GetDIBImageBytes(info->bmiHeader.biWidth,
						info->bmiHeader.biHeight,
						info->bmiHeader.biBitCount);
310
	      biSize = bitmap_info_size(info, LOWORD(logbrush.lbColor));
311
	      size = sizeof(METARECORD) + biSize + bmSize + 2;
312
	      mr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
313
	      if(!mr) goto done;
314 315
	      mr->rdFunction = META_DIBCREATEPATTERNBRUSH;
	      mr->rdSize = size / 2;
316 317
	      *(mr->rdParm) = logbrush.lbStyle;
	      *(mr->rdParm + 1) = LOWORD(logbrush.lbColor);
318 319 320 321
	      memcpy(mr->rdParm + 2, info, biSize + bmSize);
	      break;
	}
	default:
322
	    FIXME("Unkonwn brush style %x\n", logbrush.lbStyle);
323
	    return 0;
324
    }
325
    r = MFDRV_WriteRecord( dev, mr, mr->rdSize * 2);
326
    HeapFree(GetProcessHeap(), 0, mr);
327 328
    if( !r )
        return -1;
329
done:
330
    return MFDRV_AddHandle( dev, hBrush );
331 332
}

333

Alexandre Julliard's avatar
Alexandre Julliard committed
334
/***********************************************************************
335
 *           MFDRV_SelectBrush
Alexandre Julliard's avatar
Alexandre Julliard committed
336
 */
337
HBRUSH MFDRV_SelectBrush( PHYSDEV dev, HBRUSH hbrush )
Alexandre Julliard's avatar
Alexandre Julliard committed
338
{
339
    METAFILEDRV_PDEVICE *physDev = (METAFILEDRV_PDEVICE *)dev;
340 341
    INT16 index;

342 343 344 345 346 347 348 349 350
    index = MFDRV_FindObject(dev, hbrush);
    if( index < 0 )
    {
        index = MFDRV_CreateBrushIndirect( dev, hbrush );
        if( index < 0 )
            return 0;
        GDI_hdc_using_object(hbrush, physDev->hdc);
    }
    return MFDRV_SelectObject( dev, index ) ? hbrush : HGDI_ERROR;
Alexandre Julliard's avatar
Alexandre Julliard committed
351 352
}

353 354 355 356
/******************************************************************
 *         MFDRV_CreateFontIndirect
 */

357
static UINT16 MFDRV_CreateFontIndirect(PHYSDEV dev, HFONT hFont, LOGFONTW *logfont)
358 359 360
{
    char buffer[sizeof(METARECORD) - 2 + sizeof(LOGFONT16)];
    METARECORD *mr = (METARECORD *)&buffer;
361
    LOGFONT16 *font16;
362 363 364

    mr->rdSize = (sizeof(METARECORD) + sizeof(LOGFONT16) - 2) / 2;
    mr->rdFunction = META_CREATEFONTINDIRECT;
365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382
    font16 = (LOGFONT16 *)&mr->rdParm;

    font16->lfHeight         = logfont->lfHeight;
    font16->lfWidth          = logfont->lfWidth;
    font16->lfEscapement     = logfont->lfEscapement;
    font16->lfOrientation    = logfont->lfOrientation;
    font16->lfWeight         = logfont->lfWeight;
    font16->lfItalic         = logfont->lfItalic;
    font16->lfUnderline      = logfont->lfUnderline;
    font16->lfStrikeOut      = logfont->lfStrikeOut;
    font16->lfCharSet        = logfont->lfCharSet;
    font16->lfOutPrecision   = logfont->lfOutPrecision;
    font16->lfClipPrecision  = logfont->lfClipPrecision;
    font16->lfQuality        = logfont->lfQuality;
    font16->lfPitchAndFamily = logfont->lfPitchAndFamily;
    WideCharToMultiByte( CP_ACP, 0, logfont->lfFaceName, -1, font16->lfFaceName, LF_FACESIZE, NULL, NULL );
    font16->lfFaceName[LF_FACESIZE-1] = 0;

383 384 385
    if (!(MFDRV_WriteRecord( dev, mr, mr->rdSize * 2)))
        return 0;
    return MFDRV_AddHandle( dev, hFont );
386 387
}

Alexandre Julliard's avatar
Alexandre Julliard committed
388 389

/***********************************************************************
390
 *           MFDRV_SelectFont
Alexandre Julliard's avatar
Alexandre Julliard committed
391
 */
392
HFONT MFDRV_SelectFont( PHYSDEV dev, HFONT hfont, HANDLE gdiFont )
Alexandre Julliard's avatar
Alexandre Julliard committed
393
{
394
    METAFILEDRV_PDEVICE *physDev = (METAFILEDRV_PDEVICE *)dev;
395
    LOGFONTW font;
396
    INT16 index;
397

398 399 400
    index = MFDRV_FindObject(dev, hfont);
    if( index < 0 )
    {
401
        if (!GetObjectW( hfont, sizeof(font), &font ))
402
            return HGDI_ERROR;
403
        index = MFDRV_CreateFontIndirect(dev, hfont, &font);
404 405 406 407 408
        if( index < 0 )
            return HGDI_ERROR;
        GDI_hdc_using_object(hfont, physDev->hdc);
    }
    return MFDRV_SelectObject( dev, index ) ? hfont : HGDI_ERROR;
Alexandre Julliard's avatar
Alexandre Julliard committed
409 410
}

411 412 413
/******************************************************************
 *         MFDRV_CreatePenIndirect
 */
414
static UINT16 MFDRV_CreatePenIndirect(PHYSDEV dev, HPEN hPen, LOGPEN16 *logpen)
415 416 417 418 419 420 421
{
    char buffer[sizeof(METARECORD) - 2 + sizeof(*logpen)];
    METARECORD *mr = (METARECORD *)&buffer;

    mr->rdSize = (sizeof(METARECORD) + sizeof(*logpen) - 2) / 2;
    mr->rdFunction = META_CREATEPENINDIRECT;
    memcpy(&(mr->rdParm), logpen, sizeof(*logpen));
422 423 424
    if (!(MFDRV_WriteRecord( dev, mr, mr->rdSize * 2)))
        return 0;
    return MFDRV_AddHandle( dev, hPen );
425 426
}

Alexandre Julliard's avatar
Alexandre Julliard committed
427 428

/***********************************************************************
429
 *           MFDRV_SelectPen
Alexandre Julliard's avatar
Alexandre Julliard committed
430
 */
431
HPEN MFDRV_SelectPen( PHYSDEV dev, HPEN hpen )
Alexandre Julliard's avatar
Alexandre Julliard committed
432
{
433
    METAFILEDRV_PDEVICE *physDev = (METAFILEDRV_PDEVICE *)dev;
434
    LOGPEN16 logpen;
435
    INT16 index;
436

437 438 439
    index = MFDRV_FindObject(dev, hpen);
    if( index < 0 )
    {
440 441 442 443
        /* must be an extended pen */
        INT size = GetObjectW( hpen, 0, NULL );

        if (!size) return 0;
444

445 446 447
        if (size == sizeof(LOGPEN))
        {
            LOGPEN pen;
448

449 450 451 452 453 454 455 456 457
            GetObjectW( hpen, sizeof(pen), &pen );
            logpen.lopnStyle   = pen.lopnStyle;
            logpen.lopnWidth.x = pen.lopnWidth.x;
            logpen.lopnWidth.y = pen.lopnWidth.y;
            logpen.lopnColor   = pen.lopnColor;
        }
        else  /* must be an extended pen */
        {
            EXTLOGPEN *elp = HeapAlloc( GetProcessHeap(), 0, size );
458 459 460 461 462

            GetObjectW( hpen, size, elp );
            /* FIXME: add support for user style pens */
            logpen.lopnStyle = elp->elpPenStyle;
            logpen.lopnWidth.x = elp->elpWidth;
463
            logpen.lopnWidth.y = 0;
464 465 466
            logpen.lopnColor = elp->elpColor;

            HeapFree( GetProcessHeap(), 0, elp );
467 468
        }

469 470 471 472 473 474
        index = MFDRV_CreatePenIndirect( dev, hpen, &logpen );
        if( index < 0 )
            return 0;
        GDI_hdc_using_object(hpen, physDev->hdc);
    }
    return MFDRV_SelectObject( dev, index ) ? hpen : HGDI_ERROR;
Alexandre Julliard's avatar
Alexandre Julliard committed
475
}
476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499


/******************************************************************
 *         MFDRV_CreatePalette
 */
static BOOL MFDRV_CreatePalette(PHYSDEV dev, HPALETTE hPalette, LOGPALETTE* logPalette, int sizeofPalette)
{
    int index;
    BOOL ret;
    METARECORD *mr;

    mr = HeapAlloc( GetProcessHeap(), 0, sizeof(METARECORD) + sizeofPalette - sizeof(WORD) );
    mr->rdSize = (sizeof(METARECORD) + sizeofPalette - sizeof(WORD)) / sizeof(WORD);
    mr->rdFunction = META_CREATEPALETTE;
    memcpy(&(mr->rdParm), logPalette, sizeofPalette);
    if (!(MFDRV_WriteRecord( dev, mr, mr->rdSize * sizeof(WORD))))
    {
        HeapFree(GetProcessHeap(), 0, mr);
        return FALSE;
    }

    mr->rdSize = sizeof(METARECORD) / sizeof(WORD);
    mr->rdFunction = META_SELECTPALETTE;

500
    if ((index = MFDRV_AddHandle( dev, hPalette )) == -1) ret = FALSE;
501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566
    else
    {
        *(mr->rdParm) = index;
        ret = MFDRV_WriteRecord( dev, mr, mr->rdSize * sizeof(WORD));
    }
    HeapFree(GetProcessHeap(), 0, mr);
    return ret;
}


/***********************************************************************
 *           MFDRV_SelectPalette
 */
HPALETTE MFDRV_SelectPalette( PHYSDEV dev, HPALETTE hPalette, BOOL bForceBackground )
{
#define PALVERSION 0x0300

    PLOGPALETTE logPalette;
    WORD        wNumEntries = 0;
    BOOL        creationSucceed;
    int         sizeofPalette;

    GetObjectA(hPalette, sizeof(WORD), (LPSTR) &wNumEntries);

    if (wNumEntries == 0) return 0;

    sizeofPalette = sizeof(LOGPALETTE) + ((wNumEntries-1) * sizeof(PALETTEENTRY));
    logPalette = HeapAlloc( GetProcessHeap(), 0, sizeofPalette );

    if (logPalette == NULL) return 0;

    logPalette->palVersion = PALVERSION;
    logPalette->palNumEntries = wNumEntries;

    GetPaletteEntries(hPalette, 0, wNumEntries, logPalette->palPalEntry);

    creationSucceed = MFDRV_CreatePalette( dev, hPalette, logPalette, sizeofPalette );

    HeapFree( GetProcessHeap(), 0, logPalette );

    if (creationSucceed)
        return hPalette;

    return 0;
}

/***********************************************************************
 *           MFDRV_RealizePalette
 */
UINT MFDRV_RealizePalette(PHYSDEV dev, HPALETTE hPalette, BOOL dummy)
{
    char buffer[sizeof(METARECORD) - sizeof(WORD)];
    METARECORD *mr = (METARECORD *)&buffer;

    mr->rdSize = (sizeof(METARECORD) - sizeof(WORD)) / sizeof(WORD);
    mr->rdFunction = META_REALIZEPALETTE;

    if (!(MFDRV_WriteRecord( dev, mr, mr->rdSize * sizeof(WORD)))) return 0;

    /* The return value is suppose to be the number of entries
       in the logical palette mapped to the system palette or 0
       if the function failed. Since it's not trivial here to
       get that kind of information and since it's of little
       use in the case of metafiles, we'll always return 1. */
    return 1;
}