xref: /reactos/win32ss/gdi/ntgdi/arc.c (revision c2c66aff)
1 #include <win32k.h>
2 
3 #define NDEBUG
4 #include <debug.h>
5 
6 /*
7  * A couple of macros to fill a single pixel or a line
8  */
9 #define PUTPIXEL(x,y,BrushInst)        \
10   ret = ret && IntEngLineTo(&psurf->SurfObj, \
11        (CLIPOBJ *)&dc->co,                       \
12        &BrushInst.BrushObject,                   \
13        x, y, (x)+1, y,                           \
14        &RectBounds,                              \
15        ROP2_TO_MIX(pdcattr->jROP2));
16 
17 #define PUTLINE(x1,y1,x2,y2,BrushInst) \
18   ret = ret && IntEngLineTo(&psurf->SurfObj, \
19        (CLIPOBJ *)&dc->co,                       \
20        &BrushInst.BrushObject,                   \
21        x1, y1, x2, y2,                           \
22        &RectBounds,                              \
23        ROP2_TO_MIX(pdcattr->jROP2));
24 
25 static
26 BOOL
27 FASTCALL
IntArc(DC * dc,int Left,int Top,int Right,int Bottom,int XRadialStart,int YRadialStart,int XRadialEnd,int YRadialEnd,ARCTYPE arctype)28 IntArc( DC *dc,
29         int  Left,
30         int  Top,
31         int  Right,
32         int  Bottom,
33         int  XRadialStart,
34         int  YRadialStart,
35         int  XRadialEnd,
36         int  YRadialEnd,
37         ARCTYPE arctype)
38 {
39     PDC_ATTR pdcattr;
40     RECTL RectBounds, RectSEpts;
41     PBRUSH pbrPen;
42     SURFACE *psurf;
43     BOOL ret = TRUE;
44     LONG PenWidth, PenOrigWidth;
45     double AngleStart, AngleEnd;
46     LONG CenterX, CenterY;
47 
48     if (Right < Left)
49     {
50        INT tmp = Right; Right = Left; Left = tmp;
51     }
52     if (Bottom < Top)
53     {
54        INT tmp = Bottom; Bottom = Top; Top = tmp;
55     }
56 
57     /* Check if the target rect is empty */
58     if ((Left == Right) || (Top == Bottom)) return TRUE;
59 
60     // FIXME: this needs to be verified
61     if ((arctype == GdiTypeChord ) || (arctype == GdiTypePie))
62     {
63         if ((Right - Left == 1) || (Bottom - Top == 1))
64            return TRUE;
65     }
66 
67 
68     pdcattr = dc->pdcattr;
69 
70     pbrPen = PEN_ShareLockPen(pdcattr->hpen);
71     if (!pbrPen)
72     {
73         DPRINT1("Arc Fail 1\n");
74         EngSetLastError(ERROR_INTERNAL_ERROR);
75         return FALSE;
76     }
77 
78     PenOrigWidth = PenWidth = pbrPen->lWidth;
79     if (pbrPen->ulPenStyle == PS_NULL) PenWidth = 0;
80 
81     if (pbrPen->ulPenStyle == PS_INSIDEFRAME)
82     {
83        if (2*PenWidth > (Right - Left)) PenWidth = (Right -Left + 1)/2;
84        if (2*PenWidth > (Bottom - Top)) PenWidth = (Bottom -Top + 1)/2;
85        Left   += PenWidth / 2;
86        Right  -= (PenWidth - 1) / 2;
87        Top    += PenWidth / 2;
88        Bottom -= (PenWidth - 1) / 2;
89     }
90 
91     if (!PenWidth) PenWidth = 1;
92     pbrPen->lWidth = PenWidth;
93 
94     RectBounds.left   = Left;
95     RectBounds.right  = Right;
96     RectBounds.top    = Top;
97     RectBounds.bottom = Bottom;
98 
99     RectSEpts.left   = XRadialStart;
100     RectSEpts.top    = YRadialStart;
101     RectSEpts.right  = XRadialEnd;
102     RectSEpts.bottom = YRadialEnd;
103 
104     IntLPtoDP(dc, (LPPOINT)&RectBounds, 2);
105     IntLPtoDP(dc, (LPPOINT)&RectSEpts, 2);
106 
107     RectBounds.left   += dc->ptlDCOrig.x;
108     RectBounds.right  += dc->ptlDCOrig.x;
109     RectBounds.top    += dc->ptlDCOrig.y;
110     RectBounds.bottom += dc->ptlDCOrig.y;
111 
112     RectSEpts.left    += dc->ptlDCOrig.x;
113     RectSEpts.top     += dc->ptlDCOrig.y;
114     RectSEpts.right   += dc->ptlDCOrig.x;
115     RectSEpts.bottom  += dc->ptlDCOrig.y;
116 
117     DPRINT("1: StartX: %d, StartY: %d, EndX: %d, EndY: %d\n",
118                RectSEpts.left,RectSEpts.top,RectSEpts.right,RectSEpts.bottom);
119 
120     DPRINT("1: Left: %d, Top: %d, Right: %d, Bottom: %d\n",
121                RectBounds.left,RectBounds.top,RectBounds.right,RectBounds.bottom);
122 
123     CenterX = (RectBounds.right + RectBounds.left) / 2;
124     CenterY = (RectBounds.bottom + RectBounds.top) / 2;
125     AngleEnd   = atan2((RectSEpts.bottom - CenterY), RectSEpts.right - CenterX)*(360.0/(M_PI*2));
126     AngleStart = atan2((RectSEpts.top - CenterY), RectSEpts.left - CenterX)*(360.0/(M_PI*2));
127 
128     /* Edge Case: Check if the start segments overlaps(is equal) the end segment */
129     if (AngleEnd == AngleStart)
130     {
131         AngleStart = AngleEnd + 360.0; // Arc(), ArcTo(), Pie() and Chord() are counterclockwise APIs.
132     }
133 
134     if ((arctype == GdiTypePie) || (arctype == GdiTypeChord))
135     {
136         ret = IntFillArc( dc,
137               RectBounds.left,
138               RectBounds.top,
139               abs(RectBounds.right-RectBounds.left), // Width
140               abs(RectBounds.bottom-RectBounds.top), // Height
141               AngleStart,
142               AngleEnd,
143               arctype);
144     }
145 
146     if(ret)
147     {
148         ret = IntDrawArc( dc,
149                   RectBounds.left,
150                   RectBounds.top,
151                   abs(RectBounds.right-RectBounds.left), // Width
152                   abs(RectBounds.bottom-RectBounds.top), // Height
153                   AngleStart,
154                   AngleEnd,
155                   arctype,
156                   pbrPen);
157     }
158 
159     psurf = dc->dclevel.pSurface;
160     if (NULL == psurf)
161     {
162         DPRINT1("Arc Fail 2\n");
163         PEN_ShareUnlockPen(pbrPen);
164         EngSetLastError(ERROR_INTERNAL_ERROR);
165         return FALSE;
166     }
167 
168     if (arctype == GdiTypePie)
169     {
170         PUTLINE(CenterX, CenterY, RectSEpts.left, RectSEpts.top, dc->eboLine);
171         PUTLINE(RectSEpts.right, RectSEpts.bottom, CenterX, CenterY, dc->eboLine);
172     }
173     if (arctype == GdiTypeChord)
174         PUTLINE(RectSEpts.right, RectSEpts.bottom, RectSEpts.left, RectSEpts.top, dc->eboLine);
175 
176     pbrPen->lWidth = PenOrigWidth;
177     PEN_ShareUnlockPen(pbrPen);
178     DPRINT("IntArc Exit.\n");
179     return ret;
180 }
181 
182 
183 BOOL FASTCALL
IntGdiArcInternal(ARCTYPE arctype,DC * dc,int LeftRect,int TopRect,int RightRect,int BottomRect,int XStartArc,int YStartArc,int XEndArc,int YEndArc)184 IntGdiArcInternal(
185           ARCTYPE arctype,
186           DC  *dc,
187           int LeftRect,
188           int TopRect,
189           int RightRect,
190           int BottomRect,
191           int XStartArc,
192           int YStartArc,
193           int XEndArc,
194           int YEndArc)
195 {
196   BOOL Ret;
197   //PDC_ATTR pdcattr;
198 
199   DPRINT("StartX: %d, StartY: %d, EndX: %d, EndY: %d\n",
200            XStartArc,YStartArc,XEndArc,YEndArc);
201   DPRINT("Left: %d, Top: %d, Right: %d, Bottom: %d\n",
202            LeftRect,TopRect,RightRect,BottomRect);
203 
204   if ((LeftRect == RightRect) || (TopRect == BottomRect)) return TRUE;
205 
206   if (PATH_IsPathOpen(dc->dclevel))
207   {
208      return PATH_Arc( dc,
209                 LeftRect,
210                  TopRect,
211                RightRect,
212               BottomRect,
213                XStartArc,
214                YStartArc,
215                  XEndArc,
216                  YEndArc,
217                        0,
218                  arctype);
219   }
220 
221   //pdcattr = dc->pdcattr;
222 
223   if (arctype == GdiTypeArcTo)
224   {
225     if (dc->dclevel.flPath & DCPATH_CLOCKWISE)
226        IntGdiLineTo(dc, XEndArc, YEndArc);
227     else
228        IntGdiLineTo(dc, XStartArc, YStartArc);
229   }
230 
231   Ret = IntArc( dc,
232           LeftRect,
233            TopRect,
234          RightRect,
235         BottomRect,
236          XStartArc,
237          YStartArc,
238            XEndArc,
239            YEndArc,
240            arctype);
241 
242   if (arctype == GdiTypeArcTo)
243   {
244      if (dc->dclevel.flPath & DCPATH_CLOCKWISE)
245        IntGdiMoveToEx(dc, XStartArc, YStartArc, NULL);
246      else
247        IntGdiMoveToEx(dc, XEndArc, YEndArc, NULL);
248   }
249   return Ret;
250 }
251 
252 BOOL
253 FASTCALL
IntGdiAngleArc(PDC pDC,INT x,INT y,DWORD dwRadius,FLOAT eStartAngle,FLOAT eSweepAngle)254 IntGdiAngleArc( PDC pDC,
255                   INT x,
256                   INT y,
257          DWORD dwRadius,
258       FLOAT eStartAngle,
259       FLOAT eSweepAngle)
260 {
261   INT  x1, y1, x2, y2, arcdir;
262   BOOL result;
263 
264   /* Calculate the end point */
265   x2 = x + (INT)(cos(((eStartAngle+eSweepAngle)/360)*(M_PI*2)) * dwRadius);
266   y2 = y - (INT)(sin(((eStartAngle+eSweepAngle)/360)*(M_PI*2)) * dwRadius);
267 
268   x1 = x + (INT)(cos((eStartAngle/360)*(M_PI*2)) * dwRadius);
269   y1 = y - (INT)(sin((eStartAngle/360)*(M_PI*2)) * dwRadius);
270 
271   arcdir = pDC->dclevel.flPath & DCPATH_CLOCKWISE;
272   if (eSweepAngle >= 0)
273      pDC->dclevel.flPath &= ~DCPATH_CLOCKWISE;
274   else
275      pDC->dclevel.flPath |= DCPATH_CLOCKWISE;
276 
277   result = IntGdiArcInternal( GdiTypeArcTo,
278                                        pDC,
279                                 x-dwRadius,
280                                 y-dwRadius,
281                                 x+dwRadius,
282                                 y+dwRadius,
283                                         x1,
284                                         y1,
285                                         x2,
286                                         y2 );
287 
288   pDC->dclevel.flPath |= (arcdir & DCPATH_CLOCKWISE);
289 
290   if (result)
291   {
292      IntGdiMoveToEx(pDC, x2, y2, NULL);
293   }
294   return result;
295 }
296 
297 /* FUNCTIONS *****************************************************************/
298 
299 BOOL
300 APIENTRY
NtGdiAngleArc(IN HDC hDC,IN INT x,IN INT y,IN DWORD dwRadius,IN DWORD dwStartAngle,IN DWORD dwSweepAngle)301 NtGdiAngleArc(
302     IN HDC hDC,
303     IN INT x,
304     IN INT y,
305     IN DWORD dwRadius,
306     IN DWORD dwStartAngle,
307     IN DWORD dwSweepAngle)
308 {
309   DC *pDC;
310   BOOL Ret = FALSE;
311   gxf_long worker, worker1;
312   KFLOATING_SAVE FloatSave;
313   NTSTATUS status;
314 
315   pDC = DC_LockDc (hDC);
316   if(!pDC)
317   {
318     EngSetLastError(ERROR_INVALID_HANDLE);
319     return FALSE;
320   }
321 
322   status = KeSaveFloatingPointState(&FloatSave);
323   if (!NT_SUCCESS(status))
324   {
325       DC_UnlockDc( pDC );
326       return FALSE;
327   }
328 
329   worker.l  = dwStartAngle;
330   worker1.l = dwSweepAngle;
331   DC_vPrepareDCsForBlit(pDC, NULL, NULL, NULL);
332   if (pDC->pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
333     DC_vUpdateFillBrush(pDC);
334   if (pDC->pdcattr->ulDirty_ & (DIRTY_LINE | DC_PEN_DIRTY))
335     DC_vUpdateLineBrush(pDC);
336   Ret = IntGdiAngleArc( pDC, x, y, dwRadius, worker.f, worker1.f);
337   DC_vFinishBlit(pDC, NULL);
338   DC_UnlockDc( pDC );
339 
340   KeRestoreFloatingPointState(&FloatSave);
341 
342   return Ret;
343 }
344 
345 BOOL
346 APIENTRY
NtGdiArcInternal(ARCTYPE arctype,HDC hDC,int LeftRect,int TopRect,int RightRect,int BottomRect,int XStartArc,int YStartArc,int XEndArc,int YEndArc)347 NtGdiArcInternal(
348         ARCTYPE arctype,
349         HDC  hDC,
350         int  LeftRect,
351         int  TopRect,
352         int  RightRect,
353         int  BottomRect,
354         int  XStartArc,
355         int  YStartArc,
356         int  XEndArc,
357         int  YEndArc)
358 {
359   DC *dc;
360   BOOL Ret;
361   KFLOATING_SAVE FloatSave;
362   NTSTATUS status;
363 
364   dc = DC_LockDc (hDC);
365   if(!dc)
366   {
367     EngSetLastError(ERROR_INVALID_HANDLE);
368     return FALSE;
369   }
370   if (arctype > GdiTypePie)
371   {
372     DC_UnlockDc(dc);
373     EngSetLastError(ERROR_INVALID_PARAMETER);
374     return FALSE;
375   }
376 
377   DC_vPrepareDCsForBlit(dc, NULL, NULL, NULL);
378 
379   if (dc->pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
380     DC_vUpdateFillBrush(dc);
381 
382   if (dc->pdcattr->ulDirty_ & (DIRTY_LINE | DC_PEN_DIRTY))
383     DC_vUpdateLineBrush(dc);
384 
385   status = KeSaveFloatingPointState(&FloatSave);
386   if (!NT_SUCCESS(status))
387   {
388       DC_UnlockDc( dc );
389       return FALSE;
390   }
391 
392   Ret = IntGdiArcInternal(
393                   arctype,
394                   dc,
395                   LeftRect,
396                   TopRect,
397                   RightRect,
398                   BottomRect,
399                   XStartArc,
400                   YStartArc,
401                   XEndArc,
402                   YEndArc);
403 
404   KeRestoreFloatingPointState(&FloatSave);
405   DC_vFinishBlit(dc, NULL);
406   DC_UnlockDc( dc );
407   return Ret;
408 }
409 
410