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