update for HEAD-2003091401
[reactos.git] / subsys / win32k / objects / line.c
1 /*
2  *  ReactOS W32 Subsystem
3  *  Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program; if not, write to the Free Software
17  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  */
19 /* $Id$ */
20
21 // Some code from the WINE project source (www.winehq.com)
22
23 #undef WIN32_LEAN_AND_MEAN
24 #include <windows.h>
25 #include <internal/safe.h>
26 #include <ddk/ntddk.h>
27 #include <win32k/dc.h>
28 #include <win32k/line.h>
29 #include <win32k/path.h>
30 #include <win32k/pen.h>
31 #include <win32k/region.h>
32 #include <include/error.h>
33 #include <include/inteng.h>
34 #include <include/object.h>
35 #include <include/path.h>
36
37 #define NDEBUG
38 #include <win32k/debug1.h>
39
40
41 BOOL
42 STDCALL
43 NtGdiAngleArc(HDC  hDC,
44              int  X,
45              int  Y,
46              DWORD  Radius,
47              FLOAT  StartAngle,
48              FLOAT  SweepAngle)
49 {
50   UNIMPLEMENTED;
51 }
52
53 BOOL
54 STDCALL
55 NtGdiArc(HDC  hDC,
56         int  LeftRect,
57         int  TopRect,
58         int  RightRect,
59         int  BottomRect,
60         int  XStartArc,
61         int  YStartArc,
62         int  XEndArc,
63         int  YEndArc)
64 {
65   DC *dc = DC_LockDc(hDC);
66   if(!dc) return FALSE;
67
68   if(PATH_IsPathOpen(dc->w.path))
69   {
70     DC_UnlockDc ( hDC );
71     return PATH_Arc(hDC, LeftRect, TopRect, RightRect, BottomRect,
72                     XStartArc, YStartArc, XEndArc, YEndArc);
73   }
74
75   // FIXME
76 //   EngArc(dc, LeftRect, TopRect, RightRect, BottomRect, UNIMPLEMENTED
77 //          XStartArc, YStartArc, XEndArc, YEndArc);
78
79   DC_UnlockDc( hDC );
80   return TRUE;
81 }
82
83 BOOL
84 STDCALL
85 NtGdiArcTo(HDC  hDC,
86           int  LeftRect,
87           int  TopRect,
88           int  RightRect,
89           int  BottomRect,
90           int  XRadial1,
91           int  YRadial1,
92           int  XRadial2,
93           int  YRadial2)
94 {
95   BOOL result;
96   //DC *dc;
97
98   // Line from current position to starting point of arc
99   if ( !NtGdiLineTo(hDC, XRadial1, YRadial1) )
100     return FALSE;
101
102   //dc = DC_LockDc(hDC);
103
104   //if(!dc) return FALSE;
105
106   // Then the arc is drawn.
107   result = NtGdiArc(hDC, LeftRect, TopRect, RightRect, BottomRect,
108                    XRadial1, YRadial1, XRadial2, YRadial2);
109
110   //DC_UnlockDc( hDC );
111
112   // If no error occured, the current position is moved to the ending point of the arc.
113   if(result)
114     NtGdiMoveToEx(hDC, XRadial2, YRadial2, NULL);
115
116   return result;
117 }
118
119 INT
120 FASTCALL
121 IntGetArcDirection ( PDC dc )
122 {
123   ASSERT ( dc );
124   return dc->w.ArcDirection;
125 }
126
127 INT
128 STDCALL
129 NtGdiGetArcDirection(HDC  hDC)
130 {
131   PDC dc = DC_LockDc (hDC);
132   int ret = 0; // default to failure
133
134   if ( dc )
135   {
136     ret = IntGetArcDirection ( dc );
137     DC_UnlockDc( hDC );
138   }
139
140   return ret;
141 }
142
143 BOOL
144 STDCALL
145 NtGdiLineTo(HDC  hDC,
146            int  XEnd,
147            int  YEnd)
148 {
149   DC      *dc = DC_LockDc(hDC);
150   SURFOBJ *SurfObj;
151   BOOL     Ret;
152   BRUSHOBJ PenBrushObj;
153   RECT     Bounds;
154
155   if ( !dc )
156     {
157       SetLastWin32Error(ERROR_INVALID_HANDLE);
158       return FALSE;
159     }
160
161   SurfObj = (SURFOBJ*)AccessUserObject ( (ULONG)dc->Surface );
162
163   if (PATH_IsPathOpen(dc->w.path))
164     {
165       DC_UnlockDc(hDC);
166       Ret = PATH_LineTo(hDC, XEnd, YEnd);
167       if (Ret)
168         {
169           // FIXME - PATH_LineTo should maybe do this...
170           dc = DC_LockDc(hDC);
171           dc->w.CursPosX = XEnd;
172           dc->w.CursPosY = YEnd;
173           DC_UnlockDc(hDC);
174         }
175       return Ret;
176     }
177   else
178     {
179       if (dc->w.CursPosX <= XEnd)
180         {
181           Bounds.left = dc->w.CursPosX;
182           Bounds.right = XEnd;
183         }
184       else
185         {
186           Bounds.left = XEnd;
187           Bounds.right = dc->w.CursPosX;
188         }
189       Bounds.left += dc->w.DCOrgX;
190       Bounds.right += dc->w.DCOrgX;
191       if (dc->w.CursPosY <= YEnd)
192         {
193           Bounds.top = dc->w.CursPosY;
194           Bounds.bottom = YEnd;
195         }
196       else
197         {
198           Bounds.top = YEnd;
199           Bounds.bottom = dc->w.CursPosY;
200         }
201       Bounds.top += dc->w.DCOrgY;
202       Bounds.bottom += dc->w.DCOrgY;
203
204       /* make BRUSHOBJ from current pen. */
205       HPenToBrushObj ( &PenBrushObj, dc->w.hPen );
206
207       Ret = IntEngLineTo(SurfObj,
208                          dc->CombinedClip,
209                          &PenBrushObj,
210                          dc->w.DCOrgX + dc->w.CursPosX, dc->w.DCOrgY + dc->w.CursPosY,
211                          dc->w.DCOrgX + XEnd,           dc->w.DCOrgY + YEnd,
212                          &Bounds,
213                          dc->w.ROPmode);
214     }
215
216   if (Ret)
217     {
218       dc->w.CursPosX = XEnd;
219       dc->w.CursPosY = YEnd;
220     }
221   DC_UnlockDc(hDC);
222
223   return Ret;
224 }
225
226 BOOL
227 STDCALL
228 NtGdiMoveToEx(HDC      hDC,
229              int      X,
230              int      Y,
231              LPPOINT  Point)
232 {
233   DC   *dc = DC_LockDc( hDC );
234   BOOL  PathIsOpen;
235
236   if ( !dc ) return FALSE;
237
238   if ( Point )
239   {
240     Point->x = dc->w.CursPosX;
241     Point->y = dc->w.CursPosY;
242   }
243   dc->w.CursPosX = X;
244   dc->w.CursPosY = Y;
245
246   PathIsOpen = PATH_IsPathOpen(dc->w.path);
247
248   DC_UnlockDc ( hDC );
249
250   if ( PathIsOpen )
251     return PATH_MoveTo ( hDC );
252
253   return TRUE;
254 }
255
256 BOOL
257 STDCALL
258 NtGdiPolyBezier(HDC            hDC,
259                CONST LPPOINT  pt,
260                DWORD          Count)
261 {
262   DC *dc = DC_LockDc(hDC);
263   BOOL ret = FALSE; // default to FAILURE
264
265   if ( !dc ) return FALSE;
266
267   if ( PATH_IsPathOpen(dc->w.path) )
268   {
269     DC_UnlockDc( hDC );
270     return PATH_PolyBezier ( hDC, pt, Count );
271   }
272
273   /* We'll convert it into line segments and draw them using Polyline */
274   {
275     POINT *Pts;
276     INT nOut;
277
278     Pts = GDI_Bezier ( pt, Count, &nOut );
279     if ( Pts )
280     {
281       DbgPrint("Pts = %p, no = %d\n", Pts, nOut);
282       ret = NtGdiPolyline(dc->hSelf, Pts, nOut);
283       ExFreePool(Pts);
284     }
285   }
286   DC_UnlockDc( hDC );
287   return ret;
288 }
289
290 BOOL
291 STDCALL
292 NtGdiPolyBezierTo(HDC  hDC,
293                  CONST LPPOINT  pt,
294                  DWORD  Count)
295 {
296   DC *dc = DC_LockDc(hDC);
297   BOOL ret = FALSE; // default to failure
298
299   if ( !dc ) return ret;
300
301   if ( PATH_IsPathOpen(dc->w.path) )
302     ret = PATH_PolyBezierTo ( hDC, pt, Count );
303   else /* We'll do it using PolyBezier */
304   {
305     POINT *npt;
306     npt = ExAllocatePool(NonPagedPool, sizeof(POINT) * (Count + 1));
307     if ( npt )
308     {
309       npt[0].x = dc->w.CursPosX;
310       npt[0].y = dc->w.CursPosY;
311       memcpy(npt + 1, pt, sizeof(POINT) * Count);
312       ret = NtGdiPolyBezier(dc->hSelf, npt, Count+1);
313       ExFreePool(npt);
314     }
315   }
316   if ( ret )
317   {
318     dc->w.CursPosX = pt[Count-1].x;
319     dc->w.CursPosY = pt[Count-1].y;
320   }
321   DC_UnlockDc( hDC );
322   return ret;
323 }
324
325 BOOL
326 STDCALL
327 NtGdiPolyDraw(HDC            hDC,
328              CONST LPPOINT  pt,
329              CONST LPBYTE   Types,
330              int            Count)
331 {
332   UNIMPLEMENTED;
333 }
334
335 BOOL
336 FASTCALL
337 IntPolyline(PDC           dc,
338             CONST LPPOINT pt,
339             int           Count)
340 {
341   SURFOBJ     *SurfObj = NULL;
342   BOOL         ret = FALSE; // default to failure
343   LONG         i;
344   PROSRGNDATA  reg;
345   BRUSHOBJ     PenBrushObj;
346   POINT       *pts;
347
348   SurfObj = (SURFOBJ*)AccessUserObject((ULONG)dc->Surface);
349   ASSERT(SurfObj);
350
351   if ( PATH_IsPathOpen ( dc->w.path ) )
352     return PATH_Polyline ( dc, pt, Count );
353
354   reg = RGNDATA_LockRgn(dc->w.hGCClipRgn);
355
356   //FIXME: Do somthing with reg...
357
358   //Allocate "Count" bytes of memory to hold a safe copy of pt
359   pts = (POINT*)ExAllocatePool ( NonPagedPool, sizeof(POINT)*Count );
360   if ( pts )
361   {
362     // safely copy pt to local version
363     if ( STATUS_SUCCESS == MmCopyFromCaller(pts, pt, sizeof(POINT)*Count) )
364     {
365       //offset the array of point by the dc->w.DCOrg
366       for ( i = 0; i < Count; i++ )
367       {
368         pts[i].x += dc->w.DCOrgX;
369         pts[i].y += dc->w.DCOrgY;
370       }
371
372       /* make BRUSHOBJ from current pen. */
373       HPenToBrushObj ( &PenBrushObj, dc->w.hPen );
374
375       //get IntEngPolyline to do the drawing.
376       ret = IntEngPolyline(SurfObj,
377                            dc->CombinedClip,
378                            &PenBrushObj,
379                            pts,
380                            Count,
381                            dc->w.ROPmode);
382     }
383
384     ExFreePool ( pts );
385   }
386
387   //Clean up
388   RGNDATA_UnlockRgn(dc->w.hGCClipRgn);
389
390   return ret;
391 }
392
393 BOOL
394 STDCALL
395 NtGdiPolyline(HDC            hDC,
396              CONST LPPOINT  pt,
397              int            Count)
398 {
399   DC    *dc = DC_LockDc(hDC);
400   BOOL   ret = FALSE; // default to failure
401
402   if ( dc )
403   {
404     ret = IntPolyline ( dc, pt, Count );
405
406     DC_UnlockDc( hDC );
407   }
408
409   return ret;
410 }
411
412 BOOL
413 STDCALL
414 NtGdiPolylineTo(HDC            hDC,
415                CONST LPPOINT  pt,
416                DWORD          Count)
417 {
418   DC *dc = DC_LockDc(hDC);
419   BOOL ret = FALSE; // default to failure
420
421   if ( !dc ) return ret;
422
423   if(PATH_IsPathOpen(dc->w.path))
424   {
425     ret = PATH_PolylineTo(hDC, pt, Count);
426   }
427   else /* do it using Polyline */
428   {
429     POINT *pts = ExAllocatePool(NonPagedPool, sizeof(POINT) * (Count + 1));
430     if ( pts )
431     {
432       pts[0].x = dc->w.CursPosX;
433       pts[0].y = dc->w.CursPosY;
434       memcpy( pts + 1, pt, sizeof(POINT) * Count);
435       ret = NtGdiPolyline(hDC, pts, Count + 1);
436       ExFreePool(pts);
437     }
438   }
439   if ( ret )
440   {
441     dc->w.CursPosX = pt[Count-1].x;
442     dc->w.CursPosY = pt[Count-1].y;
443   }
444   DC_UnlockDc( hDC );
445   return ret;
446 }
447
448 BOOL
449 STDCALL
450 NtGdiPolyPolyline(HDC            hDC,
451                  CONST LPPOINT  pt,
452                  CONST LPDWORD  PolyPoints,
453                  DWORD          Count)
454 {
455   DC    *dc = DC_LockDc(hDC);
456   int i;
457   LPPOINT pts;
458   LPDWORD pc;
459   BOOL   ret = FALSE; // default to failure
460   pts = pt;
461   pc = PolyPoints;
462   if ( dc )
463   {
464         for (i=0;i<Count;i++)
465         {
466                 ret = IntPolyline ( dc, pts, *pc );
467                 if (ret == FALSE)
468                 {
469                     DC_UnlockDc( hDC );
470                         return ret;
471                 }
472                 pts+=*pc++;
473         }
474     DC_UnlockDc( hDC );
475   }
476
477   return ret;
478 }
479
480 int
481 STDCALL
482 NtGdiSetArcDirection(HDC  hDC,
483                     int  ArcDirection)
484 {
485   PDC  dc;
486   INT  nOldDirection = 0; // default to FAILURE
487
488   dc = DC_LockDc (hDC);
489   if ( !dc ) return 0;
490
491   if ( ArcDirection == AD_COUNTERCLOCKWISE || ArcDirection == AD_CLOCKWISE )
492   {
493     nOldDirection = dc->w.ArcDirection;
494     dc->w.ArcDirection = ArcDirection;
495   }
496
497   DC_UnlockDc( hDC );
498   return nOldDirection;
499 }
500 /* EOF */