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