[WIN32SS]
[reactos.git] / reactos / subsystems / win32 / win32k / objects / 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->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 static
29 BOOL
30 FASTCALL
31 IntArc( DC *dc,
32 int Left,
33 int Top,
34 int Right,
35 int Bottom,
36 int XRadialStart,
37 int YRadialStart,
38 int XRadialEnd,
39 int YRadialEnd,
40 ARCTYPE arctype)
41 {
42 PDC_ATTR pdcattr;
43 RECTL RectBounds, RectSEpts;
44 PBRUSH pbrPen;
45 SURFACE *psurf;
46 BOOL ret = TRUE;
47 LONG PenWidth, PenOrigWidth;
48 double AngleStart, AngleEnd;
49 LONG RadiusX, RadiusY, CenterX, CenterY;
50 LONG SfCx, SfCy, EfCx, EfCy;
51
52 if (Right < Left)
53 {
54 INT tmp = Right; Right = Left; Left = tmp;
55 }
56 if (Bottom < Top)
57 {
58 INT tmp = Bottom; Bottom = Top; Top = tmp;
59 }
60 if ((Left == Right) ||
61 (Top == Bottom) ||
62 (((arctype != GdiTypeArc) || (arctype != GdiTypeArcTo)) &&
63 ((Right - Left == 1) ||
64 (Bottom - Top == 1))))
65 return TRUE;
66
67 pdcattr = dc->pdcattr;
68
69 pbrPen = PEN_ShareLockPen(pdcattr->hpen);
70 if (!pbrPen)
71 {
72 DPRINT1("Arc Fail 1\n");
73 EngSetLastError(ERROR_INTERNAL_ERROR);
74 return FALSE;
75 }
76
77 PenOrigWidth = PenWidth = pbrPen->ptPenWidth.x;
78 if (pbrPen->ulPenStyle == PS_NULL) PenWidth = 0;
79
80 if (pbrPen->ulPenStyle == PS_INSIDEFRAME)
81 {
82 if (2*PenWidth > (Right - Left)) PenWidth = (Right -Left + 1)/2;
83 if (2*PenWidth > (Bottom - Top)) PenWidth = (Bottom -Top + 1)/2;
84 Left += PenWidth / 2;
85 Right -= (PenWidth - 1) / 2;
86 Top += PenWidth / 2;
87 Bottom -= (PenWidth - 1) / 2;
88 }
89
90 if (!PenWidth) PenWidth = 1;
91 pbrPen->ptPenWidth.x = PenWidth;
92
93 RectBounds.left = Left;
94 RectBounds.right = Right;
95 RectBounds.top = Top;
96 RectBounds.bottom = Bottom;
97
98 RectSEpts.left = XRadialStart;
99 RectSEpts.top = YRadialStart;
100 RectSEpts.right = XRadialEnd;
101 RectSEpts.bottom = YRadialEnd;
102
103 IntLPtoDP(dc, (LPPOINT)&RectBounds, 2);
104 IntLPtoDP(dc, (LPPOINT)&RectSEpts, 2);
105
106 RectBounds.left += dc->ptlDCOrig.x;
107 RectBounds.right += dc->ptlDCOrig.x;
108 RectBounds.top += dc->ptlDCOrig.y;
109 RectBounds.bottom += dc->ptlDCOrig.y;
110
111 RectSEpts.left += dc->ptlDCOrig.x;
112 RectSEpts.top += dc->ptlDCOrig.y;
113 RectSEpts.right += dc->ptlDCOrig.x;
114 RectSEpts.bottom += dc->ptlDCOrig.y;
115
116 DPRINT("1: StartX: %d, StartY: %d, EndX: %d, EndY: %d\n",
117 RectSEpts.left,RectSEpts.top,RectSEpts.right,RectSEpts.bottom);
118
119 DPRINT("1: Left: %d, Top: %d, Right: %d, Bottom: %d\n",
120 RectBounds.left,RectBounds.top,RectBounds.right,RectBounds.bottom);
121
122 RadiusX = max((RectBounds.right - RectBounds.left) / 2, 1);
123 RadiusY = max((RectBounds.bottom - RectBounds.top) / 2, 1);
124 CenterX = (RectBounds.right + RectBounds.left) / 2;
125 CenterY = (RectBounds.bottom + RectBounds.top) / 2;
126 AngleEnd = atan2((RectSEpts.bottom - CenterY), RectSEpts.right - CenterX)*(360.0/(M_PI*2));
127 AngleStart = atan2((RectSEpts.top - CenterY), RectSEpts.left - CenterX)*(360.0/(M_PI*2));
128
129 SfCx = (LONG)(Rcos(AngleStart) * RadiusX);
130 SfCy = (LONG)(Rsin(AngleStart) * RadiusY);
131 EfCx = (LONG)(Rcos(AngleEnd) * RadiusX);
132 EfCy = (LONG)(Rsin(AngleEnd) * RadiusY);
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, SfCx + CenterX, SfCy + CenterY, dc->eboLine);
168 PUTLINE(EfCx + CenterX, EfCy + CenterY, CenterX, CenterY, dc->eboLine);
169 }
170 if (arctype == GdiTypeChord)
171 PUTLINE(EfCx + CenterX, EfCy + CenterY, SfCx + CenterX, SfCy + CenterY, dc->eboLine);
172
173 pbrPen->ptPenWidth.x = 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
309 pDC = DC_LockDc (hDC);
310 if(!pDC)
311 {
312 EngSetLastError(ERROR_INVALID_HANDLE);
313 return FALSE;
314 }
315 if (pDC->dctype == DC_TYPE_INFO)
316 {
317 DC_UnlockDc(pDC);
318 /* Yes, Windows really returns TRUE in this case */
319 return TRUE;
320 }
321 worker.l = dwStartAngle;
322 worker1.l = dwSweepAngle;
323 DC_vPrepareDCsForBlit(pDC, pDC->rosdc.CombinedClip->rclBounds,
324 NULL, pDC->rosdc.CombinedClip->rclBounds);
325 if (pDC->pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
326 DC_vUpdateFillBrush(pDC);
327 if (pDC->pdcattr->ulDirty_ & (DIRTY_LINE | DC_PEN_DIRTY))
328 DC_vUpdateLineBrush(pDC);
329 Ret = IntGdiAngleArc( pDC, x, y, dwRadius, worker.f, worker1.f);
330 DC_vFinishBlit(pDC, NULL);
331 DC_UnlockDc( pDC );
332 return Ret;
333 }
334
335 BOOL
336 APIENTRY
337 NtGdiArcInternal(
338 ARCTYPE arctype,
339 HDC hDC,
340 int LeftRect,
341 int TopRect,
342 int RightRect,
343 int BottomRect,
344 int XStartArc,
345 int YStartArc,
346 int XEndArc,
347 int YEndArc)
348 {
349 DC *dc;
350 BOOL Ret;
351
352 dc = DC_LockDc (hDC);
353 if(!dc)
354 {
355 EngSetLastError(ERROR_INVALID_HANDLE);
356 return FALSE;
357 }
358 if (dc->dctype == DC_TYPE_INFO)
359 {
360 DC_UnlockDc(dc);
361 /* Yes, Windows really returns TRUE in this case */
362 return TRUE;
363 }
364
365 DC_vPrepareDCsForBlit(dc, dc->rosdc.CombinedClip->rclBounds,
366 NULL, dc->rosdc.CombinedClip->rclBounds);
367
368 if (dc->pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
369 DC_vUpdateFillBrush(dc);
370
371 if (dc->pdcattr->ulDirty_ & (DIRTY_LINE | DC_PEN_DIRTY))
372 DC_vUpdateLineBrush(dc);
373
374 Ret = IntGdiArcInternal(
375 arctype,
376 dc,
377 LeftRect,
378 TopRect,
379 RightRect,
380 BottomRect,
381 XStartArc,
382 YStartArc,
383 XEndArc,
384 YEndArc);
385
386 DC_vFinishBlit(dc, NULL);
387 DC_UnlockDc( dc );
388 return Ret;
389 }
390