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
);
64 if (!(dc
= DC_LockDc(hdc
)))
66 EngSetLastError(ERROR_INVALID_HANDLE
);
69 return IntGdiMoveToEx(dc
, x
, y
, pptOut
, TRUE
);
72 // Should use Fx in pt
75 IntGetCurrentPositionEx(PDC dc
, LPPOINT pt
)
77 PDC_ATTR pdcattr
= dc
->pdcattr
;
81 if (pdcattr
->ulDirty_
& DIRTY_PTFXCURRENT
)
83 pdcattr
->ptfxCurrent
= pdcattr
->ptlCurrent
;
84 CoordLPtoDP(dc
, &pdcattr
->ptfxCurrent
); // Update fx
85 pdcattr
->ulDirty_
&= ~(DIRTY_PTFXCURRENT
|DIRTY_STYLESTATE
);
87 pt
->x
= pdcattr
->ptlCurrent
.x
;
88 pt
->y
= pdcattr
->ptlCurrent
.y
;
102 PDC_ATTR pdcattr
= dc
->pdcattr
;
104 if (PATH_IsPathOpen(dc
->dclevel
))
106 Ret
= PATH_LineTo(dc
, XEnd
, YEnd
);
109 // FIXME: PATH_LineTo should maybe do this? No
110 pdcattr
->ptlCurrent
.x
= XEnd
;
111 pdcattr
->ptlCurrent
.y
= YEnd
;
112 pdcattr
->ptfxCurrent
= pdcattr
->ptlCurrent
;
113 CoordLPtoDP(dc
, &pdcattr
->ptfxCurrent
); // Update fx
114 pdcattr
->ulDirty_
&= ~(DIRTY_PTLCURRENT
|DIRTY_PTFXCURRENT
|DIRTY_STYLESTATE
);
120 psurf
= dc
->dclevel
.pSurface
;
123 EngSetLastError(ERROR_INVALID_HANDLE
);
127 Points
[0].x
= pdcattr
->ptlCurrent
.x
;
128 Points
[0].y
= pdcattr
->ptlCurrent
.y
;
132 IntLPtoDP(dc
, Points
, 2);
134 /* The DCOrg is in device coordinates */
135 Points
[0].x
+= dc
->ptlDCOrig
.x
;
136 Points
[0].y
+= dc
->ptlDCOrig
.y
;
137 Points
[1].x
+= dc
->ptlDCOrig
.x
;
138 Points
[1].y
+= dc
->ptlDCOrig
.y
;
140 Bounds
.left
= min(Points
[0].x
, Points
[1].x
);
141 Bounds
.top
= min(Points
[0].y
, Points
[1].y
);
142 Bounds
.right
= max(Points
[0].x
, Points
[1].x
);
143 Bounds
.bottom
= max(Points
[0].y
, Points
[1].y
);
145 /* Get BRUSH from current pen. */
146 pbrLine
= dc
->dclevel
.pbrLine
;
149 if (!(pbrLine
->flAttrs
& BR_IS_NULL
))
151 Ret
= IntEngLineTo(&psurf
->SurfObj
,
152 dc
->rosdc
.CombinedClip
,
153 &dc
->eboLine
.BrushObject
,
154 Points
[0].x
, Points
[0].y
,
155 Points
[1].x
, Points
[1].y
,
157 ROP2_TO_MIX(pdcattr
->jROP2
));
164 pdcattr
->ptlCurrent
.x
= XEnd
;
165 pdcattr
->ptlCurrent
.y
= YEnd
;
166 pdcattr
->ptfxCurrent
= pdcattr
->ptlCurrent
;
167 CoordLPtoDP(dc
, &pdcattr
->ptfxCurrent
); // Update fx
168 pdcattr
->ulDirty_
&= ~(DIRTY_PTLCURRENT
|DIRTY_PTFXCURRENT
|DIRTY_STYLESTATE
);
175 IntGdiPolyBezier(DC
*dc
,
179 BOOL ret
= FALSE
; // Default to FAILURE
181 if ( PATH_IsPathOpen(dc
->dclevel
) )
183 return PATH_PolyBezier ( dc
, pt
, Count
);
186 /* We'll convert it into line segments and draw them using Polyline */
191 Pts
= GDI_Bezier ( pt
, Count
, &nOut
);
194 ret
= IntGdiPolyline(dc
, Pts
, nOut
);
195 ExFreePoolWithTag(Pts
, TAG_BEZIER
);
203 IntGdiPolyBezierTo(DC
*dc
,
207 BOOL ret
= FALSE
; // Default to failure
208 PDC_ATTR pdcattr
= dc
->pdcattr
;
210 if ( PATH_IsPathOpen(dc
->dclevel
) )
211 ret
= PATH_PolyBezierTo ( dc
, pt
, Count
);
212 else /* We'll do it using PolyBezier */
215 npt
= ExAllocatePoolWithTag(PagedPool
,
216 sizeof(POINT
) * (Count
+ 1),
220 npt
[0].x
= pdcattr
->ptlCurrent
.x
;
221 npt
[0].y
= pdcattr
->ptlCurrent
.y
;
222 memcpy(npt
+ 1, pt
, sizeof(POINT
) * Count
);
223 ret
= IntGdiPolyBezier(dc
, npt
, Count
+1);
224 ExFreePoolWithTag(npt
, TAG_BEZIER
);
229 pdcattr
->ptlCurrent
.x
= pt
[Count
-1].x
;
230 pdcattr
->ptlCurrent
.y
= pt
[Count
-1].y
;
231 pdcattr
->ptfxCurrent
= pdcattr
->ptlCurrent
;
232 CoordLPtoDP(dc
, &pdcattr
->ptfxCurrent
); // Update fx
233 pdcattr
->ulDirty_
&= ~(DIRTY_PTLCURRENT
|DIRTY_PTFXCURRENT
|DIRTY_STYLESTATE
);
240 IntGdiPolyline(DC
*dc
,
249 PDC_ATTR pdcattr
= dc
->pdcattr
;
251 psurf
= dc
->dclevel
.pSurface
;
257 if (PATH_IsPathOpen(dc
->dclevel
))
258 return PATH_Polyline(dc
, pt
, Count
);
260 DC_vPrepareDCsForBlit(dc
, dc
->rosdc
.CombinedClip
->rclBounds
,
261 NULL
, dc
->rosdc
.CombinedClip
->rclBounds
);
263 if (pdcattr
->ulDirty_
& (DIRTY_FILL
| DC_BRUSH_DIRTY
))
264 DC_vUpdateFillBrush(dc
);
266 if (pdcattr
->ulDirty_
& (DIRTY_LINE
| DC_PEN_DIRTY
))
267 DC_vUpdateLineBrush(dc
);
269 /* Get BRUSHOBJ from current pen. */
270 pbrLine
= dc
->dclevel
.pbrLine
;
273 if (!(pbrLine
->flAttrs
& BR_IS_NULL
))
275 Points
= EngAllocMem(0, Count
* sizeof(POINT
), GDITAG_TEMP
);
278 RtlCopyMemory(Points
, pt
, Count
* sizeof(POINT
));
279 IntLPtoDP(dc
, Points
, Count
);
281 /* Offset the array of points by the DC origin */
282 for (i
= 0; i
< Count
; i
++)
284 Points
[i
].x
+= dc
->ptlDCOrig
.x
;
285 Points
[i
].y
+= dc
->ptlDCOrig
.y
;
288 Ret
= IntEngPolyline(&psurf
->SurfObj
,
289 dc
->rosdc
.CombinedClip
,
290 &dc
->eboLine
.BrushObject
,
293 ROP2_TO_MIX(pdcattr
->jROP2
));
303 DC_vFinishBlit(dc
, NULL
);
309 IntGdiPolylineTo(DC
*dc
,
313 BOOL ret
= FALSE
; // Default to failure
314 PDC_ATTR pdcattr
= dc
->pdcattr
;
316 if (PATH_IsPathOpen(dc
->dclevel
))
318 ret
= PATH_PolylineTo(dc
, pt
, Count
);
320 else /* Do it using Polyline */
322 POINT
*pts
= ExAllocatePoolWithTag(PagedPool
,
323 sizeof(POINT
) * (Count
+ 1),
327 pts
[0].x
= pdcattr
->ptlCurrent
.x
;
328 pts
[0].y
= pdcattr
->ptlCurrent
.y
;
329 memcpy( pts
+ 1, pt
, sizeof(POINT
) * Count
);
330 ret
= IntGdiPolyline(dc
, pts
, Count
+ 1);
331 ExFreePoolWithTag(pts
, TAG_SHAPE
);
336 pdcattr
->ptlCurrent
.x
= pt
[Count
-1].x
;
337 pdcattr
->ptlCurrent
.y
= pt
[Count
-1].y
;
338 pdcattr
->ptfxCurrent
= pdcattr
->ptlCurrent
;
339 CoordLPtoDP(dc
, &pdcattr
->ptfxCurrent
); // Update fx
340 pdcattr
->ulDirty_
&= ~(DIRTY_PTLCURRENT
|DIRTY_PTFXCURRENT
|DIRTY_STYLESTATE
);
348 IntGdiPolyPolyline(DC
*dc
,
356 BOOL ret
= FALSE
; // Default to failure
360 if (PATH_IsPathOpen(dc
->dclevel
))
361 return PATH_PolyPolyline( dc
, pt
, PolyPoints
, Count
);
363 for (i
= 0; i
< Count
; i
++)
365 ret
= IntGdiPolyline ( dc
, pts
, *pc
);
376 /******************************************************************************/
391 EngSetLastError(ERROR_INVALID_HANDLE
);
394 if (dc
->dctype
== DC_TYPE_INFO
)
397 /* Yes, Windows really returns TRUE in this case */
401 rcLockRect
.left
= dc
->pdcattr
->ptlCurrent
.x
;
402 rcLockRect
.top
= dc
->pdcattr
->ptlCurrent
.y
;
403 rcLockRect
.right
= XEnd
;
404 rcLockRect
.bottom
= YEnd
;
406 IntLPtoDP(dc
, &rcLockRect
, 2);
408 /* The DCOrg is in device coordinates */
409 rcLockRect
.left
+= dc
->ptlDCOrig
.x
;
410 rcLockRect
.top
+= dc
->ptlDCOrig
.y
;
411 rcLockRect
.right
+= dc
->ptlDCOrig
.x
;
412 rcLockRect
.bottom
+= dc
->ptlDCOrig
.y
;
414 DC_vPrepareDCsForBlit(dc
, rcLockRect
, NULL
, rcLockRect
);
416 if (dc
->pdcattr
->ulDirty_
& (DIRTY_LINE
| DC_PEN_DIRTY
))
417 DC_vUpdateLineBrush(dc
);
419 Ret
= IntGdiLineTo(dc
, XEnd
, YEnd
);
421 DC_vFinishBlit(dc
, NULL
);
427 // FIXME: This function is completely broken
439 volatile PPOINT line_pts
, line_pts_old
, bzr_pts
;
440 INT num_pts
, num_bzr_pts
, space
, space_old
, size
;
445 if (!dc
) return FALSE
;
446 pdcattr
= dc
->pdcattr
;
448 if (pdcattr
->ulDirty_
& (DIRTY_FILL
| DC_BRUSH_DIRTY
))
449 DC_vUpdateFillBrush(dc
);
451 if (pdcattr
->ulDirty_
& (DIRTY_LINE
| DC_PEN_DIRTY
))
452 DC_vUpdateLineBrush(dc
);
466 ProbeArrayForRead(lppt
, sizeof(POINT
), cCount
, sizeof(LONG
));
467 ProbeArrayForRead(lpbTypes
, sizeof(BYTE
), cCount
, sizeof(BYTE
));
469 if (PATH_IsPathOpen(dc
->dclevel
))
471 result
= PATH_PolyDraw(dc
, (const POINT
*)lppt
, (const BYTE
*)lpbTypes
, cCount
);
475 /* Check for valid point types */
476 for (i
= 0; i
< cCount
; i
++)
481 case PT_LINETO
| PT_CLOSEFIGURE
:
485 if((i
+ 2 < cCount
) && (lpbTypes
[i
+ 1] == PT_BEZIERTO
) &&
486 ((lpbTypes
[i
+ 2] & ~PT_CLOSEFIGURE
) == PT_BEZIERTO
))
496 space
= cCount
+ 300;
497 line_pts
= ExAllocatePoolWithTag(PagedPool
, space
* sizeof(POINT
), TAG_SHAPE
);
498 if (line_pts
== NULL
)
506 line_pts
[0].x
= pdcattr
->ptlCurrent
.x
;
507 line_pts
[0].y
= pdcattr
->ptlCurrent
.y
;
509 for ( i
= 0; i
< cCount
; i
++ )
514 if (num_pts
>= 2) IntGdiPolyline( dc
, line_pts
, num_pts
);
516 line_pts
[num_pts
++] = lppt
[i
];
519 case (PT_LINETO
| PT_CLOSEFIGURE
):
520 line_pts
[num_pts
++] = lppt
[i
];
523 bzr
[0].x
= line_pts
[num_pts
- 1].x
;
524 bzr
[0].y
= line_pts
[num_pts
- 1].y
;
525 RtlCopyMemory( &bzr
[1], &lppt
[i
], 3 * sizeof(POINT
) );
527 if ((bzr_pts
= GDI_Bezier( bzr
, 4, &num_bzr_pts
)))
529 size
= num_pts
+ (cCount
- i
) + num_bzr_pts
;
534 line_pts_old
= line_pts
;
535 line_pts
= ExAllocatePoolWithTag(PagedPool
, space
* sizeof(POINT
), TAG_SHAPE
);
536 if (!line_pts
) _SEH2_LEAVE
;
537 RtlCopyMemory(line_pts
, line_pts_old
, space_old
* sizeof(POINT
));
538 ExFreePoolWithTag(line_pts_old
, TAG_SHAPE
);
541 RtlCopyMemory( &line_pts
[num_pts
], &bzr_pts
[1], (num_bzr_pts
- 1) * sizeof(POINT
) );
542 num_pts
+= num_bzr_pts
- 1;
543 ExFreePoolWithTag(bzr_pts
, TAG_BEZIER
);
549 if (lpbTypes
[i
] & PT_CLOSEFIGURE
) line_pts
[num_pts
++] = line_pts
[0];
552 if (num_pts
>= 2) IntGdiPolyline( dc
, line_pts
, num_pts
);
553 IntGdiMoveToEx( dc
, line_pts
[num_pts
- 1].x
, line_pts
[num_pts
- 1].y
, NULL
, TRUE
);
556 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
558 SetLastNtError(_SEH2_GetExceptionCode());
562 if (line_pts
!= NULL
)
564 ExFreePoolWithTag(line_pts
, TAG_SHAPE
);
567 if ((line_pts_old
!= NULL
) && (line_pts_old
!= line_pts
))
569 ExFreePoolWithTag(line_pts_old
, TAG_SHAPE
);
574 ExFreePoolWithTag(bzr_pts
, TAG_BEZIER
);
585 _Success_(return != FALSE
)
592 OUT OPTIONAL LPPOINT pptOut
)
598 pdc
= DC_LockDc(hdc
);
599 if (!pdc
) return FALSE
;
601 Ret
= IntGdiMoveToEx(pdc
, x
, y
, &Point
, TRUE
);
607 ProbeForWrite(pptOut
, sizeof(POINT
), 1);
608 RtlCopyMemory(pptOut
, &Point
, sizeof(POINT
));
610 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
612 SetLastNtError(_SEH2_GetExceptionCode());
613 Ret
= FALSE
; // CHECKME: is this correct?