2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
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.
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.
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.
21 #undef WIN32_LEAN_AND_MEAN
23 #include <ddk/ntddk.h>
24 #include <win32k/fillshap.h>
25 #include <win32k/brush.h>
26 #include <win32k/dc.h>
27 #include <win32k/pen.h>
28 #include <win32k/region.h>
29 #include <include/error.h>
30 #include <include/object.h>
31 #include <include/inteng.h>
32 #include <include/path.h>
33 #include <include/paint.h>
34 #include <internal/safe.h>
37 #include <win32k/debug1.h>
40 * a couple macros to fill a single pixel or a line
42 #define PUTPIXEL(x,y,brushObj) \
43 ret = ret && IntEngLineTo(SurfObj, \
50 #define PUTLINE(x1,y1,x2,y2,brushObj) \
51 ret = ret && IntEngLineTo(SurfObj, \
82 int X, X18, X27, X36, X45;
83 int Y, Y14, Y23, Y58, Y67;
88 PBRUSHOBJ FillBrushObj;
91 if (Right <= Left || Bottom <= Top)
93 SetLastWin32Error(ERROR_INVALID_PARAMETER);
97 if (Right - Left != Bottom - Top)
102 dc = DC_LockDc ( hDC );
105 SetLastWin32Error(ERROR_INVALID_PARAMETER);
109 FillBrushObj = BRUSHOBJ_LockBrush(dc->w.hBrush);
110 if (NULL == FillBrushObj)
113 SetLastWin32Error(ERROR_INTERNAL_ERROR);
117 Left += dc->w.DCOrgX;
118 Right += dc->w.DCOrgX;
120 Bottom += dc->w.DCOrgY;
122 RectBounds.left = Left;
123 RectBounds.right = Right;
124 RectBounds.top = Top;
125 RectBounds.bottom = Bottom;
127 SurfObj = (PSURFOBJ) AccessUserObject((ULONG)dc->Surface);
128 HPenToBrushObj(&PenBrushObj, dc->w.hPen);
129 Radius = (Right - Left) / 2;
133 X27 = (Left + Right) / 2;
134 X36 = (Left + Right) / 2;
139 Y67 = Top + (Right - Left);
141 PUTLINE(X45 + 1, Y14, X18, Y58, FillBrushObj);
142 PUTPIXEL(X27, Y23, &PenBrushObj);
143 PUTPIXEL(X45, Y14, &PenBrushObj);
144 PUTPIXEL(X18, Y58, &PenBrushObj);
145 PUTPIXEL(X27, Y67, &PenBrushObj);
160 d += 2 * (X - Y) + 5;
171 PUTLINE(X36 + 1, Y23, X27, Y23, FillBrushObj);
172 PUTLINE(X36 + 1, Y67, X27, Y67, FillBrushObj);
176 PUTLINE(X45 + 1, Y14, X18, Y14, FillBrushObj);
177 PUTLINE(X45 + 1, Y58, X18, Y58, FillBrushObj);
178 PUTPIXEL(X27, Y23, &PenBrushObj);
179 PUTPIXEL(X36, Y23, &PenBrushObj);
180 PUTPIXEL(X18, Y14, &PenBrushObj);
181 PUTPIXEL(X45, Y14, &PenBrushObj);
182 PUTPIXEL(X18, Y58, &PenBrushObj);
183 PUTPIXEL(X45, Y58, &PenBrushObj);
184 PUTPIXEL(X27, Y67, &PenBrushObj);
185 PUTPIXEL(X36, Y67, &PenBrushObj);
188 BRUSHOBJ_UnlockBrush(dc->w.hBrush);
211 //When the fill mode is ALTERNATE, GDI fills the area between odd-numbered and
212 //even-numbered polygon sides on each scan line. That is, GDI fills the area between the
213 //first and second side, between the third and fourth side, and so on.
215 //WINDING Selects winding mode (fills any region with a nonzero winding value).
216 //When the fill mode is WINDING, GDI fills any region that has a nonzero winding value.
217 //This value is defined as the number of times a pen used to draw the polygon would go around the region.
218 //The direction of each edge of the polygon is important.
220 extern BOOL FillPolygon(PDC dc,
233 CONST PPOINT UnsafePoints,
237 BRUSHOBJ PenBrushObj, *FillBrushObj;
238 BOOL ret = FALSE; // default to failure
245 ASSERT(dc); // caller's responsibility to pass a valid dc
247 if ( NULL == UnsafePoints || Count < 2 )
249 SetLastWin32Error(ERROR_INVALID_PARAMETER);
253 SurfObj = (SURFOBJ*)AccessUserObject((ULONG)dc->Surface);
256 /* Copy points from userspace to kernelspace */
257 Points = ExAllocatePool(PagedPool, Count * sizeof(POINT));
259 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
262 Status = MmCopyFromCaller(Points, UnsafePoints, Count * sizeof(POINT));
263 if ( !NT_SUCCESS(Status) )
264 SetLastNtError(Status);
267 /* Convert to screen coordinates */
268 for (CurrentPoint = 0; CurrentPoint < Count; CurrentPoint++)
270 Points[CurrentPoint].x += dc->w.DCOrgX;
271 Points[CurrentPoint].y += dc->w.DCOrgY;
274 RectBounds = (PRECTL) RGNDATA_LockRgn(dc->w.hGCClipRgn);
275 //ei not yet implemented ASSERT(RectBounds);
277 if (PATH_IsPathOpen(dc->w.path))
278 ret = PATH_Polygon(dc, Points, Count );
281 DestRect.left = Points[0].x;
282 DestRect.right = Points[0].x;
283 DestRect.top = Points[0].y;
284 DestRect.bottom = Points[0].y;
286 for (CurrentPoint = 1; CurrentPoint < Count; ++CurrentPoint)
288 DestRect.left = MIN(DestRect.left, Points[CurrentPoint].x);
289 DestRect.right = MAX(DestRect.right, Points[CurrentPoint].x);
290 DestRect.top = MIN(DestRect.top, Points[CurrentPoint].y);
291 DestRect.bottom = MAX(DestRect.bottom, Points[CurrentPoint].y);
295 /* Now fill the polygon with the current brush. */
296 FillBrushObj = BRUSHOBJ_LockBrush(dc->w.hBrush);
297 ASSERT(FillBrushObj);
298 if ( FillBrushObj->logbrush.lbStyle != BS_NULL )
299 ret = FillPolygon ( dc, SurfObj, FillBrushObj, dc->w.ROPmode, Points, Count, DestRect );
300 BRUSHOBJ_UnlockBrush(dc->w.hBrush);
303 /* make BRUSHOBJ from current pen. */
304 HPenToBrushObj ( &PenBrushObj, dc->w.hPen );
306 // Draw the Polygon Edges with the current pen ( if not a NULL pen )
307 if ( PenBrushObj.logbrush.lbStyle != BS_NULL )
309 for ( CurrentPoint = 0; CurrentPoint < Count; ++CurrentPoint )
311 POINT To, From; //, Next;
313 /* Let CurrentPoint be i
314 * if i+1 > Count, Draw a line from Points[i] to Points[0]
315 * Draw a line from Points[i] to Points[i+1]
317 From = Points[CurrentPoint];
318 if (Count <= CurrentPoint + 1)
321 To = Points[CurrentPoint + 1];
323 //DPRINT("Polygon Making line from (%d,%d) to (%d,%d)\n", From.x, From.y, To.x, To.y );
324 ret = IntEngLineTo(SurfObj,
332 dc->w.ROPmode); /* MIX */
336 /* Now fill the polygon with the current brush. */
337 FillBrushObj = BRUSHOBJ_LockBrush(dc->w.hBrush);
338 ASSERT(FillBrushObj);
339 if ( FillBrushObj->logbrush.lbStyle != BS_NULL )
340 ret = FillPolygon ( dc, SurfObj, FillBrushObj, dc->w.ROPmode, Points, Count, DestRect );
341 BRUSHOBJ_UnlockBrush(dc->w.hBrush);
345 RGNDATA_UnlockRgn(dc->w.hGCClipRgn);
347 ExFreePool ( Points );
352 //This implementation is blatantly ripped off from NtGdiRectangle
355 NtGdiPolygon(HDC hDC,
356 CONST PPOINT UnsafePoints,
360 BOOL ret = FALSE; // default to failure
362 //DPRINT("In NtGdiPolygon()\n");
364 dc = DC_LockDc ( hDC );
367 SetLastWin32Error(ERROR_INVALID_PARAMETER);
370 ret = IntPolygon ( dc, UnsafePoints, Count );
380 NtGdiPolyPolygon(HDC hDC,
381 CONST LPPOINT Points,
382 CONST LPINT PolyCounts,
389 BOOL ret = FALSE; // default to failure
391 dc = DC_LockDc ( hDC );
395 SetLastWin32Error(ERROR_INVALID_PARAMETER);
398 for (i=0;i<Count;i++)
400 ret = IntPolygon ( dc, pt, *pc );
422 SURFOBJ *SurfObj = (SURFOBJ*)AccessUserObject((ULONG)dc->Surface);
423 BRUSHOBJ PenBrushObj, *FillBrushObj;
424 BOOL ret = FALSE; // default to failure
428 ASSERT ( dc ); // caller's responsibility to set this up
430 RectBounds = (PRECTL) RGNDATA_LockRgn(dc->w.hGCClipRgn);
431 //ei not yet implemented ASSERT(RectBounds);
433 if ( PATH_IsPathOpen(dc->w.path) )
435 ret = PATH_Rectangle ( dc, LeftRect, TopRect, RightRect, BottomRect );
439 LeftRect += dc->w.DCOrgX;
440 RightRect += dc->w.DCOrgX - 1;
441 TopRect += dc->w.DCOrgY;
442 BottomRect += dc->w.DCOrgY - 1;
444 FillBrushObj = BRUSHOBJ_LockBrush(dc->w.hBrush);
446 ASSERT(FillBrushObj); // FIXME - I *think* this should always happen...
447 // it would be nice to remove the following if statement if that proves to be true
450 if ( FillBrushObj->logbrush.lbStyle != BS_NULL )
452 DestRect.left = LeftRect;
453 DestRect.right = RightRect;
454 DestRect.top = TopRect;
455 DestRect.bottom = BottomRect;
456 ret = ret && IntEngBitBlt(SurfObj,
470 BRUSHOBJ_UnlockBrush(dc->w.hBrush);
472 /* make BRUSHOBJ from current pen. */
473 HPenToBrushObj ( &PenBrushObj, dc->w.hPen );
475 // Draw the rectangle with the current pen
477 ret = TRUE; // change default to success
479 if ( PenBrushObj.logbrush.lbStyle != BS_NULL )
481 ret = ret && IntEngLineTo(SurfObj,
484 LeftRect, TopRect, RightRect, TopRect,
485 RectBounds, // Bounding rectangle
486 dc->w.ROPmode); // MIX
488 ret = ret && IntEngLineTo(SurfObj,
491 RightRect, TopRect, RightRect, BottomRect,
492 RectBounds, // Bounding rectangle
493 dc->w.ROPmode); // MIX
495 ret = ret && IntEngLineTo(SurfObj,
498 RightRect, BottomRect, LeftRect, BottomRect,
499 RectBounds, // Bounding rectangle
500 dc->w.ROPmode); // MIX
502 ret = ret && IntEngLineTo(SurfObj,
505 LeftRect, BottomRect, LeftRect, TopRect,
506 RectBounds, // Bounding rectangle
507 dc->w.ROPmode); // MIX */
511 // Move current position in DC?
512 // MSDN: The current position is neither used nor updated by Rectangle.
513 RGNDATA_UnlockRgn(dc->w.hGCClipRgn);
519 NtGdiRectangle(HDC hDC,
525 DC *dc = DC_LockDc(hDC);
526 BOOL ret = FALSE; // default to failure
530 ret = IntRectangle ( dc, LeftRect, TopRect, RightRect, BottomRect );
550 BRUSHOBJ PenBrush, *PenBrushObj, *FillBrushObj;
552 int i, col, row, width, height, x1, x1start, x2, x2start, y1, y2;
553 //float aspect_square;
554 long a_square, b_square,
555 two_a_square, two_b_square,
556 four_a_square, four_b_square,
559 ret = TRUE; // default to success
561 ASSERT ( dc ); // caller's responsibility to set this up
563 if ( PATH_IsPathOpen(dc->w.path) )
564 return PATH_RoundRect ( dc, left, top, right, bottom, xradius, yradius );
566 left += dc->w.DCOrgX;
567 right += dc->w.DCOrgX;
569 bottom += dc->w.DCOrgY;
571 RectBounds.left = left;
572 RectBounds.right = right;
573 RectBounds.top = top;
574 RectBounds.bottom = bottom;
576 SurfObj = (SURFOBJ*)AccessUserObject((ULONG)dc->Surface);
578 FillBrushObj = BRUSHOBJ_LockBrush(dc->w.hBrush);
579 ASSERT(FillBrushObj);
580 if ( FillBrushObj->logbrush.lbStyle == BS_NULL )
581 FillBrushObj = NULL; // make null brush check simpler...
583 HPenToBrushObj ( &PenBrush, dc->w.hPen );
584 if ( PenBrush.logbrush.lbStyle != BS_NULL )
585 PenBrushObj = &PenBrush;
592 width = right - left;
593 height = bottom - top;
595 if ( (xradius<<1) > width )
596 xradius = width >> 1;
597 if ( (yradius<<1) > height )
598 yradius = height >> 1;
600 b_square = yradius * yradius;
601 a_square = xradius * xradius;
604 two_a_square = a_square << 1;
605 four_a_square = a_square << 2;
606 four_b_square = b_square << 2;
607 two_b_square = b_square << 1;
608 d = two_a_square * ((row - 1) * (row))
610 + two_b_square * (1 - a_square);
620 dinc = two_b_square*3; /* two_b_square * (3 + (col << 1)); */
621 ddec = four_a_square * row;
629 PUTLINE ( x1, y1, x2, y1, FillBrushObj );
636 PUTLINE ( x1, y1, x1start, y1, PenBrushObj );
637 PUTLINE ( x2start+1, y2, x2+1, y2, PenBrushObj );
641 PUTPIXEL ( x1, y1, PenBrushObj );
642 PUTPIXEL ( x2, y2, PenBrushObj );
650 PUTLINE ( x1, y2, x2, y2, FillBrushObj );
655 PUTLINE ( x1, y1, x1start+1, y1, PenBrushObj );
656 PUTLINE ( x2start, y2, x2+1, y2, PenBrushObj );
660 PUTPIXEL ( x1, y1, PenBrushObj );
661 PUTPIXEL ( x2, y2, PenBrushObj );
669 PUTLINE ( x1, y2, x1start+1, y2, PenBrushObj );
670 PUTLINE ( x2start, y1, x2+1, y1, PenBrushObj );
674 PUTPIXEL ( x1, y2, PenBrushObj );
675 PUTPIXEL ( x2, y1, PenBrushObj );
680 row--, y1++, y2--, ddec -= four_a_square;
684 int potential_steps = ( a_square * row ) / b_square - col + 1;
685 while ( d < 0 && potential_steps-- )
687 d += dinc; /* two_b_square * (3 + (col << 1)); */
688 col++, x1--, x2++, dinc += four_b_square;
691 if ( a_square * row <= b_square * col )
695 d = two_b_square * (col + 1) * col
696 + two_a_square * (row * (row - 2) + 1)
697 + (1 - two_a_square) * b_square;
698 dinc = ddec; /* four_b_square * col; */
699 ddec = two_a_square * ((row << 1) - 3);
705 PUTLINE ( x1, y1, x2, y1, FillBrushObj );
706 PUTLINE ( x1, y2, x2, y2, FillBrushObj );
710 PUTPIXEL ( x2, y1, PenBrushObj );
711 PUTPIXEL ( x1, y2, PenBrushObj );
712 PUTPIXEL ( x2, y2, PenBrushObj );
713 PUTPIXEL ( x1, y1, PenBrushObj );
718 col++, x1--, x2++, dinc += four_b_square;
719 d += dinc; //four_b_square * col;
722 row--, y1++, y2--, ddec -= four_a_square;
723 d -= ddec; //two_a_square * ((row << 1) - 3);
728 PUTLINE ( left, y1, right, y1, FillBrushObj );
729 PUTLINE ( left, y2, right, y2, FillBrushObj );
735 PUTLINE ( left, y1, x1, y1, PenBrushObj );
736 PUTLINE ( x2+1, y1, right, y1, PenBrushObj );
737 PUTLINE ( left+1, y2, x1, y2, PenBrushObj );
738 PUTLINE ( x2+1, y2, right+1, y2, PenBrushObj );
742 PUTPIXEL ( left, y1, PenBrushObj );
743 PUTPIXEL ( right, y2, PenBrushObj );
754 for ( i = y1+1; i < y2; i++ )
755 PUTLINE ( left, i, right, i, FillBrushObj );
760 PUTLINE ( x1, top, x2, top, PenBrushObj );
761 PUTLINE ( right, y1, right, y2, PenBrushObj );
762 PUTLINE ( x2, bottom, x1, bottom, PenBrushObj );
763 PUTLINE ( left, y2, left, y1, PenBrushObj );
766 BRUSHOBJ_UnlockBrush(dc->w.hBrush);
782 DC *dc = DC_LockDc(hDC);
783 BOOL ret = FALSE; /* default to failure */
785 DPRINT("NtGdiRoundRect(0x%x,%i,%i,%i,%i,%i,%i)\n",hDC,LeftRect,TopRect,RightRect,BottomRect,Width,Height);
788 DPRINT1("NtGdiRoundRect() - hDC is invalid\n");
789 SetLastWin32Error(ERROR_INVALID_PARAMETER);
793 ret = IntRoundRect ( dc, LeftRect, TopRect, RightRect, BottomRect, Width, Height );