Bug 38447 implement imgIContainer* version of SetCursor on windows

r=ere sr=roc
This commit is contained in:
cbiesinger%web.de 2005-03-15 22:13:12 +00:00
Родитель 9ba5078538
Коммит 75bbd70202
3 изменённых файлов: 320 добавлений и 3 удалений

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

@ -66,6 +66,7 @@ REQUIRES = xpcom \
layout \
xuldoc \
view \
imglib2 \
$(NULL)
CPPSRCS = \

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

@ -1,4 +1,5 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sts=2 sw=2 et cin: */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
@ -31,6 +32,7 @@
* Makoto Kato <m_kato@ga2.so-net.ne.jp>
* Masayuki Nakano <masayuki@d-toybox.com>
* Dainis Jonitis <Dainis_Jonitis@swh-t.lv>
* Christian Biesinger <cbiesinger@web.de>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
@ -70,6 +72,10 @@
#include "nsColor.h"
#include "nsTransform2D.h"
#include "nsIEventQueue.h"
#include "imgIContainer.h"
#include "gfxIImageFrame.h"
#include "nsIProperties.h"
#include "nsISupportsPrimitives.h"
#include "nsNativeCharsetUtils.h"
#include <windows.h>
@ -127,7 +133,7 @@
#include "prprf.h"
#include "prmem.h"
static const char *kMozHeapDumpMessageString = "MOZ_HeapDump";
static const char kMozHeapDumpMessageString[] = "MOZ_HeapDump";
#define kWindowPositionSlop 20
@ -171,6 +177,24 @@ static inline PRBool IsAlphaTranslucencySupported() { return pUpdateLayeredWindo
#endif
static PRBool IsCursorTranslucencySupported() {
static didCheck = PR_FALSE;
static isSupported = PR_FALSE;
if (!didCheck) {
didCheck = PR_TRUE;
// Cursor translucency is supported on Windows XP and newer
OSVERSIONINFO osversion;
memset(&osversion, 0, sizeof(OSVERSIONINFO));
osversion.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
if (GetVersionEx(&osversion))
isSupported = osversion.dwMajorVersion > 5 || // Newer Windows versions
osversion.dwMajorVersion == 5 &&
osversion.dwMinorVersion >= 1; // WinXP, Server 2003
}
return isSupported;
}
// Pick some random timer ID. Is there a better way?
#define NS_FLASH_TIMER_ID 0x011231984
@ -2588,7 +2612,7 @@ NS_METHOD nsWindow::SetCursor(nsCursor aCursor)
break;
default:
NS_ASSERTION(0, "Invalid cursor type");
NS_ERROR("Invalid cursor type");
break;
}
@ -2600,6 +2624,256 @@ NS_METHOD nsWindow::SetCursor(nsCursor aCursor)
return NS_OK;
}
// static
PRUint8* nsWindow::DataToAData(PRUint8* aImageData, PRUint32 aImageBytesPerRow,
PRUint8* aAlphaData, PRUint32 aAlphaBytesPerRow,
PRUint32 aWidth, PRUint32 aHeight)
{
// We will have 32 bpp, so bytes per row will be 4 * w
PRUint32 outBpr = aWidth * 4;
// Avoid overflows
if (aWidth > 0xfff || aHeight > 0xfff)
return NULL;
PRUint8* outData = new PRUint8[outBpr * aHeight];
if (!outData)
return NULL;
PRUint8 *outRow = outData,
*imageRow = aImageData,
*alphaRow = aAlphaData;
for (PRUint32 curRow = 0; curRow < aHeight; curRow++) {
PRUint8 *irow = imageRow, *arow = alphaRow;
for (PRUint32 curCol = 0; curCol < aWidth; curCol++) {
*outRow++ = *imageRow++; // B
*outRow++ = *imageRow++; // G
*outRow++ = *imageRow++; // R
*outRow++ = *alphaRow++; // A
}
imageRow = irow + aImageBytesPerRow;
alphaRow = arow + aAlphaBytesPerRow;
}
return outData;
}
// static
HBITMAP nsWindow::DataToBitmap(PRUint8* aImageData,
PRUint32 aWidth,
PRUint32 aHeight,
PRUint32 aDepth)
{
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,
NS_REINTERPRET_CAST(CONST BITMAPINFOHEADER*, &head),
CBM_INIT,
aImageData,
NS_REINTERPRET_CAST(CONST BITMAPINFO*, &head),
DIB_RGB_COLORS);
::ReleaseDC(NULL, dc);
return bmp;
}
BITMAPINFOHEADER head = { 0 };
head.biSize = sizeof(head);
head.biWidth = aWidth;
head.biHeight = aHeight;
head.biPlanes = 1;
head.biBitCount = aDepth;
head.biCompression = BI_RGB;
head.biSizeImage = 0; // Uncompressed
head.biXPelsPerMeter = 0;
head.biYPelsPerMeter = 0;
head.biClrUsed = (aDepth == 1) ? 2 : 0;
head.biClrImportant = 0;
char reserved_space[sizeof(BITMAPINFO) + sizeof(RGBQUAD) * 256];
BITMAPINFO& bi = *(BITMAPINFO*)reserved_space;
bi.bmiHeader = head;
if (aDepth == 1) {
RGBQUAD black = { 0, 0, 0, 0 };
RGBQUAD white = { 255, 255, 255, 0 };
bi.bmiColors[0] = white;
bi.bmiColors[1] = black;
} else {
for (int i = 0; i < 256; i++) {
RGBQUAD cur = { i, i, i, 0 };
bi.bmiColors[255 - i] = cur;
}
}
HBITMAP bmp = ::CreateDIBitmap(dc, &head, CBM_INIT, aImageData, &bi, DIB_RGB_COLORS);
::ReleaseDC(NULL, dc);
return bmp;
}
// static
HBITMAP nsWindow::CreateOpaqueAlphaChannel(PRUint32 aWidth, PRUint32 aHeight)
{
// Make up an opaque alpha channel
PRUint32 abpr = ((aWidth / 8) + 3) & ~3;
PRUint8* opaque = (PRUint8*)malloc(abpr * aHeight);
if (!opaque)
return NULL;
memset(opaque, 0xff, abpr * aHeight);
HBITMAP hAlpha = DataToBitmap(opaque, aWidth, aHeight, 1);
free(opaque);
return hAlpha;
}
NS_IMETHODIMP nsWindow::SetCursor(imgIContainer* aCursor)
{
// Get the image data
nsCOMPtr<gfxIImageFrame> frame;
aCursor->GetFrameAt(0, getter_AddRefs(frame));
if (!frame)
return NS_ERROR_NOT_AVAILABLE;
PRInt32 width, height;
frame->GetWidth(&width);
frame->GetHeight(&height);
PRUint32 hotspotX = 0, hotspotY = 0;
nsCOMPtr<nsIProperties> props(do_QueryInterface(aCursor));
if (props) {
nsCOMPtr<nsISupportsPRUint32> hotspotXWrap, hotspotYWrap;
props->Get("hotspotX", NS_GET_IID(nsISupportsPRUint32), getter_AddRefs(hotspotXWrap));
props->Get("hotspotY", NS_GET_IID(nsISupportsPRUint32), getter_AddRefs(hotspotYWrap));
if (hotspotXWrap)
hotspotXWrap->GetData(&hotspotX);
if (hotspotYWrap)
hotspotYWrap->GetData(&hotspotY);
}
gfx_format format;
nsresult rv = frame->GetFormat(&format);
if (NS_FAILED(rv))
return rv;
if (format != gfxIFormats::BGR_A1 && format != gfxIFormats::BGR_A8 &&
format != gfxIFormats::BGR)
return NS_ERROR_UNEXPECTED;
PRUint32 bpr;
rv = frame->GetImageBytesPerRow(&bpr);
if (NS_FAILED(rv))
return rv;
frame->LockImageData();
PRUint32 dataLen;
PRUint8* data;
rv = frame->GetImageData(&data, &dataLen);
if (NS_FAILED(rv)) {
frame->UnlockImageData();
return rv;
}
HBITMAP hBMP = NULL;
if (format != gfxIFormats::BGR_A8) {
hBMP = DataToBitmap(data, width, height, 24);
if (hBMP == NULL) {
frame->UnlockImageData();
return NS_ERROR_FAILURE;
}
}
HBITMAP hAlpha = NULL;
if (format == gfxIFormats::BGR) {
hAlpha = CreateOpaqueAlphaChannel(width, height);
} else {
PRUint32 abpr;
rv = frame->GetAlphaBytesPerRow(&abpr);
if (NS_FAILED(rv)) {
frame->UnlockImageData();
if (hBMP != NULL)
::DeleteObject(hBMP);
return rv;
}
PRUint8* adata;
frame->LockAlphaData();
rv = frame->GetAlphaData(&adata, &dataLen);
if (NS_FAILED(rv)) {
if (hBMP != NULL)
::DeleteObject(hBMP);
frame->UnlockImageData();
frame->UnlockAlphaData();
return rv;
}
if (format == gfxIFormats::BGR_A8) {
PRUint8* bgra8data = DataToAData(data, bpr, adata, abpr, width, height);
if (bgra8data) {
hBMP = DataToBitmap(bgra8data, width, height, 32);
if (hBMP != NULL) {
hAlpha = CreateOpaqueAlphaChannel(width, height);
}
}
} else {
hAlpha = DataToBitmap(adata, width, height, 1);
}
frame->UnlockAlphaData();
}
frame->UnlockImageData();
if (hBMP == NULL) {
return NS_ERROR_FAILURE;
}
if (hAlpha == NULL) {
::DeleteObject(hBMP);
return NS_ERROR_FAILURE;
}
ICONINFO info = {0};
info.fIcon = FALSE;
info.xHotspot = hotspotX;
info.yHotspot = hotspotY;
info.hbmMask = hAlpha;
info.hbmColor = hBMP;
HCURSOR cursor = ::CreateIconIndirect(&info);
::DeleteObject(hBMP);
::DeleteObject(hAlpha);
if (cursor == NULL) {
return NS_ERROR_FAILURE;
}
mCursor = nsCursor(-1);
::SetCursor(cursor);
::DestroyIcon(cursor);
return NS_OK;
}
NS_IMETHODIMP nsWindow::HideWindowChrome(PRBool aShouldHide)
{
HWND hwnd = GetTopLevelHWND(mWnd);

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

@ -65,6 +65,8 @@ class nsIRollupListener;
class nsIMenuBar;
class nsIFile;
class imgIContainer;
#ifdef ACCESSIBILITY
#include "OLEACC.H"
#include "nsIAccessible.h"
@ -342,6 +344,7 @@ public:
virtual nsIFontMetrics* GetFont(void);
NS_IMETHOD SetFont(const nsFont &aFont);
NS_IMETHOD SetCursor(nsCursor aCursor);
NS_IMETHOD SetCursor(imgIContainer* aCursor);
NS_IMETHOD HideWindowChrome(PRBool aShouldHide);
NS_IMETHOD Validate();
NS_IMETHOD Invalidate(PRBool aIsSynchronous);
@ -642,6 +645,45 @@ protected:
// Heap dump
static UINT uWM_HEAP_DUMP; // Dump heap to a file
/**
* Combine the given image data with a separate alpha channel to image data
* with the alpha channel interleaved with the image data (BGRA).
*
* @return BGRA data. Must be delete[]d. On failure, NULL will be returned.
*/
static PRUint8* DataToAData(PRUint8* aImageData, PRUint32 aImageBytesPerRow,
PRUint8* aAlphaData, PRUint32 aAlphaBytesPerRow,
PRUint32 aWidth, PRUint32 aHeight);
/**
* 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.
*/
static HBITMAP DataToBitmap(PRUint8* aImageData,
PRUint32 aWidth,
PRUint32 aHeight,
PRUint32 aDepth);
/**
* Create a bitmap representing an opaque alpha channel (filled with 0xff).
* @param aWidth Desired with of the bitmap
* @param aHeight Desired height of the bitmap
* @return The bitmap. Caller should call DeleteObject when done with
* the bitmap. On failure, NULL will be returned.
*/
static HBITMAP CreateOpaqueAlphaChannel(PRUint32 aWidth, PRUint32 aHeight);
#ifdef ACCESSIBILITY
nsIAccessible* mRootAccessible;
static BOOL gIsAccessibilityOn;