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