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