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