wined3d: Store user clip planes as 4-component float vectors.
[wine] / dlls / gdi32 / brush.c
index 8c74c0a..cb5a163 100644 (file)
@@ -26,8 +26,6 @@
 #include "windef.h"
 #include "winbase.h"
 #include "wingdi.h"
-#include "wine/wingdi16.h"
-#include "wownt32.h"
 #include "gdi_private.h"
 #include "wine/debug.h"
 
@@ -36,14 +34,15 @@ WINE_DEFAULT_DEBUG_CHANNEL(gdi);
 /* GDI logical brush object */
 typedef struct
 {
-    GDIOBJHDR header;
-    LOGBRUSH  logbrush;
+    GDIOBJHDR             header;
+    LOGBRUSH              logbrush;
+    struct brush_pattern  pattern;
 } BRUSHOBJ;
 
 #define NB_HATCH_STYLES  6
 
 static HGDIOBJ BRUSH_SelectObject( HGDIOBJ handle, HDC hdc );
-static INT BRUSH_GetObject( HGDIOBJ handle, void *obj, INT count, LPVOID buffer );
+static INT BRUSH_GetObject( HGDIOBJ handle, INT count, LPVOID buffer );
 static BOOL BRUSH_DeleteObject( HGDIOBJ handle );
 
 static const struct gdi_obj_funcs brush_funcs =
@@ -55,28 +54,176 @@ static const struct gdi_obj_funcs brush_funcs =
     BRUSH_DeleteObject   /* pDeleteObject */
 };
 
-static HGLOBAL16 dib_copy(const BITMAPINFO *info, UINT coloruse)
+
+/* fetch the contents of the brush bitmap and cache them in the brush pattern */
+void cache_pattern_bits( PHYSDEV physdev, struct brush_pattern *pattern )
 {
-    BITMAPINFO  *newInfo;
-    HGLOBAL16   hmem;
-    INT         size;
-
-    if (info->bmiHeader.biCompression != BI_RGB && info->bmiHeader.biCompression != BI_BITFIELDS)
-        size = info->bmiHeader.biSizeImage;
-    else
-        size = DIB_GetDIBImageBytes(info->bmiHeader.biWidth,
-                                    info->bmiHeader.biHeight,
-                                    info->bmiHeader.biBitCount);
-    size += bitmap_info_size( info, coloruse );
-
-    if (!(hmem = GlobalAlloc16( GMEM_MOVEABLE, size )))
+    struct gdi_image_bits bits;
+    struct bitblt_coords src;
+    BITMAPINFO *info;
+    BITMAPOBJ *bmp;
+
+    if (pattern->info) return;  /* already cached */
+    if (!(bmp = GDI_GetObjPtr( pattern->bitmap, OBJ_BITMAP ))) return;
+
+    /* we don't need to cache if we are selecting into the same type of DC */
+    if (physdev && bmp->funcs == physdev->funcs) goto done;
+
+    if (!(info = HeapAlloc( GetProcessHeap(), 0, FIELD_OFFSET( BITMAPINFO, bmiColors[256] )))) goto done;
+
+    src.visrect.left   = src.x = 0;
+    src.visrect.top    = src.y = 0;
+    src.visrect.right  = src.width = bmp->dib.dsBm.bmWidth;
+    src.visrect.bottom = src.height = bmp->dib.dsBm.bmHeight;
+    if (bmp->funcs->pGetImage( NULL, pattern->bitmap, info, &bits, &src ))
     {
-        return 0;
+        HeapFree( GetProcessHeap(), 0, info );
+        goto done;
     }
-    newInfo = GlobalLock16( hmem );
-    memcpy( newInfo, info, size );
-    GlobalUnlock16( hmem );
-    return hmem;
+
+    /* release the unneeded space */
+    HeapReAlloc( GetProcessHeap(), HEAP_REALLOC_IN_PLACE_ONLY, info,
+                 get_dib_info_size( info, DIB_RGB_COLORS ));
+    pattern->info  = info;
+    pattern->bits  = bits;
+    pattern->usage = DIB_RGB_COLORS;
+
+done:
+    GDI_ReleaseObj( pattern->bitmap );
+}
+
+static BOOL copy_bitmap( struct brush_pattern *brush, HBITMAP bitmap )
+{
+    BITMAPINFO *info;
+    BITMAPOBJ *bmp = GDI_GetObjPtr( bitmap, OBJ_BITMAP );
+
+    if (!bmp) return FALSE;
+
+    if (!is_bitmapobj_dib( bmp ))
+    {
+        if ((brush->bitmap = CreateBitmap( bmp->dib.dsBm.bmWidth, bmp->dib.dsBm.bmHeight,
+                                           bmp->dib.dsBm.bmPlanes, bmp->dib.dsBm.bmBitsPixel, NULL )))
+        {
+            if (bmp->funcs->pCopyBitmap( bitmap, brush->bitmap ))
+            {
+                BITMAPOBJ *copy = GDI_GetObjPtr( brush->bitmap, OBJ_BITMAP );
+                copy->funcs = bmp->funcs;
+                GDI_ReleaseObj( copy );
+            }
+            else
+            {
+                DeleteObject( brush->bitmap );
+                brush->bitmap = 0;
+            }
+        }
+        GDI_ReleaseObj( bitmap );
+        return brush->bitmap != 0;
+    }
+
+    info = HeapAlloc( GetProcessHeap(), 0,
+                      get_dib_info_size( (BITMAPINFO *)&bmp->dib.dsBmih, DIB_RGB_COLORS ));
+    if (!info) goto done;
+    info->bmiHeader = bmp->dib.dsBmih;
+    if (info->bmiHeader.biCompression == BI_BITFIELDS)
+        memcpy( &info->bmiHeader + 1, bmp->dib.dsBitfields, sizeof(bmp->dib.dsBitfields) );
+    else if (info->bmiHeader.biClrUsed)
+        memcpy( &info->bmiHeader + 1, bmp->color_table, info->bmiHeader.biClrUsed * sizeof(RGBQUAD) );
+    if (!(brush->bits.ptr = HeapAlloc( GetProcessHeap(), 0, info->bmiHeader.biSizeImage )))
+    {
+        HeapFree( GetProcessHeap(), 0, info );
+        goto done;
+    }
+    memcpy( brush->bits.ptr, bmp->dib.dsBm.bmBits, info->bmiHeader.biSizeImage );
+    brush->bits.is_copy = TRUE;
+    brush->bits.free = free_heap_bits;
+    brush->info = info;
+    brush->usage = DIB_RGB_COLORS;
+
+done:
+    GDI_ReleaseObj( bitmap );
+    return brush->info != NULL;
+}
+
+BOOL store_brush_pattern( LOGBRUSH *brush, struct brush_pattern *pattern )
+{
+    HGLOBAL hmem = 0;
+
+    pattern->bitmap = 0;
+    pattern->info = NULL;
+    pattern->bits.free = NULL;
+
+    switch (brush->lbStyle)
+    {
+    case BS_SOLID:
+    case BS_HOLLOW:
+        return TRUE;
+
+    case BS_HATCHED:
+        if (brush->lbHatch > HS_DIAGCROSS)
+        {
+            if (brush->lbHatch >= HS_API_MAX) return FALSE;
+            brush->lbStyle = BS_SOLID;
+            brush->lbHatch = 0;
+        }
+        return TRUE;
+
+    case BS_PATTERN8X8:
+        brush->lbStyle = BS_PATTERN;
+        /* fall through */
+    case BS_PATTERN:
+        brush->lbColor = 0;
+        return copy_bitmap( pattern, (HBITMAP)brush->lbHatch );
+
+    case BS_DIBPATTERN:
+        hmem = (HGLOBAL)brush->lbHatch;
+        if (!(brush->lbHatch = (ULONG_PTR)GlobalLock( hmem ))) return FALSE;
+        /* fall through */
+    case BS_DIBPATTERNPT:
+        pattern->usage = brush->lbColor;
+        pattern->info = copy_packed_dib( (BITMAPINFO *)brush->lbHatch, pattern->usage );
+        if (hmem) GlobalUnlock( hmem );
+        if (!pattern->info) return FALSE;
+        pattern->bits.ptr = (char *)pattern->info + get_dib_info_size( pattern->info, pattern->usage );
+        brush->lbStyle = BS_DIBPATTERN;
+        brush->lbColor = 0;
+        return TRUE;
+
+    case BS_DIBPATTERN8X8:
+    case BS_MONOPATTERN:
+    case BS_INDEXED:
+    default:
+        WARN( "invalid brush style %u\n", brush->lbStyle );
+        return FALSE;
+    }
+}
+
+void free_brush_pattern( struct brush_pattern *pattern )
+{
+    if (pattern->bits.free) pattern->bits.free( &pattern->bits );
+    if (pattern->bitmap) DeleteObject( pattern->bitmap );
+    HeapFree( GetProcessHeap(), 0, pattern->info );
+}
+
+BOOL get_brush_bitmap_info( HBRUSH handle, BITMAPINFO *info, void **bits, UINT *usage )
+{
+    BRUSHOBJ *brush;
+    BOOL ret = FALSE;
+
+    if (!(brush = GDI_GetObjPtr( handle, OBJ_BRUSH ))) return FALSE;
+
+    if (!brush->pattern.info) cache_pattern_bits( NULL, &brush->pattern );
+
+    if (brush->pattern.info)
+    {
+        memcpy( info, brush->pattern.info, get_dib_info_size( brush->pattern.info, brush->pattern.usage ));
+        if (info->bmiHeader.biBitCount <= 8 && !info->bmiHeader.biClrUsed)
+            fill_default_color_table( info );
+        *bits = brush->pattern.bits.ptr;
+        *usage = brush->pattern.usage;
+        ret = TRUE;
+    }
+    GDI_ReleaseObj( handle );
+    return ret;
 }
 
 
@@ -104,54 +251,19 @@ HBRUSH WINAPI CreateBrushIndirect( const LOGBRUSH * brush )
     BRUSHOBJ * ptr;
     HBRUSH hbrush;
 
-    if (!(ptr = GDI_AllocObject( sizeof(BRUSHOBJ), BRUSH_MAGIC,
-                                (HGDIOBJ *)&hbrush, &brush_funcs ))) return 0;
-    ptr->logbrush.lbStyle = brush->lbStyle;
-    ptr->logbrush.lbColor = brush->lbColor;
-    ptr->logbrush.lbHatch = brush->lbHatch;
-
-    switch (ptr->logbrush.lbStyle)
-    {
-    case BS_PATTERN8X8:
-        ptr->logbrush.lbStyle = BS_PATTERN;
-        /* fall through */
-    case BS_PATTERN:
-        ptr->logbrush.lbHatch = (ULONG_PTR)BITMAP_CopyBitmap( (HBITMAP) ptr->logbrush.lbHatch );
-        if (!ptr->logbrush.lbHatch) goto error;
-        break;
-
-    case BS_DIBPATTERNPT:
-        ptr->logbrush.lbStyle = BS_DIBPATTERN;
-        ptr->logbrush.lbHatch = (ULONG_PTR)dib_copy( (BITMAPINFO *) ptr->logbrush.lbHatch,
-                                                     ptr->logbrush.lbColor);
-        if (!ptr->logbrush.lbHatch) goto error;
-        break;
+    if (!(ptr = HeapAlloc( GetProcessHeap(), 0, sizeof(*ptr) ))) return 0;
 
-    case BS_DIBPATTERN8X8:
-    case BS_DIBPATTERN:
-       {
-            BITMAPINFO* bmi;
-            HGLOBAL h = (HGLOBAL)ptr->logbrush.lbHatch;
-
-            ptr->logbrush.lbStyle = BS_DIBPATTERN;
-            if (!(bmi = GlobalLock( h ))) goto error;
-            ptr->logbrush.lbHatch = dib_copy( bmi, ptr->logbrush.lbColor);
-            GlobalUnlock( h );
-            if (!ptr->logbrush.lbHatch) goto error;
-            break;
-       }
+    ptr->logbrush = *brush;
 
-    default:
-        if(ptr->logbrush.lbStyle > BS_MONOPATTERN) goto error;
-        break;
+    if (store_brush_pattern( &ptr->logbrush, &ptr->pattern ) &&
+        (hbrush = alloc_gdi_handle( &ptr->header, OBJ_BRUSH, &brush_funcs )))
+    {
+        TRACE("%p\n", hbrush);
+        return hbrush;
     }
 
-    GDI_ReleaseObj( hbrush );
-    TRACE("%p\n", hbrush);
-    return hbrush;
-
- error:
-    GDI_FreeObject( hbrush, ptr );
+    free_brush_pattern( &ptr->pattern );
+    HeapFree( GetProcessHeap(), 0, ptr );
     return 0;
 }
 
@@ -324,9 +436,9 @@ HBRUSH WINAPI CreateSolidBrush( COLORREF color )
  * Set the brush origin for a device context.
  *
  * PARAMS
- *  hdc    [I] Device context to set the brush origin for 
+ *  hdc    [I] Device context to set the brush origin for
  *  x      [I] New x origin
- *  y      [I] Ney y origin
+ *  y      [I] New y origin
  *  oldorg [O] If non NULL, destination for previously set brush origin.
  *
  * RETURNS
@@ -378,15 +490,21 @@ static HGDIOBJ BRUSH_SelectObject( HGDIOBJ handle, HDC hdc )
         return 0;
     }
 
-    if ((brush = GDI_GetObjPtr( handle, BRUSH_MAGIC )))
+    if ((brush = GDI_GetObjPtr( handle, OBJ_BRUSH )))
     {
-        if (brush->logbrush.lbStyle == BS_PATTERN)
-            BITMAP_SetOwnerDC( (HBITMAP)brush->logbrush.lbHatch, dc );
+        PHYSDEV physdev = GET_DC_PHYSDEV( dc, pSelectBrush );
+        struct brush_pattern *pattern = &brush->pattern;
+
+        if (!pattern->info)
+        {
+            if (pattern->bitmap) cache_pattern_bits( physdev, pattern );
+            else pattern = NULL;
+        }
 
         GDI_inc_ref_count( handle );
         GDI_ReleaseObj( handle );
 
-        if (dc->funcs->pSelectBrush && !dc->funcs->pSelectBrush( dc->physDev, handle ))
+        if (!physdev->funcs->pSelectBrush( physdev, handle, pattern ))
         {
             GDI_dec_ref_count( handle );
         }
@@ -407,70 +525,28 @@ static HGDIOBJ BRUSH_SelectObject( HGDIOBJ handle, HDC hdc )
  */
 static BOOL BRUSH_DeleteObject( HGDIOBJ handle )
 {
-    BRUSHOBJ *brush = GDI_GetObjPtr( handle, BRUSH_MAGIC );
+    BRUSHOBJ *brush = free_gdi_handle( handle );
 
     if (!brush) return FALSE;
-    switch(brush->logbrush.lbStyle)
-    {
-      case BS_PATTERN:
-         DeleteObject( (HGDIOBJ)brush->logbrush.lbHatch );
-         break;
-      case BS_DIBPATTERN:
-         GlobalFree16( (HGLOBAL16)brush->logbrush.lbHatch );
-         break;
-    }
-    return GDI_FreeObject( handle, brush );
+    free_brush_pattern( &brush->pattern );
+    return HeapFree( GetProcessHeap(), 0, brush );
 }
 
 
 /***********************************************************************
  *           BRUSH_GetObject
  */
-static INT BRUSH_GetObject( HGDIOBJ handle, void *obj, INT count, LPVOID buffer )
-{
-    BRUSHOBJ *brush = obj;
-
-    if( !buffer )
-        return sizeof(brush->logbrush);
-
-    if (count > sizeof(brush->logbrush)) count = sizeof(brush->logbrush);
-    memcpy( buffer, &brush->logbrush, count );
-    return count;
-}
-
-
-/***********************************************************************
- *           SetSolidBrush   (GDI.604)
- *
- * Change the color of a solid brush.
- *
- * PARAMS
- *  hBrush   [I] Brush to change the color of
- *  newColor [I] New color for hBrush
- *
- * RETURNS
- *  Success: TRUE. The color of hBrush is set to newColor.
- *  Failure: FALSE.
- *
- * FIXME
- *  This function is undocumented and untested. The implementation may
- *  not be correct.
- */
-BOOL16 WINAPI SetSolidBrush16(HBRUSH16 hBrush, COLORREF newColor )
+static INT BRUSH_GetObject( HGDIOBJ handle, INT count, LPVOID buffer )
 {
-    BRUSHOBJ * brushPtr;
-    BOOL16 res = FALSE;
-
-    TRACE("(hBrush %04x, newColor %08x)\n", hBrush, newColor);
-    if (!(brushPtr = GDI_GetObjPtr( HBRUSH_32(hBrush), BRUSH_MAGIC )))
-       return FALSE;
+    BRUSHOBJ *brush = GDI_GetObjPtr( handle, OBJ_BRUSH );
 
-    if (brushPtr->logbrush.lbStyle == BS_SOLID)
+    if (!brush) return 0;
+    if (buffer)
     {
-        brushPtr->logbrush.lbColor = newColor;
-       res = TRUE;
+        if (count > sizeof(brush->logbrush)) count = sizeof(brush->logbrush);
+        memcpy( buffer, &brush->logbrush, count );
     }
-
-     GDI_ReleaseObj( HBRUSH_32(hBrush) );
-     return res;
+    else count = sizeof(brush->logbrush);
+    GDI_ReleaseObj( handle );
+    return count;
 }