Create a branch for network fixes.
[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
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 UnsafePoints,
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 ( NULL == UnsafePoints || 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, UnsafePoints, Count);
78 for (CurrentPoint = 0; CurrentPoint < Count; CurrentPoint++)
79 {
80 UnsafePoints[CurrentPoint].x += dc->ptlDCOrig.x;
81 UnsafePoints[CurrentPoint].y += dc->ptlDCOrig.y;
82 }
83 // No need to have path here.
84 {
85 DestRect.left = UnsafePoints[0].x;
86 DestRect.right = UnsafePoints[0].x;
87 DestRect.top = UnsafePoints[0].y;
88 DestRect.bottom = UnsafePoints[0].y;
89
90 for (CurrentPoint = 1; CurrentPoint < Count; ++CurrentPoint)
91 {
92 DestRect.left = min(DestRect.left, UnsafePoints[CurrentPoint].x);
93 DestRect.right = max(DestRect.right, UnsafePoints[CurrentPoint].x);
94 DestRect.top = min(DestRect.top, UnsafePoints[CurrentPoint].y);
95 DestRect.bottom = max(DestRect.bottom, UnsafePoints[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), UnsafePoints, 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 // UnsafePoints[0].x, UnsafePoints[0].y,
126 // UnsafePoints[1].x, UnsafePoints[1].y );
127
128 ret = IntEngLineTo(&BitmapObj->SurfObj,
129 dc->CombinedClip,
130 &PenBrushInst.BrushObject,
131 UnsafePoints[i].x, /* From */
132 UnsafePoints[i].y,
133 UnsafePoints[i+1].x, /* To */
134 UnsafePoints[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 UnsafePoints[Count-1].x, /* From */
146 UnsafePoints[Count-1].y,
147 UnsafePoints[0].x, /* To */
148 UnsafePoints[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 LPINT PolyCounts,
165 int Count)
166 {
167 if (PATH_IsPathOpen(dc->DcLevel))
168 return PATH_PolyPolygon ( dc, Points, 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 Points,
340 IN PULONG PolyCounts,
341 IN ULONG Count,
342 IN INT iFunc )
343 {
344 DC *dc;
345 LPPOINT Safept;
346 LPINT SafePolyPoints;
347 NTSTATUS Status = STATUS_SUCCESS;
348 BOOL Ret = TRUE;
349 INT nPoints, nEmpty, nInvalid, i;
350
351 if (iFunc == GdiPolyPolyRgn)
352 {
353 return (ULONG_PTR) GdiCreatePolyPolygonRgn((CONST PPOINT) Points,
354 (CONST PINT) PolyCounts,
355 Count,
356 (INT) hDC);
357 }
358 dc = DC_LockDc(hDC);
359 if (!dc)
360 {
361 SetLastWin32Error(ERROR_INVALID_HANDLE);
362 return FALSE;
363 }
364 if (dc->DC_Type == DC_TYPE_INFO)
365 {
366 DC_UnlockDc(dc);
367 /* Yes, Windows really returns TRUE in this case */
368 return TRUE;
369 }
370
371 if (Count > 0)
372 {
373 _SEH_TRY
374 {
375 ProbeForRead(Points,
376 Count * sizeof(POINT),
377 1);
378 ProbeForRead(PolyCounts,
379 Count * sizeof(INT),
380 1);
381 }
382 _SEH_HANDLE
383 {
384 Status = _SEH_GetExceptionCode();
385 }
386 _SEH_END;
387
388 if (!NT_SUCCESS(Status))
389 {
390 DC_UnlockDc(dc);
391 SetLastNtError(Status);
392 return FALSE;
393 }
394
395 SafePolyPoints = ExAllocatePoolWithTag(PagedPool, Count * sizeof(INT), TAG_SHAPE);
396 if (!SafePolyPoints)
397 {
398 DC_UnlockDc(dc);
399 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
400 return FALSE;
401 }
402
403 _SEH_TRY
404 {
405 /* pointers already probed! */
406 RtlCopyMemory(SafePolyPoints,
407 PolyCounts,
408 Count * sizeof(INT));
409 }
410 _SEH_HANDLE
411 {
412 Status = _SEH_GetExceptionCode();
413 }
414 _SEH_END;
415
416 if (!NT_SUCCESS(Status))
417 {
418 DC_UnlockDc(dc);
419 ExFreePool(SafePolyPoints);
420 SetLastNtError(Status);
421 return FALSE;
422 }
423 /* validate poligons */
424 nPoints = 0;
425 nEmpty = 0;
426 nInvalid = 0;
427 for (i = 0; i < Count; i++)
428 {
429 if (SafePolyPoints[i] == 0)
430 {
431 nEmpty++;
432 }
433 if (SafePolyPoints[i] == 1)
434 {
435 nInvalid++;
436 }
437 nPoints += SafePolyPoints[i];
438 }
439
440 if (nEmpty == Count)
441 {
442 /* if all polygon counts are zero, return without setting a last error code. */
443 ExFreePool(SafePolyPoints);
444 return FALSE;
445 }
446 if (nInvalid != 0)
447 {
448 /* if at least one poly count is 1, fail */
449 ExFreePool(SafePolyPoints);
450 SetLastWin32Error(ERROR_INVALID_PARAMETER);
451 return FALSE;
452 }
453
454 Safept = ExAllocatePoolWithTag(PagedPool, nPoints * sizeof(POINT), TAG_SHAPE);
455 if (!Safept)
456 {
457 DC_UnlockDc(dc);
458 ExFreePool(SafePolyPoints);
459 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
460 return FALSE;
461 }
462
463 _SEH_TRY
464 {
465 /* pointers already probed! */
466 RtlCopyMemory(Safept,
467 Points,
468 nPoints * sizeof(POINT));
469 }
470 _SEH_HANDLE
471 {
472 Status = _SEH_GetExceptionCode();
473 }
474 _SEH_END;
475
476 if (!NT_SUCCESS(Status))
477 {
478 DC_UnlockDc(dc);
479 ExFreePool(SafePolyPoints);
480 ExFreePool(Safept);
481 SetLastNtError(Status);
482 return FALSE;
483 }
484 }
485 else
486 {
487 DC_UnlockDc(dc);
488 SetLastWin32Error(ERROR_INVALID_PARAMETER);
489 return FALSE;
490 }
491
492 switch (iFunc)
493 {
494 case GdiPolyPolygon:
495 Ret = IntGdiPolyPolygon(dc, Safept, SafePolyPoints, Count);
496 break;
497 case GdiPolyPolyLine:
498 Ret = IntGdiPolyPolyline(dc, Safept, (LPDWORD) SafePolyPoints, Count);
499 break;
500 case GdiPolyBezier:
501 Ret = IntGdiPolyBezier(dc, Safept, *PolyCounts);
502 break;
503 case GdiPolyLineTo:
504 Ret = IntGdiPolylineTo(dc, Safept, *PolyCounts);
505 break;
506 case GdiPolyBezierTo:
507 Ret = IntGdiPolyBezierTo(dc, Safept, *PolyCounts);
508 break;
509 default:
510 SetLastWin32Error(ERROR_INVALID_PARAMETER);
511 Ret = FALSE;
512 }
513 ExFreePool(SafePolyPoints);
514 ExFreePool(Safept);
515 DC_UnlockDc(dc);
516
517 return (ULONG_PTR) Ret;
518 }
519
520
521 BOOL
522 FASTCALL
523 IntRectangle(PDC dc,
524 int LeftRect,
525 int TopRect,
526 int RightRect,
527 int BottomRect)
528 {
529 BITMAPOBJ *BitmapObj = NULL;
530 PGDIBRUSHOBJ PenBrushObj = NULL, FillBrushObj = NULL;
531 GDIBRUSHINST PenBrushInst, FillBrushInst;
532 BOOL ret = FALSE; // default to failure
533 RECTL DestRect;
534 MIX Mix;
535 PDC_ATTR Dc_Attr;
536
537 ASSERT ( dc ); // caller's responsibility to set this up
538
539 Dc_Attr = dc->pDc_Attr;
540 if(!Dc_Attr) Dc_Attr = &dc->Dc_Attr;
541
542 /* Do we rotate or shear? */
543 if (!(dc->DcLevel.mxWorldToDevice.flAccel & MX_SCALE))
544 {
545 POINTL DestCoords[4];
546 DestCoords[0].x = DestCoords[3].x = LeftRect;
547 DestCoords[0].y = DestCoords[1].y = TopRect;
548 DestCoords[1].x = DestCoords[2].x = RightRect;
549 DestCoords[2].y = DestCoords[3].y = BottomRect;
550 return IntGdiPolygon(dc, DestCoords, 4);
551 }
552
553 if ( PATH_IsPathOpen(dc->DcLevel) )
554 {
555 return PATH_Rectangle ( dc, LeftRect, TopRect, RightRect, BottomRect );
556 }
557
558 DestRect.left = LeftRect;
559 DestRect.right = RightRect;
560 DestRect.top = TopRect;
561 DestRect.bottom = BottomRect;
562
563 IntLPtoDP(dc, (LPPOINT)&DestRect, 2);
564
565 DestRect.left += dc->ptlDCOrig.x;
566 DestRect.right += dc->ptlDCOrig.x;
567 DestRect.top += dc->ptlDCOrig.y;
568 DestRect.bottom += dc->ptlDCOrig.y;
569
570 /* In GM_COMPATIBLE, don't include bottom and right edges */
571 if (IntGetGraphicsMode(dc) == GM_COMPATIBLE)
572 {
573 DestRect.right--;
574 DestRect.bottom--;
575 }
576
577 /* Special locking order to avoid lock-ups! */
578 FillBrushObj = BRUSHOBJ_LockBrush(Dc_Attr->hbrush);
579 PenBrushObj = PENOBJ_LockPen(Dc_Attr->hpen);
580 if (!PenBrushObj)
581 {
582 ret = FALSE;
583 goto cleanup;
584 }
585 BitmapObj = BITMAPOBJ_LockBitmap(dc->w.hBitmap);
586 if (!BitmapObj)
587 {
588 ret = FALSE;
589 goto cleanup;
590 }
591
592 if ( FillBrushObj )
593 {
594 if (!(FillBrushObj->flAttrs & GDIBRUSH_IS_NULL))
595 {
596 IntGdiInitBrushInstance(&FillBrushInst, FillBrushObj, dc->XlateBrush);
597 ret = IntEngBitBlt(&BitmapObj->SurfObj,
598 NULL,
599 NULL,
600 dc->CombinedClip,
601 NULL,
602 &DestRect,
603 NULL,
604 NULL,
605 &FillBrushInst.BrushObject,
606 NULL,
607 ROP3_TO_ROP4(PATCOPY));
608 }
609 }
610
611 IntGdiInitBrushInstance(&PenBrushInst, PenBrushObj, dc->XlatePen);
612
613 // Draw the rectangle with the current pen
614
615 ret = TRUE; // change default to success
616
617 if (!(PenBrushObj->flAttrs & GDIBRUSH_IS_NULL))
618 {
619 Mix = ROP2_TO_MIX(Dc_Attr->jROP2);
620 ret = ret && IntEngLineTo(&BitmapObj->SurfObj,
621 dc->CombinedClip,
622 &PenBrushInst.BrushObject,
623 DestRect.left, DestRect.top, DestRect.right, DestRect.top,
624 &DestRect, // Bounding rectangle
625 Mix);
626
627 ret = ret && IntEngLineTo(&BitmapObj->SurfObj,
628 dc->CombinedClip,
629 &PenBrushInst.BrushObject,
630 DestRect.right, DestRect.top, DestRect.right, DestRect.bottom,
631 &DestRect, // Bounding rectangle
632 Mix);
633
634 ret = ret && IntEngLineTo(&BitmapObj->SurfObj,
635 dc->CombinedClip,
636 &PenBrushInst.BrushObject,
637 DestRect.right, DestRect.bottom, DestRect.left, DestRect.bottom,
638 &DestRect, // Bounding rectangle
639 Mix);
640
641 ret = ret && IntEngLineTo(&BitmapObj->SurfObj,
642 dc->CombinedClip,
643 &PenBrushInst.BrushObject,
644 DestRect.left, DestRect.bottom, DestRect.left, DestRect.top,
645 &DestRect, // Bounding rectangle
646 Mix);
647 }
648
649 cleanup:
650 if (FillBrushObj)
651 BRUSHOBJ_UnlockBrush(FillBrushObj);
652
653 if (PenBrushObj)
654 PENOBJ_UnlockPen(PenBrushObj);
655
656 if (BitmapObj)
657 BITMAPOBJ_UnlockBitmap(BitmapObj);
658
659 /* Move current position in DC?
660 MSDN: The current position is neither used nor updated by Rectangle. */
661
662 return ret;
663 }
664
665 BOOL
666 STDCALL
667 NtGdiRectangle(HDC hDC,
668 int LeftRect,
669 int TopRect,
670 int RightRect,
671 int BottomRect)
672 {
673 DC *dc;
674 BOOL ret; // default to failure
675
676 dc = DC_LockDc(hDC);
677 if (!dc)
678 {
679 SetLastWin32Error(ERROR_INVALID_HANDLE);
680 return FALSE;
681 }
682 if (dc->DC_Type == DC_TYPE_INFO)
683 {
684 DC_UnlockDc(dc);
685 /* Yes, Windows really returns TRUE in this case */
686 return TRUE;
687 }
688
689 ret = IntRectangle ( dc, LeftRect, TopRect, RightRect, BottomRect );
690 DC_UnlockDc ( dc );
691
692 return ret;
693 }
694
695
696 BOOL
697 FASTCALL
698 IntRoundRect(
699 PDC dc,
700 int Left,
701 int Top,
702 int Right,
703 int Bottom,
704 int xCurveDiameter,
705 int yCurveDiameter)
706 {
707 PDC_ATTR Dc_Attr;
708 PGDIBRUSHOBJ PenBrushObj;
709 RECTL RectBounds;
710 LONG PenWidth, PenOrigWidth;
711 BOOL ret = TRUE; // default to success
712
713 ASSERT ( dc ); // caller's responsibility to set this up
714
715 if ( PATH_IsPathOpen(dc->DcLevel) )
716 return PATH_RoundRect ( dc, Left, Top, Right, Bottom,
717 xCurveDiameter, yCurveDiameter );
718
719 if ((Left == Right) || (Top == Bottom)) return TRUE;
720
721 xCurveDiameter = max(abs( xCurveDiameter ), 1);
722 yCurveDiameter = max(abs( yCurveDiameter ), 1);
723
724 if (Right < Left)
725 {
726 INT tmp = Right; Right = Left; Left = tmp;
727 }
728 if (Bottom < Top)
729 {
730 INT tmp = Bottom; Bottom = Top; Top = tmp;
731 }
732
733 Dc_Attr = dc->pDc_Attr;
734 if(!Dc_Attr) Dc_Attr = &dc->Dc_Attr;
735
736 PenBrushObj = PENOBJ_LockPen(Dc_Attr->hpen);
737 if (!PenBrushObj)
738 {
739 /* Nothing to do, as we don't have a bitmap */
740 SetLastWin32Error(ERROR_INTERNAL_ERROR);
741 return FALSE;
742 }
743
744 PenOrigWidth = PenWidth = PenBrushObj->ptPenWidth.x;
745 if (PenBrushObj->ulPenStyle == PS_NULL) PenWidth = 0;
746
747 if (PenBrushObj->ulPenStyle == PS_INSIDEFRAME)
748 {
749 if (2*PenWidth > (Right - Left)) PenWidth = (Right -Left + 1)/2;
750 if (2*PenWidth > (Bottom - Top)) PenWidth = (Bottom -Top + 1)/2;
751 Left += PenWidth / 2;
752 Right -= (PenWidth - 1) / 2;
753 Top += PenWidth / 2;
754 Bottom -= (PenWidth - 1) / 2;
755 }
756
757 if (!PenWidth) PenWidth = 1;
758 PenBrushObj->ptPenWidth.x = PenWidth;
759
760 RectBounds.left = Left;
761 RectBounds.top = Top;
762 RectBounds.right = Right;
763 RectBounds.bottom = Bottom;
764
765 IntLPtoDP(dc, (LPPOINT)&RectBounds, 2);
766
767 RectBounds.left += dc->ptlDCOrig.x;
768 RectBounds.top += dc->ptlDCOrig.y;
769 RectBounds.right += dc->ptlDCOrig.x;
770 RectBounds.bottom += dc->ptlDCOrig.y;
771
772 ret = IntFillRoundRect( dc,
773 RectBounds.left,
774 RectBounds.top,
775 RectBounds.right,
776 RectBounds.bottom,
777 xCurveDiameter,
778 yCurveDiameter);
779 if (ret)
780 ret = IntDrawRoundRect( dc,
781 RectBounds.left,
782 RectBounds.top,
783 RectBounds.right,
784 RectBounds.bottom,
785 xCurveDiameter,
786 yCurveDiameter,
787 PenBrushObj);
788
789 PenBrushObj->ptPenWidth.x = PenOrigWidth;
790 PENOBJ_UnlockPen(PenBrushObj);
791 return ret;
792 }
793
794 BOOL
795 STDCALL
796 NtGdiRoundRect(
797 HDC hDC,
798 int LeftRect,
799 int TopRect,
800 int RightRect,
801 int BottomRect,
802 int Width,
803 int Height)
804 {
805 DC *dc = DC_LockDc(hDC);
806 BOOL ret = FALSE; /* default to failure */
807
808 DPRINT("NtGdiRoundRect(0x%x,%i,%i,%i,%i,%i,%i)\n",hDC,LeftRect,TopRect,RightRect,BottomRect,Width,Height);
809 if ( !dc )
810 {
811 DPRINT1("NtGdiRoundRect() - hDC is invalid\n");
812 SetLastWin32Error(ERROR_INVALID_HANDLE);
813 }
814 else if (dc->DC_Type == DC_TYPE_INFO)
815 {
816 DC_UnlockDc(dc);
817 /* Yes, Windows really returns TRUE in this case */
818 ret = TRUE;
819 }
820 else
821 {
822 ret = IntRoundRect ( dc, LeftRect, TopRect, RightRect, BottomRect, Width, Height );
823 DC_UnlockDc ( dc );
824 }
825
826 return ret;
827 }
828
829 BOOL FASTCALL
830 IntGdiGradientFill(
831 DC *dc,
832 PTRIVERTEX pVertex,
833 ULONG uVertex,
834 PVOID pMesh,
835 ULONG uMesh,
836 ULONG ulMode)
837 {
838 BITMAPOBJ *BitmapObj;
839 PPALGDI PalDestGDI;
840 XLATEOBJ *XlateObj;
841 RECTL Extent;
842 POINTL DitherOrg;
843 ULONG Mode, i;
844 BOOL Ret;
845 HPALETTE hDestPalette;
846
847 ASSERT(dc);
848 ASSERT(pVertex);
849 ASSERT(uVertex);
850 ASSERT(pMesh);
851 ASSERT(uMesh);
852
853 /* check parameters */
854 if (ulMode & GRADIENT_FILL_TRIANGLE)
855 {
856 PGRADIENT_TRIANGLE tr = (PGRADIENT_TRIANGLE)pMesh;
857
858 for (i = 0; i < uMesh; i++, tr++)
859 {
860 if (tr->Vertex1 >= uVertex ||
861 tr->Vertex2 >= uVertex ||
862 tr->Vertex3 >= uVertex)
863 {
864 SetLastWin32Error(ERROR_INVALID_PARAMETER);
865 return FALSE;
866 }
867 }
868 }
869 else
870 {
871 PGRADIENT_RECT rc = (PGRADIENT_RECT)pMesh;
872 for (i = 0; i < uMesh; i++, rc++)
873 {
874 if (rc->UpperLeft >= uVertex || rc->LowerRight >= uVertex)
875 {
876 SetLastWin32Error(ERROR_INVALID_PARAMETER);
877 return FALSE;
878 }
879 }
880 }
881
882 /* calculate extent */
883 Extent.left = Extent.right = pVertex->x;
884 Extent.top = Extent.bottom = pVertex->y;
885 for (i = 0; i < uVertex; i++)
886 {
887 Extent.left = min(Extent.left, (pVertex + i)->x);
888 Extent.right = max(Extent.right, (pVertex + i)->x);
889 Extent.top = min(Extent.top, (pVertex + i)->y);
890 Extent.bottom = max(Extent.bottom, (pVertex + i)->y);
891 }
892
893 DitherOrg.x = dc->ptlDCOrig.x;
894 DitherOrg.y = dc->ptlDCOrig.y;
895 Extent.left += DitherOrg.x;
896 Extent.right += DitherOrg.x;
897 Extent.top += DitherOrg.y;
898 Extent.bottom += DitherOrg.y;
899
900 BitmapObj = BITMAPOBJ_LockBitmap(dc->w.hBitmap);
901 /* FIXME - BitmapObj can be NULL!!! Don't assert but handle this case gracefully! */
902 ASSERT(BitmapObj);
903
904 hDestPalette = BitmapObj->hDIBPalette;
905 if (!hDestPalette) hDestPalette = pPrimarySurface->DevInfo.hpalDefault;
906
907 PalDestGDI = PALETTE_LockPalette(hDestPalette);
908 if (PalDestGDI)
909 {
910 Mode = PalDestGDI->Mode;
911 PALETTE_UnlockPalette(PalDestGDI);
912 }
913 else
914 Mode = PAL_RGB;
915
916 XlateObj = (XLATEOBJ*)IntEngCreateXlate(Mode, PAL_RGB, hDestPalette, NULL);
917 ASSERT(XlateObj);
918
919 Ret = IntEngGradientFill(&BitmapObj->SurfObj,
920 dc->CombinedClip,
921 XlateObj,
922 pVertex,
923 uVertex,
924 pMesh,
925 uMesh,
926 &Extent,
927 &DitherOrg,
928 ulMode);
929
930 BITMAPOBJ_UnlockBitmap(BitmapObj);
931 EngDeleteXlate(XlateObj);
932
933 return Ret;
934 }
935
936 BOOL
937 STDCALL
938 NtGdiGradientFill(
939 HDC hdc,
940 PTRIVERTEX pVertex,
941 ULONG uVertex,
942 PVOID pMesh,
943 ULONG uMesh,
944 ULONG ulMode)
945 {
946 DC *dc;
947 BOOL Ret;
948 PTRIVERTEX SafeVertex;
949 PVOID SafeMesh;
950 ULONG SizeMesh;
951 NTSTATUS Status = STATUS_SUCCESS;
952
953 dc = DC_LockDc(hdc);
954 if (!dc)
955 {
956 SetLastWin32Error(ERROR_INVALID_HANDLE);
957 return FALSE;
958 }
959 if (dc->DC_Type == DC_TYPE_INFO)
960 {
961 DC_UnlockDc(dc);
962 /* Yes, Windows really returns TRUE in this case */
963 return TRUE;
964 }
965 if (!pVertex || !uVertex || !pMesh || !uMesh)
966 {
967 DC_UnlockDc(dc);
968 SetLastWin32Error(ERROR_INVALID_PARAMETER);
969 return FALSE;
970 }
971
972 switch (ulMode)
973 {
974 case GRADIENT_FILL_RECT_H:
975 case GRADIENT_FILL_RECT_V:
976 SizeMesh = uMesh * sizeof(GRADIENT_RECT);
977 break;
978 case GRADIENT_FILL_TRIANGLE:
979 SizeMesh = uMesh * sizeof(TRIVERTEX);
980 break;
981 default:
982 DC_UnlockDc(dc);
983 SetLastWin32Error(ERROR_INVALID_PARAMETER);
984 return FALSE;
985 }
986
987 _SEH_TRY
988 {
989 ProbeForRead(pVertex,
990 uVertex * sizeof(TRIVERTEX),
991 1);
992 ProbeForRead(pMesh,
993 SizeMesh,
994 1);
995 }
996 _SEH_HANDLE
997 {
998 Status = _SEH_GetExceptionCode();
999 }
1000 _SEH_END;
1001
1002 if (!NT_SUCCESS(Status))
1003 {
1004 DC_UnlockDc(dc);
1005 SetLastWin32Error(Status);
1006 return FALSE;
1007 }
1008
1009 if (!(SafeVertex = ExAllocatePoolWithTag(PagedPool, (uVertex * sizeof(TRIVERTEX)) + SizeMesh, TAG_SHAPE)))
1010 {
1011 DC_UnlockDc(dc);
1012 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
1013 return FALSE;
1014 }
1015
1016 SafeMesh = (PTRIVERTEX)(SafeVertex + uVertex);
1017
1018 _SEH_TRY
1019 {
1020 /* pointers were already probed! */
1021 RtlCopyMemory(SafeVertex,
1022 pVertex,
1023 uVertex * sizeof(TRIVERTEX));
1024 RtlCopyMemory(SafeMesh,
1025 pMesh,
1026 SizeMesh);
1027 }
1028 _SEH_HANDLE
1029 {
1030 Status = _SEH_GetExceptionCode();
1031 }
1032 _SEH_END;
1033
1034 if (!NT_SUCCESS(Status))
1035 {
1036 DC_UnlockDc(dc);
1037 ExFreePool(SafeVertex);
1038 SetLastNtError(Status);
1039 return FALSE;
1040 }
1041
1042 Ret = IntGdiGradientFill(dc, SafeVertex, uVertex, SafeMesh, uMesh, ulMode);
1043
1044 DC_UnlockDc(dc);
1045 ExFreePool(SafeVertex);
1046 return Ret;
1047 }
1048
1049 BOOL STDCALL
1050 NtGdiExtFloodFill(
1051 HDC hDC,
1052 INT XStart,
1053 INT YStart,
1054 COLORREF Color,
1055 UINT FillType)
1056 {
1057 DPRINT1("FIXME: NtGdiExtFloodFill is UNIMPLEMENTED\n");
1058
1059 /* lie and say we succeded */
1060 return TRUE;
1061 }
1062
1063 /* EOF */