Bug 1520502 - Set the standard cursor and the custom cursor in the same IPC message. r=jmathies

This cleans up a bit and allows us to be smarter about which cursors
should we allow from content or what not, which will help with bug 1445844 and
co.

Differential Revision: https://phabricator.services.mozilla.com/D16711
This commit is contained in:
Emilio Cobos Álvarez 2019-01-15 14:56:52 +01:00
parent 51cb6c2749
commit ef7d8198eb
19 changed files with 308 additions and 377 deletions

View File

@ -6391,7 +6391,7 @@ nsDocShell::OnStateChange(nsIWebProgress* aProgress, nsIRequest* aRequest,
nsCOMPtr<nsIWidget> mainWidget;
GetMainWidget(getter_AddRefs(mainWidget));
if (mainWidget) {
mainWidget->SetCursor(eCursor_spinning);
mainWidget->SetCursor(eCursor_spinning, nullptr, 0, 0);
}
}
}
@ -6407,7 +6407,7 @@ nsDocShell::OnStateChange(nsIWebProgress* aProgress, nsIRequest* aRequest,
nsCOMPtr<nsIWidget> mainWidget;
GetMainWidget(getter_AddRefs(mainWidget));
if (mainWidget) {
mainWidget->SetCursor(eCursor_standard);
mainWidget->SetCursor(eCursor_standard, nullptr, 0, 0);
}
}
}

View File

@ -3826,9 +3826,9 @@ nsresult EventStateManager::SetCursor(StyleCursorKind aCursor,
}
// First, try the imgIContainer, if non-null
nsresult rv = NS_ERROR_FAILURE;
uint32_t hotspotX = 0;
uint32_t hotspotY = 0;
if (aContainer) {
uint32_t hotspotX, hotspotY;
// css3-ui says to use the CSS-specified hotspot if present,
// otherwise use the intrinsic hotspot, otherwise use the top left
@ -3859,12 +3859,9 @@ nsresult EventStateManager::SetCursor(StyleCursorKind aCursor,
if (hotspotYWrap) hotspotYWrap->GetData(&hotspotY);
}
}
rv = aWidget->SetCursor(aContainer, hotspotX, hotspotY);
}
if (NS_FAILED(rv)) aWidget->SetCursor(c);
aWidget->SetCursor(c, aContainer, hotspotX, hotspotY);
return NS_OK;
}

View File

@ -386,15 +386,10 @@ parent:
* Set the native cursor.
* @param value
* The widget cursor to set.
* @param force
* Invalidate any locally cached cursor settings and force an
* update.
*/
async SetCursor(nsCursor value, bool force);
/**
* Set the native cursor using a custom image.
* @param cursorData
* @param hasCustomCursor
* Whether there's any custom cursor represented by cursorData and
* company.
* @param customCursorData
* Serialized image data.
* @param width
* Width of the image.
@ -412,7 +407,10 @@ parent:
* Invalidate any locally cached cursor settings and force an
* update.
*/
async SetCustomCursor(nsCString cursorData, uint32_t width, uint32_t height,
async SetCursor(nsCursor value,
bool hasCustomCursor,
nsCString customCursorData,
uint32_t width, uint32_t height,
uint32_t stride, SurfaceFormat format,
uint32_t hotspotX, uint32_t hotspotY, bool force);

View File

@ -1038,11 +1038,9 @@ void TabParent::SendRealMouseEvent(WidgetMouseEvent& aEvent) {
// become the current cursor. When we mouseexit, we stop.
if (eMouseEnterIntoWidget == aEvent.mMessage) {
mTabSetsCursor = true;
if (mCustomCursor) {
widget->SetCursor(mCustomCursor, mCustomCursorHotspotX,
if (mCursor != eCursorInvalid) {
widget->SetCursor(mCursor, mCustomCursor, mCustomCursorHotspotX,
mCustomCursorHotspotY);
} else if (mCursor != eCursorInvalid) {
widget->SetCursor(mCursor);
}
} else if (eMouseExitFromWidget == aEvent.mMessage) {
mTabSetsCursor = false;
@ -1632,39 +1630,29 @@ mozilla::ipc::IPCResult TabParent::RecvAsyncMessage(
return IPC_OK();
}
mozilla::ipc::IPCResult TabParent::RecvSetCursor(const nsCursor& aCursor,
const bool& aForce) {
mCursor = aCursor;
mCustomCursor = nullptr;
nsCOMPtr<nsIWidget> widget = GetWidget();
if (widget) {
if (aForce) {
widget->ClearCachedCursor();
}
if (mTabSetsCursor) {
widget->SetCursor(mCursor);
}
}
return IPC_OK();
}
mozilla::ipc::IPCResult TabParent::RecvSetCustomCursor(
mozilla::ipc::IPCResult TabParent::RecvSetCursor(
const nsCursor& aCursor,
const bool& aHasCustomCursor,
const nsCString& aCursorData, const uint32_t& aWidth,
const uint32_t& aHeight, const uint32_t& aStride,
const gfx::SurfaceFormat& aFormat, const uint32_t& aHotspotX,
const uint32_t& aHotspotY, const bool& aForce) {
mCursor = eCursorInvalid;
nsCOMPtr<nsIWidget> widget = GetWidget();
if (widget) {
if (!widget) {
return IPC_OK();
}
if (aForce) {
widget->ClearCachedCursor();
}
if (mTabSetsCursor) {
const gfx::IntSize size(aWidth, aHeight);
if (!mTabSetsCursor) {
return IPC_OK();
}
nsCOMPtr<imgIContainer> cursorImage;
if (aHasCustomCursor) {
const gfx::IntSize size(aWidth, aHeight);
RefPtr<gfx::DataSourceSurface> customCursor =
gfx::CreateDataSourceSurfaceFromData(
size, aFormat,
@ -1672,14 +1660,14 @@ mozilla::ipc::IPCResult TabParent::RecvSetCustomCursor(
aStride);
RefPtr<gfxDrawable> drawable = new gfxSurfaceDrawable(customCursor, size);
nsCOMPtr<imgIContainer> cursorImage(
image::ImageOps::CreateFromDrawable(drawable));
widget->SetCursor(cursorImage, aHotspotX, aHotspotY);
cursorImage = image::ImageOps::CreateFromDrawable(drawable);
}
widget->SetCursor(aCursor, cursorImage, aHotspotX, aHotspotY);
mCursor = aCursor;
mCustomCursor = cursorImage;
mCustomCursorHotspotX = aHotspotX;
mCustomCursorHotspotY = aHotspotY;
}
}
return IPC_OK();
}

View File

@ -260,12 +260,13 @@ class TabParent final : public PBrowserParent,
nsTArray<nsCString>&& aDisabledCommands) override;
virtual mozilla::ipc::IPCResult RecvSetCursor(const nsCursor& aValue,
const bool& aForce) override;
virtual mozilla::ipc::IPCResult RecvSetCustomCursor(
const nsCString& aUri, const uint32_t& aWidth, const uint32_t& aHeight,
const uint32_t& aStride, const gfx::SurfaceFormat& aFormat,
const uint32_t& aHotspotX, const uint32_t& aHotspotY,
const bool& aHasCustomCursor,
const nsCString& aUri,
const uint32_t& aWidth, const uint32_t& aHeight,
const uint32_t& aStride,
const gfx::SurfaceFormat& aFormat,
const uint32_t& aHotspotX,
const uint32_t& aHotspotY,
const bool& aForce) override;
virtual mozilla::ipc::IPCResult RecvSetStatus(

View File

@ -898,70 +898,65 @@ nsresult PuppetWidget::NotifyIMEOfPositionChange(
return NS_OK;
}
void PuppetWidget::SetCursor(nsCursor aCursor) {
struct CursorSurface {
UniquePtr<char[]> mData;
IntSize mSize;
};
void PuppetWidget::SetCursor(nsCursor aCursor,
imgIContainer* aCursorImage,
uint32_t aHotspotX,
uint32_t aHotspotY) {
if (!mTabChild) {
return;
}
// Don't cache on windows, Windowless flash breaks this via async cursor
// updates.
#if !defined(XP_WIN)
if (mCursor == aCursor && !mCustomCursor && !mUpdateCursor) {
if (!mUpdateCursor && mCursor == aCursor && mCustomCursor == aCursorImage &&
(!aCursorImage ||
(mCursorHotspotX == aHotspotX && mCursorHotspotY == aHotspotY))) {
return;
}
#endif
bool hasCustomCursor = false;
UniquePtr<char[]> customCursorData;
size_t length = 0;
IntSize customCursorSize;
int32_t stride = 0;
auto format = SurfaceFormat::B8G8R8A8;
bool force = mUpdateCursor;
if (aCursorImage) {
RefPtr<SourceSurface> surface = aCursorImage->GetFrame(
imgIContainer::FRAME_CURRENT, imgIContainer::FLAG_SYNC_DECODE);
if (surface) {
if (RefPtr<DataSourceSurface> dataSurface = surface->GetDataSurface()) {
hasCustomCursor = true;
customCursorData = nsContentUtils::GetSurfaceData(
WrapNotNull(dataSurface), &length, &stride);
customCursorSize = dataSurface->GetSize();
format = dataSurface->GetFormat();
}
}
}
mCustomCursor = nullptr;
if (mTabChild && !mTabChild->SendSetCursor(aCursor, mUpdateCursor)) {
nsDependentCString cursorData(customCursorData ? customCursorData.get() : "", length);
if (!mTabChild->SendSetCursor(aCursor, hasCustomCursor, cursorData,
customCursorSize.width, customCursorSize.height,
stride, format, aHotspotX, aHotspotY, force)) {
return;
}
mCursor = aCursor;
mUpdateCursor = false;
}
nsresult PuppetWidget::SetCursor(imgIContainer* aCursor, uint32_t aHotspotX,
uint32_t aHotspotY) {
if (!aCursor || !mTabChild) {
return NS_OK;
}
#if !defined(XP_WIN)
if (mCustomCursor == aCursor && mCursorHotspotX == aHotspotX &&
mCursorHotspotY == aHotspotY && !mUpdateCursor) {
return NS_OK;
}
#endif
RefPtr<mozilla::gfx::SourceSurface> surface = aCursor->GetFrame(
imgIContainer::FRAME_CURRENT, imgIContainer::FLAG_SYNC_DECODE);
if (!surface) {
return NS_ERROR_FAILURE;
}
RefPtr<mozilla::gfx::DataSourceSurface> dataSurface =
surface->GetDataSurface();
if (!dataSurface) {
return NS_ERROR_FAILURE;
}
size_t length;
int32_t stride;
mozilla::UniquePtr<char[]> surfaceData = nsContentUtils::GetSurfaceData(
WrapNotNull(dataSurface), &length, &stride);
nsDependentCString cursorData(surfaceData.get(), length);
mozilla::gfx::IntSize size = dataSurface->GetSize();
if (!mTabChild->SendSetCustomCursor(cursorData, size.width, size.height,
stride, dataSurface->GetFormat(),
aHotspotX, aHotspotY, mUpdateCursor)) {
return NS_ERROR_FAILURE;
}
mCursor = eCursorInvalid;
mCustomCursor = aCursor;
mCustomCursor = aCursorImage;
mCursorHotspotX = aHotspotX;
mCursorHotspotY = aHotspotY;
mUpdateCursor = false;
return NS_OK;
}
void PuppetWidget::ClearCachedCursor() {

View File

@ -198,9 +198,8 @@ class PuppetWidget : public nsBaseWidget,
mNativeTextEventDispatcherListener = aListener;
}
virtual void SetCursor(nsCursor aCursor) override;
virtual nsresult SetCursor(imgIContainer* aCursor, uint32_t aHotspotX,
uint32_t aHotspotY) override;
virtual void SetCursor(nsCursor aDefaultCursor, imgIContainer* aCustomCursor,
uint32_t aHotspotX, uint32_t aHotspotY) override;
virtual void ClearCachedCursor() override;

View File

@ -258,12 +258,8 @@ class nsWindow final : public nsBaseWidget {
virtual already_AddRefed<nsIScreen> GetWidgetScreen() override;
virtual nsresult MakeFullScreen(bool aFullScreen,
nsIScreen* aTargetScreen = nullptr) override;
virtual void SetCursor(nsCursor aCursor) override {}
virtual nsresult SetCursor(imgIContainer* aCursor, uint32_t aHotspotX,
uint32_t aHotspotY) override {
return NS_ERROR_NOT_IMPLEMENTED;
}
void SetCursor(nsCursor aDefaultCursor, imgIContainer* aImageCursor,
uint32_t aHotspotX, uint32_t aHotspotY) override {}
void* GetNativeData(uint32_t aDataType) override;
void SetNativeData(uint32_t aDataType, uintptr_t aVal) override;
virtual nsresult SetTitle(const nsAString& aTitle) override { return NS_OK; }

View File

@ -364,9 +364,8 @@ class nsChildView final : public nsBaseWidget {
virtual bool WidgetTypeSupportsAcceleration() override;
virtual bool ShouldUseOffMainThreadCompositing() override;
virtual void SetCursor(nsCursor aCursor) override;
virtual nsresult SetCursor(imgIContainer* aCursor, uint32_t aHotspotX,
uint32_t aHotspotY) override;
virtual void SetCursor(nsCursor aDefaultCursor, imgIContainer* aCursor,
uint32_t aHotspotX, uint32_t aHotspotY) override;
virtual nsresult SetTitle(const nsAString& title) override;

View File

@ -762,28 +762,26 @@ nsresult nsChildView::SetFocus(bool aRaise) {
}
// Override to set the cursor on the mac
void nsChildView::SetCursor(nsCursor aCursor) {
void nsChildView::SetCursor(nsCursor aDefaultCursor, imgIContainer* aImageCursor,
uint32_t aHotspotX, uint32_t aHotspotY) {
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
if ([mView isDragInProgress]) return; // Don't change the cursor during dragging.
nsBaseWidget::SetCursor(aCursor);
[[nsCursorManager sharedInstance] setCursor:aCursor];
NS_OBJC_END_TRY_ABORT_BLOCK;
}
// implement to fix "hidden virtual function" warning
nsresult nsChildView::SetCursor(imgIContainer* aCursor, uint32_t aHotspotX, uint32_t aHotspotY) {
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
nsBaseWidget::SetCursor(aCursor, aHotspotX, aHotspotY);
return [[nsCursorManager sharedInstance] setCursorWithImage:aCursor
if (aImageCursor) {
nsresult rv = [[nsCursorManager sharedInstance] setCursorWithImage:aImageCursor
hotSpotX:aHotspotX
hotSpotY:aHotspotY
scaleFactor:BackingScaleFactor()];
if (NS_SUCCEEDED(rv)) {
return;
}
}
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
nsBaseWidget::SetCursor(aDefaultCursor, nullptr, 0, 0);
[[nsCursorManager sharedInstance] setCursor:aDefaultCursor];
NS_OBJC_END_TRY_ABORT_BLOCK;
}
#pragma mark -

View File

@ -242,8 +242,7 @@ class nsCocoaWindow final : public nsBaseWidget, public nsPIWidgetCocoa {
virtual LayoutDeviceIntRect GetScreenBounds() override;
void ReportMoveEvent();
void ReportSizeEvent();
virtual void SetCursor(nsCursor aCursor) override;
virtual nsresult SetCursor(imgIContainer* aCursor, uint32_t aHotspotX,
virtual void SetCursor(nsCursor aDefaultCursor, imgIContainer* aCursorImage, uint32_t aHotspotX,
uint32_t aHotspotY) override;
CGFloat BackingScaleFactor();

View File

@ -1629,16 +1629,10 @@ int32_t nsCocoaWindow::RoundsWidgetCoordinatesTo() {
return 1;
}
void nsCocoaWindow::SetCursor(nsCursor aCursor) {
if (mPopupContentView) {
mPopupContentView->SetCursor(aCursor);
}
}
nsresult nsCocoaWindow::SetCursor(imgIContainer* aCursor, uint32_t aHotspotX, uint32_t aHotspotY) {
if (mPopupContentView) return mPopupContentView->SetCursor(aCursor, aHotspotX, aHotspotY);
return NS_OK;
void nsCocoaWindow::SetCursor(nsCursor aDefaultCursor, imgIContainer* aCursorImage,
uint32_t aHotspotX, uint32_t aHotspotY) {
if (mPopupContentView)
mPopupContentView->SetCursor(aDefaultCursor, aCursorImage, aHotspotX, aHotspotY);
}
nsresult nsCocoaWindow::SetTitle(const nsAString& aTitle) {

View File

@ -1,5 +1,5 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:expandtab:shiftwidth=4:tabstop=4:
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:expandtab:shiftwidth=2:tabstop=2:
*/
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
@ -1434,61 +1434,31 @@ gboolean nsWindow::OnPropertyNotifyEvent(GtkWidget *aWidget,
return FALSE;
}
void nsWindow::SetCursor(nsCursor aCursor) {
// if we're not the toplevel window pass up the cursor request to
// the toplevel window to handle it.
if (!mContainer && mGdkWindow) {
nsWindow *window = GetContainerWindow();
if (!window) return;
window->SetCursor(aCursor);
return;
static GdkCursor *GetCursorForImage(imgIContainer *aCursorImage,
uint32_t aHotspotX, uint32_t aHotspotY) {
if (!aCursorImage) {
return nullptr;
}
// Only change cursor if it's actually been changed
if (aCursor != mCursor || mUpdateCursor) {
GdkCursor *newCursor = nullptr;
mUpdateCursor = false;
newCursor = get_gtk_cursor(aCursor);
if (nullptr != newCursor) {
mCursor = aCursor;
if (!mContainer) return;
gdk_window_set_cursor(gtk_widget_get_window(GTK_WIDGET(mContainer)),
newCursor);
GdkPixbuf *pixbuf = nsImageToPixbuf::ImageToPixbuf(aCursorImage);
if (!pixbuf) {
return nullptr;
}
}
}
nsresult nsWindow::SetCursor(imgIContainer *aCursor, uint32_t aHotspotX,
uint32_t aHotspotY) {
// if we're not the toplevel window pass up the cursor request to
// the toplevel window to handle it.
if (!mContainer && mGdkWindow) {
nsWindow *window = GetContainerWindow();
if (!window) return NS_ERROR_FAILURE;
return window->SetCursor(aCursor, aHotspotX, aHotspotY);
}
mCursor = eCursorInvalid;
// Get the image's current frame
GdkPixbuf *pixbuf = nsImageToPixbuf::ImageToPixbuf(aCursor);
if (!pixbuf) return NS_ERROR_NOT_AVAILABLE;
int width = gdk_pixbuf_get_width(pixbuf);
int height = gdk_pixbuf_get_height(pixbuf);
auto CleanupPixBuf =
mozilla::MakeScopeExit([&]() { g_object_unref(pixbuf); });
// Reject cursors greater than 128 pixels in some direction, to prevent
// spoofing.
// XXX ideally we should rescale. Also, we could modify the API to
// allow trusted content to set larger cursors.
//
// TODO(emilio, bug 1445844): Unify the solution for this with other
// platforms.
if (width > 128 || height > 128) {
g_object_unref(pixbuf);
return NS_ERROR_NOT_AVAILABLE;
return nullptr;
}
// Looks like all cursors need an alpha channel (tested on Gtk 2.4.4). This
@ -1497,26 +1467,58 @@ nsresult nsWindow::SetCursor(imgIContainer *aCursor, uint32_t aHotspotX,
if (!gdk_pixbuf_get_has_alpha(pixbuf)) {
GdkPixbuf *alphaBuf = gdk_pixbuf_add_alpha(pixbuf, FALSE, 0, 0, 0);
g_object_unref(pixbuf);
if (!alphaBuf) {
return NS_ERROR_OUT_OF_MEMORY;
}
pixbuf = alphaBuf;
if (!alphaBuf) {
return nullptr;
}
}
return gdk_cursor_new_from_pixbuf(gdk_display_get_default(), pixbuf,
aHotspotX, aHotspotY);
}
void nsWindow::SetCursor(nsCursor aDefaultCursor, imgIContainer *aCursorImage,
uint32_t aHotspotX, uint32_t aHotspotY) {
// if we're not the toplevel window pass up the cursor request to
// the toplevel window to handle it.
if (!mContainer && mGdkWindow) {
nsWindow *window = GetContainerWindow();
if (!window) return;
window->SetCursor(aDefaultCursor, aCursorImage, aHotspotX, aHotspotY);
return;
}
// Only change cursor if it's actually been changed
if (!aCursorImage && aDefaultCursor == mCursor && !mUpdateCursor) {
return;
}
mUpdateCursor = false;
mCursor = eCursorInvalid;
// Try to set the cursor image first, and fall back to the numeric cursor.
GdkCursor *newCursor = GetCursorForImage(aCursorImage, aHotspotX, aHotspotY);
if (!newCursor) {
newCursor = get_gtk_cursor(aDefaultCursor);
if (newCursor) {
mCursor = aDefaultCursor;
}
}
auto CleanupCursor = mozilla::MakeScopeExit([&]() {
// get_gtk_cursor returns a weak reference, which we shouldn't unref.
if (newCursor && mCursor == eCursorInvalid) {
g_object_unref(newCursor);
}
});
if (!newCursor || !mContainer) {
return;
}
GdkCursor *cursor = gdk_cursor_new_from_pixbuf(gdk_display_get_default(),
pixbuf, aHotspotX, aHotspotY);
g_object_unref(pixbuf);
nsresult rv = NS_ERROR_OUT_OF_MEMORY;
if (cursor) {
if (mContainer) {
gdk_window_set_cursor(gtk_widget_get_window(GTK_WIDGET(mContainer)),
cursor);
rv = NS_OK;
}
g_object_unref(cursor);
}
return rv;
newCursor);
}
void nsWindow::Invalidate(const LayoutDeviceIntRect &aRect) {
@ -3482,7 +3484,7 @@ nsresult nsWindow::Create(nsIWidget *aParent, nsNativeWidget aNativeParent,
// cursor, even though our internal state
// indicates that we already have the
// standard cursor.
SetCursor(eCursor_standard);
SetCursor(eCursor_standard, nullptr, 0, 0);
if (aInitData->mNoAutoHide) {
gint wmd = ConvertBorderStyles(mBorderStyle);

View File

@ -144,9 +144,8 @@ class nsWindow final : public nsBaseWidget {
virtual LayoutDeviceIntRect GetClientBounds() override;
virtual LayoutDeviceIntSize GetClientSize() override;
virtual LayoutDeviceIntPoint GetClientOffset() override;
virtual void SetCursor(nsCursor aCursor) override;
virtual nsresult SetCursor(imgIContainer* aCursor, uint32_t aHotspotX,
uint32_t aHotspotY) override;
virtual void SetCursor(nsCursor aDefaultCursor, imgIContainer* aCursor,
uint32_t aHotspotX, uint32_t aHotspotY) override;
virtual void Invalidate(const LayoutDeviceIntRect& aRect) override;
virtual void* GetNativeData(uint32_t aDataType) override;
virtual nsresult SetTitle(const nsAString& aTitle) override;

View File

@ -640,11 +640,10 @@ void nsBaseWidget::SetSizeMode(nsSizeMode aMode) {
//
//-------------------------------------------------------------------------
void nsBaseWidget::SetCursor(nsCursor aCursor) { mCursor = aCursor; }
nsresult nsBaseWidget::SetCursor(imgIContainer* aCursor, uint32_t aHotspotX,
uint32_t aHotspotY) {
return NS_ERROR_NOT_IMPLEMENTED;
void nsBaseWidget::SetCursor(nsCursor aCursor,
imgIContainer*, uint32_t, uint32_t) {
// We don't support the cursor image.
mCursor = aCursor;
}
//-------------------------------------------------------------------------

View File

@ -168,9 +168,8 @@ class nsBaseWidget : public nsIWidget, public nsSupportsWeakReference {
virtual bool IsFullyOccluded() const override { return mIsFullyOccluded; }
virtual void SetCursor(nsCursor aCursor) override;
virtual nsresult SetCursor(imgIContainer* aCursor, uint32_t aHotspotX,
uint32_t aHotspotY) override;
virtual void SetCursor(nsCursor aDefaultCursor, imgIContainer* aCursor,
uint32_t aHotspotX, uint32_t aHotspotY) override;
virtual void ClearCachedCursor() override { mUpdateCursor = true; }
virtual void SetTransparencyMode(nsTransparencyMode aMode) override;
virtual nsTransparencyMode GetTransparencyMode() override;

View File

@ -933,13 +933,6 @@ class nsIWidget : public nsISupports {
virtual void SetBackgroundColor(const nscolor& aColor) {}
/**
* Set the cursor for this widget
*
* @param aCursor the new cursor for this widget
*/
virtual void SetCursor(nsCursor aCursor) = 0;
/**
* If a cursor type is currently cached locally for this widget, clear the
* cached cursor to force an update on the next SetCursor call.
@ -948,16 +941,15 @@ class nsIWidget : public nsISupports {
virtual void ClearCachedCursor() = 0;
/**
* Sets an image as the cursor for this widget.
* Sets the cursor cursor for this widget.
*
* @param aCursor the cursor to set
* @param aX the X coordinate of the hotspot (from left).
* @param aY the Y coordinate of the hotspot (from top).
* @retval NS_ERROR_NOT_IMPLEMENTED if setting images as cursors is not
* supported
* @param aDefaultCursor the default cursor to be set
* @param aCursorImage a custom cursor, maybe null.
* @param aX the X coordinate of the hotspot for aCursorImage (from left).
* @param aY the Y coordinate of the hotspot for aCursorImage (from top).
*/
virtual nsresult SetCursor(imgIContainer* aCursor, uint32_t aHotspotX,
uint32_t aHotspotY) = 0;
virtual void SetCursor(nsCursor aDefaultCursor, imgIContainer* aCursorImage,
uint32_t aHotspotX, uint32_t aHotspotY) = 0;
/**
* Get the window type of this widget.

View File

@ -1516,7 +1516,7 @@ void nsWindow::Show(bool bState) {
// Set the cursor before showing the window to avoid the default wait
// cursor.
SetCursor(eCursor_standard);
SetCursor(eCursor_standard, nullptr, 0, 0);
switch (mSizeMode) {
case nsSizeMode_Fullscreen:
@ -2710,208 +2710,183 @@ void nsWindow::SetBackgroundColor(const nscolor& aColor) {
**************************************************************/
// Set this component cursor
void nsWindow::SetCursor(nsCursor aCursor) {
// Only change cursor if it's changing
// XXX mCursor isn't always right. Scrollbars and others change it, too.
// XXX If we want this optimization we need a better way to do it.
// if (aCursor != mCursor) {
HCURSOR newCursor = nullptr;
static HCURSOR CursorFor(nsCursor aCursor) {
switch (aCursor) {
case eCursor_select:
newCursor = ::LoadCursor(nullptr, IDC_IBEAM);
break;
return ::LoadCursor(nullptr, IDC_IBEAM);
case eCursor_wait:
newCursor = ::LoadCursor(nullptr, IDC_WAIT);
break;
case eCursor_hyperlink: {
newCursor = ::LoadCursor(nullptr, IDC_HAND);
break;
}
return ::LoadCursor(nullptr, IDC_WAIT);
case eCursor_hyperlink:
return ::LoadCursor(nullptr, IDC_HAND);
case eCursor_standard:
case eCursor_context_menu: // XXX See bug 258960.
newCursor = ::LoadCursor(nullptr, IDC_ARROW);
break;
return ::LoadCursor(nullptr, IDC_ARROW);
case eCursor_n_resize:
case eCursor_s_resize:
newCursor = ::LoadCursor(nullptr, IDC_SIZENS);
break;
return ::LoadCursor(nullptr, IDC_SIZENS);
case eCursor_w_resize:
case eCursor_e_resize:
newCursor = ::LoadCursor(nullptr, IDC_SIZEWE);
break;
return ::LoadCursor(nullptr, IDC_SIZEWE);
case eCursor_nw_resize:
case eCursor_se_resize:
newCursor = ::LoadCursor(nullptr, IDC_SIZENWSE);
break;
return ::LoadCursor(nullptr, IDC_SIZENWSE);
case eCursor_ne_resize:
case eCursor_sw_resize:
newCursor = ::LoadCursor(nullptr, IDC_SIZENESW);
break;
return ::LoadCursor(nullptr, IDC_SIZENESW);
case eCursor_crosshair:
newCursor = ::LoadCursor(nullptr, IDC_CROSS);
break;
return ::LoadCursor(nullptr, IDC_CROSS);
case eCursor_move:
newCursor = ::LoadCursor(nullptr, IDC_SIZEALL);
break;
return ::LoadCursor(nullptr, IDC_SIZEALL);
case eCursor_help:
newCursor = ::LoadCursor(nullptr, IDC_HELP);
break;
return ::LoadCursor(nullptr, IDC_HELP);
case eCursor_copy: // CSS3
newCursor =
::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_COPY));
break;
return ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_COPY));
case eCursor_alias:
newCursor =
::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_ALIAS));
break;
return ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_ALIAS));
case eCursor_cell:
newCursor =
::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_CELL));
break;
return ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_CELL));
case eCursor_grab:
newCursor =
::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_GRAB));
break;
return ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_GRAB));
case eCursor_grabbing:
newCursor =
::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_GRABBING));
break;
return ::LoadCursor(nsToolkit::mDllInstance,
MAKEINTRESOURCE(IDC_GRABBING));
case eCursor_spinning:
newCursor = ::LoadCursor(nullptr, IDC_APPSTARTING);
break;
return ::LoadCursor(nullptr, IDC_APPSTARTING);
case eCursor_zoom_in:
newCursor =
::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_ZOOMIN));
break;
return ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_ZOOMIN));
case eCursor_zoom_out:
newCursor =
::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_ZOOMOUT));
break;
return ::LoadCursor(nsToolkit::mDllInstance,
MAKEINTRESOURCE(IDC_ZOOMOUT));
case eCursor_not_allowed:
case eCursor_no_drop:
newCursor = ::LoadCursor(nullptr, IDC_NO);
break;
return ::LoadCursor(nullptr, IDC_NO);
case eCursor_col_resize:
newCursor =
::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_COLRESIZE));
break;
return ::LoadCursor(nsToolkit::mDllInstance,
MAKEINTRESOURCE(IDC_COLRESIZE));
case eCursor_row_resize:
newCursor =
::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_ROWRESIZE));
break;
return ::LoadCursor(nsToolkit::mDllInstance,
MAKEINTRESOURCE(IDC_ROWRESIZE));
case eCursor_vertical_text:
newCursor = ::LoadCursor(nsToolkit::mDllInstance,
return ::LoadCursor(nsToolkit::mDllInstance,
MAKEINTRESOURCE(IDC_VERTICALTEXT));
break;
case eCursor_all_scroll:
// XXX not 100% appropriate perhaps
newCursor = ::LoadCursor(nullptr, IDC_SIZEALL);
break;
return ::LoadCursor(nullptr, IDC_SIZEALL);
case eCursor_nesw_resize:
newCursor = ::LoadCursor(nullptr, IDC_SIZENESW);
break;
return ::LoadCursor(nullptr, IDC_SIZENESW);
case eCursor_nwse_resize:
newCursor = ::LoadCursor(nullptr, IDC_SIZENWSE);
break;
return ::LoadCursor(nullptr, IDC_SIZENWSE);
case eCursor_ns_resize:
newCursor = ::LoadCursor(nullptr, IDC_SIZENS);
break;
return ::LoadCursor(nullptr, IDC_SIZENS);
case eCursor_ew_resize:
newCursor = ::LoadCursor(nullptr, IDC_SIZEWE);
break;
return ::LoadCursor(nullptr, IDC_SIZEWE);
case eCursor_none:
newCursor =
::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_NONE));
break;
return ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_NONE));
default:
NS_ERROR("Invalid cursor type");
break;
}
if (nullptr != newCursor) {
mCursor = aCursor;
HCURSOR oldCursor = ::SetCursor(newCursor);
if (sHCursor == oldCursor) {
NS_IF_RELEASE(sCursorImgContainer);
if (sHCursor != nullptr) ::DestroyIcon(sHCursor);
sHCursor = nullptr;
}
return nullptr;
}
}
// Setting the actual cursor
nsresult nsWindow::SetCursor(imgIContainer* aCursor, uint32_t aHotspotX,
uint32_t aHotspotY) {
if (sCursorImgContainer == aCursor && sHCursor) {
::SetCursor(sHCursor);
return NS_OK;
static HCURSOR CursorForImage(imgIContainer* aImageContainer,
uint32_t aHotspotX, uint32_t aHotspotY,
double aScale) {
if (!aImageContainer) {
return nullptr;
}
int32_t width;
int32_t height;
int32_t width = 0;
int32_t height = 0;
nsresult rv;
rv = aCursor->GetWidth(&width);
NS_ENSURE_SUCCESS(rv, rv);
rv = aCursor->GetHeight(&height);
NS_ENSURE_SUCCESS(rv, rv);
if (NS_FAILED(aImageContainer->GetWidth(&width)) ||
NS_FAILED(aImageContainer->GetHeight(&height))) {
return nullptr;
}
// Reject cursors greater than 128 pixels in either direction, to prevent
// spoofing.
// XXX ideally we should rescale. Also, we could modify the API to
// allow trusted content to set larger cursors.
if (width > 128 || height > 128) return NS_ERROR_NOT_AVAILABLE;
if (width > 128 || height > 128) {
return nullptr;
}
IntSize size = RoundedToInt(Size(width * aScale, height * aScale));
HCURSOR cursor;
double scale = GetDefaultScale().scale;
IntSize size = RoundedToInt(Size(width * scale, height * scale));
rv = nsWindowGfx::CreateIcon(aCursor, true, aHotspotX, aHotspotY, size,
&cursor);
NS_ENSURE_SUCCESS(rv, rv);
nsresult rv = nsWindowGfx::CreateIcon(aImageContainer, true, aHotspotX,
aHotspotY, size, &cursor);
if (NS_FAILED(rv)) {
return nullptr;
}
return cursor;
}
// Setting the actual cursor
void nsWindow::SetCursor(nsCursor aDefaultCursor, imgIContainer* aImageCursor,
uint32_t aHotspotX, uint32_t aHotspotY) {
if (aImageCursor && sCursorImgContainer == aImageCursor && sHCursor) {
::SetCursor(sHCursor);
return;
}
double scale = GetDefaultScale().scale;
HCURSOR cursor = CursorForImage(aImageCursor, aHotspotX, aHotspotY, scale);
if (cursor) {
mCursor = eCursorInvalid;
::SetCursor(cursor);
NS_IF_RELEASE(sCursorImgContainer);
sCursorImgContainer = aCursor;
sCursorImgContainer = aImageCursor;
NS_ADDREF(sCursorImgContainer);
if (sHCursor != nullptr) ::DestroyIcon(sHCursor);
if (sHCursor) {
::DestroyIcon(sHCursor);
}
sHCursor = cursor;
return;
}
return NS_OK;
cursor = CursorFor(aDefaultCursor);
if (!cursor) {
return;
}
mCursor = aDefaultCursor;
HCURSOR oldCursor = ::SetCursor(cursor);
if (sHCursor == oldCursor) {
NS_IF_RELEASE(sCursorImgContainer);
if (sHCursor) {
::DestroyIcon(sHCursor);
}
sHCursor = nullptr;
}
}
/**************************************************************
@ -6930,7 +6905,9 @@ void nsWindow::OnDestroy() {
}
// Destroy any custom cursor resources.
if (mCursor == eCursorInvalid) SetCursor(eCursor_standard);
if (mCursor == eCursorInvalid) {
SetCursor(eCursor_standard, nullptr, 0, 0);
}
if (mCompositorWidgetDelegate) {
mCompositorWidgetDelegate->OnDestroyWindow();

View File

@ -151,9 +151,8 @@ class nsWindow final : public nsWindowBase {
virtual LayoutDeviceIntRect GetClientBounds() override;
virtual LayoutDeviceIntPoint GetClientOffset() override;
void SetBackgroundColor(const nscolor& aColor) override;
virtual nsresult SetCursor(imgIContainer* aCursor, uint32_t aHotspotX,
uint32_t aHotspotY) override;
virtual void SetCursor(nsCursor aCursor) override;
virtual void SetCursor(nsCursor aDefaultCursor, imgIContainer* aCursorImage,
uint32_t aHotspotX, uint32_t aHotspotY) override;
virtual nsresult ConfigureChildren(
const nsTArray<Configuration>& aConfigurations) override;
virtual bool PrepareForFullscreenTransition(nsISupports** aData) override;