63c2740074f3a48d108214fce7057ae793de38f5
[reactos.git] / reactos / win32ss / gdi / ntgdi / line.c
1 /*
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
6 * PROGRAMMERS: ...
7 */
8
9 #include <win32k.h>
10
11 #define NDEBUG
12 #include <debug.h>
13
14 // Some code from the WINE project source (www.winehq.com)
15
16 // Should use Fx in Point
17 //
18 BOOL FASTCALL
19 IntGdiMoveToEx(DC *dc,
20 int X,
21 int Y,
22 LPPOINT Point)
23 {
24 PDC_ATTR pdcattr = dc->pdcattr;
25 if ( Point )
26 {
27 if ( pdcattr->ulDirty_ & DIRTY_PTLCURRENT ) // Double hit!
28 {
29 Point->x = pdcattr->ptfxCurrent.x; // ret prev before change.
30 Point->y = pdcattr->ptfxCurrent.y;
31 IntDPtoLP ( dc, Point, 1); // Reconvert back.
32 }
33 else
34 {
35 Point->x = pdcattr->ptlCurrent.x;
36 Point->y = pdcattr->ptlCurrent.y;
37 }
38 }
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);
44
45 return TRUE;
46 }
47
48 BOOL FASTCALL
49 GreMoveTo( HDC hdc,
50 INT x,
51 INT y,
52 LPPOINT pptOut)
53 {
54 BOOL Ret;
55 PDC dc;
56 if (!(dc = DC_LockDc(hdc)))
57 {
58 EngSetLastError(ERROR_INVALID_HANDLE);
59 return FALSE;
60 }
61 Ret = IntGdiMoveToEx(dc, x, y, pptOut);
62 DC_UnlockDc(dc);
63 return Ret;
64 }
65
66 // Should use Fx in pt
67 //
68 VOID FASTCALL
69 IntGetCurrentPositionEx(PDC dc, LPPOINT pt)
70 {
71 PDC_ATTR pdcattr = dc->pdcattr;
72
73 if ( pt )
74 {
75 if (pdcattr->ulDirty_ & DIRTY_PTFXCURRENT)
76 {
77 pdcattr->ptfxCurrent = pdcattr->ptlCurrent;
78 CoordLPtoDP(dc, &pdcattr->ptfxCurrent); // Update fx
79 pdcattr->ulDirty_ &= ~(DIRTY_PTFXCURRENT|DIRTY_STYLESTATE);
80 }
81 pt->x = pdcattr->ptlCurrent.x;
82 pt->y = pdcattr->ptlCurrent.y;
83 }
84 }
85
86 BOOL FASTCALL
87 IntGdiLineTo(DC *dc,
88 int XEnd,
89 int YEnd)
90 {
91 SURFACE *psurf;
92 BOOL Ret = TRUE;
93 PBRUSH pbrLine;
94 RECTL Bounds;
95 POINT Points[2];
96 PDC_ATTR pdcattr = dc->pdcattr;
97 ASSERT_DC_PREPARED(dc);
98
99 if (PATH_IsPathOpen(dc->dclevel))
100 {
101 Ret = PATH_LineTo(dc, XEnd, YEnd);
102 }
103 else
104 {
105 psurf = dc->dclevel.pSurface;
106 if (NULL == psurf)
107 {
108 EngSetLastError(ERROR_INVALID_HANDLE);
109 return FALSE;
110 }
111
112 Points[0].x = pdcattr->ptlCurrent.x;
113 Points[0].y = pdcattr->ptlCurrent.y;
114 Points[1].x = XEnd;
115 Points[1].y = YEnd;
116
117 IntLPtoDP(dc, Points, 2);
118
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;
124
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);
129
130 /* Get BRUSH from current pen. */
131 pbrLine = dc->dclevel.pbrLine;
132 ASSERT(pbrLine);
133
134 if (!(pbrLine->flAttrs & BR_IS_NULL))
135 {
136 Ret = IntEngLineTo(&psurf->SurfObj,
137 &dc->co.ClipObj,
138 &dc->eboLine.BrushObject,
139 Points[0].x, Points[0].y,
140 Points[1].x, Points[1].y,
141 &Bounds,
142 ROP2_TO_MIX(pdcattr->jROP2));
143 }
144
145 }
146
147 if (Ret)
148 {
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);
154 }
155
156 return Ret;
157 }
158
159 BOOL FASTCALL
160 IntGdiPolyBezier(DC *dc,
161 LPPOINT pt,
162 DWORD Count)
163 {
164 BOOL ret = FALSE; // Default to FAILURE
165
166 if ( PATH_IsPathOpen(dc->dclevel) )
167 {
168 return PATH_PolyBezier ( dc, pt, Count );
169 }
170
171 /* We'll convert it into line segments and draw them using Polyline */
172 {
173 POINT *Pts;
174 INT nOut;
175
176 Pts = GDI_Bezier ( pt, Count, &nOut );
177 if ( Pts )
178 {
179 ret = IntGdiPolyline(dc, Pts, nOut);
180 ExFreePoolWithTag(Pts, TAG_BEZIER);
181 }
182 }
183
184 return ret;
185 }
186
187 BOOL FASTCALL
188 IntGdiPolyBezierTo(DC *dc,
189 LPPOINT pt,
190 DWORD Count)
191 {
192 BOOL ret = FALSE; // Default to failure
193 PDC_ATTR pdcattr = dc->pdcattr;
194
195 if ( PATH_IsPathOpen(dc->dclevel) )
196 ret = PATH_PolyBezierTo ( dc, pt, Count );
197 else /* We'll do it using PolyBezier */
198 {
199 POINT *npt;
200 npt = ExAllocatePoolWithTag(PagedPool,
201 sizeof(POINT) * (Count + 1),
202 TAG_BEZIER);
203 if ( npt )
204 {
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);
210 }
211 }
212 if ( ret )
213 {
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);
219 }
220
221 return ret;
222 }
223
224 BOOL FASTCALL
225 IntGdiPolyline(DC *dc,
226 LPPOINT pt,
227 int Count)
228 {
229 SURFACE *psurf;
230 BRUSH *pbrLine;
231 LPPOINT Points;
232 BOOL Ret = TRUE;
233 LONG i;
234 PDC_ATTR pdcattr = dc->pdcattr;
235
236 if (!dc->dclevel.pSurface)
237 {
238 return FALSE;
239 }
240
241 DC_vPrepareDCsForBlit(dc, NULL, NULL, NULL);
242 psurf = dc->dclevel.pSurface;
243
244 /* Get BRUSHOBJ from current pen. */
245 pbrLine = dc->dclevel.pbrLine;
246 ASSERT(pbrLine);
247
248 if (!(pbrLine->flAttrs & BR_IS_NULL))
249 {
250 Points = EngAllocMem(0, Count * sizeof(POINT), GDITAG_TEMP);
251 if (Points != NULL)
252 {
253 RtlCopyMemory(Points, pt, Count * sizeof(POINT));
254 IntLPtoDP(dc, Points, Count);
255
256 /* Offset the array of points by the DC origin */
257 for (i = 0; i < Count; i++)
258 {
259 Points[i].x += dc->ptlDCOrig.x;
260 Points[i].y += dc->ptlDCOrig.y;
261 }
262
263 Ret = IntEngPolyline(&psurf->SurfObj,
264 &dc->co.ClipObj,
265 &dc->eboLine.BrushObject,
266 Points,
267 Count,
268 ROP2_TO_MIX(pdcattr->jROP2));
269
270 EngFreeMem(Points);
271 }
272 else
273 {
274 Ret = FALSE;
275 }
276 }
277
278 DC_vFinishBlit(dc, NULL);
279
280 return Ret;
281 }
282
283 BOOL FASTCALL
284 IntGdiPolylineTo(DC *dc,
285 LPPOINT pt,
286 DWORD Count)
287 {
288 BOOL ret = FALSE; // Default to failure
289 PDC_ATTR pdcattr = dc->pdcattr;
290
291 if (PATH_IsPathOpen(dc->dclevel))
292 {
293 ret = PATH_PolylineTo(dc, pt, Count);
294 }
295 else /* Do it using Polyline */
296 {
297 POINT *pts = ExAllocatePoolWithTag(PagedPool,
298 sizeof(POINT) * (Count + 1),
299 TAG_SHAPE);
300 if ( pts )
301 {
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);
307 }
308 }
309 if ( ret )
310 {
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);
316 }
317
318 return ret;
319 }
320
321
322 BOOL FASTCALL
323 IntGdiPolyPolyline(DC *dc,
324 LPPOINT pt,
325 PULONG PolyPoints,
326 DWORD Count)
327 {
328 ULONG i;
329 LPPOINT pts;
330 PULONG pc;
331 BOOL ret = FALSE; // Default to failure
332 pts = pt;
333 pc = PolyPoints;
334
335 if (PATH_IsPathOpen(dc->dclevel))
336 {
337 return PATH_PolyPolyline( dc, pt, PolyPoints, Count );
338 }
339 for (i = 0; i < Count; i++)
340 {
341 ret = IntGdiPolyline ( dc, pts, *pc );
342 if (ret == FALSE)
343 {
344 return ret;
345 }
346 pts+=*pc++;
347 }
348
349 return ret;
350 }
351
352 /******************************************************************************/
353
354 BOOL
355 APIENTRY
356 NtGdiLineTo(HDC hDC,
357 int XEnd,
358 int YEnd)
359 {
360 DC *dc;
361 BOOL Ret;
362 RECT rcLockRect ;
363
364 dc = DC_LockDc(hDC);
365 if (!dc)
366 {
367 EngSetLastError(ERROR_INVALID_HANDLE);
368 return FALSE;
369 }
370 if (dc->dctype == DC_TYPE_INFO)
371 {
372 DC_UnlockDc(dc);
373 /* Yes, Windows really returns TRUE in this case */
374 return TRUE;
375 }
376
377 rcLockRect.left = dc->pdcattr->ptlCurrent.x;
378 rcLockRect.top = dc->pdcattr->ptlCurrent.y;
379 rcLockRect.right = XEnd;
380 rcLockRect.bottom = YEnd;
381
382 IntLPtoDP(dc, &rcLockRect, 2);
383
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;
389
390 DC_vPrepareDCsForBlit(dc, &rcLockRect, NULL, NULL);
391
392 Ret = IntGdiLineTo(dc, XEnd, YEnd);
393
394 DC_vFinishBlit(dc, NULL);
395
396 DC_UnlockDc(dc);
397 return Ret;
398 }
399
400 // FIXME: This function is completely broken
401 BOOL
402 APIENTRY
403 NtGdiPolyDraw(
404 IN HDC hdc,
405 IN LPPOINT lppt,
406 IN LPBYTE lpbTypes,
407 IN ULONG cCount)
408 {
409 PDC dc;
410 PDC_ATTR pdcattr;
411 POINT bzr[4];
412 volatile PPOINT line_pts, line_pts_old, bzr_pts;
413 INT num_pts, num_bzr_pts, space, space_old, size;
414 ULONG i;
415 BOOL result = FALSE;
416
417 dc = DC_LockDc(hdc);
418 if (!dc) return FALSE;
419 pdcattr = dc->pdcattr;
420
421 if (pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
422 DC_vUpdateFillBrush(dc);
423
424 if (pdcattr->ulDirty_ & (DIRTY_LINE | DC_PEN_DIRTY))
425 DC_vUpdateLineBrush(dc);
426
427 if (!cCount)
428 {
429 DC_UnlockDc(dc);
430 return TRUE;
431 }
432
433 line_pts = NULL;
434 line_pts_old = NULL;
435 bzr_pts = NULL;
436
437 _SEH2_TRY
438 {
439 ProbeArrayForRead(lppt, sizeof(POINT), cCount, sizeof(LONG));
440 ProbeArrayForRead(lpbTypes, sizeof(BYTE), cCount, sizeof(BYTE));
441
442 if (PATH_IsPathOpen(dc->dclevel))
443 {
444 result = PATH_PolyDraw(dc, (const POINT *)lppt, (const BYTE *)lpbTypes, cCount);
445 _SEH2_LEAVE;
446 }
447
448 /* Check for valid point types */
449 for (i = 0; i < cCount; i++)
450 {
451 switch (lpbTypes[i])
452 {
453 case PT_MOVETO:
454 case PT_LINETO | PT_CLOSEFIGURE:
455 case PT_LINETO:
456 break;
457 case PT_BEZIERTO:
458 if((i + 2 < cCount) && (lpbTypes[i + 1] == PT_BEZIERTO) &&
459 ((lpbTypes[i + 2] & ~PT_CLOSEFIGURE) == PT_BEZIERTO))
460 {
461 i += 2;
462 break;
463 }
464 default:
465 _SEH2_LEAVE;
466 }
467 }
468
469 space = cCount + 300;
470 line_pts = ExAllocatePoolWithTag(PagedPool, space * sizeof(POINT), TAG_SHAPE);
471 if (line_pts == NULL)
472 {
473 result = FALSE;
474 _SEH2_LEAVE;
475 }
476
477 num_pts = 1;
478
479 line_pts[0].x = pdcattr->ptlCurrent.x;
480 line_pts[0].y = pdcattr->ptlCurrent.y;
481
482 for ( i = 0; i < cCount; i++ )
483 {
484 switch (lpbTypes[i])
485 {
486 case PT_MOVETO:
487 if (num_pts >= 2) IntGdiPolyline( dc, line_pts, num_pts );
488 num_pts = 0;
489 line_pts[num_pts++] = lppt[i];
490 break;
491 case PT_LINETO:
492 case (PT_LINETO | PT_CLOSEFIGURE):
493 line_pts[num_pts++] = lppt[i];
494 break;
495 case PT_BEZIERTO:
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) );
499
500 if ((bzr_pts = GDI_Bezier( bzr, 4, &num_bzr_pts )))
501 {
502 size = num_pts + (cCount - i) + num_bzr_pts;
503 if (space < size)
504 {
505 space_old = space;
506 space = size * 2;
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);
512 line_pts_old = NULL;
513 }
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);
517 bzr_pts = NULL;
518 }
519 i += 2;
520 break;
521 }
522 if (lpbTypes[i] & PT_CLOSEFIGURE) line_pts[num_pts++] = line_pts[0];
523 }
524
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 );
527 result = TRUE;
528 }
529 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
530 {
531 SetLastNtError(_SEH2_GetExceptionCode());
532 }
533 _SEH2_END;
534
535 if (line_pts != NULL)
536 {
537 ExFreePoolWithTag(line_pts, TAG_SHAPE);
538 }
539
540 if ((line_pts_old != NULL) && (line_pts_old != line_pts))
541 {
542 ExFreePoolWithTag(line_pts_old, TAG_SHAPE);
543 }
544
545 if (bzr_pts != NULL)
546 {
547 ExFreePoolWithTag(bzr_pts, TAG_BEZIER);
548 }
549
550 DC_UnlockDc(dc);
551
552 return result;
553 }
554
555 /*
556 * @implemented
557 */
558 _Success_(return != FALSE)
559 BOOL
560 APIENTRY
561 NtGdiMoveTo(
562 IN HDC hdc,
563 IN INT x,
564 IN INT y,
565 OUT OPTIONAL LPPOINT pptOut)
566 {
567 PDC pdc;
568 BOOL Ret;
569 POINT Point;
570
571 pdc = DC_LockDc(hdc);
572 if (!pdc) return FALSE;
573
574 Ret = IntGdiMoveToEx(pdc, x, y, &Point);
575
576 if (Ret && pptOut)
577 {
578 _SEH2_TRY
579 {
580 ProbeForWrite(pptOut, sizeof(POINT), 1);
581 RtlCopyMemory(pptOut, &Point, sizeof(POINT));
582 }
583 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
584 {
585 SetLastNtError(_SEH2_GetExceptionCode());
586 Ret = FALSE; // CHECKME: is this correct?
587 }
588 _SEH2_END;
589 }
590
591 DC_UnlockDc(pdc);
592
593 return Ret;
594 }
595
596 /* EOF */