| /* |
| * GDI brush objects |
| * |
| * Copyright 1993, 1994 Alexandre Julliard |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation; either |
| * version 2.1 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this library; if not, write to the Free Software |
| * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA |
| */ |
| |
| #include "config.h" |
| |
| #include <stdarg.h> |
| #include <string.h> |
| |
| #include "windef.h" |
| #include "winbase.h" |
| #include "wingdi.h" |
| #include "gdi_private.h" |
| #include "wine/debug.h" |
| |
| WINE_DEFAULT_DEBUG_CHANNEL(gdi); |
| |
| /* GDI logical brush object */ |
| typedef struct |
| { |
| 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, INT count, LPVOID buffer ); |
| static BOOL BRUSH_DeleteObject( HGDIOBJ handle ); |
| |
| static const struct gdi_obj_funcs brush_funcs = |
| { |
| BRUSH_SelectObject, /* pSelectObject */ |
| BRUSH_GetObject, /* pGetObjectA */ |
| BRUSH_GetObject, /* pGetObjectW */ |
| NULL, /* pUnrealizeObject */ |
| BRUSH_DeleteObject /* pDeleteObject */ |
| }; |
| |
| |
| static BOOL copy_bitmap( struct brush_pattern *brush, HBITMAP bitmap ) |
| { |
| char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256])]; |
| BITMAPINFO *info = (BITMAPINFO *)buffer; |
| struct gdi_image_bits bits; |
| struct bitblt_coords src; |
| BITMAPOBJ *bmp = GDI_GetObjPtr( bitmap, OBJ_BITMAP ); |
| |
| if (!bmp) return FALSE; |
| |
| 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 (get_image_from_bitmap( bmp, info, &bits, &src )) goto done; |
| |
| brush->bits = bits; |
| if (!bits.free) |
| { |
| if (!(brush->bits.ptr = HeapAlloc( GetProcessHeap(), 0, info->bmiHeader.biSizeImage ))) goto done; |
| memcpy( brush->bits.ptr, bits.ptr, info->bmiHeader.biSizeImage ); |
| brush->bits.free = free_heap_bits; |
| } |
| |
| if (!(brush->info = HeapAlloc( GetProcessHeap(), 0, get_dib_info_size( info, DIB_RGB_COLORS )))) |
| { |
| if (brush->bits.free) brush->bits.free( &brush->bits ); |
| goto done; |
| } |
| memcpy( brush->info, info, get_dib_info_size( info, DIB_RGB_COLORS )); |
| brush->bits.is_copy = FALSE; /* the bits can't be modified */ |
| 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->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 ); |
| 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) |
| { |
| 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; |
| } |
| |
| |
| /*********************************************************************** |
| * CreateBrushIndirect (GDI32.@) |
| * |
| * Create a logical brush with a given style, color or pattern. |
| * |
| * PARAMS |
| * brush [I] Pointer to a LOGBRUSH structure describing the desired brush. |
| * |
| * RETURNS |
| * A handle to the created brush, or a NULL handle if the brush cannot be |
| * created. |
| * |
| * NOTES |
| * - The brush returned should be freed by the caller using DeleteObject() |
| * when it is no longer required. |
| * - Windows 95 and earlier cannot create brushes from bitmaps or DIBs larger |
| * than 8x8 pixels. If a larger bitmap is given, only a portion of the bitmap |
| * is used. |
| */ |
| HBRUSH WINAPI CreateBrushIndirect( const LOGBRUSH * brush ) |
| { |
| BRUSHOBJ * ptr; |
| HBRUSH hbrush; |
| |
| if (!(ptr = HeapAlloc( GetProcessHeap(), 0, sizeof(*ptr) ))) return 0; |
| |
| ptr->logbrush = *brush; |
| |
| if (store_brush_pattern( &ptr->logbrush, &ptr->pattern ) && |
| (hbrush = alloc_gdi_handle( ptr, OBJ_BRUSH, &brush_funcs ))) |
| { |
| TRACE("%p\n", hbrush); |
| return hbrush; |
| } |
| |
| free_brush_pattern( &ptr->pattern ); |
| HeapFree( GetProcessHeap(), 0, ptr ); |
| return 0; |
| } |
| |
| |
| /*********************************************************************** |
| * CreateHatchBrush (GDI32.@) |
| * |
| * Create a logical brush with a hatched pattern. |
| * |
| * PARAMS |
| * style [I] Direction of lines for the hatch pattern (HS_* values from "wingdi.h") |
| * color [I] Colour of the hatched pattern |
| * |
| * RETURNS |
| * A handle to the created brush, or a NULL handle if the brush cannot |
| * be created. |
| * |
| * NOTES |
| * - This function uses CreateBrushIndirect() to create the brush. |
| * - The brush returned should be freed by the caller using DeleteObject() |
| * when it is no longer required. |
| */ |
| HBRUSH WINAPI CreateHatchBrush( INT style, COLORREF color ) |
| { |
| LOGBRUSH logbrush; |
| |
| TRACE("%d %06x\n", style, color ); |
| |
| logbrush.lbStyle = BS_HATCHED; |
| logbrush.lbColor = color; |
| logbrush.lbHatch = style; |
| |
| return CreateBrushIndirect( &logbrush ); |
| } |
| |
| |
| /*********************************************************************** |
| * CreatePatternBrush (GDI32.@) |
| * |
| * Create a logical brush with a pattern from a bitmap. |
| * |
| * PARAMS |
| * hbitmap [I] Bitmap containing pattern for the brush |
| * |
| * RETURNS |
| * A handle to the created brush, or a NULL handle if the brush cannot |
| * be created. |
| * |
| * NOTES |
| * - This function uses CreateBrushIndirect() to create the brush. |
| * - The brush returned should be freed by the caller using DeleteObject() |
| * when it is no longer required. |
| */ |
| HBRUSH WINAPI CreatePatternBrush( HBITMAP hbitmap ) |
| { |
| LOGBRUSH logbrush = { BS_PATTERN, 0, 0 }; |
| TRACE("%p\n", hbitmap ); |
| |
| logbrush.lbHatch = (ULONG_PTR)hbitmap; |
| return CreateBrushIndirect( &logbrush ); |
| } |
| |
| |
| /*********************************************************************** |
| * CreateDIBPatternBrush (GDI32.@) |
| * |
| * Create a logical brush with a pattern from a DIB. |
| * |
| * PARAMS |
| * hbitmap [I] Global object containing BITMAPINFO structure for the pattern |
| * coloruse [I] Specifies color format, if provided |
| * |
| * RETURNS |
| * A handle to the created brush, or a NULL handle if the brush cannot |
| * be created. |
| * |
| * NOTES |
| * - This function uses CreateBrushIndirect() to create the brush. |
| * - The brush returned should be freed by the caller using DeleteObject() |
| * when it is no longer required. |
| * - This function is for compatibility only. CreateDIBPatternBrushPt() should |
| * be used instead. |
| */ |
| HBRUSH WINAPI CreateDIBPatternBrush( HGLOBAL hbitmap, UINT coloruse ) |
| { |
| LOGBRUSH logbrush; |
| |
| TRACE("%p\n", hbitmap ); |
| |
| logbrush.lbStyle = BS_DIBPATTERN; |
| logbrush.lbColor = coloruse; |
| |
| logbrush.lbHatch = (ULONG_PTR)hbitmap; |
| |
| return CreateBrushIndirect( &logbrush ); |
| } |
| |
| |
| /*********************************************************************** |
| * CreateDIBPatternBrushPt (GDI32.@) |
| * |
| * Create a logical brush with a pattern from a DIB. |
| * |
| * PARAMS |
| * data [I] Pointer to a BITMAPINFO structure and image data for the pattern |
| * coloruse [I] Specifies color format, if provided |
| * |
| * RETURNS |
| * A handle to the created brush, or a NULL handle if the brush cannot |
| * be created. |
| * |
| * NOTES |
| * - This function uses CreateBrushIndirect() to create the brush. |
| * - The brush returned should be freed by the caller using DeleteObject() |
| * when it is no longer required. |
| */ |
| HBRUSH WINAPI CreateDIBPatternBrushPt( const void* data, UINT coloruse ) |
| { |
| const BITMAPINFO *info=data; |
| LOGBRUSH logbrush; |
| |
| if (!data) |
| return NULL; |
| |
| TRACE("%p %dx%d %dbpp\n", info, info->bmiHeader.biWidth, |
| info->bmiHeader.biHeight, info->bmiHeader.biBitCount); |
| |
| logbrush.lbStyle = BS_DIBPATTERNPT; |
| logbrush.lbColor = coloruse; |
| logbrush.lbHatch = (ULONG_PTR)data; |
| |
| return CreateBrushIndirect( &logbrush ); |
| } |
| |
| |
| /*********************************************************************** |
| * CreateSolidBrush (GDI32.@) |
| * |
| * Create a logical brush consisting of a single colour. |
| * |
| * PARAMS |
| * color [I] Colour to make the solid brush |
| * |
| * RETURNS |
| * A handle to the newly created brush, or a NULL handle if the brush cannot |
| * be created. |
| * |
| * NOTES |
| * - This function uses CreateBrushIndirect() to create the brush. |
| * - The brush returned should be freed by the caller using DeleteObject() |
| * when it is no longer required. |
| */ |
| HBRUSH WINAPI CreateSolidBrush( COLORREF color ) |
| { |
| LOGBRUSH logbrush; |
| |
| TRACE("%06x\n", color ); |
| |
| logbrush.lbStyle = BS_SOLID; |
| logbrush.lbColor = color; |
| logbrush.lbHatch = 0; |
| |
| return CreateBrushIndirect( &logbrush ); |
| } |
| |
| |
| /*********************************************************************** |
| * SetBrushOrgEx (GDI32.@) |
| * |
| * Set the brush origin for a device context. |
| * |
| * PARAMS |
| * hdc [I] Device context to set the brush origin for |
| * x [I] New x origin |
| * y [I] New y origin |
| * oldorg [O] If non NULL, destination for previously set brush origin. |
| * |
| * RETURNS |
| * Success: TRUE. The origin is set to (x,y), and oldorg is updated if given. |
| */ |
| BOOL WINAPI SetBrushOrgEx( HDC hdc, INT x, INT y, LPPOINT oldorg ) |
| { |
| DC *dc = get_dc_ptr( hdc ); |
| |
| if (!dc) return FALSE; |
| if (oldorg) |
| { |
| oldorg->x = dc->brushOrgX; |
| oldorg->y = dc->brushOrgY; |
| } |
| dc->brushOrgX = x; |
| dc->brushOrgY = y; |
| release_dc_ptr( dc ); |
| return TRUE; |
| } |
| |
| /*********************************************************************** |
| * FixBrushOrgEx (GDI32.@) |
| * |
| * See SetBrushOrgEx. |
| * |
| * NOTES |
| * This function is no longer documented by MSDN, but in Win95 GDI32 it |
| * is the same as SetBrushOrgEx(). |
| */ |
| BOOL WINAPI FixBrushOrgEx( HDC hdc, INT x, INT y, LPPOINT oldorg ) |
| { |
| return SetBrushOrgEx(hdc,x,y,oldorg); |
| } |
| |
| |
| /*********************************************************************** |
| * BRUSH_SelectObject |
| */ |
| static HGDIOBJ BRUSH_SelectObject( HGDIOBJ handle, HDC hdc ) |
| { |
| BRUSHOBJ *brush; |
| HGDIOBJ ret = 0; |
| DC *dc = get_dc_ptr( hdc ); |
| |
| if (!dc) |
| { |
| SetLastError( ERROR_INVALID_HANDLE ); |
| return 0; |
| } |
| |
| if ((brush = GDI_GetObjPtr( handle, OBJ_BRUSH ))) |
| { |
| PHYSDEV physdev = GET_DC_PHYSDEV( dc, pSelectBrush ); |
| struct brush_pattern *pattern = &brush->pattern; |
| |
| if (!pattern->info) pattern = NULL; |
| |
| GDI_inc_ref_count( handle ); |
| GDI_ReleaseObj( handle ); |
| |
| if (!physdev->funcs->pSelectBrush( physdev, handle, pattern )) |
| { |
| GDI_dec_ref_count( handle ); |
| } |
| else |
| { |
| ret = dc->hBrush; |
| dc->hBrush = handle; |
| GDI_dec_ref_count( ret ); |
| } |
| } |
| release_dc_ptr( dc ); |
| return ret; |
| } |
| |
| |
| /*********************************************************************** |
| * BRUSH_DeleteObject |
| */ |
| static BOOL BRUSH_DeleteObject( HGDIOBJ handle ) |
| { |
| BRUSHOBJ *brush = free_gdi_handle( handle ); |
| |
| if (!brush) return FALSE; |
| free_brush_pattern( &brush->pattern ); |
| return HeapFree( GetProcessHeap(), 0, brush ); |
| } |
| |
| |
| /*********************************************************************** |
| * BRUSH_GetObject |
| */ |
| static INT BRUSH_GetObject( HGDIOBJ handle, INT count, LPVOID buffer ) |
| { |
| BRUSHOBJ *brush = GDI_GetObjPtr( handle, OBJ_BRUSH ); |
| |
| if (!brush) return 0; |
| if (buffer) |
| { |
| if (count > sizeof(brush->logbrush)) count = sizeof(brush->logbrush); |
| memcpy( buffer, &brush->logbrush, count ); |
| } |
| else count = sizeof(brush->logbrush); |
| GDI_ReleaseObj( handle ); |
| return count; |
| } |