* Replace NtGdiCreatePatternBrush and NtGdiCreateHatchBrush with NtGdiCreatePatternBr...
[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 NtGdiCreateHatchBrushInternal(
612 ULONG Style,
613 COLORREF Color,
614 BOOL bPen)
615 {
616 return IntGdiCreateHatchBrush(Style, Color);
617 }
618
619 HBRUSH STDCALL
620 NtGdiCreatePatternBrushInternal(
621 HBITMAP hBitmap,
622 BOOL bPen,
623 BOOL b8x8)
624 {
625 return IntGdiCreatePatternBrush(hBitmap);
626 }
627
628 HBRUSH STDCALL
629 NtGdiCreateSolidBrush(COLORREF Color,
630 IN OPTIONAL HBRUSH hbr)
631 {
632 return IntGdiCreateSolidBrush(Color);
633 }
634
635 /*
636 * NtGdiSetBrushOrgEx
637 *
638 * The NtGdiSetBrushOrgEx function sets the brush origin that GDI assigns to
639 * the next brush an application selects into the specified device context.
640 *
641 * Status
642 * @implemented
643 */
644
645 BOOL STDCALL
646 NtGdiSetBrushOrgEx(HDC hDC, INT XOrg, INT YOrg, LPPOINT Point)
647 {
648 PDC dc = DC_LockDc(hDC);
649 if (dc == NULL)
650 {
651 SetLastWin32Error(ERROR_INVALID_HANDLE);
652 return FALSE;
653 }
654
655 if (Point != NULL)
656 {
657 NTSTATUS Status = STATUS_SUCCESS;
658 POINT SafePoint;
659 SafePoint.x = dc->w.brushOrgX;
660 SafePoint.y = dc->w.brushOrgY;
661 _SEH_TRY
662 {
663 ProbeForWrite(Point,
664 sizeof(POINT),
665 1);
666 *Point = SafePoint;
667 }
668 _SEH_HANDLE
669 {
670 Status = _SEH_GetExceptionCode();
671 }
672 _SEH_END;
673
674 if(!NT_SUCCESS(Status))
675 {
676 DC_UnlockDc(dc);
677 SetLastNtError(Status);
678 return FALSE;
679 }
680 }
681
682 dc->w.brushOrgX = XOrg;
683 dc->w.brushOrgY = YOrg;
684 DC_UnlockDc(dc);
685
686 return TRUE;
687 }
688
689 BOOL STDCALL
690 NtGdiPolyPatBlt(
691 HDC hDC,
692 DWORD dwRop,
693 IN PPOLYPATBLT pRects,
694 IN DWORD cRects,
695 IN DWORD Mode)
696 {
697 PPATRECT rb = NULL;
698 NTSTATUS Status = STATUS_SUCCESS;
699 BOOL Ret;
700
701 if (cRects > 0)
702 {
703 rb = ExAllocatePoolWithTag(PagedPool, sizeof(PATRECT) * cRects, TAG_PATBLT);
704 if (!rb)
705 {
706 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
707 return FALSE;
708 }
709 _SEH_TRY
710 {
711 ProbeForRead(pRects,
712 cRects * sizeof(PATRECT),
713 1);
714 RtlCopyMemory(rb,
715 pRects,
716 cRects * sizeof(PATRECT));
717 }
718 _SEH_HANDLE
719 {
720 Status = _SEH_GetExceptionCode();
721 }
722 _SEH_END;
723
724 if (!NT_SUCCESS(Status))
725 {
726 ExFreePool(rb);
727 SetLastNtError(Status);
728 return FALSE;
729 }
730 }
731
732 Ret = IntGdiPolyPatBlt(hDC, dwRop, (PPATRECT)pRects, cRects, Mode);
733
734 if (cRects > 0)
735 ExFreePool(rb);
736
737 return Ret;
738 }
739
740 BOOL STDCALL
741 NtGdiPatBlt(
742 HDC hDC,
743 INT XLeft,
744 INT YLeft,
745 INT Width,
746 INT Height,
747 DWORD ROP)
748 {
749 PGDIBRUSHOBJ BrushObj;
750 DC *dc = DC_LockDc(hDC);
751 BOOL ret;
752
753 if (dc == NULL)
754 {
755 SetLastWin32Error(ERROR_INVALID_HANDLE);
756 return FALSE;
757 }
758 if (dc->IsIC)
759 {
760 DC_UnlockDc(dc);
761 /* Yes, Windows really returns TRUE in this case */
762 return TRUE;
763 }
764
765 BrushObj = BRUSHOBJ_LockBrush(dc->w.hBrush);
766 if (BrushObj == NULL)
767 {
768 SetLastWin32Error(ERROR_INVALID_HANDLE);
769 DC_UnlockDc(dc);
770 return FALSE;
771 }
772
773 ret = IntPatBlt(
774 dc,
775 XLeft,
776 YLeft,
777 Width,
778 Height,
779 ROP,
780 BrushObj);
781
782 BRUSHOBJ_UnlockBrush(BrushObj);
783 DC_UnlockDc(dc);
784
785 return ret;
786 }
787
788 /* EOF */