Update PDEVOBJ and GRAPHICS_DEVICE fields
[reactos.git] / reactos / subsystems / win32 / win32k / objects / fillshap.c
1 /*
2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19
20 #include <w32k.h>
21
22 #define NDEBUG
23 #include <debug.h>
24
25 #define Rsin(d) ((d) == 0.0 ? 0.0 : ((d) == 90.0 ? 1.0 : sin(d*M_PI/180.0)))
26 #define Rcos(d) ((d) == 0.0 ? 1.0 : ((d) == 90.0 ? 0.0 : cos(d*M_PI/180.0)))
27
28 BOOL FASTCALL IntFillEllipse( PDC dc, INT XLeft, INT YLeft, INT Width, INT Height, PBRUSH pbrush);
29 BOOL FASTCALL IntDrawEllipse( PDC dc, INT XLeft, INT YLeft, INT Width, INT Height, PBRUSH pbrush);
30 BOOL FASTCALL IntFillRoundRect( PDC dc, INT Left, INT Top, INT Right, INT Bottom, INT Wellipse, INT Hellipse, PBRUSH pbrush);
31 BOOL FASTCALL IntDrawRoundRect( PDC dc, INT Left, INT Top, INT Right, INT Bottom, INT Wellipse, INT Hellipse, PBRUSH pbrush);
32
33 BOOL FASTCALL
34 IntGdiPolygon(PDC dc,
35 PPOINT Points,
36 int Count)
37 {
38 SURFACE *psurf;
39 PBRUSH pbrLine, pbrFill;
40 BOOL ret = FALSE; // default to failure
41 RECTL DestRect;
42 int CurrentPoint;
43 PDC_ATTR pdcattr;
44 POINTL BrushOrigin;
45 // int Left;
46 // int Top;
47
48 ASSERT(dc); // caller's responsibility to pass a valid dc
49
50 if (!Points || Count < 2 )
51 {
52 SetLastWin32Error(ERROR_INVALID_PARAMETER);
53 return FALSE;
54 }
55
56 /*
57 //Find start x, y
58 Left = Points[0].x;
59 Top = Points[0].y;
60 for (CurrentPoint = 1; CurrentPoint < Count; ++CurrentPoint) {
61 Left = min(Left, Points[CurrentPoint].x);
62 Top = min(Top, Points[CurrentPoint].y);
63 }
64 */
65
66 pdcattr = dc->pdcattr;
67
68 /* Convert to screen coordinates */
69 IntLPtoDP(dc, Points, Count);
70 for (CurrentPoint = 0; CurrentPoint < Count; CurrentPoint++)
71 {
72 Points[CurrentPoint].x += dc->ptlDCOrig.x;
73 Points[CurrentPoint].y += dc->ptlDCOrig.y;
74 }
75 // No need to have path here.
76 {
77 DestRect.left = Points[0].x;
78 DestRect.right = Points[0].x;
79 DestRect.top = Points[0].y;
80 DestRect.bottom = Points[0].y;
81
82 for (CurrentPoint = 1; CurrentPoint < Count; ++CurrentPoint)
83 {
84 DestRect.left = min(DestRect.left, Points[CurrentPoint].x);
85 DestRect.right = max(DestRect.right, Points[CurrentPoint].x);
86 DestRect.top = min(DestRect.top, Points[CurrentPoint].y);
87 DestRect.bottom = max(DestRect.bottom, Points[CurrentPoint].y);
88 }
89
90 if (pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
91 DC_vUpdateFillBrush(dc);
92
93 if (pdcattr->ulDirty_ & (DIRTY_LINE | DC_PEN_DIRTY))
94 DC_vUpdateLineBrush(dc);
95
96 /* Special locking order to avoid lock-ups */
97 pbrFill = dc->dclevel.pbrFill;
98 pbrLine = dc->dclevel.pbrLine;
99 psurf = 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 /* Perform the actual work */
482 switch (iFunc)
483 {
484 case GdiPolyPolygon:
485 Ret = IntGdiPolyPolygon(dc, SafePoints, SafeCounts, Count);
486 break;
487 case GdiPolyPolyLine:
488 Ret = IntGdiPolyPolyline(dc, SafePoints, SafeCounts, Count);
489 break;
490 case GdiPolyBezier:
491 Ret = IntGdiPolyBezier(dc, SafePoints, *SafeCounts);
492 break;
493 case GdiPolyLineTo:
494 Ret = IntGdiPolylineTo(dc, SafePoints, *SafeCounts);
495 break;
496 case GdiPolyBezierTo:
497 Ret = IntGdiPolyBezierTo(dc, SafePoints, *SafeCounts);
498 break;
499 default:
500 SetLastWin32Error(ERROR_INVALID_PARAMETER);
501 Ret = FALSE;
502 }
503
504 /* Cleanup and return */
505 DC_UnlockDc(dc);
506 ExFreePool(pTemp);
507
508 return (ULONG_PTR)Ret;
509 }
510
511
512 BOOL
513 FASTCALL
514 IntRectangle(PDC dc,
515 int LeftRect,
516 int TopRect,
517 int RightRect,
518 int BottomRect)
519 {
520 SURFACE *psurf = NULL;
521 PBRUSH pbrLine, pbrFill;
522 BOOL ret = FALSE; // default to failure
523 RECTL DestRect;
524 MIX Mix;
525 PDC_ATTR pdcattr;
526 POINTL BrushOrigin;
527
528 ASSERT ( dc ); // caller's responsibility to set this up
529
530 pdcattr = dc->pdcattr;
531
532 /* Do we rotate or shear? */
533 if (!(dc->dclevel.mxWorldToDevice.flAccel & MX_SCALE))
534 {
535
536 POINTL DestCoords[4];
537 ULONG PolyCounts = 4;
538 DestCoords[0].x = DestCoords[3].x = LeftRect;
539 DestCoords[0].y = DestCoords[1].y = TopRect;
540 DestCoords[1].x = DestCoords[2].x = RightRect;
541 DestCoords[2].y = DestCoords[3].y = BottomRect;
542 // Use IntGdiPolyPolygon so to support PATH.
543 return IntGdiPolyPolygon(dc, DestCoords, &PolyCounts, 1);
544 }
545 // Rectangle Path only.
546 if ( PATH_IsPathOpen(dc->dclevel) )
547 {
548 return PATH_Rectangle ( dc, LeftRect, TopRect, RightRect, BottomRect );
549 }
550
551 DestRect.left = LeftRect;
552 DestRect.right = RightRect;
553 DestRect.top = TopRect;
554 DestRect.bottom = BottomRect;
555
556 IntLPtoDP(dc, (LPPOINT)&DestRect, 2);
557
558 DestRect.left += dc->ptlDCOrig.x;
559 DestRect.right += dc->ptlDCOrig.x;
560 DestRect.top += dc->ptlDCOrig.y;
561 DestRect.bottom += dc->ptlDCOrig.y;
562
563 /* In GM_COMPATIBLE, don't include bottom and right edges */
564 if (pdcattr->iGraphicsMode == GM_COMPATIBLE)
565 {
566 DestRect.right--;
567 DestRect.bottom--;
568 }
569
570 if (pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
571 DC_vUpdateFillBrush(dc);
572
573 if (pdcattr->ulDirty_ & (DIRTY_LINE | DC_PEN_DIRTY))
574 DC_vUpdateLineBrush(dc);
575
576 pbrFill = dc->dclevel.pbrFill;
577 pbrLine = dc->dclevel.pbrLine;
578 if (!pbrLine)
579 {
580 ret = FALSE;
581 goto cleanup;
582 }
583 psurf = dc->dclevel.pSurface;
584 if (!psurf)
585 {
586 ret = FALSE;
587 goto cleanup;
588 }
589
590 if (pbrFill)
591 {
592 if (!(pbrFill->flAttrs & GDIBRUSH_IS_NULL))
593 {
594 BrushOrigin = *((PPOINTL)&pbrFill->ptOrigin);
595 BrushOrigin.x += dc->ptlDCOrig.x;
596 BrushOrigin.y += dc->ptlDCOrig.y;
597 ret = IntEngBitBlt(&psurf->SurfObj,
598 NULL,
599 NULL,
600 dc->rosdc.CombinedClip,
601 NULL,
602 &DestRect,
603 NULL,
604 NULL,
605 &dc->eboFill.BrushObject,
606 &BrushOrigin,
607 ROP3_TO_ROP4(PATCOPY));
608 }
609 }
610
611 // Draw the rectangle with the current pen
612
613 ret = TRUE; // change default to success
614
615 if (!(pbrLine->flAttrs & GDIBRUSH_IS_NULL))
616 {
617 Mix = ROP2_TO_MIX(pdcattr->jROP2);
618 ret = ret && IntEngLineTo(&psurf->SurfObj,
619 dc->rosdc.CombinedClip,
620 &dc->eboLine.BrushObject,
621 DestRect.left, DestRect.top, DestRect.right, DestRect.top,
622 &DestRect, // Bounding rectangle
623 Mix);
624
625 ret = ret && IntEngLineTo(&psurf->SurfObj,
626 dc->rosdc.CombinedClip,
627 &dc->eboLine.BrushObject,
628 DestRect.right, DestRect.top, DestRect.right, DestRect.bottom,
629 &DestRect, // Bounding rectangle
630 Mix);
631
632 ret = ret && IntEngLineTo(&psurf->SurfObj,
633 dc->rosdc.CombinedClip,
634 &dc->eboLine.BrushObject,
635 DestRect.right, DestRect.bottom, DestRect.left, DestRect.bottom,
636 &DestRect, // Bounding rectangle
637 Mix);
638
639 ret = ret && IntEngLineTo(&psurf->SurfObj,
640 dc->rosdc.CombinedClip,
641 &dc->eboLine.BrushObject,
642 DestRect.left, DestRect.bottom, DestRect.left, DestRect.top,
643 &DestRect, // Bounding rectangle
644 Mix);
645 }
646
647 cleanup:
648 /* Move current position in DC?
649 MSDN: The current position is neither used nor updated by Rectangle. */
650
651 return ret;
652 }
653
654 BOOL
655 APIENTRY
656 NtGdiRectangle(HDC hDC,
657 int LeftRect,
658 int TopRect,
659 int RightRect,
660 int BottomRect)
661 {
662 DC *dc;
663 BOOL ret; // default to failure
664
665 dc = DC_LockDc(hDC);
666 if (!dc)
667 {
668 SetLastWin32Error(ERROR_INVALID_HANDLE);
669 return FALSE;
670 }
671 if (dc->dctype == DC_TYPE_INFO)
672 {
673 DC_UnlockDc(dc);
674 /* Yes, Windows really returns TRUE in this case */
675 return TRUE;
676 }
677
678 ret = IntRectangle ( dc, LeftRect, TopRect, RightRect, BottomRect );
679 DC_UnlockDc ( dc );
680
681 return ret;
682 }
683
684
685 BOOL
686 FASTCALL
687 IntRoundRect(
688 PDC dc,
689 int Left,
690 int Top,
691 int Right,
692 int Bottom,
693 int xCurveDiameter,
694 int yCurveDiameter)
695 {
696 PDC_ATTR pdcattr;
697 PBRUSH pbrushLine, pbrushFill;
698 RECTL RectBounds;
699 LONG PenWidth, PenOrigWidth;
700 BOOL ret = TRUE; // default to success
701 BRUSH brushTemp;
702
703 ASSERT ( dc ); // caller's responsibility to set this up
704
705 if ( PATH_IsPathOpen(dc->dclevel) )
706 return PATH_RoundRect ( dc, Left, Top, Right, Bottom,
707 xCurveDiameter, yCurveDiameter );
708
709 if ((Left == Right) || (Top == Bottom)) return TRUE;
710
711 xCurveDiameter = max(abs( xCurveDiameter ), 1);
712 yCurveDiameter = max(abs( yCurveDiameter ), 1);
713
714 if (Right < Left)
715 {
716 INT tmp = Right; Right = Left; Left = tmp;
717 }
718 if (Bottom < Top)
719 {
720 INT tmp = Bottom; Bottom = Top; Top = tmp;
721 }
722
723 pdcattr = dc->pdcattr;
724
725 if (pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
726 DC_vUpdateFillBrush(dc);
727
728 if (pdcattr->ulDirty_ & (DIRTY_LINE | DC_PEN_DIRTY))
729 DC_vUpdateLineBrush(dc);
730
731 pbrushLine = PEN_LockPen(pdcattr->hpen);
732 if (!pbrushLine)
733 {
734 /* Nothing to do, as we don't have a bitmap */
735 SetLastWin32Error(ERROR_INTERNAL_ERROR);
736 return FALSE;
737 }
738
739 PenOrigWidth = PenWidth = pbrushLine->ptPenWidth.x;
740 if (pbrushLine->ulPenStyle == PS_NULL) PenWidth = 0;
741
742 if (pbrushLine->ulPenStyle == PS_INSIDEFRAME)
743 {
744 if (2*PenWidth > (Right - Left)) PenWidth = (Right -Left + 1)/2;
745 if (2*PenWidth > (Bottom - Top)) PenWidth = (Bottom -Top + 1)/2;
746 Left += PenWidth / 2;
747 Right -= (PenWidth - 1) / 2;
748 Top += PenWidth / 2;
749 Bottom -= (PenWidth - 1) / 2;
750 }
751
752 if (!PenWidth) PenWidth = 1;
753 pbrushLine->ptPenWidth.x = PenWidth;
754
755 RectBounds.left = Left;
756 RectBounds.top = Top;
757 RectBounds.right = Right;
758 RectBounds.bottom = Bottom;
759
760 IntLPtoDP(dc, (LPPOINT)&RectBounds, 2);
761
762 RectBounds.left += dc->ptlDCOrig.x;
763 RectBounds.top += dc->ptlDCOrig.y;
764 RectBounds.right += dc->ptlDCOrig.x;
765 RectBounds.bottom += dc->ptlDCOrig.y;
766
767 pbrushFill = BRUSH_LockBrush(pdcattr->hbrush);
768 if (NULL == pbrushFill)
769 {
770 DPRINT1("FillRound Fail\n");
771 SetLastWin32Error(ERROR_INTERNAL_ERROR);
772 ret = FALSE;
773 }
774 else
775 {
776 RtlCopyMemory(&brushTemp, pbrushFill, sizeof(brushTemp));
777 brushTemp.ptOrigin.x += RectBounds.left - Left;
778 brushTemp.ptOrigin.y += RectBounds.top - Top;
779 ret = IntFillRoundRect( dc,
780 RectBounds.left,
781 RectBounds.top,
782 RectBounds.right,
783 RectBounds.bottom,
784 xCurveDiameter,
785 yCurveDiameter,
786 &brushTemp);
787 BRUSH_UnlockBrush(pbrushFill);
788 }
789
790 if (ret)
791 ret = IntDrawRoundRect( dc,
792 RectBounds.left,
793 RectBounds.top,
794 RectBounds.right,
795 RectBounds.bottom,
796 xCurveDiameter,
797 yCurveDiameter,
798 pbrushLine);
799
800 pbrushLine->ptPenWidth.x = PenOrigWidth;
801 PEN_UnlockPen(pbrushLine);
802 return ret;
803 }
804
805 BOOL
806 APIENTRY
807 NtGdiRoundRect(
808 HDC hDC,
809 int LeftRect,
810 int TopRect,
811 int RightRect,
812 int BottomRect,
813 int Width,
814 int Height)
815 {
816 DC *dc = DC_LockDc(hDC);
817 BOOL ret = FALSE; /* default to failure */
818
819 DPRINT("NtGdiRoundRect(0x%x,%i,%i,%i,%i,%i,%i)\n",hDC,LeftRect,TopRect,RightRect,BottomRect,Width,Height);
820 if ( !dc )
821 {
822 DPRINT1("NtGdiRoundRect() - hDC is invalid\n");
823 SetLastWin32Error(ERROR_INVALID_HANDLE);
824 }
825 else if (dc->dctype == DC_TYPE_INFO)
826 {
827 DC_UnlockDc(dc);
828 /* Yes, Windows really returns TRUE in this case */
829 ret = TRUE;
830 }
831 else
832 {
833 ret = IntRoundRect ( dc, LeftRect, TopRect, RightRect, BottomRect, Width, Height );
834 DC_UnlockDc ( dc );
835 }
836
837 return ret;
838 }
839
840 BOOL FASTCALL
841 IntGdiGradientFill(
842 DC *dc,
843 PTRIVERTEX pVertex,
844 ULONG uVertex,
845 PVOID pMesh,
846 ULONG uMesh,
847 ULONG ulMode)
848 {
849 SURFACE *psurf;
850 PPALETTE PalDestGDI;
851 EXLATEOBJ exlo;
852 RECTL Extent;
853 POINTL DitherOrg;
854 ULONG i;
855 BOOL Ret;
856 HPALETTE hDestPalette;
857
858 ASSERT(dc);
859 ASSERT(pVertex);
860 ASSERT(uVertex);
861 ASSERT(pMesh);
862 ASSERT(uMesh);
863
864 /* check parameters */
865 if (ulMode & GRADIENT_FILL_TRIANGLE)
866 {
867 PGRADIENT_TRIANGLE tr = (PGRADIENT_TRIANGLE)pMesh;
868
869 for (i = 0; i < uMesh; i++, tr++)
870 {
871 if (tr->Vertex1 >= uVertex ||
872 tr->Vertex2 >= uVertex ||
873 tr->Vertex3 >= uVertex)
874 {
875 SetLastWin32Error(ERROR_INVALID_PARAMETER);
876 return FALSE;
877 }
878 }
879 }
880 else
881 {
882 PGRADIENT_RECT rc = (PGRADIENT_RECT)pMesh;
883 for (i = 0; i < uMesh; i++, rc++)
884 {
885 if (rc->UpperLeft >= uVertex || rc->LowerRight >= uVertex)
886 {
887 SetLastWin32Error(ERROR_INVALID_PARAMETER);
888 return FALSE;
889 }
890 }
891 }
892
893 /* calculate extent */
894 Extent.left = Extent.right = pVertex->x;
895 Extent.top = Extent.bottom = pVertex->y;
896 for (i = 0; i < uVertex; i++)
897 {
898 Extent.left = min(Extent.left, (pVertex + i)->x);
899 Extent.right = max(Extent.right, (pVertex + i)->x);
900 Extent.top = min(Extent.top, (pVertex + i)->y);
901 Extent.bottom = max(Extent.bottom, (pVertex + i)->y);
902 }
903 IntLPtoDP(dc, (LPPOINT)&Extent, 2);
904
905 Extent.left += dc->ptlDCOrig.x;
906 Extent.right += dc->ptlDCOrig.x;
907 Extent.top += dc->ptlDCOrig.y;
908 Extent.bottom += dc->ptlDCOrig.y;
909
910 DitherOrg.x = DitherOrg.y = 0;
911 IntLPtoDP(dc, (LPPOINT)&DitherOrg, 1);
912
913 DitherOrg.x += dc->ptlDCOrig.x;
914 DitherOrg.y += dc->ptlDCOrig.y;
915
916 psurf = dc->dclevel.pSurface;
917 /* FIXME - psurf can be NULL!!! Don't assert but handle this case gracefully! */
918 ASSERT(psurf);
919
920 hDestPalette = psurf->hDIBPalette;
921 if (!hDestPalette) hDestPalette = pPrimarySurface->devinfo.hpalDefault;
922
923 PalDestGDI = PALETTE_LockPalette(hDestPalette);
924 EXLATEOBJ_vInitialize(&exlo, &gpalRGB, PalDestGDI, 0, 0, 0);
925
926 Ret = IntEngGradientFill(&psurf->SurfObj,
927 dc->rosdc.CombinedClip,
928 &exlo.xlo,
929 pVertex,
930 uVertex,
931 pMesh,
932 uMesh,
933 &Extent,
934 &DitherOrg,
935 ulMode);
936
937 EXLATEOBJ_vCleanup(&exlo);
938
939 if (PalDestGDI)
940 PALETTE_UnlockPalette(PalDestGDI);
941
942 return Ret;
943 }
944
945 BOOL
946 APIENTRY
947 NtGdiGradientFill(
948 HDC hdc,
949 PTRIVERTEX pVertex,
950 ULONG uVertex,
951 PVOID pMesh,
952 ULONG uMesh,
953 ULONG ulMode)
954 {
955 DC *dc;
956 BOOL Ret;
957 PTRIVERTEX SafeVertex;
958 PVOID SafeMesh;
959 ULONG SizeMesh;
960 NTSTATUS Status = STATUS_SUCCESS;
961
962 dc = DC_LockDc(hdc);
963 if (!dc)
964 {
965 SetLastWin32Error(ERROR_INVALID_HANDLE);
966 return FALSE;
967 }
968 if (dc->dctype == DC_TYPE_INFO)
969 {
970 DC_UnlockDc(dc);
971 /* Yes, Windows really returns TRUE in this case */
972 return TRUE;
973 }
974 if (!pVertex || !uVertex || !pMesh || !uMesh)
975 {
976 DC_UnlockDc(dc);
977 SetLastWin32Error(ERROR_INVALID_PARAMETER);
978 return FALSE;
979 }
980
981 switch (ulMode)
982 {
983 case GRADIENT_FILL_RECT_H:
984 case GRADIENT_FILL_RECT_V:
985 SizeMesh = uMesh * sizeof(GRADIENT_RECT);
986 break;
987 case GRADIENT_FILL_TRIANGLE:
988 SizeMesh = uMesh * sizeof(TRIVERTEX);
989 break;
990 default:
991 DC_UnlockDc(dc);
992 SetLastWin32Error(ERROR_INVALID_PARAMETER);
993 return FALSE;
994 }
995
996 _SEH2_TRY
997 {
998 ProbeForRead(pVertex,
999 uVertex * sizeof(TRIVERTEX),
1000 1);
1001 ProbeForRead(pMesh,
1002 SizeMesh,
1003 1);
1004 }
1005 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1006 {
1007 Status = _SEH2_GetExceptionCode();
1008 }
1009 _SEH2_END;
1010
1011 if (!NT_SUCCESS(Status))
1012 {
1013 DC_UnlockDc(dc);
1014 SetLastWin32Error(Status);
1015 return FALSE;
1016 }
1017
1018 if (!(SafeVertex = ExAllocatePoolWithTag(PagedPool, (uVertex * sizeof(TRIVERTEX)) + SizeMesh, TAG_SHAPE)))
1019 {
1020 DC_UnlockDc(dc);
1021 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
1022 return FALSE;
1023 }
1024
1025 SafeMesh = (PTRIVERTEX)(SafeVertex + uVertex);
1026
1027 _SEH2_TRY
1028 {
1029 /* pointers were already probed! */
1030 RtlCopyMemory(SafeVertex,
1031 pVertex,
1032 uVertex * sizeof(TRIVERTEX));
1033 RtlCopyMemory(SafeMesh,
1034 pMesh,
1035 SizeMesh);
1036 }
1037 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1038 {
1039 Status = _SEH2_GetExceptionCode();
1040 }
1041 _SEH2_END;
1042
1043 if (!NT_SUCCESS(Status))
1044 {
1045 DC_UnlockDc(dc);
1046 ExFreePoolWithTag(SafeVertex, TAG_SHAPE);
1047 SetLastNtError(Status);
1048 return FALSE;
1049 }
1050
1051 Ret = IntGdiGradientFill(dc, SafeVertex, uVertex, SafeMesh, uMesh, ulMode);
1052
1053 DC_UnlockDc(dc);
1054 ExFreePool(SafeVertex);
1055 return Ret;
1056 }
1057
1058 BOOL APIENTRY
1059 NtGdiExtFloodFill(
1060 HDC hDC,
1061 INT XStart,
1062 INT YStart,
1063 COLORREF Color,
1064 UINT FillType)
1065 {
1066 PDC dc;
1067 PDC_ATTR pdcattr;
1068 SURFACE *psurf = NULL;
1069 HPALETTE hpal;
1070 PPALETTE ppal;
1071 EXLATEOBJ exlo;
1072 BOOL Ret = FALSE;
1073 RECTL DestRect;
1074 POINTL Pt;
1075 ULONG ConvColor;
1076
1077 dc = DC_LockDc(hDC);
1078 if (!dc)
1079 {
1080 SetLastWin32Error(ERROR_INVALID_HANDLE);
1081 return FALSE;
1082 }
1083 if (dc->dctype == DC_TYPE_INFO)
1084 {
1085 DC_UnlockDc(dc);
1086 /* Yes, Windows really returns TRUE in this case */
1087 return TRUE;
1088 }
1089
1090 pdcattr = dc->pdcattr;
1091
1092 if (pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
1093 DC_vUpdateFillBrush(dc);
1094
1095 if (pdcattr->ulDirty_ & (DIRTY_LINE | DC_PEN_DIRTY))
1096 DC_vUpdateLineBrush(dc);
1097
1098 Pt.x = XStart;
1099 Pt.y = YStart;
1100 IntLPtoDP(dc, (LPPOINT)&Pt, 1);
1101
1102 Ret = NtGdiPtInRegion(dc->rosdc.hGCClipRgn, Pt.x, Pt.y);
1103 if (Ret)
1104 IntGdiGetRgnBox(dc->rosdc.hGCClipRgn,(LPRECT)&DestRect);
1105 else
1106 goto cleanup;
1107
1108 psurf = dc->dclevel.pSurface;
1109 if (!psurf)
1110 {
1111 Ret = FALSE;
1112 goto cleanup;
1113 }
1114
1115 hpal = dc->dclevel.pSurface->hDIBPalette;
1116 if (!hpal) hpal = pPrimarySurface->devinfo.hpalDefault;
1117 ppal = PALETTE_ShareLockPalette(hpal);
1118
1119 EXLATEOBJ_vInitialize(&exlo, &gpalRGB, ppal, 0, 0xffffff, 0);
1120
1121 /* Only solid fills supported for now
1122 * How to support pattern brushes and non standard surfaces (not offering dib functions):
1123 * Version a (most likely slow): call DrvPatBlt for every pixel
1124 * Version b: create a flood mask and let MaskBlt blit a masked brush */
1125 ConvColor = XLATEOBJ_iXlate(&exlo.xlo, Color);
1126 Ret = DIB_XXBPP_FloodFillSolid(&psurf->SurfObj, &dc->eboFill.BrushObject, &DestRect, &Pt, ConvColor, FillType);
1127
1128 EXLATEOBJ_vCleanup(&exlo);
1129 PALETTE_ShareUnlockPalette(ppal);
1130
1131 cleanup:
1132 DC_UnlockDc(dc);
1133 return Ret;
1134 }
1135
1136 /* EOF */