Move old pie code into arc.
[reactos.git] / reactos / subsystems / win32 / win32k / objects / arc.c
1
2 #include <w32k.h>
3
4 #define NDEBUG
5 #include <debug.h>
6
7 typedef struct tagSHAPEPOINT
8 {
9 int X;
10 int Y;
11 int Type;
12 } SHAPEPOINT, *PSHAPEPOINT;
13
14 #define SHAPEPOINT_TYPE_CIRCLE 'C'
15 #define SHAPEPOINT_TYPE_LINE_RIGHT 'R' /* Fill at right side of line */
16 #define SHAPEPOINT_TYPE_LINE_LEFT 'L' /* Fill at left side of line */
17
18 #define SETPOINT(x, y, type) \
19 ShapePoints[*PointCount].X = (x); \
20 ShapePoints[*PointCount].Y = (y); \
21 ShapePoints[*PointCount].Type = (type); \
22 (*PointCount)++
23
24 #define SETCIRCLEPOINT(x, y) \
25 SETPOINT(x, y, SHAPEPOINT_TYPE_CIRCLE)
26
27 #ifdef TODO
28 STATIC VOID
29 FASTCALL
30 CirclePoints(UINT *PointCount, PSHAPEPOINT ShapePoints, int Left, int Top,
31 int Right, int Bottom)
32 {
33 int X, X18, X27, X36, X45;
34 int Y, Y14, Y23, Y58, Y67;
35 int d, Radius;
36 BOOL Even;
37
38 Even = (0 == (Right - Left) % 2);
39 Right--;
40 Bottom--;
41 Radius = (Right - Left) >> 1;
42
43 if (Even)
44 {
45 X = 0;
46 Y = Radius;
47 d = 2 - Radius;
48 X18 = Right;
49 X27 = ((Left + Right) >> 1) + 1;
50 X36 = (Left + Right) >> 1;
51 X45 = Left;
52 Y14 = Top + Radius;
53 Y23 = Top;
54 Y58 = Top + Radius + 1;
55 Y67 = Top + (Right - Left);
56 ShapePoints[*PointCount].X = X27;
57 SETCIRCLEPOINT(X27, Y23);
58 SETCIRCLEPOINT(X36, Y23);
59 SETCIRCLEPOINT(X18, Y14);
60 SETCIRCLEPOINT(X45, Y14);
61 SETCIRCLEPOINT(X18, Y58);
62 SETCIRCLEPOINT(X45, Y58);
63 SETCIRCLEPOINT(X27, Y67);
64 SETCIRCLEPOINT(X36, Y67);
65 }
66 else
67 {
68 X = 0;
69 Y = Radius;
70 d = 1 - Radius;
71 X18 = Right;
72 X27 = (Left + Right) >> 1;
73 X36 = (Left + Right) >> 1;
74 X45 = Left;
75 Y14 = Top + Radius;
76 Y23 = Top;
77 Y58 = Top + Radius;
78 Y67 = Top + (Right - Left);
79 SETCIRCLEPOINT(X27, Y23);
80 SETCIRCLEPOINT(X45, Y14);
81 SETCIRCLEPOINT(X18, Y58);
82 SETCIRCLEPOINT(X27, Y67);
83 }
84
85 while (X < Y)
86 {
87 if (d < 0)
88 {
89 d += (X << 1) + (Even ? 4 : 3);
90
91 X27++;
92 X36--;
93 Y14--;
94 Y58++;
95 }
96 else
97 {
98 d += ((X - Y) << 1) + 5;
99 Y--;
100
101 Y23++;
102 Y67--;
103 X18--;
104 X45++;
105 X27++;
106 X36--;
107 Y14--;
108 Y58++;
109 }
110 X++;
111
112 SETCIRCLEPOINT(X27, Y23);
113 SETCIRCLEPOINT(X36, Y23);
114 SETCIRCLEPOINT(X18, Y14);
115 SETCIRCLEPOINT(X45, Y14);
116 SETCIRCLEPOINT(X18, Y58);
117 SETCIRCLEPOINT(X45, Y58);
118 SETCIRCLEPOINT(X27, Y67);
119 SETCIRCLEPOINT(X36, Y67);
120 }
121 }
122
123 STATIC VOID
124 LinePoints(UINT *PointCount, PSHAPEPOINT ShapePoints, int Left, int Top,
125 int Right, int Bottom, int XTo, int YTo, BOOL Start)
126 {
127 LONG x, y, deltax, deltay, i, xchange, ychange, error;
128 int Type;
129
130 x = (Right + Left) >> 1;
131 y = (Bottom + Top) >> 1;
132 deltax = XTo - x;
133 deltay = YTo - y;
134
135 if (deltax < 0)
136 {
137 xchange = -1;
138 deltax = - deltax;
139 x--;
140 }
141 else
142 {
143 xchange = 1;
144 }
145
146 if (deltay < 0)
147 {
148 ychange = -1;
149 deltay = - deltay;
150 y--;
151 Type = (Start ? SHAPEPOINT_TYPE_LINE_LEFT : SHAPEPOINT_TYPE_LINE_RIGHT);
152 }
153 else
154 {
155 ychange = 1;
156 Type = (Start ? SHAPEPOINT_TYPE_LINE_RIGHT : SHAPEPOINT_TYPE_LINE_LEFT);
157 }
158
159 if (y == YTo)
160 {
161 for (i = x; i <= XTo; i++)
162 {
163 SETPOINT(i, y, Type);
164 }
165 }
166 else if (x == XTo)
167 {
168 for (i = y; i <= YTo; i++)
169 {
170 SETPOINT(x, i, Type);
171 }
172 }
173 else
174 {
175 error = 0;
176
177 if (deltax < deltay)
178 {
179 for (i = 0; i < deltay; i++)
180 {
181 SETPOINT(x, y, Type);
182 y = y + ychange;
183 error = error + deltax;
184
185 if (deltay <= error)
186 {
187 x = x + xchange;
188 error = error - deltay;
189 }
190 }
191 }
192 else
193 {
194 for (i = 0; i < deltax; i++)
195 {
196 SETPOINT(x, y, Type);
197 x = x + xchange;
198 error = error + deltay;
199 if (deltax <= error)
200 {
201 y = y + ychange;
202 error = error - deltax;
203 }
204 }
205 }
206 }
207 }
208
209 STATIC int
210 CDECL
211 CompareShapePoints(const void *pv1, const void *pv2)
212 {
213 if (((const PSHAPEPOINT) pv1)->Y < ((const PSHAPEPOINT) pv2)->Y)
214 {
215 return -1;
216 }
217 else if (((const PSHAPEPOINT) pv2)->Y < ((const PSHAPEPOINT) pv1)->Y)
218 {
219 return +1;
220 }
221 else if (((const PSHAPEPOINT) pv1)->X < ((const PSHAPEPOINT) pv2)->X)
222 {
223 return -1;
224 }
225 else if (((const PSHAPEPOINT) pv2)->X < ((const PSHAPEPOINT) pv1)->X)
226 {
227 return +1;
228 }
229 else
230 {
231 return 0;
232 }
233 }
234 #endif
235
236
237 BOOL
238 STDCALL
239 NtGdiPie(HDC hDC,
240 int Left,
241 int Top,
242 int Right,
243 int Bottom,
244 int XRadialStart,
245 int YRadialStart,
246 int XRadialEnd,
247 int YRadialEnd)
248 {
249 #ifdef TODO
250 PDC dc;
251 PDC_ATTR;
252 RECTL RectBounds;
253 SURFOBJ *SurfObj;
254 BRUSHOBJ PenBrushObj;
255 PBRUSHOBJ FillBrushObj;
256 PSHAPEPOINT ShapePoints;
257 UINT Point, PointCount;
258 BOOL ret = TRUE;
259 int Y, CircleStart, CircleEnd, LineStart, LineEnd;
260 BOOL FullFill;
261
262 if (Right <= Left || Bottom <= Top)
263 {
264 SetLastWin32Error(ERROR_INVALID_PARAMETER);
265 return FALSE;
266 }
267
268 if (Right - Left != Bottom - Top)
269 {
270 UNIMPLEMENTED;
271 }
272
273 dc = DC_LockDc ( hDC );
274 if (NULL == dc)
275 {
276 SetLastWin32Error(ERROR_INVALID_HANDLE);
277 return FALSE;
278 }
279 if (dc->DC_Type == DC_TYPE_INFO)
280 {
281 DC_UnlockDc(dc);
282 /* Yes, Windows really returns TRUE in this case */
283 return TRUE;
284 }
285
286 Dc_Attr = dc->pDc_Attr;
287 if(!Dc_Attr) Dc_Attr = &dc->Dc_Attr;
288
289 FillBrushObj = BRUSHOBJ_LockBrush(Dc_Attr->hbrush);
290 if (NULL == FillBrushObj)
291 {
292 DC_UnlockDc(dc);
293 SetLastWin32Error(ERROR_INTERNAL_ERROR);
294 return FALSE;
295 }
296
297 Left += dc->ptlDCOrig.x;
298 Right += dc->ptlDCOrig.x;
299 Top += dc->ptlDCOrig.y;
300 Bottom += dc->ptlDCOrig.y;
301 XRadialStart += dc->ptlDCOrig.x;
302 YRadialStart += dc->ptlDCOrig.y;
303 XRadialEnd += dc->ptlDCOrig.x;
304 YRadialEnd += dc->ptlDCOrig.y;
305
306 RectBounds.left = Left;
307 RectBounds.right = Right;
308 RectBounds.top = Top;
309 RectBounds.bottom = Bottom;
310
311 SurfObj = (SURFOBJ*) AccessUserObject((ULONG)dc->Surface);
312 HPenToBrushObj(&PenBrushObj, Dc_Attr->hpen);
313
314 /* Number of points for the circle is 4 * sqrt(2) * Radius, start
315 and end line have at most Radius points, so allocate at least
316 that much */
317 ShapePoints = ExAllocatePoolWithTag(PagedPool, 8 * (Right - Left + 1) / 2 * sizeof(SHAPEPOINT), TAG_SHAPE);
318 if (NULL == ShapePoints)
319 {
320 BRUSHOBJ_UnlockBrush(FillBrushObj);
321 DC_UnlockDc(dc);
322
323 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
324 return FALSE;
325 }
326
327 if (Left == Right)
328 {
329 PUTPIXEL(Left, Top, &PenBrushObj);
330 BRUSHOBJ_UnlockBrush(FillBrushObj);
331 DC_UnlockDc(dc);
332
333 return ret;
334 }
335
336 PointCount = 0;
337 CirclePoints(&PointCount, ShapePoints, Left, Top, Right, Bottom);
338 LinePoints(&PointCount, ShapePoints, Left, Top, Right, Bottom,
339 XRadialStart, YRadialStart, TRUE);
340 LinePoints(&PointCount, ShapePoints, Left, Top, Right, Bottom,
341 XRadialEnd, YRadialEnd, FALSE);
342 ASSERT(PointCount <= 8 * (Right - Left + 1) / 2);
343 EngSort((PBYTE) ShapePoints, sizeof(SHAPEPOINT), PointCount, CompareShapePoints);
344
345 FullFill = TRUE;
346 Point = 0;
347 while (Point < PointCount)
348 {
349 Y = ShapePoints[Point].Y;
350
351 /* Skip any line pixels before circle */
352 while (Point < PointCount && ShapePoints[Point].Y == Y
353 && SHAPEPOINT_TYPE_CIRCLE != ShapePoints[Point].Type)
354 {
355 Point++;
356 }
357
358 /* Handle left side of circle */
359 if (Point < PointCount && ShapePoints[Point].Y == Y)
360 {
361 CircleStart = ShapePoints[Point].X;
362 Point++;
363 while (Point < PointCount && ShapePoints[Point].Y == Y
364 && ShapePoints[Point].X == ShapePoints[Point - 1].X + 1
365 && SHAPEPOINT_TYPE_CIRCLE == ShapePoints[Point].Type)
366 {
367 Point++;
368 }
369 CircleEnd = ShapePoints[Point - 1].X;
370
371 PUTLINE(CircleStart, Y, CircleEnd + 1, Y, &PenBrushObj);
372 }
373
374 /* Handle line(s) (max 2) inside the circle */
375 while (Point < PointCount && ShapePoints[Point].Y == Y
376 && SHAPEPOINT_TYPE_CIRCLE != ShapePoints[Point].Type)
377 {
378 LineStart = ShapePoints[Point].X;
379 Point++;
380 while (Point < PointCount && ShapePoints[Point].Y == Y
381 && ShapePoints[Point].X == ShapePoints[Point - 1].X + 1
382 && ShapePoints[Point].Type == ShapePoints[Point - 1].Type)
383 {
384 Point++;
385 }
386 LineEnd = ShapePoints[Point - 1].X;
387
388 PUTLINE(LineStart, Y, LineEnd + 1, Y, &PenBrushObj);
389 }
390
391 /* Handle right side of circle */
392 while (Point < PointCount && ShapePoints[Point].Y == Y
393 && SHAPEPOINT_TYPE_CIRCLE == ShapePoints[Point].Type)
394 {
395 CircleStart = ShapePoints[Point].X;
396 Point++;
397 while (Point < PointCount && ShapePoints[Point].Y == Y
398 && ShapePoints[Point].X == ShapePoints[Point - 1].X + 1
399 && SHAPEPOINT_TYPE_CIRCLE == ShapePoints[Point].Type)
400 {
401 Point++;
402 }
403 CircleEnd = ShapePoints[Point - 1].X;
404
405 PUTLINE(CircleStart, Y, CircleEnd + 1, Y, &PenBrushObj);
406 }
407
408 /* Skip any line pixels after circle */
409 while (Point < PointCount && ShapePoints[Point].Y == Y)
410 {
411 Point++;
412 }
413 }
414
415 ExFreePool(ShapePoints);
416 BRUSHOBJ_UnlockBrush(FillBrushObj);
417 DC_UnlockDc(dc);
418
419 return ret;
420 #else
421 return TRUE;
422 #endif
423 }
424
425
426 static BOOL FASTCALL
427 IntArc( DC *dc, int LeftRect, int TopRect, int RightRect, int BottomRect,
428 int XStartArc, int YStartArc, int XEndArc, int YEndArc, ARCTYPE arctype)
429 {
430 return TRUE;
431 }
432
433 BOOL FASTCALL
434 IntGdiArcInternal(
435 ARCTYPE arctype,
436 DC *dc,
437 int LeftRect,
438 int TopRect,
439 int RightRect,
440 int BottomRect,
441 int XStartArc,
442 int YStartArc,
443 int XEndArc,
444 int YEndArc)
445 {
446 INT rx, ry;
447 RECT rc, rc1;
448
449 if(PATH_IsPathOpen(dc->w.path))
450 {
451 INT type = arctype;
452 if (arctype == GdiTypeArcTo) type = GdiTypeArc;
453 return PATH_Arc(dc, LeftRect, TopRect, RightRect, BottomRect,
454 XStartArc, YStartArc, XEndArc, YEndArc, type);
455 }
456
457 IntGdiSetRect(&rc, LeftRect, TopRect, RightRect, BottomRect);
458 IntGdiSetRect(&rc1, XStartArc, YStartArc, XEndArc, YEndArc);
459
460 rx = (rc.right - rc.left)/2 - 1;
461 ry = (rc.bottom - rc.top)/2 -1;
462 rc.left += rx;
463 rc.top += ry;
464
465 return IntArc( dc, rc.left, rc.top, rx, ry,
466 rc1.left, rc1.top, rc1.right, rc1.bottom, arctype);
467 }
468
469 BOOL
470 STDCALL
471 NtGdiArcInternal(
472 ARCTYPE arctype,
473 HDC hDC,
474 int LeftRect,
475 int TopRect,
476 int RightRect,
477 int BottomRect,
478 int XStartArc,
479 int YStartArc,
480 int XEndArc,
481 int YEndArc)
482 {
483 DC *dc;
484 BOOL Ret;
485
486 dc = DC_LockDc (hDC);
487 if(!dc)
488 {
489 SetLastWin32Error(ERROR_INVALID_HANDLE);
490 return FALSE;
491 }
492 if (dc->DC_Type == DC_TYPE_INFO)
493 {
494 DC_UnlockDc(dc);
495 /* Yes, Windows really returns TRUE in this case */
496 return TRUE;
497 }
498
499 if (arctype == GdiTypeArcTo)
500 {
501 // Line from current position to starting point of arc
502 if ( !IntGdiLineTo(dc, XStartArc, YStartArc) )
503 {
504 DC_UnlockDc(dc);
505 return FALSE;
506 }
507 }
508
509 Ret = IntGdiArcInternal(
510 arctype,
511 dc,
512 LeftRect,
513 TopRect,
514 RightRect,
515 BottomRect,
516 XStartArc,
517 YStartArc,
518 XEndArc,
519 YEndArc);
520
521 if (arctype == GdiTypeArcTo)
522 {
523 // If no error occured, the current position is moved to the ending point of the arc.
524 if(Ret)
525 IntGdiMoveToEx(dc, XEndArc, YEndArc, NULL);
526 }
527
528 DC_UnlockDc( dc );
529 return Ret;
530 }
531