1 /*
2 * PROJECT: ReactOS win32 kernel mode subsystem
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: win32ss/gdi/ntgdi/fillshap.c
5 * PURPOSE: fillshap
6 * PROGRAMMER:
7 */
8
9 #include <win32k.h>
10
11 #define NDEBUG
12 #include <debug.h>
13
14 #define Rsin(d) ((d) == 0.0 ? 0.0 : ((d) == 90.0 ? 1.0 : sin(d*M_PI/180.0)))
15 #define Rcos(d) ((d) == 0.0 ? 1.0 : ((d) == 90.0 ? 0.0 : cos(d*M_PI/180.0)))
16
17 BOOL FASTCALL
IntGdiPolygon(PDC dc,PPOINT Points,int Count)18 IntGdiPolygon(PDC dc,
19 PPOINT Points,
20 int Count)
21 {
22 SURFACE *psurf;
23 PBRUSH pbrLine, pbrFill;
24 BOOL ret = FALSE; // Default to failure
25 RECTL DestRect;
26 INT i, CurrentPoint;
27 PDC_ATTR pdcattr;
28 POINTL BrushOrigin;
29 PPATH pPath;
30 // int Left;
31 // int Top;
32
33 ASSERT(dc); // Caller's responsibility to pass a valid dc
34
35 if (!Points || Count < 2 )
36 {
37 EngSetLastError(ERROR_INVALID_PARAMETER);
38 return FALSE;
39 }
40
41 /*
42 // Find start x, y
43 Left = Points[0].x;
44 Top = Points[0].y;
45 for (CurrentPoint = 1; CurrentPoint < Count; ++CurrentPoint) {
46 Left = min(Left, Points[CurrentPoint].x);
47 Top = min(Top, Points[CurrentPoint].y);
48 }
49 */
50
51 pdcattr = dc->pdcattr;
52
53 /* Convert to screen coordinates */
54 IntLPtoDP(dc, Points, Count);
55 for (CurrentPoint = 0; CurrentPoint < Count; CurrentPoint++)
56 {
57 Points[CurrentPoint].x += dc->ptlDCOrig.x;
58 Points[CurrentPoint].y += dc->ptlDCOrig.y;
59 }
60 // No need to have path here.
61 {
62 DestRect.left = Points[0].x;
63 DestRect.right = Points[0].x;
64 DestRect.top = Points[0].y;
65 DestRect.bottom = Points[0].y;
66
67 for (CurrentPoint = 1; CurrentPoint < Count; ++CurrentPoint)
68 {
69 DestRect.left = min(DestRect.left, Points[CurrentPoint].x);
70 DestRect.right = max(DestRect.right, Points[CurrentPoint].x);
71 DestRect.top = min(DestRect.top, Points[CurrentPoint].y);
72 DestRect.bottom = max(DestRect.bottom, Points[CurrentPoint].y);
73 }
74
75 if (pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
76 DC_vUpdateFillBrush(dc);
77
78 if (pdcattr->ulDirty_ & (DIRTY_LINE | DC_PEN_DIRTY))
79 DC_vUpdateLineBrush(dc);
80
81 /* Special locking order to avoid lock-ups */
82 pbrFill = dc->dclevel.pbrFill;
83 pbrLine = dc->dclevel.pbrLine;
84 psurf = dc->dclevel.pSurface;
85 if (psurf == NULL)
86 {
87 /* Memory DC without a bitmap selected, nothing to do. */
88 return TRUE;
89 }
90
91 /* Now fill the polygon with the current fill brush. */
92 if (!(pbrFill->flAttrs & BR_IS_NULL))
93 {
94 BrushOrigin = *((PPOINTL)&pbrFill->ptOrigin);
95 BrushOrigin.x += dc->ptlDCOrig.x;
96 BrushOrigin.y += dc->ptlDCOrig.y;
97 ret = IntFillPolygon (dc,
98 psurf,
99 &dc->eboFill.BrushObject,
100 Points,
101 Count,
102 DestRect,
103 &BrushOrigin);
104 }
105
106 // Draw the Polygon Edges with the current pen ( if not a NULL pen )
107 if (!(pbrLine->flAttrs & BR_IS_NULL))
108 {
109 if (IntIsEffectiveWidePen(pbrLine))
110 {
111 /* Clear the path */
112 PATH_Delete(dc->dclevel.hPath);
113 dc->dclevel.hPath = NULL;
114
115 /* Begin a path */
116 pPath = PATH_CreatePath(Count + 1);
117 dc->dclevel.flPath |= DCPATH_ACTIVE;
118 dc->dclevel.hPath = pPath->BaseObject.hHmgr;
119 pPath->pos = Points[0];
120 IntLPtoDP(dc, &pPath->pos, 1);
121
122 PATH_MoveTo(dc, pPath);
123 for (i = 1; i < Count; ++i)
124 {
125 PATH_LineTo(dc, Points[i].x, Points[i].y);
126 }
127 PATH_LineTo(dc, Points[0].x, Points[0].y);
128
129 /* Close the path */
130 pPath->state = PATH_Closed;
131 dc->dclevel.flPath &= ~DCPATH_ACTIVE;
132
133 /* Actually stroke a path */
134 ret = PATH_StrokePath(dc, pPath);
135
136 /* Clear the path */
137 PATH_UnlockPath(pPath);
138 PATH_Delete(dc->dclevel.hPath);
139 dc->dclevel.hPath = NULL;
140 }
141 else
142 {
143 for (i = 0; i < Count-1; i++)
144 {
145 // DPRINT1("Polygon Making line from (%d,%d) to (%d,%d)\n",
146 // Points[0].x, Points[0].y,
147 // Points[1].x, Points[1].y );
148
149 ret = IntEngLineTo(&psurf->SurfObj,
150 (CLIPOBJ *)&dc->co,
151 &dc->eboLine.BrushObject,
152 Points[i].x, /* From */
153 Points[i].y,
154 Points[i+1].x, /* To */
155 Points[i+1].y,
156 &DestRect,
157 ROP2_TO_MIX(pdcattr->jROP2)); /* MIX */
158 if (!ret) break;
159 }
160 /* Close the polygon */
161 if (ret)
162 {
163 ret = IntEngLineTo(&psurf->SurfObj,
164 (CLIPOBJ *)&dc->co,
165 &dc->eboLine.BrushObject,
166 Points[Count-1].x, /* From */
167 Points[Count-1].y,
168 Points[0].x, /* To */
169 Points[0].y,
170 &DestRect,
171 ROP2_TO_MIX(pdcattr->jROP2)); /* MIX */
172 }
173 }
174 }
175 }
176
177 return ret;
178 }
179
180 BOOL FASTCALL
IntGdiPolyPolygon(DC * dc,LPPOINT Points,PULONG PolyCounts,int Count)181 IntGdiPolyPolygon(DC *dc,
182 LPPOINT Points,
183 PULONG PolyCounts,
184 int Count)
185 {
186 if (PATH_IsPathOpen(dc->dclevel))
187 return PATH_PolyPolygon ( dc, Points, (PINT)PolyCounts, Count);
188
189 while (--Count >=0)
190 {
191 if (!IntGdiPolygon ( dc, Points, *PolyCounts ))
192 return FALSE;
193 Points+=*PolyCounts++;
194 }
195 return TRUE;
196 }
197
198 BOOL FASTCALL
IntPolygon(HDC hdc,POINT * Point,int Count)199 IntPolygon(HDC hdc, POINT *Point, int Count)
200 {
201 BOOL bResult;
202 PDC pdc;
203
204 pdc = DC_LockDc(hdc);
205 if (pdc == NULL)
206 {
207 EngSetLastError(ERROR_INVALID_HANDLE);
208 return FALSE;
209 }
210
211 bResult = IntGdiPolygon(pdc, Point, Count);
212
213 DC_UnlockDc(pdc);
214 return bResult;
215 }
216
217
218 /******************************************************************************/
219
220 /*
221 * NtGdiEllipse
222 *
223 * Author
224 * Filip Navara
225 *
226 * Remarks
227 * This function uses optimized Bresenham's ellipse algorithm. It draws
228 * four lines of the ellipse in one pass.
229 *
230 */
231
232 BOOL APIENTRY
NtGdiEllipse(HDC hDC,int Left,int Top,int Right,int Bottom)233 NtGdiEllipse(
234 HDC hDC,
235 int Left,
236 int Top,
237 int Right,
238 int Bottom)
239 {
240 PDC dc;
241 PDC_ATTR pdcattr;
242 RECTL RectBounds;
243 PBRUSH pbrush;
244 BOOL ret = TRUE;
245 LONG PenWidth, PenOrigWidth;
246 LONG RadiusX, RadiusY, CenterX, CenterY;
247 PBRUSH pFillBrushObj;
248 BRUSH tmpFillBrushObj;
249
250 dc = DC_LockDc(hDC);
251 if (dc == NULL)
252 {
253 EngSetLastError(ERROR_INVALID_HANDLE);
254 return FALSE;
255 }
256
257 if (PATH_IsPathOpen(dc->dclevel))
258 {
259 ret = PATH_Ellipse(dc, Left, Top, Right, Bottom);
260 DC_UnlockDc(dc);
261 return ret;
262 }
263
264 ////
265 //// Could this use PATH_CheckCorners ?
266 ////
267 if ((Left == Right) || (Top == Bottom))
268 {
269 DC_UnlockDc(dc);
270 return TRUE;
271 }
272
273 if (Right < Left)
274 {
275 INT tmp = Right; Right = Left; Left = tmp;
276 }
277 if (Bottom < Top)
278 {
279 INT tmp = Bottom; Bottom = Top; Top = tmp;
280 }
281 ////
282
283 pdcattr = dc->pdcattr;
284
285 if (pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
286 DC_vUpdateFillBrush(dc);
287
288 if (pdcattr->ulDirty_ & (DIRTY_LINE | DC_PEN_DIRTY))
289 DC_vUpdateLineBrush(dc);
290
291 pbrush = PEN_ShareLockPen(pdcattr->hpen);
292 if (!pbrush)
293 {
294 DPRINT1("Ellipse Fail 1\n");
295 DC_UnlockDc(dc);
296 EngSetLastError(ERROR_INTERNAL_ERROR);
297 return FALSE;
298 }
299
300 PenOrigWidth = PenWidth = pbrush->lWidth;
301 if (pbrush->ulPenStyle == PS_NULL) PenWidth = 0;
302
303 if (pbrush->ulPenStyle == PS_INSIDEFRAME)
304 {
305 if (2*PenWidth > (Right - Left)) PenWidth = (Right -Left + 1)/2;
306 if (2*PenWidth > (Bottom - Top)) PenWidth = (Bottom -Top + 1)/2;
307 Left += PenWidth / 2;
308 Right -= (PenWidth - 1) / 2;
309 Top += PenWidth / 2;
310 Bottom -= (PenWidth - 1) / 2;
311 }
312
313 if (!PenWidth) PenWidth = 1;
314 pbrush->lWidth = PenWidth;
315
316 RectBounds.left = Left;
317 RectBounds.right = Right;
318 RectBounds.top = Top;
319 RectBounds.bottom = Bottom;
320
321 IntLPtoDP(dc, (LPPOINT)&RectBounds, 2);
322
323 RectBounds.left += dc->ptlDCOrig.x;
324 RectBounds.right += dc->ptlDCOrig.x;
325 RectBounds.top += dc->ptlDCOrig.y;
326 RectBounds.bottom += dc->ptlDCOrig.y;
327
328 // Setup for dynamic width and height.
329 RadiusX = max((RectBounds.right - RectBounds.left) / 2, 2); // Needs room
330 RadiusY = max((RectBounds.bottom - RectBounds.top) / 2, 2);
331 CenterX = (RectBounds.right + RectBounds.left) / 2;
332 CenterY = (RectBounds.bottom + RectBounds.top) / 2;
333
334 DPRINT("Ellipse 1: Left: %d, Top: %d, Right: %d, Bottom: %d\n",
335 RectBounds.left,RectBounds.top,RectBounds.right,RectBounds.bottom);
336
337 DPRINT("Ellipse 2: XLeft: %d, YLeft: %d, Width: %d, Height: %d\n",
338 CenterX - RadiusX, CenterY + RadiusY, RadiusX*2, RadiusY*2);
339
340 pFillBrushObj = BRUSH_ShareLockBrush(pdcattr->hbrush);
341 if (NULL == pFillBrushObj)
342 {
343 DPRINT1("FillEllipse Fail\n");
344 EngSetLastError(ERROR_INTERNAL_ERROR);
345 ret = FALSE;
346 }
347 else
348 {
349 RtlCopyMemory(&tmpFillBrushObj, pFillBrushObj, sizeof(tmpFillBrushObj));
350 //tmpFillBrushObj.ptOrigin.x += RectBounds.left - Left;
351 //tmpFillBrushObj.ptOrigin.y += RectBounds.top - Top;
352 tmpFillBrushObj.ptOrigin.x += dc->ptlDCOrig.x;
353 tmpFillBrushObj.ptOrigin.y += dc->ptlDCOrig.y;
354
355 DC_vPrepareDCsForBlit(dc, &RectBounds, NULL, NULL);
356
357 ret = IntFillEllipse( dc,
358 CenterX - RadiusX,
359 CenterY - RadiusY,
360 RadiusX*2, // Width
361 RadiusY*2, // Height
362 &tmpFillBrushObj);
363 BRUSH_ShareUnlockBrush(pFillBrushObj);
364
365 if (ret)
366 {
367 ret = IntDrawEllipse( dc,
368 CenterX - RadiusX,
369 CenterY - RadiusY,
370 RadiusX*2, // Width
371 RadiusY*2, // Height
372 pbrush);
373 }
374
375 DC_vFinishBlit(dc, NULL);
376 }
377
378 pbrush->lWidth = PenOrigWidth;
379 PEN_ShareUnlockPen(pbrush);
380 DC_UnlockDc(dc);
381 DPRINT("Ellipse Exit.\n");
382 return ret;
383 }
384
385 #if 0
386
387 // When the fill mode is ALTERNATE, GDI fills the area between odd-numbered and
388 // even-numbered polygon sides on each scan line. That is, GDI fills the area between the
389 // first and second side, between the third and fourth side, and so on.
390
391 // WINDING Selects winding mode (fills any region with a nonzero winding value).
392 // When the fill mode is WINDING, GDI fills any region that has a nonzero winding value.
393 // This value is defined as the number of times a pen used to draw the polygon would go around the region.
394 // The direction of each edge of the polygon is important.
395
396 extern BOOL FillPolygon(PDC dc,
397 SURFOBJ *SurfObj,
398 PBRUSHOBJ BrushObj,
399 MIX RopMode,
400 CONST PPOINT Points,
401 int Count,
402 RECTL BoundRect);
403
404 #endif
405
406
407 ULONG_PTR
408 APIENTRY
NtGdiPolyPolyDraw(IN HDC hDC,IN PPOINT UnsafePoints,IN PULONG UnsafeCounts,IN ULONG Count,IN INT iFunc)409 NtGdiPolyPolyDraw( IN HDC hDC,
410 IN PPOINT UnsafePoints,
411 IN PULONG UnsafeCounts,
412 IN ULONG Count,
413 IN INT iFunc )
414 {
415 DC *dc;
416 PVOID pTemp;
417 LPPOINT SafePoints;
418 PULONG SafeCounts;
419 NTSTATUS Status = STATUS_SUCCESS;
420 BOOL Ret = TRUE;
421 ULONG nPoints = 0, nMaxPoints = 0, nInvalid = 0, i;
422
423 if (!UnsafePoints || !UnsafeCounts ||
424 Count == 0 || iFunc == 0 || iFunc > GdiPolyPolyRgn)
425 {
426 /* Windows doesn't set last error */
427 return FALSE;
428 }
429
430 _SEH2_TRY
431 {
432 ProbeForRead(UnsafePoints, Count * sizeof(POINT), 1);
433 ProbeForRead(UnsafeCounts, Count * sizeof(ULONG), 1);
434
435 /* Count points and validate poligons */
436 for (i = 0; i < Count; i++)
437 {
438 if (UnsafeCounts[i] < 2)
439 {
440 nInvalid++;
441 }
442 nPoints += UnsafeCounts[i];
443 nMaxPoints = max(nMaxPoints, UnsafeCounts[i]);
444 }
445 }
446 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
447 {
448 Status = _SEH2_GetExceptionCode();
449 }
450 _SEH2_END;
451
452 if (!NT_SUCCESS(Status))
453 {
454 /* Windows doesn't set last error */
455 return FALSE;
456 }
457
458 if (nPoints == 0 || nPoints < nMaxPoints)
459 {
460 /* If all polygon counts are zero, or we have overflow,
461 return without setting a last error code. */
462 return FALSE;
463 }
464
465 if (nInvalid != 0)
466 {
467 /* If at least one poly count is 0 or 1, fail */
468 EngSetLastError(ERROR_INVALID_PARAMETER);
469 return FALSE;
470 }
471
472 /* Allocate one buffer for both counts and points */
473 pTemp = ExAllocatePoolWithTag(PagedPool,
474 Count * sizeof(ULONG) + nPoints * sizeof(POINT),
475 TAG_SHAPE);
476 if (!pTemp)
477 {
478 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
479 return FALSE;
480 }
481
482 SafeCounts = pTemp;
483 SafePoints = (PVOID)(SafeCounts + Count);
484
485 _SEH2_TRY
486 {
487 /* Pointers already probed! */
488 RtlCopyMemory(SafeCounts, UnsafeCounts, Count * sizeof(ULONG));
489 RtlCopyMemory(SafePoints, UnsafePoints, nPoints * sizeof(POINT));
490 }
491 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
492 {
493 Status = _SEH2_GetExceptionCode();
494 }
495 _SEH2_END;
496
497 if (!NT_SUCCESS(Status))
498 {
499 ExFreePoolWithTag(pTemp, TAG_SHAPE);
500 return FALSE;
501 }
502
503 /* Special handling for GdiPolyPolyRgn */
504 if (iFunc == GdiPolyPolyRgn)
505 {
506 INT iMode = (INT)(UINT_PTR)hDC;
507 HRGN hrgn;
508
509 hrgn = GreCreatePolyPolygonRgn(SafePoints, SafeCounts, Count, iMode);
510
511 ExFreePoolWithTag(pTemp, TAG_SHAPE);
512 return (ULONG_PTR)hrgn;
513 }
514
515 dc = DC_LockDc(hDC);
516 if (!dc)
517 {
518 EngSetLastError(ERROR_INVALID_HANDLE);
519 ExFreePoolWithTag(pTemp, TAG_SHAPE);
520 return FALSE;
521 }
522
523 DC_vPrepareDCsForBlit(dc, NULL, NULL, NULL);
524
525 if (dc->pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
526 DC_vUpdateFillBrush(dc);
527
528 if (dc->pdcattr->ulDirty_ & (DIRTY_LINE | DC_PEN_DIRTY))
529 DC_vUpdateLineBrush(dc);
530
531 /* Perform the actual work */
532 switch (iFunc)
533 {
534 case GdiPolyPolygon:
535 Ret = IntGdiPolyPolygon(dc, SafePoints, SafeCounts, Count);
536 break;
537 case GdiPolyPolyLine:
538 Ret = IntGdiPolyPolyline(dc, SafePoints, SafeCounts, Count);
539 break;
540 case GdiPolyBezier:
541 Ret = IntGdiPolyBezier(dc, SafePoints, *SafeCounts);
542 break;
543 case GdiPolyLineTo:
544 Ret = IntGdiPolylineTo(dc, SafePoints, *SafeCounts);
545 break;
546 case GdiPolyBezierTo:
547 Ret = IntGdiPolyBezierTo(dc, SafePoints, *SafeCounts);
548 break;
549 default:
550 EngSetLastError(ERROR_INVALID_PARAMETER);
551 Ret = FALSE;
552 }
553
554 /* Cleanup and return */
555 DC_vFinishBlit(dc, NULL);
556 DC_UnlockDc(dc);
557 ExFreePoolWithTag(pTemp, TAG_SHAPE);
558
559 return (ULONG_PTR)Ret;
560 }
561
562
563 BOOL
564 FASTCALL
IntRectangle(PDC dc,int LeftRect,int TopRect,int RightRect,int BottomRect)565 IntRectangle(PDC dc,
566 int LeftRect,
567 int TopRect,
568 int RightRect,
569 int BottomRect)
570 {
571 SURFACE *psurf = NULL;
572 PBRUSH pbrLine, pbrFill;
573 BOOL ret = FALSE; // Default to failure
574 RECTL DestRect;
575 MIX Mix;
576 PDC_ATTR pdcattr;
577 POINTL BrushOrigin;
578 PPATH pPath;
579
580 ASSERT ( dc ); // Caller's responsibility to set this up
581
582 pdcattr = dc->pdcattr;
583
584 // Rectangle Path only.
585 if ( PATH_IsPathOpen(dc->dclevel) )
586 {
587 return PATH_Rectangle ( dc, LeftRect, TopRect, RightRect, BottomRect );
588 }
589
590 /* Make sure rectangle is not inverted */
591 DestRect.left = min(LeftRect, RightRect);
592 DestRect.right = max(LeftRect, RightRect);
593 DestRect.top = min(TopRect, BottomRect);
594 DestRect.bottom = max(TopRect, BottomRect);
595
596 IntLPtoDP(dc, (LPPOINT)&DestRect, 2);
597
598 DestRect.left += dc->ptlDCOrig.x;
599 DestRect.right += dc->ptlDCOrig.x;
600 DestRect.top += dc->ptlDCOrig.y;
601 DestRect.bottom += dc->ptlDCOrig.y;
602
603 if (dc->fs & (DC_ACCUM_APP|DC_ACCUM_WMGR))
604 {
605 IntUpdateBoundsRect(dc, &DestRect);
606 }
607
608 /* In GM_COMPATIBLE, don't include bottom and right edges */
609 if (pdcattr->iGraphicsMode == GM_COMPATIBLE)
610 {
611 DestRect.right--;
612 DestRect.bottom--;
613 }
614
615 DC_vPrepareDCsForBlit(dc, &DestRect, NULL, NULL);
616
617 if (pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
618 DC_vUpdateFillBrush(dc);
619
620 if (pdcattr->ulDirty_ & (DIRTY_LINE | DC_PEN_DIRTY))
621 DC_vUpdateLineBrush(dc);
622
623 pbrFill = dc->dclevel.pbrFill;
624 pbrLine = dc->dclevel.pbrLine;
625 if (!pbrLine)
626 {
627 ret = FALSE;
628 goto cleanup;
629 }
630
631 psurf = dc->dclevel.pSurface;
632 if (!psurf)
633 {
634 ret = TRUE;
635 goto cleanup;
636 }
637
638 if (pbrFill)
639 {
640 if (!(pbrFill->flAttrs & BR_IS_NULL))
641 {
642 BrushOrigin = *((PPOINTL)&pbrFill->ptOrigin);
643 BrushOrigin.x += dc->ptlDCOrig.x;
644 BrushOrigin.y += dc->ptlDCOrig.y;
645 ret = IntEngBitBlt(&psurf->SurfObj,
646 NULL,
647 NULL,
648 (CLIPOBJ *)&dc->co,
649 NULL,
650 &DestRect,
651 NULL,
652 NULL,
653 &dc->eboFill.BrushObject,
654 &BrushOrigin,
655 ROP4_FROM_INDEX(R3_OPINDEX_PATCOPY));
656 }
657 }
658
659 // Draw the rectangle with the current pen
660
661 ret = TRUE; // Change default to success
662
663 if (!(pbrLine->flAttrs & BR_IS_NULL))
664 {
665 if (IntIsEffectiveWidePen(pbrLine))
666 {
667 /* Clear the path */
668 PATH_Delete(dc->dclevel.hPath);
669 dc->dclevel.hPath = NULL;
670
671 /* Begin a path */
672 pPath = PATH_CreatePath(5);
673 dc->dclevel.flPath |= DCPATH_ACTIVE;
674 dc->dclevel.hPath = pPath->BaseObject.hHmgr;
675 pPath->pos.x = LeftRect;
676 pPath->pos.y = TopRect;
677 IntLPtoDP(dc, &pPath->pos, 1);
678
679 PATH_MoveTo(dc, pPath);
680 PATH_LineTo(dc, RightRect, TopRect);
681 PATH_LineTo(dc, RightRect, BottomRect);
682 PATH_LineTo(dc, LeftRect, BottomRect);
683 PATH_LineTo(dc, LeftRect, TopRect);
684
685 /* Close the path */
686 pPath->state = PATH_Closed;
687 dc->dclevel.flPath &= ~DCPATH_ACTIVE;
688
689 /* Actually stroke a path */
690 ret = PATH_StrokePath(dc, pPath);
691
692 /* Clear the path */
693 PATH_UnlockPath(pPath);
694 PATH_Delete(dc->dclevel.hPath);
695 dc->dclevel.hPath = NULL;
696 }
697 else
698 {
699 Mix = ROP2_TO_MIX(pdcattr->jROP2);
700 ret = ret && IntEngLineTo(&psurf->SurfObj,
701 (CLIPOBJ *)&dc->co,
702 &dc->eboLine.BrushObject,
703 DestRect.left, DestRect.top, DestRect.right, DestRect.top,
704 &DestRect, // Bounding rectangle
705 Mix);
706
707 ret = ret && IntEngLineTo(&psurf->SurfObj,
708 (CLIPOBJ *)&dc->co,
709 &dc->eboLine.BrushObject,
710 DestRect.right, DestRect.top, DestRect.right, DestRect.bottom,
711 &DestRect, // Bounding rectangle
712 Mix);
713
714 ret = ret && IntEngLineTo(&psurf->SurfObj,
715 (CLIPOBJ *)&dc->co,
716 &dc->eboLine.BrushObject,
717 DestRect.right, DestRect.bottom, DestRect.left, DestRect.bottom,
718 &DestRect, // Bounding rectangle
719 Mix);
720
721 ret = ret && IntEngLineTo(&psurf->SurfObj,
722 (CLIPOBJ *)&dc->co,
723 &dc->eboLine.BrushObject,
724 DestRect.left, DestRect.bottom, DestRect.left, DestRect.top,
725 &DestRect, // Bounding rectangle
726 Mix);
727 }
728 }
729
730 cleanup:
731 DC_vFinishBlit(dc, NULL);
732
733 /* Move current position in DC?
734 MSDN: The current position is neither used nor updated by Rectangle. */
735
736 return ret;
737 }
738
739 BOOL
740 APIENTRY
NtGdiRectangle(HDC hDC,int LeftRect,int TopRect,int RightRect,int BottomRect)741 NtGdiRectangle(HDC hDC,
742 int LeftRect,
743 int TopRect,
744 int RightRect,
745 int BottomRect)
746 {
747 DC *dc;
748 BOOL ret; // Default to failure
749
750 dc = DC_LockDc(hDC);
751 if (!dc)
752 {
753 EngSetLastError(ERROR_INVALID_HANDLE);
754 return FALSE;
755 }
756
757 /* Do we rotate or shear? */
758 if (!(dc->pdcattr->mxWorldToDevice.flAccel & XFORM_SCALE))
759 {
760 POINTL DestCoords[4];
761 ULONG PolyCounts = 4;
762
763 DestCoords[0].x = DestCoords[3].x = LeftRect;
764 DestCoords[0].y = DestCoords[1].y = TopRect;
765 DestCoords[1].x = DestCoords[2].x = RightRect;
766 DestCoords[2].y = DestCoords[3].y = BottomRect;
767 // Use IntGdiPolyPolygon so to support PATH.
768 ret = IntGdiPolyPolygon(dc, DestCoords, &PolyCounts, 1);
769 }
770 else
771 {
772 ret = IntRectangle(dc, LeftRect, TopRect, RightRect, BottomRect );
773 }
774
775 DC_UnlockDc(dc);
776
777 return ret;
778 }
779
780
781 BOOL
782 FASTCALL
IntRoundRect(PDC dc,int Left,int Top,int Right,int Bottom,int xCurveDiameter,int yCurveDiameter)783 IntRoundRect(
784 PDC dc,
785 int Left,
786 int Top,
787 int Right,
788 int Bottom,
789 int xCurveDiameter,
790 int yCurveDiameter)
791 {
792 PDC_ATTR pdcattr;
793 PBRUSH pbrLine, pbrFill;
794 RECTL RectBounds;
795 LONG PenWidth, PenOrigWidth;
796 BOOL ret = TRUE; // Default to success
797 BRUSH brushTemp;
798
799 ASSERT ( dc ); // Caller's responsibility to set this up
800
801 if ( PATH_IsPathOpen(dc->dclevel) )
802 return PATH_RoundRect ( dc, Left, Top, Right, Bottom,
803 xCurveDiameter, yCurveDiameter );
804
805 if ((Left == Right) || (Top == Bottom)) return TRUE;
806
807 xCurveDiameter = max(abs( xCurveDiameter ), 1);
808 yCurveDiameter = max(abs( yCurveDiameter ), 1);
809
810 if (Right < Left)
811 {
812 INT tmp = Right; Right = Left; Left = tmp;
813 }
814 if (Bottom < Top)
815 {
816 INT tmp = Bottom; Bottom = Top; Top = tmp;
817 }
818
819 pdcattr = dc->pdcattr;
820
821 if (pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
822 DC_vUpdateFillBrush(dc);
823
824 if (pdcattr->ulDirty_ & (DIRTY_LINE | DC_PEN_DIRTY))
825 DC_vUpdateLineBrush(dc);
826
827 pbrLine = PEN_ShareLockPen(pdcattr->hpen);
828 if (!pbrLine)
829 {
830 /* Nothing to do, as we don't have a bitmap */
831 EngSetLastError(ERROR_INTERNAL_ERROR);
832 return FALSE;
833 }
834
835 PenOrigWidth = PenWidth = pbrLine->lWidth;
836 if (pbrLine->ulPenStyle == PS_NULL) PenWidth = 0;
837
838 if (pbrLine->ulPenStyle == PS_INSIDEFRAME)
839 {
840 if (2*PenWidth > (Right - Left)) PenWidth = (Right -Left + 1)/2;
841 if (2*PenWidth > (Bottom - Top)) PenWidth = (Bottom -Top + 1)/2;
842 Left += PenWidth / 2;
843 Right -= (PenWidth - 1) / 2;
844 Top += PenWidth / 2;
845 Bottom -= (PenWidth - 1) / 2;
846 }
847
848 if (!PenWidth) PenWidth = 1;
849 pbrLine->lWidth = PenWidth;
850
851 RectBounds.left = Left;
852 RectBounds.top = Top;
853 RectBounds.right = Right;
854 RectBounds.bottom = Bottom;
855
856 IntLPtoDP(dc, (LPPOINT)&RectBounds, 2);
857
858 RectBounds.left += dc->ptlDCOrig.x;
859 RectBounds.top += dc->ptlDCOrig.y;
860 RectBounds.right += dc->ptlDCOrig.x;
861 RectBounds.bottom += dc->ptlDCOrig.y;
862
863 pbrFill = BRUSH_ShareLockBrush(pdcattr->hbrush);
864 if (!pbrFill)
865 {
866 DPRINT1("FillRound Fail\n");
867 EngSetLastError(ERROR_INTERNAL_ERROR);
868 ret = FALSE;
869 }
870 else
871 {
872
873 DC_vPrepareDCsForBlit(dc, &RectBounds, NULL, NULL);
874
875 RtlCopyMemory(&brushTemp, pbrFill, sizeof(brushTemp));
876 brushTemp.ptOrigin.x += RectBounds.left - Left;
877 brushTemp.ptOrigin.y += RectBounds.top - Top;
878 ret = IntFillRoundRect( dc,
879 RectBounds.left,
880 RectBounds.top,
881 RectBounds.right,
882 RectBounds.bottom,
883 xCurveDiameter,
884 yCurveDiameter,
885 &brushTemp);
886 BRUSH_ShareUnlockBrush(pbrFill);
887
888 if (ret)
889 {
890 ret = IntDrawRoundRect( dc,
891 RectBounds.left,
892 RectBounds.top,
893 RectBounds.right,
894 RectBounds.bottom,
895 xCurveDiameter,
896 yCurveDiameter,
897 pbrLine);
898 }
899
900 DC_vFinishBlit(dc, NULL);
901 }
902
903
904 pbrLine->lWidth = PenOrigWidth;
905 PEN_ShareUnlockPen(pbrLine);
906 return ret;
907 }
908
909 BOOL
910 APIENTRY
NtGdiRoundRect(HDC hDC,int LeftRect,int TopRect,int RightRect,int BottomRect,int Width,int Height)911 NtGdiRoundRect(
912 HDC hDC,
913 int LeftRect,
914 int TopRect,
915 int RightRect,
916 int BottomRect,
917 int Width,
918 int Height)
919 {
920 DC *dc = DC_LockDc(hDC);
921 BOOL ret = FALSE; /* Default to failure */
922
923 DPRINT("NtGdiRoundRect(0x%p,%i,%i,%i,%i,%i,%i)\n",hDC,LeftRect,TopRect,RightRect,BottomRect,Width,Height);
924 if ( !dc )
925 {
926 DPRINT1("NtGdiRoundRect() - hDC is invalid\n");
927 EngSetLastError(ERROR_INVALID_HANDLE);
928 }
929 else
930 {
931 ret = IntRoundRect ( dc, LeftRect, TopRect, RightRect, BottomRect, Width, Height );
932 DC_UnlockDc ( dc );
933 }
934
935 return ret;
936 }
937
938 BOOL
939 NTAPI
GreGradientFill(HDC hdc,PTRIVERTEX pVertex,ULONG nVertex,PVOID pMesh,ULONG nMesh,ULONG ulMode)940 GreGradientFill(
941 HDC hdc,
942 PTRIVERTEX pVertex,
943 ULONG nVertex,
944 PVOID pMesh,
945 ULONG nMesh,
946 ULONG ulMode)
947 {
948 PDC pdc;
949 SURFACE *psurf;
950 EXLATEOBJ exlo;
951 RECTL rclExtent;
952 POINTL ptlDitherOrg;
953 ULONG i;
954 BOOL bRet;
955
956 /* Check parameters */
957 if (ulMode & GRADIENT_FILL_TRIANGLE)
958 {
959 PGRADIENT_TRIANGLE pTriangle = (PGRADIENT_TRIANGLE)pMesh;
960
961 for (i = 0; i < nMesh; i++, pTriangle++)
962 {
963 if (pTriangle->Vertex1 >= nVertex ||
964 pTriangle->Vertex2 >= nVertex ||
965 pTriangle->Vertex3 >= nVertex)
966 {
967 EngSetLastError(ERROR_INVALID_PARAMETER);
968 return FALSE;
969 }
970 }
971 }
972 else
973 {
974 PGRADIENT_RECT pRect = (PGRADIENT_RECT)pMesh;
975 for (i = 0; i < nMesh; i++, pRect++)
976 {
977 if (pRect->UpperLeft >= nVertex || pRect->LowerRight >= nVertex)
978 {
979 EngSetLastError(ERROR_INVALID_PARAMETER);
980 return FALSE;
981 }
982 }
983 }
984
985 /* Lock the output DC */
986 pdc = DC_LockDc(hdc);
987 if(!pdc)
988 {
989 EngSetLastError(ERROR_INVALID_HANDLE);
990 return FALSE;
991 }
992
993 if (!pdc->dclevel.pSurface)
994 {
995 /* Memory DC with no surface selected */
996 DC_UnlockDc(pdc);
997 return TRUE; // CHECKME
998 }
999
1000 /* Calculate extent */
1001 rclExtent.left = rclExtent.right = pVertex->x;
1002 rclExtent.top = rclExtent.bottom = pVertex->y;
1003 for (i = 0; i < nVertex; i++)
1004 {
1005 rclExtent.left = min(rclExtent.left, (pVertex + i)->x);
1006 rclExtent.right = max(rclExtent.right, (pVertex + i)->x);
1007 rclExtent.top = min(rclExtent.top, (pVertex + i)->y);
1008 rclExtent.bottom = max(rclExtent.bottom, (pVertex + i)->y);
1009 }
1010 IntLPtoDP(pdc, (LPPOINT)&rclExtent, 2);
1011
1012 rclExtent.left += pdc->ptlDCOrig.x;
1013 rclExtent.right += pdc->ptlDCOrig.x;
1014 rclExtent.top += pdc->ptlDCOrig.y;
1015 rclExtent.bottom += pdc->ptlDCOrig.y;
1016
1017 if (RECTL_bIsEmptyRect(&rclExtent))
1018 {
1019 DC_UnlockDc(pdc);
1020 return TRUE;
1021 }
1022
1023 ptlDitherOrg.x = ptlDitherOrg.y = 0;
1024 IntLPtoDP(pdc, (LPPOINT)&ptlDitherOrg, 1);
1025
1026 ptlDitherOrg.x += pdc->ptlDCOrig.x;
1027 ptlDitherOrg.y += pdc->ptlDCOrig.y;
1028
1029 if (pdc->fs & (DC_ACCUM_APP|DC_ACCUM_WMGR))
1030 {
1031 IntUpdateBoundsRect(pdc, &rclExtent);
1032 }
1033
1034 DC_vPrepareDCsForBlit(pdc, &rclExtent, NULL, NULL);
1035
1036 psurf = pdc->dclevel.pSurface;
1037
1038 EXLATEOBJ_vInitialize(&exlo, &gpalRGB, psurf->ppal, 0, 0, 0);
1039
1040 bRet = IntEngGradientFill(&psurf->SurfObj,
1041 (CLIPOBJ *)&pdc->co,
1042 &exlo.xlo,
1043 pVertex,
1044 nVertex,
1045 pMesh,
1046 nMesh,
1047 &rclExtent,
1048 &ptlDitherOrg,
1049 ulMode);
1050
1051 EXLATEOBJ_vCleanup(&exlo);
1052 DC_vFinishBlit(pdc, NULL);
1053 DC_UnlockDc(pdc);
1054
1055 return bRet;
1056 }
1057
1058 BOOL
1059 APIENTRY
NtGdiGradientFill(HDC hdc,PTRIVERTEX pVertex,ULONG nVertex,PVOID pMesh,ULONG nMesh,ULONG ulMode)1060 NtGdiGradientFill(
1061 HDC hdc,
1062 PTRIVERTEX pVertex,
1063 ULONG nVertex,
1064 PVOID pMesh,
1065 ULONG nMesh,
1066 ULONG ulMode)
1067 {
1068 BOOL bRet;
1069 PTRIVERTEX SafeVertex;
1070 PVOID SafeMesh;
1071 ULONG cbVertex, cbMesh;
1072
1073 /* Validate parameters */
1074 if (!pVertex || !nVertex || !pMesh || !nMesh)
1075 {
1076 EngSetLastError(ERROR_INVALID_PARAMETER);
1077 return FALSE;
1078 }
1079
1080 switch (ulMode)
1081 {
1082 case GRADIENT_FILL_RECT_H:
1083 case GRADIENT_FILL_RECT_V:
1084 cbMesh = nMesh * sizeof(GRADIENT_RECT);
1085 break;
1086 case GRADIENT_FILL_TRIANGLE:
1087 cbMesh = nMesh * sizeof(GRADIENT_TRIANGLE);
1088 break;
1089 default:
1090 EngSetLastError(ERROR_INVALID_PARAMETER);
1091 return FALSE;
1092 }
1093
1094 cbVertex = nVertex * sizeof(TRIVERTEX) ;
1095 if(cbVertex + cbMesh <= cbVertex)
1096 {
1097 /* Overflow */
1098 return FALSE ;
1099 }
1100
1101 /* Allocate a kernel mode buffer */
1102 SafeVertex = ExAllocatePoolWithTag(PagedPool, cbVertex + cbMesh, TAG_SHAPE);
1103 if(!SafeVertex)
1104 {
1105 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
1106 return FALSE;
1107 }
1108
1109 SafeMesh = (PVOID)((ULONG_PTR)SafeVertex + cbVertex);
1110
1111 /* Copy the parameters to kernel mode */
1112 _SEH2_TRY
1113 {
1114 ProbeForRead(pVertex, cbVertex, 1);
1115 ProbeForRead(pMesh, cbMesh, 1);
1116 RtlCopyMemory(SafeVertex, pVertex, cbVertex);
1117 RtlCopyMemory(SafeMesh, pMesh, cbMesh);
1118 }
1119 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1120 {
1121 ExFreePoolWithTag(SafeVertex, TAG_SHAPE);
1122 SetLastNtError(_SEH2_GetExceptionCode());
1123 _SEH2_YIELD(return FALSE;)
1124 }
1125 _SEH2_END;
1126
1127 /* Call the internal function */
1128 bRet = GreGradientFill(hdc, SafeVertex, nVertex, SafeMesh, nMesh, ulMode);
1129
1130 /* Cleanup and return result */
1131 ExFreePoolWithTag(SafeVertex, TAG_SHAPE);
1132 return bRet;
1133 }
1134
1135 BOOL APIENTRY
NtGdiExtFloodFill(HDC hDC,INT XStart,INT YStart,COLORREF Color,UINT FillType)1136 NtGdiExtFloodFill(
1137 HDC hDC,
1138 INT XStart,
1139 INT YStart,
1140 COLORREF Color,
1141 UINT FillType)
1142 {
1143 PDC dc;
1144 #if 0
1145 PDC_ATTR pdcattr;
1146 #endif
1147 SURFACE *psurf;
1148 EXLATEOBJ exlo;
1149 BOOL Ret = FALSE;
1150 RECTL DestRect;
1151 POINTL Pt;
1152 ULONG ConvColor;
1153 PREGION prgn;
1154
1155 dc = DC_LockDc(hDC);
1156 if (!dc)
1157 {
1158 EngSetLastError(ERROR_INVALID_HANDLE);
1159 return FALSE;
1160 }
1161
1162 if (!dc->dclevel.pSurface)
1163 {
1164 Ret = TRUE;
1165 goto cleanup;
1166 }
1167
1168 #if 0
1169 pdcattr = dc->pdcattr;
1170 #endif
1171
1172 Pt.x = XStart;
1173 Pt.y = YStart;
1174 IntLPtoDP(dc, (LPPOINT)&Pt, 1);
1175
1176 DC_vPrepareDCsForBlit(dc, &DestRect, NULL, NULL);
1177
1178 psurf = dc->dclevel.pSurface;
1179
1180 prgn = dc->prgnRao ? dc->prgnRao : dc->prgnVis;
1181 if (prgn)
1182 {
1183 Ret = REGION_PtInRegion(prgn, Pt.x, Pt.y);
1184 if (Ret)
1185 REGION_GetRgnBox(prgn, (LPRECT)&DestRect);
1186 else
1187 {
1188 DC_vFinishBlit(dc, NULL);
1189 goto cleanup;
1190 }
1191 }
1192 else
1193 {
1194 RECTL_vSetRect(&DestRect, 0, 0, psurf->SurfObj.sizlBitmap.cx, psurf->SurfObj.sizlBitmap.cy);
1195 }
1196
1197 if (dc->fs & (DC_ACCUM_APP|DC_ACCUM_WMGR))
1198 {
1199 IntUpdateBoundsRect(dc, &DestRect);
1200 }
1201
1202 EXLATEOBJ_vInitialize(&exlo, &gpalRGB, psurf->ppal, 0, 0xffffff, 0);
1203
1204 /* Only solid fills supported for now
1205 * How to support pattern brushes and non standard surfaces (not offering dib functions):
1206 * Version a (most likely slow): call DrvPatBlt for every pixel
1207 * Version b: create a flood mask and let MaskBlt blit a masked brush */
1208 ConvColor = XLATEOBJ_iXlate(&exlo.xlo, Color);
1209 Ret = DIB_XXBPP_FloodFillSolid(&psurf->SurfObj, &dc->eboFill.BrushObject, &DestRect, &Pt, ConvColor, FillType);
1210
1211 DC_vFinishBlit(dc, NULL);
1212
1213 EXLATEOBJ_vCleanup(&exlo);
1214
1215 cleanup:
1216 DC_UnlockDc(dc);
1217 return Ret;
1218 }
1219
1220 /* EOF */
1221