[10/10] gdiplus: use page unit when drawing

Evan Stade estade at gmail.com
Mon Jul 23 22:24:53 CDT 2007


Hi,

This patch reorganizes the drawing functions to all go through a
helper function before being drawn on the device.  This helper
function will transform the points according to the gdi+ world
transformation and page unit (right now it only does page unit).  As
noted in one of the comments,

"Native gdiplus uses gdi32 to do all this (via SetMapMode, SetViewportExtEx,
SetWindowExtEx, SetWorldTransform, etc.) but we cannot because we are using
gdi to draw, and these functions would irreparably mess with line widths."

So, for example, say you set page units to UnitInch.  On my monitor
this multiplies the length of the line by 96 as compared to UnitPixel.
 If you used gdi32 to do this, then the pen width will also scale by
96.  I can find no way of counteracting this pen width growth without
messing with the line's endpoints (and merely dividing the width of
the pen is insufficient, because gdi32 only takes integer pen widths
and then we can only have pens with widths a multiple of 96).  Hence
we have to take care of all transformations within gdiplus.

If anyone knows a way around this, I'd be glad to hear it.

 dlls/gdiplus/graphics.c |  305 ++++++++++++++++++++++++++++-------------------
 1 files changed, 180 insertions(+), 125 deletions(-)

-- 
Evan Stade
-------------- next part --------------
diff --git a/dlls/gdiplus/graphics.c b/dlls/gdiplus/graphics.c
index 7a26d87..8a53c03 100644
--- a/dlls/gdiplus/graphics.c
+++ b/dlls/gdiplus/graphics.c
@@ -72,12 +72,45 @@ static BYTE convert_path_point_type(BYTE
     return ret;
 }
 
+/* This helper applies all the changes that the points listed in ptf need in
+ * order to be drawn on the device context.  In the end, this should include at
+ * least:
+ *  -scaling by page unit
+ *  -applying world transformation
+ *  -converting from float to int
+ * Native gdiplus uses gdi32 to do all this (via SetMapMode, SetViewportExtEx,
+ * SetWindowExtEx, SetWorldTransform, etc.) but we cannot because we are using
+ * gdi to draw, and these functions would irreparably mess with line widths.
+ */
+static void transform_and_round_points(GpGraphics *graphics, POINT *pti,
+    GDIPCONST GpPointF *ptf, INT count)
+{
+    REAL unitscale;
+    int i;
+
+    switch(graphics->unit)
+    {
+        case UnitInch:
+            unitscale = GetDeviceCaps(graphics->hdc, LOGPIXELSX);
+            break;
+        default:
+            unitscale = 1.0;
+            break;
+    }
+
+    for(i = 0; i < count; i++){
+        pti[i].x = roundr(unitscale * ptf[i].X);
+        pti[i].y = roundr(unitscale * ptf[i].Y);
+    }
+}
+
 /* GdipDrawPie/GdipFillPie helper function */
 static GpStatus draw_pie(GpGraphics *graphics, HBRUSH gdibrush, HPEN gdipen,
     REAL x, REAL y, REAL width, REAL height, REAL startAngle, REAL sweepAngle)
 {
     INT save_state;
-    REAL x_0, y_0, x_1, y_1, x_2, y_2;
+    GpPointF ptf[4];
+    POINT pti[4];
 
     if(!graphics)
         return InvalidParameter;
@@ -87,14 +120,18 @@ static GpStatus draw_pie(GpGraphics *gra
     SelectObject(graphics->hdc, gdipen);
     SelectObject(graphics->hdc, gdibrush);
 
-    x_0 = x + (width/2.0);
-    y_0 = y + (height/2.0);
+    ptf[0].X = x;
+    ptf[0].Y = y;
+    ptf[1].X = x + width;
+    ptf[1].Y = y + height;
+
+    deg2xy(startAngle+sweepAngle, x + width / 2.0, y + width / 2.0, &ptf[2].X, &ptf[2].Y);
+    deg2xy(startAngle, x + width / 2.0, y + width / 2.0, &ptf[3].X, &ptf[3].Y);
 
-    deg2xy(startAngle+sweepAngle, x_0, y_0, &x_1, &y_1);
-    deg2xy(startAngle, x_0, y_0, &x_2, &y_2);
+    transform_and_round_points(graphics, pti, ptf, 4);
 
-    Pie(graphics->hdc, roundr(x), roundr(y), roundr(x+width), roundr(y+height),
-        roundr(x_1), roundr(y_1), roundr(x_2), roundr(y_2));
+    Pie(graphics->hdc, pti[0].x, pti[0].y, pti[1].x, pti[1].y, pti[2].x,
+        pti[2].y, pti[3].x, pti[3].y);
 
     RestoreDC(graphics->hdc, save_state);
 
@@ -132,17 +169,17 @@ static void calc_curve_bezier_endp(REAL 
 /* Draws the linecap the specified color and size on the hdc.  The linecap is in
  * direction of the line from x1, y1 to x2, y2 and is anchored on x2, y2. Probably
  * should not be called on an hdc that has a path you care about. */
-static void draw_cap(HDC hdc, COLORREF color, GpLineCap cap, REAL size,
+static void draw_cap(GpGraphics *graphics, COLORREF color, GpLineCap cap, REAL size,
     const GpCustomLineCap *custom, REAL x1, REAL y1, REAL x2, REAL y2)
 {
     HGDIOBJ oldbrush, oldpen;
     GpMatrix *matrix = NULL;
     HBRUSH brush;
     HPEN pen;
-    PointF *custptf = NULL;
+    PointF ptf[4], *custptf = NULL;
     POINT pt[4], *custpt = NULL;
     BYTE *tp = NULL;
-    REAL theta, dsmall, dbig, dx, dy;
+    REAL theta, dsmall, dbig, dx, dy = 0.0;
     INT i, count;
     LOGBRUSH lb;
 
@@ -158,8 +195,8 @@ static void draw_cap(HDC hdc, COLORREF c
     pen = ExtCreatePen(PS_GEOMETRIC | PS_SOLID | PS_ENDCAP_FLAT,
                ((cap == LineCapCustom) && custom && (custom->fill)) ? size : 1,
                &lb, 0, NULL);
-    oldbrush = SelectObject(hdc, brush);
-    oldpen = SelectObject(hdc, pen);
+    oldbrush = SelectObject(graphics->hdc, brush);
+    oldpen = SelectObject(graphics->hdc, pen);
 
     switch(cap){
         case LineCapFlat:
@@ -177,21 +214,20 @@ static void draw_cap(HDC hdc, COLORREF c
                 dbig = sin(theta + M_PI_4) * size;
             }
 
-            /* calculating the latter points from the earlier points makes them
-             * look a little better because of rounding issues */
-            pt[0].x = roundr(x2 - dsmall);
-            pt[1].x = roundr(((REAL)pt[0].x) + dbig + dsmall);
+            ptf[0].X = x2 - dsmall;
+            ptf[1].X = x2 + dbig;
 
-            pt[0].y = roundr(y2 - dbig);
-            pt[3].y = roundr(((REAL)pt[0].y) + dsmall + dbig);
+            ptf[0].Y = y2 - dbig;
+            ptf[3].Y = y2 + dsmall;
 
-            pt[1].y = roundr(y2 - dsmall);
-            pt[2].y = roundr(dbig + dsmall + ((REAL)pt[1].y));
+            ptf[1].Y = y2 - dsmall;
+            ptf[2].Y = y2 + dbig;
 
-            pt[3].x = roundr(x2 - dbig);
-            pt[2].x = roundr(((REAL)pt[3].x) + dsmall + dbig);
+            ptf[3].X = x2 - dbig;
+            ptf[2].X = x2 + dsmall;
 
-            Polygon(hdc, pt, 4);
+            transform_and_round_points(graphics, pt, ptf, 4);
+            Polygon(graphics->hdc, pt, 4);
 
             break;
         case LineCapArrowAnchor:
@@ -200,67 +236,74 @@ static void draw_cap(HDC hdc, COLORREF c
             dx = cos(M_PI / 6.0 + theta) * size;
             dy = sin(M_PI / 6.0 + theta) * size;
 
-            pt[0].x = roundr(x2 - dx);
-            pt[0].y = roundr(y2 - dy);
+            ptf[0].X = x2 - dx;
+            ptf[0].Y = y2 - dy;
 
             dx = cos(- M_PI / 6.0 + theta) * size;
             dy = sin(- M_PI / 6.0 + theta) * size;
 
-            pt[1].x = roundr(x2 - dx);
-            pt[1].y = roundr(y2 - dy);
+            ptf[1].X = x2 - dx;
+            ptf[1].Y = y2 - dy;
 
-            pt[2].x = roundr(x2);
-            pt[2].y = roundr(y2);
+            ptf[2].X = x2;
+            ptf[2].Y = y2;
 
-            Polygon(hdc, pt, 3);
+            transform_and_round_points(graphics, pt, ptf, 3);
+            Polygon(graphics->hdc, pt, 3);
 
             break;
         case LineCapRoundAnchor:
             dx = dy = ANCHOR_WIDTH * size / 2.0;
 
-            x2 = (REAL) roundr(x2 - dx);
-            y2 = (REAL) roundr(y2 - dy);
+            ptf[0].X = x2 - dx;
+            ptf[0].Y = y2 - dy;
+            ptf[1].X = x2 + dx;
+            ptf[1].Y = y2 + dy;
+
+            transform_and_round_points(graphics, pt, ptf, 2);
+            Ellipse(graphics->hdc, pt[0].x, pt[0].y, pt[1].x, pt[1].y);
 
-            Ellipse(hdc, (INT) x2, (INT) y2, roundr(x2 + 2.0 * dx),
-                roundr(y2 + 2.0 * dy));
             break;
         case LineCapTriangle:
             size = size / 2.0;
             dx = cos(M_PI_2 + theta) * size;
             dy = sin(M_PI_2 + theta) * size;
 
-            /* Using roundr here can make the triangle float off the end of the
-             * line. */
-            pt[0].x = ((x2 - x1) >= 0 ? floorf(x2 - dx) : ceilf(x2 - dx));
-            pt[0].y = ((y2 - y1) >= 0 ? floorf(y2 - dy) : ceilf(y2 - dy));
-            pt[1].x = roundr(pt[0].x + 2.0 * dx);
-            pt[1].y = roundr(pt[0].y + 2.0 * dy);
+            ptf[0].X = x2 - dx;
+            ptf[0].Y = y2 - dy;
+            ptf[1].X = x2 + dx;
+            ptf[1].Y = y2 + dy;
 
             dx = cos(theta) * size;
             dy = sin(theta) * size;
 
-            pt[2].x = roundr(x2 + dx);
-            pt[2].y = roundr(y2 + dy);
+            ptf[2].X = x2 + dx;
+            ptf[2].Y = y2 + dy;
 
-            Polygon(hdc, pt, 3);
+            transform_and_round_points(graphics, pt, ptf, 3);
+            Polygon(graphics->hdc, pt, 3);
 
             break;
         case LineCapRound:
+            dx = dy = size / 2.0;
+
+            ptf[0].X = x2 - dx;
+            ptf[0].Y = y2 - dy;
+            ptf[1].X = x2 + dx;
+            ptf[1].Y = y2 + dy;
+
             dx = -cos(M_PI_2 + theta) * size;
             dy = -sin(M_PI_2 + theta) * size;
 
-            pt[0].x = ((x2 - x1) >= 0 ? floorf(x2 - dx) : ceilf(x2 - dx));
-            pt[0].y = ((y2 - y1) >= 0 ? floorf(y2 - dy) : ceilf(y2 - dy));
-            pt[1].x = roundr(pt[0].x + 2.0 * dx);
-            pt[1].y = roundr(pt[0].y + 2.0 * dy);
+            ptf[2].X = x2 - dx;
+            ptf[2].Y = y2 - dy;
+            ptf[3].X = x2 + dx;
+            ptf[3].Y = y2 + dy;
 
-            dx = dy = size / 2.0;
-
-            x2 = (REAL) roundr(x2 - dx);
-            y2 = (REAL) roundr(y2 - dy);
+            transform_and_round_points(graphics, pt, ptf, 4);
+            Pie(graphics->hdc, pt[0].x, pt[0].y, pt[1].x, pt[1].y, pt[2].x,
+                pt[2].y, pt[3].x, pt[3].y);
 
-            Pie(hdc, (INT) x2, (INT) y2, roundr(x2 + 2.0 * dx),
-                roundr(y2 + 2.0 * dy), pt[0].x, pt[0].y, pt[1].x, pt[1].y);
             break;
         case LineCapCustom:
             if(!custom)
@@ -282,20 +325,19 @@ static void draw_cap(HDC hdc, COLORREF c
             GdipTranslateMatrix(matrix, x2, y2, MatrixOrderAppend);
             GdipTransformMatrixPoints(matrix, custptf, count);
 
-            for(i = 0; i < count; i++){
-                custpt[i].x = roundr(custptf[i].X);
-                custpt[i].y = roundr(custptf[i].Y);
+            transform_and_round_points(graphics, custpt, custptf, count);
+
+            for(i = 0; i < count; i++)
                 tp[i] = convert_path_point_type(custom->pathdata.Types[i]);
-            }
 
             if(custom->fill){
-                BeginPath(hdc);
-                PolyDraw(hdc, custpt, tp, count);
-                EndPath(hdc);
-                StrokeAndFillPath(hdc);
+                BeginPath(graphics->hdc);
+                PolyDraw(graphics->hdc, custpt, tp, count);
+                EndPath(graphics->hdc);
+                StrokeAndFillPath(graphics->hdc);
             }
             else
-                PolyDraw(hdc, custpt, tp, count);
+                PolyDraw(graphics->hdc, custpt, tp, count);
 
 custend:
             GdipFree(custptf);
@@ -307,8 +349,8 @@ custend:
             break;
     }
 
-    SelectObject(hdc, oldbrush);
-    SelectObject(hdc, oldpen);
+    SelectObject(graphics->hdc, oldbrush);
+    SelectObject(graphics->hdc, oldpen);
     DeleteObject(brush);
     DeleteObject(pen);
 }
@@ -356,12 +398,11 @@ static void shorten_line_amt(REAL x1, RE
 
 /* Draws lines between the given points, and if caps is true then draws an endcap
  * at the end of the last line.  FIXME: Startcaps not implemented. */
-static GpStatus draw_polyline(HDC hdc, GpPen *pen, GDIPCONST GpPointF * pt,
-    INT count, BOOL caps)
+static GpStatus draw_polyline(GpGraphics *graphics, GpPen *pen,
+    GDIPCONST GpPointF * pt, INT count, BOOL caps)
 {
     POINT *pti = NULL;
     GpPointF *ptcopy = NULL;
-    INT i;
     GpStatus status = GenericError;
 
     if(!count)
@@ -375,9 +416,9 @@ static GpStatus draw_polyline(HDC hdc, G
         goto end;
     }
 
-    memcpy(ptcopy, pt, count * sizeof(GpPointF));
-
     if(caps){
+        memcpy(ptcopy, pt, count * sizeof(GpPointF));
+
         if(pen->endcap == LineCapArrowAnchor)
             shorten_line_amt(ptcopy[count-2].X, ptcopy[count-2].Y,
                              &ptcopy[count-1].X, &ptcopy[count-1].Y, pen->width);
@@ -394,18 +435,17 @@ static GpStatus draw_polyline(HDC hdc, G
                              &ptcopy[0].X, &ptcopy[0].Y,
                              pen->customend->inset * pen->width);
 
-        draw_cap(hdc, pen->brush->lb.lbColor, pen->endcap, pen->width, pen->customend,
+        draw_cap(graphics, pen->brush->lb.lbColor, pen->endcap, pen->width, pen->customend,
                  pt[count - 2].X, pt[count - 2].Y, pt[count - 1].X, pt[count - 1].Y);
-        draw_cap(hdc, pen->brush->lb.lbColor, pen->startcap, pen->width, pen->customstart,
-                         pt[1].X, pt[1].Y, pt[0].X, pt[0].Y);
-    }
+        draw_cap(graphics, pen->brush->lb.lbColor, pen->startcap, pen->width, pen->customstart,
+                         pt[1].X, pt[1].Y, pt[0].X, pt[0].Y);\
 
-    for(i = 0; i < count; i ++){
-        pti[i].x = roundr(ptcopy[i].X);
-        pti[i].y = roundr(ptcopy[i].Y);
+        transform_and_round_points(graphics, pti, ptcopy, count);
     }
+    else
+        transform_and_round_points(graphics, pti, pt, count);
 
-    Polyline(hdc, pti, count);
+    Polyline(graphics->hdc, pti, count);
 
 end:
     GdipFree(pti);
@@ -459,12 +499,11 @@ static void shorten_bezier_amt(GpPointF 
 
 /* Draws bezier curves between given points, and if caps is true then draws an
  * endcap at the end of the last line.  FIXME: Startcaps not implemented. */
-static GpStatus draw_polybezier(HDC hdc, GpPen *pen, GDIPCONST GpPointF * pt,
-    INT count, BOOL caps)
+static GpStatus draw_polybezier(GpGraphics *graphics, GpPen *pen,
+    GDIPCONST GpPointF * pt, INT count, BOOL caps)
 {
     POINT *pti, curpos;
     GpPointF *ptcopy;
-    INT i;
     REAL x, y;
     GpStatus status = GenericError;
 
@@ -479,9 +518,9 @@ static GpStatus draw_polybezier(HDC hdc,
         goto end;
     }
 
-    memcpy(ptcopy, pt, count * sizeof(GpPointF));
-
     if(caps){
+        memcpy(ptcopy, pt, count * sizeof(GpPointF));
+
         if(pen->endcap == LineCapArrowAnchor)
             shorten_bezier_amt(&ptcopy[count-4], pen->width, FALSE);
         /* FIXME The following is seemingly correct only for baseinset < 0 or
@@ -492,9 +531,9 @@ static GpStatus draw_polybezier(HDC hdc,
             y = pt[count - 1].Y;
             shorten_line_amt(pt[count - 2].X, pt[count - 2].Y, &x, &y,
                              pen->width * pen->customend->inset);
-            MoveToEx(hdc, roundr(pt[count - 1].X), roundr(pt[count - 1].Y), &curpos);
-            LineTo(hdc, roundr(x), roundr(y));
-            MoveToEx(hdc, curpos.x, curpos.y, NULL);
+            MoveToEx(graphics->hdc, roundr(pt[count - 1].X), roundr(pt[count - 1].Y), &curpos);
+            LineTo(graphics->hdc, roundr(x), roundr(y));
+            MoveToEx(graphics->hdc, curpos.x, curpos.y, NULL);
         }
 
         if(pen->startcap == LineCapArrowAnchor)
@@ -504,30 +543,29 @@ static GpStatus draw_polybezier(HDC hdc,
             y = ptcopy[0].Y;
             shorten_line_amt(ptcopy[1].X, ptcopy[1].Y, &x, &y,
                              pen->width * pen->customend->inset);
-            MoveToEx(hdc, roundr(pt[0].X), roundr(pt[0].Y), &curpos);
-            LineTo(hdc, roundr(x), roundr(y));
-            MoveToEx(hdc, curpos.x, curpos.y, NULL);
+            MoveToEx(graphics->hdc, roundr(pt[0].X), roundr(pt[0].Y), &curpos);
+            LineTo(graphics->hdc, roundr(x), roundr(y));
+            MoveToEx(graphics->hdc, curpos.x, curpos.y, NULL);
         }
 
         /* the direction of the line cap is parallel to the direction at the
          * end of the bezier (which, if it has been shortened, is not the same
          * as the direction from pt[count-2] to pt[count-1]) */
-        draw_cap(hdc, pen->brush->lb.lbColor, pen->endcap, pen->width, pen->customend,
+        draw_cap(graphics, pen->brush->lb.lbColor, pen->endcap, pen->width, pen->customend,
             pt[count - 1].X - (ptcopy[count - 1].X - ptcopy[count - 2].X),
             pt[count - 1].Y - (ptcopy[count - 1].Y - ptcopy[count - 2].Y),
             pt[count - 1].X, pt[count - 1].Y);
 
-        draw_cap(hdc, pen->brush->lb.lbColor, pen->startcap, pen->width, pen->customstart,
+        draw_cap(graphics, pen->brush->lb.lbColor, pen->startcap, pen->width, pen->customstart,
             pt[0].X - (ptcopy[0].X - ptcopy[1].X),
             pt[0].Y - (ptcopy[0].Y - ptcopy[1].Y), pt[0].X, pt[0].Y);
-    }
 
-    for(i = 0; i < count; i ++){
-        pti[i].x = roundr(ptcopy[i].X);
-        pti[i].y = roundr(ptcopy[i].Y);
+        transform_and_round_points(graphics, pti, ptcopy, count);
     }
+    else
+        transform_and_round_points(graphics, pti, pt, count);
 
-    PolyBezier(hdc, pti, count);
+    PolyBezier(graphics->hdc, pti, count);
 
     status = Ok;
 
@@ -539,7 +577,7 @@ end:
 }
 
 /* Draws a combination of bezier curves and lines between points. */
-static GpStatus draw_poly(HDC hdc, GpPen *pen, GDIPCONST GpPointF * pt,
+static GpStatus draw_poly(GpGraphics *graphics, GpPen *pen, GDIPCONST GpPointF * pt,
     GDIPCONST BYTE * types, INT count, BOOL caps)
 {
     POINT *pti = GdipAlloc(count * sizeof(POINT)), curpos;
@@ -583,12 +621,13 @@ static GpStatus draw_poly(HDC hdc, GpPen
                     y = pt[count - 1].Y;
                     shorten_line_amt(pt[count - 2].X, pt[count - 2].Y, &x, &y,
                                      pen->width * pen->customend->inset);
-                    MoveToEx(hdc, roundr(pt[count - 1].X), roundr(pt[count - 1].Y), &curpos);
-                    LineTo(hdc, roundr(x), roundr(y));
-                    MoveToEx(hdc, curpos.x, curpos.y, NULL);
+                    MoveToEx(graphics->hdc, roundr(pt[count - 1].X),
+                             roundr(pt[count - 1].Y), &curpos);
+                    LineTo(graphics->hdc, roundr(x), roundr(y));
+                    MoveToEx(graphics->hdc, curpos.x, curpos.y, NULL);
                 }
 
-                draw_cap(hdc, pen->brush->lb.lbColor, pen->endcap, pen->width, pen->customend,
+                draw_cap(graphics, pen->brush->lb.lbColor, pen->endcap, pen->width, pen->customend,
                     pt[count - 1].X - (ptcopy[count - 1].X - ptcopy[count - 2].X),
                     pt[count - 1].Y - (ptcopy[count - 1].Y - ptcopy[count - 2].Y),
                     pt[count - 1].X, pt[count - 1].Y);
@@ -604,7 +643,7 @@ static GpStatus draw_poly(HDC hdc, GpPen
                                      &ptcopy[count - 1].X, &ptcopy[count - 1].Y,
                                      pen->customend->inset * pen->width);
 
-                draw_cap(hdc, pen->brush->lb.lbColor, pen->endcap, pen->width, pen->customend,
+                draw_cap(graphics, pen->brush->lb.lbColor, pen->endcap, pen->width, pen->customend,
                          pt[count - 2].X, pt[count - 2].Y, pt[count - 1].X,
                          pt[count - 1].Y);
 
@@ -627,12 +666,12 @@ static GpStatus draw_poly(HDC hdc, GpPen
                     y = pt[j - 1].Y;
                     shorten_line_amt(ptcopy[j].X, ptcopy[j].Y, &x, &y,
                                      pen->width * pen->customstart->inset);
-                    MoveToEx(hdc, roundr(pt[j - 1].X), roundr(pt[j - 1].Y), &curpos);
-                    LineTo(hdc, roundr(x), roundr(y));
-                    MoveToEx(hdc, curpos.x, curpos.y, NULL);
+                    MoveToEx(graphics->hdc, roundr(pt[j - 1].X), roundr(pt[j - 1].Y), &curpos);
+                    LineTo(graphics->hdc, roundr(x), roundr(y));
+                    MoveToEx(graphics->hdc, curpos.x, curpos.y, NULL);
                 }
 
-                draw_cap(hdc, pen->brush->lb.lbColor, pen->startcap, pen->width, pen->customstart,
+                draw_cap(graphics, pen->brush->lb.lbColor, pen->startcap, pen->width, pen->customstart,
                     pt[j - 1].X - (ptcopy[j - 1].X - ptcopy[j].X),
                     pt[j - 1].Y - (ptcopy[j - 1].Y - ptcopy[j].Y),
                     pt[j - 1].X, pt[j - 1].Y);
@@ -648,7 +687,7 @@ static GpStatus draw_poly(HDC hdc, GpPen
                                      &ptcopy[j - 1].X, &ptcopy[j - 1].Y,
                                      pen->customstart->inset * pen->width);
 
-                draw_cap(hdc, pen->brush->lb.lbColor, pen->endcap, pen->width, pen->customstart,
+                draw_cap(graphics, pen->brush->lb.lbColor, pen->endcap, pen->width, pen->customstart,
                          pt[j].X, pt[j].Y, pt[j - 1].X,
                          pt[j - 1].Y);
 
@@ -657,22 +696,16 @@ static GpStatus draw_poly(HDC hdc, GpPen
                 ERR("Bad path points\n");
                 goto end;
         }
-        for(i = 0; i < count; i++){
-            pti[i].x = roundr(ptcopy[i].X);
-            pti[i].y = roundr(ptcopy[i].Y);
-        }
+        transform_and_round_points(graphics, pti, ptcopy, count);
     }
     else
-        for(i = 0; i < count; i++){
-            pti[i].x = roundr(pt[i].X);
-            pti[i].y = roundr(pt[i].Y);
-        }
+        transform_and_round_points(graphics, pti, pt, count);
 
     for(i = 0; i < count; i++){
         tp[i] = convert_path_point_type(types[i]);
     }
 
-    PolyDraw(hdc, pti, tp, count);
+    PolyDraw(graphics->hdc, pti, tp, count);
 
     status = Ok;
 
@@ -745,7 +778,7 @@ GpStatus WINGDIPAPI GdipDrawArc(GpGraphi
     EndPath(graphics->hdc);
     SelectObject(graphics->hdc, pen->gdipen);
 
-    retval = draw_polybezier(graphics->hdc, pen, points, num_pts, TRUE);
+    retval = draw_polybezier(graphics, pen, points, num_pts, TRUE);
 
     RestoreDC(graphics->hdc, save_state);
 
@@ -775,7 +808,7 @@ GpStatus WINGDIPAPI GdipDrawBezier(GpGra
     EndPath(graphics->hdc);
     SelectObject(graphics->hdc, pen->gdipen);
 
-    retval = draw_polybezier(graphics->hdc, pen, pt, 4, TRUE);
+    retval = draw_polybezier(graphics, pen, pt, 4, TRUE);
 
     RestoreDC(graphics->hdc, save_state);
 
@@ -829,7 +862,7 @@ GpStatus WINGDIPAPI GdipDrawCurve2(GpGra
     EndPath(graphics->hdc);
     SelectObject(graphics->hdc, pen->gdipen);
 
-    retval = draw_polybezier(graphics->hdc, pen, pt, len_pt, TRUE);
+    retval = draw_polybezier(graphics, pen, pt, len_pt, TRUE);
 
     GdipFree(pt);
     RestoreDC(graphics->hdc, save_state);
@@ -856,7 +889,7 @@ GpStatus WINGDIPAPI GdipDrawLineI(GpGrap
     EndPath(graphics->hdc);
     SelectObject(graphics->hdc, pen->gdipen);
 
-    retval = draw_polyline(graphics->hdc, pen, pt, 2, TRUE);
+    retval = draw_polyline(graphics, pen, pt, 2, TRUE);
 
     RestoreDC(graphics->hdc, save_state);
 
@@ -876,7 +909,7 @@ GpStatus WINGDIPAPI GdipDrawLines(GpGrap
     EndPath(graphics->hdc);
     SelectObject(graphics->hdc, pen->gdipen);
 
-    retval = draw_polyline(graphics->hdc, pen, points, count, TRUE);
+    retval = draw_polyline(graphics, pen, points, count, TRUE);
 
     RestoreDC(graphics->hdc, save_state);
 
@@ -895,7 +928,7 @@ GpStatus WINGDIPAPI GdipDrawPath(GpGraph
     EndPath(graphics->hdc);
     SelectObject(graphics->hdc, pen->gdipen);
 
-    retval = draw_poly(graphics->hdc, pen, path->pathdata.Points,
+    retval = draw_poly(graphics, pen, path->pathdata.Points,
                        path->pathdata.Types, path->pathdata.Count, TRUE);
 
     RestoreDC(graphics->hdc, save_state);
@@ -948,7 +981,7 @@ GpStatus WINGDIPAPI GdipFillPath(GpGraph
                                                                     : WINDING));
 
     BeginPath(graphics->hdc);
-    retval = draw_poly(graphics->hdc, NULL, path->pathdata.Points,
+    retval = draw_poly(graphics, NULL, path->pathdata.Points,
                        path->pathdata.Types, path->pathdata.Count, FALSE);
 
     if(retval != Ok)
@@ -978,21 +1011,43 @@ GpStatus WINGDIPAPI GdipFillPie(GpGraphi
 GpStatus WINGDIPAPI GdipFillPolygonI(GpGraphics *graphics, GpBrush *brush,
     GDIPCONST GpPoint *points, INT count, GpFillMode fillMode)
 {
-    INT save_state;
+    INT save_state, i;
+    GpPointF *ptf = NULL;
+    POINT *pti = NULL;
+    GpStatus retval = Ok;
 
     if(!graphics || !brush || !points || !count)
         return InvalidParameter;
 
+    ptf = GdipAlloc(count * sizeof(GpPointF));
+    pti = GdipAlloc(count * sizeof(POINT));
+    if(!ptf || !pti){
+        retval = OutOfMemory;
+        goto end;
+    }
+
+    for(i = 0; i < count; i ++){
+        ptf[i].X = (REAL) points[i].X;
+        ptf[i].Y = (REAL) points[i].Y;
+    }
+
     save_state = SaveDC(graphics->hdc);
     EndPath(graphics->hdc);
     SelectObject(graphics->hdc, brush->gdibrush);
     SelectObject(graphics->hdc, GetStockObject(NULL_PEN));
     SetPolyFillMode(graphics->hdc, (fillMode == FillModeAlternate ? ALTERNATE
                                                                   : WINDING));
-    Polygon(graphics->hdc, (GDIPCONST POINT*) points, count);
+
+    transform_and_round_points(graphics, pti, ptf, count);
+    Polygon(graphics->hdc, pti, count);
 
     RestoreDC(graphics->hdc, save_state);
-    return Ok;
+
+end:
+    GdipFree(ptf);
+    GdipFree(pti);
+
+    return retval;
 }
 
 /* FIXME: Compositing quality is not used anywhere except the getter/setter. */
-- 
1.4.1


More information about the wine-patches mailing list