[WIN32K]
[reactos.git] / subsystems / win32 / win32k / objects / arc.c
1 #include <w32k.h>
2
3 #define NDEBUG
4 #include <debug.h>
5
6 /*
7 * a couple 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 BOOL FASTCALL IntFillArc( PDC dc, INT XLeft, INT YLeft, INT Width, INT Height, double StartArc, double EndArc, ARCTYPE arctype);
29 BOOL FASTCALL IntDrawArc( PDC dc, INT XLeft, INT YLeft, INT Width, INT Height, double StartArc, double EndArc, ARCTYPE arctype, PBRUSH pbrush);
30
31 static
32 BOOL
33 FASTCALL
34 IntArc( DC *dc,
35 int Left,
36 int Top,
37 int Right,
38 int Bottom,
39 int XRadialStart,
40 int YRadialStart,
41 int XRadialEnd,
42 int YRadialEnd,
43 ARCTYPE arctype)
44 {
45 PDC_ATTR pdcattr;
46 RECTL RectBounds, RectSEpts;
47 PBRUSH pbrushPen;
48 SURFACE *psurf;
49 BOOL ret = TRUE;
50 LONG PenWidth, PenOrigWidth;
51 double AngleStart, AngleEnd;
52 LONG RadiusX, RadiusY, CenterX, CenterY;
53 LONG SfCx, SfCy, EfCx, EfCy;
54
55 if (Right < Left)
56 {
57 INT tmp = Right; Right = Left; Left = tmp;
58 }
59 if (Bottom < Top)
60 {
61 INT tmp = Bottom; Bottom = Top; Top = tmp;
62 }
63 if ((Left == Right) ||
64 (Top == Bottom) ||
65 (((arctype != GdiTypeArc) || (arctype != GdiTypeArcTo)) &&
66 ((Right - Left == 1) ||
67 (Bottom - Top == 1))))
68 return TRUE;
69
70 pdcattr = dc->pdcattr;
71
72 pbrushPen = PEN_LockPen(pdcattr->hpen);
73 if (!pbrushPen)
74 {
75 DPRINT1("Arc Fail 1\n");
76 SetLastWin32Error(ERROR_INTERNAL_ERROR);
77 return FALSE;
78 }
79
80 PenOrigWidth = PenWidth = pbrushPen->ptPenWidth.x;
81 if (pbrushPen->ulPenStyle == PS_NULL) PenWidth = 0;
82
83 if (pbrushPen->ulPenStyle == PS_INSIDEFRAME)
84 {
85 if (2*PenWidth > (Right - Left)) PenWidth = (Right -Left + 1)/2;
86 if (2*PenWidth > (Bottom - Top)) PenWidth = (Bottom -Top + 1)/2;
87 Left += PenWidth / 2;
88 Right -= (PenWidth - 1) / 2;
89 Top += PenWidth / 2;
90 Bottom -= (PenWidth - 1) / 2;
91 }
92
93 if (!PenWidth) PenWidth = 1;
94 pbrushPen->ptPenWidth.x = PenWidth;
95
96 RectBounds.left = Left;
97 RectBounds.right = Right;
98 RectBounds.top = Top;
99 RectBounds.bottom = Bottom;
100
101 RectSEpts.left = XRadialStart;
102 RectSEpts.top = YRadialStart;
103 RectSEpts.right = XRadialEnd;
104 RectSEpts.bottom = YRadialEnd;
105
106 IntLPtoDP(dc, (LPPOINT)&RectBounds, 2);
107 IntLPtoDP(dc, (LPPOINT)&RectSEpts, 2);
108
109 RectBounds.left += dc->ptlDCOrig.x;
110 RectBounds.right += dc->ptlDCOrig.x;
111 RectBounds.top += dc->ptlDCOrig.y;
112 RectBounds.bottom += dc->ptlDCOrig.y;
113
114 RectSEpts.left += dc->ptlDCOrig.x;
115 RectSEpts.top += dc->ptlDCOrig.y;
116 RectSEpts.right += dc->ptlDCOrig.x;
117 RectSEpts.bottom += dc->ptlDCOrig.y;
118
119 DPRINT("1: StartX: %d, StartY: %d, EndX: %d, EndY: %d\n",
120 RectSEpts.left,RectSEpts.top,RectSEpts.right,RectSEpts.bottom);
121
122 DPRINT("1: Left: %d, Top: %d, Right: %d, Bottom: %d\n",
123 RectBounds.left,RectBounds.top,RectBounds.right,RectBounds.bottom);
124
125 RadiusX = max((RectBounds.right - RectBounds.left) / 2, 1);
126 RadiusY = max((RectBounds.bottom - RectBounds.top) / 2, 1);
127 CenterX = (RectBounds.right + RectBounds.left) / 2;
128 CenterY = (RectBounds.bottom + RectBounds.top) / 2;
129 AngleEnd = atan2((RectSEpts.bottom - CenterY), RectSEpts.right - CenterX)*(360.0/(M_PI*2));
130 AngleStart = atan2((RectSEpts.top - CenterY), RectSEpts.left - CenterX)*(360.0/(M_PI*2));
131
132 SfCx = (Rcos(AngleStart) * RadiusX);
133 SfCy = (Rsin(AngleStart) * RadiusY);
134 EfCx = (Rcos(AngleEnd) * RadiusX);
135 EfCy = (Rsin(AngleEnd) * RadiusY);
136
137 if ((arctype == GdiTypePie) || (arctype == GdiTypeChord))
138 {
139 ret = IntFillArc( dc,
140 RectBounds.left,
141 RectBounds.top,
142 abs(RectBounds.right-RectBounds.left), // Width
143 abs(RectBounds.bottom-RectBounds.top), // Height
144 AngleStart,
145 AngleEnd,
146 arctype);
147 }
148
149 ret = IntDrawArc( dc,
150 RectBounds.left,
151 RectBounds.top,
152 abs(RectBounds.right-RectBounds.left), // Width
153 abs(RectBounds.bottom-RectBounds.top), // Height
154 AngleStart,
155 AngleEnd,
156 arctype,
157 pbrushPen);
158
159 psurf = dc->dclevel.pSurface;
160 if (NULL == psurf)
161 {
162 DPRINT1("Arc Fail 2\n");
163 PEN_UnlockPen(pbrushPen);
164 SetLastWin32Error(ERROR_INTERNAL_ERROR);
165 return FALSE;
166 }
167
168 if (arctype == GdiTypePie)
169 {
170 PUTLINE(CenterX, CenterY, SfCx + CenterX, SfCy + CenterY, dc->eboLine);
171 PUTLINE(EfCx + CenterX, EfCy + CenterY, CenterX, CenterY, dc->eboLine);
172 }
173 if (arctype == GdiTypeChord)
174 PUTLINE(EfCx + CenterX, EfCy + CenterY, SfCx + CenterX, SfCy + CenterY, dc->eboLine);
175
176 pbrushPen->ptPenWidth.x = PenOrigWidth;
177 PEN_UnlockPen(pbrushPen);
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 arctype);
218 }
219
220 pdcattr = dc->pdcattr;
221
222 if (pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
223 DC_vUpdateFillBrush(dc);
224
225 if (pdcattr->ulDirty_ & (DIRTY_LINE | DC_PEN_DIRTY))
226 DC_vUpdateLineBrush(dc);
227
228 if (arctype == GdiTypeArcTo)
229 {
230 if (dc->dclevel.flPath & DCPATH_CLOCKWISE)
231 IntGdiLineTo(dc, XEndArc, YEndArc);
232 else
233 IntGdiLineTo(dc, XStartArc, YStartArc);
234 }
235
236 Ret = IntArc( dc,
237 LeftRect,
238 TopRect,
239 RightRect,
240 BottomRect,
241 XStartArc,
242 YStartArc,
243 XEndArc,
244 YEndArc,
245 arctype);
246
247 if (arctype == GdiTypeArcTo)
248 {
249 if (dc->dclevel.flPath & DCPATH_CLOCKWISE)
250 IntGdiMoveToEx(dc, XStartArc, YStartArc, NULL, TRUE);
251 else
252 IntGdiMoveToEx(dc, XEndArc, YEndArc, NULL, TRUE);
253 }
254 return Ret;
255 }
256
257 BOOL
258 FASTCALL
259 IntGdiAngleArc( PDC pDC,
260 INT x,
261 INT y,
262 DWORD dwRadius,
263 FLOAT eStartAngle,
264 FLOAT eSweepAngle)
265 {
266 INT x1, y1, x2, y2, arcdir;
267 BOOL result;
268
269 /* Calculate the end point */
270 x2 = x + (INT)(cos(((eStartAngle+eSweepAngle)/360)*(M_PI*2)) * dwRadius);
271 y2 = y - (INT)(sin(((eStartAngle+eSweepAngle)/360)*(M_PI*2)) * dwRadius);
272
273 x1 = x + (INT)(cos((eStartAngle/360)*(M_PI*2)) * dwRadius);
274 y1 = y - (INT)(sin((eStartAngle/360)*(M_PI*2)) * dwRadius);
275
276 arcdir = pDC->dclevel.flPath & DCPATH_CLOCKWISE;
277 if (eSweepAngle >= 0)
278 pDC->dclevel.flPath &= ~DCPATH_CLOCKWISE;
279 else
280 pDC->dclevel.flPath |= DCPATH_CLOCKWISE;
281
282 result = IntGdiArcInternal( GdiTypeArcTo,
283 pDC,
284 x-dwRadius,
285 y-dwRadius,
286 x+dwRadius,
287 y+dwRadius,
288 x1,
289 y1,
290 x2,
291 y2 );
292
293 pDC->dclevel.flPath |= (arcdir & DCPATH_CLOCKWISE);
294
295 if (result)
296 {
297 IntGdiMoveToEx(pDC, x2, y2, NULL, TRUE);
298 }
299 return result;
300 }
301
302 /* FUNCTIONS *****************************************************************/
303
304 BOOL
305 APIENTRY
306 NtGdiAngleArc(
307 IN HDC hDC,
308 IN INT x,
309 IN INT y,
310 IN DWORD dwRadius,
311 IN DWORD dwStartAngle,
312 IN DWORD dwSweepAngle)
313 {
314 DC *pDC;
315 BOOL Ret = FALSE;
316 gxf_long worker, worker1;
317
318 pDC = DC_LockDc (hDC);
319 if(!pDC)
320 {
321 SetLastWin32Error(ERROR_INVALID_HANDLE);
322 return FALSE;
323 }
324 if (pDC->dctype == DC_TYPE_INFO)
325 {
326 DC_UnlockDc(pDC);
327 /* Yes, Windows really returns TRUE in this case */
328 return TRUE;
329 }
330 worker.l = dwStartAngle;
331 worker1.l = dwSweepAngle;
332 DC_vPrepareDCsForBlit(pDC, pDC->rosdc.CombinedClip->rclBounds,
333 NULL, pDC->rosdc.CombinedClip->rclBounds);
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 SetLastWin32Error(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 Ret = IntGdiArcInternal(
374 arctype,
375 dc,
376 LeftRect,
377 TopRect,
378 RightRect,
379 BottomRect,
380 XStartArc,
381 YStartArc,
382 XEndArc,
383 YEndArc);
384
385 DC_vFinishBlit(dc, NULL);
386 DC_UnlockDc( dc );
387 return Ret;
388 }
389