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