xref: /reactos/win32ss/gdi/ntgdi/dclife.c (revision c8d07514)
1 /*
2  * COPYRIGHT:         See COPYING in the top level directory
3  * PROJECT:           ReactOS kernel
4  * PURPOSE:           Functions for creation and destruction of DCs
5  * FILE:              win32ss/gdi/ntgdi/dclife.c
6  * PROGRAMER:         Timo Kreuzer (timo.kreuzer@rectos.org)
7  */
8 
9 #include <win32k.h>
10 
11 #define NDEBUG
12 #include <debug.h>
13 
14 // FIXME: Windows uses 0x0012009f
15 #define DIRTY_DEFAULT DIRTY_CHARSET|DIRTY_BACKGROUND|DIRTY_TEXT|DIRTY_LINE|DIRTY_FILL
16 
17 PSURFACE psurfDefaultBitmap = NULL;
18 PBRUSH pbrDefaultBrush = NULL;
19 
20 const MATRIX gmxWorldToDeviceDefault =
21 {
22     FLOATOBJ_16, FLOATOBJ_0,
23     FLOATOBJ_0, FLOATOBJ_16,
24     FLOATOBJ_0, FLOATOBJ_0,
25     0, 0, 0x4b
26 };
27 
28 const MATRIX gmxDeviceToWorldDefault =
29 {
30     FLOATOBJ_1_16, FLOATOBJ_0,
31     FLOATOBJ_0, FLOATOBJ_1_16,
32     FLOATOBJ_0, FLOATOBJ_0,
33     0, 0, 0x53
34 };
35 
36 const MATRIX gmxWorldToPageDefault =
37 {
38     FLOATOBJ_1, FLOATOBJ_0,
39     FLOATOBJ_0, FLOATOBJ_1,
40     FLOATOBJ_0, FLOATOBJ_0,
41     0, 0, 0x63
42 };
43 
44 // HACK!! Fix XFORMOBJ then use 1:16 / 16:1
45 #define gmxWorldToDeviceDefault gmxWorldToPageDefault
46 #define gmxDeviceToWorldDefault gmxWorldToPageDefault
47 
48 /** Internal functions ********************************************************/
49 
50 CODE_SEG("INIT")
51 NTSTATUS
52 NTAPI
53 InitDcImpl(VOID)
54 {
55     psurfDefaultBitmap = SURFACE_ShareLockSurface(StockObjects[DEFAULT_BITMAP]);
56     if (!psurfDefaultBitmap)
57         return STATUS_UNSUCCESSFUL;
58 
59     pbrDefaultBrush = BRUSH_ShareLockBrush(StockObjects[BLACK_BRUSH]);
60     if (!pbrDefaultBrush)
61         return STATUS_UNSUCCESSFUL;
62 
63     return STATUS_SUCCESS;
64 }
65 
66 
67 PDC
68 NTAPI
69 DC_AllocDcWithHandle(GDILOOBJTYPE eDcObjType)
70 {
71     PDC pdc;
72 
73     NT_ASSERT((eDcObjType == GDILoObjType_LO_DC_TYPE) ||
74               (eDcObjType == GDILoObjType_LO_ALTDC_TYPE));
75 
76     /* Allocate the object */
77     pdc = (PDC)GDIOBJ_AllocateObject(GDIObjType_DC_TYPE,
78                                      sizeof(DC),
79                                      BASEFLAG_LOOKASIDE);
80     if (!pdc)
81     {
82         DPRINT1("Could not allocate a DC.\n");
83         return NULL;
84     }
85 
86     /* Set the actual DC type */
87     pdc->BaseObject.hHmgr = UlongToHandle(eDcObjType);
88 
89     pdc->pdcattr = &pdc->dcattr;
90 
91     /* Insert the object */
92     if (!GDIOBJ_hInsertObject(&pdc->BaseObject, GDI_OBJ_HMGR_POWNED))
93     {
94         DPRINT1("Could not insert DC into handle table.\n");
95         GDIOBJ_vFreeObject(&pdc->BaseObject);
96         return NULL;
97     }
98 
99     return pdc;
100 }
101 
102 
103 void
104 DC_InitHack(PDC pdc)
105 {
106     if (defaultDCstate == NULL)
107     {
108         defaultDCstate = ExAllocatePoolWithTag(PagedPool, sizeof(DC), TAG_DC);
109         ASSERT(defaultDCstate);
110         RtlZeroMemory(defaultDCstate, sizeof(DC));
111         defaultDCstate->pdcattr = &defaultDCstate->dcattr;
112         DC_vCopyState(pdc, defaultDCstate, TRUE);
113     }
114 
115     if (prgnDefault == NULL)
116     {
117         prgnDefault = IntSysCreateRectpRgn(0, 0, 0, 0);
118     }
119 
120     TextIntRealizeFont(pdc->pdcattr->hlfntNew,NULL);
121     pdc->pdcattr->iCS_CP = ftGdiGetTextCharsetInfo(pdc,NULL,0);
122 
123     /* This should never fail */
124     ASSERT(pdc->dclevel.ppal);
125 }
126 
127 VOID
128 NTAPI
129 DC_vInitDc(
130     PDC pdc,
131     DCTYPE dctype,
132     PPDEVOBJ ppdev)
133 {
134     /* Setup some basic fields */
135     pdc->dctype = dctype;
136     pdc->ppdev = ppdev;
137     pdc->dhpdev = ppdev->dhpdev;
138     pdc->hsem = ppdev->hsemDevLock;
139     pdc->flGraphicsCaps = ppdev->devinfo.flGraphicsCaps;
140     pdc->flGraphicsCaps2 = ppdev->devinfo.flGraphicsCaps2;
141     pdc->fs = DC_DIRTY_RAO;
142 
143     /* Setup dc attribute */
144     pdc->pdcattr = &pdc->dcattr;
145     pdc->dcattr.pvLDC = NULL;
146     pdc->dcattr.ulDirty_ = DIRTY_DEFAULT;
147     if (ppdev == gppdevPrimary)
148         pdc->dcattr.ulDirty_ |= DC_PRIMARY_DISPLAY;
149 
150     /* Setup the DC size */
151     if (dctype == DCTYPE_MEMORY)
152     {
153         /* Memory DCs have a 1 x 1 bitmap by default */
154         pdc->dclevel.sizl.cx = 1;
155         pdc->dclevel.sizl.cy = 1;
156     }
157     else
158     {
159         /* Other DC's are as big as the related PDEV */
160 	    pdc->dclevel.sizl.cx = ppdev->gdiinfo.ulHorzRes;
161 	    pdc->dclevel.sizl.cy = ppdev->gdiinfo.ulVertRes;
162     }
163 
164     /* Setup Window rect based on DC size */
165     pdc->erclWindow.left = 0;
166     pdc->erclWindow.top = 0;
167     pdc->erclWindow.right = pdc->dclevel.sizl.cx;
168     pdc->erclWindow.bottom = pdc->dclevel.sizl.cy;
169 
170     if (dctype == DCTYPE_DIRECT)
171     {
172         /* Direct DCs get the surface from the PDEV */
173         pdc->dclevel.pSurface = PDEVOBJ_pSurface(ppdev);
174 
175         pdc->erclBounds.left = 0x7fffffff;
176         pdc->erclBounds.top = 0x7fffffff;
177         pdc->erclBounds.right = 0x80000000;
178         pdc->erclBounds.bottom = 0x80000000;
179         pdc->erclBoundsApp.left = 0xffffffff;
180         pdc->erclBoundsApp.top = 0xfffffffc;
181         pdc->erclBoundsApp.right = 0x00007ffc; // FIXME
182         pdc->erclBoundsApp.bottom = 0x00000333; // FIXME
183         pdc->erclClip = pdc->erclBounds;
184         pdc->co = gxcoTrivial;
185     }
186     else
187     {
188         /* Non-direct DCs don't have a surface by default */
189         pdc->dclevel.pSurface = NULL;
190 
191         pdc->erclBounds.left = 0;
192         pdc->erclBounds.top = 0;
193         pdc->erclBounds.right = 0;
194         pdc->erclBounds.bottom = 0;
195         pdc->erclBoundsApp = pdc->erclBounds;
196         pdc->erclClip = pdc->erclWindow;
197         pdc->co = gxcoTrivial;
198     }
199 
200       //pdc->dcattr.VisRectRegion:
201 
202     /* Setup coordinate transformation data */
203 	pdc->dclevel.mxWorldToDevice = gmxWorldToDeviceDefault;
204 	pdc->dclevel.mxDeviceToWorld = gmxDeviceToWorldDefault;
205 	pdc->dclevel.mxWorldToPage = gmxWorldToPageDefault;
206 	pdc->dclevel.efM11PtoD = gef16;
207 	pdc->dclevel.efM22PtoD = gef16;
208 	pdc->dclevel.efDxPtoD = gef0;
209 	pdc->dclevel.efDyPtoD = gef0;
210 	pdc->dclevel.efM11_TWIPS = gef0;
211 	pdc->dclevel.efM22_TWIPS = gef0;
212 	pdc->dclevel.efPr11 = gef0;
213 	pdc->dclevel.efPr22 = gef0;
214 	pdc->dcattr.mxWorldToDevice = pdc->dclevel.mxWorldToDevice;
215 	pdc->dcattr.mxDeviceToWorld = pdc->dclevel.mxDeviceToWorld;
216 	pdc->dcattr.mxWorldToPage = pdc->dclevel.mxWorldToPage;
217 	pdc->dcattr.efM11PtoD = pdc->dclevel.efM11PtoD;
218 	pdc->dcattr.efM22PtoD = pdc->dclevel.efM22PtoD;
219 	pdc->dcattr.efDxPtoD = pdc->dclevel.efDxPtoD;
220 	pdc->dcattr.efDyPtoD = pdc->dclevel.efDyPtoD;
221 	pdc->dcattr.iMapMode = MM_TEXT;
222 	pdc->dcattr.dwLayout = 0;
223 	pdc->dcattr.flXform = PAGE_TO_DEVICE_SCALE_IDENTITY |
224 	                      PAGE_TO_DEVICE_IDENTITY |
225 	                      WORLD_TO_PAGE_IDENTITY;
226 
227     /* Setup more coordinates */
228     pdc->ptlDCOrig.x = 0;
229     pdc->ptlDCOrig.y = 0;
230 	pdc->dcattr.lWindowOrgx = 0;
231 	pdc->dcattr.ptlWindowOrg.x = 0;
232 	pdc->dcattr.ptlWindowOrg.y = 0;
233 	pdc->dcattr.szlWindowExt.cx = 1;
234 	pdc->dcattr.szlWindowExt.cy = 1;
235 	pdc->dcattr.ptlViewportOrg.x = 0;
236 	pdc->dcattr.ptlViewportOrg.y = 0;
237 	pdc->dcattr.szlViewportExt.cx = 1;
238 	pdc->dcattr.szlViewportExt.cy = 1;
239     pdc->dcattr.szlVirtualDevicePixel.cx = ppdev->gdiinfo.ulHorzRes;
240     pdc->dcattr.szlVirtualDevicePixel.cy = ppdev->gdiinfo.ulVertRes;
241     pdc->dcattr.szlVirtualDeviceMm.cx = ppdev->gdiinfo.ulHorzSize;
242     pdc->dcattr.szlVirtualDeviceMm.cy = ppdev->gdiinfo.ulVertSize;
243     pdc->dcattr.szlVirtualDeviceSize.cx = 0;
244     pdc->dcattr.szlVirtualDeviceSize.cy = 0;
245 
246     /* Setup regions */
247     pdc->prgnAPI = NULL;
248 	pdc->prgnRao = NULL;
249 	pdc->dclevel.prgnClip = NULL;
250 	pdc->dclevel.prgnMeta = NULL;
251     /* Allocate a Vis region */
252     pdc->prgnVis = IntSysCreateRectpRgn(0, 0, pdc->dclevel.sizl.cx, pdc->dclevel.sizl.cy);
253 	ASSERT(pdc->prgnVis);
254 
255     /* Setup Vis Region Attribute information */
256     UpdateVisRgn(pdc);
257 
258 	/* Initialize Clip object */
259 	IntEngInitClipObj(&pdc->co);
260 
261     /* Setup palette */
262     pdc->dclevel.hpal = StockObjects[DEFAULT_PALETTE];
263     pdc->dclevel.ppal = PALETTE_ShareLockPalette(pdc->dclevel.hpal);
264 
265     /* Setup path */
266 	pdc->dclevel.hPath = NULL;
267     pdc->dclevel.flPath = 0;
268 //	pdc->dclevel.lapath:
269 
270     /* Setup colors */
271 	pdc->dcattr.crBackgroundClr = RGB(0xff, 0xff, 0xff);
272 	pdc->dcattr.ulBackgroundClr = RGB(0xff, 0xff, 0xff);
273 	pdc->dcattr.crForegroundClr = RGB(0, 0, 0);
274 	pdc->dcattr.ulForegroundClr = RGB(0, 0, 0);
275 	pdc->dcattr.crBrushClr = RGB(0xff, 0xff, 0xff);
276 	pdc->dcattr.ulBrushClr = RGB(0xff, 0xff, 0xff);
277 	pdc->dcattr.crPenClr = RGB(0, 0, 0);
278 	pdc->dcattr.ulPenClr = RGB(0, 0, 0);
279 
280     /* Select the default fill and line brush */
281 	pdc->dcattr.hbrush = StockObjects[WHITE_BRUSH];
282 	pdc->dcattr.hpen = StockObjects[BLACK_PEN];
283     pdc->dclevel.pbrFill = BRUSH_ShareLockBrush(pdc->pdcattr->hbrush);
284     pdc->dclevel.pbrLine = PEN_ShareLockPen(pdc->pdcattr->hpen);
285 	pdc->dclevel.ptlBrushOrigin.x = 0;
286 	pdc->dclevel.ptlBrushOrigin.y = 0;
287 	pdc->dcattr.ptlBrushOrigin = pdc->dclevel.ptlBrushOrigin;
288 
289     /* Initialize EBRUSHOBJs */
290     EBRUSHOBJ_vInitFromDC(&pdc->eboFill, pdc->dclevel.pbrFill, pdc);
291     EBRUSHOBJ_vInitFromDC(&pdc->eboLine, pdc->dclevel.pbrLine, pdc);
292     EBRUSHOBJ_vInitFromDC(&pdc->eboText, pbrDefaultBrush, pdc);
293     EBRUSHOBJ_vInitFromDC(&pdc->eboBackground, pbrDefaultBrush, pdc);
294 
295     /* Setup fill data */
296 	pdc->dcattr.jROP2 = R2_COPYPEN;
297 	pdc->dcattr.jBkMode = 2;
298 	pdc->dcattr.lBkMode = 2;
299 	pdc->dcattr.jFillMode = ALTERNATE;
300 	pdc->dcattr.lFillMode = 1;
301 	pdc->dcattr.jStretchBltMode = 1;
302 	pdc->dcattr.lStretchBltMode = 1;
303     pdc->ptlFillOrigin.x = 0;
304     pdc->ptlFillOrigin.y = 0;
305 
306     /* Setup drawing position */
307 	pdc->dcattr.ptlCurrent.x = 0;
308 	pdc->dcattr.ptlCurrent.y = 0;
309 	pdc->dcattr.ptfxCurrent.x = 0;
310 	pdc->dcattr.ptfxCurrent.y = 0;
311 
312 	/* Setup ICM data */
313 	pdc->dclevel.lIcmMode = 0;
314 	pdc->dcattr.lIcmMode = 0;
315 	pdc->dcattr.hcmXform = NULL;
316 	pdc->dcattr.flIcmFlags = 0;
317 	pdc->dcattr.IcmBrushColor = CLR_INVALID;
318 	pdc->dcattr.IcmPenColor = CLR_INVALID;
319 	pdc->dcattr.pvLIcm = NULL;
320     pdc->dcattr.hColorSpace = NULL; // FIXME: 0189001f
321 	pdc->dclevel.pColorSpace = NULL; // FIXME
322     pdc->pClrxFormLnk = NULL;
323 //	pdc->dclevel.ca =
324 
325 	/* Setup font data */
326     pdc->hlfntCur = NULL; // FIXME: 2f0a0cf8
327     pdc->pPFFList = NULL;
328     pdc->flSimulationFlags = 0;
329     pdc->lEscapement = 0;
330     pdc->prfnt = NULL;
331 	pdc->dcattr.flFontMapper = 0;
332 	pdc->dcattr.flTextAlign = 0;
333 	pdc->dcattr.lTextAlign = 0;
334 	pdc->dcattr.lTextExtra = 0;
335 	pdc->dcattr.lRelAbs = 1;
336 	pdc->dcattr.lBreakExtra = 0;
337 	pdc->dcattr.cBreak = 0;
338     pdc->dcattr.hlfntNew = StockObjects[SYSTEM_FONT];
339     pdc->dclevel.plfnt = LFONT_ShareLockFont(pdc->dcattr.hlfntNew);
340 
341     /* Other stuff */
342     pdc->hdcNext = NULL;
343     pdc->hdcPrev = NULL;
344     pdc->ipfdDevMax = 0;
345     pdc->ulCopyCount = -1;
346     pdc->ptlDoBanding.x = 0;
347     pdc->ptlDoBanding.y = 0;
348 	pdc->dclevel.lSaveDepth = 1;
349 	pdc->dclevel.hdcSave = NULL;
350 	pdc->dcattr.iGraphicsMode = GM_COMPATIBLE;
351 	pdc->dcattr.iCS_CP = 0;
352     pdc->pSurfInfo = NULL;
353 }
354 
355 VOID
356 NTAPI
357 DC_vCleanup(PVOID ObjectBody)
358 {
359     PDC pdc = (PDC)ObjectBody;
360 
361     /* Free DC_ATTR */
362     DC_vFreeDcAttr(pdc);
363 
364     /* Delete saved DCs */
365     DC_vRestoreDC(pdc, 1);
366 
367     /* Deselect dc objects */
368     DC_vSelectSurface(pdc, NULL);
369     DC_vSelectFillBrush(pdc, NULL);
370     DC_vSelectLineBrush(pdc, NULL);
371     DC_vSelectPalette(pdc, NULL);
372 
373     /* Cleanup the dc brushes */
374     EBRUSHOBJ_vCleanup(&pdc->eboFill);
375     EBRUSHOBJ_vCleanup(&pdc->eboLine);
376     EBRUSHOBJ_vCleanup(&pdc->eboText);
377     EBRUSHOBJ_vCleanup(&pdc->eboBackground);
378 
379     /* Release font */
380     if (pdc->dclevel.plfnt)
381         LFONT_ShareUnlockFont(pdc->dclevel.plfnt);
382 
383     /*  Free regions */
384     if (pdc->dclevel.prgnClip)
385         REGION_Delete(pdc->dclevel.prgnClip);
386     if (pdc->dclevel.prgnMeta)
387         REGION_Delete(pdc->dclevel.prgnMeta);
388     if (pdc->prgnVis)
389         REGION_Delete(pdc->prgnVis);
390     if (pdc->prgnRao)
391         REGION_Delete(pdc->prgnRao);
392     if (pdc->prgnAPI)
393         REGION_Delete(pdc->prgnAPI);
394 
395     /* Free CLIPOBJ resources */
396     IntEngFreeClipResources(&pdc->co);
397 
398     if (pdc->dclevel.hPath)
399     {
400        DPRINT("DC_vCleanup Path\n");
401        PATH_Delete(pdc->dclevel.hPath);
402        pdc->dclevel.hPath = 0;
403        pdc->dclevel.flPath = 0;
404     }
405     if (pdc->dclevel.pSurface)
406         SURFACE_ShareUnlockSurface(pdc->dclevel.pSurface);
407 
408     if (pdc->ppdev)
409         PDEVOBJ_vRelease(pdc->ppdev);
410 }
411 
412 VOID
413 NTAPI
414 DC_vSetOwner(PDC pdc, ULONG ulOwner)
415 {
416     /* Delete saved DCs */
417     DC_vRestoreDC(pdc, 1);
418 
419     if (pdc->dclevel.hPath)
420     {
421         GreSetObjectOwner(pdc->dclevel.hPath, ulOwner);
422     }
423 
424     /* Dereference current brush and pen */
425     BRUSH_ShareUnlockBrush(pdc->dclevel.pbrFill);
426     BRUSH_ShareUnlockBrush(pdc->dclevel.pbrLine);
427 
428     /* Select the default fill and line brush */
429     pdc->dcattr.hbrush = StockObjects[WHITE_BRUSH];
430     pdc->dcattr.hpen = StockObjects[BLACK_PEN];
431     pdc->dclevel.pbrFill = BRUSH_ShareLockBrush(pdc->pdcattr->hbrush);
432     pdc->dclevel.pbrLine = PEN_ShareLockPen(pdc->pdcattr->hpen);
433 
434     /* Mark them as dirty */
435     pdc->pdcattr->ulDirty_ |= DIRTY_FILL|DIRTY_LINE;
436 
437     /* Allocate or free DC attribute */
438     if (ulOwner == GDI_OBJ_HMGR_PUBLIC || ulOwner == GDI_OBJ_HMGR_NONE)
439     {
440         if (pdc->pdcattr != &pdc->dcattr)
441             DC_vFreeDcAttr(pdc);
442     }
443     else if (ulOwner == GDI_OBJ_HMGR_POWNED)
444     {
445         if (pdc->pdcattr == &pdc->dcattr)
446             DC_bAllocDcAttr(pdc);
447     }
448 
449     /* Set the DC's ownership */
450     GDIOBJ_vSetObjectOwner(&pdc->BaseObject, ulOwner);
451 }
452 
453 BOOL
454 NTAPI
455 GreSetDCOwner(HDC hdc, ULONG ulOwner)
456 {
457     PDC pdc;
458 
459     pdc = DC_LockDc(hdc);
460     if (!pdc)
461     {
462         DPRINT1("GreSetDCOwner: Could not lock DC\n");
463         return FALSE;
464     }
465 
466     /* Call the internal DC function */
467     DC_vSetOwner(pdc, ulOwner);
468 
469     DC_UnlockDc(pdc);
470     return TRUE;
471 }
472 
473 static
474 void
475 DC_vUpdateDC(PDC pdc)
476 {
477     // PREGION VisRgn ;
478     PPDEVOBJ ppdev = pdc->ppdev;
479 
480     pdc->dhpdev = ppdev->dhpdev;
481 
482     SURFACE_ShareUnlockSurface(pdc->dclevel.pSurface);
483     pdc->dclevel.pSurface = PDEVOBJ_pSurface(ppdev);
484 
485     PDEVOBJ_sizl(pdc->ppdev, &pdc->dclevel.sizl);
486 #if 0
487     VisRgn = IntSysCreateRectpRgn(0, 0, pdc->dclevel.sizl.cx, pdc->dclevel.sizl.cy);
488     ASSERT(VisRgn);
489     GdiSelectVisRgn(pdc->BaseObject.hHmgr, VisRgn);
490     REGION_Delete(VisRgn);
491 #endif
492 
493     pdc->flGraphicsCaps = ppdev->devinfo.flGraphicsCaps;
494     pdc->flGraphicsCaps2 = ppdev->devinfo.flGraphicsCaps2;
495 
496     /* Mark EBRUSHOBJs as dirty */
497     pdc->pdcattr->ulDirty_ |= DIRTY_DEFAULT ;
498 }
499 
500 /* Prepare a blit for up to 2 DCs */
501 /* rc1 and rc2 are the rectangles where we want to draw or
502  * from where we take pixels. */
503 VOID
504 FASTCALL
505 DC_vPrepareDCsForBlit(
506     PDC pdcDest,
507     const RECT* rcDest,
508     PDC pdcSrc,
509     const RECT* rcSrc)
510 {
511     PDC pdcFirst, pdcSecond;
512     const RECT *prcFirst, *prcSecond;
513 
514     /* Update brushes */
515     if (pdcDest->pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
516         DC_vUpdateFillBrush(pdcDest);
517     if (pdcDest->pdcattr->ulDirty_ & (DIRTY_LINE | DC_PEN_DIRTY))
518         DC_vUpdateLineBrush(pdcDest);
519     if(pdcDest->pdcattr->ulDirty_ & DIRTY_TEXT)
520         DC_vUpdateTextBrush(pdcDest);
521 
522     /* Lock them in good order */
523     if (pdcSrc)
524     {
525         if((ULONG_PTR)pdcDest->ppdev->hsemDevLock >=
526            (ULONG_PTR)pdcSrc->ppdev->hsemDevLock)
527         {
528             pdcFirst = pdcDest;
529             prcFirst = rcDest;
530             pdcSecond = pdcSrc;
531             prcSecond = rcSrc;
532         }
533         else
534         {
535             pdcFirst = pdcSrc;
536             prcFirst = rcSrc;
537             pdcSecond = pdcDest;
538             prcSecond = rcDest;
539         }
540     }
541     else
542     {
543         pdcFirst = pdcDest;
544         prcFirst = rcDest;
545         pdcSecond = NULL;
546         prcSecond = NULL;
547     }
548 
549     if (pdcDest->fs & DC_FLAG_DIRTY_RAO)
550         CLIPPING_UpdateGCRegion(pdcDest);
551 
552     /* Lock and update first DC */
553     if (pdcFirst->dctype == DCTYPE_DIRECT)
554     {
555         EngAcquireSemaphore(pdcFirst->ppdev->hsemDevLock);
556 
557         /* Update surface if needed */
558         if (pdcFirst->ppdev->pSurface != pdcFirst->dclevel.pSurface)
559         {
560             DC_vUpdateDC(pdcFirst);
561         }
562     }
563 
564     if (pdcFirst->dctype == DCTYPE_DIRECT)
565     {
566         if (!prcFirst)
567             prcFirst = &pdcFirst->erclClip;
568 
569         MouseSafetyOnDrawStart(pdcFirst->ppdev,
570                                prcFirst->left,
571                                prcFirst->top,
572                                prcFirst->right,
573                                prcFirst->bottom) ;
574     }
575 
576 #if DBG
577     pdcFirst->fs |= DC_PREPARED;
578 #endif
579 
580     if (!pdcSecond)
581         return;
582 
583     /* Lock and update second DC */
584     if (pdcSecond->dctype == DCTYPE_DIRECT)
585     {
586         EngAcquireSemaphore(pdcSecond->ppdev->hsemDevLock);
587 
588         /* Update surface if needed */
589         if (pdcSecond->ppdev->pSurface != pdcSecond->dclevel.pSurface)
590         {
591             DC_vUpdateDC(pdcSecond);
592         }
593     }
594 
595     if (pdcSecond->dctype == DCTYPE_DIRECT)
596     {
597         if (!prcSecond)
598             prcSecond = &pdcSecond->erclClip;
599         MouseSafetyOnDrawStart(pdcSecond->ppdev,
600                                prcSecond->left,
601                                prcSecond->top,
602                                prcSecond->right,
603                                prcSecond->bottom) ;
604     }
605 
606 #if DBG
607     pdcSecond->fs |= DC_PREPARED;
608 #endif
609 }
610 
611 /* Finishes a blit for one or two DCs */
612 VOID
613 FASTCALL
614 DC_vFinishBlit(PDC pdc1, PDC pdc2)
615 {
616     if (pdc1->dctype == DCTYPE_DIRECT)
617     {
618         MouseSafetyOnDrawEnd(pdc1->ppdev);
619         EngReleaseSemaphore(pdc1->ppdev->hsemDevLock);
620     }
621 #if DBG
622     pdc1->fs &= ~DC_PREPARED;
623 #endif
624 
625     if (pdc2)
626     {
627         if (pdc2->dctype == DCTYPE_DIRECT)
628         {
629             MouseSafetyOnDrawEnd(pdc2->ppdev);
630             EngReleaseSemaphore(pdc2->ppdev->hsemDevLock);
631         }
632 #if DBG
633         pdc2->fs &= ~DC_PREPARED;
634 #endif
635     }
636 }
637 
638 HDC
639 NTAPI
640 GreOpenDCW(
641     PUNICODE_STRING pustrDevice,
642     DEVMODEW *pdmInit,
643     PUNICODE_STRING pustrLogAddr,
644     ULONG iType,
645     BOOL bDisplay,
646     HANDLE hspool,
647     VOID *pDriverInfo2,
648     PVOID *pUMdhpdev)
649 {
650     PPDEVOBJ ppdev;
651     PDC pdc;
652     HDC hdc;
653 
654     DPRINT("GreOpenDCW(%S, iType=%lu)\n",
655            pustrDevice ? pustrDevice->Buffer : NULL, iType);
656 
657     /* Get a PDEVOBJ for the device */
658     ppdev = EngpGetPDEV(pustrDevice);
659     if (!ppdev)
660     {
661         DPRINT1("Didn't find a suitable PDEV\n");
662         return NULL;
663     }
664 
665     DPRINT("GreOpenDCW - ppdev = %p\n", ppdev);
666 
667     pdc = DC_AllocDcWithHandle(GDILoObjType_LO_DC_TYPE);
668     if (!pdc)
669     {
670         DPRINT1("Could not Allocate a DC\n");
671         PDEVOBJ_vRelease(ppdev);
672         return NULL;
673     }
674     hdc = pdc->BaseObject.hHmgr;
675 
676     /* Lock ppdev and initialize the new DC */
677     DC_vInitDc(pdc, iType, ppdev);
678     if (pUMdhpdev) *pUMdhpdev = ppdev->dhpdev;
679     /* FIXME: HACK! */
680     DC_InitHack(pdc);
681 
682     DC_bAllocDcAttr(pdc);
683 
684     DC_UnlockDc(pdc);
685 
686     DPRINT("Returning hdc = %p\n", hdc);
687 
688     return hdc;
689 }
690 
691 __kernel_entry
692 HDC
693 APIENTRY
694 NtGdiOpenDCW(
695     _In_opt_ PUNICODE_STRING pustrDevice,
696     _In_ DEVMODEW *pdmInit,
697     _In_ PUNICODE_STRING pustrLogAddr,
698     _In_ ULONG iType,
699     _In_ BOOL bDisplay,
700     _In_opt_ HANDLE hspool,
701     /*_In_opt_ DRIVER_INFO2W *pdDriverInfo2, Need this soon!!!! */
702     _At_((PUMDHPDEV*)pUMdhpdev, _Out_) PVOID pUMdhpdev)
703 {
704     UNICODE_STRING ustrDevice;
705     WCHAR awcDevice[CCHDEVICENAME];
706     PVOID dhpdev;
707     HDC hdc;
708     WORD dmSize, dmDriverExtra;
709     DWORD Size;
710     DEVMODEW * _SEH2_VOLATILE pdmAllocated = NULL;
711 
712     /* Only if a devicename is given, we need any data */
713     if (pustrDevice)
714     {
715         /* Initialize destination string */
716         RtlInitEmptyUnicodeString(&ustrDevice, awcDevice, sizeof(awcDevice));
717 
718         _SEH2_TRY
719         {
720             /* Probe the UNICODE_STRING and the buffer */
721             ProbeForRead(pustrDevice, sizeof(UNICODE_STRING), 1);
722             ProbeForRead(pustrDevice->Buffer, pustrDevice->Length, 1);
723 
724             /* Copy the string */
725             RtlCopyUnicodeString(&ustrDevice, pustrDevice);
726 
727             /* Allocate and store pdmAllocated if pdmInit is not NULL */
728             if (pdmInit)
729             {
730                 ProbeForRead(pdmInit, sizeof(DEVMODEW), 1);
731 
732                 dmSize = pdmInit->dmSize;
733                 dmDriverExtra = pdmInit->dmDriverExtra;
734                 Size = dmSize + dmDriverExtra;
735                 ProbeForRead(pdmInit, Size, 1);
736 
737                 pdmAllocated = ExAllocatePoolWithTag(PagedPool | POOL_RAISE_IF_ALLOCATION_FAILURE,
738                                                      Size,
739                                                      TAG_DC);
740                 RtlCopyMemory(pdmAllocated, pdmInit, Size);
741                 pdmAllocated->dmSize = dmSize;
742                 pdmAllocated->dmDriverExtra = dmDriverExtra;
743             }
744 
745             if (pUMdhpdev)
746             {
747                 ProbeForWrite(pUMdhpdev, sizeof(HANDLE), 1);
748             }
749         }
750         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
751         {
752             if (pdmAllocated)
753             {
754                 ExFreePoolWithTag(pdmAllocated, TAG_DC);
755             }
756             SetLastNtError(_SEH2_GetExceptionCode());
757             _SEH2_YIELD(return NULL);
758         }
759         _SEH2_END
760     }
761     else
762     {
763         pdmInit = NULL;
764         pUMdhpdev = NULL;
765         // return UserGetDesktopDC(iType, FALSE, TRUE);
766     }
767 
768     /* FIXME: HACK! */
769     if (pustrDevice)
770     {
771         UNICODE_STRING ustrDISPLAY = RTL_CONSTANT_STRING(L"DISPLAY");
772         if (RtlEqualUnicodeString(&ustrDevice, &ustrDISPLAY, TRUE))
773         {
774             pustrDevice = NULL;
775         }
776     }
777 
778     /* Call the internal function */
779     hdc = GreOpenDCW(pustrDevice ? &ustrDevice : NULL,
780                      pdmAllocated,
781                      NULL, // FIXME: pwszLogAddress
782                      iType,
783                      bDisplay,
784                      hspool,
785                      NULL, // FIXME: pDriverInfo2
786                      pUMdhpdev ? &dhpdev : NULL);
787 
788     /* If we got a HDC and a UM dhpdev is requested,... */
789     if (hdc && pUMdhpdev)
790     {
791         /* Copy dhpdev to caller */
792         _SEH2_TRY
793         {
794             /* Pointer was already probed */
795             *(HANDLE*)pUMdhpdev = dhpdev;
796         }
797         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
798         {
799             /* Ignore error */
800             (void)0;
801         }
802         _SEH2_END
803     }
804 
805     /* Free the allocated */
806     if (pdmAllocated)
807     {
808         ExFreePoolWithTag(pdmAllocated, TAG_DC);
809     }
810 
811     return hdc;
812 }
813 
814 
815 HDC
816 APIENTRY
817 GreCreateCompatibleDC(HDC hdc, BOOL bAltDc)
818 {
819     GDILOOBJTYPE eDcObjType;
820     HDC hdcNew;
821     PPDEVOBJ ppdev;
822     PDC pdc, pdcNew;
823 
824     DPRINT("NtGdiCreateCompatibleDC(0x%p)\n", hdc);
825 
826     /* Did the caller provide a DC? */
827     if (hdc)
828     {
829         /* Yes, try to lock it */
830         pdc = DC_LockDc(hdc);
831         if (!pdc)
832         {
833             DPRINT1("Could not lock source DC %p\n", hdc);
834             return NULL;
835         }
836 
837         /* Get the pdev from the DC */
838         ppdev = pdc->ppdev;
839         PDEVOBJ_vReference(ppdev);
840 
841         /* Unlock the source DC */
842         DC_UnlockDc(pdc);
843     }
844     else
845     {
846         /* No DC given, get default device */
847         ppdev = EngpGetPDEV(NULL);
848     }
849 
850     if (!ppdev)
851     {
852         DPRINT1("Didn't find a suitable PDEV\n");
853         return NULL;
854     }
855 
856     /* Allocate a new DC */
857     eDcObjType = bAltDc ? GDILoObjType_LO_ALTDC_TYPE : GDILoObjType_LO_DC_TYPE;
858     pdcNew = DC_AllocDcWithHandle(eDcObjType);
859     if (!pdcNew)
860     {
861         DPRINT1("Could not allocate a new DC\n");
862         PDEVOBJ_vRelease(ppdev);
863         return NULL;
864     }
865     hdcNew = pdcNew->BaseObject.hHmgr;
866 
867     /* Lock ppdev and initialize the new DC */
868     DC_vInitDc(pdcNew, bAltDc ? DCTYPE_INFO : DCTYPE_MEMORY, ppdev);
869     /* FIXME: HACK! */
870     DC_InitHack(pdcNew);
871 
872     /* Allocate a dc attribute */
873     DC_bAllocDcAttr(pdcNew);
874 
875     DC_UnlockDc(pdcNew);
876 
877     DPRINT("Leave NtGdiCreateCompatibleDC hdcNew = %p\n", hdcNew);
878 
879     return hdcNew;
880 }
881 
882 HDC
883 APIENTRY
884 NtGdiCreateCompatibleDC(HDC hdc)
885 {
886     /* Call the internal function to create a normal memory DC */
887     return GreCreateCompatibleDC(hdc, FALSE);
888 }
889 
890 BOOL
891 FASTCALL
892 IntGdiDeleteDC(HDC hDC, BOOL Force)
893 {
894     PDC DCToDelete = DC_LockDc(hDC);
895 
896     if (DCToDelete == NULL)
897     {
898         EngSetLastError(ERROR_INVALID_HANDLE);
899         return FALSE;
900     }
901 
902     if (!Force)
903     {
904         /* Windows permits NtGdiDeleteObjectApp to delete a permanent DC
905          * For some reason, it's still a valid handle, pointing to some kernel data.
906          * Not sure if this is a bug, a feature, some cache stuff... Who knows?
907          * See NtGdiDeleteObjectApp test for details */
908         if (DCToDelete->fs & DC_FLAG_PERMANENT)
909         {
910             DC_UnlockDc(DCToDelete);
911             if(UserReleaseDC(NULL, hDC, FALSE))
912             {
913                 /* ReactOS feature: Call UserReleaseDC
914                  * I don't think Windows does it.
915                  * Still, complain, no one should ever call DeleteDC
916                  * on a window DC */
917                  DPRINT1("No, you naughty application!\n");
918                  return TRUE;
919             }
920             else
921             {
922                 /* This is not a window owned DC.
923                  * Force its deletion */
924                 return IntGdiDeleteDC(hDC, TRUE);
925             }
926         }
927     }
928 
929     DC_UnlockDc(DCToDelete);
930 
931     if (GreIsHandleValid(hDC))
932     {
933         if (!GreDeleteObject(hDC))
934         {
935             DPRINT1("DC_FreeDC failed\n");
936             return FALSE;
937         }
938     }
939     else
940     {
941         DPRINT1("Attempted to Delete 0x%p currently being destroyed!!!\n", hDC);
942         return FALSE;
943     }
944 
945     return TRUE;
946 }
947 
948 BOOL
949 APIENTRY
950 NtGdiDeleteObjectApp(HANDLE hobj)
951 {
952     if (GDI_HANDLE_IS_STOCKOBJ(hobj)) return TRUE;
953 
954     if (GreGetObjectOwner(hobj) != GDI_OBJ_HMGR_POWNED)
955     {
956         EngSetLastError(ERROR_INVALID_HANDLE);
957         return FALSE;
958     }
959 
960     if (GDI_HANDLE_GET_TYPE(hobj) != GDI_OBJECT_TYPE_DC)
961         return GreDeleteObject(hobj);
962 
963     // FIXME: Everything should be callback based
964     return IntGdiDeleteDC(hobj, FALSE);
965 }
966 
967 BOOL
968 FASTCALL
969 MakeInfoDC(PDC pdc, BOOL bSet)
970 {
971     PSURFACE pSurface;
972     SIZEL sizl;
973 
974     /* Can not be a display DC. */
975     if (pdc->fs & DC_FLAG_DISPLAY) return FALSE;
976     if (bSet)
977     {
978         if (pdc->fs & DC_FLAG_TEMPINFODC || pdc->dctype == DC_TYPE_DIRECT)
979             return FALSE;
980 
981         pSurface = pdc->dclevel.pSurface;
982         pdc->fs |= DC_FLAG_TEMPINFODC;
983         pdc->pSurfInfo = pSurface;
984         pdc->dctype = DC_TYPE_INFO;
985         pdc->dclevel.pSurface = NULL;
986 
987         PDEVOBJ_sizl(pdc->ppdev, &sizl);
988 
989         if ( sizl.cx == pdc->dclevel.sizl.cx &&
990              sizl.cy == pdc->dclevel.sizl.cy )
991             return TRUE;
992 
993         pdc->dclevel.sizl.cx = sizl.cx;
994         pdc->dclevel.sizl.cy = sizl.cy;
995     }
996     else
997     {
998         if (!(pdc->fs & DC_FLAG_TEMPINFODC) || pdc->dctype != DC_TYPE_INFO)
999             return FALSE;
1000 
1001         pSurface = pdc->pSurfInfo;
1002         pdc->fs &= ~DC_FLAG_TEMPINFODC;
1003         pdc->dclevel.pSurface = pSurface;
1004         pdc->dctype = DC_TYPE_DIRECT;
1005         pdc->pSurfInfo = NULL;
1006 
1007         if ( !pSurface ||
1008              (pSurface->SurfObj.sizlBitmap.cx == pdc->dclevel.sizl.cx &&
1009               pSurface->SurfObj.sizlBitmap.cy == pdc->dclevel.sizl.cy) )
1010             return TRUE;
1011 
1012         pdc->dclevel.sizl.cx = pSurface->SurfObj.sizlBitmap.cx;
1013         pdc->dclevel.sizl.cy = pSurface->SurfObj.sizlBitmap.cy;
1014     }
1015     return IntSetDefaultRegion(pdc);
1016 }
1017 
1018 /*
1019 * @implemented
1020 */
1021 BOOL
1022 APIENTRY
1023 NtGdiMakeInfoDC(
1024     IN HDC hdc,
1025     IN BOOL bSet)
1026 {
1027     BOOL Ret;
1028     PDC pdc = DC_LockDc(hdc);
1029     if (pdc)
1030     {
1031         Ret = MakeInfoDC(pdc, bSet);
1032         DC_UnlockDc(pdc);
1033         return Ret;
1034     }
1035     return FALSE;
1036 }
1037 
1038 
1039 HDC FASTCALL
1040 IntGdiCreateDC(
1041     PUNICODE_STRING Driver,
1042     PUNICODE_STRING pustrDevice,
1043     PVOID pUMdhpdev,
1044     CONST PDEVMODEW pdmInit,
1045     BOOL CreateAsIC)
1046 {
1047     HDC hdc;
1048 
1049     hdc = GreOpenDCW(pustrDevice,
1050                      pdmInit,
1051                      NULL,
1052                      CreateAsIC ? DCTYPE_INFO :
1053                           (Driver ? DC_TYPE_DIRECT : DC_TYPE_DIRECT),
1054                      TRUE,
1055                      NULL,
1056                      NULL,
1057                      pUMdhpdev);
1058 
1059     return hdc;
1060 }
1061 
1062 HDC FASTCALL
1063 IntGdiCreateDisplayDC(HDEV hDev, ULONG DcType, BOOL EmptyDC)
1064 {
1065     HDC hDC;
1066     UNIMPLEMENTED;
1067     ASSERT(FALSE);
1068 
1069     if (DcType == DC_TYPE_MEMORY)
1070         hDC = NtGdiCreateCompatibleDC(NULL); // OH~ Yuck! I think I taste vomit in my mouth!
1071     else
1072         hDC = IntGdiCreateDC(NULL, NULL, NULL, NULL, (DcType == DC_TYPE_INFO));
1073 
1074     return hDC;
1075 }
1076 
1077