dc.c 40.1 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"

Alexandre Julliard's avatar
Alexandre Julliard committed
23
#include <stdlib.h>
Alexandre Julliard's avatar
Alexandre Julliard committed
24
#include <string.h>
25 26
#include "windef.h"
#include "wingdi.h"
27 28
#include "winerror.h"
#include "wownt32.h"
29
#include "wine/winuser16.h"
30 31 32
#include "gdi.h"
#include "heap.h"
#include "wine/debug.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
33

34
WINE_DEFAULT_DEBUG_CHANNEL(dc);
35

36 37 38 39 40 41 42 43 44 45 46 47
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
48 49 50 51 52
/***********************************************************************
 *           DC_AllocDC
 */
DC *DC_AllocDC( const DC_FUNCTIONS *funcs )
{
53
    HDC hdc;
Alexandre Julliard's avatar
Alexandre Julliard committed
54 55
    DC *dc;

56
    if (!(dc = GDI_AllocObject( sizeof(*dc), DC_MAGIC, (HGDIOBJ*)&hdc, &dc_funcs ))) return NULL;
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82

    dc->hSelf               = hdc;
    dc->funcs               = funcs;
    dc->physDev             = NULL;
    dc->saveLevel           = 0;
    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;
    dc->flags               = 0;
    dc->hClipRgn            = 0;
    dc->hVisRgn             = 0;
    dc->hGCClipRgn          = 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 );
83
    dc->gdiFont             = 0;
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119
    dc->ROPmode             = R2_COPYPEN;
    dc->polyFillMode        = ALTERNATE;
    dc->stretchBltMode      = BLACKONWHITE;
    dc->relAbsMode          = ABSOLUTE;
    dc->backgroundMode      = OPAQUE;
    dc->backgroundColor     = RGB( 255, 255, 255 );
    dc->textColor           = RGB( 0, 0, 0 );
    dc->brushOrgX           = 0;
    dc->brushOrgY           = 0;
    dc->textAlign           = TA_LEFT | TA_TOP | TA_NOUPDATECP;
    dc->charExtra           = 0;
    dc->breakTotalExtra     = 0;
    dc->breakCount          = 0;
    dc->breakExtra          = 0;
    dc->breakRem            = 0;
    dc->totalExtent.left    = 0;
    dc->totalExtent.top     = 0;
    dc->totalExtent.right   = 0;
    dc->totalExtent.bottom  = 0;
    dc->bitsPerPixel        = 1;
    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;
    PATH_InitGdiPath(&dc->path);
Alexandre Julliard's avatar
Alexandre Julliard committed
120 121 122 123
    return dc;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
124

Alexandre Julliard's avatar
Alexandre Julliard committed
125 126 127
/***********************************************************************
 *           DC_GetDCPtr
 */
128
DC *DC_GetDCPtr( HDC hdc )
Alexandre Julliard's avatar
Alexandre Julliard committed
129
{
130
    GDIOBJHDR *ptr = GDI_GetObjPtr( hdc, MAGIC_DONTCARE );
Alexandre Julliard's avatar
Alexandre Julliard committed
131
    if (!ptr) return NULL;
132 133 134
    if ((GDIMAGIC(ptr->wMagic) == DC_MAGIC) ||
	(GDIMAGIC(ptr->wMagic) == METAFILE_DC_MAGIC) ||
	(GDIMAGIC(ptr->wMagic) == ENHMETAFILE_DC_MAGIC))
Alexandre Julliard's avatar
Alexandre Julliard committed
135
        return (DC *)ptr;
136
    GDI_ReleaseObj( hdc );
137
    SetLastError( ERROR_INVALID_HANDLE );
Alexandre Julliard's avatar
Alexandre Julliard committed
138 139 140
    return NULL;
}

141 142 143 144 145 146 147 148 149 150 151
/***********************************************************************
 *           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;
152
    while (dc->flags & DC_DIRTY)
153
    {
154 155
        dc->flags &= ~DC_DIRTY;
        if (!(dc->flags & (DC_SAVED | DC_MEMORY)))
156 157 158 159 160 161
        {
            DCHOOKPROC proc = dc->hookThunk;
            if (proc)
            {
                DWORD data = dc->dwHookData;
                GDI_ReleaseObj( hdc );
162
                proc( HDC_16(hdc), DCHC_INVALIDVISRGN, data, 0 );
163 164 165 166 167 168 169
                if (!(dc = DC_GetDCPtr( hdc ))) break;
                /* otherwise restart the loop in case it became dirty again in the meantime */
            }
        }
    }
    return dc;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
170

171 172 173 174 175 176 177 178 179 180 181

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


Alexandre Julliard's avatar
Alexandre Julliard committed
182
/***********************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
183
 *           DC_InitDC
Alexandre Julliard's avatar
Alexandre Julliard committed
184
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
185
 * Setup device-specific DC values for a newly created DC.
Alexandre Julliard's avatar
Alexandre Julliard committed
186
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
187
void DC_InitDC( DC* dc )
Alexandre Julliard's avatar
Alexandre Julliard committed
188
{
189
    if (dc->funcs->pRealizeDefaultPalette) dc->funcs->pRealizeDefaultPalette( dc->physDev );
190 191 192 193 194
    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
195
    CLIPPING_UpdateGCRegion( dc );
Alexandre Julliard's avatar
Alexandre Julliard committed
196 197 198
}


Alexandre Julliard's avatar
Alexandre Julliard committed
199 200 201 202 203 204 205
/***********************************************************************
 *           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.
 */
206
static BOOL DC_InvertXform( const XFORM *xformSrc, XFORM *xformDest )
Alexandre Julliard's avatar
Alexandre Julliard committed
207 208
{
    FLOAT determinant;
209

Alexandre Julliard's avatar
Alexandre Julliard committed
210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241
    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 )
{
    XFORM xformWnd2Vport;
    FLOAT scaleX, scaleY;
242

Alexandre Julliard's avatar
Alexandre Julliard committed
243 244 245 246 247 248 249 250 251 252 253 254 255
    /* 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;

    /* Combine with the world transformation */
256
    CombineTransform( &dc->xformWorld2Vport, &dc->xformWorld2Wnd,
Alexandre Julliard's avatar
Alexandre Julliard committed
257 258 259
        &xformWnd2Vport );

    /* Create inverse of world-to-viewport transformation */
260 261
    dc->vport2WorldValid = DC_InvertXform( &dc->xformWorld2Vport,
        &dc->xformVport2World );
Alexandre Julliard's avatar
Alexandre Julliard committed
262 263 264
}


Alexandre Julliard's avatar
Alexandre Julliard committed
265
/***********************************************************************
266
 *           GetDCState   (Not a Windows API)
Alexandre Julliard's avatar
Alexandre Julliard committed
267
 */
268
HDC WINAPI GetDCState( HDC hdc )
Alexandre Julliard's avatar
Alexandre Julliard committed
269 270
{
    DC * newdc, * dc;
271
    HGDIOBJ handle;
272

273
    if (!(dc = DC_GetDCPtr( hdc ))) return 0;
274
    if (!(newdc = GDI_AllocObject( sizeof(DC), DC_MAGIC, &handle, &dc_funcs )))
Alexandre Julliard's avatar
Alexandre Julliard committed
275
    {
276
      GDI_ReleaseObj( hdc );
Alexandre Julliard's avatar
Alexandre Julliard committed
277 278
      return 0;
    }
279
    TRACE("(%p): returning %p\n", hdc, handle );
Alexandre Julliard's avatar
Alexandre Julliard committed
280

281
    newdc->flags            = dc->flags | DC_SAVED;
282 283 284 285
    newdc->hPen             = dc->hPen;
    newdc->hBrush           = dc->hBrush;
    newdc->hFont            = dc->hFont;
    newdc->hBitmap          = dc->hBitmap;
286
    newdc->hDevice          = dc->hDevice;
287
    newdc->hPalette         = dc->hPalette;
288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321
    newdc->totalExtent      = dc->totalExtent;
    newdc->bitsPerPixel     = dc->bitsPerPixel;
    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;
    newdc->brushOrgX        = dc->brushOrgX;
    newdc->brushOrgY        = dc->brushOrgY;
    newdc->textAlign        = dc->textAlign;
    newdc->charExtra        = dc->charExtra;
    newdc->breakTotalExtra  = dc->breakTotalExtra;
    newdc->breakCount       = dc->breakCount;
    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;
Alexandre Julliard's avatar
Alexandre Julliard committed
322

323
    newdc->hSelf = (HDC)handle;
Alexandre Julliard's avatar
Alexandre Julliard committed
324 325
    newdc->saveLevel = 0;

326
    PATH_InitGdiPath( &newdc->path );
327

328
    newdc->pAbortProc = NULL;
329
    newdc->hookThunk  = NULL;
330
    newdc->hookProc   = 0;
331

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

334 335
    newdc->hGCClipRgn = newdc->hVisRgn = 0;
    if (dc->hClipRgn)
Alexandre Julliard's avatar
Alexandre Julliard committed
336
    {
337 338
	newdc->hClipRgn = CreateRectRgn( 0, 0, 0, 0 );
	CombineRgn( newdc->hClipRgn, dc->hClipRgn, 0, RGN_COPY );
Alexandre Julliard's avatar
Alexandre Julliard committed
339
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
340
    else
341
	newdc->hClipRgn = 0;
342 343 344 345 346 347

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

348 349
    GDI_ReleaseObj( handle );
    GDI_ReleaseObj( hdc );
Alexandre Julliard's avatar
Alexandre Julliard committed
350 351 352 353 354
    return handle;
}


/***********************************************************************
355
 *           SetDCState   (Not a Windows API)
Alexandre Julliard's avatar
Alexandre Julliard committed
356
 */
357
void WINAPI SetDCState( HDC hdc, HDC hdcs )
Alexandre Julliard's avatar
Alexandre Julliard committed
358
{
Alexandre Julliard's avatar
Alexandre Julliard committed
359
    DC *dc, *dcs;
360

361
    if (!(dc = DC_GetDCUpdate( hdc ))) return;
362
    if (!(dcs = DC_GetDCPtr( hdcs )))
Alexandre Julliard's avatar
Alexandre Julliard committed
363
    {
364
      GDI_ReleaseObj( hdc );
Alexandre Julliard's avatar
Alexandre Julliard committed
365 366
      return;
    }
367
    if (!dcs->flags & DC_SAVED)
Alexandre Julliard's avatar
Alexandre Julliard committed
368
    {
369 370
      GDI_ReleaseObj( hdc );
      GDI_ReleaseObj( hdcs );
Alexandre Julliard's avatar
Alexandre Julliard committed
371 372
      return;
    }
373
    TRACE("%p %p\n", hdc, hdcs );
Alexandre Julliard's avatar
Alexandre Julliard committed
374

375
    dc->flags            = dcs->flags & ~(DC_SAVED | DC_DIRTY);
376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414
    dc->hDevice          = dcs->hDevice;
    dc->totalExtent      = dcs->totalExtent;
    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;
    dc->brushOrgX        = dcs->brushOrgX;
    dc->brushOrgY        = dcs->brushOrgY;
    dc->textAlign        = dcs->textAlign;
    dc->charExtra        = dcs->charExtra;
    dc->breakTotalExtra  = dcs->breakTotalExtra;
    dc->breakCount       = dcs->breakCount;
    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;

    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 (!(dc->flags & DC_MEMORY)) dc->bitsPerPixel = dcs->bitsPerPixel;

    if (dcs->hClipRgn)
415
    {
416 417
        if (!dc->hClipRgn) dc->hClipRgn = CreateRectRgn( 0, 0, 0, 0 );
        CombineRgn( dc->hClipRgn, dcs->hClipRgn, 0, RGN_COPY );
418 419
    }
    else
420
    {
421
        if (dc->hClipRgn) DeleteObject( dc->hClipRgn );
422
        dc->hClipRgn = 0;
423 424
    }
    CLIPPING_UpdateGCRegion( dc );
Alexandre Julliard's avatar
Alexandre Julliard committed
425

426 427 428 429 430 431
    SelectObject( hdc, dcs->hBitmap );
    SelectObject( hdc, dcs->hBrush );
    SelectObject( hdc, dcs->hFont );
    SelectObject( hdc, dcs->hPen );
    SetBkColor( hdc, dcs->backgroundColor);
    SetTextColor( hdc, dcs->textColor);
432
    GDISelectPalette( hdc, dcs->hPalette, FALSE );
433 434
    GDI_ReleaseObj( hdcs );
    GDI_ReleaseObj( hdc );
Alexandre Julliard's avatar
Alexandre Julliard committed
435 436 437
}


438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455
/***********************************************************************
 *           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
456
/***********************************************************************
457
 *           SaveDC    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
458
 */
459
INT WINAPI SaveDC( HDC hdc )
Alexandre Julliard's avatar
Alexandre Julliard committed
460
{
461
    HDC hdcs;
Alexandre Julliard's avatar
Alexandre Julliard committed
462
    DC * dc, * dcs;
463
    INT ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
464

465
    dc = DC_GetDCPtr( hdc );
466 467 468
    if (!dc) return 0;

    if(dc->funcs->pSaveDC)
469
    {
470
        ret = dc->funcs->pSaveDC( dc->physDev );
471 472 473
        GDI_ReleaseObj( hdc );
        return ret;
    }
474

475
    if (!(hdcs = GetDCState( hdc )))
Alexandre Julliard's avatar
Alexandre Julliard committed
476
    {
477
      GDI_ReleaseObj( hdc );
Alexandre Julliard's avatar
Alexandre Julliard committed
478 479
      return 0;
    }
480
    dcs = DC_GetDCPtr( hdcs );
Alexandre Julliard's avatar
Alexandre Julliard committed
481 482 483 484 485 486 487

    /* 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).
     */
488
    if (!PATH_AssignGdiPath( &dcs->path, &dc->path ))
Alexandre Julliard's avatar
Alexandre Julliard committed
489
    {
490 491
        GDI_ReleaseObj( hdc );
	GDI_ReleaseObj( hdcs );
492
	DeleteDC( hdcs );
Alexandre Julliard's avatar
Alexandre Julliard committed
493 494
	return 0;
    }
495

Alexandre Julliard's avatar
Alexandre Julliard committed
496
    dcs->header.hNext = dc->header.hNext;
497
    dc->header.hNext = HDC_16(hdcs);
498
    TRACE("(%p): returning %d\n", hdc, dc->saveLevel+1 );
Alexandre Julliard's avatar
Alexandre Julliard committed
499
    ret = ++dc->saveLevel;
500 501
    GDI_ReleaseObj( hdcs );
    GDI_ReleaseObj( hdc );
Alexandre Julliard's avatar
Alexandre Julliard committed
502
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
503 504 505
}


Alexandre Julliard's avatar
Alexandre Julliard committed
506
/***********************************************************************
507
 *           RestoreDC    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
508
 */
509
BOOL WINAPI RestoreDC( HDC hdc, INT level )
Alexandre Julliard's avatar
Alexandre Julliard committed
510 511
{
    DC * dc, * dcs;
512
    BOOL success;
Alexandre Julliard's avatar
Alexandre Julliard committed
513

514
    TRACE("%p %d\n", hdc, level );
515
    dc = DC_GetDCUpdate( hdc );
516 517
    if(!dc) return FALSE;
    if(dc->funcs->pRestoreDC)
518
    {
519
        success = dc->funcs->pRestoreDC( dc->physDev, level );
520 521 522
        GDI_ReleaseObj( hdc );
        return success;
    }
523

Alexandre Julliard's avatar
Alexandre Julliard committed
524
    if (level == -1) level = dc->saveLevel;
525
    if ((level < 1)
526 527 528 529 530 531
            /* This pair of checks disagrees with MSDN "Platform SDK:
               Windows GDI" July 2000 which says all negative values
               for level will be interpreted as an instance relative
               to the current state.  Restricting it to just -1 does
               not satisfy this */
	|| (level > dc->saveLevel))
Alexandre Julliard's avatar
Alexandre Julliard committed
532
    {
533 534
        GDI_ReleaseObj( hdc );
        return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
535
    }
536

Alexandre Julliard's avatar
Alexandre Julliard committed
537
    success=TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
538
    while (dc->saveLevel >= level)
Alexandre Julliard's avatar
Alexandre Julliard committed
539
    {
540
	HDC hdcs = HDC_32(dc->header.hNext);
541
	if (!(dcs = DC_GetDCPtr( hdcs )))
Alexandre Julliard's avatar
Alexandre Julliard committed
542
	{
543
	  GDI_ReleaseObj( hdc );
Alexandre Julliard's avatar
Alexandre Julliard committed
544
	  return FALSE;
545
	}
Alexandre Julliard's avatar
Alexandre Julliard committed
546
	dc->header.hNext = dcs->header.hNext;
Alexandre Julliard's avatar
Alexandre Julliard committed
547 548
	if (--dc->saveLevel < level)
	{
549
	    SetDCState( hdc, hdcs );
550
            if (!PATH_AssignGdiPath( &dc->path, &dcs->path ))
Alexandre Julliard's avatar
Alexandre Julliard committed
551 552 553 554
		/* FIXME: This might not be quite right, since we're
		 * returning FALSE but still destroying the saved DC state */
	        success=FALSE;
	}
555
        GDI_ReleaseObj( hdcs );
556
        GDI_ReleaseObj( hdc );
557
	DeleteDC( hdcs );
558
        if (!(dc = DC_GetDCPtr( hdc ))) return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
559
    }
560
    GDI_ReleaseObj( hdc );
Alexandre Julliard's avatar
Alexandre Julliard committed
561
    return success;
Alexandre Julliard's avatar
Alexandre Julliard committed
562 563 564
}


565 566 567 568 569
/***********************************************************************
 *           CreateDCA    (GDI32.@)
 */
HDC WINAPI CreateDCA( LPCSTR driver, LPCSTR device, LPCSTR output,
                          const DEVMODEA *initData )
Alexandre Julliard's avatar
Alexandre Julliard committed
570
{
571
    HDC hdc;
Alexandre Julliard's avatar
Alexandre Julliard committed
572
    DC * dc;
Alexandre Julliard's avatar
Alexandre Julliard committed
573
    const DC_FUNCTIONS *funcs;
574
    char buf[300];
Alexandre Julliard's avatar
Alexandre Julliard committed
575

576 577
    GDI_CheckNotLock();

578
    if (!device || !DRIVER_GetDriverName( device, buf, sizeof(buf) ))
579 580
    {
        if (!driver) return 0;
581
        strcpy(buf, driver);
582
    }
583

584 585 586 587 588 589 590 591 592 593 594
    if (!(funcs = DRIVER_load_driver( buf )))
    {
        ERR( "no driver found for %s\n", buf );
        return 0;
    }
    if (!(dc = DC_AllocDC( funcs )))
    {
        DRIVER_release_driver( funcs );
        return 0;
    }

595 596
    dc->flags   = 0;
    dc->hBitmap = GetStockObject( DEFAULT_BITMAP );
Alexandre Julliard's avatar
Alexandre Julliard committed
597

598 599
    TRACE("(driver=%s, device=%s, output=%s): returning %p\n",
          debugstr_a(driver), debugstr_a(device), debugstr_a(output), dc->hSelf );
Alexandre Julliard's avatar
Alexandre Julliard committed
600 601

    if (dc->funcs->pCreateDC &&
602
        !dc->funcs->pCreateDC( dc, &dc->physDev, buf, device, output, initData ))
Alexandre Julliard's avatar
Alexandre Julliard committed
603
    {
604
        WARN("creation aborted by device\n" );
605
        GDI_FreeObject( dc->hSelf, dc );
606
        DRIVER_release_driver( funcs );
Alexandre Julliard's avatar
Alexandre Julliard committed
607 608
        return 0;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
609

610 611 612 613 614 615
    dc->totalExtent.left   = 0;
    dc->totalExtent.top    = 0;
    dc->totalExtent.right  = GetDeviceCaps( dc->hSelf, HORZRES );
    dc->totalExtent.bottom = GetDeviceCaps( dc->hSelf, VERTRES );
    dc->hVisRgn = CreateRectRgnIndirect( &dc->totalExtent );

Alexandre Julliard's avatar
Alexandre Julliard committed
616
    DC_InitDC( dc );
617 618 619
    hdc = dc->hSelf;
    GDI_ReleaseObj( hdc );
    return hdc;
Alexandre Julliard's avatar
Alexandre Julliard committed
620 621 622
}


Alexandre Julliard's avatar
Alexandre Julliard committed
623
/***********************************************************************
624
 *           CreateDCW    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
625
 */
626 627
HDC WINAPI CreateDCW( LPCWSTR driver, LPCWSTR device, LPCWSTR output,
                          const DEVMODEW *initData )
628
{
Alexandre Julliard's avatar
Alexandre Julliard committed
629 630 631
    LPSTR driverA = HEAP_strdupWtoA( GetProcessHeap(), 0, driver );
    LPSTR deviceA = HEAP_strdupWtoA( GetProcessHeap(), 0, device );
    LPSTR outputA = HEAP_strdupWtoA( GetProcessHeap(), 0, output );
632
    HDC res = CreateDCA( driverA, deviceA, outputA,
633
                            (const DEVMODEA *)initData /*FIXME*/ );
Alexandre Julliard's avatar
Alexandre Julliard committed
634 635 636
    HeapFree( GetProcessHeap(), 0, driverA );
    HeapFree( GetProcessHeap(), 0, deviceA );
    HeapFree( GetProcessHeap(), 0, outputA );
Alexandre Julliard's avatar
Alexandre Julliard committed
637 638 639 640
    return res;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
641
/***********************************************************************
642
 *           CreateICA    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
643
 */
644 645
HDC WINAPI CreateICA( LPCSTR driver, LPCSTR device, LPCSTR output,
                          const DEVMODEA* initData )
Alexandre Julliard's avatar
Alexandre Julliard committed
646 647
{
      /* Nothing special yet for ICs */
648
    return CreateDCA( driver, device, output, initData );
Alexandre Julliard's avatar
Alexandre Julliard committed
649 650 651 652
}


/***********************************************************************
653
 *           CreateICW    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
654
 */
655 656
HDC WINAPI CreateICW( LPCWSTR driver, LPCWSTR device, LPCWSTR output,
                          const DEVMODEW* initData )
Alexandre Julliard's avatar
Alexandre Julliard committed
657 658
{
      /* Nothing special yet for ICs */
659
    return CreateDCW( driver, device, output, initData );
Alexandre Julliard's avatar
Alexandre Julliard committed
660 661 662 663
}


/***********************************************************************
664
 *           CreateCompatibleDC   (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
665
 */
666
HDC WINAPI CreateCompatibleDC( HDC hdc )
Alexandre Julliard's avatar
Alexandre Julliard committed
667
{
Alexandre Julliard's avatar
Alexandre Julliard committed
668 669 670
    DC *dc, *origDC;
    const DC_FUNCTIONS *funcs;

671
    GDI_CheckNotLock();
672

673
    if ((origDC = GDI_GetObjPtr( hdc, DC_MAGIC )))
674
    {
675 676 677
        funcs = origDC->funcs;
        GDI_ReleaseObj( hdc ); /* can't hold the lock while loading the driver */
        funcs = DRIVER_get_driver( funcs );
678
    }
679 680 681
    else funcs = DRIVER_load_driver( "DISPLAY" );

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

683
    if (!(dc = DC_AllocDC( funcs )))
684
    {
685
        DRIVER_release_driver( funcs );
686 687
        return 0;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
688

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

691 692
    dc->flags        = DC_MEMORY;
    dc->bitsPerPixel = 1;
693
    dc->hBitmap      = GetStockObject( DEFAULT_BITMAP );
Alexandre Julliard's avatar
Alexandre Julliard committed
694

695 696 697
    /* 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. */
698
    if ((origDC = GDI_GetObjPtr( hdc, DC_MAGIC ))) dc->physDev = origDC->physDev;
699

Alexandre Julliard's avatar
Alexandre Julliard committed
700
    if (dc->funcs->pCreateDC &&
701
        !dc->funcs->pCreateDC( dc, &dc->physDev, NULL, NULL, NULL, NULL ))
Alexandre Julliard's avatar
Alexandre Julliard committed
702
    {
703
        WARN("creation aborted by device\n");
704
        GDI_FreeObject( dc->hSelf, dc );
705
        if (origDC) GDI_ReleaseObj( hdc );
706
        DRIVER_release_driver( funcs );
Alexandre Julliard's avatar
Alexandre Julliard committed
707 708
        return 0;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
709

710 711 712 713 714 715
    dc->totalExtent.left   = 0;
    dc->totalExtent.top    = 0;
    dc->totalExtent.right  = 1;  /* default bitmap is 1x1 */
    dc->totalExtent.bottom = 1;
    dc->hVisRgn = CreateRectRgnIndirect( &dc->totalExtent );

Alexandre Julliard's avatar
Alexandre Julliard committed
716
    DC_InitDC( dc );
717 718
    GDI_ReleaseObj( dc->hSelf );
    if (origDC) GDI_ReleaseObj( hdc );
Alexandre Julliard's avatar
Alexandre Julliard committed
719
    return dc->hSelf;
Alexandre Julliard's avatar
Alexandre Julliard committed
720 721 722
}


Alexandre Julliard's avatar
Alexandre Julliard committed
723
/***********************************************************************
724
 *           DeleteDC    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
725
 */
726
BOOL WINAPI DeleteDC( HDC hdc )
Alexandre Julliard's avatar
Alexandre Julliard committed
727
{
728 729
    const DC_FUNCTIONS *funcs = NULL;
    DC * dc;
Alexandre Julliard's avatar
Alexandre Julliard committed
730

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

733 734 735 736
    GDI_CheckNotLock();

    if (!(dc = GDI_GetObjPtr( hdc, DC_MAGIC ))) return FALSE;

737
    /* Call hook procedure to check whether is it OK to delete this DC */
738
    if (dc->hookThunk && !(dc->flags & (DC_SAVED | DC_MEMORY)))
739
    {
740 741 742 743 744
        DCHOOKPROC proc = dc->hookThunk;
        if (proc)
        {
            DWORD data = dc->dwHookData;
            GDI_ReleaseObj( hdc );
745
            if (!proc( HDC_16(hdc), DCHC_DELETEDC, data, 0 )) return FALSE;
746
            if (!(dc = DC_GetDCPtr( hdc ))) return TRUE;  /* deleted by the hook */
747
        }
748 749
    }

Alexandre Julliard's avatar
Alexandre Julliard committed
750 751 752
    while (dc->saveLevel)
    {
	DC * dcs;
753
	HDC hdcs = HDC_32(dc->header.hNext);
754
	if (!(dcs = DC_GetDCPtr( hdcs ))) break;
Alexandre Julliard's avatar
Alexandre Julliard committed
755 756
	dc->header.hNext = dcs->header.hNext;
	dc->saveLevel--;
757 758 759 760 761
        if (dcs->hClipRgn) DeleteObject( dcs->hClipRgn );
        if (dcs->hVisRgn) DeleteObject( dcs->hVisRgn );
        if (dcs->hGCClipRgn) DeleteObject( dcs->hGCClipRgn );
        PATH_DestroyGdiPath(&dcs->path);
        GDI_FreeObject( hdcs, dcs );
Alexandre Julliard's avatar
Alexandre Julliard committed
762
    }
763

764
    if (!(dc->flags & DC_SAVED))
Alexandre Julliard's avatar
Alexandre Julliard committed
765
    {
766 767 768
	SelectObject( hdc, GetStockObject(BLACK_PEN) );
	SelectObject( hdc, GetStockObject(WHITE_BRUSH) );
	SelectObject( hdc, GetStockObject(SYSTEM_FONT) );
769
        SelectObject( hdc, GetStockObject(DEFAULT_BITMAP) );
770
        funcs = dc->funcs;
771
        if (dc->funcs->pDeleteDC) dc->funcs->pDeleteDC(dc->physDev);
772
        dc->physDev = NULL;
Alexandre Julliard's avatar
Alexandre Julliard committed
773
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
774

775 776 777 778
    if (dc->hClipRgn) DeleteObject( dc->hClipRgn );
    if (dc->hVisRgn) DeleteObject( dc->hVisRgn );
    if (dc->hGCClipRgn) DeleteObject( dc->hGCClipRgn );
    PATH_DestroyGdiPath(&dc->path);
779

780 781 782
    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
783 784 785
}


Alexandre Julliard's avatar
Alexandre Julliard committed
786
/***********************************************************************
787
 *           ResetDCA    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
788
 */
789
HDC WINAPI ResetDCA( HDC hdc, const DEVMODEA *devmode )
Alexandre Julliard's avatar
Alexandre Julliard committed
790
{
791 792 793 794 795 796 797 798 799
    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
800 801 802 803
}


/***********************************************************************
804
 *           ResetDCW    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
805
 */
806
HDC WINAPI ResetDCW( HDC hdc, const DEVMODEW *devmode )
Alexandre Julliard's avatar
Alexandre Julliard committed
807
{
808
    return ResetDCA(hdc, (const DEVMODEA*)devmode); /* FIXME */
Alexandre Julliard's avatar
Alexandre Julliard committed
809 810 811
}


Alexandre Julliard's avatar
Alexandre Julliard committed
812
/***********************************************************************
813
 *           GetDeviceCaps    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
814
 */
815
INT WINAPI GetDeviceCaps( HDC hdc, INT cap )
Alexandre Julliard's avatar
Alexandre Julliard committed
816
{
817
    DC *dc;
818
    INT ret = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
819

820
    if ((dc = DC_GetDCPtr( hdc )))
821
    {
822
        if (dc->funcs->pGetDeviceCaps) ret = dc->funcs->pGetDeviceCaps( dc->physDev, cap );
823
        GDI_ReleaseObj( hdc );
824
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
825
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
826 827 828
}


Alexandre Julliard's avatar
Alexandre Julliard committed
829
/***********************************************************************
830
 *           SetBkColor    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
831
 */
832
COLORREF WINAPI SetBkColor( HDC hdc, COLORREF color )
Alexandre Julliard's avatar
Alexandre Julliard committed
833 834
{
    COLORREF oldColor;
Alexandre Julliard's avatar
Alexandre Julliard committed
835
    DC * dc = DC_GetDCPtr( hdc );
836 837 838

    if (!dc) return CLR_INVALID;
    oldColor = dc->backgroundColor;
Alexandre Julliard's avatar
Alexandre Julliard committed
839
    if (dc->funcs->pSetBkColor)
840 841 842 843 844 845 846
    {
        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
847
    }
848
    dc->backgroundColor = color;
849
    GDI_ReleaseObj( hdc );
Alexandre Julliard's avatar
Alexandre Julliard committed
850 851 852 853
    return oldColor;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
854
/***********************************************************************
855
 *           SetTextColor    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
856
 */
857
COLORREF WINAPI SetTextColor( HDC hdc, COLORREF color )
Alexandre Julliard's avatar
Alexandre Julliard committed
858 859
{
    COLORREF oldColor;
Alexandre Julliard's avatar
Alexandre Julliard committed
860
    DC * dc = DC_GetDCPtr( hdc );
861 862 863

    if (!dc) return CLR_INVALID;
    oldColor = dc->textColor;
Alexandre Julliard's avatar
Alexandre Julliard committed
864
    if (dc->funcs->pSetTextColor)
865 866 867 868 869 870 871
    {
        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
872
    }
873
    dc->textColor = color;
874
    GDI_ReleaseObj( hdc );
Alexandre Julliard's avatar
Alexandre Julliard committed
875 876 877
    return oldColor;
}

Alexandre Julliard's avatar
Alexandre Julliard committed
878 879

/***********************************************************************
880
 *           SetTextAlign    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
881
 */
882
UINT WINAPI SetTextAlign( HDC hdc, UINT align )
Alexandre Julliard's avatar
Alexandre Julliard committed
883
{
884
    UINT prevAlign;
885 886 887
    DC *dc = DC_GetDCPtr( hdc );
    if (!dc) return 0x0;
    if (dc->funcs->pSetTextAlign)
888
        prevAlign = dc->funcs->pSetTextAlign(dc->physDev, align);
889
    else {
890 891
	prevAlign = dc->textAlign;
	dc->textAlign = align;
Alexandre Julliard's avatar
Alexandre Julliard committed
892
    }
893
    GDI_ReleaseObj( hdc );
Alexandre Julliard's avatar
Alexandre Julliard committed
894 895 896
    return prevAlign;
}

Alexandre Julliard's avatar
Alexandre Julliard committed
897
/***********************************************************************
898
 *           GetDCOrgEx  (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
899
 */
900
BOOL WINAPI GetDCOrgEx( HDC hDC, LPPOINT lpp )
Alexandre Julliard's avatar
Alexandre Julliard committed
901
{
Alexandre Julliard's avatar
Alexandre Julliard committed
902
    DC * dc;
903

Alexandre Julliard's avatar
Alexandre Julliard committed
904
    if (!lpp) return FALSE;
905
    if (!(dc = DC_GetDCPtr( hDC ))) return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
906

907
    lpp->x = lpp->y = 0;
908
    if (dc->funcs->pGetDCOrgEx) dc->funcs->pGetDCOrgEx( dc->physDev, lpp );
909
    GDI_ReleaseObj( hDC );
Alexandre Julliard's avatar
Alexandre Julliard committed
910 911 912 913
    return TRUE;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
914
/***********************************************************************
915
 *           SetDCOrg   (GDI.117)
Alexandre Julliard's avatar
Alexandre Julliard committed
916
 */
917
DWORD WINAPI SetDCOrg16( HDC16 hdc16, INT16 x, INT16 y )
Alexandre Julliard's avatar
Alexandre Julliard committed
918
{
919
    DWORD prevOrg = 0;
920
    HDC hdc = HDC_32( hdc16 );
921
    DC *dc = DC_GetDCPtr( hdc );
Alexandre Julliard's avatar
Alexandre Julliard committed
922
    if (!dc) return 0;
923
    if (dc->funcs->pSetDCOrg) prevOrg = dc->funcs->pSetDCOrg( dc->physDev, x, y );
924
    GDI_ReleaseObj( hdc );
Alexandre Julliard's avatar
Alexandre Julliard committed
925 926
    return prevOrg;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
927 928


Alexandre Julliard's avatar
Alexandre Julliard committed
929
/***********************************************************************
930
 *           SetGraphicsMode    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
931
 */
932
INT WINAPI SetGraphicsMode( HDC hdc, INT mode )
Alexandre Julliard's avatar
Alexandre Julliard committed
933
{
934
    INT ret = 0;
935
    DC *dc = DC_GetDCPtr( hdc );
Alexandre Julliard's avatar
Alexandre Julliard committed
936 937 938 939 940 941

    /* 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
942
    if (!dc) return 0;
943
    if ((mode > 0) || (mode <= GM_LAST))
944
    {
945 946 947
        ret = dc->GraphicsMode;
        dc->GraphicsMode = mode;
    }
948 949
    GDI_ReleaseObj( hdc );
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
950 951 952 953
}


/***********************************************************************
954
 *           SetArcDirection    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
955
 */
956
INT WINAPI SetArcDirection( HDC hdc, INT nDirection )
Alexandre Julliard's avatar
Alexandre Julliard committed
957
{
958 959
    DC * dc;
    INT nOldDirection = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
960 961 962 963 964 965 966

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

967
    if ((dc = DC_GetDCPtr( hdc )))
968
    {
969 970
        nOldDirection = dc->ArcDirection;
        dc->ArcDirection = nDirection;
971 972
        GDI_ReleaseObj( hdc );
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
973 974 975 976
    return nOldDirection;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
977
/***********************************************************************
978
 *           GetWorldTransform    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
979
 */
980
BOOL WINAPI GetWorldTransform( HDC hdc, LPXFORM xform )
Alexandre Julliard's avatar
Alexandre Julliard committed
981
{
982 983
    DC * dc;
    if (!xform) return FALSE;
984 985
    if (!(dc = DC_GetDCPtr( hdc ))) return FALSE;
    *xform = dc->xformWorld2Wnd;
986
    GDI_ReleaseObj( hdc );
Alexandre Julliard's avatar
Alexandre Julliard committed
987 988 989 990 991
    return TRUE;
}


/***********************************************************************
992
 *           SetWorldTransform    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
993
 */
994
BOOL WINAPI SetWorldTransform( HDC hdc, const XFORM *xform )
Alexandre Julliard's avatar
Alexandre Julliard committed
995
{
996
    BOOL ret = FALSE;
997
    DC *dc = DC_GetDCPtr( hdc );
Alexandre Julliard's avatar
Alexandre Julliard committed
998

999
    if (!dc) return FALSE;
1000
    if (!xform) goto done;
1001

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

1005
    dc->xformWorld2Wnd = *xform;
Alexandre Julliard's avatar
Alexandre Julliard committed
1006
    DC_UpdateXforms( dc );
1007 1008 1009 1010
    ret = TRUE;
 done:
    GDI_ReleaseObj( hdc );
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
1011 1012 1013 1014
}


/****************************************************************************
1015
 * ModifyWorldTransform [GDI32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035
 * 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.
 *
 * RETURNS STD
 */
1036
BOOL WINAPI ModifyWorldTransform( HDC hdc, const XFORM *xform,
Alexandre Julliard's avatar
Alexandre Julliard committed
1037 1038
    DWORD iMode )
{
1039
    BOOL ret = FALSE;
1040 1041
    DC *dc = DC_GetDCPtr( hdc );

Alexandre Julliard's avatar
Alexandre Julliard committed
1042
    /* Check for illegal parameters */
1043
    if (!dc) return FALSE;
1044
    if (!xform) goto done;
1045

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

Alexandre Julliard's avatar
Alexandre Julliard committed
1049 1050 1051
    switch (iMode)
    {
        case MWT_IDENTITY:
1052 1053 1054 1055 1056 1057
	    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
1058 1059
	    break;
        case MWT_LEFTMULTIPLY:
1060 1061
	    CombineTransform( &dc->xformWorld2Wnd, xform,
	        &dc->xformWorld2Wnd );
Alexandre Julliard's avatar
Alexandre Julliard committed
1062 1063
	    break;
	case MWT_RIGHTMULTIPLY:
1064
	    CombineTransform( &dc->xformWorld2Wnd, &dc->xformWorld2Wnd,
Alexandre Julliard's avatar
Alexandre Julliard committed
1065 1066 1067
	        xform );
	    break;
        default:
1068
            goto done;
Alexandre Julliard's avatar
Alexandre Julliard committed
1069 1070 1071
    }

    DC_UpdateXforms( dc );
1072 1073 1074 1075
    ret = TRUE;
 done:
    GDI_ReleaseObj( hdc );
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
1076 1077 1078 1079
}


/****************************************************************************
1080
 * CombineTransform [GDI32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092
 * 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.
 *
 * RETURNS STD
 */
1093
BOOL WINAPI CombineTransform( LPXFORM xformResult, const XFORM *xform1,
Alexandre Julliard's avatar
Alexandre Julliard committed
1094 1095 1096
    const XFORM *xform2 )
{
    XFORM xformTemp;
1097

Alexandre Julliard's avatar
Alexandre Julliard committed
1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121
    /* 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
1122
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1123 1124 1125
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1126
/***********************************************************************
1127 1128 1129
 *           SetDCHook   (GDI32.@)
 *
 * Note: this doesn't exist in Win32, we add it here because user32 needs it.
Alexandre Julliard's avatar
Alexandre Julliard committed
1130
 */
1131 1132 1133
BOOL WINAPI SetDCHook( HDC hdc, DCHOOKPROC hookProc, DWORD dwHookData )
{
    DC *dc = DC_GetDCPtr( hdc );
1134

1135 1136 1137 1138 1139 1140
    if (!dc) return FALSE;
    dc->dwHookData = dwHookData;
    dc->hookThunk = hookProc;
    GDI_ReleaseObj( hdc );
    return TRUE;
}
1141 1142


1143
/* relay function to call the 16-bit DC hook proc */
1144
static BOOL16 WINAPI call_dc_hook16( HDC16 hdc16, WORD code, DWORD data, LPARAM lParam )
Alexandre Julliard's avatar
Alexandre Julliard committed
1145
{
1146 1147
    WORD args[6];
    DWORD ret;
1148
    FARPROC16 proc = NULL;
1149
    HDC hdc = HDC_32( hdc16 );
1150
    DC *dc = DC_GetDCPtr( hdc );
1151

1152
    if (!dc) return FALSE;
1153 1154 1155
    proc = dc->hookProc;
    GDI_ReleaseObj( hdc );
    if (!proc) return FALSE;
1156 1157 1158 1159 1160 1161 1162 1163
    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);
1164
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1165

1166 1167 1168
/***********************************************************************
 *           SetDCHook   (GDI.190)
 */
1169
BOOL16 WINAPI SetDCHook16( HDC16 hdc16, FARPROC16 hookProc, DWORD dwHookData )
1170
{
1171
    HDC hdc = HDC_32( hdc16 );
1172 1173
    DC *dc = DC_GetDCPtr( hdc );
    if (!dc) return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1174 1175

    dc->hookProc = hookProc;
1176
    GDI_ReleaseObj( hdc );
1177
    return SetDCHook( hdc, call_dc_hook16, dwHookData );
Alexandre Julliard's avatar
Alexandre Julliard committed
1178 1179 1180 1181 1182 1183
}


/***********************************************************************
 *           GetDCHook   (GDI.191)
 */
1184
DWORD WINAPI GetDCHook16( HDC16 hdc16, FARPROC16 *phookProc )
Alexandre Julliard's avatar
Alexandre Julliard committed
1185
{
1186
    HDC hdc = HDC_32( hdc16 );
1187
    DC *dc = DC_GetDCPtr( hdc );
1188 1189
    DWORD ret;

Alexandre Julliard's avatar
Alexandre Julliard committed
1190 1191
    if (!dc) return 0;
    *phookProc = dc->hookProc;
1192
    ret = dc->dwHookData;
1193
    GDI_ReleaseObj( hdc );
1194
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
1195 1196 1197 1198
}


/***********************************************************************
1199
 *           SetHookFlags   (GDI.192)
Alexandre Julliard's avatar
Alexandre Julliard committed
1200
 */
1201
WORD WINAPI SetHookFlags16(HDC16 hdc16, WORD flags)
Alexandre Julliard's avatar
Alexandre Julliard committed
1202
{
1203 1204
    HDC hdc = HDC_32( hdc16 );
    DC *dc = DC_GetDCPtr( hdc );
Alexandre Julliard's avatar
Alexandre Julliard committed
1205

Alexandre Julliard's avatar
Alexandre Julliard committed
1206
    if( dc )
Alexandre Julliard's avatar
Alexandre Julliard committed
1207
    {
1208
        WORD wRet = dc->flags & DC_DIRTY;
Alexandre Julliard's avatar
Alexandre Julliard committed
1209

Alexandre Julliard's avatar
Alexandre Julliard committed
1210
        /* "Undocumented Windows" info is slightly confusing.
Alexandre Julliard's avatar
Alexandre Julliard committed
1211 1212
         */

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

        if( flags & DCHF_INVALIDATEVISRGN )
1216
            dc->flags |= DC_DIRTY;
Alexandre Julliard's avatar
Alexandre Julliard committed
1217
        else if( flags & DCHF_VALIDATEVISRGN || !flags )
1218
            dc->flags &= ~DC_DIRTY;
1219
        GDI_ReleaseObj( hdc );
Alexandre Julliard's avatar
Alexandre Julliard committed
1220 1221
        return wRet;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1222
    return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1223 1224
}

Alexandre Julliard's avatar
Alexandre Julliard committed
1225
/***********************************************************************
1226
 *           SetICMMode    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
1227
 */
1228
INT WINAPI SetICMMode(HDC hdc, INT iEnableICM)
Alexandre Julliard's avatar
Alexandre Julliard committed
1229 1230 1231 1232 1233 1234 1235 1236
{
/*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;
}

1237
/***********************************************************************
1238
 *           GetDeviceGammaRamp    (GDI32.@)
1239
 */
1240 1241 1242 1243 1244 1245 1246 1247
BOOL WINAPI GetDeviceGammaRamp(HDC hDC, LPVOID ptr)
{
    BOOL ret = FALSE;
    DC *dc = DC_GetDCPtr( hDC );

    if( dc )
    {
	if (dc->funcs->pGetDeviceGammaRamp)
1248
	    ret = dc->funcs->pGetDeviceGammaRamp(dc->physDev, ptr);
1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264
	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)
1265
	    ret = dc->funcs->pSetDeviceGammaRamp(dc->physDev, ptr);
1266 1267 1268
	GDI_ReleaseObj( hDC );
    }
    return ret;
1269
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1270 1271

/***********************************************************************
1272
 *           GetColorSpace    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
1273
 */
1274
HCOLORSPACE WINAPI GetColorSpace(HDC hdc)
Alexandre Julliard's avatar
Alexandre Julliard committed
1275 1276 1277 1278
{
/*FIXME    Need to to whatever GetColorSpace actually does */
    return 0;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1279

1280
/***********************************************************************
1281
 *           CreateColorSpaceA    (GDI32.@)
1282 1283 1284 1285
 */
HCOLORSPACE WINAPI CreateColorSpaceA( LPLOGCOLORSPACEA lpLogColorSpace )
{
  FIXME( "stub\n" );
1286
  return 0;
1287 1288 1289
}

/***********************************************************************
1290
 *           CreateColorSpaceW    (GDI32.@)
1291 1292 1293 1294 1295 1296 1297 1298
 */
HCOLORSPACE WINAPI CreateColorSpaceW( LPLOGCOLORSPACEW lpLogColorSpace )
{
  FIXME( "stub\n" );
  return 0;
}

/***********************************************************************
1299
 *           DeleteColorSpace     (GDI32.@)
1300 1301 1302 1303
 */
BOOL WINAPI DeleteColorSpace( HCOLORSPACE hColorSpace )
{
  FIXME( "stub\n" );
1304

1305
  return TRUE;
1306 1307 1308
}

/***********************************************************************
1309
 *           SetColorSpace     (GDI32.@)
1310 1311 1312 1313 1314 1315 1316 1317
 */
HCOLORSPACE WINAPI SetColorSpace( HDC hDC, HCOLORSPACE hColorSpace )
{
  FIXME( "stub\n" );

  return hColorSpace;
}

Alexandre Julliard's avatar
Alexandre Julliard committed
1318
/***********************************************************************
1319
 *           GetBoundsRect    (GDI.194)
Alexandre Julliard's avatar
Alexandre Julliard committed
1320 1321 1322
 */
UINT16 WINAPI GetBoundsRect16(HDC16 hdc, LPRECT16 rect, UINT16 flags)
{
1323
    return DCB_RESET | DCB_DISABLE; /* bounding rectangle always empty and disabled*/
Alexandre Julliard's avatar
Alexandre Julliard committed
1324 1325
}

1326
/***********************************************************************
1327
 *           GetBoundsRect    (GDI32.@)
1328
 */
1329
UINT WINAPI GetBoundsRect(HDC hdc, LPRECT rect, UINT flags)
1330
{
1331
    FIXME("(): stub\n");
1332 1333
    return DCB_RESET;   /* bounding rectangle always empty */
}
1334

1335
/***********************************************************************
1336
 *           SetBoundsRect    (GDI.193)
1337
 */
1338
UINT16 WINAPI SetBoundsRect16(HDC16 hdc, const RECT16* rect, UINT16 flags)
1339
{
1340
    if ( (flags & DCB_ACCUMULATE) || (flags & DCB_ENABLE) )
1341
        FIXME("(%04x, %p, %04x): stub\n", hdc, rect, flags );
1342 1343

    return DCB_RESET | DCB_DISABLE; /* bounding rectangle always empty and disabled*/
1344 1345
}

1346
/***********************************************************************
1347
 *           SetBoundsRect    (GDI32.@)
1348
 */
1349
UINT WINAPI SetBoundsRect(HDC hdc, const RECT* rect, UINT flags)
1350
{
1351
    FIXME("(): stub\n");
1352 1353 1354
    return DCB_DISABLE;   /* bounding rectangle always empty */
}

1355 1356

/***********************************************************************
1357
 *		GetRelAbs		(GDI32.@)
1358 1359 1360
 */
INT WINAPI GetRelAbs( HDC hdc, DWORD dwIgnore )
{
1361 1362 1363 1364 1365
    INT ret = 0;
    DC *dc = DC_GetDCPtr( hdc );
    if (dc) ret = dc->relAbsMode;
    GDI_ReleaseObj( hdc );
    return ret;
1366 1367
}

1368
/***********************************************************************
1369
 *           GetLayout    (GDI32.@)
1370 1371 1372 1373 1374 1375 1376
 *
 * Gets left->right or right->left text layout flags of a dc.
 * win98 just returns 0 and sets ERROR_CALL_NOT_IMPLEMENTED so we do the same
 *
 */
DWORD WINAPI GetLayout(HDC hdc)
{
1377
    FIXME("(%p): stub\n", hdc);
1378 1379 1380 1381 1382
    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
    return 0;
}

/***********************************************************************
1383
 *           SetLayout    (GDI32.@)
1384 1385 1386 1387 1388 1389 1390
 *
 * Sets left->right or right->left text layout flags of a dc.
 * win98 just returns 0 and sets ERROR_CALL_NOT_IMPLEMENTED so we do the same
 *
 */
DWORD WINAPI SetLayout(HDC hdc, DWORD layout)
{
1391
    FIXME("(%p,%08lx): stub\n", hdc, layout);
1392 1393 1394
    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
    return 0;
}
1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405

/***********************************************************************
 *           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)
{
1406
    FIXME("(%p, %08lx): stub\n", hdc, crColor);
1407 1408 1409
    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
    return CLR_INVALID;
}