[WIN32K] Fix drawing the Start and End Segments with Pie(). Brought to you by Barrett...
[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 ret = IntDrawArc( dc,
147 RectBounds.left,
148 RectBounds.top,
149 abs(RectBounds.right-RectBounds.left), // Width
150 abs(RectBounds.bottom-RectBounds.top), // Height
151 AngleStart,
152 AngleEnd,
153 arctype,
154 pbrPen);
155
156 psurf = dc->dclevel.pSurface;
157 if (NULL == psurf)
158 {
159 DPRINT1("Arc Fail 2\n");
160 PEN_ShareUnlockPen(pbrPen);
161 EngSetLastError(ERROR_INTERNAL_ERROR);
162 return FALSE;
163 }
164
165 if (arctype == GdiTypePie)
166 {
167 PUTLINE(CenterX, CenterY, RectSEpts.left, RectSEpts.top, dc->eboLine);
168 PUTLINE(RectSEpts.right, RectSEpts.bottom, CenterX, CenterY, dc->eboLine);
169 }
170 if (arctype == GdiTypeChord)
171 PUTLINE(RectSEpts.right, RectSEpts.bottom, RectSEpts.left, RectSEpts.top, dc->eboLine);
172
173 pbrPen->lWidth = PenOrigWidth;
174 PEN_ShareUnlockPen(pbrPen);
175 DPRINT("IntArc Exit.\n");
176 return ret;
177 }
178
179
180 BOOL FASTCALL
181 IntGdiArcInternal(
182 ARCTYPE arctype,
183 DC *dc,
184 int LeftRect,
185 int TopRect,
186 int RightRect,
187 int BottomRect,
188 int XStartArc,
189 int YStartArc,
190 int XEndArc,
191 int YEndArc)
192 {
193 BOOL Ret;
194 //PDC_ATTR pdcattr;
195
196 DPRINT("StartX: %d, StartY: %d, EndX: %d, EndY: %d\n",
197 XStartArc,YStartArc,XEndArc,YEndArc);
198 DPRINT("Left: %d, Top: %d, Right: %d, Bottom: %d\n",
199 LeftRect,TopRect,RightRect,BottomRect);
200
201 if ((LeftRect == RightRect) || (TopRect == BottomRect)) return TRUE;
202
203 if (PATH_IsPathOpen(dc->dclevel))
204 {
205 return PATH_Arc( dc,
206 LeftRect,
207 TopRect,
208 RightRect,
209 BottomRect,
210 XStartArc,
211 YStartArc,
212 XEndArc,
213 YEndArc,
214 arctype);
215 }
216
217 //pdcattr = dc->pdcattr;
218
219 if (arctype == GdiTypeArcTo)
220 {
221 if (dc->dclevel.flPath & DCPATH_CLOCKWISE)
222 IntGdiLineTo(dc, XEndArc, YEndArc);
223 else
224 IntGdiLineTo(dc, XStartArc, YStartArc);
225 }
226
227 Ret = IntArc( dc,
228 LeftRect,
229 TopRect,
230 RightRect,
231 BottomRect,
232 XStartArc,
233 YStartArc,
234 XEndArc,
235 YEndArc,
236 arctype);
237
238 if (arctype == GdiTypeArcTo)
239 {
240 if (dc->dclevel.flPath & DCPATH_CLOCKWISE)
241 IntGdiMoveToEx(dc, XStartArc, YStartArc, NULL, TRUE);
242 else
243 IntGdiMoveToEx(dc, XEndArc, YEndArc, NULL, TRUE);
244 }
245 return Ret;
246 }
247
248 BOOL
249 FASTCALL
250 IntGdiAngleArc( PDC pDC,
251 INT x,
252 INT y,
253 DWORD dwRadius,
254 FLOAT eStartAngle,
255 FLOAT eSweepAngle)
256 {
257 INT x1, y1, x2, y2, arcdir;
258 BOOL result;
259
260 /* Calculate the end point */
261 x2 = x + (INT)(cos(((eStartAngle+eSweepAngle)/360)*(M_PI*2)) * dwRadius);
262 y2 = y - (INT)(sin(((eStartAngle+eSweepAngle)/360)*(M_PI*2)) * dwRadius);
263
264 x1 = x + (INT)(cos((eStartAngle/360)*(M_PI*2)) * dwRadius);
265 y1 = y - (INT)(sin((eStartAngle/360)*(M_PI*2)) * dwRadius);
266
267 arcdir = pDC->dclevel.flPath & DCPATH_CLOCKWISE;
268 if (eSweepAngle >= 0)
269 pDC->dclevel.flPath &= ~DCPATH_CLOCKWISE;
270 else
271 pDC->dclevel.flPath |= DCPATH_CLOCKWISE;
272
273 result = IntGdiArcInternal( GdiTypeArcTo,
274 pDC,
275 x-dwRadius,
276 y-dwRadius,
277 x+dwRadius,
278 y+dwRadius,
279 x1,
280 y1,
281 x2,
282 y2 );
283
284 pDC->dclevel.flPath |= (arcdir & DCPATH_CLOCKWISE);
285
286 if (result)
287 {
288 IntGdiMoveToEx(pDC, x2, y2, NULL, TRUE);
289 }
290 return result;
291 }
292
293 /* FUNCTIONS *****************************************************************/
294
295 BOOL
296 APIENTRY
297 NtGdiAngleArc(
298 IN HDC hDC,
299 IN INT x,
300 IN INT y,
301 IN DWORD dwRadius,
302 IN DWORD dwStartAngle,
303 IN DWORD dwSweepAngle)
304 {
305 DC *pDC;
306 BOOL Ret = FALSE;
307 gxf_long worker, worker1;
308 KFLOATING_SAVE FloatSave;
309 NTSTATUS status;
310
311 pDC = DC_LockDc (hDC);
312 if(!pDC)
313 {
314 EngSetLastError(ERROR_INVALID_HANDLE);
315 return FALSE;
316 }
317 if (pDC->dctype == DC_TYPE_INFO)
318 {
319 DC_UnlockDc(pDC);
320 /* Yes, Windows really returns TRUE in this case */
321 return TRUE;
322 }
323
324 status = KeSaveFloatingPointState(&FloatSave);
325 if (!NT_SUCCESS(status))
326 {
327 DC_UnlockDc( pDC );
328 return FALSE;
329 }
330
331 worker.l = dwStartAngle;
332 worker1.l = dwSweepAngle;
333 DC_vPrepareDCsForBlit(pDC, NULL, NULL, NULL);
334 if (pDC->pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
335 DC_vUpdateFillBrush(pDC);
336 if (pDC->pdcattr->ulDirty_ & (DIRTY_LINE | DC_PEN_DIRTY))
337 DC_vUpdateLineBrush(pDC);
338 Ret = IntGdiAngleArc( pDC, x, y, dwRadius, worker.f, worker1.f);
339 DC_vFinishBlit(pDC, NULL);
340 DC_UnlockDc( pDC );
341
342 KeRestoreFloatingPointState(&FloatSave);
343
344 return Ret;
345 }
346
347 BOOL
348 APIENTRY
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 KFLOATING_SAVE FloatSave;
364 NTSTATUS status;
365
366 dc = DC_LockDc (hDC);
367 if(!dc)
368 {
369 EngSetLastError(ERROR_INVALID_HANDLE);
370 return FALSE;
371 }
372 if (dc->dctype == DC_TYPE_INFO)
373 {
374 DC_UnlockDc(dc);
375 /* Yes, Windows really returns TRUE in this case */
376 return TRUE;
377 }
378
379 DC_vPrepareDCsForBlit(dc, NULL, NULL, NULL);
380
381 if (dc->pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
382 DC_vUpdateFillBrush(dc);
383
384 if (dc->pdcattr->ulDirty_ & (DIRTY_LINE | DC_PEN_DIRTY))
385 DC_vUpdateLineBrush(dc);
386
387 status = KeSaveFloatingPointState(&FloatSave);
388 if (!NT_SUCCESS(status))
389 {
390 DC_UnlockDc( dc );
391 return FALSE;
392 }
393
394 Ret = IntGdiArcInternal(
395 arctype,
396 dc,
397 LeftRect,
398 TopRect,
399 RightRect,
400 BottomRect,
401 XStartArc,
402 YStartArc,
403 XEndArc,
404 YEndArc);
405
406 KeRestoreFloatingPointState(&FloatSave);
407 DC_vFinishBlit(dc, NULL);
408 DC_UnlockDc( dc );
409 return Ret;
410 }
411