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