[WIN32K]
[reactos.git] / subsystems / win32 / 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 along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 // Should use Fx in Point
28 //
29 BOOL FASTCALL
30 IntGdiMoveToEx(DC *dc,
31 int X,
32 int Y,
33 LPPOINT Point,
34 BOOL BypassPath)
35 {
36 BOOL PathIsOpen;
37 PDC_ATTR pdcattr = dc->pdcattr;
38 if ( Point )
39 {
40 if ( pdcattr->ulDirty_ & DIRTY_PTLCURRENT ) // Double hit!
41 {
42 Point->x = pdcattr->ptfxCurrent.x; // ret prev before change.
43 Point->y = pdcattr->ptfxCurrent.y;
44 IntDPtoLP ( dc, Point, 1); // reconvert back.
45 }
46 else
47 {
48 Point->x = pdcattr->ptlCurrent.x;
49 Point->y = pdcattr->ptlCurrent.y;
50 }
51 }
52 pdcattr->ptlCurrent.x = X;
53 pdcattr->ptlCurrent.y = Y;
54 pdcattr->ptfxCurrent = pdcattr->ptlCurrent;
55 CoordLPtoDP(dc, &pdcattr->ptfxCurrent); // Update fx
56 pdcattr->ulDirty_ &= ~(DIRTY_PTLCURRENT|DIRTY_PTFXCURRENT|DIRTY_STYLESTATE);
57
58 if (BypassPath) return TRUE;
59
60 PathIsOpen = PATH_IsPathOpen(dc->dclevel);
61
62 if ( PathIsOpen )
63 return PATH_MoveTo ( dc );
64
65 return TRUE;
66 }
67
68 // Should use Fx in pt
69 //
70 VOID FASTCALL
71 IntGetCurrentPositionEx(PDC dc, LPPOINT pt)
72 {
73 PDC_ATTR pdcattr = dc->pdcattr;
74
75 if ( pt )
76 {
77 if (pdcattr->ulDirty_ & DIRTY_PTFXCURRENT)
78 {
79 pdcattr->ptfxCurrent = pdcattr->ptlCurrent;
80 CoordLPtoDP(dc, &pdcattr->ptfxCurrent); // Update fx
81 pdcattr->ulDirty_ &= ~(DIRTY_PTFXCURRENT|DIRTY_STYLESTATE);
82 }
83 pt->x = pdcattr->ptlCurrent.x;
84 pt->y = pdcattr->ptlCurrent.y;
85 }
86 }
87
88 BOOL FASTCALL
89 IntGdiLineTo(DC *dc,
90 int XEnd,
91 int YEnd)
92 {
93 SURFACE *psurf;
94 BOOL Ret = TRUE;
95 PBRUSH pbrLine;
96 RECTL Bounds;
97 POINT Points[2];
98 PDC_ATTR pdcattr = dc->pdcattr;
99
100 if (PATH_IsPathOpen(dc->dclevel))
101 {
102 Ret = PATH_LineTo(dc, XEnd, YEnd);
103 if (Ret)
104 {
105 // FIXME - PATH_LineTo should maybe do this? No
106 pdcattr->ptlCurrent.x = XEnd;
107 pdcattr->ptlCurrent.y = YEnd;
108 pdcattr->ptfxCurrent = pdcattr->ptlCurrent;
109 CoordLPtoDP(dc, &pdcattr->ptfxCurrent); // Update fx
110 pdcattr->ulDirty_ &= ~(DIRTY_PTLCURRENT|DIRTY_PTFXCURRENT|DIRTY_STYLESTATE);
111 }
112 return Ret;
113 }
114 else
115 {
116 if (pdcattr->ulDirty_ & (DIRTY_LINE | DC_PEN_DIRTY))
117 DC_vUpdateLineBrush(dc);
118
119 psurf = dc->dclevel.pSurface;
120 if (NULL == psurf)
121 {
122 SetLastWin32Error(ERROR_INVALID_HANDLE);
123 return FALSE;
124 }
125
126 Points[0].x = pdcattr->ptlCurrent.x;
127 Points[0].y = pdcattr->ptlCurrent.y;
128 Points[1].x = XEnd;
129 Points[1].y = YEnd;
130
131 IntLPtoDP(dc, Points, 2);
132
133 /* The DCOrg is in device coordinates */
134 Points[0].x += dc->ptlDCOrig.x;
135 Points[0].y += dc->ptlDCOrig.y;
136 Points[1].x += dc->ptlDCOrig.x;
137 Points[1].y += dc->ptlDCOrig.y;
138
139 Bounds.left = min(Points[0].x, Points[1].x);
140 Bounds.top = min(Points[0].y, Points[1].y);
141 Bounds.right = max(Points[0].x, Points[1].x);
142 Bounds.bottom = max(Points[0].y, Points[1].y);
143
144 /* get BRUSH from current pen. */
145 pbrLine = dc->dclevel.pbrLine;
146 ASSERT(pbrLine);
147
148 if (!(pbrLine->flAttrs & GDIBRUSH_IS_NULL))
149 {
150 Ret = IntEngLineTo(&psurf->SurfObj,
151 dc->rosdc.CombinedClip,
152 &dc->eboLine.BrushObject,
153 Points[0].x, Points[0].y,
154 Points[1].x, Points[1].y,
155 &Bounds,
156 ROP2_TO_MIX(pdcattr->jROP2));
157 }
158
159 }
160
161 if (Ret)
162 {
163 pdcattr->ptlCurrent.x = XEnd;
164 pdcattr->ptlCurrent.y = YEnd;
165 pdcattr->ptfxCurrent = pdcattr->ptlCurrent;
166 CoordLPtoDP(dc, &pdcattr->ptfxCurrent); // Update fx
167 pdcattr->ulDirty_ &= ~(DIRTY_PTLCURRENT|DIRTY_PTFXCURRENT|DIRTY_STYLESTATE);
168 }
169
170 return Ret;
171 }
172
173 BOOL FASTCALL
174 IntGdiPolyBezier(DC *dc,
175 LPPOINT pt,
176 DWORD Count)
177 {
178 BOOL ret = FALSE; // default to FAILURE
179
180 if ( PATH_IsPathOpen(dc->dclevel) )
181 {
182 return PATH_PolyBezier ( dc, pt, Count );
183 }
184
185 /* We'll convert it into line segments and draw them using Polyline */
186 {
187 POINT *Pts;
188 INT nOut;
189
190 Pts = GDI_Bezier ( pt, Count, &nOut );
191 if ( Pts )
192 {
193 ret = IntGdiPolyline(dc, Pts, nOut);
194 ExFreePoolWithTag(Pts, TAG_BEZIER);
195 }
196 }
197
198 return ret;
199 }
200
201 BOOL FASTCALL
202 IntGdiPolyBezierTo(DC *dc,
203 LPPOINT pt,
204 DWORD Count)
205 {
206 BOOL ret = FALSE; // default to failure
207 PDC_ATTR pdcattr = dc->pdcattr;
208
209 if ( PATH_IsPathOpen(dc->dclevel) )
210 ret = PATH_PolyBezierTo ( dc, pt, Count );
211 else /* We'll do it using PolyBezier */
212 {
213 POINT *npt;
214 npt = ExAllocatePoolWithTag(PagedPool,
215 sizeof(POINT) * (Count + 1),
216 TAG_BEZIER);
217 if ( npt )
218 {
219 npt[0].x = pdcattr->ptlCurrent.x;
220 npt[0].y = pdcattr->ptlCurrent.y;
221 memcpy(npt + 1, pt, sizeof(POINT) * Count);
222 ret = IntGdiPolyBezier(dc, npt, Count+1);
223 ExFreePoolWithTag(npt, TAG_BEZIER);
224 }
225 }
226 if ( ret )
227 {
228 pdcattr->ptlCurrent.x = pt[Count-1].x;
229 pdcattr->ptlCurrent.y = pt[Count-1].y;
230 pdcattr->ptfxCurrent = pdcattr->ptlCurrent;
231 CoordLPtoDP(dc, &pdcattr->ptfxCurrent); // Update fx
232 pdcattr->ulDirty_ &= ~(DIRTY_PTLCURRENT|DIRTY_PTFXCURRENT|DIRTY_STYLESTATE);
233 }
234
235 return ret;
236 }
237
238 BOOL FASTCALL
239 IntGdiPolyline(DC *dc,
240 LPPOINT pt,
241 int Count)
242 {
243 SURFACE *psurf;
244 BRUSH *pbrLine;
245 LPPOINT Points;
246 BOOL Ret = TRUE;
247 LONG i;
248 PDC_ATTR pdcattr = dc->pdcattr;
249
250 if (PATH_IsPathOpen(dc->dclevel))
251 return PATH_Polyline(dc, pt, Count);
252
253 if (pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
254 DC_vUpdateFillBrush(dc);
255
256 if (pdcattr->ulDirty_ & (DIRTY_LINE | DC_PEN_DIRTY))
257 DC_vUpdateLineBrush(dc);
258
259 /* Get BRUSHOBJ from current pen. */
260 pbrLine = dc->dclevel.pbrLine;
261 ASSERT(pbrLine);
262
263 if (!(pbrLine->flAttrs & GDIBRUSH_IS_NULL))
264 {
265 Points = EngAllocMem(0, Count * sizeof(POINT), TAG_COORD);
266 if (Points != NULL)
267 {
268 DC_vPrepareDCsForBlit(dc, dc->rosdc.CombinedClip->rclBounds,
269 NULL, dc->rosdc.CombinedClip->rclBounds);
270 psurf = dc->dclevel.pSurface;
271 /* FIXME - psurf can be NULL!!!!
272 Don't assert but handle this case gracefully! */
273 ASSERT(psurf);
274
275 RtlCopyMemory(Points, pt, Count * sizeof(POINT));
276 IntLPtoDP(dc, Points, Count);
277
278 /* Offset the array of points by the DC origin */
279 for (i = 0; i < Count; i++)
280 {
281 Points[i].x += dc->ptlDCOrig.x;
282 Points[i].y += dc->ptlDCOrig.y;
283 }
284
285 Ret = IntEngPolyline(&psurf->SurfObj,
286 dc->rosdc.CombinedClip,
287 &dc->eboLine.BrushObject,
288 Points,
289 Count,
290 ROP2_TO_MIX(pdcattr->jROP2));
291
292 EngFreeMem(Points);
293 DC_vFinishBlit(dc, NULL);
294 }
295 else
296 {
297 Ret = FALSE;
298 }
299 }
300
301 return Ret;
302 }
303
304 BOOL FASTCALL
305 IntGdiPolylineTo(DC *dc,
306 LPPOINT pt,
307 DWORD Count)
308 {
309 BOOL ret = FALSE; // default to failure
310 PDC_ATTR pdcattr = dc->pdcattr;
311
312 if (PATH_IsPathOpen(dc->dclevel))
313 {
314 ret = PATH_PolylineTo(dc, pt, Count);
315 }
316 else /* do it using Polyline */
317 {
318 POINT *pts = ExAllocatePoolWithTag(PagedPool,
319 sizeof(POINT) * (Count + 1),
320 TAG_SHAPE);
321 if ( pts )
322 {
323 pts[0].x = pdcattr->ptlCurrent.x;
324 pts[0].y = pdcattr->ptlCurrent.y;
325 memcpy( pts + 1, pt, sizeof(POINT) * Count);
326 ret = IntGdiPolyline(dc, pts, Count + 1);
327 ExFreePoolWithTag(pts, TAG_SHAPE);
328 }
329 }
330 if ( ret )
331 {
332 pdcattr->ptlCurrent.x = pt[Count-1].x;
333 pdcattr->ptlCurrent.y = pt[Count-1].y;
334 pdcattr->ptfxCurrent = pdcattr->ptlCurrent;
335 CoordLPtoDP(dc, &pdcattr->ptfxCurrent); // Update fx
336 pdcattr->ulDirty_ &= ~(DIRTY_PTLCURRENT|DIRTY_PTFXCURRENT|DIRTY_STYLESTATE);
337 }
338
339 return ret;
340 }
341
342
343 BOOL FASTCALL
344 IntGdiPolyPolyline(DC *dc,
345 LPPOINT pt,
346 PULONG PolyPoints,
347 DWORD Count)
348 {
349 int i;
350 LPPOINT pts;
351 PULONG pc;
352 BOOL ret = FALSE; // default to failure
353 pts = pt;
354 pc = PolyPoints;
355
356 if (PATH_IsPathOpen(dc->dclevel))
357 return PATH_PolyPolyline( dc, pt, PolyPoints, Count );
358
359 for (i = 0; i < Count; i++)
360 {
361 ret = IntGdiPolyline ( dc, pts, *pc );
362 if (ret == FALSE)
363 {
364 return ret;
365 }
366 pts+=*pc++;
367 }
368
369 return ret;
370 }
371
372 /******************************************************************************/
373
374 BOOL
375 APIENTRY
376 NtGdiLineTo(HDC hDC,
377 int XEnd,
378 int YEnd)
379 {
380 DC *dc;
381 BOOL Ret;
382 RECT rcLockRect ;
383
384 dc = DC_LockDc(hDC);
385 if (!dc)
386 {
387 SetLastWin32Error(ERROR_INVALID_HANDLE);
388 return FALSE;
389 }
390 if (dc->dctype == DC_TYPE_INFO)
391 {
392 DC_UnlockDc(dc);
393 /* Yes, Windows really returns TRUE in this case */
394 return TRUE;
395 }
396
397 rcLockRect.left = dc->pdcattr->ptlCurrent.x;
398 rcLockRect.top = dc->pdcattr->ptlCurrent.y;
399 rcLockRect.right = XEnd;
400 rcLockRect.bottom = YEnd;
401
402 IntLPtoDP(dc, &rcLockRect, 2);
403
404 /* The DCOrg is in device coordinates */
405 rcLockRect.left += dc->ptlDCOrig.x;
406 rcLockRect.top += dc->ptlDCOrig.y;
407 rcLockRect.right += dc->ptlDCOrig.x;
408 rcLockRect.bottom += dc->ptlDCOrig.y;
409
410 DC_vPrepareDCsForBlit(dc, rcLockRect, NULL, rcLockRect);
411
412 Ret = IntGdiLineTo(dc, XEnd, YEnd);
413
414 DC_vFinishBlit(dc, NULL);
415
416 DC_UnlockDc(dc);
417 return Ret;
418 }
419
420 BOOL
421 APIENTRY
422 NtGdiPolyDraw(
423 IN HDC hdc,
424 IN LPPOINT lppt,
425 IN LPBYTE lpbTypes,
426 IN ULONG cCount)
427 {
428 PDC dc;
429 PPATH pPath;
430 BOOL result = FALSE;
431 POINT lastmove;
432 unsigned int i;
433 PDC_ATTR pdcattr;
434
435 dc = DC_LockDc(hdc);
436 if (!dc) return FALSE;
437 pdcattr = dc->pdcattr;
438
439 _SEH2_TRY
440 {
441 ProbeArrayForRead(lppt, sizeof(POINT), cCount, sizeof(LONG));
442 ProbeArrayForRead(lpbTypes, sizeof(BYTE), cCount, sizeof(BYTE));
443
444 /* check for each bezierto if there are two more points */
445 for ( i = 0; i < cCount; i++ )
446 {
447 if ( lpbTypes[i] != PT_MOVETO &&
448 lpbTypes[i] & PT_BEZIERTO )
449 {
450 if ( cCount < i+3 ) _SEH2_LEAVE;
451 else i += 2;
452 }
453 }
454
455 /* if no moveto occurs, we will close the figure here */
456 lastmove.x = pdcattr->ptlCurrent.x;
457 lastmove.y = pdcattr->ptlCurrent.y;
458
459 /* now let's draw */
460 for ( i = 0; i < cCount; i++ )
461 {
462 if ( lpbTypes[i] == PT_MOVETO )
463 {
464 IntGdiMoveToEx( dc, lppt[i].x, lppt[i].y, NULL, FALSE );
465 lastmove.x = pdcattr->ptlCurrent.x;
466 lastmove.y = pdcattr->ptlCurrent.y;
467 }
468 else if ( lpbTypes[i] & PT_LINETO )
469 IntGdiLineTo( dc, lppt[i].x, lppt[i].y );
470 else if ( lpbTypes[i] & PT_BEZIERTO )
471 {
472 POINT pts[4];
473 pts[0].x = pdcattr->ptlCurrent.x;
474 pts[0].y = pdcattr->ptlCurrent.y;
475 RtlCopyMemory(pts + 1, &lppt[i], sizeof(POINT) * 3);
476 IntGdiPolyBezier(dc, pts, 4);
477 i += 2;
478 }
479 else _SEH2_LEAVE;
480
481 if ( lpbTypes[i] & PT_CLOSEFIGURE )
482 {
483 if ( PATH_IsPathOpen(dc->dclevel) )
484 {
485 pPath = PATH_LockPath( dc->dclevel.hPath );
486 if (pPath)
487 {
488 IntGdiCloseFigure( pPath );
489 PATH_UnlockPath( pPath );
490 }
491 }
492 else IntGdiLineTo( dc, lastmove.x, lastmove.y );
493 }
494 }
495
496 result = TRUE;
497 }
498 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
499 {
500 SetLastNtError(_SEH2_GetExceptionCode());
501 }
502 _SEH2_END;
503
504 DC_UnlockDc(dc);
505
506 return result;
507 }
508
509 /*
510 * @unimplemented
511 */
512 BOOL
513 APIENTRY
514 NtGdiMoveTo(
515 IN HDC hdc,
516 IN INT x,
517 IN INT y,
518 OUT OPTIONAL LPPOINT pptOut)
519 {
520 UNIMPLEMENTED;
521 return FALSE;
522 }
523
524 /* EOF */