objects.c 16.1 KB
Newer Older
1 2 3 4
/*
 * Enhanced MetaFile objects
 *
 * Copyright 1999 Huw D M Davies
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
19 20 21 22
 */

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

25
#include "enhmfdrv/enhmetafiledrv.h"
26
#include "gdi_private.h"
27
#include "wine/debug.h"
28

29
WINE_DEFAULT_DEBUG_CHANNEL(enhmetafile);
30

31 32 33 34 35 36

/******************************************************************
 *         EMFDRV_AddHandle
 */
static UINT EMFDRV_AddHandle( PHYSDEV dev, HGDIOBJ obj )
{
37
    EMFDRV_PDEVICE *physDev = get_emf_physdev( dev );
38 39 40 41 42 43 44 45 46 47
    UINT index;

    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]));
    }
48
    physDev->handles[index] = get_full_gdi_handle( obj );
49 50 51 52 53 54 55 56 57 58 59 60 61

    physDev->cur_handles++;
    if(physDev->cur_handles > physDev->emh->nHandles)
        physDev->emh->nHandles++;

    return index + 1; /* index 0 is reserved for the hmf, so we increment everything by 1 */
}

/******************************************************************
 *         EMFDRV_FindObject
 */
static UINT EMFDRV_FindObject( PHYSDEV dev, HGDIOBJ obj )
{
62
    EMFDRV_PDEVICE *physDev = get_emf_physdev( dev );
63 64 65 66 67 68 69 70 71 72 73 74 75 76
    UINT index;

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

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

    return index + 1;
}


/******************************************************************
 *         EMFDRV_DeleteObject
 */
77
BOOL EMFDRV_DeleteObject( PHYSDEV dev, HGDIOBJ obj )
78 79
{
    EMRDELETEOBJECT emr;
80
    EMFDRV_PDEVICE *physDev = get_emf_physdev( dev );
81 82 83
    UINT index;
    BOOL ret = TRUE;

84
    if(!(index = EMFDRV_FindObject(dev, obj))) return FALSE;
85 86 87 88 89 90 91 92 93 94 95 96 97

    emr.emr.iType = EMR_DELETEOBJECT;
    emr.emr.nSize = sizeof(emr);
    emr.ihObject = index;

    if(!EMFDRV_WriteRecord( dev, &emr.emr ))
        ret = FALSE;

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

98

99
/***********************************************************************
100
 *           EMFDRV_SelectBitmap
101
 */
102
HBITMAP EMFDRV_SelectBitmap( PHYSDEV dev, HBITMAP hbitmap )
103 104 105 106 107 108 109 110
{
    return 0;
}


/***********************************************************************
 *           EMFDRV_CreateBrushIndirect
 */
111
DWORD EMFDRV_CreateBrushIndirect( PHYSDEV dev, HBRUSH hBrush )
112 113
{
    DWORD index = 0;
114
    LOGBRUSH logbrush;
115

116 117 118
    if (!GetObjectA( hBrush, sizeof(logbrush), &logbrush )) return 0;

    switch (logbrush.lbStyle) {
119 120 121 122 123 124 125
    case BS_SOLID:
    case BS_HATCHED:
    case BS_NULL:
      {
	EMRCREATEBRUSHINDIRECT emr;
	emr.emr.iType = EMR_CREATEBRUSHINDIRECT;
	emr.emr.nSize = sizeof(emr);
126
	emr.ihBrush = index = EMFDRV_AddHandle( dev, hBrush );
127 128 129
	emr.lb.lbStyle = logbrush.lbStyle;
	emr.lb.lbColor = logbrush.lbColor;
	emr.lb.lbHatch = logbrush.lbHatch;
130

131
	if(!EMFDRV_WriteRecord( dev, &emr.emr ))
132 133 134 135
	    index = 0;
      }
      break;
    case BS_PATTERN:
136
    case BS_DIBPATTERN:
137 138
      {
        EMRCREATEDIBPATTERNBRUSHPT *emr;
139
        char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
140
        BITMAPINFO *info = (BITMAPINFO *)buffer;
141
        DWORD info_size;
142 143
        void *bits;
        UINT usage;
144

145
        if (!get_brush_bitmap_info( hBrush, info, &bits, &usage )) break;
146
        info_size = get_dib_info_size( info, usage );
147

148 149
        emr = HeapAlloc( GetProcessHeap(), 0,
                         sizeof(EMRCREATEDIBPATTERNBRUSHPT)+info_size+info->bmiHeader.biSizeImage );
150
        if(!emr) break;
151

152
        if (logbrush.lbStyle == BS_PATTERN && info->bmiHeader.biBitCount == 1)
153
        {
154 155 156 157 158 159 160 161 162 163
            /* Presumably to reduce the size of the written EMF, MS supports an
             * undocumented iUsage value of 2, indicating a mono bitmap without the
             * 8 byte 2 entry black/white palette. Stupidly, they could have saved
             * over 20 bytes more by also ignoring the BITMAPINFO fields that are
             * irrelevant/constant for monochrome bitmaps.
             * FIXME: It may be that the DIB functions themselves accept this value.
             */
            emr->emr.iType = EMR_CREATEMONOBRUSH;
            usage = DIB_PAL_MONO;
            /* FIXME: There is an extra DWORD written by native before the BMI.
164
             *        Not sure what it's meant to contain.
165 166 167
             */
            emr->offBmi = sizeof( EMRCREATEDIBPATTERNBRUSHPT ) + sizeof(DWORD);
            emr->cbBmi = sizeof( BITMAPINFOHEADER );
168
        }
169 170 171 172 173 174
        else
        {
            emr->emr.iType = EMR_CREATEDIBPATTERNBRUSHPT;
            emr->offBmi = sizeof( EMRCREATEDIBPATTERNBRUSHPT );
            emr->cbBmi = info_size;
        }
175
        emr->ihBrush = index = EMFDRV_AddHandle( dev, hBrush );
176
        emr->iUsage = usage;
177
        emr->offBits = emr->offBmi + emr->cbBmi;
178
        emr->cbBits = info->bmiHeader.biSizeImage;
179
        emr->emr.nSize = emr->offBits + emr->cbBits;
180 181 182

        memcpy( (BYTE *)emr + emr->offBmi, info, emr->cbBmi );
        memcpy( (BYTE *)emr + emr->offBits, bits, emr->cbBits );
183 184 185 186 187 188 189

        if(!EMFDRV_WriteRecord( dev, &emr->emr ))
            index = 0;
        HeapFree( GetProcessHeap(), 0, emr );
      }
      break;

190
    default:
191
        FIXME("Unknown style %x\n", logbrush.lbStyle);
192
	break;
193 194 195 196 197 198
    }
    return index;
}


/***********************************************************************
199
 *           EMFDRV_SelectBrush
200
 */
201
HBRUSH EMFDRV_SelectBrush( PHYSDEV dev, HBRUSH hBrush, const struct brush_pattern *pattern )
202
{
203
    EMFDRV_PDEVICE *physDev = get_emf_physdev( dev );
204 205
    EMRSELECTOBJECT emr;
    DWORD index;
206 207
    int i;

208 209
    if (physDev->restoring) return hBrush;  /* don't output SelectObject records during RestoreDC */

210 211 212 213 214
    /* If the object is a stock brush object, do not need to create it.
     * See definitions in  wingdi.h for range of stock brushes.
     * We do however have to handle setting the higher order bit to
     * designate that this is a stock object.
     */
215
    for (i = WHITE_BRUSH; i <= DC_BRUSH; i++)
216
    {
217 218 219 220 221
        if (hBrush == GetStockObject(i))
        {
            index = i | 0x80000000;
            goto found;
        }
222
    }
223 224 225
    if((index = EMFDRV_FindObject(dev, hBrush)) != 0)
        goto found;

226
    if (!(index = EMFDRV_CreateBrushIndirect(dev, hBrush ))) return 0;
227
    GDI_hdc_using_object(hBrush, dev->hdc);
228

229
 found:
230 231 232
    emr.emr.iType = EMR_SELECTOBJECT;
    emr.emr.nSize = sizeof(emr);
    emr.ihObject = index;
233
    return EMFDRV_WriteRecord( dev, &emr.emr ) ? hBrush : 0;
234 235 236 237 238 239
}


/******************************************************************
 *         EMFDRV_CreateFontIndirect
 */
240
static BOOL EMFDRV_CreateFontIndirect(PHYSDEV dev, HFONT hFont )
241 242 243 244
{
    DWORD index = 0;
    EMREXTCREATEFONTINDIRECTW emr;
    int i;
245

246
    if (!GetObjectW( hFont, sizeof(emr.elfw.elfLogFont), &emr.elfw.elfLogFont )) return FALSE;
247

248 249
    emr.emr.iType = EMR_EXTCREATEFONTINDIRECTW;
    emr.emr.nSize = (sizeof(emr) + 3) / 4 * 4;
250
    emr.ihFont = index = EMFDRV_AddHandle( dev, hFont );
251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270
    emr.elfw.elfFullName[0] = '\0';
    emr.elfw.elfStyle[0]    = '\0';
    emr.elfw.elfVersion     = 0;
    emr.elfw.elfStyleSize   = 0;
    emr.elfw.elfMatch       = 0;
    emr.elfw.elfReserved    = 0;
    for(i = 0; i < ELF_VENDOR_SIZE; i++)
        emr.elfw.elfVendorId[i] = 0;
    emr.elfw.elfCulture                 = PAN_CULTURE_LATIN;
    emr.elfw.elfPanose.bFamilyType      = PAN_NO_FIT;
    emr.elfw.elfPanose.bSerifStyle      = PAN_NO_FIT;
    emr.elfw.elfPanose.bWeight          = PAN_NO_FIT;
    emr.elfw.elfPanose.bProportion      = PAN_NO_FIT;
    emr.elfw.elfPanose.bContrast        = PAN_NO_FIT;
    emr.elfw.elfPanose.bStrokeVariation = PAN_NO_FIT;
    emr.elfw.elfPanose.bArmStyle        = PAN_NO_FIT;
    emr.elfw.elfPanose.bLetterform      = PAN_NO_FIT;
    emr.elfw.elfPanose.bMidline         = PAN_NO_FIT;
    emr.elfw.elfPanose.bXHeight         = PAN_NO_FIT;

271
    if(!EMFDRV_WriteRecord( dev, &emr.emr ))
272 273 274 275 276 277
        index = 0;
    return index;
}


/***********************************************************************
278
 *           EMFDRV_SelectFont
279
 */
280
HFONT EMFDRV_SelectFont( PHYSDEV dev, HFONT hFont, UINT *aa_flags )
281
{
282
    EMFDRV_PDEVICE *physDev = get_emf_physdev( dev );
283 284
    EMRSELECTOBJECT emr;
    DWORD index;
285
    int i;
286

287
    if (physDev->restoring) goto done;  /* don't output SelectObject records during RestoreDC */
288

289 290 291 292 293 294
    /* If the object is a stock font object, do not need to create it.
     * See definitions in  wingdi.h for range of stock fonts.
     * We do however have to handle setting the higher order bit to
     * designate that this is a stock object.
     */

295
    for (i = OEM_FIXED_FONT; i <= DEFAULT_GUI_FONT; i++)
296
    {
297 298 299 300 301
        if (i != DEFAULT_PALETTE && hFont == GetStockObject(i))
        {
            index = i | 0x80000000;
            goto found;
        }
302
    }
303 304 305 306

    if((index = EMFDRV_FindObject(dev, hFont)) != 0)
        goto found;

307
    if (!(index = EMFDRV_CreateFontIndirect(dev, hFont ))) return 0;
308
    GDI_hdc_using_object(hFont, dev->hdc);
309

310
 found:
311 312 313
    emr.emr.iType = EMR_SELECTOBJECT;
    emr.emr.nSize = sizeof(emr);
    emr.ihObject = index;
314
    if(!EMFDRV_WriteRecord( dev, &emr.emr ))
315 316
        return 0;
done:
317
    *aa_flags = GGO_BITMAP;  /* no point in anti-aliasing on metafiles */
318
    dev = GET_NEXT_PHYSDEV( dev, pSelectFont );
319
    dev->funcs->pSelectFont( dev, hFont, aa_flags );
320
    return hFont;
321 322 323 324 325 326 327
}



/******************************************************************
 *         EMFDRV_CreatePenIndirect
 */
328
static DWORD EMFDRV_CreatePenIndirect(PHYSDEV dev, HPEN hPen)
329 330 331 332
{
    EMRCREATEPEN emr;
    DWORD index = 0;

333 334 335
    if (!GetObjectW( hPen, sizeof(emr.lopn), &emr.lopn ))
    {
        /* must be an extended pen */
336 337 338 339 340 341 342 343 344 345 346
        EXTLOGPEN *elp;
        INT size = GetObjectW( hPen, 0, NULL );

        if (!size) return 0;

        elp = HeapAlloc( GetProcessHeap(), 0, size );

        GetObjectW( hPen, size, elp );
        /* FIXME: add support for user style pens */
        emr.lopn.lopnStyle = elp->elpPenStyle;
        emr.lopn.lopnWidth.x = elp->elpWidth;
347
        emr.lopn.lopnWidth.y = 0;
348 349 350
        emr.lopn.lopnColor = elp->elpColor;

        HeapFree( GetProcessHeap(), 0, elp );
351
    }
352

353 354
    emr.emr.iType = EMR_CREATEPEN;
    emr.emr.nSize = sizeof(emr);
355
    emr.ihPen = index = EMFDRV_AddHandle( dev, hPen );
356

357
    if(!EMFDRV_WriteRecord( dev, &emr.emr ))
358
        index = 0;
359
    return index;
360 361 362
}

/******************************************************************
363
 *         EMFDRV_SelectPen
364
 */
365
HPEN EMFDRV_SelectPen(PHYSDEV dev, HPEN hPen, const struct brush_pattern *pattern )
366
{
367
    EMFDRV_PDEVICE *physDev = get_emf_physdev( dev );
368 369
    EMRSELECTOBJECT emr;
    DWORD index;
370
    int i;
371

372 373
    if (physDev->restoring) return hPen;  /* don't output SelectObject records during RestoreDC */

374 375 376 377 378 379
    /* If the object is a stock pen object, do not need to create it.
     * See definitions in  wingdi.h for range of stock pens.
     * We do however have to handle setting the higher order bit to
     * designate that this is a stock object.
     */

380
    for (i = WHITE_PEN; i <= DC_PEN; i++)
381
    {
382 383 384 385 386
        if (hPen == GetStockObject(i))
        {
            index = i | 0x80000000;
            goto found;
        }
387
    }
388 389 390
    if((index = EMFDRV_FindObject(dev, hPen)) != 0)
        goto found;

391
    if (!(index = EMFDRV_CreatePenIndirect(dev, hPen))) return 0;
392
    GDI_hdc_using_object(hPen, dev->hdc);
393

394
 found:
395 396 397
    emr.emr.iType = EMR_SELECTOBJECT;
    emr.emr.nSize = sizeof(emr);
    emr.ihObject = index;
398
    return EMFDRV_WriteRecord( dev, &emr.emr ) ? hPen : 0;
399
}
400 401


402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432
/******************************************************************
 *         EMFDRV_CreatePalette
 */
static DWORD EMFDRV_CreatePalette(PHYSDEV dev, HPALETTE hPal)
{
    WORD i;
    struct {
        EMRCREATEPALETTE hdr;
        PALETTEENTRY entry[255];
    } pal;

    memset( &pal, 0, sizeof(pal) );

    if (!GetObjectW( hPal, sizeof(pal.hdr.lgpl) + sizeof(pal.entry), &pal.hdr.lgpl ))
        return 0;

    for (i = 0; i < pal.hdr.lgpl.palNumEntries; i++)
        pal.hdr.lgpl.palPalEntry[i].peFlags = 0;

    pal.hdr.emr.iType = EMR_CREATEPALETTE;
    pal.hdr.emr.nSize = sizeof(pal.hdr) + pal.hdr.lgpl.palNumEntries * sizeof(PALETTEENTRY);
    pal.hdr.ihPal = EMFDRV_AddHandle( dev, hPal );

    if (!EMFDRV_WriteRecord( dev, &pal.hdr.emr ))
        pal.hdr.ihPal = 0;
    return pal.hdr.ihPal;
}

/******************************************************************
 *         EMFDRV_SelectPalette
 */
433
HPALETTE EMFDRV_SelectPalette( PHYSDEV dev, HPALETTE hPal, BOOL force )
434
{
435
    EMFDRV_PDEVICE *physDev = get_emf_physdev( dev );
436 437 438
    EMRSELECTPALETTE emr;
    DWORD index;

439 440
    if (physDev->restoring) return hPal;  /* don't output SelectObject records during RestoreDC */

441
    if (hPal == GetStockObject( DEFAULT_PALETTE ))
442
    {
443 444
        index = DEFAULT_PALETTE | 0x80000000;
        goto found;
445
    }
446 447 448 449 450

    if ((index = EMFDRV_FindObject( dev, hPal )) != 0)
        goto found;

    if (!(index = EMFDRV_CreatePalette( dev, hPal ))) return 0;
451
    GDI_hdc_using_object( hPal, dev->hdc );
452 453 454 455 456 457 458 459

found:
    emr.emr.iType = EMR_SELECTPALETTE;
    emr.emr.nSize = sizeof(emr);
    emr.ihPal = index;
    return EMFDRV_WriteRecord( dev, &emr.emr ) ? hPal : 0;
}

460 461 462
/******************************************************************
 *         EMFDRV_SetDCBrushColor
 */
463
COLORREF EMFDRV_SetDCBrushColor( PHYSDEV dev, COLORREF color )
464
{
465
    EMFDRV_PDEVICE *physDev = get_emf_physdev( dev );
466
    DC *dc = get_physdev_dc( dev );
467 468 469
    EMRSELECTOBJECT emr;
    DWORD index;

470
    if (dc->hBrush != GetStockObject( DC_BRUSH )) return color;
471 472 473 474

    if (physDev->dc_brush) DeleteObject( physDev->dc_brush );
    if (!(physDev->dc_brush = CreateSolidBrush( color ))) return CLR_INVALID;
    if (!(index = EMFDRV_CreateBrushIndirect(dev, physDev->dc_brush ))) return CLR_INVALID;
475
    GDI_hdc_using_object( physDev->dc_brush, dev->hdc );
476 477 478 479 480 481 482 483 484
    emr.emr.iType = EMR_SELECTOBJECT;
    emr.emr.nSize = sizeof(emr);
    emr.ihObject = index;
    return EMFDRV_WriteRecord( dev, &emr.emr ) ? color : CLR_INVALID;
}

/******************************************************************
 *         EMFDRV_SetDCPenColor
 */
485
COLORREF EMFDRV_SetDCPenColor( PHYSDEV dev, COLORREF color )
486
{
487
    EMFDRV_PDEVICE *physDev = get_emf_physdev( dev );
488
    DC *dc = get_physdev_dc( dev );
489 490 491 492
    EMRSELECTOBJECT emr;
    DWORD index;
    LOGPEN logpen = { PS_SOLID, { 0, 0 }, color };

493
    if (dc->hPen != GetStockObject( DC_PEN )) return color;
494 495 496 497

    if (physDev->dc_pen) DeleteObject( physDev->dc_pen );
    if (!(physDev->dc_pen = CreatePenIndirect( &logpen ))) return CLR_INVALID;
    if (!(index = EMFDRV_CreatePenIndirect(dev, physDev->dc_pen))) return CLR_INVALID;
498
    GDI_hdc_using_object( physDev->dc_pen, dev->hdc );
499 500 501 502 503
    emr.emr.iType = EMR_SELECTOBJECT;
    emr.emr.nSize = sizeof(emr);
    emr.ihObject = index;
    return EMFDRV_WriteRecord( dev, &emr.emr ) ? color : CLR_INVALID;
}
504

505 506 507
/******************************************************************
 *         EMFDRV_GdiComment
 */
508
BOOL EMFDRV_GdiComment(PHYSDEV dev, UINT bytes, const BYTE *buffer)
509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529
{
    EMRGDICOMMENT *emr;
    UINT total, rounded_size;
    BOOL ret;

    rounded_size = (bytes+3) & ~3;
    total = offsetof(EMRGDICOMMENT,Data) + rounded_size;

    emr = HeapAlloc(GetProcessHeap(), 0, total);
    emr->emr.iType = EMR_GDICOMMENT;
    emr->emr.nSize = total;
    emr->cbData = bytes;
    memset(&emr->Data[bytes], 0, rounded_size - bytes);
    memcpy(&emr->Data[0], buffer, bytes);

    ret = EMFDRV_WriteRecord( dev, &emr->emr );

    HeapFree(GetProcessHeap(), 0, emr);

    return ret;
}