sync to trunk revision 36700
[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 /*
26 * a couple macros to fill a single pixel or a line
27 */
28 #define PUTPIXEL(x,y,BrushInst) \
29 ret = ret && IntEngLineTo(&BitmapObj->SurfObj, \
30 dc->CombinedClip, \
31 &BrushInst.BrushObject, \
32 x, y, (x)+1, y, \
33 &RectBounds, \
34 ROP2_TO_MIX(Dc_Attr->jROP2));
35
36 #define PUTLINE(x1,y1,x2,y2,BrushInst) \
37 ret = ret && IntEngLineTo(&BitmapObj->SurfObj, \
38 dc->CombinedClip, \
39 &BrushInst.BrushObject, \
40 x1, y1, x2, y2, \
41 &RectBounds, \
42 ROP2_TO_MIX(Dc_Attr->jROP2));
43
44 #define Rsin(d) ((d) == 0.0 ? 0.0 : ((d) == 90.0 ? 1.0 : sin(d*M_PI/180.0)))
45 #define Rcos(d) ((d) == 0.0 ? 1.0 : ((d) == 90.0 ? 0.0 : cos(d*M_PI/180.0)))
46
47 BOOL FASTCALL IntFillEllipse( PDC dc, INT XLeft, INT YLeft, INT Width, INT Height);
48 BOOL FASTCALL IntDrawEllipse( PDC dc, INT XLeft, INT YLeft, INT Width, INT Height, PGDIBRUSHOBJ PenBrushObj);
49 BOOL FASTCALL IntFillRoundRect( PDC dc, INT Left, INT Top, INT Right, INT Bottom, INT Wellipse, INT Hellipse);
50 BOOL FASTCALL IntDrawRoundRect( PDC dc, INT Left, INT Top, INT Right, INT Bottom, INT Wellipse, INT Hellipse, PGDIBRUSHOBJ PenBrushObj);
51
52 BOOL FASTCALL
53 IntGdiPolygon(PDC dc,
54 PPOINT Points,
55 int Count)
56 {
57 BITMAPOBJ *BitmapObj;
58 PGDIBRUSHOBJ PenBrushObj, FillBrushObj;
59 GDIBRUSHINST PenBrushInst, FillBrushInst;
60 BOOL ret = FALSE; // default to failure
61 RECTL DestRect;
62 int CurrentPoint;
63 PDC_ATTR Dc_Attr;
64
65 ASSERT(dc); // caller's responsibility to pass a valid dc
66
67 if (!Points || Count < 2 )
68 {
69 SetLastWin32Error(ERROR_INVALID_PARAMETER);
70 return FALSE;
71 }
72
73 Dc_Attr = dc->pDc_Attr;
74 if (!Dc_Attr) Dc_Attr = &dc->Dc_Attr;
75
76 /* Convert to screen coordinates */
77 IntLPtoDP(dc, Points, Count);
78 for (CurrentPoint = 0; CurrentPoint < Count; CurrentPoint++)
79 {
80 Points[CurrentPoint].x += dc->ptlDCOrig.x;
81 Points[CurrentPoint].y += dc->ptlDCOrig.y;
82 }
83 // No need to have path here.
84 {
85 DestRect.left = Points[0].x;
86 DestRect.right = Points[0].x;
87 DestRect.top = Points[0].y;
88 DestRect.bottom = Points[0].y;
89
90 for (CurrentPoint = 1; CurrentPoint < Count; ++CurrentPoint)
91 {
92 DestRect.left = min(DestRect.left, Points[CurrentPoint].x);
93 DestRect.right = max(DestRect.right, Points[CurrentPoint].x);
94 DestRect.top = min(DestRect.top, Points[CurrentPoint].y);
95 DestRect.bottom = max(DestRect.bottom, Points[CurrentPoint].y);
96 }
97
98 /* Special locking order to avoid lock-ups */
99 FillBrushObj = BRUSHOBJ_LockBrush(Dc_Attr->hbrush);
100 PenBrushObj = PENOBJ_LockPen(Dc_Attr->hpen);
101 BitmapObj = BITMAPOBJ_LockBitmap(dc->w.hBitmap);
102 /* FIXME - BitmapObj can be NULL!!!! don't assert but handle this case gracefully! */
103 ASSERT(BitmapObj);
104
105 /* Now fill the polygon with the current brush. */
106 if (FillBrushObj && !(FillBrushObj->flAttrs & GDIBRUSH_IS_NULL))
107 {
108 IntGdiInitBrushInstance(&FillBrushInst, FillBrushObj, dc->XlateBrush);
109 ret = FillPolygon ( dc, BitmapObj, &FillBrushInst.BrushObject, ROP2_TO_MIX(Dc_Attr->jROP2), Points, Count, DestRect );
110 }
111 if (FillBrushObj)
112 BRUSHOBJ_UnlockBrush(FillBrushObj);
113
114 // Draw the Polygon Edges with the current pen ( if not a NULL pen )
115 if (PenBrushObj && !(PenBrushObj->flAttrs & GDIBRUSH_IS_NULL))
116 {
117 int i;
118
119 IntGdiInitBrushInstance(&PenBrushInst, PenBrushObj, dc->XlatePen);
120
121 for (i = 0; i < Count-1; i++)
122 {
123
124 // DPRINT1("Polygon Making line from (%d,%d) to (%d,%d)\n",
125 // Points[0].x, Points[0].y,
126 // Points[1].x, Points[1].y );
127
128 ret = IntEngLineTo(&BitmapObj->SurfObj,
129 dc->CombinedClip,
130 &PenBrushInst.BrushObject,
131 Points[i].x, /* From */
132 Points[i].y,
133 Points[i+1].x, /* To */
134 Points[i+1].y,
135 &DestRect,
136 ROP2_TO_MIX(Dc_Attr->jROP2)); /* MIX */
137 if (!ret) break;
138 }
139 /* Close the polygon */
140 if (ret)
141 {
142 ret = IntEngLineTo(&BitmapObj->SurfObj,
143 dc->CombinedClip,
144 &PenBrushInst.BrushObject,
145 Points[Count-1].x, /* From */
146 Points[Count-1].y,
147 Points[0].x, /* To */
148 Points[0].y,
149 &DestRect,
150 ROP2_TO_MIX(Dc_Attr->jROP2)); /* MIX */
151 }
152 }
153 if (PenBrushObj)
154 PENOBJ_UnlockPen(PenBrushObj);
155 }
156 BITMAPOBJ_UnlockBitmap(BitmapObj);
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 STDCALL
196 NtGdiEllipse(
197 HDC hDC,
198 int Left,
199 int Top,
200 int Right,
201 int Bottom)
202 {
203 PDC dc;
204 PDC_ATTR Dc_Attr;
205 RECTL RectBounds;
206 PGDIBRUSHOBJ PenBrushObj;
207 BOOL ret = TRUE;
208 LONG PenWidth, PenOrigWidth;
209 LONG RadiusX, RadiusY, CenterX, CenterY;
210
211 if ((Left == Right) || (Top == Bottom)) return TRUE;
212
213 dc = DC_LockDc(hDC);
214 if (dc == NULL)
215 {
216 SetLastWin32Error(ERROR_INVALID_HANDLE);
217 return FALSE;
218 }
219 if (dc->DC_Type == DC_TYPE_INFO)
220 {
221 DC_UnlockDc(dc);
222 /* Yes, Windows really returns TRUE in this case */
223 return TRUE;
224 }
225
226 if (PATH_IsPathOpen(dc->DcLevel))
227 {
228 ret = PATH_Ellipse(dc, Left, Top, Right, Bottom);
229 DC_UnlockDc(dc);
230 return ret;
231 }
232
233 if (Right < Left)
234 {
235 INT tmp = Right; Right = Left; Left = tmp;
236 }
237 if (Bottom < Top)
238 {
239 INT tmp = Bottom; Bottom = Top; Top = tmp;
240 }
241
242 Dc_Attr = dc->pDc_Attr;
243 if(!Dc_Attr) Dc_Attr = &dc->Dc_Attr;
244
245 PenBrushObj = PENOBJ_LockPen(Dc_Attr->hpen);
246 if (NULL == PenBrushObj)
247 {
248 DPRINT1("Ellipse Fail 1\n");
249 DC_UnlockDc(dc);
250 SetLastWin32Error(ERROR_INTERNAL_ERROR);
251 return FALSE;
252 }
253
254 PenOrigWidth = PenWidth = PenBrushObj->ptPenWidth.x;
255 if (PenBrushObj->ulPenStyle == PS_NULL) PenWidth = 0;
256
257 if (PenBrushObj->ulPenStyle == PS_INSIDEFRAME)
258 {
259 if (2*PenWidth > (Right - Left)) PenWidth = (Right -Left + 1)/2;
260 if (2*PenWidth > (Bottom - Top)) PenWidth = (Bottom -Top + 1)/2;
261 Left += PenWidth / 2;
262 Right -= (PenWidth - 1) / 2;
263 Top += PenWidth / 2;
264 Bottom -= (PenWidth - 1) / 2;
265 }
266
267 if (!PenWidth) PenWidth = 1;
268 PenBrushObj->ptPenWidth.x = PenWidth;
269
270 RectBounds.left = Left;
271 RectBounds.right = Right;
272 RectBounds.top = Top;
273 RectBounds.bottom = Bottom;
274
275 IntLPtoDP(dc, (LPPOINT)&RectBounds, 2);
276
277 RectBounds.left += dc->ptlDCOrig.x;
278 RectBounds.right += dc->ptlDCOrig.x;
279 RectBounds.top += dc->ptlDCOrig.y;
280 RectBounds.bottom += dc->ptlDCOrig.y;
281
282 // Setup for dynamic width and height.
283 RadiusX = max((RectBounds.right - RectBounds.left) / 2, 2); // Needs room
284 RadiusY = max((RectBounds.bottom - RectBounds.top) / 2, 2);
285 CenterX = (RectBounds.right + RectBounds.left) / 2;
286 CenterY = (RectBounds.bottom + RectBounds.top) / 2;
287
288 DPRINT("Ellipse 1: Left: %d, Top: %d, Right: %d, Bottom: %d\n",
289 RectBounds.left,RectBounds.top,RectBounds.right,RectBounds.bottom);
290
291 DPRINT("Ellipse 2: XLeft: %d, YLeft: %d, Width: %d, Height: %d\n",
292 CenterX - RadiusX, CenterY + RadiusY, RadiusX*2, RadiusY*2);
293
294 ret = IntFillEllipse( dc,
295 CenterX - RadiusX,
296 CenterY - RadiusY,
297 RadiusX*2, // Width
298 RadiusY*2); // Height
299 if (ret)
300 ret = IntDrawEllipse( dc,
301 CenterX - RadiusX,
302 CenterY - RadiusY,
303 RadiusX*2, // Width
304 RadiusY*2, // Height
305 PenBrushObj);
306
307 PenBrushObj->ptPenWidth.x = PenOrigWidth;
308 PENOBJ_UnlockPen(PenBrushObj);
309 DC_UnlockDc(dc);
310 DPRINT("Ellipse Exit.\n");
311 return ret;
312 }
313
314 #if 0
315
316 //When the fill mode is ALTERNATE, GDI fills the area between odd-numbered and
317 //even-numbered polygon sides on each scan line. That is, GDI fills the area between the
318 //first and second side, between the third and fourth side, and so on.
319
320 //WINDING Selects winding mode (fills any region with a nonzero winding value).
321 //When the fill mode is WINDING, GDI fills any region that has a nonzero winding value.
322 //This value is defined as the number of times a pen used to draw the polygon would go around the region.
323 //The direction of each edge of the polygon is important.
324
325 extern BOOL FillPolygon(PDC dc,
326 SURFOBJ *SurfObj,
327 PBRUSHOBJ BrushObj,
328 MIX RopMode,
329 CONST PPOINT Points,
330 int Count,
331 RECTL BoundRect);
332
333 #endif
334
335
336 ULONG_PTR
337 STDCALL
338 NtGdiPolyPolyDraw( IN HDC hDC,
339 IN PPOINT UnsafePoints,
340 IN PULONG UnsafeCounts,
341 IN ULONG Count,
342 IN INT iFunc )
343 {
344 DC *dc;
345 PVOID pTemp;
346 LPPOINT SafePoints;
347 PULONG SafeCounts;
348 NTSTATUS Status = STATUS_SUCCESS;
349 BOOL Ret = TRUE;
350 INT nPoints = 0, nMaxPoints = 0, nInvalid = 0, i;
351
352 if (!UnsafePoints || !UnsafeCounts ||
353 Count == 0 || iFunc == 0 || iFunc > GdiPolyPolyRgn)
354 {
355 /* Windows doesn't set last error */
356 return FALSE;
357 }
358
359 _SEH_TRY
360 {
361 ProbeForRead(UnsafePoints, Count * sizeof(POINT), 1);
362 ProbeForRead(UnsafeCounts, Count * sizeof(ULONG), 1);
363
364 /* Count points and validate poligons */
365 for (i = 0; i < Count; i++)
366 {
367 if (UnsafeCounts[i] < 2)
368 {
369 nInvalid++;
370 }
371 nPoints += UnsafeCounts[i];
372 nMaxPoints = max(nMaxPoints, UnsafeCounts[i]);
373 }
374 }
375 _SEH_HANDLE
376 {
377 Status = _SEH_GetExceptionCode();
378 }
379 _SEH_END;
380
381 if (!NT_SUCCESS(Status))
382 {
383 /* Windows doesn't set last error */
384 return FALSE;
385 }
386
387 if (nPoints == 0 || nPoints < nMaxPoints)
388 {
389 /* If all polygon counts are zero, or we have overflow,
390 return without setting a last error code. */
391 return FALSE;
392 }
393
394 if (nInvalid != 0)
395 {
396 /* If at least one poly count is 0 or 1, fail */
397 SetLastWin32Error(ERROR_INVALID_PARAMETER);
398 return FALSE;
399 }
400
401 /* Allocate one buffer for both counts and points */
402 pTemp = ExAllocatePoolWithTag(PagedPool,
403 Count * sizeof(ULONG) + nPoints * sizeof(POINT),
404 TAG_SHAPE);
405 if (!pTemp)
406 {
407 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
408 return FALSE;
409 }
410
411 SafeCounts = pTemp;
412 SafePoints = (PVOID)(SafeCounts + Count);
413
414 _SEH_TRY
415 {
416 /* Pointers already probed! */
417 RtlCopyMemory(SafeCounts, UnsafeCounts, Count * sizeof(ULONG));
418 RtlCopyMemory(SafePoints, UnsafePoints, nPoints * sizeof(POINT));
419 }
420 _SEH_HANDLE
421 {
422 Status = _SEH_GetExceptionCode();
423 }
424 _SEH_END;
425
426 if (!NT_SUCCESS(Status))
427 {
428 ExFreePool(pTemp);
429 return FALSE;
430 }
431
432 /* Special handling for GdiPolyPolyRgn */
433 if (iFunc == GdiPolyPolyRgn)
434 {
435 HRGN hRgn;
436 hRgn = IntCreatePolyPolygonRgn(SafePoints, SafeCounts, Count, (INT_PTR)hDC);
437 ExFreePool(pTemp);
438 return (ULONG_PTR)hRgn;
439 }
440
441 dc = DC_LockDc(hDC);
442 if (!dc)
443 {
444 SetLastWin32Error(ERROR_INVALID_HANDLE);
445 ExFreePool(pTemp);
446 return FALSE;
447 }
448
449 if (dc->DC_Type == DC_TYPE_INFO)
450 {
451 DC_UnlockDc(dc);
452 ExFreePool(pTemp);
453 /* Yes, Windows really returns TRUE in this case */
454 return TRUE;
455 }
456
457 /* Perform the actual work */
458 switch (iFunc)
459 {
460 case GdiPolyPolygon:
461 Ret = IntGdiPolyPolygon(dc, SafePoints, SafeCounts, Count);
462 break;
463 case GdiPolyPolyLine:
464 Ret = IntGdiPolyPolyline(dc, SafePoints, SafeCounts, Count);
465 break;
466 case GdiPolyBezier:
467 Ret = IntGdiPolyBezier(dc, SafePoints, *SafeCounts);
468 break;
469 case GdiPolyLineTo:
470 Ret = IntGdiPolylineTo(dc, SafePoints, *SafeCounts);
471 break;
472 case GdiPolyBezierTo:
473 Ret = IntGdiPolyBezierTo(dc, SafePoints, *SafeCounts);
474 break;
475 default:
476 SetLastWin32Error(ERROR_INVALID_PARAMETER);
477 Ret = FALSE;
478 }
479
480 /* Cleanup and return */
481 DC_UnlockDc(dc);
482 ExFreePool(pTemp);
483
484 return (ULONG_PTR)Ret;
485 }
486
487
488 BOOL
489 FASTCALL
490 IntRectangle(PDC dc,
491 int LeftRect,
492 int TopRect,
493 int RightRect,
494 int BottomRect)
495 {
496 BITMAPOBJ *BitmapObj = NULL;
497 PGDIBRUSHOBJ PenBrushObj = NULL, FillBrushObj = NULL;
498 GDIBRUSHINST PenBrushInst, FillBrushInst;
499 BOOL ret = FALSE; // default to failure
500 RECTL DestRect;
501 MIX Mix;
502 PDC_ATTR Dc_Attr;
503
504 ASSERT ( dc ); // caller's responsibility to set this up
505
506 Dc_Attr = dc->pDc_Attr;
507 if(!Dc_Attr) Dc_Attr = &dc->Dc_Attr;
508
509 if ( PATH_IsPathOpen(dc->DcLevel) )
510 {
511 return PATH_Rectangle ( dc, LeftRect, TopRect, RightRect, BottomRect );
512 }
513
514 /* Do we rotate or shear? */
515 if (!(dc->DcLevel.mxWorldToDevice.flAccel & MX_SCALE))
516 {
517 POINTL DestCoords[4];
518 DestCoords[0].x = DestCoords[3].x = LeftRect;
519 DestCoords[0].y = DestCoords[1].y = TopRect;
520 DestCoords[1].x = DestCoords[2].x = RightRect;
521 DestCoords[2].y = DestCoords[3].y = BottomRect;
522 return IntGdiPolygon(dc, DestCoords, 4);
523 }
524
525 DestRect.left = LeftRect;
526 DestRect.right = RightRect;
527 DestRect.top = TopRect;
528 DestRect.bottom = BottomRect;
529
530 IntLPtoDP(dc, (LPPOINT)&DestRect, 2);
531
532 DestRect.left += dc->ptlDCOrig.x;
533 DestRect.right += dc->ptlDCOrig.x;
534 DestRect.top += dc->ptlDCOrig.y;
535 DestRect.bottom += dc->ptlDCOrig.y;
536
537 /* In GM_COMPATIBLE, don't include bottom and right edges */
538 if (IntGetGraphicsMode(dc) == GM_COMPATIBLE)
539 {
540 DestRect.right--;
541 DestRect.bottom--;
542 }
543
544 /* Special locking order to avoid lock-ups! */
545 FillBrushObj = BRUSHOBJ_LockBrush(Dc_Attr->hbrush);
546 PenBrushObj = PENOBJ_LockPen(Dc_Attr->hpen);
547 if (!PenBrushObj)
548 {
549 ret = FALSE;
550 goto cleanup;
551 }
552 BitmapObj = BITMAPOBJ_LockBitmap(dc->w.hBitmap);
553 if (!BitmapObj)
554 {
555 ret = FALSE;
556 goto cleanup;
557 }
558
559 if ( FillBrushObj )
560 {
561 if (!(FillBrushObj->flAttrs & GDIBRUSH_IS_NULL))
562 {
563 IntGdiInitBrushInstance(&FillBrushInst, FillBrushObj, dc->XlateBrush);
564 ret = IntEngBitBlt(&BitmapObj->SurfObj,
565 NULL,
566 NULL,
567 dc->CombinedClip,
568 NULL,
569 &DestRect,
570 NULL,
571 NULL,
572 &FillBrushInst.BrushObject,
573 NULL,
574 ROP3_TO_ROP4(PATCOPY));
575 }
576 }
577
578 IntGdiInitBrushInstance(&PenBrushInst, PenBrushObj, dc->XlatePen);
579
580 // Draw the rectangle with the current pen
581
582 ret = TRUE; // change default to success
583
584 if (!(PenBrushObj->flAttrs & GDIBRUSH_IS_NULL))
585 {
586 Mix = ROP2_TO_MIX(Dc_Attr->jROP2);
587 ret = ret && IntEngLineTo(&BitmapObj->SurfObj,
588 dc->CombinedClip,
589 &PenBrushInst.BrushObject,
590 DestRect.left, DestRect.top, DestRect.right, DestRect.top,
591 &DestRect, // Bounding rectangle
592 Mix);
593
594 ret = ret && IntEngLineTo(&BitmapObj->SurfObj,
595 dc->CombinedClip,
596 &PenBrushInst.BrushObject,
597 DestRect.right, DestRect.top, DestRect.right, DestRect.bottom,
598 &DestRect, // Bounding rectangle
599 Mix);
600
601 ret = ret && IntEngLineTo(&BitmapObj->SurfObj,
602 dc->CombinedClip,
603 &PenBrushInst.BrushObject,
604 DestRect.right, DestRect.bottom, DestRect.left, DestRect.bottom,
605 &DestRect, // Bounding rectangle
606 Mix);
607
608 ret = ret && IntEngLineTo(&BitmapObj->SurfObj,
609 dc->CombinedClip,
610 &PenBrushInst.BrushObject,
611 DestRect.left, DestRect.bottom, DestRect.left, DestRect.top,
612 &DestRect, // Bounding rectangle
613 Mix);
614 }
615
616 cleanup:
617 if (FillBrushObj)
618 BRUSHOBJ_UnlockBrush(FillBrushObj);
619
620 if (PenBrushObj)
621 PENOBJ_UnlockPen(PenBrushObj);
622
623 if (BitmapObj)
624 BITMAPOBJ_UnlockBitmap(BitmapObj);
625
626 /* Move current position in DC?
627 MSDN: The current position is neither used nor updated by Rectangle. */
628
629 return ret;
630 }
631
632 BOOL
633 STDCALL
634 NtGdiRectangle(HDC hDC,
635 int LeftRect,
636 int TopRect,
637 int RightRect,
638 int BottomRect)
639 {
640 DC *dc;
641 BOOL ret; // default to failure
642
643 dc = DC_LockDc(hDC);
644 if (!dc)
645 {
646 SetLastWin32Error(ERROR_INVALID_HANDLE);
647 return FALSE;
648 }
649 if (dc->DC_Type == DC_TYPE_INFO)
650 {
651 DC_UnlockDc(dc);
652 /* Yes, Windows really returns TRUE in this case */
653 return TRUE;
654 }
655
656 ret = IntRectangle ( dc, LeftRect, TopRect, RightRect, BottomRect );
657 DC_UnlockDc ( dc );
658
659 return ret;
660 }
661
662
663 BOOL
664 FASTCALL
665 IntRoundRect(
666 PDC dc,
667 int Left,
668 int Top,
669 int Right,
670 int Bottom,
671 int xCurveDiameter,
672 int yCurveDiameter)
673 {
674 PDC_ATTR Dc_Attr;
675 PGDIBRUSHOBJ PenBrushObj;
676 RECTL RectBounds;
677 LONG PenWidth, PenOrigWidth;
678 BOOL ret = TRUE; // default to success
679
680 ASSERT ( dc ); // caller's responsibility to set this up
681
682 if ( PATH_IsPathOpen(dc->DcLevel) )
683 return PATH_RoundRect ( dc, Left, Top, Right, Bottom,
684 xCurveDiameter, yCurveDiameter );
685
686 if ((Left == Right) || (Top == Bottom)) return TRUE;
687
688 xCurveDiameter = max(abs( xCurveDiameter ), 1);
689 yCurveDiameter = max(abs( yCurveDiameter ), 1);
690
691 if (Right < Left)
692 {
693 INT tmp = Right; Right = Left; Left = tmp;
694 }
695 if (Bottom < Top)
696 {
697 INT tmp = Bottom; Bottom = Top; Top = tmp;
698 }
699
700 Dc_Attr = dc->pDc_Attr;
701 if(!Dc_Attr) Dc_Attr = &dc->Dc_Attr;
702
703 PenBrushObj = PENOBJ_LockPen(Dc_Attr->hpen);
704 if (!PenBrushObj)
705 {
706 /* Nothing to do, as we don't have a bitmap */
707 SetLastWin32Error(ERROR_INTERNAL_ERROR);
708 return FALSE;
709 }
710
711 PenOrigWidth = PenWidth = PenBrushObj->ptPenWidth.x;
712 if (PenBrushObj->ulPenStyle == PS_NULL) PenWidth = 0;
713
714 if (PenBrushObj->ulPenStyle == PS_INSIDEFRAME)
715 {
716 if (2*PenWidth > (Right - Left)) PenWidth = (Right -Left + 1)/2;
717 if (2*PenWidth > (Bottom - Top)) PenWidth = (Bottom -Top + 1)/2;
718 Left += PenWidth / 2;
719 Right -= (PenWidth - 1) / 2;
720 Top += PenWidth / 2;
721 Bottom -= (PenWidth - 1) / 2;
722 }
723
724 if (!PenWidth) PenWidth = 1;
725 PenBrushObj->ptPenWidth.x = PenWidth;
726
727 RectBounds.left = Left;
728 RectBounds.top = Top;
729 RectBounds.right = Right;
730 RectBounds.bottom = Bottom;
731
732 IntLPtoDP(dc, (LPPOINT)&RectBounds, 2);
733
734 RectBounds.left += dc->ptlDCOrig.x;
735 RectBounds.top += dc->ptlDCOrig.y;
736 RectBounds.right += dc->ptlDCOrig.x;
737 RectBounds.bottom += dc->ptlDCOrig.y;
738
739 ret = IntFillRoundRect( dc,
740 RectBounds.left,
741 RectBounds.top,
742 RectBounds.right,
743 RectBounds.bottom,
744 xCurveDiameter,
745 yCurveDiameter);
746 if (ret)
747 ret = IntDrawRoundRect( dc,
748 RectBounds.left,
749 RectBounds.top,
750 RectBounds.right,
751 RectBounds.bottom,
752 xCurveDiameter,
753 yCurveDiameter,
754 PenBrushObj);
755
756 PenBrushObj->ptPenWidth.x = PenOrigWidth;
757 PENOBJ_UnlockPen(PenBrushObj);
758 return ret;
759 }
760
761 BOOL
762 STDCALL
763 NtGdiRoundRect(
764 HDC hDC,
765 int LeftRect,
766 int TopRect,
767 int RightRect,
768 int BottomRect,
769 int Width,
770 int Height)
771 {
772 DC *dc = DC_LockDc(hDC);
773 BOOL ret = FALSE; /* default to failure */
774
775 DPRINT("NtGdiRoundRect(0x%x,%i,%i,%i,%i,%i,%i)\n",hDC,LeftRect,TopRect,RightRect,BottomRect,Width,Height);
776 if ( !dc )
777 {
778 DPRINT1("NtGdiRoundRect() - hDC is invalid\n");
779 SetLastWin32Error(ERROR_INVALID_HANDLE);
780 }
781 else if (dc->DC_Type == DC_TYPE_INFO)
782 {
783 DC_UnlockDc(dc);
784 /* Yes, Windows really returns TRUE in this case */
785 ret = TRUE;
786 }
787 else
788 {
789 ret = IntRoundRect ( dc, LeftRect, TopRect, RightRect, BottomRect, Width, Height );
790 DC_UnlockDc ( dc );
791 }
792
793 return ret;
794 }
795
796 BOOL FASTCALL
797 IntGdiGradientFill(
798 DC *dc,
799 PTRIVERTEX pVertex,
800 ULONG uVertex,
801 PVOID pMesh,
802 ULONG uMesh,
803 ULONG ulMode)
804 {
805 BITMAPOBJ *BitmapObj;
806 PPALGDI PalDestGDI;
807 XLATEOBJ *XlateObj;
808 RECTL Extent;
809 POINTL DitherOrg;
810 ULONG Mode, i;
811 BOOL Ret;
812 HPALETTE hDestPalette;
813
814 ASSERT(dc);
815 ASSERT(pVertex);
816 ASSERT(uVertex);
817 ASSERT(pMesh);
818 ASSERT(uMesh);
819
820 /* check parameters */
821 if (ulMode & GRADIENT_FILL_TRIANGLE)
822 {
823 PGRADIENT_TRIANGLE tr = (PGRADIENT_TRIANGLE)pMesh;
824
825 for (i = 0; i < uMesh; i++, tr++)
826 {
827 if (tr->Vertex1 >= uVertex ||
828 tr->Vertex2 >= uVertex ||
829 tr->Vertex3 >= uVertex)
830 {
831 SetLastWin32Error(ERROR_INVALID_PARAMETER);
832 return FALSE;
833 }
834 }
835 }
836 else
837 {
838 PGRADIENT_RECT rc = (PGRADIENT_RECT)pMesh;
839 for (i = 0; i < uMesh; i++, rc++)
840 {
841 if (rc->UpperLeft >= uVertex || rc->LowerRight >= uVertex)
842 {
843 SetLastWin32Error(ERROR_INVALID_PARAMETER);
844 return FALSE;
845 }
846 }
847 }
848
849 /* calculate extent */
850 Extent.left = Extent.right = pVertex->x;
851 Extent.top = Extent.bottom = pVertex->y;
852 for (i = 0; i < uVertex; i++)
853 {
854 Extent.left = min(Extent.left, (pVertex + i)->x);
855 Extent.right = max(Extent.right, (pVertex + i)->x);
856 Extent.top = min(Extent.top, (pVertex + i)->y);
857 Extent.bottom = max(Extent.bottom, (pVertex + i)->y);
858 }
859
860 DitherOrg.x = dc->ptlDCOrig.x;
861 DitherOrg.y = dc->ptlDCOrig.y;
862 Extent.left += DitherOrg.x;
863 Extent.right += DitherOrg.x;
864 Extent.top += DitherOrg.y;
865 Extent.bottom += DitherOrg.y;
866
867 BitmapObj = BITMAPOBJ_LockBitmap(dc->w.hBitmap);
868 /* FIXME - BitmapObj can be NULL!!! Don't assert but handle this case gracefully! */
869 ASSERT(BitmapObj);
870
871 hDestPalette = BitmapObj->hDIBPalette;
872 if (!hDestPalette) hDestPalette = pPrimarySurface->DevInfo.hpalDefault;
873
874 PalDestGDI = PALETTE_LockPalette(hDestPalette);
875 if (PalDestGDI)
876 {
877 Mode = PalDestGDI->Mode;
878 PALETTE_UnlockPalette(PalDestGDI);
879 }
880 else
881 Mode = PAL_RGB;
882
883 XlateObj = (XLATEOBJ*)IntEngCreateXlate(Mode, PAL_RGB, hDestPalette, NULL);
884 ASSERT(XlateObj);
885
886 Ret = IntEngGradientFill(&BitmapObj->SurfObj,
887 dc->CombinedClip,
888 XlateObj,
889 pVertex,
890 uVertex,
891 pMesh,
892 uMesh,
893 &Extent,
894 &DitherOrg,
895 ulMode);
896
897 BITMAPOBJ_UnlockBitmap(BitmapObj);
898 EngDeleteXlate(XlateObj);
899
900 return Ret;
901 }
902
903 BOOL
904 STDCALL
905 NtGdiGradientFill(
906 HDC hdc,
907 PTRIVERTEX pVertex,
908 ULONG uVertex,
909 PVOID pMesh,
910 ULONG uMesh,
911 ULONG ulMode)
912 {
913 DC *dc;
914 BOOL Ret;
915 PTRIVERTEX SafeVertex;
916 PVOID SafeMesh;
917 ULONG SizeMesh;
918 NTSTATUS Status = STATUS_SUCCESS;
919
920 dc = DC_LockDc(hdc);
921 if (!dc)
922 {
923 SetLastWin32Error(ERROR_INVALID_HANDLE);
924 return FALSE;
925 }
926 if (dc->DC_Type == DC_TYPE_INFO)
927 {
928 DC_UnlockDc(dc);
929 /* Yes, Windows really returns TRUE in this case */
930 return TRUE;
931 }
932 if (!pVertex || !uVertex || !pMesh || !uMesh)
933 {
934 DC_UnlockDc(dc);
935 SetLastWin32Error(ERROR_INVALID_PARAMETER);
936 return FALSE;
937 }
938
939 switch (ulMode)
940 {
941 case GRADIENT_FILL_RECT_H:
942 case GRADIENT_FILL_RECT_V:
943 SizeMesh = uMesh * sizeof(GRADIENT_RECT);
944 break;
945 case GRADIENT_FILL_TRIANGLE:
946 SizeMesh = uMesh * sizeof(TRIVERTEX);
947 break;
948 default:
949 DC_UnlockDc(dc);
950 SetLastWin32Error(ERROR_INVALID_PARAMETER);
951 return FALSE;
952 }
953
954 _SEH_TRY
955 {
956 ProbeForRead(pVertex,
957 uVertex * sizeof(TRIVERTEX),
958 1);
959 ProbeForRead(pMesh,
960 SizeMesh,
961 1);
962 }
963 _SEH_HANDLE
964 {
965 Status = _SEH_GetExceptionCode();
966 }
967 _SEH_END;
968
969 if (!NT_SUCCESS(Status))
970 {
971 DC_UnlockDc(dc);
972 SetLastWin32Error(Status);
973 return FALSE;
974 }
975
976 if (!(SafeVertex = ExAllocatePoolWithTag(PagedPool, (uVertex * sizeof(TRIVERTEX)) + SizeMesh, TAG_SHAPE)))
977 {
978 DC_UnlockDc(dc);
979 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
980 return FALSE;
981 }
982
983 SafeMesh = (PTRIVERTEX)(SafeVertex + uVertex);
984
985 _SEH_TRY
986 {
987 /* pointers were already probed! */
988 RtlCopyMemory(SafeVertex,
989 pVertex,
990 uVertex * sizeof(TRIVERTEX));
991 RtlCopyMemory(SafeMesh,
992 pMesh,
993 SizeMesh);
994 }
995 _SEH_HANDLE
996 {
997 Status = _SEH_GetExceptionCode();
998 }
999 _SEH_END;
1000
1001 if (!NT_SUCCESS(Status))
1002 {
1003 DC_UnlockDc(dc);
1004 ExFreePool(SafeVertex);
1005 SetLastNtError(Status);
1006 return FALSE;
1007 }
1008
1009 Ret = IntGdiGradientFill(dc, SafeVertex, uVertex, SafeMesh, uMesh, ulMode);
1010
1011 DC_UnlockDc(dc);
1012 ExFreePool(SafeVertex);
1013 return Ret;
1014 }
1015
1016 BOOL STDCALL
1017 NtGdiExtFloodFill(
1018 HDC hDC,
1019 INT XStart,
1020 INT YStart,
1021 COLORREF Color,
1022 UINT FillType)
1023 {
1024 DPRINT1("FIXME: NtGdiExtFloodFill is UNIMPLEMENTED\n");
1025
1026 /* lie and say we succeded */
1027 return TRUE;
1028 }
1029
1030 /* EOF */