0b6f421fbf85b998fc4155e5effabbcd5d267cb4
[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->rosdc.CombinedClip, \
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->rosdc.CombinedClip, \
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->ptPenWidth.x;
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->ptPenWidth.x = 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->ptPenWidth.x = 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
321 pDC = DC_LockDc (hDC);
322 if(!pDC)
323 {
324 EngSetLastError(ERROR_INVALID_HANDLE);
325 return FALSE;
326 }
327 if (pDC->dctype == DC_TYPE_INFO)
328 {
329 DC_UnlockDc(pDC);
330 /* Yes, Windows really returns TRUE in this case */
331 return TRUE;
332 }
333
334 KeSaveFloatingPointState(&FloatSave);
335
336 worker.l = dwStartAngle;
337 worker1.l = dwSweepAngle;
338 DC_vPrepareDCsForBlit(pDC, pDC->rosdc.CombinedClip->rclBounds,
339 NULL, pDC->rosdc.CombinedClip->rclBounds);
340 if (pDC->pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
341 DC_vUpdateFillBrush(pDC);
342 if (pDC->pdcattr->ulDirty_ & (DIRTY_LINE | DC_PEN_DIRTY))
343 DC_vUpdateLineBrush(pDC);
344 Ret = IntGdiAngleArc( pDC, x, y, dwRadius, worker.f, worker1.f);
345 DC_vFinishBlit(pDC, NULL);
346 DC_UnlockDc( pDC );
347
348 KeRestoreFloatingPointState(&FloatSave);
349
350 return Ret;
351 }
352
353 BOOL
354 APIENTRY
355 NtGdiArcInternal(
356 ARCTYPE arctype,
357 HDC hDC,
358 int LeftRect,
359 int TopRect,
360 int RightRect,
361 int BottomRect,
362 int XStartArc,
363 int YStartArc,
364 int XEndArc,
365 int YEndArc)
366 {
367 DC *dc;
368 BOOL Ret;
369 KFLOATING_SAVE FloatSave;
370
371 dc = DC_LockDc (hDC);
372 if(!dc)
373 {
374 EngSetLastError(ERROR_INVALID_HANDLE);
375 return FALSE;
376 }
377 if (dc->dctype == DC_TYPE_INFO)
378 {
379 DC_UnlockDc(dc);
380 /* Yes, Windows really returns TRUE in this case */
381 return TRUE;
382 }
383
384 DC_vPrepareDCsForBlit(dc, dc->rosdc.CombinedClip->rclBounds,
385 NULL, dc->rosdc.CombinedClip->rclBounds);
386
387 if (dc->pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
388 DC_vUpdateFillBrush(dc);
389
390 if (dc->pdcattr->ulDirty_ & (DIRTY_LINE | DC_PEN_DIRTY))
391 DC_vUpdateLineBrush(dc);
392
393 KeSaveFloatingPointState(&FloatSave);
394
395 Ret = IntGdiArcInternal(
396 arctype,
397 dc,
398 LeftRect,
399 TopRect,
400 RightRect,
401 BottomRect,
402 XStartArc,
403 YStartArc,
404 XEndArc,
405 YEndArc);
406
407 KeRestoreFloatingPointState(&FloatSave);
408 DC_vFinishBlit(dc, NULL);
409 DC_UnlockDc( dc );
410 return Ret;
411 }
412