[WIN32SS][FONT] Fix the system logical stock font data (#709)
[reactos.git] / 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
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
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
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
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
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
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 != DC_TYPE_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_FLAG_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
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
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
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
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
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_FLAG_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
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 */