win32k brush update:
[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 = SURFACE_LockSurface(dc->rosdc.hBitmap);
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 SURFACE_UnlockSurface(psurf);
178 PEN_UnlockPen(pbrushPen);
179 DPRINT("IntArc Exit.\n");
180 return ret;
181 }
182
183
184 BOOL FASTCALL
185 IntGdiArcInternal(
186 ARCTYPE arctype,
187 DC *dc,
188 int LeftRect,
189 int TopRect,
190 int RightRect,
191 int BottomRect,
192 int XStartArc,
193 int YStartArc,
194 int XEndArc,
195 int YEndArc)
196 {
197 BOOL Ret;
198 PDC_ATTR pdcattr;
199
200 DPRINT("StartX: %d, StartY: %d, EndX: %d, EndY: %d\n",
201 XStartArc,YStartArc,XEndArc,YEndArc);
202 DPRINT("Left: %d, Top: %d, Right: %d, Bottom: %d\n",
203 LeftRect,TopRect,RightRect,BottomRect);
204
205 if ((LeftRect == RightRect) || (TopRect == BottomRect)) return TRUE;
206
207 if (PATH_IsPathOpen(dc->dclevel))
208 {
209 return PATH_Arc( dc,
210 LeftRect,
211 TopRect,
212 RightRect,
213 BottomRect,
214 XStartArc,
215 YStartArc,
216 XEndArc,
217 YEndArc,
218 arctype);
219 }
220
221 pdcattr = dc->pdcattr;
222
223 if (pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
224 DC_vUpdateFillBrush(dc);
225
226 if (pdcattr->ulDirty_ & (DIRTY_LINE | DC_PEN_DIRTY))
227 DC_vUpdateLineBrush(dc);
228
229 if (arctype == GdiTypeArcTo)
230 {
231 if (dc->dclevel.flPath & DCPATH_CLOCKWISE)
232 IntGdiLineTo(dc, XEndArc, YEndArc);
233 else
234 IntGdiLineTo(dc, XStartArc, YStartArc);
235 }
236
237 Ret = IntArc( dc,
238 LeftRect,
239 TopRect,
240 RightRect,
241 BottomRect,
242 XStartArc,
243 YStartArc,
244 XEndArc,
245 YEndArc,
246 arctype);
247
248 if (arctype == GdiTypeArcTo)
249 {
250 if (dc->dclevel.flPath & DCPATH_CLOCKWISE)
251 IntGdiMoveToEx(dc, XStartArc, YStartArc, NULL);
252 else
253 IntGdiMoveToEx(dc, XEndArc, YEndArc, NULL);
254 }
255 return Ret;
256 }
257
258 BOOL
259 FASTCALL
260 IntGdiAngleArc( PDC pDC,
261 INT x,
262 INT y,
263 DWORD dwRadius,
264 FLOAT eStartAngle,
265 FLOAT eSweepAngle)
266 {
267 INT x1, y1, x2, y2, arcdir;
268 BOOL result;
269
270 /* Calculate the end point */
271 x2 = x + (INT)(cos(((eStartAngle+eSweepAngle)/360)*(M_PI*2)) * dwRadius);
272 y2 = y - (INT)(sin(((eStartAngle+eSweepAngle)/360)*(M_PI*2)) * dwRadius);
273
274 x1 = x + (INT)(cos((eStartAngle/360)*(M_PI*2)) * dwRadius);
275 y1 = y - (INT)(sin((eStartAngle/360)*(M_PI*2)) * dwRadius);
276
277 arcdir = pDC->dclevel.flPath & DCPATH_CLOCKWISE;
278 if (eSweepAngle >= 0)
279 pDC->dclevel.flPath &= ~DCPATH_CLOCKWISE;
280 else
281 pDC->dclevel.flPath |= DCPATH_CLOCKWISE;
282
283 result = IntGdiArcInternal( GdiTypeArcTo,
284 pDC,
285 x-dwRadius,
286 y-dwRadius,
287 x+dwRadius,
288 y+dwRadius,
289 x1,
290 y1,
291 x2,
292 y2 );
293
294 pDC->dclevel.flPath |= (arcdir & DCPATH_CLOCKWISE);
295
296 if (result)
297 {
298 IntGdiMoveToEx(pDC, x2, y2, NULL); // Dont forget Path.
299 }
300 return result;
301 }
302
303 /* FUNCTIONS *****************************************************************/
304
305 BOOL
306 APIENTRY
307 NtGdiAngleArc(
308 IN HDC hDC,
309 IN INT x,
310 IN INT y,
311 IN DWORD dwRadius,
312 IN DWORD dwStartAngle,
313 IN DWORD dwSweepAngle)
314 {
315 DC *pDC;
316 BOOL Ret = FALSE;
317 gxf_long worker, worker1;
318
319 pDC = DC_LockDc (hDC);
320 if(!pDC)
321 {
322 SetLastWin32Error(ERROR_INVALID_HANDLE);
323 return FALSE;
324 }
325 if (pDC->dctype == DC_TYPE_INFO)
326 {
327 DC_UnlockDc(pDC);
328 /* Yes, Windows really returns TRUE in this case */
329 return TRUE;
330 }
331 worker.l = dwStartAngle;
332 worker1.l = dwSweepAngle;
333 Ret = IntGdiAngleArc( pDC, x, y, dwRadius, worker.f, worker1.f);
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 SetLastWin32Error(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 Ret = IntGdiArcInternal(
369 arctype,
370 dc,
371 LeftRect,
372 TopRect,
373 RightRect,
374 BottomRect,
375 XStartArc,
376 YStartArc,
377 XEndArc,
378 YEndArc);
379
380 DC_UnlockDc( dc );
381 return Ret;
382 }
383