Partial merge of condrv_restructure branch r65657.
[reactos.git] / reactos / win32ss / gdi / ntgdi / 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->co.ClipObj, \
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->co.ClipObj, \
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
61 /* Check if the target rect is empty */
62 if ((Left == Right) || (Top == Bottom)) return TRUE;
63
64 // FIXME: this needs to be verified
65 if ((arctype == GdiTypeChord ) || (arctype == GdiTypePie))
66 {
67 if ((Right - Left == 1) || (Bottom - Top == 1))
68 return TRUE;
69 }
70
71
72 pdcattr = dc->pdcattr;
73
74 pbrPen = PEN_ShareLockPen(pdcattr->hpen);
75 if (!pbrPen)
76 {
77 DPRINT1("Arc Fail 1\n");
78 EngSetLastError(ERROR_INTERNAL_ERROR);
79 return FALSE;
80 }
81
82 PenOrigWidth = PenWidth = pbrPen->ptPenWidth.x;
83 if (pbrPen->ulPenStyle == PS_NULL) PenWidth = 0;
84
85 if (pbrPen->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 pbrPen->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 /* Edge Case: Check if the start segments overlaps(is equal) the end segment */
135 if (AngleEnd == AngleStart)
136 {
137 AngleStart = AngleEnd + 360.0; // Arc(), ArcTo(), Pie() and Chord() are counterclockwise APIs.
138 }
139
140 SfCx = (LONG)(Rcos(AngleStart) * RadiusX);
141 SfCy = (LONG)(Rsin(AngleStart) * RadiusY);
142 EfCx = (LONG)(Rcos(AngleEnd) * RadiusX);
143 EfCy = (LONG)(Rsin(AngleEnd) * RadiusY);
144
145 if ((arctype == GdiTypePie) || (arctype == GdiTypeChord))
146 {
147 ret = IntFillArc( dc,
148 RectBounds.left,
149 RectBounds.top,
150 abs(RectBounds.right-RectBounds.left), // Width
151 abs(RectBounds.bottom-RectBounds.top), // Height
152 AngleStart,
153 AngleEnd,
154 arctype);
155 }
156
157 ret = IntDrawArc( dc,
158 RectBounds.left,
159 RectBounds.top,
160 abs(RectBounds.right-RectBounds.left), // Width
161 abs(RectBounds.bottom-RectBounds.top), // Height
162 AngleStart,
163 AngleEnd,
164 arctype,
165 pbrPen);
166
167 psurf = dc->dclevel.pSurface;
168 if (NULL == psurf)
169 {
170 DPRINT1("Arc Fail 2\n");
171 PEN_ShareUnlockPen(pbrPen);
172 EngSetLastError(ERROR_INTERNAL_ERROR);
173 return FALSE;
174 }
175
176 if (arctype == GdiTypePie)
177 {
178 PUTLINE(CenterX, CenterY, SfCx + CenterX, SfCy + CenterY, dc->eboLine);
179 PUTLINE(EfCx + CenterX, EfCy + CenterY, CenterX, CenterY, dc->eboLine);
180 }
181 if (arctype == GdiTypeChord)
182 PUTLINE(EfCx + CenterX, EfCy + CenterY, SfCx + CenterX, SfCy + CenterY, dc->eboLine);
183
184 pbrPen->ptPenWidth.x = PenOrigWidth;
185 PEN_ShareUnlockPen(pbrPen);
186 DPRINT("IntArc Exit.\n");
187 return ret;
188 }
189
190
191 BOOL FASTCALL
192 IntGdiArcInternal(
193 ARCTYPE arctype,
194 DC *dc,
195 int LeftRect,
196 int TopRect,
197 int RightRect,
198 int BottomRect,
199 int XStartArc,
200 int YStartArc,
201 int XEndArc,
202 int YEndArc)
203 {
204 BOOL Ret;
205 //PDC_ATTR pdcattr;
206
207 DPRINT("StartX: %d, StartY: %d, EndX: %d, EndY: %d\n",
208 XStartArc,YStartArc,XEndArc,YEndArc);
209 DPRINT("Left: %d, Top: %d, Right: %d, Bottom: %d\n",
210 LeftRect,TopRect,RightRect,BottomRect);
211
212 if ((LeftRect == RightRect) || (TopRect == BottomRect)) return TRUE;
213
214 if (PATH_IsPathOpen(dc->dclevel))
215 {
216 return PATH_Arc( dc,
217 LeftRect,
218 TopRect,
219 RightRect,
220 BottomRect,
221 XStartArc,
222 YStartArc,
223 XEndArc,
224 YEndArc,
225 arctype);
226 }
227
228 //pdcattr = dc->pdcattr;
229
230 if (arctype == GdiTypeArcTo)
231 {
232 if (dc->dclevel.flPath & DCPATH_CLOCKWISE)
233 IntGdiLineTo(dc, XEndArc, YEndArc);
234 else
235 IntGdiLineTo(dc, XStartArc, YStartArc);
236 }
237
238 Ret = IntArc( dc,
239 LeftRect,
240 TopRect,
241 RightRect,
242 BottomRect,
243 XStartArc,
244 YStartArc,
245 XEndArc,
246 YEndArc,
247 arctype);
248
249 if (arctype == GdiTypeArcTo)
250 {
251 if (dc->dclevel.flPath & DCPATH_CLOCKWISE)
252 IntGdiMoveToEx(dc, XStartArc, YStartArc, NULL, TRUE);
253 else
254 IntGdiMoveToEx(dc, XEndArc, YEndArc, NULL, TRUE);
255 }
256 return Ret;
257 }
258
259 BOOL
260 FASTCALL
261 IntGdiAngleArc( PDC pDC,
262 INT x,
263 INT y,
264 DWORD dwRadius,
265 FLOAT eStartAngle,
266 FLOAT eSweepAngle)
267 {
268 INT x1, y1, x2, y2, arcdir;
269 BOOL result;
270
271 /* Calculate the end point */
272 x2 = x + (INT)(cos(((eStartAngle+eSweepAngle)/360)*(M_PI*2)) * dwRadius);
273 y2 = y - (INT)(sin(((eStartAngle+eSweepAngle)/360)*(M_PI*2)) * dwRadius);
274
275 x1 = x + (INT)(cos((eStartAngle/360)*(M_PI*2)) * dwRadius);
276 y1 = y - (INT)(sin((eStartAngle/360)*(M_PI*2)) * dwRadius);
277
278 arcdir = pDC->dclevel.flPath & DCPATH_CLOCKWISE;
279 if (eSweepAngle >= 0)
280 pDC->dclevel.flPath &= ~DCPATH_CLOCKWISE;
281 else
282 pDC->dclevel.flPath |= DCPATH_CLOCKWISE;
283
284 result = IntGdiArcInternal( GdiTypeArcTo,
285 pDC,
286 x-dwRadius,
287 y-dwRadius,
288 x+dwRadius,
289 y+dwRadius,
290 x1,
291 y1,
292 x2,
293 y2 );
294
295 pDC->dclevel.flPath |= (arcdir & DCPATH_CLOCKWISE);
296
297 if (result)
298 {
299 IntGdiMoveToEx(pDC, x2, y2, NULL, TRUE);
300 }
301 return result;
302 }
303
304 /* FUNCTIONS *****************************************************************/
305
306 BOOL
307 APIENTRY
308 NtGdiAngleArc(
309 IN HDC hDC,
310 IN INT x,
311 IN INT y,
312 IN DWORD dwRadius,
313 IN DWORD dwStartAngle,
314 IN DWORD dwSweepAngle)
315 {
316 DC *pDC;
317 BOOL Ret = FALSE;
318 gxf_long worker, worker1;
319 KFLOATING_SAVE FloatSave;
320
321 pDC = DC_LockDc (hDC);
322 if(!pDC)
323 {
324 EngSetLastError(ERROR_INVALID_HANDLE);
325 return FALSE;
326 }
327 if (pDC->dctype == DC_TYPE_INFO)
328 {
329 DC_UnlockDc(pDC);
330 /* Yes, Windows really returns TRUE in this case */
331 return TRUE;
332 }
333
334 KeSaveFloatingPointState(&FloatSave);
335
336 worker.l = dwStartAngle;
337 worker1.l = dwSweepAngle;
338 DC_vPrepareDCsForBlit(pDC, NULL, NULL, NULL);
339 if (pDC->pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
340 DC_vUpdateFillBrush(pDC);
341 if (pDC->pdcattr->ulDirty_ & (DIRTY_LINE | DC_PEN_DIRTY))
342 DC_vUpdateLineBrush(pDC);
343 Ret = IntGdiAngleArc( pDC, x, y, dwRadius, worker.f, worker1.f);
344 DC_vFinishBlit(pDC, NULL);
345 DC_UnlockDc( pDC );
346
347 KeRestoreFloatingPointState(&FloatSave);
348
349 return Ret;
350 }
351
352 BOOL
353 APIENTRY
354 NtGdiArcInternal(
355 ARCTYPE arctype,
356 HDC hDC,
357 int LeftRect,
358 int TopRect,
359 int RightRect,
360 int BottomRect,
361 int XStartArc,
362 int YStartArc,
363 int XEndArc,
364 int YEndArc)
365 {
366 DC *dc;
367 BOOL Ret;
368 KFLOATING_SAVE FloatSave;
369
370 dc = DC_LockDc (hDC);
371 if(!dc)
372 {
373 EngSetLastError(ERROR_INVALID_HANDLE);
374 return FALSE;
375 }
376 if (dc->dctype == DC_TYPE_INFO)
377 {
378 DC_UnlockDc(dc);
379 /* Yes, Windows really returns TRUE in this case */
380 return TRUE;
381 }
382
383 DC_vPrepareDCsForBlit(dc, NULL, NULL, NULL);
384
385 if (dc->pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
386 DC_vUpdateFillBrush(dc);
387
388 if (dc->pdcattr->ulDirty_ & (DIRTY_LINE | DC_PEN_DIRTY))
389 DC_vUpdateLineBrush(dc);
390
391 KeSaveFloatingPointState(&FloatSave);
392
393 Ret = IntGdiArcInternal(
394 arctype,
395 dc,
396 LeftRect,
397 TopRect,
398 RightRect,
399 BottomRect,
400 XStartArc,
401 YStartArc,
402 XEndArc,
403 YEndArc);
404
405 KeRestoreFloatingPointState(&FloatSave);
406 DC_vFinishBlit(dc, NULL);
407 DC_UnlockDc( dc );
408 return Ret;
409 }
410