[9/17] gdiplus: added rendering of custom line caps [try2]

Evan Stade estade at gmail.com
Thu Jul 19 20:22:51 CDT 2007


Hi,

 dlls/gdiplus/graphics.c |  120 +++++++++++++++++++++++++++++++++--------------
 1 files changed, 83 insertions(+), 37 deletions(-)

-- 
Evan Stade
-------------- next part --------------
diff --git a/dlls/gdiplus/graphics.c b/dlls/gdiplus/graphics.c
index 0720163..4a581d1 100644
--- a/dlls/gdiplus/graphics.c
+++ b/dlls/gdiplus/graphics.c
@@ -46,6 +46,32 @@ static void deg2xy(REAL angle, REAL x_0,
     *y = y_0 + sin(radAngle) * hypotenuse;
 }
 
+/* Converts from gdiplus path point type to gdi path point type. */
+static BYTE convert_path_point_type(BYTE type)
+{
+    BYTE ret;
+
+    switch(type & PathPointTypePathTypeMask){
+        case PathPointTypeBezier:
+            ret = PT_BEZIERTO;
+            break;
+        case PathPointTypeLine:
+            ret = PT_LINETO;
+            break;
+        case PathPointTypeStart:
+            ret = PT_MOVETO;
+            break;
+        default:
+            ERR("Bad point type\n");
+            return 0;
+    }
+
+    if(type & PathPointTypeCloseSubpath)
+        ret |= PT_CLOSEFIGURE;
+
+    return ret;
+}
+
 /* 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)
@@ -106,13 +132,18 @@ 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. */
 static void draw_cap(HDC hdc, COLORREF color, GpLineCap cap, REAL size,
-    REAL x1, REAL y1, REAL x2, REAL y2)
+    const GpCustomLineCap *custom, REAL x1, REAL y1, REAL x2, REAL y2)
 {
     HGDIOBJ oldbrush, oldpen;
+    GpMatrix *matrix = NULL;
     HBRUSH brush;
     HPEN pen;
-    POINT pt[4];
+    PointF *custptf = NULL;
+    POINT pt[4], *custpt = NULL;
+    BYTE *tp = NULL;
     REAL theta, dsmall, dbig, dx, dy;
+    INT i, count;
+    LOGBRUSH lb;
 
     if(x2 != x1)
         theta = atan2(y2 - y1, x2 - x1);
@@ -123,7 +154,11 @@ static void draw_cap(HDC hdc, COLORREF c
         return;
 
     brush = CreateSolidBrush(color);
-    pen = CreatePen(PS_SOLID, 1, color);
+    lb.lbStyle = BS_SOLID;
+    lb.lbColor = color;
+    lb.lbHatch = 0;
+    pen = ExtCreatePen(PS_GEOMETRIC | PS_SOLID | PS_ENDCAP_FLAT,
+                       (cap == LineCapCustom ? size : 1), &lb, 0, NULL);
     oldbrush = SelectObject(hdc, brush);
     oldpen = SelectObject(hdc, pen);
 
@@ -229,7 +264,44 @@ static void draw_cap(HDC hdc, COLORREF c
                 roundr(y2 + 2.0 * dy), pt[0].x, pt[0].y, pt[1].x, pt[1].y);
             break;
         case LineCapCustom:
-            FIXME("line cap not implemented\n");
+            if(!custom)
+                break;
+
+            if(custom->fill){
+                FIXME("fill-path custom line caps not implemented\n");
+                break;
+            }
+
+            count = custom->pathdata.Count;
+            custptf = GdipAlloc(count * sizeof(PointF));
+            custpt = GdipAlloc(count * sizeof(POINT));
+            tp = GdipAlloc(count);
+
+            if(!custptf || !custpt || !tp || (GdipCreateMatrix(&matrix) != Ok))
+                goto custend;
+
+            memcpy(custptf, custom->pathdata.Points, count * sizeof(PointF));
+
+            GdipScaleMatrix(matrix, size, size, MatrixOrderAppend);
+            GdipRotateMatrix(matrix, (180.0 / M_PI) * (theta - M_PI_2),
+                             MatrixOrderAppend);
+            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);
+                tp[i] = convert_path_point_type(custom->pathdata.Types[i]);
+            }
+
+            PolyDraw(hdc, custpt, tp, count);
+
+custend:
+            GdipFree(custptf);
+            GdipFree(custpt);
+            GdipFree(tp);
+            GdipDeleteMatrix(matrix);
+            break;
         default:
             break;
     }
@@ -303,8 +375,8 @@ static GpStatus draw_polyline(HDC hdc, G
         if(pen->endcap == LineCapArrowAnchor)
             shorten_line_amt(pt[count-2].X, pt[count-2].Y, &x, &y, pen->width);
 
-        draw_cap(hdc, pen->color, pen->endcap, pen->width, pt[count-2].X,
-            pt[count-2].Y, pt[count - 1].X, pt[count - 1].Y);
+        draw_cap(hdc, pen->color, pen->endcap, pen->width, pen->customend,
+                 pt[count-2].X, pt[count-2].Y, pt[count - 1].X, pt[count - 1].Y);
     }
 
     for(i = 0; i < count - 1; i ++){
@@ -386,7 +458,7 @@ static GpStatus draw_polybezier(HDC hdc,
         /* 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->color, pen->endcap, pen->width,
+        draw_cap(hdc, pen->color, pen->endcap, pen->width, pen->customend,
             pt[count - 1].X - (ptf[3].X - ptf[2].X),
             pt[count - 1].Y - (ptf[3].Y - ptf[2].Y),
             pt[count - 1].X, pt[count - 1].Y);
@@ -412,32 +484,6 @@ end:
     return status;
 }
 
-/* Converts from gdiplus path point type to gdi path point type. */
-static BYTE convert_path_point_type(BYTE type)
-{
-    BYTE ret;
-
-    switch(type & PathPointTypePathTypeMask){
-        case PathPointTypeBezier:
-            ret = PT_BEZIERTO;
-            break;
-        case PathPointTypeLine:
-            ret = PT_LINETO;
-            break;
-        case PathPointTypeStart:
-            ret = PT_MOVETO;
-            break;
-        default:
-            ERR("Bad point type\n");
-            return 0;
-    }
-
-    if(type & PathPointTypeCloseSubpath)
-        ret |= PT_CLOSEFIGURE;
-
-    return ret;
-}
-
 /* Draws a combination of bezier curves and lines between points. */
 static GpStatus draw_poly(HDC hdc, GpPen *pen, GDIPCONST GpPointF * pt,
     GDIPCONST BYTE * types, INT count, BOOL caps)
@@ -489,8 +535,7 @@ static GpStatus draw_poly(HDC hdc, GpPen
                 if(pen->endcap == LineCapArrowAnchor)
                     shorten_bezier_amt(ptf, pen->width);
 
-
-                draw_cap(hdc, pen->color, pen->endcap, pen->width,
+                draw_cap(hdc, pen->color, pen->endcap, pen->width, pen->customend,
                     pt[count - 1].X - (ptf[3].X - ptf[2].X),
                     pt[count - 1].Y - (ptf[3].Y - ptf[2].Y),
                     pt[count - 1].X, pt[count - 1].Y);
@@ -507,8 +552,9 @@ static GpStatus draw_poly(HDC hdc, GpPen
                     shorten_line_amt(pt[count - 2].X, pt[count - 2].Y, &x, &y,
                                      pen->width);
 
-                draw_cap(hdc, pen->color, pen->endcap, pen->width, pt[count - 2].X,
-                         pt[count - 2].Y, pt[count - 1].X, pt[count - 1].Y);
+                draw_cap(hdc, pen->color, pen->endcap, pen->width, pen->customend,
+                         pt[count - 2].X, pt[count - 2].Y, pt[count - 1].X,
+                         pt[count - 1].Y);
 
                 pti[count - 1].x = roundr(x);
                 pti[count - 1].y = roundr(y);
-- 
1.4.1


More information about the wine-patches mailing list