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