Bug 1200469 part 1 - Avoid using fallback cursor if from the same frame. r?tnikkel,smaug
MozReview-Commit-ID: A2Ku0TND66L
--- a/dom/events/EventStateManager.cpp
+++ b/dom/events/EventStateManager.cpp
@@ -108,16 +108,20 @@ using namespace dom;
#define NS_USER_INTERACTION_INTERVAL 5000 // ms
static const LayoutDeviceIntPoint kInvalidRefPoint = LayoutDeviceIntPoint(-1,-1);
static uint32_t gMouseOrKeyboardEventCounter = 0;
static nsITimer* gUserInteractionTimer = nullptr;
static nsITimerCallback* gUserInteractionTimerCallback = nullptr;
+static const double kCursorLoadingTimeout = 1000; // ms
+static nsWeakFrame gLastCursorSourceFrame;
+static TimeStamp gLastCursorUpdateTime;
+
static inline int32_t
RoundDown(double aDouble)
{
return (aDouble > 0) ? static_cast<int32_t>(floor(aDouble)) :
static_cast<int32_t>(ceil(aDouble));
}
#ifdef DEBUG_DOCSHELL_FOCUS
@@ -3539,37 +3543,46 @@ EventStateManager::UpdateCursor(nsPresCo
float hotspotX = 0.0f, hotspotY = 0.0f;
//If cursor is locked just use the locked one
if (mLockCursor) {
cursor = mLockCursor;
}
//If not locked, look for correct cursor
else if (aTargetFrame) {
- nsIFrame::Cursor framecursor;
- nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent,
- aTargetFrame);
- // Avoid setting cursor when the mouse is over a windowless pluign.
- if (NS_FAILED(aTargetFrame->GetCursor(pt, framecursor))) {
- if (XRE_IsContentProcess()) {
- mLastFrameConsumedSetCursor = true;
- }
- return;
+ nsIFrame::Cursor framecursor;
+ nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent,
+ aTargetFrame);
+ // Avoid setting cursor when the mouse is over a windowless pluign.
+ if (NS_FAILED(aTargetFrame->GetCursor(pt, framecursor))) {
+ if (XRE_IsContentProcess()) {
+ mLastFrameConsumedSetCursor = true;
}
- // Make sure cursors get reset after the mouse leaves a
- // windowless plugin frame.
- if (mLastFrameConsumedSetCursor) {
- ClearCachedWidgetCursor(aTargetFrame);
- mLastFrameConsumedSetCursor = false;
- }
- cursor = framecursor.mCursor;
- container = framecursor.mContainer;
- haveHotspot = framecursor.mHaveHotspot;
- hotspotX = framecursor.mHotspotX;
- hotspotY = framecursor.mHotspotY;
+ return;
+ }
+ // Make sure cursors get reset after the mouse leaves a
+ // windowless plugin frame.
+ if (mLastFrameConsumedSetCursor) {
+ ClearCachedWidgetCursor(aTargetFrame);
+ mLastFrameConsumedSetCursor = false;
+ }
+ // If the current cursor is from the same frame, and it is now
+ // loading some new image for the cursor, we should wait for a
+ // while rather than taking its fallback cursor directly.
+ if (framecursor.mLoading &&
+ gLastCursorSourceFrame == aTargetFrame &&
+ TimeStamp::NowLoRes() - gLastCursorUpdateTime <
+ TimeDuration::FromMilliseconds(kCursorLoadingTimeout)) {
+ return;
+ }
+ cursor = framecursor.mCursor;
+ container = framecursor.mContainer;
+ haveHotspot = framecursor.mHaveHotspot;
+ hotspotX = framecursor.mHotspotX;
+ hotspotY = framecursor.mHotspotY;
}
if (Preferences::GetBool("ui.use_activity_cursor", false)) {
// Check whether or not to show the busy cursor
nsCOMPtr<nsIDocShell> docShell(aPresContext->GetDocShell());
if (!docShell) return;
uint32_t busyFlags = nsIDocShell::BUSY_FLAGS_NONE;
docShell->GetBusyFlags(&busyFlags);
@@ -3582,16 +3595,18 @@ EventStateManager::UpdateCursor(nsPresCo
cursor = NS_STYLE_CURSOR_SPINNING;
container = nullptr;
}
}
if (aTargetFrame) {
SetCursor(cursor, container, haveHotspot, hotspotX, hotspotY,
aTargetFrame->GetNearestWidget(), false);
+ gLastCursorSourceFrame = aTargetFrame;
+ gLastCursorUpdateTime = TimeStamp::NowLoRes();
}
if (mLockCursor || NS_STYLE_CURSOR_AUTO != cursor) {
*aStatus = nsEventStatus_eConsumeDoDefault;
}
}
void
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -8668,32 +8668,37 @@ nsIFrame::VerticalAlignEnum() const
}
/* static */
void nsFrame::FillCursorInformationFromStyle(const nsStyleUserInterface* ui,
nsIFrame::Cursor& aCursor)
{
aCursor.mCursor = ui->mCursor;
aCursor.mHaveHotspot = false;
+ aCursor.mLoading = false;
aCursor.mHotspotX = aCursor.mHotspotY = 0.0f;
for (nsCursorImage *item = ui->mCursorArray,
*item_end = ui->mCursorArray + ui->mCursorArrayLength;
item < item_end; ++item) {
uint32_t status;
nsresult rv = item->GetImage()->GetImageStatus(&status);
- if (NS_SUCCEEDED(rv) &&
- (status & imgIRequest::STATUS_LOAD_COMPLETE) &&
- !(status & imgIRequest::STATUS_ERROR)) {
- // This is the one we want
- item->GetImage()->GetImage(getter_AddRefs(aCursor.mContainer));
- aCursor.mHaveHotspot = item->mHaveHotspot;
- aCursor.mHotspotX = item->mHotspotX;
- aCursor.mHotspotY = item->mHotspotY;
- break;
+ if (NS_SUCCEEDED(rv)) {
+ if (!(status & imgIRequest::STATUS_LOAD_COMPLETE)) {
+ // If we are falling back because any cursor before is loading,
+ // let the consumer know.
+ aCursor.mLoading = true;
+ } else if (!(status & imgIRequest::STATUS_ERROR)) {
+ // This is the one we want
+ item->GetImage()->GetImage(getter_AddRefs(aCursor.mContainer));
+ aCursor.mHaveHotspot = item->mHaveHotspot;
+ aCursor.mHotspotX = item->mHotspotX;
+ aCursor.mHotspotY = item->mHotspotY;
+ break;
+ }
}
}
}
NS_IMETHODIMP
nsFrame::RefreshSizeCache(nsBoxLayoutState& aState)
{
// XXXbz this comment needs some rewriting to make sense in the
--- a/layout/generic/nsIFrame.h
+++ b/layout/generic/nsIFrame.h
@@ -1528,16 +1528,17 @@ public:
* This structure holds information about a cursor. mContainer represents a
* loaded image that should be preferred. If it is not possible to use it, or
* if it is null, mCursor should be used.
*/
struct MOZ_STACK_CLASS Cursor {
nsCOMPtr<imgIContainer> mContainer;
int32_t mCursor;
bool mHaveHotspot;
+ bool mLoading;
float mHotspotX, mHotspotY;
};
/**
* Get the cursor for a given frame.
*/
virtual nsresult GetCursor(const nsPoint& aPoint,
Cursor& aCursor) = 0;