xref: /reactos/win32ss/gdi/ntgdi/dcobjs.c (revision 5e93daa9)
1 /*
2  * COPYRIGHT:         See COPYING in the top level directory
3  * PROJECT:           ReactOS Win32k subsystem
4  * PURPOSE:           Functions for creation and destruction of DCs
5  * FILE:              win32ss/gdi/ntgdi/dcobjs.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 VOID
15 FASTCALL
DC_vUpdateFillBrush(PDC pdc)16 DC_vUpdateFillBrush(PDC pdc)
17 {
18     PDC_ATTR pdcattr = pdc->pdcattr;
19     PBRUSH pbrFill;
20 
21     /* Check if the brush handle has changed */
22     if (pdcattr->hbrush != pdc->dclevel.pbrFill->BaseObject.hHmgr)
23     {
24         /* Try to lock the new brush */
25         pbrFill = BRUSH_ShareLockBrush(pdcattr->hbrush);
26         if (pbrFill)
27         {
28             /* Unlock old brush, set new brush */
29             BRUSH_ShareUnlockBrush(pdc->dclevel.pbrFill);
30             pdc->dclevel.pbrFill = pbrFill;
31 
32             /* Mark eboFill as dirty */
33             pdcattr->ulDirty_ |= DIRTY_FILL;
34         }
35         else
36         {
37             /* Invalid brush handle, restore old one */
38             pdcattr->hbrush = pdc->dclevel.pbrFill->BaseObject.hHmgr;
39         }
40     }
41 
42     /* Check if the EBRUSHOBJ needs update */
43     if (pdcattr->ulDirty_ & DIRTY_FILL)
44     {
45         /* Update eboFill */
46         EBRUSHOBJ_vUpdateFromDC(&pdc->eboFill, pdc->dclevel.pbrFill, pdc);
47     }
48 
49     /* Check for DC brush */
50     if (pdcattr->hbrush == StockObjects[DC_BRUSH])
51     {
52         /* Update the eboFill's solid color */
53         EBRUSHOBJ_vSetSolidRGBColor(&pdc->eboFill, pdcattr->crBrushClr);
54     }
55 
56     /* Clear flags */
57     pdcattr->ulDirty_ &= ~(DIRTY_FILL | DC_BRUSH_DIRTY);
58 }
59 
60 VOID
61 FASTCALL
DC_vUpdateLineBrush(PDC pdc)62 DC_vUpdateLineBrush(PDC pdc)
63 {
64     PDC_ATTR pdcattr = pdc->pdcattr;
65     PBRUSH pbrLine;
66 
67     /* Check if the pen handle has changed */
68     if (pdcattr->hpen != pdc->dclevel.pbrLine->BaseObject.hHmgr)
69     {
70         /* Try to lock the new pen */
71         pbrLine = PEN_ShareLockPen(pdcattr->hpen);
72         if (pbrLine)
73         {
74             /* Unlock old brush, set new brush */
75             BRUSH_ShareUnlockBrush(pdc->dclevel.pbrLine);
76             pdc->dclevel.pbrLine = pbrLine;
77 
78             /* Mark eboLine as dirty */
79             pdcattr->ulDirty_ |= DIRTY_LINE;
80         }
81         else
82         {
83             /* Invalid pen handle, restore old one */
84             pdcattr->hpen = pdc->dclevel.pbrLine->BaseObject.hHmgr;
85         }
86     }
87 
88     /* Check if the EBRUSHOBJ needs update */
89     if (pdcattr->ulDirty_ & DIRTY_LINE)
90     {
91         /* Update eboLine */
92         EBRUSHOBJ_vUpdateFromDC(&pdc->eboLine, pdc->dclevel.pbrLine, pdc);
93     }
94 
95     /* Check for DC pen */
96     if (pdcattr->hpen == StockObjects[DC_PEN])
97     {
98         /* Update the eboLine's solid color */
99         EBRUSHOBJ_vSetSolidRGBColor(&pdc->eboLine, pdcattr->crPenClr);
100     }
101 
102     /* Clear flags */
103     pdcattr->ulDirty_ &= ~(DIRTY_LINE | DC_PEN_DIRTY);
104 }
105 
106 VOID
107 FASTCALL
DC_vUpdateTextBrush(PDC pdc)108 DC_vUpdateTextBrush(PDC pdc)
109 {
110     PDC_ATTR pdcattr = pdc->pdcattr;
111 
112     /* Timo : The text brush should never be changed.
113      * Jérôme : Yeah, but its palette must be updated anyway! */
114     if(pdcattr->ulDirty_ & DIRTY_TEXT)
115         EBRUSHOBJ_vUpdateFromDC(&pdc->eboText, pbrDefaultBrush, pdc);
116 
117     /* Update the eboText's solid color */
118     EBRUSHOBJ_vSetSolidRGBColor(&pdc->eboText, pdcattr->crForegroundClr);
119 
120     /* Clear flag */
121     pdcattr->ulDirty_ &= ~DIRTY_TEXT;
122 }
123 
124 VOID
125 FASTCALL
DC_vUpdateBackgroundBrush(PDC pdc)126 DC_vUpdateBackgroundBrush(PDC pdc)
127 {
128     PDC_ATTR pdcattr = pdc->pdcattr;
129 
130     if(pdcattr->ulDirty_ & DIRTY_BACKGROUND)
131         EBRUSHOBJ_vUpdateFromDC(&pdc->eboBackground, pbrDefaultBrush, pdc);
132 
133     /* Update the eboBackground's solid color */
134     EBRUSHOBJ_vSetSolidRGBColor(&pdc->eboBackground, pdcattr->crBackgroundClr);
135 
136     /* Clear flag */
137     pdcattr->ulDirty_ &= ~DIRTY_BACKGROUND;
138 }
139 
140 VOID
141 NTAPI
DC_vSetBrushOrigin(PDC pdc,LONG x,LONG y)142 DC_vSetBrushOrigin(PDC pdc, LONG x, LONG y)
143 {
144     /* Set the brush origin */
145     pdc->dclevel.ptlBrushOrigin.x = x;
146     pdc->dclevel.ptlBrushOrigin.y = y;
147 
148     /* Set the fill origin */
149     pdc->ptlFillOrigin.x = x + pdc->ptlDCOrig.x;
150     pdc->ptlFillOrigin.y = y + pdc->ptlDCOrig.y;
151 }
152 
153 /**
154  * \name NtGdiSetBrushOrg
155  *
156  * \brief Sets the brush origin that GDI uses when drawing with pattern
157  *     brushes. The brush origin is relative to the DC origin.
158  *
159  * @implemented
160  */
161 _Success_(return!=FALSE)
162 __kernel_entry
163 BOOL
164 APIENTRY
NtGdiSetBrushOrg(_In_ HDC hdc,_In_ INT x,_In_ INT y,_Out_opt_ LPPOINT pptOut)165 NtGdiSetBrushOrg(
166     _In_ HDC hdc,
167     _In_ INT x,
168     _In_ INT y,
169     _Out_opt_ LPPOINT pptOut)
170 {
171 
172     POINT ptOut;
173                 /* Call the internal function */
174     BOOL  Ret = GreSetBrushOrg( hdc, x, y, &ptOut);
175     if (Ret)
176     {
177        /* Check if the old origin was requested */
178        if (pptOut != NULL)
179        {
180            /* Enter SEH for buffer transfer */
181            _SEH2_TRY
182            {
183                /* Probe and copy the old origin */
184                ProbeForWrite(pptOut, sizeof(POINT), 1);
185                *pptOut = ptOut;
186            }
187            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
188            {
189                _SEH2_YIELD(return FALSE);
190            }
191            _SEH2_END;
192        }
193     }
194     return Ret;
195 }
196 
197 HPALETTE
198 NTAPI
GdiSelectPalette(HDC hDC,HPALETTE hpal,BOOL ForceBackground)199 GdiSelectPalette(
200     HDC hDC,
201     HPALETTE hpal,
202     BOOL ForceBackground)
203 {
204     PDC pdc;
205     HPALETTE oldPal = NULL;
206     PPALETTE ppal;
207 
208     // FIXME: Mark the palette as a [fore\back]ground pal
209     pdc = DC_LockDc(hDC);
210     if (!pdc)
211     {
212         return NULL;
213     }
214 
215     /* Check if this is a valid palette handle */
216     ppal = PALETTE_ShareLockPalette(hpal);
217     if (!ppal)
218     {
219         DC_UnlockDc(pdc);
220         return NULL;
221     }
222 
223     /// FIXME: we shouldn't dereference pSurface when the PDEV is not locked
224     /* Is this a valid palette for this depth? */
225 	if ((!pdc->dclevel.pSurface) ||
226         (BitsPerFormat(pdc->dclevel.pSurface->SurfObj.iBitmapFormat) <= 8
227             && (ppal->flFlags & PAL_INDEXED)) ||
228         (BitsPerFormat(pdc->dclevel.pSurface->SurfObj.iBitmapFormat) > 8))
229     {
230         /* Get old palette, set new one */
231         oldPal = pdc->dclevel.hpal;
232         pdc->dclevel.hpal = hpal;
233         DC_vSelectPalette(pdc, ppal);
234 
235         /* Mark the brushes invalid */
236         pdc->pdcattr->ulDirty_ |= DIRTY_FILL | DIRTY_LINE |
237                                   DIRTY_BACKGROUND | DIRTY_TEXT;
238     }
239 
240     if(pdc->dctype == DCTYPE_MEMORY)
241     {
242         // This didn't work anyway
243         //IntGdiRealizePalette(hDC);
244     }
245 
246     PALETTE_ShareUnlockPalette(ppal);
247     DC_UnlockDc(pdc);
248 
249     return oldPal;
250 }
251 
252  /*
253  * @implemented
254  */
255 HBRUSH
256 APIENTRY
NtGdiSelectBrush(IN HDC hDC,IN HBRUSH hBrush)257 NtGdiSelectBrush(
258     IN HDC hDC,
259     IN HBRUSH hBrush)
260 {
261     PDC pDC;
262     HBRUSH hOrgBrush;
263 
264     if (hDC == NULL || hBrush == NULL) return NULL;
265 
266     pDC = DC_LockDc(hDC);
267     if (!pDC)
268     {
269         return NULL;
270     }
271 
272     /* Simply return the user mode value, without checking */
273     hOrgBrush = pDC->pdcattr->hbrush;
274     pDC->pdcattr->hbrush = hBrush;
275     DC_vUpdateFillBrush(pDC);
276 
277     DC_UnlockDc(pDC);
278 
279     return hOrgBrush;
280 }
281 
282  /*
283  * @implemented
284  */
285 HPEN
286 APIENTRY
NtGdiSelectPen(IN HDC hDC,IN HPEN hPen)287 NtGdiSelectPen(
288     IN HDC hDC,
289     IN HPEN hPen)
290 {
291     PDC pDC;
292     HPEN hOrgPen;
293 
294     if (hDC == NULL || hPen == NULL) return NULL;
295 
296     pDC = DC_LockDc(hDC);
297     if (!pDC)
298     {
299         return NULL;
300     }
301 
302     /* Simply return the user mode value, without checking */
303     hOrgPen = pDC->pdcattr->hpen;
304     pDC->pdcattr->hpen = hPen;
305     DC_vUpdateLineBrush(pDC);
306 
307     DC_UnlockDc(pDC);
308 
309     return hOrgPen;
310 }
311 
312 BOOL
313 NTAPI
DC_bIsBitmapCompatible(PDC pdc,PSURFACE psurf)314 DC_bIsBitmapCompatible(PDC pdc, PSURFACE psurf)
315 {
316     ULONG cBitsPixel;
317 
318     /* Must be an API bitmap */
319     if (!(psurf->flags & API_BITMAP)) return FALSE;
320 
321     /* DIB sections are always compatible */
322     if (psurf->hSecure != NULL) return TRUE;
323 
324     /* See if this is the same PDEV */
325     if (psurf->SurfObj.hdev == (HDEV)pdc->ppdev)
326         return TRUE;
327 
328     /* Get the bit depth of the bitmap */
329     cBitsPixel = gajBitsPerFormat[psurf->SurfObj.iBitmapFormat];
330 
331     /* 1 BPP is compatible */
332     if ((cBitsPixel == 1) || (cBitsPixel == pdc->ppdev->gdiinfo.cBitsPixel))
333         return TRUE;
334 
335     return FALSE;
336 }
337 
338 /*
339  * @implemented
340  */
341 HBITMAP
342 APIENTRY
NtGdiSelectBitmap(IN HDC hdc,IN HBITMAP hbmp)343 NtGdiSelectBitmap(
344     IN HDC hdc,
345     IN HBITMAP hbmp)
346 {
347     PDC pdc;
348     HBITMAP hbmpOld;
349     PSURFACE psurfNew, psurfOld;
350     HDC hdcOld;
351     ASSERT_NOGDILOCKS();
352 
353     /* Verify parameters */
354     if (hdc == NULL || hbmp == NULL) return NULL;
355 
356     /* First lock the DC */
357     pdc = DC_LockDc(hdc);
358     if (!pdc)
359     {
360         return NULL;
361     }
362 
363     /* Must be a memory dc to select a bitmap */
364     if (pdc->dctype != DCTYPE_MEMORY)
365     {
366         DC_UnlockDc(pdc);
367         return NULL;
368     }
369 
370     /* Save the old bitmap */
371     psurfOld = pdc->dclevel.pSurface;
372 
373     /* Check if there is a bitmap selected */
374     if (psurfOld)
375     {
376         /* Get the old bitmap's handle */
377         hbmpOld = psurfOld->BaseObject.hHmgr;
378     }
379     else
380     {
381         /* Use the default bitmap */
382         hbmpOld = StockObjects[DEFAULT_BITMAP];
383     }
384 
385     /* Check if the new bitmap is already selected */
386     if (hbmp == hbmpOld)
387     {
388         /* Unlock the DC and return the old bitmap */
389         DC_UnlockDc(pdc);
390         return hbmpOld;
391     }
392 
393     /* Check if the default bitmap was passed */
394     if (hbmp == StockObjects[DEFAULT_BITMAP])
395     {
396         psurfNew = NULL;
397 
398         /* Default bitmap is 1x1 pixel */
399         pdc->dclevel.sizl.cx = 1;
400         pdc->dclevel.sizl.cy = 1;
401     }
402     else
403     {
404         /* Reference the new bitmap and check if it's valid */
405         psurfNew = SURFACE_ShareLockSurface(hbmp);
406         if (!psurfNew)
407         {
408             DC_UnlockDc(pdc);
409             return NULL;
410         }
411 
412         /* Check if the bitmap is compatible with the dc */
413         if (!DC_bIsBitmapCompatible(pdc, psurfNew))
414         {
415             /* Dereference the bitmap, unlock the DC and fail. */
416             SURFACE_ShareUnlockSurface(psurfNew);
417             DC_UnlockDc(pdc);
418             return NULL;
419         }
420 
421         /* Set the bitmap's hdc and check if it was set before */
422         hdcOld = InterlockedCompareExchangePointer((PVOID*)&psurfNew->hdc, hdc, 0);
423         if (hdcOld != NULL)
424         {
425             /* The bitmap is already selected into a different DC */
426             ASSERT(hdcOld != hdc);
427 
428             /* Dereference the bitmap, unlock the DC and fail. */
429             SURFACE_ShareUnlockSurface(psurfNew);
430             DC_UnlockDc(pdc);
431             return NULL;
432         }
433 
434         /* Copy the bitmap size */
435         pdc->dclevel.sizl = psurfNew->SurfObj.sizlBitmap;
436 
437         /* Check if the bitmap is a dibsection */
438         if (psurfNew->hSecure)
439         {
440             /* Set DIBSECTION attribute */
441             pdc->pdcattr->ulDirty_ |= DC_DIBSECTION;
442         }
443         else
444         {
445             /* Remove DIBSECTION attribute */
446             pdc->pdcattr->ulDirty_ &= ~DC_DIBSECTION;
447         }
448     }
449 
450     /* Select the new bitmap */
451     pdc->dclevel.pSurface = psurfNew;
452 
453     /* Check if there was a bitmap selected before */
454     if (psurfOld)
455     {
456         /* Reset hdc of the old bitmap, it isn't selected anymore */
457         psurfOld->hdc = NULL;
458 
459         /* Dereference the old bitmap */
460         SURFACE_ShareUnlockSurface(psurfOld);
461     }
462 
463     /* Mark the DC brushes and the RAO region invalid */
464     pdc->pdcattr->ulDirty_ |= DIRTY_FILL | DIRTY_LINE;
465     pdc->fs |= DC_DIRTY_RAO;
466 
467     /* Update the system region */
468     REGION_SetRectRgn(pdc->prgnVis,
469                       0,
470                       0,
471                       pdc->dclevel.sizl.cx,
472                       pdc->dclevel.sizl.cy);
473 
474     /* Unlock the DC */
475     DC_UnlockDc(pdc);
476 
477     /* Return the old bitmap handle */
478     return hbmpOld;
479 }
480 
481 
482 BOOL
483 APIENTRY
NtGdiSelectClipPath(HDC hDC,int Mode)484 NtGdiSelectClipPath(
485     HDC hDC,
486     int Mode)
487 {
488     PREGION  RgnPath;
489     PPATH pPath, pNewPath;
490     BOOL  success = FALSE;
491     PDC_ATTR pdcattr;
492     PDC pdc;
493 
494     pdc = DC_LockDc(hDC);
495     if (!pdc)
496     {
497         EngSetLastError(ERROR_INVALID_PARAMETER);
498         return FALSE;
499     }
500     pdcattr = pdc->pdcattr;
501 
502     pPath = PATH_LockPath(pdc->dclevel.hPath);
503     if (!pPath)
504     {
505         DC_UnlockDc(pdc);
506         return FALSE;
507     }
508 
509     /* Check that path is closed */
510     if (pPath->state != PATH_Closed)
511     {
512         EngSetLastError(ERROR_CAN_NOT_COMPLETE);
513         success = FALSE;
514         goto Exit;
515     }
516 
517     /* Construct a region from the path */
518     RgnPath = IntSysCreateRectpRgn(0, 0, 0, 0);
519     if (!RgnPath)
520     {
521         EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
522         DC_UnlockDc(pdc);
523         return FALSE;
524     }
525 
526     pNewPath = PATH_FlattenPath(pPath);
527 
528     success = PATH_PathToRegion(pNewPath, pdcattr->jFillMode, RgnPath);
529 
530     PATH_UnlockPath(pNewPath);
531     PATH_Delete(pNewPath->BaseObject.hHmgr);
532 
533     if (success) success = IntGdiExtSelectClipRgn(pdc, RgnPath, Mode) != ERROR;
534 
535     REGION_Delete(RgnPath);
536 
537 Exit:
538     PATH_UnlockPath(pPath);
539     PATH_Delete(pdc->dclevel.hPath);
540     pdc->dclevel.flPath &= ~DCPATH_ACTIVE;
541     pdc->dclevel.hPath = NULL;
542 
543     DC_UnlockDc(pdc);
544 
545     return success;
546 }
547 
548 HFONT
549 NTAPI
DC_hSelectFont(_In_ PDC pdc,_In_ HFONT hlfntNew)550 DC_hSelectFont(
551     _In_ PDC pdc,
552     _In_ HFONT hlfntNew)
553 {
554     PLFONT plfntNew;
555     HFONT hlfntOld;
556 
557     // Legacy crap that will die with font engine rewrite
558     if (!NT_SUCCESS(TextIntRealizeFont(hlfntNew, NULL)))
559     {
560         return NULL;
561     }
562 
563     /* Get the current selected font */
564     hlfntOld = pdc->dclevel.plfnt->BaseObject.hHmgr;
565 
566     /* Check if a new font should be selected */
567     if (hlfntNew != hlfntOld)
568     {
569         /* Lock the new font */
570         plfntNew = LFONT_ShareLockFont(hlfntNew);
571         if (plfntNew)
572         {
573             /* Success, dereference the old font */
574             LFONT_ShareUnlockFont(pdc->dclevel.plfnt);
575 
576             /* Select the new font */
577             pdc->dclevel.plfnt = plfntNew;
578             pdc->pdcattr->hlfntNew = hlfntNew;
579 
580             /* Update dirty flags */
581             pdc->pdcattr->ulDirty_ |= DIRTY_CHARSET;
582             pdc->pdcattr->ulDirty_ &= ~SLOW_WIDTHS;
583         }
584         else
585         {
586             /* Failed, restore old, return NULL */
587             pdc->pdcattr->hlfntNew = hlfntOld;
588             hlfntOld = NULL;
589         }
590     }
591 
592     return hlfntOld;
593 }
594 
595 HFONT
596 APIENTRY
NtGdiSelectFont(_In_ HDC hdc,_In_ HFONT hfont)597 NtGdiSelectFont(
598     _In_ HDC hdc,
599     _In_ HFONT hfont)
600 {
601     HFONT hfontOld;
602     PDC pdc;
603 
604     /* Check parameters */
605     if ((hdc == NULL) || (hfont == NULL))
606     {
607         return NULL;
608     }
609 
610     /* Lock the DC */
611     pdc = DC_LockDc(hdc);
612     if (!pdc)
613     {
614         return NULL;
615     }
616 
617     /* Call the internal function */
618     hfontOld = DC_hSelectFont(pdc, hfont);
619 
620     /* Unlock the DC */
621     DC_UnlockDc(pdc);
622 
623     /* Return the previously selected font */
624     return hfontOld;
625 }
626 
627 HANDLE
628 APIENTRY
NtGdiGetDCObject(HDC hDC,INT ObjectType)629 NtGdiGetDCObject(HDC hDC, INT ObjectType)
630 {
631     HGDIOBJ SelObject;
632     DC *pdc;
633     PDC_ATTR pdcattr;
634 
635     /* From Wine: GetCurrentObject does not SetLastError() on a null object */
636     if(!hDC) return NULL;
637 
638     if(!(pdc = DC_LockDc(hDC)))
639     {
640         return NULL;
641     }
642     pdcattr = pdc->pdcattr;
643 
644     if (pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
645         DC_vUpdateFillBrush(pdc);
646 
647     if (pdcattr->ulDirty_ & (DIRTY_LINE | DC_PEN_DIRTY))
648         DC_vUpdateLineBrush(pdc);
649 
650     switch(ObjectType)
651     {
652         case GDI_OBJECT_TYPE_EXTPEN:
653         case GDI_OBJECT_TYPE_PEN:
654             SelObject = pdcattr->hpen;
655             break;
656 
657         case GDI_OBJECT_TYPE_BRUSH:
658             SelObject = pdcattr->hbrush;
659             break;
660 
661         case GDI_OBJECT_TYPE_PALETTE:
662             SelObject = pdc->dclevel.hpal;
663             break;
664 
665         case GDI_OBJECT_TYPE_FONT:
666             SelObject = pdcattr->hlfntNew;
667             break;
668 
669         case GDI_OBJECT_TYPE_BITMAP:
670         {
671             SURFACE *psurf = pdc->dclevel.pSurface;
672             SelObject = psurf ? psurf->BaseObject.hHmgr : StockObjects[DEFAULT_BITMAP];
673             break;
674         }
675 
676         case GDI_OBJECT_TYPE_COLORSPACE:
677             DPRINT1("FIXME: NtGdiGetCurrentObject() ObjectType OBJ_COLORSPACE not supported yet!\n");
678             // SelObject = dc->dclevel.pColorSpace.BaseObject.hHmgr; ?
679             SelObject = NULL;
680             break;
681 
682         default:
683             SelObject = NULL;
684             EngSetLastError(ERROR_INVALID_PARAMETER);
685             break;
686     }
687 
688     DC_UnlockDc(pdc);
689     return SelObject;
690 }
691 
692 /* See WINE, MSDN, OSR and Feng Yuan - Windows Graphics Programming Win32 GDI and DirectDraw
693  *
694  * 1st: http://www.codeproject.com/gdi/cliprgnguide.asp is wrong!
695  *
696  * The intersection of the clip with the meta region is not Rao it's API!
697  * Go back and read 7.2 Clipping pages 418-19:
698  * Rao = API & Vis:
699  * 1) The Rao region is the intersection of the API region and the system region,
700  *    named after the Microsoft engineer who initially proposed it.
701  * 2) The Rao region can be calculated from the API region and the system region.
702  *
703  * API:
704  *    API region is the intersection of the meta region and the clipping region,
705  *    clearly named after the fact that it is controlled by GDI API calls.
706  */
707 INT
708 APIENTRY
NtGdiGetRandomRgn(HDC hdc,HRGN hrgnDest,INT iCode)709 NtGdiGetRandomRgn(
710     HDC hdc,
711     HRGN hrgnDest,
712     INT iCode)
713 {
714     INT ret = 0;
715     PDC pdc;
716     PREGION prgnSrc = NULL;
717 
718     pdc = DC_LockDc(hdc);
719     if (!pdc)
720     {
721         EngSetLastError(ERROR_INVALID_HANDLE);
722         return -1;
723     }
724 
725     switch (iCode)
726     {
727         case CLIPRGN:
728             prgnSrc = pdc->dclevel.prgnClip;
729             break;
730 
731         case METARGN:
732             prgnSrc = pdc->dclevel.prgnMeta;
733             break;
734 
735         case APIRGN:
736             if (pdc->fs & DC_DIRTY_RAO)
737                 CLIPPING_UpdateGCRegion(pdc);
738             if (pdc->prgnAPI)
739             {
740                 prgnSrc = pdc->prgnAPI;
741             }
742             else if (pdc->dclevel.prgnClip)
743             {
744                 prgnSrc = pdc->dclevel.prgnClip;
745             }
746             else if (pdc->dclevel.prgnMeta)
747             {
748                 prgnSrc = pdc->dclevel.prgnMeta;
749             }
750             break;
751 
752         case SYSRGN:
753             prgnSrc = pdc->prgnVis;
754             break;
755 
756         default:
757             break;
758     }
759 
760     if (prgnSrc)
761     {
762         PREGION prgnDest = REGION_LockRgn(hrgnDest);
763         if (prgnDest)
764         {
765             ret = IntGdiCombineRgn(prgnDest, prgnSrc, 0, RGN_COPY) == ERROR ? -1 : 1;
766             if ((ret == 1) && (iCode == SYSRGN))
767             {
768                 /// \todo FIXME This is not really correct, since we already modified the region
769                 ret = REGION_bOffsetRgn(prgnDest, pdc->ptlDCOrig.x, pdc->ptlDCOrig.y);
770             }
771             REGION_UnlockRgn(prgnDest);
772         }
773         else
774             ret = -1;
775     }
776 
777     DC_UnlockDc(pdc);
778 
779     return ret;
780 }
781 
782 ULONG
783 APIENTRY
NtGdiEnumObjects(IN HDC hdc,IN INT iObjectType,IN ULONG cjBuf,OUT OPTIONAL PVOID pvBuf)784 NtGdiEnumObjects(
785     IN HDC hdc,
786     IN INT iObjectType,
787     IN ULONG cjBuf,
788     OUT OPTIONAL PVOID pvBuf)
789 {
790     UNIMPLEMENTED;
791     return 0;
792 }
793 
794 /* EOF */
795