dc.c 57.2 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
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
Alexandre Julliard's avatar
Alexandre Julliard committed
19 20
 */

21 22
#include "config.h"

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

38
WINE_DEFAULT_DEBUG_CHANNEL(dc);
39

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

42
static BOOL DC_DeleteObject( HGDIOBJ handle );
43 44 45 46 47 48 49 50 51 52

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

53 54 55

static inline DC *get_dc_obj( HDC hdc )
{
56
    DC *dc = GDI_GetObjPtr( hdc, 0 );
57 58
    if (!dc) return NULL;

59 60 61 62
    if ((dc->header.type != OBJ_DC) &&
        (dc->header.type != OBJ_MEMDC) &&
        (dc->header.type != OBJ_METADC) &&
        (dc->header.type != OBJ_ENHMETADC))
63 64 65 66 67 68 69 70 71
    {
        GDI_ReleaseObj( hdc );
        SetLastError( ERROR_INVALID_HANDLE );
        dc = NULL;
    }
    return dc;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
72
/***********************************************************************
73
 *           alloc_dc_ptr
Alexandre Julliard's avatar
Alexandre Julliard committed
74
 */
75
DC *alloc_dc_ptr( const DC_FUNCTIONS *funcs, WORD magic )
Alexandre Julliard's avatar
Alexandre Julliard committed
76 77 78
{
    DC *dc;

79
    if (!(dc = HeapAlloc( GetProcessHeap(), 0, sizeof(*dc) ))) return NULL;
80 81 82

    dc->funcs               = funcs;
    dc->physDev             = NULL;
83 84 85
    dc->thread              = GetCurrentThreadId();
    dc->refcount            = 1;
    dc->dirty               = 0;
86
    dc->saveLevel           = 0;
87
    dc->saved_dc            = 0;
88 89 90 91 92 93 94 95 96 97
    dc->dwHookData          = 0;
    dc->hookProc            = 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;
98
    dc->miterLimit          = 10.0f; /* 10.0 is the default, from MSDN */
99
    dc->flags               = 0;
100
    dc->layout              = 0;
101
    dc->hClipRgn            = 0;
102 103
    dc->hMetaRgn            = 0;
    dc->hMetaClipRgn        = 0;
104
    dc->hVisRgn             = 0;
105 106 107
    dc->hPen                = GDI_inc_ref_count( GetStockObject( BLACK_PEN ));
    dc->hBrush              = GDI_inc_ref_count( GetStockObject( WHITE_BRUSH ));
    dc->hFont               = GDI_inc_ref_count( GetStockObject( SYSTEM_FONT ));
108 109 110
    dc->hBitmap             = 0;
    dc->hDevice             = 0;
    dc->hPalette            = GetStockObject( DEFAULT_PALETTE );
111
    dc->gdiFont             = 0;
112
    dc->font_code_page      = CP_ACP;
113 114 115 116 117 118
    dc->ROPmode             = R2_COPYPEN;
    dc->polyFillMode        = ALTERNATE;
    dc->stretchBltMode      = BLACKONWHITE;
    dc->relAbsMode          = ABSOLUTE;
    dc->backgroundMode      = OPAQUE;
    dc->backgroundColor     = RGB( 255, 255, 255 );
119 120
    dc->dcBrushColor        = RGB( 255, 255, 255 );
    dc->dcPenColor          = RGB( 0, 0, 0 );
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
    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;
143 144 145 146
    dc->BoundsRect.left     = 0;
    dc->BoundsRect.top      = 0;
    dc->BoundsRect.right    = 0;
    dc->BoundsRect.bottom   = 0;
147
    PATH_InitGdiPath(&dc->path);
148 149 150 151 152 153

    if (!(dc->hSelf = alloc_gdi_handle( &dc->header, magic, &dc_funcs )))
    {
        HeapFree( GetProcessHeap(), 0, dc );
        dc = NULL;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
154 155 156 157
    return dc;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
158

159
/***********************************************************************
160
 *           free_dc_ptr
161
 */
162
BOOL free_dc_ptr( DC *dc )
163
{
164
    assert( dc->refcount == 1 );
165
    if (free_gdi_handle( dc->hSelf ) != dc) return FALSE;  /* shouldn't happen */
166 167 168 169 170
    if (dc->hClipRgn) DeleteObject( dc->hClipRgn );
    if (dc->hMetaRgn) DeleteObject( dc->hMetaRgn );
    if (dc->hMetaClipRgn) DeleteObject( dc->hMetaClipRgn );
    if (dc->hVisRgn) DeleteObject( dc->hVisRgn );
    PATH_DestroyGdiPath( &dc->path );
171
    return HeapFree( GetProcessHeap(), 0, dc );
172 173 174
}


175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224
/***********************************************************************
 *           get_dc_ptr
 *
 * Retrieve a DC pointer but release the GDI lock.
 */
DC *get_dc_ptr( HDC hdc )
{
    DC *dc = get_dc_obj( hdc );
    if (!dc) return NULL;

    if (!InterlockedCompareExchange( &dc->refcount, 1, 0 ))
    {
        dc->thread = GetCurrentThreadId();
    }
    else if (dc->thread != GetCurrentThreadId())
    {
        WARN( "dc %p belongs to thread %04x\n", hdc, dc->thread );
        GDI_ReleaseObj( hdc );
        return NULL;
    }
    else InterlockedIncrement( &dc->refcount );

    GDI_ReleaseObj( hdc );
    return dc;
}


/***********************************************************************
 *           release_dc_ptr
 */
void release_dc_ptr( DC *dc )
{
    LONG ref;

    dc->thread = 0;
    ref = InterlockedDecrement( &dc->refcount );
    assert( ref >= 0 );
    if (ref) dc->thread = GetCurrentThreadId();  /* we still own it */
}


/***********************************************************************
 *           update_dc
 *
 * Make sure the DC vis region is up to date.
 * This function may call up to USER so the GDI lock should _not_
 * be held when calling it.
 */
void update_dc( DC *dc )
{
225 226
    if (InterlockedExchange( &dc->dirty, 0 ) && dc->hookProc)
        dc->hookProc( dc->hSelf, DCHC_INVALIDVISRGN, dc->dwHookData, 0 );
227 228 229
}


230 231 232
/***********************************************************************
 *           DC_DeleteObject
 */
233
static BOOL DC_DeleteObject( HGDIOBJ handle )
234 235 236 237 238
{
    return DeleteDC( handle );
}


Alexandre Julliard's avatar
Alexandre Julliard committed
239
/***********************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
240
 *           DC_InitDC
Alexandre Julliard's avatar
Alexandre Julliard committed
241
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
242
 * Setup device-specific DC values for a newly created DC.
Alexandre Julliard's avatar
Alexandre Julliard committed
243
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
244
void DC_InitDC( DC* dc )
Alexandre Julliard's avatar
Alexandre Julliard committed
245
{
246
    if (dc->funcs->pRealizeDefaultPalette) dc->funcs->pRealizeDefaultPalette( dc->physDev );
247 248 249 250 251
    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
252
    CLIPPING_UpdateGCRegion( dc );
253
    SetVirtualResolution( dc->hSelf, 0, 0, 0, 0 );
Alexandre Julliard's avatar
Alexandre Julliard committed
254 255 256
}


Alexandre Julliard's avatar
Alexandre Julliard committed
257 258 259 260 261 262 263
/***********************************************************************
 *           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.
 */
264
static BOOL DC_InvertXform( const XFORM *xformSrc, XFORM *xformDest )
Alexandre Julliard's avatar
Alexandre Julliard committed
265
{
266
    double determinant;
267

Alexandre Julliard's avatar
Alexandre Julliard committed
268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284
    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;
}

285 286 287 288 289 290 291
/* Construct a transformation to do the window-to-viewport conversion */
static void construct_window_to_viewport(DC *dc, XFORM *xform)
{
    double scaleX, scaleY;
    scaleX = (double)dc->vportExtX / (double)dc->wndExtX;
    scaleY = (double)dc->vportExtY / (double)dc->wndExtY;

292
    if (dc->layout & LAYOUT_RTL) scaleX = -scaleX;
293 294 295 296 297 298
    xform->eM11 = scaleX;
    xform->eM12 = 0.0;
    xform->eM21 = 0.0;
    xform->eM22 = scaleY;
    xform->eDx  = (double)dc->vportOrgX - scaleX * (double)dc->wndOrgX;
    xform->eDy  = (double)dc->vportOrgY - scaleY * (double)dc->wndOrgY;
299
    if (dc->layout & LAYOUT_RTL) xform->eDx = dc->vis_rect.right - dc->vis_rect.left - 1 - xform->eDx;
300
}
Alexandre Julliard's avatar
Alexandre Julliard committed
301 302 303 304 305 306 307 308 309 310 311 312 313

/***********************************************************************
 *           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 )
{
314
    XFORM xformWnd2Vport, oldworld2vport;
315

316
    construct_window_to_viewport(dc, &xformWnd2Vport);
Alexandre Julliard's avatar
Alexandre Julliard committed
317

318
    oldworld2vport = dc->xformWorld2Vport;
Alexandre Julliard's avatar
Alexandre Julliard committed
319
    /* Combine with the world transformation */
320
    CombineTransform( &dc->xformWorld2Vport, &dc->xformWorld2Wnd,
Alexandre Julliard's avatar
Alexandre Julliard committed
321 322 323
        &xformWnd2Vport );

    /* Create inverse of world-to-viewport transformation */
324 325
    dc->vport2WorldValid = DC_InvertXform( &dc->xformWorld2Vport,
        &dc->xformVport2World );
326

327
    /* Reselect the font and pen back into the dc so that the size
328
       gets updated. */
329 330
    if (memcmp(&oldworld2vport, &dc->xformWorld2Vport, sizeof(oldworld2vport)) &&
        !GdiIsMetaFileDC(dc->hSelf))
331
    {
332
        SelectObject(dc->hSelf, GetCurrentObject(dc->hSelf, OBJ_FONT));
333 334
        SelectObject(dc->hSelf, GetCurrentObject(dc->hSelf, OBJ_PEN));
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
335 336 337
}


Alexandre Julliard's avatar
Alexandre Julliard committed
338
/***********************************************************************
339
 *           save_dc_state
Alexandre Julliard's avatar
Alexandre Julliard committed
340
 */
341
INT save_dc_state( HDC hdc )
Alexandre Julliard's avatar
Alexandre Julliard committed
342 343
{
    DC * newdc, * dc;
344
    INT ret;
345

346
    if (!(dc = get_dc_ptr( hdc ))) return 0;
347
    if (!(newdc = HeapAlloc( GetProcessHeap(), 0, sizeof(*newdc ))))
Alexandre Julliard's avatar
Alexandre Julliard committed
348
    {
349
      release_dc_ptr( dc );
Alexandre Julliard's avatar
Alexandre Julliard committed
350 351
      return 0;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
352

353
    newdc->flags            = dc->flags | DC_SAVED;
354
    newdc->layout           = dc->layout;
355 356 357 358
    newdc->hPen             = dc->hPen;
    newdc->hBrush           = dc->hBrush;
    newdc->hFont            = dc->hFont;
    newdc->hBitmap          = dc->hBitmap;
359
    newdc->hDevice          = dc->hDevice;
360
    newdc->hPalette         = dc->hPalette;
361 362 363 364 365 366 367
    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;
368 369
    newdc->dcBrushColor     = dc->dcBrushColor;
    newdc->dcPenColor       = dc->dcPenColor;
370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392
    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;
393 394
    newdc->virtual_res      = dc->virtual_res;
    newdc->virtual_size     = dc->virtual_size;
395
    newdc->BoundsRect       = dc->BoundsRect;
396
    newdc->gdiFont          = dc->gdiFont;
Alexandre Julliard's avatar
Alexandre Julliard committed
397

398 399
    newdc->thread    = GetCurrentThreadId();
    newdc->refcount  = 1;
Alexandre Julliard's avatar
Alexandre Julliard committed
400
    newdc->saveLevel = 0;
401
    newdc->saved_dc  = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
402

403
    PATH_InitGdiPath( &newdc->path );
404

405
    newdc->pAbortProc = NULL;
406
    newdc->hookProc   = NULL;
407

408 409 410 411 412 413 414
    if (!(newdc->hSelf = alloc_gdi_handle( &newdc->header, dc->header.type, &dc_funcs )))
    {
        HeapFree( GetProcessHeap(), 0, newdc );
        release_dc_ptr( dc );
        return 0;
    }

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

417 418 419 420
    newdc->hVisRgn      = 0;
    newdc->hClipRgn     = 0;
    newdc->hMetaRgn     = 0;
    newdc->hMetaClipRgn = 0;
421
    if (dc->hClipRgn)
Alexandre Julliard's avatar
Alexandre Julliard committed
422
    {
423 424
        newdc->hClipRgn = CreateRectRgn( 0, 0, 0, 0 );
        CombineRgn( newdc->hClipRgn, dc->hClipRgn, 0, RGN_COPY );
Alexandre Julliard's avatar
Alexandre Julliard committed
425
    }
426 427 428 429 430 431
    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 */
432

433 434 435 436 437 438 439 440 441 442
    if (!PATH_AssignGdiPath( &newdc->path, &dc->path ))
    {
        release_dc_ptr( dc );
        free_dc_ptr( newdc );
	return 0;
    }

    newdc->saved_dc = dc->saved_dc;
    dc->saved_dc = newdc->hSelf;
    ret = ++dc->saveLevel;
443 444
    release_dc_ptr( newdc );
    release_dc_ptr( dc );
445
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
446 447 448 449
}


/***********************************************************************
450
 *           restore_dc_state
Alexandre Julliard's avatar
Alexandre Julliard committed
451
 */
452
BOOL restore_dc_state( HDC hdc, INT level )
Alexandre Julliard's avatar
Alexandre Julliard committed
453
{
454
    HDC hdcs, first_dcs;
Alexandre Julliard's avatar
Alexandre Julliard committed
455
    DC *dc, *dcs;
456 457 458 459 460 461
    INT save_level;

    if (!(dc = get_dc_ptr( hdc ))) return FALSE;

    /* find the state level to restore */

462 463 464 465 466
    if (abs(level) > dc->saveLevel || level == 0)
    {
        release_dc_ptr( dc );
        return FALSE;
    }
467 468 469 470 471 472 473 474 475 476 477 478 479 480
    if (level < 0) level = dc->saveLevel + level + 1;
    first_dcs = dc->saved_dc;
    for (hdcs = first_dcs, save_level = dc->saveLevel; save_level > level; save_level--)
    {
	if (!(dcs = get_dc_ptr( hdcs )))
	{
            release_dc_ptr( dc );
            return FALSE;
	}
        hdcs = dcs->saved_dc;
        release_dc_ptr( dcs );
    }

    /* restore the state */
481

482
    if (!(dcs = get_dc_ptr( hdcs )))
Alexandre Julliard's avatar
Alexandre Julliard committed
483
    {
484
        release_dc_ptr( dc );
485
        return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
486
    }
487
    if (!PATH_AssignGdiPath( &dc->path, &dcs->path ))
Alexandre Julliard's avatar
Alexandre Julliard committed
488
    {
489
        release_dc_ptr( dcs );
490 491
        release_dc_ptr( dc );
        return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
492
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
493

494
    dc->flags            = dcs->flags & ~DC_SAVED;
495
    dc->layout           = dcs->layout;
496 497 498 499 500 501 502 503
    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;
504 505
    dc->dcBrushColor     = dcs->dcBrushColor;
    dc->dcPenColor       = dcs->dcPenColor;
506 507 508 509 510 511 512 513 514 515 516 517 518 519 520
    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;
521
    dc->BoundsRect       = dcs->BoundsRect;
522 523 524 525 526 527 528 529 530

    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;
531 532
    dc->virtual_res      = dcs->virtual_res;
    dc->virtual_size     = dcs->virtual_size;
533 534

    if (dcs->hClipRgn)
535
    {
536 537
        if (!dc->hClipRgn) dc->hClipRgn = CreateRectRgn( 0, 0, 0, 0 );
        CombineRgn( dc->hClipRgn, dcs->hClipRgn, 0, RGN_COPY );
538 539
    }
    else
540
    {
541
        if (dc->hClipRgn) DeleteObject( dc->hClipRgn );
542
        dc->hClipRgn = 0;
543
    }
544 545 546 547 548 549 550 551 552 553
    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;
    }
554
    DC_UpdateXforms( dc );
555
    CLIPPING_UpdateGCRegion( dc );
Alexandre Julliard's avatar
Alexandre Julliard committed
556

557 558 559 560 561 562
    SelectObject( hdc, dcs->hBitmap );
    SelectObject( hdc, dcs->hBrush );
    SelectObject( hdc, dcs->hFont );
    SelectObject( hdc, dcs->hPen );
    SetBkColor( hdc, dcs->backgroundColor);
    SetTextColor( hdc, dcs->textColor);
563
    GDISelectPalette( hdc, dcs->hPalette, FALSE );
564 565 566 567 568

    dc->saved_dc  = dcs->saved_dc;
    dcs->saved_dc = 0;
    dc->saveLevel = save_level - 1;

569
    release_dc_ptr( dcs );
570 571 572 573 574 575 576 577 578 579 580 581

    /* now destroy all the saved DCs */

    while (first_dcs)
    {
	if (!(dcs = get_dc_ptr( first_dcs ))) break;
        hdcs = dcs->saved_dc;
        free_dc_ptr( dcs );
        first_dcs = hdcs;
    }
    release_dc_ptr( dc );
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
582 583 584
}


Alexandre Julliard's avatar
Alexandre Julliard committed
585
/***********************************************************************
586
 *           SaveDC    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
587
 */
588
INT WINAPI SaveDC( HDC hdc )
Alexandre Julliard's avatar
Alexandre Julliard committed
589
{
590
    DC * dc;
591
    INT ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
592

593
    if (!(dc = get_dc_ptr( hdc ))) return 0;
594 595

    if(dc->funcs->pSaveDC)
596
        ret = dc->funcs->pSaveDC( dc->physDev );
597 598
    else
        ret = save_dc_state( hdc );
599

600
    release_dc_ptr( dc );
Alexandre Julliard's avatar
Alexandre Julliard committed
601
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
602 603 604
}


Alexandre Julliard's avatar
Alexandre Julliard committed
605
/***********************************************************************
606
 *           RestoreDC    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
607
 */
608
BOOL WINAPI RestoreDC( HDC hdc, INT level )
Alexandre Julliard's avatar
Alexandre Julliard committed
609
{
610
    DC *dc;
611
    BOOL success;
Alexandre Julliard's avatar
Alexandre Julliard committed
612

613
    TRACE("%p %d\n", hdc, level );
614
    if (!(dc = get_dc_ptr( hdc ))) return FALSE;
615
    update_dc( dc );
616 617 618

    if(dc->funcs->pRestoreDC)
        success = dc->funcs->pRestoreDC( dc->physDev, level );
619 620
    else
        success = restore_dc_state( hdc, level );
621

622
    release_dc_ptr( dc );
Alexandre Julliard's avatar
Alexandre Julliard committed
623
    return success;
Alexandre Julliard's avatar
Alexandre Julliard committed
624 625 626
}


627
/***********************************************************************
628
 *           CreateDCW    (GDI32.@)
629
 */
630 631
HDC WINAPI CreateDCW( LPCWSTR driver, LPCWSTR device, LPCWSTR output,
                      const DEVMODEW *initData )
Alexandre Julliard's avatar
Alexandre Julliard committed
632
{
633
    HDC hdc;
Alexandre Julliard's avatar
Alexandre Julliard committed
634
    DC * dc;
Alexandre Julliard's avatar
Alexandre Julliard committed
635
    const DC_FUNCTIONS *funcs;
636
    WCHAR buf[300];
Alexandre Julliard's avatar
Alexandre Julliard committed
637

638 639
    GDI_CheckNotLock();

640
    if (!device || !DRIVER_GetDriverName( device, buf, 300 ))
641
    {
642 643 644 645 646
        if (!driver)
        {
            ERR( "no device found for %s\n", debugstr_w(device) );
            return 0;
        }
647
        strcpyW(buf, driver);
648
    }
649

650 651
    if (!(funcs = DRIVER_load_driver( buf )))
    {
652
        ERR( "no driver found for %s\n", debugstr_w(buf) );
653 654
        return 0;
    }
655
    if (!(dc = alloc_dc_ptr( funcs, OBJ_DC ))) goto error;
656
    hdc = dc->hSelf;
657

658
    dc->hBitmap = GDI_inc_ref_count( GetStockObject( DEFAULT_BITMAP ));
659
    if (!(dc->hVisRgn = CreateRectRgn( 0, 0, 1, 1 ))) goto error;
Alexandre Julliard's avatar
Alexandre Julliard committed
660

661
    TRACE("(driver=%s, device=%s, output=%s): returning %p\n",
662
          debugstr_w(driver), debugstr_w(device), debugstr_w(output), dc->hSelf );
Alexandre Julliard's avatar
Alexandre Julliard committed
663 664

    if (dc->funcs->pCreateDC &&
665
        !dc->funcs->pCreateDC( hdc, &dc->physDev, buf, device, output, initData ))
Alexandre Julliard's avatar
Alexandre Julliard committed
666
    {
667
        WARN("creation aborted by device\n" );
668
        goto error;
Alexandre Julliard's avatar
Alexandre Julliard committed
669
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
670

671 672 673 674 675
    dc->vis_rect.left   = 0;
    dc->vis_rect.top    = 0;
    dc->vis_rect.right  = GetDeviceCaps( hdc, DESKTOPHORZRES );
    dc->vis_rect.bottom = GetDeviceCaps( hdc, DESKTOPVERTRES );
    SetRectRgn(dc->hVisRgn, dc->vis_rect.left, dc->vis_rect.top, dc->vis_rect.right, dc->vis_rect.bottom);
676

Alexandre Julliard's avatar
Alexandre Julliard committed
677
    DC_InitDC( dc );
678
    release_dc_ptr( dc );
679
    return hdc;
680 681

error:
682
    if (dc) free_dc_ptr( dc );
683
    return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
684 685 686
}


Alexandre Julliard's avatar
Alexandre Julliard committed
687
/***********************************************************************
688
 *           CreateDCA    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
689
 */
690 691
HDC WINAPI CreateDCA( LPCSTR driver, LPCSTR device, LPCSTR output,
                      const DEVMODEA *initData )
692
{
693
    UNICODE_STRING driverW, deviceW, outputW;
694
    DEVMODEW *initDataW;
695 696 697 698 699 700 701 702 703 704 705
    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;

706 707 708 709 710 711 712
    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);
    }
713

714
    ret = CreateDCW( driverW.Buffer, deviceW.Buffer, outputW.Buffer, initDataW );
715 716 717 718

    RtlFreeUnicodeString(&driverW);
    RtlFreeUnicodeString(&deviceW);
    RtlFreeUnicodeString(&outputW);
719
    HeapFree(GetProcessHeap(), 0, initDataW);
720
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
721 722 723
}


Alexandre Julliard's avatar
Alexandre Julliard committed
724
/***********************************************************************
725
 *           CreateICA    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
726
 */
727 728
HDC WINAPI CreateICA( LPCSTR driver, LPCSTR device, LPCSTR output,
                          const DEVMODEA* initData )
Alexandre Julliard's avatar
Alexandre Julliard committed
729 730
{
      /* Nothing special yet for ICs */
731
    return CreateDCA( driver, device, output, initData );
Alexandre Julliard's avatar
Alexandre Julliard committed
732 733 734 735
}


/***********************************************************************
736
 *           CreateICW    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
737
 */
738 739
HDC WINAPI CreateICW( LPCWSTR driver, LPCWSTR device, LPCWSTR output,
                          const DEVMODEW* initData )
Alexandre Julliard's avatar
Alexandre Julliard committed
740 741
{
      /* Nothing special yet for ICs */
742
    return CreateDCW( driver, device, output, initData );
Alexandre Julliard's avatar
Alexandre Julliard committed
743 744 745 746
}


/***********************************************************************
747
 *           CreateCompatibleDC   (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
748
 */
749
HDC WINAPI CreateCompatibleDC( HDC hdc )
Alexandre Julliard's avatar
Alexandre Julliard committed
750
{
Alexandre Julliard's avatar
Alexandre Julliard committed
751
    DC *dc, *origDC;
752
    HDC ret;
753 754
    const DC_FUNCTIONS *funcs = NULL;
    PHYSDEV physDev = NULL;
Alexandre Julliard's avatar
Alexandre Julliard committed
755

756
    GDI_CheckNotLock();
757

758
    if (hdc)
759
    {
760
        if (!(origDC = get_dc_ptr( hdc ))) return 0;
761 762 763 764 765
        if (GetObjectType( hdc ) == OBJ_DC)
        {
            funcs = origDC->funcs;
            physDev = origDC->physDev;
        }
766
        release_dc_ptr( origDC );
767
    }
768

769
    if (!funcs && !(funcs = DRIVER_get_display_driver())) return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
770

771
    if (!(dc = alloc_dc_ptr( funcs, OBJ_MEMDC ))) goto error;
Alexandre Julliard's avatar
Alexandre Julliard committed
772

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

775
    dc->hBitmap = GDI_inc_ref_count( GetStockObject( DEFAULT_BITMAP ));
776 777 778 779
    dc->vis_rect.left   = 0;
    dc->vis_rect.top    = 0;
    dc->vis_rect.right  = 1;
    dc->vis_rect.bottom = 1;
780
    if (!(dc->hVisRgn = CreateRectRgn( 0, 0, 1, 1 ))) goto error;   /* default bitmap is 1x1 */
Alexandre Julliard's avatar
Alexandre Julliard committed
781

782 783 784
    /* 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. */
785
    dc->physDev = physDev;
786
    ret = dc->hSelf;
787

Alexandre Julliard's avatar
Alexandre Julliard committed
788
    if (dc->funcs->pCreateDC &&
789
        !dc->funcs->pCreateDC( dc->hSelf, &dc->physDev, NULL, NULL, NULL, NULL ))
Alexandre Julliard's avatar
Alexandre Julliard committed
790
    {
791
        WARN("creation aborted by device\n");
792
        goto error;
Alexandre Julliard's avatar
Alexandre Julliard committed
793
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
794

Alexandre Julliard's avatar
Alexandre Julliard committed
795
    DC_InitDC( dc );
796
    release_dc_ptr( dc );
797
    return ret;
798 799

error:
800
    if (dc) free_dc_ptr( dc );
801
    return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
802 803 804
}


Alexandre Julliard's avatar
Alexandre Julliard committed
805
/***********************************************************************
806
 *           DeleteDC    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
807
 */
808
BOOL WINAPI DeleteDC( HDC hdc )
Alexandre Julliard's avatar
Alexandre Julliard committed
809
{
810
    DC * dc;
Alexandre Julliard's avatar
Alexandre Julliard committed
811

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

814 815
    GDI_CheckNotLock();

816
    if (!(dc = get_dc_ptr( hdc ))) return FALSE;
817 818 819
    if (dc->refcount != 1)
    {
        FIXME( "not deleting busy DC %p refcount %u\n", dc->hSelf, dc->refcount );
820
        release_dc_ptr( dc );
821 822
        return FALSE;
    }
823

824
    /* Call hook procedure to check whether is it OK to delete this DC */
825
    if (dc->hookProc && !dc->hookProc( hdc, DCHC_DELETEDC, dc->dwHookData, 0 ))
826
    {
827
        release_dc_ptr( dc );
828
        return TRUE;
829 830
    }

Alexandre Julliard's avatar
Alexandre Julliard committed
831 832
    while (dc->saveLevel)
    {
833 834
        DC * dcs;
        HDC hdcs = dc->saved_dc;
835
        if (!(dcs = get_dc_ptr( hdcs ))) break;
836 837
        dc->saved_dc = dcs->saved_dc;
        dc->saveLevel--;
838
        free_dc_ptr( dcs );
Alexandre Julliard's avatar
Alexandre Julliard committed
839
    }
840

841
    if (!(dc->flags & DC_SAVED))
Alexandre Julliard's avatar
Alexandre Julliard committed
842
    {
843 844 845
	SelectObject( hdc, GetStockObject(BLACK_PEN) );
	SelectObject( hdc, GetStockObject(WHITE_BRUSH) );
	SelectObject( hdc, GetStockObject(SYSTEM_FONT) );
846
        SelectObject( hdc, GetStockObject(DEFAULT_BITMAP) );
847
        if (dc->funcs->pDeleteDC) dc->funcs->pDeleteDC(dc->physDev);
848
        dc->physDev = NULL;
Alexandre Julliard's avatar
Alexandre Julliard committed
849
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
850

851
    free_dc_ptr( dc );
852
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
853 854 855
}


Alexandre Julliard's avatar
Alexandre Julliard committed
856
/***********************************************************************
857
 *           ResetDCW    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
858
 */
859
HDC WINAPI ResetDCW( HDC hdc, const DEVMODEW *devmode )
Alexandre Julliard's avatar
Alexandre Julliard committed
860
{
861 862 863
    DC *dc;
    HDC ret = hdc;

864
    if ((dc = get_dc_ptr( hdc )))
865
    {
866 867 868 869 870 871
        if (dc->funcs->pResetDC)
        {
            ret = dc->funcs->pResetDC( dc->physDev, devmode );
            if (ret)  /* reset the visible region */
            {
                dc->dirty = 0;
872 873 874 875 876 877
                dc->vis_rect.left   = 0;
                dc->vis_rect.top    = 0;
                dc->vis_rect.right  = GetDeviceCaps( hdc, DESKTOPHORZRES );
                dc->vis_rect.bottom = GetDeviceCaps( hdc, DESKTOPVERTRES );
                SetRectRgn( dc->hVisRgn, dc->vis_rect.left, dc->vis_rect.top,
                            dc->vis_rect.right, dc->vis_rect.bottom );
878 879 880
                CLIPPING_UpdateGCRegion( dc );
            }
        }
881
        release_dc_ptr( dc );
882 883
    }
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
884 885 886 887
}


/***********************************************************************
888
 *           ResetDCA    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
889
 */
890
HDC WINAPI ResetDCA( HDC hdc, const DEVMODEA *devmode )
Alexandre Julliard's avatar
Alexandre Julliard committed
891
{
892 893 894 895 896 897 898 899
    DEVMODEW *devmodeW;
    HDC ret;

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

    ret = ResetDCW(hdc, devmodeW);

900
    HeapFree(GetProcessHeap(), 0, devmodeW);
901
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
902 903 904
}


Alexandre Julliard's avatar
Alexandre Julliard committed
905
/***********************************************************************
906
 *           GetDeviceCaps    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
907
 */
908
INT WINAPI GetDeviceCaps( HDC hdc, INT cap )
Alexandre Julliard's avatar
Alexandre Julliard committed
909
{
910
    DC *dc;
911
    INT ret = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
912

913
    if ((dc = get_dc_ptr( hdc )))
914
    {
915
        if (dc->funcs->pGetDeviceCaps) ret = dc->funcs->pGetDeviceCaps( dc->physDev, cap );
916 917 918 919 920 921 922 923 924 925 926 927 928
        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;
929 930 931 932 933
        case TEXTCAPS:
            ret = (TC_OP_CHARACTER | TC_OP_STROKE | TC_CP_STROKE |
                   TC_CR_ANY | TC_SF_X_YINDEP | TC_SA_DOUBLE | TC_SA_INTEGER |
                   TC_SA_CONTIN | TC_UA_ABLE | TC_SO_ABLE | TC_RA_ABLE | TC_VA_ABLE);
            break;
934
        }
935
        release_dc_ptr( dc );
936
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
937
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
938 939 940
}


941 942 943 944 945 946
/***********************************************************************
 *		GetBkColor (GDI32.@)
 */
COLORREF WINAPI GetBkColor( HDC hdc )
{
    COLORREF ret = 0;
947
    DC * dc = get_dc_ptr( hdc );
948 949 950
    if (dc)
    {
        ret = dc->backgroundColor;
951
        release_dc_ptr( dc );
952 953 954 955 956
    }
    return ret;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
957
/***********************************************************************
958
 *           SetBkColor    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
959
 */
960
COLORREF WINAPI SetBkColor( HDC hdc, COLORREF color )
Alexandre Julliard's avatar
Alexandre Julliard committed
961 962
{
    COLORREF oldColor;
963
    DC * dc = get_dc_ptr( hdc );
964

965
    TRACE("hdc=%p color=0x%08x\n", hdc, color);
966

967 968
    if (!dc) return CLR_INVALID;
    oldColor = dc->backgroundColor;
Alexandre Julliard's avatar
Alexandre Julliard committed
969
    if (dc->funcs->pSetBkColor)
970 971 972 973 974 975 976
    {
        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
977
    }
978
    dc->backgroundColor = color;
979
    release_dc_ptr( dc );
Alexandre Julliard's avatar
Alexandre Julliard committed
980 981 982 983
    return oldColor;
}


984 985 986 987 988 989
/***********************************************************************
 *		GetTextColor (GDI32.@)
 */
COLORREF WINAPI GetTextColor( HDC hdc )
{
    COLORREF ret = 0;
990
    DC * dc = get_dc_ptr( hdc );
991 992 993
    if (dc)
    {
        ret = dc->textColor;
994
        release_dc_ptr( dc );
995 996 997 998 999
    }
    return ret;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1000
/***********************************************************************
1001
 *           SetTextColor    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
1002
 */
1003
COLORREF WINAPI SetTextColor( HDC hdc, COLORREF color )
Alexandre Julliard's avatar
Alexandre Julliard committed
1004 1005
{
    COLORREF oldColor;
1006
    DC * dc = get_dc_ptr( hdc );
1007

1008
    TRACE(" hdc=%p color=0x%08x\n", hdc, color);
1009

1010 1011
    if (!dc) return CLR_INVALID;
    oldColor = dc->textColor;
Alexandre Julliard's avatar
Alexandre Julliard committed
1012
    if (dc->funcs->pSetTextColor)
1013 1014 1015 1016 1017 1018 1019
    {
        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
1020
    }
1021
    dc->textColor = color;
1022
    release_dc_ptr( dc );
Alexandre Julliard's avatar
Alexandre Julliard committed
1023 1024 1025
    return oldColor;
}

Alexandre Julliard's avatar
Alexandre Julliard committed
1026

1027 1028 1029 1030 1031 1032
/***********************************************************************
 *		GetTextAlign (GDI32.@)
 */
UINT WINAPI GetTextAlign( HDC hdc )
{
    UINT ret = 0;
1033
    DC * dc = get_dc_ptr( hdc );
1034 1035 1036
    if (dc)
    {
        ret = dc->textAlign;
1037
        release_dc_ptr( dc );
1038 1039 1040 1041 1042
    }
    return ret;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1043
/***********************************************************************
1044
 *           SetTextAlign    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
1045
 */
1046
UINT WINAPI SetTextAlign( HDC hdc, UINT align )
Alexandre Julliard's avatar
Alexandre Julliard committed
1047
{
1048
    UINT ret;
1049
    DC *dc = get_dc_ptr( hdc );
1050 1051 1052

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

1053
    if (!dc) return 0x0;
1054
    ret = dc->textAlign;
1055
    if (dc->funcs->pSetTextAlign)
1056 1057 1058
        if (!dc->funcs->pSetTextAlign(dc->physDev, align))
            ret = GDI_ERROR;
    if (ret != GDI_ERROR)
1059
	dc->textAlign = align;
1060
    release_dc_ptr( dc );
1061
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
1062 1063
}

Alexandre Julliard's avatar
Alexandre Julliard committed
1064
/***********************************************************************
1065
 *           GetDCOrgEx  (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
1066
 */
1067
BOOL WINAPI GetDCOrgEx( HDC hDC, LPPOINT lpp )
Alexandre Julliard's avatar
Alexandre Julliard committed
1068
{
Alexandre Julliard's avatar
Alexandre Julliard committed
1069
    DC * dc;
1070

Alexandre Julliard's avatar
Alexandre Julliard committed
1071
    if (!lpp) return FALSE;
1072
    if (!(dc = get_dc_ptr( hDC ))) return FALSE;
1073 1074
    lpp->x = dc->vis_rect.left;
    lpp->y = dc->vis_rect.top;
1075
    release_dc_ptr( dc );
Alexandre Julliard's avatar
Alexandre Julliard committed
1076 1077 1078 1079
    return TRUE;
}


1080 1081 1082 1083 1084 1085
/***********************************************************************
 *		GetGraphicsMode (GDI32.@)
 */
INT WINAPI GetGraphicsMode( HDC hdc )
{
    INT ret = 0;
1086
    DC * dc = get_dc_ptr( hdc );
1087 1088 1089
    if (dc)
    {
        ret = dc->GraphicsMode;
1090
        release_dc_ptr( dc );
1091 1092 1093 1094 1095
    }
    return ret;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1096
/***********************************************************************
1097
 *           SetGraphicsMode    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
1098
 */
1099
INT WINAPI SetGraphicsMode( HDC hdc, INT mode )
Alexandre Julliard's avatar
Alexandre Julliard committed
1100
{
1101
    INT ret = 0;
1102
    DC *dc = get_dc_ptr( hdc );
Alexandre Julliard's avatar
Alexandre Julliard committed
1103 1104 1105 1106 1107 1108

    /* 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
1109
    if (!dc) return 0;
1110
    if ((mode > 0) && (mode <= GM_LAST))
1111
    {
1112 1113 1114
        ret = dc->GraphicsMode;
        dc->GraphicsMode = mode;
    }
1115
    release_dc_ptr( dc );
1116
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
1117 1118 1119
}


1120 1121 1122 1123 1124 1125
/***********************************************************************
 *		GetArcDirection (GDI32.@)
 */
INT WINAPI GetArcDirection( HDC hdc )
{
    INT ret = 0;
1126
    DC * dc = get_dc_ptr( hdc );
1127 1128 1129
    if (dc)
    {
        ret = dc->ArcDirection;
1130
        release_dc_ptr( dc );
1131 1132 1133 1134 1135
    }
    return ret;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1136
/***********************************************************************
1137
 *           SetArcDirection    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
1138
 */
1139
INT WINAPI SetArcDirection( HDC hdc, INT nDirection )
Alexandre Julliard's avatar
Alexandre Julliard committed
1140
{
1141 1142
    DC * dc;
    INT nOldDirection = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1143 1144 1145 1146 1147 1148 1149

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

1150
    if ((dc = get_dc_ptr( hdc )))
1151
    {
1152 1153 1154 1155
        if (dc->funcs->pSetArcDirection)
        {
            dc->funcs->pSetArcDirection(dc->physDev, nDirection);
        }
1156 1157
        nOldDirection = dc->ArcDirection;
        dc->ArcDirection = nDirection;
1158
        release_dc_ptr( dc );
1159
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1160 1161 1162 1163
    return nOldDirection;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1164
/***********************************************************************
1165
 *           GetWorldTransform    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
1166
 */
1167
BOOL WINAPI GetWorldTransform( HDC hdc, LPXFORM xform )
Alexandre Julliard's avatar
Alexandre Julliard committed
1168
{
1169 1170
    DC * dc;
    if (!xform) return FALSE;
1171
    if (!(dc = get_dc_ptr( hdc ))) return FALSE;
1172
    *xform = dc->xformWorld2Wnd;
1173
    release_dc_ptr( dc );
Alexandre Julliard's avatar
Alexandre Julliard committed
1174 1175 1176 1177
    return TRUE;
}


1178 1179
/***********************************************************************
 *           GetTransform    (GDI32.@)
1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193
 *
 * Undocumented
 *
 * Returns one of the co-ordinate space transforms
 *
 * PARAMS
 *    hdc   [I] Device context.
 *    which [I] Which xform to return:
 *                  0x203 World -> Page transform (that set by SetWorldTransform).
 *                  0x304 Page -> Device transform (the mapping mode transform).
 *                  0x204 World -> Device transform (the combination of the above two).
 *                  0x402 Device -> World transform (the inversion of the above).
 *    xform [O] The xform.
 *
1194
 */
1195
BOOL WINAPI GetTransform( HDC hdc, DWORD which, XFORM *xform )
1196
{
1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225
    BOOL ret = TRUE;
    DC *dc = get_dc_ptr( hdc );
    if (!dc) return FALSE;

    switch(which)
    {
    case 0x203:
        *xform = dc->xformWorld2Wnd;
        break;

    case 0x304:
        construct_window_to_viewport(dc, xform);
        break;

    case 0x204:
        *xform = dc->xformWorld2Vport;
        break;

    case 0x402:
        *xform = dc->xformVport2World;
        break;

    default:
        FIXME("Unknown code %x\n", which);
        ret = FALSE;
    }

    release_dc_ptr( dc );
    return ret;
1226 1227 1228
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1229
/***********************************************************************
1230
 *           SetWorldTransform    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
1231
 */
1232
BOOL WINAPI SetWorldTransform( HDC hdc, const XFORM *xform )
Alexandre Julliard's avatar
Alexandre Julliard committed
1233
{
1234
    BOOL ret = FALSE;
1235 1236 1237
    DC *dc;

    if (!xform) return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1238

1239
    dc = get_dc_ptr( hdc );
1240 1241
    if (!dc) return FALSE;

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

1245 1246 1247
    TRACE("eM11 %f eM12 %f eM21 %f eM22 %f eDx %f eDy %f\n",
        xform->eM11, xform->eM12, xform->eM21, xform->eM22, xform->eDx, xform->eDy);

1248 1249 1250
    /* The transform must conform to (eM11 * eM22 != eM12 * eM21) requirement */
    if (xform->eM11 * xform->eM22 == xform->eM12 * xform->eM21) goto done;

1251 1252 1253 1254 1255 1256
    if (dc->funcs->pSetWorldTransform)
    {
        ret = dc->funcs->pSetWorldTransform(dc->physDev, xform);
        if (!ret) goto done;
    }

1257
    dc->xformWorld2Wnd = *xform;
Alexandre Julliard's avatar
Alexandre Julliard committed
1258
    DC_UpdateXforms( dc );
1259 1260
    ret = TRUE;
 done:
1261
    release_dc_ptr( dc );
1262
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
1263 1264 1265 1266
}


/****************************************************************************
1267
 * ModifyWorldTransform [GDI32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285
 * 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
1286 1287 1288
 * RETURNS
 *  Success: TRUE.
 *  Failure: FALSE. Use GetLastError() to determine the cause.
Alexandre Julliard's avatar
Alexandre Julliard committed
1289
 */
1290
BOOL WINAPI ModifyWorldTransform( HDC hdc, const XFORM *xform,
Alexandre Julliard's avatar
Alexandre Julliard committed
1291 1292
    DWORD iMode )
{
1293
    BOOL ret = FALSE;
1294
    DC *dc = get_dc_ptr( hdc );
1295

Alexandre Julliard's avatar
Alexandre Julliard committed
1296
    /* Check for illegal parameters */
1297
    if (!dc) return FALSE;
1298
    if (!xform && iMode != MWT_IDENTITY) goto done;
1299

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

1303 1304 1305 1306 1307 1308
    if (dc->funcs->pModifyWorldTransform)
    {
        ret = dc->funcs->pModifyWorldTransform(dc->physDev, xform, iMode);
        if (!ret) goto done;
    }

Alexandre Julliard's avatar
Alexandre Julliard committed
1309 1310 1311
    switch (iMode)
    {
        case MWT_IDENTITY:
1312 1313 1314 1315 1316 1317
	    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
1318 1319
	    break;
        case MWT_LEFTMULTIPLY:
1320 1321
	    CombineTransform( &dc->xformWorld2Wnd, xform,
	        &dc->xformWorld2Wnd );
Alexandre Julliard's avatar
Alexandre Julliard committed
1322 1323
	    break;
	case MWT_RIGHTMULTIPLY:
1324
	    CombineTransform( &dc->xformWorld2Wnd, &dc->xformWorld2Wnd,
Alexandre Julliard's avatar
Alexandre Julliard committed
1325 1326 1327
	        xform );
	    break;
        default:
1328
            goto done;
Alexandre Julliard's avatar
Alexandre Julliard committed
1329 1330 1331
    }

    DC_UpdateXforms( dc );
1332 1333
    ret = TRUE;
 done:
1334
    release_dc_ptr( dc );
1335
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
1336 1337 1338 1339
}


/****************************************************************************
1340
 * CombineTransform [GDI32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
1341 1342 1343 1344 1345 1346 1347 1348 1349 1350
 * 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
1351 1352 1353
 * RETURNS
 *  Success: TRUE.
 *  Failure: FALSE. Use GetLastError() to determine the cause.
Alexandre Julliard's avatar
Alexandre Julliard committed
1354
 */
1355
BOOL WINAPI CombineTransform( LPXFORM xformResult, const XFORM *xform1,
Alexandre Julliard's avatar
Alexandre Julliard committed
1356 1357 1358
    const XFORM *xform2 )
{
    XFORM xformTemp;
1359

Alexandre Julliard's avatar
Alexandre Julliard committed
1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383
    /* 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
1384
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1385 1386 1387
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1388
/***********************************************************************
1389 1390 1391
 *           SetDCHook   (GDI32.@)
 *
 * Note: this doesn't exist in Win32, we add it here because user32 needs it.
Alexandre Julliard's avatar
Alexandre Julliard committed
1392
 */
1393
BOOL WINAPI SetDCHook( HDC hdc, DCHOOKPROC hookProc, DWORD_PTR dwHookData )
1394
{
1395
    DC *dc = get_dc_ptr( hdc );
1396

1397
    if (!dc) return FALSE;
1398 1399 1400 1401

    if (!(dc->flags & DC_SAVED))
    {
        dc->dwHookData = dwHookData;
1402
        dc->hookProc = hookProc;
1403
    }
1404
    release_dc_ptr( dc );
1405 1406
    return TRUE;
}
1407 1408


1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419
/***********************************************************************
 *           GetDCHook   (GDI32.@)
 *
 * Note: this doesn't exist in Win32, we add it here because user32 needs it.
 */
DWORD_PTR WINAPI GetDCHook( HDC hdc, DCHOOKPROC *proc )
{
    DC *dc = get_dc_ptr( hdc );
    DWORD_PTR ret;

    if (!dc) return 0;
1420
    if (proc) *proc = dc->hookProc;
1421
    ret = dc->dwHookData;
1422
    release_dc_ptr( dc );
1423
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
1424 1425 1426 1427
}


/***********************************************************************
1428 1429 1430
 *           SetHookFlags   (GDI32.@)
 *
 * Note: this doesn't exist in Win32, we add it here because user32 needs it.
Alexandre Julliard's avatar
Alexandre Julliard committed
1431
 */
1432
WORD WINAPI SetHookFlags( HDC hdc, WORD flags )
Alexandre Julliard's avatar
Alexandre Julliard committed
1433
{
1434 1435
    DC *dc = get_dc_obj( hdc );  /* not get_dc_ptr, this needs to work from any thread */
    LONG ret = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1436

1437
    if (!dc) return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1438

1439
    /* "Undocumented Windows" info is slightly confusing. */
Alexandre Julliard's avatar
Alexandre Julliard committed
1440

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

1443 1444 1445 1446 1447 1448 1449
    if (flags & DCHF_INVALIDATEVISRGN)
        ret = InterlockedExchange( &dc->dirty, 1 );
    else if (flags & DCHF_VALIDATEVISRGN || !flags)
        ret = InterlockedExchange( &dc->dirty, 0 );

    GDI_ReleaseObj( dc );
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
1450 1451
}

Alexandre Julliard's avatar
Alexandre Julliard committed
1452
/***********************************************************************
1453
 *           SetICMMode    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
1454
 */
1455
INT WINAPI SetICMMode(HDC hdc, INT iEnableICM)
Alexandre Julliard's avatar
Alexandre Julliard committed
1456
{
Austin English's avatar
Austin English committed
1457
/*FIXME:  Assume that ICM is always off, and cannot be turned on */
Alexandre Julliard's avatar
Alexandre Julliard committed
1458 1459 1460 1461 1462 1463
    if (iEnableICM == ICM_OFF) return ICM_OFF;
    if (iEnableICM == ICM_ON) return 0;
    if (iEnableICM == ICM_QUERY) return ICM_OFF;
    return 0;
}

1464
/***********************************************************************
1465
 *           GetDeviceGammaRamp    (GDI32.@)
1466
 */
1467 1468 1469
BOOL WINAPI GetDeviceGammaRamp(HDC hDC, LPVOID ptr)
{
    BOOL ret = FALSE;
1470
    DC *dc = get_dc_ptr( hDC );
1471 1472 1473 1474

    if( dc )
    {
	if (dc->funcs->pGetDeviceGammaRamp)
1475
	    ret = dc->funcs->pGetDeviceGammaRamp(dc->physDev, ptr);
1476
	release_dc_ptr( dc );
1477 1478 1479 1480 1481 1482 1483 1484 1485 1486
    }
    return ret;
}

/***********************************************************************
 *           SetDeviceGammaRamp    (GDI32.@)
 */
BOOL WINAPI SetDeviceGammaRamp(HDC hDC, LPVOID ptr)
{
    BOOL ret = FALSE;
1487
    DC *dc = get_dc_ptr( hDC );
1488 1489 1490 1491

    if( dc )
    {
	if (dc->funcs->pSetDeviceGammaRamp)
1492
	    ret = dc->funcs->pSetDeviceGammaRamp(dc->physDev, ptr);
1493
	release_dc_ptr( dc );
1494 1495
    }
    return ret;
1496
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1497 1498

/***********************************************************************
1499
 *           GetColorSpace    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
1500
 */
1501
HCOLORSPACE WINAPI GetColorSpace(HDC hdc)
Alexandre Julliard's avatar
Alexandre Julliard committed
1502 1503 1504 1505
{
/*FIXME    Need to to whatever GetColorSpace actually does */
    return 0;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1506

1507
/***********************************************************************
1508
 *           CreateColorSpaceA    (GDI32.@)
1509 1510 1511 1512
 */
HCOLORSPACE WINAPI CreateColorSpaceA( LPLOGCOLORSPACEA lpLogColorSpace )
{
  FIXME( "stub\n" );
1513
  return 0;
1514 1515 1516
}

/***********************************************************************
1517
 *           CreateColorSpaceW    (GDI32.@)
1518 1519 1520 1521 1522 1523 1524 1525
 */
HCOLORSPACE WINAPI CreateColorSpaceW( LPLOGCOLORSPACEW lpLogColorSpace )
{
  FIXME( "stub\n" );
  return 0;
}

/***********************************************************************
1526
 *           DeleteColorSpace     (GDI32.@)
1527 1528 1529 1530
 */
BOOL WINAPI DeleteColorSpace( HCOLORSPACE hColorSpace )
{
  FIXME( "stub\n" );
1531

1532
  return TRUE;
1533 1534 1535
}

/***********************************************************************
1536
 *           SetColorSpace     (GDI32.@)
1537 1538 1539 1540 1541 1542 1543 1544
 */
HCOLORSPACE WINAPI SetColorSpace( HDC hDC, HCOLORSPACE hColorSpace )
{
  FIXME( "stub\n" );

  return hColorSpace;
}

1545
/***********************************************************************
1546
 *           GetBoundsRect    (GDI32.@)
1547
 */
1548
UINT WINAPI GetBoundsRect(HDC hdc, LPRECT rect, UINT flags)
1549
{
1550
    UINT ret;
1551
    DC *dc = get_dc_ptr( hdc );
1552

1553 1554
    if ( !dc ) return 0;

1555 1556 1557 1558 1559 1560 1561
    if (rect)
    {
        *rect = dc->BoundsRect;
        ret = ((dc->flags & DC_BOUNDS_SET) ? DCB_SET : DCB_RESET);
    }
    else
        ret = 0;
1562

1563 1564 1565 1566 1567 1568 1569 1570
    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;
    }
1571
    release_dc_ptr( dc );
1572
    return ret;
1573 1574
}

1575

1576
/***********************************************************************
1577
 *           SetBoundsRect    (GDI32.@)
1578
 */
1579
UINT WINAPI SetBoundsRect(HDC hdc, const RECT* rect, UINT flags)
1580
{
1581 1582 1583 1584
    UINT ret;
    DC *dc;

    if ((flags & DCB_ENABLE) && (flags & DCB_DISABLE)) return 0;
1585
    if (!(dc = get_dc_ptr( hdc ))) return 0;
1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617

    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;

1618
    release_dc_ptr( dc );
1619
    return ret;
1620 1621
}

1622 1623

/***********************************************************************
1624
 *		GetRelAbs		(GDI32.@)
1625 1626 1627
 */
INT WINAPI GetRelAbs( HDC hdc, DWORD dwIgnore )
{
1628
    INT ret = 0;
1629
    DC *dc = get_dc_ptr( hdc );
1630 1631 1632
    if (dc)
    {
        ret = dc->relAbsMode;
1633
        release_dc_ptr( dc );
1634
    }
1635
    return ret;
1636 1637
}

1638 1639 1640 1641 1642 1643 1644 1645 1646



/***********************************************************************
 *		GetBkMode (GDI32.@)
 */
INT WINAPI GetBkMode( HDC hdc )
{
    INT ret = 0;
1647
    DC * dc = get_dc_ptr( hdc );
1648 1649 1650
    if (dc)
    {
        ret = dc->backgroundMode;
1651
        release_dc_ptr( dc );
1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668
    }
    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;
    }
1669
    if (!(dc = get_dc_ptr( hdc ))) return 0;
1670 1671

    ret = dc->backgroundMode;
1672
    if (dc->funcs->pSetBkMode)
1673 1674 1675
        if (!dc->funcs->pSetBkMode( dc->physDev, mode ))
            ret = 0;
    if (ret)
1676
        dc->backgroundMode = mode;
1677
    release_dc_ptr( dc );
1678 1679 1680 1681 1682 1683 1684 1685 1686 1687
    return ret;
}


/***********************************************************************
 *		GetROP2 (GDI32.@)
 */
INT WINAPI GetROP2( HDC hdc )
{
    INT ret = 0;
1688
    DC * dc = get_dc_ptr( hdc );
1689 1690 1691
    if (dc)
    {
        ret = dc->ROPmode;
1692
        release_dc_ptr( dc );
1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709
    }
    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;
    }
1710
    if (!(dc = get_dc_ptr( hdc ))) return 0;
1711
    ret = dc->ROPmode;
1712
    if (dc->funcs->pSetROP2)
1713 1714 1715
        if (!dc->funcs->pSetROP2( dc->physDev, mode ))
            ret = 0;
    if (ret)
1716
        dc->ROPmode = mode;
1717
    release_dc_ptr( dc );
1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733
    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;
    }
1734
    if (!(dc = get_dc_ptr( hdc ))) return 0;
1735 1736 1737 1738 1739 1740 1741
    if (dc->funcs->pSetRelAbs)
        ret = dc->funcs->pSetRelAbs( dc->physDev, mode );
    else
    {
        ret = dc->relAbsMode;
        dc->relAbsMode = mode;
    }
1742
    release_dc_ptr( dc );
1743 1744 1745 1746 1747 1748 1749 1750 1751 1752
    return ret;
}


/***********************************************************************
 *		GetPolyFillMode (GDI32.@)
 */
INT WINAPI GetPolyFillMode( HDC hdc )
{
    INT ret = 0;
1753
    DC * dc = get_dc_ptr( hdc );
1754 1755 1756
    if (dc)
    {
        ret = dc->polyFillMode;
1757
        release_dc_ptr( dc );
1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774
    }
    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;
    }
1775
    if (!(dc = get_dc_ptr( hdc ))) return 0;
1776
    ret = dc->polyFillMode;
1777
    if (dc->funcs->pSetPolyFillMode)
1778 1779 1780
        if (!dc->funcs->pSetPolyFillMode( dc->physDev, mode ))
            ret = 0;
    if (ret)
1781
        dc->polyFillMode = mode;
1782
    release_dc_ptr( dc );
1783 1784 1785 1786 1787 1788 1789 1790 1791 1792
    return ret;
}


/***********************************************************************
 *		GetStretchBltMode (GDI32.@)
 */
INT WINAPI GetStretchBltMode( HDC hdc )
{
    INT ret = 0;
1793
    DC * dc = get_dc_ptr( hdc );
1794 1795 1796
    if (dc)
    {
        ret = dc->stretchBltMode;
1797
        release_dc_ptr( dc );
1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814
    }
    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;
    }
1815
    if (!(dc = get_dc_ptr( hdc ))) return 0;
1816
    ret = dc->stretchBltMode;
1817
    if (dc->funcs->pSetStretchBltMode)
1818 1819 1820
        if (!dc->funcs->pSetStretchBltMode( dc->physDev, mode ))
            ret = 0;
    if (ret)
1821
        dc->stretchBltMode = mode;
1822
    release_dc_ptr( dc );
1823 1824 1825 1826 1827 1828 1829 1830 1831 1832
    return ret;
}


/***********************************************************************
 *		GetMapMode (GDI32.@)
 */
INT WINAPI GetMapMode( HDC hdc )
{
    INT ret = 0;
1833
    DC * dc = get_dc_ptr( hdc );
1834 1835 1836
    if (dc)
    {
        ret = dc->MapMode;
1837
        release_dc_ptr( dc );
1838 1839 1840 1841 1842 1843 1844 1845 1846 1847
    }
    return ret;
}


/***********************************************************************
 *		GetBrushOrgEx (GDI32.@)
 */
BOOL WINAPI GetBrushOrgEx( HDC hdc, LPPOINT pt )
{
1848
    DC * dc = get_dc_ptr( hdc );
1849 1850 1851
    if (!dc) return FALSE;
    pt->x = dc->brushOrgX;
    pt->y = dc->brushOrgY;
1852
    release_dc_ptr( dc );
1853 1854 1855 1856 1857 1858 1859 1860 1861
    return TRUE;
}


/***********************************************************************
 *		GetCurrentPositionEx (GDI32.@)
 */
BOOL WINAPI GetCurrentPositionEx( HDC hdc, LPPOINT pt )
{
1862
    DC * dc = get_dc_ptr( hdc );
1863 1864 1865
    if (!dc) return FALSE;
    pt->x = dc->CursPosX;
    pt->y = dc->CursPosY;
1866
    release_dc_ptr( dc );
1867 1868 1869 1870 1871 1872 1873 1874 1875
    return TRUE;
}


/***********************************************************************
 *		GetViewportExtEx (GDI32.@)
 */
BOOL WINAPI GetViewportExtEx( HDC hdc, LPSIZE size )
{
1876
    DC * dc = get_dc_ptr( hdc );
1877 1878 1879
    if (!dc) return FALSE;
    size->cx = dc->vportExtX;
    size->cy = dc->vportExtY;
1880
    release_dc_ptr( dc );
1881 1882 1883 1884 1885 1886 1887 1888 1889
    return TRUE;
}


/***********************************************************************
 *		GetViewportOrgEx (GDI32.@)
 */
BOOL WINAPI GetViewportOrgEx( HDC hdc, LPPOINT pt )
{
1890
    DC * dc = get_dc_ptr( hdc );
1891 1892 1893
    if (!dc) return FALSE;
    pt->x = dc->vportOrgX;
    pt->y = dc->vportOrgY;
1894
    release_dc_ptr( dc );
1895 1896 1897 1898 1899 1900 1901 1902 1903
    return TRUE;
}


/***********************************************************************
 *		GetWindowExtEx (GDI32.@)
 */
BOOL WINAPI GetWindowExtEx( HDC hdc, LPSIZE size )
{
1904
    DC * dc = get_dc_ptr( hdc );
1905 1906 1907
    if (!dc) return FALSE;
    size->cx = dc->wndExtX;
    size->cy = dc->wndExtY;
1908
    release_dc_ptr( dc );
1909 1910 1911 1912 1913 1914 1915 1916 1917
    return TRUE;
}


/***********************************************************************
 *		GetWindowOrgEx (GDI32.@)
 */
BOOL WINAPI GetWindowOrgEx( HDC hdc, LPPOINT pt )
{
1918
    DC * dc = get_dc_ptr( hdc );
1919 1920 1921
    if (!dc) return FALSE;
    pt->x = dc->wndOrgX;
    pt->y = dc->wndOrgY;
1922
    release_dc_ptr( dc );
1923 1924 1925 1926
    return TRUE;
}


1927
/***********************************************************************
1928
 *           GetLayout    (GDI32.@)
1929 1930 1931 1932 1933 1934
 *
 * Gets left->right or right->left text layout flags of a dc.
 *
 */
DWORD WINAPI GetLayout(HDC hdc)
{
1935 1936
    DWORD layout = GDI_ERROR;

1937
    DC * dc = get_dc_ptr( hdc );
1938 1939 1940
    if (dc)
    {
        layout = dc->layout;
1941
        release_dc_ptr( dc );
1942 1943
    }

1944
    TRACE("hdc : %p, layout : %08x\n", hdc, layout);
1945 1946

    return layout;
1947 1948 1949
}

/***********************************************************************
1950
 *           SetLayout    (GDI32.@)
1951 1952 1953 1954 1955 1956
 *
 * Sets left->right or right->left text layout flags of a dc.
 *
 */
DWORD WINAPI SetLayout(HDC hdc, DWORD layout)
{
1957 1958
    DWORD oldlayout = GDI_ERROR;

1959
    DC * dc = get_dc_ptr( hdc );
1960 1961 1962 1963
    if (dc)
    {
        oldlayout = dc->layout;
        dc->layout = layout;
1964 1965 1966 1967 1968
        if (layout != oldlayout)
        {
            if (layout & LAYOUT_RTL) dc->MapMode = MM_ANISOTROPIC;
            DC_UpdateXforms( dc );
        }
1969
        release_dc_ptr( dc );
1970 1971
    }

1972
    TRACE("hdc : %p, old layout : %08x, new layout : %08x\n", hdc, oldlayout, layout);
1973 1974

    return oldlayout;
1975
}
1976

1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990
/***********************************************************************
 *           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);

1991
    dc = get_dc_ptr( hdc );
1992 1993 1994
    if (dc)
    {
        dcBrushColor = dc->dcBrushColor;
1995
	release_dc_ptr( dc );
1996 1997 1998 1999 2000
    }

    return dcBrushColor;
}

2001 2002 2003 2004 2005 2006 2007 2008 2009 2010
/***********************************************************************
 *           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)
{
2011 2012 2013
    DC *dc;
    COLORREF oldClr = CLR_INVALID;

2014
    TRACE("hdc(%p) crColor(%08x)\n", hdc, crColor);
2015

2016
    dc = get_dc_ptr( hdc );
2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034
    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;
        }

2035
        release_dc_ptr( dc );
2036 2037 2038 2039 2040
    }

    return oldClr;
}

2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054
/***********************************************************************
 *           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);

2055
    dc = get_dc_ptr( hdc );
2056 2057 2058
    if (dc)
    {
        dcPenColor = dc->dcPenColor;
2059
	release_dc_ptr( dc );
2060 2061 2062 2063 2064
    }

    return dcPenColor;
}

2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077
/***********************************************************************
 *           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;

2078
    TRACE("hdc(%p) crColor(%08x)\n", hdc, crColor);
2079

2080
    dc = get_dc_ptr( hdc );
2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099
    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;
        }

2100
        release_dc_ptr( dc );
2101 2102 2103
    }

    return oldClr;
2104
}
2105

2106 2107 2108 2109 2110 2111 2112 2113 2114
/***********************************************************************
 *           CancelDC    (GDI32.@)
 */
BOOL WINAPI CancelDC(HDC hdc)
{
    FIXME("stub\n");
    return TRUE;
}

2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126
/*******************************************************************
 *      GetMiterLimit [GDI32.@]
 *
 *
 */
BOOL WINAPI GetMiterLimit(HDC hdc, PFLOAT peLimit)
{
    BOOL bRet = FALSE;
    DC *dc;

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

2127
    dc = get_dc_ptr( hdc );
2128 2129 2130 2131 2132
    if (dc)
    {
        if (peLimit)
            *peLimit = dc->miterLimit;

2133
        release_dc_ptr( dc );
2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150
        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);

2151
    dc = get_dc_ptr( hdc );
2152 2153 2154 2155 2156
    if (dc)
    {
        if (peOldLimit)
            *peOldLimit = dc->miterLimit;
        dc->miterLimit = eNewLimit;
2157
        release_dc_ptr( dc );
2158 2159 2160 2161
        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;
}