87304e3c729ffd2b40bfcb3b3888b712687b6fcf
[reactos.git] / reactos / 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 SetLastWin32Error(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 SetLastWin32Error(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 SetLastWin32Error(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 SetLastWin32Error(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 SetLastWin32Error(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 SetLastWin32Error(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 SetLastWin32Error(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 /* Perform the actual work */
482 switch (iFunc)
483 {
484 case GdiPolyPolygon:
485 Ret = IntGdiPolyPolygon(dc, SafePoints, SafeCounts, Count);
486 break;
487 case GdiPolyPolyLine:
488 Ret = IntGdiPolyPolyline(dc, SafePoints, SafeCounts, Count);
489 break;
490 case GdiPolyBezier:
491 Ret = IntGdiPolyBezier(dc, SafePoints, *SafeCounts);
492 break;
493 case GdiPolyLineTo:
494 Ret = IntGdiPolylineTo(dc, SafePoints, *SafeCounts);
495 break;
496 case GdiPolyBezierTo:
497 Ret = IntGdiPolyBezierTo(dc, SafePoints, *SafeCounts);
498 break;
499 default:
500 SetLastWin32Error(ERROR_INVALID_PARAMETER);
501 Ret = FALSE;
502 }
503
504 /* Cleanup and return */
505 DC_UnlockDc(dc);
506 ExFreePool(pTemp);
507
508 return (ULONG_PTR)Ret;
509 }
510
511
512 BOOL
513 FASTCALL
514 IntRectangle(PDC dc,
515 int LeftRect,
516 int TopRect,
517 int RightRect,
518 int BottomRect)
519 {
520 SURFACE *psurf = NULL;
521 PBRUSH pbrLine, pbrFill;
522 BOOL ret = FALSE; // default to failure
523 RECTL DestRect;
524 MIX Mix;
525 PDC_ATTR pdcattr;
526 POINTL BrushOrigin;
527
528 ASSERT ( dc ); // caller's responsibility to set this up
529
530 pdcattr = dc->pdcattr;
531
532 /* Do we rotate or shear? */
533 if (!(dc->dclevel.mxWorldToDevice.flAccel & MX_SCALE))
534 {
535
536 POINTL DestCoords[4];
537 ULONG PolyCounts = 4;
538 DestCoords[0].x = DestCoords[3].x = LeftRect;
539 DestCoords[0].y = DestCoords[1].y = TopRect;
540 DestCoords[1].x = DestCoords[2].x = RightRect;
541 DestCoords[2].y = DestCoords[3].y = BottomRect;
542 // Use IntGdiPolyPolygon so to support PATH.
543 return IntGdiPolyPolygon(dc, DestCoords, &PolyCounts, 1);
544 }
545 // Rectangle Path only.
546 if ( PATH_IsPathOpen(dc->dclevel) )
547 {
548 return PATH_Rectangle ( dc, LeftRect, TopRect, RightRect, BottomRect );
549 }
550
551 DestRect.left = LeftRect;
552 DestRect.right = RightRect;
553 DestRect.top = TopRect;
554 DestRect.bottom = 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 if (pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
571 DC_vUpdateFillBrush(dc);
572
573 if (pdcattr->ulDirty_ & (DIRTY_LINE | DC_PEN_DIRTY))
574 DC_vUpdateLineBrush(dc);
575
576 pbrFill = dc->dclevel.pbrFill;
577 pbrLine = dc->dclevel.pbrLine;
578 if (!pbrLine)
579 {
580 ret = FALSE;
581 goto cleanup;
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 /* Move current position in DC?
649 MSDN: The current position is neither used nor updated by Rectangle. */
650
651 return ret;
652 }
653
654 BOOL
655 APIENTRY
656 NtGdiRectangle(HDC hDC,
657 int LeftRect,
658 int TopRect,
659 int RightRect,
660 int BottomRect)
661 {
662 DC *dc;
663 BOOL ret; // default to failure
664
665 dc = DC_LockDc(hDC);
666 if (!dc)
667 {
668 SetLastWin32Error(ERROR_INVALID_HANDLE);
669 return FALSE;
670 }
671 if (dc->dctype == DC_TYPE_INFO)
672 {
673 DC_UnlockDc(dc);
674 /* Yes, Windows really returns TRUE in this case */
675 return TRUE;
676 }
677
678 ret = IntRectangle ( dc, LeftRect, TopRect, RightRect, BottomRect );
679 DC_UnlockDc ( dc );
680
681 return ret;
682 }
683
684
685 BOOL
686 FASTCALL
687 IntRoundRect(
688 PDC dc,
689 int Left,
690 int Top,
691 int Right,
692 int Bottom,
693 int xCurveDiameter,
694 int yCurveDiameter)
695 {
696 PDC_ATTR pdcattr;
697 PBRUSH pbrushLine, pbrushFill;
698 RECTL RectBounds;
699 LONG PenWidth, PenOrigWidth;
700 BOOL ret = TRUE; // default to success
701 BRUSH brushTemp;
702
703 ASSERT ( dc ); // caller's responsibility to set this up
704
705 if ( PATH_IsPathOpen(dc->dclevel) )
706 return PATH_RoundRect ( dc, Left, Top, Right, Bottom,
707 xCurveDiameter, yCurveDiameter );
708
709 if ((Left == Right) || (Top == Bottom)) return TRUE;
710
711 xCurveDiameter = max(abs( xCurveDiameter ), 1);
712 yCurveDiameter = max(abs( yCurveDiameter ), 1);
713
714 if (Right < Left)
715 {
716 INT tmp = Right; Right = Left; Left = tmp;
717 }
718 if (Bottom < Top)
719 {
720 INT tmp = Bottom; Bottom = Top; Top = tmp;
721 }
722
723 pdcattr = dc->pdcattr;
724
725 if (pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
726 DC_vUpdateFillBrush(dc);
727
728 if (pdcattr->ulDirty_ & (DIRTY_LINE | DC_PEN_DIRTY))
729 DC_vUpdateLineBrush(dc);
730
731 pbrushLine = PEN_LockPen(pdcattr->hpen);
732 if (!pbrushLine)
733 {
734 /* Nothing to do, as we don't have a bitmap */
735 SetLastWin32Error(ERROR_INTERNAL_ERROR);
736 return FALSE;
737 }
738
739 PenOrigWidth = PenWidth = pbrushLine->ptPenWidth.x;
740 if (pbrushLine->ulPenStyle == PS_NULL) PenWidth = 0;
741
742 if (pbrushLine->ulPenStyle == PS_INSIDEFRAME)
743 {
744 if (2*PenWidth > (Right - Left)) PenWidth = (Right -Left + 1)/2;
745 if (2*PenWidth > (Bottom - Top)) PenWidth = (Bottom -Top + 1)/2;
746 Left += PenWidth / 2;
747 Right -= (PenWidth - 1) / 2;
748 Top += PenWidth / 2;
749 Bottom -= (PenWidth - 1) / 2;
750 }
751
752 if (!PenWidth) PenWidth = 1;
753 pbrushLine->ptPenWidth.x = PenWidth;
754
755 RectBounds.left = Left;
756 RectBounds.top = Top;
757 RectBounds.right = Right;
758 RectBounds.bottom = Bottom;
759
760 IntLPtoDP(dc, (LPPOINT)&RectBounds, 2);
761
762 RectBounds.left += dc->ptlDCOrig.x;
763 RectBounds.top += dc->ptlDCOrig.y;
764 RectBounds.right += dc->ptlDCOrig.x;
765 RectBounds.bottom += dc->ptlDCOrig.y;
766
767 pbrushFill = BRUSH_LockBrush(pdcattr->hbrush);
768 if (NULL == pbrushFill)
769 {
770 DPRINT1("FillRound Fail\n");
771 SetLastWin32Error(ERROR_INTERNAL_ERROR);
772 ret = FALSE;
773 }
774 else
775 {
776 RtlCopyMemory(&brushTemp, pbrushFill, sizeof(brushTemp));
777 brushTemp.ptOrigin.x += RectBounds.left - Left;
778 brushTemp.ptOrigin.y += RectBounds.top - Top;
779 ret = IntFillRoundRect( dc,
780 RectBounds.left,
781 RectBounds.top,
782 RectBounds.right,
783 RectBounds.bottom,
784 xCurveDiameter,
785 yCurveDiameter,
786 &brushTemp);
787 BRUSH_UnlockBrush(pbrushFill);
788 }
789
790 if (ret)
791 ret = IntDrawRoundRect( dc,
792 RectBounds.left,
793 RectBounds.top,
794 RectBounds.right,
795 RectBounds.bottom,
796 xCurveDiameter,
797 yCurveDiameter,
798 pbrushLine);
799
800 pbrushLine->ptPenWidth.x = PenOrigWidth;
801 PEN_UnlockPen(pbrushLine);
802 return ret;
803 }
804
805 BOOL
806 APIENTRY
807 NtGdiRoundRect(
808 HDC hDC,
809 int LeftRect,
810 int TopRect,
811 int RightRect,
812 int BottomRect,
813 int Width,
814 int Height)
815 {
816 DC *dc = DC_LockDc(hDC);
817 BOOL ret = FALSE; /* default to failure */
818
819 DPRINT("NtGdiRoundRect(0x%x,%i,%i,%i,%i,%i,%i)\n",hDC,LeftRect,TopRect,RightRect,BottomRect,Width,Height);
820 if ( !dc )
821 {
822 DPRINT1("NtGdiRoundRect() - hDC is invalid\n");
823 SetLastWin32Error(ERROR_INVALID_HANDLE);
824 }
825 else if (dc->dctype == DC_TYPE_INFO)
826 {
827 DC_UnlockDc(dc);
828 /* Yes, Windows really returns TRUE in this case */
829 ret = TRUE;
830 }
831 else
832 {
833 ret = IntRoundRect ( dc, LeftRect, TopRect, RightRect, BottomRect, Width, Height );
834 DC_UnlockDc ( dc );
835 }
836
837 return ret;
838 }
839
840 BOOL
841 NTAPI
842 GreGradientFill(
843 HDC hdc,
844 PTRIVERTEX pVertex,
845 ULONG nVertex,
846 PVOID pMesh,
847 ULONG nMesh,
848 ULONG ulMode)
849 {
850 PDC pdc;
851 SURFACE *psurf;
852 PPALETTE ppal;
853 EXLATEOBJ exlo;
854 RECTL rclExtent;
855 POINTL ptlDitherOrg;
856 ULONG i;
857 BOOL bRet;
858 HPALETTE hDestPalette;
859
860 /* Check parameters */
861 if (ulMode == GRADIENT_FILL_TRIANGLE)
862 {
863 PGRADIENT_TRIANGLE pTriangle = (PGRADIENT_TRIANGLE)pMesh;
864
865 for (i = 0; i < nMesh; i++, pTriangle++)
866 {
867 if (pTriangle->Vertex1 >= nVertex ||
868 pTriangle->Vertex2 >= nVertex ||
869 pTriangle->Vertex3 >= nVertex)
870 {
871 SetLastWin32Error(ERROR_INVALID_PARAMETER);
872 return FALSE;
873 }
874 }
875 }
876 else
877 {
878 PGRADIENT_RECT pRect = (PGRADIENT_RECT)pMesh;
879 for (i = 0; i < nMesh; i++, pRect++)
880 {
881 if (pRect->UpperLeft >= nVertex || pRect->LowerRight >= nVertex)
882 {
883 SetLastWin32Error(ERROR_INVALID_PARAMETER);
884 return FALSE;
885 }
886 }
887 }
888
889 /* Lock the output DC */
890 pdc = DC_LockDc(hdc);
891 if (!pdc)
892 {
893 SetLastWin32Error(ERROR_INVALID_HANDLE);
894 return FALSE;
895 }
896
897 if (pdc->dctype == DC_TYPE_INFO)
898 {
899 DC_UnlockDc(pdc);
900 /* Yes, Windows really returns TRUE in this case */
901 return TRUE;
902 }
903
904 psurf = pdc->dclevel.pSurface;
905 if (!psurf)
906 {
907 /* Memory DC with no surface selected */
908 DC_UnlockDc(pdc);
909 return TRUE; // CHECKME
910 }
911
912 /* calculate extent */
913 rclExtent.left = rclExtent.right = pVertex->x;
914 rclExtent.top = rclExtent.bottom = pVertex->y;
915 for (i = 0; i < nVertex; i++)
916 {
917 rclExtent.left = min(rclExtent.left, (pVertex + i)->x);
918 rclExtent.right = max(rclExtent.right, (pVertex + i)->x);
919 rclExtent.top = min(rclExtent.top, (pVertex + i)->y);
920 rclExtent.bottom = max(rclExtent.bottom, (pVertex + i)->y);
921 }
922
923 IntLPtoDP(pdc, (LPPOINT)&rclExtent, 2);
924 rclExtent.left += pdc->ptlDCOrig.x;
925 rclExtent.right += pdc->ptlDCOrig.x;
926 rclExtent.top += pdc->ptlDCOrig.y;
927 rclExtent.bottom += pdc->ptlDCOrig.y;
928
929 ptlDitherOrg.x = ptlDitherOrg.y = 0;
930 IntLPtoDP(pdc, (LPPOINT)&ptlDitherOrg, 1);
931 ptlDitherOrg.x += pdc->ptlDCOrig.x;
932 ptlDitherOrg.y += pdc->ptlDCOrig.y;
933
934 hDestPalette = psurf->hDIBPalette;
935 if (!hDestPalette) hDestPalette = pPrimarySurface->devinfo.hpalDefault;
936
937 ppal = PALETTE_LockPalette(hDestPalette);
938 EXLATEOBJ_vInitialize(&exlo, &gpalRGB, ppal, 0, 0, 0);
939
940 ASSERT(pdc->rosdc.CombinedClip);
941
942 bRet = IntEngGradientFill(&psurf->SurfObj,
943 pdc->rosdc.CombinedClip,
944 &exlo.xlo,
945 pVertex,
946 nVertex,
947 pMesh,
948 nMesh,
949 &rclExtent,
950 &ptlDitherOrg,
951 ulMode);
952
953 EXLATEOBJ_vCleanup(&exlo);
954
955 if (ppal)
956 PALETTE_UnlockPalette(ppal);
957
958 return bRet;
959 }
960
961 BOOL
962 APIENTRY
963 NtGdiGradientFill(
964 HDC hdc,
965 PTRIVERTEX pVertex,
966 ULONG nVertex,
967 PVOID pMesh,
968 ULONG nMesh,
969 ULONG ulMode)
970 {
971 BOOL bRet;
972 PTRIVERTEX SafeVertex;
973 PVOID SafeMesh;
974 ULONG cbVertex, cbMesh;
975
976 /* Validate parameters */
977 if (!pVertex || !nVertex || !pMesh || !nMesh)
978 {
979 SetLastWin32Error(ERROR_INVALID_PARAMETER);
980 return FALSE;
981 }
982
983 switch (ulMode)
984 {
985 case GRADIENT_FILL_RECT_H:
986 case GRADIENT_FILL_RECT_V:
987 cbMesh = nMesh * sizeof(GRADIENT_RECT);
988 break;
989 case GRADIENT_FILL_TRIANGLE:
990 cbMesh = nMesh * sizeof(GRADIENT_TRIANGLE);
991 break;
992 default:
993 SetLastWin32Error(ERROR_INVALID_PARAMETER);
994 return FALSE;
995 }
996
997 cbVertex = nVertex * sizeof(TRIVERTEX);
998 if (cbVertex + cbMesh <= cbVertex)
999 {
1000 /* Overflow */
1001 return FALSE;
1002 }
1003
1004 /* Allocate a kernel mode buffer */
1005 SafeVertex = ExAllocatePoolWithTag(PagedPool, cbVertex + cbMesh, TAG_SHAPE);
1006 if (!SafeVertex)
1007 {
1008 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
1009 return FALSE;
1010 }
1011
1012 SafeMesh = (PVOID)((ULONG_PTR)SafeVertex + cbVertex);
1013
1014 /* Copy the parameters to kernel mode */
1015 _SEH2_TRY
1016 {
1017 ProbeForRead(pVertex, cbVertex, 1);
1018 ProbeForRead(pMesh, cbMesh, 1);
1019 RtlCopyMemory(SafeVertex, pVertex, cbVertex);
1020 RtlCopyMemory(SafeMesh, pMesh, cbMesh);
1021 }
1022 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1023 {
1024 ExFreePoolWithTag(SafeVertex, TAG_SHAPE);
1025 SetLastNtError(_SEH2_GetExceptionCode());
1026 _SEH2_YIELD(return FALSE;)
1027 }
1028 _SEH2_END;
1029
1030 /* Call the internal function */
1031 bRet = GreGradientFill(hdc, SafeVertex, nVertex, SafeMesh, nMesh, ulMode);
1032
1033 /* Cleanup and return result */
1034 ExFreePoolWithTag(SafeVertex, TAG_SHAPE);
1035 return bRet;
1036 }
1037
1038 BOOL APIENTRY
1039 NtGdiExtFloodFill(
1040 HDC hDC,
1041 INT XStart,
1042 INT YStart,
1043 COLORREF Color,
1044 UINT FillType)
1045 {
1046 PDC dc;
1047 PDC_ATTR pdcattr;
1048 SURFACE *psurf = NULL;
1049 HPALETTE hpal;
1050 PPALETTE ppal;
1051 EXLATEOBJ exlo;
1052 BOOL Ret = FALSE;
1053 RECTL DestRect;
1054 POINTL Pt;
1055 ULONG ConvColor;
1056
1057 dc = DC_LockDc(hDC);
1058 if (!dc)
1059 {
1060 SetLastWin32Error(ERROR_INVALID_HANDLE);
1061 return FALSE;
1062 }
1063 if (dc->dctype == DC_TYPE_INFO)
1064 {
1065 DC_UnlockDc(dc);
1066 /* Yes, Windows really returns TRUE in this case */
1067 return TRUE;
1068 }
1069
1070 pdcattr = dc->pdcattr;
1071
1072 if (pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
1073 DC_vUpdateFillBrush(dc);
1074
1075 if (pdcattr->ulDirty_ & (DIRTY_LINE | DC_PEN_DIRTY))
1076 DC_vUpdateLineBrush(dc);
1077
1078 Pt.x = XStart;
1079 Pt.y = YStart;
1080 IntLPtoDP(dc, (LPPOINT)&Pt, 1);
1081
1082 Ret = NtGdiPtInRegion(dc->rosdc.hGCClipRgn, Pt.x, Pt.y);
1083 if (Ret)
1084 IntGdiGetRgnBox(dc->rosdc.hGCClipRgn,(LPRECT)&DestRect);
1085 else
1086 goto cleanup;
1087
1088 psurf = dc->dclevel.pSurface;
1089 if (!psurf)
1090 {
1091 Ret = FALSE;
1092 goto cleanup;
1093 }
1094
1095 hpal = dc->dclevel.pSurface->hDIBPalette;
1096 if (!hpal) hpal = pPrimarySurface->devinfo.hpalDefault;
1097 ppal = PALETTE_ShareLockPalette(hpal);
1098
1099 EXLATEOBJ_vInitialize(&exlo, &gpalRGB, ppal, 0, 0xffffff, 0);
1100
1101 /* Only solid fills supported for now
1102 * How to support pattern brushes and non standard surfaces (not offering dib functions):
1103 * Version a (most likely slow): call DrvPatBlt for every pixel
1104 * Version b: create a flood mask and let MaskBlt blit a masked brush */
1105 ConvColor = XLATEOBJ_iXlate(&exlo.xlo, Color);
1106 Ret = DIB_XXBPP_FloodFillSolid(&psurf->SurfObj, &dc->eboFill.BrushObject, &DestRect, &Pt, ConvColor, FillType);
1107
1108 EXLATEOBJ_vCleanup(&exlo);
1109 PALETTE_ShareUnlockPalette(ppal);
1110
1111 cleanup:
1112 DC_UnlockDc(dc);
1113 return Ret;
1114 }
1115
1116 /* EOF */