Vincent Povirk : gdiplus: Add a software implementation of GdipDrawDriverString.

Alexandre Julliard julliard at winehq.org
Tue Apr 5 11:23:30 CDT 2011


Module: wine
Branch: master
Commit: be0af56be3ba2f6e03b22ed747ebcd5500e74ed0
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=be0af56be3ba2f6e03b22ed747ebcd5500e74ed0

Author: Vincent Povirk <vincent at codeweavers.com>
Date:   Mon Apr  4 16:40:00 2011 -0500

gdiplus: Add a software implementation of GdipDrawDriverString.

---

 dlls/gdiplus/graphics.c       |  188 ++++++++++++++++++++++++++++++++++++++++-
 dlls/gdiplus/tests/graphics.c |    2 -
 2 files changed, 187 insertions(+), 3 deletions(-)

diff --git a/dlls/gdiplus/graphics.c b/dlls/gdiplus/graphics.c
index f26561a..d7cc644 100644
--- a/dlls/gdiplus/graphics.c
+++ b/dlls/gdiplus/graphics.c
@@ -5650,6 +5650,191 @@ static GpStatus GDI32_GdipDrawDriverString(GpGraphics *graphics, GDIPCONST UINT1
     return Ok;
 }
 
+static GpStatus SOFTWARE_GdipDrawDriverString(GpGraphics *graphics, GDIPCONST UINT16 *text, INT length,
+                                         GDIPCONST GpFont *font, GDIPCONST GpBrush *brush,
+                                         GDIPCONST PointF *positions, INT flags,
+                                         GDIPCONST GpMatrix *matrix )
+{
+    static const INT unsupported_flags = ~(DriverStringOptionsCmapLookup);
+    GpStatus stat;
+    PointF *real_positions;
+    POINT *pti;
+    HFONT hfont;
+    HDC hdc;
+    int min_x=INT_MAX, min_y=INT_MAX, max_x=INT_MIN, max_y=INT_MIN, i, x, y;
+    DWORD max_glyphsize=0;
+    GLYPHMETRICS glyphmetrics;
+    static const MAT2 identity = {{0,1}, {0,0}, {0,0}, {0,1}};
+    BYTE *glyph_mask;
+    BYTE *text_mask;
+    int text_mask_stride;
+    BYTE *pixel_data;
+    int pixel_data_stride;
+    GpRect pixel_area;
+    UINT ggo_flags = GGO_GRAY8_BITMAP;
+
+    if (length <= 0)
+        return Ok;
+
+    if (flags & DriverStringOptionsRealizedAdvance)
+    {
+        FIXME("Not implemented for DriverStringOptionsRealizedAdvance\n");
+        return NotImplemented;
+    }
+
+    if (!(flags & DriverStringOptionsCmapLookup))
+        ggo_flags |= GGO_GLYPH_INDEX;
+
+    if (flags & unsupported_flags)
+        FIXME("Ignoring flags %x\n", flags & unsupported_flags);
+
+    if (matrix)
+        FIXME("Ignoring matrix\n");
+
+    real_positions = GdipAlloc(sizeof(PointF) * length);
+    if (!real_positions)
+        return OutOfMemory;
+
+    pti = GdipAlloc(sizeof(POINT) * length);
+    if (!pti)
+    {
+        GdipFree(real_positions);
+        return OutOfMemory;
+    }
+
+    memcpy(real_positions, positions, sizeof(PointF) * length);
+
+    transform_and_round_points(graphics, pti, real_positions, length);
+
+    GdipFree(real_positions);
+
+    get_font_hfont(graphics, font, &hfont);
+
+    hdc = CreateCompatibleDC(0);
+    SelectObject(hdc, hfont);
+
+    /* Get the boundaries of the text to be drawn */
+    for (i=0; i<length; i++)
+    {
+        DWORD glyphsize;
+        int left, top, right, bottom;
+
+        glyphsize = GetGlyphOutlineW(hdc, text[i], ggo_flags,
+            &glyphmetrics, 0, NULL, &identity);
+
+        if (glyphsize == GDI_ERROR)
+        {
+            ERR("GetGlyphOutlineW failed\n");
+            GdipFree(pti);
+            DeleteDC(hdc);
+            DeleteObject(hfont);
+            return GenericError;
+        }
+
+        if (glyphsize > max_glyphsize)
+            max_glyphsize = glyphsize;
+
+        left = pti[i].x - glyphmetrics.gmptGlyphOrigin.x;
+        top = pti[i].y - glyphmetrics.gmptGlyphOrigin.y;
+        right = pti[i].x - glyphmetrics.gmptGlyphOrigin.x + glyphmetrics.gmBlackBoxX;
+        bottom = pti[i].y - glyphmetrics.gmptGlyphOrigin.y + glyphmetrics.gmBlackBoxY;
+
+        if (left < min_x) min_x = left;
+        if (top < min_y) min_y = top;
+        if (right > max_x) max_x = right;
+        if (bottom > max_y) max_y = bottom;
+    }
+
+    glyph_mask = GdipAlloc(max_glyphsize);
+    text_mask = GdipAlloc((max_x - min_x) * (max_y - min_y));
+    text_mask_stride = max_x - min_x;
+
+    if (!(glyph_mask && text_mask))
+    {
+        GdipFree(glyph_mask);
+        GdipFree(text_mask);
+        GdipFree(pti);
+        DeleteDC(hdc);
+        DeleteObject(hfont);
+        return OutOfMemory;
+    }
+
+    /* Generate a mask for the text */
+    for (i=0; i<length; i++)
+    {
+        int left, top, stride;
+
+        GetGlyphOutlineW(hdc, text[i], ggo_flags,
+            &glyphmetrics, max_glyphsize, glyph_mask, &identity);
+
+        left = pti[i].x - glyphmetrics.gmptGlyphOrigin.x;
+        top = pti[i].y - glyphmetrics.gmptGlyphOrigin.y;
+        stride = (glyphmetrics.gmBlackBoxX + 3) & (~3);
+
+        for (y=0; y<glyphmetrics.gmBlackBoxY; y++)
+        {
+            BYTE *glyph_val = glyph_mask + y * stride;
+            BYTE *text_val = text_mask + (left - min_x) + (top - min_y + y) * text_mask_stride;
+            for (x=0; x<glyphmetrics.gmBlackBoxX; x++)
+            {
+                *text_val = min(64, *text_val + *glyph_val);
+                glyph_val++;
+                text_val++;
+            }
+        }
+    }
+
+    GdipFree(pti);
+    DeleteDC(hdc);
+    DeleteObject(hfont);
+    GdipFree(glyph_mask);
+
+    /* get the brush data */
+    pixel_data = GdipAlloc(4 * (max_x - min_x) * (max_y - min_y));
+    if (!pixel_data)
+    {
+        GdipFree(text_mask);
+        return OutOfMemory;
+    }
+
+    pixel_area.X = min_x;
+    pixel_area.Y = min_y;
+    pixel_area.Width = max_x - min_x;
+    pixel_area.Height = max_y - min_y;
+    pixel_data_stride = pixel_area.Width * 4;
+
+    stat = brush_fill_pixels(graphics, (GpBrush*)brush, (DWORD*)pixel_data, &pixel_area, pixel_area.Width);
+    if (stat != Ok)
+    {
+        GdipFree(text_mask);
+        GdipFree(pixel_data);
+        return stat;
+    }
+
+    /* multiply the brush data by the mask */
+    for (y=0; y<pixel_area.Height; y++)
+    {
+        BYTE *text_val = text_mask + text_mask_stride * y;
+        BYTE *pixel_val = pixel_data + pixel_data_stride * y + 3;
+        for (x=0; x<pixel_area.Width; x++)
+        {
+            *pixel_val = (*pixel_val) * (*text_val) / 64;
+            text_val++;
+            pixel_val+=4;
+        }
+    }
+
+    GdipFree(text_mask);
+
+    /* draw the result */
+    stat = alpha_blend_pixels(graphics, min_x, min_y, pixel_data, pixel_area.Width,
+        pixel_area.Height, pixel_data_stride);
+
+    GdipFree(pixel_data);
+
+    return stat;
+}
+
 /*****************************************************************************
  * GdipDrawDriverString [GDIPLUS.@]
  */
@@ -5676,7 +5861,8 @@ GpStatus WINGDIPAPI GdipDrawDriverString(GpGraphics *graphics, GDIPCONST UINT16
             positions, flags, matrix);
 
     if (stat == NotImplemented)
-        FIXME("Not fully implemented\n");
+        stat = SOFTWARE_GdipDrawDriverString(graphics, text, length, font, brush,
+            positions, flags, matrix);
 
     return stat;
 }
diff --git a/dlls/gdiplus/tests/graphics.c b/dlls/gdiplus/tests/graphics.c
index 9f5449a..28414cc 100644
--- a/dlls/gdiplus/tests/graphics.c
+++ b/dlls/gdiplus/tests/graphics.c
@@ -2005,7 +2005,6 @@ static void test_GdipDrawString(void)
     status = GdipDrawDriverString(graphics, string, 4, fnt, brush, NULL, DriverStringOptionsCmapLookup, matrix);
     expect(InvalidParameter, status);
 
-todo_wine {
     status = GdipDrawDriverString(graphics, string, 4, fnt, brush, positions, DriverStringOptionsCmapLookup|0x10, matrix);
     expect(Ok, status);
 
@@ -2014,7 +2013,6 @@ todo_wine {
 
     status = GdipDrawDriverString(graphics, string, 4, fnt, brush, positions, DriverStringOptionsCmapLookup, matrix);
     expect(Ok, status);
-}
 
     GdipDeleteMatrix(matrix);
     GdipDeleteGraphics(graphics);




More information about the wine-cvs mailing list