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

Alexandre Julliard julliard at winehq.org
Mon Jan 24 11:07:29 CST 2011


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

Author: Vincent Povirk <vincent at codeweavers.com>
Date:   Fri Jan 21 13:00:34 2011 -0600

gdiplus: Add a software implementation of GdipFillRegion.

---

 dlls/gdiplus/graphics.c |  152 ++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 149 insertions(+), 3 deletions(-)

diff --git a/dlls/gdiplus/graphics.c b/dlls/gdiplus/graphics.c
index c196ab8..7759685 100644
--- a/dlls/gdiplus/graphics.c
+++ b/dlls/gdiplus/graphics.c
@@ -487,6 +487,36 @@ static void brush_fill_path(GpGraphics *graphics, GpBrush* brush)
     }
 }
 
+static INT brush_can_fill_pixels(GpBrush *brush)
+{
+    switch (brush->bt)
+    {
+    case BrushTypeSolidColor:
+        return 1;
+    default:
+        return 0;
+    }
+}
+
+static GpStatus brush_fill_pixels(GpGraphics *graphics, GpBrush *brush,
+    DWORD *argb_pixels, GpRect *fill_area, UINT cdwStride)
+{
+    switch (brush->bt)
+    {
+    case BrushTypeSolidColor:
+    {
+        int x, y;
+        GpSolidFill *fill = (GpSolidFill*)brush;
+        for (x=0; x<fill_area->Width; x++)
+            for (y=0; y<fill_area->Height; y++)
+                argb_pixels[x + y*cdwStride] = fill->color;
+        return Ok;
+    }
+    default:
+        return NotImplemented;
+    }
+}
+
 /* GdipDrawPie/GdipFillPie helper function */
 static void draw_pie(GpGraphics *graphics, REAL x, REAL y, REAL width,
     REAL height, REAL startAngle, REAL sweepAngle)
@@ -3321,13 +3351,122 @@ static GpStatus GDI32_GdipFillRegion(GpGraphics* graphics, GpBrush* brush,
     return Ok;
 }
 
+static GpStatus SOFTWARE_GdipFillRegion(GpGraphics *graphics, GpBrush *brush,
+    GpRegion* region)
+{
+    GpStatus stat;
+    GpRegion *temp_region;
+    GpMatrix *world_to_device, *identity;
+    GpRectF graphics_bounds;
+    UINT scans_count, i;
+    INT dummy;
+    GpRect *scans;
+    DWORD *pixel_data;
+
+    if (!brush_can_fill_pixels(brush))
+        return NotImplemented;
+
+    stat = get_graphics_bounds(graphics, &graphics_bounds);
+
+    if (stat == Ok)
+        stat = GdipCloneRegion(region, &temp_region);
+
+    if (stat == Ok)
+    {
+        stat = get_graphics_transform(graphics, CoordinateSpaceDevice,
+            CoordinateSpaceWorld, &world_to_device);
+
+        if (stat == Ok)
+        {
+            stat = GdipTransformRegion(temp_region, world_to_device);
+
+            GdipDeleteMatrix(world_to_device);
+        }
+
+        if (stat == Ok)
+            stat = GdipCombineRegionRect(temp_region, &graphics_bounds, CombineModeIntersect);
+
+        if (stat == Ok)
+            stat = GdipCreateMatrix(&identity);
+
+        if (stat == Ok)
+        {
+            stat = GdipGetRegionScansCount(temp_region, &scans_count, identity);
+
+            if (stat == Ok && scans_count != 0)
+            {
+                scans = GdipAlloc(sizeof(*scans) * scans_count);
+                if (!scans)
+                    stat = OutOfMemory;
+
+                if (stat == Ok)
+                {
+                    stat = GdipGetRegionScansI(temp_region, scans, &dummy, identity);
+
+                    if (stat != Ok)
+                        GdipFree(scans);
+                }
+            }
+
+            GdipDeleteMatrix(identity);
+        }
+
+        GdipDeleteRegion(temp_region);
+    }
+
+    if (stat == Ok && scans_count == 0)
+        return Ok;
+
+    if (stat == Ok)
+    {
+        UINT max_size=0;
+
+        for (i=0; i<scans_count; i++)
+        {
+            UINT size = scans[i].Width * scans[i].Height;
+
+            if (size > max_size)
+                max_size = size;
+        }
+
+        pixel_data = GdipAlloc(sizeof(*pixel_data) * max_size);
+        if (!pixel_data)
+            stat = OutOfMemory;
+
+        if (stat == Ok)
+        {
+            for (i=0; i<scans_count; i++)
+            {
+                stat = brush_fill_pixels(graphics, brush, pixel_data, &scans[i],
+                    scans[i].Width);
+
+                if (stat == Ok)
+                {
+                    stat = alpha_blend_pixels(graphics, scans[i].X, scans[i].Y,
+                        (BYTE*)pixel_data, scans[i].Width, scans[i].Height,
+                        scans[i].Width * 4);
+                }
+
+                if (stat != Ok)
+                    break;
+            }
+
+            GdipFree(pixel_data);
+        }
+
+        GdipFree(scans);
+    }
+
+    return stat;
+}
+
 /*****************************************************************************
  * GdipFillRegion [GDIPLUS.@]
  */
 GpStatus WINGDIPAPI GdipFillRegion(GpGraphics* graphics, GpBrush* brush,
         GpRegion* region)
 {
-    GpStatus stat;
+    GpStatus stat = NotImplemented;
 
     TRACE("(%p, %p, %p)\n", graphics, brush, region);
 
@@ -3337,11 +3476,18 @@ GpStatus WINGDIPAPI GdipFillRegion(GpGraphics* graphics, GpBrush* brush,
     if(graphics->busy)
         return ObjectBusy;
 
-    stat = GDI32_GdipFillRegion(graphics, brush, region);
+    if (!graphics->image)
+        stat = GDI32_GdipFillRegion(graphics, brush, region);
+
+    if (stat == NotImplemented)
+        stat = SOFTWARE_GdipFillRegion(graphics, brush, region);
+
+    if (stat == NotImplemented && graphics->image)
+        stat = GDI32_GdipFillRegion(graphics, brush, region);
 
     if (stat == NotImplemented)
     {
-        FIXME("partially implemented\n");
+        FIXME("not implemented for brushtype %i\n", brush->bt);
         stat = Ok;
     }
 




More information about the wine-cvs mailing list