Delete all Trailing spaces in code.
[reactos.git] / reactos / subsystems / win32 / win32k / objects / fillshap.c
1 /*
2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19
20 #include <w32k.h>
21
22 #define NDEBUG
23 #include <debug.h>
24
25 /*
26 * a couple macros to fill a single pixel or a line
27 */
28 #define PUTPIXEL(x,y,BrushInst) \
29 ret = ret && IntEngLineTo(&BitmapObj->SurfObj, \
30 dc->CombinedClip, \
31 &BrushInst.BrushObject, \
32 x, y, (x)+1, y, \
33 &RectBounds, \
34 ROP2_TO_MIX(dc->Dc_Attr.jROP2));
35
36 #define PUTLINE(x1,y1,x2,y2,BrushInst) \
37 ret = ret && IntEngLineTo(&BitmapObj->SurfObj, \
38 dc->CombinedClip, \
39 &BrushInst.BrushObject, \
40 x1, y1, x2, y2, \
41 &RectBounds, \
42 ROP2_TO_MIX(dc->Dc_Attr.jROP2));
43
44 BOOL FASTCALL
45 IntGdiPolygon(PDC dc,
46 PPOINT UnsafePoints,
47 int Count)
48 {
49 BITMAPOBJ *BitmapObj;
50 PGDIBRUSHOBJ PenBrushObj, FillBrushObj;
51 GDIBRUSHINST PenBrushInst, FillBrushInst;
52 BOOL ret = FALSE; // default to failure
53 RECTL DestRect;
54 int CurrentPoint;
55
56 ASSERT(dc); // caller's responsibility to pass a valid dc
57
58 if ( NULL == UnsafePoints || Count < 2 )
59 {
60 SetLastWin32Error(ERROR_INVALID_PARAMETER);
61 return FALSE;
62 }
63
64 BitmapObj = BITMAPOBJ_LockBitmap(dc->w.hBitmap);
65 /* FIXME - BitmapObj can be NULL!!!! don't assert but handle this case gracefully! */
66 ASSERT(BitmapObj);
67
68 /* Convert to screen coordinates */
69 IntLPtoDP(dc, UnsafePoints, Count);
70 for (CurrentPoint = 0; CurrentPoint < Count; CurrentPoint++)
71 {
72 UnsafePoints[CurrentPoint].x += dc->w.DCOrgX;
73 UnsafePoints[CurrentPoint].y += dc->w.DCOrgY;
74 }
75
76 if (PATH_IsPathOpen(dc->w.path))
77 ret = PATH_Polygon(dc, UnsafePoints, Count );
78 else
79 {
80 DestRect.left = UnsafePoints[0].x;
81 DestRect.right = UnsafePoints[0].x;
82 DestRect.top = UnsafePoints[0].y;
83 DestRect.bottom = UnsafePoints[0].y;
84
85 for (CurrentPoint = 1; CurrentPoint < Count; ++CurrentPoint)
86 {
87 DestRect.left = min(DestRect.left, UnsafePoints[CurrentPoint].x);
88 DestRect.right = max(DestRect.right, UnsafePoints[CurrentPoint].x);
89 DestRect.top = min(DestRect.top, UnsafePoints[CurrentPoint].y);
90 DestRect.bottom = max(DestRect.bottom, UnsafePoints[CurrentPoint].y);
91 }
92
93 /* Now fill the polygon with the current brush. */
94 FillBrushObj = BRUSHOBJ_LockBrush(dc->Dc_Attr.hbrush);
95 if (FillBrushObj && !(FillBrushObj->flAttrs & GDIBRUSH_IS_NULL))
96 {
97 IntGdiInitBrushInstance(&FillBrushInst, FillBrushObj, dc->XlateBrush);
98 ret = FillPolygon ( dc, BitmapObj, &FillBrushInst.BrushObject, ROP2_TO_MIX(dc->Dc_Attr.jROP2), UnsafePoints, Count, DestRect );
99 }
100 BRUSHOBJ_UnlockBrush(FillBrushObj);
101
102 /* get BRUSHOBJ from current pen. */
103 PenBrushObj = PENOBJ_LockPen(dc->Dc_Attr.hpen);
104 // Draw the Polygon Edges with the current pen ( if not a NULL pen )
105 if (PenBrushObj && !(PenBrushObj->flAttrs & GDIBRUSH_IS_NULL))
106 {
107 IntGdiInitBrushInstance(&PenBrushInst, PenBrushObj, dc->XlatePen);
108
109 while(Count-- >1)
110 {
111
112 // DPRINT1("Polygon Making line from (%d,%d) to (%d,%d)\n",
113 // UnsafePoints[0].x, UnsafePoints[0].y,
114 // UnsafePoints[1].x, UnsafePoints[1].y );
115
116 ret = IntEngLineTo(&BitmapObj->SurfObj,
117 dc->CombinedClip,
118 &PenBrushInst.BrushObject,
119 UnsafePoints[0].x, /* From */
120 UnsafePoints[0].y,
121 UnsafePoints[1].x, /* To */
122 UnsafePoints[1].y,
123 &DestRect,
124 ROP2_TO_MIX(dc->Dc_Attr.jROP2)); /* MIX */
125 if(!ret) break;
126 UnsafePoints++;
127 }
128 }
129 PENOBJ_UnlockPen(PenBrushObj);
130 }
131 BITMAPOBJ_UnlockBitmap(BitmapObj);
132
133 return ret;
134 }
135
136 BOOL FASTCALL
137 IntGdiPolyPolygon(DC *dc,
138 LPPOINT Points,
139 LPINT PolyCounts,
140 int Count)
141 {
142 while(--Count >=0)
143 {
144 if(!IntGdiPolygon ( dc, Points, *PolyCounts )) return FALSE;
145 Points+=*PolyCounts++;
146 }
147 return TRUE;
148 }
149
150 /******************************************************************************/
151
152 /*
153 * NtGdiEllipse
154 *
155 * Author
156 * Filip Navara
157 *
158 * Remarks
159 * This function uses optimized Bresenham's ellipse algorithm. It draws
160 * four lines of the ellipse in one pass.
161 *
162 * Todo
163 * Make it look like a Windows ellipse.
164 */
165
166 BOOL STDCALL
167 NtGdiEllipse(
168 HDC hDC,
169 int nLeftRect,
170 int nTopRect,
171 int nRightRect,
172 int nBottomRect)
173 {
174 int ix, iy;
175 int A, B, C, D;
176 int da, db;
177 int NewA, NewB, NewC, NewD;
178 int nx, ny;
179 int CenterX, CenterY;
180 int RadiusX, RadiusY;
181 int Temp;
182 PGDIBRUSHOBJ FillBrush, PenBrush;
183 GDIBRUSHINST FillBrushInst, PenBrushInst;
184 BITMAPOBJ *BitmapObj;
185 RECTL RectBounds;
186 PDC dc;
187 BOOL ret = TRUE, Cond1, Cond2;
188
189 /*
190 * Check the parameters.
191 */
192
193 if (nRightRect <= nLeftRect || nBottomRect <= nTopRect)
194 {
195 SetLastWin32Error(ERROR_INVALID_PARAMETER);
196 return FALSE;
197 }
198
199 /*
200 * Get pointers to all necessary GDI objects.
201 */
202
203 dc = DC_LockDc(hDC);
204 if (dc == NULL)
205 {
206 SetLastWin32Error(ERROR_INVALID_HANDLE);
207 return FALSE;
208 }
209 if (dc->IsIC)
210 {
211 DC_UnlockDc(dc);
212 /* Yes, Windows really returns TRUE in this case */
213 return TRUE;
214 }
215
216 FillBrush = BRUSHOBJ_LockBrush(dc->Dc_Attr.hbrush);
217 if (NULL == FillBrush)
218 {
219 DC_UnlockDc(dc);
220 SetLastWin32Error(ERROR_INTERNAL_ERROR);
221 return FALSE;
222 }
223
224 PenBrush = PENOBJ_LockPen(dc->Dc_Attr.hpen);
225 if (NULL == PenBrush)
226 {
227 BRUSHOBJ_UnlockBrush(FillBrush);
228 DC_UnlockDc(dc);
229 SetLastWin32Error(ERROR_INTERNAL_ERROR);
230 return FALSE;
231 }
232
233 BitmapObj = BITMAPOBJ_LockBitmap(dc->w.hBitmap);
234 if (NULL == BitmapObj)
235 {
236 BRUSHOBJ_UnlockBrush(FillBrush);
237 PENOBJ_UnlockPen(PenBrush);
238 DC_UnlockDc(dc);
239 SetLastWin32Error(ERROR_INTERNAL_ERROR);
240 return FALSE;
241 }
242
243 IntGdiInitBrushInstance(&FillBrushInst, FillBrush, dc->XlateBrush);
244 IntGdiInitBrushInstance(&PenBrushInst, PenBrush, dc->XlatePen);
245
246 RectBounds.left = nLeftRect;
247 RectBounds.right = nRightRect;
248 RectBounds.top = nTopRect;
249 RectBounds.bottom = nBottomRect;
250
251 IntLPtoDP(dc, (LPPOINT)&RectBounds, 2);
252
253 RectBounds.left += dc->w.DCOrgX;
254 RectBounds.right += dc->w.DCOrgX;
255 RectBounds.top += dc->w.DCOrgY;
256 RectBounds.bottom += dc->w.DCOrgY;
257
258 RadiusX = max((RectBounds.right - RectBounds.left) >> 1, 1);
259 RadiusY = max((RectBounds.bottom - RectBounds.top) >> 1, 1);
260 CenterX = RectBounds.left + RadiusX;
261 CenterY = RectBounds.top + RadiusY;
262
263 if (RadiusX > RadiusY)
264 {
265 nx = RadiusX;
266 ny = RadiusY;
267 }
268 else
269 {
270 nx = RadiusY;
271 ny = RadiusX;
272 }
273
274 da = -1;
275 db = 0xFFFF;
276 ix = 0;
277 iy = nx * 64;
278 NewA = 0;
279 NewB = (iy + 32) >> 6;
280 NewC = 0;
281 NewD = (NewB * ny) / nx;
282
283 do {
284 A = NewA;
285 B = NewB;
286 C = NewC;
287 D = NewD;
288
289 ix += iy / nx;
290 iy -= ix / nx;
291 NewA = (ix + 32) >> 6;
292 NewB = (iy + 32) >> 6;
293 NewC = (NewA * ny) / nx;
294 NewD = (NewB * ny) / nx;
295
296 if (RadiusX > RadiusY)
297 {
298 Temp = A; A = C; C = Temp;
299 Temp = B; B = D; D = Temp;
300 Cond1 = ((C != NewA) || (B != NewD)) && (NewC <= NewD);
301 Cond2 = ((D != NewB) || (A != NewC)) && (NewC <= B);
302 }
303 else
304 {
305 Cond1 = ((C != NewC) || (B != NewB)) && (NewA <= NewB);
306 Cond2 = ((D != NewD) || (A != NewA)) && (NewA <= B);
307 }
308
309 /*
310 * Draw the lines going from inner to outer (+ mirrored).
311 */
312
313 if ((A > da) && (A < db))
314 {
315 PUTLINE(CenterX - D, CenterY + A, CenterX + D, CenterY + A, FillBrushInst);
316 if (A)
317 {
318 PUTLINE(CenterX - D, CenterY - A, CenterX + D, CenterY - A, FillBrushInst);
319 }
320 da = A;
321 }
322
323 /*
324 * Draw the lines going from outer to inner (+ mirrored).
325 */
326
327 if ((B < db) && (B > da))
328 {
329 PUTLINE(CenterX - C, CenterY + B, CenterX + C, CenterY + B, FillBrushInst);
330 PUTLINE(CenterX - C, CenterY - B, CenterX + C, CenterY - B, FillBrushInst);
331 db = B;
332 }
333
334 /*
335 * Draw the pixels on the margin.
336 */
337
338 if (Cond1)
339 {
340 PUTPIXEL(CenterX + C, CenterY + B, PenBrushInst);
341 if (C)
342 PUTPIXEL(CenterX - C, CenterY + B, PenBrushInst);
343 if (B)
344 {
345 PUTPIXEL(CenterX + C, CenterY - B, PenBrushInst);
346 if (C)
347 PUTPIXEL(CenterX - C, CenterY - B, PenBrushInst);
348 }
349 }
350
351 if (Cond2)
352 {
353 PUTPIXEL(CenterX + D, CenterY + A, PenBrushInst);
354 if (D)
355 PUTPIXEL(CenterX - D, CenterY + A, PenBrushInst);
356 if (A)
357 {
358 PUTPIXEL(CenterX + D, CenterY - A, PenBrushInst);
359 if (D)
360 PUTPIXEL(CenterX - D, CenterY - A, PenBrushInst);
361 }
362 }
363 } while (B > A);
364
365 BITMAPOBJ_UnlockBitmap(BitmapObj);
366 BRUSHOBJ_UnlockBrush(FillBrush);
367 PENOBJ_UnlockPen(PenBrush);
368 DC_UnlockDc(dc);
369
370 return ret;
371 }
372
373 typedef struct tagSHAPEPOINT
374 {
375 int X;
376 int Y;
377 int Type;
378 } SHAPEPOINT, *PSHAPEPOINT;
379
380 #define SHAPEPOINT_TYPE_CIRCLE 'C'
381 #define SHAPEPOINT_TYPE_LINE_RIGHT 'R' /* Fill at right side of line */
382 #define SHAPEPOINT_TYPE_LINE_LEFT 'L' /* Fill at left side of line */
383
384 #define SETPOINT(x, y, type) \
385 ShapePoints[*PointCount].X = (x); \
386 ShapePoints[*PointCount].Y = (y); \
387 ShapePoints[*PointCount].Type = (type); \
388 (*PointCount)++
389
390 #define SETCIRCLEPOINT(x, y) \
391 SETPOINT(x, y, SHAPEPOINT_TYPE_CIRCLE)
392
393 #ifdef TODO
394 STATIC VOID
395 FASTCALL
396 CirclePoints(UINT *PointCount, PSHAPEPOINT ShapePoints, int Left, int Top,
397 int Right, int Bottom)
398 {
399 int X, X18, X27, X36, X45;
400 int Y, Y14, Y23, Y58, Y67;
401 int d, Radius;
402 BOOL Even;
403
404 Even = (0 == (Right - Left) % 2);
405 Right--;
406 Bottom--;
407 Radius = (Right - Left) >> 1;
408
409 if (Even)
410 {
411 X = 0;
412 Y = Radius;
413 d = 2 - Radius;
414 X18 = Right;
415 X27 = ((Left + Right) >> 1) + 1;
416 X36 = (Left + Right) >> 1;
417 X45 = Left;
418 Y14 = Top + Radius;
419 Y23 = Top;
420 Y58 = Top + Radius + 1;
421 Y67 = Top + (Right - Left);
422 ShapePoints[*PointCount].X = X27;
423 SETCIRCLEPOINT(X27, Y23);
424 SETCIRCLEPOINT(X36, Y23);
425 SETCIRCLEPOINT(X18, Y14);
426 SETCIRCLEPOINT(X45, Y14);
427 SETCIRCLEPOINT(X18, Y58);
428 SETCIRCLEPOINT(X45, Y58);
429 SETCIRCLEPOINT(X27, Y67);
430 SETCIRCLEPOINT(X36, Y67);
431 }
432 else
433 {
434 X = 0;
435 Y = Radius;
436 d = 1 - Radius;
437 X18 = Right;
438 X27 = (Left + Right) >> 1;
439 X36 = (Left + Right) >> 1;
440 X45 = Left;
441 Y14 = Top + Radius;
442 Y23 = Top;
443 Y58 = Top + Radius;
444 Y67 = Top + (Right - Left);
445 SETCIRCLEPOINT(X27, Y23);
446 SETCIRCLEPOINT(X45, Y14);
447 SETCIRCLEPOINT(X18, Y58);
448 SETCIRCLEPOINT(X27, Y67);
449 }
450
451 while (X < Y)
452 {
453 if (d < 0)
454 {
455 d += (X << 1) + (Even ? 4 : 3);
456
457 X27++;
458 X36--;
459 Y14--;
460 Y58++;
461 }
462 else
463 {
464 d += ((X - Y) << 1) + 5;
465 Y--;
466
467 Y23++;
468 Y67--;
469 X18--;
470 X45++;
471 X27++;
472 X36--;
473 Y14--;
474 Y58++;
475 }
476 X++;
477
478 SETCIRCLEPOINT(X27, Y23);
479 SETCIRCLEPOINT(X36, Y23);
480 SETCIRCLEPOINT(X18, Y14);
481 SETCIRCLEPOINT(X45, Y14);
482 SETCIRCLEPOINT(X18, Y58);
483 SETCIRCLEPOINT(X45, Y58);
484 SETCIRCLEPOINT(X27, Y67);
485 SETCIRCLEPOINT(X36, Y67);
486 }
487 }
488
489 STATIC VOID
490 LinePoints(UINT *PointCount, PSHAPEPOINT ShapePoints, int Left, int Top,
491 int Right, int Bottom, int XTo, int YTo, BOOL Start)
492 {
493 LONG x, y, deltax, deltay, i, xchange, ychange, error;
494 int Type;
495
496 x = (Right + Left) >> 1;
497 y = (Bottom + Top) >> 1;
498 deltax = XTo - x;
499 deltay = YTo - y;
500
501 if (deltax < 0)
502 {
503 xchange = -1;
504 deltax = - deltax;
505 x--;
506 }
507 else
508 {
509 xchange = 1;
510 }
511
512 if (deltay < 0)
513 {
514 ychange = -1;
515 deltay = - deltay;
516 y--;
517 Type = (Start ? SHAPEPOINT_TYPE_LINE_LEFT : SHAPEPOINT_TYPE_LINE_RIGHT);
518 }
519 else
520 {
521 ychange = 1;
522 Type = (Start ? SHAPEPOINT_TYPE_LINE_RIGHT : SHAPEPOINT_TYPE_LINE_LEFT);
523 }
524
525 if (y == YTo)
526 {
527 for (i = x; i <= XTo; i++)
528 {
529 SETPOINT(i, y, Type);
530 }
531 }
532 else if (x == XTo)
533 {
534 for (i = y; i <= YTo; i++)
535 {
536 SETPOINT(x, i, Type);
537 }
538 }
539 else
540 {
541 error = 0;
542
543 if (deltax < deltay)
544 {
545 for (i = 0; i < deltay; i++)
546 {
547 SETPOINT(x, y, Type);
548 y = y + ychange;
549 error = error + deltax;
550
551 if (deltay <= error)
552 {
553 x = x + xchange;
554 error = error - deltay;
555 }
556 }
557 }
558 else
559 {
560 for (i = 0; i < deltax; i++)
561 {
562 SETPOINT(x, y, Type);
563 x = x + xchange;
564 error = error + deltay;
565 if (deltax <= error)
566 {
567 y = y + ychange;
568 error = error - deltax;
569 }
570 }
571 }
572 }
573 }
574
575 STATIC int
576 CDECL
577 CompareShapePoints(const void *pv1, const void *pv2)
578 {
579 if (((const PSHAPEPOINT) pv1)->Y < ((const PSHAPEPOINT) pv2)->Y)
580 {
581 return -1;
582 }
583 else if (((const PSHAPEPOINT) pv2)->Y < ((const PSHAPEPOINT) pv1)->Y)
584 {
585 return +1;
586 }
587 else if (((const PSHAPEPOINT) pv1)->X < ((const PSHAPEPOINT) pv2)->X)
588 {
589 return -1;
590 }
591 else if (((const PSHAPEPOINT) pv2)->X < ((const PSHAPEPOINT) pv1)->X)
592 {
593 return +1;
594 }
595 else
596 {
597 return 0;
598 }
599 }
600 #endif
601
602
603 BOOL
604 STDCALL
605 NtGdiPie(HDC hDC,
606 int Left,
607 int Top,
608 int Right,
609 int Bottom,
610 int XRadialStart,
611 int YRadialStart,
612 int XRadialEnd,
613 int YRadialEnd)
614 {
615 #ifdef TODO
616 PDC dc;
617 RECTL RectBounds;
618 SURFOBJ *SurfObj;
619 BRUSHOBJ PenBrushObj;
620 PBRUSHOBJ FillBrushObj;
621 PSHAPEPOINT ShapePoints;
622 UINT Point, PointCount;
623 BOOL ret = TRUE;
624 int Y, CircleStart, CircleEnd, LineStart, LineEnd;
625 BOOL FullFill;
626
627 if (Right <= Left || Bottom <= Top)
628 {
629 SetLastWin32Error(ERROR_INVALID_PARAMETER);
630 return FALSE;
631 }
632
633 if (Right - Left != Bottom - Top)
634 {
635 UNIMPLEMENTED;
636 }
637
638 dc = DC_LockDc ( hDC );
639 if (NULL == dc)
640 {
641 SetLastWin32Error(ERROR_INVALID_HANDLE);
642 return FALSE;
643 }
644 if (dc->IsIC)
645 {
646 DC_UnlockDc(dc);
647 /* Yes, Windows really returns TRUE in this case */
648 return TRUE;
649 }
650
651 FillBrushObj = BRUSHOBJ_LockBrush(dc->Dc_Attr.hbrush);
652 if (NULL == FillBrushObj)
653 {
654 DC_UnlockDc(dc);
655 SetLastWin32Error(ERROR_INTERNAL_ERROR);
656 return FALSE;
657 }
658
659 Left += dc->w.DCOrgX;
660 Right += dc->w.DCOrgX;
661 Top += dc->w.DCOrgY;
662 Bottom += dc->w.DCOrgY;
663 XRadialStart += dc->w.DCOrgX;
664 YRadialStart += dc->w.DCOrgY;
665 XRadialEnd += dc->w.DCOrgX;
666 YRadialEnd += dc->w.DCOrgY;
667
668 RectBounds.left = Left;
669 RectBounds.right = Right;
670 RectBounds.top = Top;
671 RectBounds.bottom = Bottom;
672
673 SurfObj = (SURFOBJ*) AccessUserObject((ULONG)dc->Surface);
674 HPenToBrushObj(&PenBrushObj, dc->Dc_Attr.hpen);
675
676 /* Number of points for the circle is 4 * sqrt(2) * Radius, start
677 and end line have at most Radius points, so allocate at least
678 that much */
679 ShapePoints = ExAllocatePoolWithTag(PagedPool, 8 * (Right - Left + 1) / 2 * sizeof(SHAPEPOINT), TAG_SHAPE);
680 if (NULL == ShapePoints)
681 {
682 BRUSHOBJ_UnlockBrush(FillBrushObj);
683 DC_UnlockDc(dc);
684
685 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
686 return FALSE;
687 }
688
689 if (Left == Right)
690 {
691 PUTPIXEL(Left, Top, &PenBrushObj);
692 BRUSHOBJ_UnlockBrush(FillBrushObj);
693 DC_UnlockDc(dc);
694
695 return ret;
696 }
697
698 PointCount = 0;
699 CirclePoints(&PointCount, ShapePoints, Left, Top, Right, Bottom);
700 LinePoints(&PointCount, ShapePoints, Left, Top, Right, Bottom,
701 XRadialStart, YRadialStart, TRUE);
702 LinePoints(&PointCount, ShapePoints, Left, Top, Right, Bottom,
703 XRadialEnd, YRadialEnd, FALSE);
704 ASSERT(PointCount <= 8 * (Right - Left + 1) / 2);
705 EngSort((PBYTE) ShapePoints, sizeof(SHAPEPOINT), PointCount, CompareShapePoints);
706
707 FullFill = TRUE;
708 Point = 0;
709 while (Point < PointCount)
710 {
711 Y = ShapePoints[Point].Y;
712
713 /* Skip any line pixels before circle */
714 while (Point < PointCount && ShapePoints[Point].Y == Y
715 && SHAPEPOINT_TYPE_CIRCLE != ShapePoints[Point].Type)
716 {
717 Point++;
718 }
719
720 /* Handle left side of circle */
721 if (Point < PointCount && ShapePoints[Point].Y == Y)
722 {
723 CircleStart = ShapePoints[Point].X;
724 Point++;
725 while (Point < PointCount && ShapePoints[Point].Y == Y
726 && ShapePoints[Point].X == ShapePoints[Point - 1].X + 1
727 && SHAPEPOINT_TYPE_CIRCLE == ShapePoints[Point].Type)
728 {
729 Point++;
730 }
731 CircleEnd = ShapePoints[Point - 1].X;
732
733 PUTLINE(CircleStart, Y, CircleEnd + 1, Y, &PenBrushObj);
734 }
735
736 /* Handle line(s) (max 2) inside the circle */
737 while (Point < PointCount && ShapePoints[Point].Y == Y
738 && SHAPEPOINT_TYPE_CIRCLE != ShapePoints[Point].Type)
739 {
740 LineStart = ShapePoints[Point].X;
741 Point++;
742 while (Point < PointCount && ShapePoints[Point].Y == Y
743 && ShapePoints[Point].X == ShapePoints[Point - 1].X + 1
744 && ShapePoints[Point].Type == ShapePoints[Point - 1].Type)
745 {
746 Point++;
747 }
748 LineEnd = ShapePoints[Point - 1].X;
749
750 PUTLINE(LineStart, Y, LineEnd + 1, Y, &PenBrushObj);
751 }
752
753 /* Handle right side of circle */
754 while (Point < PointCount && ShapePoints[Point].Y == Y
755 && SHAPEPOINT_TYPE_CIRCLE == ShapePoints[Point].Type)
756 {
757 CircleStart = ShapePoints[Point].X;
758 Point++;
759 while (Point < PointCount && ShapePoints[Point].Y == Y
760 && ShapePoints[Point].X == ShapePoints[Point - 1].X + 1
761 && SHAPEPOINT_TYPE_CIRCLE == ShapePoints[Point].Type)
762 {
763 Point++;
764 }
765 CircleEnd = ShapePoints[Point - 1].X;
766
767 PUTLINE(CircleStart, Y, CircleEnd + 1, Y, &PenBrushObj);
768 }
769
770 /* Skip any line pixels after circle */
771 while (Point < PointCount && ShapePoints[Point].Y == Y)
772 {
773 Point++;
774 }
775 }
776
777 ExFreePool(ShapePoints);
778 BRUSHOBJ_UnlockBrush(FillBrushObj);
779 DC_UnlockDc(dc);
780
781 return ret;
782 #else
783 return TRUE;
784 #endif
785 }
786
787 #if 0
788
789 //When the fill mode is ALTERNATE, GDI fills the area between odd-numbered and
790 //even-numbered polygon sides on each scan line. That is, GDI fills the area between the
791 //first and second side, between the third and fourth side, and so on.
792
793 //WINDING Selects winding mode (fills any region with a nonzero winding value).
794 //When the fill mode is WINDING, GDI fills any region that has a nonzero winding value.
795 //This value is defined as the number of times a pen used to draw the polygon would go around the region.
796 //The direction of each edge of the polygon is important.
797
798 extern BOOL FillPolygon(PDC dc,
799 SURFOBJ *SurfObj,
800 PBRUSHOBJ BrushObj,
801 MIX RopMode,
802 CONST PPOINT Points,
803 int Count,
804 RECTL BoundRect);
805
806 #endif
807
808
809 ULONG_PTR
810 STDCALL
811 NtGdiPolyPolyDraw( IN HDC hDC,
812 IN PPOINT Points,
813 IN PULONG PolyCounts,
814 IN ULONG Count,
815 IN INT iFunc )
816 {
817 DC *dc;
818 LPPOINT Safept;
819 LPINT SafePolyPoints;
820 NTSTATUS Status = STATUS_SUCCESS;
821 BOOL Ret = TRUE;
822 INT nPoints, nEmpty, nInvalid, i;
823
824 if (iFunc == GdiPolyPolyRgn)
825 {
826 return (ULONG_PTR) GdiCreatePolyPolygonRgn((CONST PPOINT) Points,
827 (CONST PINT) PolyCounts,
828 Count,
829 (INT) hDC);
830 }
831 dc = DC_LockDc(hDC);
832 if(!dc)
833 {
834 SetLastWin32Error(ERROR_INVALID_HANDLE);
835 return FALSE;
836 }
837 if (dc->IsIC)
838 {
839 DC_UnlockDc(dc);
840 /* Yes, Windows really returns TRUE in this case */
841 return TRUE;
842 }
843
844 if(Count > 0)
845 {
846 _SEH_TRY
847 {
848 ProbeForRead(Points,
849 Count * sizeof(POINT),
850 1);
851 ProbeForRead(PolyCounts,
852 Count * sizeof(INT),
853 1);
854 }
855 _SEH_HANDLE
856 {
857 Status = _SEH_GetExceptionCode();
858 }
859 _SEH_END;
860
861 if (!NT_SUCCESS(Status))
862 {
863 DC_UnlockDc(dc);
864 SetLastNtError(Status);
865 return FALSE;
866 }
867
868 SafePolyPoints = ExAllocatePoolWithTag(PagedPool, Count * sizeof(INT), TAG_SHAPE);
869 if(!SafePolyPoints)
870 {
871 DC_UnlockDc(dc);
872 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
873 return FALSE;
874 }
875
876 _SEH_TRY
877 {
878 /* pointers already probed! */
879 RtlCopyMemory(SafePolyPoints,
880 PolyCounts,
881 Count * sizeof(INT));
882 }
883 _SEH_HANDLE
884 {
885 Status = _SEH_GetExceptionCode();
886 }
887 _SEH_END;
888
889 if(!NT_SUCCESS(Status))
890 {
891 DC_UnlockDc(dc);
892 ExFreePool(SafePolyPoints);
893 SetLastNtError(Status);
894 return FALSE;
895 }
896 /* validate poligons */
897 nPoints = 0;
898 nEmpty = 0;
899 nInvalid = 0;
900 for (i = 0; i < Count; i++)
901 {
902 if (SafePolyPoints[i] == 0)
903 {
904 nEmpty++;
905 }
906 if (SafePolyPoints[i] == 1)
907 {
908 nInvalid++;
909 }
910 nPoints += SafePolyPoints[i];
911 }
912
913 if (nEmpty == Count)
914 {
915 /* if all polygon counts are zero, return without setting a last error code. */
916 ExFreePool(SafePolyPoints);
917 return FALSE;
918 }
919 if (nInvalid != 0)
920 {
921 /* if at least one poly count is 1, fail */
922 ExFreePool(SafePolyPoints);
923 SetLastWin32Error(ERROR_INVALID_PARAMETER);
924 return FALSE;
925 }
926
927 Safept = ExAllocatePoolWithTag(PagedPool, nPoints * sizeof(POINT), TAG_SHAPE);
928 if(!Safept)
929 {
930 DC_UnlockDc(dc);
931 ExFreePool(SafePolyPoints);
932 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
933 return FALSE;
934 }
935
936 _SEH_TRY
937 {
938 /* pointers already probed! */
939 RtlCopyMemory(Safept,
940 Points,
941 nPoints * sizeof(POINT));
942 }
943 _SEH_HANDLE
944 {
945 Status = _SEH_GetExceptionCode();
946 }
947 _SEH_END;
948
949 if(!NT_SUCCESS(Status))
950 {
951 DC_UnlockDc(dc);
952 ExFreePool(SafePolyPoints);
953 ExFreePool(Safept);
954 SetLastNtError(Status);
955 return FALSE;
956 }
957 }
958 else
959 {
960 DC_UnlockDc(dc);
961 SetLastWin32Error(ERROR_INVALID_PARAMETER);
962 return FALSE;
963 }
964
965 switch(iFunc)
966 {
967 case GdiPolyPolygon:
968 Ret = IntGdiPolyPolygon(dc, Safept, SafePolyPoints, Count);
969 break;
970 case GdiPolyPolyLine:
971 Ret = IntGdiPolyPolyline(dc, Safept, (LPDWORD) SafePolyPoints, Count);
972 break;
973 case GdiPolyBezier:
974 Ret = IntGdiPolyBezier(dc, Safept, *PolyCounts);
975 break;
976 case GdiPolyLineTo:
977 Ret = IntGdiPolylineTo(dc, Safept, *PolyCounts);
978 break;
979 case GdiPolyBezierTo:
980 Ret = IntGdiPolyBezierTo(dc, Safept, *PolyCounts);
981 break;
982 default:
983 SetLastWin32Error(ERROR_INVALID_PARAMETER);
984 Ret = FALSE;
985 }
986 ExFreePool(SafePolyPoints);
987 ExFreePool(Safept);
988 DC_UnlockDc(dc);
989
990 return (ULONG_PTR) Ret;
991 }
992
993
994 BOOL
995 FASTCALL
996 IntRectangle(PDC dc,
997 int LeftRect,
998 int TopRect,
999 int RightRect,
1000 int BottomRect)
1001 {
1002 BITMAPOBJ *BitmapObj = BITMAPOBJ_LockBitmap(dc->w.hBitmap);
1003 PGDIBRUSHOBJ PenBrushObj, FillBrushObj;
1004 GDIBRUSHINST PenBrushInst, FillBrushInst;
1005 BOOL ret = FALSE; // default to failure
1006 RECTL DestRect;
1007 MIX Mix;
1008
1009 ASSERT ( dc ); // caller's responsibility to set this up
1010 /* FIXME - BitmapObj can be NULL!!! Don't assert but handle this case gracefully! */
1011 ASSERT ( BitmapObj );
1012
1013 if ( PATH_IsPathOpen(dc->w.path) )
1014 {
1015 ret = PATH_Rectangle ( dc, LeftRect, TopRect, RightRect, BottomRect );
1016 }
1017 else
1018 {
1019 LeftRect += dc->w.DCOrgX;
1020 RightRect += dc->w.DCOrgX - 1;
1021 TopRect += dc->w.DCOrgY;
1022 BottomRect += dc->w.DCOrgY - 1;
1023
1024 DestRect.left = LeftRect;
1025 DestRect.right = RightRect;
1026 DestRect.top = TopRect;
1027 DestRect.bottom = BottomRect;
1028
1029 FillBrushObj = BRUSHOBJ_LockBrush(dc->Dc_Attr.hbrush);
1030
1031 if ( FillBrushObj )
1032 {
1033 if (!(FillBrushObj->flAttrs & GDIBRUSH_IS_NULL))
1034 {
1035 IntGdiInitBrushInstance(&FillBrushInst, FillBrushObj, dc->XlateBrush);
1036 ret = IntEngBitBlt(&BitmapObj->SurfObj,
1037 NULL,
1038 NULL,
1039 dc->CombinedClip,
1040 NULL,
1041 &DestRect,
1042 NULL,
1043 NULL,
1044 &FillBrushInst.BrushObject,
1045 NULL,
1046 ROP3_TO_ROP4(PATCOPY));
1047 }
1048 }
1049
1050 BRUSHOBJ_UnlockBrush(FillBrushObj);
1051
1052 /* get BRUSHOBJ from current pen. */
1053 PenBrushObj = PENOBJ_LockPen(dc->Dc_Attr.hpen);
1054 if (PenBrushObj == NULL)
1055 {
1056 SetLastWin32Error(ERROR_INVALID_HANDLE);
1057 BITMAPOBJ_UnlockBitmap(BitmapObj);
1058 return FALSE;
1059 }
1060
1061 IntGdiInitBrushInstance(&PenBrushInst, PenBrushObj, dc->XlatePen);
1062
1063 // Draw the rectangle with the current pen
1064
1065 ret = TRUE; // change default to success
1066
1067 if (!(PenBrushObj->flAttrs & GDIBRUSH_IS_NULL))
1068 {
1069 Mix = ROP2_TO_MIX(dc->Dc_Attr.jROP2);
1070 ret = ret && IntEngLineTo(&BitmapObj->SurfObj,
1071 dc->CombinedClip,
1072 &PenBrushInst.BrushObject,
1073 LeftRect, TopRect, RightRect, TopRect,
1074 &DestRect, // Bounding rectangle
1075 Mix);
1076
1077 ret = ret && IntEngLineTo(&BitmapObj->SurfObj,
1078 dc->CombinedClip,
1079 &PenBrushInst.BrushObject,
1080 RightRect, TopRect, RightRect, BottomRect,
1081 &DestRect, // Bounding rectangle
1082 Mix);
1083
1084 ret = ret && IntEngLineTo(&BitmapObj->SurfObj,
1085 dc->CombinedClip,
1086 &PenBrushInst.BrushObject,
1087 RightRect, BottomRect, LeftRect, BottomRect,
1088 &DestRect, // Bounding rectangle
1089 Mix);
1090
1091 ret = ret && IntEngLineTo(&BitmapObj->SurfObj,
1092 dc->CombinedClip,
1093 &PenBrushInst.BrushObject,
1094 LeftRect, BottomRect, LeftRect, TopRect,
1095 &DestRect, // Bounding rectangle
1096 Mix);
1097 }
1098
1099 PENOBJ_UnlockPen(PenBrushObj);
1100 }
1101
1102 BITMAPOBJ_UnlockBitmap(BitmapObj);
1103
1104 /* Move current position in DC?
1105 MSDN: The current position is neither used nor updated by Rectangle. */
1106
1107 return TRUE;
1108 }
1109
1110 BOOL
1111 STDCALL
1112 NtGdiRectangle(HDC hDC,
1113 int LeftRect,
1114 int TopRect,
1115 int RightRect,
1116 int BottomRect)
1117 {
1118 DC *dc;
1119 BOOL ret; // default to failure
1120
1121 dc = DC_LockDc(hDC);
1122 if(!dc)
1123 {
1124 SetLastWin32Error(ERROR_INVALID_HANDLE);
1125 return FALSE;
1126 }
1127 if (dc->IsIC)
1128 {
1129 DC_UnlockDc(dc);
1130 /* Yes, Windows really returns TRUE in this case */
1131 return TRUE;
1132 }
1133
1134 ret = IntRectangle ( dc, LeftRect, TopRect, RightRect, BottomRect );
1135 DC_UnlockDc ( dc );
1136
1137 return ret;
1138 }
1139
1140
1141 BOOL
1142 FASTCALL
1143 IntRoundRect(
1144 PDC dc,
1145 int left,
1146 int top,
1147 int right,
1148 int bottom,
1149 int xCurveDiameter,
1150 int yCurveDiameter)
1151 {
1152 BITMAPOBJ *BitmapObj;
1153 PGDIBRUSHOBJ PenBrushObj, FillBrushObj;
1154 GDIBRUSHINST FillBrushInst, PenBrushInst;
1155 RECTL RectBounds;
1156 int potential_steps;
1157 int i, col, row, width, height, x1, x1start, x2, x2start, y1, y2;
1158 int xradius, yradius;
1159 //float aspect_square;
1160 long a_square, b_square,
1161 two_a_square, two_b_square,
1162 four_a_square, four_b_square,
1163 d, dinc, ddec;
1164 BOOL first,
1165 ret = TRUE; // default to success
1166
1167 ASSERT ( dc ); // caller's responsibility to set this up
1168
1169 if ( PATH_IsPathOpen(dc->w.path) )
1170 return PATH_RoundRect ( dc, left, top, right, bottom,
1171 xCurveDiameter, yCurveDiameter );
1172
1173 xradius = xCurveDiameter >> 1;
1174 yradius = yCurveDiameter >> 1;
1175
1176 left += dc->w.DCOrgX;
1177 right += dc->w.DCOrgX;
1178 top += dc->w.DCOrgY;
1179 bottom += dc->w.DCOrgY;
1180
1181 RectBounds.left = left;
1182 RectBounds.right = right;
1183 RectBounds.top = top;
1184 RectBounds.bottom = bottom;
1185
1186 BitmapObj = BITMAPOBJ_LockBitmap(dc->w.hBitmap);
1187 if (!BitmapObj)
1188 {
1189 /* Nothing to do, as we don't have a bitmap */
1190 SetLastWin32Error(ERROR_INTERNAL_ERROR);
1191 return FALSE;
1192 }
1193
1194 FillBrushObj = BRUSHOBJ_LockBrush(dc->Dc_Attr.hbrush);
1195 if (FillBrushObj)
1196 {
1197 if (FillBrushObj->flAttrs & GDIBRUSH_IS_NULL)
1198 {
1199 /* make null brush check simpler... */
1200 BRUSHOBJ_UnlockBrush(FillBrushObj);
1201 FillBrushObj = NULL;
1202 }
1203 else
1204 {
1205 IntGdiInitBrushInstance(&FillBrushInst, FillBrushObj, dc->XlateBrush);
1206 }
1207 }
1208
1209 PenBrushObj = PENOBJ_LockPen(dc->Dc_Attr.hpen);
1210 if (PenBrushObj)
1211 {
1212 if (PenBrushObj->flAttrs & GDIBRUSH_IS_NULL)
1213 {
1214 /* make null pen check simpler... */
1215 PENOBJ_UnlockPen(PenBrushObj);
1216 PenBrushObj = NULL;
1217 }
1218 else
1219 {
1220 IntGdiInitBrushInstance(&PenBrushInst, PenBrushObj, dc->XlatePen);
1221 }
1222 }
1223
1224 right--;
1225 bottom--;
1226
1227 width = right - left;
1228 height = bottom - top;
1229
1230 if ( (xradius<<1) > width )
1231 xradius = width >> 1;
1232 if ( (yradius<<1) > height )
1233 yradius = height >> 1;
1234
1235 b_square = yradius * yradius;
1236 a_square = xradius * xradius;
1237 row = yradius;
1238 col = 0;
1239 two_a_square = a_square << 1;
1240 four_a_square = a_square << 2;
1241 four_b_square = b_square << 2;
1242 two_b_square = b_square << 1;
1243 d = two_a_square * ((row - 1) * (row))
1244 + a_square
1245 + two_b_square * (1 - a_square);
1246
1247 x1 = left+xradius;
1248 x2 = right-xradius;
1249 y1 = top;
1250 y2 = bottom;
1251
1252 x1start = x1;
1253 x2start = x2;
1254
1255 dinc = two_b_square*3; /* two_b_square * (3 + (col << 1)); */
1256 ddec = four_a_square * row;
1257
1258 first = TRUE;
1259 for ( ;; )
1260 {
1261 if ( d >= 0 )
1262 {
1263 if ( FillBrushObj )
1264 PUTLINE ( x1, y1, x2, y1, FillBrushInst );
1265 if ( first )
1266 {
1267 if ( PenBrushObj )
1268 {
1269 if ( x1start > x1 )
1270 {
1271 PUTLINE ( x1, y1, x1start, y1, PenBrushInst );
1272 PUTLINE ( x2start+1, y2, x2+1, y2, PenBrushInst );
1273 }
1274 else
1275 {
1276 PUTPIXEL ( x1, y1, PenBrushInst );
1277 PUTPIXEL ( x2, y2, PenBrushInst );
1278 }
1279 }
1280 first = FALSE;
1281 }
1282 else
1283 {
1284 if ( FillBrushObj )
1285 PUTLINE ( x1, y2, x2, y2, FillBrushInst );
1286 if ( PenBrushObj )
1287 {
1288 if ( x1start >= x1 )
1289 {
1290 PUTLINE ( x1, y1, x1start+1, y1, PenBrushInst );
1291 PUTLINE ( x2start, y2, x2+1, y2, PenBrushInst );
1292 }
1293 else
1294 {
1295 PUTPIXEL ( x1, y1, PenBrushInst );
1296 PUTPIXEL ( x2, y2, PenBrushInst );
1297 }
1298 }
1299 }
1300 if ( PenBrushObj )
1301 {
1302 if ( x1start > x1 )
1303 {
1304 PUTLINE ( x1, y2, x1start+1, y2, PenBrushInst );
1305 PUTLINE ( x2start, y1, x2+1, y1, PenBrushInst );
1306 }
1307 else
1308 {
1309 PUTPIXEL ( x1, y2, PenBrushInst );
1310 PUTPIXEL ( x2, y1, PenBrushInst );
1311 }
1312 }
1313 x1start = x1-1;
1314 x2start = x2+1;
1315 row--, y1++, y2--, ddec -= four_a_square;
1316 d -= ddec;
1317 }
1318
1319 potential_steps = ( a_square * row ) / b_square - col + 1;
1320 while ( d < 0 && potential_steps-- )
1321 {
1322 d += dinc; /* two_b_square * (3 + (col << 1)); */
1323 col++, x1--, x2++, dinc += four_b_square;
1324 }
1325
1326 if ( a_square * row <= b_square * col )
1327 break;
1328 };
1329
1330 d = two_b_square * (col + 1) * col
1331 + two_a_square * (row * (row - 2) + 1)
1332 + (1 - two_a_square) * b_square;
1333 dinc = ddec; /* four_b_square * col; */
1334 ddec = two_a_square * ((row << 1) - 3);
1335
1336 while ( row )
1337 {
1338 if ( FillBrushObj )
1339 {
1340 PUTLINE ( x1, y1, x2, y1, FillBrushInst );
1341 PUTLINE ( x1, y2, x2, y2, FillBrushInst );
1342 }
1343 if ( PenBrushObj )
1344 {
1345 PUTPIXEL ( x2, y1, PenBrushInst );
1346 PUTPIXEL ( x1, y2, PenBrushInst );
1347 PUTPIXEL ( x2, y2, PenBrushInst );
1348 PUTPIXEL ( x1, y1, PenBrushInst );
1349 }
1350
1351 if ( d <= 0 )
1352 {
1353 col++, x1--, x2++, dinc += four_b_square;
1354 d += dinc; //four_b_square * col;
1355 }
1356
1357 row--, y1++, y2--, ddec -= four_a_square;
1358 d -= ddec; //two_a_square * ((row << 1) - 3);
1359 }
1360
1361 if ( FillBrushObj )
1362 {
1363 PUTLINE ( left, y1, right, y1, FillBrushInst );
1364 PUTLINE ( left, y2, right, y2, FillBrushInst );
1365 }
1366 if ( PenBrushObj )
1367 {
1368 if ( x1 > (left+1) )
1369 {
1370 PUTLINE ( left, y1, x1, y1, PenBrushInst );
1371 PUTLINE ( x2+1, y1, right, y1, PenBrushInst );
1372 PUTLINE ( left+1, y2, x1, y2, PenBrushInst );
1373 PUTLINE ( x2+1, y2, right+1, y2, PenBrushInst );
1374 }
1375 else
1376 {
1377 PUTPIXEL ( left, y1, PenBrushInst );
1378 PUTPIXEL ( right, y2, PenBrushInst );
1379 }
1380 }
1381
1382 x1 = left+xradius;
1383 x2 = right-xradius;
1384 y1 = top+yradius;
1385 y2 = bottom-yradius;
1386
1387 if ( FillBrushObj )
1388 {
1389 for ( i = y1+1; i < y2; i++ )
1390 PUTLINE ( left, i, right, i, FillBrushInst );
1391 }
1392
1393 if ( PenBrushObj )
1394 {
1395 PUTLINE ( x1, top, x2, top, PenBrushInst );
1396 PUTLINE ( right, y1, right, y2, PenBrushInst );
1397 PUTLINE ( x2, bottom, x1, bottom, PenBrushInst );
1398 PUTLINE ( left, y2, left, y1, PenBrushInst );
1399 }
1400
1401 BITMAPOBJ_UnlockBitmap(BitmapObj);
1402 if(PenBrushObj != NULL)
1403 PENOBJ_UnlockPen(PenBrushObj);
1404 if(FillBrushObj != NULL)
1405 BRUSHOBJ_UnlockBrush(FillBrushObj);
1406
1407 return ret;
1408 }
1409
1410 BOOL
1411 STDCALL
1412 NtGdiRoundRect(
1413 HDC hDC,
1414 int LeftRect,
1415 int TopRect,
1416 int RightRect,
1417 int BottomRect,
1418 int Width,
1419 int Height)
1420 {
1421 DC *dc = DC_LockDc(hDC);
1422 BOOL ret = FALSE; /* default to failure */
1423
1424 DPRINT("NtGdiRoundRect(0x%x,%i,%i,%i,%i,%i,%i)\n",hDC,LeftRect,TopRect,RightRect,BottomRect,Width,Height);
1425 if ( !dc )
1426 {
1427 DPRINT1("NtGdiRoundRect() - hDC is invalid\n");
1428 SetLastWin32Error(ERROR_INVALID_HANDLE);
1429 }
1430 else if (dc->IsIC)
1431 {
1432 DC_UnlockDc(dc);
1433 /* Yes, Windows really returns TRUE in this case */
1434 ret = TRUE;
1435 }
1436 else
1437 {
1438 ret = IntRoundRect ( dc, LeftRect, TopRect, RightRect, BottomRect, Width, Height );
1439 DC_UnlockDc ( dc );
1440 }
1441
1442 return ret;
1443 }
1444
1445 BOOL FASTCALL
1446 IntGdiGradientFill(
1447 DC *dc,
1448 PTRIVERTEX pVertex,
1449 ULONG uVertex,
1450 PVOID pMesh,
1451 ULONG uMesh,
1452 ULONG ulMode)
1453 {
1454 BITMAPOBJ *BitmapObj;
1455 PPALGDI PalDestGDI;
1456 XLATEOBJ *XlateObj;
1457 RECTL Extent;
1458 POINTL DitherOrg;
1459 ULONG Mode, i;
1460 BOOL Ret;
1461
1462 ASSERT(dc);
1463 ASSERT(pVertex);
1464 ASSERT(uVertex);
1465 ASSERT(pMesh);
1466 ASSERT(uMesh);
1467
1468 /* check parameters */
1469 if(ulMode & GRADIENT_FILL_TRIANGLE)
1470 {
1471 PGRADIENT_TRIANGLE tr = (PGRADIENT_TRIANGLE)pMesh;
1472
1473 for(i = 0; i < uMesh; i++, tr++)
1474 {
1475 if(tr->Vertex1 >= uVertex ||
1476 tr->Vertex2 >= uVertex ||
1477 tr->Vertex3 >= uVertex)
1478 {
1479 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1480 return FALSE;
1481 }
1482 }
1483 }
1484 else
1485 {
1486 PGRADIENT_RECT rc = (PGRADIENT_RECT)pMesh;
1487 for(i = 0; i < uMesh; i++, rc++)
1488 {
1489 if(rc->UpperLeft >= uVertex || rc->LowerRight >= uVertex)
1490 {
1491 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1492 return FALSE;
1493 }
1494 }
1495 }
1496
1497 /* calculate extent */
1498 Extent.left = Extent.right = pVertex->x;
1499 Extent.top = Extent.bottom = pVertex->y;
1500 for(i = 0; i < uVertex; i++)
1501 {
1502 Extent.left = min(Extent.left, (pVertex + i)->x);
1503 Extent.right = max(Extent.right, (pVertex + i)->x);
1504 Extent.top = min(Extent.top, (pVertex + i)->y);
1505 Extent.bottom = max(Extent.bottom, (pVertex + i)->y);
1506 }
1507
1508 DitherOrg.x = dc->w.DCOrgX;
1509 DitherOrg.y = dc->w.DCOrgY;
1510 Extent.left += DitherOrg.x;
1511 Extent.right += DitherOrg.x;
1512 Extent.top += DitherOrg.y;
1513 Extent.bottom += DitherOrg.y;
1514
1515 BitmapObj = BITMAPOBJ_LockBitmap(dc->w.hBitmap);
1516 /* FIXME - BitmapObj can be NULL!!! Don't assert but handle this case gracefully! */
1517 ASSERT(BitmapObj);
1518
1519 PalDestGDI = PALETTE_LockPalette(dc->w.hPalette);
1520 /* FIXME - PalDestGDI can be NULL!!! Don't assert but handle this case gracefully! */
1521 ASSERT(PalDestGDI);
1522 Mode = PalDestGDI->Mode;
1523 PALETTE_UnlockPalette(PalDestGDI);
1524
1525 XlateObj = (XLATEOBJ*)IntEngCreateXlate(Mode, PAL_RGB, dc->w.hPalette, NULL);
1526 ASSERT(XlateObj);
1527
1528 Ret = IntEngGradientFill(&BitmapObj->SurfObj,
1529 dc->CombinedClip,
1530 XlateObj,
1531 pVertex,
1532 uVertex,
1533 pMesh,
1534 uMesh,
1535 &Extent,
1536 &DitherOrg,
1537 ulMode);
1538
1539 BITMAPOBJ_UnlockBitmap(BitmapObj);
1540 EngDeleteXlate(XlateObj);
1541
1542 return Ret;
1543 }
1544
1545 BOOL
1546 STDCALL
1547 NtGdiGradientFill(
1548 HDC hdc,
1549 PTRIVERTEX pVertex,
1550 ULONG uVertex,
1551 PVOID pMesh,
1552 ULONG uMesh,
1553 ULONG ulMode)
1554 {
1555 DC *dc;
1556 BOOL Ret;
1557 PTRIVERTEX SafeVertex;
1558 PVOID SafeMesh;
1559 ULONG SizeMesh;
1560 NTSTATUS Status = STATUS_SUCCESS;
1561
1562 dc = DC_LockDc(hdc);
1563 if(!dc)
1564 {
1565 SetLastWin32Error(ERROR_INVALID_HANDLE);
1566 return FALSE;
1567 }
1568 if (dc->IsIC)
1569 {
1570 DC_UnlockDc(dc);
1571 /* Yes, Windows really returns TRUE in this case */
1572 return TRUE;
1573 }
1574 if(!pVertex || !uVertex || !pMesh || !uMesh)
1575 {
1576 DC_UnlockDc(dc);
1577 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1578 return FALSE;
1579 }
1580
1581 switch(ulMode)
1582 {
1583 case GRADIENT_FILL_RECT_H:
1584 case GRADIENT_FILL_RECT_V:
1585 SizeMesh = uMesh * sizeof(GRADIENT_RECT);
1586 break;
1587 case GRADIENT_FILL_TRIANGLE:
1588 SizeMesh = uMesh * sizeof(TRIVERTEX);
1589 break;
1590 default:
1591 DC_UnlockDc(dc);
1592 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1593 return FALSE;
1594 }
1595
1596 _SEH_TRY
1597 {
1598 ProbeForRead(pVertex,
1599 uVertex * sizeof(TRIVERTEX),
1600 1);
1601 ProbeForRead(pMesh,
1602 SizeMesh,
1603 1);
1604 }
1605 _SEH_HANDLE
1606 {
1607 Status = _SEH_GetExceptionCode();
1608 }
1609 _SEH_END;
1610
1611 if (!NT_SUCCESS(Status))
1612 {
1613 DC_UnlockDc(dc);
1614 SetLastWin32Error(Status);
1615 return FALSE;
1616 }
1617
1618 if(!(SafeVertex = ExAllocatePoolWithTag(PagedPool, (uVertex * sizeof(TRIVERTEX)) + SizeMesh, TAG_SHAPE)))
1619 {
1620 DC_UnlockDc(dc);
1621 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
1622 return FALSE;
1623 }
1624
1625 SafeMesh = (PTRIVERTEX)(SafeVertex + uVertex);
1626
1627 _SEH_TRY
1628 {
1629 /* pointers were already probed! */
1630 RtlCopyMemory(SafeVertex,
1631 pVertex,
1632 uVertex * sizeof(TRIVERTEX));
1633 RtlCopyMemory(SafeMesh,
1634 pMesh,
1635 SizeMesh);
1636 }
1637 _SEH_HANDLE
1638 {
1639 Status = _SEH_GetExceptionCode();
1640 }
1641 _SEH_END;
1642
1643 if(!NT_SUCCESS(Status))
1644 {
1645 DC_UnlockDc(dc);
1646 ExFreePool(SafeVertex);
1647 SetLastNtError(Status);
1648 return FALSE;
1649 }
1650
1651 Ret = IntGdiGradientFill(dc, SafeVertex, uVertex, SafeMesh, uMesh, ulMode);
1652
1653 DC_UnlockDc(dc);
1654 ExFreePool(SafeVertex);
1655 return Ret;
1656 }
1657
1658 BOOL STDCALL
1659 NtGdiExtFloodFill(
1660 HDC hDC,
1661 INT XStart,
1662 INT YStart,
1663 COLORREF Color,
1664 UINT FillType)
1665 {
1666 DPRINT1("FIXME: NtGdiExtFloodFill is UNIMPLEMENTED\n");
1667
1668 /* lie and say we succeded */
1669 return TRUE;
1670 }
1671
1672 /* EOF */