[CMAKE]
[reactos.git] / subsystems / win32 / win32k / objects / arc.c
1 #include <win32k.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 EngSetLastError(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 EngSetLastError(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 (arctype == GdiTypeArcTo)
223 {
224 if (dc->dclevel.flPath & DCPATH_CLOCKWISE)
225 IntGdiLineTo(dc, XEndArc, YEndArc);
226 else
227 IntGdiLineTo(dc, XStartArc, YStartArc);
228 }
229
230 Ret = IntArc( dc,
231 LeftRect,
232 TopRect,
233 RightRect,
234 BottomRect,
235 XStartArc,
236 YStartArc,
237 XEndArc,
238 YEndArc,
239 arctype);
240
241 if (arctype == GdiTypeArcTo)
242 {
243 if (dc->dclevel.flPath & DCPATH_CLOCKWISE)
244 IntGdiMoveToEx(dc, XStartArc, YStartArc, NULL, TRUE);
245 else
246 IntGdiMoveToEx(dc, XEndArc, YEndArc, NULL, TRUE);
247 }
248 return Ret;
249 }
250
251 BOOL
252 FASTCALL
253 IntGdiAngleArc( PDC pDC,
254 INT x,
255 INT y,
256 DWORD dwRadius,
257 FLOAT eStartAngle,
258 FLOAT eSweepAngle)
259 {
260 INT x1, y1, x2, y2, arcdir;
261 BOOL result;
262
263 /* Calculate the end point */
264 x2 = x + (INT)(cos(((eStartAngle+eSweepAngle)/360)*(M_PI*2)) * dwRadius);
265 y2 = y - (INT)(sin(((eStartAngle+eSweepAngle)/360)*(M_PI*2)) * dwRadius);
266
267 x1 = x + (INT)(cos((eStartAngle/360)*(M_PI*2)) * dwRadius);
268 y1 = y - (INT)(sin((eStartAngle/360)*(M_PI*2)) * dwRadius);
269
270 arcdir = pDC->dclevel.flPath & DCPATH_CLOCKWISE;
271 if (eSweepAngle >= 0)
272 pDC->dclevel.flPath &= ~DCPATH_CLOCKWISE;
273 else
274 pDC->dclevel.flPath |= DCPATH_CLOCKWISE;
275
276 result = IntGdiArcInternal( GdiTypeArcTo,
277 pDC,
278 x-dwRadius,
279 y-dwRadius,
280 x+dwRadius,
281 y+dwRadius,
282 x1,
283 y1,
284 x2,
285 y2 );
286
287 pDC->dclevel.flPath |= (arcdir & DCPATH_CLOCKWISE);
288
289 if (result)
290 {
291 IntGdiMoveToEx(pDC, x2, y2, NULL, TRUE);
292 }
293 return result;
294 }
295
296 /* FUNCTIONS *****************************************************************/
297
298 BOOL
299 APIENTRY
300 NtGdiAngleArc(
301 IN HDC hDC,
302 IN INT x,
303 IN INT y,
304 IN DWORD dwRadius,
305 IN DWORD dwStartAngle,
306 IN DWORD dwSweepAngle)
307 {
308 DC *pDC;
309 BOOL Ret = FALSE;
310 gxf_long worker, worker1;
311
312 pDC = DC_LockDc (hDC);
313 if(!pDC)
314 {
315 EngSetLastError(ERROR_INVALID_HANDLE);
316 return FALSE;
317 }
318 if (pDC->dctype == DC_TYPE_INFO)
319 {
320 DC_UnlockDc(pDC);
321 /* Yes, Windows really returns TRUE in this case */
322 return TRUE;
323 }
324 worker.l = dwStartAngle;
325 worker1.l = dwSweepAngle;
326 DC_vPrepareDCsForBlit(pDC, pDC->rosdc.CombinedClip->rclBounds,
327 NULL, pDC->rosdc.CombinedClip->rclBounds);
328 if (pDC->pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
329 DC_vUpdateFillBrush(pDC);
330 if (pDC->pdcattr->ulDirty_ & (DIRTY_LINE | DC_PEN_DIRTY))
331 DC_vUpdateLineBrush(pDC);
332 Ret = IntGdiAngleArc( pDC, x, y, dwRadius, worker.f, worker1.f);
333 DC_vFinishBlit(pDC, NULL);
334 DC_UnlockDc( pDC );
335 return Ret;
336 }
337
338 BOOL
339 APIENTRY
340 NtGdiArcInternal(
341 ARCTYPE arctype,
342 HDC hDC,
343 int LeftRect,
344 int TopRect,
345 int RightRect,
346 int BottomRect,
347 int XStartArc,
348 int YStartArc,
349 int XEndArc,
350 int YEndArc)
351 {
352 DC *dc;
353 BOOL Ret;
354
355 dc = DC_LockDc (hDC);
356 if(!dc)
357 {
358 EngSetLastError(ERROR_INVALID_HANDLE);
359 return FALSE;
360 }
361 if (dc->dctype == DC_TYPE_INFO)
362 {
363 DC_UnlockDc(dc);
364 /* Yes, Windows really returns TRUE in this case */
365 return TRUE;
366 }
367
368 DC_vPrepareDCsForBlit(dc, dc->rosdc.CombinedClip->rclBounds,
369 NULL, dc->rosdc.CombinedClip->rclBounds);
370
371 if (dc->pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
372 DC_vUpdateFillBrush(dc);
373
374 if (dc->pdcattr->ulDirty_ & (DIRTY_LINE | DC_PEN_DIRTY))
375 DC_vUpdateLineBrush(dc);
376
377 Ret = IntGdiArcInternal(
378 arctype,
379 dc,
380 LeftRect,
381 TopRect,
382 RightRect,
383 BottomRect,
384 XStartArc,
385 YStartArc,
386 XEndArc,
387 YEndArc);
388
389 DC_vFinishBlit(dc, NULL);
390 DC_UnlockDc( dc );
391 return Ret;
392 }
393