зеркало из https://github.com/mozilla/gecko-dev.git
Bug 38447 implement imgIContainer* version of SetCursor on windows
r=ere sr=roc
This commit is contained in:
Родитель
9ba5078538
Коммит
75bbd70202
|
@ -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
|
||||
|
@ -582,7 +606,7 @@ static PRBool LangIDToCP(WORD aLangID, UINT& oCP)
|
|||
oCP = atoi(cp_name);
|
||||
if (cp_name != cp_on_stack)
|
||||
delete [] cp_name;
|
||||
return PR_TRUE;
|
||||
return PR_TRUE;
|
||||
} else {
|
||||
oCP = CP_ACP;
|
||||
return PR_FALSE;
|
||||
|
@ -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;
|
||||
|
|
Загрузка…
Ссылка в новой задаче