[WIN32K]
[reactos.git] / reactos / subsystems / win32 / win32k / objects / arc.c
1 #include <win32k.h>
2 #define _USE_MATH_DEFINES
3 #include <math.h>
4
5 #define NDEBUG
6 #include <debug.h>
7
8 /*
9 * a couple macros to fill a single pixel or a line
10 */
11 #define PUTPIXEL(x,y,BrushInst) \
12 ret = ret && IntEngLineTo(&psurf->SurfObj, \
13 dc->rosdc.CombinedClip, \
14 &BrushInst.BrushObject, \
15 x, y, (x)+1, y, \
16 &RectBounds, \
17 ROP2_TO_MIX(pdcattr->jROP2));
18
19 #define PUTLINE(x1,y1,x2,y2,BrushInst) \
20 ret = ret && IntEngLineTo(&psurf->SurfObj, \
21 dc->rosdc.CombinedClip, \
22 &BrushInst.BrushObject, \
23 x1, y1, x2, y2, \
24 &RectBounds, \
25 ROP2_TO_MIX(pdcattr->jROP2));
26
27 #define Rsin(d) ((d) == 0.0 ? 0.0 : ((d) == 90.0 ? 1.0 : sin(d*M_PI/180.0)))
28 #define Rcos(d) ((d) == 0.0 ? 1.0 : ((d) == 90.0 ? 0.0 : cos(d*M_PI/180.0)))
29
30 BOOL FASTCALL IntFillArc( PDC dc, INT XLeft, INT YLeft, INT Width, INT Height, double StartArc, double EndArc, ARCTYPE arctype);
31 BOOL FASTCALL IntDrawArc( PDC dc, INT XLeft, INT YLeft, INT Width, INT Height, double StartArc, double EndArc, ARCTYPE arctype, PBRUSH pbrush);
32
33 static
34 BOOL
35 FASTCALL
36 IntArc( DC *dc,
37 int Left,
38 int Top,
39 int Right,
40 int Bottom,
41 int XRadialStart,
42 int YRadialStart,
43 int XRadialEnd,
44 int YRadialEnd,
45 ARCTYPE arctype)
46 {
47 PDC_ATTR pdcattr;
48 RECTL RectBounds, RectSEpts;
49 PBRUSH pbrushPen;
50 SURFACE *psurf;
51 BOOL ret = TRUE;
52 LONG PenWidth, PenOrigWidth;
53 double AngleStart, AngleEnd;
54 LONG RadiusX, RadiusY, CenterX, CenterY;
55 LONG SfCx, SfCy, EfCx, EfCy;
56
57 if (Right < Left)
58 {
59 INT tmp = Right; Right = Left; Left = tmp;
60 }
61 if (Bottom < Top)
62 {
63 INT tmp = Bottom; Bottom = Top; Top = tmp;
64 }
65 if ((Left == Right) ||
66 (Top == Bottom) ||
67 (((arctype != GdiTypeArc) || (arctype != GdiTypeArcTo)) &&
68 ((Right - Left == 1) ||
69 (Bottom - Top == 1))))
70 return TRUE;
71
72 pdcattr = dc->pdcattr;
73
74 pbrushPen = PEN_LockPen(pdcattr->hpen);
75 if (!pbrushPen)
76 {
77 DPRINT1("Arc Fail 1\n");
78 EngSetLastError(ERROR_INTERNAL_ERROR);
79 return FALSE;
80 }
81
82 PenOrigWidth = PenWidth = pbrushPen->ptPenWidth.x;
83 if (pbrushPen->ulPenStyle == PS_NULL) PenWidth = 0;
84
85 if (pbrushPen->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 pbrushPen->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 SfCx = (Rcos(AngleStart) * RadiusX);
135 SfCy = (Rsin(AngleStart) * RadiusY);
136 EfCx = (Rcos(AngleEnd) * RadiusX);
137 EfCy = (Rsin(AngleEnd) * RadiusY);
138
139 if ((arctype == GdiTypePie) || (arctype == GdiTypeChord))
140 {
141 ret = IntFillArc( dc,
142 RectBounds.left,
143 RectBounds.top,
144 abs(RectBounds.right-RectBounds.left), // Width
145 abs(RectBounds.bottom-RectBounds.top), // Height
146 AngleStart,
147 AngleEnd,
148 arctype);
149 }
150
151 ret = IntDrawArc( dc,
152 RectBounds.left,
153 RectBounds.top,
154 abs(RectBounds.right-RectBounds.left), // Width
155 abs(RectBounds.bottom-RectBounds.top), // Height
156 AngleStart,
157 AngleEnd,
158 arctype,
159 pbrushPen);
160
161 psurf = dc->dclevel.pSurface;
162 if (NULL == psurf)
163 {
164 DPRINT1("Arc Fail 2\n");
165 PEN_UnlockPen(pbrushPen);
166 EngSetLastError(ERROR_INTERNAL_ERROR);
167 return FALSE;
168 }
169
170 if (arctype == GdiTypePie)
171 {
172 PUTLINE(CenterX, CenterY, SfCx + CenterX, SfCy + CenterY, dc->eboLine);
173 PUTLINE(EfCx + CenterX, EfCy + CenterY, CenterX, CenterY, dc->eboLine);
174 }
175 if (arctype == GdiTypeChord)
176 PUTLINE(EfCx + CenterX, EfCy + CenterY, SfCx + CenterX, SfCy + CenterY, dc->eboLine);
177
178 pbrushPen->ptPenWidth.x = PenOrigWidth;
179 PEN_UnlockPen(pbrushPen);
180 DPRINT("IntArc Exit.\n");
181 return ret;
182 }
183
184
185 BOOL FASTCALL
186 IntGdiArcInternal(
187 ARCTYPE arctype,
188 DC *dc,
189 int LeftRect,
190 int TopRect,
191 int RightRect,
192 int BottomRect,
193 int XStartArc,
194 int YStartArc,
195 int XEndArc,
196 int YEndArc)
197 {
198 BOOL Ret;
199 PDC_ATTR pdcattr;
200
201 DPRINT("StartX: %d, StartY: %d, EndX: %d, EndY: %d\n",
202 XStartArc,YStartArc,XEndArc,YEndArc);
203 DPRINT("Left: %d, Top: %d, Right: %d, Bottom: %d\n",
204 LeftRect,TopRect,RightRect,BottomRect);
205
206 if ((LeftRect == RightRect) || (TopRect == BottomRect)) return TRUE;
207
208 if (PATH_IsPathOpen(dc->dclevel))
209 {
210 return PATH_Arc( dc,
211 LeftRect,
212 TopRect,
213 RightRect,
214 BottomRect,
215 XStartArc,
216 YStartArc,
217 XEndArc,
218 YEndArc,
219 arctype);
220 }
221
222 pdcattr = dc->pdcattr;
223
224 if (arctype == GdiTypeArcTo)
225 {
226 if (dc->dclevel.flPath & DCPATH_CLOCKWISE)
227 IntGdiLineTo(dc, XEndArc, YEndArc);
228 else
229 IntGdiLineTo(dc, XStartArc, YStartArc);
230 }
231
232 Ret = IntArc( dc,
233 LeftRect,
234 TopRect,
235 RightRect,
236 BottomRect,
237 XStartArc,
238 YStartArc,
239 XEndArc,
240 YEndArc,
241 arctype);
242
243 if (arctype == GdiTypeArcTo)
244 {
245 if (dc->dclevel.flPath & DCPATH_CLOCKWISE)
246 IntGdiMoveToEx(dc, XStartArc, YStartArc, NULL, TRUE);
247 else
248 IntGdiMoveToEx(dc, XEndArc, YEndArc, NULL, TRUE);
249 }
250 return Ret;
251 }
252
253 BOOL
254 FASTCALL
255 IntGdiAngleArc( PDC pDC,
256 INT x,
257 INT y,
258 DWORD dwRadius,
259 FLOAT eStartAngle,
260 FLOAT eSweepAngle)
261 {
262 INT x1, y1, x2, y2, arcdir;
263 BOOL result;
264
265 /* Calculate the end point */
266 x2 = x + (INT)(cos(((eStartAngle+eSweepAngle)/360)*(M_PI*2)) * dwRadius);
267 y2 = y - (INT)(sin(((eStartAngle+eSweepAngle)/360)*(M_PI*2)) * dwRadius);
268
269 x1 = x + (INT)(cos((eStartAngle/360)*(M_PI*2)) * dwRadius);
270 y1 = y - (INT)(sin((eStartAngle/360)*(M_PI*2)) * dwRadius);
271
272 arcdir = pDC->dclevel.flPath & DCPATH_CLOCKWISE;
273 if (eSweepAngle >= 0)
274 pDC->dclevel.flPath &= ~DCPATH_CLOCKWISE;
275 else
276 pDC->dclevel.flPath |= DCPATH_CLOCKWISE;
277
278 result = IntGdiArcInternal( GdiTypeArcTo,
279 pDC,
280 x-dwRadius,
281 y-dwRadius,
282 x+dwRadius,
283 y+dwRadius,
284 x1,
285 y1,
286 x2,
287 y2 );
288
289 pDC->dclevel.flPath |= (arcdir & DCPATH_CLOCKWISE);
290
291 if (result)
292 {
293 IntGdiMoveToEx(pDC, x2, y2, NULL, TRUE);
294 }
295 return result;
296 }
297
298 /* FUNCTIONS *****************************************************************/
299
300 BOOL
301 APIENTRY
302 NtGdiAngleArc(
303 IN HDC hDC,
304 IN INT x,
305 IN INT y,
306 IN DWORD dwRadius,
307 IN DWORD dwStartAngle,
308 IN DWORD dwSweepAngle)
309 {
310 DC *pDC;
311 BOOL Ret = FALSE;
312 gxf_long worker, worker1;
313
314 pDC = DC_LockDc (hDC);
315 if(!pDC)
316 {
317 EngSetLastError(ERROR_INVALID_HANDLE);
318 return FALSE;
319 }
320 if (pDC->dctype == DC_TYPE_INFO)
321 {
322 DC_UnlockDc(pDC);
323 /* Yes, Windows really returns TRUE in this case */
324 return TRUE;
325 }
326 worker.l = dwStartAngle;
327 worker1.l = dwSweepAngle;
328 DC_vPrepareDCsForBlit(pDC, pDC->rosdc.CombinedClip->rclBounds,
329 NULL, pDC->rosdc.CombinedClip->rclBounds);
330 if (pDC->pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
331 DC_vUpdateFillBrush(pDC);
332 if (pDC->pdcattr->ulDirty_ & (DIRTY_LINE | DC_PEN_DIRTY))
333 DC_vUpdateLineBrush(pDC);
334 Ret = IntGdiAngleArc( pDC, x, y, dwRadius, worker.f, worker1.f);
335 DC_vFinishBlit(pDC, NULL);
336 DC_UnlockDc( pDC );
337 return Ret;
338 }
339
340 BOOL
341 APIENTRY
342 NtGdiArcInternal(
343 ARCTYPE arctype,
344 HDC hDC,
345 int LeftRect,
346 int TopRect,
347 int RightRect,
348 int BottomRect,
349 int XStartArc,
350 int YStartArc,
351 int XEndArc,
352 int YEndArc)
353 {
354 DC *dc;
355 BOOL Ret;
356
357 dc = DC_LockDc (hDC);
358 if(!dc)
359 {
360 EngSetLastError(ERROR_INVALID_HANDLE);
361 return FALSE;
362 }
363 if (dc->dctype == DC_TYPE_INFO)
364 {
365 DC_UnlockDc(dc);
366 /* Yes, Windows really returns TRUE in this case */
367 return TRUE;
368 }
369
370 DC_vPrepareDCsForBlit(dc, dc->rosdc.CombinedClip->rclBounds,
371 NULL, dc->rosdc.CombinedClip->rclBounds);
372
373 if (dc->pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
374 DC_vUpdateFillBrush(dc);
375
376 if (dc->pdcattr->ulDirty_ & (DIRTY_LINE | DC_PEN_DIRTY))
377 DC_vUpdateLineBrush(dc);
378
379 Ret = IntGdiArcInternal(
380 arctype,
381 dc,
382 LeftRect,
383 TopRect,
384 RightRect,
385 BottomRect,
386 XStartArc,
387 YStartArc,
388 XEndArc,
389 YEndArc);
390
391 DC_vFinishBlit(dc, NULL);
392 DC_UnlockDc( dc );
393 return Ret;
394 }
395