5fd09fd80647d861389ade76b5e5d8ed495e6937
[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 <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 = 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 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 SetLastWin32Error(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 /* Do we rotate or shear? */
543 if (!(dc->dclevel.mxWorldToDevice.flAccel & MX_SCALE))
544 {
545
546 POINTL DestCoords[4];
547 ULONG PolyCounts = 4;
548 DestCoords[0].x = DestCoords[3].x = LeftRect;
549 DestCoords[0].y = DestCoords[1].y = TopRect;
550 DestCoords[1].x = DestCoords[2].x = RightRect;
551 DestCoords[2].y = DestCoords[3].y = BottomRect;
552 // Use IntGdiPolyPolygon so to support PATH.
553 return IntGdiPolyPolygon(dc, DestCoords, &PolyCounts, 1);
554 }
555 // Rectangle Path only.
556 if ( PATH_IsPathOpen(dc->dclevel) )
557 {
558 return PATH_Rectangle ( dc, LeftRect, TopRect, RightRect, BottomRect );
559 }
560
561 DestRect.left = LeftRect;
562 DestRect.right = RightRect;
563 DestRect.top = TopRect;
564 DestRect.bottom = BottomRect;
565
566 IntLPtoDP(dc, (LPPOINT)&DestRect, 2);
567
568 DestRect.left += dc->ptlDCOrig.x;
569 DestRect.right += dc->ptlDCOrig.x;
570 DestRect.top += dc->ptlDCOrig.y;
571 DestRect.bottom += dc->ptlDCOrig.y;
572
573 /* In GM_COMPATIBLE, don't include bottom and right edges */
574 if (pdcattr->iGraphicsMode == GM_COMPATIBLE)
575 {
576 DestRect.right--;
577 DestRect.bottom--;
578 }
579
580 if (pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
581 DC_vUpdateFillBrush(dc);
582
583 if (pdcattr->ulDirty_ & (DIRTY_LINE | DC_PEN_DIRTY))
584 DC_vUpdateLineBrush(dc);
585
586 pbrFill = dc->dclevel.pbrFill;
587 pbrLine = dc->dclevel.pbrLine;
588 if (!pbrLine)
589 {
590 ret = FALSE;
591 goto cleanup;
592 }
593 psurf = dc->dclevel.pSurface;
594 if (!psurf)
595 {
596 ret = FALSE;
597 goto cleanup;
598 }
599
600 if (pbrFill)
601 {
602 if (!(pbrFill->flAttrs & GDIBRUSH_IS_NULL))
603 {
604 BrushOrigin = *((PPOINTL)&pbrFill->ptOrigin);
605 BrushOrigin.x += dc->ptlDCOrig.x;
606 BrushOrigin.y += dc->ptlDCOrig.y;
607 ret = IntEngBitBlt(&psurf->SurfObj,
608 NULL,
609 NULL,
610 dc->rosdc.CombinedClip,
611 NULL,
612 &DestRect,
613 NULL,
614 NULL,
615 &dc->eboFill.BrushObject,
616 &BrushOrigin,
617 ROP3_TO_ROP4(PATCOPY));
618 }
619 }
620
621 // Draw the rectangle with the current pen
622
623 ret = TRUE; // change default to success
624
625 if (!(pbrLine->flAttrs & GDIBRUSH_IS_NULL))
626 {
627 Mix = ROP2_TO_MIX(pdcattr->jROP2);
628 ret = ret && IntEngLineTo(&psurf->SurfObj,
629 dc->rosdc.CombinedClip,
630 &dc->eboLine.BrushObject,
631 DestRect.left, DestRect.top, DestRect.right, DestRect.top,
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.top, DestRect.right, 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.right, DestRect.bottom, DestRect.left, DestRect.bottom,
646 &DestRect, // Bounding rectangle
647 Mix);
648
649 ret = ret && IntEngLineTo(&psurf->SurfObj,
650 dc->rosdc.CombinedClip,
651 &dc->eboLine.BrushObject,
652 DestRect.left, DestRect.bottom, DestRect.left, DestRect.top,
653 &DestRect, // Bounding rectangle
654 Mix);
655 }
656
657 cleanup:
658 /* Move current position in DC?
659 MSDN: The current position is neither used nor updated by Rectangle. */
660
661 return ret;
662 }
663
664 BOOL
665 APIENTRY
666 NtGdiRectangle(HDC hDC,
667 int LeftRect,
668 int TopRect,
669 int RightRect,
670 int BottomRect)
671 {
672 DC *dc;
673 BOOL ret; // default to failure
674 RECT rect = {LeftRect, TopRect, RightRect, BottomRect} ;
675
676 dc = DC_LockDc(hDC);
677 if (!dc)
678 {
679 SetLastWin32Error(ERROR_INVALID_HANDLE);
680 return FALSE;
681 }
682 if (dc->dctype == DC_TYPE_INFO)
683 {
684 DC_UnlockDc(dc);
685 /* Yes, Windows really returns TRUE in this case */
686 return TRUE;
687 }
688
689 DC_vPrepareDCsForBlit(dc, rect, NULL, rect);
690 if (dc->pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
691 DC_vUpdateFillBrush(dc);
692
693 if (dc->pdcattr->ulDirty_ & (DIRTY_LINE | DC_PEN_DIRTY))
694 DC_vUpdateLineBrush(dc);
695
696 ret = IntRectangle ( dc, LeftRect, TopRect, RightRect, BottomRect );
697 DC_vFinishBlit(dc, NULL);
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 SetLastWin32Error(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 SetLastWin32Error(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 SetLastWin32Error(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 FASTCALL
860 IntGdiGradientFill(
861 DC *dc,
862 PTRIVERTEX pVertex,
863 ULONG uVertex,
864 PVOID pMesh,
865 ULONG uMesh,
866 ULONG ulMode)
867 {
868 SURFACE *psurf;
869 PPALETTE PalDestGDI;
870 EXLATEOBJ exlo;
871 RECTL Extent;
872 POINTL DitherOrg;
873 ULONG i;
874 BOOL Ret;
875 HPALETTE hDestPalette;
876
877 ASSERT(dc);
878 ASSERT(pVertex);
879 ASSERT(uVertex);
880 ASSERT(pMesh);
881 ASSERT(uMesh);
882
883 /* check parameters */
884 if (ulMode & GRADIENT_FILL_TRIANGLE)
885 {
886 PGRADIENT_TRIANGLE tr = (PGRADIENT_TRIANGLE)pMesh;
887
888 for (i = 0; i < uMesh; i++, tr++)
889 {
890 if (tr->Vertex1 >= uVertex ||
891 tr->Vertex2 >= uVertex ||
892 tr->Vertex3 >= uVertex)
893 {
894 SetLastWin32Error(ERROR_INVALID_PARAMETER);
895 return FALSE;
896 }
897 }
898 }
899 else
900 {
901 PGRADIENT_RECT rc = (PGRADIENT_RECT)pMesh;
902 for (i = 0; i < uMesh; i++, rc++)
903 {
904 if (rc->UpperLeft >= uVertex || rc->LowerRight >= uVertex)
905 {
906 SetLastWin32Error(ERROR_INVALID_PARAMETER);
907 return FALSE;
908 }
909 }
910 }
911
912 /* calculate extent */
913 Extent.left = Extent.right = pVertex->x;
914 Extent.top = Extent.bottom = pVertex->y;
915 for (i = 0; i < uVertex; i++)
916 {
917 Extent.left = min(Extent.left, (pVertex + i)->x);
918 Extent.right = max(Extent.right, (pVertex + i)->x);
919 Extent.top = min(Extent.top, (pVertex + i)->y);
920 Extent.bottom = max(Extent.bottom, (pVertex + i)->y);
921 }
922 IntLPtoDP(dc, (LPPOINT)&Extent, 2);
923
924 Extent.left += dc->ptlDCOrig.x;
925 Extent.right += dc->ptlDCOrig.x;
926 Extent.top += dc->ptlDCOrig.y;
927 Extent.bottom += dc->ptlDCOrig.y;
928
929 DitherOrg.x = DitherOrg.y = 0;
930 IntLPtoDP(dc, (LPPOINT)&DitherOrg, 1);
931
932 DitherOrg.x += dc->ptlDCOrig.x;
933 DitherOrg.y += dc->ptlDCOrig.y;
934
935 psurf = dc->dclevel.pSurface;
936 /* FIXME - psurf can be NULL!!! Don't assert but handle this case gracefully! */
937 ASSERT(psurf);
938
939 hDestPalette = psurf->hDIBPalette;
940 if (!hDestPalette) hDestPalette = pPrimarySurface->devinfo.hpalDefault;
941
942 PalDestGDI = PALETTE_LockPalette(hDestPalette);
943 EXLATEOBJ_vInitialize(&exlo, &gpalRGB, PalDestGDI, 0, 0, 0);
944
945 Ret = IntEngGradientFill(&psurf->SurfObj,
946 dc->rosdc.CombinedClip,
947 &exlo.xlo,
948 pVertex,
949 uVertex,
950 pMesh,
951 uMesh,
952 &Extent,
953 &DitherOrg,
954 ulMode);
955
956 EXLATEOBJ_vCleanup(&exlo);
957
958 if (PalDestGDI)
959 PALETTE_UnlockPalette(PalDestGDI);
960
961 return Ret;
962 }
963
964 BOOL
965 APIENTRY
966 NtGdiGradientFill(
967 HDC hdc,
968 PTRIVERTEX pVertex,
969 ULONG uVertex,
970 PVOID pMesh,
971 ULONG uMesh,
972 ULONG ulMode)
973 {
974 DC *dc;
975 BOOL Ret;
976 PTRIVERTEX SafeVertex;
977 PVOID SafeMesh;
978 ULONG SizeMesh;
979 NTSTATUS Status = STATUS_SUCCESS;
980
981 dc = DC_LockDc(hdc);
982 if (!dc)
983 {
984 SetLastWin32Error(ERROR_INVALID_HANDLE);
985 return FALSE;
986 }
987 if (dc->dctype == DC_TYPE_INFO)
988 {
989 DC_UnlockDc(dc);
990 /* Yes, Windows really returns TRUE in this case */
991 return TRUE;
992 }
993 if (!pVertex || !uVertex || !pMesh || !uMesh)
994 {
995 DC_UnlockDc(dc);
996 SetLastWin32Error(ERROR_INVALID_PARAMETER);
997 return FALSE;
998 }
999
1000 switch (ulMode)
1001 {
1002 case GRADIENT_FILL_RECT_H:
1003 case GRADIENT_FILL_RECT_V:
1004 SizeMesh = uMesh * sizeof(GRADIENT_RECT);
1005 break;
1006 case GRADIENT_FILL_TRIANGLE:
1007 SizeMesh = uMesh * sizeof(TRIVERTEX);
1008 break;
1009 default:
1010 DC_UnlockDc(dc);
1011 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1012 return FALSE;
1013 }
1014
1015 _SEH2_TRY
1016 {
1017 ProbeForRead(pVertex,
1018 uVertex * sizeof(TRIVERTEX),
1019 1);
1020 ProbeForRead(pMesh,
1021 SizeMesh,
1022 1);
1023 }
1024 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1025 {
1026 Status = _SEH2_GetExceptionCode();
1027 }
1028 _SEH2_END;
1029
1030 if (!NT_SUCCESS(Status))
1031 {
1032 DC_UnlockDc(dc);
1033 SetLastWin32Error(Status);
1034 return FALSE;
1035 }
1036
1037 if (!(SafeVertex = ExAllocatePoolWithTag(PagedPool, (uVertex * sizeof(TRIVERTEX)) + SizeMesh, TAG_SHAPE)))
1038 {
1039 DC_UnlockDc(dc);
1040 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
1041 return FALSE;
1042 }
1043
1044 SafeMesh = (PTRIVERTEX)(SafeVertex + uVertex);
1045
1046 _SEH2_TRY
1047 {
1048 /* pointers were already probed! */
1049 RtlCopyMemory(SafeVertex,
1050 pVertex,
1051 uVertex * sizeof(TRIVERTEX));
1052 RtlCopyMemory(SafeMesh,
1053 pMesh,
1054 SizeMesh);
1055 }
1056 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1057 {
1058 Status = _SEH2_GetExceptionCode();
1059 }
1060 _SEH2_END;
1061
1062 if (!NT_SUCCESS(Status))
1063 {
1064 DC_UnlockDc(dc);
1065 ExFreePoolWithTag(SafeVertex, TAG_SHAPE);
1066 SetLastNtError(Status);
1067 return FALSE;
1068 }
1069
1070 DC_vPrepareDCsForBlit(dc, dc->rosdc.CombinedClip->rclBounds,
1071 NULL, dc->rosdc.CombinedClip->rclBounds);
1072
1073 Ret = IntGdiGradientFill(dc, SafeVertex, uVertex, SafeMesh, uMesh, ulMode);
1074
1075 DC_vFinishBlit(dc, NULL) ;
1076 DC_UnlockDc(dc);
1077 ExFreePool(SafeVertex);
1078 return Ret;
1079 }
1080
1081 BOOL APIENTRY
1082 NtGdiExtFloodFill(
1083 HDC hDC,
1084 INT XStart,
1085 INT YStart,
1086 COLORREF Color,
1087 UINT FillType)
1088 {
1089 PDC dc;
1090 PDC_ATTR pdcattr;
1091 SURFACE *psurf = NULL;
1092 HPALETTE hpal;
1093 PPALETTE ppal;
1094 EXLATEOBJ exlo;
1095 BOOL Ret = FALSE;
1096 RECTL DestRect;
1097 POINTL Pt;
1098 ULONG ConvColor;
1099
1100 dc = DC_LockDc(hDC);
1101 if (!dc)
1102 {
1103 SetLastWin32Error(ERROR_INVALID_HANDLE);
1104 return FALSE;
1105 }
1106 if (dc->dctype == DC_TYPE_INFO)
1107 {
1108 DC_UnlockDc(dc);
1109 /* Yes, Windows really returns TRUE in this case */
1110 return TRUE;
1111 }
1112
1113 pdcattr = dc->pdcattr;
1114
1115 if (pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
1116 DC_vUpdateFillBrush(dc);
1117
1118 if (pdcattr->ulDirty_ & (DIRTY_LINE | DC_PEN_DIRTY))
1119 DC_vUpdateLineBrush(dc);
1120
1121 Pt.x = XStart;
1122 Pt.y = YStart;
1123 IntLPtoDP(dc, (LPPOINT)&Pt, 1);
1124
1125 Ret = NtGdiPtInRegion(dc->rosdc.hGCClipRgn, Pt.x, Pt.y);
1126 if (Ret)
1127 IntGdiGetRgnBox(dc->rosdc.hGCClipRgn,(LPRECT)&DestRect);
1128 else
1129 goto cleanup;
1130
1131 psurf = dc->dclevel.pSurface;
1132 if (!psurf)
1133 {
1134 Ret = FALSE;
1135 goto cleanup;
1136 }
1137
1138 hpal = dc->dclevel.pSurface->hDIBPalette;
1139 if (!hpal) hpal = pPrimarySurface->devinfo.hpalDefault;
1140 ppal = PALETTE_ShareLockPalette(hpal);
1141
1142 EXLATEOBJ_vInitialize(&exlo, &gpalRGB, ppal, 0, 0xffffff, 0);
1143
1144 /* Only solid fills supported for now
1145 * How to support pattern brushes and non standard surfaces (not offering dib functions):
1146 * Version a (most likely slow): call DrvPatBlt for every pixel
1147 * Version b: create a flood mask and let MaskBlt blit a masked brush */
1148 ConvColor = XLATEOBJ_iXlate(&exlo.xlo, Color);
1149 Ret = DIB_XXBPP_FloodFillSolid(&psurf->SurfObj, &dc->eboFill.BrushObject, &DestRect, &Pt, ConvColor, FillType);
1150
1151 EXLATEOBJ_vCleanup(&exlo);
1152 PALETTE_ShareUnlockPalette(ppal);
1153
1154 cleanup:
1155 DC_UnlockDc(dc);
1156 return Ret;
1157 }
1158
1159 /* EOF */