1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is Mozilla Communicator client code.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Netscape Communications Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 1998
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : * Original Author: David W. Hyatt (hyatt@netscape.com)
24 : *
25 : * Alternatively, the contents of this file may be used under the terms of
26 : * either of the GNU General Public License Version 2 or later (the "GPL"),
27 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 : * in which case the provisions of the GPL or the LGPL are applicable instead
29 : * of those above. If you wish to allow use of your version of this file only
30 : * under the terms of either the GPL or the LGPL, and not to allow others to
31 : * use your version of this file under the terms of the MPL, indicate your
32 : * decision by deleting the provisions above and replace them with the notice
33 : * and other provisions required by the GPL or the LGPL. If you do not delete
34 : * the provisions above, a recipient may use your version of this file under
35 : * the terms of any one of the MPL, the GPL or the LGPL.
36 : *
37 : * ***** END LICENSE BLOCK ***** */
38 :
39 : #include "mozilla/Util.h"
40 :
41 : #include "nsCOMPtr.h"
42 : #include "nsXBLPrototypeHandler.h"
43 : #include "nsXBLPrototypeBinding.h"
44 : #include "nsContentUtils.h"
45 : #include "nsIContent.h"
46 : #include "nsIAtom.h"
47 : #include "nsIDOMKeyEvent.h"
48 : #include "nsIDOMMouseEvent.h"
49 : #include "nsINameSpaceManager.h"
50 : #include "nsIScriptContext.h"
51 : #include "nsIDocument.h"
52 : #include "nsIDOMDocument.h"
53 : #include "nsIJSEventListener.h"
54 : #include "nsIController.h"
55 : #include "nsIControllers.h"
56 : #include "nsIDOMXULElement.h"
57 : #include "nsIURI.h"
58 : #include "nsIDOMHTMLTextAreaElement.h"
59 : #include "nsIDOMHTMLInputElement.h"
60 : #include "nsFocusManager.h"
61 : #include "nsEventListenerManager.h"
62 : #include "nsIDOMEventTarget.h"
63 : #include "nsIDOMEventListener.h"
64 : #include "nsIPrivateDOMEvent.h"
65 : #include "nsIDOMNSEvent.h"
66 : #include "nsPIDOMWindow.h"
67 : #include "nsPIWindowRoot.h"
68 : #include "nsIDOMWindow.h"
69 : #include "nsIServiceManager.h"
70 : #include "nsIScriptError.h"
71 : #include "nsXPIDLString.h"
72 : #include "nsReadableUtils.h"
73 : #include "nsGkAtoms.h"
74 : #include "nsGUIEvent.h"
75 : #include "nsIXPConnect.h"
76 : #include "nsIDOMScriptObjectFactory.h"
77 : #include "nsDOMCID.h"
78 : #include "nsUnicharUtils.h"
79 : #include "nsReadableUtils.h"
80 : #include "nsCRT.h"
81 : #include "nsXBLEventHandler.h"
82 : #include "nsXBLSerialize.h"
83 : #include "nsEventDispatcher.h"
84 : #include "mozilla/Preferences.h"
85 :
86 : using namespace mozilla;
87 :
88 : static NS_DEFINE_CID(kDOMScriptObjectFactoryCID,
89 : NS_DOM_SCRIPT_OBJECT_FACTORY_CID);
90 :
91 : PRUint32 nsXBLPrototypeHandler::gRefCnt = 0;
92 :
93 : PRInt32 nsXBLPrototypeHandler::kMenuAccessKey = -1;
94 : PRInt32 nsXBLPrototypeHandler::kAccelKey = -1;
95 :
96 : const PRInt32 nsXBLPrototypeHandler::cShift = (1<<0);
97 : const PRInt32 nsXBLPrototypeHandler::cAlt = (1<<1);
98 : const PRInt32 nsXBLPrototypeHandler::cControl = (1<<2);
99 : const PRInt32 nsXBLPrototypeHandler::cMeta = (1<<3);
100 :
101 : const PRInt32 nsXBLPrototypeHandler::cShiftMask = (1<<4);
102 : const PRInt32 nsXBLPrototypeHandler::cAltMask = (1<<5);
103 : const PRInt32 nsXBLPrototypeHandler::cControlMask = (1<<6);
104 : const PRInt32 nsXBLPrototypeHandler::cMetaMask = (1<<7);
105 :
106 : const PRInt32 nsXBLPrototypeHandler::cAllModifiers = cShiftMask | cAltMask | cControlMask | cMetaMask;
107 :
108 0 : nsXBLPrototypeHandler::nsXBLPrototypeHandler(const PRUnichar* aEvent,
109 : const PRUnichar* aPhase,
110 : const PRUnichar* aAction,
111 : const PRUnichar* aCommand,
112 : const PRUnichar* aKeyCode,
113 : const PRUnichar* aCharCode,
114 : const PRUnichar* aModifiers,
115 : const PRUnichar* aButton,
116 : const PRUnichar* aClickCount,
117 : const PRUnichar* aGroup,
118 : const PRUnichar* aPreventDefault,
119 : const PRUnichar* aAllowUntrusted,
120 : nsXBLPrototypeBinding* aBinding,
121 : PRUint32 aLineNumber)
122 : : mHandlerText(nsnull),
123 : mLineNumber(aLineNumber),
124 : mNextHandler(nsnull),
125 0 : mPrototypeBinding(aBinding)
126 : {
127 0 : Init();
128 :
129 : ConstructPrototype(nsnull, aEvent, aPhase, aAction, aCommand, aKeyCode,
130 : aCharCode, aModifiers, aButton, aClickCount,
131 0 : aGroup, aPreventDefault, aAllowUntrusted);
132 0 : }
133 :
134 0 : nsXBLPrototypeHandler::nsXBLPrototypeHandler(nsIContent* aHandlerElement)
135 : : mHandlerElement(nsnull),
136 : mLineNumber(0),
137 : mNextHandler(nsnull),
138 0 : mPrototypeBinding(nsnull)
139 : {
140 0 : Init();
141 :
142 : // Make sure our prototype is initialized.
143 0 : ConstructPrototype(aHandlerElement);
144 0 : }
145 :
146 0 : nsXBLPrototypeHandler::nsXBLPrototypeHandler(nsXBLPrototypeBinding* aBinding)
147 : : mHandlerText(nsnull),
148 : mLineNumber(nsnull),
149 : mNextHandler(nsnull),
150 0 : mPrototypeBinding(aBinding)
151 : {
152 0 : Init();
153 0 : }
154 :
155 0 : nsXBLPrototypeHandler::~nsXBLPrototypeHandler()
156 : {
157 0 : --gRefCnt;
158 0 : if (mType & NS_HANDLER_TYPE_XUL) {
159 0 : NS_IF_RELEASE(mHandlerElement);
160 0 : } else if (mHandlerText) {
161 0 : nsMemory::Free(mHandlerText);
162 : }
163 :
164 : // We own the next handler in the chain, so delete it now.
165 0 : NS_CONTENT_DELETE_LIST_MEMBER(nsXBLPrototypeHandler, this, mNextHandler);
166 0 : }
167 :
168 : already_AddRefed<nsIContent>
169 0 : nsXBLPrototypeHandler::GetHandlerElement()
170 : {
171 0 : if (mType & NS_HANDLER_TYPE_XUL) {
172 0 : nsCOMPtr<nsIContent> element = do_QueryReferent(mHandlerElement);
173 0 : nsIContent* el = nsnull;
174 0 : element.swap(el);
175 0 : return el;
176 : }
177 :
178 0 : return nsnull;
179 : }
180 :
181 : void
182 0 : nsXBLPrototypeHandler::AppendHandlerText(const nsAString& aText)
183 : {
184 0 : if (mHandlerText) {
185 : // Append our text to the existing text.
186 0 : PRUnichar* temp = mHandlerText;
187 0 : mHandlerText = ToNewUnicode(nsDependentString(temp) + aText);
188 0 : nsMemory::Free(temp);
189 : }
190 : else {
191 0 : mHandlerText = ToNewUnicode(aText);
192 : }
193 0 : }
194 :
195 : /////////////////////////////////////////////////////////////////////////////
196 : // Get the menu access key from prefs.
197 : // XXX Eventually pick up using CSS3 key-equivalent property or somesuch
198 : void
199 0 : nsXBLPrototypeHandler::InitAccessKeys()
200 : {
201 0 : if (kAccelKey >= 0 && kMenuAccessKey >= 0)
202 0 : return;
203 :
204 : // Compiled-in defaults, in case we can't get the pref --
205 : // mac doesn't have menu shortcuts, other platforms use alt.
206 : #ifdef XP_MACOSX
207 : kMenuAccessKey = 0;
208 : kAccelKey = nsIDOMKeyEvent::DOM_VK_META;
209 : #else
210 0 : kMenuAccessKey = nsIDOMKeyEvent::DOM_VK_ALT;
211 0 : kAccelKey = nsIDOMKeyEvent::DOM_VK_CONTROL;
212 : #endif
213 :
214 : // Get the menu access key value from prefs, overriding the default:
215 : kMenuAccessKey =
216 0 : Preferences::GetInt("ui.key.menuAccessKey", kMenuAccessKey);
217 0 : kAccelKey = Preferences::GetInt("ui.key.accelKey", kAccelKey);
218 : }
219 :
220 : nsresult
221 0 : nsXBLPrototypeHandler::ExecuteHandler(nsIDOMEventTarget* aTarget,
222 : nsIDOMEvent* aEvent)
223 : {
224 0 : nsresult rv = NS_ERROR_FAILURE;
225 :
226 : // Prevent default action?
227 0 : if (mType & NS_HANDLER_TYPE_PREVENTDEFAULT) {
228 0 : aEvent->PreventDefault();
229 : // If we prevent default, then it's okay for
230 : // mHandlerElement and mHandlerText to be null
231 0 : rv = NS_OK;
232 : }
233 :
234 0 : if (!mHandlerElement) // This works for both types of handlers. In both cases, the union's var should be defined.
235 0 : return rv;
236 :
237 : // See if our event receiver is a content node (and not us).
238 0 : bool isXULKey = !!(mType & NS_HANDLER_TYPE_XUL);
239 0 : bool isXBLCommand = !!(mType & NS_HANDLER_TYPE_XBL_COMMAND);
240 0 : NS_ASSERTION(!(isXULKey && isXBLCommand),
241 : "can't be both a key and xbl command handler");
242 :
243 : // XUL handlers and commands shouldn't be triggered by non-trusted
244 : // events.
245 0 : if (isXULKey || isXBLCommand) {
246 0 : nsCOMPtr<nsIDOMNSEvent> domNSEvent = do_QueryInterface(aEvent);
247 0 : bool trustedEvent = false;
248 0 : if (domNSEvent) {
249 0 : domNSEvent->GetIsTrusted(&trustedEvent);
250 : }
251 :
252 0 : if (!trustedEvent)
253 0 : return NS_OK;
254 : }
255 :
256 0 : if (isXBLCommand) {
257 0 : return DispatchXBLCommand(aTarget, aEvent);
258 : }
259 :
260 : // If we're executing on a XUL key element, just dispatch a command
261 : // event at the element. It will take care of retargeting it to its
262 : // command element, if applicable, and executing the event handler.
263 0 : if (isXULKey) {
264 0 : return DispatchXULKeyCommand(aEvent);
265 : }
266 :
267 : // Look for a compiled handler on the element.
268 : // Should be compiled and bound with "on" in front of the name.
269 0 : nsCOMPtr<nsIAtom> onEventAtom = do_GetAtom(NS_LITERAL_STRING("onxbl") +
270 0 : nsDependentAtomString(mEventName));
271 :
272 : // Compile the handler and bind it to the element.
273 0 : nsCOMPtr<nsIScriptGlobalObject> boundGlobal;
274 0 : nsCOMPtr<nsPIWindowRoot> winRoot(do_QueryInterface(aTarget));
275 0 : nsCOMPtr<nsPIDOMWindow> window;
276 :
277 0 : if (winRoot) {
278 0 : window = winRoot->GetWindow();
279 : }
280 :
281 0 : if (window) {
282 0 : window = window->GetCurrentInnerWindow();
283 0 : NS_ENSURE_TRUE(window, NS_ERROR_UNEXPECTED);
284 :
285 0 : boundGlobal = do_QueryInterface(window->GetPrivateRoot());
286 : }
287 0 : else boundGlobal = do_QueryInterface(aTarget);
288 :
289 0 : if (!boundGlobal) {
290 0 : nsCOMPtr<nsIDocument> boundDocument(do_QueryInterface(aTarget));
291 0 : if (!boundDocument) {
292 : // We must be an element.
293 0 : nsCOMPtr<nsIContent> content(do_QueryInterface(aTarget));
294 0 : if (!content)
295 0 : return NS_OK;
296 0 : boundDocument = content->OwnerDoc();
297 : }
298 :
299 0 : boundGlobal = boundDocument->GetScopeObject();
300 : }
301 :
302 0 : if (!boundGlobal)
303 0 : return NS_OK;
304 :
305 : nsIScriptContext *boundContext =
306 0 : boundGlobal->GetScriptContext(nsIProgrammingLanguage::JAVASCRIPT);
307 0 : if (!boundContext)
308 0 : return NS_OK;
309 :
310 0 : nsScriptObjectHolder<JSObject> handler(boundContext);
311 : nsISupports *scriptTarget;
312 :
313 0 : if (winRoot) {
314 0 : scriptTarget = boundGlobal;
315 : } else {
316 0 : scriptTarget = aTarget;
317 : }
318 :
319 0 : rv = EnsureEventHandler(boundGlobal, boundContext, onEventAtom, handler);
320 0 : NS_ENSURE_SUCCESS(rv, rv);
321 :
322 : // Bind it to the bound element
323 0 : JSObject* scope = boundGlobal->GetGlobalJSObject();
324 0 : nsScriptObjectHolder<JSObject> boundHandler(boundContext);
325 : rv = boundContext->BindCompiledEventHandler(scriptTarget, scope,
326 0 : handler.get(), boundHandler);
327 0 : NS_ENSURE_SUCCESS(rv, rv);
328 :
329 : // Execute it.
330 0 : nsCOMPtr<nsIJSEventListener> eventListener;
331 : rv = NS_NewJSEventListener(boundContext, scope,
332 : scriptTarget, onEventAtom,
333 : boundHandler.get(),
334 0 : getter_AddRefs(eventListener));
335 0 : NS_ENSURE_SUCCESS(rv, rv);
336 :
337 : // Handle the event.
338 0 : eventListener->HandleEvent(aEvent);
339 0 : eventListener->Disconnect();
340 0 : return NS_OK;
341 : }
342 :
343 : nsresult
344 0 : nsXBLPrototypeHandler::EnsureEventHandler(nsIScriptGlobalObject* aGlobal,
345 : nsIScriptContext *aBoundContext,
346 : nsIAtom *aName,
347 : nsScriptObjectHolder<JSObject>& aHandler)
348 : {
349 : // Check to see if we've already compiled this
350 0 : nsCOMPtr<nsPIDOMWindow> pWindow = do_QueryInterface(aGlobal);
351 0 : if (pWindow) {
352 0 : JSObject* cachedHandler = pWindow->GetCachedXBLPrototypeHandler(this);
353 0 : if (cachedHandler) {
354 0 : aHandler.set(cachedHandler);
355 0 : return aHandler ? NS_OK : NS_ERROR_FAILURE;
356 : }
357 : }
358 :
359 : // Ensure that we have something to compile
360 0 : nsDependentString handlerText(mHandlerText);
361 0 : if (handlerText.IsEmpty())
362 0 : return NS_ERROR_FAILURE;
363 :
364 0 : nsCAutoString bindingURI;
365 0 : mPrototypeBinding->DocURI()->GetSpec(bindingURI);
366 :
367 : PRUint32 argCount;
368 : const char **argNames;
369 : nsContentUtils::GetEventArgNames(kNameSpaceID_XBL, aName, &argCount,
370 0 : &argNames);
371 : nsresult rv = aBoundContext->CompileEventHandler(aName, argCount, argNames,
372 : handlerText,
373 : bindingURI.get(),
374 : mLineNumber,
375 0 : JSVERSION_LATEST, aHandler);
376 0 : NS_ENSURE_SUCCESS(rv, rv);
377 :
378 0 : if (pWindow) {
379 0 : pWindow->CacheXBLPrototypeHandler(this, aHandler);
380 : }
381 :
382 0 : return NS_OK;
383 : }
384 :
385 : nsresult
386 0 : nsXBLPrototypeHandler::DispatchXBLCommand(nsIDOMEventTarget* aTarget, nsIDOMEvent* aEvent)
387 : {
388 : // This is a special-case optimization to make command handling fast.
389 : // It isn't really a part of XBL, but it helps speed things up.
390 :
391 : // See if preventDefault has been set. If so, don't execute.
392 0 : bool preventDefault = false;
393 0 : nsCOMPtr<nsIDOMNSEvent> domNSEvent = do_QueryInterface(aEvent);
394 0 : if (domNSEvent) {
395 0 : domNSEvent->GetPreventDefault(&preventDefault);
396 : }
397 :
398 0 : if (preventDefault)
399 0 : return NS_OK;
400 :
401 0 : nsCOMPtr<nsIPrivateDOMEvent> privateEvent = do_QueryInterface(aEvent);
402 0 : if (privateEvent) {
403 0 : bool dispatchStopped = privateEvent->IsDispatchStopped();
404 0 : if (dispatchStopped)
405 0 : return NS_OK;
406 : }
407 :
408 : // Instead of executing JS, let's get the controller for the bound
409 : // element and call doCommand on it.
410 0 : nsCOMPtr<nsIController> controller;
411 :
412 0 : nsCOMPtr<nsPIDOMWindow> privateWindow;
413 0 : nsCOMPtr<nsPIWindowRoot> windowRoot(do_QueryInterface(aTarget));
414 0 : if (windowRoot) {
415 0 : privateWindow = windowRoot->GetWindow();
416 : }
417 : else {
418 0 : privateWindow = do_QueryInterface(aTarget);
419 0 : if (!privateWindow) {
420 0 : nsCOMPtr<nsIContent> elt(do_QueryInterface(aTarget));
421 0 : nsCOMPtr<nsIDocument> doc;
422 : // XXXbz sXBL/XBL2 issue -- this should be the "scope doc" or
423 : // something... whatever we use when wrapping DOM nodes
424 : // normally. It's not clear that the owner doc is the right
425 : // thing.
426 0 : if (elt)
427 0 : doc = elt->OwnerDoc();
428 :
429 0 : if (!doc)
430 0 : doc = do_QueryInterface(aTarget);
431 :
432 0 : if (!doc)
433 0 : return NS_ERROR_FAILURE;
434 :
435 0 : privateWindow = do_QueryInterface(doc->GetScriptGlobalObject());
436 0 : if (!privateWindow)
437 0 : return NS_ERROR_FAILURE;
438 : }
439 :
440 0 : windowRoot = privateWindow->GetTopWindowRoot();
441 : }
442 :
443 0 : NS_LossyConvertUTF16toASCII command(mHandlerText);
444 0 : if (windowRoot)
445 0 : windowRoot->GetControllerForCommand(command.get(), getter_AddRefs(controller));
446 : else
447 0 : controller = GetController(aTarget); // We're attached to the receiver possibly.
448 :
449 0 : if (mEventName == nsGkAtoms::keypress &&
450 : mDetail == nsIDOMKeyEvent::DOM_VK_SPACE &&
451 : mMisc == 1) {
452 : // get the focused element so that we can pageDown only at
453 : // certain times.
454 :
455 0 : nsCOMPtr<nsPIDOMWindow> windowToCheck;
456 0 : if (windowRoot)
457 0 : windowToCheck = windowRoot->GetWindow();
458 : else
459 0 : windowToCheck = privateWindow->GetPrivateRoot();
460 :
461 0 : nsCOMPtr<nsIContent> focusedContent;
462 0 : if (windowToCheck) {
463 0 : nsCOMPtr<nsPIDOMWindow> focusedWindow;
464 : focusedContent =
465 0 : nsFocusManager::GetFocusedDescendant(windowToCheck, true, getter_AddRefs(focusedWindow));
466 : }
467 :
468 0 : bool isLink = false;
469 0 : nsIContent *content = focusedContent;
470 :
471 : // if the focused element is a link then we do want space to
472 : // scroll down. The focused element may be an element in a link,
473 : // we need to check the parent node too. Only do this check if an
474 : // element is focused and has a parent.
475 0 : if (focusedContent && focusedContent->GetParent()) {
476 0 : while (content) {
477 0 : if (content->Tag() == nsGkAtoms::a && content->IsHTML()) {
478 0 : isLink = true;
479 0 : break;
480 : }
481 :
482 0 : if (content->HasAttr(kNameSpaceID_XLink, nsGkAtoms::type)) {
483 : isLink = content->AttrValueIs(kNameSpaceID_XLink, nsGkAtoms::type,
484 0 : nsGkAtoms::simple, eCaseMatters);
485 :
486 0 : if (isLink) {
487 0 : break;
488 : }
489 : }
490 :
491 0 : content = content->GetParent();
492 : }
493 :
494 0 : if (!isLink)
495 0 : return NS_OK;
496 : }
497 : }
498 :
499 : // We are the default action for this command.
500 : // Stop any other default action from executing.
501 0 : aEvent->PreventDefault();
502 :
503 0 : if (controller)
504 0 : controller->DoCommand(command.get());
505 :
506 0 : return NS_OK;
507 : }
508 :
509 : nsresult
510 0 : nsXBLPrototypeHandler::DispatchXULKeyCommand(nsIDOMEvent* aEvent)
511 : {
512 0 : nsCOMPtr<nsIContent> handlerElement = GetHandlerElement();
513 0 : NS_ENSURE_STATE(handlerElement);
514 0 : if (handlerElement->AttrValueIs(kNameSpaceID_None,
515 : nsGkAtoms::disabled,
516 : nsGkAtoms::_true,
517 0 : eCaseMatters)) {
518 : // Don't dispatch command events for disabled keys.
519 0 : return NS_OK;
520 : }
521 :
522 0 : aEvent->PreventDefault();
523 :
524 : // Copy the modifiers from the key event.
525 0 : nsCOMPtr<nsIDOMKeyEvent> keyEvent = do_QueryInterface(aEvent);
526 0 : if (!keyEvent) {
527 0 : NS_ERROR("Trying to execute a key handler for a non-key event!");
528 0 : return NS_ERROR_FAILURE;
529 : }
530 :
531 0 : bool isAlt = false;
532 0 : bool isControl = false;
533 0 : bool isShift = false;
534 0 : bool isMeta = false;
535 0 : keyEvent->GetAltKey(&isAlt);
536 0 : keyEvent->GetCtrlKey(&isControl);
537 0 : keyEvent->GetShiftKey(&isShift);
538 0 : keyEvent->GetMetaKey(&isMeta);
539 :
540 : nsContentUtils::DispatchXULCommand(handlerElement, true,
541 : nsnull, nsnull,
542 0 : isControl, isAlt, isShift, isMeta);
543 0 : return NS_OK;
544 : }
545 :
546 : already_AddRefed<nsIAtom>
547 0 : nsXBLPrototypeHandler::GetEventName()
548 : {
549 0 : nsIAtom* eventName = mEventName;
550 0 : NS_IF_ADDREF(eventName);
551 0 : return eventName;
552 : }
553 :
554 : already_AddRefed<nsIController>
555 0 : nsXBLPrototypeHandler::GetController(nsIDOMEventTarget* aTarget)
556 : {
557 : // XXX Fix this so there's a generic interface that describes controllers,
558 : // This code should have no special knowledge of what objects might have controllers.
559 0 : nsCOMPtr<nsIControllers> controllers;
560 :
561 0 : nsCOMPtr<nsIDOMXULElement> xulElement(do_QueryInterface(aTarget));
562 0 : if (xulElement)
563 0 : xulElement->GetControllers(getter_AddRefs(controllers));
564 :
565 0 : if (!controllers) {
566 0 : nsCOMPtr<nsIDOMHTMLTextAreaElement> htmlTextArea(do_QueryInterface(aTarget));
567 0 : if (htmlTextArea)
568 0 : htmlTextArea->GetControllers(getter_AddRefs(controllers));
569 : }
570 :
571 0 : if (!controllers) {
572 0 : nsCOMPtr<nsIDOMHTMLInputElement> htmlInputElement(do_QueryInterface(aTarget));
573 0 : if (htmlInputElement)
574 0 : htmlInputElement->GetControllers(getter_AddRefs(controllers));
575 : }
576 :
577 0 : if (!controllers) {
578 0 : nsCOMPtr<nsIDOMWindow> domWindow(do_QueryInterface(aTarget));
579 0 : if (domWindow)
580 0 : domWindow->GetControllers(getter_AddRefs(controllers));
581 : }
582 :
583 : // Return the first controller.
584 : // XXX This code should be checking the command name and using supportscommand and
585 : // iscommandenabled.
586 : nsIController* controller;
587 0 : if (controllers) {
588 0 : controllers->GetControllerAt(0, &controller); // return reference
589 : }
590 0 : else controller = nsnull;
591 :
592 0 : return controller;
593 : }
594 :
595 : bool
596 0 : nsXBLPrototypeHandler::KeyEventMatched(nsIDOMKeyEvent* aKeyEvent,
597 : PRUint32 aCharCode,
598 : bool aIgnoreShiftKey)
599 : {
600 0 : if (mDetail != -1) {
601 : // Get the keycode or charcode of the key event.
602 : PRUint32 code;
603 :
604 0 : if (mMisc) {
605 0 : if (aCharCode)
606 0 : code = aCharCode;
607 : else
608 0 : aKeyEvent->GetCharCode(&code);
609 0 : if (IS_IN_BMP(code))
610 0 : code = ToLowerCase(PRUnichar(code));
611 : }
612 : else
613 0 : aKeyEvent->GetKeyCode(&code);
614 :
615 0 : if (code != PRUint32(mDetail))
616 0 : return false;
617 : }
618 :
619 0 : return ModifiersMatchMask(aKeyEvent, aIgnoreShiftKey);
620 : }
621 :
622 : bool
623 0 : nsXBLPrototypeHandler::MouseEventMatched(nsIDOMMouseEvent* aMouseEvent)
624 : {
625 0 : if (mDetail == -1 && mMisc == 0 && (mKeyMask & cAllModifiers) == 0)
626 0 : return true; // No filters set up. It's generic.
627 :
628 : PRUint16 button;
629 0 : aMouseEvent->GetButton(&button);
630 0 : if (mDetail != -1 && (button != mDetail))
631 0 : return false;
632 :
633 : PRInt32 clickcount;
634 0 : aMouseEvent->GetDetail(&clickcount);
635 0 : if (mMisc != 0 && (clickcount != mMisc))
636 0 : return false;
637 :
638 0 : return ModifiersMatchMask(aMouseEvent);
639 : }
640 :
641 : struct keyCodeData {
642 : const char* str;
643 : size_t strlength;
644 : PRUint32 keycode;
645 : };
646 :
647 : // All of these must be uppercase, since the function below does
648 : // case-insensitive comparison by converting to uppercase.
649 : // XXX: be sure to check this periodically for new symbol additions!
650 : static const keyCodeData gKeyCodes[] = {
651 :
652 : #define KEYCODE_ENTRY(str) {#str, sizeof(#str) - 1, nsIDOMKeyEvent::DOM_##str}
653 : #define KEYCODE_ENTRY2(str, code) {str, sizeof(str) - 1, code}
654 :
655 : KEYCODE_ENTRY(VK_CANCEL),
656 : KEYCODE_ENTRY2("VK_BACK", nsIDOMKeyEvent::DOM_VK_BACK_SPACE),
657 : KEYCODE_ENTRY(VK_TAB),
658 : KEYCODE_ENTRY(VK_CLEAR),
659 : KEYCODE_ENTRY(VK_RETURN),
660 : KEYCODE_ENTRY(VK_ENTER),
661 : KEYCODE_ENTRY(VK_SHIFT),
662 : KEYCODE_ENTRY(VK_CONTROL),
663 : KEYCODE_ENTRY(VK_ALT),
664 : KEYCODE_ENTRY(VK_PAUSE),
665 : KEYCODE_ENTRY(VK_CAPS_LOCK),
666 : KEYCODE_ENTRY(VK_ESCAPE),
667 : KEYCODE_ENTRY(VK_SPACE),
668 : KEYCODE_ENTRY(VK_PAGE_UP),
669 : KEYCODE_ENTRY(VK_PAGE_DOWN),
670 : KEYCODE_ENTRY(VK_END),
671 : KEYCODE_ENTRY(VK_HOME),
672 : KEYCODE_ENTRY(VK_LEFT),
673 : KEYCODE_ENTRY(VK_UP),
674 : KEYCODE_ENTRY(VK_RIGHT),
675 : KEYCODE_ENTRY(VK_DOWN),
676 : KEYCODE_ENTRY(VK_PRINTSCREEN),
677 : KEYCODE_ENTRY(VK_INSERT),
678 : KEYCODE_ENTRY(VK_HELP),
679 : KEYCODE_ENTRY(VK_DELETE),
680 : KEYCODE_ENTRY(VK_0),
681 : KEYCODE_ENTRY(VK_1),
682 : KEYCODE_ENTRY(VK_2),
683 : KEYCODE_ENTRY(VK_3),
684 : KEYCODE_ENTRY(VK_4),
685 : KEYCODE_ENTRY(VK_5),
686 : KEYCODE_ENTRY(VK_6),
687 : KEYCODE_ENTRY(VK_7),
688 : KEYCODE_ENTRY(VK_8),
689 : KEYCODE_ENTRY(VK_9),
690 : KEYCODE_ENTRY(VK_SEMICOLON),
691 : KEYCODE_ENTRY(VK_EQUALS),
692 : KEYCODE_ENTRY(VK_A),
693 : KEYCODE_ENTRY(VK_B),
694 : KEYCODE_ENTRY(VK_C),
695 : KEYCODE_ENTRY(VK_D),
696 : KEYCODE_ENTRY(VK_E),
697 : KEYCODE_ENTRY(VK_F),
698 : KEYCODE_ENTRY(VK_G),
699 : KEYCODE_ENTRY(VK_H),
700 : KEYCODE_ENTRY(VK_I),
701 : KEYCODE_ENTRY(VK_J),
702 : KEYCODE_ENTRY(VK_K),
703 : KEYCODE_ENTRY(VK_L),
704 : KEYCODE_ENTRY(VK_M),
705 : KEYCODE_ENTRY(VK_N),
706 : KEYCODE_ENTRY(VK_O),
707 : KEYCODE_ENTRY(VK_P),
708 : KEYCODE_ENTRY(VK_Q),
709 : KEYCODE_ENTRY(VK_R),
710 : KEYCODE_ENTRY(VK_S),
711 : KEYCODE_ENTRY(VK_T),
712 : KEYCODE_ENTRY(VK_U),
713 : KEYCODE_ENTRY(VK_V),
714 : KEYCODE_ENTRY(VK_W),
715 : KEYCODE_ENTRY(VK_X),
716 : KEYCODE_ENTRY(VK_Y),
717 : KEYCODE_ENTRY(VK_Z),
718 : KEYCODE_ENTRY(VK_NUMPAD0),
719 : KEYCODE_ENTRY(VK_NUMPAD1),
720 : KEYCODE_ENTRY(VK_NUMPAD2),
721 : KEYCODE_ENTRY(VK_NUMPAD3),
722 : KEYCODE_ENTRY(VK_NUMPAD4),
723 : KEYCODE_ENTRY(VK_NUMPAD5),
724 : KEYCODE_ENTRY(VK_NUMPAD6),
725 : KEYCODE_ENTRY(VK_NUMPAD7),
726 : KEYCODE_ENTRY(VK_NUMPAD8),
727 : KEYCODE_ENTRY(VK_NUMPAD9),
728 : KEYCODE_ENTRY(VK_MULTIPLY),
729 : KEYCODE_ENTRY(VK_ADD),
730 : KEYCODE_ENTRY(VK_SEPARATOR),
731 : KEYCODE_ENTRY(VK_SUBTRACT),
732 : KEYCODE_ENTRY(VK_DECIMAL),
733 : KEYCODE_ENTRY(VK_DIVIDE),
734 : KEYCODE_ENTRY(VK_F1),
735 : KEYCODE_ENTRY(VK_F2),
736 : KEYCODE_ENTRY(VK_F3),
737 : KEYCODE_ENTRY(VK_F4),
738 : KEYCODE_ENTRY(VK_F5),
739 : KEYCODE_ENTRY(VK_F6),
740 : KEYCODE_ENTRY(VK_F7),
741 : KEYCODE_ENTRY(VK_F8),
742 : KEYCODE_ENTRY(VK_F9),
743 : KEYCODE_ENTRY(VK_F10),
744 : KEYCODE_ENTRY(VK_F11),
745 : KEYCODE_ENTRY(VK_F12),
746 : KEYCODE_ENTRY(VK_F13),
747 : KEYCODE_ENTRY(VK_F14),
748 : KEYCODE_ENTRY(VK_F15),
749 : KEYCODE_ENTRY(VK_F16),
750 : KEYCODE_ENTRY(VK_F17),
751 : KEYCODE_ENTRY(VK_F18),
752 : KEYCODE_ENTRY(VK_F19),
753 : KEYCODE_ENTRY(VK_F20),
754 : KEYCODE_ENTRY(VK_F21),
755 : KEYCODE_ENTRY(VK_F22),
756 : KEYCODE_ENTRY(VK_F23),
757 : KEYCODE_ENTRY(VK_F24),
758 : KEYCODE_ENTRY(VK_NUM_LOCK),
759 : KEYCODE_ENTRY(VK_SCROLL_LOCK),
760 : KEYCODE_ENTRY(VK_COMMA),
761 : KEYCODE_ENTRY(VK_PERIOD),
762 : KEYCODE_ENTRY(VK_SLASH),
763 : KEYCODE_ENTRY(VK_BACK_QUOTE),
764 : KEYCODE_ENTRY(VK_OPEN_BRACKET),
765 : KEYCODE_ENTRY(VK_BACK_SLASH),
766 : KEYCODE_ENTRY(VK_CLOSE_BRACKET),
767 : KEYCODE_ENTRY(VK_QUOTE)
768 :
769 : #undef KEYCODE_ENTRY
770 : #undef KEYCODE_ENTRY2
771 :
772 : };
773 :
774 0 : PRInt32 nsXBLPrototypeHandler::GetMatchingKeyCode(const nsAString& aKeyName)
775 : {
776 0 : nsCAutoString keyName;
777 0 : keyName.AssignWithConversion(aKeyName);
778 0 : ToUpperCase(keyName); // We want case-insensitive comparison with data
779 : // stored as uppercase.
780 :
781 0 : PRUint32 keyNameLength = keyName.Length();
782 0 : const char* keyNameStr = keyName.get();
783 0 : for (PRUint16 i = 0; i < (sizeof(gKeyCodes) / sizeof(gKeyCodes[0])); ++i)
784 0 : if (keyNameLength == gKeyCodes[i].strlength &&
785 0 : !nsCRT::strcmp(gKeyCodes[i].str, keyNameStr))
786 0 : return gKeyCodes[i].keycode;
787 :
788 0 : return 0;
789 : }
790 :
791 0 : PRInt32 nsXBLPrototypeHandler::KeyToMask(PRInt32 key)
792 : {
793 0 : switch (key)
794 : {
795 : case nsIDOMKeyEvent::DOM_VK_META:
796 0 : return cMeta | cMetaMask;
797 : break;
798 :
799 : case nsIDOMKeyEvent::DOM_VK_ALT:
800 0 : return cAlt | cAltMask;
801 : break;
802 :
803 : case nsIDOMKeyEvent::DOM_VK_CONTROL:
804 : default:
805 0 : return cControl | cControlMask;
806 : }
807 : return cControl | cControlMask; // for warning avoidance
808 : }
809 :
810 : void
811 0 : nsXBLPrototypeHandler::GetEventType(nsAString& aEvent)
812 : {
813 0 : nsCOMPtr<nsIContent> handlerElement = GetHandlerElement();
814 0 : if (!handlerElement) {
815 0 : aEvent.Truncate();
816 : return;
817 : }
818 0 : handlerElement->GetAttr(kNameSpaceID_None, nsGkAtoms::event, aEvent);
819 :
820 0 : if (aEvent.IsEmpty() && (mType & NS_HANDLER_TYPE_XUL))
821 : // If no type is specified for a XUL <key> element, let's assume that we're "keypress".
822 0 : aEvent.AssignLiteral("keypress");
823 : }
824 :
825 : void
826 0 : nsXBLPrototypeHandler::ConstructPrototype(nsIContent* aKeyElement,
827 : const PRUnichar* aEvent,
828 : const PRUnichar* aPhase,
829 : const PRUnichar* aAction,
830 : const PRUnichar* aCommand,
831 : const PRUnichar* aKeyCode,
832 : const PRUnichar* aCharCode,
833 : const PRUnichar* aModifiers,
834 : const PRUnichar* aButton,
835 : const PRUnichar* aClickCount,
836 : const PRUnichar* aGroup,
837 : const PRUnichar* aPreventDefault,
838 : const PRUnichar* aAllowUntrusted)
839 : {
840 0 : mType = 0;
841 :
842 0 : if (aKeyElement) {
843 0 : mType |= NS_HANDLER_TYPE_XUL;
844 0 : nsCOMPtr<nsIWeakReference> weak = do_GetWeakReference(aKeyElement);
845 0 : if (!weak) {
846 : return;
847 : }
848 0 : weak.swap(mHandlerElement);
849 : }
850 : else {
851 0 : mType |= aCommand ? NS_HANDLER_TYPE_XBL_COMMAND : NS_HANDLER_TYPE_XBL_JS;
852 0 : mHandlerText = nsnull;
853 : }
854 :
855 0 : mDetail = -1;
856 0 : mMisc = 0;
857 0 : mKeyMask = 0;
858 0 : mPhase = NS_PHASE_BUBBLING;
859 :
860 0 : if (aAction)
861 0 : mHandlerText = ToNewUnicode(nsDependentString(aAction));
862 0 : else if (aCommand)
863 0 : mHandlerText = ToNewUnicode(nsDependentString(aCommand));
864 :
865 0 : nsAutoString event(aEvent);
866 0 : if (event.IsEmpty()) {
867 0 : if (mType & NS_HANDLER_TYPE_XUL)
868 0 : GetEventType(event);
869 0 : if (event.IsEmpty())
870 : return;
871 : }
872 :
873 0 : mEventName = do_GetAtom(event);
874 :
875 0 : if (aPhase) {
876 0 : const nsDependentString phase(aPhase);
877 0 : if (phase.EqualsLiteral("capturing"))
878 0 : mPhase = NS_PHASE_CAPTURING;
879 0 : else if (phase.EqualsLiteral("target"))
880 0 : mPhase = NS_PHASE_TARGET;
881 : }
882 :
883 : // Button and clickcount apply only to XBL handlers and don't apply to XUL key
884 : // handlers.
885 0 : if (aButton && *aButton)
886 0 : mDetail = *aButton - '0';
887 :
888 0 : if (aClickCount && *aClickCount)
889 0 : mMisc = *aClickCount - '0';
890 :
891 : // Modifiers are supported by both types of handlers (XUL and XBL).
892 0 : nsAutoString modifiers(aModifiers);
893 0 : if (mType & NS_HANDLER_TYPE_XUL)
894 0 : aKeyElement->GetAttr(kNameSpaceID_None, nsGkAtoms::modifiers, modifiers);
895 :
896 0 : if (!modifiers.IsEmpty()) {
897 0 : mKeyMask = cAllModifiers;
898 0 : char* str = ToNewCString(modifiers);
899 : char* newStr;
900 0 : char* token = nsCRT::strtok( str, ", \t", &newStr );
901 0 : while( token != NULL ) {
902 0 : if (PL_strcmp(token, "shift") == 0)
903 0 : mKeyMask |= cShift | cShiftMask;
904 0 : else if (PL_strcmp(token, "alt") == 0)
905 0 : mKeyMask |= cAlt | cAltMask;
906 0 : else if (PL_strcmp(token, "meta") == 0)
907 0 : mKeyMask |= cMeta | cMetaMask;
908 0 : else if (PL_strcmp(token, "control") == 0)
909 0 : mKeyMask |= cControl | cControlMask;
910 0 : else if (PL_strcmp(token, "accel") == 0)
911 0 : mKeyMask |= KeyToMask(kAccelKey);
912 0 : else if (PL_strcmp(token, "access") == 0)
913 0 : mKeyMask |= KeyToMask(kMenuAccessKey);
914 0 : else if (PL_strcmp(token, "any") == 0)
915 0 : mKeyMask &= ~(mKeyMask << 4);
916 :
917 0 : token = nsCRT::strtok( newStr, ", \t", &newStr );
918 : }
919 :
920 0 : nsMemory::Free(str);
921 : }
922 :
923 0 : nsAutoString key(aCharCode);
924 0 : if (key.IsEmpty()) {
925 0 : if (mType & NS_HANDLER_TYPE_XUL) {
926 0 : aKeyElement->GetAttr(kNameSpaceID_None, nsGkAtoms::key, key);
927 0 : if (key.IsEmpty())
928 0 : aKeyElement->GetAttr(kNameSpaceID_None, nsGkAtoms::charcode, key);
929 : }
930 : }
931 :
932 0 : if (!key.IsEmpty()) {
933 0 : if (mKeyMask == 0)
934 0 : mKeyMask = cAllModifiers;
935 0 : nsContentUtils::ASCIIToLower(key);
936 :
937 : // We have a charcode.
938 0 : mMisc = 1;
939 0 : mDetail = key[0];
940 0 : const PRUint8 GTK2Modifiers = cShift | cControl | cShiftMask | cControlMask;
941 0 : if ((mKeyMask & GTK2Modifiers) == GTK2Modifiers &&
942 0 : modifiers.First() != PRUnichar(',') && mDetail == 'u')
943 0 : ReportKeyConflict(key.get(), modifiers.get(), aKeyElement, "GTK2Conflict");
944 0 : const PRUint8 WinModifiers = cControl | cAlt | cControlMask | cAltMask;
945 0 : if ((mKeyMask & WinModifiers) == WinModifiers &&
946 0 : modifiers.First() != PRUnichar(',') && ('a' <= mDetail && mDetail <= 'z'))
947 0 : ReportKeyConflict(key.get(), modifiers.get(), aKeyElement, "WinConflict");
948 : }
949 : else {
950 0 : key.Assign(aKeyCode);
951 0 : if (mType & NS_HANDLER_TYPE_XUL)
952 0 : aKeyElement->GetAttr(kNameSpaceID_None, nsGkAtoms::keycode, key);
953 :
954 0 : if (!key.IsEmpty()) {
955 0 : if (mKeyMask == 0)
956 0 : mKeyMask = cAllModifiers;
957 0 : mDetail = GetMatchingKeyCode(key);
958 : }
959 : }
960 :
961 0 : if (aGroup && nsDependentString(aGroup).EqualsLiteral("system"))
962 0 : mType |= NS_HANDLER_TYPE_SYSTEM;
963 :
964 0 : if (aPreventDefault &&
965 0 : nsDependentString(aPreventDefault).EqualsLiteral("true"))
966 0 : mType |= NS_HANDLER_TYPE_PREVENTDEFAULT;
967 :
968 0 : if (aAllowUntrusted) {
969 0 : mType |= NS_HANDLER_HAS_ALLOW_UNTRUSTED_ATTR;
970 0 : if (nsDependentString(aAllowUntrusted).EqualsLiteral("true")) {
971 0 : mType |= NS_HANDLER_ALLOW_UNTRUSTED;
972 : } else {
973 0 : mType &= ~NS_HANDLER_ALLOW_UNTRUSTED;
974 : }
975 : }
976 : }
977 :
978 : void
979 0 : nsXBLPrototypeHandler::ReportKeyConflict(const PRUnichar* aKey, const PRUnichar* aModifiers, nsIContent* aKeyElement, const char *aMessageName)
980 : {
981 0 : nsCOMPtr<nsIDocument> doc;
982 0 : if (mPrototypeBinding) {
983 0 : nsXBLDocumentInfo* docInfo = mPrototypeBinding->XBLDocumentInfo();
984 0 : if (docInfo) {
985 0 : doc = docInfo->GetDocument();
986 : }
987 0 : } else if (aKeyElement) {
988 0 : doc = aKeyElement->OwnerDoc();
989 : }
990 :
991 0 : const PRUnichar* params[] = { aKey, aModifiers };
992 : nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
993 : "XBL Prototype Handler", doc,
994 : nsContentUtils::eXBL_PROPERTIES,
995 : aMessageName,
996 : params, ArrayLength(params),
997 0 : nsnull, EmptyString(), mLineNumber);
998 0 : }
999 :
1000 : bool
1001 0 : nsXBLPrototypeHandler::ModifiersMatchMask(nsIDOMUIEvent* aEvent,
1002 : bool aIgnoreShiftKey)
1003 : {
1004 0 : nsCOMPtr<nsIDOMKeyEvent> key(do_QueryInterface(aEvent));
1005 0 : nsCOMPtr<nsIDOMMouseEvent> mouse(do_QueryInterface(aEvent));
1006 :
1007 : bool keyPresent;
1008 0 : if (mKeyMask & cMetaMask) {
1009 0 : key ? key->GetMetaKey(&keyPresent) : mouse->GetMetaKey(&keyPresent);
1010 0 : if (keyPresent != ((mKeyMask & cMeta) != 0))
1011 0 : return false;
1012 : }
1013 :
1014 0 : if (mKeyMask & cShiftMask && !aIgnoreShiftKey) {
1015 0 : key ? key->GetShiftKey(&keyPresent) : mouse->GetShiftKey(&keyPresent);
1016 0 : if (keyPresent != ((mKeyMask & cShift) != 0))
1017 0 : return false;
1018 : }
1019 :
1020 0 : if (mKeyMask & cAltMask) {
1021 0 : key ? key->GetAltKey(&keyPresent) : mouse->GetAltKey(&keyPresent);
1022 0 : if (keyPresent != ((mKeyMask & cAlt) != 0))
1023 0 : return false;
1024 : }
1025 :
1026 0 : if (mKeyMask & cControlMask) {
1027 0 : key ? key->GetCtrlKey(&keyPresent) : mouse->GetCtrlKey(&keyPresent);
1028 0 : if (keyPresent != ((mKeyMask & cControl) != 0))
1029 0 : return false;
1030 : }
1031 :
1032 0 : return true;
1033 : }
1034 :
1035 : nsresult
1036 0 : nsXBLPrototypeHandler::Read(nsIScriptContext* aContext, nsIObjectInputStream* aStream)
1037 : {
1038 0 : nsresult rv = aStream->Read8(&mPhase);
1039 0 : NS_ENSURE_SUCCESS(rv, rv);
1040 0 : rv = aStream->Read8(&mKeyMask);
1041 0 : NS_ENSURE_SUCCESS(rv, rv);
1042 0 : rv = aStream->Read8(&mType);
1043 0 : NS_ENSURE_SUCCESS(rv, rv);
1044 0 : rv = aStream->Read8(&mMisc);
1045 0 : NS_ENSURE_SUCCESS(rv, rv);
1046 :
1047 : PRUint32 detail;
1048 0 : rv = aStream->Read32(&detail);
1049 0 : NS_ENSURE_SUCCESS(rv, rv);
1050 0 : mDetail = detail;
1051 :
1052 0 : nsAutoString name;
1053 0 : rv = aStream->ReadString(name);
1054 0 : NS_ENSURE_SUCCESS(rv, rv);
1055 0 : mEventName = do_GetAtom(name);
1056 :
1057 0 : rv = aStream->Read32(&mLineNumber);
1058 0 : NS_ENSURE_SUCCESS(rv, rv);
1059 :
1060 0 : nsAutoString handlerText;
1061 0 : rv = aStream->ReadString(handlerText);
1062 0 : NS_ENSURE_SUCCESS(rv, rv);
1063 0 : if (!handlerText.IsEmpty())
1064 0 : mHandlerText = ToNewUnicode(handlerText);
1065 :
1066 0 : return NS_OK;
1067 : }
1068 :
1069 : nsresult
1070 0 : nsXBLPrototypeHandler::Write(nsIScriptContext* aContext, nsIObjectOutputStream* aStream)
1071 : {
1072 : // Make sure we don't write out NS_HANDLER_TYPE_XUL types, as they are used
1073 : // for <keyset> elements.
1074 0 : if ((mType & NS_HANDLER_TYPE_XUL) || !mEventName)
1075 0 : return NS_OK;
1076 :
1077 0 : XBLBindingSerializeDetails type = XBLBinding_Serialize_Handler;
1078 :
1079 0 : nsresult rv = aStream->Write8(type);
1080 0 : rv = aStream->Write8(mPhase);
1081 0 : NS_ENSURE_SUCCESS(rv, rv);
1082 0 : rv = aStream->Write8(mKeyMask);
1083 0 : NS_ENSURE_SUCCESS(rv, rv);
1084 0 : rv = aStream->Write8(mType);
1085 0 : NS_ENSURE_SUCCESS(rv, rv);
1086 0 : rv = aStream->Write8(mMisc);
1087 0 : NS_ENSURE_SUCCESS(rv, rv);
1088 0 : rv = aStream->Write32(mDetail);
1089 0 : NS_ENSURE_SUCCESS(rv, rv);
1090 :
1091 0 : rv = aStream->WriteWStringZ(nsDependentAtomString(mEventName).get());
1092 0 : NS_ENSURE_SUCCESS(rv, rv);
1093 :
1094 0 : rv = aStream->Write32(mLineNumber);
1095 0 : NS_ENSURE_SUCCESS(rv, rv);
1096 0 : return aStream->WriteWStringZ(mHandlerText ? mHandlerText : EmptyString().get());
1097 : }
|