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

21 22
#include "config.h"

23
#include <stdarg.h>
Alexandre Julliard's avatar
Alexandre Julliard committed
24
#include <stdlib.h>
Alexandre Julliard's avatar
Alexandre Julliard committed
25
#include <string.h>
26
#include "windef.h"
27
#include "winbase.h"
28
#include "wingdi.h"
29
#include "winreg.h"
30
#include "winternl.h"
31 32
#include "winerror.h"
#include "wownt32.h"
33
#include "wine/winuser16.h"
34
#include "gdi.h"
35
#include "gdi_private.h"
36
#include "wine/unicode.h"
37
#include "wine/debug.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
38

39
WINE_DEFAULT_DEBUG_CHANNEL(dc);
40

41 42
static const WCHAR displayW[] = { 'd','i','s','p','l','a','y',0 };

43 44 45 46 47 48 49 50 51 52 53 54
static BOOL DC_DeleteObject( HGDIOBJ handle, void *obj );

static const struct gdi_obj_funcs dc_funcs =
{
    NULL,             /* pSelectObject */
    NULL,             /* pGetObject16 */
    NULL,             /* pGetObjectA */
    NULL,             /* pGetObjectW */
    NULL,             /* pUnrealizeObject */
    DC_DeleteObject   /* pDeleteObject */
};

Alexandre Julliard's avatar
Alexandre Julliard committed
55 56 57
/***********************************************************************
 *           DC_AllocDC
 */
58
DC *DC_AllocDC( const DC_FUNCTIONS *funcs, WORD magic )
Alexandre Julliard's avatar
Alexandre Julliard committed
59
{
60
    HDC hdc;
Alexandre Julliard's avatar
Alexandre Julliard committed
61 62
    DC *dc;

63
    if (!(dc = GDI_AllocObject( sizeof(*dc), magic, (HGDIOBJ*)&hdc, &dc_funcs ))) return NULL;
64 65 66 67 68

    dc->hSelf               = hdc;
    dc->funcs               = funcs;
    dc->physDev             = NULL;
    dc->saveLevel           = 0;
69
    dc->saved_dc            = 0;
70 71 72 73 74 75 76 77 78 79 80
    dc->dwHookData          = 0;
    dc->hookProc            = NULL;
    dc->hookThunk           = NULL;
    dc->wndOrgX             = 0;
    dc->wndOrgY             = 0;
    dc->wndExtX             = 1;
    dc->wndExtY             = 1;
    dc->vportOrgX           = 0;
    dc->vportOrgY           = 0;
    dc->vportExtX           = 1;
    dc->vportExtY           = 1;
81
    dc->miterLimit          = 10.0f; /* 10.0 is the default, from MSDN */
82
    dc->flags               = 0;
83
    dc->layout              = 0;
84
    dc->hClipRgn            = 0;
85 86
    dc->hMetaRgn            = 0;
    dc->hMetaClipRgn        = 0;
87 88 89 90 91 92 93
    dc->hVisRgn             = 0;
    dc->hPen                = GetStockObject( BLACK_PEN );
    dc->hBrush              = GetStockObject( WHITE_BRUSH );
    dc->hFont               = GetStockObject( SYSTEM_FONT );
    dc->hBitmap             = 0;
    dc->hDevice             = 0;
    dc->hPalette            = GetStockObject( DEFAULT_PALETTE );
94
    dc->gdiFont             = 0;
95 96 97 98 99 100
    dc->ROPmode             = R2_COPYPEN;
    dc->polyFillMode        = ALTERNATE;
    dc->stretchBltMode      = BLACKONWHITE;
    dc->relAbsMode          = ABSOLUTE;
    dc->backgroundMode      = OPAQUE;
    dc->backgroundColor     = RGB( 255, 255, 255 );
101 102
    dc->dcBrushColor        = RGB( 255, 255, 255 );
    dc->dcPenColor          = RGB( 0, 0, 0 );
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124
    dc->textColor           = RGB( 0, 0, 0 );
    dc->brushOrgX           = 0;
    dc->brushOrgY           = 0;
    dc->textAlign           = TA_LEFT | TA_TOP | TA_NOUPDATECP;
    dc->charExtra           = 0;
    dc->breakExtra          = 0;
    dc->breakRem            = 0;
    dc->MapMode             = MM_TEXT;
    dc->GraphicsMode        = GM_COMPATIBLE;
    dc->pAbortProc          = NULL;
    dc->CursPosX            = 0;
    dc->CursPosY            = 0;
    dc->ArcDirection        = AD_COUNTERCLOCKWISE;
    dc->xformWorld2Wnd.eM11 = 1.0f;
    dc->xformWorld2Wnd.eM12 = 0.0f;
    dc->xformWorld2Wnd.eM21 = 0.0f;
    dc->xformWorld2Wnd.eM22 = 1.0f;
    dc->xformWorld2Wnd.eDx  = 0.0f;
    dc->xformWorld2Wnd.eDy  = 0.0f;
    dc->xformWorld2Vport    = dc->xformWorld2Wnd;
    dc->xformVport2World    = dc->xformWorld2Wnd;
    dc->vport2WorldValid    = TRUE;
125 126 127 128
    dc->BoundsRect.left     = 0;
    dc->BoundsRect.top      = 0;
    dc->BoundsRect.right    = 0;
    dc->BoundsRect.bottom   = 0;
129
    dc->saved_visrgn        = NULL;
130
    PATH_InitGdiPath(&dc->path);
Alexandre Julliard's avatar
Alexandre Julliard committed
131 132 133 134
    return dc;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
135

Alexandre Julliard's avatar
Alexandre Julliard committed
136 137 138
/***********************************************************************
 *           DC_GetDCPtr
 */
139
DC *DC_GetDCPtr( HDC hdc )
Alexandre Julliard's avatar
Alexandre Julliard committed
140
{
141
    GDIOBJHDR *ptr = GDI_GetObjPtr( hdc, MAGIC_DONTCARE );
Alexandre Julliard's avatar
Alexandre Julliard committed
142
    if (!ptr) return NULL;
143
    if ((GDIMAGIC(ptr->wMagic) == DC_MAGIC) ||
144 145 146
        (GDIMAGIC(ptr->wMagic) == MEMORY_DC_MAGIC) ||
        (GDIMAGIC(ptr->wMagic) == METAFILE_DC_MAGIC) ||
        (GDIMAGIC(ptr->wMagic) == ENHMETAFILE_DC_MAGIC))
Alexandre Julliard's avatar
Alexandre Julliard committed
147
        return (DC *)ptr;
148
    GDI_ReleaseObj( hdc );
149
    SetLastError( ERROR_INVALID_HANDLE );
Alexandre Julliard's avatar
Alexandre Julliard committed
150 151 152
    return NULL;
}

153 154 155 156 157 158 159 160 161 162 163
/***********************************************************************
 *           DC_GetDCUpdate
 *
 * Retrieve a DC ptr while making sure the visRgn is updated.
 * This function may call up to USER so the GDI lock should _not_
 * be held when calling it.
 */
DC *DC_GetDCUpdate( HDC hdc )
{
    DC *dc = DC_GetDCPtr( hdc );
    if (!dc) return NULL;
164
    while (dc->flags & DC_DIRTY)
165
    {
166
        DCHOOKPROC proc = dc->hookThunk;
167
        dc->flags &= ~DC_DIRTY;
168
        if (proc)
169
        {
170 171 172 173 174
            DWORD data = dc->dwHookData;
            GDI_ReleaseObj( hdc );
            proc( HDC_16(hdc), DCHC_INVALIDVISRGN, data, 0 );
            if (!(dc = DC_GetDCPtr( hdc ))) break;
            /* otherwise restart the loop in case it became dirty again in the meantime */
175 176 177 178
        }
    }
    return dc;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
179

180 181 182 183 184 185 186 187 188 189 190

/***********************************************************************
 *           DC_DeleteObject
 */
static BOOL DC_DeleteObject( HGDIOBJ handle, void *obj )
{
    GDI_ReleaseObj( handle );
    return DeleteDC( handle );
}


Alexandre Julliard's avatar
Alexandre Julliard committed
191
/***********************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
192
 *           DC_InitDC
Alexandre Julliard's avatar
Alexandre Julliard committed
193
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
194
 * Setup device-specific DC values for a newly created DC.
Alexandre Julliard's avatar
Alexandre Julliard committed
195
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
196
void DC_InitDC( DC* dc )
Alexandre Julliard's avatar
Alexandre Julliard committed
197
{
198
    if (dc->funcs->pRealizeDefaultPalette) dc->funcs->pRealizeDefaultPalette( dc->physDev );
199 200 201 202 203
    SetTextColor( dc->hSelf, dc->textColor );
    SetBkColor( dc->hSelf, dc->backgroundColor );
    SelectObject( dc->hSelf, dc->hPen );
    SelectObject( dc->hSelf, dc->hBrush );
    SelectObject( dc->hSelf, dc->hFont );
Alexandre Julliard's avatar
Alexandre Julliard committed
204
    CLIPPING_UpdateGCRegion( dc );
Alexandre Julliard's avatar
Alexandre Julliard committed
205 206 207
}


Alexandre Julliard's avatar
Alexandre Julliard committed
208 209 210 211 212 213 214
/***********************************************************************
 *           DC_InvertXform
 *
 * Computes the inverse of the transformation xformSrc and stores it to
 * xformDest. Returns TRUE if successful or FALSE if the xformSrc matrix
 * is singular.
 */
215
static BOOL DC_InvertXform( const XFORM *xformSrc, XFORM *xformDest )
Alexandre Julliard's avatar
Alexandre Julliard committed
216 217
{
    FLOAT determinant;
218

Alexandre Julliard's avatar
Alexandre Julliard committed
219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248
    determinant = xformSrc->eM11*xformSrc->eM22 -
        xformSrc->eM12*xformSrc->eM21;
    if (determinant > -1e-12 && determinant < 1e-12)
        return FALSE;

    xformDest->eM11 =  xformSrc->eM22 / determinant;
    xformDest->eM12 = -xformSrc->eM12 / determinant;
    xformDest->eM21 = -xformSrc->eM21 / determinant;
    xformDest->eM22 =  xformSrc->eM11 / determinant;
    xformDest->eDx  = -xformSrc->eDx * xformDest->eM11 -
                       xformSrc->eDy * xformDest->eM21;
    xformDest->eDy  = -xformSrc->eDx * xformDest->eM12 -
                       xformSrc->eDy * xformDest->eM22;

    return TRUE;
}


/***********************************************************************
 *           DC_UpdateXforms
 *
 * Updates the xformWorld2Vport, xformVport2World and vport2WorldValid
 * fields of the specified DC by creating a transformation that
 * represents the current mapping mode and combining it with the DC's
 * world transform. This function should be called whenever the
 * parameters associated with the mapping mode (window and viewport
 * extents and origins) or the world transform change.
 */
void DC_UpdateXforms( DC *dc )
{
249
    XFORM xformWnd2Vport, oldworld2vport;
Alexandre Julliard's avatar
Alexandre Julliard committed
250
    FLOAT scaleX, scaleY;
251

Alexandre Julliard's avatar
Alexandre Julliard committed
252 253 254 255 256 257 258 259 260 261 262 263
    /* Construct a transformation to do the window-to-viewport conversion */
    scaleX = (FLOAT)dc->vportExtX / (FLOAT)dc->wndExtX;
    scaleY = (FLOAT)dc->vportExtY / (FLOAT)dc->wndExtY;
    xformWnd2Vport.eM11 = scaleX;
    xformWnd2Vport.eM12 = 0.0;
    xformWnd2Vport.eM21 = 0.0;
    xformWnd2Vport.eM22 = scaleY;
    xformWnd2Vport.eDx  = (FLOAT)dc->vportOrgX -
        scaleX * (FLOAT)dc->wndOrgX;
    xformWnd2Vport.eDy  = (FLOAT)dc->vportOrgY -
        scaleY * (FLOAT)dc->wndOrgY;

264
    oldworld2vport = dc->xformWorld2Vport;
Alexandre Julliard's avatar
Alexandre Julliard committed
265
    /* Combine with the world transformation */
266
    CombineTransform( &dc->xformWorld2Vport, &dc->xformWorld2Wnd,
Alexandre Julliard's avatar
Alexandre Julliard committed
267 268 269
        &xformWnd2Vport );

    /* Create inverse of world-to-viewport transformation */
270 271
    dc->vport2WorldValid = DC_InvertXform( &dc->xformWorld2Vport,
        &dc->xformVport2World );
272

273
    /* Reselect the font and pen back into the dc so that the size
274
       gets updated. */
275
    if(memcmp(&oldworld2vport, &dc->xformWorld2Vport, sizeof(oldworld2vport)))
276
    {
277
        SelectObject(dc->hSelf, GetCurrentObject(dc->hSelf, OBJ_FONT));
278 279
        SelectObject(dc->hSelf, GetCurrentObject(dc->hSelf, OBJ_PEN));
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
280 281 282
}


Alexandre Julliard's avatar
Alexandre Julliard committed
283
/***********************************************************************
284
 *           GetDCState   (Not a Windows API)
Alexandre Julliard's avatar
Alexandre Julliard committed
285
 */
286
HDC WINAPI GetDCState( HDC hdc )
Alexandre Julliard's avatar
Alexandre Julliard committed
287 288
{
    DC * newdc, * dc;
289
    HGDIOBJ handle;
290

291
    if (!(dc = DC_GetDCPtr( hdc ))) return 0;
292
    if (!(newdc = GDI_AllocObject( sizeof(DC), GDIMAGIC(dc->header.wMagic), &handle, &dc_funcs )))
Alexandre Julliard's avatar
Alexandre Julliard committed
293
    {
294
      GDI_ReleaseObj( hdc );
Alexandre Julliard's avatar
Alexandre Julliard committed
295 296
      return 0;
    }
297
    TRACE("(%p): returning %p\n", hdc, handle );
Alexandre Julliard's avatar
Alexandre Julliard committed
298

299
    newdc->flags            = dc->flags | DC_SAVED;
300
    newdc->layout           = dc->layout;
301 302 303 304
    newdc->hPen             = dc->hPen;
    newdc->hBrush           = dc->hBrush;
    newdc->hFont            = dc->hFont;
    newdc->hBitmap          = dc->hBitmap;
305
    newdc->hDevice          = dc->hDevice;
306
    newdc->hPalette         = dc->hPalette;
307 308 309 310 311 312 313
    newdc->ROPmode          = dc->ROPmode;
    newdc->polyFillMode     = dc->polyFillMode;
    newdc->stretchBltMode   = dc->stretchBltMode;
    newdc->relAbsMode       = dc->relAbsMode;
    newdc->backgroundMode   = dc->backgroundMode;
    newdc->backgroundColor  = dc->backgroundColor;
    newdc->textColor        = dc->textColor;
314 315
    newdc->dcBrushColor     = dc->dcBrushColor;
    newdc->dcPenColor       = dc->dcPenColor;
316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338
    newdc->brushOrgX        = dc->brushOrgX;
    newdc->brushOrgY        = dc->brushOrgY;
    newdc->textAlign        = dc->textAlign;
    newdc->charExtra        = dc->charExtra;
    newdc->breakExtra       = dc->breakExtra;
    newdc->breakRem         = dc->breakRem;
    newdc->MapMode          = dc->MapMode;
    newdc->GraphicsMode     = dc->GraphicsMode;
    newdc->CursPosX         = dc->CursPosX;
    newdc->CursPosY         = dc->CursPosY;
    newdc->ArcDirection     = dc->ArcDirection;
    newdc->xformWorld2Wnd   = dc->xformWorld2Wnd;
    newdc->xformWorld2Vport = dc->xformWorld2Vport;
    newdc->xformVport2World = dc->xformVport2World;
    newdc->vport2WorldValid = dc->vport2WorldValid;
    newdc->wndOrgX          = dc->wndOrgX;
    newdc->wndOrgY          = dc->wndOrgY;
    newdc->wndExtX          = dc->wndExtX;
    newdc->wndExtY          = dc->wndExtY;
    newdc->vportOrgX        = dc->vportOrgX;
    newdc->vportOrgY        = dc->vportOrgY;
    newdc->vportExtX        = dc->vportExtX;
    newdc->vportExtY        = dc->vportExtY;
339
    newdc->BoundsRect       = dc->BoundsRect;
Alexandre Julliard's avatar
Alexandre Julliard committed
340

341
    newdc->hSelf = (HDC)handle;
Alexandre Julliard's avatar
Alexandre Julliard committed
342
    newdc->saveLevel = 0;
343
    newdc->saved_dc  = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
344

345
    PATH_InitGdiPath( &newdc->path );
346

347
    newdc->pAbortProc = NULL;
348
    newdc->hookThunk  = NULL;
349
    newdc->hookProc   = 0;
350
    newdc->saved_visrgn = NULL;
351

Alexandre Julliard's avatar
Alexandre Julliard committed
352 353
    /* Get/SetDCState() don't change hVisRgn field ("Undoc. Windows" p.559). */

354 355 356 357
    newdc->hVisRgn      = 0;
    newdc->hClipRgn     = 0;
    newdc->hMetaRgn     = 0;
    newdc->hMetaClipRgn = 0;
358
    if (dc->hClipRgn)
Alexandre Julliard's avatar
Alexandre Julliard committed
359
    {
360 361
        newdc->hClipRgn = CreateRectRgn( 0, 0, 0, 0 );
        CombineRgn( newdc->hClipRgn, dc->hClipRgn, 0, RGN_COPY );
Alexandre Julliard's avatar
Alexandre Julliard committed
362
    }
363 364 365 366 367 368
    if (dc->hMetaRgn)
    {
        newdc->hMetaRgn = CreateRectRgn( 0, 0, 0, 0 );
        CombineRgn( newdc->hMetaRgn, dc->hMetaRgn, 0, RGN_COPY );
    }
    /* don't bother recomputing hMetaClipRgn, we'll do that in SetDCState */
369 370 371 372 373 374

    if(dc->gdiFont) {
	newdc->gdiFont = dc->gdiFont;
    } else
        newdc->gdiFont = 0;

375 376
    GDI_ReleaseObj( handle );
    GDI_ReleaseObj( hdc );
Alexandre Julliard's avatar
Alexandre Julliard committed
377 378 379 380 381
    return handle;
}


/***********************************************************************
382
 *           SetDCState   (Not a Windows API)
Alexandre Julliard's avatar
Alexandre Julliard committed
383
 */
384
void WINAPI SetDCState( HDC hdc, HDC hdcs )
Alexandre Julliard's avatar
Alexandre Julliard committed
385
{
Alexandre Julliard's avatar
Alexandre Julliard committed
386
    DC *dc, *dcs;
387

388
    if (!(dc = DC_GetDCUpdate( hdc ))) return;
389
    if (!(dcs = DC_GetDCPtr( hdcs )))
Alexandre Julliard's avatar
Alexandre Julliard committed
390
    {
391
      GDI_ReleaseObj( hdc );
Alexandre Julliard's avatar
Alexandre Julliard committed
392 393
      return;
    }
394
    if (!dcs->flags & DC_SAVED)
Alexandre Julliard's avatar
Alexandre Julliard committed
395
    {
396 397
      GDI_ReleaseObj( hdc );
      GDI_ReleaseObj( hdcs );
Alexandre Julliard's avatar
Alexandre Julliard committed
398 399
      return;
    }
400
    TRACE("%p %p\n", hdc, hdcs );
Alexandre Julliard's avatar
Alexandre Julliard committed
401

402
    dc->flags            = dcs->flags & ~(DC_SAVED | DC_DIRTY);
403
    dc->layout           = dcs->layout;
404 405 406 407 408 409 410 411
    dc->hDevice          = dcs->hDevice;
    dc->ROPmode          = dcs->ROPmode;
    dc->polyFillMode     = dcs->polyFillMode;
    dc->stretchBltMode   = dcs->stretchBltMode;
    dc->relAbsMode       = dcs->relAbsMode;
    dc->backgroundMode   = dcs->backgroundMode;
    dc->backgroundColor  = dcs->backgroundColor;
    dc->textColor        = dcs->textColor;
412 413
    dc->dcBrushColor     = dcs->dcBrushColor;
    dc->dcPenColor       = dcs->dcPenColor;
414 415 416 417 418 419 420 421 422 423 424 425 426 427 428
    dc->brushOrgX        = dcs->brushOrgX;
    dc->brushOrgY        = dcs->brushOrgY;
    dc->textAlign        = dcs->textAlign;
    dc->charExtra        = dcs->charExtra;
    dc->breakExtra       = dcs->breakExtra;
    dc->breakRem         = dcs->breakRem;
    dc->MapMode          = dcs->MapMode;
    dc->GraphicsMode     = dcs->GraphicsMode;
    dc->CursPosX         = dcs->CursPosX;
    dc->CursPosY         = dcs->CursPosY;
    dc->ArcDirection     = dcs->ArcDirection;
    dc->xformWorld2Wnd   = dcs->xformWorld2Wnd;
    dc->xformWorld2Vport = dcs->xformWorld2Vport;
    dc->xformVport2World = dcs->xformVport2World;
    dc->vport2WorldValid = dcs->vport2WorldValid;
429
    dc->BoundsRect       = dcs->BoundsRect;
430 431 432 433 434 435 436 437 438 439 440

    dc->wndOrgX          = dcs->wndOrgX;
    dc->wndOrgY          = dcs->wndOrgY;
    dc->wndExtX          = dcs->wndExtX;
    dc->wndExtY          = dcs->wndExtY;
    dc->vportOrgX        = dcs->vportOrgX;
    dc->vportOrgY        = dcs->vportOrgY;
    dc->vportExtX        = dcs->vportExtX;
    dc->vportExtY        = dcs->vportExtY;

    if (dcs->hClipRgn)
441
    {
442 443
        if (!dc->hClipRgn) dc->hClipRgn = CreateRectRgn( 0, 0, 0, 0 );
        CombineRgn( dc->hClipRgn, dcs->hClipRgn, 0, RGN_COPY );
444 445
    }
    else
446
    {
447
        if (dc->hClipRgn) DeleteObject( dc->hClipRgn );
448
        dc->hClipRgn = 0;
449
    }
450 451 452 453 454 455 456 457 458 459
    if (dcs->hMetaRgn)
    {
        if (!dc->hMetaRgn) dc->hMetaRgn = CreateRectRgn( 0, 0, 0, 0 );
        CombineRgn( dc->hMetaRgn, dcs->hMetaRgn, 0, RGN_COPY );
    }
    else
    {
        if (dc->hMetaRgn) DeleteObject( dc->hMetaRgn );
        dc->hMetaRgn = 0;
    }
460
    CLIPPING_UpdateGCRegion( dc );
Alexandre Julliard's avatar
Alexandre Julliard committed
461

462 463 464 465 466 467
    SelectObject( hdc, dcs->hBitmap );
    SelectObject( hdc, dcs->hBrush );
    SelectObject( hdc, dcs->hFont );
    SelectObject( hdc, dcs->hPen );
    SetBkColor( hdc, dcs->backgroundColor);
    SetTextColor( hdc, dcs->textColor);
468
    GDISelectPalette( hdc, dcs->hPalette, FALSE );
469 470
    GDI_ReleaseObj( hdcs );
    GDI_ReleaseObj( hdc );
Alexandre Julliard's avatar
Alexandre Julliard committed
471 472 473
}


474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491
/***********************************************************************
 *           GetDCState   (GDI.179)
 */
HDC16 WINAPI GetDCState16( HDC16 hdc )
{
    return HDC_16( GetDCState( HDC_32(hdc) ));
}


/***********************************************************************
 *           SetDCState   (GDI.180)
 */
void WINAPI SetDCState16( HDC16 hdc, HDC16 hdcs )
{
    SetDCState( HDC_32(hdc), HDC_32(hdcs) );
}


Alexandre Julliard's avatar
Alexandre Julliard committed
492
/***********************************************************************
493
 *           SaveDC    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
494
 */
495
INT WINAPI SaveDC( HDC hdc )
Alexandre Julliard's avatar
Alexandre Julliard committed
496
{
497
    HDC hdcs;
Alexandre Julliard's avatar
Alexandre Julliard committed
498
    DC * dc, * dcs;
499
    INT ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
500

501
    dc = DC_GetDCPtr( hdc );
502 503 504
    if (!dc) return 0;

    if(dc->funcs->pSaveDC)
505
    {
506
        ret = dc->funcs->pSaveDC( dc->physDev );
507 508
        if(ret)
            ret = ++dc->saveLevel;
509 510 511
        GDI_ReleaseObj( hdc );
        return ret;
    }
512

513
    if (!(hdcs = GetDCState( hdc )))
Alexandre Julliard's avatar
Alexandre Julliard committed
514
    {
515
      GDI_ReleaseObj( hdc );
Alexandre Julliard's avatar
Alexandre Julliard committed
516 517
      return 0;
    }
518
    dcs = DC_GetDCPtr( hdcs );
Alexandre Julliard's avatar
Alexandre Julliard committed
519 520 521 522 523 524 525

    /* Copy path. The reason why path saving / restoring is in SaveDC/
     * RestoreDC and not in GetDCState/SetDCState is that the ...DCState
     * functions are only in Win16 (which doesn't have paths) and that
     * SetDCState doesn't allow us to signal an error (which can happen
     * when copying paths).
     */
526
    if (!PATH_AssignGdiPath( &dcs->path, &dc->path ))
Alexandre Julliard's avatar
Alexandre Julliard committed
527
    {
528 529
        GDI_ReleaseObj( hdc );
	GDI_ReleaseObj( hdcs );
530
	DeleteDC( hdcs );
Alexandre Julliard's avatar
Alexandre Julliard committed
531 532
	return 0;
    }
533

534 535
    dcs->saved_dc = dc->saved_dc;
    dc->saved_dc = hdcs;
536
    TRACE("(%p): returning %d\n", hdc, dc->saveLevel+1 );
Alexandre Julliard's avatar
Alexandre Julliard committed
537
    ret = ++dc->saveLevel;
538 539
    GDI_ReleaseObj( hdcs );
    GDI_ReleaseObj( hdc );
Alexandre Julliard's avatar
Alexandre Julliard committed
540
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
541 542 543
}


Alexandre Julliard's avatar
Alexandre Julliard committed
544
/***********************************************************************
545
 *           RestoreDC    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
546
 */
547
BOOL WINAPI RestoreDC( HDC hdc, INT level )
Alexandre Julliard's avatar
Alexandre Julliard committed
548 549
{
    DC * dc, * dcs;
550
    BOOL success;
Alexandre Julliard's avatar
Alexandre Julliard committed
551

552
    TRACE("%p %d\n", hdc, level );
553
    dc = DC_GetDCUpdate( hdc );
554
    if(!dc) return FALSE;
555 556

    if(abs(level) > dc->saveLevel || level == 0)
557 558
    {
        GDI_ReleaseObj( hdc );
559
        return FALSE;
560
    }
561 562
        
    if(dc->funcs->pRestoreDC)
Alexandre Julliard's avatar
Alexandre Julliard committed
563
    {
564 565 566 567
        success = dc->funcs->pRestoreDC( dc->physDev, level );
        if(level < 0) level = dc->saveLevel + level + 1;
        if(success)
            dc->saveLevel = level - 1;
568
        GDI_ReleaseObj( hdc );
569
        return success;
Alexandre Julliard's avatar
Alexandre Julliard committed
570
    }
571

572
    if (level < 0) level = dc->saveLevel + level + 1;
Alexandre Julliard's avatar
Alexandre Julliard committed
573
    success=TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
574
    while (dc->saveLevel >= level)
Alexandre Julliard's avatar
Alexandre Julliard committed
575
    {
576
        HDC hdcs = dc->saved_dc;
577
	if (!(dcs = DC_GetDCPtr( hdcs )))
Alexandre Julliard's avatar
Alexandre Julliard committed
578
	{
579
	  GDI_ReleaseObj( hdc );
Alexandre Julliard's avatar
Alexandre Julliard committed
580
	  return FALSE;
581
	}
582 583
        dc->saved_dc = dcs->saved_dc;
        dcs->saved_dc = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
584 585
	if (--dc->saveLevel < level)
	{
586
	    SetDCState( hdc, hdcs );
587
            if (!PATH_AssignGdiPath( &dc->path, &dcs->path ))
Alexandre Julliard's avatar
Alexandre Julliard committed
588 589 590 591
		/* FIXME: This might not be quite right, since we're
		 * returning FALSE but still destroying the saved DC state */
	        success=FALSE;
	}
592
        GDI_ReleaseObj( hdcs );
593
        GDI_ReleaseObj( hdc );
594
	DeleteDC( hdcs );
595
        if (!(dc = DC_GetDCPtr( hdc ))) return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
596
    }
597
    GDI_ReleaseObj( hdc );
Alexandre Julliard's avatar
Alexandre Julliard committed
598
    return success;
Alexandre Julliard's avatar
Alexandre Julliard committed
599 600 601
}


602
/***********************************************************************
603
 *           CreateDCW    (GDI32.@)
604
 */
605 606
HDC WINAPI CreateDCW( LPCWSTR driver, LPCWSTR device, LPCWSTR output,
                      const DEVMODEW *initData )
Alexandre Julliard's avatar
Alexandre Julliard committed
607
{
608
    HDC hdc;
Alexandre Julliard's avatar
Alexandre Julliard committed
609
    DC * dc;
Alexandre Julliard's avatar
Alexandre Julliard committed
610
    const DC_FUNCTIONS *funcs;
611
    WCHAR buf[300];
Alexandre Julliard's avatar
Alexandre Julliard committed
612

613 614
    GDI_CheckNotLock();

615
    if (!device || !DRIVER_GetDriverName( device, buf, 300 ))
616
    {
617 618 619 620 621
        if (!driver)
        {
            ERR( "no device found for %s\n", debugstr_w(device) );
            return 0;
        }
622
        strcpyW(buf, driver);
623
    }
624

625 626
    if (!(funcs = DRIVER_load_driver( buf )))
    {
627
        ERR( "no driver found for %s\n", debugstr_w(buf) );
628 629
        return 0;
    }
630
    if (!(dc = DC_AllocDC( funcs, DC_MAGIC )))
631 632 633 634
    {
        DRIVER_release_driver( funcs );
        return 0;
    }
635
    hdc = dc->hSelf;
636

637
    dc->hBitmap = GetStockObject( DEFAULT_BITMAP );
Alexandre Julliard's avatar
Alexandre Julliard committed
638

639
    TRACE("(driver=%s, device=%s, output=%s): returning %p\n",
640
          debugstr_w(driver), debugstr_w(device), debugstr_w(output), dc->hSelf );
Alexandre Julliard's avatar
Alexandre Julliard committed
641 642

    if (dc->funcs->pCreateDC &&
643
        !dc->funcs->pCreateDC( hdc, &dc->physDev, buf, device, output, initData ))
Alexandre Julliard's avatar
Alexandre Julliard committed
644
    {
645
        WARN("creation aborted by device\n" );
646
        GDI_FreeObject( dc->hSelf, dc );
647
        DRIVER_release_driver( funcs );
Alexandre Julliard's avatar
Alexandre Julliard committed
648 649
        return 0;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
650

651 652
    dc->hVisRgn = CreateRectRgn( 0, 0, GetDeviceCaps( hdc, HORZRES ),
                                 GetDeviceCaps( hdc, VERTRES ) );
653

Alexandre Julliard's avatar
Alexandre Julliard committed
654
    DC_InitDC( dc );
655 656
    GDI_ReleaseObj( hdc );
    return hdc;
Alexandre Julliard's avatar
Alexandre Julliard committed
657 658 659
}


Alexandre Julliard's avatar
Alexandre Julliard committed
660
/***********************************************************************
661
 *           CreateDCA    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
662
 */
663 664
HDC WINAPI CreateDCA( LPCSTR driver, LPCSTR device, LPCSTR output,
                      const DEVMODEA *initData )
665
{
666
    UNICODE_STRING driverW, deviceW, outputW;
667
    DEVMODEW *initDataW;
668 669 670 671 672 673 674 675 676 677 678
    HDC ret;

    if (driver) RtlCreateUnicodeStringFromAsciiz(&driverW, driver);
    else driverW.Buffer = NULL;

    if (device) RtlCreateUnicodeStringFromAsciiz(&deviceW, device);
    else deviceW.Buffer = NULL;

    if (output) RtlCreateUnicodeStringFromAsciiz(&outputW, output);
    else outputW.Buffer = NULL;

679 680 681 682 683 684 685
    initDataW = NULL;
    if (initData)
    {
        /* don't convert initData for DISPLAY driver, it's not used */
        if (!driverW.Buffer || strcmpiW( driverW.Buffer, displayW ))
            initDataW = GdiConvertToDevmodeW(initData);
    }
686

687
    ret = CreateDCW( driverW.Buffer, deviceW.Buffer, outputW.Buffer, initDataW );
688 689 690 691

    RtlFreeUnicodeString(&driverW);
    RtlFreeUnicodeString(&deviceW);
    RtlFreeUnicodeString(&outputW);
692
    HeapFree(GetProcessHeap(), 0, initDataW);
693
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
694 695 696
}


Alexandre Julliard's avatar
Alexandre Julliard committed
697
/***********************************************************************
698
 *           CreateICA    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
699
 */
700 701
HDC WINAPI CreateICA( LPCSTR driver, LPCSTR device, LPCSTR output,
                          const DEVMODEA* initData )
Alexandre Julliard's avatar
Alexandre Julliard committed
702 703
{
      /* Nothing special yet for ICs */
704
    return CreateDCA( driver, device, output, initData );
Alexandre Julliard's avatar
Alexandre Julliard committed
705 706 707 708
}


/***********************************************************************
709
 *           CreateICW    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
710
 */
711 712
HDC WINAPI CreateICW( LPCWSTR driver, LPCWSTR device, LPCWSTR output,
                          const DEVMODEW* initData )
Alexandre Julliard's avatar
Alexandre Julliard committed
713 714
{
      /* Nothing special yet for ICs */
715
    return CreateDCW( driver, device, output, initData );
Alexandre Julliard's avatar
Alexandre Julliard committed
716 717 718 719
}


/***********************************************************************
720
 *           CreateCompatibleDC   (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
721
 */
722
HDC WINAPI CreateCompatibleDC( HDC hdc )
Alexandre Julliard's avatar
Alexandre Julliard committed
723
{
Alexandre Julliard's avatar
Alexandre Julliard committed
724 725
    DC *dc, *origDC;
    const DC_FUNCTIONS *funcs;
726
    PHYSDEV physDev;
Alexandre Julliard's avatar
Alexandre Julliard committed
727

728
    GDI_CheckNotLock();
729

730
    if ((origDC = GDI_GetObjPtr( hdc, DC_MAGIC )))
731
    {
732
        funcs = origDC->funcs;
733
        physDev = origDC->physDev;
734 735
        GDI_ReleaseObj( hdc ); /* can't hold the lock while loading the driver */
        funcs = DRIVER_get_driver( funcs );
736
    }
737 738
    else
    {
739
        funcs = DRIVER_load_driver( displayW );
740 741
        physDev = NULL;
    }
742 743

    if (!funcs) return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
744

745
    if (!(dc = DC_AllocDC( funcs, MEMORY_DC_MAGIC )))
746
    {
747
        DRIVER_release_driver( funcs );
748 749
        return 0;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
750

751
    TRACE("(%p): returning %p\n", hdc, dc->hSelf );
Alexandre Julliard's avatar
Alexandre Julliard committed
752

753
    dc->hBitmap = GetStockObject( DEFAULT_BITMAP );
Alexandre Julliard's avatar
Alexandre Julliard committed
754

755 756 757
    /* Copy the driver-specific physical device info into
     * the new DC. The driver may use this read-only info
     * while creating the compatible DC below. */
758
    dc->physDev = physDev;
759

Alexandre Julliard's avatar
Alexandre Julliard committed
760
    if (dc->funcs->pCreateDC &&
761
        !dc->funcs->pCreateDC( dc->hSelf, &dc->physDev, NULL, NULL, NULL, NULL ))
Alexandre Julliard's avatar
Alexandre Julliard committed
762
    {
763
        WARN("creation aborted by device\n");
764
        GDI_FreeObject( dc->hSelf, dc );
765
        DRIVER_release_driver( funcs );
Alexandre Julliard's avatar
Alexandre Julliard committed
766 767
        return 0;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
768

769
    dc->hVisRgn = CreateRectRgn( 0, 0, 1, 1 );  /* default bitmap is 1x1 */
770

Alexandre Julliard's avatar
Alexandre Julliard committed
771
    DC_InitDC( dc );
772
    GDI_ReleaseObj( dc->hSelf );
Alexandre Julliard's avatar
Alexandre Julliard committed
773
    return dc->hSelf;
Alexandre Julliard's avatar
Alexandre Julliard committed
774 775 776
}


Alexandre Julliard's avatar
Alexandre Julliard committed
777
/***********************************************************************
778
 *           DeleteDC    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
779
 */
780
BOOL WINAPI DeleteDC( HDC hdc )
Alexandre Julliard's avatar
Alexandre Julliard committed
781
{
782 783
    const DC_FUNCTIONS *funcs = NULL;
    DC * dc;
Alexandre Julliard's avatar
Alexandre Julliard committed
784

785
    TRACE("%p\n", hdc );
Alexandre Julliard's avatar
Alexandre Julliard committed
786

787 788
    GDI_CheckNotLock();

789
    if (!(dc = DC_GetDCPtr( hdc ))) return FALSE;
790

791
    /* Call hook procedure to check whether is it OK to delete this DC */
792
    if (dc->hookThunk)
793
    {
794
        DCHOOKPROC proc = dc->hookThunk;
795 796 797 798
        DWORD data = dc->dwHookData;
        GDI_ReleaseObj( hdc );
        if (!proc( HDC_16(hdc), DCHC_DELETEDC, data, 0 )) return FALSE;
        if (!(dc = DC_GetDCPtr( hdc ))) return TRUE;  /* deleted by the hook */
799 800
    }

Alexandre Julliard's avatar
Alexandre Julliard committed
801 802
    while (dc->saveLevel)
    {
803 804 805 806 807
        DC * dcs;
        HDC hdcs = dc->saved_dc;
        if (!(dcs = DC_GetDCPtr( hdcs ))) break;
        dc->saved_dc = dcs->saved_dc;
        dc->saveLevel--;
808
        if (dcs->hClipRgn) DeleteObject( dcs->hClipRgn );
809 810
        if (dcs->hMetaRgn) DeleteObject( dcs->hMetaRgn );
        if (dcs->hMetaClipRgn) DeleteObject( dcs->hMetaClipRgn );
811 812 813
        if (dcs->hVisRgn) DeleteObject( dcs->hVisRgn );
        PATH_DestroyGdiPath(&dcs->path);
        GDI_FreeObject( hdcs, dcs );
Alexandre Julliard's avatar
Alexandre Julliard committed
814
    }
815

816
    if (!(dc->flags & DC_SAVED))
Alexandre Julliard's avatar
Alexandre Julliard committed
817
    {
818 819 820
	SelectObject( hdc, GetStockObject(BLACK_PEN) );
	SelectObject( hdc, GetStockObject(WHITE_BRUSH) );
	SelectObject( hdc, GetStockObject(SYSTEM_FONT) );
821
        SelectObject( hdc, GetStockObject(DEFAULT_BITMAP) );
822
        funcs = dc->funcs;
823
        if (dc->funcs->pDeleteDC) dc->funcs->pDeleteDC(dc->physDev);
824
        dc->physDev = NULL;
Alexandre Julliard's avatar
Alexandre Julliard committed
825
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
826

827 828 829 830 831 832 833
    while (dc->saved_visrgn)
    {
        struct saved_visrgn *next = dc->saved_visrgn->next;
        DeleteObject( dc->saved_visrgn->hrgn );
        HeapFree( GetProcessHeap(), 0, dc->saved_visrgn );
        dc->saved_visrgn = next;
    }
834
    if (dc->hClipRgn) DeleteObject( dc->hClipRgn );
835 836
    if (dc->hMetaRgn) DeleteObject( dc->hMetaRgn );
    if (dc->hMetaClipRgn) DeleteObject( dc->hMetaClipRgn );
837 838
    if (dc->hVisRgn) DeleteObject( dc->hVisRgn );
    PATH_DestroyGdiPath(&dc->path);
839

840 841 842
    GDI_FreeObject( hdc, dc );
    if (funcs) DRIVER_release_driver( funcs );  /* do that after releasing the GDI lock */
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
843 844 845
}


Alexandre Julliard's avatar
Alexandre Julliard committed
846
/***********************************************************************
847
 *           ResetDCW    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
848
 */
849
HDC WINAPI ResetDCW( HDC hdc, const DEVMODEW *devmode )
Alexandre Julliard's avatar
Alexandre Julliard committed
850
{
851 852 853 854 855 856 857 858 859
    DC *dc;
    HDC ret = hdc;

    if ((dc = DC_GetDCPtr( hdc )))
    {
        if (dc->funcs->pResetDC) ret = dc->funcs->pResetDC( dc->physDev, devmode );
        GDI_ReleaseObj( hdc );
    }
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
860 861 862 863
}


/***********************************************************************
864
 *           ResetDCA    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
865
 */
866
HDC WINAPI ResetDCA( HDC hdc, const DEVMODEA *devmode )
Alexandre Julliard's avatar
Alexandre Julliard committed
867
{
868 869 870 871 872 873 874 875
    DEVMODEW *devmodeW;
    HDC ret;

    if (devmode) devmodeW = GdiConvertToDevmodeW(devmode);
    else devmodeW = NULL;

    ret = ResetDCW(hdc, devmodeW);

876
    HeapFree(GetProcessHeap(), 0, devmodeW);
877
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
878 879 880
}


Alexandre Julliard's avatar
Alexandre Julliard committed
881
/***********************************************************************
882
 *           GetDeviceCaps    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
883
 */
884
INT WINAPI GetDeviceCaps( HDC hdc, INT cap )
Alexandre Julliard's avatar
Alexandre Julliard committed
885
{
886
    DC *dc;
887
    INT ret = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
888

889
    if ((dc = DC_GetDCPtr( hdc )))
890
    {
891
        if (dc->funcs->pGetDeviceCaps) ret = dc->funcs->pGetDeviceCaps( dc->physDev, cap );
892 893 894 895 896 897 898 899 900 901 902 903 904 905
        else switch(cap)  /* return meaningful values for some entries */
        {
        case HORZRES:     ret = 640; break;
        case VERTRES:     ret = 480; break;
        case BITSPIXEL:   ret = 1; break;
        case PLANES:      ret = 1; break;
        case NUMCOLORS:   ret = 2; break;
        case ASPECTX:     ret = 36; break;
        case ASPECTY:     ret = 36; break;
        case ASPECTXY:    ret = 51; break;
        case LOGPIXELSX:  ret = 72; break;
        case LOGPIXELSY:  ret = 72; break;
        case SIZEPALETTE: ret = 2; break;
        }
906
        GDI_ReleaseObj( hdc );
907
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
908
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
909 910 911
}


912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927
/***********************************************************************
 *		GetBkColor (GDI32.@)
 */
COLORREF WINAPI GetBkColor( HDC hdc )
{
    COLORREF ret = 0;
    DC * dc = DC_GetDCPtr( hdc );
    if (dc)
    {
        ret = dc->backgroundColor;
        GDI_ReleaseObj( hdc );
    }
    return ret;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
928
/***********************************************************************
929
 *           SetBkColor    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
930
 */
931
COLORREF WINAPI SetBkColor( HDC hdc, COLORREF color )
Alexandre Julliard's avatar
Alexandre Julliard committed
932 933
{
    COLORREF oldColor;
Alexandre Julliard's avatar
Alexandre Julliard committed
934
    DC * dc = DC_GetDCPtr( hdc );
935

936 937
    TRACE("hdc=%p color=0x%08lx\n", hdc, color);

938 939
    if (!dc) return CLR_INVALID;
    oldColor = dc->backgroundColor;
Alexandre Julliard's avatar
Alexandre Julliard committed
940
    if (dc->funcs->pSetBkColor)
941 942 943 944 945 946 947
    {
        color = dc->funcs->pSetBkColor(dc->physDev, color);
        if (color == CLR_INVALID)  /* don't change it */
        {
            color = oldColor;
            oldColor = CLR_INVALID;
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
948
    }
949
    dc->backgroundColor = color;
950
    GDI_ReleaseObj( hdc );
Alexandre Julliard's avatar
Alexandre Julliard committed
951 952 953 954
    return oldColor;
}


955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970
/***********************************************************************
 *		GetTextColor (GDI32.@)
 */
COLORREF WINAPI GetTextColor( HDC hdc )
{
    COLORREF ret = 0;
    DC * dc = DC_GetDCPtr( hdc );
    if (dc)
    {
        ret = dc->textColor;
        GDI_ReleaseObj( hdc );
    }
    return ret;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
971
/***********************************************************************
972
 *           SetTextColor    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
973
 */
974
COLORREF WINAPI SetTextColor( HDC hdc, COLORREF color )
Alexandre Julliard's avatar
Alexandre Julliard committed
975 976
{
    COLORREF oldColor;
Alexandre Julliard's avatar
Alexandre Julliard committed
977
    DC * dc = DC_GetDCPtr( hdc );
978

979 980
    TRACE(" hdc=%p color=0x%08lx\n", hdc, color);

981 982
    if (!dc) return CLR_INVALID;
    oldColor = dc->textColor;
Alexandre Julliard's avatar
Alexandre Julliard committed
983
    if (dc->funcs->pSetTextColor)
984 985 986 987 988 989 990
    {
        color = dc->funcs->pSetTextColor(dc->physDev, color);
        if (color == CLR_INVALID)  /* don't change it */
        {
            color = oldColor;
            oldColor = CLR_INVALID;
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
991
    }
992
    dc->textColor = color;
993
    GDI_ReleaseObj( hdc );
Alexandre Julliard's avatar
Alexandre Julliard committed
994 995 996
    return oldColor;
}

Alexandre Julliard's avatar
Alexandre Julliard committed
997

998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013
/***********************************************************************
 *		GetTextAlign (GDI32.@)
 */
UINT WINAPI GetTextAlign( HDC hdc )
{
    UINT ret = 0;
    DC * dc = DC_GetDCPtr( hdc );
    if (dc)
    {
        ret = dc->textAlign;
        GDI_ReleaseObj( hdc );
    }
    return ret;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1014
/***********************************************************************
1015
 *           SetTextAlign    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
1016
 */
1017
UINT WINAPI SetTextAlign( HDC hdc, UINT align )
Alexandre Julliard's avatar
Alexandre Julliard committed
1018
{
1019
    UINT ret;
1020
    DC *dc = DC_GetDCPtr( hdc );
1021 1022 1023

    TRACE("hdc=%p align=%d\n", hdc, align);

1024
    if (!dc) return 0x0;
1025
    ret = dc->textAlign;
1026
    if (dc->funcs->pSetTextAlign)
1027 1028 1029
        if (!dc->funcs->pSetTextAlign(dc->physDev, align))
            ret = GDI_ERROR;
    if (ret != GDI_ERROR)
1030
	dc->textAlign = align;
1031
    GDI_ReleaseObj( hdc );
1032
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
1033 1034
}

Alexandre Julliard's avatar
Alexandre Julliard committed
1035
/***********************************************************************
1036
 *           GetDCOrgEx  (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
1037
 */
1038
BOOL WINAPI GetDCOrgEx( HDC hDC, LPPOINT lpp )
Alexandre Julliard's avatar
Alexandre Julliard committed
1039
{
Alexandre Julliard's avatar
Alexandre Julliard committed
1040
    DC * dc;
1041

Alexandre Julliard's avatar
Alexandre Julliard committed
1042
    if (!lpp) return FALSE;
1043
    if (!(dc = DC_GetDCPtr( hDC ))) return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1044

1045
    lpp->x = lpp->y = 0;
1046
    if (dc->funcs->pGetDCOrgEx) dc->funcs->pGetDCOrgEx( dc->physDev, lpp );
1047
    GDI_ReleaseObj( hDC );
Alexandre Julliard's avatar
Alexandre Julliard committed
1048 1049 1050 1051
    return TRUE;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1052
/***********************************************************************
1053
 *           SetDCOrg   (GDI.117)
Alexandre Julliard's avatar
Alexandre Julliard committed
1054
 */
1055
DWORD WINAPI SetDCOrg16( HDC16 hdc16, INT16 x, INT16 y )
Alexandre Julliard's avatar
Alexandre Julliard committed
1056
{
1057
    DWORD prevOrg = 0;
1058
    HDC hdc = HDC_32( hdc16 );
1059
    DC *dc = DC_GetDCPtr( hdc );
Alexandre Julliard's avatar
Alexandre Julliard committed
1060
    if (!dc) return 0;
1061
    if (dc->funcs->pSetDCOrg) prevOrg = dc->funcs->pSetDCOrg( dc->physDev, x, y );
1062
    GDI_ReleaseObj( hdc );
Alexandre Julliard's avatar
Alexandre Julliard committed
1063 1064
    return prevOrg;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1065 1066


1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082
/***********************************************************************
 *		GetGraphicsMode (GDI32.@)
 */
INT WINAPI GetGraphicsMode( HDC hdc )
{
    INT ret = 0;
    DC * dc = DC_GetDCPtr( hdc );
    if (dc)
    {
        ret = dc->GraphicsMode;
        GDI_ReleaseObj( hdc );
    }
    return ret;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1083
/***********************************************************************
1084
 *           SetGraphicsMode    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
1085
 */
1086
INT WINAPI SetGraphicsMode( HDC hdc, INT mode )
Alexandre Julliard's avatar
Alexandre Julliard committed
1087
{
1088
    INT ret = 0;
1089
    DC *dc = DC_GetDCPtr( hdc );
Alexandre Julliard's avatar
Alexandre Julliard committed
1090 1091 1092 1093 1094 1095

    /* One would think that setting the graphics mode to GM_COMPATIBLE
     * would also reset the world transformation matrix to the unity
     * matrix. However, in Windows, this is not the case. This doesn't
     * make a lot of sense to me, but that's the way it is.
     */
Alexandre Julliard's avatar
Alexandre Julliard committed
1096
    if (!dc) return 0;
1097
    if ((mode > 0) && (mode <= GM_LAST))
1098
    {
1099 1100 1101
        ret = dc->GraphicsMode;
        dc->GraphicsMode = mode;
    }
1102 1103
    GDI_ReleaseObj( hdc );
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
1104 1105 1106
}


1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122
/***********************************************************************
 *		GetArcDirection (GDI32.@)
 */
INT WINAPI GetArcDirection( HDC hdc )
{
    INT ret = 0;
    DC * dc = DC_GetDCPtr( hdc );
    if (dc)
    {
        ret = dc->ArcDirection;
        GDI_ReleaseObj( hdc );
    }
    return ret;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1123
/***********************************************************************
1124
 *           SetArcDirection    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
1125
 */
1126
INT WINAPI SetArcDirection( HDC hdc, INT nDirection )
Alexandre Julliard's avatar
Alexandre Julliard committed
1127
{
1128 1129
    DC * dc;
    INT nOldDirection = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1130 1131 1132 1133 1134 1135 1136

    if (nDirection!=AD_COUNTERCLOCKWISE && nDirection!=AD_CLOCKWISE)
    {
        SetLastError(ERROR_INVALID_PARAMETER);
	return 0;
    }

1137
    if ((dc = DC_GetDCPtr( hdc )))
1138
    {
1139 1140 1141 1142
        if (dc->funcs->pSetArcDirection)
        {
            dc->funcs->pSetArcDirection(dc->physDev, nDirection);
        }
1143 1144
        nOldDirection = dc->ArcDirection;
        dc->ArcDirection = nDirection;
1145 1146
        GDI_ReleaseObj( hdc );
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1147 1148 1149 1150
    return nOldDirection;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1151
/***********************************************************************
1152
 *           GetWorldTransform    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
1153
 */
1154
BOOL WINAPI GetWorldTransform( HDC hdc, LPXFORM xform )
Alexandre Julliard's avatar
Alexandre Julliard committed
1155
{
1156 1157
    DC * dc;
    if (!xform) return FALSE;
1158 1159
    if (!(dc = DC_GetDCPtr( hdc ))) return FALSE;
    *xform = dc->xformWorld2Wnd;
1160
    GDI_ReleaseObj( hdc );
Alexandre Julliard's avatar
Alexandre Julliard committed
1161 1162 1163 1164
    return TRUE;
}


1165 1166 1167 1168 1169 1170
/***********************************************************************
 *           GetTransform    (GDI32.@)
 */
BOOL WINAPI GetTransform( HDC hdc, DWORD unknown, LPXFORM xform )
{
    if (unknown == 0x0203) return GetWorldTransform( hdc, xform );
1171
    FIXME("stub: don't know what to do for code %lx\n", unknown );
1172 1173 1174 1175
    return FALSE;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1176
/***********************************************************************
1177
 *           SetWorldTransform    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
1178
 */
1179
BOOL WINAPI SetWorldTransform( HDC hdc, const XFORM *xform )
Alexandre Julliard's avatar
Alexandre Julliard committed
1180
{
1181
    BOOL ret = FALSE;
1182
    DC *dc = DC_GetDCPtr( hdc );
Alexandre Julliard's avatar
Alexandre Julliard committed
1183

1184
    if (!dc) return FALSE;
1185
    if (!xform) goto done;
1186

Alexandre Julliard's avatar
Alexandre Julliard committed
1187
    /* Check that graphics mode is GM_ADVANCED */
1188
    if (dc->GraphicsMode!=GM_ADVANCED) goto done;
Alexandre Julliard's avatar
Alexandre Julliard committed
1189

1190 1191 1192 1193 1194 1195
    if (dc->funcs->pSetWorldTransform)
    {
        ret = dc->funcs->pSetWorldTransform(dc->physDev, xform);
        if (!ret) goto done;
    }

1196
    dc->xformWorld2Wnd = *xform;
Alexandre Julliard's avatar
Alexandre Julliard committed
1197
    DC_UpdateXforms( dc );
1198 1199 1200 1201
    ret = TRUE;
 done:
    GDI_ReleaseObj( hdc );
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
1202 1203 1204 1205
}


/****************************************************************************
1206
 * ModifyWorldTransform [GDI32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224
 * Modifies the world transformation for a device context.
 *
 * PARAMS
 *    hdc   [I] Handle to device context
 *    xform [I] XFORM structure that will be used to modify the world
 *              transformation
 *    iMode [I] Specifies in what way to modify the world transformation
 *              Possible values:
 *              MWT_IDENTITY
 *                 Resets the world transformation to the identity matrix.
 *                 The parameter xform is ignored.
 *              MWT_LEFTMULTIPLY
 *                 Multiplies xform into the world transformation matrix from
 *                 the left.
 *              MWT_RIGHTMULTIPLY
 *                 Multiplies xform into the world transformation matrix from
 *                 the right.
 *
Jon Griffiths's avatar
Jon Griffiths committed
1225 1226 1227
 * RETURNS
 *  Success: TRUE.
 *  Failure: FALSE. Use GetLastError() to determine the cause.
Alexandre Julliard's avatar
Alexandre Julliard committed
1228
 */
1229
BOOL WINAPI ModifyWorldTransform( HDC hdc, const XFORM *xform,
Alexandre Julliard's avatar
Alexandre Julliard committed
1230 1231
    DWORD iMode )
{
1232
    BOOL ret = FALSE;
1233 1234
    DC *dc = DC_GetDCPtr( hdc );

Alexandre Julliard's avatar
Alexandre Julliard committed
1235
    /* Check for illegal parameters */
1236
    if (!dc) return FALSE;
1237
    if (!xform && iMode != MWT_IDENTITY) goto done;
1238

Alexandre Julliard's avatar
Alexandre Julliard committed
1239
    /* Check that graphics mode is GM_ADVANCED */
1240 1241
    if (dc->GraphicsMode!=GM_ADVANCED) goto done;

1242 1243 1244 1245 1246 1247
    if (dc->funcs->pModifyWorldTransform)
    {
        ret = dc->funcs->pModifyWorldTransform(dc->physDev, xform, iMode);
        if (!ret) goto done;
    }

Alexandre Julliard's avatar
Alexandre Julliard committed
1248 1249 1250
    switch (iMode)
    {
        case MWT_IDENTITY:
1251 1252 1253 1254 1255 1256
	    dc->xformWorld2Wnd.eM11 = 1.0f;
	    dc->xformWorld2Wnd.eM12 = 0.0f;
	    dc->xformWorld2Wnd.eM21 = 0.0f;
	    dc->xformWorld2Wnd.eM22 = 1.0f;
	    dc->xformWorld2Wnd.eDx  = 0.0f;
	    dc->xformWorld2Wnd.eDy  = 0.0f;
Alexandre Julliard's avatar
Alexandre Julliard committed
1257 1258
	    break;
        case MWT_LEFTMULTIPLY:
1259 1260
	    CombineTransform( &dc->xformWorld2Wnd, xform,
	        &dc->xformWorld2Wnd );
Alexandre Julliard's avatar
Alexandre Julliard committed
1261 1262
	    break;
	case MWT_RIGHTMULTIPLY:
1263
	    CombineTransform( &dc->xformWorld2Wnd, &dc->xformWorld2Wnd,
Alexandre Julliard's avatar
Alexandre Julliard committed
1264 1265 1266
	        xform );
	    break;
        default:
1267
            goto done;
Alexandre Julliard's avatar
Alexandre Julliard committed
1268 1269 1270
    }

    DC_UpdateXforms( dc );
1271 1272 1273 1274
    ret = TRUE;
 done:
    GDI_ReleaseObj( hdc );
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
1275 1276 1277 1278
}


/****************************************************************************
1279
 * CombineTransform [GDI32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
1280 1281 1282 1283 1284 1285 1286 1287 1288 1289
 * Combines two transformation matrices.
 *
 * PARAMS
 *    xformResult [O] Stores the result of combining the two matrices
 *    xform1      [I] Specifies the first matrix to apply
 *    xform2      [I] Specifies the second matrix to apply
 *
 * REMARKS
 *    The same matrix can be passed in for more than one of the parameters.
 *
Jon Griffiths's avatar
Jon Griffiths committed
1290 1291 1292
 * RETURNS
 *  Success: TRUE.
 *  Failure: FALSE. Use GetLastError() to determine the cause.
Alexandre Julliard's avatar
Alexandre Julliard committed
1293
 */
1294
BOOL WINAPI CombineTransform( LPXFORM xformResult, const XFORM *xform1,
Alexandre Julliard's avatar
Alexandre Julliard committed
1295 1296 1297
    const XFORM *xform2 )
{
    XFORM xformTemp;
1298

Alexandre Julliard's avatar
Alexandre Julliard committed
1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322
    /* Check for illegal parameters */
    if (!xformResult || !xform1 || !xform2)
        return FALSE;

    /* Create the result in a temporary XFORM, since xformResult may be
     * equal to xform1 or xform2 */
    xformTemp.eM11 = xform1->eM11 * xform2->eM11 +
                     xform1->eM12 * xform2->eM21;
    xformTemp.eM12 = xform1->eM11 * xform2->eM12 +
                     xform1->eM12 * xform2->eM22;
    xformTemp.eM21 = xform1->eM21 * xform2->eM11 +
                     xform1->eM22 * xform2->eM21;
    xformTemp.eM22 = xform1->eM21 * xform2->eM12 +
                     xform1->eM22 * xform2->eM22;
    xformTemp.eDx  = xform1->eDx  * xform2->eM11 +
                     xform1->eDy  * xform2->eM21 +
                     xform2->eDx;
    xformTemp.eDy  = xform1->eDx  * xform2->eM12 +
                     xform1->eDy  * xform2->eM22 +
                     xform2->eDy;

    /* Copy the result to xformResult */
    *xformResult = xformTemp;

Alexandre Julliard's avatar
Alexandre Julliard committed
1323
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1324 1325 1326
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1327
/***********************************************************************
1328 1329 1330
 *           SetDCHook   (GDI32.@)
 *
 * Note: this doesn't exist in Win32, we add it here because user32 needs it.
Alexandre Julliard's avatar
Alexandre Julliard committed
1331
 */
1332 1333
BOOL WINAPI SetDCHook( HDC hdc, DCHOOKPROC hookProc, DWORD dwHookData )
{
1334
    DC *dc = GDI_GetObjPtr( hdc, DC_MAGIC );
1335

1336
    if (!dc) return FALSE;
1337 1338 1339 1340 1341 1342

    if (!(dc->flags & DC_SAVED))
    {
        dc->dwHookData = dwHookData;
        dc->hookThunk = hookProc;
    }
1343 1344 1345
    GDI_ReleaseObj( hdc );
    return TRUE;
}
1346 1347


1348
/* relay function to call the 16-bit DC hook proc */
1349
static BOOL16 WINAPI call_dc_hook16( HDC16 hdc16, WORD code, DWORD data, LPARAM lParam )
Alexandre Julliard's avatar
Alexandre Julliard committed
1350
{
1351 1352
    WORD args[6];
    DWORD ret;
1353
    FARPROC16 proc = NULL;
1354
    HDC hdc = HDC_32( hdc16 );
1355
    DC *dc = DC_GetDCPtr( hdc );
1356

1357
    if (!dc) return FALSE;
1358 1359 1360
    proc = dc->hookProc;
    GDI_ReleaseObj( hdc );
    if (!proc) return FALSE;
1361 1362 1363 1364 1365 1366 1367 1368
    args[5] = hdc16;
    args[4] = code;
    args[3] = HIWORD(data);
    args[2] = LOWORD(data);
    args[1] = HIWORD(lParam);
    args[0] = LOWORD(lParam);
    WOWCallback16Ex( (DWORD)proc, WCB16_PASCAL, sizeof(args), args, &ret );
    return LOWORD(ret);
1369
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1370

1371 1372 1373
/***********************************************************************
 *           SetDCHook   (GDI.190)
 */
1374
BOOL16 WINAPI SetDCHook16( HDC16 hdc16, FARPROC16 hookProc, DWORD dwHookData )
1375
{
1376
    HDC hdc = HDC_32( hdc16 );
1377 1378
    DC *dc = DC_GetDCPtr( hdc );
    if (!dc) return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1379 1380

    dc->hookProc = hookProc;
1381
    GDI_ReleaseObj( hdc );
1382
    return SetDCHook( hdc, call_dc_hook16, dwHookData );
Alexandre Julliard's avatar
Alexandre Julliard committed
1383 1384 1385 1386 1387 1388
}


/***********************************************************************
 *           GetDCHook   (GDI.191)
 */
1389
DWORD WINAPI GetDCHook16( HDC16 hdc16, FARPROC16 *phookProc )
Alexandre Julliard's avatar
Alexandre Julliard committed
1390
{
1391
    HDC hdc = HDC_32( hdc16 );
1392
    DC *dc = DC_GetDCPtr( hdc );
1393 1394
    DWORD ret;

Alexandre Julliard's avatar
Alexandre Julliard committed
1395 1396
    if (!dc) return 0;
    *phookProc = dc->hookProc;
1397
    ret = dc->dwHookData;
1398
    GDI_ReleaseObj( hdc );
1399
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
1400 1401 1402 1403
}


/***********************************************************************
1404
 *           SetHookFlags   (GDI.192)
Alexandre Julliard's avatar
Alexandre Julliard committed
1405
 */
1406
WORD WINAPI SetHookFlags16(HDC16 hdc16, WORD flags)
Alexandre Julliard's avatar
Alexandre Julliard committed
1407
{
1408 1409
    HDC hdc = HDC_32( hdc16 );
    DC *dc = DC_GetDCPtr( hdc );
Alexandre Julliard's avatar
Alexandre Julliard committed
1410

Alexandre Julliard's avatar
Alexandre Julliard committed
1411
    if( dc )
Alexandre Julliard's avatar
Alexandre Julliard committed
1412
    {
1413
        WORD wRet = dc->flags & DC_DIRTY;
Alexandre Julliard's avatar
Alexandre Julliard committed
1414

Alexandre Julliard's avatar
Alexandre Julliard committed
1415
        /* "Undocumented Windows" info is slightly confusing.
Alexandre Julliard's avatar
Alexandre Julliard committed
1416 1417
         */

1418
        TRACE("hDC %p, flags %04x\n",hdc,flags);
Alexandre Julliard's avatar
Alexandre Julliard committed
1419 1420

        if( flags & DCHF_INVALIDATEVISRGN )
1421
            dc->flags |= DC_DIRTY;
Alexandre Julliard's avatar
Alexandre Julliard committed
1422
        else if( flags & DCHF_VALIDATEVISRGN || !flags )
1423
            dc->flags &= ~DC_DIRTY;
1424
        GDI_ReleaseObj( hdc );
Alexandre Julliard's avatar
Alexandre Julliard committed
1425 1426
        return wRet;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1427
    return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1428 1429
}

Alexandre Julliard's avatar
Alexandre Julliard committed
1430
/***********************************************************************
1431
 *           SetICMMode    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
1432
 */
1433
INT WINAPI SetICMMode(HDC hdc, INT iEnableICM)
Alexandre Julliard's avatar
Alexandre Julliard committed
1434 1435 1436 1437 1438 1439 1440 1441
{
/*FIXME  Asuming that ICM is always off, and cannot be turned on */
    if (iEnableICM == ICM_OFF) return ICM_OFF;
    if (iEnableICM == ICM_ON) return 0;
    if (iEnableICM == ICM_QUERY) return ICM_OFF;
    return 0;
}

1442
/***********************************************************************
1443
 *           GetDeviceGammaRamp    (GDI32.@)
1444
 */
1445 1446 1447 1448 1449 1450 1451 1452
BOOL WINAPI GetDeviceGammaRamp(HDC hDC, LPVOID ptr)
{
    BOOL ret = FALSE;
    DC *dc = DC_GetDCPtr( hDC );

    if( dc )
    {
	if (dc->funcs->pGetDeviceGammaRamp)
1453
	    ret = dc->funcs->pGetDeviceGammaRamp(dc->physDev, ptr);
1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469
	GDI_ReleaseObj( hDC );
    }
    return ret;
}

/***********************************************************************
 *           SetDeviceGammaRamp    (GDI32.@)
 */
BOOL WINAPI SetDeviceGammaRamp(HDC hDC, LPVOID ptr)
{
    BOOL ret = FALSE;
    DC *dc = DC_GetDCPtr( hDC );

    if( dc )
    {
	if (dc->funcs->pSetDeviceGammaRamp)
1470
	    ret = dc->funcs->pSetDeviceGammaRamp(dc->physDev, ptr);
1471 1472 1473
	GDI_ReleaseObj( hDC );
    }
    return ret;
1474
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1475 1476

/***********************************************************************
1477
 *           GetColorSpace    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
1478
 */
1479
HCOLORSPACE WINAPI GetColorSpace(HDC hdc)
Alexandre Julliard's avatar
Alexandre Julliard committed
1480 1481 1482 1483
{
/*FIXME    Need to to whatever GetColorSpace actually does */
    return 0;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1484

1485
/***********************************************************************
1486
 *           CreateColorSpaceA    (GDI32.@)
1487 1488 1489 1490
 */
HCOLORSPACE WINAPI CreateColorSpaceA( LPLOGCOLORSPACEA lpLogColorSpace )
{
  FIXME( "stub\n" );
1491
  return 0;
1492 1493 1494
}

/***********************************************************************
1495
 *           CreateColorSpaceW    (GDI32.@)
1496 1497 1498 1499 1500 1501 1502 1503
 */
HCOLORSPACE WINAPI CreateColorSpaceW( LPLOGCOLORSPACEW lpLogColorSpace )
{
  FIXME( "stub\n" );
  return 0;
}

/***********************************************************************
1504
 *           DeleteColorSpace     (GDI32.@)
1505 1506 1507 1508
 */
BOOL WINAPI DeleteColorSpace( HCOLORSPACE hColorSpace )
{
  FIXME( "stub\n" );
1509

1510
  return TRUE;
1511 1512 1513
}

/***********************************************************************
1514
 *           SetColorSpace     (GDI32.@)
1515 1516 1517 1518 1519 1520 1521 1522
 */
HCOLORSPACE WINAPI SetColorSpace( HDC hDC, HCOLORSPACE hColorSpace )
{
  FIXME( "stub\n" );

  return hColorSpace;
}

1523
/***********************************************************************
1524
 *           GetBoundsRect    (GDI32.@)
1525
 */
1526
UINT WINAPI GetBoundsRect(HDC hdc, LPRECT rect, UINT flags)
1527
{
1528 1529
    UINT ret;
    DC *dc = DC_GetDCPtr( hdc );
1530

1531 1532 1533 1534 1535
    if ( !dc ) return 0;

    if (rect) *rect = dc->BoundsRect;

    ret = ((dc->flags & DC_BOUNDS_SET) ? DCB_SET : DCB_RESET);
1536

1537 1538 1539 1540 1541 1542 1543 1544 1545 1546
    if (flags & DCB_RESET)
    {
        dc->BoundsRect.left   = 0;
        dc->BoundsRect.top    = 0;
        dc->BoundsRect.right  = 0;
        dc->BoundsRect.bottom = 0;
        dc->flags &= ~DC_BOUNDS_SET;
    }
    GDI_ReleaseObj( hdc );
    return ret;
1547 1548
}

1549

1550
/***********************************************************************
1551
 *           SetBoundsRect    (GDI32.@)
1552
 */
1553
UINT WINAPI SetBoundsRect(HDC hdc, const RECT* rect, UINT flags)
1554
{
1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593
    UINT ret;
    DC *dc;

    if ((flags & DCB_ENABLE) && (flags & DCB_DISABLE)) return 0;
    if (!(dc = DC_GetDCPtr( hdc ))) return 0;

    ret = ((dc->flags & DC_BOUNDS_ENABLE) ? DCB_ENABLE : DCB_DISABLE) |
          ((dc->flags & DC_BOUNDS_SET) ? DCB_SET : DCB_RESET);

    if (flags & DCB_RESET)
    {
        dc->BoundsRect.left   = 0;
        dc->BoundsRect.top    = 0;
        dc->BoundsRect.right  = 0;
        dc->BoundsRect.bottom = 0;
        dc->flags &= ~DC_BOUNDS_SET;
    }

    if ((flags & DCB_ACCUMULATE) && rect && rect->left < rect->right && rect->top < rect->bottom)
    {
        if (dc->flags & DC_BOUNDS_SET)
        {
            dc->BoundsRect.left   = min( dc->BoundsRect.left, rect->left );
            dc->BoundsRect.top    = min( dc->BoundsRect.top, rect->top );
            dc->BoundsRect.right  = max( dc->BoundsRect.right, rect->right );
            dc->BoundsRect.bottom = max( dc->BoundsRect.bottom, rect->bottom );
        }
        else
        {
            dc->BoundsRect = *rect;
            dc->flags |= DC_BOUNDS_SET;
        }
    }

    if (flags & DCB_ENABLE) dc->flags |= DC_BOUNDS_ENABLE;
    if (flags & DCB_DISABLE) dc->flags &= ~DC_BOUNDS_ENABLE;

    GDI_ReleaseObj( hdc );
    return ret;
1594 1595
}

1596 1597

/***********************************************************************
1598
 *		GetRelAbs		(GDI32.@)
1599 1600 1601
 */
INT WINAPI GetRelAbs( HDC hdc, DWORD dwIgnore )
{
1602 1603 1604 1605 1606
    INT ret = 0;
    DC *dc = DC_GetDCPtr( hdc );
    if (dc) ret = dc->relAbsMode;
    GDI_ReleaseObj( hdc );
    return ret;
1607 1608
}

1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640



/***********************************************************************
 *		GetBkMode (GDI32.@)
 */
INT WINAPI GetBkMode( HDC hdc )
{
    INT ret = 0;
    DC * dc = DC_GetDCPtr( hdc );
    if (dc)
    {
        ret = dc->backgroundMode;
        GDI_ReleaseObj( hdc );
    }
    return ret;
}


/***********************************************************************
 *		SetBkMode (GDI32.@)
 */
INT WINAPI SetBkMode( HDC hdc, INT mode )
{
    INT ret;
    DC *dc;
    if ((mode <= 0) || (mode > BKMODE_LAST))
    {
        SetLastError(ERROR_INVALID_PARAMETER);
        return 0;
    }
    if (!(dc = DC_GetDCPtr( hdc ))) return 0;
1641 1642

    ret = dc->backgroundMode;
1643
    if (dc->funcs->pSetBkMode)
1644 1645 1646
        if (!dc->funcs->pSetBkMode( dc->physDev, mode ))
            ret = 0;
    if (ret)
1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681
        dc->backgroundMode = mode;
    GDI_ReleaseObj( hdc );
    return ret;
}


/***********************************************************************
 *		GetROP2 (GDI32.@)
 */
INT WINAPI GetROP2( HDC hdc )
{
    INT ret = 0;
    DC * dc = DC_GetDCPtr( hdc );
    if (dc)
    {
        ret = dc->ROPmode;
        GDI_ReleaseObj( hdc );
    }
    return ret;
}


/***********************************************************************
 *		SetROP2 (GDI32.@)
 */
INT WINAPI SetROP2( HDC hdc, INT mode )
{
    INT ret;
    DC *dc;
    if ((mode < R2_BLACK) || (mode > R2_WHITE))
    {
        SetLastError(ERROR_INVALID_PARAMETER);
        return 0;
    }
    if (!(dc = DC_GetDCPtr( hdc ))) return 0;
1682
    ret = dc->ROPmode;
1683
    if (dc->funcs->pSetROP2)
1684 1685 1686
        if (!dc->funcs->pSetROP2( dc->physDev, mode ))
            ret = 0;
    if (ret)
1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746
        dc->ROPmode = mode;
    GDI_ReleaseObj( hdc );
    return ret;
}


/***********************************************************************
 *		SetRelAbs (GDI32.@)
 */
INT WINAPI SetRelAbs( HDC hdc, INT mode )
{
    INT ret;
    DC *dc;
    if ((mode != ABSOLUTE) && (mode != RELATIVE))
    {
        SetLastError(ERROR_INVALID_PARAMETER);
        return 0;
    }
    if (!(dc = DC_GetDCPtr( hdc ))) return 0;
    if (dc->funcs->pSetRelAbs)
        ret = dc->funcs->pSetRelAbs( dc->physDev, mode );
    else
    {
        ret = dc->relAbsMode;
        dc->relAbsMode = mode;
    }
    GDI_ReleaseObj( hdc );
    return ret;
}


/***********************************************************************
 *		GetPolyFillMode (GDI32.@)
 */
INT WINAPI GetPolyFillMode( HDC hdc )
{
    INT ret = 0;
    DC * dc = DC_GetDCPtr( hdc );
    if (dc)
    {
        ret = dc->polyFillMode;
        GDI_ReleaseObj( hdc );
    }
    return ret;
}


/***********************************************************************
 *		SetPolyFillMode (GDI32.@)
 */
INT WINAPI SetPolyFillMode( HDC hdc, INT mode )
{
    INT ret;
    DC *dc;
    if ((mode <= 0) || (mode > POLYFILL_LAST))
    {
        SetLastError(ERROR_INVALID_PARAMETER);
        return 0;
    }
    if (!(dc = DC_GetDCPtr( hdc ))) return 0;
1747
    ret = dc->polyFillMode;
1748
    if (dc->funcs->pSetPolyFillMode)
1749 1750 1751
        if (!dc->funcs->pSetPolyFillMode( dc->physDev, mode ))
            ret = 0;
    if (ret)
1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786
        dc->polyFillMode = mode;
    GDI_ReleaseObj( hdc );
    return ret;
}


/***********************************************************************
 *		GetStretchBltMode (GDI32.@)
 */
INT WINAPI GetStretchBltMode( HDC hdc )
{
    INT ret = 0;
    DC * dc = DC_GetDCPtr( hdc );
    if (dc)
    {
        ret = dc->stretchBltMode;
        GDI_ReleaseObj( hdc );
    }
    return ret;
}


/***********************************************************************
 *		SetStretchBltMode (GDI32.@)
 */
INT WINAPI SetStretchBltMode( HDC hdc, INT mode )
{
    INT ret;
    DC *dc;
    if ((mode <= 0) || (mode > MAXSTRETCHBLTMODE))
    {
        SetLastError(ERROR_INVALID_PARAMETER);
        return 0;
    }
    if (!(dc = DC_GetDCPtr( hdc ))) return 0;
1787
    ret = dc->stretchBltMode;
1788
    if (dc->funcs->pSetStretchBltMode)
1789 1790 1791
        if (!dc->funcs->pSetStretchBltMode( dc->physDev, mode ))
            ret = 0;
    if (ret)
1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929
        dc->stretchBltMode = mode;
    GDI_ReleaseObj( hdc );
    return ret;
}


/***********************************************************************
 *		GetMapMode (GDI32.@)
 */
INT WINAPI GetMapMode( HDC hdc )
{
    INT ret = 0;
    DC * dc = DC_GetDCPtr( hdc );
    if (dc)
    {
        ret = dc->MapMode;
        GDI_ReleaseObj( hdc );
    }
    return ret;
}


/***********************************************************************
 *		GetBrushOrgEx (GDI32.@)
 */
BOOL WINAPI GetBrushOrgEx( HDC hdc, LPPOINT pt )
{
    DC * dc = DC_GetDCPtr( hdc );
    if (!dc) return FALSE;
    pt->x = dc->brushOrgX;
    pt->y = dc->brushOrgY;
    GDI_ReleaseObj( hdc );
    return TRUE;
}


/***********************************************************************
 *		GetCurrentPositionEx (GDI32.@)
 */
BOOL WINAPI GetCurrentPositionEx( HDC hdc, LPPOINT pt )
{
    DC * dc = DC_GetDCPtr( hdc );
    if (!dc) return FALSE;
    pt->x = dc->CursPosX;
    pt->y = dc->CursPosY;
    GDI_ReleaseObj( hdc );
    return TRUE;
}


/***********************************************************************
 *		GetViewportExtEx (GDI32.@)
 */
BOOL WINAPI GetViewportExtEx( HDC hdc, LPSIZE size )
{
    DC * dc = DC_GetDCPtr( hdc );
    if (!dc) return FALSE;
    size->cx = dc->vportExtX;
    size->cy = dc->vportExtY;
    GDI_ReleaseObj( hdc );
    return TRUE;
}


/***********************************************************************
 *		GetViewportOrgEx (GDI32.@)
 */
BOOL WINAPI GetViewportOrgEx( HDC hdc, LPPOINT pt )
{
    DC * dc = DC_GetDCPtr( hdc );
    if (!dc) return FALSE;
    pt->x = dc->vportOrgX;
    pt->y = dc->vportOrgY;
    GDI_ReleaseObj( hdc );
    return TRUE;
}


/***********************************************************************
 *		GetWindowExtEx (GDI32.@)
 */
BOOL WINAPI GetWindowExtEx( HDC hdc, LPSIZE size )
{
    DC * dc = DC_GetDCPtr( hdc );
    if (!dc) return FALSE;
    size->cx = dc->wndExtX;
    size->cy = dc->wndExtY;
    GDI_ReleaseObj( hdc );
    return TRUE;
}


/***********************************************************************
 *		GetWindowOrgEx (GDI32.@)
 */
BOOL WINAPI GetWindowOrgEx( HDC hdc, LPPOINT pt )
{
    DC * dc = DC_GetDCPtr( hdc );
    if (!dc) return FALSE;
    pt->x = dc->wndOrgX;
    pt->y = dc->wndOrgY;
    GDI_ReleaseObj( hdc );
    return TRUE;
}


/***********************************************************************
 *		InquireVisRgn   (GDI.131)
 */
HRGN16 WINAPI InquireVisRgn16( HDC16 hdc )
{
    HRGN16 ret = 0;
    DC * dc = DC_GetDCPtr( HDC_32(hdc) );
    if (dc)
    {
        ret = HRGN_16(dc->hVisRgn);
        GDI_ReleaseObj( HDC_32(hdc) );
    }
    return ret;
}


/***********************************************************************
 *		GetClipRgn (GDI.173)
 */
HRGN16 WINAPI GetClipRgn16( HDC16 hdc )
{
    HRGN16 ret = 0;
    DC * dc = DC_GetDCPtr( HDC_32(hdc) );
    if (dc)
    {
        ret = HRGN_16(dc->hClipRgn);
        GDI_ReleaseObj( HDC_32(hdc) );
    }
    return ret;
}


1930
/***********************************************************************
1931
 *           GetLayout    (GDI32.@)
1932 1933 1934 1935 1936 1937
 *
 * Gets left->right or right->left text layout flags of a dc.
 *
 */
DWORD WINAPI GetLayout(HDC hdc)
{
1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949
    DWORD layout = GDI_ERROR;

    DC * dc = DC_GetDCPtr( hdc );
    if (dc)
    {
        layout = dc->layout;
        GDI_ReleaseObj( hdc );
    }

    TRACE("hdc : %p, layout : %08lx\n", hdc, layout);

    return layout;
1950 1951 1952
}

/***********************************************************************
1953
 *           SetLayout    (GDI32.@)
1954 1955 1956 1957 1958 1959
 *
 * Sets left->right or right->left text layout flags of a dc.
 *
 */
DWORD WINAPI SetLayout(HDC hdc, DWORD layout)
{
1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972
    DWORD oldlayout = GDI_ERROR;

    DC * dc = DC_GetDCPtr( hdc );
    if (dc)
    {
        oldlayout = dc->layout;
        dc->layout = layout;
        GDI_ReleaseObj( hdc );
    }

    TRACE("hdc : %p, old layout : %08lx, new layout : %08lx\n", hdc, oldlayout, layout);

    return oldlayout;
1973
}
1974

1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992
/***********************************************************************
 *           GetDCBrushColor    (GDI32.@)
 *
 * Retrieves the current brush color for the specified device
 * context (DC).
 *
 */
COLORREF WINAPI GetDCBrushColor(HDC hdc)
{
    DC *dc;
    COLORREF dcBrushColor = CLR_INVALID;

    TRACE("hdc(%p)\n", hdc);

    dc = DC_GetDCPtr( hdc );
    if (dc)
    {
        dcBrushColor = dc->dcBrushColor;
1993
	GDI_ReleaseObj( hdc );
1994 1995 1996 1997 1998
    }

    return dcBrushColor;
}

1999 2000 2001 2002 2003 2004 2005 2006 2007 2008
/***********************************************************************
 *           SetDCBrushColor    (GDI32.@)
 *
 * Sets the current device context (DC) brush color to the specified
 * color value. If the device cannot represent the specified color
 * value, the color is set to the nearest physical color.
 *
 */
COLORREF WINAPI SetDCBrushColor(HDC hdc, COLORREF crColor)
{
2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038
    DC *dc;
    COLORREF oldClr = CLR_INVALID;

    TRACE("hdc(%p) crColor(%08lx)\n", hdc, crColor);

    dc = DC_GetDCPtr( hdc );
    if (dc)
    {
        if (dc->funcs->pSetDCBrushColor)
            crColor = dc->funcs->pSetDCBrushColor( dc->physDev, crColor );
        else if (dc->hBrush == GetStockObject( DC_BRUSH ))
        {
            /* If DC_BRUSH is selected, update driver pen color */
            HBRUSH hBrush = CreateSolidBrush( crColor );
            dc->funcs->pSelectBrush( dc->physDev, hBrush );
	    DeleteObject( hBrush );
	}

        if (crColor != CLR_INVALID)
        {
            oldClr = dc->dcBrushColor;
            dc->dcBrushColor = crColor;
        }

        GDI_ReleaseObj( hdc );
    }

    return oldClr;
}

2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056
/***********************************************************************
 *           GetDCPenColor    (GDI32.@)
 *
 * Retrieves the current pen color for the specified device
 * context (DC).
 *
 */
COLORREF WINAPI GetDCPenColor(HDC hdc)
{
    DC *dc;
    COLORREF dcPenColor = CLR_INVALID;

    TRACE("hdc(%p)\n", hdc);

    dc = DC_GetDCPtr( hdc );
    if (dc)
    {
        dcPenColor = dc->dcPenColor;
2057
	GDI_ReleaseObj( hdc );
2058 2059 2060 2061 2062
    }

    return dcPenColor;
}

2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101
/***********************************************************************
 *           SetDCPenColor    (GDI32.@)
 *
 * Sets the current device context (DC) pen color to the specified
 * color value. If the device cannot represent the specified color
 * value, the color is set to the nearest physical color.
 *
 */
COLORREF WINAPI SetDCPenColor(HDC hdc, COLORREF crColor)
{
    DC *dc;
    COLORREF oldClr = CLR_INVALID;

    TRACE("hdc(%p) crColor(%08lx)\n", hdc, crColor);

    dc = DC_GetDCPtr( hdc );
    if (dc)
    {
        if (dc->funcs->pSetDCPenColor)
            crColor = dc->funcs->pSetDCPenColor( dc->physDev, crColor );
        else if (dc->hPen == GetStockObject( DC_PEN ))
        {
            /* If DC_PEN is selected, update the driver pen color */
            LOGPEN logpen = { PS_SOLID, { 0, 0 }, crColor };
            HPEN hPen = CreatePenIndirect( &logpen );
            dc->funcs->pSelectPen( dc->physDev, hPen );
	    DeleteObject( hPen );
	}

        if (crColor != CLR_INVALID)
        {
            oldClr = dc->dcPenColor;
            dc->dcPenColor = crColor;
        }

        GDI_ReleaseObj( hdc );
    }

    return oldClr;
2102
}
2103 2104 2105 2106

/***********************************************************************
 *           SetVirtualResolution   (GDI32.@)
 *
2107
 * Undocumented on msdn.  Called when PowerPoint XP saves a file.
2108 2109 2110 2111 2112 2113
 */
DWORD WINAPI SetVirtualResolution(HDC hdc, DWORD dw2, DWORD dw3, DWORD dw4, DWORD dw5)
{
    FIXME("(%p %08lx %08lx %08lx %08lx): stub!\n", hdc, dw2, dw3, dw4, dw5);
    return FALSE;
}
2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161

/*******************************************************************
 *      GetMiterLimit [GDI32.@]
 *
 *
 */
BOOL WINAPI GetMiterLimit(HDC hdc, PFLOAT peLimit)
{
    BOOL bRet = FALSE;
    DC *dc;

    TRACE("(%p,%p)\n", hdc, peLimit);

    dc = DC_GetDCPtr( hdc );
    if (dc)
    {
        if (peLimit)
            *peLimit = dc->miterLimit;

        GDI_ReleaseObj( hdc );
        bRet = TRUE;
    }
    return bRet;
}

/*******************************************************************
 *      SetMiterLimit [GDI32.@]
 *
 *
 */
BOOL WINAPI SetMiterLimit(HDC hdc, FLOAT eNewLimit, PFLOAT peOldLimit)
{
    BOOL bRet = FALSE;
    DC *dc;

    TRACE("(%p,%f,%p)\n", hdc, eNewLimit, peOldLimit);

    dc = DC_GetDCPtr( hdc );
    if (dc)
    {
        if (peOldLimit)
            *peOldLimit = dc->miterLimit;
        dc->miterLimit = eNewLimit;
        GDI_ReleaseObj( hdc );
        bRet = TRUE;
    }
    return bRet;
}
2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195

/*******************************************************************
 *      GdiIsMetaPrintDC [GDI32.@]
 */
BOOL WINAPI GdiIsMetaPrintDC(HDC hdc)
{
    FIXME("%p\n", hdc);
    return FALSE;
}

/*******************************************************************
 *      GdiIsMetaFileDC [GDI32.@]
 */
BOOL WINAPI GdiIsMetaFileDC(HDC hdc)
{
    TRACE("%p\n", hdc);

    switch( GetObjectType( hdc ) )
    {
    case OBJ_METADC:
    case OBJ_ENHMETADC:
        return TRUE;
    }
    return FALSE;
}

/*******************************************************************
 *      GdiIsPlayMetafileDC [GDI32.@]
 */
BOOL WINAPI GdiIsPlayMetafileDC(HDC hdc)
{
    FIXME("%p\n", hdc);
    return FALSE;
}