mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 977003 - Make async got/lostpointercapture events. r=smaug
This commit is contained in:
parent
5e29ba50b8
commit
d645e05bbd
@ -682,11 +682,16 @@ public:
|
||||
aError.Throw(NS_ERROR_DOM_INVALID_POINTER_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
// Ignoring ReleasePointerCapture call on incorrect element (on element
|
||||
// that didn't have capture before).
|
||||
if (nsIPresShell::GetPointerCapturingContent(aPointerId) == this) {
|
||||
nsIPresShell::ReleasePointerCapturingContent(aPointerId, this);
|
||||
nsIPresShell::PointerCaptureInfo* pointerCaptureInfo = nullptr;
|
||||
if (nsIPresShell::gPointerCaptureList->Get(aPointerId, &pointerCaptureInfo) && pointerCaptureInfo) {
|
||||
// Call ReleasePointerCapture only on correct element
|
||||
// (on element that have status pointer capture override
|
||||
// or on element that have status pending pointer capture)
|
||||
if (pointerCaptureInfo->mOverrideContent == this) {
|
||||
nsIPresShell::ReleasePointerCapturingContent(aPointerId, this);
|
||||
} else if (pointerCaptureInfo->mPendingContent == this) {
|
||||
nsIPresShell::ReleasePointerCapturingContent(aPointerId, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
void SetCapture(bool aRetargetToElement)
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include "nsTHashtable.h"
|
||||
#include "nsHashKeys.h"
|
||||
#include "nsISupports.h"
|
||||
#include "nsIContent.h"
|
||||
#include "nsQueryFrame.h"
|
||||
#include "nsCoord.h"
|
||||
#include "nsColor.h"
|
||||
@ -43,7 +44,6 @@
|
||||
#include "nsMargin.h"
|
||||
#include "nsFrameState.h"
|
||||
|
||||
class nsIContent;
|
||||
class nsDocShell;
|
||||
class nsIDocument;
|
||||
class nsIFrame;
|
||||
@ -1213,10 +1213,32 @@ public:
|
||||
static nsRefPtrHashtable<nsUint32HashKey, mozilla::dom::Touch>* gCaptureTouchList;
|
||||
static bool gPreventMouseEvents;
|
||||
|
||||
struct PointerCaptureInfo
|
||||
{
|
||||
nsCOMPtr<nsIContent> mPendingContent;
|
||||
nsCOMPtr<nsIContent> mOverrideContent;
|
||||
bool mReleaseContent;
|
||||
|
||||
PointerCaptureInfo(nsIContent* aPendingContent) :
|
||||
mPendingContent(aPendingContent), mReleaseContent(false)
|
||||
{
|
||||
MOZ_COUNT_CTOR(PointerCaptureInfo);
|
||||
}
|
||||
~PointerCaptureInfo()
|
||||
{
|
||||
MOZ_COUNT_DTOR(PointerCaptureInfo);
|
||||
}
|
||||
|
||||
bool Empty()
|
||||
{
|
||||
return !(mPendingContent || mOverrideContent);
|
||||
}
|
||||
};
|
||||
|
||||
// Keeps a map between pointerId and element that currently capturing pointer
|
||||
// with such pointerId. If pointerId is absent in this map then nobody is
|
||||
// capturing it.
|
||||
static nsRefPtrHashtable<nsUint32HashKey, nsIContent>* gPointerCaptureList;
|
||||
// capturing it. Additionally keep information about pending capturing content.
|
||||
static nsClassHashtable<nsUint32HashKey, PointerCaptureInfo>* gPointerCaptureList;
|
||||
|
||||
struct PointerInfo
|
||||
{
|
||||
@ -1229,11 +1251,12 @@ public:
|
||||
static nsClassHashtable<nsUint32HashKey, PointerInfo>* gActivePointersIds;
|
||||
|
||||
static void DispatchGotOrLostPointerCaptureEvent(bool aIsGotCapture,
|
||||
uint32_t aPointerId,
|
||||
nsIContent* aCaptureTarget);
|
||||
uint32_t aPointerId,
|
||||
nsIContent* aCaptureTarget);
|
||||
static void SetPointerCapturingContent(uint32_t aPointerId, nsIContent* aContent);
|
||||
static void ReleasePointerCapturingContent(uint32_t aPointerId, nsIContent* aContent);
|
||||
static nsIContent* GetPointerCapturingContent(uint32_t aPointerId);
|
||||
static void CheckPointerCaptureState(uint32_t aPointerId);
|
||||
|
||||
// GetPointerInfo returns true if pointer with aPointerId is situated in device, false otherwise.
|
||||
// aActiveState is additional information, which shows state of pointer like button state for mouse.
|
||||
|
@ -201,7 +201,7 @@ CapturingContentInfo nsIPresShell::gCaptureInfo =
|
||||
false /* mPreventDrag */, nullptr /* mContent */ };
|
||||
nsIContent* nsIPresShell::gKeyDownTarget;
|
||||
nsRefPtrHashtable<nsUint32HashKey, dom::Touch>* nsIPresShell::gCaptureTouchList;
|
||||
nsRefPtrHashtable<nsUint32HashKey, nsIContent>* nsIPresShell::gPointerCaptureList;
|
||||
nsClassHashtable<nsUint32HashKey, nsIPresShell::PointerCaptureInfo>* nsIPresShell::gPointerCaptureList;
|
||||
nsClassHashtable<nsUint32HashKey, nsIPresShell::PointerInfo>* nsIPresShell::gActivePointersIds;
|
||||
bool nsIPresShell::gPreventMouseEvents = false;
|
||||
|
||||
@ -6274,10 +6274,27 @@ nsIPresShell::SetCapturingContent(nsIContent* aContent, uint8_t aFlags)
|
||||
}
|
||||
}
|
||||
|
||||
class AsyncCheckPointerCaptureStateCaller : public nsRunnable
|
||||
{
|
||||
public:
|
||||
AsyncCheckPointerCaptureStateCaller(int32_t aPointerId) : mPointerId(aPointerId) {}
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
nsIPresShell::CheckPointerCaptureState(mPointerId);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
int32_t mPointerId;
|
||||
};
|
||||
|
||||
/* static */ void
|
||||
nsIPresShell::SetPointerCapturingContent(uint32_t aPointerId, nsIContent* aContent)
|
||||
{
|
||||
nsIContent* content = GetPointerCapturingContent(aPointerId);
|
||||
PointerCaptureInfo* pointerCaptureInfo = nullptr;
|
||||
gPointerCaptureList->Get(aPointerId, &pointerCaptureInfo);
|
||||
nsIContent* content = pointerCaptureInfo ? pointerCaptureInfo->mOverrideContent : nullptr;
|
||||
|
||||
PointerInfo* pointerInfo = nullptr;
|
||||
if (!content && gActivePointersIds->Get(aPointerId, &pointerInfo) &&
|
||||
@ -6286,19 +6303,11 @@ nsIPresShell::SetPointerCapturingContent(uint32_t aPointerId, nsIContent* aConte
|
||||
SetCapturingContent(aContent, CAPTURE_PREVENTDRAG);
|
||||
}
|
||||
|
||||
if (content) {
|
||||
// Releasing capture for given pointer.
|
||||
gPointerCaptureList->Remove(aPointerId);
|
||||
DispatchGotOrLostPointerCaptureEvent(false, aPointerId, content);
|
||||
// Need to check the state because a lostpointercapture listener
|
||||
// may have called SetPointerCapture
|
||||
if (GetPointerCapturingContent(aPointerId)) {
|
||||
return;
|
||||
}
|
||||
if (pointerCaptureInfo) {
|
||||
pointerCaptureInfo->mPendingContent = aContent;
|
||||
} else {
|
||||
gPointerCaptureList->Put(aPointerId, new PointerCaptureInfo(aContent));
|
||||
}
|
||||
|
||||
gPointerCaptureList->Put(aPointerId, aContent);
|
||||
DispatchGotOrLostPointerCaptureEvent(true, aPointerId, aContent);
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
@ -6308,16 +6317,61 @@ nsIPresShell::ReleasePointerCapturingContent(uint32_t aPointerId, nsIContent* aC
|
||||
SetCapturingContent(nullptr, CAPTURE_PREVENTDRAG);
|
||||
}
|
||||
|
||||
// Releasing capture for given pointer.
|
||||
gPointerCaptureList->Remove(aPointerId);
|
||||
|
||||
DispatchGotOrLostPointerCaptureEvent(false, aPointerId, aContent);
|
||||
PointerCaptureInfo* pointerCaptureInfo = nullptr;
|
||||
if (gPointerCaptureList->Get(aPointerId, &pointerCaptureInfo) && pointerCaptureInfo) {
|
||||
// Set flag to asyncronously release capture for given pointer.
|
||||
pointerCaptureInfo->mReleaseContent = true;
|
||||
nsRefPtr<AsyncCheckPointerCaptureStateCaller> asyncCaller =
|
||||
new AsyncCheckPointerCaptureStateCaller(aPointerId);
|
||||
NS_DispatchToCurrentThread(asyncCaller);
|
||||
}
|
||||
}
|
||||
|
||||
/* static */ nsIContent*
|
||||
nsIPresShell::GetPointerCapturingContent(uint32_t aPointerId)
|
||||
{
|
||||
return gPointerCaptureList->GetWeak(aPointerId);
|
||||
PointerCaptureInfo* pointerCaptureInfo = nullptr;
|
||||
if (gPointerCaptureList->Get(aPointerId, &pointerCaptureInfo) && pointerCaptureInfo) {
|
||||
return pointerCaptureInfo->mOverrideContent;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
nsIPresShell::CheckPointerCaptureState(uint32_t aPointerId)
|
||||
{
|
||||
PointerCaptureInfo* pointerCaptureInfo = nullptr;
|
||||
if (gPointerCaptureList->Get(aPointerId, &pointerCaptureInfo) && pointerCaptureInfo) {
|
||||
// If pendingContent exist or anybody calls element.releasePointerCapture
|
||||
// we should dispatch lostpointercapture event to overrideContent if it exist
|
||||
if (pointerCaptureInfo->mPendingContent || pointerCaptureInfo->mReleaseContent) {
|
||||
if (pointerCaptureInfo->mOverrideContent) {
|
||||
nsCOMPtr<nsIContent> content;
|
||||
pointerCaptureInfo->mOverrideContent.swap(content);
|
||||
if (pointerCaptureInfo->mReleaseContent) {
|
||||
pointerCaptureInfo->mPendingContent = nullptr;
|
||||
}
|
||||
if (pointerCaptureInfo->Empty()) {
|
||||
gPointerCaptureList->Remove(aPointerId);
|
||||
}
|
||||
DispatchGotOrLostPointerCaptureEvent(false, aPointerId, content);
|
||||
} else if (pointerCaptureInfo->mPendingContent && pointerCaptureInfo->mReleaseContent) {
|
||||
// If anybody calls element.releasePointerCapture
|
||||
// We should clear overrideContent and pendingContent
|
||||
pointerCaptureInfo->mPendingContent = nullptr;
|
||||
pointerCaptureInfo->mReleaseContent = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (gPointerCaptureList->Get(aPointerId, &pointerCaptureInfo) && pointerCaptureInfo) {
|
||||
// If pendingContent exist we should dispatch gotpointercapture event to it
|
||||
if (pointerCaptureInfo && pointerCaptureInfo->mPendingContent) {
|
||||
pointerCaptureInfo->mOverrideContent = pointerCaptureInfo->mPendingContent;
|
||||
pointerCaptureInfo->mPendingContent = nullptr;
|
||||
pointerCaptureInfo->mReleaseContent = false;
|
||||
DispatchGotOrLostPointerCaptureEvent(true, aPointerId, pointerCaptureInfo->mOverrideContent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
@ -7188,6 +7242,14 @@ PresShell::HandleEvent(nsIFrame* aFrame,
|
||||
}
|
||||
}
|
||||
|
||||
if (aEvent->mClass == ePointerEventClass) {
|
||||
if (WidgetPointerEvent* pointerEvent = aEvent->AsPointerEvent()) {
|
||||
// Before any pointer events, we should check state of pointer capture,
|
||||
// Thus got/lostpointercapture events emulate asynchronous behavior.
|
||||
CheckPointerCaptureState(pointerEvent->pointerId);
|
||||
}
|
||||
}
|
||||
|
||||
if (aEvent->mClass == ePointerEventClass &&
|
||||
aEvent->message != NS_POINTER_DOWN) {
|
||||
if (WidgetPointerEvent* pointerEvent = aEvent->AsPointerEvent()) {
|
||||
@ -10345,7 +10407,7 @@ void nsIPresShell::InitializeStatics()
|
||||
{
|
||||
NS_ASSERTION(!gCaptureTouchList, "InitializeStatics called multiple times!");
|
||||
gCaptureTouchList = new nsRefPtrHashtable<nsUint32HashKey, dom::Touch>;
|
||||
gPointerCaptureList = new nsRefPtrHashtable<nsUint32HashKey, nsIContent>;
|
||||
gPointerCaptureList = new nsClassHashtable<nsUint32HashKey, PointerCaptureInfo>;
|
||||
gActivePointersIds = new nsClassHashtable<nsUint32HashKey, PointerInfo>;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user