Small fix for the patch special char patch earlier.
[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 IntLPtoDP(dc, (LPPOINT)&DestRect, 2);
484
485 BrushOrigin.x = BrushObj->ptOrigin.x + dc->w.DCOrgX;
486 BrushOrigin.y = BrushObj->ptOrigin.y + dc->w.DCOrgY;
487
488 IntGdiInitBrushInstance(&BrushInst, BrushObj, dc->XlateBrush);
489
490 ret = IntEngBitBlt(
491 &BitmapObj->SurfObj,
492 NULL,
493 NULL,
494 dc->CombinedClip,
495 NULL,
496 &DestRect,
497 NULL,
498 NULL,
499 &BrushInst.BrushObject,
500 &BrushOrigin,
501 ROP3_TO_ROP4(ROP));
502 }
503
504 BITMAPOBJ_UnlockBitmap(BitmapObj);
505
506 return ret;
507 }
508
509 BOOL FASTCALL
510 IntGdiPolyPatBlt(
511 HDC hDC,
512 DWORD dwRop,
513 PPATRECT pRects,
514 int cRects,
515 ULONG Reserved)
516 {
517 int i;
518 PPATRECT r;
519 PGDIBRUSHOBJ BrushObj;
520 DC *dc;
521
522 dc = DC_LockDc(hDC);
523 if (dc == NULL)
524 {
525 SetLastWin32Error(ERROR_INVALID_HANDLE);
526 return FALSE;
527 }
528 if (dc->IsIC)
529 {
530 DC_UnlockDc(dc);
531 /* Yes, Windows really returns TRUE in this case */
532 return TRUE;
533 }
534
535 for (r = pRects, i = 0; i < cRects; i++)
536 {
537 BrushObj = BRUSHOBJ_LockBrush(r->hBrush);
538 if(BrushObj != NULL)
539 {
540 IntPatBlt(
541 dc,
542 r->r.left,
543 r->r.top,
544 r->r.right,
545 r->r.bottom,
546 dwRop,
547 BrushObj);
548 BRUSHOBJ_UnlockBrush(BrushObj);
549 }
550 r++;
551 }
552
553 DC_UnlockDc(dc);
554
555 return TRUE;
556 }
557
558 /* PUBLIC FUNCTIONS ***********************************************************/
559
560 HBRUSH STDCALL
561 NtGdiCreateDIBBrush(
562 IN PVOID BitmapInfoAndData,
563 IN FLONG ColorSpec,
564 IN UINT BitmapInfoSize,
565 IN BOOL b8X8,
566 IN BOOL bPen,
567 IN PVOID PackedDIB)
568 {
569 BITMAPINFO *SafeBitmapInfoAndData;
570 NTSTATUS Status = STATUS_SUCCESS;
571 HBRUSH hBrush;
572
573 SafeBitmapInfoAndData = EngAllocMem(0, BitmapInfoSize, 0);
574 if (SafeBitmapInfoAndData == NULL)
575 {
576 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
577 return NULL;
578 }
579
580 _SEH_TRY
581 {
582 ProbeForRead(BitmapInfoAndData,
583 BitmapInfoSize,
584 1);
585 RtlCopyMemory(SafeBitmapInfoAndData,
586 BitmapInfoAndData,
587 BitmapInfoSize);
588 }
589 _SEH_HANDLE
590 {
591 Status = _SEH_GetExceptionCode();
592 }
593 _SEH_END;
594
595 if (!NT_SUCCESS(Status))
596 {
597 EngFreeMem(SafeBitmapInfoAndData);
598 SetLastNtError(Status);
599 return 0;
600 }
601
602 hBrush = IntGdiCreateDIBBrush(SafeBitmapInfoAndData, ColorSpec,
603 BitmapInfoSize, PackedDIB);
604
605 EngFreeMem(SafeBitmapInfoAndData);
606
607 return hBrush;
608 }
609
610 HBRUSH STDCALL
611 NtGdiCreateHatchBrush(
612 INT Style,
613 COLORREF Color)
614 {
615 return IntGdiCreateHatchBrush(Style, Color);
616 }
617
618 HBRUSH STDCALL
619 NtGdiCreatePatternBrush(
620 HBITMAP hBitmap)
621 {
622 return IntGdiCreatePatternBrush(hBitmap);
623 }
624
625 HBRUSH STDCALL
626 NtGdiCreateSolidBrush(COLORREF Color,
627 IN OPTIONAL HBRUSH hbr)
628 {
629 return IntGdiCreateSolidBrush(Color);
630 }
631
632 /*
633 * NtGdiSetBrushOrgEx
634 *
635 * The NtGdiSetBrushOrgEx function sets the brush origin that GDI assigns to
636 * the next brush an application selects into the specified device context.
637 *
638 * Status
639 * @implemented
640 */
641
642 BOOL STDCALL
643 NtGdiSetBrushOrgEx(HDC hDC, INT XOrg, INT YOrg, LPPOINT Point)
644 {
645 PDC dc = DC_LockDc(hDC);
646 if (dc == NULL)
647 {
648 SetLastWin32Error(ERROR_INVALID_HANDLE);
649 return FALSE;
650 }
651
652 if (Point != NULL)
653 {
654 NTSTATUS Status = STATUS_SUCCESS;
655 POINT SafePoint;
656 SafePoint.x = dc->w.brushOrgX;
657 SafePoint.y = dc->w.brushOrgY;
658 _SEH_TRY
659 {
660 ProbeForWrite(Point,
661 sizeof(POINT),
662 1);
663 *Point = SafePoint;
664 }
665 _SEH_HANDLE
666 {
667 Status = _SEH_GetExceptionCode();
668 }
669 _SEH_END;
670
671 if(!NT_SUCCESS(Status))
672 {
673 DC_UnlockDc(dc);
674 SetLastNtError(Status);
675 return FALSE;
676 }
677 }
678
679 dc->w.brushOrgX = XOrg;
680 dc->w.brushOrgY = YOrg;
681 DC_UnlockDc(dc);
682
683 return TRUE;
684 }
685
686 BOOL STDCALL
687 NtGdiPolyPatBlt(
688 HDC hDC,
689 DWORD dwRop,
690 IN PPOLYPATBLT pRects,
691 IN DWORD cRects,
692 IN DWORD Mode)
693 {
694 PPATRECT rb = NULL;
695 NTSTATUS Status = STATUS_SUCCESS;
696 BOOL Ret;
697
698 if (cRects > 0)
699 {
700 rb = ExAllocatePoolWithTag(PagedPool, sizeof(PATRECT) * cRects, TAG_PATBLT);
701 if (!rb)
702 {
703 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
704 return FALSE;
705 }
706 _SEH_TRY
707 {
708 ProbeForRead(pRects,
709 cRects * sizeof(PATRECT),
710 1);
711 RtlCopyMemory(rb,
712 pRects,
713 cRects * sizeof(PATRECT));
714 }
715 _SEH_HANDLE
716 {
717 Status = _SEH_GetExceptionCode();
718 }
719 _SEH_END;
720
721 if (!NT_SUCCESS(Status))
722 {
723 ExFreePool(rb);
724 SetLastNtError(Status);
725 return FALSE;
726 }
727 }
728
729 Ret = IntGdiPolyPatBlt(hDC, dwRop, (PPATRECT)pRects, cRects, Mode);
730
731 if (cRects > 0)
732 ExFreePool(rb);
733
734 return Ret;
735 }
736
737 BOOL STDCALL
738 NtGdiPatBlt(
739 HDC hDC,
740 INT XLeft,
741 INT YLeft,
742 INT Width,
743 INT Height,
744 DWORD ROP)
745 {
746 PGDIBRUSHOBJ BrushObj;
747 DC *dc = DC_LockDc(hDC);
748 BOOL ret;
749
750 if (dc == NULL)
751 {
752 SetLastWin32Error(ERROR_INVALID_HANDLE);
753 return FALSE;
754 }
755 if (dc->IsIC)
756 {
757 DC_UnlockDc(dc);
758 /* Yes, Windows really returns TRUE in this case */
759 return TRUE;
760 }
761
762 BrushObj = BRUSHOBJ_LockBrush(dc->w.hBrush);
763 if (BrushObj == NULL)
764 {
765 SetLastWin32Error(ERROR_INVALID_HANDLE);
766 DC_UnlockDc(dc);
767 return FALSE;
768 }
769
770 ret = IntPatBlt(
771 dc,
772 XLeft,
773 YLeft,
774 Width,
775 Height,
776 ROP,
777 BrushObj);
778
779 BRUSHOBJ_UnlockBrush(BrushObj);
780 DC_UnlockDc(dc);
781
782 return ret;
783 }
784
785 /* EOF */