Sync with trunk head (part 1 of 2)
[reactos.git] / subsystems / win32 / win32k / objects / brush.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS win32 subsystem
4 * PURPOSE: Functions for brushes
5 * FILE: subsystem/win32/win32k/objects/brush.c
6 * PROGRAMER:
7 */
8
9 #include <win32k.h>
10
11 #define NDEBUG
12 #include <debug.h>
13
14 #define GDIOBJATTRFREE 170
15
16 typedef struct _GDI_OBJ_ATTR_FREELIST
17 {
18 LIST_ENTRY Entry;
19 DWORD nEntries;
20 PVOID AttrList[GDIOBJATTRFREE];
21 } GDI_OBJ_ATTR_FREELIST, *PGDI_OBJ_ATTR_FREELIST;
22
23 typedef struct _GDI_OBJ_ATTR_ENTRY
24 {
25 RGN_ATTR Attr[GDIOBJATTRFREE];
26 } GDI_OBJ_ATTR_ENTRY, *PGDI_OBJ_ATTR_ENTRY;
27
28 static const USHORT HatchBrushes[NB_HATCH_STYLES][8] =
29 {
30 {0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF}, /* HS_HORIZONTAL */
31 {0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7}, /* HS_VERTICAL */
32 {0xFE, 0xFD, 0xFB, 0xF7, 0xEF, 0xDF, 0xBF, 0x7F}, /* HS_FDIAGONAL */
33 {0x7F, 0xBF, 0xDF, 0xEF, 0xF7, 0xFB, 0xFD, 0xFE}, /* HS_BDIAGONAL */
34 {0xF7, 0xF7, 0xF7, 0xF7, 0x00, 0xF7, 0xF7, 0xF7}, /* HS_CROSS */
35 {0x7E, 0xBD, 0xDB, 0xE7, 0xE7, 0xDB, 0xBD, 0x7E} /* HS_DIAGCROSS */
36 };
37
38
39 PVOID
40 FASTCALL
41 AllocateObjectAttr(VOID)
42 {
43 PTHREADINFO pti;
44 PPROCESSINFO ppi;
45 PVOID pAttr;
46 PGDI_OBJ_ATTR_FREELIST pGdiObjAttrFreeList;
47 PGDI_OBJ_ATTR_ENTRY pGdiObjAttrEntry;
48 int i;
49
50 pti = PsGetCurrentThreadWin32Thread();
51 if (pti->pgdiBrushAttr)
52 {
53 pAttr = pti->pgdiBrushAttr; // Get the free one.
54 pti->pgdiBrushAttr = NULL;
55 return pAttr;
56 }
57
58 ppi = PsGetCurrentProcessWin32Process();
59
60 if (!ppi->pBrushAttrList) // If set point is null, allocate new group.
61 {
62 pGdiObjAttrEntry = EngAllocUserMem(sizeof(GDI_OBJ_ATTR_ENTRY), 0);
63
64 if (!pGdiObjAttrEntry)
65 {
66 DPRINT1("Attr Failed User Allocation!\n");
67 return NULL;
68 }
69
70 DPRINT("AllocObjectAttr User 0x%x\n",pGdiObjAttrEntry);
71
72 pGdiObjAttrFreeList = ExAllocatePoolWithTag( PagedPool,
73 sizeof(GDI_OBJ_ATTR_FREELIST),
74 GDITAG_BRUSH_FREELIST);
75 if ( !pGdiObjAttrFreeList )
76 {
77 EngFreeUserMem(pGdiObjAttrEntry);
78 return NULL;
79 }
80
81 RtlZeroMemory(pGdiObjAttrFreeList, sizeof(GDI_OBJ_ATTR_FREELIST));
82
83 DPRINT("AllocObjectAttr Ex 0x%x\n",pGdiObjAttrFreeList);
84
85 InsertHeadList( &ppi->GDIBrushAttrFreeList, &pGdiObjAttrFreeList->Entry);
86
87 pGdiObjAttrFreeList->nEntries = GDIOBJATTRFREE;
88 // Start at the bottom up and set end of free list point.
89 ppi->pBrushAttrList = &pGdiObjAttrEntry->Attr[GDIOBJATTRFREE-1];
90 // Build the free attr list.
91 for ( i = 0; i < GDIOBJATTRFREE; i++)
92 {
93 pGdiObjAttrFreeList->AttrList[i] = &pGdiObjAttrEntry->Attr[i];
94 }
95 }
96
97 pAttr = ppi->pBrushAttrList;
98 pGdiObjAttrFreeList = (PGDI_OBJ_ATTR_FREELIST)ppi->GDIBrushAttrFreeList.Flink;
99
100 // Free the list when it is full!
101 if ( pGdiObjAttrFreeList->nEntries-- == 1)
102 { // No more free entries, so yank the list.
103 RemoveEntryList( &pGdiObjAttrFreeList->Entry );
104
105 ExFreePoolWithTag( pGdiObjAttrFreeList, GDITAG_BRUSH_FREELIST );
106
107 if ( IsListEmpty( &ppi->GDIBrushAttrFreeList ) )
108 {
109 ppi->pBrushAttrList = NULL;
110 return pAttr;
111 }
112
113 pGdiObjAttrFreeList = (PGDI_OBJ_ATTR_FREELIST)ppi->GDIBrushAttrFreeList.Flink;
114 }
115
116 ppi->pBrushAttrList = pGdiObjAttrFreeList->AttrList[pGdiObjAttrFreeList->nEntries-1];
117
118 return pAttr;
119 }
120
121 VOID
122 FASTCALL
123 FreeObjectAttr(PVOID pAttr)
124 {
125 PTHREADINFO pti;
126 PPROCESSINFO ppi;
127 PGDI_OBJ_ATTR_FREELIST pGdiObjAttrFreeList;
128
129 pti = PsGetCurrentThreadWin32Thread();
130
131 if (!pti) return;
132
133 if (!pti->pgdiBrushAttr)
134 { // If it is null, just cache it for the next time.
135 pti->pgdiBrushAttr = pAttr;
136 return;
137 }
138
139 ppi = PsGetCurrentProcessWin32Process();
140
141 pGdiObjAttrFreeList = (PGDI_OBJ_ATTR_FREELIST)ppi->GDIBrushAttrFreeList.Flink;
142
143 // We add to the list of free entries, so this will grows!
144 if ( IsListEmpty(&ppi->GDIBrushAttrFreeList) ||
145 pGdiObjAttrFreeList->nEntries == GDIOBJATTRFREE )
146 {
147 pGdiObjAttrFreeList = ExAllocatePoolWithTag( PagedPool,
148 sizeof(GDI_OBJ_ATTR_FREELIST),
149 GDITAG_BRUSH_FREELIST);
150 if ( !pGdiObjAttrFreeList )
151 {
152 return;
153 }
154 InsertHeadList( &ppi->GDIBrushAttrFreeList, &pGdiObjAttrFreeList->Entry);
155 pGdiObjAttrFreeList->nEntries = 0;
156 }
157 // Up count, save the entry and set end of free list point.
158 ++pGdiObjAttrFreeList->nEntries; // Top Down...
159 pGdiObjAttrFreeList->AttrList[pGdiObjAttrFreeList->nEntries-1] = pAttr;
160 ppi->pBrushAttrList = pAttr;
161
162 return;
163 }
164
165
166 BOOL
167 INTERNAL_CALL
168 BRUSH_Cleanup(PVOID ObjectBody)
169 {
170 PBRUSH pbrush = (PBRUSH)ObjectBody;
171 if (pbrush->flAttrs & (GDIBRUSH_IS_HATCH | GDIBRUSH_IS_BITMAP))
172 {
173 ASSERT(pbrush->hbmPattern);
174 GDIOBJ_SetOwnership(pbrush->hbmPattern, PsGetCurrentProcess());
175 GreDeleteObject(pbrush->hbmPattern);
176 }
177
178 /* Free the kmode styles array of EXTPENS */
179 if (pbrush->pStyle)
180 {
181 ExFreePool(pbrush->pStyle);
182 }
183
184 return TRUE;
185 }
186
187 INT
188 FASTCALL
189 BRUSH_GetObject(PBRUSH pbrush, INT Count, LPLOGBRUSH Buffer)
190 {
191 if (Buffer == NULL) return sizeof(LOGBRUSH);
192 if (Count == 0) return 0;
193
194 /* Set colour */
195 Buffer->lbColor = pbrush->BrushAttr.lbColor;
196
197 /* Set Hatch */
198 if ((pbrush->flAttrs & GDIBRUSH_IS_HATCH)!=0)
199 {
200 /* FIXME : this is not the right value */
201 Buffer->lbHatch = (LONG)pbrush->hbmPattern;
202 }
203 else
204 {
205 Buffer->lbHatch = 0;
206 }
207
208 Buffer->lbStyle = 0;
209
210 /* Get the type of style */
211 if ((pbrush->flAttrs & GDIBRUSH_IS_SOLID)!=0)
212 {
213 Buffer->lbStyle = BS_SOLID;
214 }
215 else if ((pbrush->flAttrs & GDIBRUSH_IS_NULL)!=0)
216 {
217 Buffer->lbStyle = BS_NULL; // BS_HOLLOW
218 }
219 else if ((pbrush->flAttrs & GDIBRUSH_IS_HATCH)!=0)
220 {
221 Buffer->lbStyle = BS_HATCHED;
222 }
223 else if ((pbrush->flAttrs & GDIBRUSH_IS_BITMAP)!=0)
224 {
225 Buffer->lbStyle = BS_PATTERN;
226 }
227 else if ((pbrush->flAttrs & GDIBRUSH_IS_DIB)!=0)
228 {
229 Buffer->lbStyle = BS_DIBPATTERN;
230 }
231
232 /* FIXME
233 else if ((pbrush->flAttrs & )!=0)
234 {
235 Buffer->lbStyle = BS_INDEXED;
236 }
237 else if ((pbrush->flAttrs & )!=0)
238 {
239 Buffer->lbStyle = BS_DIBPATTERNPT;
240 }
241 */
242
243 /* FIXME */
244 return sizeof(LOGBRUSH);
245 }
246
247 /**
248 * @name CalculateColorTableSize
249 *
250 * Internal routine to calculate the number of color table entries.
251 *
252 * @param BitmapInfoHeader
253 * Input bitmap information header, can be any version of
254 * BITMAPINFOHEADER or BITMAPCOREHEADER.
255 *
256 * @param ColorSpec
257 * Pointer to variable which specifiing the color mode (DIB_RGB_COLORS
258 * or DIB_RGB_COLORS). On successful return this value is normalized
259 * according to the bitmap info.
260 *
261 * @param ColorTableSize
262 * On successful return this variable is filled with number of
263 * entries in color table for the image with specified parameters.
264 *
265 * @return
266 * TRUE if the input values together form a valid image, FALSE otherwise.
267 */
268 BOOL
269 APIENTRY
270 CalculateColorTableSize(
271 CONST BITMAPINFOHEADER *BitmapInfoHeader,
272 UINT *ColorSpec,
273 UINT *ColorTableSize)
274 {
275 WORD BitCount;
276 DWORD ClrUsed;
277 DWORD Compression;
278
279 /*
280 * At first get some basic parameters from the passed BitmapInfoHeader
281 * structure. It can have one of the following formats:
282 * - BITMAPCOREHEADER (the oldest one with totally different layout
283 * from the others)
284 * - BITMAPINFOHEADER (the standard and most common header)
285 * - BITMAPV4HEADER (extension of BITMAPINFOHEADER)
286 * - BITMAPV5HEADER (extension of BITMAPV4HEADER)
287 */
288 if (BitmapInfoHeader->biSize == sizeof(BITMAPCOREHEADER))
289 {
290 BitCount = ((LPBITMAPCOREHEADER)BitmapInfoHeader)->bcBitCount;
291 ClrUsed = 0;
292 Compression = BI_RGB;
293 }
294 else
295 {
296 BitCount = BitmapInfoHeader->biBitCount;
297 ClrUsed = BitmapInfoHeader->biClrUsed;
298 Compression = BitmapInfoHeader->biCompression;
299 }
300
301 switch (Compression)
302 {
303 case BI_BITFIELDS:
304 if (*ColorSpec == DIB_PAL_COLORS)
305 *ColorSpec = DIB_RGB_COLORS;
306
307 if (BitCount != 16 && BitCount != 32)
308 return FALSE;
309
310 /* For BITMAPV4HEADER/BITMAPV5HEADER the masks are included in
311 * the structure itself (bV4RedMask, bV4GreenMask, and bV4BlueMask).
312 * For BITMAPINFOHEADER the color masks are stored in the palette. */
313 if (BitmapInfoHeader->biSize > sizeof(BITMAPINFOHEADER))
314 *ColorTableSize = 0;
315 else
316 *ColorTableSize = 3;
317
318 return TRUE;
319
320 case BI_RGB:
321 switch (BitCount)
322 {
323 case 1:
324 *ColorTableSize = ClrUsed ? min(ClrUsed, 2) : 2;
325 return TRUE;
326
327 case 4:
328 *ColorTableSize = ClrUsed ? min(ClrUsed, 16) : 16;
329 return TRUE;
330
331 case 8:
332 *ColorTableSize = ClrUsed ? min(ClrUsed, 256) : 256;
333 return TRUE;
334
335 default:
336 if (*ColorSpec == DIB_PAL_COLORS)
337 *ColorSpec = DIB_RGB_COLORS;
338 if (BitCount != 16 && BitCount != 24 && BitCount != 32)
339 return FALSE;
340 *ColorTableSize = ClrUsed;
341 return TRUE;
342 }
343
344 case BI_RLE4:
345 if (BitCount == 4)
346 {
347 *ColorTableSize = ClrUsed ? min(ClrUsed, 16) : 16;
348 return TRUE;
349 }
350 return FALSE;
351
352 case BI_RLE8:
353 if (BitCount == 8)
354 {
355 *ColorTableSize = ClrUsed ? min(ClrUsed, 256) : 256;
356 return TRUE;
357 }
358 return FALSE;
359
360 case BI_JPEG:
361 case BI_PNG:
362 *ColorTableSize = ClrUsed;
363 return TRUE;
364
365 default:
366 return FALSE;
367 }
368 }
369
370 HBRUSH
371 APIENTRY
372 IntGdiCreateDIBBrush(
373 CONST BITMAPINFO *BitmapInfo,
374 UINT ColorSpec,
375 UINT BitmapInfoSize,
376 CONST VOID *PackedDIB)
377 {
378 HBRUSH hBrush;
379 PBRUSH pbrush;
380 HBITMAP hPattern;
381 ULONG_PTR DataPtr;
382 UINT PaletteEntryCount;
383 PSURFACE psurfPattern;
384 INT PaletteType;
385
386 if (BitmapInfo->bmiHeader.biSize < sizeof(BITMAPINFOHEADER))
387 {
388 SetLastWin32Error(ERROR_INVALID_PARAMETER);
389 return NULL;
390 }
391
392 if (!CalculateColorTableSize(&BitmapInfo->bmiHeader,
393 &ColorSpec,
394 &PaletteEntryCount))
395 {
396 SetLastWin32Error(ERROR_INVALID_PARAMETER);
397 return NULL;
398 }
399
400 // FIXME: What about BI_BITFIELDS
401 DataPtr = (ULONG_PTR)BitmapInfo + BitmapInfo->bmiHeader.biSize;
402 if (ColorSpec == DIB_RGB_COLORS)
403 DataPtr += PaletteEntryCount * sizeof(RGBQUAD);
404 else
405 DataPtr += PaletteEntryCount * sizeof(USHORT);
406
407 hPattern = IntGdiCreateBitmap(BitmapInfo->bmiHeader.biWidth,
408 BitmapInfo->bmiHeader.biHeight,
409 BitmapInfo->bmiHeader.biPlanes,
410 BitmapInfo->bmiHeader.biBitCount,
411 (PVOID)DataPtr);
412 if (hPattern == NULL)
413 {
414 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
415 return NULL;
416 }
417
418 psurfPattern = SURFACE_LockSurface(hPattern);
419 ASSERT(psurfPattern != NULL);
420 psurfPattern->hDIBPalette = BuildDIBPalette(BitmapInfo, &PaletteType);
421 SURFACE_UnlockSurface(psurfPattern);
422
423 pbrush = BRUSH_AllocBrushWithHandle();
424 if (pbrush == NULL)
425 {
426 GreDeleteObject(hPattern);
427 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
428 return NULL;
429 }
430 hBrush = pbrush->BaseObject.hHmgr;
431
432 pbrush->flAttrs |= GDIBRUSH_IS_BITMAP | GDIBRUSH_IS_DIB;
433 pbrush->hbmPattern = hPattern;
434 /* FIXME: Fill in the rest of fields!!! */
435
436 GDIOBJ_SetOwnership(hPattern, NULL);
437
438 BRUSH_UnlockBrush(pbrush);
439
440 return hBrush;
441 }
442
443 HBRUSH
444 APIENTRY
445 IntGdiCreateHatchBrush(
446 INT Style,
447 COLORREF Color)
448 {
449 HBRUSH hBrush;
450 PBRUSH pbrush;
451 HBITMAP hPattern;
452
453 if (Style < 0 || Style >= NB_HATCH_STYLES)
454 {
455 return 0;
456 }
457
458 hPattern = IntGdiCreateBitmap(8, 8, 1, 1, (LPBYTE)HatchBrushes[Style]);
459 if (hPattern == NULL)
460 {
461 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
462 return NULL;
463 }
464
465 pbrush = BRUSH_AllocBrushWithHandle();
466 if (pbrush == NULL)
467 {
468 GreDeleteObject(hPattern);
469 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
470 return NULL;
471 }
472 hBrush = pbrush->BaseObject.hHmgr;
473
474 pbrush->flAttrs |= GDIBRUSH_IS_HATCH;
475 pbrush->hbmPattern = hPattern;
476 pbrush->BrushAttr.lbColor = Color & 0xFFFFFF;
477
478 GDIOBJ_SetOwnership(hPattern, NULL);
479
480 BRUSH_UnlockBrush(pbrush);
481
482 return hBrush;
483 }
484
485 HBRUSH
486 APIENTRY
487 IntGdiCreatePatternBrush(
488 HBITMAP hBitmap)
489 {
490 HBRUSH hBrush;
491 PBRUSH pbrush;
492 HBITMAP hPattern;
493
494 hPattern = BITMAP_CopyBitmap(hBitmap);
495 if (hPattern == NULL)
496 {
497 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
498 return NULL;
499 }
500
501 pbrush = BRUSH_AllocBrushWithHandle();
502 if (pbrush == NULL)
503 {
504 GreDeleteObject(hPattern);
505 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
506 return NULL;
507 }
508 hBrush = pbrush->BaseObject.hHmgr;
509
510 pbrush->flAttrs |= GDIBRUSH_IS_BITMAP;
511 pbrush->hbmPattern = hPattern;
512 /* FIXME: Fill in the rest of fields!!! */
513
514 GDIOBJ_SetOwnership(hPattern, NULL);
515
516 BRUSH_UnlockBrush(pbrush);
517
518 return hBrush;
519 }
520
521 HBRUSH
522 APIENTRY
523 IntGdiCreateSolidBrush(
524 COLORREF Color)
525 {
526 HBRUSH hBrush;
527 PBRUSH pbrush;
528
529 pbrush = BRUSH_AllocBrushWithHandle();
530 if (pbrush == NULL)
531 {
532 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
533 return NULL;
534 }
535 hBrush = pbrush->BaseObject.hHmgr;
536
537 pbrush->flAttrs |= GDIBRUSH_IS_SOLID;
538
539 pbrush->BrushAttr.lbColor = Color;
540 /* FIXME: Fill in the rest of fields!!! */
541
542 BRUSH_UnlockBrush(pbrush);
543
544 return hBrush;
545 }
546
547 HBRUSH
548 APIENTRY
549 IntGdiCreateNullBrush(VOID)
550 {
551 HBRUSH hBrush;
552 PBRUSH pbrush;
553
554 pbrush = BRUSH_AllocBrushWithHandle();
555 if (pbrush == NULL)
556 {
557 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
558 return NULL;
559 }
560 hBrush = pbrush->BaseObject.hHmgr;
561
562 pbrush->flAttrs |= GDIBRUSH_IS_NULL;
563 BRUSH_UnlockBrush(pbrush);
564
565 return hBrush;
566 }
567
568 VOID
569 FASTCALL
570 IntGdiSetSolidBrushColor(HBRUSH hBrush, COLORREF Color)
571 {
572 PBRUSH pbrush;
573
574 pbrush = BRUSH_LockBrush(hBrush);
575 if (pbrush->flAttrs & GDIBRUSH_IS_SOLID)
576 {
577 pbrush->BrushAttr.lbColor = Color & 0xFFFFFF;
578 }
579 BRUSH_UnlockBrush(pbrush);
580 }
581
582
583 /* PUBLIC FUNCTIONS ***********************************************************/
584
585 HBRUSH
586 APIENTRY
587 NtGdiCreateDIBBrush(
588 IN PVOID BitmapInfoAndData,
589 IN FLONG ColorSpec,
590 IN UINT BitmapInfoSize,
591 IN BOOL b8X8,
592 IN BOOL bPen,
593 IN PVOID PackedDIB)
594 {
595 BITMAPINFO *SafeBitmapInfoAndData;
596 NTSTATUS Status = STATUS_SUCCESS;
597 HBRUSH hBrush;
598
599 SafeBitmapInfoAndData = EngAllocMem(FL_ZERO_MEMORY, BitmapInfoSize, TAG_DIB);
600 if (SafeBitmapInfoAndData == NULL)
601 {
602 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
603 return NULL;
604 }
605
606 _SEH2_TRY
607 {
608 ProbeForRead(BitmapInfoAndData, BitmapInfoSize, 1);
609 RtlCopyMemory(SafeBitmapInfoAndData, BitmapInfoAndData, BitmapInfoSize);
610 }
611 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
612 {
613 Status = _SEH2_GetExceptionCode();
614 }
615 _SEH2_END;
616
617 if (!NT_SUCCESS(Status))
618 {
619 EngFreeMem(SafeBitmapInfoAndData);
620 SetLastNtError(Status);
621 return 0;
622 }
623
624 hBrush = IntGdiCreateDIBBrush(SafeBitmapInfoAndData,
625 ColorSpec,
626 BitmapInfoSize,
627 PackedDIB);
628
629 EngFreeMem(SafeBitmapInfoAndData);
630
631 return hBrush;
632 }
633
634 HBRUSH
635 APIENTRY
636 NtGdiCreateHatchBrushInternal(
637 ULONG Style,
638 COLORREF Color,
639 BOOL bPen)
640 {
641 return IntGdiCreateHatchBrush(Style, Color);
642 }
643
644 HBRUSH
645 APIENTRY
646 NtGdiCreatePatternBrushInternal(
647 HBITMAP hBitmap,
648 BOOL bPen,
649 BOOL b8x8)
650 {
651 return IntGdiCreatePatternBrush(hBitmap);
652 }
653
654 HBRUSH
655 APIENTRY
656 NtGdiCreateSolidBrush(COLORREF Color,
657 IN OPTIONAL HBRUSH hbr)
658 {
659 return IntGdiCreateSolidBrush(Color);
660 }
661
662 /**
663 * \name NtGdiSetBrushOrg
664 *
665 * \brief Sets the brush origin that GDI assigns to
666 * the next brush an application selects into the specified device context.
667 *
668 * @implemented
669 */
670 BOOL
671 APIENTRY
672 NtGdiSetBrushOrg(HDC hDC, INT XOrg, INT YOrg, LPPOINT Point)
673 {
674 PDC dc;
675 PDC_ATTR pdcattr;
676
677 dc = DC_LockDc(hDC);
678 if (dc == NULL)
679 {
680 SetLastWin32Error(ERROR_INVALID_HANDLE);
681 return FALSE;
682 }
683 pdcattr = dc->pdcattr;
684
685 if (Point != NULL)
686 {
687 NTSTATUS Status = STATUS_SUCCESS;
688 POINT SafePoint;
689 SafePoint.x = pdcattr->ptlBrushOrigin.x;
690 SafePoint.y = pdcattr->ptlBrushOrigin.y;
691 _SEH2_TRY
692 {
693 ProbeForWrite(Point, sizeof(POINT), 1);
694 *Point = SafePoint;
695 }
696 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
697 {
698 Status = _SEH2_GetExceptionCode();
699 }
700 _SEH2_END;
701
702 if (!NT_SUCCESS(Status))
703 {
704 DC_UnlockDc(dc);
705 SetLastNtError(Status);
706 return FALSE;
707 }
708 }
709
710 pdcattr->ptlBrushOrigin.x = XOrg;
711 pdcattr->ptlBrushOrigin.y = YOrg;
712 IntptlBrushOrigin(dc, XOrg, YOrg );
713 DC_UnlockDc(dc);
714
715 return TRUE;
716 }
717
718 /* EOF */