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 DBG_DEFAULT_CHANNEL(GdiLine);
15
16 // Some code from the WINE project source (www.winehq.com)
17
18 VOID FASTCALL
AddPenLinesBounds(PDC dc,int count,POINT * points)19 AddPenLinesBounds(PDC dc, int count, POINT *points)
20 {
21 DWORD join, endcap;
22 RECTL bounds, rect;
23 LONG lWidth;
24 PBRUSH pbrLine;
25
26 /* Get BRUSH from current pen. */
27 pbrLine = dc->dclevel.pbrLine;
28 ASSERT(pbrLine);
29
30 lWidth = 0;
31
32 // Setup bounds
33 bounds.left = bounds.top = INT_MAX;
34 bounds.right = bounds.bottom = INT_MIN;
35
36 if (((pbrLine->ulPenStyle & PS_TYPE_MASK) & PS_GEOMETRIC) || pbrLine->lWidth > 1)
37 {
38 /* Windows uses some heuristics to estimate the distance from the point that will be painted */
39 lWidth = pbrLine->lWidth + 2;
40 endcap = (PS_ENDCAP_MASK & pbrLine->ulPenStyle);
41 join = (PS_JOIN_MASK & pbrLine->ulPenStyle);
42 if (join == PS_JOIN_MITER)
43 {
44 lWidth *= 5;
45 if (endcap == PS_ENDCAP_SQUARE) lWidth = (lWidth * 3 + 1) / 2;
46 }
47 else
48 {
49 if (endcap == PS_ENDCAP_SQUARE) lWidth -= lWidth / 4;
50 else lWidth = (lWidth + 1) / 2;
51 }
52 }
53
54 while (count-- > 0)
55 {
56 rect.left = points->x - lWidth;
57 rect.top = points->y - lWidth;
58 rect.right = points->x + lWidth + 1;
59 rect.bottom = points->y + lWidth + 1;
60 RECTL_bUnionRect(&bounds, &bounds, &rect);
61 points++;
62 }
63
64 DPRINT("APLB dc %p l %d t %d\n",dc,rect.left,rect.top);
65 DPRINT(" r %d b %d\n",rect.right,rect.bottom);
66
67 {
68 RECTL rcRgn = dc->erclClip; // Use the clip box for now.
69
70 if (RECTL_bIntersectRect( &rcRgn, &rcRgn, &bounds ))
71 IntUpdateBoundsRect(dc, &rcRgn);
72 else
73 IntUpdateBoundsRect(dc, &bounds);
74 }
75 }
76
77 // Should use Fx in Point
78 //
79 BOOL FASTCALL
IntGdiMoveToEx(DC * dc,int X,int Y,LPPOINT Point)80 IntGdiMoveToEx(DC *dc,
81 int X,
82 int Y,
83 LPPOINT Point)
84 {
85 PDC_ATTR pdcattr = dc->pdcattr;
86 if ( Point )
87 {
88 if ( pdcattr->ulDirty_ & DIRTY_PTLCURRENT ) // Double hit!
89 {
90 Point->x = pdcattr->ptfxCurrent.x; // ret prev before change.
91 Point->y = pdcattr->ptfxCurrent.y;
92 IntDPtoLP ( dc, Point, 1); // Reconvert back.
93 }
94 else
95 {
96 Point->x = pdcattr->ptlCurrent.x;
97 Point->y = pdcattr->ptlCurrent.y;
98 }
99 }
100 pdcattr->ptlCurrent.x = X;
101 pdcattr->ptlCurrent.y = Y;
102 pdcattr->ptfxCurrent = pdcattr->ptlCurrent;
103 CoordLPtoDP(dc, &pdcattr->ptfxCurrent); // Update fx
104 pdcattr->ulDirty_ &= ~(DIRTY_PTLCURRENT|DIRTY_PTFXCURRENT|DIRTY_STYLESTATE);
105
106 return TRUE;
107 }
108
109 BOOL FASTCALL
GreMoveTo(HDC hdc,INT x,INT y,LPPOINT pptOut)110 GreMoveTo( HDC hdc,
111 INT x,
112 INT y,
113 LPPOINT pptOut)
114 {
115 BOOL Ret;
116 PDC dc;
117 if (!(dc = DC_LockDc(hdc)))
118 {
119 EngSetLastError(ERROR_INVALID_HANDLE);
120 return FALSE;
121 }
122 Ret = IntGdiMoveToEx(dc, x, y, pptOut);
123 DC_UnlockDc(dc);
124 return Ret;
125 }
126
127 // Should use Fx in pt
128 //
129 VOID FASTCALL
IntGetCurrentPositionEx(PDC dc,LPPOINT pt)130 IntGetCurrentPositionEx(PDC dc, LPPOINT pt)
131 {
132 PDC_ATTR pdcattr = dc->pdcattr;
133
134 if ( pt )
135 {
136 if (pdcattr->ulDirty_ & DIRTY_PTFXCURRENT)
137 {
138 pdcattr->ptfxCurrent = pdcattr->ptlCurrent;
139 CoordLPtoDP(dc, &pdcattr->ptfxCurrent); // Update fx
140 pdcattr->ulDirty_ &= ~(DIRTY_PTFXCURRENT|DIRTY_STYLESTATE);
141 }
142 pt->x = pdcattr->ptlCurrent.x;
143 pt->y = pdcattr->ptlCurrent.y;
144 }
145 }
146
147 BOOL FASTCALL
IntGdiLineTo(DC * dc,int XEnd,int YEnd)148 IntGdiLineTo(DC *dc,
149 int XEnd,
150 int YEnd)
151 {
152 SURFACE *psurf;
153 BOOL Ret = TRUE;
154 PBRUSH pbrLine;
155 RECTL Bounds;
156 POINT Points[2];
157 PDC_ATTR pdcattr;
158 PPATH pPath;
159
160 ASSERT_DC_PREPARED(dc);
161
162 pdcattr = dc->pdcattr;
163
164 if (PATH_IsPathOpen(dc->dclevel))
165 {
166 Ret = PATH_LineTo(dc, XEnd, YEnd);
167 }
168 else
169 {
170 psurf = dc->dclevel.pSurface;
171 if (NULL == psurf)
172 {
173 EngSetLastError(ERROR_INVALID_HANDLE);
174 return FALSE;
175 }
176
177 Points[0].x = pdcattr->ptlCurrent.x;
178 Points[0].y = pdcattr->ptlCurrent.y;
179 Points[1].x = XEnd;
180 Points[1].y = YEnd;
181
182 IntLPtoDP(dc, Points, 2);
183
184 /* The DCOrg is in device coordinates */
185 Points[0].x += dc->ptlDCOrig.x;
186 Points[0].y += dc->ptlDCOrig.y;
187 Points[1].x += dc->ptlDCOrig.x;
188 Points[1].y += dc->ptlDCOrig.y;
189
190 Bounds.left = min(Points[0].x, Points[1].x);
191 Bounds.top = min(Points[0].y, Points[1].y);
192 Bounds.right = max(Points[0].x, Points[1].x);
193 Bounds.bottom = max(Points[0].y, Points[1].y);
194
195 /* Get BRUSH from current pen. */
196 pbrLine = dc->dclevel.pbrLine;
197 ASSERT(pbrLine);
198
199 if (dc->fs & (DC_ACCUM_APP|DC_ACCUM_WMGR))
200 {
201 DPRINT("Bounds dc %p l %d t %d\n",dc,Bounds.left,Bounds.top);
202 DPRINT(" r %d b %d\n",Bounds.right,Bounds.bottom);
203 AddPenLinesBounds(dc, 2, Points);
204 }
205
206 if (!(pbrLine->flAttrs & BR_IS_NULL))
207 {
208 if (IntIsEffectiveWidePen(pbrLine))
209 {
210 /* Clear the path */
211 PATH_Delete(dc->dclevel.hPath);
212 dc->dclevel.hPath = NULL;
213
214 /* Begin a path */
215 pPath = PATH_CreatePath(2);
216 dc->dclevel.flPath |= DCPATH_ACTIVE;
217 dc->dclevel.hPath = pPath->BaseObject.hHmgr;
218 IntGetCurrentPositionEx(dc, &pPath->pos);
219 IntLPtoDP(dc, &pPath->pos, 1);
220
221 PATH_MoveTo(dc, pPath);
222 PATH_LineTo(dc, XEnd, YEnd);
223
224 /* Close the path */
225 pPath->state = PATH_Closed;
226 dc->dclevel.flPath &= ~DCPATH_ACTIVE;
227
228 /* Actually stroke a path */
229 Ret = PATH_StrokePath(dc, pPath);
230
231 /* Clear the path */
232 PATH_UnlockPath(pPath);
233 PATH_Delete(dc->dclevel.hPath);
234 dc->dclevel.hPath = NULL;
235 }
236 else
237 {
238 Ret = IntEngLineTo(&psurf->SurfObj,
239 (CLIPOBJ *)&dc->co,
240 &dc->eboLine.BrushObject,
241 Points[0].x, Points[0].y,
242 Points[1].x, Points[1].y,
243 &Bounds,
244 ROP2_TO_MIX(pdcattr->jROP2));
245 }
246 }
247 }
248
249 if (Ret)
250 {
251 pdcattr->ptlCurrent.x = XEnd;
252 pdcattr->ptlCurrent.y = YEnd;
253 pdcattr->ptfxCurrent = pdcattr->ptlCurrent;
254 CoordLPtoDP(dc, &pdcattr->ptfxCurrent); // Update fx
255 pdcattr->ulDirty_ &= ~(DIRTY_PTLCURRENT|DIRTY_PTFXCURRENT|DIRTY_STYLESTATE);
256 }
257
258 return Ret;
259 }
260
261 BOOL FASTCALL
IntGdiPolyBezier(DC * dc,LPPOINT pt,DWORD Count)262 IntGdiPolyBezier(DC *dc,
263 LPPOINT pt,
264 DWORD Count)
265 {
266 BOOL ret = FALSE; // Default to FAILURE
267
268 if ( PATH_IsPathOpen(dc->dclevel) )
269 {
270 return PATH_PolyBezier ( dc, pt, Count );
271 }
272
273 /* We'll convert it into line segments and draw them using Polyline */
274 {
275 POINT *Pts;
276 INT nOut;
277
278 Pts = GDI_Bezier ( pt, Count, &nOut );
279 if ( Pts )
280 {
281 ret = IntGdiPolyline(dc, Pts, nOut);
282 ExFreePoolWithTag(Pts, TAG_BEZIER);
283 }
284 }
285
286 return ret;
287 }
288
289 BOOL FASTCALL
IntGdiPolyBezierTo(DC * dc,LPPOINT pt,DWORD Count)290 IntGdiPolyBezierTo(DC *dc,
291 LPPOINT pt,
292 DWORD Count)
293 {
294 BOOL ret = FALSE; // Default to failure
295 PDC_ATTR pdcattr = dc->pdcattr;
296
297 if ( PATH_IsPathOpen(dc->dclevel) )
298 ret = PATH_PolyBezierTo ( dc, pt, Count );
299 else /* We'll do it using PolyBezier */
300 {
301 POINT *npt;
302 npt = ExAllocatePoolWithTag(PagedPool,
303 sizeof(POINT) * (Count + 1),
304 TAG_BEZIER);
305 if ( npt )
306 {
307 npt[0].x = pdcattr->ptlCurrent.x;
308 npt[0].y = pdcattr->ptlCurrent.y;
309 memcpy(npt + 1, pt, sizeof(POINT) * Count);
310 ret = IntGdiPolyBezier(dc, npt, Count+1);
311 ExFreePoolWithTag(npt, TAG_BEZIER);
312 }
313 }
314 if ( ret )
315 {
316 pdcattr->ptlCurrent.x = pt[Count-1].x;
317 pdcattr->ptlCurrent.y = pt[Count-1].y;
318 pdcattr->ptfxCurrent = pdcattr->ptlCurrent;
319 CoordLPtoDP(dc, &pdcattr->ptfxCurrent); // Update fx
320 pdcattr->ulDirty_ &= ~(DIRTY_PTLCURRENT|DIRTY_PTFXCURRENT|DIRTY_STYLESTATE);
321 }
322
323 return ret;
324 }
325
326 BOOL FASTCALL
IntGdiPolyline(DC * dc,LPPOINT pt,int Count)327 IntGdiPolyline(DC *dc,
328 LPPOINT pt,
329 int Count)
330 {
331 SURFACE *psurf;
332 BRUSH *pbrLine;
333 LPPOINT Points;
334 BOOL Ret = TRUE;
335 LONG i;
336 PDC_ATTR pdcattr = dc->pdcattr;
337 PPATH pPath;
338
339 if (!dc->dclevel.pSurface)
340 {
341 return TRUE;
342 }
343
344 DC_vPrepareDCsForBlit(dc, NULL, NULL, NULL);
345 psurf = dc->dclevel.pSurface;
346
347 /* Get BRUSHOBJ from current pen. */
348 pbrLine = dc->dclevel.pbrLine;
349 ASSERT(pbrLine);
350
351 if (!(pbrLine->flAttrs & BR_IS_NULL))
352 {
353 Points = EngAllocMem(0, Count * sizeof(POINT), GDITAG_TEMP);
354 if (Points != NULL)
355 {
356 RtlCopyMemory(Points, pt, Count * sizeof(POINT));
357 IntLPtoDP(dc, Points, Count);
358
359 /* Offset the array of points by the DC origin */
360 for (i = 0; i < Count; i++)
361 {
362 Points[i].x += dc->ptlDCOrig.x;
363 Points[i].y += dc->ptlDCOrig.y;
364 }
365
366 if (dc->fs & (DC_ACCUM_APP|DC_ACCUM_WMGR))
367 {
368 AddPenLinesBounds(dc, Count, Points);
369 }
370
371 if (IntIsEffectiveWidePen(pbrLine))
372 {
373 /* Clear the path */
374 PATH_Delete(dc->dclevel.hPath);
375 dc->dclevel.hPath = NULL;
376
377 /* Begin a path */
378 pPath = PATH_CreatePath(Count);
379 dc->dclevel.flPath |= DCPATH_ACTIVE;
380 dc->dclevel.hPath = pPath->BaseObject.hHmgr;
381 pPath->pos = pt[0];
382 IntLPtoDP(dc, &pPath->pos, 1);
383
384 PATH_MoveTo(dc, pPath);
385 for (i = 1; i < Count; ++i)
386 {
387 PATH_LineTo(dc, pt[i].x, pt[i].y);
388 }
389
390 /* Close the path */
391 pPath->state = PATH_Closed;
392 dc->dclevel.flPath &= ~DCPATH_ACTIVE;
393
394 /* Actually stroke a path */
395 Ret = PATH_StrokePath(dc, pPath);
396
397 /* Clear the path */
398 PATH_UnlockPath(pPath);
399 PATH_Delete(dc->dclevel.hPath);
400 dc->dclevel.hPath = NULL;
401 }
402 else
403 {
404 Ret = IntEngPolyline(&psurf->SurfObj,
405 (CLIPOBJ *)&dc->co,
406 &dc->eboLine.BrushObject,
407 Points,
408 Count,
409 ROP2_TO_MIX(pdcattr->jROP2));
410 }
411 EngFreeMem(Points);
412 }
413 else
414 {
415 Ret = FALSE;
416 }
417 }
418
419 DC_vFinishBlit(dc, NULL);
420
421 return Ret;
422 }
423
424 BOOL FASTCALL
IntGdiPolylineTo(DC * dc,LPPOINT pt,DWORD Count)425 IntGdiPolylineTo(DC *dc,
426 LPPOINT pt,
427 DWORD Count)
428 {
429 BOOL ret = FALSE; // Default to failure
430 PDC_ATTR pdcattr = dc->pdcattr;
431
432 if (PATH_IsPathOpen(dc->dclevel))
433 {
434 ret = PATH_PolylineTo(dc, pt, Count);
435 }
436 else /* Do it using Polyline */
437 {
438 POINT *pts = ExAllocatePoolWithTag(PagedPool,
439 sizeof(POINT) * (Count + 1),
440 TAG_SHAPE);
441 if ( pts )
442 {
443 pts[0].x = pdcattr->ptlCurrent.x;
444 pts[0].y = pdcattr->ptlCurrent.y;
445 memcpy( pts + 1, pt, sizeof(POINT) * Count);
446 ret = IntGdiPolyline(dc, pts, Count + 1);
447 ExFreePoolWithTag(pts, TAG_SHAPE);
448 }
449 }
450 if ( ret )
451 {
452 pdcattr->ptlCurrent.x = pt[Count-1].x;
453 pdcattr->ptlCurrent.y = pt[Count-1].y;
454 pdcattr->ptfxCurrent = pdcattr->ptlCurrent;
455 CoordLPtoDP(dc, &pdcattr->ptfxCurrent); // Update fx
456 pdcattr->ulDirty_ &= ~(DIRTY_PTLCURRENT|DIRTY_PTFXCURRENT|DIRTY_STYLESTATE);
457 }
458
459 return ret;
460 }
461
462
463 BOOL FASTCALL
IntGdiPolyPolyline(DC * dc,LPPOINT pt,PULONG PolyPoints,DWORD Count)464 IntGdiPolyPolyline(DC *dc,
465 LPPOINT pt,
466 PULONG PolyPoints,
467 DWORD Count)
468 {
469 ULONG i;
470 LPPOINT pts;
471 PULONG pc;
472 BOOL ret = FALSE; // Default to failure
473 pts = pt;
474 pc = PolyPoints;
475
476 if (PATH_IsPathOpen(dc->dclevel))
477 {
478 return PATH_PolyPolyline( dc, pt, PolyPoints, Count );
479 }
480 for (i = 0; i < Count; i++)
481 {
482 ret = IntGdiPolyline ( dc, pts, *pc );
483 if (ret == FALSE)
484 {
485 return ret;
486 }
487 pts+=*pc++;
488 }
489
490 return ret;
491 }
492
493 /******************************************************************************/
494
495 BOOL
496 APIENTRY
NtGdiLineTo(HDC hDC,int XEnd,int YEnd)497 NtGdiLineTo(HDC hDC,
498 int XEnd,
499 int YEnd)
500 {
501 DC *dc;
502 BOOL Ret;
503 RECT rcLockRect ;
504
505 dc = DC_LockDc(hDC);
506 if (!dc)
507 {
508 EngSetLastError(ERROR_INVALID_HANDLE);
509 return FALSE;
510 }
511
512 rcLockRect.left = dc->pdcattr->ptlCurrent.x;
513 rcLockRect.top = dc->pdcattr->ptlCurrent.y;
514 rcLockRect.right = XEnd;
515 rcLockRect.bottom = YEnd;
516
517 IntLPtoDP(dc, (PPOINT)&rcLockRect, 2);
518
519 /* The DCOrg is in device coordinates */
520 rcLockRect.left += dc->ptlDCOrig.x;
521 rcLockRect.top += dc->ptlDCOrig.y;
522 rcLockRect.right += dc->ptlDCOrig.x;
523 rcLockRect.bottom += dc->ptlDCOrig.y;
524
525 DC_vPrepareDCsForBlit(dc, &rcLockRect, NULL, NULL);
526
527 Ret = IntGdiLineTo(dc, XEnd, YEnd);
528
529 DC_vFinishBlit(dc, NULL);
530
531 DC_UnlockDc(dc);
532 return Ret;
533 }
534
535 // FIXME: This function is completely broken
536 static
537 BOOL
GdiPolyDraw(IN HDC hdc,IN LPPOINT lppt,IN LPBYTE lpbTypes,IN ULONG cCount)538 GdiPolyDraw(
539 IN HDC hdc,
540 IN LPPOINT lppt,
541 IN LPBYTE lpbTypes,
542 IN ULONG cCount)
543 {
544 PDC dc;
545 PDC_ATTR pdcattr;
546 POINT bzr[4];
547 volatile PPOINT line_pts, line_pts_old, bzr_pts;
548 INT num_pts, num_bzr_pts, space, space_old, size;
549 ULONG i;
550 BOOL result = FALSE;
551
552 dc = DC_LockDc(hdc);
553 if (!dc) return FALSE;
554 pdcattr = dc->pdcattr;
555
556 if (pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
557 DC_vUpdateFillBrush(dc);
558
559 if (pdcattr->ulDirty_ & (DIRTY_LINE | DC_PEN_DIRTY))
560 DC_vUpdateLineBrush(dc);
561
562 if (!cCount)
563 {
564 DC_UnlockDc(dc);
565 return TRUE;
566 }
567
568 line_pts = NULL;
569 line_pts_old = NULL;
570 bzr_pts = NULL;
571
572 {
573 if (PATH_IsPathOpen(dc->dclevel))
574 {
575 result = PATH_PolyDraw(dc, (const POINT *)lppt, (const BYTE *)lpbTypes, cCount);
576 goto Cleanup;
577 }
578
579 /* Check for valid point types */
580 for (i = 0; i < cCount; i++)
581 {
582 switch (lpbTypes[i])
583 {
584 case PT_MOVETO:
585 case PT_LINETO | PT_CLOSEFIGURE:
586 case PT_LINETO:
587 break;
588 case PT_BEZIERTO:
589 if((i + 2 < cCount) && (lpbTypes[i + 1] == PT_BEZIERTO) &&
590 ((lpbTypes[i + 2] & ~PT_CLOSEFIGURE) == PT_BEZIERTO))
591 {
592 i += 2;
593 break;
594 }
595 default:
596 goto Cleanup;
597 }
598 }
599
600 space = cCount + 300;
601 line_pts = ExAllocatePoolWithTag(PagedPool, space * sizeof(POINT), TAG_SHAPE);
602 if (line_pts == NULL)
603 {
604 result = FALSE;
605 goto Cleanup;
606 }
607
608 num_pts = 1;
609
610 line_pts[0].x = pdcattr->ptlCurrent.x;
611 line_pts[0].y = pdcattr->ptlCurrent.y;
612
613 for ( i = 0; i < cCount; i++ )
614 {
615 switch (lpbTypes[i])
616 {
617 case PT_MOVETO:
618 if (num_pts >= 2) IntGdiPolyline( dc, line_pts, num_pts );
619 num_pts = 0;
620 line_pts[num_pts++] = lppt[i];
621 break;
622 case PT_LINETO:
623 case (PT_LINETO | PT_CLOSEFIGURE):
624 line_pts[num_pts++] = lppt[i];
625 break;
626 case PT_BEZIERTO:
627 bzr[0].x = line_pts[num_pts - 1].x;
628 bzr[0].y = line_pts[num_pts - 1].y;
629 RtlCopyMemory( &bzr[1], &lppt[i], 3 * sizeof(POINT) );
630
631 if ((bzr_pts = GDI_Bezier( bzr, 4, &num_bzr_pts )))
632 {
633 size = num_pts + (cCount - i) + num_bzr_pts;
634 if (space < size)
635 {
636 space_old = space;
637 space = size * 2;
638 line_pts_old = line_pts;
639 line_pts = ExAllocatePoolWithTag(PagedPool, space * sizeof(POINT), TAG_SHAPE);
640 if (!line_pts) goto Cleanup;
641 RtlCopyMemory(line_pts, line_pts_old, space_old * sizeof(POINT));
642 ExFreePoolWithTag(line_pts_old, TAG_SHAPE);
643 line_pts_old = NULL;
644 }
645 RtlCopyMemory( &line_pts[num_pts], &bzr_pts[1], (num_bzr_pts - 1) * sizeof(POINT) );
646 num_pts += num_bzr_pts - 1;
647 ExFreePoolWithTag(bzr_pts, TAG_BEZIER);
648 bzr_pts = NULL;
649 }
650 i += 2;
651 break;
652 }
653 if (lpbTypes[i] & PT_CLOSEFIGURE) line_pts[num_pts++] = line_pts[0];
654 }
655
656 if (num_pts >= 2) IntGdiPolyline( dc, line_pts, num_pts );
657 IntGdiMoveToEx( dc, line_pts[num_pts - 1].x, line_pts[num_pts - 1].y, NULL );
658 result = TRUE;
659 }
660
661 Cleanup:
662
663 if (line_pts != NULL)
664 {
665 ExFreePoolWithTag(line_pts, TAG_SHAPE);
666 }
667
668 if ((line_pts_old != NULL) && (line_pts_old != line_pts))
669 {
670 ExFreePoolWithTag(line_pts_old, TAG_SHAPE);
671 }
672
673 if (bzr_pts != NULL)
674 {
675 ExFreePoolWithTag(bzr_pts, TAG_BEZIER);
676 }
677
678 DC_UnlockDc(dc);
679
680 return result;
681 }
682
683 __kernel_entry
684 W32KAPI
685 BOOL
686 APIENTRY
NtGdiPolyDraw(_In_ HDC hdc,_In_reads_ (cpt)LPPOINT ppt,_In_reads_ (cpt)LPBYTE pjAttr,_In_ ULONG cpt)687 NtGdiPolyDraw(
688 _In_ HDC hdc,
689 _In_reads_(cpt) LPPOINT ppt,
690 _In_reads_(cpt) LPBYTE pjAttr,
691 _In_ ULONG cpt)
692 {
693 PBYTE pjBuffer;
694 PPOINT pptSafe;
695 PBYTE pjSafe;
696 SIZE_T cjSizePt;
697 BOOL bResult;
698
699 if (cpt == 0)
700 {
701 ERR("cpt is 0\n");
702 return FALSE;
703 }
704
705 /* Validate that cpt isn't too large */
706 if (cpt > ((MAXULONG - cpt) / sizeof(*ppt)))
707 {
708 ERR("cpt is too large\n", cpt);
709 return FALSE;
710 }
711
712 /* Calculate size for a buffer */
713 cjSizePt = cpt * sizeof(*ppt);
714 ASSERT(cjSizePt + cpt > cjSizePt);
715
716 /* Allocate a buffer for all data */
717 pjBuffer = ExAllocatePoolWithTag(PagedPool, cjSizePt + cpt, TAG_SHAPE);
718 if (pjBuffer == NULL)
719 {
720 ERR("Failed to allocate buffer\n");
721 return FALSE;
722 }
723
724 pptSafe = (PPOINT)pjBuffer;
725 pjSafe = pjBuffer + cjSizePt;
726
727 _SEH2_TRY
728 {
729 ProbeArrayForRead(ppt, sizeof(*ppt), cpt, sizeof(ULONG));
730 ProbeArrayForRead(pjAttr, sizeof(*pjAttr), cpt, sizeof(BYTE));
731
732 /* Copy the arrays */
733 RtlCopyMemory(pptSafe, ppt, cjSizePt);
734 RtlCopyMemory(pjSafe, pjAttr, cpt);
735 }
736 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
737 {
738 SetLastNtError(_SEH2_GetExceptionCode());
739 bResult = FALSE;
740 goto Cleanup;
741 }
742 _SEH2_END;
743
744 /* Call the internal function */
745 bResult = GdiPolyDraw(hdc, pptSafe, pjSafe, cpt);
746
747 Cleanup:
748
749 /* Free the buffer */
750 ExFreePoolWithTag(pjBuffer, TAG_SHAPE);
751
752 return bResult;
753 }
754
755 /*
756 * @implemented
757 */
758 _Success_(return != FALSE)
759 BOOL
760 APIENTRY
NtGdiMoveTo(IN HDC hdc,IN INT x,IN INT y,OUT OPTIONAL LPPOINT pptOut)761 NtGdiMoveTo(
762 IN HDC hdc,
763 IN INT x,
764 IN INT y,
765 OUT OPTIONAL LPPOINT pptOut)
766 {
767 PDC pdc;
768 BOOL Ret;
769 POINT Point;
770
771 pdc = DC_LockDc(hdc);
772 if (!pdc) return FALSE;
773
774 Ret = IntGdiMoveToEx(pdc, x, y, &Point);
775
776 if (Ret && pptOut)
777 {
778 _SEH2_TRY
779 {
780 ProbeForWrite(pptOut, sizeof(POINT), 1);
781 RtlCopyMemory(pptOut, &Point, sizeof(POINT));
782 }
783 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
784 {
785 SetLastNtError(_SEH2_GetExceptionCode());
786 Ret = FALSE; // CHECKME: is this correct?
787 }
788 _SEH2_END;
789 }
790
791 DC_UnlockDc(pdc);
792
793 return Ret;
794 }
795
796 /* EOF */
797