Bug 633602 - Implement Pointer Lock (Mouse Lock) API. r=roc, smaug

This commit is contained in:
David Humphrey 2012-03-28 21:00:14 -04:00
parent 16a1cfed7e
commit b174382f2b
50 changed files with 2387 additions and 44 deletions

View File

@ -780,6 +780,12 @@ public:
*/
static void ExitFullScreen(bool aRunAsync);
virtual void RequestPointerLock(Element* aElement) = 0;
static void UnlockPointer();
//----------------------------------------------------------------------
// Document notification API's

View File

@ -1329,6 +1329,8 @@ private:
NodeHasExplicitBaseURI,
// Set if the element has some style states locked
ElementHasLockedStyleStates,
// Set if element has pointer locked
ElementHasPointerLock,
// Guard value
BooleanFlagCount
};
@ -1387,6 +1389,9 @@ public:
bool IsPurpleRoot() const { return GetBoolFlag(NodeIsPurpleRoot); }
bool HasListenerManager() { return HasFlag(NODE_HAS_LISTENERMANAGER); }
bool HasPointerLock() const { return GetBoolFlag(ElementHasPointerLock); }
void SetPointerLock() { SetBoolFlag(ElementHasPointerLock); }
void ClearPointerLock() { ClearBoolFlag(ElementHasPointerLock); }
protected:
void SetParentIsContent(bool aValue) { SetBoolFlag(ParentIsContent, aValue); }
void SetInDocument() { SetBoolFlag(IsInDocument); }

View File

@ -8658,6 +8658,13 @@ nsDocument::ExitFullScreen()
// dispatch to so that we dispatch in the specified order.
nsAutoTArray<nsIDocument*, 8> changed;
// We may also need to unlock the pointer, if it's locked.
nsCOMPtr<Element> pointerLockedElement =
do_QueryReferent(nsEventStateManager::sPointerLockedElement);
if (pointerLockedElement) {
UnlockPointer();
}
// Walk the tree of full-screen documents, and reset their full-screen state.
ResetFullScreen(root, static_cast<void*>(&changed));
@ -8688,12 +8695,20 @@ nsDocument::RestorePreviousFullScreenState()
return;
}
// If fullscreen mode is updated the pointer should be unlocked
nsCOMPtr<Element> pointerLockedElement =
do_QueryReferent(nsEventStateManager::sPointerLockedElement);
if (pointerLockedElement) {
UnlockPointer();
}
// Clear full-screen stacks in all descendant documents, bottom up.
nsCOMPtr<nsIDocument> fullScreenDoc(do_QueryReferent(sFullScreenDoc));
nsIDocument* doc = fullScreenDoc;
while (doc != this) {
NS_ASSERTION(doc->IsFullScreenDoc(), "Should be full-screen doc");
static_cast<nsDocument*>(doc)->ClearFullScreenStack();
UnlockPointer();
DispatchFullScreenChange(doc);
doc = doc->GetParentDocument();
}
@ -8702,6 +8717,7 @@ nsDocument::RestorePreviousFullScreenState()
NS_ASSERTION(doc == this, "Must have reached this doc.");
while (doc != nsnull) {
static_cast<nsDocument*>(doc)->FullScreenStackPop();
UnlockPointer();
DispatchFullScreenChange(doc);
if (static_cast<nsDocument*>(doc)->mFullScreenStack.IsEmpty()) {
// Full-screen stack in document is empty. Go back up to the parent
@ -8977,7 +8993,22 @@ nsDocument::RequestFullScreen(Element* aElement, bool aWasCallerChrome)
// Remember the root document, so that if a full-screen document is hidden
// we can reset full-screen state in the remaining visible full-screen documents.
sFullScreenRootDoc = do_GetWeakReference(nsContentUtils::GetRootDocument(this));
nsIDocument* fullScreenDoc = nsContentUtils::GetRootDocument(this);
sFullScreenRootDoc = do_GetWeakReference(fullScreenDoc);
// If a document is already in fullscreen, then unlock the mouse pointer
// before setting a new document to fullscreen
if (fullScreenDoc) {
UnlockPointer();
}
// If a document is already in fullscreen, then unlock the mouse pointer
// before setting a new document to fullscreen
nsCOMPtr<Element> pointerLockedElement =
do_QueryReferent(nsEventStateManager::sPointerLockedElement);
if (pointerLockedElement) {
UnlockPointer();
}
// Set the full-screen element. This sets the full-screen style on the
// element, and the full-screen-ancestor styles on ancestors of the element
@ -9141,6 +9172,223 @@ nsDocument::IsFullScreenEnabled(bool aCallerIsChrome, bool aLogFailure)
return true;
}
static void
DispatchPointerLockChange(nsIDocument* aTarget)
{
nsRefPtr<nsAsyncDOMEvent> e =
new nsAsyncDOMEvent(aTarget,
NS_LITERAL_STRING("mozpointerlockchange"),
true,
false);
e->PostDOMEvent();
}
static void
DispatchPointerLockError(nsIDocument* aTarget)
{
nsRefPtr<nsAsyncDOMEvent> e =
new nsAsyncDOMEvent(aTarget,
NS_LITERAL_STRING("mozpointerlockerror"),
true,
false);
e->PostDOMEvent();
}
void
nsDocument::RequestPointerLock(Element* aElement)
{
NS_ASSERTION(aElement,
"Must pass non-null element to nsDocument::RequestPointerLock");
nsCOMPtr<Element> pointerLockedElement =
do_QueryReferent(nsEventStateManager::sPointerLockedElement);
if (aElement == pointerLockedElement) {
DispatchPointerLockChange(this);
return;
}
if (!ShouldLockPointer(aElement) ||
!SetPointerLock(aElement, NS_STYLE_CURSOR_NONE)) {
DispatchPointerLockError(this);
return;
}
aElement->SetPointerLock();
nsEventStateManager::sPointerLockedElement = do_GetWeakReference(aElement);
nsEventStateManager::sPointerLockedDoc =
do_GetWeakReference(static_cast<nsIDocument*>(this));
DispatchPointerLockChange(this);
}
bool
nsDocument::ShouldLockPointer(Element* aElement)
{
// Check if pointer lock pref is enabled
if (!Preferences::GetBool("full-screen-api.pointer-lock.enabled")) {
NS_WARNING("ShouldLockPointer(): Pointer Lock pref not enabled");
return false;
}
if (aElement != GetFullScreenElement()) {
NS_WARNING("ShouldLockPointer(): Element not in fullscreen");
return false;
}
if (!aElement->IsInDoc()) {
NS_WARNING("ShouldLockPointer(): Element without Document");
return false;
}
// Check if the element is in a document with a docshell.
nsCOMPtr<nsIDocument> ownerDoc = aElement->OwnerDoc();
if (!ownerDoc) {
return false;
}
if (!nsCOMPtr<nsISupports>(ownerDoc->GetContainer())) {
return false;
}
nsCOMPtr<nsPIDOMWindow> ownerWindow = ownerDoc->GetWindow();
if (!ownerWindow) {
return false;
}
nsCOMPtr<nsPIDOMWindow> ownerInnerWindow = ownerDoc->GetInnerWindow();
if (!ownerInnerWindow) {
return false;
}
if (ownerWindow->GetCurrentInnerWindow() != ownerInnerWindow) {
return false;
}
return true;
}
bool
nsDocument::SetPointerLock(Element* aElement, int aCursorStyle)
{
// NOTE: aElement will be nsnull when unlocking.
nsCOMPtr<nsPIDOMWindow> window = GetWindow();
if (!window) {
NS_WARNING("SetPointerLock(): No Window");
return false;
}
nsIDocShell *docShell = window->GetDocShell();
if (!docShell) {
NS_WARNING("SetPointerLock(): No DocShell (window already closed?)");
return false;
}
nsRefPtr<nsPresContext> presContext;
docShell->GetPresContext(getter_AddRefs(presContext));
if (!presContext) {
NS_WARNING("SetPointerLock(): Unable to get presContext in \
domWindow->GetDocShell()->GetPresContext()");
return false;
}
nsCOMPtr<nsIPresShell> shell = presContext->PresShell();
if (!shell) {
NS_WARNING("SetPointerLock(): Unable to find presContext->PresShell()");
return false;
}
nsIFrame* rootFrame = shell->GetRootFrame();
if (!rootFrame) {
NS_WARNING("SetPointerLock(): Unable to get root frame");
return false;
}
nsCOMPtr<nsIWidget> widget = rootFrame->GetNearestWidget();
if (!widget) {
NS_WARNING("SetPointerLock(): Unable to find widget in \
shell->GetRootFrame()->GetNearestWidget();");
return false;
}
if (aElement && (aElement->OwnerDoc() != this)) {
NS_WARNING("SetPointerLock(): Element not in this document.");
return false;
}
// Hide the cursor and set pointer lock for future mouse events
nsRefPtr<nsEventStateManager> esm = presContext->EventStateManager();
esm->SetCursor(aCursorStyle, nsnull, false,
0.0f, 0.0f, widget, true);
esm->SetPointerLock(widget, aElement);
return true;
}
void
nsDocument::UnlockPointer()
{
if (!nsEventStateManager::sIsPointerLocked) {
return;
}
nsCOMPtr<nsIDocument> pointerLockedDoc =
do_QueryReferent(nsEventStateManager::sPointerLockedDoc);
if (!pointerLockedDoc) {
return;
}
nsDocument* doc = static_cast<nsDocument*>(pointerLockedDoc.get());
if (!doc->SetPointerLock(nsnull, NS_STYLE_CURSOR_AUTO)) {
return;
}
nsCOMPtr<Element> pointerLockedElement =
do_QueryReferent(nsEventStateManager::sPointerLockedElement);
if (!pointerLockedElement) {
return;
}
nsEventStateManager::sPointerLockedElement = nsnull;
nsEventStateManager::sPointerLockedDoc = nsnull;
pointerLockedElement->ClearPointerLock();
DispatchPointerLockChange(pointerLockedDoc);
}
void
nsIDocument::UnlockPointer()
{
nsDocument::UnlockPointer();
}
NS_IMETHODIMP
nsDocument::MozExitPointerLock()
{
UnlockPointer();
return NS_OK;
}
NS_IMETHODIMP
nsDocument::GetMozPointerLockElement(nsIDOMElement** aPointerLockedElement)
{
NS_ENSURE_ARG_POINTER(aPointerLockedElement);
*aPointerLockedElement = nsnull;
nsCOMPtr<Element> pointerLockedElement =
do_QueryReferent(nsEventStateManager::sPointerLockedElement);
if (!pointerLockedElement) {
return NS_OK;
}
// Make sure pointer locked element is in the same document and domain.
nsCOMPtr<nsIDocument> pointerLockedDoc =
do_QueryReferent(nsEventStateManager::sPointerLockedDoc);
nsDocument* doc = static_cast<nsDocument*>(pointerLockedDoc.get());
if (doc != this) {
return NS_OK;
}
nsCOMPtr<nsIDOMNode> pointerLockedNode =
do_QueryInterface(pointerLockedElement);
nsresult rv = nsContentUtils::CheckSameOrigin(this, pointerLockedNode.get());
if (NS_FAILED(rv)) {
return NS_OK;
}
return CallQueryInterface(pointerLockedElement, aPointerLockedElement);
}
#define EVENT(name_, id_, type_, struct_) \
NS_IMETHODIMP nsDocument::GetOn##name_(JSContext *cx, jsval *vp) { \
return nsINode::GetOn##name_(cx, vp); \

View File

@ -988,6 +988,11 @@ public:
// Returns the top element from the full-screen stack.
Element* FullScreenStackTop();
void RequestPointerLock(Element* aElement);
bool ShouldLockPointer(Element* aElement);
bool SetPointerLock(Element* aElement, int aCursorStyle);
static void UnlockPointer();
// This method may fire a DOM event; if it does so it will happen
// synchronously.
void UpdateVisibilityState();

View File

@ -3274,6 +3274,9 @@ nsGenericElement::UnbindFromTree(bool aDeep, bool aNullParent)
// Fully exit full-screen.
nsIDocument::ExitFullScreen(false);
}
if (HasPointerLock()) {
nsIDocument::UnlockPointer();
}
if (GetParent()) {
NS_RELEASE(mParent);
} else {
@ -6418,7 +6421,15 @@ nsINode::Contains(nsIDOMNode* aOther, bool* aReturn)
return NS_OK;
}
nsresult nsGenericElement::MozRequestFullScreen()
NS_IMETHODIMP
nsGenericElement::MozRequestPointerLock()
{
OwnerDoc()->RequestPointerLock(this);
return NS_OK;
}
NS_IMETHODIMP
nsGenericElement::MozRequestFullScreen()
{
// Only grant full-screen requests if this is called from inside a trusted
// event handler (i.e. inside an event handler for a user initiated event).

View File

@ -592,6 +592,8 @@ GK_ATOM(mousethrough, "mousethrough")
GK_ATOM(mouseup, "mouseup")
GK_ATOM(mozfullscreenchange, "mozfullscreenchange")
GK_ATOM(mozfullscreenerror, "mozfullscreenerror")
GK_ATOM(mozpointerlockchange, "mozpointerlockchange")
GK_ATOM(mozpointerlockerror, "mozpointerlockerror")
GK_ATOM(moz_opaque, "moz-opaque")
GK_ATOM(moz_action_hint, "mozactionhint")
GK_ATOM(x_moz_errormessage, "x-moz-errormessage")
@ -713,6 +715,8 @@ GK_ATOM(onmouseup, "onmouseup")
GK_ATOM(onMozAfterPaint, "onMozAfterPaint")
GK_ATOM(onmozfullscreenchange, "onmozfullscreenchange")
GK_ATOM(onmozfullscreenerror, "onmozfullscreenerror")
GK_ATOM(onmozpointerlockchange, "onmozpointerlockchange")
GK_ATOM(onmozpointerlockerror, "onmozpointerlockerror")
GK_ATOM(onMozMousePixelScroll, "onMozMousePixelScroll")
GK_ATOM(onMozScrolledAreaChanged, "onMozScrolledAreaChanged")
GK_ATOM(ononline, "ononline")

View File

@ -275,6 +275,14 @@ EVENT(mozfullscreenerror,
NS_FULLSCREENERROR,
EventNameType_HTML,
NS_EVENT_NULL)
EVENT(mozpointerlockchange,
NS_POINTERLOCKCHANGE,
EventNameType_HTML,
NS_EVENT_NULL)
EVENT(mozpointerlockerror,
NS_POINTERLOCKERROR,
EventNameType_HTML,
NS_EVENT_NULL)
// Not supported yet; probably never because "wheel" is a better idea.
// EVENT(mousewheel)
EVENT(pause,

View File

@ -100,6 +100,8 @@ static const char* const sEventNames[] = {
"MozBeforeResize",
"mozfullscreenchange",
"mozfullscreenerror",
"mozpointerlockchange",
"mozpointerlockerror",
"MozSwipeGesture",
"MozMagnifyGestureStart",
"MozMagnifyGestureUpdate",
@ -1169,6 +1171,10 @@ nsDOMEvent::GetScreenCoords(nsPresContext* aPresContext,
nsEvent* aEvent,
nsIntPoint aPoint)
{
if (nsEventStateManager::sIsPointerLocked) {
return nsEventStateManager::sLastScreenPoint;
}
if (!aEvent ||
(aEvent->eventStructType != NS_MOUSE_EVENT &&
aEvent->eventStructType != NS_POPUP_EVENT &&
@ -1224,6 +1230,10 @@ nsDOMEvent::GetClientCoords(nsPresContext* aPresContext,
nsIntPoint aPoint,
nsIntPoint aDefaultPoint)
{
if (nsEventStateManager::sIsPointerLocked) {
return nsEventStateManager::sLastClientPoint;
}
if (!aEvent ||
(aEvent->eventStructType != NS_MOUSE_EVENT &&
aEvent->eventStructType != NS_POPUP_EVENT &&

View File

@ -183,6 +183,8 @@ public:
eDOMEvents_beforeresize,
eDOMEvents_mozfullscreenchange,
eDOMEvents_mozfullscreenerror,
eDOMEvents_mozpointerlockchange,
eDOMEvents_mozpointerlockerror,
eDOMEvents_MozSwipeGesture,
eDOMEvents_MozMagnifyGestureStart,
eDOMEvents_MozMagnifyGestureUpdate,

View File

@ -233,6 +233,24 @@ nsDOMMouseEvent::GetRelatedTarget(nsIDOMEventTarget** aRelatedTarget)
return NS_OK;
}
NS_IMETHODIMP
nsDOMMouseEvent::GetMozMovementX(PRInt32* aMovementX)
{
NS_ENSURE_ARG_POINTER(aMovementX);
*aMovementX = GetMovementPoint().x;
return NS_OK;
}
NS_IMETHODIMP
nsDOMMouseEvent::GetMozMovementY(PRInt32* aMovementY)
{
NS_ENSURE_ARG_POINTER(aMovementY);
*aMovementY = GetMovementPoint().y;
return NS_OK;
}
NS_METHOD nsDOMMouseEvent::GetScreenX(PRInt32* aScreenX)
{
NS_ENSURE_ARG_POINTER(aScreenX);

View File

@ -49,7 +49,6 @@
#include "nsContentUtils.h"
#include "nsEventStateManager.h"
#include "nsIFrame.h"
#include "nsLayoutUtils.h"
#include "nsIScrollableFrame.h"
#include "DictionaryHelpers.h"
@ -58,6 +57,9 @@ nsDOMUIEvent::nsDOMUIEvent(nsPresContext* aPresContext, nsGUIEvent* aEvent)
static_cast<nsEvent *>(aEvent) :
static_cast<nsEvent *>(new nsUIEvent(false, 0, 0)))
, mClientPoint(0, 0), mLayerPoint(0, 0), mPagePoint(0, 0)
, mIsPointerLocked(nsEventStateManager::sIsPointerLocked)
, mLastScreenPoint(nsEventStateManager::sLastScreenPoint)
, mLastClientPoint(nsEventStateManager::sLastClientPoint)
{
if (aEvent) {
mEventIsInternal = false;
@ -124,7 +126,7 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsDOMUIEvent)
NS_INTERFACE_MAP_END_INHERITING(nsDOMEvent)
nsIntPoint
nsDOMUIEvent::GetScreenPoint()
nsDOMUIEvent::GetMovementPoint()
{
if (!mEvent ||
(mEvent->eventStructType != NS_MOUSE_EVENT &&
@ -136,43 +138,41 @@ nsDOMUIEvent::GetScreenPoint()
return nsIntPoint(0, 0);
}
if (!((nsGUIEvent*)mEvent)->widget ) {
return mEvent->refPoint;
if (!((nsGUIEvent*)mEvent)->widget) {
return mEvent->lastRefPoint;
}
nsIntPoint offset = mEvent->refPoint +
// Calculate the delta between the previous screen point and the current one.
nsIntPoint currentPoint = CalculateScreenPoint(mPresContext, mEvent);
// Adjust previous event's refPoint so it compares to current screenX, screenY
nsIntPoint offset = mEvent->lastRefPoint +
((nsGUIEvent*)mEvent)->widget->WidgetToScreenOffset();
nscoord factor = mPresContext->DeviceContext()->UnscaledAppUnitsPerDevPixel();
return nsIntPoint(nsPresContext::AppUnitsToIntCSSPixels(offset.x * factor),
nsIntPoint lastPoint = nsIntPoint(nsPresContext::AppUnitsToIntCSSPixels(offset.x * factor),
nsPresContext::AppUnitsToIntCSSPixels(offset.y * factor));
return currentPoint - lastPoint;
}
nsIntPoint
nsDOMUIEvent::GetScreenPoint()
{
if (mIsPointerLocked) {
return mLastScreenPoint;
}
return CalculateScreenPoint(mPresContext, mEvent);
}
nsIntPoint
nsDOMUIEvent::GetClientPoint()
{
if (!mEvent ||
(mEvent->eventStructType != NS_MOUSE_EVENT &&
mEvent->eventStructType != NS_POPUP_EVENT &&
mEvent->eventStructType != NS_MOUSE_SCROLL_EVENT &&
mEvent->eventStructType != NS_MOZTOUCH_EVENT &&
mEvent->eventStructType != NS_DRAG_EVENT &&
mEvent->eventStructType != NS_SIMPLE_GESTURE_EVENT) ||
!mPresContext ||
!((nsGUIEvent*)mEvent)->widget) {
return mClientPoint;
if (mIsPointerLocked) {
return mLastClientPoint;
}
nsPoint pt(0, 0);
nsIPresShell* shell = mPresContext->GetPresShell();
if (!shell) {
return nsIntPoint(0, 0);
}
nsIFrame* rootFrame = shell->GetRootFrame();
if (rootFrame)
pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(mEvent, rootFrame);
return nsIntPoint(nsPresContext::AppUnitsToIntCSSPixels(pt.x),
nsPresContext::AppUnitsToIntCSSPixels(pt.y));
return CalculateClientPoint(mPresContext, mEvent, &mClientPoint);
}
NS_IMETHODIMP

View File

@ -41,6 +41,7 @@
#include "nsIDOMUIEvent.h"
#include "nsDOMEvent.h"
#include "nsLayoutUtils.h"
class nsDOMUIEvent : public nsDOMEvent,
public nsIDOMUIEvent
@ -66,10 +67,67 @@ public:
virtual nsresult InitFromCtor(const nsAString& aType,
JSContext* aCx, jsval* aVal);
static nsIntPoint CalculateScreenPoint(nsPresContext* aPresContext,
nsEvent* aEvent)
{
if (!aEvent ||
(aEvent->eventStructType != NS_MOUSE_EVENT &&
aEvent->eventStructType != NS_POPUP_EVENT &&
aEvent->eventStructType != NS_MOUSE_SCROLL_EVENT &&
aEvent->eventStructType != NS_MOZTOUCH_EVENT &&
aEvent->eventStructType != NS_DRAG_EVENT &&
aEvent->eventStructType != NS_SIMPLE_GESTURE_EVENT)) {
return nsIntPoint(0, 0);
}
if (!((nsGUIEvent*)aEvent)->widget ) {
return aEvent->refPoint;
}
nsIntPoint offset = aEvent->refPoint +
((nsGUIEvent*)aEvent)->widget->WidgetToScreenOffset();
nscoord factor = aPresContext->DeviceContext()->UnscaledAppUnitsPerDevPixel();
return nsIntPoint(nsPresContext::AppUnitsToIntCSSPixels(offset.x * factor),
nsPresContext::AppUnitsToIntCSSPixels(offset.y * factor));
}
static nsIntPoint CalculateClientPoint(nsPresContext* aPresContext,
nsEvent* aEvent,
nsIntPoint* aDefaultClientPoint)
{
if (!aEvent ||
(aEvent->eventStructType != NS_MOUSE_EVENT &&
aEvent->eventStructType != NS_POPUP_EVENT &&
aEvent->eventStructType != NS_MOUSE_SCROLL_EVENT &&
aEvent->eventStructType != NS_MOZTOUCH_EVENT &&
aEvent->eventStructType != NS_DRAG_EVENT &&
aEvent->eventStructType != NS_SIMPLE_GESTURE_EVENT) ||
!aPresContext ||
!((nsGUIEvent*)aEvent)->widget) {
return (nsnull == aDefaultClientPoint ? nsIntPoint(0, 0) :
nsIntPoint(aDefaultClientPoint->x, aDefaultClientPoint->y));
}
nsPoint pt(0, 0);
nsIPresShell* shell = aPresContext->GetPresShell();
if (!shell) {
return nsIntPoint(0, 0);
}
nsIFrame* rootFrame = shell->GetRootFrame();
if (rootFrame) {
pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, rootFrame);
}
return nsIntPoint(nsPresContext::AppUnitsToIntCSSPixels(pt.x),
nsPresContext::AppUnitsToIntCSSPixels(pt.y));
}
protected:
// Internal helper functions
nsIntPoint GetScreenPoint();
nsIntPoint GetClientPoint();
nsIntPoint GetMovementPoint();
nsIntPoint GetLayerPoint();
nsIntPoint GetPagePoint();
@ -88,6 +146,10 @@ protected:
// Screenpoint is mEvent->refPoint.
nsIntPoint mLayerPoint;
nsIntPoint mPagePoint;
nsIntPoint mMovement;
bool mIsPointerLocked;
nsIntPoint mLastScreenPoint;
nsIntPoint mLastClientPoint;
};
#define NS_FORWARD_TO_NSDOMUIEVENT \

View File

@ -137,6 +137,8 @@
#include "mozilla/LookAndFeel.h"
#include "sampler.h"
#include "nsIDOMClientRect.h"
#ifdef XP_MACOSX
#import <ApplicationServices/ApplicationServices.h>
#endif
@ -159,6 +161,15 @@ bool nsEventStateManager::sNormalLMouseEventInProcess = false;
nsEventStateManager* nsEventStateManager::sActiveESM = nsnull;
nsIDocument* nsEventStateManager::sMouseOverDocument = nsnull;
nsWeakFrame nsEventStateManager::sLastDragOverFrame = nsnull;
nsIntPoint nsEventStateManager::sLastRefPoint = nsIntPoint(0,0);
nsIntPoint nsEventStateManager::sLastScreenOffset = nsIntPoint(0,0);
nsIntPoint nsEventStateManager::sLastScreenPoint = nsIntPoint(0,0);
nsIntPoint nsEventStateManager::sLastClientPoint = nsIntPoint(0,0);
bool nsEventStateManager::sIsPointerLocked = false;
// Reference to the pointer locked element.
nsWeakPtr nsEventStateManager::sPointerLockedElement;
// Reference to the document which requested pointer lock.
nsWeakPtr nsEventStateManager::sPointerLockedDoc;
nsCOMPtr<nsIContent> nsEventStateManager::sDragOverContent = nsnull;
static PRUint32 gMouseOrKeyboardEventCounter = 0;
@ -772,6 +783,7 @@ nsMouseWheelTransaction::LimitToOnePageScroll(PRInt32 aScrollLines,
nsEventStateManager::nsEventStateManager()
: mLockCursor(0),
mPreLockPoint(0,0),
mCurrentTarget(nsnull),
mLastMouseOverFrame(nsnull),
// init d&d gesture state machine variables
@ -1046,6 +1058,23 @@ nsEventStateManager::PreHandleEvent(nsPresContext* aPresContext,
NS_ASSERTION(mCurrentTarget, "mCurrentTarget is null. this should not happen. see bug #13007");
if (!mCurrentTarget) return NS_ERROR_NULL_POINTER;
}
#ifdef DEBUG
if (NS_IS_DRAG_EVENT(aEvent) && sIsPointerLocked) {
NS_ASSERTION(sIsPointerLocked,
"sIsPointerLocked is true. Drag events should be suppressed when the pointer is locked.");
}
#endif
// Store last known screenPoint and clientPoint so pointer lock
// can use these values as constants.
if (NS_IS_TRUSTED_EVENT(aEvent) &&
(NS_IS_MOUSE_EVENT_STRUCT(aEvent) &&
IsMouseEventReal(aEvent)) ||
aEvent->eventStructType == NS_MOUSE_SCROLL_EVENT) {
if (!sIsPointerLocked) {
sLastScreenPoint = nsDOMUIEvent::CalculateScreenPoint(aPresContext, aEvent);
sLastClientPoint = nsDOMUIEvent::CalculateClientPoint(aPresContext, aEvent, nsnull);
}
}
// Do not take account NS_MOUSE_ENTER/EXIT so that loading a page
// when user is not active doesn't change the state to active.
@ -3779,6 +3808,25 @@ nsEventStateManager::DispatchMouseEvent(nsGUIEvent* aEvent, PRUint32 aMessage,
nsIContent* aTargetContent,
nsIContent* aRelatedContent)
{
// http://dvcs.w3.org/hg/webevents/raw-file/default/mouse-lock.html#methods
// "[When the mouse is locked on an element...e]vents that require the concept
// of a mouse cursor must not be dispatched (for example: mouseover, mouseout).
if (sIsPointerLocked &&
(aMessage == NS_MOUSELEAVE ||
aMessage == NS_MOUSEENTER ||
aMessage == NS_MOUSE_ENTER_SYNTH ||
aMessage == NS_MOUSE_EXIT_SYNTH)) {
mCurrentTargetContent = nsnull;
nsCOMPtr<Element> pointerLockedElement =
do_QueryReferent(nsEventStateManager::sPointerLockedElement);
if (!pointerLockedElement) {
NS_WARNING("Should have pointer locked element, but didn't.");
return nsnull;
}
nsCOMPtr<nsIContent> content = do_QueryInterface(pointerLockedElement);
return mPresContext->GetPrimaryFrameFor(content);
}
SAMPLE_LABEL("Input", "DispatchMouseEvent");
nsEventStatus status = nsEventStatus_eIgnore;
nsMouseEvent event(NS_IS_TRUSTED_EVENT(aEvent), aMessage, aEvent->widget,
@ -3989,6 +4037,26 @@ nsEventStateManager::GenerateMouseEnterExit(nsGUIEvent* aEvent)
switch(aEvent->message) {
case NS_MOUSE_MOVE:
{
if (sIsPointerLocked && aEvent->widget) {
// Perform mouse lock by recentering the mouse directly, then remembering the deltas.
nsIntRect bounds;
aEvent->widget->GetScreenBounds(bounds);
aEvent->lastRefPoint = GetMouseCoords(bounds);
// refPoint should not be the centre on mousemove
if (aEvent->refPoint.x == aEvent->lastRefPoint.x &&
aEvent->refPoint.y == aEvent->lastRefPoint.y) {
aEvent->refPoint = sLastRefPoint;
} else {
aEvent->widget->SynthesizeNativeMouseMove(aEvent->lastRefPoint);
}
} else {
aEvent->lastRefPoint = nsIntPoint(sLastRefPoint.x, sLastRefPoint.y);
}
// Update the last known refPoint with the current refPoint.
sLastRefPoint = nsIntPoint(aEvent->refPoint.x, aEvent->refPoint.y);
// Get the target content target (mousemove target == mouseover target)
nsCOMPtr<nsIContent> targetElement = GetEventTargetContent(aEvent);
if (!targetElement) {
@ -4024,6 +4092,79 @@ nsEventStateManager::GenerateMouseEnterExit(nsGUIEvent* aEvent)
mCurrentTargetContent = targetBeforeEvent;
}
void
nsEventStateManager::SetPointerLock(nsIWidget* aWidget,
nsIContent* aElement)
{
// NOTE: aElement will be nsnull when unlocking.
sIsPointerLocked = !!aElement;
if (!aWidget) {
return;
}
// Reset mouse wheel transaction
nsMouseWheelTransaction::EndTransaction();
// Deal with DnD events
nsCOMPtr<nsIDragService> dragService =
do_GetService("@mozilla.org/widget/dragservice;1");
if (sIsPointerLocked) {
// Store the last known ref point so we can reposition the pointer after unlock.
mPreLockPoint = sLastRefPoint + sLastScreenOffset;
nsIntRect bounds;
aWidget->GetScreenBounds(bounds);
sLastRefPoint = GetMouseCoords(bounds);
aWidget->SynthesizeNativeMouseMove(sLastRefPoint);
// Retarget all events to this element via capture.
nsIPresShell::SetCapturingContent(aElement, CAPTURE_POINTERLOCK);
// Suppress DnD
if (dragService) {
dragService->Suppress();
}
} else {
// Unlocking, so return pointer to the original position
aWidget->SynthesizeNativeMouseMove(sLastScreenPoint);
// Don't retarget events to this element any more.
nsIPresShell::SetCapturingContent(nsnull, CAPTURE_POINTERLOCK);
// Unsuppress DnD
if (dragService) {
dragService->Unsuppress();
}
}
}
nsIntPoint
nsEventStateManager::GetMouseCoords(nsIntRect aBounds)
{
NS_ASSERTION(sIsPointerLocked, "GetMouseCoords when not pointer locked!");
nsCOMPtr<nsIDocument> pointerLockedDoc =
do_QueryReferent(nsEventStateManager::sPointerLockedDoc);
if (!pointerLockedDoc) {
NS_WARNING("GetMouseCoords(): No Document");
return nsIntPoint(0, 0);
}
nsCOMPtr<nsPIDOMWindow> domWin = pointerLockedDoc->GetInnerWindow();
if (!domWin) {
NS_WARNING("GetMouseCoords(): No Window");
return nsIntPoint(0, 0);
}
int innerHeight;
domWin->GetInnerHeight(&innerHeight);
return nsIntPoint((aBounds.width / 2) + aBounds.x,
(innerHeight / 2) + (aBounds.y + (aBounds.height - innerHeight)));
}
void
nsEventStateManager::GenerateDragDropEnterExit(nsPresContext* aPresContext,
nsGUIEvent* aEvent)

View File

@ -228,6 +228,12 @@ public:
static bool IsRemoteTarget(nsIContent* aTarget);
static nsIntPoint sLastScreenPoint;
static nsIntPoint sLastClientPoint;
static bool sIsPointerLocked;
static nsWeakPtr sPointerLockedElement;
static nsWeakPtr sPointerLockedDoc;
protected:
friend class MouseEnterLeaveDispatcher;
@ -480,11 +486,16 @@ private:
PRInt32 mLockCursor;
// Point when mouse was locked, used to reposition after unlocking.
nsIntPoint mPreLockPoint;
nsWeakFrame mCurrentTarget;
nsCOMPtr<nsIContent> mCurrentTargetContent;
nsWeakFrame mLastMouseOverFrame;
nsCOMPtr<nsIContent> mLastMouseOverElement;
static nsWeakFrame sLastDragOverFrame;
static nsIntPoint sLastRefPoint;
static nsIntPoint sLastScreenOffset;
// member variables for the d&d gesture state machine
nsIntPoint mGestureDownPoint; // screen coordinates
@ -556,6 +567,9 @@ public:
nsGUIEvent* inMouseDownEvent ) ;
void KillClickHoldTimer ( ) ;
void FireContextClick ( ) ;
void SetPointerLock(nsIWidget* aWidget, nsIContent* aElement) ;
nsIntPoint GetMouseCoords(nsIntRect aBounds);
static void sClickHoldCallback ( nsITimer* aTimer, void* aESM ) ;
};

View File

@ -66,7 +66,7 @@ interface nsIDOMLocation;
* http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html
*/
[scriptable, uuid(ac4942fe-1679-4000-aaa7-41dee590a120)]
[scriptable, uuid(e8d73d0a-cbf6-4037-a565-32c8d64cc294)]
interface nsIDOMDocument : nsIDOMNode
{
readonly attribute nsIDOMDocumentType doctype;
@ -396,6 +396,21 @@ interface nsIDOMDocument : nsIDOMNode
*/
readonly attribute boolean mozFullScreenEnabled;
/**
* The element to which the mouse pointer is locked, if any, as per the
* DOM pointer lock api.
*
* @see <http://dvcs.w3.org/hg/pointerlock/raw-file/default/index.html>
*/
readonly attribute nsIDOMElement mozPointerLockElement;
/**
* Exit pointer is lock if locked, as per the DOM pointer lock api.
*
* @see <http://dvcs.w3.org/hg/pointerlock/raw-file/default/index.html>
*/
void mozExitPointerLock();
/**
* Inline event handler for readystatechange events.
*/

View File

@ -49,7 +49,7 @@
* http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#interface-element
*/
[scriptable, uuid(295e05d9-9174-48ae-bc59-d7e6a8757726)]
[scriptable, uuid(432a86dd-c0b8-4d21-8ac6-5ae57d28ea6b)]
interface nsIDOMElement : nsIDOMNode
{
readonly attribute DOMString tagName;
@ -228,4 +228,12 @@ interface nsIDOMElement : nsIDOMNode
* @see <https://wiki.mozilla.org/index.php?title=Gecko:FullScreenAPI>
*/
void mozRequestFullScreen();
/**
* Requests that this element be made the pointer-locked element, as per the DOM
* pointer lock api.
*
* @see <http://dvcs.w3.org/hg/pointerlock/raw-file/default/index.html>
*/
void mozRequestPointerLock();
};

View File

@ -82,6 +82,8 @@ interface nsIInlineEventHandlers : nsISupports
// [implicit_jscontext] attribute jsval onmousewheel;
[implicit_jscontext] attribute jsval onmozfullscreenchange;
[implicit_jscontext] attribute jsval onmozfullscreenerror;
[implicit_jscontext] attribute jsval onmozpointerlockchange;
[implicit_jscontext] attribute jsval onmozpointerlockerror;
[implicit_jscontext] attribute jsval onpause;
[implicit_jscontext] attribute jsval onplay;
[implicit_jscontext] attribute jsval onplaying;

View File

@ -48,12 +48,15 @@
* http://www.w3.org/TR/DOM-Level-2-Events/
*/
[scriptable, uuid(7f57aa45-6792-4d8b-ba5b-201533cf0b2f)]
[scriptable, uuid(53E29996-F851-4032-B896-8AAFBD0BDF25)]
interface nsIDOMMouseEvent : nsIDOMUIEvent
{
readonly attribute long screenX;
readonly attribute long screenY;
readonly attribute long mozMovementX;
readonly attribute long mozMovementY;
readonly attribute long clientX;
readonly attribute long clientY;

View File

@ -48,6 +48,7 @@ DIRS += \
dom-level2-core \
dom-level2-html \
ajax \
browser-frame \
bugs \
chrome \
general \
@ -55,9 +56,9 @@ DIRS += \
geolocation \
localstorage \
orientation \
pointerlock \
sessionstorage \
storageevent \
browser-frame \
$(NULL)
#needs IPC support, also tests do not run successfully in Firefox for now

View File

@ -0,0 +1,39 @@
# 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 file,
# You can obtain one at http://mozilla.org/MPL/2.0/.
DEPTH = ../../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
relativesrcdir = dom/tests/mochitest/pointerlock
include $(DEPTH)/config/autoconf.mk
include $(topsrcdir)/config/rules.mk
_TEST_FILES = \
test_pointerlock-api.html \
pointerlock_utils.js \
file_pointerlock-api.html \
file_pointerlockerror.html \
file_escapeKey.html \
file_withoutDOM.html \
file_removedFromDOM.html \
file_pointerLockPref.html \
file_nestedFullScreen.html \
file_doubleLock.html \
file_loseFocusWindow.html \
file_childIframe.html \
file_movementXY.html \
file_infiniteMovement.html \
file_retargetMouseEvents.html \
file_targetOutOfFocus.html \
file_screenClientXYConst.html \
file_suppressSomeMouseEvents.html \
file_locksvgelement.html \
iframe_differentDOM.html \
$(NULL)
libs:: $(_TEST_FILES)
$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)

View File

@ -0,0 +1,143 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=633602
-->
<head>
<title>Bug 633602 - file_childIframe.html</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js">
</script>
<script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
<script type="application/javascript" src="pointerlock_utils.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<style>
#parent, #childDiv, #iframe, #table, #table td {
margin: 0;
padding: 0;
border: none;
}
#iframe, #table {
background-color: red;
width: 100%;
height: 100%;
}
#childDiv, #table td {
background-color: blue;
width: 50%;
height: 50%;
}
</style>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=633602">
Mozilla Bug 633602
</a>
<div id="parent">
<table id="childTable">
<tr>
<td>
<iframe id="iframe" src="iframe_differentDOM.html" onload="start();">
</iframe>
</td>
<td>
<div id="childDiv">
</div>
</td>
</tr>
</table>
</div>
<pre id="test">
<script type="application/javascript">
/*
* Test for Bug 633602
* Check if pointer is locked when over a child iframe of
* the locked element
* Check if pointer is being repositioned back to center of
* the locked element even when pointer goes over a child ifame
*/
SimpleTest.waitForExplicitFinish();
var parent = document.getElementById("parent")
, childDiv = document.getElementById("childDiv")
, iframe = document.getElementById("iframe");
function MozMovementStats() {
this.mozMovementX = false;
this.mozMovementY = false;
}
var firstMove = new MozMovementStats()
, secondMove = new MozMovementStats()
, hoverIframe = false;
function runTests () {
ok(hoverIframe, "Pointer should be locked even when pointer " +
"hovers over a child iframe");
is(firstMove.mozMovementX, secondMove.mozMovementX, "MovementX of first " +
"move to childDiv should be equal to movementX of second move " +
"to child div");
is(firstMove.mozMovementY, secondMove.mozMovementY, "MovementY of first " +
"move to childDiv should be equal to movementY of second move " +
"to child div");
}
var firstMoveChild = function (e) {
firstMove.mozMovementX = e.mozMovementX;
firstMove.mozMovementY = e.mozMovementY;
parent.removeEventListener("mousemove", firstMoveChild);
parent.addEventListener("mousemove", moveIframe);
synthesizeMouseAtCenter(iframe, {type: "mousemove"}, window);
};
var moveIframe = function (e) {
hoverIframe = !!document.mozPointerLockElement;
parent.removeEventListener("mousemove", moveIframe);
parent.addEventListener("mousemove", secondMoveChild);
synthesizeMouseAtCenter(childDiv, {type: "mousemove"}, window);
};
var secondMoveChild = function (e) {
secondMove.mozMovementX = e.mozMovementX;
secondMove.mozMovementY = e.mozMovementY;
parent.removeEventListener("mousemove", secondMoveChild);
document.mozCancelFullScreen();
};
document.addEventListener("mozpointerlockchange", function () {
if (document.mozPointerLockElement === parent) {
parent.addEventListener("mousemove", firstMoveChild);
synthesizeMouseAtCenter(childDiv, {type: "mousemove"}, window);
}
}, false);
document.addEventListener("mozpointerlockerror", function () {
document.mozCancelFullScreen();
}, false);
document.addEventListener("mozfullscreenchange", function (e) {
if (document.mozFullScreenElement === parent) {
parent.mozRequestPointerLock();
}
else {
runTests();
SimpleTest.finish();
}
}, false);
function start() {
SimpleTest.waitForFocus(function() {
parent.mozRequestFullScreen();
});
}
</script>
</pre>
</body>
</html>

View File

@ -0,0 +1,70 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=633602
-->
<head>
<title>Bug 633602 - file_doubleLockCallBack.html</title>
<script type="text/javascript"
src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript"
src="/tests/SimpleTest/EventUtils.js"></script>
<script type="application/javascript" src="pointerlock_utils.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<style type="text/css">
#test-element { background-color: #94E01B; width:100px; height:100px; }
</style>
</head>
<body onload="start();">
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=633602">
Mozilla Bug 633602</a>
<div id="div"></div>
<pre id="test">
<script type="text/javascript">
/*
* Test for Bug 633602
* If element requests pointerlock on itself while in pointerlock state
* mozpointerlockchange event should be dispatched
*/
SimpleTest.waitForExplicitFinish();
var div = document.getElementById("div")
, numberOfLocks = 0;
function runTests () {
is(numberOfLocks, 2, "Requesting pointer lock on a locked element " +
"should dispatch mozpointerlockchange event");
}
document.addEventListener("mozpointerlockchange", function (e) {
if (document.mozPointerLockElement === div) {
if (numberOfLocks === 2) {
document.mozCancelFullScreen();
}
else {
numberOfLocks++;
div.mozRequestPointerLock();
}
}
}, false);
document.addEventListener("mozfullscreenchange", function (e) {
if (document.mozFullScreenElement === div) {
div.mozRequestPointerLock();
}
else {
runTests();
SimpleTest.finish();
}
}, false);
function start() {
SimpleTest.waitForFocus(function() {
div.mozRequestFullScreen();
});
}
</script>
</pre>
</body>
</html>

View File

@ -0,0 +1,63 @@
<!DOCTYPE HTML>
<html>
<!--https://bugzilla.mozilla.org/show_bug.cgi?id=633602-->
<head>
<title>Bug 633602</title>
<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js">
</script>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js">
</script>
<script type="application/javascript" src="pointerlock_utils.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body onload="start();">
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=633602">
Mozilla Bug 633602
</a>
<div id="div"></div>
<pre id="test">
<script type="text/javascript">
/*
* Test for Bug 633602
* Escape key should unlock the pointer
*/
SimpleTest.waitForExplicitFinish();
var div = document.getElementById("div")
, pointerUnLocked = false;
function runTests () {
ok(pointerUnLocked, "Pressing Escape key should unlock the pointer");
}
document.addEventListener("mozpointerlockchange", function (e) {
if (document.mozPointerLockElement === div) {
synthesizeKey("VK_ESCAPE", {});
}
else {
pointerUnLocked = true;
document.mozCancelFullScreen();
}
}, false);
document.addEventListener("mozfullscreenchange", function(e) {
if (document.mozFullScreenElement === div) {
div.mozRequestPointerLock();
}
else {
runTests();
SimpleTest.finish();
}
}, false);
function start() {
SimpleTest.waitForFocus(function() {
div.mozRequestFullScreen();
});
}
</script>
</pre>
</body>
</html>

View File

@ -0,0 +1,100 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=633602
-->
<head>
<title>Bug 633602 - file_movementXY.html</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js">
</script>
<script type="text/javascript" src="/tests/SimpleTest/EventUtils.js">
</script>
<script type="application/javascript" src="pointerlock_utils.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body onload="start();">
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=633602">
Mozilla Bug 633602
</a>
<div id="div"></div>
<pre id="test">
<script type="application/javascript">
/*
* Test for Bug 633602
* This test checks if mozMovementX and mozMovementY
* are present in a mouse event object.
* It also checks the values for mozMovementXY.
* They should be equal to the current screenXY minus
* the last screenXY
* This test will also test that the incremental movement is
* not constrained to the width of the screen.
*/
SimpleTest.waitForExplicitFinish();
var div = document.getElementById("div")
, divCenterWidth = 0
, divCenterHeight = 0
, totalMovementX = 0
, totalMovementY = 0;
function runTests () {
ok(totalMovementX > div.getBoundingClientRect().width,
"Should have moved more than one screen's worth in width." +
"TotalX: " + totalMovementX + " Screensize X: " + div.getBoundingClientRect().width);
ok(totalMovementY > div.getBoundingClientRect().height,
"Should have moved more than one screen's worth in height." +
"TotalY: " + totalMovementY + " Screensize Y: " + div.getBoundingClientRect().height);
}
var firstMoveListener = function (e) {
div.removeEventListener("mousemove", firstMoveListener, false);
div.addEventListener("mousemove", secondMoveListener, false);
synthesizeMouse(div,(divCenterWidth/2) * 3,
(divCenterHeight/2) * 3, {
type: "mousemove"
}, window);
}
var secondMoveListener = function (e) {
totalMovementX = divCenterWidth + ((divCenterWidth / 2) * 3);
totalMovementY = divCenterHeight + ((divCenterHeight / 2) * 3);
div.removeEventListener("mousemove", secondMoveListener, false);
document.mozCancelFullScreen();
}
document.addEventListener("mozpointerlockchange", function (e) {
if (document.mozPointerLockElement === div) {
div.addEventListener("mousemove", firstMoveListener, false);
divCenterWidth = Math.round(div.getBoundingClientRect().width / 2);
divCenterHeight = Math.round(div.getBoundingClientRect().height / 2);
synthesizeMouse(div, divCenterWidth, divCenterHeight, {
type: "mousemove"
}, window);
}
}, false);
document.addEventListener("mozfullscreenchange", function() {
if (document.mozFullScreenElement === div) {
div.mozRequestPointerLock();
}
else {
runTests();
SimpleTest.finish();
}
}, false);
function start() {
SimpleTest.waitForFocus(function() {
div.mozRequestFullScreen();
});
}
</script>
</pre>
</body>
</html>

View File

@ -0,0 +1,67 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=633602
-->
<head>
<title>Bug 633602</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js">
</script>
<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js">
</script>
<script type="application/javascript" src="pointerlock_utils.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body onload="start();">
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=633602">
Mozilla Bug 633602</a>
<p id="display"></p>
<svg width="100" height="100" viewbox="0 0 100 100">
<rect id="svg-elem" x="10" y="10" width="50" height="50"
fill="black" stroke="blue" stroke-width="2"/>
</svg>
<pre id="test">
<script type="application/javascript">
/*
* Test for Bug 633602
* Test locking non-html element.
*/
SimpleTest.waitForExplicitFinish(1);
var elem,
elemWasLocked = false;
document.addEventListener("mozpointerlockchange", function (e) {
if (document.mozFullScreen &&
document.mozPointerLockElement === elem) {
elemWasLocked = true;
document.mozExitPointerLock();
} else {
document.mozCancelFullScreen();
}
}, false);
document.addEventListener("mozfullscreenchange", function (e) {
if (document.mozFullScreenElement === elem) {
elem.mozRequestPointerLock();
} else {
ok(elemWasLocked, "Expected SVG elem to become locked.");
SimpleTest.finish();
}
}, false);
function start() {
elem = document.getElementById("svg-elem");
SimpleTest.waitForFocus(function() {
elem.mozRequestFullScreen();
});
}
</script>
</pre>
</body>
</html>

View File

@ -0,0 +1,71 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=633602
-->
<head>
<title>Bug 633602 - file_exitMouseLockOnLoseFocus.html</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js">
</script>
<script type="text/javascript" src="/tests/SimpleTest/EventUtils.js">
</script>
<script type="application/javascript" src="pointerlock_utils.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body onload="start();">
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=633602">
Mozilla Bug 633602
</a>
<div id="div"></div>
<pre id="test">
<script type="text/javascript">
/*
* Test for Bug 633602
* If element has the pointer locked and window loses focus
* pointer should be unlocked
*/
SimpleTest.waitForExplicitFinish();
var div = document.getElementById("div")
, newWindow = null
, looseFocusUnlock = false
, pointerLockLost = false;
function runTests () {
ok(looseFocusUnlock, "Pointer should be unlocked if window " +
"loses focus");
}
document.addEventListener("mozpointerlockchange", function (e) {
if (document.mozPointerLockElement === div) {
divPointerLocked = true;
newWindow = window.open(); // Open new window to blur current one
}
else {
looseFocusUnlock = true;
newWindow && newWindow.close();
document.mozCancelFullScreen();
}
}, false);
document.addEventListener("mozfullscreenchange", function() {
if (document.mozFullScreenElement === div) {
div.mozRequestPointerLock();
}
else {
runTests();
SimpleTest.finish();
}
}, false);
function start() {
SimpleTest.waitForFocus(function() {
div.mozRequestFullScreen();
});
}
</script>
</pre>
</body>
</html>

View File

@ -0,0 +1,105 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=633602
-->
<head>
<title>Bug 633602 - file_movementXY.html</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js">
</script>
<script type="text/javascript" src="/tests/SimpleTest/EventUtils.js">
</script>
<script type="application/javascript" src="pointerlock_utils.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body onload="start();">
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=633602">
Mozilla Bug 633602
</a>
<div id="div"></div>
<pre id="test">
<script type="application/javascript">
/*
* Test for Bug 633602
* Checks if mozMovementX and mozMovementY are present
* in the mouse event object.
* It also checks the values for mozMovementXY.
* They should be equal to the current screenXY minus
* the last screenXY
*/
SimpleTest.waitForExplicitFinish();
function MouseMovementStats() {
this.screenX = false;
this.screenY = false;
this.mozMovementX = false;
this.mozMovementY = false;
}
var div = document.getElementById("div")
, divCenterWidth = 0
, divCenterHeight = 0
, mozMovementX = false
, mozMovementY = false
, firstMove = new MouseMovementStats()
, secondMove = new MouseMovementStats();
function runTests () {
ok(mozMovementX && mozMovementY, "mozMovementX and " +
"mozMovementY should exist in mouse events objects.");
is(secondMove.mozMovementX, secondMove.screenX - firstMove.screenX,
"mozMovementX should be equal to eNow.screenX-ePrevious.screenX");
is(secondMove.mozMovementY, secondMove.screenY - firstMove.screenY,
"mozMovementY should be equal to eNow.screenY-ePrevious.screenY");
}
var moveMouse = function(e) {
mozMovementX = ("mozMovementX" in e);
mozMovementY = ("mozMovementY" in e);
div.removeEventListener("mousemove", moveMouse, false);
div.addEventListener("mousemove", moveMouseAgain, false);
firstMove.screenX = e.screenX;
firstMove.screenY = e.screenY;
divCenterWidth = Math.round(div.getBoundingClientRect().width / 2);
divCenterHeight = Math.round(div.getBoundingClientRect().height / 2);
synthesizeMouse(div, (divCenterWidth + 10), (divCenterHeight + 10), {
type: "mousemove"
}, window);
};
var moveMouseAgain = function(e) {
secondMove.screenX = e.screenX;
secondMove.screenY = e.screenY;
secondMove.mozMovementX = e.mozMovementX;
secondMove.mozMovementY = e.mozMovementY;
div.removeEventListener("mousemove", moveMouseAgain, false);
document.mozCancelFullScreen();
};
document.addEventListener("mozfullscreenchange", function() {
if (document.mozFullScreenElement === div) {
div.addEventListener("mousemove", moveMouse, false);
synthesizeMouseAtCenter(div, {type: "mousemove"}, window);
}
else {
runTests();
SimpleTest.finish();
}
}, false);
function start() {
SimpleTest.waitForFocus(function() {
div.mozRequestFullScreen();
});
}
</script>
</pre>
</body>
</html>

View File

@ -0,0 +1,81 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=633602
-->
<head>
<title>Bug 633602 - file_nestedFullScreen.html</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js">
</script>
<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js">
</script>
<script type="application/javascript" src="pointerlock_utils.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body onload="start();">
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=633602">
Mozilla Bug 633602
</a>
<div id="parentDiv">
<div id="childDiv"></div>
</div>
<script type="application/javascript">
/*
* Test for Bug 633602
* Requesting fullscreen on a child element of the element with
* the pointer locked should unlock the pointer
*/
SimpleTest.waitForExplicitFinish();
var parentDiv = document.getElementById("parentDiv")
, childDiv = document.getElementById("childDiv")
, parentDivLocked = false
, parentDivFullScreen = false
, pointerLocked = false;
function runTests () {
ok(parentDivLocked, "After requesting pointerlock on parentDiv " +
"document.mozPointerLockElement should be equal to " +
" parentDiv element");
isnot(pointerLocked, true, "Requesting fullscreen on " +
"childDiv while parentDiv still in fullscreen should " +
"unlock the pointer");
}
document.addEventListener("mozpointerlockchange", function (e) {
if (document.mozPointerLockElement === parentDiv) {
parentDivLocked = true;
childDiv.mozRequestFullScreen();
}
}, false);
document.addEventListener("mozfullscreenchange", function() {
if (document.mozFullScreenElement === parentDiv) {
if (parentDivFullScreen === true) {
document.mozCancelFullScreen();
}
parentDivFullScreen = true;
parentDiv.mozRequestPointerLock();
}
else if (document.mozFullScreenElement === childDiv) {
pointerLocked = !!document.mozPointerLockElement;
document.mozCancelFullScreen();
}
else {
runTests();
SimpleTest.finish();
}
}, false);
function start() {
SimpleTest.waitForFocus(function() {
parentDiv.mozRequestFullScreen();
});
}
</script>
</body>
</html>

View File

@ -0,0 +1,80 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=633602
-->
<head>
<title>Bug 633602</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js">
</script>
<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js">
</script>
<script type="application/javascript" src="pointerlock_utils.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body onload="start();">
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=633602">
Mozilla Bug 633602</a>
<p id="display"></p>
<div id="div"></div>
<pre id="test">
<script type="application/javascript">
/*
* Test for Bug 633602
* Tests full-screen-api.pointer-lock pref
*/
SimpleTest.waitForExplicitFinish();
var div = document.getElementById("div")
, prefEnabled = false
, prefDisabled = false;
function runTests () {
ok(prefEnabled, "Element should be able to lock the pointer " +
"if pointer-lock pref is set to TRUE");
ok(prefDisabled, "Element should NOT be able to lock the pointer " +
"if pointer-lock pref is set to FALSE");
}
document.addEventListener("mozpointerlockchange", function (e) {
if (document.mozPointerLockElement === div) {
prefEnabled = true;
document.mozExitPointerLock();
}
else {
SpecialPowers.setBoolPref("full-screen-api.pointer-lock.enabled",
false );
div.mozRequestPointerLock();
}
}, false);
document.addEventListener("mozpointerlockerror", function (e) {
prefDisabled = true;
document.mozCancelFullScreen();
}, false);
document.addEventListener("mozfullscreenchange", function (e) {
if (document.mozFullScreenElement === div) {
SpecialPowers.setBoolPref("full-screen-api.pointer-lock.enabled",
true );
div.mozRequestPointerLock();
}
else {
SpecialPowers.setBoolPref("full-screen-api.pointer-lock.enabled",
true );
runTests();
SimpleTest.finish();
}
}, false);
function start() {
SimpleTest.waitForFocus(function() {
div.mozRequestFullScreen();
});
}
</script>
</pre>
</body>
</html>

View File

@ -0,0 +1,92 @@
<!DOCTYPE HTML>
<html>
<!--https://bugzilla.mozilla.org/show_bug.cgi?id=633602-->
<head>
<title>Bug 633602</title>
<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js">
</script>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js">
</script>
<script type="application/javascript" src="pointerlock_utils.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body onload="start();">
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=633602">
Mozilla Bug 633602
</a>
<div id="div"></div>
<pre id="test">
<script type="text/javascript">
/*
* Test for Bug 633602
* Make sure DOM API is correct.
*/
SimpleTest.waitForExplicitFinish();
var div,
hasRequestPointerLock = false,
pointerLockChangeEventFired = false,
pointerUnlocked = false,
pointerLocked = false,
hasExitPointerLock = false,
pointerLockElement = false,
hasMovementX = false,
hasMovementY = false;
function runTests () {
ok(hasRequestPointerLock, "Element should have mozRequestPointerLock.");
ok(pointerLockChangeEventFired, "pointerlockchange event should fire.");
ok(pointerUnlocked, "Should be able to unlock pointer locked element.");
ok(pointerLocked, "Requested element should be able to lock.");
ok(hasExitPointerLock, "Document should have mozExitPointerLock");
ok(pointerLockElement, "Document should keep track of correct pointer locked element");
ok(hasMovementX, "Mouse Event should have mozMovementX.");
ok(hasMovementY, "Mouse Event should have mozMovementY.");
}
function mouseMoveHandler(e) {
document.removeEventListener("mousemove", mouseMoveHandler, false);
hasMovementX = "mozMovementX" in e;
hasMovementY = "mozMovementY" in e;
hasExitPointerLock = "mozExitPointerLock" in document;
document.mozExitPointerLock();
}
document.addEventListener("mozpointerlockchange", function (e) {
pointerLockChangeEventFired = true;
if (document.mozPointerLockElement) {
pointerLocked = true;
pointerLockElement = document.mozPointerLockElement === div;
document.addEventListener("mousemove", mouseMoveHandler, false);
synthesizeMouseAtCenter(div, {type: "mousemove"}, window);
} else {
pointerUnlocked = true;
document.mozCancelFullScreen();
}
}, false);
document.addEventListener("mozfullscreenchange", function(e) {
if (document.mozFullScreenElement === div) {
hasRequestPointerLock = "mozRequestPointerLock" in div;
div.mozRequestPointerLock();
} else {
runTests();
SimpleTest.finish();
}
}, false);
function start() {
SimpleTest.waitForFocus(function() {
div = document.getElementById("div");
div.mozRequestFullScreen();
});
}
</script>
</pre>
</body>
</html>

View File

@ -0,0 +1,43 @@
<!DOCTYPE HTML>
<html>
<!--https://bugzilla.mozilla.org/show_bug.cgi?id=633602-->
<head>
<title>Bug 633602</title>
<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js">
</script>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js">
</script>
<script type="application/javascript" src="pointerlock_utils.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body onload="start();">
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=633602">
Mozilla Bug 633602
</a>
<pre id="test">
<script type="text/javascript">
/*
* Test for Bug 633602
* Make sure pointerlockerror event fires.
*/
SimpleTest.waitForExplicitFinish();
document.addEventListener("mozpointerlockerror", function (e) {
ok(true, "pointerlockerror event should fire.");
SimpleTest.finish();
}, false);
function start() {
SimpleTest.waitForFocus(function() {
// element not in the DOM, not fullscreen, should fail to lock
div = document.createElement("div");
div.mozRequestPointerLock();
});
}
</script>
</pre>
</body>
</html>

View File

@ -0,0 +1,70 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=633602
Test DOM tree in full screen
-->
<head>
<title>Bug 633602 - file_DOMtree.html</title>
<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js">
</script>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js">
</script>
<script type="application/javascript" src="pointerlock_utils.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<style>
</style>
</head>
<body onload="start();">
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=633602">
Mozilla Bug 633602
</a>
<div id="div"></div>
<pre id="test">
<script type="text/javascript">
/*
* Test for Bug 633602
* Checks if pointer is unlocked when element is removed from
* the DOM Tree
*/
SimpleTest.waitForExplicitFinish();
var div = document.getElementById("div")
, removedDOM = false;
function runTests() {
ok(removedDOM, "Pointer should be unlocked when " +
"an element is removed the DOM Tree");
}
document.addEventListener("mozpointerlockchange", function (e) {
if (document.mozPointerLockElement === div) {
document.body.removeChild(div);
removedDOM = !document.mozPointerLockElement;
document.mozCancelFullScreen();
}
}, false);
document.addEventListener("mozfullscreenchange", function (e) {
if (document.mozFullScreenElement === div) {
div.mozRequestPointerLock();
}
else {
runTests();
SimpleTest.finish();
}
}, false);
function start() {
SimpleTest.waitForFocus(function() {
div.mozRequestFullScreen();
});
}
</script>
</pre>
</body>
</html>

View File

@ -0,0 +1,164 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=633602
-->
<head>
<title>Bug 633602 - file_retargetMouseEvents.html</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js">
</script>
<script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
<script type="application/javascript" src="pointerlock_utils.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body onload="start();">
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=633602">
Mozilla Bug 633602
</a>
<div id="parent">
<div id="child" style="width: 100%; height: 100%;">
</div>
</div>
<pre id="test">
<script type="application/javascript">
/*
* Test for Bug 633602
* Retarget mouse events to the locked element
*/
SimpleTest.waitForExplicitFinish();
function MouseEventStats() {
this.mouseMove = false;
this.mouseDown = false;
this.mouseUp = false;
this.mouseClick = false;
this.mouseScroll = false;
}
var parent = document.getElementById("parent")
, child = document.getElementById("child")
, parentStats = new MouseEventStats()
, childStats = new MouseEventStats();
function runTests () {
is(childStats.mouseMove, false, "Child shound not receive mousemove event.");
is(childStats.mouseDown, false, "Child should not receive mousedown event.");
is(childStats.mouseUp, false, "Child should not receive mouseup event.");
is(childStats.mouseClick, false, "Child should not receive click event.");
is(childStats.mouseScroll, false, "Child should not receive DOMMouseScroll event.");
ok(parentStats.mouseMove, "Parent should receive mousemove event.");
ok(parentStats.mouseDown, "Parent should receive mousedown event.");
ok(parentStats.mouseUp, "Parent should receive mouseup event.");
ok(parentStats.mouseClick, "Parent should receive click event.");
ok(parentStats.mouseScroll, "Parent should receive DOMMouseScroll event.");
}
/**
* The event listeners for the child element shouldn't be fired
* Mouse events will only happen when the pointer is locked
* and if the pointer is locked all the mouse events should be
* retargetted to the locked element
**/
var childMoveTest = function() {
childStats.mouseMove = true;
}
var childDownTest = function() {
childStats.mouseDown = true;
};
var childUpTest = function() {
childStats.mouseUp = true;
};
var childClickTest = function() {
childStats.mouseClick = true;
};
var childScrollTest = function() {
childStats.mouseScroll = true;
};
// Event listeners for the parent element
var startMouseTests = function() {
parent.removeEventListener("mousemove", startMouseTests);
parent.addEventListener("DOMMouseScroll", parentScrollTest);
child.addEventListener("DOMMouseScroll", childScrollTest);
synthesizeMouseScroll(child, 5, 5, {'delta': 10, 'type': "DOMMouseScroll"});
};
var parentScrollTest = function (e) {
parentStats.mouseScroll = true;
parent.removeEventListener("DOMMouseScroll", parentScrollTest);
child.removeEventListener("DOMMouseScroll", childScrollTest);
parent.addEventListener("mousedown", parentDownTest);
child.addEventListener("mousedown", childDownTest);
synthesizeMouseAtCenter(child, {type: "mousedown"}, window);
};
var parentDownTest = function (e) {
parentStats.mouseDown = true;
parent.removeEventListener("mousedown", parentDownTest);
child.removeEventListener("mousedown", childDownTest);
parent.addEventListener("mouseup", parentUpTest);
child.addEventListener("mouseup", childUpTest);
synthesizeMouseAtCenter(child, {type: "mouseup"}, window);
};
var parentUpTest = function (e) {
parentStats.mouseUp = true;
parent.removeEventListener("mouseup", parentUpTest);
child.removeEventListener("mouseup", childUpTest);
parent.addEventListener("click", parentClickTest);
child.addEventListener("click", childClickTest);
synthesizeMouseAtCenter(child, {type: "click"}, window);
};
var parentClickTest = function (e) {
parentStats.mouseClick = true;
parent.removeEventListener("click", parentClickTest);
child.removeEventListener("click", childClickTest);
parent.addEventListener("mousemove", parentMoveTest);
child.addEventListener("mousemove", childMoveTest);
synthesizeMouseAtCenter(child, {type: "mousemove"}, window);
};
var parentMoveTest = function (e) {
parentStats.mouseMove = true;
parent.removeEventListener("mousemove", parentMoveTest);
child.removeEventListener("mousemove", childMoveTest);
document.mozCancelFullScreen();
}
document.addEventListener("mozpointerlockchange", function (e) {
if (document.mozPointerLockElement === parent) {
parent.addEventListener("mousemove", startMouseTests);
child.addEventListener("mousemove", childMoveTest);
synthesizeMouseAtCenter(parent, {type: "mousemove"}, window);
}
}, false);
document.addEventListener("mozfullscreenchange", function (e) {
if (document.mozFullScreenElement === parent) {
parent.mozRequestPointerLock();
}
else {
runTests();
SimpleTest.finish();
}
}, false);
function start() {
SimpleTest.waitForFocus(function() {
parent.mozRequestFullScreen();
});
}
</script>
</pre>
</body>
</html>

View File

@ -0,0 +1,106 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=633602
-->
<head>
<title>Bug 633602 - constantXY.html</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js">
</script>
<script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
<script type="application/javascript" src="pointerlock_utils.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body onload="start();">
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=633602">
Mozilla Bug 633602
</a>
<div id="div"></div>
<script type="application/javascript">
/*
* Test for Bug 633602
* Confirm that screenX/Y and clientX/Y are constants when the pointer
* is locked.
*/
SimpleTest.waitForExplicitFinish();
var div
, divRect
, unLockedCoords
, lockedCoords
, isUnlocked = false
, isLocked = false;
function runTests () {
ok(isUnlocked, "Pointer should be unlocked");
ok(isLocked, "Pointer should be locked");
// Confirm that pointer coords are constant while locked
is(unLockedCoords.clientX, lockedCoords.clientX,
"clientX should be equal to where the mouse was originaly locked");
is(unLockedCoords.clientY, lockedCoords.clientY,
"clientY should be equal to where the mouse was originaly locked");
is(unLockedCoords.screenX, lockedCoords.screenX,
"screenX should be equal to where the mouse was originaly locked");
is(unLockedCoords.screenY, lockedCoords.screenY,
"screenY should be equal to where the mouse was originaly locked");
}
function moveUnlocked(e) {
div.removeEventListener("mousemove", moveUnlocked, false);
isUnlocked = !document.mozPointerLockElement;
unLockedCoords = {
screenX: e.screenX,
screenY: e.screenY,
clientX: e.clientX,
clientY: e.clientY
};
div.mozRequestPointerLock();
}
function moveLocked(e) {
div.removeEventListener("mousemove", moveLocked, false);
isLocked = !!document.mozPointerLockElement;
lockedCoords = {
screenX: e.screenX,
screenY: e.screenY,
clientX: e.clientX,
clientY: e.clientY
};
document.mozCancelFullScreen();
}
document.addEventListener("mozpointerlockchange", function (e) {
if (document.mozPointerLockElement === div) {
div.addEventListener("mousemove", moveLocked, false);
divRect = div.getBoundingClientRect();
synthesizeMouse(div, (divRect.width / 4) * 3, (divRect.height / 4) * 3, {
type: "mousemove"
}, window);
}
}, false);
document.addEventListener("mozfullscreenchange", function() {
if (document.mozFullScreenElement === div) {
div.addEventListener("mousemove", moveUnlocked, false);
synthesizeMouseAtCenter(div, { type: "mousemove" }, window);
} else {
runTests();
SimpleTest.finish();
}
}, false);
function start() {
SimpleTest.waitForFocus(function() {
div = document.getElementById("div");
div.mozRequestFullScreen();
});
}
</script>
</body>
</html>

View File

@ -0,0 +1,163 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=633602
-->
<head>
<title>Bug 633602 - file_cursorPosEvents.html</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js">
</script>
<script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
<script type="application/javascript" src="pointerlock_utils.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<style type="text/css">
#child {
width: 100px;
height: 100px;
background-color:Green;
}
</style>
</head>
<body onload="start();">
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=633602">
Mozilla Bug 633602</a>
<div id="parent">
<div id="child"></div>
</div>
<script type="application/javascript">
/*
* Test for Bug 633602
* Test will check to make sure that the following mouse events are no
* longer executed in pointer lock.
* - mouseover, mouseout, mouseenter, mouseleave
*/
SimpleTest.waitForExplicitFinish();
function PointerEventStats() {
this.mouseEnter = false;
this.mouseLeave = false;
this.mouseOver = false;
this.mouseOut = false;
}
var parent
, child
, parentStats = new PointerEventStats()
, childStats = new PointerEventStats()
, isPointerLocked = false;
function runTests () {
ok(isPointerLocked, "expected mouse to be locked, but wasn't.");
is(childStats.mouseEnter, false,
"child's mouseenter should not be firing in Full Screen and Pointer Lock.");
is(childStats.mouseOver, false,
"child's mouseover should not be firing in Full Screen and Pointer Lock.");
is(childStats.mouseLeave, false,
"child's mouseleave should not be firing in Full Screen and Pointer Lock.");
is(childStats.mouseOut, false,
"child's mouseout should not be firing in Full Screen and Pointer Lock.");
is(parentStats.mouseEnter, false,
"parent's mouseenter should not be firing in Full Screen and Pointer Lock.");
is(parentStats.mouseOver, false,
"parent's mouseover should not be firing in Full Screen and Pointer Lock.");
is(parentStats.mouseLeave, false,
"parent's mouseleave should not be firing in Full Screen and Pointer Lock.");
is(parentStats.mouseOut, false,
"parent's mouseout should not be firing in Full Screen and Pointer Lock.");
}
var parentMoveListener = function () {
isPointerLocked = !!document.mozPointerLockElement;
removeEventListeners();
document.mozExitPointerLock();
};
var parentOutListener = function (e) {
parentStats.mouseOut = true;
};
var parentLeaveListener = function (e) {
parentStats.mouseLeave = true;
};
var parentOverListener = function (e) {
parentStats.mouseOver = true;
};
var parentEnterListener = function (e) {
parentStats.mouseEnter = true;
};
var childOutListener = function (e) {
childStats.mouseOut = true;
};
var childLeaveListener = function (e) {
childStats.mouseLeave = true;
};
var childOverListener = function (e) {
childStats.mouseOver = true;
};
var childEnterListener = function (e) {
childStats.mouseEnter = true;
};
function addEventListeners() {
parent.addEventListener("mousemove", parentMoveListener, false);
parent.addEventListener("mouseout", parentOutListener, false);
parent.addEventListener("mouseleave", parentLeaveListener, false);
parent.addEventListener("mouseover", parentOverListener, false);
parent.addEventListener("mouseenter", parentEnterListener, false);
child.addEventListener("mouseout", childOutListener, false);
child.addEventListener("mouseleave", childLeaveListener, false);
child.addEventListener("mouseover", childOverListener, false);
child.addEventListener("mouseenter", childEnterListener, false);
}
function removeEventListeners() {
parent.removeEventListener("mousemove", parentMoveListener, false);
parent.removeEventListener("mouseout", parentOutListener, false);
parent.removeEventListener("mouseleave", parentLeaveListener, false);
parent.removeEventListener("mouseover", parentOverListener, false);
parent.removeEventListener("mouseenter", parentEnterListener, false);
child.removeEventListener("mouseout", childOutListener, false);
child.removeEventListener("mouseleave", childLeaveListener, false);
child.removeEventListener("mouseover" , childOverListener, false);
child.removeEventListener("mouseenter", childEnterListener, false);
}
document.addEventListener("mozpointerlockchange", function (e) {
if (document.mozPointerLockElement === parent) {
addEventListeners();
synthesizeMouseAtCenter(child, { type: "mousemove" }, window);
}
else {
document.mozCancelFullScreen();
}
}, false);
document.addEventListener("mozfullscreenchange", function() {
if (document.mozFullScreenElement === parent) {
parent.mozRequestPointerLock();
}
else {
runTests();
SimpleTest.finish();
}
}, false);
function start() {
SimpleTest.waitForFocus(function() {
parent = document.getElementById("parent");
child = document.getElementById("child");
parent.mozRequestFullScreen();
});
}
</script>
</body>
</html>

View File

@ -0,0 +1,73 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=633602
-->
<head>
<title>Bug 633602 - file_targetOutOfFocus.html</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js">
</script>
<script type="text/javascript" src="/tests/SimpleTest/EventUtils.js">
</script>
<script type="application/javascript" src="pointerlock_utils.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body onload="start();">
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=633602">
Mozilla Bug 633602
</a>
<p id="display"></p>
<div id="content">
</div>
<div id="div"></div>
<input id="input" type="text" />
<pre id="test">
<script type="application/javascript">
/*
* Test for Bug 633602
* Element doesn't need to have focus to request
* pointer lock
*/
SimpleTest.waitForExplicitFinish();
var div = document.getElementById("div")
, input = document.getElementById("input")
, divPointerLock = false;
function runTests () {
ok(divPointerLock, "Pointer should be locked even if " +
"the element being locked is not focused");
}
input.addEventListener("focus", function() {
div.mozRequestPointerLock();
}, false);
document.addEventListener("mozpointerlockchange", function (e) {
if (document.mozPointerLockElement === div) {
divPointerLock = true;
document.mozCancelFullScreen();
}
}, false);
document.addEventListener("mozfullscreenchange", function() {
if (document.mozFullScreenElement === div) {
input.focus();
}
else {
runTests();
SimpleTest.finish();
}
}, false);
function start() {
SimpleTest.waitForFocus(function() {
div.mozRequestFullScreen();
});
}
</script>
</pre>
</body>
</html>

View File

@ -0,0 +1,56 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=633602
Test DOM tree in full screen
-->
<head>
<title>Bug 633602 - file_DOMtree.html</title>
<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js">
</script>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js">
</script>
<script type="application/javascript" src="pointerlock_utils.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<style>
</style>
</head>
<body onload="start();">
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=633602">
Mozilla Bug 633602
</a>
<pre id="test">
<script type="text/javascript">
/*
* Test for Bug 633602
* Checks if element is attached to the DOM Tree before locking
* the pointer
*/
SimpleTest.waitForExplicitFinish();
var div = document.createElement("div")
, withouthDOM = false;
function runTests () {
ok(withouthDOM, "If an element is NOT in the " +
"DOM Tree pointer should NOT be locked");
}
document.addEventListener("mozpointerlockerror", function (e) {
withouthDOM = true;
runTests();
SimpleTest.finish();
}, false);
function start() {
SimpleTest.waitForFocus(function() {
div.mozRequestPointerLock();
});
}
</script>
</pre>
</body>
</html>

View File

@ -0,0 +1,7 @@
<html>
<head>
</head>
<body>
<div id="div"></div>
</body>
</html>

View File

@ -0,0 +1,34 @@
// Get test filename for page being run in popup so errors are more useful
var testName = location.pathname.split('/').pop();
// Wrap test functions and pass to parent window
function ok(a, msg) {
opener.ok(a, testName + ": " + msg);
}
function is(a, b, msg) {
opener.is(a, b, testName + ": " + msg);
}
function isnot(a, b, msg) {
opener.isnot(a, b, testName + ": " + msg);
}
function todo(a, msg) {
opener.todo(a, testName + ": " + msg);
}
function todo_is(a, b, msg) {
opener.todo_is(a, b, testName + ": " + msg);
}
function todo_isnot(a, b, msg) {
opener.todo_isnot(a, b, testName + ": " + msg);
}
// Override SimpleTest so test files work stand-alone
SimpleTest.finish = function () {
opener.nextTest();
};
SimpleTest.waitForExplicitFinish = function() {};

View File

@ -0,0 +1,85 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=633602
-->
<head>
<title>Test for Bug 633602</title>
<script type="application/javascript"
src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript"
src="/tests/SimpleTest/EventUtils.js"></script>
<link rel="stylesheet" type="text/css"
href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=633602">
Mozilla Bug 633602
</a>
<div id="content">
</div>
<pre id="test">
<script type="application/javascript">
SimpleTest.waitForExplicitFinish();
// Ensure the full-screen api is enabled,
// and will be disabled on test exit.
var prevEnabled = SpecialPowers.getBoolPref("full-screen-api.enabled");
SpecialPowers.setBoolPref("full-screen-api.enabled", true);
// Disable the requirement for trusted contexts only,
// so the tests are easier to write.
var prevTrusted = SpecialPowers.getBoolPref(
"full-screen-api.allow-trusted-requests-only");
SpecialPowers.setBoolPref("full-screen-api.allow-trusted-requests-only",
false);
// Run the tests which go full-screen in new window, as Mochitests
// normally run in an iframe, which by default will not have the
// mozallowfullscreen attribute set, so full-screen won't work.
var gTestFiles = [
"file_childIframe.html",
"file_doubleLock.html",
"file_escapeKey.html",
"file_infiniteMovement.html",
"file_locksvgelement.html",
"file_loseFocusWindow.html",
"file_movementXY.html",
"file_nestedFullScreen.html",
"file_pointerlock-api.html",
"file_pointerlockerror.html",
"file_pointerLockPref.html",
"file_removedFromDOM.html",
"file_retargetMouseEvents.html",
"file_screenClientXYConst.html",
"file_suppressSomeMouseEvents.html",
"file_targetOutOfFocus.html",
"file_withoutDOM.html"
];
var testWindow = null;
var gTestIndex = 0;
function nextTest() {
if (testWindow) {
testWindow.close();
}
if (gTestIndex < gTestFiles.length) {
testWindow = window.open(gTestFiles[gTestIndex],
"",
"width=500,height=500");
gTestIndex++;
} else {
SpecialPowers.setBoolPref("full-screen-api.enabled",
prevEnabled);
SpecialPowers.setBoolPref("full-screen-api.allow-trusted-requests-only",
prevTrusted);
SimpleTest.finish();
}
}
addLoadEvent(nextTest);
</script>
</pre>
</body>
</html>

View File

@ -134,10 +134,13 @@ class LayerManager;
#define CAPTURE_RETARGETTOELEMENT 2
// true if the current capture wants drags to be prevented
#define CAPTURE_PREVENTDRAG 4
// true when the mouse is pointer locked, and events are sent to locked elemnt
#define CAPTURE_POINTERLOCK 8
typedef struct CapturingContentInfo {
// capture should only be allowed during a mousedown event
bool mAllowed;
bool mPointerLock;
bool mRetargetToElement;
bool mPreventDrag;
nsIContent* mContent;
@ -1103,6 +1106,11 @@ public:
*
* If CAPTURE_PREVENTDRAG is set then drags are prevented from starting while
* this capture is active.
*
* If CAPTURE_POINTERLOCK is set, similar to CAPTURE_RETARGETTOELEMENT, then
* events are targeted at aContent, but capturing is held more strongly (i.e.,
* calls to SetCapturingContent won't unlock unless CAPTURE_POINTERLOCK is
* set again).
*/
static void SetCapturingContent(nsIContent* aContent, PRUint8 aFlags);

View File

@ -228,7 +228,7 @@ using namespace mozilla::dom;
using namespace mozilla::layers;
CapturingContentInfo nsIPresShell::gCaptureInfo =
{ false /* mAllowed */, false /* mRetargetToElement */,
{ false /* mAllowed */, false /* mPointerLock */, false /* mRetargetToElement */,
false /* mPreventDrag */, nsnull /* mContent */ };
nsIContent* nsIPresShell::gKeyDownTarget;
nsInterfaceHashtable<nsUint32HashKey, nsIDOMTouch> nsIPresShell::gCaptureTouchList;
@ -5447,16 +5447,27 @@ PresShell::Paint(nsIView* aViewToPaint,
void
nsIPresShell::SetCapturingContent(nsIContent* aContent, PRUint8 aFlags)
{
// If capture was set for pointer lock, don't unlock unless we are coming
// out of pointer lock explicitly.
if (!aContent && gCaptureInfo.mPointerLock &&
!(aFlags & CAPTURE_POINTERLOCK)) {
return;
}
NS_IF_RELEASE(gCaptureInfo.mContent);
// only set capturing content if allowed or the CAPTURE_IGNOREALLOWED flag
// is used
if ((aFlags & CAPTURE_IGNOREALLOWED) || gCaptureInfo.mAllowed) {
// only set capturing content if allowed or the CAPTURE_IGNOREALLOWED or
// CAPTURE_POINTERLOCK flags are used.
if ((aFlags & CAPTURE_IGNOREALLOWED) || gCaptureInfo.mAllowed ||
(aFlags & CAPTURE_POINTERLOCK)) {
if (aContent) {
NS_ADDREF(gCaptureInfo.mContent = aContent);
}
gCaptureInfo.mRetargetToElement = (aFlags & CAPTURE_RETARGETTOELEMENT) != 0;
// CAPTURE_POINTERLOCK is the same as CAPTURE_RETARGETTOELEMENT & CAPTURE_IGNOREALLOWED
gCaptureInfo.mRetargetToElement = ((aFlags & CAPTURE_RETARGETTOELEMENT) != 0) ||
((aFlags & CAPTURE_POINTERLOCK) != 0);
gCaptureInfo.mPreventDrag = (aFlags & CAPTURE_PREVENTDRAG) != 0;
gCaptureInfo.mPointerLock = (aFlags & CAPTURE_POINTERLOCK) != 0;
}
}
@ -5750,7 +5761,8 @@ PresShell::HandleEvent(nsIFrame *aFrame,
NS_TIME_FUNCTION_MIN(1.0);
nsIContent* capturingContent =
NS_IS_MOUSE_EVENT(aEvent) ? GetCapturingContent() : nsnull;
NS_IS_MOUSE_EVENT(aEvent) || aEvent->eventStructType == NS_MOUSE_SCROLL_EVENT ?
GetCapturingContent() : nsnull;
nsCOMPtr<nsIDocument> retargetEventDoc;
if (!aDontRetargetEvents) {

View File

@ -3486,6 +3486,7 @@ pref("full-screen-api.allow-trusted-requests-only", true);
pref("full-screen-api.key-input-restricted", true);
pref("full-screen-api.warning.enabled", true);
pref("full-screen-api.exit-on-deactivate", true);
pref("full-screen-api.pointer-lock.enabled", true);
// Time limit, in milliseconds, for nsEventStateManager::IsHandlingUserInput().
// Used to detect long running handlers of user-generated events.

View File

@ -489,6 +489,9 @@ public:
PRUint32 aNativeMessage,
PRUint32 aModifierFlags);
virtual nsresult SynthesizeNativeMouseMove(nsIntPoint aPoint)
{ return SynthesizeNativeMouseEvent(aPoint, NSMouseMoved, 0); }
// Mac specific methods
virtual bool DispatchWindowEvent(nsGUIEvent& event);

View File

@ -6493,3 +6493,19 @@ nsWindow::ClearCachedResources()
}
}
}
nsresult
nsWindow::SynthesizeNativeMouseEvent(nsIntPoint aPoint,
PRUint32 aNativeMessage,
PRUint32 aModifierFlags)
{
if (!mGdkWindow) {
return NS_OK;
}
GdkDisplay* display = gdk_window_get_display(mGdkWindow);
GdkScreen* screen = gdk_window_get_screen(mGdkWindow);
gdk_display_warp_pointer(display, screen, aPoint.x, aPoint.y);
return NS_OK;
}

View File

@ -347,6 +347,13 @@ public:
#endif
NS_IMETHOD ReparentNativeWidget(nsIWidget* aNewParent);
virtual nsresult SynthesizeNativeMouseEvent(nsIntPoint aPoint,
PRUint32 aNativeMessage,
PRUint32 aModifierFlags);
virtual nsresult SynthesizeNativeMouseMove(nsIntPoint aPoint)
{ return SynthesizeNativeMouseEvent(aPoint, GDK_MOTION_NOTIFY, 0); }
protected:
// Helper for SetParent and ReparentNativeWidget.
void ReparentNativeWidgetInternal(nsIWidget* aNewParent,

View File

@ -558,6 +558,11 @@ class nsHashKey;
#define NS_TOUCH_LEAVE (NS_TOUCH_EVENT_START+4)
#define NS_TOUCH_CANCEL (NS_TOUCH_EVENT_START+5)
// Pointerlock DOM API
#define NS_POINTERLOCK_START 5300
#define NS_POINTERLOCKCHANGE (NS_POINTERLOCK_START)
#define NS_POINTERLOCKERROR (NS_POINTERLOCK_START + 1)
/**
* Return status for event processors, nsEventStatus, is defined in
* nsEvent.h.
@ -583,6 +588,7 @@ protected:
: eventStructType(structType),
message(msg),
refPoint(0, 0),
lastRefPoint(0, 0),
time(0),
flags(isTrusted ? NS_EVENT_FLAG_TRUSTED : NS_EVENT_FLAG_NONE),
userType(0)
@ -599,6 +605,7 @@ public:
: eventStructType(NS_EVENT),
message(msg),
refPoint(0, 0),
lastRefPoint(0, 0),
time(0),
flags(isTrusted ? NS_EVENT_FLAG_TRUSTED : NS_EVENT_FLAG_NONE),
userType(0)
@ -618,6 +625,8 @@ public:
// Relative to the widget of the event, or if there is no widget then it is
// in screen coordinates. Not modified by layout code.
nsIntPoint refPoint;
// The previous refPoint, if known, used to calculate mouse movement deltas.
nsIntPoint lastRefPoint;
// Elapsed time, in milliseconds, from a platform-specific zero time
// to the time the message was created
PRUint64 time;

View File

@ -118,8 +118,8 @@ typedef nsEventStatus (* EVENT_CALLBACK)(nsGUIEvent *event);
#endif
#define NS_IWIDGET_IID \
{ 0xe7af49c1, 0xd11b, 0x4070, \
{ 0x99, 0x7a, 0x2d, 0x2b, 0x7, 0x4b, 0xea, 0xf4 } }
{ 0xb5bb55c7, 0x9a50, 0x4fa8, \
{ 0xa7, 0x6e, 0xbd, 0x31, 0x6f, 0x3e, 0x9c, 0x13 } }
/*
* Window shadow styles
@ -1376,6 +1376,11 @@ class nsIWidget : public nsISupports {
PRUint32 aNativeMessage,
PRUint32 aModifierFlags) = 0;
/**
* A shortcut to SynthesizeNativeMouseEvent, abstracting away the native message.
*/
virtual nsresult SynthesizeNativeMouseMove(nsIntPoint aPoint) = 0;
/**
* Utility method intended for testing. Dispatching native mouse scroll
* events may move the mouse cursor.

View File

@ -177,6 +177,10 @@ public:
virtual nsresult SynthesizeNativeMouseEvent(nsIntPoint aPoint,
PRUint32 aNativeMessage,
PRUint32 aModifierFlags);
virtual nsresult SynthesizeNativeMouseMove(nsIntPoint aPoint)
{ return SynthesizeNativeMouseEvent(aPoint, MOUSEEVENTF_MOVE, 0); }
virtual nsresult SynthesizeNativeMouseScrollEvent(nsIntPoint aPoint,
PRUint32 aNativeMessage,
double aDeltaX,

View File

@ -270,6 +270,9 @@ protected:
PRUint32 aModifierFlags)
{ return NS_ERROR_UNEXPECTED; }
virtual nsresult SynthesizeNativeMouseMove(nsIntPoint aPoint)
{ return NS_ERROR_UNEXPECTED; }
virtual nsresult SynthesizeNativeMouseScrollEvent(nsIntPoint aPoint,
PRUint32 aNativeMessage,
double aDeltaX,