/* fetch the contents of the brush bitmap and cache them in the brush object */ static BOOL store_bitmap_bits( BRUSHOBJ *brush, BITMAPOBJ *bmp ) { const struct gdi_dc_funcs *funcs = get_bitmap_funcs( bmp ); struct gdi_image_bits bits; struct bitblt_coords src; BITMAPINFO *info; if (!(info = HeapAlloc( GetProcessHeap(), 0, FIELD_OFFSET( BITMAPINFO, bmiColors[256] )))) return FALSE; src.visrect.left = src.x = 0; src.visrect.top = src.y = 0; src.visrect.right = src.width = bmp->bitmap.bmWidth; src.visrect.bottom = src.height = bmp->bitmap.bmHeight; if (funcs->pGetImage( NULL, brush->bitmap, info, &bits, &src )) { HeapFree( GetProcessHeap(), 0, info ); return FALSE; } /* release the unneeded space */ HeapReAlloc( GetProcessHeap(), HEAP_REALLOC_IN_PLACE_ONLY, info, get_dib_info_size( info, DIB_RGB_COLORS )); brush->info = info; brush->bits = bits; brush->usage = DIB_RGB_COLORS; return TRUE; }
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->info) { BITMAPOBJ *bmp = GDI_GetObjPtr( brush->bitmap, OBJ_BITMAP ); if (bmp) { store_bitmap_bits( brush, bmp ); GDI_ReleaseObj( brush->bitmap ); } } if (brush->info) { memcpy( info, brush->info, get_dib_info_size( brush->info, brush->usage )); if (info->bmiHeader.biBitCount <= 8 && !info->bmiHeader.biClrUsed) fill_default_color_table( info ); *bits = brush->bits.ptr; *usage = brush->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; HGLOBAL hmem = 0; if (!(ptr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ptr) ))) return 0; ptr->logbrush = *brush; switch (ptr->logbrush.lbStyle) { case BS_SOLID: case BS_HOLLOW: case BS_HATCHED: break; case BS_PATTERN8X8: ptr->logbrush.lbStyle = BS_PATTERN; /* fall through */ case BS_PATTERN: if (!copy_bitmap( ptr, (HBITMAP)ptr->logbrush.lbHatch )) goto error; ptr->logbrush.lbColor = 0; break; case BS_DIBPATTERN: hmem = (HGLOBAL)ptr->logbrush.lbHatch; if (!(ptr->logbrush.lbHatch = (ULONG_PTR)GlobalLock( hmem ))) goto error; /* fall through */ case BS_DIBPATTERNPT: ptr->usage = ptr->logbrush.lbColor; ptr->info = copy_packed_dib( (BITMAPINFO *)ptr->logbrush.lbHatch, ptr->usage ); if (hmem) GlobalUnlock( hmem ); if (!ptr->info) goto error; ptr->bits.ptr = (char *)ptr->info + get_dib_info_size( ptr->info, ptr->usage ); ptr->logbrush.lbStyle = BS_DIBPATTERN; ptr->logbrush.lbColor = 0; break; case BS_DIBPATTERN8X8: case BS_MONOPATTERN: case BS_INDEXED: default: WARN( "invalid brush style %u\n", ptr->logbrush.lbStyle ); goto error; } if ((hbrush = alloc_gdi_handle( &ptr->header, OBJ_BRUSH, &brush_funcs ))) { TRACE("%p\n", hbrush); return hbrush; } error: if (ptr->bitmap) DeleteObject( ptr->bitmap ); HeapFree( GetProcessHeap(), 0, ptr->info ); HeapFree( GetProcessHeap(), 0, ptr ); return 0; }
/*********************************************************************** * macdrv_surface_get_bitmap_info */ static void *macdrv_surface_get_bitmap_info(struct window_surface *window_surface, BITMAPINFO *info) { struct macdrv_window_surface *surface = get_mac_surface(window_surface); memcpy(info, &surface->info, get_dib_info_size(&surface->info, DIB_RGB_COLORS)); return surface->bits; }
INT EMFDRV_StretchDIBits( PHYSDEV dev, INT xDst, INT yDst, INT widthDst, INT heightDst, INT xSrc, INT ySrc, INT widthSrc, INT heightSrc, const void *bits, BITMAPINFO *info, UINT wUsage, DWORD dwRop ) { EMRSTRETCHDIBITS *emr; BOOL ret; UINT bmi_size, emr_size; /* calculate the size of the colour table */ bmi_size = get_dib_info_size(info, wUsage); emr_size = sizeof (EMRSTRETCHDIBITS) + bmi_size + info->bmiHeader.biSizeImage; emr = HeapAlloc(GetProcessHeap(), 0, emr_size ); if (!emr) return 0; /* write a bitmap info header (with colours) to the record */ memcpy( &emr[1], info, bmi_size); /* write bitmap bits to the record */ memcpy ( ( (BYTE *) (&emr[1]) ) + bmi_size, bits, info->bmiHeader.biSizeImage); /* fill in the EMR header at the front of our piece of memory */ emr->emr.iType = EMR_STRETCHDIBITS; emr->emr.nSize = emr_size; emr->xDest = xDst; emr->yDest = yDst; emr->cxDest = widthDst; emr->cyDest = heightDst; emr->dwRop = dwRop; emr->xSrc = xSrc; /* FIXME: only save the piece of the bitmap needed */ emr->ySrc = ySrc; emr->iUsageSrc = wUsage; emr->offBmiSrc = sizeof (EMRSTRETCHDIBITS); emr->cbBmiSrc = bmi_size; emr->offBitsSrc = emr->offBmiSrc + bmi_size; emr->cbBitsSrc = info->bmiHeader.biSizeImage; emr->cxSrc = widthSrc; emr->cySrc = heightSrc; emr->rclBounds.left = xDst; emr->rclBounds.top = yDst; emr->rclBounds.right = xDst + widthDst; emr->rclBounds.bottom = yDst + heightDst; /* save the record we just created */ ret = EMFDRV_WriteRecord( dev, &emr->emr ); if(ret) EMFDRV_UpdateBBox( dev, &emr->rclBounds ); HeapFree(GetProcessHeap(), 0, emr); return ret ? heightSrc : GDI_ERROR; }
static BOOL copy_bitmap( BRUSHOBJ *brush, HBITMAP bitmap ) { BITMAPINFO *info; BITMAPOBJ *bmp = GDI_GetObjPtr( bitmap, OBJ_BITMAP ); if (!bmp) return FALSE; if (!bmp->dib) { if ((brush->bitmap = CreateBitmap( bmp->bitmap.bmWidth, bmp->bitmap.bmHeight, bmp->bitmap.bmPlanes, bmp->bitmap.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->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; } }
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; }
INT EMFDRV_SetDIBitsToDevice( PHYSDEV dev, INT xDst, INT yDst, DWORD width, DWORD height, INT xSrc, INT ySrc, UINT startscan, UINT lines, LPCVOID bits, BITMAPINFO *info, UINT wUsage ) { EMRSETDIBITSTODEVICE* pEMR; DWORD bmiSize = get_dib_info_size(info, wUsage); DWORD size = sizeof(EMRSETDIBITSTODEVICE) + bmiSize + info->bmiHeader.biSizeImage; pEMR = HeapAlloc(GetProcessHeap(), 0, size); if (!pEMR) return 0; pEMR->emr.iType = EMR_SETDIBITSTODEVICE; pEMR->emr.nSize = size; pEMR->rclBounds.left = xDst; pEMR->rclBounds.top = yDst; pEMR->rclBounds.right = xDst + width - 1; pEMR->rclBounds.bottom = yDst + height - 1; pEMR->xDest = xDst; pEMR->yDest = yDst; pEMR->xSrc = xSrc; pEMR->ySrc = ySrc; pEMR->cxSrc = width; pEMR->cySrc = height; pEMR->offBmiSrc = sizeof(EMRSETDIBITSTODEVICE); pEMR->cbBmiSrc = bmiSize; pEMR->offBitsSrc = sizeof(EMRSETDIBITSTODEVICE) + bmiSize; pEMR->cbBitsSrc = info->bmiHeader.biSizeImage; pEMR->iUsageSrc = wUsage; pEMR->iStartScan = startscan; pEMR->cScans = lines; memcpy((BYTE*)pEMR + pEMR->offBmiSrc, info, bmiSize); memcpy((BYTE*)pEMR + pEMR->offBitsSrc, bits, info->bmiHeader.biSizeImage); if (EMFDRV_WriteRecord(dev, (EMR*)pEMR)) EMFDRV_UpdateBBox(dev, &(pEMR->rclBounds)); HeapFree( GetProcessHeap(), 0, pEMR); return lines; }
/*********************************************************************** * EMFDRV_CreateBrushIndirect */ DWORD EMFDRV_CreateBrushIndirect( PHYSDEV dev, HBRUSH hBrush ) { DWORD index = 0; LOGBRUSH logbrush; if (!GetObjectA( hBrush, sizeof(logbrush), &logbrush )) return 0; switch (logbrush.lbStyle) { case BS_SOLID: case BS_HATCHED: case BS_NULL: { EMRCREATEBRUSHINDIRECT emr; emr.emr.iType = EMR_CREATEBRUSHINDIRECT; emr.emr.nSize = sizeof(emr); emr.ihBrush = index = EMFDRV_AddHandle( dev, hBrush ); emr.lb.lbStyle = logbrush.lbStyle; emr.lb.lbColor = logbrush.lbColor; emr.lb.lbHatch = logbrush.lbHatch; if(!EMFDRV_WriteRecord( dev, &emr.emr )) index = 0; } break; case BS_PATTERN: case BS_DIBPATTERN: { EMRCREATEDIBPATTERNBRUSHPT *emr; char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )]; BITMAPINFO *info = (BITMAPINFO *)buffer; DWORD info_size; void *bits; UINT usage; if (!get_brush_bitmap_info( hBrush, info, &bits, &usage )) break; info_size = get_dib_info_size( info, usage ); emr = HeapAlloc( GetProcessHeap(), 0, sizeof(EMRCREATEDIBPATTERNBRUSHPT)+info_size+info->bmiHeader.biSizeImage ); if(!emr) break; if (logbrush.lbStyle == BS_PATTERN && info->bmiHeader.biBitCount == 1) { /* Presumably to reduce the size of the written EMF, MS supports an * undocumented iUsage value of 2, indicating a mono bitmap without the * 8 byte 2 entry black/white palette. Stupidly, they could have saved * over 20 bytes more by also ignoring the BITMAPINFO fields that are * irrelevant/constant for monochrome bitmaps. * FIXME: It may be that the DIB functions themselves accept this value. */ emr->emr.iType = EMR_CREATEMONOBRUSH; usage = DIB_PAL_MONO; /* FIXME: There is an extra DWORD written by native before the BMI. * Not sure what its meant to contain. */ emr->offBmi = sizeof( EMRCREATEDIBPATTERNBRUSHPT ) + sizeof(DWORD); emr->cbBmi = sizeof( BITMAPINFOHEADER ); } else { emr->emr.iType = EMR_CREATEDIBPATTERNBRUSHPT; emr->offBmi = sizeof( EMRCREATEDIBPATTERNBRUSHPT ); emr->cbBmi = info_size; } emr->ihBrush = index = EMFDRV_AddHandle( dev, hBrush ); emr->iUsage = usage; emr->offBits = emr->offBmi + emr->cbBmi; emr->cbBits = info->bmiHeader.biSizeImage; emr->emr.nSize = emr->offBits + emr->cbBits; memcpy( (BYTE *)emr + emr->offBmi, info, emr->cbBmi ); memcpy( (BYTE *)emr + emr->offBits, bits, emr->cbBits ); if(!EMFDRV_WriteRecord( dev, &emr->emr )) index = 0; HeapFree( GetProcessHeap(), 0, emr ); } break; default: FIXME("Unknown style %x\n", logbrush.lbStyle); break; } return index; }
INT16 MFDRV_CreateBrushIndirect(PHYSDEV dev, HBRUSH hBrush ) { DWORD size; METARECORD *mr; LOGBRUSH logbrush; BOOL r; if (!GetObjectA( hBrush, sizeof(logbrush), &logbrush )) return -1; switch(logbrush.lbStyle) { case BS_SOLID: case BS_NULL: case BS_HATCHED: { LOGBRUSH16 lb16; lb16.lbStyle = logbrush.lbStyle; lb16.lbColor = logbrush.lbColor; lb16.lbHatch = logbrush.lbHatch; size = sizeof(METARECORD) + sizeof(LOGBRUSH16) - 2; mr = HeapAlloc( GetProcessHeap(), 0, size ); mr->rdSize = size / 2; mr->rdFunction = META_CREATEBRUSHINDIRECT; memcpy( mr->rdParm, &lb16, sizeof(LOGBRUSH16)); break; } case BS_PATTERN: case BS_DIBPATTERN: { char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )]; BITMAPINFO *dst_info, *src_info = (BITMAPINFO *)buffer; DWORD info_size; char *dst_ptr; void *bits; UINT usage; if (!get_brush_bitmap_info( hBrush, src_info, &bits, &usage )) goto done; info_size = get_dib_info_size( src_info, usage ); size = FIELD_OFFSET( METARECORD, rdParm[2] ) + info_size + src_info->bmiHeader.biSizeImage; if (!(mr = HeapAlloc( GetProcessHeap(), 0, size ))) goto done; mr->rdFunction = META_DIBCREATEPATTERNBRUSH; mr->rdSize = size / 2; mr->rdParm[0] = logbrush.lbStyle; mr->rdParm[1] = usage; dst_info = (BITMAPINFO *)(mr->rdParm + 2); memcpy( dst_info, src_info, info_size ); if (dst_info->bmiHeader.biClrUsed == 1 << dst_info->bmiHeader.biBitCount) dst_info->bmiHeader.biClrUsed = 0; dst_ptr = (char *)dst_info + info_size; /* always return a bottom-up DIB */ if (dst_info->bmiHeader.biHeight < 0) { int i, width_bytes = get_dib_stride( dst_info->bmiHeader.biWidth, dst_info->bmiHeader.biBitCount ); dst_info->bmiHeader.biHeight = -dst_info->bmiHeader.biHeight; dst_ptr += (dst_info->bmiHeader.biHeight - 1) * width_bytes; for (i = 0; i < dst_info->bmiHeader.biHeight; i++, dst_ptr -= width_bytes) memcpy( dst_ptr, (char *)bits + i * width_bytes, width_bytes ); } else memcpy( dst_ptr, bits, src_info->bmiHeader.biSizeImage ); break; } default: FIXME("Unkonwn brush style %x\n", logbrush.lbStyle); return 0; } r = MFDRV_WriteRecord( dev, mr, mr->rdSize * 2); HeapFree(GetProcessHeap(), 0, mr); if( !r ) return -1; done: return MFDRV_AddHandle( dev, hBrush ); }