- Fix dirty bit support for select brush and pen, see bug 3863.
[reactos.git] / reactos / subsystems / win32 / win32k / objects / fillshap.c
1 /*
2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19
20 #include <w32k.h>
21
22 #define NDEBUG
23 #include <debug.h>
24
25 /*
26 * a couple macros to fill a single pixel or a line
27 */
28 #define PUTPIXEL(x,y,BrushInst) \
29 ret = ret && IntEngLineTo(&BitmapObj->SurfObj, \
30 dc->CombinedClip, \
31 &BrushInst.BrushObject, \
32 x, y, (x)+1, y, \
33 &RectBounds, \
34 ROP2_TO_MIX(Dc_Attr->jROP2));
35
36 #define PUTLINE(x1,y1,x2,y2,BrushInst) \
37 ret = ret && IntEngLineTo(&BitmapObj->SurfObj, \
38 dc->CombinedClip, \
39 &BrushInst.BrushObject, \
40 x1, y1, x2, y2, \
41 &RectBounds, \
42 ROP2_TO_MIX(Dc_Attr->jROP2));
43
44 #define Rsin(d) ((d) == 0.0 ? 0.0 : ((d) == 90.0 ? 1.0 : sin(d*M_PI/180.0)))
45 #define Rcos(d) ((d) == 0.0 ? 1.0 : ((d) == 90.0 ? 0.0 : cos(d*M_PI/180.0)))
46
47 BOOL FASTCALL IntFillEllipse( PDC dc, INT XLeft, INT YLeft, INT Width, INT Height);
48 BOOL FASTCALL IntDrawEllipse( PDC dc, INT XLeft, INT YLeft, INT Width, INT Height, PGDIBRUSHOBJ PenBrushObj);
49 BOOL FASTCALL IntFillRoundRect( PDC dc, INT Left, INT Top, INT Right, INT Bottom, INT Wellipse, INT Hellipse);
50 BOOL FASTCALL IntDrawRoundRect( PDC dc, INT Left, INT Top, INT Right, INT Bottom, INT Wellipse, INT Hellipse, PGDIBRUSHOBJ PenBrushObj);
51
52 BOOL FASTCALL
53 IntGdiPolygon(PDC dc,
54 PPOINT Points,
55 int Count)
56 {
57 BITMAPOBJ *BitmapObj;
58 PGDIBRUSHOBJ PenBrushObj, FillBrushObj;
59 GDIBRUSHINST PenBrushInst, FillBrushInst;
60 BOOL ret = FALSE; // default to failure
61 RECTL DestRect;
62 int CurrentPoint;
63 PDC_ATTR Dc_Attr;
64
65 ASSERT(dc); // caller's responsibility to pass a valid dc
66
67 if (!Points || Count < 2 )
68 {
69 SetLastWin32Error(ERROR_INVALID_PARAMETER);
70 return FALSE;
71 }
72
73 Dc_Attr = dc->pDc_Attr;
74 if (!Dc_Attr) Dc_Attr = &dc->Dc_Attr;
75
76 /* Convert to screen coordinates */
77 IntLPtoDP(dc, Points, Count);
78 for (CurrentPoint = 0; CurrentPoint < Count; CurrentPoint++)
79 {
80 Points[CurrentPoint].x += dc->ptlDCOrig.x;
81 Points[CurrentPoint].y += dc->ptlDCOrig.y;
82 }
83 // No need to have path here.
84 {
85 DestRect.left = Points[0].x;
86 DestRect.right = Points[0].x;
87 DestRect.top = Points[0].y;
88 DestRect.bottom = Points[0].y;
89
90 for (CurrentPoint = 1; CurrentPoint < Count; ++CurrentPoint)
91 {
92 DestRect.left = min(DestRect.left, Points[CurrentPoint].x);
93 DestRect.right = max(DestRect.right, Points[CurrentPoint].x);
94 DestRect.top = min(DestRect.top, Points[CurrentPoint].y);
95 DestRect.bottom = max(DestRect.bottom, Points[CurrentPoint].y);
96 }
97
98 if (Dc_Attr->ulDirty_ & DC_BRUSH_DIRTY)
99 IntGdiSelectBrush(dc,Dc_Attr->hbrush);
100
101 if (Dc_Attr->ulDirty_ & DC_PEN_DIRTY)
102 IntGdiSelectPen(dc,Dc_Attr->hpen);
103
104 /* Special locking order to avoid lock-ups */
105 FillBrushObj = BRUSHOBJ_LockBrush(Dc_Attr->hbrush);
106 PenBrushObj = PENOBJ_LockPen(Dc_Attr->hpen);
107 BitmapObj = BITMAPOBJ_LockBitmap(dc->w.hBitmap);
108 /* FIXME - BitmapObj can be NULL!!!! don't assert but handle this case gracefully! */
109 ASSERT(BitmapObj);
110
111 /* Now fill the polygon with the current brush. */
112 if (FillBrushObj && !(FillBrushObj->flAttrs & GDIBRUSH_IS_NULL))
113 {
114 IntGdiInitBrushInstance(&FillBrushInst, FillBrushObj, dc->XlateBrush);
115 ret = FillPolygon ( dc, BitmapObj, &FillBrushInst.BrushObject, ROP2_TO_MIX(Dc_Attr->jROP2), Points, Count, DestRect );
116 }
117 if (FillBrushObj)
118 BRUSHOBJ_UnlockBrush(FillBrushObj);
119
120 // Draw the Polygon Edges with the current pen ( if not a NULL pen )
121 if (PenBrushObj && !(PenBrushObj->flAttrs & GDIBRUSH_IS_NULL))
122 {
123 int i;
124
125 IntGdiInitBrushInstance(&PenBrushInst, PenBrushObj, dc->XlatePen);
126
127 for (i = 0; i < Count-1; i++)
128 {
129
130 // DPRINT1("Polygon Making line from (%d,%d) to (%d,%d)\n",
131 // Points[0].x, Points[0].y,
132 // Points[1].x, Points[1].y );
133
134 ret = IntEngLineTo(&BitmapObj->SurfObj,
135 dc->CombinedClip,
136 &PenBrushInst.BrushObject,
137 Points[i].x, /* From */
138 Points[i].y,
139 Points[i+1].x, /* To */
140 Points[i+1].y,
141 &DestRect,
142 ROP2_TO_MIX(Dc_Attr->jROP2)); /* MIX */
143 if (!ret) break;
144 }
145 /* Close the polygon */
146 if (ret)
147 {
148 ret = IntEngLineTo(&BitmapObj->SurfObj,
149 dc->CombinedClip,
150 &PenBrushInst.BrushObject,
151 Points[Count-1].x, /* From */
152 Points[Count-1].y,
153 Points[0].x, /* To */
154 Points[0].y,
155 &DestRect,
156 ROP2_TO_MIX(Dc_Attr->jROP2)); /* MIX */
157 }
158 }
159 if (PenBrushObj)
160 PENOBJ_UnlockPen(PenBrushObj);
161 }
162 BITMAPOBJ_UnlockBitmap(BitmapObj);
163
164 return ret;
165 }
166
167 BOOL FASTCALL
168 IntGdiPolyPolygon(DC *dc,
169 LPPOINT Points,
170 PULONG PolyCounts,
171 int Count)
172 {
173 if (PATH_IsPathOpen(dc->DcLevel))
174 return PATH_PolyPolygon ( dc, Points, (PINT)PolyCounts, Count);
175
176 while (--Count >=0)
177 {
178 if (!IntGdiPolygon ( dc, Points, *PolyCounts ))
179 return FALSE;
180 Points+=*PolyCounts++;
181 }
182 return TRUE;
183 }
184
185
186
187 /******************************************************************************/
188
189 /*
190 * NtGdiEllipse
191 *
192 * Author
193 * Filip Navara
194 *
195 * Remarks
196 * This function uses optimized Bresenham's ellipse algorithm. It draws
197 * four lines of the ellipse in one pass.
198 *
199 */
200
201 BOOL STDCALL
202 NtGdiEllipse(
203 HDC hDC,
204 int Left,
205 int Top,
206 int Right,
207 int Bottom)
208 {
209 PDC dc;
210 PDC_ATTR Dc_Attr;
211 RECTL RectBounds;
212 PGDIBRUSHOBJ PenBrushObj;
213 BOOL ret = TRUE;
214 LONG PenWidth, PenOrigWidth;
215 LONG RadiusX, RadiusY, CenterX, CenterY;
216
217 if ((Left == Right) || (Top == Bottom)) return TRUE;
218
219 dc = DC_LockDc(hDC);
220 if (dc == NULL)
221 {
222 SetLastWin32Error(ERROR_INVALID_HANDLE);
223 return FALSE;
224 }
225 if (dc->DC_Type == DC_TYPE_INFO)
226 {
227 DC_UnlockDc(dc);
228 /* Yes, Windows really returns TRUE in this case */
229 return TRUE;
230 }
231
232 if (PATH_IsPathOpen(dc->DcLevel))
233 {
234 ret = PATH_Ellipse(dc, Left, Top, Right, Bottom);
235 DC_UnlockDc(dc);
236 return ret;
237 }
238
239 if (Right < Left)
240 {
241 INT tmp = Right; Right = Left; Left = tmp;
242 }
243 if (Bottom < Top)
244 {
245 INT tmp = Bottom; Bottom = Top; Top = tmp;
246 }
247
248 Dc_Attr = dc->pDc_Attr;
249 if(!Dc_Attr) Dc_Attr = &dc->Dc_Attr;
250
251 if (Dc_Attr->ulDirty_ & DC_BRUSH_DIRTY)
252 IntGdiSelectBrush(dc,Dc_Attr->hbrush);
253
254 if (Dc_Attr->ulDirty_ & DC_PEN_DIRTY)
255 IntGdiSelectPen(dc,Dc_Attr->hpen);
256
257 PenBrushObj = PENOBJ_LockPen(Dc_Attr->hpen);
258 if (NULL == PenBrushObj)
259 {
260 DPRINT1("Ellipse Fail 1\n");
261 DC_UnlockDc(dc);
262 SetLastWin32Error(ERROR_INTERNAL_ERROR);
263 return FALSE;
264 }
265
266 PenOrigWidth = PenWidth = PenBrushObj->ptPenWidth.x;
267 if (PenBrushObj->ulPenStyle == PS_NULL) PenWidth = 0;
268
269 if (PenBrushObj->ulPenStyle == PS_INSIDEFRAME)
270 {
271 if (2*PenWidth > (Right - Left)) PenWidth = (Right -Left + 1)/2;
272 if (2*PenWidth > (Bottom - Top)) PenWidth = (Bottom -Top + 1)/2;
273 Left += PenWidth / 2;
274 Right -= (PenWidth - 1) / 2;
275 Top += PenWidth / 2;
276 Bottom -= (PenWidth - 1) / 2;
277 }
278
279 if (!PenWidth) PenWidth = 1;
280 PenBrushObj->ptPenWidth.x = PenWidth;
281
282 RectBounds.left = Left;
283 RectBounds.right = Right;
284 RectBounds.top = Top;
285 RectBounds.bottom = Bottom;
286
287 IntLPtoDP(dc, (LPPOINT)&RectBounds, 2);
288
289 RectBounds.left += dc->ptlDCOrig.x;
290 RectBounds.right += dc->ptlDCOrig.x;
291 RectBounds.top += dc->ptlDCOrig.y;
292 RectBounds.bottom += dc->ptlDCOrig.y;
293
294 // Setup for dynamic width and height.
295 RadiusX = max((RectBounds.right - RectBounds.left) / 2, 2); // Needs room
296 RadiusY = max((RectBounds.bottom - RectBounds.top) / 2, 2);
297 CenterX = (RectBounds.right + RectBounds.left) / 2;
298 CenterY = (RectBounds.bottom + RectBounds.top) / 2;
299
300 DPRINT("Ellipse 1: Left: %d, Top: %d, Right: %d, Bottom: %d\n",
301 RectBounds.left,RectBounds.top,RectBounds.right,RectBounds.bottom);
302
303 DPRINT("Ellipse 2: XLeft: %d, YLeft: %d, Width: %d, Height: %d\n",
304 CenterX - RadiusX, CenterY + RadiusY, RadiusX*2, RadiusY*2);
305
306 ret = IntFillEllipse( dc,
307 CenterX - RadiusX,
308 CenterY - RadiusY,
309 RadiusX*2, // Width
310 RadiusY*2); // Height
311 if (ret)
312 ret = IntDrawEllipse( dc,
313 CenterX - RadiusX,
314 CenterY - RadiusY,
315 RadiusX*2, // Width
316 RadiusY*2, // Height
317 PenBrushObj);
318
319 PenBrushObj->ptPenWidth.x = PenOrigWidth;
320 PENOBJ_UnlockPen(PenBrushObj);
321 DC_UnlockDc(dc);
322 DPRINT("Ellipse Exit.\n");
323 return ret;
324 }
325
326 #if 0
327
328 //When the fill mode is ALTERNATE, GDI fills the area between odd-numbered and
329 //even-numbered polygon sides on each scan line. That is, GDI fills the area between the
330 //first and second side, between the third and fourth side, and so on.
331
332 //WINDING Selects winding mode (fills any region with a nonzero winding value).
333 //When the fill mode is WINDING, GDI fills any region that has a nonzero winding value.
334 //This value is defined as the number of times a pen used to draw the polygon would go around the region.
335 //The direction of each edge of the polygon is important.
336
337 extern BOOL FillPolygon(PDC dc,
338 SURFOBJ *SurfObj,
339 PBRUSHOBJ BrushObj,
340 MIX RopMode,
341 CONST PPOINT Points,
342 int Count,
343 RECTL BoundRect);
344
345 #endif
346
347
348 ULONG_PTR
349 STDCALL
350 NtGdiPolyPolyDraw( IN HDC hDC,
351 IN PPOINT UnsafePoints,
352 IN PULONG UnsafeCounts,
353 IN ULONG Count,
354 IN INT iFunc )
355 {
356 DC *dc;
357 PVOID pTemp;
358 LPPOINT SafePoints;
359 PULONG SafeCounts;
360 NTSTATUS Status = STATUS_SUCCESS;
361 BOOL Ret = TRUE;
362 INT nPoints = 0, nMaxPoints = 0, nInvalid = 0, i;
363
364 if (!UnsafePoints || !UnsafeCounts ||
365 Count == 0 || iFunc == 0 || iFunc > GdiPolyPolyRgn)
366 {
367 /* Windows doesn't set last error */
368 return FALSE;
369 }
370
371 _SEH_TRY
372 {
373 ProbeForRead(UnsafePoints, Count * sizeof(POINT), 1);
374 ProbeForRead(UnsafeCounts, Count * sizeof(ULONG), 1);
375
376 /* Count points and validate poligons */
377 for (i = 0; i < Count; i++)
378 {
379 if (UnsafeCounts[i] < 2)
380 {
381 nInvalid++;
382 }
383 nPoints += UnsafeCounts[i];
384 nMaxPoints = max(nMaxPoints, UnsafeCounts[i]);
385 }
386 }
387 _SEH_HANDLE
388 {
389 Status = _SEH_GetExceptionCode();
390 }
391 _SEH_END;
392
393 if (!NT_SUCCESS(Status))
394 {
395 /* Windows doesn't set last error */
396 return FALSE;
397 }
398
399 if (nPoints == 0 || nPoints < nMaxPoints)
400 {
401 /* If all polygon counts are zero, or we have overflow,
402 return without setting a last error code. */
403 return FALSE;
404 }
405
406 if (nInvalid != 0)
407 {
408 /* If at least one poly count is 0 or 1, fail */
409 SetLastWin32Error(ERROR_INVALID_PARAMETER);
410 return FALSE;
411 }
412
413 /* Allocate one buffer for both counts and points */
414 pTemp = ExAllocatePoolWithTag(PagedPool,
415 Count * sizeof(ULONG) + nPoints * sizeof(POINT),
416 TAG_SHAPE);
417 if (!pTemp)
418 {
419 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
420 return FALSE;
421 }
422
423 SafeCounts = pTemp;
424 SafePoints = (PVOID)(SafeCounts + Count);
425
426 _SEH_TRY
427 {
428 /* Pointers already probed! */
429 RtlCopyMemory(SafeCounts, UnsafeCounts, Count * sizeof(ULONG));
430 RtlCopyMemory(SafePoints, UnsafePoints, nPoints * sizeof(POINT));
431 }
432 _SEH_HANDLE
433 {
434 Status = _SEH_GetExceptionCode();
435 }
436 _SEH_END;
437
438 if (!NT_SUCCESS(Status))
439 {
440 ExFreePoolWithTag(pTemp, TAG_SHAPE);
441 return FALSE;
442 }
443
444 /* Special handling for GdiPolyPolyRgn */
445 if (iFunc == GdiPolyPolyRgn)
446 {
447 HRGN hRgn;
448 hRgn = IntCreatePolyPolygonRgn(SafePoints, SafeCounts, Count, (INT_PTR)hDC);
449 ExFreePoolWithTag(pTemp, TAG_SHAPE);
450 return (ULONG_PTR)hRgn;
451 }
452
453 dc = DC_LockDc(hDC);
454 if (!dc)
455 {
456 SetLastWin32Error(ERROR_INVALID_HANDLE);
457 ExFreePool(pTemp);
458 return FALSE;
459 }
460
461 if (dc->DC_Type == DC_TYPE_INFO)
462 {
463 DC_UnlockDc(dc);
464 ExFreePool(pTemp);
465 /* Yes, Windows really returns TRUE in this case */
466 return TRUE;
467 }
468
469 /* Perform the actual work */
470 switch (iFunc)
471 {
472 case GdiPolyPolygon:
473 Ret = IntGdiPolyPolygon(dc, SafePoints, SafeCounts, Count);
474 break;
475 case GdiPolyPolyLine:
476 Ret = IntGdiPolyPolyline(dc, SafePoints, SafeCounts, Count);
477 break;
478 case GdiPolyBezier:
479 Ret = IntGdiPolyBezier(dc, SafePoints, *SafeCounts);
480 break;
481 case GdiPolyLineTo:
482 Ret = IntGdiPolylineTo(dc, SafePoints, *SafeCounts);
483 break;
484 case GdiPolyBezierTo:
485 Ret = IntGdiPolyBezierTo(dc, SafePoints, *SafeCounts);
486 break;
487 default:
488 SetLastWin32Error(ERROR_INVALID_PARAMETER);
489 Ret = FALSE;
490 }
491
492 /* Cleanup and return */
493 DC_UnlockDc(dc);
494 ExFreePool(pTemp);
495
496 return (ULONG_PTR)Ret;
497 }
498
499
500 BOOL
501 FASTCALL
502 IntRectangle(PDC dc,
503 int LeftRect,
504 int TopRect,
505 int RightRect,
506 int BottomRect)
507 {
508 BITMAPOBJ *BitmapObj = NULL;
509 PGDIBRUSHOBJ PenBrushObj = NULL, FillBrushObj = NULL;
510 GDIBRUSHINST PenBrushInst, FillBrushInst;
511 BOOL ret = FALSE; // default to failure
512 RECTL DestRect;
513 MIX Mix;
514 PDC_ATTR Dc_Attr;
515
516 ASSERT ( dc ); // caller's responsibility to set this up
517
518 Dc_Attr = dc->pDc_Attr;
519 if(!Dc_Attr) Dc_Attr = &dc->Dc_Attr;
520
521 /* Do we rotate or shear? */
522 if (!(dc->DcLevel.mxWorldToDevice.flAccel & MX_SCALE))
523 {
524
525 POINTL DestCoords[4];
526 ULONG PolyCounts = 4;
527 DestCoords[0].x = DestCoords[3].x = LeftRect;
528 DestCoords[0].y = DestCoords[1].y = TopRect;
529 DestCoords[1].x = DestCoords[2].x = RightRect;
530 DestCoords[2].y = DestCoords[3].y = BottomRect;
531 // Use IntGdiPolyPolygon so to support PATH.
532 return IntGdiPolyPolygon(dc, DestCoords, &PolyCounts, 1);
533 }
534 // Rectangle Path only.
535 if ( PATH_IsPathOpen(dc->DcLevel) )
536 {
537 return PATH_Rectangle ( dc, LeftRect, TopRect, RightRect, BottomRect );
538 }
539
540 DestRect.left = LeftRect;
541 DestRect.right = RightRect;
542 DestRect.top = TopRect;
543 DestRect.bottom = BottomRect;
544
545 IntLPtoDP(dc, (LPPOINT)&DestRect, 2);
546
547 DestRect.left += dc->ptlDCOrig.x;
548 DestRect.right += dc->ptlDCOrig.x;
549 DestRect.top += dc->ptlDCOrig.y;
550 DestRect.bottom += dc->ptlDCOrig.y;
551
552 /* In GM_COMPATIBLE, don't include bottom and right edges */
553 if (IntGetGraphicsMode(dc) == GM_COMPATIBLE)
554 {
555 DestRect.right--;
556 DestRect.bottom--;
557 }
558
559 if (Dc_Attr->ulDirty_ & DC_BRUSH_DIRTY)
560 IntGdiSelectBrush(dc,Dc_Attr->hbrush);
561
562 if (Dc_Attr->ulDirty_ & DC_PEN_DIRTY)
563 IntGdiSelectPen(dc,Dc_Attr->hpen);
564
565 /* Special locking order to avoid lock-ups! */
566 FillBrushObj = BRUSHOBJ_LockBrush(Dc_Attr->hbrush);
567 PenBrushObj = PENOBJ_LockPen(Dc_Attr->hpen);
568 if (!PenBrushObj)
569 {
570 ret = FALSE;
571 goto cleanup;
572 }
573 BitmapObj = BITMAPOBJ_LockBitmap(dc->w.hBitmap);
574 if (!BitmapObj)
575 {
576 ret = FALSE;
577 goto cleanup;
578 }
579
580 if ( FillBrushObj )
581 {
582 if (!(FillBrushObj->flAttrs & GDIBRUSH_IS_NULL))
583 {
584 IntGdiInitBrushInstance(&FillBrushInst, FillBrushObj, dc->XlateBrush);
585 ret = IntEngBitBlt(&BitmapObj->SurfObj,
586 NULL,
587 NULL,
588 dc->CombinedClip,
589 NULL,
590 &DestRect,
591 NULL,
592 NULL,
593 &FillBrushInst.BrushObject,
594 NULL,
595 ROP3_TO_ROP4(PATCOPY));
596 }
597 }
598
599 IntGdiInitBrushInstance(&PenBrushInst, PenBrushObj, dc->XlatePen);
600
601 // Draw the rectangle with the current pen
602
603 ret = TRUE; // change default to success
604
605 if (!(PenBrushObj->flAttrs & GDIBRUSH_IS_NULL))
606 {
607 Mix = ROP2_TO_MIX(Dc_Attr->jROP2);
608 ret = ret && IntEngLineTo(&BitmapObj->SurfObj,
609 dc->CombinedClip,
610 &PenBrushInst.BrushObject,
611 DestRect.left, DestRect.top, DestRect.right, DestRect.top,
612 &DestRect, // Bounding rectangle
613 Mix);
614
615 ret = ret && IntEngLineTo(&BitmapObj->SurfObj,
616 dc->CombinedClip,
617 &PenBrushInst.BrushObject,
618 DestRect.right, DestRect.top, DestRect.right, DestRect.bottom,
619 &DestRect, // Bounding rectangle
620 Mix);
621
622 ret = ret && IntEngLineTo(&BitmapObj->SurfObj,
623 dc->CombinedClip,
624 &PenBrushInst.BrushObject,
625 DestRect.right, DestRect.bottom, DestRect.left, DestRect.bottom,
626 &DestRect, // Bounding rectangle
627 Mix);
628
629 ret = ret && IntEngLineTo(&BitmapObj->SurfObj,
630 dc->CombinedClip,
631 &PenBrushInst.BrushObject,
632 DestRect.left, DestRect.bottom, DestRect.left, DestRect.top,
633 &DestRect, // Bounding rectangle
634 Mix);
635 }
636
637 cleanup:
638 if (FillBrushObj)
639 BRUSHOBJ_UnlockBrush(FillBrushObj);
640
641 if (PenBrushObj)
642 PENOBJ_UnlockPen(PenBrushObj);
643
644 if (BitmapObj)
645 BITMAPOBJ_UnlockBitmap(BitmapObj);
646
647 /* Move current position in DC?
648 MSDN: The current position is neither used nor updated by Rectangle. */
649
650 return ret;
651 }
652
653 BOOL
654 STDCALL
655 NtGdiRectangle(HDC hDC,
656 int LeftRect,
657 int TopRect,
658 int RightRect,
659 int BottomRect)
660 {
661 DC *dc;
662 BOOL ret; // default to failure
663
664 dc = DC_LockDc(hDC);
665 if (!dc)
666 {
667 SetLastWin32Error(ERROR_INVALID_HANDLE);
668 return FALSE;
669 }
670 if (dc->DC_Type == DC_TYPE_INFO)
671 {
672 DC_UnlockDc(dc);
673 /* Yes, Windows really returns TRUE in this case */
674 return TRUE;
675 }
676
677 ret = IntRectangle ( dc, LeftRect, TopRect, RightRect, BottomRect );
678 DC_UnlockDc ( dc );
679
680 return ret;
681 }
682
683
684 BOOL
685 FASTCALL
686 IntRoundRect(
687 PDC dc,
688 int Left,
689 int Top,
690 int Right,
691 int Bottom,
692 int xCurveDiameter,
693 int yCurveDiameter)
694 {
695 PDC_ATTR Dc_Attr;
696 PGDIBRUSHOBJ PenBrushObj;
697 RECTL RectBounds;
698 LONG PenWidth, PenOrigWidth;
699 BOOL ret = TRUE; // default to success
700
701 ASSERT ( dc ); // caller's responsibility to set this up
702
703 if ( PATH_IsPathOpen(dc->DcLevel) )
704 return PATH_RoundRect ( dc, Left, Top, Right, Bottom,
705 xCurveDiameter, yCurveDiameter );
706
707 if ((Left == Right) || (Top == Bottom)) return TRUE;
708
709 xCurveDiameter = max(abs( xCurveDiameter ), 1);
710 yCurveDiameter = max(abs( yCurveDiameter ), 1);
711
712 if (Right < Left)
713 {
714 INT tmp = Right; Right = Left; Left = tmp;
715 }
716 if (Bottom < Top)
717 {
718 INT tmp = Bottom; Bottom = Top; Top = tmp;
719 }
720
721 Dc_Attr = dc->pDc_Attr;
722 if(!Dc_Attr) Dc_Attr = &dc->Dc_Attr;
723
724 if (Dc_Attr->ulDirty_ & DC_BRUSH_DIRTY)
725 IntGdiSelectBrush(dc,Dc_Attr->hbrush);
726
727 if (Dc_Attr->ulDirty_ & DC_PEN_DIRTY)
728 IntGdiSelectPen(dc,Dc_Attr->hpen);
729
730 PenBrushObj = PENOBJ_LockPen(Dc_Attr->hpen);
731 if (!PenBrushObj)
732 {
733 /* Nothing to do, as we don't have a bitmap */
734 SetLastWin32Error(ERROR_INTERNAL_ERROR);
735 return FALSE;
736 }
737
738 PenOrigWidth = PenWidth = PenBrushObj->ptPenWidth.x;
739 if (PenBrushObj->ulPenStyle == PS_NULL) PenWidth = 0;
740
741 if (PenBrushObj->ulPenStyle == PS_INSIDEFRAME)
742 {
743 if (2*PenWidth > (Right - Left)) PenWidth = (Right -Left + 1)/2;
744 if (2*PenWidth > (Bottom - Top)) PenWidth = (Bottom -Top + 1)/2;
745 Left += PenWidth / 2;
746 Right -= (PenWidth - 1) / 2;
747 Top += PenWidth / 2;
748 Bottom -= (PenWidth - 1) / 2;
749 }
750
751 if (!PenWidth) PenWidth = 1;
752 PenBrushObj->ptPenWidth.x = PenWidth;
753
754 RectBounds.left = Left;
755 RectBounds.top = Top;
756 RectBounds.right = Right;
757 RectBounds.bottom = Bottom;
758
759 IntLPtoDP(dc, (LPPOINT)&RectBounds, 2);
760
761 RectBounds.left += dc->ptlDCOrig.x;
762 RectBounds.top += dc->ptlDCOrig.y;
763 RectBounds.right += dc->ptlDCOrig.x;
764 RectBounds.bottom += dc->ptlDCOrig.y;
765
766 ret = IntFillRoundRect( dc,
767 RectBounds.left,
768 RectBounds.top,
769 RectBounds.right,
770 RectBounds.bottom,
771 xCurveDiameter,
772 yCurveDiameter);
773 if (ret)
774 ret = IntDrawRoundRect( dc,
775 RectBounds.left,
776 RectBounds.top,
777 RectBounds.right,
778 RectBounds.bottom,
779 xCurveDiameter,
780 yCurveDiameter,
781 PenBrushObj);
782
783 PenBrushObj->ptPenWidth.x = PenOrigWidth;
784 PENOBJ_UnlockPen(PenBrushObj);
785 return ret;
786 }
787
788 BOOL
789 STDCALL
790 NtGdiRoundRect(
791 HDC hDC,
792 int LeftRect,
793 int TopRect,
794 int RightRect,
795 int BottomRect,
796 int Width,
797 int Height)
798 {
799 DC *dc = DC_LockDc(hDC);
800 BOOL ret = FALSE; /* default to failure */
801
802 DPRINT("NtGdiRoundRect(0x%x,%i,%i,%i,%i,%i,%i)\n",hDC,LeftRect,TopRect,RightRect,BottomRect,Width,Height);
803 if ( !dc )
804 {
805 DPRINT1("NtGdiRoundRect() - hDC is invalid\n");
806 SetLastWin32Error(ERROR_INVALID_HANDLE);
807 }
808 else if (dc->DC_Type == DC_TYPE_INFO)
809 {
810 DC_UnlockDc(dc);
811 /* Yes, Windows really returns TRUE in this case */
812 ret = TRUE;
813 }
814 else
815 {
816 ret = IntRoundRect ( dc, LeftRect, TopRect, RightRect, BottomRect, Width, Height );
817 DC_UnlockDc ( dc );
818 }
819
820 return ret;
821 }
822
823 BOOL FASTCALL
824 IntGdiGradientFill(
825 DC *dc,
826 PTRIVERTEX pVertex,
827 ULONG uVertex,
828 PVOID pMesh,
829 ULONG uMesh,
830 ULONG ulMode)
831 {
832 BITMAPOBJ *BitmapObj;
833 PPALGDI PalDestGDI;
834 XLATEOBJ *XlateObj;
835 RECTL Extent;
836 POINTL DitherOrg;
837 ULONG Mode, i;
838 BOOL Ret;
839 HPALETTE hDestPalette;
840
841 ASSERT(dc);
842 ASSERT(pVertex);
843 ASSERT(uVertex);
844 ASSERT(pMesh);
845 ASSERT(uMesh);
846
847 /* check parameters */
848 if (ulMode & GRADIENT_FILL_TRIANGLE)
849 {
850 PGRADIENT_TRIANGLE tr = (PGRADIENT_TRIANGLE)pMesh;
851
852 for (i = 0; i < uMesh; i++, tr++)
853 {
854 if (tr->Vertex1 >= uVertex ||
855 tr->Vertex2 >= uVertex ||
856 tr->Vertex3 >= uVertex)
857 {
858 SetLastWin32Error(ERROR_INVALID_PARAMETER);
859 return FALSE;
860 }
861 }
862 }
863 else
864 {
865 PGRADIENT_RECT rc = (PGRADIENT_RECT)pMesh;
866 for (i = 0; i < uMesh; i++, rc++)
867 {
868 if (rc->UpperLeft >= uVertex || rc->LowerRight >= uVertex)
869 {
870 SetLastWin32Error(ERROR_INVALID_PARAMETER);
871 return FALSE;
872 }
873 }
874 }
875
876 /* calculate extent */
877 Extent.left = Extent.right = pVertex->x;
878 Extent.top = Extent.bottom = pVertex->y;
879 for (i = 0; i < uVertex; i++)
880 {
881 Extent.left = min(Extent.left, (pVertex + i)->x);
882 Extent.right = max(Extent.right, (pVertex + i)->x);
883 Extent.top = min(Extent.top, (pVertex + i)->y);
884 Extent.bottom = max(Extent.bottom, (pVertex + i)->y);
885 }
886
887 DitherOrg.x = dc->ptlDCOrig.x;
888 DitherOrg.y = dc->ptlDCOrig.y;
889 Extent.left += DitherOrg.x;
890 Extent.right += DitherOrg.x;
891 Extent.top += DitherOrg.y;
892 Extent.bottom += DitherOrg.y;
893
894 BitmapObj = BITMAPOBJ_LockBitmap(dc->w.hBitmap);
895 /* FIXME - BitmapObj can be NULL!!! Don't assert but handle this case gracefully! */
896 ASSERT(BitmapObj);
897
898 hDestPalette = BitmapObj->hDIBPalette;
899 if (!hDestPalette) hDestPalette = pPrimarySurface->DevInfo.hpalDefault;
900
901 PalDestGDI = PALETTE_LockPalette(hDestPalette);
902 if (PalDestGDI)
903 {
904 Mode = PalDestGDI->Mode;
905 PALETTE_UnlockPalette(PalDestGDI);
906 }
907 else
908 Mode = PAL_RGB;
909
910 XlateObj = (XLATEOBJ*)IntEngCreateXlate(Mode, PAL_RGB, hDestPalette, NULL);
911 ASSERT(XlateObj);
912
913 Ret = IntEngGradientFill(&BitmapObj->SurfObj,
914 dc->CombinedClip,
915 XlateObj,
916 pVertex,
917 uVertex,
918 pMesh,
919 uMesh,
920 &Extent,
921 &DitherOrg,
922 ulMode);
923
924 BITMAPOBJ_UnlockBitmap(BitmapObj);
925 EngDeleteXlate(XlateObj);
926
927 return Ret;
928 }
929
930 BOOL
931 STDCALL
932 NtGdiGradientFill(
933 HDC hdc,
934 PTRIVERTEX pVertex,
935 ULONG uVertex,
936 PVOID pMesh,
937 ULONG uMesh,
938 ULONG ulMode)
939 {
940 DC *dc;
941 BOOL Ret;
942 PTRIVERTEX SafeVertex;
943 PVOID SafeMesh;
944 ULONG SizeMesh;
945 NTSTATUS Status = STATUS_SUCCESS;
946
947 dc = DC_LockDc(hdc);
948 if (!dc)
949 {
950 SetLastWin32Error(ERROR_INVALID_HANDLE);
951 return FALSE;
952 }
953 if (dc->DC_Type == DC_TYPE_INFO)
954 {
955 DC_UnlockDc(dc);
956 /* Yes, Windows really returns TRUE in this case */
957 return TRUE;
958 }
959 if (!pVertex || !uVertex || !pMesh || !uMesh)
960 {
961 DC_UnlockDc(dc);
962 SetLastWin32Error(ERROR_INVALID_PARAMETER);
963 return FALSE;
964 }
965
966 switch (ulMode)
967 {
968 case GRADIENT_FILL_RECT_H:
969 case GRADIENT_FILL_RECT_V:
970 SizeMesh = uMesh * sizeof(GRADIENT_RECT);
971 break;
972 case GRADIENT_FILL_TRIANGLE:
973 SizeMesh = uMesh * sizeof(TRIVERTEX);
974 break;
975 default:
976 DC_UnlockDc(dc);
977 SetLastWin32Error(ERROR_INVALID_PARAMETER);
978 return FALSE;
979 }
980
981 _SEH_TRY
982 {
983 ProbeForRead(pVertex,
984 uVertex * sizeof(TRIVERTEX),
985 1);
986 ProbeForRead(pMesh,
987 SizeMesh,
988 1);
989 }
990 _SEH_HANDLE
991 {
992 Status = _SEH_GetExceptionCode();
993 }
994 _SEH_END;
995
996 if (!NT_SUCCESS(Status))
997 {
998 DC_UnlockDc(dc);
999 SetLastWin32Error(Status);
1000 return FALSE;
1001 }
1002
1003 if (!(SafeVertex = ExAllocatePoolWithTag(PagedPool, (uVertex * sizeof(TRIVERTEX)) + SizeMesh, TAG_SHAPE)))
1004 {
1005 DC_UnlockDc(dc);
1006 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
1007 return FALSE;
1008 }
1009
1010 SafeMesh = (PTRIVERTEX)(SafeVertex + uVertex);
1011
1012 _SEH_TRY
1013 {
1014 /* pointers were already probed! */
1015 RtlCopyMemory(SafeVertex,
1016 pVertex,
1017 uVertex * sizeof(TRIVERTEX));
1018 RtlCopyMemory(SafeMesh,
1019 pMesh,
1020 SizeMesh);
1021 }
1022 _SEH_HANDLE
1023 {
1024 Status = _SEH_GetExceptionCode();
1025 }
1026 _SEH_END;
1027
1028 if (!NT_SUCCESS(Status))
1029 {
1030 DC_UnlockDc(dc);
1031 ExFreePoolWithTag(SafeVertex, TAG_SHAPE);
1032 SetLastNtError(Status);
1033 return FALSE;
1034 }
1035
1036 Ret = IntGdiGradientFill(dc, SafeVertex, uVertex, SafeMesh, uMesh, ulMode);
1037
1038 DC_UnlockDc(dc);
1039 ExFreePool(SafeVertex);
1040 return Ret;
1041 }
1042
1043 BOOL STDCALL
1044 NtGdiExtFloodFill(
1045 HDC hDC,
1046 INT XStart,
1047 INT YStart,
1048 COLORREF Color,
1049 UINT FillType)
1050 {
1051 PDC dc;
1052 PDC_ATTR Dc_Attr;
1053 BITMAPOBJ *BitmapObj = NULL;
1054 PGDIBRUSHOBJ FillBrushObj = NULL;
1055 GDIBRUSHINST FillBrushInst;
1056 BOOL Ret = FALSE;
1057 RECTL DestRect;
1058 POINTL Pt;
1059 // MIX Mix;
1060
1061 DPRINT1("FIXME: NtGdiExtFloodFill is UNIMPLEMENTED\n");
1062
1063 dc = DC_LockDc(hDC);
1064 if (!dc)
1065 {
1066 SetLastWin32Error(ERROR_INVALID_HANDLE);
1067 return FALSE;
1068 }
1069 if (dc->DC_Type == DC_TYPE_INFO)
1070 {
1071 DC_UnlockDc(dc);
1072 /* Yes, Windows really returns TRUE in this case */
1073 return TRUE;
1074 }
1075
1076 Dc_Attr = dc->pDc_Attr;
1077 if(!Dc_Attr) Dc_Attr = &dc->Dc_Attr;
1078
1079 if (Dc_Attr->ulDirty_ & DC_PEN_DIRTY)
1080 IntGdiSelectPen(dc,Dc_Attr->hpen);
1081
1082 if (Dc_Attr->ulDirty_ & DC_BRUSH_DIRTY)
1083 IntGdiSelectBrush(dc,Dc_Attr->hbrush);
1084
1085 Pt.x = XStart;
1086 Pt.y = YStart;
1087 IntLPtoDP(dc, (LPPOINT)&Pt, 1);
1088
1089 Ret = NtGdiPtInRegion(dc->w.hGCClipRgn, Pt.x, Pt.y);
1090 if (Ret)
1091 IntGdiGetRgnBox(dc->w.hGCClipRgn,(LPRECT)&DestRect);
1092 else
1093 goto cleanup;
1094
1095 FillBrushObj = BRUSHOBJ_LockBrush(Dc_Attr->hbrush);
1096 if (!FillBrushObj)
1097 {
1098 Ret = FALSE;
1099 goto cleanup;
1100 }
1101 BitmapObj = BITMAPOBJ_LockBitmap(dc->w.hBitmap);
1102 if (!BitmapObj)
1103 {
1104 Ret = FALSE;
1105 goto cleanup;
1106 }
1107
1108 if ( FillBrushObj && (FillType == FLOODFILLBORDER))
1109 {
1110 if (!(FillBrushObj->flAttrs & GDIBRUSH_IS_NULL))
1111 {
1112 FillBrushObj->BrushAttr.lbColor = Color;
1113 IntGdiInitBrushInstance(&FillBrushInst, FillBrushObj, dc->XlateBrush);
1114 Ret = IntEngBitBlt(&BitmapObj->SurfObj,
1115 NULL,
1116 NULL,
1117 dc->CombinedClip,
1118 NULL,
1119 &DestRect,
1120 NULL,
1121 NULL,
1122 &FillBrushInst.BrushObject,
1123 NULL,
1124 ROP3_TO_ROP4(PATCOPY));
1125 }
1126 }
1127 else
1128 {
1129 }
1130
1131 cleanup:
1132 if (FillBrushObj)
1133 BRUSHOBJ_UnlockBrush(FillBrushObj);
1134
1135 if (BitmapObj)
1136 BITMAPOBJ_UnlockBitmap(BitmapObj);
1137
1138 DC_UnlockDc(dc);
1139 return Ret;
1140 }
1141
1142 /* EOF */