Huw Davies : gdi32: Implement SelectBrush for DIB pattern brushes.

Alexandre Julliard julliard at winehq.org
Thu May 12 13:57:51 CDT 2011


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

Author: Huw Davies <huw at codeweavers.com>
Date:   Thu May 12 12:05:37 2011 +0100

gdi32: Implement SelectBrush for DIB pattern brushes.

---

 dlls/gdi32/dibdrv/dc.c      |  102 ++++++++++++++++++++++++++++++++++++++++++-
 dlls/gdi32/dibdrv/dibdrv.h  |    5 ++
 dlls/gdi32/dibdrv/objects.c |   49 ++++++++++++++++++++
 dlls/gdi32/gdi_private.h    |    2 +
 4 files changed, 157 insertions(+), 1 deletions(-)

diff --git a/dlls/gdi32/dibdrv/dc.c b/dlls/gdi32/dibdrv/dc.c
index a9a53ad..7a11bec 100644
--- a/dlls/gdi32/dibdrv/dc.c
+++ b/dlls/gdi32/dibdrv/dc.c
@@ -108,6 +108,29 @@ static BOOL init_dib_info(dib_info *dib, const BITMAPINFOHEADER *bi, const DWORD
     return TRUE;
 }
 
+BOOL init_dib_info_from_packed(dib_info *dib, const BITMAPINFOHEADER *bi, WORD usage)
+{
+    DWORD *masks = NULL;
+    RGBQUAD *color_table = NULL;
+    BYTE *ptr = (BYTE*)bi + bi->biSize;
+    int num_colors = bi->biClrUsed;
+
+    if(bi->biCompression == BI_BITFIELDS)
+    {
+        masks = (DWORD *)ptr;
+        ptr += 3 * sizeof(DWORD);
+    }
+
+    if(!num_colors && bi->biBitCount <= 8) num_colors = 1 << bi->biBitCount;
+    if(num_colors) color_table = (RGBQUAD*)ptr;
+    if(usage == DIB_PAL_COLORS)
+        ptr += num_colors * sizeof(WORD);
+    else
+        ptr += num_colors * sizeof(*color_table);
+
+    return init_dib_info(dib, bi, masks, ptr);
+}
+
 static void clear_dib_info(dib_info *dib)
 {
     dib->bits = NULL;
@@ -118,7 +141,7 @@ static void clear_dib_info(dib_info *dib)
  *
  * Free the resources associated with a dib and optionally the bits
  */
-static void free_dib_info(dib_info *dib, BOOL free_bits)
+void free_dib_info(dib_info *dib, BOOL free_bits)
 {
     if(free_bits)
     {
@@ -127,6 +150,80 @@ static void free_dib_info(dib_info *dib, BOOL free_bits)
     }
 }
 
+void copy_dib_color_info(dib_info *dst, const dib_info *src)
+{
+    dst->bit_count        = src->bit_count;
+    dst->red_mask         = src->red_mask;
+    dst->green_mask       = src->green_mask;
+    dst->blue_mask        = src->blue_mask;
+    dst->red_len          = src->red_len;
+    dst->green_len        = src->green_len;
+    dst->blue_len         = src->blue_len;
+    dst->red_shift        = src->red_shift;
+    dst->green_shift      = src->green_shift;
+    dst->blue_shift       = src->blue_shift;
+    dst->funcs            = src->funcs;
+}
+
+static BOOL dib_formats_match(const dib_info *d1, const dib_info *d2)
+{
+    if(d1->bit_count != d2->bit_count) return FALSE;
+
+    switch(d1->bit_count)
+    {
+    case 24: return TRUE;
+
+    case 32:
+    case 16:
+        return (d1->red_mask == d2->red_mask) && (d1->green_mask == d2->green_mask) &&
+            (d1->blue_mask == d2->blue_mask);
+
+    default:
+        ERR("Unexpected depth %d\n", d1->bit_count);
+        return FALSE;
+    }
+}
+
+/**************************************************************
+ *            convert_dib
+ *
+ * Converts src into the format specified in dst.
+ *
+ * FIXME: At the moment this always creates a top-down dib,
+ * do we want to give the option of bottom-up?
+ */
+BOOL convert_dib(dib_info *dst, const dib_info *src)
+{
+    INT y;
+
+    dst->height = src->height;
+    dst->width = src->width;
+    dst->stride = ((dst->width * dst->bit_count + 31) >> 3) & ~3;
+    dst->bits = NULL;
+
+    if(dib_formats_match(src, dst))
+    {
+        dst->bits = HeapAlloc(GetProcessHeap(), 0, dst->height * dst->stride);
+
+        if(src->stride > 0)
+            memcpy(dst->bits, src->bits, dst->height * dst->stride);
+        else
+        {
+            BYTE *src_bits = src->bits;
+            BYTE *dst_bits = dst->bits;
+            for(y = 0; y < dst->height; y++)
+            {
+                memcpy(dst_bits, src_bits, dst->stride);
+                dst_bits += dst->stride;
+                src_bits += src->stride;
+            }
+        }
+        return TRUE;
+    }
+    FIXME("Format conversion not implemented\n");
+    return FALSE;
+}
+
 /***********************************************************************
  *           dibdrv_DeleteDC
  */
@@ -135,6 +232,7 @@ static BOOL CDECL dibdrv_DeleteDC( PHYSDEV dev )
     dibdrv_physdev *pdev = get_dibdrv_pdev(dev);
     TRACE("(%p)\n", dev);
     DeleteObject(pdev->clip);
+    free_pattern_brush(pdev);
     free_dib_info(&pdev->dib, FALSE);
     return 0;
 }
@@ -156,6 +254,8 @@ static HBITMAP CDECL dibdrv_SelectBitmap( PHYSDEV dev, HBITMAP bitmap )
     pdev->defer = 0;
 
     clear_dib_info(&pdev->dib);
+    clear_dib_info(&pdev->brush_dib);
+    pdev->brush_and_bits = pdev->brush_xor_bits = NULL;
 
     if(!init_dib_info(&pdev->dib, &bmp->dib->dsBmih, bmp->dib->dsBitfields, bmp->dib->dsBm.bmBits))
         pdev->defer |= DEFER_FORMAT;
diff --git a/dlls/gdi32/dibdrv/dibdrv.h b/dlls/gdi32/dibdrv/dibdrv.h
index 7327fca..1982866 100644
--- a/dlls/gdi32/dibdrv/dibdrv.h
+++ b/dlls/gdi32/dibdrv/dibdrv.h
@@ -48,6 +48,11 @@ extern const primitive_funcs funcs_null DECLSPEC_HIDDEN;
 extern void calc_and_xor_masks(INT rop, DWORD color, DWORD *and, DWORD *xor) DECLSPEC_HIDDEN;
 extern void update_brush_rop( dibdrv_physdev *pdev, INT rop ) DECLSPEC_HIDDEN;
 extern void reset_dash_origin(dibdrv_physdev *pdev) DECLSPEC_HIDDEN;
+extern BOOL init_dib_info_from_packed(dib_info *dib, const BITMAPINFOHEADER *bi, WORD usage) DECLSPEC_HIDDEN;
+extern void free_dib_info(dib_info *dib, BOOL free_bits) DECLSPEC_HIDDEN;
+extern void free_pattern_brush(dibdrv_physdev *pdev) DECLSPEC_HIDDEN;
+extern void copy_dib_color_info(dib_info *dst, const dib_info *src) DECLSPEC_HIDDEN;
+extern BOOL convert_dib(dib_info *dst, const dib_info *src) DECLSPEC_HIDDEN;
 
 static inline BOOL defer_pen(dibdrv_physdev *pdev)
 {
diff --git a/dlls/gdi32/dibdrv/objects.c b/dlls/gdi32/dibdrv/objects.c
index 52aab44..dde7a96 100644
--- a/dlls/gdi32/dibdrv/objects.c
+++ b/dlls/gdi32/dibdrv/objects.c
@@ -956,11 +956,37 @@ static BOOL solid_brush(dibdrv_physdev *pdev, int num, RECT *rects)
     return TRUE;
 }
 
+/**********************************************************************
+ *             pattern_brush
+ *
+ * Fill a number of rectangles with the pattern brush
+ * FIXME: Should we insist l < r && t < b?  Currently we assume this.
+ */
+static BOOL pattern_brush(dibdrv_physdev *pdev, int num, RECT *rects)
+{
+    return FALSE;
+}
+
+static void free_pattern_brush_bits( dibdrv_physdev *pdev )
+{
+    HeapFree(GetProcessHeap(), 0, pdev->brush_and_bits);
+    HeapFree(GetProcessHeap(), 0, pdev->brush_xor_bits);
+    pdev->brush_and_bits = NULL;
+    pdev->brush_xor_bits = NULL;
+}
+
+void free_pattern_brush( dibdrv_physdev *pdev )
+{
+    free_pattern_brush_bits( pdev );
+    free_dib_info( &pdev->brush_dib, TRUE );
+}
+
 void update_brush_rop( dibdrv_physdev *pdev, INT rop )
 {
     pdev->brush_rop = rop;
     if(pdev->brush_style == BS_SOLID)
         calc_and_xor_masks(rop, pdev->brush_color, &pdev->brush_and, &pdev->brush_xor);
+    free_pattern_brush_bits( pdev );
 }
 
 /***********************************************************************
@@ -983,6 +1009,8 @@ HBRUSH CDECL dibdrv_SelectBrush( PHYSDEV dev, HBRUSH hbrush )
 
     pdev->defer |= DEFER_BRUSH;
 
+    free_pattern_brush( pdev );
+
     switch(logbrush.lbStyle)
     {
     case BS_SOLID:
@@ -991,6 +1019,27 @@ HBRUSH CDECL dibdrv_SelectBrush( PHYSDEV dev, HBRUSH hbrush )
         pdev->brush_rects = solid_brush;
         pdev->defer &= ~DEFER_BRUSH;
         break;
+
+    case BS_DIBPATTERN:
+    {
+        BITMAPINFOHEADER *bi = GlobalLock((HGLOBAL)logbrush.lbHatch);
+        dib_info orig_dib;
+
+        if(!bi) return NULL;
+        if(init_dib_info_from_packed(&orig_dib, bi, LOWORD(logbrush.lbColor)))
+        {
+            copy_dib_color_info(&pdev->brush_dib, &pdev->dib);
+            if(convert_dib(&pdev->brush_dib, &orig_dib))
+            {
+                pdev->brush_rects = pattern_brush;
+                pdev->defer &= ~DEFER_BRUSH;
+            }
+            free_dib_info(&orig_dib, FALSE);
+        }
+        GlobalUnlock((HGLOBAL)logbrush.lbHatch);
+        break;
+    }
+
     default:
         break;
     }
diff --git a/dlls/gdi32/gdi_private.h b/dlls/gdi32/gdi_private.h
index 9cb528c..0f59f48 100644
--- a/dlls/gdi32/gdi_private.h
+++ b/dlls/gdi32/gdi_private.h
@@ -124,6 +124,8 @@ typedef struct dibdrv_physdev
     UINT brush_style;
     INT brush_rop;   /* PatBlt, for example, can override the DC's rop2 */
     DWORD brush_color, brush_and, brush_xor;
+    dib_info brush_dib;
+    void *brush_and_bits, *brush_xor_bits;
     BOOL   (* brush_rects)(struct dibdrv_physdev *pdev, int num, RECT *rects);
 
     /* background */




More information about the wine-cvs mailing list