2 * PROJECT: ReactOS Win32k Subsystem
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: win32ss/gdi/ntgdi/line.c
5 * PURPOSE: Line functions
14 // Some code from the WINE project source (www.winehq.com)
16 // Should use Fx in Point
19 IntGdiMoveToEx(DC
*dc
,
24 PDC_ATTR pdcattr
= dc
->pdcattr
;
27 if ( pdcattr
->ulDirty_
& DIRTY_PTLCURRENT
) // Double hit!
29 Point
->x
= pdcattr
->ptfxCurrent
.x
; // ret prev before change.
30 Point
->y
= pdcattr
->ptfxCurrent
.y
;
31 IntDPtoLP ( dc
, Point
, 1); // Reconvert back.
35 Point
->x
= pdcattr
->ptlCurrent
.x
;
36 Point
->y
= pdcattr
->ptlCurrent
.y
;
39 pdcattr
->ptlCurrent
.x
= X
;
40 pdcattr
->ptlCurrent
.y
= Y
;
41 pdcattr
->ptfxCurrent
= pdcattr
->ptlCurrent
;
42 CoordLPtoDP(dc
, &pdcattr
->ptfxCurrent
); // Update fx
43 pdcattr
->ulDirty_
&= ~(DIRTY_PTLCURRENT
|DIRTY_PTFXCURRENT
|DIRTY_STYLESTATE
);
56 if (!(dc
= DC_LockDc(hdc
)))
58 EngSetLastError(ERROR_INVALID_HANDLE
);
61 Ret
= IntGdiMoveToEx(dc
, x
, y
, pptOut
);
66 // Should use Fx in pt
69 IntGetCurrentPositionEx(PDC dc
, LPPOINT pt
)
71 PDC_ATTR pdcattr
= dc
->pdcattr
;
75 if (pdcattr
->ulDirty_
& DIRTY_PTFXCURRENT
)
77 pdcattr
->ptfxCurrent
= pdcattr
->ptlCurrent
;
78 CoordLPtoDP(dc
, &pdcattr
->ptfxCurrent
); // Update fx
79 pdcattr
->ulDirty_
&= ~(DIRTY_PTFXCURRENT
|DIRTY_STYLESTATE
);
81 pt
->x
= pdcattr
->ptlCurrent
.x
;
82 pt
->y
= pdcattr
->ptlCurrent
.y
;
96 PDC_ATTR pdcattr
= dc
->pdcattr
;
97 ASSERT_DC_PREPARED(dc
);
99 if (PATH_IsPathOpen(dc
->dclevel
))
101 Ret
= PATH_LineTo(dc
, XEnd
, YEnd
);
105 psurf
= dc
->dclevel
.pSurface
;
108 EngSetLastError(ERROR_INVALID_HANDLE
);
112 Points
[0].x
= pdcattr
->ptlCurrent
.x
;
113 Points
[0].y
= pdcattr
->ptlCurrent
.y
;
117 IntLPtoDP(dc
, Points
, 2);
119 /* The DCOrg is in device coordinates */
120 Points
[0].x
+= dc
->ptlDCOrig
.x
;
121 Points
[0].y
+= dc
->ptlDCOrig
.y
;
122 Points
[1].x
+= dc
->ptlDCOrig
.x
;
123 Points
[1].y
+= dc
->ptlDCOrig
.y
;
125 Bounds
.left
= min(Points
[0].x
, Points
[1].x
);
126 Bounds
.top
= min(Points
[0].y
, Points
[1].y
);
127 Bounds
.right
= max(Points
[0].x
, Points
[1].x
);
128 Bounds
.bottom
= max(Points
[0].y
, Points
[1].y
);
130 /* Get BRUSH from current pen. */
131 pbrLine
= dc
->dclevel
.pbrLine
;
134 if (!(pbrLine
->flAttrs
& BR_IS_NULL
))
136 Ret
= IntEngLineTo(&psurf
->SurfObj
,
138 &dc
->eboLine
.BrushObject
,
139 Points
[0].x
, Points
[0].y
,
140 Points
[1].x
, Points
[1].y
,
142 ROP2_TO_MIX(pdcattr
->jROP2
));
149 pdcattr
->ptlCurrent
.x
= XEnd
;
150 pdcattr
->ptlCurrent
.y
= YEnd
;
151 pdcattr
->ptfxCurrent
= pdcattr
->ptlCurrent
;
152 CoordLPtoDP(dc
, &pdcattr
->ptfxCurrent
); // Update fx
153 pdcattr
->ulDirty_
&= ~(DIRTY_PTLCURRENT
|DIRTY_PTFXCURRENT
|DIRTY_STYLESTATE
);
160 IntGdiPolyBezier(DC
*dc
,
164 BOOL ret
= FALSE
; // Default to FAILURE
166 if ( PATH_IsPathOpen(dc
->dclevel
) )
168 return PATH_PolyBezier ( dc
, pt
, Count
);
171 /* We'll convert it into line segments and draw them using Polyline */
176 Pts
= GDI_Bezier ( pt
, Count
, &nOut
);
179 ret
= IntGdiPolyline(dc
, Pts
, nOut
);
180 ExFreePoolWithTag(Pts
, TAG_BEZIER
);
188 IntGdiPolyBezierTo(DC
*dc
,
192 BOOL ret
= FALSE
; // Default to failure
193 PDC_ATTR pdcattr
= dc
->pdcattr
;
195 if ( PATH_IsPathOpen(dc
->dclevel
) )
196 ret
= PATH_PolyBezierTo ( dc
, pt
, Count
);
197 else /* We'll do it using PolyBezier */
200 npt
= ExAllocatePoolWithTag(PagedPool
,
201 sizeof(POINT
) * (Count
+ 1),
205 npt
[0].x
= pdcattr
->ptlCurrent
.x
;
206 npt
[0].y
= pdcattr
->ptlCurrent
.y
;
207 memcpy(npt
+ 1, pt
, sizeof(POINT
) * Count
);
208 ret
= IntGdiPolyBezier(dc
, npt
, Count
+1);
209 ExFreePoolWithTag(npt
, TAG_BEZIER
);
214 pdcattr
->ptlCurrent
.x
= pt
[Count
-1].x
;
215 pdcattr
->ptlCurrent
.y
= pt
[Count
-1].y
;
216 pdcattr
->ptfxCurrent
= pdcattr
->ptlCurrent
;
217 CoordLPtoDP(dc
, &pdcattr
->ptfxCurrent
); // Update fx
218 pdcattr
->ulDirty_
&= ~(DIRTY_PTLCURRENT
|DIRTY_PTFXCURRENT
|DIRTY_STYLESTATE
);
225 IntGdiPolyline(DC
*dc
,
234 PDC_ATTR pdcattr
= dc
->pdcattr
;
236 if (!dc
->dclevel
.pSurface
)
241 DC_vPrepareDCsForBlit(dc
, NULL
, NULL
, NULL
);
242 psurf
= dc
->dclevel
.pSurface
;
244 /* Get BRUSHOBJ from current pen. */
245 pbrLine
= dc
->dclevel
.pbrLine
;
248 if (!(pbrLine
->flAttrs
& BR_IS_NULL
))
250 Points
= EngAllocMem(0, Count
* sizeof(POINT
), GDITAG_TEMP
);
253 RtlCopyMemory(Points
, pt
, Count
* sizeof(POINT
));
254 IntLPtoDP(dc
, Points
, Count
);
256 /* Offset the array of points by the DC origin */
257 for (i
= 0; i
< Count
; i
++)
259 Points
[i
].x
+= dc
->ptlDCOrig
.x
;
260 Points
[i
].y
+= dc
->ptlDCOrig
.y
;
263 Ret
= IntEngPolyline(&psurf
->SurfObj
,
265 &dc
->eboLine
.BrushObject
,
268 ROP2_TO_MIX(pdcattr
->jROP2
));
278 DC_vFinishBlit(dc
, NULL
);
284 IntGdiPolylineTo(DC
*dc
,
288 BOOL ret
= FALSE
; // Default to failure
289 PDC_ATTR pdcattr
= dc
->pdcattr
;
291 if (PATH_IsPathOpen(dc
->dclevel
))
293 ret
= PATH_PolylineTo(dc
, pt
, Count
);
295 else /* Do it using Polyline */
297 POINT
*pts
= ExAllocatePoolWithTag(PagedPool
,
298 sizeof(POINT
) * (Count
+ 1),
302 pts
[0].x
= pdcattr
->ptlCurrent
.x
;
303 pts
[0].y
= pdcattr
->ptlCurrent
.y
;
304 memcpy( pts
+ 1, pt
, sizeof(POINT
) * Count
);
305 ret
= IntGdiPolyline(dc
, pts
, Count
+ 1);
306 ExFreePoolWithTag(pts
, TAG_SHAPE
);
311 pdcattr
->ptlCurrent
.x
= pt
[Count
-1].x
;
312 pdcattr
->ptlCurrent
.y
= pt
[Count
-1].y
;
313 pdcattr
->ptfxCurrent
= pdcattr
->ptlCurrent
;
314 CoordLPtoDP(dc
, &pdcattr
->ptfxCurrent
); // Update fx
315 pdcattr
->ulDirty_
&= ~(DIRTY_PTLCURRENT
|DIRTY_PTFXCURRENT
|DIRTY_STYLESTATE
);
323 IntGdiPolyPolyline(DC
*dc
,
331 BOOL ret
= FALSE
; // Default to failure
335 if (PATH_IsPathOpen(dc
->dclevel
))
337 return PATH_PolyPolyline( dc
, pt
, PolyPoints
, Count
);
339 for (i
= 0; i
< Count
; i
++)
341 ret
= IntGdiPolyline ( dc
, pts
, *pc
);
352 /******************************************************************************/
367 EngSetLastError(ERROR_INVALID_HANDLE
);
370 if (dc
->dctype
== DC_TYPE_INFO
)
373 /* Yes, Windows really returns TRUE in this case */
377 rcLockRect
.left
= dc
->pdcattr
->ptlCurrent
.x
;
378 rcLockRect
.top
= dc
->pdcattr
->ptlCurrent
.y
;
379 rcLockRect
.right
= XEnd
;
380 rcLockRect
.bottom
= YEnd
;
382 IntLPtoDP(dc
, &rcLockRect
, 2);
384 /* The DCOrg is in device coordinates */
385 rcLockRect
.left
+= dc
->ptlDCOrig
.x
;
386 rcLockRect
.top
+= dc
->ptlDCOrig
.y
;
387 rcLockRect
.right
+= dc
->ptlDCOrig
.x
;
388 rcLockRect
.bottom
+= dc
->ptlDCOrig
.y
;
390 DC_vPrepareDCsForBlit(dc
, &rcLockRect
, NULL
, NULL
);
392 Ret
= IntGdiLineTo(dc
, XEnd
, YEnd
);
394 DC_vFinishBlit(dc
, NULL
);
400 // FIXME: This function is completely broken
412 volatile PPOINT line_pts
, line_pts_old
, bzr_pts
;
413 INT num_pts
, num_bzr_pts
, space
, space_old
, size
;
418 if (!dc
) return FALSE
;
419 pdcattr
= dc
->pdcattr
;
421 if (pdcattr
->ulDirty_
& (DIRTY_FILL
| DC_BRUSH_DIRTY
))
422 DC_vUpdateFillBrush(dc
);
424 if (pdcattr
->ulDirty_
& (DIRTY_LINE
| DC_PEN_DIRTY
))
425 DC_vUpdateLineBrush(dc
);
439 ProbeArrayForRead(lppt
, sizeof(POINT
), cCount
, sizeof(LONG
));
440 ProbeArrayForRead(lpbTypes
, sizeof(BYTE
), cCount
, sizeof(BYTE
));
442 if (PATH_IsPathOpen(dc
->dclevel
))
444 result
= PATH_PolyDraw(dc
, (const POINT
*)lppt
, (const BYTE
*)lpbTypes
, cCount
);
448 /* Check for valid point types */
449 for (i
= 0; i
< cCount
; i
++)
454 case PT_LINETO
| PT_CLOSEFIGURE
:
458 if((i
+ 2 < cCount
) && (lpbTypes
[i
+ 1] == PT_BEZIERTO
) &&
459 ((lpbTypes
[i
+ 2] & ~PT_CLOSEFIGURE
) == PT_BEZIERTO
))
469 space
= cCount
+ 300;
470 line_pts
= ExAllocatePoolWithTag(PagedPool
, space
* sizeof(POINT
), TAG_SHAPE
);
471 if (line_pts
== NULL
)
479 line_pts
[0].x
= pdcattr
->ptlCurrent
.x
;
480 line_pts
[0].y
= pdcattr
->ptlCurrent
.y
;
482 for ( i
= 0; i
< cCount
; i
++ )
487 if (num_pts
>= 2) IntGdiPolyline( dc
, line_pts
, num_pts
);
489 line_pts
[num_pts
++] = lppt
[i
];
492 case (PT_LINETO
| PT_CLOSEFIGURE
):
493 line_pts
[num_pts
++] = lppt
[i
];
496 bzr
[0].x
= line_pts
[num_pts
- 1].x
;
497 bzr
[0].y
= line_pts
[num_pts
- 1].y
;
498 RtlCopyMemory( &bzr
[1], &lppt
[i
], 3 * sizeof(POINT
) );
500 if ((bzr_pts
= GDI_Bezier( bzr
, 4, &num_bzr_pts
)))
502 size
= num_pts
+ (cCount
- i
) + num_bzr_pts
;
507 line_pts_old
= line_pts
;
508 line_pts
= ExAllocatePoolWithTag(PagedPool
, space
* sizeof(POINT
), TAG_SHAPE
);
509 if (!line_pts
) _SEH2_LEAVE
;
510 RtlCopyMemory(line_pts
, line_pts_old
, space_old
* sizeof(POINT
));
511 ExFreePoolWithTag(line_pts_old
, TAG_SHAPE
);
514 RtlCopyMemory( &line_pts
[num_pts
], &bzr_pts
[1], (num_bzr_pts
- 1) * sizeof(POINT
) );
515 num_pts
+= num_bzr_pts
- 1;
516 ExFreePoolWithTag(bzr_pts
, TAG_BEZIER
);
522 if (lpbTypes
[i
] & PT_CLOSEFIGURE
) line_pts
[num_pts
++] = line_pts
[0];
525 if (num_pts
>= 2) IntGdiPolyline( dc
, line_pts
, num_pts
);
526 IntGdiMoveToEx( dc
, line_pts
[num_pts
- 1].x
, line_pts
[num_pts
- 1].y
, NULL
);
529 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
531 SetLastNtError(_SEH2_GetExceptionCode());
535 if (line_pts
!= NULL
)
537 ExFreePoolWithTag(line_pts
, TAG_SHAPE
);
540 if ((line_pts_old
!= NULL
) && (line_pts_old
!= line_pts
))
542 ExFreePoolWithTag(line_pts_old
, TAG_SHAPE
);
547 ExFreePoolWithTag(bzr_pts
, TAG_BEZIER
);
558 _Success_(return != FALSE
)
565 OUT OPTIONAL LPPOINT pptOut
)
571 pdc
= DC_LockDc(hdc
);
572 if (!pdc
) return FALSE
;
574 Ret
= IntGdiMoveToEx(pdc
, x
, y
, &Point
);
580 ProbeForWrite(pptOut
, sizeof(POINT
), 1);
581 RtlCopyMemory(pptOut
, &Point
, sizeof(POINT
));
583 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
585 SetLastNtError(_SEH2_GetExceptionCode());
586 Ret
= FALSE
; // CHECKME: is this correct?