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