2007-03-22 10:30:00 -07:00
|
|
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
2012-05-21 04:12:37 -07:00
|
|
|
/* 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/. */
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2013-12-08 18:52:54 -08:00
|
|
|
#include "mozilla/ArrayUtils.h"
|
2011-10-10 22:50:08 -07:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
#include "nsCOMPtr.h"
|
|
|
|
#include "nsXBLPrototypeHandler.h"
|
|
|
|
#include "nsXBLPrototypeBinding.h"
|
|
|
|
#include "nsContentUtils.h"
|
2013-05-22 09:05:26 -07:00
|
|
|
#include "nsCxPusher.h"
|
2007-03-22 10:30:00 -07:00
|
|
|
#include "nsIContent.h"
|
|
|
|
#include "nsIAtom.h"
|
|
|
|
#include "nsIDOMKeyEvent.h"
|
|
|
|
#include "nsIDOMMouseEvent.h"
|
2014-02-27 15:04:46 -08:00
|
|
|
#include "nsNameSpaceManager.h"
|
2007-03-22 10:30:00 -07:00
|
|
|
#include "nsIScriptContext.h"
|
|
|
|
#include "nsIDocument.h"
|
|
|
|
#include "nsIController.h"
|
|
|
|
#include "nsIControllers.h"
|
|
|
|
#include "nsIDOMXULElement.h"
|
|
|
|
#include "nsIURI.h"
|
2011-06-11 00:52:24 -07:00
|
|
|
#include "nsIDOMHTMLTextAreaElement.h"
|
2010-08-04 19:40:18 -07:00
|
|
|
#include "nsIDOMHTMLInputElement.h"
|
Bug 178324, refactor focus by moving all focus handling into one place and simplifying it, add many tests, fixes many other bugs too numerous to mention in this small checkin comment, r=josh,smichaud,ere,dbaron,marco,neil,gavin,smaug,sr=smaug (CLOSED TREE)
2009-06-10 11:00:39 -07:00
|
|
|
#include "nsFocusManager.h"
|
2007-03-22 10:30:00 -07:00
|
|
|
#include "nsIDOMEventListener.h"
|
|
|
|
#include "nsPIDOMWindow.h"
|
|
|
|
#include "nsPIWindowRoot.h"
|
2011-07-15 03:31:34 -07:00
|
|
|
#include "nsIDOMWindow.h"
|
2007-03-22 10:30:00 -07:00
|
|
|
#include "nsIServiceManager.h"
|
|
|
|
#include "nsIScriptError.h"
|
|
|
|
#include "nsXPIDLString.h"
|
2008-03-28 12:44:45 -07:00
|
|
|
#include "nsReadableUtils.h"
|
2007-03-22 10:30:00 -07:00
|
|
|
#include "nsGkAtoms.h"
|
|
|
|
#include "nsIXPConnect.h"
|
|
|
|
#include "nsIDOMScriptObjectFactory.h"
|
|
|
|
#include "nsDOMCID.h"
|
|
|
|
#include "nsUnicharUtils.h"
|
|
|
|
#include "nsCRT.h"
|
|
|
|
#include "nsXBLEventHandler.h"
|
2011-11-03 13:39:08 -07:00
|
|
|
#include "nsXBLSerialize.h"
|
2013-01-22 22:12:50 -08:00
|
|
|
#include "nsJSUtils.h"
|
2013-09-25 04:21:22 -07:00
|
|
|
#include "mozilla/BasicEvents.h"
|
2014-04-01 19:00:45 -07:00
|
|
|
#include "mozilla/JSEventHandler.h"
|
2011-05-24 23:32:00 -07:00
|
|
|
#include "mozilla/Preferences.h"
|
2012-11-09 08:00:25 -08:00
|
|
|
#include "mozilla/dom/EventHandlerBinding.h"
|
2011-05-24 23:32:00 -07:00
|
|
|
|
|
|
|
using namespace mozilla;
|
2012-11-09 08:00:25 -08:00
|
|
|
using namespace mozilla::dom;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-08-22 08:56:38 -07:00
|
|
|
uint32_t nsXBLPrototypeHandler::gRefCnt = 0;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-08-22 08:56:38 -07:00
|
|
|
int32_t nsXBLPrototypeHandler::kMenuAccessKey = -1;
|
|
|
|
int32_t nsXBLPrototypeHandler::kAccelKey = -1;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-08-22 08:56:38 -07:00
|
|
|
const int32_t nsXBLPrototypeHandler::cShift = (1<<0);
|
|
|
|
const int32_t nsXBLPrototypeHandler::cAlt = (1<<1);
|
|
|
|
const int32_t nsXBLPrototypeHandler::cControl = (1<<2);
|
|
|
|
const int32_t nsXBLPrototypeHandler::cMeta = (1<<3);
|
|
|
|
const int32_t nsXBLPrototypeHandler::cOS = (1<<4);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-08-22 08:56:38 -07:00
|
|
|
const int32_t nsXBLPrototypeHandler::cShiftMask = (1<<5);
|
|
|
|
const int32_t nsXBLPrototypeHandler::cAltMask = (1<<6);
|
|
|
|
const int32_t nsXBLPrototypeHandler::cControlMask = (1<<7);
|
|
|
|
const int32_t nsXBLPrototypeHandler::cMetaMask = (1<<8);
|
|
|
|
const int32_t nsXBLPrototypeHandler::cOSMask = (1<<9);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-08-22 08:56:38 -07:00
|
|
|
const int32_t nsXBLPrototypeHandler::cAllModifiers =
|
2012-07-18 18:28:16 -07:00
|
|
|
cShiftMask | cAltMask | cControlMask | cMetaMask | cOSMask;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2014-01-04 07:02:17 -08:00
|
|
|
nsXBLPrototypeHandler::nsXBLPrototypeHandler(const char16_t* aEvent,
|
|
|
|
const char16_t* aPhase,
|
|
|
|
const char16_t* aAction,
|
|
|
|
const char16_t* aCommand,
|
|
|
|
const char16_t* aKeyCode,
|
|
|
|
const char16_t* aCharCode,
|
|
|
|
const char16_t* aModifiers,
|
|
|
|
const char16_t* aButton,
|
|
|
|
const char16_t* aClickCount,
|
|
|
|
const char16_t* aGroup,
|
|
|
|
const char16_t* aPreventDefault,
|
|
|
|
const char16_t* aAllowUntrusted,
|
2007-12-04 23:21:18 -08:00
|
|
|
nsXBLPrototypeBinding* aBinding,
|
2012-08-22 08:56:38 -07:00
|
|
|
uint32_t aLineNumber)
|
2012-07-30 07:20:58 -07:00
|
|
|
: mHandlerText(nullptr),
|
2007-12-04 23:21:18 -08:00
|
|
|
mLineNumber(aLineNumber),
|
2012-07-30 07:20:58 -07:00
|
|
|
mNextHandler(nullptr),
|
2007-03-22 10:30:00 -07:00
|
|
|
mPrototypeBinding(aBinding)
|
|
|
|
{
|
2011-11-03 13:39:08 -07:00
|
|
|
Init();
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-07-30 07:20:58 -07:00
|
|
|
ConstructPrototype(nullptr, aEvent, aPhase, aAction, aCommand, aKeyCode,
|
2007-03-22 10:30:00 -07:00
|
|
|
aCharCode, aModifiers, aButton, aClickCount,
|
|
|
|
aGroup, aPreventDefault, aAllowUntrusted);
|
|
|
|
}
|
|
|
|
|
|
|
|
nsXBLPrototypeHandler::nsXBLPrototypeHandler(nsIContent* aHandlerElement)
|
2012-07-30 07:20:58 -07:00
|
|
|
: mHandlerElement(nullptr),
|
2007-03-22 10:30:00 -07:00
|
|
|
mLineNumber(0),
|
2012-07-30 07:20:58 -07:00
|
|
|
mNextHandler(nullptr),
|
|
|
|
mPrototypeBinding(nullptr)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2011-11-03 13:39:08 -07:00
|
|
|
Init();
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
// Make sure our prototype is initialized.
|
|
|
|
ConstructPrototype(aHandlerElement);
|
|
|
|
}
|
|
|
|
|
2011-11-03 13:39:08 -07:00
|
|
|
nsXBLPrototypeHandler::nsXBLPrototypeHandler(nsXBLPrototypeBinding* aBinding)
|
2012-07-30 07:20:58 -07:00
|
|
|
: mHandlerText(nullptr),
|
2012-07-20 04:16:17 -07:00
|
|
|
mLineNumber(0),
|
2012-07-30 07:20:58 -07:00
|
|
|
mNextHandler(nullptr),
|
2011-11-03 13:39:08 -07:00
|
|
|
mPrototypeBinding(aBinding)
|
|
|
|
{
|
|
|
|
Init();
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
nsXBLPrototypeHandler::~nsXBLPrototypeHandler()
|
|
|
|
{
|
|
|
|
--gRefCnt;
|
|
|
|
if (mType & NS_HANDLER_TYPE_XUL) {
|
|
|
|
NS_IF_RELEASE(mHandlerElement);
|
|
|
|
} else if (mHandlerText) {
|
|
|
|
nsMemory::Free(mHandlerText);
|
|
|
|
}
|
|
|
|
|
|
|
|
// We own the next handler in the chain, so delete it now.
|
2008-12-15 03:33:56 -08:00
|
|
|
NS_CONTENT_DELETE_LIST_MEMBER(nsXBLPrototypeHandler, this, mNextHandler);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
already_AddRefed<nsIContent>
|
|
|
|
nsXBLPrototypeHandler::GetHandlerElement()
|
|
|
|
{
|
|
|
|
if (mType & NS_HANDLER_TYPE_XUL) {
|
|
|
|
nsCOMPtr<nsIContent> element = do_QueryReferent(mHandlerElement);
|
2013-04-22 04:15:59 -07:00
|
|
|
return element.forget();
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2012-07-30 07:20:58 -07:00
|
|
|
return nullptr;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsXBLPrototypeHandler::AppendHandlerText(const nsAString& aText)
|
|
|
|
{
|
|
|
|
if (mHandlerText) {
|
|
|
|
// Append our text to the existing text.
|
2014-01-04 07:02:17 -08:00
|
|
|
char16_t* temp = mHandlerText;
|
2007-03-22 10:30:00 -07:00
|
|
|
mHandlerText = ToNewUnicode(nsDependentString(temp) + aText);
|
|
|
|
nsMemory::Free(temp);
|
|
|
|
}
|
2008-02-12 20:17:18 -08:00
|
|
|
else {
|
2007-03-22 10:30:00 -07:00
|
|
|
mHandlerText = ToNewUnicode(aText);
|
2008-02-12 20:17:18 -08:00
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Get the menu access key from prefs.
|
|
|
|
// XXX Eventually pick up using CSS3 key-equivalent property or somesuch
|
|
|
|
void
|
|
|
|
nsXBLPrototypeHandler::InitAccessKeys()
|
|
|
|
{
|
|
|
|
if (kAccelKey >= 0 && kMenuAccessKey >= 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Compiled-in defaults, in case we can't get the pref --
|
|
|
|
// mac doesn't have menu shortcuts, other platforms use alt.
|
|
|
|
#ifdef XP_MACOSX
|
|
|
|
kMenuAccessKey = 0;
|
|
|
|
kAccelKey = nsIDOMKeyEvent::DOM_VK_META;
|
|
|
|
#else
|
|
|
|
kMenuAccessKey = nsIDOMKeyEvent::DOM_VK_ALT;
|
|
|
|
kAccelKey = nsIDOMKeyEvent::DOM_VK_CONTROL;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// Get the menu access key value from prefs, overriding the default:
|
|
|
|
kMenuAccessKey =
|
2011-05-24 23:32:00 -07:00
|
|
|
Preferences::GetInt("ui.key.menuAccessKey", kMenuAccessKey);
|
|
|
|
kAccelKey = Preferences::GetInt("ui.key.accelKey", kAccelKey);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
2013-04-05 17:44:26 -07:00
|
|
|
nsXBLPrototypeHandler::ExecuteHandler(EventTarget* aTarget,
|
2007-03-22 10:30:00 -07:00
|
|
|
nsIDOMEvent* aEvent)
|
|
|
|
{
|
|
|
|
nsresult rv = NS_ERROR_FAILURE;
|
|
|
|
|
|
|
|
// Prevent default action?
|
|
|
|
if (mType & NS_HANDLER_TYPE_PREVENTDEFAULT) {
|
|
|
|
aEvent->PreventDefault();
|
|
|
|
// If we prevent default, then it's okay for
|
|
|
|
// mHandlerElement and mHandlerText to be null
|
|
|
|
rv = NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!mHandlerElement) // This works for both types of handlers. In both cases, the union's var should be defined.
|
|
|
|
return rv;
|
|
|
|
|
|
|
|
// See if our event receiver is a content node (and not us).
|
2011-09-28 23:19:26 -07:00
|
|
|
bool isXULKey = !!(mType & NS_HANDLER_TYPE_XUL);
|
|
|
|
bool isXBLCommand = !!(mType & NS_HANDLER_TYPE_XBL_COMMAND);
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_ASSERTION(!(isXULKey && isXBLCommand),
|
|
|
|
"can't be both a key and xbl command handler");
|
|
|
|
|
|
|
|
// XUL handlers and commands shouldn't be triggered by non-trusted
|
|
|
|
// events.
|
|
|
|
if (isXULKey || isXBLCommand) {
|
2011-09-28 23:19:26 -07:00
|
|
|
bool trustedEvent = false;
|
2012-08-04 00:44:00 -07:00
|
|
|
aEvent->GetIsTrusted(&trustedEvent);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
if (!trustedEvent)
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (isXBLCommand) {
|
2007-12-04 23:21:18 -08:00
|
|
|
return DispatchXBLCommand(aTarget, aEvent);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// If we're executing on a XUL key element, just dispatch a command
|
|
|
|
// event at the element. It will take care of retargeting it to its
|
|
|
|
// command element, if applicable, and executing the event handler.
|
|
|
|
if (isXULKey) {
|
2007-12-04 23:21:18 -08:00
|
|
|
return DispatchXULKeyCommand(aEvent);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Look for a compiled handler on the element.
|
|
|
|
// Should be compiled and bound with "on" in front of the name.
|
2010-03-08 07:45:00 -08:00
|
|
|
nsCOMPtr<nsIAtom> onEventAtom = do_GetAtom(NS_LITERAL_STRING("onxbl") +
|
|
|
|
nsDependentAtomString(mEventName));
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
// Compile the handler and bind it to the element.
|
|
|
|
nsCOMPtr<nsIScriptGlobalObject> boundGlobal;
|
2007-05-14 02:11:38 -07:00
|
|
|
nsCOMPtr<nsPIWindowRoot> winRoot(do_QueryInterface(aTarget));
|
2010-02-20 08:07:03 -08:00
|
|
|
nsCOMPtr<nsPIDOMWindow> window;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
if (winRoot) {
|
2007-07-06 06:47:50 -07:00
|
|
|
window = winRoot->GetWindow();
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2007-07-06 06:47:50 -07:00
|
|
|
if (window) {
|
2010-02-20 08:07:03 -08:00
|
|
|
window = window->GetCurrentInnerWindow();
|
|
|
|
NS_ENSURE_TRUE(window, NS_ERROR_UNEXPECTED);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2010-02-20 08:07:03 -08:00
|
|
|
boundGlobal = do_QueryInterface(window->GetPrivateRoot());
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
2007-05-14 02:11:38 -07:00
|
|
|
else boundGlobal = do_QueryInterface(aTarget);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
if (!boundGlobal) {
|
2007-05-14 02:11:38 -07:00
|
|
|
nsCOMPtr<nsIDocument> boundDocument(do_QueryInterface(aTarget));
|
2007-03-22 10:30:00 -07:00
|
|
|
if (!boundDocument) {
|
|
|
|
// We must be an element.
|
2007-05-14 02:11:38 -07:00
|
|
|
nsCOMPtr<nsIContent> content(do_QueryInterface(aTarget));
|
2007-03-22 10:30:00 -07:00
|
|
|
if (!content)
|
|
|
|
return NS_OK;
|
2011-10-18 03:53:36 -07:00
|
|
|
boundDocument = content->OwnerDoc();
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2013-04-04 02:27:41 -07:00
|
|
|
boundGlobal = do_QueryInterface(boundDocument->GetScopeObject());
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!boundGlobal)
|
|
|
|
return NS_OK;
|
|
|
|
|
2012-03-23 10:13:29 -07:00
|
|
|
nsIScriptContext *boundContext = boundGlobal->GetScriptContext();
|
2007-12-04 23:21:18 -08:00
|
|
|
if (!boundContext)
|
|
|
|
return NS_OK;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
nsISupports *scriptTarget;
|
|
|
|
|
|
|
|
if (winRoot) {
|
|
|
|
scriptTarget = boundGlobal;
|
|
|
|
} else {
|
2007-05-14 02:11:38 -07:00
|
|
|
scriptTarget = aTarget;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
2007-08-16 14:46:33 -07:00
|
|
|
|
2014-04-01 19:00:46 -07:00
|
|
|
// We're about to create a new JSEventHandler, which means that we're
|
2012-06-28 14:47:56 -07:00
|
|
|
// responsible for pushing the context of the event target. See the similar
|
|
|
|
// comment in nsEventManagerListener.cpp.
|
|
|
|
nsCxPusher pusher;
|
|
|
|
NS_ENSURE_STATE(pusher.Push(aTarget));
|
|
|
|
|
2013-03-20 13:09:09 -07:00
|
|
|
AutoPushJSContext cx(boundContext->GetNativeContext());
|
|
|
|
JS::Rooted<JSObject*> handler(cx);
|
|
|
|
|
|
|
|
rv = EnsureEventHandler(boundGlobal, boundContext, onEventAtom, &handler);
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
2013-03-20 13:09:09 -07:00
|
|
|
JS::Rooted<JSObject*> globalObject(cx, boundGlobal->GetGlobalJSObject());
|
2014-03-19 09:35:45 -07:00
|
|
|
JS::Rooted<JSObject*> scopeObject(cx, xpc::GetXBLScopeOrGlobal(cx, globalObject));
|
2013-04-05 12:04:09 -07:00
|
|
|
NS_ENSURE_TRUE(scopeObject, NS_ERROR_OUT_OF_MEMORY);
|
2013-02-08 06:24:22 -08:00
|
|
|
|
|
|
|
// Bind it to the bound element. Note that if we're using a separate XBL scope,
|
|
|
|
// we'll actually be binding the event handler to a cross-compartment wrapper
|
|
|
|
// to the bound element's reflector.
|
|
|
|
|
|
|
|
// First, enter our XBL scope. This is where the generic handler should have
|
|
|
|
// been compiled, above.
|
|
|
|
JSAutoCompartment ac(cx, scopeObject);
|
2013-03-20 13:09:09 -07:00
|
|
|
JS::Rooted<JSObject*> genericHandler(cx, handler.get());
|
2013-10-15 17:02:23 -07:00
|
|
|
bool ok = JS_WrapObject(cx, &genericHandler);
|
2013-02-08 06:24:22 -08:00
|
|
|
NS_ENSURE_TRUE(ok, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
MOZ_ASSERT(!js::IsCrossCompartmentWrapper(genericHandler));
|
|
|
|
|
|
|
|
// Wrap the native into the XBL scope. This creates a reflector in the document
|
|
|
|
// scope if one doesn't already exist, and potentially wraps it cross-
|
|
|
|
// compartment into our scope (via aAllowWrapping=true).
|
2013-03-20 13:09:09 -07:00
|
|
|
JS::Rooted<JS::Value> targetV(cx, JS::UndefinedValue());
|
2014-04-09 21:58:41 -07:00
|
|
|
rv = nsContentUtils::WrapNative(cx, scriptTarget, &targetV);
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
2013-02-08 06:24:22 -08:00
|
|
|
// Next, clone the generic handler to be parented to the target.
|
2014-01-17 10:09:38 -08:00
|
|
|
JS::Rooted<JSObject*> target(cx, &targetV.toObject());
|
|
|
|
JS::Rooted<JSObject*> bound(cx, JS_CloneFunctionObject(cx, genericHandler, target));
|
2013-02-08 06:24:22 -08:00
|
|
|
NS_ENSURE_TRUE(bound, NS_ERROR_FAILURE);
|
|
|
|
|
|
|
|
// Now, wrap the bound handler into the content compartment and use it.
|
|
|
|
JSAutoCompartment ac2(cx, globalObject);
|
2013-10-15 17:02:23 -07:00
|
|
|
if (!JS_WrapObject(cx, &bound)) {
|
2013-02-08 06:24:22 -08:00
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
2012-11-09 08:00:25 -08:00
|
|
|
nsRefPtr<EventHandlerNonNull> handlerCallback =
|
2013-12-11 17:51:58 -08:00
|
|
|
new EventHandlerNonNull(bound, /* aIncumbentGlobal = */ nullptr);
|
2012-11-09 08:00:25 -08:00
|
|
|
|
2014-04-01 19:00:45 -07:00
|
|
|
TypedEventHandler typedHandler(handlerCallback);
|
2012-11-09 08:00:25 -08:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
// Execute it.
|
2014-04-01 19:00:46 -07:00
|
|
|
nsCOMPtr<JSEventHandler> jsEventHandler;
|
2014-04-01 19:00:45 -07:00
|
|
|
rv = NS_NewJSEventHandler(scriptTarget, onEventAtom,
|
2014-04-01 19:00:45 -07:00
|
|
|
typedHandler,
|
2014-04-01 19:00:46 -07:00
|
|
|
getter_AddRefs(jsEventHandler));
|
2011-08-24 12:49:25 -07:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
// Handle the event.
|
2014-04-01 19:00:46 -07:00
|
|
|
jsEventHandler->HandleEvent(aEvent);
|
|
|
|
jsEventHandler->Disconnect();
|
2007-03-22 10:30:00 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2007-12-04 23:21:18 -08:00
|
|
|
nsresult
|
|
|
|
nsXBLPrototypeHandler::EnsureEventHandler(nsIScriptGlobalObject* aGlobal,
|
|
|
|
nsIScriptContext *aBoundContext,
|
|
|
|
nsIAtom *aName,
|
2013-03-20 13:09:09 -07:00
|
|
|
JS::MutableHandle<JSObject*> aHandler)
|
2007-12-04 23:21:18 -08:00
|
|
|
{
|
2013-03-20 13:09:09 -07:00
|
|
|
AutoPushJSContext cx(aBoundContext->GetNativeContext());
|
|
|
|
|
2007-12-04 23:21:18 -08:00
|
|
|
// Check to see if we've already compiled this
|
2008-02-12 20:17:18 -08:00
|
|
|
nsCOMPtr<nsPIDOMWindow> pWindow = do_QueryInterface(aGlobal);
|
|
|
|
if (pWindow) {
|
2013-03-20 13:09:09 -07:00
|
|
|
JS::Rooted<JSObject*> cachedHandler(cx, pWindow->GetCachedXBLPrototypeHandler(this));
|
2008-02-12 20:17:18 -08:00
|
|
|
if (cachedHandler) {
|
2013-09-08 20:28:48 -07:00
|
|
|
JS::ExposeObjectToActiveJS(cachedHandler);
|
2011-12-18 02:05:12 -08:00
|
|
|
aHandler.set(cachedHandler);
|
2013-02-08 06:24:22 -08:00
|
|
|
NS_ENSURE_TRUE(aHandler, NS_ERROR_FAILURE);
|
|
|
|
return NS_OK;
|
2008-01-28 22:15:25 -08:00
|
|
|
}
|
2007-12-04 23:21:18 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Ensure that we have something to compile
|
|
|
|
nsDependentString handlerText(mHandlerText);
|
2013-02-08 06:24:22 -08:00
|
|
|
NS_ENSURE_TRUE(!handlerText.IsEmpty(), NS_ERROR_FAILURE);
|
|
|
|
|
2013-03-20 13:09:09 -07:00
|
|
|
JS::Rooted<JSObject*> globalObject(cx, aGlobal->GetGlobalJSObject());
|
2014-03-19 09:35:45 -07:00
|
|
|
JS::Rooted<JSObject*> scopeObject(cx, xpc::GetXBLScopeOrGlobal(cx, globalObject));
|
2013-04-05 12:04:09 -07:00
|
|
|
NS_ENSURE_TRUE(scopeObject, NS_ERROR_OUT_OF_MEMORY);
|
2007-12-04 23:21:18 -08:00
|
|
|
|
2012-09-01 19:35:17 -07:00
|
|
|
nsAutoCString bindingURI;
|
2007-12-04 23:21:18 -08:00
|
|
|
mPrototypeBinding->DocURI()->GetSpec(bindingURI);
|
|
|
|
|
2012-08-22 08:56:38 -07:00
|
|
|
uint32_t argCount;
|
2007-12-04 23:21:18 -08:00
|
|
|
const char **argNames;
|
|
|
|
nsContentUtils::GetEventArgNames(kNameSpaceID_XBL, aName, &argCount,
|
|
|
|
&argNames);
|
2013-01-22 22:12:50 -08:00
|
|
|
|
2013-02-08 06:24:22 -08:00
|
|
|
// Compile the event handler in the xbl scope.
|
|
|
|
JSAutoCompartment ac(cx, scopeObject);
|
2013-01-22 22:12:50 -08:00
|
|
|
JS::CompileOptions options(cx);
|
|
|
|
options.setFileAndLine(bindingURI.get(), mLineNumber)
|
2013-05-20 21:34:17 -07:00
|
|
|
.setVersion(JSVERSION_LATEST);
|
2013-01-22 22:12:50 -08:00
|
|
|
|
2013-03-20 13:09:09 -07:00
|
|
|
JS::Rooted<JSObject*> handlerFun(cx);
|
2013-11-11 00:04:41 -08:00
|
|
|
nsresult rv = nsJSUtils::CompileFunction(cx, JS::NullPtr(), options,
|
2013-01-22 22:12:50 -08:00
|
|
|
nsAtomCString(aName), argCount,
|
2013-11-11 00:04:41 -08:00
|
|
|
argNames, handlerText,
|
|
|
|
handlerFun.address());
|
2007-12-04 23:21:18 -08:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2013-02-08 06:24:22 -08:00
|
|
|
NS_ENSURE_TRUE(handlerFun, NS_ERROR_FAILURE);
|
|
|
|
|
|
|
|
// Wrap the handler into the content scope, since we're about to stash it
|
|
|
|
// on the DOM window and such.
|
|
|
|
JSAutoCompartment ac2(cx, globalObject);
|
2013-10-15 17:02:23 -07:00
|
|
|
bool ok = JS_WrapObject(cx, &handlerFun);
|
2013-02-08 06:24:22 -08:00
|
|
|
NS_ENSURE_TRUE(ok, NS_ERROR_OUT_OF_MEMORY);
|
2013-01-22 22:12:50 -08:00
|
|
|
aHandler.set(handlerFun);
|
|
|
|
NS_ENSURE_TRUE(aHandler, NS_ERROR_FAILURE);
|
2007-12-04 23:21:18 -08:00
|
|
|
|
2008-02-12 20:17:18 -08:00
|
|
|
if (pWindow) {
|
|
|
|
pWindow->CacheXBLPrototypeHandler(this, aHandler);
|
|
|
|
}
|
2007-12-04 23:21:18 -08:00
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
2013-04-05 17:44:26 -07:00
|
|
|
nsXBLPrototypeHandler::DispatchXBLCommand(EventTarget* aTarget, nsIDOMEvent* aEvent)
|
2007-12-04 23:21:18 -08:00
|
|
|
{
|
|
|
|
// This is a special-case optimization to make command handling fast.
|
|
|
|
// It isn't really a part of XBL, but it helps speed things up.
|
|
|
|
|
2012-06-10 16:44:50 -07:00
|
|
|
if (aEvent) {
|
2012-08-04 00:44:00 -07:00
|
|
|
// See if preventDefault has been set. If so, don't execute.
|
|
|
|
bool preventDefault = false;
|
2013-05-25 14:05:36 -07:00
|
|
|
aEvent->GetDefaultPrevented(&preventDefault);
|
2012-08-04 00:44:00 -07:00
|
|
|
if (preventDefault) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2012-06-10 16:44:50 -07:00
|
|
|
bool dispatchStopped = aEvent->IsDispatchStopped();
|
2012-08-04 00:44:00 -07:00
|
|
|
if (dispatchStopped) {
|
2007-12-04 23:21:18 -08:00
|
|
|
return NS_OK;
|
2012-08-04 00:44:00 -07:00
|
|
|
}
|
2007-12-04 23:21:18 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Instead of executing JS, let's get the controller for the bound
|
|
|
|
// element and call doCommand on it.
|
|
|
|
nsCOMPtr<nsIController> controller;
|
|
|
|
|
Bug 178324, refactor focus by moving all focus handling into one place and simplifying it, add many tests, fixes many other bugs too numerous to mention in this small checkin comment, r=josh,smichaud,ere,dbaron,marco,neil,gavin,smaug,sr=smaug (CLOSED TREE)
2009-06-10 11:00:39 -07:00
|
|
|
nsCOMPtr<nsPIDOMWindow> privateWindow;
|
2007-12-04 23:21:18 -08:00
|
|
|
nsCOMPtr<nsPIWindowRoot> windowRoot(do_QueryInterface(aTarget));
|
|
|
|
if (windowRoot) {
|
2010-02-20 08:07:03 -08:00
|
|
|
privateWindow = windowRoot->GetWindow();
|
2007-12-04 23:21:18 -08:00
|
|
|
}
|
|
|
|
else {
|
Bug 178324, refactor focus by moving all focus handling into one place and simplifying it, add many tests, fixes many other bugs too numerous to mention in this small checkin comment, r=josh,smichaud,ere,dbaron,marco,neil,gavin,smaug,sr=smaug (CLOSED TREE)
2009-06-10 11:00:39 -07:00
|
|
|
privateWindow = do_QueryInterface(aTarget);
|
2007-12-04 23:21:18 -08:00
|
|
|
if (!privateWindow) {
|
|
|
|
nsCOMPtr<nsIContent> elt(do_QueryInterface(aTarget));
|
|
|
|
nsCOMPtr<nsIDocument> doc;
|
|
|
|
// XXXbz sXBL/XBL2 issue -- this should be the "scope doc" or
|
|
|
|
// something... whatever we use when wrapping DOM nodes
|
|
|
|
// normally. It's not clear that the owner doc is the right
|
|
|
|
// thing.
|
|
|
|
if (elt)
|
2011-10-18 03:53:36 -07:00
|
|
|
doc = elt->OwnerDoc();
|
2007-12-04 23:21:18 -08:00
|
|
|
|
|
|
|
if (!doc)
|
|
|
|
doc = do_QueryInterface(aTarget);
|
|
|
|
|
|
|
|
if (!doc)
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
2013-06-21 07:25:20 -07:00
|
|
|
privateWindow = doc->GetWindow();
|
2007-12-04 23:21:18 -08:00
|
|
|
if (!privateWindow)
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
2010-02-20 08:07:03 -08:00
|
|
|
windowRoot = privateWindow->GetTopWindowRoot();
|
2007-12-04 23:21:18 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_LossyConvertUTF16toASCII command(mHandlerText);
|
2010-02-20 08:07:03 -08:00
|
|
|
if (windowRoot)
|
|
|
|
windowRoot->GetControllerForCommand(command.get(), getter_AddRefs(controller));
|
2007-12-04 23:21:18 -08:00
|
|
|
else
|
|
|
|
controller = GetController(aTarget); // We're attached to the receiver possibly.
|
|
|
|
|
2010-03-08 07:45:00 -08:00
|
|
|
if (mEventName == nsGkAtoms::keypress &&
|
2007-12-04 23:21:18 -08:00
|
|
|
mDetail == nsIDOMKeyEvent::DOM_VK_SPACE &&
|
|
|
|
mMisc == 1) {
|
|
|
|
// get the focused element so that we can pageDown only at
|
|
|
|
// certain times.
|
Bug 178324, refactor focus by moving all focus handling into one place and simplifying it, add many tests, fixes many other bugs too numerous to mention in this small checkin comment, r=josh,smichaud,ere,dbaron,marco,neil,gavin,smaug,sr=smaug (CLOSED TREE)
2009-06-10 11:00:39 -07:00
|
|
|
|
|
|
|
nsCOMPtr<nsPIDOMWindow> windowToCheck;
|
|
|
|
if (windowRoot)
|
2010-02-20 08:07:03 -08:00
|
|
|
windowToCheck = windowRoot->GetWindow();
|
Bug 178324, refactor focus by moving all focus handling into one place and simplifying it, add many tests, fixes many other bugs too numerous to mention in this small checkin comment, r=josh,smichaud,ere,dbaron,marco,neil,gavin,smaug,sr=smaug (CLOSED TREE)
2009-06-10 11:00:39 -07:00
|
|
|
else
|
|
|
|
windowToCheck = privateWindow->GetPrivateRoot();
|
|
|
|
|
|
|
|
nsCOMPtr<nsIContent> focusedContent;
|
|
|
|
if (windowToCheck) {
|
|
|
|
nsCOMPtr<nsPIDOMWindow> focusedWindow;
|
|
|
|
focusedContent =
|
2011-10-17 07:59:28 -07:00
|
|
|
nsFocusManager::GetFocusedDescendant(windowToCheck, true, getter_AddRefs(focusedWindow));
|
Bug 178324, refactor focus by moving all focus handling into one place and simplifying it, add many tests, fixes many other bugs too numerous to mention in this small checkin comment, r=josh,smichaud,ere,dbaron,marco,neil,gavin,smaug,sr=smaug (CLOSED TREE)
2009-06-10 11:00:39 -07:00
|
|
|
}
|
|
|
|
|
2011-09-28 23:19:26 -07:00
|
|
|
bool isLink = false;
|
2007-12-04 23:21:18 -08:00
|
|
|
nsIContent *content = focusedContent;
|
|
|
|
|
|
|
|
// if the focused element is a link then we do want space to
|
Bug 178324, refactor focus by moving all focus handling into one place and simplifying it, add many tests, fixes many other bugs too numerous to mention in this small checkin comment, r=josh,smichaud,ere,dbaron,marco,neil,gavin,smaug,sr=smaug (CLOSED TREE)
2009-06-10 11:00:39 -07:00
|
|
|
// scroll down. The focused element may be an element in a link,
|
|
|
|
// we need to check the parent node too. Only do this check if an
|
|
|
|
// element is focused and has a parent.
|
|
|
|
if (focusedContent && focusedContent->GetParent()) {
|
2007-12-04 23:21:18 -08:00
|
|
|
while (content) {
|
2009-08-24 13:02:07 -07:00
|
|
|
if (content->Tag() == nsGkAtoms::a && content->IsHTML()) {
|
2011-10-17 07:59:28 -07:00
|
|
|
isLink = true;
|
2007-12-04 23:21:18 -08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (content->HasAttr(kNameSpaceID_XLink, nsGkAtoms::type)) {
|
|
|
|
isLink = content->AttrValueIs(kNameSpaceID_XLink, nsGkAtoms::type,
|
|
|
|
nsGkAtoms::simple, eCaseMatters);
|
|
|
|
|
|
|
|
if (isLink) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
content = content->GetParent();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!isLink)
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// We are the default action for this command.
|
|
|
|
// Stop any other default action from executing.
|
|
|
|
aEvent->PreventDefault();
|
|
|
|
|
|
|
|
if (controller)
|
|
|
|
controller->DoCommand(command.get());
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsXBLPrototypeHandler::DispatchXULKeyCommand(nsIDOMEvent* aEvent)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIContent> handlerElement = GetHandlerElement();
|
|
|
|
NS_ENSURE_STATE(handlerElement);
|
|
|
|
if (handlerElement->AttrValueIs(kNameSpaceID_None,
|
|
|
|
nsGkAtoms::disabled,
|
|
|
|
nsGkAtoms::_true,
|
|
|
|
eCaseMatters)) {
|
|
|
|
// Don't dispatch command events for disabled keys.
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
aEvent->PreventDefault();
|
|
|
|
|
|
|
|
// Copy the modifiers from the key event.
|
|
|
|
nsCOMPtr<nsIDOMKeyEvent> keyEvent = do_QueryInterface(aEvent);
|
|
|
|
if (!keyEvent) {
|
|
|
|
NS_ERROR("Trying to execute a key handler for a non-key event!");
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
2013-09-13 19:39:41 -07:00
|
|
|
// XXX We should use mozilla::Modifiers for supporting all modifiers.
|
2012-07-18 18:28:16 -07:00
|
|
|
|
2011-09-28 23:19:26 -07:00
|
|
|
bool isAlt = false;
|
|
|
|
bool isControl = false;
|
|
|
|
bool isShift = false;
|
|
|
|
bool isMeta = false;
|
2009-06-30 00:56:40 -07:00
|
|
|
keyEvent->GetAltKey(&isAlt);
|
|
|
|
keyEvent->GetCtrlKey(&isControl);
|
|
|
|
keyEvent->GetShiftKey(&isShift);
|
|
|
|
keyEvent->GetMetaKey(&isMeta);
|
|
|
|
|
2011-10-17 07:59:28 -07:00
|
|
|
nsContentUtils::DispatchXULCommand(handlerElement, true,
|
2012-07-30 07:20:58 -07:00
|
|
|
nullptr, nullptr,
|
2009-06-30 00:56:40 -07:00
|
|
|
isControl, isAlt, isShift, isMeta);
|
2007-12-04 23:21:18 -08:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
already_AddRefed<nsIAtom>
|
|
|
|
nsXBLPrototypeHandler::GetEventName()
|
|
|
|
{
|
2013-04-22 04:15:59 -07:00
|
|
|
nsCOMPtr<nsIAtom> eventName = mEventName;
|
|
|
|
return eventName.forget();
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
already_AddRefed<nsIController>
|
2013-04-05 17:44:26 -07:00
|
|
|
nsXBLPrototypeHandler::GetController(EventTarget* aTarget)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2013-04-05 17:44:26 -07:00
|
|
|
// XXX Fix this so there's a generic interface that describes controllers,
|
2007-03-22 10:30:00 -07:00
|
|
|
// This code should have no special knowledge of what objects might have controllers.
|
|
|
|
nsCOMPtr<nsIControllers> controllers;
|
|
|
|
|
2007-05-14 02:11:38 -07:00
|
|
|
nsCOMPtr<nsIDOMXULElement> xulElement(do_QueryInterface(aTarget));
|
2007-03-22 10:30:00 -07:00
|
|
|
if (xulElement)
|
|
|
|
xulElement->GetControllers(getter_AddRefs(controllers));
|
|
|
|
|
|
|
|
if (!controllers) {
|
2011-06-11 00:52:24 -07:00
|
|
|
nsCOMPtr<nsIDOMHTMLTextAreaElement> htmlTextArea(do_QueryInterface(aTarget));
|
2007-03-22 10:30:00 -07:00
|
|
|
if (htmlTextArea)
|
|
|
|
htmlTextArea->GetControllers(getter_AddRefs(controllers));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!controllers) {
|
2010-08-04 19:40:18 -07:00
|
|
|
nsCOMPtr<nsIDOMHTMLInputElement> htmlInputElement(do_QueryInterface(aTarget));
|
2007-03-22 10:30:00 -07:00
|
|
|
if (htmlInputElement)
|
|
|
|
htmlInputElement->GetControllers(getter_AddRefs(controllers));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!controllers) {
|
2011-07-15 03:31:34 -07:00
|
|
|
nsCOMPtr<nsIDOMWindow> domWindow(do_QueryInterface(aTarget));
|
2007-03-22 10:30:00 -07:00
|
|
|
if (domWindow)
|
|
|
|
domWindow->GetControllers(getter_AddRefs(controllers));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Return the first controller.
|
|
|
|
// XXX This code should be checking the command name and using supportscommand and
|
|
|
|
// iscommandenabled.
|
2013-04-22 04:15:59 -07:00
|
|
|
nsCOMPtr<nsIController> controller;
|
2007-03-22 10:30:00 -07:00
|
|
|
if (controllers) {
|
2013-04-22 04:15:59 -07:00
|
|
|
controllers->GetControllerAt(0, getter_AddRefs(controller));
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2013-04-22 04:15:59 -07:00
|
|
|
return controller.forget();
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2011-09-28 23:19:26 -07:00
|
|
|
bool
|
2008-04-14 21:16:24 -07:00
|
|
|
nsXBLPrototypeHandler::KeyEventMatched(nsIDOMKeyEvent* aKeyEvent,
|
2012-08-22 08:56:38 -07:00
|
|
|
uint32_t aCharCode,
|
2011-09-28 23:19:26 -07:00
|
|
|
bool aIgnoreShiftKey)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2008-09-07 02:43:57 -07:00
|
|
|
if (mDetail != -1) {
|
|
|
|
// Get the keycode or charcode of the key event.
|
2012-08-22 08:56:38 -07:00
|
|
|
uint32_t code;
|
2008-09-07 02:43:57 -07:00
|
|
|
|
|
|
|
if (mMisc) {
|
|
|
|
if (aCharCode)
|
|
|
|
code = aCharCode;
|
|
|
|
else
|
|
|
|
aKeyEvent->GetCharCode(&code);
|
|
|
|
if (IS_IN_BMP(code))
|
2014-01-04 07:02:17 -08:00
|
|
|
code = ToLowerCase(char16_t(code));
|
2008-09-07 02:43:57 -07:00
|
|
|
}
|
2008-04-14 21:16:24 -07:00
|
|
|
else
|
2008-09-07 02:43:57 -07:00
|
|
|
aKeyEvent->GetKeyCode(&code);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-08-22 08:56:38 -07:00
|
|
|
if (code != uint32_t(mDetail))
|
2011-10-17 07:59:28 -07:00
|
|
|
return false;
|
2008-09-07 02:43:57 -07:00
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2008-04-14 21:16:24 -07:00
|
|
|
return ModifiersMatchMask(aKeyEvent, aIgnoreShiftKey);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2011-09-28 23:19:26 -07:00
|
|
|
bool
|
2007-03-22 10:30:00 -07:00
|
|
|
nsXBLPrototypeHandler::MouseEventMatched(nsIDOMMouseEvent* aMouseEvent)
|
|
|
|
{
|
|
|
|
if (mDetail == -1 && mMisc == 0 && (mKeyMask & cAllModifiers) == 0)
|
2011-10-17 07:59:28 -07:00
|
|
|
return true; // No filters set up. It's generic.
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2014-02-20 10:38:13 -08:00
|
|
|
int16_t button;
|
2007-03-22 10:30:00 -07:00
|
|
|
aMouseEvent->GetButton(&button);
|
|
|
|
if (mDetail != -1 && (button != mDetail))
|
2011-10-17 07:59:28 -07:00
|
|
|
return false;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-08-22 08:56:38 -07:00
|
|
|
int32_t clickcount;
|
2007-03-22 10:30:00 -07:00
|
|
|
aMouseEvent->GetDetail(&clickcount);
|
|
|
|
if (mMisc != 0 && (clickcount != mMisc))
|
2011-10-17 07:59:28 -07:00
|
|
|
return false;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
return ModifiersMatchMask(aMouseEvent);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct keyCodeData {
|
|
|
|
const char* str;
|
|
|
|
size_t strlength;
|
2012-08-22 08:56:38 -07:00
|
|
|
uint32_t keycode;
|
2007-03-22 10:30:00 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
// All of these must be uppercase, since the function below does
|
|
|
|
// case-insensitive comparison by converting to uppercase.
|
|
|
|
// XXX: be sure to check this periodically for new symbol additions!
|
|
|
|
static const keyCodeData gKeyCodes[] = {
|
|
|
|
|
2012-05-17 00:04:16 -07:00
|
|
|
#define NS_DEFINE_VK(aDOMKeyName, aDOMKeyCode) \
|
|
|
|
{ #aDOMKeyName, sizeof(#aDOMKeyName) - 1, aDOMKeyCode }
|
2014-04-01 04:42:16 -07:00
|
|
|
#include "mozilla/VirtualKeyCodeList.h"
|
2012-05-17 00:04:16 -07:00
|
|
|
#undef NS_DEFINE_VK
|
2007-03-22 10:30:00 -07:00
|
|
|
};
|
|
|
|
|
2012-08-22 08:56:38 -07:00
|
|
|
int32_t nsXBLPrototypeHandler::GetMatchingKeyCode(const nsAString& aKeyName)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2012-09-01 19:35:17 -07:00
|
|
|
nsAutoCString keyName;
|
2007-03-22 10:30:00 -07:00
|
|
|
keyName.AssignWithConversion(aKeyName);
|
|
|
|
ToUpperCase(keyName); // We want case-insensitive comparison with data
|
|
|
|
// stored as uppercase.
|
|
|
|
|
2012-08-22 08:56:38 -07:00
|
|
|
uint32_t keyNameLength = keyName.Length();
|
2007-03-22 10:30:00 -07:00
|
|
|
const char* keyNameStr = keyName.get();
|
2012-08-22 08:56:38 -07:00
|
|
|
for (uint16_t i = 0; i < (sizeof(gKeyCodes) / sizeof(gKeyCodes[0])); ++i)
|
2007-03-22 10:30:00 -07:00
|
|
|
if (keyNameLength == gKeyCodes[i].strlength &&
|
|
|
|
!nsCRT::strcmp(gKeyCodes[i].str, keyNameStr))
|
|
|
|
return gKeyCodes[i].keycode;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-08-22 08:56:38 -07:00
|
|
|
int32_t nsXBLPrototypeHandler::KeyToMask(int32_t key)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
switch (key)
|
|
|
|
{
|
|
|
|
case nsIDOMKeyEvent::DOM_VK_META:
|
|
|
|
return cMeta | cMetaMask;
|
2012-07-18 18:28:16 -07:00
|
|
|
|
|
|
|
case nsIDOMKeyEvent::DOM_VK_WIN:
|
|
|
|
return cOS | cOSMask;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
case nsIDOMKeyEvent::DOM_VK_ALT:
|
|
|
|
return cAlt | cAltMask;
|
|
|
|
|
|
|
|
case nsIDOMKeyEvent::DOM_VK_CONTROL:
|
|
|
|
default:
|
|
|
|
return cControl | cControlMask;
|
|
|
|
}
|
|
|
|
return cControl | cControlMask; // for warning avoidance
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsXBLPrototypeHandler::GetEventType(nsAString& aEvent)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIContent> handlerElement = GetHandlerElement();
|
|
|
|
if (!handlerElement) {
|
|
|
|
aEvent.Truncate();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
handlerElement->GetAttr(kNameSpaceID_None, nsGkAtoms::event, aEvent);
|
|
|
|
|
|
|
|
if (aEvent.IsEmpty() && (mType & NS_HANDLER_TYPE_XUL))
|
|
|
|
// If no type is specified for a XUL <key> element, let's assume that we're "keypress".
|
|
|
|
aEvent.AssignLiteral("keypress");
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsXBLPrototypeHandler::ConstructPrototype(nsIContent* aKeyElement,
|
2014-01-04 07:02:17 -08:00
|
|
|
const char16_t* aEvent,
|
|
|
|
const char16_t* aPhase,
|
|
|
|
const char16_t* aAction,
|
|
|
|
const char16_t* aCommand,
|
|
|
|
const char16_t* aKeyCode,
|
|
|
|
const char16_t* aCharCode,
|
|
|
|
const char16_t* aModifiers,
|
|
|
|
const char16_t* aButton,
|
|
|
|
const char16_t* aClickCount,
|
|
|
|
const char16_t* aGroup,
|
|
|
|
const char16_t* aPreventDefault,
|
|
|
|
const char16_t* aAllowUntrusted)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
mType = 0;
|
|
|
|
|
|
|
|
if (aKeyElement) {
|
|
|
|
mType |= NS_HANDLER_TYPE_XUL;
|
|
|
|
nsCOMPtr<nsIWeakReference> weak = do_GetWeakReference(aKeyElement);
|
|
|
|
if (!weak) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
weak.swap(mHandlerElement);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
mType |= aCommand ? NS_HANDLER_TYPE_XBL_COMMAND : NS_HANDLER_TYPE_XBL_JS;
|
2012-07-30 07:20:58 -07:00
|
|
|
mHandlerText = nullptr;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
mDetail = -1;
|
|
|
|
mMisc = 0;
|
|
|
|
mKeyMask = 0;
|
|
|
|
mPhase = NS_PHASE_BUBBLING;
|
|
|
|
|
|
|
|
if (aAction)
|
|
|
|
mHandlerText = ToNewUnicode(nsDependentString(aAction));
|
|
|
|
else if (aCommand)
|
|
|
|
mHandlerText = ToNewUnicode(nsDependentString(aCommand));
|
|
|
|
|
|
|
|
nsAutoString event(aEvent);
|
|
|
|
if (event.IsEmpty()) {
|
|
|
|
if (mType & NS_HANDLER_TYPE_XUL)
|
|
|
|
GetEventType(event);
|
|
|
|
if (event.IsEmpty())
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
mEventName = do_GetAtom(event);
|
|
|
|
|
|
|
|
if (aPhase) {
|
|
|
|
const nsDependentString phase(aPhase);
|
|
|
|
if (phase.EqualsLiteral("capturing"))
|
|
|
|
mPhase = NS_PHASE_CAPTURING;
|
|
|
|
else if (phase.EqualsLiteral("target"))
|
|
|
|
mPhase = NS_PHASE_TARGET;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Button and clickcount apply only to XBL handlers and don't apply to XUL key
|
|
|
|
// handlers.
|
|
|
|
if (aButton && *aButton)
|
|
|
|
mDetail = *aButton - '0';
|
|
|
|
|
|
|
|
if (aClickCount && *aClickCount)
|
|
|
|
mMisc = *aClickCount - '0';
|
|
|
|
|
|
|
|
// Modifiers are supported by both types of handlers (XUL and XBL).
|
|
|
|
nsAutoString modifiers(aModifiers);
|
|
|
|
if (mType & NS_HANDLER_TYPE_XUL)
|
|
|
|
aKeyElement->GetAttr(kNameSpaceID_None, nsGkAtoms::modifiers, modifiers);
|
|
|
|
|
|
|
|
if (!modifiers.IsEmpty()) {
|
|
|
|
mKeyMask = cAllModifiers;
|
|
|
|
char* str = ToNewCString(modifiers);
|
|
|
|
char* newStr;
|
|
|
|
char* token = nsCRT::strtok( str, ", \t", &newStr );
|
2013-04-02 18:14:24 -07:00
|
|
|
while( token != nullptr ) {
|
2007-03-22 10:30:00 -07:00
|
|
|
if (PL_strcmp(token, "shift") == 0)
|
|
|
|
mKeyMask |= cShift | cShiftMask;
|
|
|
|
else if (PL_strcmp(token, "alt") == 0)
|
|
|
|
mKeyMask |= cAlt | cAltMask;
|
|
|
|
else if (PL_strcmp(token, "meta") == 0)
|
|
|
|
mKeyMask |= cMeta | cMetaMask;
|
2012-07-18 18:28:16 -07:00
|
|
|
else if (PL_strcmp(token, "os") == 0)
|
|
|
|
mKeyMask |= cOS | cOSMask;
|
2007-03-22 10:30:00 -07:00
|
|
|
else if (PL_strcmp(token, "control") == 0)
|
|
|
|
mKeyMask |= cControl | cControlMask;
|
|
|
|
else if (PL_strcmp(token, "accel") == 0)
|
|
|
|
mKeyMask |= KeyToMask(kAccelKey);
|
|
|
|
else if (PL_strcmp(token, "access") == 0)
|
|
|
|
mKeyMask |= KeyToMask(kMenuAccessKey);
|
|
|
|
else if (PL_strcmp(token, "any") == 0)
|
2012-07-18 18:28:16 -07:00
|
|
|
mKeyMask &= ~(mKeyMask << 5);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
token = nsCRT::strtok( newStr, ", \t", &newStr );
|
|
|
|
}
|
|
|
|
|
|
|
|
nsMemory::Free(str);
|
|
|
|
}
|
|
|
|
|
|
|
|
nsAutoString key(aCharCode);
|
|
|
|
if (key.IsEmpty()) {
|
|
|
|
if (mType & NS_HANDLER_TYPE_XUL) {
|
|
|
|
aKeyElement->GetAttr(kNameSpaceID_None, nsGkAtoms::key, key);
|
|
|
|
if (key.IsEmpty())
|
|
|
|
aKeyElement->GetAttr(kNameSpaceID_None, nsGkAtoms::charcode, key);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!key.IsEmpty()) {
|
|
|
|
if (mKeyMask == 0)
|
|
|
|
mKeyMask = cAllModifiers;
|
2012-08-20 19:23:32 -07:00
|
|
|
ToLowerCase(key);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
// We have a charcode.
|
|
|
|
mMisc = 1;
|
|
|
|
mDetail = key[0];
|
2012-08-22 08:56:38 -07:00
|
|
|
const uint8_t GTK2Modifiers = cShift | cControl | cShiftMask | cControlMask;
|
2007-03-22 10:30:00 -07:00
|
|
|
if ((mKeyMask & GTK2Modifiers) == GTK2Modifiers &&
|
2014-01-04 07:02:17 -08:00
|
|
|
modifiers.First() != char16_t(',') &&
|
2012-08-20 19:23:32 -07:00
|
|
|
(mDetail == 'u' || mDetail == 'U'))
|
2007-03-22 10:30:00 -07:00
|
|
|
ReportKeyConflict(key.get(), modifiers.get(), aKeyElement, "GTK2Conflict");
|
2012-08-22 08:56:38 -07:00
|
|
|
const uint8_t WinModifiers = cControl | cAlt | cControlMask | cAltMask;
|
2007-03-22 10:30:00 -07:00
|
|
|
if ((mKeyMask & WinModifiers) == WinModifiers &&
|
2014-01-04 07:02:17 -08:00
|
|
|
modifiers.First() != char16_t(',') &&
|
2012-08-20 19:23:32 -07:00
|
|
|
(('A' <= mDetail && mDetail <= 'Z') ||
|
|
|
|
('a' <= mDetail && mDetail <= 'z')))
|
2007-03-22 10:30:00 -07:00
|
|
|
ReportKeyConflict(key.get(), modifiers.get(), aKeyElement, "WinConflict");
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
key.Assign(aKeyCode);
|
|
|
|
if (mType & NS_HANDLER_TYPE_XUL)
|
|
|
|
aKeyElement->GetAttr(kNameSpaceID_None, nsGkAtoms::keycode, key);
|
|
|
|
|
|
|
|
if (!key.IsEmpty()) {
|
|
|
|
if (mKeyMask == 0)
|
|
|
|
mKeyMask = cAllModifiers;
|
|
|
|
mDetail = GetMatchingKeyCode(key);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (aGroup && nsDependentString(aGroup).EqualsLiteral("system"))
|
|
|
|
mType |= NS_HANDLER_TYPE_SYSTEM;
|
|
|
|
|
2007-04-15 09:28:53 -07:00
|
|
|
if (aPreventDefault &&
|
|
|
|
nsDependentString(aPreventDefault).EqualsLiteral("true"))
|
2007-03-22 10:30:00 -07:00
|
|
|
mType |= NS_HANDLER_TYPE_PREVENTDEFAULT;
|
|
|
|
|
|
|
|
if (aAllowUntrusted) {
|
2007-04-15 09:28:53 -07:00
|
|
|
mType |= NS_HANDLER_HAS_ALLOW_UNTRUSTED_ATTR;
|
2007-03-22 10:30:00 -07:00
|
|
|
if (nsDependentString(aAllowUntrusted).EqualsLiteral("true")) {
|
|
|
|
mType |= NS_HANDLER_ALLOW_UNTRUSTED;
|
|
|
|
} else {
|
|
|
|
mType &= ~NS_HANDLER_ALLOW_UNTRUSTED;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2014-01-04 07:02:17 -08:00
|
|
|
nsXBLPrototypeHandler::ReportKeyConflict(const char16_t* aKey, const char16_t* aModifiers, nsIContent* aKeyElement, const char *aMessageName)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2010-12-20 08:21:58 -08:00
|
|
|
nsCOMPtr<nsIDocument> doc;
|
|
|
|
if (mPrototypeBinding) {
|
|
|
|
nsXBLDocumentInfo* docInfo = mPrototypeBinding->XBLDocumentInfo();
|
|
|
|
if (docInfo) {
|
|
|
|
doc = docInfo->GetDocument();
|
|
|
|
}
|
|
|
|
} else if (aKeyElement) {
|
2011-10-18 03:53:36 -07:00
|
|
|
doc = aKeyElement->OwnerDoc();
|
2010-12-20 08:21:58 -08:00
|
|
|
}
|
|
|
|
|
2014-01-04 07:02:17 -08:00
|
|
|
const char16_t* params[] = { aKey, aModifiers };
|
2011-12-15 06:47:03 -08:00
|
|
|
nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
|
2013-08-21 12:28:26 -07:00
|
|
|
NS_LITERAL_CSTRING("XBL Prototype Handler"), doc,
|
2011-12-15 06:47:03 -08:00
|
|
|
nsContentUtils::eXBL_PROPERTIES,
|
2007-03-22 10:30:00 -07:00
|
|
|
aMessageName,
|
2011-10-10 22:50:08 -07:00
|
|
|
params, ArrayLength(params),
|
2012-07-30 07:20:58 -07:00
|
|
|
nullptr, EmptyString(), mLineNumber);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2011-09-28 23:19:26 -07:00
|
|
|
bool
|
2008-04-14 21:16:24 -07:00
|
|
|
nsXBLPrototypeHandler::ModifiersMatchMask(nsIDOMUIEvent* aEvent,
|
2011-09-28 23:19:26 -07:00
|
|
|
bool aIgnoreShiftKey)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2013-10-17 23:10:26 -07:00
|
|
|
WidgetInputEvent* inputEvent = aEvent->GetInternalNSEvent()->AsInputEvent();
|
|
|
|
NS_ENSURE_TRUE(inputEvent, false);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
if (mKeyMask & cMetaMask) {
|
2012-07-18 18:28:16 -07:00
|
|
|
if (inputEvent->IsMeta() != ((mKeyMask & cMeta) != 0)) {
|
2011-10-17 07:59:28 -07:00
|
|
|
return false;
|
2012-07-18 18:28:16 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mKeyMask & cOSMask) {
|
|
|
|
if (inputEvent->IsOS() != ((mKeyMask & cOS) != 0)) {
|
|
|
|
return false;
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2008-04-14 21:16:24 -07:00
|
|
|
if (mKeyMask & cShiftMask && !aIgnoreShiftKey) {
|
2012-07-18 18:28:16 -07:00
|
|
|
if (inputEvent->IsShift() != ((mKeyMask & cShift) != 0)) {
|
2011-10-17 07:59:28 -07:00
|
|
|
return false;
|
2012-07-18 18:28:16 -07:00
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
if (mKeyMask & cAltMask) {
|
2012-07-18 18:28:16 -07:00
|
|
|
if (inputEvent->IsAlt() != ((mKeyMask & cAlt) != 0)) {
|
2011-10-17 07:59:28 -07:00
|
|
|
return false;
|
2012-07-18 18:28:16 -07:00
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
if (mKeyMask & cControlMask) {
|
2012-07-18 18:28:16 -07:00
|
|
|
if (inputEvent->IsControl() != ((mKeyMask & cControl) != 0)) {
|
2011-10-17 07:59:28 -07:00
|
|
|
return false;
|
2012-07-18 18:28:16 -07:00
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2011-10-17 07:59:28 -07:00
|
|
|
return true;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
2011-11-03 13:39:08 -07:00
|
|
|
|
|
|
|
nsresult
|
2013-08-09 09:25:13 -07:00
|
|
|
nsXBLPrototypeHandler::Read(nsIObjectInputStream* aStream)
|
2011-11-03 13:39:08 -07:00
|
|
|
{
|
2013-08-09 09:25:13 -07:00
|
|
|
AssertInCompilationScope();
|
2011-11-03 13:39:08 -07:00
|
|
|
nsresult rv = aStream->Read8(&mPhase);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
rv = aStream->Read8(&mType);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
rv = aStream->Read8(&mMisc);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
2012-08-22 08:56:38 -07:00
|
|
|
rv = aStream->Read32(reinterpret_cast<uint32_t*>(&mKeyMask));
|
2012-07-18 18:28:16 -07:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2012-08-22 08:56:38 -07:00
|
|
|
uint32_t detail;
|
2011-11-03 13:39:08 -07:00
|
|
|
rv = aStream->Read32(&detail);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
mDetail = detail;
|
|
|
|
|
|
|
|
nsAutoString name;
|
|
|
|
rv = aStream->ReadString(name);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
mEventName = do_GetAtom(name);
|
|
|
|
|
|
|
|
rv = aStream->Read32(&mLineNumber);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
nsAutoString handlerText;
|
|
|
|
rv = aStream->ReadString(handlerText);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
if (!handlerText.IsEmpty())
|
|
|
|
mHandlerText = ToNewUnicode(handlerText);
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
2013-08-09 09:25:13 -07:00
|
|
|
nsXBLPrototypeHandler::Write(nsIObjectOutputStream* aStream)
|
2011-11-03 13:39:08 -07:00
|
|
|
{
|
2013-08-09 09:25:13 -07:00
|
|
|
AssertInCompilationScope();
|
2011-11-03 13:39:08 -07:00
|
|
|
// Make sure we don't write out NS_HANDLER_TYPE_XUL types, as they are used
|
|
|
|
// for <keyset> elements.
|
2012-02-13 11:24:28 -08:00
|
|
|
if ((mType & NS_HANDLER_TYPE_XUL) || !mEventName)
|
2011-11-03 13:39:08 -07:00
|
|
|
return NS_OK;
|
|
|
|
|
|
|
|
XBLBindingSerializeDetails type = XBLBinding_Serialize_Handler;
|
|
|
|
|
|
|
|
nsresult rv = aStream->Write8(type);
|
|
|
|
rv = aStream->Write8(mPhase);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
rv = aStream->Write8(mType);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
rv = aStream->Write8(mMisc);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2012-08-22 08:56:38 -07:00
|
|
|
rv = aStream->Write32(static_cast<uint32_t>(mKeyMask));
|
2012-07-18 18:28:16 -07:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2011-11-03 13:39:08 -07:00
|
|
|
rv = aStream->Write32(mDetail);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
rv = aStream->WriteWStringZ(nsDependentAtomString(mEventName).get());
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
rv = aStream->Write32(mLineNumber);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2013-12-03 07:09:50 -08:00
|
|
|
return aStream->WriteWStringZ(mHandlerText ? mHandlerText : MOZ_UTF16(""));
|
2011-11-03 13:39:08 -07:00
|
|
|
}
|