2 * PROJECT: ReactOS Win32k Subsystem
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: win32k/objects/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
,
26 PDC_ATTR pdcattr
= dc
->pdcattr
;
29 if ( pdcattr
->ulDirty_
& DIRTY_PTLCURRENT
) // Double hit!
31 Point
->x
= pdcattr
->ptfxCurrent
.x
; // ret prev before change.
32 Point
->y
= pdcattr
->ptfxCurrent
.y
;
33 IntDPtoLP ( dc
, Point
, 1); // reconvert back.
37 Point
->x
= pdcattr
->ptlCurrent
.x
;
38 Point
->y
= pdcattr
->ptlCurrent
.y
;
41 pdcattr
->ptlCurrent
.x
= X
;
42 pdcattr
->ptlCurrent
.y
= Y
;
43 pdcattr
->ptfxCurrent
= pdcattr
->ptlCurrent
;
44 CoordLPtoDP(dc
, &pdcattr
->ptfxCurrent
); // Update fx
45 pdcattr
->ulDirty_
&= ~(DIRTY_PTLCURRENT
|DIRTY_PTFXCURRENT
|DIRTY_STYLESTATE
);
47 if (BypassPath
) return TRUE
;
49 PathIsOpen
= PATH_IsPathOpen(dc
->dclevel
);
52 return PATH_MoveTo ( dc
);
57 // Should use Fx in pt
60 IntGetCurrentPositionEx(PDC dc
, LPPOINT pt
)
62 PDC_ATTR pdcattr
= dc
->pdcattr
;
66 if (pdcattr
->ulDirty_
& DIRTY_PTFXCURRENT
)
68 pdcattr
->ptfxCurrent
= pdcattr
->ptlCurrent
;
69 CoordLPtoDP(dc
, &pdcattr
->ptfxCurrent
); // Update fx
70 pdcattr
->ulDirty_
&= ~(DIRTY_PTFXCURRENT
|DIRTY_STYLESTATE
);
72 pt
->x
= pdcattr
->ptlCurrent
.x
;
73 pt
->y
= pdcattr
->ptlCurrent
.y
;
87 PDC_ATTR pdcattr
= dc
->pdcattr
;
89 if (PATH_IsPathOpen(dc
->dclevel
))
91 Ret
= PATH_LineTo(dc
, XEnd
, YEnd
);
94 // FIXME - PATH_LineTo should maybe do this? No
95 pdcattr
->ptlCurrent
.x
= XEnd
;
96 pdcattr
->ptlCurrent
.y
= YEnd
;
97 pdcattr
->ptfxCurrent
= pdcattr
->ptlCurrent
;
98 CoordLPtoDP(dc
, &pdcattr
->ptfxCurrent
); // Update fx
99 pdcattr
->ulDirty_
&= ~(DIRTY_PTLCURRENT
|DIRTY_PTFXCURRENT
|DIRTY_STYLESTATE
);
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
& GDIBRUSH_IS_NULL
))
136 Ret
= IntEngLineTo(&psurf
->SurfObj
,
137 dc
->rosdc
.CombinedClip
,
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 (PATH_IsPathOpen(dc
->dclevel
))
237 return PATH_Polyline(dc
, pt
, Count
);
239 DC_vPrepareDCsForBlit(dc
, dc
->rosdc
.CombinedClip
->rclBounds
,
240 NULL
, dc
->rosdc
.CombinedClip
->rclBounds
);
242 if (pdcattr
->ulDirty_
& (DIRTY_FILL
| DC_BRUSH_DIRTY
))
243 DC_vUpdateFillBrush(dc
);
245 if (pdcattr
->ulDirty_
& (DIRTY_LINE
| DC_PEN_DIRTY
))
246 DC_vUpdateLineBrush(dc
);
248 /* Get BRUSHOBJ from current pen. */
249 pbrLine
= dc
->dclevel
.pbrLine
;
252 if (!(pbrLine
->flAttrs
& GDIBRUSH_IS_NULL
))
254 Points
= EngAllocMem(0, Count
* sizeof(POINT
), GDITAG_TEMP
);
257 psurf
= dc
->dclevel
.pSurface
;
258 /* FIXME - psurf can be NULL!!!!
259 Don't assert but handle this case gracefully! */
262 RtlCopyMemory(Points
, pt
, Count
* sizeof(POINT
));
263 IntLPtoDP(dc
, Points
, Count
);
265 /* Offset the array of points by the DC origin */
266 for (i
= 0; i
< Count
; i
++)
268 Points
[i
].x
+= dc
->ptlDCOrig
.x
;
269 Points
[i
].y
+= dc
->ptlDCOrig
.y
;
272 Ret
= IntEngPolyline(&psurf
->SurfObj
,
273 dc
->rosdc
.CombinedClip
,
274 &dc
->eboLine
.BrushObject
,
277 ROP2_TO_MIX(pdcattr
->jROP2
));
287 DC_vFinishBlit(dc
, NULL
);
293 IntGdiPolylineTo(DC
*dc
,
297 BOOL ret
= FALSE
; // default to failure
298 PDC_ATTR pdcattr
= dc
->pdcattr
;
300 if (PATH_IsPathOpen(dc
->dclevel
))
302 ret
= PATH_PolylineTo(dc
, pt
, Count
);
304 else /* do it using Polyline */
306 POINT
*pts
= ExAllocatePoolWithTag(PagedPool
,
307 sizeof(POINT
) * (Count
+ 1),
311 pts
[0].x
= pdcattr
->ptlCurrent
.x
;
312 pts
[0].y
= pdcattr
->ptlCurrent
.y
;
313 memcpy( pts
+ 1, pt
, sizeof(POINT
) * Count
);
314 ret
= IntGdiPolyline(dc
, pts
, Count
+ 1);
315 ExFreePoolWithTag(pts
, TAG_SHAPE
);
320 pdcattr
->ptlCurrent
.x
= pt
[Count
-1].x
;
321 pdcattr
->ptlCurrent
.y
= pt
[Count
-1].y
;
322 pdcattr
->ptfxCurrent
= pdcattr
->ptlCurrent
;
323 CoordLPtoDP(dc
, &pdcattr
->ptfxCurrent
); // Update fx
324 pdcattr
->ulDirty_
&= ~(DIRTY_PTLCURRENT
|DIRTY_PTFXCURRENT
|DIRTY_STYLESTATE
);
332 IntGdiPolyPolyline(DC
*dc
,
340 BOOL ret
= FALSE
; // default to failure
344 if (PATH_IsPathOpen(dc
->dclevel
))
345 return PATH_PolyPolyline( dc
, pt
, PolyPoints
, Count
);
347 for (i
= 0; i
< Count
; i
++)
349 ret
= IntGdiPolyline ( dc
, pts
, *pc
);
360 /******************************************************************************/
375 EngSetLastError(ERROR_INVALID_HANDLE
);
378 if (dc
->dctype
== DC_TYPE_INFO
)
381 /* Yes, Windows really returns TRUE in this case */
385 rcLockRect
.left
= dc
->pdcattr
->ptlCurrent
.x
;
386 rcLockRect
.top
= dc
->pdcattr
->ptlCurrent
.y
;
387 rcLockRect
.right
= XEnd
;
388 rcLockRect
.bottom
= YEnd
;
390 IntLPtoDP(dc
, &rcLockRect
, 2);
392 /* The DCOrg is in device coordinates */
393 rcLockRect
.left
+= dc
->ptlDCOrig
.x
;
394 rcLockRect
.top
+= dc
->ptlDCOrig
.y
;
395 rcLockRect
.right
+= dc
->ptlDCOrig
.x
;
396 rcLockRect
.bottom
+= dc
->ptlDCOrig
.y
;
398 DC_vPrepareDCsForBlit(dc
, rcLockRect
, NULL
, rcLockRect
);
400 if (dc
->pdcattr
->ulDirty_
& (DIRTY_LINE
| DC_PEN_DIRTY
))
401 DC_vUpdateLineBrush(dc
);
403 Ret
= IntGdiLineTo(dc
, XEnd
, YEnd
);
405 DC_vFinishBlit(dc
, NULL
);
427 if (!dc
) return FALSE
;
428 pdcattr
= dc
->pdcattr
;
432 ProbeArrayForRead(lppt
, sizeof(POINT
), cCount
, sizeof(LONG
));
433 ProbeArrayForRead(lpbTypes
, sizeof(BYTE
), cCount
, sizeof(BYTE
));
435 /* check for each bezierto if there are two more points */
436 for ( i
= 0; i
< cCount
; i
++ )
438 if ( lpbTypes
[i
] != PT_MOVETO
&&
439 lpbTypes
[i
] & PT_BEZIERTO
)
441 if ( cCount
< i
+3 ) _SEH2_LEAVE
;
446 /* if no moveto occurs, we will close the figure here */
447 lastmove
.x
= pdcattr
->ptlCurrent
.x
;
448 lastmove
.y
= pdcattr
->ptlCurrent
.y
;
451 for ( i
= 0; i
< cCount
; i
++ )
453 if ( lpbTypes
[i
] == PT_MOVETO
)
455 IntGdiMoveToEx( dc
, lppt
[i
].x
, lppt
[i
].y
, NULL
, FALSE
);
456 lastmove
.x
= pdcattr
->ptlCurrent
.x
;
457 lastmove
.y
= pdcattr
->ptlCurrent
.y
;
459 else if ( lpbTypes
[i
] & PT_LINETO
)
460 IntGdiLineTo( dc
, lppt
[i
].x
, lppt
[i
].y
);
461 else if ( lpbTypes
[i
] & PT_BEZIERTO
)
464 pts
[0].x
= pdcattr
->ptlCurrent
.x
;
465 pts
[0].y
= pdcattr
->ptlCurrent
.y
;
466 RtlCopyMemory(pts
+ 1, &lppt
[i
], sizeof(POINT
) * 3);
467 IntGdiPolyBezier(dc
, pts
, 4);
472 if ( lpbTypes
[i
] & PT_CLOSEFIGURE
)
474 if ( PATH_IsPathOpen(dc
->dclevel
) )
476 pPath
= PATH_LockPath( dc
->dclevel
.hPath
);
479 IntGdiCloseFigure( pPath
);
480 PATH_UnlockPath( pPath
);
483 else IntGdiLineTo( dc
, lastmove
.x
, lastmove
.y
);
489 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
491 SetLastNtError(_SEH2_GetExceptionCode());
509 OUT OPTIONAL LPPOINT pptOut
)