dom/xbl/nsXBLPrototypeHandler.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 #include "mozilla/ArrayUtils.h"
michael@0 7
michael@0 8 #include "nsCOMPtr.h"
michael@0 9 #include "nsXBLPrototypeHandler.h"
michael@0 10 #include "nsXBLPrototypeBinding.h"
michael@0 11 #include "nsContentUtils.h"
michael@0 12 #include "nsCxPusher.h"
michael@0 13 #include "nsIContent.h"
michael@0 14 #include "nsIAtom.h"
michael@0 15 #include "nsIDOMKeyEvent.h"
michael@0 16 #include "nsIDOMMouseEvent.h"
michael@0 17 #include "nsNameSpaceManager.h"
michael@0 18 #include "nsIScriptContext.h"
michael@0 19 #include "nsIDocument.h"
michael@0 20 #include "nsIController.h"
michael@0 21 #include "nsIControllers.h"
michael@0 22 #include "nsIDOMXULElement.h"
michael@0 23 #include "nsIURI.h"
michael@0 24 #include "nsIDOMHTMLTextAreaElement.h"
michael@0 25 #include "nsIDOMHTMLInputElement.h"
michael@0 26 #include "nsFocusManager.h"
michael@0 27 #include "nsIDOMEventListener.h"
michael@0 28 #include "nsPIDOMWindow.h"
michael@0 29 #include "nsPIWindowRoot.h"
michael@0 30 #include "nsIDOMWindow.h"
michael@0 31 #include "nsIServiceManager.h"
michael@0 32 #include "nsIScriptError.h"
michael@0 33 #include "nsXPIDLString.h"
michael@0 34 #include "nsReadableUtils.h"
michael@0 35 #include "nsGkAtoms.h"
michael@0 36 #include "nsIXPConnect.h"
michael@0 37 #include "nsIDOMScriptObjectFactory.h"
michael@0 38 #include "nsDOMCID.h"
michael@0 39 #include "nsUnicharUtils.h"
michael@0 40 #include "nsCRT.h"
michael@0 41 #include "nsXBLEventHandler.h"
michael@0 42 #include "nsXBLSerialize.h"
michael@0 43 #include "nsJSUtils.h"
michael@0 44 #include "mozilla/BasicEvents.h"
michael@0 45 #include "mozilla/JSEventHandler.h"
michael@0 46 #include "mozilla/Preferences.h"
michael@0 47 #include "mozilla/dom/EventHandlerBinding.h"
michael@0 48
michael@0 49 using namespace mozilla;
michael@0 50 using namespace mozilla::dom;
michael@0 51
michael@0 52 uint32_t nsXBLPrototypeHandler::gRefCnt = 0;
michael@0 53
michael@0 54 int32_t nsXBLPrototypeHandler::kMenuAccessKey = -1;
michael@0 55 int32_t nsXBLPrototypeHandler::kAccelKey = -1;
michael@0 56
michael@0 57 const int32_t nsXBLPrototypeHandler::cShift = (1<<0);
michael@0 58 const int32_t nsXBLPrototypeHandler::cAlt = (1<<1);
michael@0 59 const int32_t nsXBLPrototypeHandler::cControl = (1<<2);
michael@0 60 const int32_t nsXBLPrototypeHandler::cMeta = (1<<3);
michael@0 61 const int32_t nsXBLPrototypeHandler::cOS = (1<<4);
michael@0 62
michael@0 63 const int32_t nsXBLPrototypeHandler::cShiftMask = (1<<5);
michael@0 64 const int32_t nsXBLPrototypeHandler::cAltMask = (1<<6);
michael@0 65 const int32_t nsXBLPrototypeHandler::cControlMask = (1<<7);
michael@0 66 const int32_t nsXBLPrototypeHandler::cMetaMask = (1<<8);
michael@0 67 const int32_t nsXBLPrototypeHandler::cOSMask = (1<<9);
michael@0 68
michael@0 69 const int32_t nsXBLPrototypeHandler::cAllModifiers =
michael@0 70 cShiftMask | cAltMask | cControlMask | cMetaMask | cOSMask;
michael@0 71
michael@0 72 nsXBLPrototypeHandler::nsXBLPrototypeHandler(const char16_t* aEvent,
michael@0 73 const char16_t* aPhase,
michael@0 74 const char16_t* aAction,
michael@0 75 const char16_t* aCommand,
michael@0 76 const char16_t* aKeyCode,
michael@0 77 const char16_t* aCharCode,
michael@0 78 const char16_t* aModifiers,
michael@0 79 const char16_t* aButton,
michael@0 80 const char16_t* aClickCount,
michael@0 81 const char16_t* aGroup,
michael@0 82 const char16_t* aPreventDefault,
michael@0 83 const char16_t* aAllowUntrusted,
michael@0 84 nsXBLPrototypeBinding* aBinding,
michael@0 85 uint32_t aLineNumber)
michael@0 86 : mHandlerText(nullptr),
michael@0 87 mLineNumber(aLineNumber),
michael@0 88 mNextHandler(nullptr),
michael@0 89 mPrototypeBinding(aBinding)
michael@0 90 {
michael@0 91 Init();
michael@0 92
michael@0 93 ConstructPrototype(nullptr, aEvent, aPhase, aAction, aCommand, aKeyCode,
michael@0 94 aCharCode, aModifiers, aButton, aClickCount,
michael@0 95 aGroup, aPreventDefault, aAllowUntrusted);
michael@0 96 }
michael@0 97
michael@0 98 nsXBLPrototypeHandler::nsXBLPrototypeHandler(nsIContent* aHandlerElement)
michael@0 99 : mHandlerElement(nullptr),
michael@0 100 mLineNumber(0),
michael@0 101 mNextHandler(nullptr),
michael@0 102 mPrototypeBinding(nullptr)
michael@0 103 {
michael@0 104 Init();
michael@0 105
michael@0 106 // Make sure our prototype is initialized.
michael@0 107 ConstructPrototype(aHandlerElement);
michael@0 108 }
michael@0 109
michael@0 110 nsXBLPrototypeHandler::nsXBLPrototypeHandler(nsXBLPrototypeBinding* aBinding)
michael@0 111 : mHandlerText(nullptr),
michael@0 112 mLineNumber(0),
michael@0 113 mNextHandler(nullptr),
michael@0 114 mPrototypeBinding(aBinding)
michael@0 115 {
michael@0 116 Init();
michael@0 117 }
michael@0 118
michael@0 119 nsXBLPrototypeHandler::~nsXBLPrototypeHandler()
michael@0 120 {
michael@0 121 --gRefCnt;
michael@0 122 if (mType & NS_HANDLER_TYPE_XUL) {
michael@0 123 NS_IF_RELEASE(mHandlerElement);
michael@0 124 } else if (mHandlerText) {
michael@0 125 nsMemory::Free(mHandlerText);
michael@0 126 }
michael@0 127
michael@0 128 // We own the next handler in the chain, so delete it now.
michael@0 129 NS_CONTENT_DELETE_LIST_MEMBER(nsXBLPrototypeHandler, this, mNextHandler);
michael@0 130 }
michael@0 131
michael@0 132 already_AddRefed<nsIContent>
michael@0 133 nsXBLPrototypeHandler::GetHandlerElement()
michael@0 134 {
michael@0 135 if (mType & NS_HANDLER_TYPE_XUL) {
michael@0 136 nsCOMPtr<nsIContent> element = do_QueryReferent(mHandlerElement);
michael@0 137 return element.forget();
michael@0 138 }
michael@0 139
michael@0 140 return nullptr;
michael@0 141 }
michael@0 142
michael@0 143 void
michael@0 144 nsXBLPrototypeHandler::AppendHandlerText(const nsAString& aText)
michael@0 145 {
michael@0 146 if (mHandlerText) {
michael@0 147 // Append our text to the existing text.
michael@0 148 char16_t* temp = mHandlerText;
michael@0 149 mHandlerText = ToNewUnicode(nsDependentString(temp) + aText);
michael@0 150 nsMemory::Free(temp);
michael@0 151 }
michael@0 152 else {
michael@0 153 mHandlerText = ToNewUnicode(aText);
michael@0 154 }
michael@0 155 }
michael@0 156
michael@0 157 /////////////////////////////////////////////////////////////////////////////
michael@0 158 // Get the menu access key from prefs.
michael@0 159 // XXX Eventually pick up using CSS3 key-equivalent property or somesuch
michael@0 160 void
michael@0 161 nsXBLPrototypeHandler::InitAccessKeys()
michael@0 162 {
michael@0 163 if (kAccelKey >= 0 && kMenuAccessKey >= 0)
michael@0 164 return;
michael@0 165
michael@0 166 // Compiled-in defaults, in case we can't get the pref --
michael@0 167 // mac doesn't have menu shortcuts, other platforms use alt.
michael@0 168 #ifdef XP_MACOSX
michael@0 169 kMenuAccessKey = 0;
michael@0 170 kAccelKey = nsIDOMKeyEvent::DOM_VK_META;
michael@0 171 #else
michael@0 172 kMenuAccessKey = nsIDOMKeyEvent::DOM_VK_ALT;
michael@0 173 kAccelKey = nsIDOMKeyEvent::DOM_VK_CONTROL;
michael@0 174 #endif
michael@0 175
michael@0 176 // Get the menu access key value from prefs, overriding the default:
michael@0 177 kMenuAccessKey =
michael@0 178 Preferences::GetInt("ui.key.menuAccessKey", kMenuAccessKey);
michael@0 179 kAccelKey = Preferences::GetInt("ui.key.accelKey", kAccelKey);
michael@0 180 }
michael@0 181
michael@0 182 nsresult
michael@0 183 nsXBLPrototypeHandler::ExecuteHandler(EventTarget* aTarget,
michael@0 184 nsIDOMEvent* aEvent)
michael@0 185 {
michael@0 186 nsresult rv = NS_ERROR_FAILURE;
michael@0 187
michael@0 188 // Prevent default action?
michael@0 189 if (mType & NS_HANDLER_TYPE_PREVENTDEFAULT) {
michael@0 190 aEvent->PreventDefault();
michael@0 191 // If we prevent default, then it's okay for
michael@0 192 // mHandlerElement and mHandlerText to be null
michael@0 193 rv = NS_OK;
michael@0 194 }
michael@0 195
michael@0 196 if (!mHandlerElement) // This works for both types of handlers. In both cases, the union's var should be defined.
michael@0 197 return rv;
michael@0 198
michael@0 199 // See if our event receiver is a content node (and not us).
michael@0 200 bool isXULKey = !!(mType & NS_HANDLER_TYPE_XUL);
michael@0 201 bool isXBLCommand = !!(mType & NS_HANDLER_TYPE_XBL_COMMAND);
michael@0 202 NS_ASSERTION(!(isXULKey && isXBLCommand),
michael@0 203 "can't be both a key and xbl command handler");
michael@0 204
michael@0 205 // XUL handlers and commands shouldn't be triggered by non-trusted
michael@0 206 // events.
michael@0 207 if (isXULKey || isXBLCommand) {
michael@0 208 bool trustedEvent = false;
michael@0 209 aEvent->GetIsTrusted(&trustedEvent);
michael@0 210
michael@0 211 if (!trustedEvent)
michael@0 212 return NS_OK;
michael@0 213 }
michael@0 214
michael@0 215 if (isXBLCommand) {
michael@0 216 return DispatchXBLCommand(aTarget, aEvent);
michael@0 217 }
michael@0 218
michael@0 219 // If we're executing on a XUL key element, just dispatch a command
michael@0 220 // event at the element. It will take care of retargeting it to its
michael@0 221 // command element, if applicable, and executing the event handler.
michael@0 222 if (isXULKey) {
michael@0 223 return DispatchXULKeyCommand(aEvent);
michael@0 224 }
michael@0 225
michael@0 226 // Look for a compiled handler on the element.
michael@0 227 // Should be compiled and bound with "on" in front of the name.
michael@0 228 nsCOMPtr<nsIAtom> onEventAtom = do_GetAtom(NS_LITERAL_STRING("onxbl") +
michael@0 229 nsDependentAtomString(mEventName));
michael@0 230
michael@0 231 // Compile the handler and bind it to the element.
michael@0 232 nsCOMPtr<nsIScriptGlobalObject> boundGlobal;
michael@0 233 nsCOMPtr<nsPIWindowRoot> winRoot(do_QueryInterface(aTarget));
michael@0 234 nsCOMPtr<nsPIDOMWindow> window;
michael@0 235
michael@0 236 if (winRoot) {
michael@0 237 window = winRoot->GetWindow();
michael@0 238 }
michael@0 239
michael@0 240 if (window) {
michael@0 241 window = window->GetCurrentInnerWindow();
michael@0 242 NS_ENSURE_TRUE(window, NS_ERROR_UNEXPECTED);
michael@0 243
michael@0 244 boundGlobal = do_QueryInterface(window->GetPrivateRoot());
michael@0 245 }
michael@0 246 else boundGlobal = do_QueryInterface(aTarget);
michael@0 247
michael@0 248 if (!boundGlobal) {
michael@0 249 nsCOMPtr<nsIDocument> boundDocument(do_QueryInterface(aTarget));
michael@0 250 if (!boundDocument) {
michael@0 251 // We must be an element.
michael@0 252 nsCOMPtr<nsIContent> content(do_QueryInterface(aTarget));
michael@0 253 if (!content)
michael@0 254 return NS_OK;
michael@0 255 boundDocument = content->OwnerDoc();
michael@0 256 }
michael@0 257
michael@0 258 boundGlobal = do_QueryInterface(boundDocument->GetScopeObject());
michael@0 259 }
michael@0 260
michael@0 261 if (!boundGlobal)
michael@0 262 return NS_OK;
michael@0 263
michael@0 264 nsIScriptContext *boundContext = boundGlobal->GetScriptContext();
michael@0 265 if (!boundContext)
michael@0 266 return NS_OK;
michael@0 267
michael@0 268 nsISupports *scriptTarget;
michael@0 269
michael@0 270 if (winRoot) {
michael@0 271 scriptTarget = boundGlobal;
michael@0 272 } else {
michael@0 273 scriptTarget = aTarget;
michael@0 274 }
michael@0 275
michael@0 276 // We're about to create a new JSEventHandler, which means that we're
michael@0 277 // responsible for pushing the context of the event target. See the similar
michael@0 278 // comment in nsEventManagerListener.cpp.
michael@0 279 nsCxPusher pusher;
michael@0 280 NS_ENSURE_STATE(pusher.Push(aTarget));
michael@0 281
michael@0 282 AutoPushJSContext cx(boundContext->GetNativeContext());
michael@0 283 JS::Rooted<JSObject*> handler(cx);
michael@0 284
michael@0 285 rv = EnsureEventHandler(boundGlobal, boundContext, onEventAtom, &handler);
michael@0 286 NS_ENSURE_SUCCESS(rv, rv);
michael@0 287
michael@0 288 JS::Rooted<JSObject*> globalObject(cx, boundGlobal->GetGlobalJSObject());
michael@0 289 JS::Rooted<JSObject*> scopeObject(cx, xpc::GetXBLScopeOrGlobal(cx, globalObject));
michael@0 290 NS_ENSURE_TRUE(scopeObject, NS_ERROR_OUT_OF_MEMORY);
michael@0 291
michael@0 292 // Bind it to the bound element. Note that if we're using a separate XBL scope,
michael@0 293 // we'll actually be binding the event handler to a cross-compartment wrapper
michael@0 294 // to the bound element's reflector.
michael@0 295
michael@0 296 // First, enter our XBL scope. This is where the generic handler should have
michael@0 297 // been compiled, above.
michael@0 298 JSAutoCompartment ac(cx, scopeObject);
michael@0 299 JS::Rooted<JSObject*> genericHandler(cx, handler.get());
michael@0 300 bool ok = JS_WrapObject(cx, &genericHandler);
michael@0 301 NS_ENSURE_TRUE(ok, NS_ERROR_OUT_OF_MEMORY);
michael@0 302 MOZ_ASSERT(!js::IsCrossCompartmentWrapper(genericHandler));
michael@0 303
michael@0 304 // Wrap the native into the XBL scope. This creates a reflector in the document
michael@0 305 // scope if one doesn't already exist, and potentially wraps it cross-
michael@0 306 // compartment into our scope (via aAllowWrapping=true).
michael@0 307 JS::Rooted<JS::Value> targetV(cx, JS::UndefinedValue());
michael@0 308 rv = nsContentUtils::WrapNative(cx, scriptTarget, &targetV);
michael@0 309 NS_ENSURE_SUCCESS(rv, rv);
michael@0 310
michael@0 311 // Next, clone the generic handler to be parented to the target.
michael@0 312 JS::Rooted<JSObject*> target(cx, &targetV.toObject());
michael@0 313 JS::Rooted<JSObject*> bound(cx, JS_CloneFunctionObject(cx, genericHandler, target));
michael@0 314 NS_ENSURE_TRUE(bound, NS_ERROR_FAILURE);
michael@0 315
michael@0 316 // Now, wrap the bound handler into the content compartment and use it.
michael@0 317 JSAutoCompartment ac2(cx, globalObject);
michael@0 318 if (!JS_WrapObject(cx, &bound)) {
michael@0 319 return NS_ERROR_FAILURE;
michael@0 320 }
michael@0 321
michael@0 322 nsRefPtr<EventHandlerNonNull> handlerCallback =
michael@0 323 new EventHandlerNonNull(bound, /* aIncumbentGlobal = */ nullptr);
michael@0 324
michael@0 325 TypedEventHandler typedHandler(handlerCallback);
michael@0 326
michael@0 327 // Execute it.
michael@0 328 nsCOMPtr<JSEventHandler> jsEventHandler;
michael@0 329 rv = NS_NewJSEventHandler(scriptTarget, onEventAtom,
michael@0 330 typedHandler,
michael@0 331 getter_AddRefs(jsEventHandler));
michael@0 332 NS_ENSURE_SUCCESS(rv, rv);
michael@0 333
michael@0 334 // Handle the event.
michael@0 335 jsEventHandler->HandleEvent(aEvent);
michael@0 336 jsEventHandler->Disconnect();
michael@0 337 return NS_OK;
michael@0 338 }
michael@0 339
michael@0 340 nsresult
michael@0 341 nsXBLPrototypeHandler::EnsureEventHandler(nsIScriptGlobalObject* aGlobal,
michael@0 342 nsIScriptContext *aBoundContext,
michael@0 343 nsIAtom *aName,
michael@0 344 JS::MutableHandle<JSObject*> aHandler)
michael@0 345 {
michael@0 346 AutoPushJSContext cx(aBoundContext->GetNativeContext());
michael@0 347
michael@0 348 // Check to see if we've already compiled this
michael@0 349 nsCOMPtr<nsPIDOMWindow> pWindow = do_QueryInterface(aGlobal);
michael@0 350 if (pWindow) {
michael@0 351 JS::Rooted<JSObject*> cachedHandler(cx, pWindow->GetCachedXBLPrototypeHandler(this));
michael@0 352 if (cachedHandler) {
michael@0 353 JS::ExposeObjectToActiveJS(cachedHandler);
michael@0 354 aHandler.set(cachedHandler);
michael@0 355 NS_ENSURE_TRUE(aHandler, NS_ERROR_FAILURE);
michael@0 356 return NS_OK;
michael@0 357 }
michael@0 358 }
michael@0 359
michael@0 360 // Ensure that we have something to compile
michael@0 361 nsDependentString handlerText(mHandlerText);
michael@0 362 NS_ENSURE_TRUE(!handlerText.IsEmpty(), NS_ERROR_FAILURE);
michael@0 363
michael@0 364 JS::Rooted<JSObject*> globalObject(cx, aGlobal->GetGlobalJSObject());
michael@0 365 JS::Rooted<JSObject*> scopeObject(cx, xpc::GetXBLScopeOrGlobal(cx, globalObject));
michael@0 366 NS_ENSURE_TRUE(scopeObject, NS_ERROR_OUT_OF_MEMORY);
michael@0 367
michael@0 368 nsAutoCString bindingURI;
michael@0 369 mPrototypeBinding->DocURI()->GetSpec(bindingURI);
michael@0 370
michael@0 371 uint32_t argCount;
michael@0 372 const char **argNames;
michael@0 373 nsContentUtils::GetEventArgNames(kNameSpaceID_XBL, aName, &argCount,
michael@0 374 &argNames);
michael@0 375
michael@0 376 // Compile the event handler in the xbl scope.
michael@0 377 JSAutoCompartment ac(cx, scopeObject);
michael@0 378 JS::CompileOptions options(cx);
michael@0 379 options.setFileAndLine(bindingURI.get(), mLineNumber)
michael@0 380 .setVersion(JSVERSION_LATEST);
michael@0 381
michael@0 382 JS::Rooted<JSObject*> handlerFun(cx);
michael@0 383 nsresult rv = nsJSUtils::CompileFunction(cx, JS::NullPtr(), options,
michael@0 384 nsAtomCString(aName), argCount,
michael@0 385 argNames, handlerText,
michael@0 386 handlerFun.address());
michael@0 387 NS_ENSURE_SUCCESS(rv, rv);
michael@0 388 NS_ENSURE_TRUE(handlerFun, NS_ERROR_FAILURE);
michael@0 389
michael@0 390 // Wrap the handler into the content scope, since we're about to stash it
michael@0 391 // on the DOM window and such.
michael@0 392 JSAutoCompartment ac2(cx, globalObject);
michael@0 393 bool ok = JS_WrapObject(cx, &handlerFun);
michael@0 394 NS_ENSURE_TRUE(ok, NS_ERROR_OUT_OF_MEMORY);
michael@0 395 aHandler.set(handlerFun);
michael@0 396 NS_ENSURE_TRUE(aHandler, NS_ERROR_FAILURE);
michael@0 397
michael@0 398 if (pWindow) {
michael@0 399 pWindow->CacheXBLPrototypeHandler(this, aHandler);
michael@0 400 }
michael@0 401
michael@0 402 return NS_OK;
michael@0 403 }
michael@0 404
michael@0 405 nsresult
michael@0 406 nsXBLPrototypeHandler::DispatchXBLCommand(EventTarget* aTarget, nsIDOMEvent* aEvent)
michael@0 407 {
michael@0 408 // This is a special-case optimization to make command handling fast.
michael@0 409 // It isn't really a part of XBL, but it helps speed things up.
michael@0 410
michael@0 411 if (aEvent) {
michael@0 412 // See if preventDefault has been set. If so, don't execute.
michael@0 413 bool preventDefault = false;
michael@0 414 aEvent->GetDefaultPrevented(&preventDefault);
michael@0 415 if (preventDefault) {
michael@0 416 return NS_OK;
michael@0 417 }
michael@0 418 bool dispatchStopped = aEvent->IsDispatchStopped();
michael@0 419 if (dispatchStopped) {
michael@0 420 return NS_OK;
michael@0 421 }
michael@0 422 }
michael@0 423
michael@0 424 // Instead of executing JS, let's get the controller for the bound
michael@0 425 // element and call doCommand on it.
michael@0 426 nsCOMPtr<nsIController> controller;
michael@0 427
michael@0 428 nsCOMPtr<nsPIDOMWindow> privateWindow;
michael@0 429 nsCOMPtr<nsPIWindowRoot> windowRoot(do_QueryInterface(aTarget));
michael@0 430 if (windowRoot) {
michael@0 431 privateWindow = windowRoot->GetWindow();
michael@0 432 }
michael@0 433 else {
michael@0 434 privateWindow = do_QueryInterface(aTarget);
michael@0 435 if (!privateWindow) {
michael@0 436 nsCOMPtr<nsIContent> elt(do_QueryInterface(aTarget));
michael@0 437 nsCOMPtr<nsIDocument> doc;
michael@0 438 // XXXbz sXBL/XBL2 issue -- this should be the "scope doc" or
michael@0 439 // something... whatever we use when wrapping DOM nodes
michael@0 440 // normally. It's not clear that the owner doc is the right
michael@0 441 // thing.
michael@0 442 if (elt)
michael@0 443 doc = elt->OwnerDoc();
michael@0 444
michael@0 445 if (!doc)
michael@0 446 doc = do_QueryInterface(aTarget);
michael@0 447
michael@0 448 if (!doc)
michael@0 449 return NS_ERROR_FAILURE;
michael@0 450
michael@0 451 privateWindow = doc->GetWindow();
michael@0 452 if (!privateWindow)
michael@0 453 return NS_ERROR_FAILURE;
michael@0 454 }
michael@0 455
michael@0 456 windowRoot = privateWindow->GetTopWindowRoot();
michael@0 457 }
michael@0 458
michael@0 459 NS_LossyConvertUTF16toASCII command(mHandlerText);
michael@0 460 if (windowRoot)
michael@0 461 windowRoot->GetControllerForCommand(command.get(), getter_AddRefs(controller));
michael@0 462 else
michael@0 463 controller = GetController(aTarget); // We're attached to the receiver possibly.
michael@0 464
michael@0 465 if (mEventName == nsGkAtoms::keypress &&
michael@0 466 mDetail == nsIDOMKeyEvent::DOM_VK_SPACE &&
michael@0 467 mMisc == 1) {
michael@0 468 // get the focused element so that we can pageDown only at
michael@0 469 // certain times.
michael@0 470
michael@0 471 nsCOMPtr<nsPIDOMWindow> windowToCheck;
michael@0 472 if (windowRoot)
michael@0 473 windowToCheck = windowRoot->GetWindow();
michael@0 474 else
michael@0 475 windowToCheck = privateWindow->GetPrivateRoot();
michael@0 476
michael@0 477 nsCOMPtr<nsIContent> focusedContent;
michael@0 478 if (windowToCheck) {
michael@0 479 nsCOMPtr<nsPIDOMWindow> focusedWindow;
michael@0 480 focusedContent =
michael@0 481 nsFocusManager::GetFocusedDescendant(windowToCheck, true, getter_AddRefs(focusedWindow));
michael@0 482 }
michael@0 483
michael@0 484 bool isLink = false;
michael@0 485 nsIContent *content = focusedContent;
michael@0 486
michael@0 487 // if the focused element is a link then we do want space to
michael@0 488 // scroll down. The focused element may be an element in a link,
michael@0 489 // we need to check the parent node too. Only do this check if an
michael@0 490 // element is focused and has a parent.
michael@0 491 if (focusedContent && focusedContent->GetParent()) {
michael@0 492 while (content) {
michael@0 493 if (content->Tag() == nsGkAtoms::a && content->IsHTML()) {
michael@0 494 isLink = true;
michael@0 495 break;
michael@0 496 }
michael@0 497
michael@0 498 if (content->HasAttr(kNameSpaceID_XLink, nsGkAtoms::type)) {
michael@0 499 isLink = content->AttrValueIs(kNameSpaceID_XLink, nsGkAtoms::type,
michael@0 500 nsGkAtoms::simple, eCaseMatters);
michael@0 501
michael@0 502 if (isLink) {
michael@0 503 break;
michael@0 504 }
michael@0 505 }
michael@0 506
michael@0 507 content = content->GetParent();
michael@0 508 }
michael@0 509
michael@0 510 if (!isLink)
michael@0 511 return NS_OK;
michael@0 512 }
michael@0 513 }
michael@0 514
michael@0 515 // We are the default action for this command.
michael@0 516 // Stop any other default action from executing.
michael@0 517 aEvent->PreventDefault();
michael@0 518
michael@0 519 if (controller)
michael@0 520 controller->DoCommand(command.get());
michael@0 521
michael@0 522 return NS_OK;
michael@0 523 }
michael@0 524
michael@0 525 nsresult
michael@0 526 nsXBLPrototypeHandler::DispatchXULKeyCommand(nsIDOMEvent* aEvent)
michael@0 527 {
michael@0 528 nsCOMPtr<nsIContent> handlerElement = GetHandlerElement();
michael@0 529 NS_ENSURE_STATE(handlerElement);
michael@0 530 if (handlerElement->AttrValueIs(kNameSpaceID_None,
michael@0 531 nsGkAtoms::disabled,
michael@0 532 nsGkAtoms::_true,
michael@0 533 eCaseMatters)) {
michael@0 534 // Don't dispatch command events for disabled keys.
michael@0 535 return NS_OK;
michael@0 536 }
michael@0 537
michael@0 538 aEvent->PreventDefault();
michael@0 539
michael@0 540 // Copy the modifiers from the key event.
michael@0 541 nsCOMPtr<nsIDOMKeyEvent> keyEvent = do_QueryInterface(aEvent);
michael@0 542 if (!keyEvent) {
michael@0 543 NS_ERROR("Trying to execute a key handler for a non-key event!");
michael@0 544 return NS_ERROR_FAILURE;
michael@0 545 }
michael@0 546
michael@0 547 // XXX We should use mozilla::Modifiers for supporting all modifiers.
michael@0 548
michael@0 549 bool isAlt = false;
michael@0 550 bool isControl = false;
michael@0 551 bool isShift = false;
michael@0 552 bool isMeta = false;
michael@0 553 keyEvent->GetAltKey(&isAlt);
michael@0 554 keyEvent->GetCtrlKey(&isControl);
michael@0 555 keyEvent->GetShiftKey(&isShift);
michael@0 556 keyEvent->GetMetaKey(&isMeta);
michael@0 557
michael@0 558 nsContentUtils::DispatchXULCommand(handlerElement, true,
michael@0 559 nullptr, nullptr,
michael@0 560 isControl, isAlt, isShift, isMeta);
michael@0 561 return NS_OK;
michael@0 562 }
michael@0 563
michael@0 564 already_AddRefed<nsIAtom>
michael@0 565 nsXBLPrototypeHandler::GetEventName()
michael@0 566 {
michael@0 567 nsCOMPtr<nsIAtom> eventName = mEventName;
michael@0 568 return eventName.forget();
michael@0 569 }
michael@0 570
michael@0 571 already_AddRefed<nsIController>
michael@0 572 nsXBLPrototypeHandler::GetController(EventTarget* aTarget)
michael@0 573 {
michael@0 574 // XXX Fix this so there's a generic interface that describes controllers,
michael@0 575 // This code should have no special knowledge of what objects might have controllers.
michael@0 576 nsCOMPtr<nsIControllers> controllers;
michael@0 577
michael@0 578 nsCOMPtr<nsIDOMXULElement> xulElement(do_QueryInterface(aTarget));
michael@0 579 if (xulElement)
michael@0 580 xulElement->GetControllers(getter_AddRefs(controllers));
michael@0 581
michael@0 582 if (!controllers) {
michael@0 583 nsCOMPtr<nsIDOMHTMLTextAreaElement> htmlTextArea(do_QueryInterface(aTarget));
michael@0 584 if (htmlTextArea)
michael@0 585 htmlTextArea->GetControllers(getter_AddRefs(controllers));
michael@0 586 }
michael@0 587
michael@0 588 if (!controllers) {
michael@0 589 nsCOMPtr<nsIDOMHTMLInputElement> htmlInputElement(do_QueryInterface(aTarget));
michael@0 590 if (htmlInputElement)
michael@0 591 htmlInputElement->GetControllers(getter_AddRefs(controllers));
michael@0 592 }
michael@0 593
michael@0 594 if (!controllers) {
michael@0 595 nsCOMPtr<nsIDOMWindow> domWindow(do_QueryInterface(aTarget));
michael@0 596 if (domWindow)
michael@0 597 domWindow->GetControllers(getter_AddRefs(controllers));
michael@0 598 }
michael@0 599
michael@0 600 // Return the first controller.
michael@0 601 // XXX This code should be checking the command name and using supportscommand and
michael@0 602 // iscommandenabled.
michael@0 603 nsCOMPtr<nsIController> controller;
michael@0 604 if (controllers) {
michael@0 605 controllers->GetControllerAt(0, getter_AddRefs(controller));
michael@0 606 }
michael@0 607
michael@0 608 return controller.forget();
michael@0 609 }
michael@0 610
michael@0 611 bool
michael@0 612 nsXBLPrototypeHandler::KeyEventMatched(nsIDOMKeyEvent* aKeyEvent,
michael@0 613 uint32_t aCharCode,
michael@0 614 bool aIgnoreShiftKey)
michael@0 615 {
michael@0 616 if (mDetail != -1) {
michael@0 617 // Get the keycode or charcode of the key event.
michael@0 618 uint32_t code;
michael@0 619
michael@0 620 if (mMisc) {
michael@0 621 if (aCharCode)
michael@0 622 code = aCharCode;
michael@0 623 else
michael@0 624 aKeyEvent->GetCharCode(&code);
michael@0 625 if (IS_IN_BMP(code))
michael@0 626 code = ToLowerCase(char16_t(code));
michael@0 627 }
michael@0 628 else
michael@0 629 aKeyEvent->GetKeyCode(&code);
michael@0 630
michael@0 631 if (code != uint32_t(mDetail))
michael@0 632 return false;
michael@0 633 }
michael@0 634
michael@0 635 return ModifiersMatchMask(aKeyEvent, aIgnoreShiftKey);
michael@0 636 }
michael@0 637
michael@0 638 bool
michael@0 639 nsXBLPrototypeHandler::MouseEventMatched(nsIDOMMouseEvent* aMouseEvent)
michael@0 640 {
michael@0 641 if (mDetail == -1 && mMisc == 0 && (mKeyMask & cAllModifiers) == 0)
michael@0 642 return true; // No filters set up. It's generic.
michael@0 643
michael@0 644 int16_t button;
michael@0 645 aMouseEvent->GetButton(&button);
michael@0 646 if (mDetail != -1 && (button != mDetail))
michael@0 647 return false;
michael@0 648
michael@0 649 int32_t clickcount;
michael@0 650 aMouseEvent->GetDetail(&clickcount);
michael@0 651 if (mMisc != 0 && (clickcount != mMisc))
michael@0 652 return false;
michael@0 653
michael@0 654 return ModifiersMatchMask(aMouseEvent);
michael@0 655 }
michael@0 656
michael@0 657 struct keyCodeData {
michael@0 658 const char* str;
michael@0 659 size_t strlength;
michael@0 660 uint32_t keycode;
michael@0 661 };
michael@0 662
michael@0 663 // All of these must be uppercase, since the function below does
michael@0 664 // case-insensitive comparison by converting to uppercase.
michael@0 665 // XXX: be sure to check this periodically for new symbol additions!
michael@0 666 static const keyCodeData gKeyCodes[] = {
michael@0 667
michael@0 668 #define NS_DEFINE_VK(aDOMKeyName, aDOMKeyCode) \
michael@0 669 { #aDOMKeyName, sizeof(#aDOMKeyName) - 1, aDOMKeyCode }
michael@0 670 #include "mozilla/VirtualKeyCodeList.h"
michael@0 671 #undef NS_DEFINE_VK
michael@0 672 };
michael@0 673
michael@0 674 int32_t nsXBLPrototypeHandler::GetMatchingKeyCode(const nsAString& aKeyName)
michael@0 675 {
michael@0 676 nsAutoCString keyName;
michael@0 677 keyName.AssignWithConversion(aKeyName);
michael@0 678 ToUpperCase(keyName); // We want case-insensitive comparison with data
michael@0 679 // stored as uppercase.
michael@0 680
michael@0 681 uint32_t keyNameLength = keyName.Length();
michael@0 682 const char* keyNameStr = keyName.get();
michael@0 683 for (uint16_t i = 0; i < (sizeof(gKeyCodes) / sizeof(gKeyCodes[0])); ++i)
michael@0 684 if (keyNameLength == gKeyCodes[i].strlength &&
michael@0 685 !nsCRT::strcmp(gKeyCodes[i].str, keyNameStr))
michael@0 686 return gKeyCodes[i].keycode;
michael@0 687
michael@0 688 return 0;
michael@0 689 }
michael@0 690
michael@0 691 int32_t nsXBLPrototypeHandler::KeyToMask(int32_t key)
michael@0 692 {
michael@0 693 switch (key)
michael@0 694 {
michael@0 695 case nsIDOMKeyEvent::DOM_VK_META:
michael@0 696 return cMeta | cMetaMask;
michael@0 697
michael@0 698 case nsIDOMKeyEvent::DOM_VK_WIN:
michael@0 699 return cOS | cOSMask;
michael@0 700
michael@0 701 case nsIDOMKeyEvent::DOM_VK_ALT:
michael@0 702 return cAlt | cAltMask;
michael@0 703
michael@0 704 case nsIDOMKeyEvent::DOM_VK_CONTROL:
michael@0 705 default:
michael@0 706 return cControl | cControlMask;
michael@0 707 }
michael@0 708 return cControl | cControlMask; // for warning avoidance
michael@0 709 }
michael@0 710
michael@0 711 void
michael@0 712 nsXBLPrototypeHandler::GetEventType(nsAString& aEvent)
michael@0 713 {
michael@0 714 nsCOMPtr<nsIContent> handlerElement = GetHandlerElement();
michael@0 715 if (!handlerElement) {
michael@0 716 aEvent.Truncate();
michael@0 717 return;
michael@0 718 }
michael@0 719 handlerElement->GetAttr(kNameSpaceID_None, nsGkAtoms::event, aEvent);
michael@0 720
michael@0 721 if (aEvent.IsEmpty() && (mType & NS_HANDLER_TYPE_XUL))
michael@0 722 // If no type is specified for a XUL <key> element, let's assume that we're "keypress".
michael@0 723 aEvent.AssignLiteral("keypress");
michael@0 724 }
michael@0 725
michael@0 726 void
michael@0 727 nsXBLPrototypeHandler::ConstructPrototype(nsIContent* aKeyElement,
michael@0 728 const char16_t* aEvent,
michael@0 729 const char16_t* aPhase,
michael@0 730 const char16_t* aAction,
michael@0 731 const char16_t* aCommand,
michael@0 732 const char16_t* aKeyCode,
michael@0 733 const char16_t* aCharCode,
michael@0 734 const char16_t* aModifiers,
michael@0 735 const char16_t* aButton,
michael@0 736 const char16_t* aClickCount,
michael@0 737 const char16_t* aGroup,
michael@0 738 const char16_t* aPreventDefault,
michael@0 739 const char16_t* aAllowUntrusted)
michael@0 740 {
michael@0 741 mType = 0;
michael@0 742
michael@0 743 if (aKeyElement) {
michael@0 744 mType |= NS_HANDLER_TYPE_XUL;
michael@0 745 nsCOMPtr<nsIWeakReference> weak = do_GetWeakReference(aKeyElement);
michael@0 746 if (!weak) {
michael@0 747 return;
michael@0 748 }
michael@0 749 weak.swap(mHandlerElement);
michael@0 750 }
michael@0 751 else {
michael@0 752 mType |= aCommand ? NS_HANDLER_TYPE_XBL_COMMAND : NS_HANDLER_TYPE_XBL_JS;
michael@0 753 mHandlerText = nullptr;
michael@0 754 }
michael@0 755
michael@0 756 mDetail = -1;
michael@0 757 mMisc = 0;
michael@0 758 mKeyMask = 0;
michael@0 759 mPhase = NS_PHASE_BUBBLING;
michael@0 760
michael@0 761 if (aAction)
michael@0 762 mHandlerText = ToNewUnicode(nsDependentString(aAction));
michael@0 763 else if (aCommand)
michael@0 764 mHandlerText = ToNewUnicode(nsDependentString(aCommand));
michael@0 765
michael@0 766 nsAutoString event(aEvent);
michael@0 767 if (event.IsEmpty()) {
michael@0 768 if (mType & NS_HANDLER_TYPE_XUL)
michael@0 769 GetEventType(event);
michael@0 770 if (event.IsEmpty())
michael@0 771 return;
michael@0 772 }
michael@0 773
michael@0 774 mEventName = do_GetAtom(event);
michael@0 775
michael@0 776 if (aPhase) {
michael@0 777 const nsDependentString phase(aPhase);
michael@0 778 if (phase.EqualsLiteral("capturing"))
michael@0 779 mPhase = NS_PHASE_CAPTURING;
michael@0 780 else if (phase.EqualsLiteral("target"))
michael@0 781 mPhase = NS_PHASE_TARGET;
michael@0 782 }
michael@0 783
michael@0 784 // Button and clickcount apply only to XBL handlers and don't apply to XUL key
michael@0 785 // handlers.
michael@0 786 if (aButton && *aButton)
michael@0 787 mDetail = *aButton - '0';
michael@0 788
michael@0 789 if (aClickCount && *aClickCount)
michael@0 790 mMisc = *aClickCount - '0';
michael@0 791
michael@0 792 // Modifiers are supported by both types of handlers (XUL and XBL).
michael@0 793 nsAutoString modifiers(aModifiers);
michael@0 794 if (mType & NS_HANDLER_TYPE_XUL)
michael@0 795 aKeyElement->GetAttr(kNameSpaceID_None, nsGkAtoms::modifiers, modifiers);
michael@0 796
michael@0 797 if (!modifiers.IsEmpty()) {
michael@0 798 mKeyMask = cAllModifiers;
michael@0 799 char* str = ToNewCString(modifiers);
michael@0 800 char* newStr;
michael@0 801 char* token = nsCRT::strtok( str, ", \t", &newStr );
michael@0 802 while( token != nullptr ) {
michael@0 803 if (PL_strcmp(token, "shift") == 0)
michael@0 804 mKeyMask |= cShift | cShiftMask;
michael@0 805 else if (PL_strcmp(token, "alt") == 0)
michael@0 806 mKeyMask |= cAlt | cAltMask;
michael@0 807 else if (PL_strcmp(token, "meta") == 0)
michael@0 808 mKeyMask |= cMeta | cMetaMask;
michael@0 809 else if (PL_strcmp(token, "os") == 0)
michael@0 810 mKeyMask |= cOS | cOSMask;
michael@0 811 else if (PL_strcmp(token, "control") == 0)
michael@0 812 mKeyMask |= cControl | cControlMask;
michael@0 813 else if (PL_strcmp(token, "accel") == 0)
michael@0 814 mKeyMask |= KeyToMask(kAccelKey);
michael@0 815 else if (PL_strcmp(token, "access") == 0)
michael@0 816 mKeyMask |= KeyToMask(kMenuAccessKey);
michael@0 817 else if (PL_strcmp(token, "any") == 0)
michael@0 818 mKeyMask &= ~(mKeyMask << 5);
michael@0 819
michael@0 820 token = nsCRT::strtok( newStr, ", \t", &newStr );
michael@0 821 }
michael@0 822
michael@0 823 nsMemory::Free(str);
michael@0 824 }
michael@0 825
michael@0 826 nsAutoString key(aCharCode);
michael@0 827 if (key.IsEmpty()) {
michael@0 828 if (mType & NS_HANDLER_TYPE_XUL) {
michael@0 829 aKeyElement->GetAttr(kNameSpaceID_None, nsGkAtoms::key, key);
michael@0 830 if (key.IsEmpty())
michael@0 831 aKeyElement->GetAttr(kNameSpaceID_None, nsGkAtoms::charcode, key);
michael@0 832 }
michael@0 833 }
michael@0 834
michael@0 835 if (!key.IsEmpty()) {
michael@0 836 if (mKeyMask == 0)
michael@0 837 mKeyMask = cAllModifiers;
michael@0 838 ToLowerCase(key);
michael@0 839
michael@0 840 // We have a charcode.
michael@0 841 mMisc = 1;
michael@0 842 mDetail = key[0];
michael@0 843 const uint8_t GTK2Modifiers = cShift | cControl | cShiftMask | cControlMask;
michael@0 844 if ((mKeyMask & GTK2Modifiers) == GTK2Modifiers &&
michael@0 845 modifiers.First() != char16_t(',') &&
michael@0 846 (mDetail == 'u' || mDetail == 'U'))
michael@0 847 ReportKeyConflict(key.get(), modifiers.get(), aKeyElement, "GTK2Conflict");
michael@0 848 const uint8_t WinModifiers = cControl | cAlt | cControlMask | cAltMask;
michael@0 849 if ((mKeyMask & WinModifiers) == WinModifiers &&
michael@0 850 modifiers.First() != char16_t(',') &&
michael@0 851 (('A' <= mDetail && mDetail <= 'Z') ||
michael@0 852 ('a' <= mDetail && mDetail <= 'z')))
michael@0 853 ReportKeyConflict(key.get(), modifiers.get(), aKeyElement, "WinConflict");
michael@0 854 }
michael@0 855 else {
michael@0 856 key.Assign(aKeyCode);
michael@0 857 if (mType & NS_HANDLER_TYPE_XUL)
michael@0 858 aKeyElement->GetAttr(kNameSpaceID_None, nsGkAtoms::keycode, key);
michael@0 859
michael@0 860 if (!key.IsEmpty()) {
michael@0 861 if (mKeyMask == 0)
michael@0 862 mKeyMask = cAllModifiers;
michael@0 863 mDetail = GetMatchingKeyCode(key);
michael@0 864 }
michael@0 865 }
michael@0 866
michael@0 867 if (aGroup && nsDependentString(aGroup).EqualsLiteral("system"))
michael@0 868 mType |= NS_HANDLER_TYPE_SYSTEM;
michael@0 869
michael@0 870 if (aPreventDefault &&
michael@0 871 nsDependentString(aPreventDefault).EqualsLiteral("true"))
michael@0 872 mType |= NS_HANDLER_TYPE_PREVENTDEFAULT;
michael@0 873
michael@0 874 if (aAllowUntrusted) {
michael@0 875 mType |= NS_HANDLER_HAS_ALLOW_UNTRUSTED_ATTR;
michael@0 876 if (nsDependentString(aAllowUntrusted).EqualsLiteral("true")) {
michael@0 877 mType |= NS_HANDLER_ALLOW_UNTRUSTED;
michael@0 878 } else {
michael@0 879 mType &= ~NS_HANDLER_ALLOW_UNTRUSTED;
michael@0 880 }
michael@0 881 }
michael@0 882 }
michael@0 883
michael@0 884 void
michael@0 885 nsXBLPrototypeHandler::ReportKeyConflict(const char16_t* aKey, const char16_t* aModifiers, nsIContent* aKeyElement, const char *aMessageName)
michael@0 886 {
michael@0 887 nsCOMPtr<nsIDocument> doc;
michael@0 888 if (mPrototypeBinding) {
michael@0 889 nsXBLDocumentInfo* docInfo = mPrototypeBinding->XBLDocumentInfo();
michael@0 890 if (docInfo) {
michael@0 891 doc = docInfo->GetDocument();
michael@0 892 }
michael@0 893 } else if (aKeyElement) {
michael@0 894 doc = aKeyElement->OwnerDoc();
michael@0 895 }
michael@0 896
michael@0 897 const char16_t* params[] = { aKey, aModifiers };
michael@0 898 nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
michael@0 899 NS_LITERAL_CSTRING("XBL Prototype Handler"), doc,
michael@0 900 nsContentUtils::eXBL_PROPERTIES,
michael@0 901 aMessageName,
michael@0 902 params, ArrayLength(params),
michael@0 903 nullptr, EmptyString(), mLineNumber);
michael@0 904 }
michael@0 905
michael@0 906 bool
michael@0 907 nsXBLPrototypeHandler::ModifiersMatchMask(nsIDOMUIEvent* aEvent,
michael@0 908 bool aIgnoreShiftKey)
michael@0 909 {
michael@0 910 WidgetInputEvent* inputEvent = aEvent->GetInternalNSEvent()->AsInputEvent();
michael@0 911 NS_ENSURE_TRUE(inputEvent, false);
michael@0 912
michael@0 913 if (mKeyMask & cMetaMask) {
michael@0 914 if (inputEvent->IsMeta() != ((mKeyMask & cMeta) != 0)) {
michael@0 915 return false;
michael@0 916 }
michael@0 917 }
michael@0 918
michael@0 919 if (mKeyMask & cOSMask) {
michael@0 920 if (inputEvent->IsOS() != ((mKeyMask & cOS) != 0)) {
michael@0 921 return false;
michael@0 922 }
michael@0 923 }
michael@0 924
michael@0 925 if (mKeyMask & cShiftMask && !aIgnoreShiftKey) {
michael@0 926 if (inputEvent->IsShift() != ((mKeyMask & cShift) != 0)) {
michael@0 927 return false;
michael@0 928 }
michael@0 929 }
michael@0 930
michael@0 931 if (mKeyMask & cAltMask) {
michael@0 932 if (inputEvent->IsAlt() != ((mKeyMask & cAlt) != 0)) {
michael@0 933 return false;
michael@0 934 }
michael@0 935 }
michael@0 936
michael@0 937 if (mKeyMask & cControlMask) {
michael@0 938 if (inputEvent->IsControl() != ((mKeyMask & cControl) != 0)) {
michael@0 939 return false;
michael@0 940 }
michael@0 941 }
michael@0 942
michael@0 943 return true;
michael@0 944 }
michael@0 945
michael@0 946 nsresult
michael@0 947 nsXBLPrototypeHandler::Read(nsIObjectInputStream* aStream)
michael@0 948 {
michael@0 949 AssertInCompilationScope();
michael@0 950 nsresult rv = aStream->Read8(&mPhase);
michael@0 951 NS_ENSURE_SUCCESS(rv, rv);
michael@0 952 rv = aStream->Read8(&mType);
michael@0 953 NS_ENSURE_SUCCESS(rv, rv);
michael@0 954 rv = aStream->Read8(&mMisc);
michael@0 955 NS_ENSURE_SUCCESS(rv, rv);
michael@0 956
michael@0 957 rv = aStream->Read32(reinterpret_cast<uint32_t*>(&mKeyMask));
michael@0 958 NS_ENSURE_SUCCESS(rv, rv);
michael@0 959 uint32_t detail;
michael@0 960 rv = aStream->Read32(&detail);
michael@0 961 NS_ENSURE_SUCCESS(rv, rv);
michael@0 962 mDetail = detail;
michael@0 963
michael@0 964 nsAutoString name;
michael@0 965 rv = aStream->ReadString(name);
michael@0 966 NS_ENSURE_SUCCESS(rv, rv);
michael@0 967 mEventName = do_GetAtom(name);
michael@0 968
michael@0 969 rv = aStream->Read32(&mLineNumber);
michael@0 970 NS_ENSURE_SUCCESS(rv, rv);
michael@0 971
michael@0 972 nsAutoString handlerText;
michael@0 973 rv = aStream->ReadString(handlerText);
michael@0 974 NS_ENSURE_SUCCESS(rv, rv);
michael@0 975 if (!handlerText.IsEmpty())
michael@0 976 mHandlerText = ToNewUnicode(handlerText);
michael@0 977
michael@0 978 return NS_OK;
michael@0 979 }
michael@0 980
michael@0 981 nsresult
michael@0 982 nsXBLPrototypeHandler::Write(nsIObjectOutputStream* aStream)
michael@0 983 {
michael@0 984 AssertInCompilationScope();
michael@0 985 // Make sure we don't write out NS_HANDLER_TYPE_XUL types, as they are used
michael@0 986 // for <keyset> elements.
michael@0 987 if ((mType & NS_HANDLER_TYPE_XUL) || !mEventName)
michael@0 988 return NS_OK;
michael@0 989
michael@0 990 XBLBindingSerializeDetails type = XBLBinding_Serialize_Handler;
michael@0 991
michael@0 992 nsresult rv = aStream->Write8(type);
michael@0 993 rv = aStream->Write8(mPhase);
michael@0 994 NS_ENSURE_SUCCESS(rv, rv);
michael@0 995 rv = aStream->Write8(mType);
michael@0 996 NS_ENSURE_SUCCESS(rv, rv);
michael@0 997 rv = aStream->Write8(mMisc);
michael@0 998 NS_ENSURE_SUCCESS(rv, rv);
michael@0 999 rv = aStream->Write32(static_cast<uint32_t>(mKeyMask));
michael@0 1000 NS_ENSURE_SUCCESS(rv, rv);
michael@0 1001 rv = aStream->Write32(mDetail);
michael@0 1002 NS_ENSURE_SUCCESS(rv, rv);
michael@0 1003
michael@0 1004 rv = aStream->WriteWStringZ(nsDependentAtomString(mEventName).get());
michael@0 1005 NS_ENSURE_SUCCESS(rv, rv);
michael@0 1006
michael@0 1007 rv = aStream->Write32(mLineNumber);
michael@0 1008 NS_ENSURE_SUCCESS(rv, rv);
michael@0 1009 return aStream->WriteWStringZ(mHandlerText ? mHandlerText : MOZ_UTF16(""));
michael@0 1010 }

mercurial