update for HEAD-2003091401
[reactos.git] / subsys / 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 /* $Id$ */
20
21 #undef WIN32_LEAN_AND_MEAN
22 #include <windows.h>
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>
35
36 #define NDEBUG
37 #include <win32k/debug1.h>
38
39 /*
40  * a couple macros to fill a single pixel or a line
41  */
42 #define PUTPIXEL(x,y,brushObj)      \
43   ret = ret && IntEngLineTo(SurfObj,  \
44        dc->CombinedClip,              \
45        brushObj,                      \
46        x, y, (x)+1, y,                \
47        &RectBounds,                   \
48        dc->w.ROPmode);
49
50 #define PUTLINE(x1,y1,x2,y2,brushObj)  \
51   ret = ret && IntEngLineTo(SurfObj,  \
52        dc->CombinedClip,              \
53        brushObj,                      \
54        x1, y1, x2, y2,                \
55        &RectBounds,                   \
56        dc->w.ROPmode);
57
58 BOOL
59 STDCALL
60 NtGdiChord(HDC  hDC,
61                 int  LeftRect,
62                 int  TopRect,
63                 int  RightRect,
64                 int  BottomRect,
65                 int  XRadial1,
66                 int  YRadial1,
67                 int  XRadial2,
68                 int  YRadial2)
69 {
70   UNIMPLEMENTED;
71 }
72
73 BOOL
74 STDCALL
75 NtGdiEllipse(HDC hDC,
76              int Left,
77              int Top,
78              int Right,
79              int Bottom)
80 {
81   PDC dc;
82   int X, X18, X27, X36, X45;
83   int Y, Y14, Y23, Y58, Y67;
84   int d, Radius;
85   RECTL RectBounds;
86   PSURFOBJ SurfObj;
87   BRUSHOBJ PenBrushObj;
88   PBRUSHOBJ FillBrushObj;
89   BOOL ret = TRUE;
90
91   if (Right <= Left || Bottom <= Top)
92     {
93       SetLastWin32Error(ERROR_INVALID_PARAMETER);
94       return FALSE;
95     }
96
97   if (Right - Left != Bottom - Top)
98     {
99       UNIMPLEMENTED;
100     }
101
102   dc = DC_LockDc ( hDC );
103   if (NULL == dc)
104     {
105       SetLastWin32Error(ERROR_INVALID_PARAMETER);
106       return FALSE;
107     }
108
109   FillBrushObj = BRUSHOBJ_LockBrush(dc->w.hBrush);
110   if (NULL == FillBrushObj)
111     {
112       DC_UnlockDc(hDC);
113       SetLastWin32Error(ERROR_INTERNAL_ERROR);
114       return FALSE;
115     }
116
117   Left += dc->w.DCOrgX;
118   Right += dc->w.DCOrgX;
119   Top += dc->w.DCOrgY;
120   Bottom += dc->w.DCOrgY;
121
122   RectBounds.left = Left;
123   RectBounds.right = Right;
124   RectBounds.top = Top;
125   RectBounds.bottom = Bottom;
126
127   SurfObj = (PSURFOBJ) AccessUserObject((ULONG)dc->Surface);
128   HPenToBrushObj(&PenBrushObj, dc->w.hPen);
129   Radius = (Right - Left) / 2;
130   X = 0;
131   Y = Radius;
132   X18 = Right;
133   X27 = (Left + Right) / 2;
134   X36 = (Left + Right) / 2;
135   X45 = Left;
136   Y14 = Top + Radius;
137   Y23 = Top;
138   Y58 = Top + Radius;
139   Y67 = Top + (Right - Left);
140   d = 1 - Radius;
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);
146
147   while (X < Y)
148     {
149       if (d < 0)
150         {
151           d += 2 * X + 3;
152
153           X27++;
154           X36--;
155           Y14--;
156           Y58++;
157         }
158       else
159         {
160           d += 2 * (X - Y) + 5;
161           Y--;
162
163           Y23++;
164           Y67--;
165           X18--;
166           X45++;
167           X27++;
168           X36--;
169           Y14--;
170           Y58++;
171           PUTLINE(X36 + 1, Y23, X27, Y23, FillBrushObj);
172           PUTLINE(X36 + 1, Y67, X27, Y67, FillBrushObj);
173         }
174       X++;
175
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);
186     }
187
188   BRUSHOBJ_UnlockBrush(dc->w.hBrush);
189   DC_UnlockDc(hDC);
190
191   return TRUE;
192 }
193
194 BOOL
195 STDCALL
196 NtGdiPie(HDC  hDC,
197               int  LeftRect,
198               int  TopRect,
199               int  RightRect,
200               int  BottomRect,
201               int  XRadial1,
202               int  YRadial1,
203               int  XRadial2,
204               int  YRadial2)
205 {
206   UNIMPLEMENTED;
207 }
208
209 #if 0
210
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. 
214
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. 
219
220 extern BOOL FillPolygon(PDC dc,
221                                   SURFOBJ *SurfObj,
222                                   PBRUSHOBJ BrushObj,
223                                   MIX RopMode,
224                                   CONST PPOINT Points,
225                                   int Count,
226                                   RECTL BoundRect);
227
228 #endif
229
230 BOOL
231 FASTCALL
232 IntPolygon(PDC          dc,
233            CONST PPOINT UnsafePoints,
234            int          Count)
235 {
236   SURFOBJ *SurfObj;
237   BRUSHOBJ PenBrushObj, *FillBrushObj;
238   BOOL ret = FALSE; // default to failure
239   PRECTL RectBounds;
240   RECTL DestRect;
241   int CurrentPoint;
242   PPOINT Points;
243   NTSTATUS Status;
244
245   ASSERT(dc); // caller's responsibility to pass a valid dc
246
247   if ( NULL == UnsafePoints || Count < 2 )
248     {
249       SetLastWin32Error(ERROR_INVALID_PARAMETER);
250       return FALSE;
251     }
252
253   SurfObj = (SURFOBJ*)AccessUserObject((ULONG)dc->Surface);
254   ASSERT(SurfObj);
255
256   /* Copy points from userspace to kernelspace */
257   Points = ExAllocatePool(PagedPool, Count * sizeof(POINT));
258   if (NULL == Points)
259     SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
260   else
261   {
262     Status = MmCopyFromCaller(Points, UnsafePoints, Count * sizeof(POINT));
263     if ( !NT_SUCCESS(Status) )
264       SetLastNtError(Status);
265     else
266     {
267       /* Convert to screen coordinates */
268       for (CurrentPoint = 0; CurrentPoint < Count; CurrentPoint++)
269         {
270           Points[CurrentPoint].x += dc->w.DCOrgX;
271           Points[CurrentPoint].y += dc->w.DCOrgY;
272         }
273
274       RectBounds = (PRECTL) RGNDATA_LockRgn(dc->w.hGCClipRgn);
275       //ei not yet implemented ASSERT(RectBounds);
276
277       if (PATH_IsPathOpen(dc->w.path)) 
278         ret = PATH_Polygon(dc, Points, Count );
279       else
280       {
281         DestRect.left   = Points[0].x;
282         DestRect.right  = Points[0].x;
283         DestRect.top    = Points[0].y;
284         DestRect.bottom = Points[0].y;
285
286         for (CurrentPoint = 1; CurrentPoint < Count; ++CurrentPoint)
287         {
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);
292         }
293
294 #if 1
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);
301 #endif
302
303         /* make BRUSHOBJ from current pen. */
304         HPenToBrushObj ( &PenBrushObj, dc->w.hPen );
305
306         // Draw the Polygon Edges with the current pen ( if not a NULL pen )
307         if ( PenBrushObj.logbrush.lbStyle != BS_NULL )
308         {
309           for ( CurrentPoint = 0; CurrentPoint < Count; ++CurrentPoint )
310           {
311             POINT To, From; //, Next;
312
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]
316              */
317             From = Points[CurrentPoint];
318             if (Count <= CurrentPoint + 1)
319               To = Points[0];
320             else
321               To = Points[CurrentPoint + 1];
322
323             //DPRINT("Polygon Making line from (%d,%d) to (%d,%d)\n", From.x, From.y, To.x, To.y );
324             ret = IntEngLineTo(SurfObj,
325                                dc->CombinedClip,
326                                &PenBrushObj,
327                                From.x,
328                                From.y,
329                                To.x,
330                                To.y,
331                                &DestRect,
332                                dc->w.ROPmode); /* MIX */
333           }
334         }
335 #if 0
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);
342 #endif
343       }
344
345       RGNDATA_UnlockRgn(dc->w.hGCClipRgn);
346     }
347     ExFreePool ( Points );
348   }
349   return ret;
350 }
351
352 //This implementation is blatantly ripped off from NtGdiRectangle
353 BOOL
354 STDCALL
355 NtGdiPolygon(HDC          hDC,
356             CONST PPOINT UnsafePoints,
357             int          Count)
358 {
359   DC *dc;
360   BOOL ret = FALSE; // default to failure
361
362   //DPRINT("In NtGdiPolygon()\n");
363
364   dc = DC_LockDc ( hDC );
365
366   if ( !dc )
367     SetLastWin32Error(ERROR_INVALID_PARAMETER);
368   else
369   {
370     ret = IntPolygon ( dc, UnsafePoints, Count );
371     DC_UnlockDc ( hDC );
372   }
373
374   return ret;
375 }
376
377
378 BOOL
379 STDCALL
380 NtGdiPolyPolygon(HDC            hDC,
381                 CONST LPPOINT  Points,
382                 CONST LPINT    PolyCounts,
383                 int            Count)
384 {
385   DC *dc;
386   int i;
387   LPPOINT pt;
388   LPINT pc;
389   BOOL ret = FALSE; // default to failure
390
391   dc = DC_LockDc ( hDC );
392   pt = Points;
393   pc = PolyCounts;
394   if ( !dc )
395     SetLastWin32Error(ERROR_INVALID_PARAMETER);
396   else
397   {
398         for (i=0;i<Count;i++)
399         {
400             ret = IntPolygon ( dc, pt, *pc );
401                 if (ret == FALSE)
402                 {
403                     DC_UnlockDc ( hDC );
404                         return ret;
405                 }
406                 pt+=*pc++;
407         }
408     DC_UnlockDc ( hDC );
409   }
410
411   return ret;
412 }
413
414 BOOL
415 FASTCALL
416 IntRectangle(PDC dc,
417              int LeftRect,
418              int TopRect,
419              int RightRect,
420              int BottomRect)
421 {
422   SURFOBJ   *SurfObj = (SURFOBJ*)AccessUserObject((ULONG)dc->Surface);
423   BRUSHOBJ   PenBrushObj, *FillBrushObj;
424   BOOL       ret = FALSE; // default to failure
425   PRECTL     RectBounds;
426   RECTL      DestRect;
427
428   ASSERT ( dc ); // caller's responsibility to set this up
429
430   RectBounds = (PRECTL) RGNDATA_LockRgn(dc->w.hGCClipRgn);
431   //ei not yet implemented ASSERT(RectBounds);
432
433   if ( PATH_IsPathOpen(dc->w.path) )
434   {
435     ret = PATH_Rectangle ( dc, LeftRect, TopRect, RightRect, BottomRect );
436   }
437   else
438   {
439     LeftRect   += dc->w.DCOrgX;
440     RightRect  += dc->w.DCOrgX - 1;
441     TopRect    += dc->w.DCOrgY;
442     BottomRect += dc->w.DCOrgY - 1;
443
444     FillBrushObj = BRUSHOBJ_LockBrush(dc->w.hBrush);
445
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
448     if ( FillBrushObj )
449     {
450       if ( FillBrushObj->logbrush.lbStyle != BS_NULL )
451       {
452         DestRect.left = LeftRect;
453         DestRect.right = RightRect;
454         DestRect.top = TopRect;
455         DestRect.bottom = BottomRect;
456         ret = ret && IntEngBitBlt(SurfObj,
457                                   NULL,
458                                   NULL,
459                                   NULL,
460                                   NULL,
461                                   &DestRect,
462                                   NULL,
463                                   NULL,
464                                   FillBrushObj,
465                                   NULL,
466                                   PATCOPY);
467       }
468     }
469
470     BRUSHOBJ_UnlockBrush(dc->w.hBrush);
471
472     /* make BRUSHOBJ from current pen. */
473     HPenToBrushObj ( &PenBrushObj, dc->w.hPen );
474
475     // Draw the rectangle with the current pen
476
477     ret = TRUE; // change default to success
478
479     if ( PenBrushObj.logbrush.lbStyle != BS_NULL )
480     {
481       ret = ret && IntEngLineTo(SurfObj,
482                          dc->CombinedClip,
483                          &PenBrushObj,
484                          LeftRect, TopRect, RightRect, TopRect,
485                          RectBounds, // Bounding rectangle
486                          dc->w.ROPmode); // MIX
487
488       ret = ret && IntEngLineTo(SurfObj,
489                          dc->CombinedClip,
490                          &PenBrushObj,
491                          RightRect, TopRect, RightRect, BottomRect,
492                          RectBounds, // Bounding rectangle
493                          dc->w.ROPmode); // MIX
494
495       ret = ret && IntEngLineTo(SurfObj,
496                          dc->CombinedClip,
497                          &PenBrushObj,
498                          RightRect, BottomRect, LeftRect, BottomRect,
499                          RectBounds, // Bounding rectangle
500                          dc->w.ROPmode); // MIX
501
502       ret = ret && IntEngLineTo(SurfObj,
503                          dc->CombinedClip,
504                          &PenBrushObj,
505                          LeftRect, BottomRect, LeftRect, TopRect,
506                          RectBounds, // Bounding rectangle
507                          dc->w.ROPmode); // MIX */
508     }
509   }
510
511   // Move current position in DC?
512   // MSDN: The current position is neither used nor updated by Rectangle.
513   RGNDATA_UnlockRgn(dc->w.hGCClipRgn);
514   return TRUE;
515 }
516
517 BOOL
518 STDCALL
519 NtGdiRectangle(HDC  hDC,
520               int  LeftRect,
521               int  TopRect,
522               int  RightRect,
523               int  BottomRect)
524 {
525   DC   *dc = DC_LockDc(hDC);
526   BOOL  ret = FALSE; // default to failure
527
528   if ( dc )
529   {
530     ret = IntRectangle ( dc, LeftRect, TopRect, RightRect, BottomRect );
531     DC_UnlockDc ( hDC );
532   }
533
534   return ret;
535 }
536
537
538 BOOL
539 FASTCALL
540 IntRoundRect(
541         PDC  dc,
542         int  left,
543         int  top,
544         int  right,
545         int  bottom,
546         int  xradius,
547         int  yradius)
548 {
549   SURFOBJ   *SurfObj;
550   BRUSHOBJ   PenBrush, *PenBrushObj, *FillBrushObj;
551   RECTL      RectBounds;
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,
557     d, dinc, ddec;
558   BOOL first,
559     ret = TRUE; // default to success
560
561   ASSERT ( dc ); // caller's responsibility to set this up
562
563   if ( PATH_IsPathOpen(dc->w.path) )
564     return PATH_RoundRect ( dc, left, top, right, bottom, xradius, yradius );
565
566   left += dc->w.DCOrgX;
567   right += dc->w.DCOrgX;
568   top += dc->w.DCOrgY;
569   bottom += dc->w.DCOrgY;
570
571   RectBounds.left = left;
572   RectBounds.right = right;
573   RectBounds.top = top;
574   RectBounds.bottom = bottom;
575
576   SurfObj = (SURFOBJ*)AccessUserObject((ULONG)dc->Surface);
577
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...
582
583   HPenToBrushObj ( &PenBrush, dc->w.hPen );
584   if ( PenBrush.logbrush.lbStyle != BS_NULL )
585     PenBrushObj = &PenBrush;
586   else
587     PenBrushObj = NULL;
588
589   right--;
590   bottom--;
591
592   width = right - left;
593   height = bottom - top;
594
595   if ( (xradius<<1) > width )
596     xradius = width >> 1;
597   if ( (yradius<<1) > height )
598     yradius = height >> 1;
599
600   b_square = yradius * yradius;
601   a_square = xradius * xradius;
602   row = yradius;
603   col = 0;
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))
609     + a_square
610     + two_b_square * (1 - a_square);
611
612   x1 = left+xradius;
613   x2 = right-xradius;
614   y1 = top;
615   y2 = bottom;
616
617   x1start = x1;
618   x2start = x2;
619
620   dinc = two_b_square*3; /* two_b_square * (3 + (col << 1)); */
621   ddec = four_a_square * row;
622
623   first = TRUE;
624   for ( ;; )
625   {
626     if ( d >= 0 )
627     {
628       if ( FillBrushObj )
629         PUTLINE ( x1, y1, x2, y1, FillBrushObj );
630       if ( first )
631       {
632         if ( PenBrushObj )
633         {
634           if ( x1start > x1 )
635           {
636             PUTLINE ( x1, y1, x1start, y1, PenBrushObj );
637             PUTLINE ( x2start+1, y2, x2+1, y2, PenBrushObj );
638           }
639           else
640           {
641             PUTPIXEL ( x1, y1, PenBrushObj );
642             PUTPIXEL ( x2, y2, PenBrushObj );
643           }
644         }
645         first = FALSE;
646       }
647       else
648       {
649         if ( FillBrushObj )
650           PUTLINE ( x1, y2, x2, y2, FillBrushObj );
651         if ( PenBrushObj )
652         {
653           if ( x1start >= x1 )
654           {
655             PUTLINE ( x1, y1, x1start+1, y1, PenBrushObj );
656             PUTLINE ( x2start, y2, x2+1, y2, PenBrushObj );
657           }
658           else
659           {
660             PUTPIXEL ( x1, y1, PenBrushObj );
661             PUTPIXEL ( x2, y2, PenBrushObj );
662           }
663         }
664       }
665       if ( PenBrushObj )
666       {
667         if ( x1start > x1 )
668         {
669           PUTLINE ( x1, y2, x1start+1, y2, PenBrushObj );
670           PUTLINE ( x2start, y1, x2+1, y1, PenBrushObj );
671         }
672         else
673         {
674           PUTPIXEL ( x1, y2, PenBrushObj );
675           PUTPIXEL ( x2, y1, PenBrushObj );
676         }
677       }
678       x1start = x1-1;
679       x2start = x2+1;
680       row--, y1++, y2--, ddec -= four_a_square;
681       d -= ddec;
682     }
683
684     int potential_steps = ( a_square * row ) / b_square - col + 1;
685     while ( d < 0 && potential_steps-- )
686     {
687       d += dinc; /* two_b_square * (3 + (col << 1)); */
688       col++, x1--, x2++, dinc += four_b_square;
689     }
690
691     if ( a_square * row <= b_square * col )
692       break;
693   };
694
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);
700
701   while ( row )
702   {
703     if ( FillBrushObj )
704     {
705       PUTLINE ( x1, y1, x2, y1, FillBrushObj );
706       PUTLINE ( x1, y2, x2, y2, FillBrushObj );
707     }
708     if ( PenBrushObj )
709     {
710       PUTPIXEL ( x2, y1, PenBrushObj );
711       PUTPIXEL ( x1, y2, PenBrushObj );
712       PUTPIXEL ( x2, y2, PenBrushObj );
713       PUTPIXEL ( x1, y1, PenBrushObj );
714     }
715
716     if ( d <= 0 )
717     {
718       col++, x1--, x2++, dinc += four_b_square;
719       d += dinc; //four_b_square * col;
720     }
721
722     row--, y1++, y2--, ddec -= four_a_square;
723     d -= ddec; //two_a_square * ((row << 1) - 3);
724   }
725
726   if ( FillBrushObj )
727   {
728     PUTLINE ( left, y1, right, y1, FillBrushObj );
729     PUTLINE ( left, y2, right, y2, FillBrushObj );
730   }
731   if ( PenBrushObj )
732   {
733     if ( x1 > (left+1) )
734     {
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 );
739     }
740     else
741     {
742       PUTPIXEL ( left, y1, PenBrushObj );
743       PUTPIXEL ( right, y2, PenBrushObj );
744     }
745   }
746
747   x1 = left+xradius;
748   x2 = right-xradius;
749   y1 = top+yradius;
750   y2 = bottom-yradius;
751
752   if ( FillBrushObj )
753   {
754     for ( i = y1+1; i < y2; i++ )
755       PUTLINE ( left, i, right, i, FillBrushObj );
756   }
757
758   if ( PenBrushObj )
759   {
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 );
764   }
765
766   BRUSHOBJ_UnlockBrush(dc->w.hBrush);
767
768   return ret;
769 }
770
771 BOOL
772 STDCALL
773 NtGdiRoundRect(
774         HDC  hDC,
775         int  LeftRect,
776         int  TopRect,
777         int  RightRect,
778         int  BottomRect,
779         int  Width,
780         int  Height)
781 {
782   DC   *dc = DC_LockDc(hDC);
783   BOOL  ret = FALSE; /* default to failure */
784
785   DPRINT("NtGdiRoundRect(0x%x,%i,%i,%i,%i,%i,%i)\n",hDC,LeftRect,TopRect,RightRect,BottomRect,Width,Height);
786   if ( !dc )
787   {
788     DPRINT1("NtGdiRoundRect() - hDC is invalid\n");
789     SetLastWin32Error(ERROR_INVALID_PARAMETER);
790   }
791   else
792   {
793     ret = IntRoundRect ( dc, LeftRect, TopRect, RightRect, BottomRect, Width, Height );
794     DC_UnlockDc ( hDC );
795   }
796
797   return ret;
798 }
799 /* EOF */