Path needed some love Phase II:
[reactos.git] / reactos / subsystems / win32 / win32k / objects / arc.c
1 #include <w32k.h>
2
3 #define NDEBUG
4 #include <debug.h>
5
6 /*
7 * a couple macros to fill a single pixel or a line
8 */
9 #define PUTPIXEL(x,y,BrushInst) \
10 ret = ret && IntEngLineTo(&BitmapObj->SurfObj, \
11 dc->CombinedClip, \
12 &BrushInst.BrushObject, \
13 x, y, (x)+1, y, \
14 &RectBounds, \
15 ROP2_TO_MIX(Dc_Attr->jROP2));
16
17 #define PUTLINE(x1,y1,x2,y2,BrushInst) \
18 ret = ret && IntEngLineTo(&BitmapObj->SurfObj, \
19 dc->CombinedClip, \
20 &BrushInst.BrushObject, \
21 x1, y1, x2, y2, \
22 &RectBounds, \
23 ROP2_TO_MIX(Dc_Attr->jROP2));
24
25 #define Rsin(d) ((d) == 0.0 ? 0.0 : ((d) == 90.0 ? 1.0 : sin(d*M_PI/180.0)))
26 #define Rcos(d) ((d) == 0.0 ? 1.0 : ((d) == 90.0 ? 0.0 : cos(d*M_PI/180.0)))
27
28 static
29 BOOL
30 FASTCALL
31 IntArc( DC *dc,
32 int Left,
33 int Top,
34 int Right,
35 int Bottom,
36 int XRadialStart,
37 int YRadialStart,
38 int XRadialEnd,
39 int YRadialEnd,
40 ARCTYPE arctype)
41 {
42 PDC_ATTR Dc_Attr;
43 RECTL RectBounds;
44 PGDIBRUSHOBJ PenBrushObj, FillBrushObj;
45 GDIBRUSHINST FillBrushInst, PenBrushInst;
46 BITMAPOBJ *BitmapObj;
47 BOOL ret = TRUE;
48 double AngleStart, AngleEnd;
49 LONG RadiusX, RadiusY, CenterX, CenterY;
50 LONG SfCx, SfCy, EfCx, EfCy;
51
52 /* top
53 ___________________
54 +| |
55 | |
56 | |
57 left | | right
58 | |
59 | |
60 0|___________________|
61 0 bottom +
62 */
63 if (Right <= Left || Top <= Bottom)
64 {
65 DPRINT1("Arc Fail 1\n");
66 SetLastWin32Error(ERROR_INVALID_PARAMETER);
67 return FALSE;
68 }
69 /*
70 if (Right - Left != Bottom - Top)
71 {
72 UNIMPLEMENTED;
73 }
74 */
75 Dc_Attr = dc->pDc_Attr;
76 if(!Dc_Attr) Dc_Attr = &dc->Dc_Attr;
77
78 FillBrushObj = BRUSHOBJ_LockBrush(Dc_Attr->hbrush);
79 if (NULL == FillBrushObj)
80 {
81 DPRINT1("Arc Fail 2\n");
82 SetLastWin32Error(ERROR_INTERNAL_ERROR);
83 return FALSE;
84 }
85
86 PenBrushObj = PENOBJ_LockPen(Dc_Attr->hpen);
87 if (NULL == PenBrushObj)
88 {
89 DPRINT1("Arc Fail 3\n");
90 BRUSHOBJ_UnlockBrush(FillBrushObj);
91 SetLastWin32Error(ERROR_INTERNAL_ERROR);
92 return FALSE;
93 }
94
95 BitmapObj = BITMAPOBJ_LockBitmap(dc->w.hBitmap);
96 if (NULL == BitmapObj)
97 {
98 DPRINT1("Arc Fail 4\n");
99 BRUSHOBJ_UnlockBrush(FillBrushObj);
100 PENOBJ_UnlockPen(PenBrushObj);
101 SetLastWin32Error(ERROR_INTERNAL_ERROR);
102 return FALSE;
103 }
104
105 IntGdiInitBrushInstance(&FillBrushInst, FillBrushObj, dc->XlateBrush);
106 IntGdiInitBrushInstance(&PenBrushInst, PenBrushObj, dc->XlatePen);
107
108 Left += dc->ptlDCOrig.x;
109 Right += dc->ptlDCOrig.x;
110 Top += dc->ptlDCOrig.y;
111 Bottom += dc->ptlDCOrig.y;
112
113 XRadialStart += dc->ptlDCOrig.x;
114 YRadialStart += dc->ptlDCOrig.y;
115 XRadialEnd += dc->ptlDCOrig.x;
116 YRadialEnd += dc->ptlDCOrig.y;
117
118 DPRINT1("1: StartX: %d, StartY: %d, EndX: %d, EndY: %d\n",
119 XRadialStart,YRadialStart,XRadialEnd,YRadialEnd);
120
121 RectBounds.left = Left;
122 RectBounds.right = Right;
123 RectBounds.top = Top;
124 RectBounds.bottom = Bottom;
125 DPRINT1("1: Left: %d, Top: %d, Right: %d, Bottom: %d\n",
126 RectBounds.left,RectBounds.top,RectBounds.right,RectBounds.bottom);
127
128 if (Left == Right)
129 {
130 DPRINT1("Arc Good Exit\n");
131 PUTPIXEL(Left, Top, PenBrushInst);
132 BITMAPOBJ_UnlockBitmap(BitmapObj);
133 BRUSHOBJ_UnlockBrush(FillBrushObj);
134 PENOBJ_UnlockPen(PenBrushObj);
135 return ret;
136 }
137 RadiusX = (RectBounds.right - RectBounds.left)/2;
138 RadiusY = (RectBounds.bottom - RectBounds.top)/2;
139 CenterX = RectBounds.left + RadiusX;
140 CenterY = RectBounds.top + RadiusY;
141
142 AngleEnd = atan2(-(YRadialEnd - CenterY), XRadialEnd - CenterX)* (180.0 / M_PI);
143 AngleStart = atan2(-(YRadialStart - CenterY), XRadialStart - CenterX)* (180.0 / M_PI);
144
145 SfCx = (Rcos(AngleStart) * RadiusX);
146 SfCy = (Rsin(AngleStart) * RadiusY);
147
148 EfCx = (Rcos(AngleEnd) * RadiusX);
149 EfCy = (Rsin(AngleEnd) * RadiusY);
150 {
151 FLOAT AngS = AngleStart, Factor = 1;
152 int x,y, ox = 0, oy = 0;
153
154 if (arctype == GdiTypePie)
155 {
156 PUTLINE(SfCx + CenterX, SfCy + CenterY, CenterX, CenterY, PenBrushInst);
157 }
158
159 for(; AngS < AngleEnd; AngS += Factor)
160 {
161 x = (Rcos(AngS) * RadiusX);
162 y = (Rsin(AngS) * RadiusY);
163
164 if (arctype == GdiTypePie)
165 PUTLINE((x + CenterX) - 1, (y + CenterY) - 1, CenterX, CenterY, FillBrushInst);
166
167 PUTPIXEL (x + CenterX, y + CenterY, PenBrushInst);
168 ox = x;
169 oy = y;
170 }
171
172 if (arctype == GdiTypePie)
173 PUTLINE(EfCx + CenterX, EfCy + CenterY, CenterX, CenterY, PenBrushInst);
174
175 }
176 BITMAPOBJ_UnlockBitmap(BitmapObj);
177 BRUSHOBJ_UnlockBrush(FillBrushObj);
178 PENOBJ_UnlockPen(PenBrushObj);
179 DPRINT1("IntArc Exit.\n");
180 return ret;
181 }
182
183
184 BOOL FASTCALL
185 IntGdiArcInternal(
186 ARCTYPE arctype,
187 DC *dc,
188 int LeftRect,
189 int TopRect,
190 int RightRect,
191 int BottomRect,
192 int XStartArc,
193 int YStartArc,
194 int XEndArc,
195 int YEndArc)
196 {
197 BOOL Ret;
198 RECT rc, rc1;
199 double AngleStart, AngleEnd;
200 LONG RadiusX, RadiusY, CenterX, CenterY, Width, Height;
201 LONG SfCx, SfCy, EfCx = 0, EfCy = 0;
202
203 DPRINT1("StartX: %d, StartY: %d, EndX: %d, EndY: %d\n",
204 XStartArc,YStartArc,XEndArc,YEndArc);
205 DPRINT1("Left: %d, Top: %d, Right: %d, Bottom: %d\n",
206 LeftRect,TopRect,RightRect,BottomRect);
207
208 if (PATH_IsPathOpen(dc->DcLevel))
209 {
210 return PATH_Arc( dc,
211 LeftRect,
212 TopRect,
213 RightRect,
214 BottomRect,
215 XStartArc,
216 YStartArc,
217 XEndArc,
218 YEndArc,
219 arctype);
220 }
221
222 if (arctype == GdiTypeArcTo)
223 {
224 Width = fabs(RightRect - LeftRect);
225 Height = fabs(BottomRect - TopRect);
226 RadiusX = Width/2;
227 RadiusY = Height/2;
228 CenterX = RightRect > LeftRect ? LeftRect + RadiusX : RightRect + RadiusX;
229 CenterY = BottomRect > TopRect ? TopRect + RadiusY : BottomRect + RadiusY;
230
231 AngleStart = atan2((YStartArc - CenterY)/Height, (XStartArc - CenterX)/Width);
232 AngleEnd = atan2((YEndArc - CenterY)/Height, (XEndArc - CenterX)/Width);
233
234 EfCx = GDI_ROUND(CenterX+cos(AngleEnd) * RadiusX);
235 EfCy = GDI_ROUND(CenterY+sin(AngleEnd) * RadiusY);
236 SfCx = GDI_ROUND(CenterX+cos(AngleStart) * RadiusX);
237 SfCy = GDI_ROUND(CenterY+sin(AngleStart) * RadiusY);
238
239 IntGdiLineTo(dc, SfCx, SfCy);
240 }
241
242 IntGdiSetRect(&rc, LeftRect, TopRect, RightRect, BottomRect);
243 IntGdiSetRect(&rc1, XStartArc, YStartArc, XEndArc, YEndArc);
244
245 // IntLPtoDP(dc, (LPPOINT)&rc, 2);
246 // IntLPtoDP(dc, (LPPOINT)&rc1, 2);
247
248 Ret = IntArc( dc,
249 rc.left,
250 rc.top,
251 rc.right,
252 rc.bottom,
253 rc1.left,
254 rc1.top,
255 rc1.right,
256 rc1.bottom,
257 arctype);
258
259 if (arctype == GdiTypeArcTo)
260 {
261 IntGdiMoveToEx(dc, EfCx, EfCy, NULL);
262 }
263
264 return Ret;
265 }
266
267 BOOL
268 FASTCALL
269 IntGdiAngleArc( PDC pDC,
270 INT x,
271 INT y,
272 DWORD dwRadius,
273 FLOAT eStartAngle,
274 FLOAT eSweepAngle)
275 {
276 INT x1, y1, x2, y2, arcdir;
277 BOOL result;
278
279 /* Calculate the end point */
280 x2 = x + (INT)(cos(((eStartAngle+eSweepAngle)/360)*(M_PI*2)) * dwRadius);
281 y2 = y - (INT)(sin(((eStartAngle+eSweepAngle)/360)*(M_PI*2)) * dwRadius);
282
283 x1 = x + (INT)(cos((eStartAngle/360)*(M_PI*2)) * dwRadius);
284 y1 = y - (INT)(sin((eStartAngle/360)*(M_PI*2)) * dwRadius);
285
286 arcdir = pDC->DcLevel.flPath & DCPATH_CLOCKWISE;
287 if (eSweepAngle >= 0)
288 pDC->DcLevel.flPath &= ~DCPATH_CLOCKWISE;
289 else
290 pDC->DcLevel.flPath |= DCPATH_CLOCKWISE;
291
292 result = IntGdiArcInternal( GdiTypeArcTo,
293 pDC,
294 x-dwRadius,
295 y+dwRadius,
296 x+dwRadius,
297 y-dwRadius,
298 x1,
299 y1,
300 x2,
301 y2 );
302
303 pDC->DcLevel.flPath |= (arcdir & DCPATH_CLOCKWISE);
304
305 if (result)
306 {
307 IntGdiMoveToEx(pDC, x2, y2, NULL);
308 }
309 return result;
310 }
311
312 /* FUNCTIONS *****************************************************************/
313
314 BOOL
315 APIENTRY
316 NtGdiAngleArc(
317 IN HDC hDC,
318 IN INT x,
319 IN INT y,
320 IN DWORD dwRadius,
321 IN DWORD dwStartAngle,
322 IN DWORD dwSweepAngle)
323 {
324 DC *pDC;
325 BOOL Ret = FALSE;
326 gxf_long worker, worker1;
327
328 pDC = DC_LockDc (hDC);
329 if(!pDC)
330 {
331 SetLastWin32Error(ERROR_INVALID_HANDLE);
332 return FALSE;
333 }
334 if (pDC->DC_Type == DC_TYPE_INFO)
335 {
336 DC_UnlockDc(pDC);
337 /* Yes, Windows really returns TRUE in this case */
338 return TRUE;
339 }
340 worker.l = dwStartAngle;
341 worker1.l = dwSweepAngle;
342 Ret = IntGdiAngleArc( pDC, x, y, dwRadius, worker.f, worker1.f);
343 DC_UnlockDc( pDC );
344 return Ret;
345 }
346
347 BOOL
348 STDCALL
349 NtGdiArcInternal(
350 ARCTYPE arctype,
351 HDC hDC,
352 int LeftRect,
353 int TopRect,
354 int RightRect,
355 int BottomRect,
356 int XStartArc,
357 int YStartArc,
358 int XEndArc,
359 int YEndArc)
360 {
361 DC *dc;
362 BOOL Ret;
363
364 dc = DC_LockDc (hDC);
365 if(!dc)
366 {
367 SetLastWin32Error(ERROR_INVALID_HANDLE);
368 return FALSE;
369 }
370 if (dc->DC_Type == DC_TYPE_INFO)
371 {
372 DC_UnlockDc(dc);
373 /* Yes, Windows really returns TRUE in this case */
374 return TRUE;
375 }
376
377 Ret = IntGdiArcInternal(
378 arctype,
379 dc,
380 LeftRect,
381 TopRect,
382 RightRect,
383 BottomRect,
384 XStartArc,
385 YStartArc,
386 XEndArc,
387 YEndArc);
388
389 DC_UnlockDc( dc );
390 return Ret;
391 }
392