Commit r20366:20368 again.
[reactos.git] / reactos / subsys / win32k / objects / brush.c
1 /*
2 * ReactOS Win32 Subsystem
3 *
4 * Copyright (C) 1998 - 2004 ReactOS Team
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 *
20 * $Id$
21 */
22
23 #include <w32k.h>
24
25 #define NDEBUG
26 #include <debug.h>
27
28 static const USHORT HatchBrushes[NB_HATCH_STYLES][8] =
29 {
30 {0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00}, /* HS_HORIZONTAL */
31 {0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08}, /* HS_VERTICAL */
32 {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80}, /* HS_FDIAGONAL */
33 {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01}, /* HS_BDIAGONAL */
34 {0x08, 0x08, 0x08, 0xff, 0x08, 0x08, 0x08, 0x08}, /* HS_CROSS */
35 {0x81, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x81} /* HS_DIAGCROSS */
36 };
37
38 BOOL INTERNAL_CALL
39 BRUSH_Cleanup(PVOID ObjectBody)
40 {
41 PGDIBRUSHOBJ pBrush = (PGDIBRUSHOBJ)ObjectBody;
42 if(pBrush->flAttrs & (GDIBRUSH_IS_HATCH | GDIBRUSH_IS_BITMAP))
43 {
44 ASSERT(pBrush->hbmPattern);
45 GDIOBJ_SetOwnership(pBrush->hbmPattern, PsGetCurrentProcess());
46 NtGdiDeleteObject(pBrush->hbmPattern);
47 }
48
49 return TRUE;
50 }
51
52 XLATEOBJ* FASTCALL
53 IntGdiCreateBrushXlate(PDC Dc, GDIBRUSHOBJ *BrushObj, BOOLEAN *Failed)
54 {
55 XLATEOBJ *Result = NULL;
56
57 if (BrushObj->flAttrs & GDIBRUSH_IS_NULL)
58 {
59 Result = NULL;
60 *Failed = FALSE;
61 }
62 else if (BrushObj->flAttrs & GDIBRUSH_IS_SOLID)
63 {
64 Result = IntEngCreateXlate(0, PAL_RGB, Dc->w.hPalette, NULL);
65 *Failed = FALSE;
66 }
67 else
68 {
69 BITMAPOBJ *Pattern = BITMAPOBJ_LockBitmap(BrushObj->hbmPattern);
70 if (Pattern == NULL)
71 return NULL;
72
73 /* Special case: 1bpp pattern */
74 if (Pattern->SurfObj.iBitmapFormat == BMF_1BPP)
75 {
76 if (Dc->w.bitsPerPixel != 1)
77 Result = IntEngCreateSrcMonoXlate(Dc->w.hPalette, Dc->w.textColor, Dc->w.backgroundColor);
78 }
79 else if (BrushObj->flAttrs & GDIBRUSH_IS_DIB)
80 {
81 Result = IntEngCreateXlate(0, 0, Dc->w.hPalette, Pattern->hDIBPalette);
82 }
83
84 BITMAPOBJ_UnlockBitmap(Pattern);
85 *Failed = FALSE;
86 }
87
88 return Result;
89 }
90
91 VOID FASTCALL
92 IntGdiInitBrushInstance(GDIBRUSHINST *BrushInst, PGDIBRUSHOBJ BrushObj, XLATEOBJ *XlateObj)
93 {
94 ASSERT(BrushInst);
95 ASSERT(BrushObj);
96 if (BrushObj->flAttrs & GDIBRUSH_IS_NULL)
97 BrushInst->BrushObject.iSolidColor = 0;
98 else if (BrushObj->flAttrs & GDIBRUSH_IS_SOLID)
99 BrushInst->BrushObject.iSolidColor = XLATEOBJ_iXlate(XlateObj, BrushObj->BrushAttr.lbColor);
100 else
101 BrushInst->BrushObject.iSolidColor = 0xFFFFFFFF;
102 BrushInst->BrushObject.pvRbrush = BrushObj->ulRealization;
103 BrushInst->BrushObject.flColorType = 0;
104 BrushInst->GdiBrushObject = BrushObj;
105 BrushInst->XlateObject = XlateObj;
106 }
107
108 /**
109 * @name CalculateColorTableSize
110 *
111 * Internal routine to calculate the number of color table entries.
112 *
113 * @param BitmapInfoHeader
114 * Input bitmap information header, can be any version of
115 * BITMAPINFOHEADER or BITMAPCOREHEADER.
116 *
117 * @param ColorSpec
118 * Pointer to variable which specifiing the color mode (DIB_RGB_COLORS
119 * or DIB_RGB_COLORS). On successful return this value is normalized
120 * according to the bitmap info.
121 *
122 * @param ColorTableSize
123 * On successful return this variable is filled with number of
124 * entries in color table for the image with specified parameters.
125 *
126 * @return
127 * TRUE if the input values together form a valid image, FALSE otherwise.
128 */
129
130 BOOL STDCALL
131 CalculateColorTableSize(
132 CONST BITMAPINFOHEADER *BitmapInfoHeader,
133 UINT *ColorSpec,
134 UINT *ColorTableSize)
135 {
136 WORD BitCount;
137 DWORD ClrUsed;
138 DWORD Compression;
139
140 /*
141 * At first get some basic parameters from the passed BitmapInfoHeader
142 * structure. It can have one of the following formats:
143 * - BITMAPCOREHEADER (the oldest one with totally different layout
144 * from the others)
145 * - BITMAPINFOHEADER (the standard and most common header)
146 * - BITMAPV4HEADER (extension of BITMAPINFOHEADER)
147 * - BITMAPV5HEADER (extension of BITMAPV4HEADER)
148 */
149
150 if (BitmapInfoHeader->biSize == sizeof(BITMAPCOREHEADER))
151 {
152 BitCount = ((LPBITMAPCOREHEADER)BitmapInfoHeader)->bcBitCount;
153 ClrUsed = 0;
154 Compression = BI_RGB;
155 }
156 else
157 {
158 BitCount = BitmapInfoHeader->biBitCount;
159 ClrUsed = BitmapInfoHeader->biClrUsed;
160 Compression = BitmapInfoHeader->biCompression;
161 }
162
163 switch (Compression)
164 {
165 case BI_BITFIELDS:
166 if (*ColorSpec == DIB_PAL_COLORS)
167 *ColorSpec = DIB_RGB_COLORS;
168
169 if (BitCount != 16 && BitCount != 32)
170 return FALSE;
171
172 /*
173 * For BITMAPV4HEADER/BITMAPV5HEADER the masks are included in
174 * the structure itself (bV4RedMask, bV4GreenMask, and bV4BlueMask).
175 * For BITMAPINFOHEADER the color masks are stored in the palette.
176 */
177
178 if (BitmapInfoHeader->biSize > sizeof(BITMAPINFOHEADER))
179 *ColorTableSize = 0;
180 else
181 *ColorTableSize = 3;
182
183 return TRUE;
184
185 case BI_RGB:
186 switch (BitCount)
187 {
188 case 1:
189 *ColorTableSize = ClrUsed ? min(ClrUsed, 2) : 2;
190 return TRUE;
191
192 case 4:
193 *ColorTableSize = ClrUsed ? min(ClrUsed, 16) : 16;
194 return TRUE;
195
196 case 8:
197 *ColorTableSize = ClrUsed ? min(ClrUsed, 256) : 256;
198 return TRUE;
199
200 default:
201 if (*ColorSpec == DIB_PAL_COLORS)
202 *ColorSpec = DIB_RGB_COLORS;
203 if (BitCount != 16 && BitCount != 24 && BitCount != 32)
204 return FALSE;
205 *ColorTableSize = ClrUsed;
206 return TRUE;
207 }
208
209 case BI_RLE4:
210 if (BitCount == 4)
211 {
212 *ColorTableSize = ClrUsed ? min(ClrUsed, 16) : 16;
213 return TRUE;
214 }
215 return FALSE;
216
217 case BI_RLE8:
218 if (BitCount == 8)
219 {
220 *ColorTableSize = ClrUsed ? min(ClrUsed, 256) : 256;
221 return TRUE;
222 }
223 return FALSE;
224
225 case BI_JPEG:
226 case BI_PNG:
227 *ColorTableSize = ClrUsed;
228 return TRUE;
229
230 default:
231 return FALSE;
232 }
233 }
234
235 HBRUSH STDCALL
236 IntGdiCreateDIBBrush(
237 CONST BITMAPINFO *BitmapInfo,
238 UINT ColorSpec,
239 UINT BitmapInfoSize,
240 CONST VOID *PackedDIB)
241 {
242 HBRUSH hBrush;
243 PGDIBRUSHOBJ BrushObject;
244 HBITMAP hPattern;
245 ULONG_PTR DataPtr;
246 UINT PaletteEntryCount;
247 PBITMAPOBJ BitmapObject;
248 INT PaletteType;
249
250 if (BitmapInfo->bmiHeader.biSize < sizeof(BITMAPINFOHEADER))
251 {
252 SetLastWin32Error(ERROR_INVALID_PARAMETER);
253 return NULL;
254 }
255
256 if (!CalculateColorTableSize(&BitmapInfo->bmiHeader, &ColorSpec,
257 &PaletteEntryCount))
258 {
259 SetLastWin32Error(ERROR_INVALID_PARAMETER);
260 return NULL;
261 }
262
263 DataPtr = (ULONG_PTR)BitmapInfo + BitmapInfo->bmiHeader.biSize;
264 if (ColorSpec == DIB_RGB_COLORS)
265 DataPtr += PaletteEntryCount * sizeof(RGBQUAD);
266 else
267 DataPtr += PaletteEntryCount * sizeof(USHORT);
268
269 hPattern = NtGdiCreateBitmap(BitmapInfo->bmiHeader.biWidth,
270 BitmapInfo->bmiHeader.biHeight,
271 BitmapInfo->bmiHeader.biPlanes,
272 BitmapInfo->bmiHeader.biBitCount,
273 (PVOID)DataPtr);
274 if (hPattern == NULL)
275 {
276 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
277 return NULL;
278 }
279
280 BitmapObject = BITMAPOBJ_LockBitmap(hPattern);
281 ASSERT(BitmapObject != NULL);
282 BitmapObject->hDIBPalette = BuildDIBPalette(BitmapInfo, &PaletteType);
283 BITMAPOBJ_UnlockBitmap(BitmapObject);
284
285 hBrush = BRUSHOBJ_AllocBrush();
286 if (hBrush == NULL)
287 {
288 NtGdiDeleteObject(hPattern);
289 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
290 return NULL;
291 }
292
293 BrushObject = BRUSHOBJ_LockBrush(hBrush);
294 ASSERT(BrushObject != NULL);
295
296 BrushObject->flAttrs |= GDIBRUSH_IS_BITMAP | GDIBRUSH_IS_DIB;
297 BrushObject->hbmPattern = hPattern;
298 /* FIXME: Fill in the rest of fields!!! */
299
300 GDIOBJ_SetOwnership(hPattern, NULL);
301
302 BRUSHOBJ_UnlockBrush(BrushObject);
303
304 return hBrush;
305 }
306
307 HBRUSH STDCALL
308 IntGdiCreateHatchBrush(
309 INT Style,
310 COLORREF Color)
311 {
312 HBRUSH hBrush;
313 PGDIBRUSHOBJ BrushObject;
314 HBITMAP hPattern;
315
316 if (Style < 0 || Style >= NB_HATCH_STYLES)
317 {
318 return 0;
319 }
320
321 hPattern = NtGdiCreateBitmap(8, 8, 1, 1, (LPBYTE)HatchBrushes[Style]);
322 if (hPattern == NULL)
323 {
324 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
325 return NULL;
326 }
327
328 hBrush = BRUSHOBJ_AllocBrush();
329 if (hBrush == NULL)
330 {
331 NtGdiDeleteObject(hPattern);
332 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
333 return NULL;
334 }
335
336 BrushObject = BRUSHOBJ_LockBrush(hBrush);
337 ASSERT(BrushObject != NULL);
338
339 BrushObject->flAttrs |= GDIBRUSH_IS_HATCH;
340 BrushObject->hbmPattern = hPattern;
341 BrushObject->BrushAttr.lbColor = Color & 0xFFFFFF;
342
343 GDIOBJ_SetOwnership(hPattern, NULL);
344
345 BRUSHOBJ_UnlockBrush(BrushObject);
346
347 return hBrush;
348 }
349
350 HBRUSH STDCALL
351 IntGdiCreatePatternBrush(
352 HBITMAP hBitmap)
353 {
354 HBRUSH hBrush;
355 PGDIBRUSHOBJ BrushObject;
356 HBITMAP hPattern;
357
358 hPattern = BITMAPOBJ_CopyBitmap(hBitmap);
359 if (hPattern == NULL)
360 {
361 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
362 return NULL;
363 }
364
365 hBrush = BRUSHOBJ_AllocBrush();
366 if (hBrush == NULL)
367 {
368 NtGdiDeleteObject(hPattern);
369 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
370 return NULL;
371 }
372
373 BrushObject = BRUSHOBJ_LockBrush(hBrush);
374 ASSERT(BrushObject != NULL);
375
376 BrushObject->flAttrs |= GDIBRUSH_IS_BITMAP;
377 BrushObject->hbmPattern = hPattern;
378 /* FIXME: Fill in the rest of fields!!! */
379
380 GDIOBJ_SetOwnership(hPattern, NULL);
381
382 BRUSHOBJ_UnlockBrush(BrushObject);
383
384 return hBrush;
385 }
386
387 HBRUSH STDCALL
388 IntGdiCreateSolidBrush(
389 COLORREF Color)
390 {
391 HBRUSH hBrush;
392 PGDIBRUSHOBJ BrushObject;
393
394 hBrush = BRUSHOBJ_AllocBrush();
395 if (hBrush == NULL)
396 {
397 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
398 return NULL;
399 }
400
401 BrushObject = BRUSHOBJ_LockBrush(hBrush);
402 ASSERT(BrushObject != NULL);
403
404 BrushObject->flAttrs |= GDIBRUSH_IS_SOLID;
405 BrushObject->BrushAttr.lbColor = Color & 0xFFFFFF;
406 /* FIXME: Fill in the rest of fields!!! */
407
408 BRUSHOBJ_UnlockBrush(BrushObject);
409
410 return hBrush;
411 }
412
413 HBRUSH STDCALL
414 IntGdiCreateNullBrush(VOID)
415 {
416 HBRUSH hBrush;
417 PGDIBRUSHOBJ BrushObject;
418
419 hBrush = BRUSHOBJ_AllocBrush();
420 if (hBrush == NULL)
421 {
422 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
423 return NULL;
424 }
425
426 BrushObject = BRUSHOBJ_LockBrush(hBrush);
427 ASSERT(BrushObject != NULL);
428 BrushObject->flAttrs |= GDIBRUSH_IS_NULL;
429 BRUSHOBJ_UnlockBrush(BrushObject);
430
431 return hBrush;
432 }
433
434 BOOL FASTCALL
435 IntPatBlt(
436 PDC dc,
437 INT XLeft,
438 INT YLeft,
439 INT Width,
440 INT Height,
441 DWORD ROP,
442 PGDIBRUSHOBJ BrushObj)
443 {
444 RECTL DestRect;
445 BITMAPOBJ *BitmapObj;
446 GDIBRUSHINST BrushInst;
447 POINTL BrushOrigin;
448 BOOL ret = TRUE;
449
450 ASSERT(BrushObj);
451
452 BitmapObj = BITMAPOBJ_LockBitmap(dc->w.hBitmap);
453 if (BitmapObj == NULL)
454 {
455 SetLastWin32Error(ERROR_INVALID_HANDLE);
456 return FALSE;
457 }
458
459 if (!(BrushObj->flAttrs & GDIBRUSH_IS_NULL))
460 {
461 if (Width > 0)
462 {
463 DestRect.left = XLeft + dc->w.DCOrgX;
464 DestRect.right = XLeft + Width + dc->w.DCOrgX;
465 }
466 else
467 {
468 DestRect.left = XLeft + Width + 1 + dc->w.DCOrgX;
469 DestRect.right = XLeft + dc->w.DCOrgX + 1;
470 }
471
472 if (Height > 0)
473 {
474 DestRect.top = YLeft + dc->w.DCOrgY;
475 DestRect.bottom = YLeft + Height + dc->w.DCOrgY;
476 }
477 else
478 {
479 DestRect.top = YLeft + Height + dc->w.DCOrgY + 1;
480 DestRect.bottom = YLeft + dc->w.DCOrgY + 1;
481 }
482
483 BrushOrigin.x = BrushObj->ptOrigin.x + dc->w.DCOrgX;
484 BrushOrigin.y = BrushObj->ptOrigin.y + dc->w.DCOrgY;
485
486 IntGdiInitBrushInstance(&BrushInst, BrushObj, dc->XlateBrush);
487
488 ret = IntEngBitBlt(
489 &BitmapObj->SurfObj,
490 NULL,
491 NULL,
492 dc->CombinedClip,
493 NULL,
494 &DestRect,
495 NULL,
496 NULL,
497 &BrushInst.BrushObject,
498 &BrushOrigin,
499 ROP3_TO_ROP4(ROP));
500 }
501
502 BITMAPOBJ_UnlockBitmap(BitmapObj);
503
504 return ret;
505 }
506
507 BOOL FASTCALL
508 IntGdiPolyPatBlt(
509 HDC hDC,
510 DWORD dwRop,
511 PPATRECT pRects,
512 int cRects,
513 ULONG Reserved)
514 {
515 int i;
516 PPATRECT r;
517 PGDIBRUSHOBJ BrushObj;
518 DC *dc;
519
520 dc = DC_LockDc(hDC);
521 if (dc == NULL)
522 {
523 SetLastWin32Error(ERROR_INVALID_HANDLE);
524 return FALSE;
525 }
526 if (dc->IsIC)
527 {
528 DC_UnlockDc(dc);
529 /* Yes, Windows really returns TRUE in this case */
530 return TRUE;
531 }
532
533 for (r = pRects, i = 0; i < cRects; i++)
534 {
535 BrushObj = BRUSHOBJ_LockBrush(r->hBrush);
536 if(BrushObj != NULL)
537 {
538 IntPatBlt(
539 dc,
540 r->r.left,
541 r->r.top,
542 r->r.right,
543 r->r.bottom,
544 dwRop,
545 BrushObj);
546 BRUSHOBJ_UnlockBrush(BrushObj);
547 }
548 r++;
549 }
550
551 DC_UnlockDc(dc);
552
553 return TRUE;
554 }
555
556 /* PUBLIC FUNCTIONS ***********************************************************/
557
558 HBRUSH STDCALL
559 NtGdiCreateDIBBrush(
560 IN PVOID BitmapInfoAndData,
561 IN FLONG ColorSpec,
562 IN UINT BitmapInfoSize,
563 IN BOOL b8X8,
564 IN BOOL bPen,
565 IN PVOID PackedDIB)
566 {
567 BITMAPINFO *SafeBitmapInfoAndData;
568 NTSTATUS Status = STATUS_SUCCESS;
569 HBRUSH hBrush;
570
571 SafeBitmapInfoAndData = EngAllocMem(0, BitmapInfoSize, 0);
572 if (SafeBitmapInfoAndData == NULL)
573 {
574 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
575 return NULL;
576 }
577
578 _SEH_TRY
579 {
580 ProbeForRead(BitmapInfoAndData,
581 BitmapInfoSize,
582 1);
583 RtlCopyMemory(SafeBitmapInfoAndData,
584 BitmapInfoAndData,
585 BitmapInfoSize);
586 }
587 _SEH_HANDLE
588 {
589 Status = _SEH_GetExceptionCode();
590 }
591 _SEH_END;
592
593 if (!NT_SUCCESS(Status))
594 {
595 EngFreeMem(SafeBitmapInfoAndData);
596 SetLastNtError(Status);
597 return 0;
598 }
599
600 hBrush = IntGdiCreateDIBBrush(SafeBitmapInfoAndData, ColorSpec,
601 BitmapInfoSize, PackedDIB);
602
603 EngFreeMem(SafeBitmapInfoAndData);
604
605 return hBrush;
606 }
607
608 HBRUSH STDCALL
609 NtGdiCreateHatchBrush(
610 INT Style,
611 COLORREF Color)
612 {
613 return IntGdiCreateHatchBrush(Style, Color);
614 }
615
616 HBRUSH STDCALL
617 NtGdiCreatePatternBrush(
618 HBITMAP hBitmap)
619 {
620 return IntGdiCreatePatternBrush(hBitmap);
621 }
622
623 HBRUSH STDCALL
624 NtGdiCreateSolidBrush(COLORREF Color,
625 IN OPTIONAL HBRUSH hbr)
626 {
627 return IntGdiCreateSolidBrush(Color);
628 }
629
630 /*
631 * NtGdiSetBrushOrgEx
632 *
633 * The NtGdiSetBrushOrgEx function sets the brush origin that GDI assigns to
634 * the next brush an application selects into the specified device context.
635 *
636 * Status
637 * @implemented
638 */
639
640 BOOL STDCALL
641 NtGdiSetBrushOrgEx(HDC hDC, INT XOrg, INT YOrg, LPPOINT Point)
642 {
643 PDC dc = DC_LockDc(hDC);
644 if (dc == NULL)
645 {
646 SetLastWin32Error(ERROR_INVALID_HANDLE);
647 return FALSE;
648 }
649
650 if (Point != NULL)
651 {
652 NTSTATUS Status = STATUS_SUCCESS;
653 POINT SafePoint;
654 SafePoint.x = dc->w.brushOrgX;
655 SafePoint.y = dc->w.brushOrgY;
656 _SEH_TRY
657 {
658 ProbeForWrite(Point,
659 sizeof(POINT),
660 1);
661 *Point = SafePoint;
662 }
663 _SEH_HANDLE
664 {
665 Status = _SEH_GetExceptionCode();
666 }
667 _SEH_END;
668
669 if(!NT_SUCCESS(Status))
670 {
671 DC_UnlockDc(dc);
672 SetLastNtError(Status);
673 return FALSE;
674 }
675 }
676
677 dc->w.brushOrgX = XOrg;
678 dc->w.brushOrgY = YOrg;
679 DC_UnlockDc(dc);
680
681 return TRUE;
682 }
683
684 BOOL STDCALL
685 NtGdiPolyPatBlt(
686 HDC hDC,
687 DWORD dwRop,
688 IN PPOLYPATBLT pRects,
689 IN DWORD cRects,
690 IN DWORD Mode)
691 {
692 PPATRECT rb = NULL;
693 NTSTATUS Status = STATUS_SUCCESS;
694 BOOL Ret;
695
696 if (cRects > 0)
697 {
698 rb = ExAllocatePoolWithTag(PagedPool, sizeof(PATRECT) * cRects, TAG_PATBLT);
699 if (!rb)
700 {
701 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
702 return FALSE;
703 }
704 _SEH_TRY
705 {
706 ProbeForRead(pRects,
707 cRects * sizeof(PATRECT),
708 1);
709 RtlCopyMemory(rb,
710 pRects,
711 cRects * sizeof(PATRECT));
712 }
713 _SEH_HANDLE
714 {
715 Status = _SEH_GetExceptionCode();
716 }
717 _SEH_END;
718
719 if (!NT_SUCCESS(Status))
720 {
721 ExFreePool(rb);
722 SetLastNtError(Status);
723 return FALSE;
724 }
725 }
726
727 Ret = IntGdiPolyPatBlt(hDC, dwRop, (PPATRECT)pRects, cRects, Mode);
728
729 if (cRects > 0)
730 ExFreePool(rb);
731
732 return Ret;
733 }
734
735 BOOL STDCALL
736 NtGdiPatBlt(
737 HDC hDC,
738 INT XLeft,
739 INT YLeft,
740 INT Width,
741 INT Height,
742 DWORD ROP)
743 {
744 PGDIBRUSHOBJ BrushObj;
745 DC *dc = DC_LockDc(hDC);
746 BOOL ret;
747
748 if (dc == NULL)
749 {
750 SetLastWin32Error(ERROR_INVALID_HANDLE);
751 return FALSE;
752 }
753 if (dc->IsIC)
754 {
755 DC_UnlockDc(dc);
756 /* Yes, Windows really returns TRUE in this case */
757 return TRUE;
758 }
759
760 BrushObj = BRUSHOBJ_LockBrush(dc->w.hBrush);
761 if (BrushObj == NULL)
762 {
763 SetLastWin32Error(ERROR_INVALID_HANDLE);
764 DC_UnlockDc(dc);
765 return FALSE;
766 }
767
768 ret = IntPatBlt(
769 dc,
770 XLeft,
771 YLeft,
772 Width,
773 Height,
774 ROP,
775 BrushObj);
776
777 BRUSHOBJ_UnlockBrush(BrushObj);
778 DC_UnlockDc(dc);
779
780 return ret;
781 }
782
783 /* EOF */