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