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