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