0170263a6f89cbdcea829cae8f4f7eedf4718107
[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 static
26 BOOL
27 FASTCALL
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
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
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
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
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