Merge from amd64 branch:
[reactos.git] / reactos / 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);
251 else
252 IntGdiMoveToEx(dc, XEndArc, YEndArc, NULL);
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); // Dont forget Path.
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 Ret = IntGdiAngleArc( pDC, x, y, dwRadius, worker.f, worker1.f);
333 DC_UnlockDc( pDC );
334 return Ret;
335 }
336
337 BOOL
338 APIENTRY
339 NtGdiArcInternal(
340 ARCTYPE arctype,
341 HDC hDC,
342 int LeftRect,
343 int TopRect,
344 int RightRect,
345 int BottomRect,
346 int XStartArc,
347 int YStartArc,
348 int XEndArc,
349 int YEndArc)
350 {
351 DC *dc;
352 BOOL Ret;
353
354 dc = DC_LockDc (hDC);
355 if(!dc)
356 {
357 SetLastWin32Error(ERROR_INVALID_HANDLE);
358 return FALSE;
359 }
360 if (dc->dctype == DC_TYPE_INFO)
361 {
362 DC_UnlockDc(dc);
363 /* Yes, Windows really returns TRUE in this case */
364 return TRUE;
365 }
366
367 Ret = IntGdiArcInternal(
368 arctype,
369 dc,
370 LeftRect,
371 TopRect,
372 RightRect,
373 BottomRect,
374 XStartArc,
375 YStartArc,
376 XEndArc,
377 YEndArc);
378
379 DC_UnlockDc( dc );
380 return Ret;
381 }
382