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