[6/14] gdiplus: create gdi pen every time gdi+ pen is used

Evan Stade estade at gmail.com
Tue Jul 24 19:18:54 CDT 2007


Hi,

The width of a pen is different on different GpGraphics objects (if
pen is UnitWorld it takes on the width of the graphics object's page
unit).  Thus we have to reconstruct the gdi pen every time we use a
pen on a graphics object. To this end I had to rework some of the
pen.c code (actually mostly deletions).

Changelog:
*remove GpPen.gdipen member
*remove all ExtCreatePen calls from pen.c
*pull unit conversion code into a helper
*pull pen selection/SaveDC/etc. code into a helper

 dlls/gdiplus/gdiplus_private.h |    1
 dlls/gdiplus/graphics.c        |  155 ++++++++++++++++++++++------------------
 dlls/gdiplus/pen.c             |   28 +------
 3 files changed, 88 insertions(+), 96 deletions(-)

-- 
Evan Stade
-------------- next part --------------
diff --git a/dlls/gdiplus/gdiplus_private.h b/dlls/gdiplus/gdiplus_private.h
index f8e79f0..79800c2 100644
--- a/dlls/gdiplus/gdiplus_private.h
+++ b/dlls/gdiplus/gdiplus_private.h
@@ -46,7 +46,6 @@ struct GpPen{
     UINT style;
     GpUnit unit;
     REAL width;
-    HPEN gdipen;
     GpLineCap endcap;
     GpLineCap startcap;
     GpDashCap dashcap;
diff --git a/dlls/gdiplus/graphics.c b/dlls/gdiplus/graphics.c
index 6f022a1..6535def 100644
--- a/dlls/gdiplus/graphics.c
+++ b/dlls/gdiplus/graphics.c
@@ -72,6 +72,51 @@ static BYTE convert_path_point_type(BYTE
     return ret;
 }
 
+static REAL convert_unit(HDC hdc, GpUnit unit)
+{
+    switch(unit)
+    {
+        case UnitInch:
+            return (REAL) GetDeviceCaps(hdc, LOGPIXELSX);
+        case UnitPoint:
+            return ((REAL)GetDeviceCaps(hdc, LOGPIXELSX)) / 72.0;
+        case UnitDocument:
+            return ((REAL)GetDeviceCaps(hdc, LOGPIXELSX)) / 300.0;
+        case UnitMillimeter:
+            return ((REAL)GetDeviceCaps(hdc, LOGPIXELSX)) / 25.4;
+        case UnitWorld:
+            ERR("cannot convert UnitWorld\n");
+            return 0.0;
+        case UnitPixel:
+        case UnitDisplay:
+        default:
+            return 1.0;
+    }
+}
+
+static INT prepare_dc(GpGraphics *graphics, GpPen *pen)
+{
+    HPEN gdipen;
+    REAL width;
+    INT save_state = SaveDC(graphics->hdc);
+
+    EndPath(graphics->hdc);
+
+    width = pen->width * convert_unit(graphics->hdc,
+                          pen->unit == UnitWorld ? graphics->unit : pen->unit);
+
+    gdipen = ExtCreatePen(pen->style, roundr(width), &pen->brush->lb, 0, NULL);
+    SelectObject(graphics->hdc, gdipen);
+
+    return save_state;
+}
+
+static void restore_dc(GpGraphics *graphics, INT state)
+{
+    DeleteObject(SelectObject(graphics->hdc, GetStockObject(NULL_PEN)));
+    RestoreDC(graphics->hdc, state);
+}
+
 /* 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:
@@ -89,26 +134,7 @@ static void transform_and_round_points(G
     GpMatrix *matrix;
     int i;
 
-    switch(graphics->unit)
-    {
-        case UnitInch:
-            unitscale = GetDeviceCaps(graphics->hdc, LOGPIXELSX);
-            break;
-        case UnitPoint:
-            unitscale = ((REAL)GetDeviceCaps(graphics->hdc, LOGPIXELSX)) / 72.0;
-            break;
-        case UnitDocument:
-            unitscale = ((REAL)GetDeviceCaps(graphics->hdc, LOGPIXELSX)) / 300.0;
-            break;
-        case UnitMillimeter:
-            unitscale = ((REAL)GetDeviceCaps(graphics->hdc, LOGPIXELSX)) / 25.4;
-            break;
-        case UnitPixel:
-        case UnitDisplay:
-        default:
-            unitscale = 1.0;
-            break;
-    }
+    unitscale = convert_unit(graphics->hdc, graphics->unit);
 
     /* apply page scale */
     if(graphics->unit != UnitDisplay)
@@ -125,21 +151,12 @@ static void transform_and_round_points(G
 }
 
 /* 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)
+static void draw_pie(GpGraphics *graphics, REAL x, REAL y, REAL width,
+    REAL height, REAL startAngle, REAL sweepAngle)
 {
-    INT save_state;
     GpPointF ptf[4];
     POINT pti[4];
 
-    if(!graphics)
-        return InvalidParameter;
-
-    save_state = SaveDC(graphics->hdc);
-    EndPath(graphics->hdc);
-    SelectObject(graphics->hdc, gdipen);
-    SelectObject(graphics->hdc, gdibrush);
-
     ptf[0].X = x;
     ptf[0].Y = y;
     ptf[1].X = x + width;
@@ -152,10 +169,6 @@ static GpStatus draw_pie(GpGraphics *gra
 
     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);
-
-    return Ok;
 }
 
 /* GdipDrawCurve helper function.
@@ -798,13 +811,11 @@ GpStatus WINGDIPAPI GdipDrawArc(GpGraphi
 
     num_pts = arc2polybezier(points, x, y, width, height, startAngle, sweepAngle);
 
-    save_state = SaveDC(graphics->hdc);
-    EndPath(graphics->hdc);
-    SelectObject(graphics->hdc, pen->gdipen);
+    save_state = prepare_dc(graphics, pen);
 
     retval = draw_polybezier(graphics, pen, points, num_pts, TRUE);
 
-    RestoreDC(graphics->hdc, save_state);
+    restore_dc(graphics, save_state);
 
     return retval;
 }
@@ -828,13 +839,11 @@ GpStatus WINGDIPAPI GdipDrawBezier(GpGra
     pt[3].X = x4;
     pt[3].Y = y4;
 
-    save_state = SaveDC(graphics->hdc);
-    EndPath(graphics->hdc);
-    SelectObject(graphics->hdc, pen->gdipen);
+    save_state = prepare_dc(graphics, pen);
 
     retval = draw_polybezier(graphics, pen, pt, 4, TRUE);
 
-    RestoreDC(graphics->hdc, save_state);
+    restore_dc(graphics, save_state);
 
     return retval;
 }
@@ -882,14 +891,12 @@ GpStatus WINGDIPAPI GdipDrawCurve2(GpGra
     pt[len_pt-1].X = points[count-1].X;
     pt[len_pt-1].Y = points[count-1].Y;
 
-    save_state = SaveDC(graphics->hdc);
-    EndPath(graphics->hdc);
-    SelectObject(graphics->hdc, pen->gdipen);
+    save_state = prepare_dc(graphics, pen);
 
     retval = draw_polybezier(graphics, pen, pt, len_pt, TRUE);
 
     GdipFree(pt);
-    RestoreDC(graphics->hdc, save_state);
+    restore_dc(graphics, save_state);
 
     return retval;
 }
@@ -909,13 +916,11 @@ GpStatus WINGDIPAPI GdipDrawLineI(GpGrap
     pt[1].X = (REAL)x2;
     pt[1].Y = (REAL)y2;
 
-    save_state = SaveDC(graphics->hdc);
-    EndPath(graphics->hdc);
-    SelectObject(graphics->hdc, pen->gdipen);
+    save_state = prepare_dc(graphics, pen);
 
     retval = draw_polyline(graphics, pen, pt, 2, TRUE);
 
-    RestoreDC(graphics->hdc, save_state);
+    restore_dc(graphics, save_state);
 
     return retval;
 }
@@ -929,13 +934,11 @@ GpStatus WINGDIPAPI GdipDrawLines(GpGrap
     if(!pen || !graphics || (count < 2))
         return InvalidParameter;
 
-    save_state = SaveDC(graphics->hdc);
-    EndPath(graphics->hdc);
-    SelectObject(graphics->hdc, pen->gdipen);
+    save_state = prepare_dc(graphics, pen);
 
     retval = draw_polyline(graphics, pen, points, count, TRUE);
 
-    RestoreDC(graphics->hdc, save_state);
+    restore_dc(graphics, save_state);
 
     return retval;
 }
@@ -948,14 +951,12 @@ GpStatus WINGDIPAPI GdipDrawPath(GpGraph
     if(!pen || !graphics)
         return InvalidParameter;
 
-    save_state = SaveDC(graphics->hdc);
-    EndPath(graphics->hdc);
-    SelectObject(graphics->hdc, pen->gdipen);
+    save_state = prepare_dc(graphics, pen);
 
     retval = draw_poly(graphics, pen, path->pathdata.Points,
                        path->pathdata.Types, path->pathdata.Count, TRUE);
 
-    RestoreDC(graphics->hdc, save_state);
+    restore_dc(graphics, save_state);
 
     return retval;
 }
@@ -963,11 +964,19 @@ GpStatus WINGDIPAPI GdipDrawPath(GpGraph
 GpStatus WINGDIPAPI GdipDrawPie(GpGraphics *graphics, GpPen *pen, REAL x,
     REAL y, REAL width, REAL height, REAL startAngle, REAL sweepAngle)
 {
-    if(!pen)
+    INT save_state;
+
+    if(!graphics || !pen)
         return InvalidParameter;
 
-    return draw_pie(graphics, GetStockObject(NULL_BRUSH), pen->gdipen, x, y,
-        width, height, startAngle, sweepAngle);
+    save_state = prepare_dc(graphics, pen);
+    SelectObject(graphics->hdc, GetStockObject(NULL_BRUSH));
+
+    draw_pie(graphics, x, y, width, height, startAngle, sweepAngle);
+
+    restore_dc(graphics, save_state);
+
+    return Ok;
 }
 
 GpStatus WINGDIPAPI GdipDrawRectangleI(GpGraphics *graphics, GpPen *pen, INT x,
@@ -978,14 +987,12 @@ GpStatus WINGDIPAPI GdipDrawRectangleI(G
     if(!pen || !graphics)
         return InvalidParameter;
 
-    save_state = SaveDC(graphics->hdc);
-    EndPath(graphics->hdc);
-    SelectObject(graphics->hdc, pen->gdipen);
+    save_state = prepare_dc(graphics, pen);
     SelectObject(graphics->hdc, GetStockObject(NULL_BRUSH));
 
     Rectangle(graphics->hdc, x, y, x + width, y + height);
 
-    RestoreDC(graphics->hdc, save_state);
+    restore_dc(graphics, save_state);
 
     return Ok;
 }
@@ -1025,11 +1032,21 @@ end:
 GpStatus WINGDIPAPI GdipFillPie(GpGraphics *graphics, GpBrush *brush, REAL x,
     REAL y, REAL width, REAL height, REAL startAngle, REAL sweepAngle)
 {
-    if(!brush)
+    INT save_state;
+
+    if(!graphics || !brush)
         return InvalidParameter;
 
-    return draw_pie(graphics, brush->gdibrush, GetStockObject(NULL_PEN), x, y,
-        width, height, startAngle, sweepAngle);
+    save_state = SaveDC(graphics->hdc);
+    EndPath(graphics->hdc);
+    SelectObject(graphics->hdc, brush->gdibrush);
+    SelectObject(graphics->hdc, GetStockObject(NULL_PEN));
+
+    draw_pie(graphics, x, y, width, height, startAngle, sweepAngle);
+
+    RestoreDC(graphics->hdc, save_state);
+
+    return Ok;
 }
 
 GpStatus WINGDIPAPI GdipFillPolygonI(GpGraphics *graphics, GpBrush *brush,
diff --git a/dlls/gdiplus/pen.c b/dlls/gdiplus/pen.c
index 0f58b25..b088ac9 100644
--- a/dlls/gdiplus/pen.c
+++ b/dlls/gdiplus/pen.c
@@ -79,10 +79,6 @@ GpStatus WINGDIPAPI GdipClonePen(GpPen *
     GdipCloneCustomLineCap(pen->customend, &(*clonepen)->customend);
     GdipCloneBrush(pen->brush, &(*clonepen)->brush);
 
-    (*clonepen)->gdipen = ExtCreatePen((*clonepen)->style,
-                                       roundr((*clonepen)->width),
-                                       &(*clonepen)->brush->lb, 0, NULL);
-
     return Ok;
 }
 
@@ -106,10 +102,7 @@ GpStatus WINGDIPAPI GdipCreatePen1(ARGB 
     gp_pen->dash = DashStyleSolid;
     GdipCreateSolidFill(color, (GpSolidFill **)(&gp_pen->brush));
 
-    if((gp_pen->unit == UnitWorld) || (gp_pen->unit == UnitPixel)) {
-        gp_pen->gdipen = ExtCreatePen(gp_pen->style, (INT) gp_pen->width,
-                                      &gp_pen->brush->lb, 0, NULL);
-    } else {
+    if(!((gp_pen->unit == UnitWorld) || (gp_pen->unit == UnitPixel))) {
         FIXME("UnitWorld, UnitPixel only supported units\n");
         GdipFree(gp_pen);
         return NotImplemented;
@@ -123,7 +116,6 @@ GpStatus WINGDIPAPI GdipCreatePen1(ARGB 
 GpStatus WINGDIPAPI GdipDeletePen(GpPen *pen)
 {
     if(!pen)    return InvalidParameter;
-    DeleteObject(pen->gdipen);
 
     GdipDeleteBrush(pen->brush);
     GdipDeleteCustomLineCap(pen->customstart);
@@ -164,21 +156,11 @@ GpStatus WINGDIPAPI GdipGetPenDashStyle(
 
 GpStatus WINGDIPAPI GdipSetPenBrushFill(GpPen *pen, GpBrush *brush)
 {
-    GpStatus retval;
-
     if(!pen || !brush)
         return InvalidParameter;
 
     GdipDeleteBrush(pen->brush);
-    retval = GdipCloneBrush(brush, &pen->brush);
-    if(retval != Ok)
-        return retval;
-
-    DeleteObject(pen->gdipen);
-    pen->gdipen = ExtCreatePen(pen->style, roundr(pen->width), &pen->brush->lb, 0,
-                               NULL);
-
-    return Ok;
+    return GdipCloneBrush(brush, &pen->brush);
 }
 
 GpStatus WINGDIPAPI GdipSetPenColor(GpPen *pen, ARGB argb)
@@ -229,14 +211,11 @@ GpStatus WINGDIPAPI GdipSetPenDashStyle(
     if(!pen)
         return InvalidParameter;
 
-    DeleteObject(pen->gdipen);
     pen->dash = dash;
     pen->style &= ~(PS_ALTERNATE | PS_SOLID | PS_DASH | PS_DOT | PS_DASHDOT |
                     PS_DASHDOTDOT | PS_NULL | PS_USERSTYLE | PS_INSIDEFRAME);
     pen->style |= gdip_to_gdi_dash(dash);
 
-    pen->gdipen = ExtCreatePen(pen->style, (INT) pen->width, &pen->brush->lb, 0, NULL);
-
     return Ok;
 }
 
@@ -277,13 +256,10 @@ GpStatus WINGDIPAPI GdipSetPenLineJoin(G
 {
     if(!pen)    return InvalidParameter;
 
-    DeleteObject(pen->gdipen);
     pen->join = join;
     pen->style &= ~(PS_JOIN_ROUND | PS_JOIN_BEVEL | PS_JOIN_MITER);
     pen->style |= gdip_to_gdi_join(join);
 
-    pen->gdipen = ExtCreatePen(pen->style, (INT) pen->width, &pen->brush->lb, 0, NULL);
-
     return Ok;
 }
 
-- 
1.4.1


More information about the wine-patches mailing list