DC_AllocDc:
[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 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 & MXACC_DIAGONAL))
544 if (dc->DcLevel.xformWorld2Vport.eM12 != 0. || dc->DcLevel.xformWorld2Vport.eM21 != 0.)
545 {
546 POINTL DestCoords[4];
547 DestCoords[0].x = DestCoords[3].x = LeftRect;
548 DestCoords[0].y = DestCoords[1].y = TopRect;
549 DestCoords[1].x = DestCoords[2].x = RightRect;
550 DestCoords[2].y = DestCoords[3].y = BottomRect;
551 return IntGdiPolygon(dc, DestCoords, 4);
552 }
553
554 if ( PATH_IsPathOpen(dc->DcLevel) )
555 {
556 return PATH_Rectangle ( dc, LeftRect, TopRect, RightRect, BottomRect );
557 }
558
559 DestRect.left = LeftRect;
560 DestRect.right = RightRect;
561 DestRect.top = TopRect;
562 DestRect.bottom = BottomRect;
563
564 IntLPtoDP(dc, (LPPOINT)&DestRect, 2);
565
566 DestRect.left += dc->ptlDCOrig.x;
567 DestRect.right += dc->ptlDCOrig.x;
568 DestRect.top += dc->ptlDCOrig.y;
569 DestRect.bottom += dc->ptlDCOrig.y;
570
571 /* In GM_COMPATIBLE, don't include bottom and right edges */
572 if (IntGetGraphicsMode(dc) == GM_COMPATIBLE)
573 {
574 DestRect.right--;
575 DestRect.bottom--;
576 }
577
578 /* Special locking order to avoid lock-ups! */
579 FillBrushObj = BRUSHOBJ_LockBrush(Dc_Attr->hbrush);
580 PenBrushObj = PENOBJ_LockPen(Dc_Attr->hpen);
581 if (!PenBrushObj)
582 {
583 ret = FALSE;
584 goto cleanup;
585 }
586 BitmapObj = BITMAPOBJ_LockBitmap(dc->w.hBitmap);
587 if (!BitmapObj)
588 {
589 ret = FALSE;
590 goto cleanup;
591 }
592
593 if ( FillBrushObj )
594 {
595 if (!(FillBrushObj->flAttrs & GDIBRUSH_IS_NULL))
596 {
597 IntGdiInitBrushInstance(&FillBrushInst, FillBrushObj, dc->XlateBrush);
598 ret = IntEngBitBlt(&BitmapObj->SurfObj,
599 NULL,
600 NULL,
601 dc->CombinedClip,
602 NULL,
603 &DestRect,
604 NULL,
605 NULL,
606 &FillBrushInst.BrushObject,
607 NULL,
608 ROP3_TO_ROP4(PATCOPY));
609 }
610 }
611
612 IntGdiInitBrushInstance(&PenBrushInst, PenBrushObj, dc->XlatePen);
613
614 // Draw the rectangle with the current pen
615
616 ret = TRUE; // change default to success
617
618 if (!(PenBrushObj->flAttrs & GDIBRUSH_IS_NULL))
619 {
620 Mix = ROP2_TO_MIX(Dc_Attr->jROP2);
621 ret = ret && IntEngLineTo(&BitmapObj->SurfObj,
622 dc->CombinedClip,
623 &PenBrushInst.BrushObject,
624 DestRect.left, DestRect.top, DestRect.right, DestRect.top,
625 &DestRect, // Bounding rectangle
626 Mix);
627
628 ret = ret && IntEngLineTo(&BitmapObj->SurfObj,
629 dc->CombinedClip,
630 &PenBrushInst.BrushObject,
631 DestRect.right, DestRect.top, DestRect.right, DestRect.bottom,
632 &DestRect, // Bounding rectangle
633 Mix);
634
635 ret = ret && IntEngLineTo(&BitmapObj->SurfObj,
636 dc->CombinedClip,
637 &PenBrushInst.BrushObject,
638 DestRect.right, DestRect.bottom, DestRect.left, DestRect.bottom,
639 &DestRect, // Bounding rectangle
640 Mix);
641
642 ret = ret && IntEngLineTo(&BitmapObj->SurfObj,
643 dc->CombinedClip,
644 &PenBrushInst.BrushObject,
645 DestRect.left, DestRect.bottom, DestRect.left, DestRect.top,
646 &DestRect, // Bounding rectangle
647 Mix);
648 }
649
650 cleanup:
651 if (FillBrushObj)
652 BRUSHOBJ_UnlockBrush(FillBrushObj);
653
654 if (PenBrushObj)
655 PENOBJ_UnlockPen(PenBrushObj);
656
657 if (BitmapObj)
658 BITMAPOBJ_UnlockBitmap(BitmapObj);
659
660 /* Move current position in DC?
661 MSDN: The current position is neither used nor updated by Rectangle. */
662
663 return ret;
664 }
665
666 BOOL
667 STDCALL
668 NtGdiRectangle(HDC hDC,
669 int LeftRect,
670 int TopRect,
671 int RightRect,
672 int BottomRect)
673 {
674 DC *dc;
675 BOOL ret; // default to failure
676
677 dc = DC_LockDc(hDC);
678 if (!dc)
679 {
680 SetLastWin32Error(ERROR_INVALID_HANDLE);
681 return FALSE;
682 }
683 if (dc->DC_Type == DC_TYPE_INFO)
684 {
685 DC_UnlockDc(dc);
686 /* Yes, Windows really returns TRUE in this case */
687 return TRUE;
688 }
689
690 ret = IntRectangle ( dc, LeftRect, TopRect, RightRect, BottomRect );
691 DC_UnlockDc ( dc );
692
693 return ret;
694 }
695
696
697 BOOL
698 FASTCALL
699 IntRoundRect(
700 PDC dc,
701 int Left,
702 int Top,
703 int Right,
704 int Bottom,
705 int xCurveDiameter,
706 int yCurveDiameter)
707 {
708 PDC_ATTR Dc_Attr;
709 PGDIBRUSHOBJ PenBrushObj;
710 RECTL RectBounds;
711 LONG PenWidth, PenOrigWidth;
712 BOOL ret = TRUE; // default to success
713
714 ASSERT ( dc ); // caller's responsibility to set this up
715
716 if ( PATH_IsPathOpen(dc->DcLevel) )
717 return PATH_RoundRect ( dc, Left, Top, Right, Bottom,
718 xCurveDiameter, yCurveDiameter );
719
720 if ((Left == Right) || (Top == Bottom)) return TRUE;
721
722 xCurveDiameter = max(abs( xCurveDiameter ), 1);
723 yCurveDiameter = max(abs( yCurveDiameter ), 1);
724
725 if (Right < Left)
726 {
727 INT tmp = Right; Right = Left; Left = tmp;
728 }
729 if (Bottom < Top)
730 {
731 INT tmp = Bottom; Bottom = Top; Top = tmp;
732 }
733
734 Dc_Attr = dc->pDc_Attr;
735 if(!Dc_Attr) Dc_Attr = &dc->Dc_Attr;
736
737 PenBrushObj = PENOBJ_LockPen(Dc_Attr->hpen);
738 if (!PenBrushObj)
739 {
740 /* Nothing to do, as we don't have a bitmap */
741 SetLastWin32Error(ERROR_INTERNAL_ERROR);
742 return FALSE;
743 }
744
745 PenOrigWidth = PenWidth = PenBrushObj->ptPenWidth.x;
746 if (PenBrushObj->ulPenStyle == PS_NULL) PenWidth = 0;
747
748 if (PenBrushObj->ulPenStyle == PS_INSIDEFRAME)
749 {
750 if (2*PenWidth > (Right - Left)) PenWidth = (Right -Left + 1)/2;
751 if (2*PenWidth > (Bottom - Top)) PenWidth = (Bottom -Top + 1)/2;
752 Left += PenWidth / 2;
753 Right -= (PenWidth - 1) / 2;
754 Top += PenWidth / 2;
755 Bottom -= (PenWidth - 1) / 2;
756 }
757
758 if (!PenWidth) PenWidth = 1;
759 PenBrushObj->ptPenWidth.x = PenWidth;
760
761 RectBounds.left = Left;
762 RectBounds.top = Top;
763 RectBounds.right = Right;
764 RectBounds.bottom = Bottom;
765
766 IntLPtoDP(dc, (LPPOINT)&RectBounds, 2);
767
768 RectBounds.left += dc->ptlDCOrig.x;
769 RectBounds.top += dc->ptlDCOrig.y;
770 RectBounds.right += dc->ptlDCOrig.x;
771 RectBounds.bottom += dc->ptlDCOrig.y;
772
773 ret = IntFillRoundRect( dc,
774 RectBounds.left,
775 RectBounds.top,
776 RectBounds.right,
777 RectBounds.bottom,
778 xCurveDiameter,
779 yCurveDiameter);
780 if (ret)
781 ret = IntDrawRoundRect( dc,
782 RectBounds.left,
783 RectBounds.top,
784 RectBounds.right,
785 RectBounds.bottom,
786 xCurveDiameter,
787 yCurveDiameter,
788 PenBrushObj);
789
790 PenBrushObj->ptPenWidth.x = PenOrigWidth;
791 PENOBJ_UnlockPen(PenBrushObj);
792 return ret;
793 }
794
795 BOOL
796 STDCALL
797 NtGdiRoundRect(
798 HDC hDC,
799 int LeftRect,
800 int TopRect,
801 int RightRect,
802 int BottomRect,
803 int Width,
804 int Height)
805 {
806 DC *dc = DC_LockDc(hDC);
807 BOOL ret = FALSE; /* default to failure */
808
809 DPRINT("NtGdiRoundRect(0x%x,%i,%i,%i,%i,%i,%i)\n",hDC,LeftRect,TopRect,RightRect,BottomRect,Width,Height);
810 if ( !dc )
811 {
812 DPRINT1("NtGdiRoundRect() - hDC is invalid\n");
813 SetLastWin32Error(ERROR_INVALID_HANDLE);
814 }
815 else if (dc->DC_Type == DC_TYPE_INFO)
816 {
817 DC_UnlockDc(dc);
818 /* Yes, Windows really returns TRUE in this case */
819 ret = TRUE;
820 }
821 else
822 {
823 ret = IntRoundRect ( dc, LeftRect, TopRect, RightRect, BottomRect, Width, Height );
824 DC_UnlockDc ( dc );
825 }
826
827 return ret;
828 }
829
830 BOOL FASTCALL
831 IntGdiGradientFill(
832 DC *dc,
833 PTRIVERTEX pVertex,
834 ULONG uVertex,
835 PVOID pMesh,
836 ULONG uMesh,
837 ULONG ulMode)
838 {
839 BITMAPOBJ *BitmapObj;
840 PPALGDI PalDestGDI;
841 XLATEOBJ *XlateObj;
842 RECTL Extent;
843 POINTL DitherOrg;
844 ULONG Mode, i;
845 BOOL Ret;
846 HPALETTE hDestPalette;
847
848 ASSERT(dc);
849 ASSERT(pVertex);
850 ASSERT(uVertex);
851 ASSERT(pMesh);
852 ASSERT(uMesh);
853
854 /* check parameters */
855 if (ulMode & GRADIENT_FILL_TRIANGLE)
856 {
857 PGRADIENT_TRIANGLE tr = (PGRADIENT_TRIANGLE)pMesh;
858
859 for (i = 0; i < uMesh; i++, tr++)
860 {
861 if (tr->Vertex1 >= uVertex ||
862 tr->Vertex2 >= uVertex ||
863 tr->Vertex3 >= uVertex)
864 {
865 SetLastWin32Error(ERROR_INVALID_PARAMETER);
866 return FALSE;
867 }
868 }
869 }
870 else
871 {
872 PGRADIENT_RECT rc = (PGRADIENT_RECT)pMesh;
873 for (i = 0; i < uMesh; i++, rc++)
874 {
875 if (rc->UpperLeft >= uVertex || rc->LowerRight >= uVertex)
876 {
877 SetLastWin32Error(ERROR_INVALID_PARAMETER);
878 return FALSE;
879 }
880 }
881 }
882
883 /* calculate extent */
884 Extent.left = Extent.right = pVertex->x;
885 Extent.top = Extent.bottom = pVertex->y;
886 for (i = 0; i < uVertex; i++)
887 {
888 Extent.left = min(Extent.left, (pVertex + i)->x);
889 Extent.right = max(Extent.right, (pVertex + i)->x);
890 Extent.top = min(Extent.top, (pVertex + i)->y);
891 Extent.bottom = max(Extent.bottom, (pVertex + i)->y);
892 }
893
894 DitherOrg.x = dc->ptlDCOrig.x;
895 DitherOrg.y = dc->ptlDCOrig.y;
896 Extent.left += DitherOrg.x;
897 Extent.right += DitherOrg.x;
898 Extent.top += DitherOrg.y;
899 Extent.bottom += DitherOrg.y;
900
901 BitmapObj = BITMAPOBJ_LockBitmap(dc->w.hBitmap);
902 /* FIXME - BitmapObj can be NULL!!! Don't assert but handle this case gracefully! */
903 ASSERT(BitmapObj);
904
905 hDestPalette = BitmapObj->hDIBPalette;
906 if (!hDestPalette) hDestPalette = pPrimarySurface->DevInfo.hpalDefault;
907
908 PalDestGDI = PALETTE_LockPalette(hDestPalette);
909 if (PalDestGDI)
910 {
911 Mode = PalDestGDI->Mode;
912 PALETTE_UnlockPalette(PalDestGDI);
913 }
914 else
915 Mode = PAL_RGB;
916
917 XlateObj = (XLATEOBJ*)IntEngCreateXlate(Mode, PAL_RGB, hDestPalette, NULL);
918 ASSERT(XlateObj);
919
920 Ret = IntEngGradientFill(&BitmapObj->SurfObj,
921 dc->CombinedClip,
922 XlateObj,
923 pVertex,
924 uVertex,
925 pMesh,
926 uMesh,
927 &Extent,
928 &DitherOrg,
929 ulMode);
930
931 BITMAPOBJ_UnlockBitmap(BitmapObj);
932 EngDeleteXlate(XlateObj);
933
934 return Ret;
935 }
936
937 BOOL
938 STDCALL
939 NtGdiGradientFill(
940 HDC hdc,
941 PTRIVERTEX pVertex,
942 ULONG uVertex,
943 PVOID pMesh,
944 ULONG uMesh,
945 ULONG ulMode)
946 {
947 DC *dc;
948 BOOL Ret;
949 PTRIVERTEX SafeVertex;
950 PVOID SafeMesh;
951 ULONG SizeMesh;
952 NTSTATUS Status = STATUS_SUCCESS;
953
954 dc = DC_LockDc(hdc);
955 if (!dc)
956 {
957 SetLastWin32Error(ERROR_INVALID_HANDLE);
958 return FALSE;
959 }
960 if (dc->DC_Type == DC_TYPE_INFO)
961 {
962 DC_UnlockDc(dc);
963 /* Yes, Windows really returns TRUE in this case */
964 return TRUE;
965 }
966 if (!pVertex || !uVertex || !pMesh || !uMesh)
967 {
968 DC_UnlockDc(dc);
969 SetLastWin32Error(ERROR_INVALID_PARAMETER);
970 return FALSE;
971 }
972
973 switch (ulMode)
974 {
975 case GRADIENT_FILL_RECT_H:
976 case GRADIENT_FILL_RECT_V:
977 SizeMesh = uMesh * sizeof(GRADIENT_RECT);
978 break;
979 case GRADIENT_FILL_TRIANGLE:
980 SizeMesh = uMesh * sizeof(TRIVERTEX);
981 break;
982 default:
983 DC_UnlockDc(dc);
984 SetLastWin32Error(ERROR_INVALID_PARAMETER);
985 return FALSE;
986 }
987
988 _SEH_TRY
989 {
990 ProbeForRead(pVertex,
991 uVertex * sizeof(TRIVERTEX),
992 1);
993 ProbeForRead(pMesh,
994 SizeMesh,
995 1);
996 }
997 _SEH_HANDLE
998 {
999 Status = _SEH_GetExceptionCode();
1000 }
1001 _SEH_END;
1002
1003 if (!NT_SUCCESS(Status))
1004 {
1005 DC_UnlockDc(dc);
1006 SetLastWin32Error(Status);
1007 return FALSE;
1008 }
1009
1010 if (!(SafeVertex = ExAllocatePoolWithTag(PagedPool, (uVertex * sizeof(TRIVERTEX)) + SizeMesh, TAG_SHAPE)))
1011 {
1012 DC_UnlockDc(dc);
1013 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
1014 return FALSE;
1015 }
1016
1017 SafeMesh = (PTRIVERTEX)(SafeVertex + uVertex);
1018
1019 _SEH_TRY
1020 {
1021 /* pointers were already probed! */
1022 RtlCopyMemory(SafeVertex,
1023 pVertex,
1024 uVertex * sizeof(TRIVERTEX));
1025 RtlCopyMemory(SafeMesh,
1026 pMesh,
1027 SizeMesh);
1028 }
1029 _SEH_HANDLE
1030 {
1031 Status = _SEH_GetExceptionCode();
1032 }
1033 _SEH_END;
1034
1035 if (!NT_SUCCESS(Status))
1036 {
1037 DC_UnlockDc(dc);
1038 ExFreePool(SafeVertex);
1039 SetLastNtError(Status);
1040 return FALSE;
1041 }
1042
1043 Ret = IntGdiGradientFill(dc, SafeVertex, uVertex, SafeMesh, uMesh, ulMode);
1044
1045 DC_UnlockDc(dc);
1046 ExFreePool(SafeVertex);
1047 return Ret;
1048 }
1049
1050 BOOL STDCALL
1051 NtGdiExtFloodFill(
1052 HDC hDC,
1053 INT XStart,
1054 INT YStart,
1055 COLORREF Color,
1056 UINT FillType)
1057 {
1058 DPRINT1("FIXME: NtGdiExtFloodFill is UNIMPLEMENTED\n");
1059
1060 /* lie and say we succeded */
1061 return TRUE;
1062 }
1063
1064 /* EOF */