Change most DC struct members to the names they have on Windows according to gdikdx
[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(&psurf->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(&psurf->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, PGDIBRUSHOBJ FillBrushObj);
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, PGDIBRUSHOBJ FillBrushObj);
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 SURFACE *psurf;
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 POINTL BrushOrigin;
65 // int Left;
66 // int Top;
67
68 ASSERT(dc); // caller's responsibility to pass a valid dc
69
70 if (!Points || Count < 2 )
71 {
72 SetLastWin32Error(ERROR_INVALID_PARAMETER);
73 return FALSE;
74 }
75
76 /*
77 //Find start x, y
78 Left = Points[0].x;
79 Top = Points[0].y;
80 for (CurrentPoint = 1; CurrentPoint < Count; ++CurrentPoint) {
81 Left = min(Left, Points[CurrentPoint].x);
82 Top = min(Top, Points[CurrentPoint].y);
83 }
84 */
85
86 Dc_Attr = dc->pDc_Attr;
87 if (!Dc_Attr) Dc_Attr = &dc->Dc_Attr;
88
89 /* Convert to screen coordinates */
90 IntLPtoDP(dc, Points, Count);
91 for (CurrentPoint = 0; CurrentPoint < Count; CurrentPoint++)
92 {
93 Points[CurrentPoint].x += dc->ptlDCOrig.x;
94 Points[CurrentPoint].y += dc->ptlDCOrig.y;
95 }
96 // No need to have path here.
97 {
98 DestRect.left = Points[0].x;
99 DestRect.right = Points[0].x;
100 DestRect.top = Points[0].y;
101 DestRect.bottom = Points[0].y;
102
103 for (CurrentPoint = 1; CurrentPoint < Count; ++CurrentPoint)
104 {
105 DestRect.left = min(DestRect.left, Points[CurrentPoint].x);
106 DestRect.right = max(DestRect.right, Points[CurrentPoint].x);
107 DestRect.top = min(DestRect.top, Points[CurrentPoint].y);
108 DestRect.bottom = max(DestRect.bottom, Points[CurrentPoint].y);
109 }
110
111 if (Dc_Attr->ulDirty_ & DC_BRUSH_DIRTY)
112 IntGdiSelectBrush(dc,Dc_Attr->hbrush);
113
114 if (Dc_Attr->ulDirty_ & DC_PEN_DIRTY)
115 IntGdiSelectPen(dc,Dc_Attr->hpen);
116
117 /* Special locking order to avoid lock-ups */
118 FillBrushObj = BRUSHOBJ_LockBrush(Dc_Attr->hbrush);
119 PenBrushObj = PENOBJ_LockPen(Dc_Attr->hpen);
120 psurf = SURFACE_LockSurface(dc->rosdc.hBitmap);
121 /* FIXME - psurf can be NULL!!!! don't assert but handle this case gracefully! */
122 ASSERT(psurf);
123
124 /* Now fill the polygon with the current brush. */
125 if (FillBrushObj && !(FillBrushObj->flAttrs & GDIBRUSH_IS_NULL))
126 {
127 BrushOrigin = *((PPOINTL)&FillBrushObj->ptOrigin);
128 BrushOrigin.x += dc->ptlDCOrig.x;
129 BrushOrigin.y += dc->ptlDCOrig.y;
130 IntGdiInitBrushInstance(&FillBrushInst, FillBrushObj, dc->rosdc.XlateBrush);
131 ret = IntFillPolygon (dc, psurf, &FillBrushInst.BrushObject, Points, Count,
132 DestRect, &BrushOrigin);
133 }
134 if (FillBrushObj)
135 BRUSHOBJ_UnlockBrush(FillBrushObj);
136
137 // Draw the Polygon Edges with the current pen ( if not a NULL pen )
138 if (PenBrushObj && !(PenBrushObj->flAttrs & GDIBRUSH_IS_NULL))
139 {
140 int i;
141
142 IntGdiInitBrushInstance(&PenBrushInst, PenBrushObj, dc->rosdc.XlatePen);
143
144 for (i = 0; i < Count-1; i++)
145 {
146
147 // DPRINT1("Polygon Making line from (%d,%d) to (%d,%d)\n",
148 // Points[0].x, Points[0].y,
149 // Points[1].x, Points[1].y );
150
151 ret = IntEngLineTo(&psurf->SurfObj,
152 dc->rosdc.CombinedClip,
153 &PenBrushInst.BrushObject,
154 Points[i].x, /* From */
155 Points[i].y,
156 Points[i+1].x, /* To */
157 Points[i+1].y,
158 &DestRect,
159 ROP2_TO_MIX(Dc_Attr->jROP2)); /* MIX */
160 if (!ret) break;
161 }
162 /* Close the polygon */
163 if (ret)
164 {
165 ret = IntEngLineTo(&psurf->SurfObj,
166 dc->rosdc.CombinedClip,
167 &PenBrushInst.BrushObject,
168 Points[Count-1].x, /* From */
169 Points[Count-1].y,
170 Points[0].x, /* To */
171 Points[0].y,
172 &DestRect,
173 ROP2_TO_MIX(Dc_Attr->jROP2)); /* MIX */
174 }
175 }
176 if (PenBrushObj)
177 PENOBJ_UnlockPen(PenBrushObj);
178 }
179 SURFACE_UnlockSurface(psurf);
180
181 return ret;
182 }
183
184 BOOL FASTCALL
185 IntGdiPolyPolygon(DC *dc,
186 LPPOINT Points,
187 PULONG PolyCounts,
188 int Count)
189 {
190 if (PATH_IsPathOpen(dc->DcLevel))
191 return PATH_PolyPolygon ( dc, Points, (PINT)PolyCounts, Count);
192
193 while (--Count >=0)
194 {
195 if (!IntGdiPolygon ( dc, Points, *PolyCounts ))
196 return FALSE;
197 Points+=*PolyCounts++;
198 }
199 return TRUE;
200 }
201
202
203
204 /******************************************************************************/
205
206 /*
207 * NtGdiEllipse
208 *
209 * Author
210 * Filip Navara
211 *
212 * Remarks
213 * This function uses optimized Bresenham's ellipse algorithm. It draws
214 * four lines of the ellipse in one pass.
215 *
216 */
217
218 BOOL APIENTRY
219 NtGdiEllipse(
220 HDC hDC,
221 int Left,
222 int Top,
223 int Right,
224 int Bottom)
225 {
226 PDC dc;
227 PDC_ATTR Dc_Attr;
228 RECTL RectBounds;
229 PGDIBRUSHOBJ PenBrushObj;
230 BOOL ret = TRUE;
231 LONG PenWidth, PenOrigWidth;
232 LONG RadiusX, RadiusY, CenterX, CenterY;
233 PGDIBRUSHOBJ pFillBrushObj;
234 GDIBRUSHOBJ tmpFillBrushObj;
235
236 if ((Left == Right) || (Top == Bottom)) return TRUE;
237
238 dc = DC_LockDc(hDC);
239 if (dc == NULL)
240 {
241 SetLastWin32Error(ERROR_INVALID_HANDLE);
242 return FALSE;
243 }
244 if (dc->dctype == DC_TYPE_INFO)
245 {
246 DC_UnlockDc(dc);
247 /* Yes, Windows really returns TRUE in this case */
248 return TRUE;
249 }
250
251 if (PATH_IsPathOpen(dc->DcLevel))
252 {
253 ret = PATH_Ellipse(dc, Left, Top, Right, Bottom);
254 DC_UnlockDc(dc);
255 return ret;
256 }
257
258 if (Right < Left)
259 {
260 INT tmp = Right; Right = Left; Left = tmp;
261 }
262 if (Bottom < Top)
263 {
264 INT tmp = Bottom; Bottom = Top; Top = tmp;
265 }
266
267 Dc_Attr = dc->pDc_Attr;
268 if(!Dc_Attr) Dc_Attr = &dc->Dc_Attr;
269
270 if (Dc_Attr->ulDirty_ & DC_BRUSH_DIRTY)
271 IntGdiSelectBrush(dc,Dc_Attr->hbrush);
272
273 if (Dc_Attr->ulDirty_ & DC_PEN_DIRTY)
274 IntGdiSelectPen(dc,Dc_Attr->hpen);
275
276 PenBrushObj = PENOBJ_LockPen(Dc_Attr->hpen);
277 if (NULL == PenBrushObj)
278 {
279 DPRINT1("Ellipse Fail 1\n");
280 DC_UnlockDc(dc);
281 SetLastWin32Error(ERROR_INTERNAL_ERROR);
282 return FALSE;
283 }
284
285 PenOrigWidth = PenWidth = PenBrushObj->ptPenWidth.x;
286 if (PenBrushObj->ulPenStyle == PS_NULL) PenWidth = 0;
287
288 if (PenBrushObj->ulPenStyle == PS_INSIDEFRAME)
289 {
290 if (2*PenWidth > (Right - Left)) PenWidth = (Right -Left + 1)/2;
291 if (2*PenWidth > (Bottom - Top)) PenWidth = (Bottom -Top + 1)/2;
292 Left += PenWidth / 2;
293 Right -= (PenWidth - 1) / 2;
294 Top += PenWidth / 2;
295 Bottom -= (PenWidth - 1) / 2;
296 }
297
298 if (!PenWidth) PenWidth = 1;
299 PenBrushObj->ptPenWidth.x = PenWidth;
300
301 RectBounds.left = Left;
302 RectBounds.right = Right;
303 RectBounds.top = Top;
304 RectBounds.bottom = Bottom;
305
306 IntLPtoDP(dc, (LPPOINT)&RectBounds, 2);
307
308 RectBounds.left += dc->ptlDCOrig.x;
309 RectBounds.right += dc->ptlDCOrig.x;
310 RectBounds.top += dc->ptlDCOrig.y;
311 RectBounds.bottom += dc->ptlDCOrig.y;
312
313 // Setup for dynamic width and height.
314 RadiusX = max((RectBounds.right - RectBounds.left) / 2, 2); // Needs room
315 RadiusY = max((RectBounds.bottom - RectBounds.top) / 2, 2);
316 CenterX = (RectBounds.right + RectBounds.left) / 2;
317 CenterY = (RectBounds.bottom + RectBounds.top) / 2;
318
319 DPRINT("Ellipse 1: Left: %d, Top: %d, Right: %d, Bottom: %d\n",
320 RectBounds.left,RectBounds.top,RectBounds.right,RectBounds.bottom);
321
322 DPRINT("Ellipse 2: XLeft: %d, YLeft: %d, Width: %d, Height: %d\n",
323 CenterX - RadiusX, CenterY + RadiusY, RadiusX*2, RadiusY*2);
324
325 pFillBrushObj = BRUSHOBJ_LockBrush(Dc_Attr->hbrush);
326 if (NULL == pFillBrushObj)
327 {
328 DPRINT1("FillEllipse Fail\n");
329 SetLastWin32Error(ERROR_INTERNAL_ERROR);
330 ret = FALSE;
331 }
332 else
333 {
334 RtlCopyMemory(&tmpFillBrushObj, pFillBrushObj, sizeof(tmpFillBrushObj));
335 // tmpFillBrushObj.ptOrigin.x += RectBounds.left - Left;
336 // tmpFillBrushObj.ptOrigin.y += RectBounds.top - Top;
337 tmpFillBrushObj.ptOrigin.x += dc->ptlDCOrig.x;
338 tmpFillBrushObj.ptOrigin.y += dc->ptlDCOrig.y;
339 ret = IntFillEllipse( dc,
340 CenterX - RadiusX,
341 CenterY - RadiusY,
342 RadiusX*2, // Width
343 RadiusY*2, // Height
344 &tmpFillBrushObj);
345 BRUSHOBJ_UnlockBrush(pFillBrushObj);
346 }
347
348 if (ret)
349 ret = IntDrawEllipse( dc,
350 CenterX - RadiusX,
351 CenterY - RadiusY,
352 RadiusX*2, // Width
353 RadiusY*2, // Height
354 PenBrushObj);
355
356 PenBrushObj->ptPenWidth.x = PenOrigWidth;
357 PENOBJ_UnlockPen(PenBrushObj);
358 DC_UnlockDc(dc);
359 DPRINT("Ellipse Exit.\n");
360 return ret;
361 }
362
363 #if 0
364
365 //When the fill mode is ALTERNATE, GDI fills the area between odd-numbered and
366 //even-numbered polygon sides on each scan line. That is, GDI fills the area between the
367 //first and second side, between the third and fourth side, and so on.
368
369 //WINDING Selects winding mode (fills any region with a nonzero winding value).
370 //When the fill mode is WINDING, GDI fills any region that has a nonzero winding value.
371 //This value is defined as the number of times a pen used to draw the polygon would go around the region.
372 //The direction of each edge of the polygon is important.
373
374 extern BOOL FillPolygon(PDC dc,
375 SURFOBJ *SurfObj,
376 PBRUSHOBJ BrushObj,
377 MIX RopMode,
378 CONST PPOINT Points,
379 int Count,
380 RECTL BoundRect);
381
382 #endif
383
384
385 ULONG_PTR
386 APIENTRY
387 NtGdiPolyPolyDraw( IN HDC hDC,
388 IN PPOINT UnsafePoints,
389 IN PULONG UnsafeCounts,
390 IN ULONG Count,
391 IN INT iFunc )
392 {
393 DC *dc;
394 PVOID pTemp;
395 LPPOINT SafePoints;
396 PULONG SafeCounts;
397 NTSTATUS Status = STATUS_SUCCESS;
398 BOOL Ret = TRUE;
399 INT nPoints = 0, nMaxPoints = 0, nInvalid = 0, i;
400
401 if (!UnsafePoints || !UnsafeCounts ||
402 Count == 0 || iFunc == 0 || iFunc > GdiPolyPolyRgn)
403 {
404 /* Windows doesn't set last error */
405 return FALSE;
406 }
407
408 _SEH2_TRY
409 {
410 ProbeForRead(UnsafePoints, Count * sizeof(POINT), 1);
411 ProbeForRead(UnsafeCounts, Count * sizeof(ULONG), 1);
412
413 /* Count points and validate poligons */
414 for (i = 0; i < Count; i++)
415 {
416 if (UnsafeCounts[i] < 2)
417 {
418 nInvalid++;
419 }
420 nPoints += UnsafeCounts[i];
421 nMaxPoints = max(nMaxPoints, UnsafeCounts[i]);
422 }
423 }
424 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
425 {
426 Status = _SEH2_GetExceptionCode();
427 }
428 _SEH2_END;
429
430 if (!NT_SUCCESS(Status))
431 {
432 /* Windows doesn't set last error */
433 return FALSE;
434 }
435
436 if (nPoints == 0 || nPoints < nMaxPoints)
437 {
438 /* If all polygon counts are zero, or we have overflow,
439 return without setting a last error code. */
440 return FALSE;
441 }
442
443 if (nInvalid != 0)
444 {
445 /* If at least one poly count is 0 or 1, fail */
446 SetLastWin32Error(ERROR_INVALID_PARAMETER);
447 return FALSE;
448 }
449
450 /* Allocate one buffer for both counts and points */
451 pTemp = ExAllocatePoolWithTag(PagedPool,
452 Count * sizeof(ULONG) + nPoints * sizeof(POINT),
453 TAG_SHAPE);
454 if (!pTemp)
455 {
456 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
457 return FALSE;
458 }
459
460 SafeCounts = pTemp;
461 SafePoints = (PVOID)(SafeCounts + Count);
462
463 _SEH2_TRY
464 {
465 /* Pointers already probed! */
466 RtlCopyMemory(SafeCounts, UnsafeCounts, Count * sizeof(ULONG));
467 RtlCopyMemory(SafePoints, UnsafePoints, nPoints * sizeof(POINT));
468 }
469 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
470 {
471 Status = _SEH2_GetExceptionCode();
472 }
473 _SEH2_END;
474
475 if (!NT_SUCCESS(Status))
476 {
477 ExFreePoolWithTag(pTemp, TAG_SHAPE);
478 return FALSE;
479 }
480
481 /* Special handling for GdiPolyPolyRgn */
482 if (iFunc == GdiPolyPolyRgn)
483 {
484 HRGN hRgn;
485 hRgn = IntCreatePolyPolygonRgn(SafePoints, SafeCounts, Count, (INT_PTR)hDC);
486 ExFreePoolWithTag(pTemp, TAG_SHAPE);
487 return (ULONG_PTR)hRgn;
488 }
489
490 dc = DC_LockDc(hDC);
491 if (!dc)
492 {
493 SetLastWin32Error(ERROR_INVALID_HANDLE);
494 ExFreePool(pTemp);
495 return FALSE;
496 }
497
498 if (dc->dctype == DC_TYPE_INFO)
499 {
500 DC_UnlockDc(dc);
501 ExFreePool(pTemp);
502 /* Yes, Windows really returns TRUE in this case */
503 return TRUE;
504 }
505
506 /* Perform the actual work */
507 switch (iFunc)
508 {
509 case GdiPolyPolygon:
510 Ret = IntGdiPolyPolygon(dc, SafePoints, SafeCounts, Count);
511 break;
512 case GdiPolyPolyLine:
513 Ret = IntGdiPolyPolyline(dc, SafePoints, SafeCounts, Count);
514 break;
515 case GdiPolyBezier:
516 Ret = IntGdiPolyBezier(dc, SafePoints, *SafeCounts);
517 break;
518 case GdiPolyLineTo:
519 Ret = IntGdiPolylineTo(dc, SafePoints, *SafeCounts);
520 break;
521 case GdiPolyBezierTo:
522 Ret = IntGdiPolyBezierTo(dc, SafePoints, *SafeCounts);
523 break;
524 default:
525 SetLastWin32Error(ERROR_INVALID_PARAMETER);
526 Ret = FALSE;
527 }
528
529 /* Cleanup and return */
530 DC_UnlockDc(dc);
531 ExFreePool(pTemp);
532
533 return (ULONG_PTR)Ret;
534 }
535
536
537 BOOL
538 FASTCALL
539 IntRectangle(PDC dc,
540 int LeftRect,
541 int TopRect,
542 int RightRect,
543 int BottomRect)
544 {
545 SURFACE *psurf = NULL;
546 PGDIBRUSHOBJ PenBrushObj = NULL, FillBrushObj = NULL;
547 GDIBRUSHINST PenBrushInst, FillBrushInst;
548 BOOL ret = FALSE; // default to failure
549 RECTL DestRect;
550 MIX Mix;
551 PDC_ATTR Dc_Attr;
552 POINTL BrushOrigin;
553
554 ASSERT ( dc ); // caller's responsibility to set this up
555
556 Dc_Attr = dc->pDc_Attr;
557 if(!Dc_Attr) Dc_Attr = &dc->Dc_Attr;
558
559 /* Do we rotate or shear? */
560 if (!(dc->DcLevel.mxWorldToDevice.flAccel & MX_SCALE))
561 {
562
563 POINTL DestCoords[4];
564 ULONG PolyCounts = 4;
565 DestCoords[0].x = DestCoords[3].x = LeftRect;
566 DestCoords[0].y = DestCoords[1].y = TopRect;
567 DestCoords[1].x = DestCoords[2].x = RightRect;
568 DestCoords[2].y = DestCoords[3].y = BottomRect;
569 // Use IntGdiPolyPolygon so to support PATH.
570 return IntGdiPolyPolygon(dc, DestCoords, &PolyCounts, 1);
571 }
572 // Rectangle Path only.
573 if ( PATH_IsPathOpen(dc->DcLevel) )
574 {
575 return PATH_Rectangle ( dc, LeftRect, TopRect, RightRect, BottomRect );
576 }
577
578 DestRect.left = LeftRect;
579 DestRect.right = RightRect;
580 DestRect.top = TopRect;
581 DestRect.bottom = BottomRect;
582
583 IntLPtoDP(dc, (LPPOINT)&DestRect, 2);
584
585 DestRect.left += dc->ptlDCOrig.x;
586 DestRect.right += dc->ptlDCOrig.x;
587 DestRect.top += dc->ptlDCOrig.y;
588 DestRect.bottom += dc->ptlDCOrig.y;
589
590 /* In GM_COMPATIBLE, don't include bottom and right edges */
591 if (IntGetGraphicsMode(dc) == GM_COMPATIBLE)
592 {
593 DestRect.right--;
594 DestRect.bottom--;
595 }
596
597 if (Dc_Attr->ulDirty_ & DC_BRUSH_DIRTY)
598 IntGdiSelectBrush(dc,Dc_Attr->hbrush);
599
600 if (Dc_Attr->ulDirty_ & DC_PEN_DIRTY)
601 IntGdiSelectPen(dc,Dc_Attr->hpen);
602
603 /* Special locking order to avoid lock-ups! */
604 FillBrushObj = BRUSHOBJ_LockBrush(Dc_Attr->hbrush);
605 PenBrushObj = PENOBJ_LockPen(Dc_Attr->hpen);
606 if (!PenBrushObj)
607 {
608 ret = FALSE;
609 goto cleanup;
610 }
611 psurf = SURFACE_LockSurface(dc->rosdc.hBitmap);
612 if (!psurf)
613 {
614 ret = FALSE;
615 goto cleanup;
616 }
617
618 if ( FillBrushObj )
619 {
620 if (!(FillBrushObj->flAttrs & GDIBRUSH_IS_NULL))
621 {
622 BrushOrigin = *((PPOINTL)&FillBrushObj->ptOrigin);
623 BrushOrigin.x += dc->ptlDCOrig.x;
624 BrushOrigin.y += dc->ptlDCOrig.y;
625 IntGdiInitBrushInstance(&FillBrushInst, FillBrushObj, dc->rosdc.XlateBrush);
626 ret = IntEngBitBlt(&psurf->SurfObj,
627 NULL,
628 NULL,
629 dc->rosdc.CombinedClip,
630 NULL,
631 &DestRect,
632 NULL,
633 NULL,
634 &FillBrushInst.BrushObject,
635 &BrushOrigin,
636 ROP3_TO_ROP4(PATCOPY));
637 }
638 }
639
640 IntGdiInitBrushInstance(&PenBrushInst, PenBrushObj, dc->rosdc.XlatePen);
641
642 // Draw the rectangle with the current pen
643
644 ret = TRUE; // change default to success
645
646 if (!(PenBrushObj->flAttrs & GDIBRUSH_IS_NULL))
647 {
648 Mix = ROP2_TO_MIX(Dc_Attr->jROP2);
649 ret = ret && IntEngLineTo(&psurf->SurfObj,
650 dc->rosdc.CombinedClip,
651 &PenBrushInst.BrushObject,
652 DestRect.left, DestRect.top, DestRect.right, DestRect.top,
653 &DestRect, // Bounding rectangle
654 Mix);
655
656 ret = ret && IntEngLineTo(&psurf->SurfObj,
657 dc->rosdc.CombinedClip,
658 &PenBrushInst.BrushObject,
659 DestRect.right, DestRect.top, DestRect.right, DestRect.bottom,
660 &DestRect, // Bounding rectangle
661 Mix);
662
663 ret = ret && IntEngLineTo(&psurf->SurfObj,
664 dc->rosdc.CombinedClip,
665 &PenBrushInst.BrushObject,
666 DestRect.right, DestRect.bottom, DestRect.left, DestRect.bottom,
667 &DestRect, // Bounding rectangle
668 Mix);
669
670 ret = ret && IntEngLineTo(&psurf->SurfObj,
671 dc->rosdc.CombinedClip,
672 &PenBrushInst.BrushObject,
673 DestRect.left, DestRect.bottom, DestRect.left, DestRect.top,
674 &DestRect, // Bounding rectangle
675 Mix);
676 }
677
678 cleanup:
679 if (FillBrushObj)
680 BRUSHOBJ_UnlockBrush(FillBrushObj);
681
682 if (PenBrushObj)
683 PENOBJ_UnlockPen(PenBrushObj);
684
685 if (psurf)
686 SURFACE_UnlockSurface(psurf);
687
688 /* Move current position in DC?
689 MSDN: The current position is neither used nor updated by Rectangle. */
690
691 return ret;
692 }
693
694 BOOL
695 APIENTRY
696 NtGdiRectangle(HDC hDC,
697 int LeftRect,
698 int TopRect,
699 int RightRect,
700 int BottomRect)
701 {
702 DC *dc;
703 BOOL ret; // default to failure
704
705 dc = DC_LockDc(hDC);
706 if (!dc)
707 {
708 SetLastWin32Error(ERROR_INVALID_HANDLE);
709 return FALSE;
710 }
711 if (dc->dctype == DC_TYPE_INFO)
712 {
713 DC_UnlockDc(dc);
714 /* Yes, Windows really returns TRUE in this case */
715 return TRUE;
716 }
717
718 ret = IntRectangle ( dc, LeftRect, TopRect, RightRect, BottomRect );
719 DC_UnlockDc ( dc );
720
721 return ret;
722 }
723
724
725 BOOL
726 FASTCALL
727 IntRoundRect(
728 PDC dc,
729 int Left,
730 int Top,
731 int Right,
732 int Bottom,
733 int xCurveDiameter,
734 int yCurveDiameter)
735 {
736 PDC_ATTR Dc_Attr;
737 PGDIBRUSHOBJ PenBrushObj;
738 RECTL RectBounds;
739 LONG PenWidth, PenOrigWidth;
740 BOOL ret = TRUE; // default to success
741 PGDIBRUSHOBJ pFillBrushObj;
742 GDIBRUSHOBJ tmpFillBrushObj;
743
744 ASSERT ( dc ); // caller's responsibility to set this up
745
746 if ( PATH_IsPathOpen(dc->DcLevel) )
747 return PATH_RoundRect ( dc, Left, Top, Right, Bottom,
748 xCurveDiameter, yCurveDiameter );
749
750 if ((Left == Right) || (Top == Bottom)) return TRUE;
751
752 xCurveDiameter = max(abs( xCurveDiameter ), 1);
753 yCurveDiameter = max(abs( yCurveDiameter ), 1);
754
755 if (Right < Left)
756 {
757 INT tmp = Right; Right = Left; Left = tmp;
758 }
759 if (Bottom < Top)
760 {
761 INT tmp = Bottom; Bottom = Top; Top = tmp;
762 }
763
764 Dc_Attr = dc->pDc_Attr;
765 if(!Dc_Attr) Dc_Attr = &dc->Dc_Attr;
766
767 if (Dc_Attr->ulDirty_ & DC_BRUSH_DIRTY)
768 IntGdiSelectBrush(dc,Dc_Attr->hbrush);
769
770 if (Dc_Attr->ulDirty_ & DC_PEN_DIRTY)
771 IntGdiSelectPen(dc,Dc_Attr->hpen);
772
773 PenBrushObj = PENOBJ_LockPen(Dc_Attr->hpen);
774 if (!PenBrushObj)
775 {
776 /* Nothing to do, as we don't have a bitmap */
777 SetLastWin32Error(ERROR_INTERNAL_ERROR);
778 return FALSE;
779 }
780
781 PenOrigWidth = PenWidth = PenBrushObj->ptPenWidth.x;
782 if (PenBrushObj->ulPenStyle == PS_NULL) PenWidth = 0;
783
784 if (PenBrushObj->ulPenStyle == PS_INSIDEFRAME)
785 {
786 if (2*PenWidth > (Right - Left)) PenWidth = (Right -Left + 1)/2;
787 if (2*PenWidth > (Bottom - Top)) PenWidth = (Bottom -Top + 1)/2;
788 Left += PenWidth / 2;
789 Right -= (PenWidth - 1) / 2;
790 Top += PenWidth / 2;
791 Bottom -= (PenWidth - 1) / 2;
792 }
793
794 if (!PenWidth) PenWidth = 1;
795 PenBrushObj->ptPenWidth.x = PenWidth;
796
797 RectBounds.left = Left;
798 RectBounds.top = Top;
799 RectBounds.right = Right;
800 RectBounds.bottom = Bottom;
801
802 IntLPtoDP(dc, (LPPOINT)&RectBounds, 2);
803
804 RectBounds.left += dc->ptlDCOrig.x;
805 RectBounds.top += dc->ptlDCOrig.y;
806 RectBounds.right += dc->ptlDCOrig.x;
807 RectBounds.bottom += dc->ptlDCOrig.y;
808
809 pFillBrushObj = BRUSHOBJ_LockBrush(Dc_Attr->hbrush);
810 if (NULL == pFillBrushObj)
811 {
812 DPRINT1("FillRound Fail\n");
813 SetLastWin32Error(ERROR_INTERNAL_ERROR);
814 ret = FALSE;
815 }
816 else
817 {
818 RtlCopyMemory(&tmpFillBrushObj, pFillBrushObj, sizeof(tmpFillBrushObj));
819 tmpFillBrushObj.ptOrigin.x += RectBounds.left - Left;
820 tmpFillBrushObj.ptOrigin.y += RectBounds.top - Top;
821 ret = IntFillRoundRect( dc,
822 RectBounds.left,
823 RectBounds.top,
824 RectBounds.right,
825 RectBounds.bottom,
826 xCurveDiameter,
827 yCurveDiameter,
828 &tmpFillBrushObj);
829 BRUSHOBJ_UnlockBrush(pFillBrushObj);
830 }
831
832 if (ret)
833 ret = IntDrawRoundRect( dc,
834 RectBounds.left,
835 RectBounds.top,
836 RectBounds.right,
837 RectBounds.bottom,
838 xCurveDiameter,
839 yCurveDiameter,
840 PenBrushObj);
841
842 PenBrushObj->ptPenWidth.x = PenOrigWidth;
843 PENOBJ_UnlockPen(PenBrushObj);
844 return ret;
845 }
846
847 BOOL
848 APIENTRY
849 NtGdiRoundRect(
850 HDC hDC,
851 int LeftRect,
852 int TopRect,
853 int RightRect,
854 int BottomRect,
855 int Width,
856 int Height)
857 {
858 DC *dc = DC_LockDc(hDC);
859 BOOL ret = FALSE; /* default to failure */
860
861 DPRINT("NtGdiRoundRect(0x%x,%i,%i,%i,%i,%i,%i)\n",hDC,LeftRect,TopRect,RightRect,BottomRect,Width,Height);
862 if ( !dc )
863 {
864 DPRINT1("NtGdiRoundRect() - hDC is invalid\n");
865 SetLastWin32Error(ERROR_INVALID_HANDLE);
866 }
867 else if (dc->dctype == DC_TYPE_INFO)
868 {
869 DC_UnlockDc(dc);
870 /* Yes, Windows really returns TRUE in this case */
871 ret = TRUE;
872 }
873 else
874 {
875 ret = IntRoundRect ( dc, LeftRect, TopRect, RightRect, BottomRect, Width, Height );
876 DC_UnlockDc ( dc );
877 }
878
879 return ret;
880 }
881
882 BOOL FASTCALL
883 IntGdiGradientFill(
884 DC *dc,
885 PTRIVERTEX pVertex,
886 ULONG uVertex,
887 PVOID pMesh,
888 ULONG uMesh,
889 ULONG ulMode)
890 {
891 SURFACE *psurf;
892 PPALGDI PalDestGDI;
893 XLATEOBJ *XlateObj;
894 RECTL Extent;
895 POINTL DitherOrg;
896 ULONG Mode, i;
897 BOOL Ret;
898 HPALETTE hDestPalette;
899
900 ASSERT(dc);
901 ASSERT(pVertex);
902 ASSERT(uVertex);
903 ASSERT(pMesh);
904 ASSERT(uMesh);
905
906 /* check parameters */
907 if (ulMode & GRADIENT_FILL_TRIANGLE)
908 {
909 PGRADIENT_TRIANGLE tr = (PGRADIENT_TRIANGLE)pMesh;
910
911 for (i = 0; i < uMesh; i++, tr++)
912 {
913 if (tr->Vertex1 >= uVertex ||
914 tr->Vertex2 >= uVertex ||
915 tr->Vertex3 >= uVertex)
916 {
917 SetLastWin32Error(ERROR_INVALID_PARAMETER);
918 return FALSE;
919 }
920 }
921 }
922 else
923 {
924 PGRADIENT_RECT rc = (PGRADIENT_RECT)pMesh;
925 for (i = 0; i < uMesh; i++, rc++)
926 {
927 if (rc->UpperLeft >= uVertex || rc->LowerRight >= uVertex)
928 {
929 SetLastWin32Error(ERROR_INVALID_PARAMETER);
930 return FALSE;
931 }
932 }
933 }
934
935 /* calculate extent */
936 Extent.left = Extent.right = pVertex->x;
937 Extent.top = Extent.bottom = pVertex->y;
938 for (i = 0; i < uVertex; i++)
939 {
940 Extent.left = min(Extent.left, (pVertex + i)->x);
941 Extent.right = max(Extent.right, (pVertex + i)->x);
942 Extent.top = min(Extent.top, (pVertex + i)->y);
943 Extent.bottom = max(Extent.bottom, (pVertex + i)->y);
944 }
945
946 DitherOrg.x = dc->ptlDCOrig.x;
947 DitherOrg.y = dc->ptlDCOrig.y;
948 Extent.left += DitherOrg.x;
949 Extent.right += DitherOrg.x;
950 Extent.top += DitherOrg.y;
951 Extent.bottom += DitherOrg.y;
952
953 psurf = SURFACE_LockSurface(dc->rosdc.hBitmap);
954 /* FIXME - psurf can be NULL!!! Don't assert but handle this case gracefully! */
955 ASSERT(psurf);
956
957 hDestPalette = psurf->hDIBPalette;
958 if (!hDestPalette) hDestPalette = pPrimarySurface->DevInfo.hpalDefault;
959
960 PalDestGDI = PALETTE_LockPalette(hDestPalette);
961 if (PalDestGDI)
962 {
963 Mode = PalDestGDI->Mode;
964 PALETTE_UnlockPalette(PalDestGDI);
965 }
966 else
967 Mode = PAL_RGB;
968
969 XlateObj = (XLATEOBJ*)IntEngCreateXlate(Mode, PAL_RGB, hDestPalette, NULL);
970 ASSERT(XlateObj);
971
972 Ret = IntEngGradientFill(&psurf->SurfObj,
973 dc->rosdc.CombinedClip,
974 XlateObj,
975 pVertex,
976 uVertex,
977 pMesh,
978 uMesh,
979 &Extent,
980 &DitherOrg,
981 ulMode);
982
983 SURFACE_UnlockSurface(psurf);
984 EngDeleteXlate(XlateObj);
985
986 return Ret;
987 }
988
989 BOOL
990 APIENTRY
991 NtGdiGradientFill(
992 HDC hdc,
993 PTRIVERTEX pVertex,
994 ULONG uVertex,
995 PVOID pMesh,
996 ULONG uMesh,
997 ULONG ulMode)
998 {
999 DC *dc;
1000 BOOL Ret;
1001 PTRIVERTEX SafeVertex;
1002 PVOID SafeMesh;
1003 ULONG SizeMesh;
1004 NTSTATUS Status = STATUS_SUCCESS;
1005
1006 dc = DC_LockDc(hdc);
1007 if (!dc)
1008 {
1009 SetLastWin32Error(ERROR_INVALID_HANDLE);
1010 return FALSE;
1011 }
1012 if (dc->dctype == DC_TYPE_INFO)
1013 {
1014 DC_UnlockDc(dc);
1015 /* Yes, Windows really returns TRUE in this case */
1016 return TRUE;
1017 }
1018 if (!pVertex || !uVertex || !pMesh || !uMesh)
1019 {
1020 DC_UnlockDc(dc);
1021 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1022 return FALSE;
1023 }
1024
1025 switch (ulMode)
1026 {
1027 case GRADIENT_FILL_RECT_H:
1028 case GRADIENT_FILL_RECT_V:
1029 SizeMesh = uMesh * sizeof(GRADIENT_RECT);
1030 break;
1031 case GRADIENT_FILL_TRIANGLE:
1032 SizeMesh = uMesh * sizeof(TRIVERTEX);
1033 break;
1034 default:
1035 DC_UnlockDc(dc);
1036 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1037 return FALSE;
1038 }
1039
1040 _SEH2_TRY
1041 {
1042 ProbeForRead(pVertex,
1043 uVertex * sizeof(TRIVERTEX),
1044 1);
1045 ProbeForRead(pMesh,
1046 SizeMesh,
1047 1);
1048 }
1049 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1050 {
1051 Status = _SEH2_GetExceptionCode();
1052 }
1053 _SEH2_END;
1054
1055 if (!NT_SUCCESS(Status))
1056 {
1057 DC_UnlockDc(dc);
1058 SetLastWin32Error(Status);
1059 return FALSE;
1060 }
1061
1062 if (!(SafeVertex = ExAllocatePoolWithTag(PagedPool, (uVertex * sizeof(TRIVERTEX)) + SizeMesh, TAG_SHAPE)))
1063 {
1064 DC_UnlockDc(dc);
1065 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
1066 return FALSE;
1067 }
1068
1069 SafeMesh = (PTRIVERTEX)(SafeVertex + uVertex);
1070
1071 _SEH2_TRY
1072 {
1073 /* pointers were already probed! */
1074 RtlCopyMemory(SafeVertex,
1075 pVertex,
1076 uVertex * sizeof(TRIVERTEX));
1077 RtlCopyMemory(SafeMesh,
1078 pMesh,
1079 SizeMesh);
1080 }
1081 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1082 {
1083 Status = _SEH2_GetExceptionCode();
1084 }
1085 _SEH2_END;
1086
1087 if (!NT_SUCCESS(Status))
1088 {
1089 DC_UnlockDc(dc);
1090 ExFreePoolWithTag(SafeVertex, TAG_SHAPE);
1091 SetLastNtError(Status);
1092 return FALSE;
1093 }
1094
1095 Ret = IntGdiGradientFill(dc, SafeVertex, uVertex, SafeMesh, uMesh, ulMode);
1096
1097 DC_UnlockDc(dc);
1098 ExFreePool(SafeVertex);
1099 return Ret;
1100 }
1101
1102 BOOL APIENTRY
1103 NtGdiExtFloodFill(
1104 HDC hDC,
1105 INT XStart,
1106 INT YStart,
1107 COLORREF Color,
1108 UINT FillType)
1109 {
1110 PDC dc;
1111 PDC_ATTR Dc_Attr;
1112 SURFACE *psurf = NULL;
1113 PGDIBRUSHOBJ FillBrushObj = NULL;
1114 GDIBRUSHINST FillBrushInst;
1115 BOOL Ret = FALSE;
1116 RECTL DestRect;
1117 POINTL Pt;
1118 POINTL BrushOrigin;
1119
1120 DPRINT1("FIXME: NtGdiExtFloodFill is UNIMPLEMENTED\n");
1121
1122 dc = DC_LockDc(hDC);
1123 if (!dc)
1124 {
1125 SetLastWin32Error(ERROR_INVALID_HANDLE);
1126 return FALSE;
1127 }
1128 if (dc->dctype == DC_TYPE_INFO)
1129 {
1130 DC_UnlockDc(dc);
1131 /* Yes, Windows really returns TRUE in this case */
1132 return TRUE;
1133 }
1134
1135 Dc_Attr = dc->pDc_Attr;
1136 if(!Dc_Attr) Dc_Attr = &dc->Dc_Attr;
1137
1138 if (Dc_Attr->ulDirty_ & DC_PEN_DIRTY)
1139 IntGdiSelectPen(dc,Dc_Attr->hpen);
1140
1141 if (Dc_Attr->ulDirty_ & DC_BRUSH_DIRTY)
1142 IntGdiSelectBrush(dc,Dc_Attr->hbrush);
1143
1144 Pt.x = XStart;
1145 Pt.y = YStart;
1146 IntLPtoDP(dc, (LPPOINT)&Pt, 1);
1147
1148 Ret = NtGdiPtInRegion(dc->rosdc.hGCClipRgn, Pt.x, Pt.y);
1149 if (Ret)
1150 IntGdiGetRgnBox(dc->rosdc.hGCClipRgn,(LPRECT)&DestRect);
1151 else
1152 goto cleanup;
1153
1154 FillBrushObj = BRUSHOBJ_LockBrush(Dc_Attr->hbrush);
1155 if (!FillBrushObj)
1156 {
1157 Ret = FALSE;
1158 goto cleanup;
1159 }
1160 psurf = SURFACE_LockSurface(dc->rosdc.hBitmap);
1161 if (!psurf)
1162 {
1163 Ret = FALSE;
1164 goto cleanup;
1165 }
1166
1167 if ( FillBrushObj && (FillType == FLOODFILLBORDER))
1168 {
1169 if (!(FillBrushObj->flAttrs & GDIBRUSH_IS_NULL))
1170 {
1171 FillBrushObj->BrushAttr.lbColor = Color;
1172 BrushOrigin = *((PPOINTL)&FillBrushObj->ptOrigin);
1173 BrushOrigin.x += dc->ptlDCOrig.x;
1174 BrushOrigin.y += dc->ptlDCOrig.y;
1175 IntGdiInitBrushInstance(&FillBrushInst, FillBrushObj, dc->rosdc.XlateBrush);
1176 Ret = IntEngBitBlt(&psurf->SurfObj, NULL, NULL,
1177 dc->rosdc.CombinedClip, NULL,
1178 &DestRect, NULL, NULL,
1179 &FillBrushInst.BrushObject,
1180 &BrushOrigin,
1181 ROP3_TO_ROP4(PATCOPY));
1182 }
1183 }
1184 else
1185 {
1186 }
1187
1188 cleanup:
1189 if (FillBrushObj)
1190 BRUSHOBJ_UnlockBrush(FillBrushObj);
1191
1192 if (psurf)
1193 SURFACE_UnlockSurface(psurf);
1194
1195 DC_UnlockDc(dc);
1196 return Ret;
1197 }
1198
1199 /* EOF */