Fix drawing pie fill aligment.
[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 BOOL FASTCALL IntFillArc( PDC dc, INT XLeft, INT YLeft, INT Width, INT Height, double StartArc, double EndArc, ARCTYPE arctype);
29
30 static
31 BOOL
32 FASTCALL
33 IntArc( DC *dc,
34 int Left,
35 int Top,
36 int Right,
37 int Bottom,
38 int XRadialStart,
39 int YRadialStart,
40 int XRadialEnd,
41 int YRadialEnd,
42 ARCTYPE arctype)
43 {
44 PDC_ATTR Dc_Attr;
45 RECTL RectBounds;
46 PGDIBRUSHOBJ PenBrushObj;
47 GDIBRUSHINST PenBrushInst;
48 BITMAPOBJ *BitmapObj;
49 BOOL ret = TRUE;
50 LONG PenWidth, PenOrigWidth;
51 double AngleStart, AngleEnd;
52 LONG RadiusX, RadiusY, CenterX, CenterY;
53 LONG SfCx, SfCy, EfCx, EfCy;
54
55 /* top
56 ___________________
57 +| |
58 | |
59 | |
60 left | | right
61 | |
62 | |
63 0|___________________|
64 0 bottom +
65 */
66 if (Right < Left)
67 {
68 INT tmp = Right; Right = Left; Left = tmp;
69 }
70 if (Bottom < Top)
71 {
72 INT tmp = Bottom; Bottom = Top; Top = tmp;
73 }
74 if ((Left == Right) ||
75 (Top == Bottom) ||
76 (((arctype != GdiTypeArc) || (arctype != GdiTypeArcTo)) &&
77 ((Right - Left == 1) ||
78 (Bottom - Top == 1))))
79 return TRUE;
80
81 if (dc->DcLevel.flPath & DCPATH_CLOCKWISE)
82 {
83 INT X, Y;
84 X = XRadialStart;
85 Y = YRadialStart;
86 XRadialStart = XRadialEnd;
87 YRadialStart = YRadialEnd;
88 XRadialEnd = X;
89 YRadialEnd = Y;
90 }
91
92 Dc_Attr = dc->pDc_Attr;
93 if(!Dc_Attr) Dc_Attr = &dc->Dc_Attr;
94
95 PenBrushObj = PENOBJ_LockPen(Dc_Attr->hpen);
96 if (NULL == PenBrushObj)
97 {
98 DPRINT1("Arc Fail 1\n");
99 SetLastWin32Error(ERROR_INTERNAL_ERROR);
100 return FALSE;
101 }
102
103 PenOrigWidth = PenWidth = PenBrushObj->ptPenWidth.x;
104 if (PenBrushObj->ulPenStyle == PS_NULL) PenWidth = 0;
105
106 if (PenBrushObj->ulPenStyle == PS_INSIDEFRAME)
107 {
108 if (2*PenWidth > (Right - Left)) PenWidth = (Right -Left + 1)/2;
109 if (2*PenWidth > (Bottom - Top)) PenWidth = (Bottom -Top + 1)/2;
110 Left += PenWidth / 2;
111 Right -= (PenWidth - 1) / 2;
112 Top += PenWidth / 2;
113 Bottom -= (PenWidth - 1) / 2;
114 }
115
116 if (!PenWidth) PenWidth = 1;
117 PenBrushObj->ptPenWidth.x = PenWidth;
118
119 Left += dc->ptlDCOrig.x;
120 Right += dc->ptlDCOrig.x;
121 Top += dc->ptlDCOrig.y;
122 Bottom += dc->ptlDCOrig.y;
123
124 XRadialStart += dc->ptlDCOrig.x;
125 YRadialStart += dc->ptlDCOrig.y;
126 XRadialEnd += dc->ptlDCOrig.x;
127 YRadialEnd += dc->ptlDCOrig.y;
128
129 DPRINT1("1: StartX: %d, StartY: %d, EndX: %d, EndY: %d\n",
130 XRadialStart,YRadialStart,XRadialEnd,YRadialEnd);
131
132 RectBounds.left = Left;
133 RectBounds.right = Right;
134 RectBounds.top = Top;
135 RectBounds.bottom = Bottom;
136
137 IntLPtoDP(dc, (LPPOINT)&RectBounds, 2);
138
139 DPRINT1("1: Left: %d, Top: %d, Right: %d, Bottom: %d\n",
140 RectBounds.left,RectBounds.top,RectBounds.right,RectBounds.bottom);
141
142 RadiusX = max((RectBounds.right - RectBounds.left) / 2, 1);
143 RadiusY = max((RectBounds.bottom - RectBounds.top) / 2, 1);
144 CenterX = (RectBounds.right + RectBounds.left) / 2;
145 CenterY = (RectBounds.bottom + RectBounds.top) / 2;
146 AngleEnd = atan2((YRadialEnd - CenterY), XRadialEnd - CenterX)*(360.0/(M_PI*2));
147 AngleStart = atan2((YRadialStart - CenterY), XRadialStart - CenterX)*(360.0/(M_PI*2));
148
149 SfCx = (Rcos(AngleStart) * RadiusX);
150 SfCy = (Rsin(AngleStart) * RadiusY);
151 EfCx = (Rcos(AngleEnd) * RadiusX);
152 EfCy = (Rsin(AngleEnd) * RadiusY);
153
154 if ((arctype == GdiTypePie) || (arctype == GdiTypeChord))
155 {
156 ret = IntFillArc( dc,
157 RectBounds.left,
158 RectBounds.top,
159 abs(RectBounds.right-RectBounds.left), // Width
160 abs(RectBounds.bottom-RectBounds.top), // Height
161 AngleStart,
162 AngleEnd,
163 arctype);
164 }
165
166 BitmapObj = BITMAPOBJ_LockBitmap(dc->w.hBitmap);
167 if (NULL == BitmapObj)
168 {
169 DPRINT1("Arc Fail 2\n");
170 PENOBJ_UnlockPen(PenBrushObj);
171 SetLastWin32Error(ERROR_INTERNAL_ERROR);
172 return FALSE;
173 }
174
175 IntGdiInitBrushInstance(&PenBrushInst, PenBrushObj, dc->XlatePen);
176
177 if (arctype == GdiTypePie)
178 {
179 PUTLINE(CenterX, CenterY, SfCx + CenterX, SfCy + CenterY, PenBrushInst);
180 }
181 {
182 double AngS = AngleStart, AngT = AngleEnd,
183 Factor = fabs(RadiusX) < 25 ? 1.0 : (25/fabs(RadiusX));
184 int x,y, ox = 0, oy = 0;
185 BOOL Start = TRUE;
186
187 if (dc->DcLevel.flPath & DCPATH_CLOCKWISE)
188 {
189 DPRINT1("Arc CW\n");
190 for (; AngS < AngT; AngS += Factor)
191 {
192 x = (RadiusX * Rcos(AngS));
193 y = (RadiusY * Rsin(AngS));
194
195 DPRINT("Arc CW -> %d, X: %d Y: %d\n",(INT)AngS,x,y);
196 if (Start)
197 {
198 PUTPIXEL(x + CenterX, y + CenterY, PenBrushInst);
199 ox = x;
200 oy = y;
201 Start = FALSE;
202 continue;
203 }
204 PUTLINE(ox + CenterX, oy + CenterY, x + CenterX, y + CenterY, PenBrushInst);
205 ox = x;
206 oy = y;
207 }
208 }
209 else
210 {
211 DPRINT1("Arc CCW\n");
212 for (; AngT < AngS; AngS -= Factor)
213 {
214 x = (RadiusX * Rcos(AngS));
215 y = (RadiusY * Rsin(AngS));
216
217 DPRINT("Arc CCW -> %d, X: %d Y: %d\n",(INT)AngS,x,y);
218 if (Start)
219 {
220 PUTPIXEL(x + CenterX, y + CenterY, PenBrushInst);
221 ox = x;
222 oy = y;
223 Start = FALSE;
224 continue;
225 }
226 PUTLINE(ox + CenterX, oy + CenterY, x + CenterX, y + CenterY, PenBrushInst);
227 ox = x;
228 oy = y;
229 }
230 }
231 }
232 if (arctype == GdiTypePie)
233 PUTLINE(EfCx + CenterX, EfCy + CenterY, CenterX, CenterY, PenBrushInst);
234 if (arctype == GdiTypeChord)
235 PUTLINE(EfCx + CenterX, EfCy + CenterY, SfCx + CenterX, SfCy + CenterY, PenBrushInst);
236
237 PenBrushObj->ptPenWidth.x = PenOrigWidth;
238 BITMAPOBJ_UnlockBitmap(BitmapObj);
239 PENOBJ_UnlockPen(PenBrushObj);
240 DPRINT1("IntArc Exit.\n");
241 return ret;
242 }
243
244
245 BOOL FASTCALL
246 IntGdiArcInternal(
247 ARCTYPE arctype,
248 DC *dc,
249 int LeftRect,
250 int TopRect,
251 int RightRect,
252 int BottomRect,
253 int XStartArc,
254 int YStartArc,
255 int XEndArc,
256 int YEndArc)
257 {
258 BOOL Ret;
259 RECT rc, rc1;
260
261 DPRINT1("StartX: %d, StartY: %d, EndX: %d, EndY: %d\n",
262 XStartArc,YStartArc,XEndArc,YEndArc);
263 DPRINT1("Left: %d, Top: %d, Right: %d, Bottom: %d\n",
264 LeftRect,TopRect,RightRect,BottomRect);
265
266 if (PATH_IsPathOpen(dc->DcLevel))
267 {
268 return PATH_Arc( dc,
269 LeftRect,
270 TopRect,
271 RightRect,
272 BottomRect,
273 XStartArc,
274 YStartArc,
275 XEndArc,
276 YEndArc,
277 arctype);
278 }
279
280 if (arctype == GdiTypeArcTo)
281 {
282 if (dc->DcLevel.flPath & DCPATH_CLOCKWISE)
283 IntGdiLineTo(dc, XEndArc, YEndArc);
284 else
285 IntGdiLineTo(dc, XStartArc, YStartArc);
286 }
287
288 IntGdiSetRect(&rc, LeftRect, TopRect, RightRect, BottomRect);
289 IntGdiSetRect(&rc1, XStartArc, YStartArc, XEndArc, YEndArc);
290
291 // IntLPtoDP(dc, (LPPOINT)&rc, 2);
292 // IntLPtoDP(dc, (LPPOINT)&rc1, 2);
293
294
295 Ret = IntArc( dc,
296 rc.left,
297 rc.top,
298 rc.right,
299 rc.bottom,
300 rc1.left,
301 rc1.top,
302 rc1.right,
303 rc1.bottom,
304 arctype);
305
306 if (arctype == GdiTypeArcTo)
307 {
308 if (dc->DcLevel.flPath & DCPATH_CLOCKWISE)
309 IntGdiMoveToEx(dc, XStartArc, YStartArc, NULL);
310 else
311 IntGdiMoveToEx(dc, XEndArc, YEndArc, NULL);
312 }
313 return Ret;
314 }
315
316 BOOL
317 FASTCALL
318 IntGdiAngleArc( PDC pDC,
319 INT x,
320 INT y,
321 DWORD dwRadius,
322 FLOAT eStartAngle,
323 FLOAT eSweepAngle)
324 {
325 INT x1, y1, x2, y2, arcdir;
326 BOOL result;
327
328 /* Calculate the end point */
329 x2 = x + (INT)(cos(((eStartAngle+eSweepAngle)/360)*(M_PI*2)) * dwRadius);
330 y2 = y - (INT)(sin(((eStartAngle+eSweepAngle)/360)*(M_PI*2)) * dwRadius);
331
332 x1 = x + (INT)(cos((eStartAngle/360)*(M_PI*2)) * dwRadius);
333 y1 = y - (INT)(sin((eStartAngle/360)*(M_PI*2)) * dwRadius);
334
335 arcdir = pDC->DcLevel.flPath & DCPATH_CLOCKWISE;
336 if (eSweepAngle >= 0)
337 pDC->DcLevel.flPath &= ~DCPATH_CLOCKWISE;
338 else
339 pDC->DcLevel.flPath |= DCPATH_CLOCKWISE;
340
341 result = IntGdiArcInternal( GdiTypeArcTo,
342 pDC,
343 x-dwRadius,
344 y-dwRadius,
345 x+dwRadius,
346 y+dwRadius,
347 x1,
348 y1,
349 x2,
350 y2 );
351
352 pDC->DcLevel.flPath |= (arcdir & DCPATH_CLOCKWISE);
353
354 if (result)
355 {
356 IntGdiMoveToEx(pDC, x2, y2, NULL); // Dont forget Path.
357 }
358 return result;
359 }
360
361 /* FUNCTIONS *****************************************************************/
362
363 BOOL
364 APIENTRY
365 NtGdiAngleArc(
366 IN HDC hDC,
367 IN INT x,
368 IN INT y,
369 IN DWORD dwRadius,
370 IN DWORD dwStartAngle,
371 IN DWORD dwSweepAngle)
372 {
373 DC *pDC;
374 BOOL Ret = FALSE;
375 gxf_long worker, worker1;
376
377 pDC = DC_LockDc (hDC);
378 if(!pDC)
379 {
380 SetLastWin32Error(ERROR_INVALID_HANDLE);
381 return FALSE;
382 }
383 if (pDC->DC_Type == DC_TYPE_INFO)
384 {
385 DC_UnlockDc(pDC);
386 /* Yes, Windows really returns TRUE in this case */
387 return TRUE;
388 }
389 worker.l = dwStartAngle;
390 worker1.l = dwSweepAngle;
391 Ret = IntGdiAngleArc( pDC, x, y, dwRadius, worker.f, worker1.f);
392 DC_UnlockDc( pDC );
393 return Ret;
394 }
395
396 BOOL
397 STDCALL
398 NtGdiArcInternal(
399 ARCTYPE arctype,
400 HDC hDC,
401 int LeftRect,
402 int TopRect,
403 int RightRect,
404 int BottomRect,
405 int XStartArc,
406 int YStartArc,
407 int XEndArc,
408 int YEndArc)
409 {
410 DC *dc;
411 BOOL Ret;
412
413 dc = DC_LockDc (hDC);
414 if(!dc)
415 {
416 SetLastWin32Error(ERROR_INVALID_HANDLE);
417 return FALSE;
418 }
419 if (dc->DC_Type == DC_TYPE_INFO)
420 {
421 DC_UnlockDc(dc);
422 /* Yes, Windows really returns TRUE in this case */
423 return TRUE;
424 }
425
426 Ret = IntGdiArcInternal(
427 arctype,
428 dc,
429 LeftRect,
430 TopRect,
431 RightRect,
432 BottomRect,
433 XStartArc,
434 YStartArc,
435 XEndArc,
436 YEndArc);
437
438 DC_UnlockDc( dc );
439 return Ret;
440 }
441