Bug 502710 - Refactor the widget icon creation code r=jimm

--HG--
extra : rebase_source : 2f145f67bdc7d9f630970786a498fb5a411ad7d0
This commit is contained in:
Rob Arnold 2009-07-28 11:52:40 -07:00
Родитель 25bee23cf5
Коммит 7e7f6f7017
4 изменённых файлов: 219 добавлений и 175 удалений

Просмотреть файл

@ -1869,142 +1869,6 @@ NS_METHOD nsWindow::SetCursor(nsCursor aCursor)
return NS_OK;
}
// Adjust cursor image data
PRUint8* nsWindow::Data32BitTo1Bit(PRUint8* aImageData,
PRUint32 aWidth, PRUint32 aHeight)
{
// We need (aWidth + 7) / 8 bytes plus zero-padding up to a multiple of
// 4 bytes for each row (HBITMAP requirement). Bug 353553.
PRUint32 outBpr = ((aWidth + 31) / 8) & ~3;
// Allocate and clear mask buffer
PRUint8* outData = (PRUint8*)PR_Calloc(outBpr, aHeight);
if (!outData)
return NULL;
PRInt32 *imageRow = (PRInt32*)aImageData;
for (PRUint32 curRow = 0; curRow < aHeight; curRow++) {
PRUint8 *outRow = outData + curRow * outBpr;
PRUint8 mask = 0x80;
for (PRUint32 curCol = 0; curCol < aWidth; curCol++) {
// Use sign bit to test for transparency, as alpha byte is highest byte
if (*imageRow++ < 0)
*outRow |= mask;
mask >>= 1;
if (!mask) {
outRow ++;
mask = 0x80;
}
}
}
return outData;
}
PRBool nsWindow::IsCursorTranslucencySupported()
{
#ifdef WINCE
return PR_FALSE;
#else
static PRBool didCheck = PR_FALSE;
static PRBool isSupported = PR_FALSE;
if (!didCheck) {
didCheck = PR_TRUE;
// Cursor translucency is supported on Windows XP and newer
isSupported = nsWindow::GetWindowsVersion() >= 0x501;
}
return isSupported;
#endif
}
/**
* Convert the given image data to a HBITMAP. If the requested depth is
* 32 bit and the OS supports translucency, a bitmap with an alpha channel
* will be returned.
*
* @param aImageData The image data to convert. Must use the format accepted
* by CreateDIBitmap.
* @param aWidth With of the bitmap, in pixels.
* @param aHeight Height of the image, in pixels.
* @param aDepth Image depth, in bits. Should be one of 1, 24 and 32.
*
* @return The HBITMAP representing the image. Caller should call
* DeleteObject when done with the bitmap.
* On failure, NULL will be returned.
*/
HBITMAP nsWindow::DataToBitmap(PRUint8* aImageData,
PRUint32 aWidth,
PRUint32 aHeight,
PRUint32 aDepth)
{
#ifndef WINCE
HDC dc = ::GetDC(NULL);
if (aDepth == 32 && IsCursorTranslucencySupported()) {
// Alpha channel. We need the new header.
BITMAPV4HEADER head = { 0 };
head.bV4Size = sizeof(head);
head.bV4Width = aWidth;
head.bV4Height = aHeight;
head.bV4Planes = 1;
head.bV4BitCount = aDepth;
head.bV4V4Compression = BI_BITFIELDS;
head.bV4SizeImage = 0; // Uncompressed
head.bV4XPelsPerMeter = 0;
head.bV4YPelsPerMeter = 0;
head.bV4ClrUsed = 0;
head.bV4ClrImportant = 0;
head.bV4RedMask = 0x00FF0000;
head.bV4GreenMask = 0x0000FF00;
head.bV4BlueMask = 0x000000FF;
head.bV4AlphaMask = 0xFF000000;
HBITMAP bmp = ::CreateDIBitmap(dc,
reinterpret_cast<CONST BITMAPINFOHEADER*>(&head),
CBM_INIT,
aImageData,
reinterpret_cast<CONST BITMAPINFO*>(&head),
DIB_RGB_COLORS);
::ReleaseDC(NULL, dc);
return bmp;
}
char reserved_space[sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * 2];
BITMAPINFOHEADER& head = *(BITMAPINFOHEADER*)reserved_space;
head.biSize = sizeof(BITMAPINFOHEADER);
head.biWidth = aWidth;
head.biHeight = aHeight;
head.biPlanes = 1;
head.biBitCount = (WORD)aDepth;
head.biCompression = BI_RGB;
head.biSizeImage = 0; // Uncompressed
head.biXPelsPerMeter = 0;
head.biYPelsPerMeter = 0;
head.biClrUsed = 0;
head.biClrImportant = 0;
BITMAPINFO& bi = *(BITMAPINFO*)reserved_space;
if (aDepth == 1) {
RGBQUAD black = { 0, 0, 0, 0 };
RGBQUAD white = { 255, 255, 255, 0 };
bi.bmiColors[0] = white;
bi.bmiColors[1] = black;
}
HBITMAP bmp = ::CreateDIBitmap(dc, &head, CBM_INIT, aImageData, &bi, DIB_RGB_COLORS);
::ReleaseDC(NULL, dc);
return bmp;
#else
return nsnull;
#endif
}
// Setting the actual cursor
NS_IMETHODIMP nsWindow::SetCursor(imgIContainer* aCursor,
PRUint32 aHotspotX, PRUint32 aHotspotY)
@ -2014,14 +1878,14 @@ NS_IMETHODIMP nsWindow::SetCursor(imgIContainer* aCursor,
return NS_OK;
}
// Get the image data
nsRefPtr<gfxImageSurface> frame;
aCursor->CopyCurrentFrame(getter_AddRefs(frame));
if (!frame)
return NS_ERROR_NOT_AVAILABLE;
PRInt32 width;
PRInt32 height;
PRInt32 width = frame->Width();
PRInt32 height = frame->Height();
nsresult rv;
rv = aCursor->GetWidth(&width);
NS_ENSURE_SUCCESS(rv, rv);
rv = aCursor->GetHeight(&height);
NS_ENSURE_SUCCESS(rv, rv);
// Reject cursors greater than 128 pixels in either direction, to prevent
// spoofing.
@ -2030,30 +1894,9 @@ NS_IMETHODIMP nsWindow::SetCursor(imgIContainer* aCursor,
if (width > 128 || height > 128)
return NS_ERROR_NOT_AVAILABLE;
PRUint8 *data = frame->Data();
HBITMAP bmp = DataToBitmap(data, width, -height, 32);
PRUint8* a1data = Data32BitTo1Bit(data, width, height);
if (!a1data) {
return NS_ERROR_FAILURE;
}
HBITMAP mbmp = DataToBitmap(a1data, width, -height, 1);
PR_Free(a1data);
ICONINFO info = {0};
info.fIcon = FALSE;
info.xHotspot = aHotspotX;
info.yHotspot = aHotspotY;
info.hbmMask = mbmp;
info.hbmColor = bmp;
HCURSOR cursor = ::CreateIconIndirect(&info);
::DeleteObject(mbmp);
::DeleteObject(bmp);
if (cursor == NULL) {
return NS_ERROR_FAILURE;
}
HCURSOR cursor;
rv = nsWindowGfx::CreateIcon(aCursor, PR_TRUE, aHotspotX, aHotspotY, &cursor);
NS_ENSURE_SUCCESS(rv, rv);
mCursor = nsCursor(-1);
::SetCursor(cursor);

Просмотреть файл

@ -374,13 +374,6 @@ private:
protected:
#endif // MOZ_XUL
/**
* Cursor helpers
*/
static PRUint8* Data32BitTo1Bit(PRUint8* aImageData, PRUint32 aWidth, PRUint32 aHeight);
static PRBool IsCursorTranslucencySupported();
static HBITMAP DataToBitmap(PRUint8* aImageData, PRUint32 aWidth, PRUint32 aHeight, PRUint32 aDepth);
/**
* Misc.
*/

Просмотреть файл

@ -63,6 +63,7 @@
#include "gfxContext.h"
#include "nsIRenderingContext.h"
#include "nsIDeviceContext.h"
#include "prmem.h"
#ifndef WINCE
#include "nsUXThemeData.h"
@ -643,6 +644,202 @@ DDRAW_FAILED:
return result;
}
nsresult nsWindowGfx::CreateIcon(imgIContainer *aContainer,
PRBool aIsCursor,
PRUint32 aHotspotX,
PRUint32 aHotspotY,
HICON *aIcon) {
nsresult rv;
PRInt32 maxWidth = GetSystemMetrics(SM_CXICON);
PRInt32 maxHeight = GetSystemMetrics(SM_CYICON);
if (!maxWidth || !maxHeight)
return NS_ERROR_UNEXPECTED;
PRUint32 nFrames;
rv = aContainer->GetNumFrames(&nFrames);
NS_ENSURE_SUCCESS(rv, rv);
if (!nFrames)
return NS_ERROR_INVALID_ARG;
// Get the image data
nsRefPtr<gfxImageSurface> frame;
aContainer->CopyCurrentFrame(getter_AddRefs(frame));
if (!frame)
return NS_ERROR_NOT_AVAILABLE;
PRUint8 *data = frame->Data();
PRInt32 width = frame->Width();
PRInt32 height = frame->Height();
if (width > maxWidth || height > maxHeight)
return NS_ERROR_INVALID_ARG;
HBITMAP bmp = DataToBitmap(data, width, -height, 32);
PRUint8* a1data = Data32BitTo1Bit(data, width, height);
if (!a1data) {
return NS_ERROR_FAILURE;
}
HBITMAP mbmp = DataToBitmap(a1data, width, -height, 1);
PR_Free(a1data);
ICONINFO info = {0};
info.fIcon = !aIsCursor;
info.xHotspot = aHotspotX;
info.yHotspot = aHotspotY;
info.hbmMask = mbmp;
info.hbmColor = bmp;
HCURSOR icon = ::CreateIconIndirect(&info);
::DeleteObject(mbmp);
::DeleteObject(bmp);
if (!icon)
return NS_ERROR_FAILURE;
*aIcon = icon;
return NS_OK;
}
// Adjust cursor image data
PRUint8* nsWindowGfx::Data32BitTo1Bit(PRUint8* aImageData,
PRUint32 aWidth, PRUint32 aHeight)
{
// We need (aWidth + 7) / 8 bytes plus zero-padding up to a multiple of
// 4 bytes for each row (HBITMAP requirement). Bug 353553.
PRUint32 outBpr = ((aWidth + 31) / 8) & ~3;
// Allocate and clear mask buffer
PRUint8* outData = (PRUint8*)PR_Calloc(outBpr, aHeight);
if (!outData)
return NULL;
PRInt32 *imageRow = (PRInt32*)aImageData;
for (PRUint32 curRow = 0; curRow < aHeight; curRow++) {
PRUint8 *outRow = outData + curRow * outBpr;
PRUint8 mask = 0x80;
for (PRUint32 curCol = 0; curCol < aWidth; curCol++) {
// Use sign bit to test for transparency, as alpha byte is highest byte
if (*imageRow++ < 0)
*outRow |= mask;
mask >>= 1;
if (!mask) {
outRow ++;
mask = 0x80;
}
}
}
return outData;
}
PRBool nsWindowGfx::IsCursorTranslucencySupported()
{
#ifdef WINCE
return PR_FALSE;
#else
static PRBool didCheck = PR_FALSE;
static PRBool isSupported = PR_FALSE;
if (!didCheck) {
didCheck = PR_TRUE;
// Cursor translucency is supported on Windows XP and newer
isSupported = nsWindow::GetWindowsVersion() >= 0x501;
}
return isSupported;
#endif
}
/**
* Convert the given image data to a HBITMAP. If the requested depth is
* 32 bit and the OS supports translucency, a bitmap with an alpha channel
* will be returned.
*
* @param aImageData The image data to convert. Must use the format accepted
* by CreateDIBitmap.
* @param aWidth With of the bitmap, in pixels.
* @param aHeight Height of the image, in pixels.
* @param aDepth Image depth, in bits. Should be one of 1, 24 and 32.
*
* @return The HBITMAP representing the image. Caller should call
* DeleteObject when done with the bitmap.
* On failure, NULL will be returned.
*/
HBITMAP nsWindowGfx::DataToBitmap(PRUint8* aImageData,
PRUint32 aWidth,
PRUint32 aHeight,
PRUint32 aDepth)
{
#ifndef WINCE
HDC dc = ::GetDC(NULL);
if (aDepth == 32 && IsCursorTranslucencySupported()) {
// Alpha channel. We need the new header.
BITMAPV4HEADER head = { 0 };
head.bV4Size = sizeof(head);
head.bV4Width = aWidth;
head.bV4Height = aHeight;
head.bV4Planes = 1;
head.bV4BitCount = aDepth;
head.bV4V4Compression = BI_BITFIELDS;
head.bV4SizeImage = 0; // Uncompressed
head.bV4XPelsPerMeter = 0;
head.bV4YPelsPerMeter = 0;
head.bV4ClrUsed = 0;
head.bV4ClrImportant = 0;
head.bV4RedMask = 0x00FF0000;
head.bV4GreenMask = 0x0000FF00;
head.bV4BlueMask = 0x000000FF;
head.bV4AlphaMask = 0xFF000000;
HBITMAP bmp = ::CreateDIBitmap(dc,
reinterpret_cast<CONST BITMAPINFOHEADER*>(&head),
CBM_INIT,
aImageData,
reinterpret_cast<CONST BITMAPINFO*>(&head),
DIB_RGB_COLORS);
::ReleaseDC(NULL, dc);
return bmp;
}
char reserved_space[sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * 2];
BITMAPINFOHEADER& head = *(BITMAPINFOHEADER*)reserved_space;
head.biSize = sizeof(BITMAPINFOHEADER);
head.biWidth = aWidth;
head.biHeight = aHeight;
head.biPlanes = 1;
head.biBitCount = (WORD)aDepth;
head.biCompression = BI_RGB;
head.biSizeImage = 0; // Uncompressed
head.biXPelsPerMeter = 0;
head.biYPelsPerMeter = 0;
head.biClrUsed = 0;
head.biClrImportant = 0;
BITMAPINFO& bi = *(BITMAPINFO*)reserved_space;
if (aDepth == 1) {
RGBQUAD black = { 0, 0, 0, 0 };
RGBQUAD white = { 255, 255, 255, 0 };
bi.bmiColors[0] = white;
bi.bmiColors[1] = black;
}
HBITMAP bmp = ::CreateDIBitmap(dc, &head, CBM_INIT, aImageData, &bi, DIB_RGB_COLORS);
::ReleaseDC(NULL, dc);
return bmp;
#else
return nsnull;
#endif
}
// Windows Mobile Special image/direct draw painting fun
#if defined(CAIRO_HAS_DDRAW_SURFACE)
PRBool nsWindow::OnPaintImageDDraw16()

Просмотреть файл

@ -43,6 +43,7 @@
*/
#include "nsWindow.h"
#include <imgIContainer.h>
// This isn't ideal, we should figure out how to export
// the #defines here; need this to figure out if we have
@ -62,6 +63,16 @@ public:
#if defined(CAIRO_HAS_DDRAW_SURFACE)
static PRBool InitDDraw();
#endif // defined(CAIRO_HAS_DDRAW_SURFACE)
static nsresult CreateIcon(imgIContainer *aContainer, PRBool aIsCursor, PRUint32 aHotspotX, PRUint32 aHotspotY, HICON *aIcon);
private:
/**
* Cursor helpers
*/
static PRUint8* Data32BitTo1Bit(PRUint8* aImageData, PRUint32 aWidth, PRUint32 aHeight);
static PRBool IsCursorTranslucencySupported();
static HBITMAP DataToBitmap(PRUint8* aImageData, PRUint32 aWidth, PRUint32 aHeight, PRUint32 aDepth);
};
#endif // WindowGfx_h__
#endif // WindowGfx_h__