Move the inclusion of <debug.h> to individual files and consolidate the inclusion...
[reactos.git] / reactos / 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
20 #include <w32k.h>
21
22 #define NDEBUG
23 #include <debug.h>
24
25 // Some code from the WINE project source (www.winehq.com)
26
27
28 BOOL FASTCALL
29 IntGdiMoveToEx(DC *dc,
30 int X,
31 int Y,
32 LPPOINT Point)
33 {
34 BOOL PathIsOpen;
35
36 if ( Point )
37 {
38 Point->x = dc->w.CursPosX;
39 Point->y = dc->w.CursPosY;
40 }
41 dc->w.CursPosX = X;
42 dc->w.CursPosY = Y;
43
44 PathIsOpen = PATH_IsPathOpen(dc->w.path);
45
46 if ( PathIsOpen )
47 return PATH_MoveTo ( dc );
48
49 return TRUE;
50 }
51
52 BOOL FASTCALL
53 IntGdiLineTo(DC *dc,
54 int XEnd,
55 int YEnd)
56 {
57 BITMAPOBJ *BitmapObj;
58 BOOL Ret = TRUE;
59 PGDIBRUSHOBJ PenBrushObj;
60 GDIBRUSHINST PenBrushInst;
61 RECTL Bounds;
62 POINT Points[2];
63
64 if (PATH_IsPathOpen(dc->w.path))
65 {
66 Ret = PATH_LineTo(dc, XEnd, YEnd);
67 if (Ret)
68 {
69 // FIXME - PATH_LineTo should maybe do this...
70 dc->w.CursPosX = XEnd;
71 dc->w.CursPosY = YEnd;
72 }
73 return Ret;
74 }
75 else
76 {
77 BitmapObj = BITMAPOBJ_LockBitmap ( dc->w.hBitmap );
78 if (NULL == BitmapObj)
79 {
80 SetLastWin32Error(ERROR_INVALID_HANDLE);
81 return FALSE;
82 }
83
84 Points[0].x = dc->w.CursPosX;
85 Points[0].y = dc->w.CursPosY;
86 Points[1].x = XEnd;
87 Points[1].y = YEnd;
88
89 IntLPtoDP(dc, Points, 2);
90
91 /* FIXME: Is it correct to do this after the transformation? */
92 Points[0].x += dc->w.DCOrgX;
93 Points[0].y += dc->w.DCOrgY;
94 Points[1].x += dc->w.DCOrgX;
95 Points[1].y += dc->w.DCOrgY;
96
97 Bounds.left = min(Points[0].x, Points[1].x);
98 Bounds.top = min(Points[0].y, Points[1].y);
99 Bounds.right = max(Points[0].x, Points[1].x);
100 Bounds.bottom = max(Points[0].y, Points[1].y);
101
102 /* get BRUSHOBJ from current pen. */
103 PenBrushObj = PENOBJ_LockPen( dc->w.hPen );
104 /* FIXME - PenBrushObj can be NULL!!!! Don't assert here! */
105 ASSERT(PenBrushObj);
106
107 if (!(PenBrushObj->flAttrs & GDIBRUSH_IS_NULL))
108 {
109 IntGdiInitBrushInstance(&PenBrushInst, PenBrushObj, dc->XlatePen);
110 Ret = IntEngLineTo(&BitmapObj->SurfObj,
111 dc->CombinedClip,
112 &PenBrushInst.BrushObject,
113 Points[0].x, Points[0].y,
114 Points[1].x, Points[1].y,
115 &Bounds,
116 ROP2_TO_MIX(dc->w.ROPmode));
117 }
118
119 BITMAPOBJ_UnlockBitmap ( BitmapObj );
120 PENOBJ_UnlockPen( PenBrushObj );
121 }
122
123 if (Ret)
124 {
125 dc->w.CursPosX = XEnd;
126 dc->w.CursPosY = YEnd;
127 }
128
129 return Ret;
130 }
131
132 BOOL FASTCALL
133 IntGdiPolyBezier(DC *dc,
134 LPPOINT pt,
135 DWORD Count)
136 {
137 BOOL ret = FALSE; // default to FAILURE
138
139 if ( PATH_IsPathOpen(dc->w.path) )
140 {
141 return PATH_PolyBezier ( dc, pt, Count );
142 }
143
144 /* We'll convert it into line segments and draw them using Polyline */
145 {
146 POINT *Pts;
147 INT nOut;
148
149 Pts = GDI_Bezier ( pt, Count, &nOut );
150 if ( Pts )
151 {
152 DbgPrint("Pts = %p, no = %d\n", Pts, nOut);
153 ret = IntGdiPolyline(dc, Pts, nOut);
154 ExFreePool(Pts);
155 }
156 }
157
158 return ret;
159 }
160
161 BOOL FASTCALL
162 IntGdiPolyBezierTo(DC *dc,
163 LPPOINT pt,
164 DWORD Count)
165 {
166 BOOL ret = FALSE; // default to failure
167
168 if ( PATH_IsPathOpen(dc->w.path) )
169 ret = PATH_PolyBezierTo ( dc, pt, Count );
170 else /* We'll do it using PolyBezier */
171 {
172 POINT *npt;
173 npt = ExAllocatePoolWithTag(PagedPool, sizeof(POINT) * (Count + 1), TAG_BEZIER);
174 if ( npt )
175 {
176 npt[0].x = dc->w.CursPosX;
177 npt[0].y = dc->w.CursPosY;
178 memcpy(npt + 1, pt, sizeof(POINT) * Count);
179 ret = IntGdiPolyBezier(dc, npt, Count+1);
180 ExFreePool(npt);
181 }
182 }
183 if ( ret )
184 {
185 dc->w.CursPosX = pt[Count-1].x;
186 dc->w.CursPosY = pt[Count-1].y;
187 }
188
189 return ret;
190 }
191
192 BOOL FASTCALL
193 IntGdiPolyline(DC *dc,
194 LPPOINT pt,
195 int Count)
196 {
197 BITMAPOBJ *BitmapObj;
198 GDIBRUSHOBJ *PenBrushObj;
199 GDIBRUSHINST PenBrushInst;
200 LPPOINT Points;
201 BOOL Ret = TRUE;
202 LONG i;
203
204 if (PATH_IsPathOpen(dc->w.path))
205 return PATH_Polyline(dc, pt, Count);
206
207 /* Get BRUSHOBJ from current pen. */
208 PenBrushObj = PENOBJ_LockPen(dc->w.hPen);
209 /* FIXME - PenBrushObj can be NULL! Don't assert here! */
210 ASSERT(PenBrushObj);
211
212 if (!(PenBrushObj->flAttrs & GDIBRUSH_IS_NULL))
213 {
214 Points = EngAllocMem(0, Count * sizeof(POINT), TAG_COORD);
215 if (Points != NULL)
216 {
217 BitmapObj = BITMAPOBJ_LockBitmap(dc->w.hBitmap);
218 /* FIXME - BitmapObj can be NULL!!!! Don't assert but handle this case gracefully! */
219 ASSERT(BitmapObj);
220
221 RtlCopyMemory(Points, pt, Count * sizeof(POINT));
222 IntLPtoDP(dc, Points, Count);
223
224 /* Offset the array of point by the dc->w.DCOrg */
225 for (i = 0; i < Count; i++)
226 {
227 Points[i].x += dc->w.DCOrgX;
228 Points[i].y += dc->w.DCOrgY;
229 }
230
231 IntGdiInitBrushInstance(&PenBrushInst, PenBrushObj, dc->XlatePen);
232 Ret = IntEngPolyline(&BitmapObj->SurfObj, dc->CombinedClip,
233 &PenBrushInst.BrushObject, Points, Count,
234 ROP2_TO_MIX(dc->w.ROPmode));
235
236 BITMAPOBJ_UnlockBitmap(BitmapObj);
237 EngFreeMem(Points);
238 }
239 else
240 {
241 Ret = FALSE;
242 }
243 }
244
245 PENOBJ_UnlockPen(PenBrushObj);
246
247 return Ret;
248 }
249
250 BOOL FASTCALL
251 IntGdiPolylineTo(DC *dc,
252 LPPOINT pt,
253 DWORD Count)
254 {
255 BOOL ret = FALSE; // default to failure
256
257 if(PATH_IsPathOpen(dc->w.path))
258 {
259 ret = PATH_PolylineTo(dc, pt, Count);
260 }
261 else /* do it using Polyline */
262 {
263 POINT *pts = ExAllocatePoolWithTag(PagedPool, sizeof(POINT) * (Count + 1), TAG_SHAPE);
264 if ( pts )
265 {
266 pts[0].x = dc->w.CursPosX;
267 pts[0].y = dc->w.CursPosY;
268 memcpy( pts + 1, pt, sizeof(POINT) * Count);
269 ret = IntGdiPolyline(dc, pts, Count + 1);
270 ExFreePool(pts);
271 }
272 }
273 if ( ret )
274 {
275 dc->w.CursPosX = pt[Count-1].x;
276 dc->w.CursPosY = pt[Count-1].y;
277 }
278
279 return ret;
280 }
281
282 INT FASTCALL
283 IntGdiGetArcDirection(DC *dc)
284 {
285 return dc->w.ArcDirection;
286 }
287
288 BOOL FASTCALL
289 IntGdiArc(DC *dc,
290 int LeftRect,
291 int TopRect,
292 int RightRect,
293 int BottomRect,
294 int XStartArc,
295 int YStartArc,
296 int XEndArc,
297 int YEndArc)
298 {
299 if(PATH_IsPathOpen(dc->w.path))
300 {
301 return PATH_Arc(dc, LeftRect, TopRect, RightRect, BottomRect,
302 XStartArc, YStartArc, XEndArc, YEndArc);
303 }
304
305 // FIXME
306 // EngArc(dc, LeftRect, TopRect, RightRect, BottomRect, UNIMPLEMENTED
307 // XStartArc, YStartArc, XEndArc, YEndArc);
308
309 return TRUE;
310 }
311
312 BOOL FASTCALL
313 IntGdiPolyPolyline(DC *dc,
314 LPPOINT pt,
315 LPDWORD PolyPoints,
316 DWORD Count)
317 {
318 int i;
319 LPPOINT pts;
320 LPDWORD pc;
321 BOOL ret = FALSE; // default to failure
322 pts = pt;
323 pc = PolyPoints;
324
325 for (i = 0; i < Count; i++)
326 {
327 ret = IntGdiPolyline ( dc, pts, *pc );
328 if (ret == FALSE)
329 {
330 return ret;
331 }
332 pts+=*pc++;
333 }
334
335 return ret;
336 }
337
338 /******************************************************************************/
339
340 BOOL
341 STDCALL
342 NtGdiAngleArc(HDC hDC,
343 int X,
344 int Y,
345 DWORD Radius,
346 FLOAT StartAngle,
347 FLOAT SweepAngle)
348 {
349 UNIMPLEMENTED;
350 return FALSE;
351 }
352
353 BOOL
354 STDCALL
355 NtGdiArc(HDC hDC,
356 int LeftRect,
357 int TopRect,
358 int RightRect,
359 int BottomRect,
360 int XStartArc,
361 int YStartArc,
362 int XEndArc,
363 int YEndArc)
364 {
365 DC *dc;
366 BOOL Ret;
367
368 dc = DC_LockDc (hDC);
369 if(!dc)
370 {
371 SetLastWin32Error(ERROR_INVALID_HANDLE);
372 return FALSE;
373 }
374 if (dc->IsIC)
375 {
376 DC_UnlockDc(dc);
377 /* Yes, Windows really returns TRUE in this case */
378 return TRUE;
379 }
380
381 Ret = IntGdiArc(dc,
382 LeftRect,
383 TopRect,
384 RightRect,
385 BottomRect,
386 XStartArc,
387 YStartArc,
388 XEndArc,
389 YEndArc);
390
391 DC_UnlockDc( dc );
392 return Ret;
393 }
394
395 BOOL
396 STDCALL
397 NtGdiArcTo(HDC hDC,
398 int LeftRect,
399 int TopRect,
400 int RightRect,
401 int BottomRect,
402 int XRadial1,
403 int YRadial1,
404 int XRadial2,
405 int YRadial2)
406 {
407 BOOL result;
408 DC *dc;
409
410 dc = DC_LockDc (hDC);
411 if(!dc)
412 {
413 SetLastWin32Error(ERROR_INVALID_HANDLE);
414 return FALSE;
415 }
416 if (dc->IsIC)
417 {
418 DC_UnlockDc(dc);
419 /* Yes, Windows really returns TRUE in this case */
420 return TRUE;
421 }
422
423 // Line from current position to starting point of arc
424 if ( !IntGdiLineTo(dc, XRadial1, YRadial1) )
425 {
426 DC_UnlockDc(dc);
427 return FALSE;
428 }
429
430 //dc = DC_LockDc(hDC);
431
432 //if(!dc) return FALSE;
433
434 // Then the arc is drawn.
435 result = IntGdiArc(dc, LeftRect, TopRect, RightRect, BottomRect,
436 XRadial1, YRadial1, XRadial2, YRadial2);
437
438 //DC_UnlockDc(dc);
439
440 // If no error occured, the current position is moved to the ending point of the arc.
441 if(result)
442 IntGdiMoveToEx(dc, XRadial2, YRadial2, NULL);
443
444 DC_UnlockDc(dc);
445
446 return result;
447 }
448
449 INT
450 STDCALL
451 NtGdiGetArcDirection(HDC hDC)
452 {
453 PDC dc = DC_LockDc (hDC);
454 int ret = 0; // default to failure
455
456 if ( dc )
457 {
458 ret = IntGdiGetArcDirection ( dc );
459 DC_UnlockDc(dc);
460 }
461 else
462 {
463 SetLastWin32Error(ERROR_INVALID_HANDLE);
464 }
465
466 return ret;
467 }
468
469 BOOL
470 STDCALL
471 NtGdiLineTo(HDC hDC,
472 int XEnd,
473 int YEnd)
474 {
475 DC *dc;
476 BOOL Ret;
477
478 dc = DC_LockDc(hDC);
479 if(!dc)
480 {
481 SetLastWin32Error(ERROR_INVALID_HANDLE);
482 return FALSE;
483 }
484 if (dc->IsIC)
485 {
486 DC_UnlockDc(dc);
487 /* Yes, Windows really returns TRUE in this case */
488 return TRUE;
489 }
490
491 Ret = IntGdiLineTo(dc, XEnd, YEnd);
492
493 DC_UnlockDc(dc);
494 return Ret;
495 }
496
497 BOOL
498 STDCALL
499 NtGdiMoveToEx(HDC hDC,
500 int X,
501 int Y,
502 LPPOINT Point)
503 {
504 DC *dc;
505 POINT SafePoint;
506 NTSTATUS Status;
507 BOOL Ret;
508
509 dc = DC_LockDc(hDC);
510 if(!dc)
511 {
512 SetLastWin32Error(ERROR_INVALID_HANDLE);
513 return FALSE;
514 }
515 if (dc->IsIC)
516 {
517 DC_UnlockDc(dc);
518 /* Yes, Windows really returns TRUE in this case */
519 return TRUE;
520 }
521
522 if(Point)
523 {
524 Status = MmCopyFromCaller(&SafePoint, Point, sizeof(POINT));
525 if(!NT_SUCCESS(Status))
526 {
527 DC_UnlockDc(dc);
528 SetLastNtError(Status);
529 return FALSE;
530 }
531 }
532
533 Ret = IntGdiMoveToEx(dc, X, Y, (Point ? &SafePoint : NULL));
534
535 DC_UnlockDc(dc);
536 return Ret;
537 }
538
539 BOOL
540 STDCALL
541 NtGdiPolyBezier(HDC hDC,
542 CONST LPPOINT pt,
543 DWORD Count)
544 {
545 DC *dc;
546 LPPOINT Safept;
547 NTSTATUS Status;
548 BOOL Ret;
549
550 dc = DC_LockDc(hDC);
551 if(!dc)
552 {
553 SetLastWin32Error(ERROR_INVALID_HANDLE);
554 return FALSE;
555 }
556 if (dc->IsIC)
557 {
558 DC_UnlockDc(dc);
559 /* Yes, Windows really returns TRUE in this case */
560 return TRUE;
561 }
562
563 if(Count > 0)
564 {
565 Safept = ExAllocatePoolWithTag(PagedPool, sizeof(POINT) * Count, TAG_BEZIER);
566 if(!Safept)
567 {
568 DC_UnlockDc(dc);
569 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
570 return FALSE;
571 }
572
573 Status = MmCopyFromCaller(Safept, pt, sizeof(POINT) * Count);
574 if(!NT_SUCCESS(Status))
575 {
576 DC_UnlockDc(dc);
577 SetLastNtError(Status);
578 return FALSE;
579 }
580 }
581 else
582 {
583 DC_UnlockDc(dc);
584 SetLastWin32Error(ERROR_INVALID_PARAMETER);
585 return FALSE;
586 }
587
588 Ret = IntGdiPolyBezier(dc, Safept, Count);
589
590 ExFreePool(Safept);
591 DC_UnlockDc(dc);
592
593 return Ret;
594 }
595
596 BOOL
597 STDCALL
598 NtGdiPolyBezierTo(HDC hDC,
599 CONST LPPOINT pt,
600 DWORD Count)
601 {
602 DC *dc;
603 LPPOINT Safept;
604 NTSTATUS Status;
605 BOOL Ret;
606
607 dc = DC_LockDc(hDC);
608 if(!dc)
609 {
610 SetLastWin32Error(ERROR_INVALID_HANDLE);
611 return FALSE;
612 }
613 if (dc->IsIC)
614 {
615 DC_UnlockDc(dc);
616 /* Yes, Windows really returns TRUE in this case */
617 return TRUE;
618 }
619
620 if(Count > 0)
621 {
622 Safept = ExAllocatePoolWithTag(PagedPool, sizeof(POINT) * Count, TAG_BEZIER);
623 if(!Safept)
624 {
625 DC_UnlockDc(dc);
626 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
627 return FALSE;
628 }
629
630 Status = MmCopyFromCaller(Safept, pt, sizeof(POINT) * Count);
631 if(!NT_SUCCESS(Status))
632 {
633 DC_UnlockDc(dc);
634 SetLastNtError(Status);
635 return FALSE;
636 }
637 }
638 else
639 {
640 DC_UnlockDc(dc);
641 SetLastWin32Error(ERROR_INVALID_PARAMETER);
642 return FALSE;
643 }
644
645 Ret = IntGdiPolyBezierTo(dc, Safept, Count);
646
647 ExFreePool(Safept);
648 DC_UnlockDc(dc);
649
650 return Ret;
651 }
652
653 BOOL
654 STDCALL
655 NtGdiPolyDraw(HDC hDC,
656 CONST LPPOINT pt,
657 CONST LPBYTE Types,
658 int Count)
659 {
660 UNIMPLEMENTED;
661 return FALSE;
662 }
663
664 BOOL
665 STDCALL
666 NtGdiPolyline(HDC hDC,
667 CONST LPPOINT pt,
668 int Count)
669 {
670 DC *dc;
671 LPPOINT Safept;
672 NTSTATUS Status;
673 BOOL Ret;
674
675 dc = DC_LockDc(hDC);
676 if(!dc)
677 {
678 SetLastWin32Error(ERROR_INVALID_HANDLE);
679 return FALSE;
680 }
681 if (dc->IsIC)
682 {
683 DC_UnlockDc(dc);
684 /* Yes, Windows really returns TRUE in this case */
685 return TRUE;
686 }
687
688 if(Count >= 2)
689 {
690 Safept = ExAllocatePoolWithTag(PagedPool, sizeof(POINT) * Count, TAG_SHAPE);
691 if(!Safept)
692 {
693 DC_UnlockDc(dc);
694 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
695 return FALSE;
696 }
697
698 Status = MmCopyFromCaller(Safept, pt, sizeof(POINT) * Count);
699 if(!NT_SUCCESS(Status))
700 {
701 DC_UnlockDc(dc);
702 SetLastNtError(Status);
703 return FALSE;
704 }
705 }
706 else
707 {
708 DC_UnlockDc(dc);
709 SetLastWin32Error(ERROR_INVALID_PARAMETER);
710 return FALSE;
711 }
712
713 Ret = IntGdiPolyline(dc, Safept, Count);
714
715 ExFreePool(Safept);
716 DC_UnlockDc(dc);
717
718 return Ret;
719 }
720
721 BOOL
722 STDCALL
723 NtGdiPolylineTo(HDC hDC,
724 CONST LPPOINT pt,
725 DWORD Count)
726 {
727 DC *dc;
728 LPPOINT Safept;
729 NTSTATUS Status;
730 BOOL Ret;
731
732 dc = DC_LockDc(hDC);
733 if(!dc)
734 {
735 SetLastWin32Error(ERROR_INVALID_HANDLE);
736 return FALSE;
737 }
738 if (dc->IsIC)
739 {
740 DC_UnlockDc(dc);
741 /* Yes, Windows really returns TRUE in this case */
742 return TRUE;
743 }
744
745 if(Count > 0)
746 {
747 Safept = ExAllocatePoolWithTag(PagedPool, sizeof(POINT) * Count, TAG_SHAPE);
748 if(!Safept)
749 {
750 DC_UnlockDc(dc);
751 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
752 return FALSE;
753 }
754
755 Status = MmCopyFromCaller(Safept, pt, sizeof(POINT) * Count);
756 if(!NT_SUCCESS(Status))
757 {
758 DC_UnlockDc(dc);
759 SetLastNtError(Status);
760 return FALSE;
761 }
762 }
763 else
764 {
765 DC_UnlockDc(dc);
766 SetLastWin32Error(ERROR_INVALID_PARAMETER);
767 return FALSE;
768 }
769
770 Ret = IntGdiPolylineTo(dc, Safept, Count);
771
772 ExFreePool(Safept);
773 DC_UnlockDc(dc);
774
775 return Ret;
776 }
777
778 BOOL
779 STDCALL
780 NtGdiPolyPolyline(HDC hDC,
781 CONST LPPOINT pt,
782 CONST LPDWORD PolyPoints,
783 DWORD Count)
784 {
785 DC *dc;
786 LPPOINT Safept;
787 LPDWORD SafePolyPoints;
788 NTSTATUS Status;
789 BOOL Ret;
790
791 dc = DC_LockDc(hDC);
792 if(!dc)
793 {
794 SetLastWin32Error(ERROR_INVALID_HANDLE);
795 return FALSE;
796 }
797 if (dc->IsIC)
798 {
799 DC_UnlockDc(dc);
800 /* Yes, Windows really returns TRUE in this case */
801 return TRUE;
802 }
803
804 if(Count > 0)
805 {
806 Safept = ExAllocatePoolWithTag(PagedPool, (sizeof(POINT) + sizeof(DWORD)) * Count, TAG_SHAPE);
807 if(!Safept)
808 {
809 DC_UnlockDc(dc);
810 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
811 return FALSE;
812 }
813
814 SafePolyPoints = (LPDWORD)&Safept[Count];
815
816 Status = MmCopyFromCaller(Safept, pt, sizeof(POINT) * Count);
817 if(!NT_SUCCESS(Status))
818 {
819 DC_UnlockDc(dc);
820 ExFreePool(Safept);
821 SetLastNtError(Status);
822 return FALSE;
823 }
824 Status = MmCopyFromCaller(SafePolyPoints, PolyPoints, sizeof(DWORD) * Count);
825 if(!NT_SUCCESS(Status))
826 {
827 DC_UnlockDc(dc);
828 ExFreePool(Safept);
829 SetLastNtError(Status);
830 return FALSE;
831 }
832 }
833 else
834 {
835 DC_UnlockDc(dc);
836 SetLastWin32Error(ERROR_INVALID_PARAMETER);
837 return FALSE;
838 }
839
840 Ret = IntGdiPolyPolyline(dc, Safept, SafePolyPoints, Count);
841
842 ExFreePool(Safept);
843 DC_UnlockDc(dc);
844
845 return Ret;
846 }
847
848 int
849 STDCALL
850 NtGdiSetArcDirection(HDC hDC,
851 int ArcDirection)
852 {
853 PDC dc;
854 INT nOldDirection = 0; // default to FAILURE
855
856 dc = DC_LockDc (hDC);
857 if ( !dc ) return 0;
858
859 if ( ArcDirection == AD_COUNTERCLOCKWISE || ArcDirection == AD_CLOCKWISE )
860 {
861 nOldDirection = dc->w.ArcDirection;
862 dc->w.ArcDirection = ArcDirection;
863 }
864
865 DC_UnlockDc( dc );
866 return nOldDirection;
867 }
868 /* EOF */