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