[WIN32SS] Rewrite font selection code. Patch by Katayama Hirofumi MZ. CORE-6621
[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: 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
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
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
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
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
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
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 /// FIXME: we shouldn't dereference pSurface when the PDEV is not locked
234 /* Is this a valid palette for this depth? */
235 if ((!pdc->dclevel.pSurface) ||
236 (BitsPerFormat(pdc->dclevel.pSurface->SurfObj.iBitmapFormat) <= 8
237 && (ppal->flFlags & PAL_INDEXED)) ||
238 (BitsPerFormat(pdc->dclevel.pSurface->SurfObj.iBitmapFormat) > 8))
239 {
240 /* Get old palette, set new one */
241 oldPal = pdc->dclevel.hpal;
242 pdc->dclevel.hpal = hpal;
243 DC_vSelectPalette(pdc, ppal);
244
245 /* Mark the brushes invalid */
246 pdc->pdcattr->ulDirty_ |= DIRTY_FILL | DIRTY_LINE |
247 DIRTY_BACKGROUND | DIRTY_TEXT;
248 }
249
250 if(pdc->dctype == DCTYPE_MEMORY)
251 {
252 // This didn't work anyway
253 //IntGdiRealizePalette(hDC);
254 }
255
256 PALETTE_ShareUnlockPalette(ppal);
257 DC_UnlockDc(pdc);
258
259 return oldPal;
260 }
261
262 /*
263 * @implemented
264 */
265 HBRUSH
266 APIENTRY
267 NtGdiSelectBrush(
268 IN HDC hDC,
269 IN HBRUSH hBrush)
270 {
271 PDC pDC;
272 HBRUSH hOrgBrush;
273
274 if (hDC == NULL || hBrush == NULL) return NULL;
275
276 pDC = DC_LockDc(hDC);
277 if (!pDC)
278 {
279 return NULL;
280 }
281
282 /* Simply return the user mode value, without checking */
283 hOrgBrush = pDC->pdcattr->hbrush;
284 pDC->pdcattr->hbrush = hBrush;
285 DC_vUpdateFillBrush(pDC);
286
287 DC_UnlockDc(pDC);
288
289 return hOrgBrush;
290 }
291
292 /*
293 * @implemented
294 */
295 HPEN
296 APIENTRY
297 NtGdiSelectPen(
298 IN HDC hDC,
299 IN HPEN hPen)
300 {
301 PDC pDC;
302 HPEN hOrgPen;
303
304 if (hDC == NULL || hPen == NULL) return NULL;
305
306 pDC = DC_LockDc(hDC);
307 if (!pDC)
308 {
309 return NULL;
310 }
311
312 /* Simply return the user mode value, without checking */
313 hOrgPen = pDC->pdcattr->hpen;
314 pDC->pdcattr->hpen = hPen;
315 DC_vUpdateLineBrush(pDC);
316
317 DC_UnlockDc(pDC);
318
319 return hOrgPen;
320 }
321
322 BOOL
323 NTAPI
324 DC_bIsBitmapCompatible(PDC pdc, PSURFACE psurf)
325 {
326 ULONG cBitsPixel;
327
328 /* Must be an API bitmap */
329 if (!(psurf->flags & API_BITMAP)) return FALSE;
330
331 /* DIB sections are always compatible */
332 if (psurf->hSecure != NULL) return TRUE;
333
334 /* See if this is the same PDEV */
335 if (psurf->SurfObj.hdev == (HDEV)pdc->ppdev)
336 return TRUE;
337
338 /* Get the bit depth of the bitmap */
339 cBitsPixel = gajBitsPerFormat[psurf->SurfObj.iBitmapFormat];
340
341 /* 1 BPP is compatible */
342 if ((cBitsPixel == 1) || (cBitsPixel == pdc->ppdev->gdiinfo.cBitsPixel))
343 return TRUE;
344
345 return FALSE;
346 }
347
348 /*
349 * @implemented
350 */
351 HBITMAP
352 APIENTRY
353 NtGdiSelectBitmap(
354 IN HDC hdc,
355 IN HBITMAP hbmp)
356 {
357 PDC pdc;
358 HBITMAP hbmpOld;
359 PSURFACE psurfNew, psurfOld;
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 compatible 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 and the RAO region invalid */
474 pdc->pdcattr->ulDirty_ |= DIRTY_FILL | DIRTY_LINE;
475 pdc->fs |= DC_FLAG_DIRTY_RAO;
476
477 /* Update the system region */
478 REGION_SetRectRgn(pdc->prgnVis,
479 0,
480 0,
481 pdc->dclevel.sizl.cx,
482 pdc->dclevel.sizl.cy);
483
484 /* Unlock the DC */
485 DC_UnlockDc(pdc);
486
487 /* Return the old bitmap handle */
488 return hbmpOld;
489 }
490
491
492 BOOL
493 APIENTRY
494 NtGdiSelectClipPath(
495 HDC hDC,
496 int Mode)
497 {
498 PREGION RgnPath;
499 PPATH pPath, pNewPath;
500 BOOL success = FALSE;
501 PDC_ATTR pdcattr;
502 PDC pdc;
503
504 pdc = DC_LockDc(hDC);
505 if (!pdc)
506 {
507 EngSetLastError(ERROR_INVALID_PARAMETER);
508 return FALSE;
509 }
510 pdcattr = pdc->pdcattr;
511
512 pPath = PATH_LockPath(pdc->dclevel.hPath);
513 if (!pPath)
514 {
515 DC_UnlockDc(pdc);
516 return FALSE;
517 }
518
519 /* Check that path is closed */
520 if (pPath->state != PATH_Closed)
521 {
522 EngSetLastError(ERROR_CAN_NOT_COMPLETE);
523 success = FALSE;
524 goto Exit;
525 }
526
527 /* Construct a region from the path */
528 RgnPath = IntSysCreateRectpRgn(0, 0, 0, 0);
529 if (!RgnPath)
530 {
531 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
532 DC_UnlockDc(pdc);
533 return FALSE;
534 }
535
536 pNewPath = PATH_FlattenPath(pPath);
537
538 success = PATH_PathToRegion(pNewPath, pdcattr->jFillMode, RgnPath);
539
540 PATH_UnlockPath(pNewPath);
541 PATH_Delete(pNewPath->BaseObject.hHmgr);
542
543 if (success) success = IntGdiExtSelectClipRgn(pdc, RgnPath, Mode) != ERROR;
544
545 REGION_Delete(RgnPath);
546
547 Exit:
548 PATH_UnlockPath(pPath);
549 PATH_Delete(pdc->dclevel.hPath);
550 pdc->dclevel.flPath &= ~DCPATH_ACTIVE;
551 pdc->dclevel.hPath = NULL;
552
553 DC_UnlockDc(pdc);
554
555 return success;
556 }
557
558 HFONT
559 NTAPI
560 DC_hSelectFont(
561 _In_ PDC pdc,
562 _In_ HFONT hlfntNew)
563 {
564 PLFONT plfntNew;
565 HFONT hlfntOld;
566
567 // Legacy crap that will die with font engine rewrite
568 if (!NT_SUCCESS(TextIntRealizeFont(hlfntNew, NULL)))
569 {
570 return NULL;
571 }
572
573 /* Get the current selected font */
574 hlfntOld = pdc->dclevel.plfnt->BaseObject.hHmgr;
575
576 /* Check if a new font should be selected */
577 if (hlfntNew != hlfntOld)
578 {
579 /* Lock the new font */
580 plfntNew = LFONT_ShareLockFont(hlfntNew);
581 if (plfntNew)
582 {
583 /* Success, dereference the old font */
584 LFONT_ShareUnlockFont(pdc->dclevel.plfnt);
585
586 /* Select the new font */
587 pdc->dclevel.plfnt = plfntNew;
588 pdc->pdcattr->hlfntNew = hlfntNew;
589
590 /* Update dirty flags */
591 pdc->pdcattr->ulDirty_ |= DIRTY_CHARSET;
592 pdc->pdcattr->ulDirty_ &= ~SLOW_WIDTHS;
593 }
594 else
595 {
596 /* Failed, restore old, return NULL */
597 pdc->pdcattr->hlfntNew = hlfntOld;
598 hlfntOld = NULL;
599 }
600 }
601
602 return hlfntOld;
603 }
604
605 HFONT
606 APIENTRY
607 NtGdiSelectFont(
608 _In_ HDC hdc,
609 _In_ HFONT hfont)
610 {
611 HFONT hfontOld;
612 PDC pdc;
613
614 /* Check parameters */
615 if ((hdc == NULL) || (hfont == NULL))
616 {
617 return NULL;
618 }
619
620 /* Lock the DC */
621 pdc = DC_LockDc(hdc);
622 if (!pdc)
623 {
624 return NULL;
625 }
626
627 /* Call the internal function */
628 hfontOld = DC_hSelectFont(pdc, hfont);
629
630 /* Unlock the DC */
631 DC_UnlockDc(pdc);
632
633 /* Return the previously selected font */
634 return hfontOld;
635 }
636
637 HANDLE
638 APIENTRY
639 NtGdiGetDCObject(HDC hDC, INT ObjectType)
640 {
641 HGDIOBJ SelObject;
642 DC *pdc;
643 PDC_ATTR pdcattr;
644
645 /* From Wine: GetCurrentObject does not SetLastError() on a null object */
646 if(!hDC) return NULL;
647
648 if(!(pdc = DC_LockDc(hDC)))
649 {
650 return NULL;
651 }
652 pdcattr = pdc->pdcattr;
653
654 if (pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
655 DC_vUpdateFillBrush(pdc);
656
657 if (pdcattr->ulDirty_ & (DIRTY_LINE | DC_PEN_DIRTY))
658 DC_vUpdateLineBrush(pdc);
659
660 switch(ObjectType)
661 {
662 case GDI_OBJECT_TYPE_EXTPEN:
663 case GDI_OBJECT_TYPE_PEN:
664 SelObject = pdcattr->hpen;
665 break;
666
667 case GDI_OBJECT_TYPE_BRUSH:
668 SelObject = pdcattr->hbrush;
669 break;
670
671 case GDI_OBJECT_TYPE_PALETTE:
672 SelObject = pdc->dclevel.hpal;
673 break;
674
675 case GDI_OBJECT_TYPE_FONT:
676 SelObject = pdcattr->hlfntNew;
677 break;
678
679 case GDI_OBJECT_TYPE_BITMAP:
680 {
681 SURFACE *psurf = pdc->dclevel.pSurface;
682 SelObject = psurf ? psurf->BaseObject.hHmgr : StockObjects[DEFAULT_BITMAP];
683 break;
684 }
685
686 case GDI_OBJECT_TYPE_COLORSPACE:
687 DPRINT1("FIXME: NtGdiGetCurrentObject() ObjectType OBJ_COLORSPACE not supported yet!\n");
688 // SelObject = dc->dclevel.pColorSpace.BaseObject.hHmgr; ?
689 SelObject = NULL;
690 break;
691
692 default:
693 SelObject = NULL;
694 EngSetLastError(ERROR_INVALID_PARAMETER);
695 break;
696 }
697
698 DC_UnlockDc(pdc);
699 return SelObject;
700 }
701
702 /* See WINE, MSDN, OSR and Feng Yuan - Windows Graphics Programming Win32 GDI and DirectDraw
703 *
704 * 1st: http://www.codeproject.com/gdi/cliprgnguide.asp is wrong!
705 *
706 * The intersection of the clip with the meta region is not Rao it's API!
707 * Go back and read 7.2 Clipping pages 418-19:
708 * Rao = API & Vis:
709 * 1) The Rao region is the intersection of the API region and the system region,
710 * named after the Microsoft engineer who initially proposed it.
711 * 2) The Rao region can be calculated from the API region and the system region.
712 *
713 * API:
714 * API region is the intersection of the meta region and the clipping region,
715 * clearly named after the fact that it is controlled by GDI API calls.
716 */
717 INT
718 APIENTRY
719 NtGdiGetRandomRgn(
720 HDC hdc,
721 HRGN hrgnDest,
722 INT iCode)
723 {
724 INT ret = 0;
725 PDC pdc;
726 PREGION prgnSrc = NULL;
727
728 pdc = DC_LockDc(hdc);
729 if (!pdc)
730 {
731 EngSetLastError(ERROR_INVALID_HANDLE);
732 return -1;
733 }
734
735 switch (iCode)
736 {
737 case CLIPRGN:
738 prgnSrc = pdc->dclevel.prgnClip;
739 break;
740
741 case METARGN:
742 prgnSrc = pdc->dclevel.prgnMeta;
743 break;
744
745 case APIRGN:
746 if (pdc->fs & DC_FLAG_DIRTY_RAO)
747 CLIPPING_UpdateGCRegion(pdc);
748 if (pdc->prgnAPI)
749 {
750 prgnSrc = pdc->prgnAPI;
751 }
752 else if (pdc->dclevel.prgnClip)
753 {
754 prgnSrc = pdc->dclevel.prgnClip;
755 }
756 else if (pdc->dclevel.prgnMeta)
757 {
758 prgnSrc = pdc->dclevel.prgnMeta;
759 }
760 break;
761
762 case SYSRGN:
763 prgnSrc = pdc->prgnVis;
764 break;
765
766 default:
767 break;
768 }
769
770 if (prgnSrc)
771 {
772 PREGION prgnDest = REGION_LockRgn(hrgnDest);
773 if (prgnDest)
774 {
775 ret = IntGdiCombineRgn(prgnDest, prgnSrc, 0, RGN_COPY) == ERROR ? -1 : 1;
776 if ((ret == 1) && (iCode == SYSRGN))
777 {
778 /// \todo FIXME This is not really correct, since we already modified the region
779 ret = REGION_bOffsetRgn(prgnDest, pdc->ptlDCOrig.x, pdc->ptlDCOrig.y);
780 }
781 REGION_UnlockRgn(prgnDest);
782 }
783 else
784 ret = -1;
785 }
786
787 DC_UnlockDc(pdc);
788
789 return ret;
790 }
791
792 ULONG
793 APIENTRY
794 NtGdiEnumObjects(
795 IN HDC hdc,
796 IN INT iObjectType,
797 IN ULONG cjBuf,
798 OUT OPTIONAL PVOID pvBuf)
799 {
800 UNIMPLEMENTED;
801 return 0;
802 }
803
804 /* EOF */