1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 : * Chris Waterson <waterson@netscape.com>
24 : * Pierre Phaneuf <pp@ludusdesign.com>
25 : * Peter Annema <disttsc@bart.nl>
26 : * Brendan Eich <brendan@mozilla.org>
27 : * Mike Shaver <shaver@mozilla.org>
28 : * Mark Hammond <mhammond@skippinet.com.au>
29 : *
30 : * Alternatively, the contents of this file may be used under the terms of
31 : * either of the GNU General Public License Version 2 or later (the "GPL"),
32 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
33 : * in which case the provisions of the GPL or the LGPL are applicable instead
34 : * of those above. If you wish to allow use of your version of this file only
35 : * under the terms of either the GPL or the LGPL, and not to allow others to
36 : * use your version of this file under the terms of the MPL, indicate your
37 : * decision by deleting the provisions above and replace them with the notice
38 : * and other provisions required by the GPL or the LGPL. If you do not delete
39 : * the provisions above, a recipient may use your version of this file under
40 : * the terms of any one of the MPL, the GPL or the LGPL.
41 : *
42 : * ***** END LICENSE BLOCK *****
43 : *
44 : * This Original Code has been modified by IBM Corporation.
45 : * Modifications made by IBM described herein are
46 : * Copyright (c) International Business Machines
47 : * Corporation, 2000
48 : *
49 : * Modifications to Mozilla code or documentation
50 : * identified per MPL Section 3.3
51 : *
52 : * Date Modified by Description of modification
53 : * 03/27/2000 IBM Corp. Added PR_CALLBACK for Optlink
54 : * use in OS2
55 : */
56 :
57 : #include "nsCOMPtr.h"
58 : #include "nsDOMCID.h"
59 : #include "nsDOMError.h"
60 : #include "nsDOMString.h"
61 : #include "nsIDOMEvent.h"
62 : #include "nsIPrivateDOMEvent.h"
63 : #include "nsHashtable.h"
64 : #include "nsIAtom.h"
65 : #include "nsIBaseWindow.h"
66 : #include "nsIDOMAttr.h"
67 : #include "nsIDOMDocument.h"
68 : #include "nsIDOMElement.h"
69 : #include "nsIDOMEventListener.h"
70 : #include "nsIDOMNodeList.h"
71 : #include "nsIDOMXULCommandDispatcher.h"
72 : #include "nsIDOMXULElement.h"
73 : #include "nsIDOMElementCSSInlineStyle.h"
74 : #include "nsIDOMXULSelectCntrlItemEl.h"
75 : #include "nsIDocument.h"
76 : #include "nsEventListenerManager.h"
77 : #include "nsEventStateManager.h"
78 : #include "nsFocusManager.h"
79 : #include "nsHTMLStyleSheet.h"
80 : #include "nsINameSpaceManager.h"
81 : #include "nsIObjectInputStream.h"
82 : #include "nsIObjectOutputStream.h"
83 : #include "nsIPresShell.h"
84 : #include "nsIPrincipal.h"
85 : #include "nsIRDFCompositeDataSource.h"
86 : #include "nsIRDFNode.h"
87 : #include "nsIRDFService.h"
88 : #include "nsIScriptContext.h"
89 : #include "nsIScriptRuntime.h"
90 : #include "nsIScriptGlobalObject.h"
91 : #include "nsIScriptGlobalObjectOwner.h"
92 : #include "nsIServiceManager.h"
93 : #include "mozilla/css/StyleRule.h"
94 : #include "nsIStyleSheet.h"
95 : #include "nsIURL.h"
96 : #include "nsIViewManager.h"
97 : #include "nsIWidget.h"
98 : #include "nsIXULDocument.h"
99 : #include "nsIXULTemplateBuilder.h"
100 : #include "nsIXBLService.h"
101 : #include "nsLayoutCID.h"
102 : #include "nsContentCID.h"
103 : #include "nsRDFCID.h"
104 : #include "nsStyleConsts.h"
105 : #include "nsXPIDLString.h"
106 : #include "nsXULControllers.h"
107 : #include "nsIBoxObject.h"
108 : #include "nsPIBoxObject.h"
109 : #include "nsXULDocument.h"
110 : #include "nsXULPopupListener.h"
111 : #include "nsRuleWalker.h"
112 : #include "nsIDOMCSSStyleDeclaration.h"
113 : #include "nsCSSParser.h"
114 : #include "nsIListBoxObject.h"
115 : #include "nsContentUtils.h"
116 : #include "nsContentList.h"
117 : #include "nsMutationEvent.h"
118 : #include "nsAsyncDOMEvent.h"
119 : #include "nsIDOMMutationEvent.h"
120 : #include "nsPIDOMWindow.h"
121 : #include "nsDOMAttributeMap.h"
122 : #include "nsGkAtoms.h"
123 : #include "nsXULContentUtils.h"
124 : #include "nsNodeUtils.h"
125 : #include "nsFrameLoader.h"
126 : #include "prlog.h"
127 : #include "rdf.h"
128 : #include "nsIControllers.h"
129 : #include "nsAttrValueOrString.h"
130 :
131 : // The XUL doc interface
132 : #include "nsIDOMXULDocument.h"
133 :
134 : #include "nsReadableUtils.h"
135 : #include "nsIFrame.h"
136 : #include "nsNodeInfoManager.h"
137 : #include "nsXBLBinding.h"
138 : #include "nsEventDispatcher.h"
139 : #include "mozAutoDocUpdate.h"
140 : #include "nsIDOMXULCommandEvent.h"
141 : #include "nsIDOMNSEvent.h"
142 : #include "nsCCUncollectableMarker.h"
143 :
144 : namespace css = mozilla::css;
145 :
146 : // Global object maintenance
147 : nsIXBLService * nsXULElement::gXBLService = nsnull;
148 :
149 : /**
150 : * A tearoff class for nsXULElement to implement nsIScriptEventHandlerOwner.
151 : */
152 : class nsScriptEventHandlerOwnerTearoff : public nsIScriptEventHandlerOwner
153 0 : {
154 : public:
155 0 : nsScriptEventHandlerOwnerTearoff(nsXULElement* aElement)
156 0 : : mElement(aElement) {}
157 :
158 0 : NS_DECL_CYCLE_COLLECTING_ISUPPORTS
159 1464 : NS_DECL_CYCLE_COLLECTION_CLASS(nsScriptEventHandlerOwnerTearoff)
160 :
161 : // nsIScriptEventHandlerOwner
162 : virtual nsresult CompileEventHandler(nsIScriptContext* aContext,
163 : nsIAtom *aName,
164 : const nsAString& aBody,
165 : const char* aURL,
166 : PRUint32 aLineNo,
167 : nsScriptObjectHolder<JSObject>& aHandler);
168 : virtual nsresult GetCompiledEventHandler(nsIAtom *aName,
169 : nsScriptObjectHolder<JSObject>& aHandler);
170 :
171 : private:
172 : nsRefPtr<nsXULElement> mElement;
173 : };
174 :
175 : //----------------------------------------------------------------------
176 :
177 : static NS_DEFINE_CID(kXULPopupListenerCID, NS_XULPOPUPLISTENER_CID);
178 :
179 : //----------------------------------------------------------------------
180 :
181 : #ifdef XUL_PROTOTYPE_ATTRIBUTE_METERING
182 : PRUint32 nsXULPrototypeAttribute::gNumElements;
183 : PRUint32 nsXULPrototypeAttribute::gNumAttributes;
184 : PRUint32 nsXULPrototypeAttribute::gNumEventHandlers;
185 : PRUint32 nsXULPrototypeAttribute::gNumCacheTests;
186 : PRUint32 nsXULPrototypeAttribute::gNumCacheHits;
187 : PRUint32 nsXULPrototypeAttribute::gNumCacheSets;
188 : PRUint32 nsXULPrototypeAttribute::gNumCacheFills;
189 : #endif
190 :
191 : class nsXULElementTearoff : public nsIDOMElementCSSInlineStyle,
192 : public nsIFrameLoaderOwner
193 0 : {
194 : public:
195 0 : NS_DECL_CYCLE_COLLECTING_ISUPPORTS
196 1464 : NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsXULElementTearoff,
197 : nsIDOMElementCSSInlineStyle)
198 :
199 0 : nsXULElementTearoff(nsXULElement *aElement)
200 0 : : mElement(aElement)
201 : {
202 0 : }
203 :
204 0 : NS_IMETHOD GetStyle(nsIDOMCSSStyleDeclaration** aStyle)
205 : {
206 : nsresult rv;
207 0 : *aStyle = static_cast<nsXULElement*>(mElement.get())->GetStyle(&rv);
208 0 : NS_ENSURE_SUCCESS(rv, rv);
209 0 : NS_ADDREF(*aStyle);
210 0 : return NS_OK;
211 : }
212 0 : NS_FORWARD_NSIFRAMELOADEROWNER(static_cast<nsXULElement*>(mElement.get())->);
213 : private:
214 : nsCOMPtr<nsIDOMXULElement> mElement;
215 : };
216 :
217 1464 : NS_IMPL_CYCLE_COLLECTION_1(nsXULElementTearoff, mElement)
218 :
219 0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(nsXULElementTearoff)
220 0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(nsXULElementTearoff)
221 :
222 0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsXULElementTearoff)
223 0 : NS_INTERFACE_MAP_ENTRY(nsIFrameLoaderOwner)
224 0 : NS_INTERFACE_MAP_ENTRY(nsIDOMElementCSSInlineStyle)
225 0 : NS_INTERFACE_MAP_END_AGGREGATED(mElement)
226 :
227 : //----------------------------------------------------------------------
228 : // nsXULElement
229 : //
230 :
231 144 : nsXULElement::nsXULElement(already_AddRefed<nsINodeInfo> aNodeInfo)
232 : : nsStyledElement(aNodeInfo),
233 144 : mBindingParent(nsnull)
234 : {
235 : XUL_PROTOTYPE_ATTRIBUTE_METER(gNumElements);
236 :
237 : // We may be READWRITE by default; check.
238 144 : if (IsReadWriteTextElement()) {
239 0 : AddStatesSilently(NS_EVENT_STATE_MOZ_READWRITE);
240 0 : RemoveStatesSilently(NS_EVENT_STATE_MOZ_READONLY);
241 : }
242 144 : }
243 :
244 9 : nsXULElement::nsXULSlots::nsXULSlots()
245 9 : : nsXULElement::nsDOMSlots()
246 : {
247 9 : }
248 :
249 27 : nsXULElement::nsXULSlots::~nsXULSlots()
250 : {
251 9 : NS_IF_RELEASE(mControllers); // Forces release
252 9 : if (mFrameLoader) {
253 0 : mFrameLoader->Destroy();
254 : }
255 36 : }
256 :
257 : void
258 9 : nsXULElement::nsXULSlots::Traverse(nsCycleCollectionTraversalCallback &cb)
259 : {
260 9 : NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mFrameLoader");
261 9 : cb.NoteXPCOMChild(NS_ISUPPORTS_CAST(nsIFrameLoader*, mFrameLoader));
262 9 : }
263 :
264 : nsINode::nsSlots*
265 9 : nsXULElement::CreateSlots()
266 : {
267 9 : return new nsXULSlots();
268 : }
269 :
270 : /* static */
271 : already_AddRefed<nsXULElement>
272 0 : nsXULElement::Create(nsXULPrototypeElement* aPrototype, nsINodeInfo *aNodeInfo,
273 : bool aIsScriptable)
274 : {
275 0 : nsCOMPtr<nsINodeInfo> ni = aNodeInfo;
276 0 : nsXULElement *element = new nsXULElement(ni.forget());
277 0 : if (element) {
278 0 : NS_ADDREF(element);
279 :
280 0 : element->mPrototype = aPrototype;
281 0 : if (aPrototype->mHasIdAttribute) {
282 0 : element->SetHasID();
283 : }
284 0 : if (aPrototype->mHasClassAttribute) {
285 0 : element->SetFlags(NODE_MAY_HAVE_CLASS);
286 : }
287 0 : if (aPrototype->mHasStyleAttribute) {
288 0 : element->SetMayHaveStyle();
289 : }
290 :
291 0 : NS_ASSERTION(aPrototype->mScriptTypeID != nsIProgrammingLanguage::UNKNOWN,
292 : "Need to know the language!");
293 0 : element->SetScriptTypeID(aPrototype->mScriptTypeID);
294 :
295 0 : if (aIsScriptable) {
296 : // Check each attribute on the prototype to see if we need to do
297 : // any additional processing and hookup that would otherwise be
298 : // done 'automagically' by SetAttr().
299 0 : for (PRUint32 i = 0; i < aPrototype->mNumAttributes; ++i) {
300 0 : element->AddListenerFor(aPrototype->mAttributes[i].mName,
301 0 : true);
302 : }
303 : }
304 : }
305 :
306 0 : return element;
307 : }
308 :
309 : nsresult
310 0 : nsXULElement::Create(nsXULPrototypeElement* aPrototype,
311 : nsIDocument* aDocument,
312 : bool aIsScriptable,
313 : Element** aResult)
314 : {
315 : // Create an nsXULElement from a prototype
316 0 : NS_PRECONDITION(aPrototype != nsnull, "null ptr");
317 0 : if (! aPrototype)
318 0 : return NS_ERROR_NULL_POINTER;
319 :
320 0 : NS_PRECONDITION(aResult != nsnull, "null ptr");
321 0 : if (! aResult)
322 0 : return NS_ERROR_NULL_POINTER;
323 :
324 0 : nsCOMPtr<nsINodeInfo> nodeInfo;
325 0 : if (aDocument) {
326 0 : nsINodeInfo* ni = aPrototype->mNodeInfo;
327 : nodeInfo = aDocument->NodeInfoManager()->
328 : GetNodeInfo(ni->NameAtom(), ni->GetPrefixAtom(), ni->NamespaceID(),
329 0 : nsIDOMNode::ELEMENT_NODE);
330 0 : NS_ENSURE_TRUE(nodeInfo, NS_ERROR_OUT_OF_MEMORY);
331 : }
332 : else {
333 0 : nodeInfo = aPrototype->mNodeInfo;
334 : }
335 :
336 : nsRefPtr<nsXULElement> element = Create(aPrototype, nodeInfo,
337 0 : aIsScriptable);
338 0 : if (!element) {
339 0 : return NS_ERROR_OUT_OF_MEMORY;
340 : }
341 :
342 0 : NS_ADDREF(*aResult = element.get());
343 :
344 0 : return NS_OK;
345 : }
346 :
347 : nsresult
348 144 : NS_NewXULElement(nsIContent** aResult, already_AddRefed<nsINodeInfo> aNodeInfo)
349 : {
350 144 : NS_PRECONDITION(aNodeInfo.get(), "need nodeinfo for non-proto Create");
351 :
352 144 : nsIDocument* doc = aNodeInfo.get()->GetDocument();
353 144 : if (doc && !doc->AllowXULXBL()) {
354 0 : nsCOMPtr<nsINodeInfo> ni = aNodeInfo;
355 0 : return NS_ERROR_NOT_AVAILABLE;
356 : }
357 :
358 144 : NS_ADDREF(*aResult = new nsXULElement(aNodeInfo));
359 :
360 144 : return NS_OK;
361 : }
362 :
363 : void
364 0 : NS_TrustedNewXULElement(nsIContent** aResult, already_AddRefed<nsINodeInfo> aNodeInfo)
365 : {
366 0 : NS_PRECONDITION(aNodeInfo.get(), "need nodeinfo for non-proto Create");
367 :
368 : // Create an nsXULElement with the specified namespace and tag.
369 0 : NS_ADDREF(*aResult = new nsXULElement(aNodeInfo));
370 0 : }
371 :
372 : //----------------------------------------------------------------------
373 : // nsISupports interface
374 :
375 1464 : NS_IMPL_CYCLE_COLLECTION_CLASS(nsXULElement)
376 144 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsXULElement,
377 : nsStyledElement)
378 144 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mPrototype)
379 : {
380 144 : nsXULSlots* slots = static_cast<nsXULSlots*>(tmp->GetExistingSlots());
381 144 : if (slots) {
382 9 : slots->Traverse(cb);
383 : }
384 : }
385 144 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
386 :
387 3310 : NS_IMPL_ADDREF_INHERITED(nsXULElement, nsStyledElement)
388 3310 : NS_IMPL_RELEASE_INHERITED(nsXULElement, nsStyledElement)
389 :
390 10 : DOMCI_NODE_DATA(XULElement, nsXULElement)
391 :
392 5865 : NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(nsXULElement)
393 : NS_NODE_OFFSET_AND_INTERFACE_TABLE_BEGIN(nsXULElement)
394 : NS_INTERFACE_TABLE_ENTRY(nsXULElement, nsIDOMNode)
395 : NS_INTERFACE_TABLE_ENTRY(nsXULElement, nsIDOMElement)
396 : NS_INTERFACE_TABLE_ENTRY(nsXULElement, nsIDOMXULElement)
397 3309 : NS_OFFSET_AND_INTERFACE_TABLE_END
398 3297 : NS_ELEMENT_INTERFACE_TABLE_TO_MAP_SEGUE
399 2 : NS_INTERFACE_MAP_ENTRY_TEAROFF(nsIScriptEventHandlerOwner,
400 : new nsScriptEventHandlerOwnerTearoff(this))
401 2 : NS_INTERFACE_MAP_ENTRY_TEAROFF(nsIDOMElementCSSInlineStyle,
402 : new nsXULElementTearoff(this))
403 2 : NS_INTERFACE_MAP_ENTRY_TEAROFF(nsIFrameLoaderOwner,
404 : new nsXULElementTearoff(this))
405 2 : NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(XULElement)
406 0 : NS_ELEMENT_INTERFACE_MAP_END
407 :
408 : //----------------------------------------------------------------------
409 : // nsIDOMNode interface
410 :
411 : nsresult
412 0 : nsXULElement::Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const
413 : {
414 0 : *aResult = nsnull;
415 :
416 : // If we have a prototype, so will our clone.
417 0 : nsRefPtr<nsXULElement> element;
418 0 : if (mPrototype) {
419 0 : element = nsXULElement::Create(mPrototype, aNodeInfo, true);
420 0 : NS_ASSERTION(GetScriptTypeID() == mPrototype->mScriptTypeID,
421 : "Didn't get the default language from proto?");
422 : }
423 : else {
424 0 : nsCOMPtr<nsINodeInfo> ni = aNodeInfo;
425 0 : element = new nsXULElement(ni.forget());
426 0 : if (element) {
427 : // If created from a prototype, we will already have the script
428 : // language specified by the proto - otherwise copy it directly
429 0 : element->SetScriptTypeID(GetScriptTypeID());
430 : }
431 : }
432 :
433 0 : if (!element) {
434 0 : return NS_ERROR_OUT_OF_MEMORY;
435 : }
436 :
437 : // XXX TODO: set up RDF generic builder n' stuff if there is a
438 : // 'datasources' attribute? This is really kind of tricky,
439 : // because then we'd need to -selectively- copy children that
440 : // -weren't- generated from RDF. Ugh. Forget it.
441 :
442 : // Note that we're _not_ copying mControllers.
443 :
444 0 : nsresult rv = CopyInnerTo(element);
445 0 : if (NS_SUCCEEDED(rv)) {
446 0 : NS_ADDREF(*aResult = element);
447 : }
448 :
449 0 : return rv;
450 : }
451 :
452 : //----------------------------------------------------------------------
453 :
454 : NS_IMETHODIMP
455 45 : nsXULElement::GetElementsByAttribute(const nsAString& aAttribute,
456 : const nsAString& aValue,
457 : nsIDOMNodeList** aReturn)
458 : {
459 90 : nsCOMPtr<nsIAtom> attrAtom(do_GetAtom(aAttribute));
460 45 : NS_ENSURE_TRUE(attrAtom, NS_ERROR_OUT_OF_MEMORY);
461 45 : void* attrValue = new nsString(aValue);
462 45 : NS_ENSURE_TRUE(attrValue, NS_ERROR_OUT_OF_MEMORY);
463 : nsContentList *list =
464 : new nsContentList(this,
465 : nsXULDocument::MatchAttribute,
466 : nsContentUtils::DestroyMatchString,
467 : attrValue,
468 : true,
469 : attrAtom,
470 90 : kNameSpaceID_Unknown);
471 45 : NS_ENSURE_TRUE(list, NS_ERROR_OUT_OF_MEMORY);
472 :
473 45 : NS_ADDREF(*aReturn = list);
474 45 : return NS_OK;
475 : }
476 :
477 : NS_IMETHODIMP
478 37 : nsXULElement::GetElementsByAttributeNS(const nsAString& aNamespaceURI,
479 : const nsAString& aAttribute,
480 : const nsAString& aValue,
481 : nsIDOMNodeList** aReturn)
482 : {
483 74 : nsCOMPtr<nsIAtom> attrAtom(do_GetAtom(aAttribute));
484 37 : NS_ENSURE_TRUE(attrAtom, NS_ERROR_OUT_OF_MEMORY);
485 :
486 37 : PRInt32 nameSpaceId = kNameSpaceID_Wildcard;
487 37 : if (!aNamespaceURI.EqualsLiteral("*")) {
488 : nsresult rv =
489 20 : nsContentUtils::NameSpaceManager()->RegisterNameSpace(aNamespaceURI,
490 20 : nameSpaceId);
491 20 : NS_ENSURE_SUCCESS(rv, rv);
492 : }
493 :
494 37 : void* attrValue = new nsString(aValue);
495 37 : NS_ENSURE_TRUE(attrValue, NS_ERROR_OUT_OF_MEMORY);
496 :
497 : nsContentList *list =
498 : new nsContentList(this,
499 : nsXULDocument::MatchAttribute,
500 : nsContentUtils::DestroyMatchString,
501 : attrValue,
502 : true,
503 : attrAtom,
504 74 : nameSpaceId);
505 37 : NS_ENSURE_TRUE(list, NS_ERROR_OUT_OF_MEMORY);
506 :
507 37 : NS_ADDREF(*aReturn = list);
508 37 : return NS_OK;
509 : }
510 :
511 : nsEventListenerManager*
512 0 : nsXULElement::GetEventListenerManagerForAttr(nsIAtom* aAttrName, bool* aDefer)
513 : {
514 : // XXXbz sXBL/XBL2 issue: should we instead use GetCurrentDoc()
515 : // here, override BindToTree for those classes and munge event
516 : // listeners there?
517 0 : nsIDocument* doc = OwnerDoc();
518 :
519 : nsPIDOMWindow *window;
520 0 : Element *root = doc->GetRootElement();
521 0 : if ((!root || root == this) && !mNodeInfo->Equals(nsGkAtoms::overlay) &&
522 0 : (window = doc->GetInnerWindow()) && window->IsInnerWindow()) {
523 :
524 0 : nsCOMPtr<nsIDOMEventTarget> piTarget = do_QueryInterface(window);
525 :
526 0 : *aDefer = false;
527 0 : return piTarget->GetListenerManager(true);
528 : }
529 :
530 0 : return nsStyledElement::GetEventListenerManagerForAttr(aAttrName, aDefer);
531 : }
532 :
533 : // returns true if the element is not a list
534 0 : static bool IsNonList(nsINodeInfo* aNodeInfo)
535 : {
536 0 : return !aNodeInfo->Equals(nsGkAtoms::tree) &&
537 0 : !aNodeInfo->Equals(nsGkAtoms::listbox) &&
538 0 : !aNodeInfo->Equals(nsGkAtoms::richlistbox);
539 : }
540 :
541 : bool
542 0 : nsXULElement::IsFocusable(PRInt32 *aTabIndex, bool aWithMouse)
543 : {
544 : /*
545 : * Returns true if an element may be focused, and false otherwise. The inout
546 : * argument aTabIndex will be set to the tab order index to be used; -1 for
547 : * elements that should not be part of the tab order and a greater value to
548 : * indicate its tab order.
549 : *
550 : * Confusingly, the supplied value for the aTabIndex argument may indicate
551 : * whether the element may be focused as a result of the -moz-user-focus
552 : * property, where -1 means no and 0 means yes.
553 : *
554 : * For controls, the element cannot be focused and is not part of the tab
555 : * order if it is disabled.
556 : *
557 : * Controls (those that implement nsIDOMXULControlElement):
558 : * *aTabIndex = -1 no tabindex Not focusable or tabbable
559 : * *aTabIndex = -1 tabindex="-1" Not focusable or tabbable
560 : * *aTabIndex = -1 tabindex=">=0" Focusable and tabbable
561 : * *aTabIndex >= 0 no tabindex Focusable and tabbable
562 : * *aTabIndex >= 0 tabindex="-1" Focusable but not tabbable
563 : * *aTabIndex >= 0 tabindex=">=0" Focusable and tabbable
564 : * Non-controls:
565 : * *aTabIndex = -1 Not focusable or tabbable
566 : * *aTabIndex >= 0 Focusable and tabbable
567 : *
568 : * If aTabIndex is null, then the tabindex is not computed, and
569 : * true is returned for non-disabled controls and false otherwise.
570 : */
571 :
572 : // elements are not focusable by default
573 0 : bool shouldFocus = false;
574 :
575 : #ifdef XP_MACOSX
576 : // on Mac, mouse interactions only focus the element if it's a list
577 : if (aWithMouse && IsNonList(mNodeInfo))
578 : return false;
579 : #endif
580 :
581 0 : nsCOMPtr<nsIDOMXULControlElement> xulControl = do_QueryObject(this);
582 0 : if (xulControl) {
583 : // a disabled element cannot be focused and is not part of the tab order
584 : bool disabled;
585 0 : xulControl->GetDisabled(&disabled);
586 0 : if (disabled) {
587 0 : if (aTabIndex)
588 0 : *aTabIndex = -1;
589 0 : return false;
590 : }
591 0 : shouldFocus = true;
592 : }
593 :
594 0 : if (aTabIndex) {
595 0 : if (xulControl) {
596 0 : if (HasAttr(kNameSpaceID_None, nsGkAtoms::tabindex)) {
597 : // if either the aTabIndex argument or a specified tabindex is non-negative,
598 : // the element becomes focusable.
599 0 : PRInt32 tabIndex = 0;
600 0 : xulControl->GetTabIndex(&tabIndex);
601 0 : shouldFocus = *aTabIndex >= 0 || tabIndex >= 0;
602 0 : *aTabIndex = tabIndex;
603 : }
604 : else {
605 : // otherwise, if there is no tabindex attribute, just use the value of
606 : // *aTabIndex to indicate focusability. Reset any supplied tabindex to 0.
607 0 : shouldFocus = *aTabIndex >= 0;
608 0 : if (shouldFocus)
609 0 : *aTabIndex = 0;
610 : }
611 :
612 0 : if (shouldFocus && sTabFocusModelAppliesToXUL &&
613 0 : !(sTabFocusModel & eTabFocus_formElementsMask)) {
614 : // By default, the tab focus model doesn't apply to xul element on any system but OS X.
615 : // on OS X we're following it for UI elements (XUL) as sTabFocusModel is based on
616 : // "Full Keyboard Access" system setting (see mac/nsILookAndFeel).
617 : // both textboxes and list elements (i.e. trees and list) should always be focusable
618 : // (textboxes are handled as html:input)
619 : // For compatibility, we only do this for controls, otherwise elements like <browser>
620 : // cannot take this focus.
621 0 : if (IsNonList(mNodeInfo))
622 0 : *aTabIndex = -1;
623 : }
624 : }
625 : else {
626 0 : shouldFocus = *aTabIndex >= 0;
627 : }
628 : }
629 :
630 0 : return shouldFocus;
631 : }
632 :
633 : void
634 0 : nsXULElement::PerformAccesskey(bool aKeyCausesActivation,
635 : bool aIsTrustedEvent)
636 : {
637 0 : nsCOMPtr<nsIContent> content(this);
638 :
639 0 : if (Tag() == nsGkAtoms::label) {
640 0 : nsCOMPtr<nsIDOMElement> element;
641 :
642 0 : nsAutoString control;
643 0 : GetAttr(kNameSpaceID_None, nsGkAtoms::control, control);
644 0 : if (!control.IsEmpty()) {
645 : nsCOMPtr<nsIDOMDocument> domDocument =
646 0 : do_QueryInterface(content->GetCurrentDoc());
647 0 : if (domDocument)
648 0 : domDocument->GetElementById(control, getter_AddRefs(element));
649 : }
650 : // here we'll either change |content| to the element referenced by
651 : // |element|, or clear it.
652 0 : content = do_QueryInterface(element);
653 :
654 0 : if (!content)
655 : return;
656 : }
657 :
658 0 : nsIFrame* frame = content->GetPrimaryFrame();
659 0 : if (!frame || !frame->IsVisibleConsideringAncestors())
660 : return;
661 :
662 0 : nsXULElement* elm = FromContent(content);
663 0 : if (elm) {
664 : // Define behavior for each type of XUL element.
665 0 : nsIAtom *tag = content->Tag();
666 0 : if (tag != nsGkAtoms::toolbarbutton) {
667 0 : nsIFocusManager* fm = nsFocusManager::GetFocusManager();
668 0 : if (fm) {
669 0 : nsCOMPtr<nsIDOMElement> element;
670 : // for radio buttons, focus the radiogroup instead
671 0 : if (tag == nsGkAtoms::radio) {
672 0 : nsCOMPtr<nsIDOMXULSelectControlItemElement> controlItem(do_QueryInterface(content));
673 0 : if (controlItem) {
674 : bool disabled;
675 0 : controlItem->GetDisabled(&disabled);
676 0 : if (!disabled) {
677 0 : nsCOMPtr<nsIDOMXULSelectControlElement> selectControl;
678 0 : controlItem->GetControl(getter_AddRefs(selectControl));
679 0 : element = do_QueryInterface(selectControl);
680 : }
681 : }
682 : }
683 : else {
684 0 : element = do_QueryInterface(content);
685 : }
686 0 : if (element)
687 0 : fm->SetFocus(element, nsIFocusManager::FLAG_BYKEY);
688 : }
689 : }
690 0 : if (aKeyCausesActivation && tag != nsGkAtoms::textbox && tag != nsGkAtoms::menulist) {
691 0 : elm->ClickWithInputSource(nsIDOMMouseEvent::MOZ_SOURCE_KEYBOARD);
692 : }
693 : }
694 : else {
695 0 : content->PerformAccesskey(aKeyCausesActivation, aIsTrustedEvent);
696 : }
697 : }
698 :
699 :
700 : //----------------------------------------------------------------------
701 : // nsIScriptEventHandlerOwner interface
702 :
703 1464 : NS_IMPL_CYCLE_COLLECTION_CLASS(nsScriptEventHandlerOwnerTearoff)
704 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsScriptEventHandlerOwnerTearoff)
705 0 : tmp->mElement = nsnull;
706 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
707 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsScriptEventHandlerOwnerTearoff)
708 0 : NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mElement");
709 0 : cb.NoteXPCOMChild(static_cast<nsIContent*>(tmp->mElement));
710 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
711 :
712 0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsScriptEventHandlerOwnerTearoff)
713 0 : NS_INTERFACE_MAP_ENTRY(nsIScriptEventHandlerOwner)
714 0 : NS_INTERFACE_MAP_END_AGGREGATED(mElement)
715 :
716 0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(nsScriptEventHandlerOwnerTearoff)
717 0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(nsScriptEventHandlerOwnerTearoff)
718 :
719 : nsresult
720 0 : nsScriptEventHandlerOwnerTearoff::GetCompiledEventHandler(
721 : nsIAtom *aName,
722 : nsScriptObjectHolder<JSObject>& aHandler)
723 : {
724 : XUL_PROTOTYPE_ATTRIBUTE_METER(gNumCacheTests);
725 0 : aHandler.drop();
726 :
727 : nsXULPrototypeAttribute *attr =
728 0 : mElement->FindPrototypeAttribute(kNameSpaceID_None, aName);
729 0 : if (attr) {
730 : XUL_PROTOTYPE_ATTRIBUTE_METER(gNumCacheHits);
731 0 : aHandler.set(attr->mEventHandler);
732 : }
733 :
734 0 : return NS_OK;
735 : }
736 :
737 : nsresult
738 0 : nsScriptEventHandlerOwnerTearoff::CompileEventHandler(
739 : nsIScriptContext* aContext,
740 : nsIAtom *aName,
741 : const nsAString& aBody,
742 : const char* aURL,
743 : PRUint32 aLineNo,
744 : nsScriptObjectHolder<JSObject>& aHandler)
745 : {
746 : nsresult rv;
747 :
748 : XUL_PROTOTYPE_ATTRIBUTE_METER(gNumCacheSets);
749 :
750 : // XXX sXBL/XBL2 issue! Owner or current document?
751 0 : nsCOMPtr<nsIXULDocument> xuldoc = do_QueryInterface(mElement->OwnerDoc());
752 :
753 0 : nsIScriptContext* context = NULL;
754 0 : nsXULPrototypeElement* elem = mElement->mPrototype;
755 0 : if (elem && xuldoc) {
756 : // It'll be shared among the instances of the prototype.
757 :
758 : // Use the prototype document's special context. Because
759 : // scopeObject is null, the JS engine has no other source of
760 : // <the-new-shared-event-handler>.__proto__ than to look in
761 : // cx->globalObject for Function.prototype. That prototype
762 : // keeps the global object alive, so if we use this document's
763 : // global object, we'll be putting something in the prototype
764 : // that protects this document's global object from GC.
765 0 : nsCOMPtr<nsIScriptGlobalObjectOwner> globalOwner;
766 0 : rv = xuldoc->GetScriptGlobalObjectOwner(getter_AddRefs(globalOwner));
767 0 : NS_ENSURE_SUCCESS(rv, rv);
768 0 : NS_ENSURE_TRUE(globalOwner, NS_ERROR_UNEXPECTED);
769 :
770 0 : nsIScriptGlobalObject* global = globalOwner->GetScriptGlobalObject();
771 0 : NS_ENSURE_TRUE(global, NS_ERROR_UNEXPECTED);
772 :
773 0 : context = global->GetScriptContext(aContext->GetScriptTypeID());
774 : // It could be possible the language has been setup on aContext but
775 : // not on the global - we don't demand-create language contexts on the
776 : // nsGlobalWindow
777 0 : NS_ASSERTION(context,
778 : "Failed to get a language context from the global!?");
779 0 : NS_ENSURE_TRUE(context, NS_ERROR_UNEXPECTED);
780 : }
781 : else {
782 0 : context = aContext;
783 : }
784 :
785 : // Compile the event handler
786 : PRUint32 argCount;
787 : const char **argNames;
788 : nsContentUtils::GetEventArgNames(kNameSpaceID_XUL, aName, &argCount,
789 0 : &argNames);
790 :
791 0 : nsCxPusher pusher;
792 0 : if (!pusher.Push(context->GetNativeContext())) {
793 0 : return NS_ERROR_FAILURE;
794 : }
795 :
796 : rv = context->CompileEventHandler(aName, argCount, argNames,
797 : aBody, aURL, aLineNo,
798 : SCRIPTVERSION_DEFAULT, // for now?
799 0 : aHandler);
800 0 : if (NS_FAILED(rv)) return rv;
801 :
802 : nsXULPrototypeAttribute *attr =
803 0 : mElement->FindPrototypeAttribute(kNameSpaceID_None, aName);
804 0 : if (attr) {
805 : XUL_PROTOTYPE_ATTRIBUTE_METER(gNumCacheFills);
806 : // take a copy of the event handler, and tell the language about it.
807 0 : if (aHandler) {
808 0 : NS_ASSERTION(!attr->mEventHandler, "Leaking handler.");
809 :
810 0 : rv = nsContentUtils::HoldScriptObject(aContext->GetScriptTypeID(),
811 : elem,
812 : &NS_CYCLE_COLLECTION_NAME(nsXULPrototypeNode),
813 0 : aHandler.get(),
814 0 : elem->mHoldsScriptObject);
815 0 : if (NS_FAILED(rv)) return rv;
816 :
817 0 : elem->mHoldsScriptObject = true;
818 : }
819 0 : attr->mEventHandler = aHandler.get();
820 : }
821 :
822 0 : return NS_OK;
823 : }
824 :
825 : void
826 0 : nsXULElement::AddListenerFor(const nsAttrName& aName,
827 : bool aCompileEventHandlers)
828 : {
829 : // If appropriate, add a popup listener and/or compile the event
830 : // handler. Called when we change the element's document, create a
831 : // new element, change an attribute's value, etc.
832 : // Eventlistenener-attributes are always in the null namespace
833 0 : if (aName.IsAtom()) {
834 0 : nsIAtom *attr = aName.Atom();
835 0 : MaybeAddPopupListener(attr);
836 0 : if (aCompileEventHandlers &&
837 0 : nsContentUtils::IsEventAttributeName(attr, EventNameType_XUL)) {
838 0 : nsAutoString value;
839 0 : GetAttr(kNameSpaceID_None, attr, value);
840 0 : AddScriptEventListener(attr, value, true);
841 : }
842 : }
843 0 : }
844 :
845 : void
846 66 : nsXULElement::MaybeAddPopupListener(nsIAtom* aLocalName)
847 : {
848 : // If appropriate, add a popup listener. Called when we change the
849 : // element's document, create a new element, change an attribute's
850 : // value, etc.
851 66 : if (aLocalName == nsGkAtoms::menu ||
852 : aLocalName == nsGkAtoms::contextmenu ||
853 : // XXXdwh popup and context are deprecated
854 : aLocalName == nsGkAtoms::popup ||
855 : aLocalName == nsGkAtoms::context) {
856 0 : AddPopupListener(aLocalName);
857 : }
858 66 : }
859 :
860 : //----------------------------------------------------------------------
861 : //
862 : // nsIContent interface
863 : //
864 : void
865 144 : nsXULElement::UpdateEditableState(bool aNotify)
866 : {
867 : // Don't call through to nsGenericElement here because the things
868 : // it does don't work for cases when we're an editable control.
869 144 : nsIContent *parent = GetParent();
870 :
871 144 : SetEditableFlag(parent && parent->HasFlag(NODE_IS_EDITABLE));
872 144 : UpdateState(aNotify);
873 144 : }
874 :
875 : nsresult
876 144 : nsXULElement::BindToTree(nsIDocument* aDocument,
877 : nsIContent* aParent,
878 : nsIContent* aBindingParent,
879 : bool aCompileEventHandlers)
880 : {
881 : nsresult rv = nsStyledElement::BindToTree(aDocument, aParent,
882 : aBindingParent,
883 144 : aCompileEventHandlers);
884 144 : NS_ENSURE_SUCCESS(rv, rv);
885 :
886 144 : if (aDocument) {
887 144 : NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(),
888 : "Missing a script blocker!");
889 : // We're in a document now. Kick off the frame load.
890 144 : LoadSrc();
891 : }
892 :
893 144 : return rv;
894 : }
895 :
896 : void
897 435 : nsXULElement::UnbindFromTree(bool aDeep, bool aNullParent)
898 : {
899 : // mControllers can own objects that are implemented
900 : // in JavaScript (such as some implementations of
901 : // nsIControllers. These objects prevent their global
902 : // object's script object from being garbage collected,
903 : // which means JS continues to hold an owning reference
904 : // to the nsGlobalWindow, which owns the document,
905 : // which owns this content. That's a cycle, so we break
906 : // it here. (It might be better to break this by releasing
907 : // mDocument in nsGlobalWindow::SetDocShell, but I'm not
908 : // sure whether that would fix all possible cycles through
909 : // mControllers.)
910 435 : nsXULSlots* slots = static_cast<nsXULSlots*>(GetExistingDOMSlots());
911 435 : if (slots) {
912 23 : NS_IF_RELEASE(slots->mControllers);
913 23 : if (slots->mFrameLoader) {
914 : // This element is being taken out of the document, destroy the
915 : // possible frame loader.
916 : // XXXbz we really want to only partially destroy the frame
917 : // loader... we don't want to tear down the docshell. Food for
918 : // later bug.
919 0 : slots->mFrameLoader->Destroy();
920 0 : slots->mFrameLoader = nsnull;
921 : }
922 : }
923 :
924 435 : nsStyledElement::UnbindFromTree(aDeep, aNullParent);
925 435 : }
926 :
927 : nsresult
928 0 : nsXULElement::RemoveChildAt(PRUint32 aIndex, bool aNotify)
929 : {
930 : nsresult rv;
931 0 : nsCOMPtr<nsIContent> oldKid = mAttrsAndChildren.GetSafeChildAt(aIndex);
932 0 : if (!oldKid) {
933 0 : return NS_OK;
934 : }
935 :
936 : // On the removal of a <treeitem>, <treechildren>, or <treecell> element,
937 : // the possibility exists that some of the items in the removed subtree
938 : // are selected (and therefore need to be deselected). We need to account for this.
939 0 : nsCOMPtr<nsIDOMXULMultiSelectControlElement> controlElement;
940 0 : nsCOMPtr<nsIListBoxObject> listBox;
941 0 : bool fireSelectionHandler = false;
942 :
943 : // -1 = do nothing, -2 = null out current item
944 : // anything else = index to re-set as current
945 0 : PRInt32 newCurrentIndex = -1;
946 :
947 0 : if (oldKid->NodeInfo()->Equals(nsGkAtoms::listitem, kNameSpaceID_XUL)) {
948 : // This is the nasty case. We have (potentially) a slew of selected items
949 : // and cells going away.
950 : // First, retrieve the tree.
951 : // Check first whether this element IS the tree
952 0 : controlElement = do_QueryObject(this);
953 :
954 : // If it's not, look at our parent
955 0 : if (!controlElement)
956 0 : rv = GetParentTree(getter_AddRefs(controlElement));
957 :
958 0 : nsCOMPtr<nsIDOMElement> oldKidElem = do_QueryInterface(oldKid);
959 0 : if (controlElement && oldKidElem) {
960 : // Iterate over all of the items and find out if they are contained inside
961 : // the removed subtree.
962 : PRInt32 length;
963 0 : controlElement->GetSelectedCount(&length);
964 0 : for (PRInt32 i = 0; i < length; i++) {
965 0 : nsCOMPtr<nsIDOMXULSelectControlItemElement> node;
966 0 : controlElement->GetSelectedItem(i, getter_AddRefs(node));
967 : // we need to QI here to do an XPCOM-correct pointercompare
968 0 : nsCOMPtr<nsIDOMElement> selElem = do_QueryInterface(node);
969 0 : if (selElem == oldKidElem &&
970 0 : NS_SUCCEEDED(controlElement->RemoveItemFromSelection(node))) {
971 0 : length--;
972 0 : i--;
973 0 : fireSelectionHandler = true;
974 : }
975 : }
976 :
977 0 : nsCOMPtr<nsIDOMXULSelectControlItemElement> curItem;
978 0 : controlElement->GetCurrentItem(getter_AddRefs(curItem));
979 0 : nsCOMPtr<nsIContent> curNode = do_QueryInterface(curItem);
980 0 : if (curNode && nsContentUtils::ContentIsDescendantOf(curNode, oldKid)) {
981 : // Current item going away
982 0 : nsCOMPtr<nsIBoxObject> box;
983 0 : controlElement->GetBoxObject(getter_AddRefs(box));
984 0 : listBox = do_QueryInterface(box);
985 0 : if (listBox && oldKidElem) {
986 0 : listBox->GetIndexOfItem(oldKidElem, &newCurrentIndex);
987 : }
988 :
989 : // If any of this fails, we'll just set the current item to null
990 0 : if (newCurrentIndex == -1)
991 0 : newCurrentIndex = -2;
992 : }
993 : }
994 : }
995 :
996 0 : rv = nsStyledElement::RemoveChildAt(aIndex, aNotify);
997 :
998 0 : if (newCurrentIndex == -2)
999 0 : controlElement->SetCurrentItem(nsnull);
1000 0 : else if (newCurrentIndex > -1) {
1001 : // Make sure the index is still valid
1002 : PRInt32 treeRows;
1003 0 : listBox->GetRowCount(&treeRows);
1004 0 : if (treeRows > 0) {
1005 0 : newCurrentIndex = NS_MIN((treeRows - 1), newCurrentIndex);
1006 0 : nsCOMPtr<nsIDOMElement> newCurrentItem;
1007 0 : listBox->GetItemAtIndex(newCurrentIndex, getter_AddRefs(newCurrentItem));
1008 0 : nsCOMPtr<nsIDOMXULSelectControlItemElement> xulCurItem = do_QueryInterface(newCurrentItem);
1009 0 : if (xulCurItem)
1010 0 : controlElement->SetCurrentItem(xulCurItem);
1011 : } else {
1012 0 : controlElement->SetCurrentItem(nsnull);
1013 : }
1014 : }
1015 :
1016 : nsIDocument* doc;
1017 0 : if (fireSelectionHandler && (doc = GetCurrentDoc())) {
1018 : nsContentUtils::DispatchTrustedEvent(doc,
1019 : static_cast<nsIContent*>(this),
1020 0 : NS_LITERAL_STRING("select"),
1021 : false,
1022 0 : true);
1023 : }
1024 :
1025 0 : return rv;
1026 : }
1027 :
1028 : void
1029 0 : nsXULElement::UnregisterAccessKey(const nsAString& aOldValue)
1030 : {
1031 : // If someone changes the accesskey, unregister the old one
1032 : //
1033 0 : nsIDocument* doc = GetCurrentDoc();
1034 0 : if (doc && !aOldValue.IsEmpty()) {
1035 0 : nsIPresShell *shell = doc->GetShell();
1036 :
1037 0 : if (shell) {
1038 0 : nsIContent *content = this;
1039 :
1040 : // find out what type of content node this is
1041 0 : if (mNodeInfo->Equals(nsGkAtoms::label)) {
1042 : // For anonymous labels the unregistering must
1043 : // occur on the binding parent control.
1044 : // XXXldb: And what if the binding parent is null?
1045 0 : content = GetBindingParent();
1046 : }
1047 :
1048 0 : if (content) {
1049 : shell->GetPresContext()->EventStateManager()->
1050 0 : UnregisterAccessKey(content, aOldValue.First());
1051 : }
1052 : }
1053 : }
1054 0 : }
1055 :
1056 : nsresult
1057 184 : nsXULElement::BeforeSetAttr(PRInt32 aNamespaceID, nsIAtom* aName,
1058 : const nsAttrValueOrString* aValue, bool aNotify)
1059 : {
1060 184 : if (aNamespaceID == kNameSpaceID_None && aName == nsGkAtoms::accesskey &&
1061 0 : IsInDoc()) {
1062 0 : const nsAttrValue* attrVal = FindLocalOrProtoAttr(aNamespaceID, aName);
1063 0 : if (attrVal) {
1064 0 : nsAutoString oldValue;
1065 0 : attrVal->ToString(oldValue);
1066 0 : UnregisterAccessKey(oldValue);
1067 : }
1068 : }
1069 184 : else if (aNamespaceID == kNameSpaceID_None && (aName ==
1070 0 : nsGkAtoms::command || aName == nsGkAtoms::observes) && IsInDoc()) {
1071 : // XXX sXBL/XBL2 issue! Owner or current document?
1072 0 : nsAutoString oldValue;
1073 0 : GetAttr(kNameSpaceID_None, nsGkAtoms::observes, oldValue);
1074 0 : if (oldValue.IsEmpty()) {
1075 0 : GetAttr(kNameSpaceID_None, nsGkAtoms::command, oldValue);
1076 : }
1077 :
1078 0 : if (!oldValue.IsEmpty()) {
1079 0 : RemoveBroadcaster(oldValue);
1080 : }
1081 : }
1082 250 : else if (aNamespaceID == kNameSpaceID_None &&
1083 : aValue &&
1084 66 : mNodeInfo->Equals(nsGkAtoms::window) &&
1085 : aName == nsGkAtoms::chromemargin) {
1086 0 : nsAttrValue attrValue;
1087 : // Make sure the margin format is valid first
1088 0 : if (!attrValue.ParseIntMarginValue(aValue->String())) {
1089 0 : return NS_ERROR_INVALID_ARG;
1090 : }
1091 : }
1092 :
1093 : return nsStyledElement::BeforeSetAttr(aNamespaceID, aName,
1094 184 : aValue, aNotify);
1095 : }
1096 :
1097 : nsresult
1098 184 : nsXULElement::AfterSetAttr(PRInt32 aNamespaceID, nsIAtom* aName,
1099 : const nsAttrValue* aValue, bool aNotify)
1100 : {
1101 184 : if (aNamespaceID == kNameSpaceID_None) {
1102 : // XXX UnsetAttr handles more attributes than we do. See bug 233642.
1103 :
1104 : // Add popup and event listeners. We can't call AddListenerFor since
1105 : // the attribute isn't set yet.
1106 66 : MaybeAddPopupListener(aName);
1107 66 : if (nsContentUtils::IsEventAttributeName(aName, EventNameType_XUL) && aValue) {
1108 : // If mPrototype->mScriptTypeID != GetScriptTypeID(), it means
1109 : // we are resolving an overlay with a different default script
1110 : // language. We can't defer compilation of those handlers as
1111 : // we will have lost the script language (storing it on each
1112 : // nsXULPrototypeAttribute is expensive!)
1113 0 : bool defer = mPrototype == nsnull ||
1114 0 : mPrototype->mScriptTypeID == GetScriptTypeID();
1115 0 : if (aValue->Type() == nsAttrValue::eString) {
1116 0 : AddScriptEventListener(aName, aValue->GetStringValue(), defer);
1117 : } else {
1118 0 : nsAutoString body;
1119 0 : aValue->ToString(body);
1120 0 : AddScriptEventListener(aName, body, defer);
1121 : }
1122 : }
1123 :
1124 : // Hide chrome if needed
1125 66 : if (mNodeInfo->Equals(nsGkAtoms::window) && aValue) {
1126 0 : if (aName == nsGkAtoms::hidechrome) {
1127 : HideWindowChrome(
1128 0 : aValue->Equals(NS_LITERAL_STRING("true"), eCaseMatters));
1129 : }
1130 0 : else if (aName == nsGkAtoms::chromemargin) {
1131 0 : SetChromeMargins(aValue);
1132 : }
1133 : }
1134 :
1135 : // title, (in)activetitlebarcolor and drawintitlebar are settable on
1136 : // any root node (windows, dialogs, etc)
1137 66 : nsIDocument *document = GetCurrentDoc();
1138 66 : if (document && document->GetRootElement() == this) {
1139 0 : if (aName == nsGkAtoms::title) {
1140 0 : document->NotifyPossibleTitleChange(false);
1141 : }
1142 0 : else if ((aName == nsGkAtoms::activetitlebarcolor ||
1143 : aName == nsGkAtoms::inactivetitlebarcolor) && aValue) {
1144 0 : nscolor color = NS_RGBA(0, 0, 0, 0);
1145 0 : if (aValue->Type() == nsAttrValue::eColor) {
1146 0 : aValue->GetColorValue(color);
1147 : } else {
1148 0 : nsAutoString tmp;
1149 0 : nsAttrValue attrValue;
1150 0 : aValue->ToString(tmp);
1151 0 : attrValue.ParseColor(tmp);
1152 0 : attrValue.GetColorValue(color);
1153 : }
1154 0 : SetTitlebarColor(color, aName == nsGkAtoms::activetitlebarcolor);
1155 : }
1156 0 : else if (aName == nsGkAtoms::drawintitlebar) {
1157 : SetDrawsInTitlebar(aValue &&
1158 0 : aValue->Equals(NS_LITERAL_STRING("true"), eCaseMatters));
1159 : }
1160 0 : else if (aName == nsGkAtoms::localedir) {
1161 : // if the localedir changed on the root element, reset the document direction
1162 0 : nsCOMPtr<nsIXULDocument> xuldoc = do_QueryInterface(document);
1163 0 : if (xuldoc) {
1164 0 : xuldoc->ResetDocumentDirection();
1165 : }
1166 : }
1167 0 : else if (aName == nsGkAtoms::lwtheme ||
1168 : aName == nsGkAtoms::lwthemetextcolor) {
1169 : // if the lwtheme changed, make sure to reset the document lwtheme cache
1170 0 : nsCOMPtr<nsIXULDocument> xuldoc = do_QueryInterface(document);
1171 0 : if (xuldoc) {
1172 0 : xuldoc->ResetDocumentLWTheme();
1173 : }
1174 : }
1175 : }
1176 :
1177 66 : if (aName == nsGkAtoms::src && document) {
1178 0 : LoadSrc();
1179 : }
1180 :
1181 : // XXX need to check if they're changing an event handler: if
1182 : // so, then we need to unhook the old one. Or something.
1183 : }
1184 :
1185 : return nsStyledElement::AfterSetAttr(aNamespaceID, aName,
1186 184 : aValue, aNotify);
1187 : }
1188 :
1189 : bool
1190 184 : nsXULElement::ParseAttribute(PRInt32 aNamespaceID,
1191 : nsIAtom* aAttribute,
1192 : const nsAString& aValue,
1193 : nsAttrValue& aResult)
1194 : {
1195 : // Parse into a nsAttrValue
1196 184 : if (!nsStyledElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
1197 184 : aResult)) {
1198 : // Fall back to parsing as atom for short values
1199 174 : aResult.ParseStringOrAtom(aValue);
1200 : }
1201 :
1202 184 : return true;
1203 : }
1204 :
1205 : const nsAttrName*
1206 0 : nsXULElement::InternalGetExistingAttrNameFromQName(const nsAString& aStr) const
1207 : {
1208 : const nsAttrName* attrName =
1209 0 : mAttrsAndChildren.GetExistingAttrNameFromQName(aStr);
1210 0 : if (attrName) {
1211 0 : return attrName;
1212 : }
1213 :
1214 0 : if (mPrototype) {
1215 : PRUint32 i;
1216 0 : for (i = 0; i < mPrototype->mNumAttributes; ++i) {
1217 0 : attrName = &mPrototype->mAttributes[i].mName;
1218 0 : if (attrName->QualifiedNameEquals(aStr)) {
1219 0 : return attrName;
1220 : }
1221 : }
1222 : }
1223 :
1224 0 : return nsnull;
1225 : }
1226 :
1227 : bool
1228 2 : nsXULElement::GetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
1229 : nsAString& aResult) const
1230 : {
1231 2 : NS_ASSERTION(nsnull != aName, "must have attribute name");
1232 2 : NS_ASSERTION(aNameSpaceID != kNameSpaceID_Unknown,
1233 : "must have a real namespace ID!");
1234 :
1235 2 : const nsAttrValue* val = FindLocalOrProtoAttr(aNameSpaceID, aName);
1236 :
1237 2 : if (!val) {
1238 : // Since we are returning a success code we'd better do
1239 : // something about the out parameters (someone may have
1240 : // given us a non-empty string).
1241 2 : aResult.Truncate();
1242 2 : return false;
1243 : }
1244 :
1245 0 : val->ToString(aResult);
1246 :
1247 0 : return true;
1248 : }
1249 :
1250 : bool
1251 2 : nsXULElement::HasAttr(PRInt32 aNameSpaceID, nsIAtom* aName) const
1252 : {
1253 2 : NS_ASSERTION(nsnull != aName, "must have attribute name");
1254 2 : NS_ASSERTION(aNameSpaceID != kNameSpaceID_Unknown,
1255 : "must have a real namespace ID!");
1256 :
1257 2 : return mAttrsAndChildren.GetAttr(aName, aNameSpaceID) ||
1258 2 : FindPrototypeAttribute(aNameSpaceID, aName);
1259 : }
1260 :
1261 : bool
1262 1221 : nsXULElement::AttrValueIs(PRInt32 aNameSpaceID,
1263 : nsIAtom* aName,
1264 : const nsAString& aValue,
1265 : nsCaseTreatment aCaseSensitive) const
1266 : {
1267 1221 : NS_ASSERTION(aName, "Must have attr name");
1268 1221 : NS_ASSERTION(aNameSpaceID != kNameSpaceID_Unknown, "Must have namespace");
1269 :
1270 1221 : const nsAttrValue* val = FindLocalOrProtoAttr(aNameSpaceID, aName);
1271 1221 : return val && val->Equals(aValue, aCaseSensitive);
1272 : }
1273 :
1274 : bool
1275 0 : nsXULElement::AttrValueIs(PRInt32 aNameSpaceID,
1276 : nsIAtom* aName,
1277 : nsIAtom* aValue,
1278 : nsCaseTreatment aCaseSensitive) const
1279 : {
1280 0 : NS_ASSERTION(aName, "Must have attr name");
1281 0 : NS_ASSERTION(aNameSpaceID != kNameSpaceID_Unknown, "Must have namespace");
1282 0 : NS_ASSERTION(aValue, "Null value atom");
1283 :
1284 0 : const nsAttrValue* val = FindLocalOrProtoAttr(aNameSpaceID, aName);
1285 0 : return val && val->Equals(aValue, aCaseSensitive);
1286 : }
1287 :
1288 : PRInt32
1289 0 : nsXULElement::FindAttrValueIn(PRInt32 aNameSpaceID,
1290 : nsIAtom* aName,
1291 : AttrValuesArray* aValues,
1292 : nsCaseTreatment aCaseSensitive) const
1293 : {
1294 0 : NS_ASSERTION(aName, "Must have attr name");
1295 0 : NS_ASSERTION(aNameSpaceID != kNameSpaceID_Unknown, "Must have namespace");
1296 0 : NS_ASSERTION(aValues, "Null value array");
1297 :
1298 0 : const nsAttrValue* val = FindLocalOrProtoAttr(aNameSpaceID, aName);
1299 0 : if (val) {
1300 0 : for (PRInt32 i = 0; aValues[i]; ++i) {
1301 0 : if (val->Equals(*aValues[i], aCaseSensitive)) {
1302 0 : return i;
1303 : }
1304 : }
1305 0 : return ATTR_VALUE_NO_MATCH;
1306 : }
1307 0 : return ATTR_MISSING;
1308 : }
1309 :
1310 : nsresult
1311 0 : nsXULElement::UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, bool aNotify)
1312 : {
1313 : // This doesn't call BeforeSetAttr/AfterSetAttr for now.
1314 :
1315 0 : NS_ASSERTION(nsnull != aName, "must have attribute name");
1316 : nsresult rv;
1317 :
1318 : // Because It's Hard to maintain a magic ``unset'' value in
1319 : // the local attributes, we'll fault all the attributes,
1320 : // unhook ourselves from the prototype, and then remove the
1321 : // local copy of the attribute that we want to unset. In
1322 : // other words, we'll become ``heavyweight''.
1323 : //
1324 : // We can avoid this if the attribute isn't in the prototype,
1325 : // then we just need to remove it locally
1326 :
1327 : nsXULPrototypeAttribute *protoattr =
1328 0 : FindPrototypeAttribute(aNameSpaceID, aName);
1329 0 : if (protoattr) {
1330 : // We've got an attribute on the prototype, so we need to
1331 : // fully fault and remove the local copy.
1332 0 : rv = MakeHeavyweight();
1333 0 : NS_ENSURE_SUCCESS(rv, rv);
1334 : }
1335 :
1336 0 : nsIDocument* doc = GetCurrentDoc();
1337 0 : mozAutoDocUpdate updateBatch(doc, UPDATE_CONTENT_MODEL, aNotify);
1338 :
1339 0 : bool isId = false;
1340 0 : if (aName == nsGkAtoms::id && aNameSpaceID == kNameSpaceID_None) {
1341 : // Have to do this before clearing flag. See RemoveFromIdTable
1342 0 : RemoveFromIdTable();
1343 0 : isId = true;
1344 : }
1345 :
1346 0 : PRInt32 index = mAttrsAndChildren.IndexOfAttr(aName, aNameSpaceID);
1347 0 : if (index < 0) {
1348 0 : NS_ASSERTION(!protoattr, "we used to have a protoattr, we should now "
1349 : "have a normal one");
1350 :
1351 0 : return NS_OK;
1352 : }
1353 :
1354 0 : nsAutoString oldValue;
1355 0 : GetAttr(aNameSpaceID, aName, oldValue);
1356 :
1357 0 : if (aNotify) {
1358 : nsNodeUtils::AttributeWillChange(this, aNameSpaceID, aName,
1359 0 : nsIDOMMutationEvent::REMOVAL);
1360 : }
1361 :
1362 : bool hasMutationListeners = aNotify &&
1363 : nsContentUtils::HasMutationListeners(this,
1364 0 : NS_EVENT_BITS_MUTATION_ATTRMODIFIED, this);
1365 :
1366 0 : nsCOMPtr<nsIDOMAttr> attrNode;
1367 0 : if (hasMutationListeners) {
1368 0 : nsAutoString ns;
1369 0 : nsContentUtils::NameSpaceManager()->GetNameSpaceURI(aNameSpaceID, ns);
1370 0 : GetAttributeNodeNSInternal(ns, nsDependentAtomString(aName),
1371 0 : getter_AddRefs(attrNode));
1372 : }
1373 :
1374 0 : nsDOMSlots *slots = GetExistingDOMSlots();
1375 0 : if (slots && slots->mAttributeMap) {
1376 0 : slots->mAttributeMap->DropAttribute(aNameSpaceID, aName);
1377 : }
1378 :
1379 : // The id-handling code, and in the future possibly other code, need to
1380 : // react to unexpected attribute changes.
1381 0 : nsMutationGuard::DidMutate();
1382 :
1383 0 : nsAttrValue ignored;
1384 0 : rv = mAttrsAndChildren.RemoveAttrAt(index, ignored);
1385 0 : NS_ENSURE_SUCCESS(rv, rv);
1386 :
1387 : // XXX if the RemoveAttrAt() call fails, we might end up having removed
1388 : // the attribute from the attribute map even though the attribute is still
1389 : // on the element
1390 : // https://bugzilla.mozilla.org/show_bug.cgi?id=296205
1391 :
1392 : // Deal with modification of magical attributes that side-effect
1393 : // other things.
1394 : // XXX Know how to remove POPUP event listeners when an attribute is unset?
1395 :
1396 0 : if (isId) {
1397 0 : ClearHasID();
1398 : }
1399 :
1400 0 : if (aNameSpaceID == kNameSpaceID_None) {
1401 0 : if (mNodeInfo->Equals(nsGkAtoms::window)) {
1402 0 : if (aName == nsGkAtoms::hidechrome) {
1403 0 : HideWindowChrome(false);
1404 : }
1405 0 : else if (aName == nsGkAtoms::chromemargin) {
1406 0 : ResetChromeMargins();
1407 : }
1408 : }
1409 :
1410 0 : if (doc && doc->GetRootElement() == this) {
1411 0 : if ((aName == nsGkAtoms::activetitlebarcolor ||
1412 : aName == nsGkAtoms::inactivetitlebarcolor)) {
1413 : // Use 0, 0, 0, 0 as the "none" color.
1414 0 : SetTitlebarColor(NS_RGBA(0, 0, 0, 0), aName == nsGkAtoms::activetitlebarcolor);
1415 : }
1416 0 : else if (aName == nsGkAtoms::localedir) {
1417 : // if the localedir changed on the root element, reset the document direction
1418 0 : nsCOMPtr<nsIXULDocument> xuldoc = do_QueryInterface(doc);
1419 0 : if (xuldoc) {
1420 0 : xuldoc->ResetDocumentDirection();
1421 : }
1422 : }
1423 0 : else if ((aName == nsGkAtoms::lwtheme ||
1424 : aName == nsGkAtoms::lwthemetextcolor)) {
1425 : // if the lwtheme changed, make sure to restyle appropriately
1426 0 : nsCOMPtr<nsIXULDocument> xuldoc = do_QueryInterface(doc);
1427 0 : if (xuldoc) {
1428 0 : xuldoc->ResetDocumentLWTheme();
1429 0 : }
1430 : }
1431 0 : else if (aName == nsGkAtoms::drawintitlebar) {
1432 0 : SetDrawsInTitlebar(false);
1433 : }
1434 : }
1435 :
1436 : // If the accesskey attribute is removed, unregister it here
1437 : // Also see nsXULLabelFrame, nsBoxFrame and nsTextBoxFrame's AttributeChanged
1438 0 : if (aName == nsGkAtoms::accesskey || aName == nsGkAtoms::control) {
1439 0 : UnregisterAccessKey(oldValue);
1440 : }
1441 :
1442 : // Check to see if the OBSERVES attribute is being unset. If so, we
1443 : // need to remove our broadcaster goop completely.
1444 0 : if (doc && (aName == nsGkAtoms::observes ||
1445 : aName == nsGkAtoms::command)) {
1446 0 : RemoveBroadcaster(oldValue);
1447 : }
1448 : }
1449 :
1450 0 : if (doc) {
1451 : nsRefPtr<nsXBLBinding> binding =
1452 0 : doc->BindingManager()->GetBinding(this);
1453 0 : if (binding)
1454 0 : binding->AttributeChanged(aName, aNameSpaceID, true, aNotify);
1455 :
1456 : }
1457 :
1458 0 : UpdateState(aNotify);
1459 :
1460 0 : if (aNotify) {
1461 : nsNodeUtils::AttributeChanged(this, aNameSpaceID, aName,
1462 0 : nsIDOMMutationEvent::REMOVAL);
1463 : }
1464 :
1465 0 : if (hasMutationListeners) {
1466 0 : nsMutationEvent mutation(true, NS_MUTATION_ATTRMODIFIED);
1467 :
1468 0 : mutation.mRelatedNode = attrNode;
1469 0 : mutation.mAttrName = aName;
1470 :
1471 0 : if (!oldValue.IsEmpty())
1472 0 : mutation.mPrevAttrValue = do_GetAtom(oldValue);
1473 0 : mutation.mAttrChange = nsIDOMMutationEvent::REMOVAL;
1474 :
1475 0 : mozAutoSubtreeModified subtree(OwnerDoc(), this);
1476 0 : (new nsAsyncDOMEvent(this, mutation))->RunDOMEventWhenSafe();
1477 : }
1478 :
1479 0 : return NS_OK;
1480 : }
1481 :
1482 : void
1483 0 : nsXULElement::RemoveBroadcaster(const nsAString & broadcasterId)
1484 : {
1485 0 : nsCOMPtr<nsIDOMXULDocument> xuldoc = do_QueryInterface(OwnerDoc());
1486 0 : if (xuldoc) {
1487 0 : nsCOMPtr<nsIDOMElement> broadcaster;
1488 0 : nsCOMPtr<nsIDOMDocument> domDoc (do_QueryInterface(xuldoc));
1489 0 : domDoc->GetElementById(broadcasterId, getter_AddRefs(broadcaster));
1490 0 : if (broadcaster) {
1491 0 : xuldoc->RemoveBroadcastListenerFor(broadcaster, this,
1492 0 : NS_LITERAL_STRING("*"));
1493 : }
1494 : }
1495 0 : }
1496 :
1497 : const nsAttrName*
1498 2286 : nsXULElement::GetAttrNameAt(PRUint32 aIndex) const
1499 : {
1500 2286 : PRUint32 localCount = mAttrsAndChildren.AttrCount();
1501 2286 : PRUint32 protoCount = mPrototype ? mPrototype->mNumAttributes : 0;
1502 :
1503 2286 : if (localCount > protoCount) {
1504 : // More local than proto, put local first
1505 :
1506 : // Is the index low enough to just grab a local attr?
1507 2286 : if (aIndex < localCount) {
1508 2286 : return mAttrsAndChildren.AttrNameAt(aIndex);
1509 : }
1510 :
1511 0 : aIndex -= localCount;
1512 :
1513 : // Search though prototype attributes while skipping names that exist in
1514 : // the local array.
1515 0 : for (PRUint32 i = 0; i < protoCount; i++) {
1516 0 : const nsAttrName* name = &mPrototype->mAttributes[i].mName;
1517 0 : if (mAttrsAndChildren.GetAttr(name->LocalName(), name->NamespaceID())) {
1518 0 : aIndex++;
1519 : }
1520 0 : if (i == aIndex) {
1521 0 : return name;
1522 : }
1523 : }
1524 : }
1525 : else {
1526 : // More proto than local, put proto first
1527 :
1528 : // Is the index low enough to just grab a proto attr?
1529 0 : if (aIndex < protoCount) {
1530 0 : return &mPrototype->mAttributes[aIndex].mName;
1531 : }
1532 :
1533 0 : aIndex -= protoCount;
1534 :
1535 : // Search though local attributes while skipping names that exist in
1536 : // the prototype array.
1537 0 : for (PRUint32 i = 0; i < localCount; i++) {
1538 0 : const nsAttrName* name = mAttrsAndChildren.AttrNameAt(i);
1539 :
1540 0 : for (PRUint32 j = 0; j < protoCount; j++) {
1541 0 : if (mPrototype->mAttributes[j].mName.Equals(*name)) {
1542 0 : aIndex++;
1543 0 : break;
1544 : }
1545 : }
1546 0 : if (i == aIndex) {
1547 0 : return name;
1548 : }
1549 : }
1550 : }
1551 :
1552 0 : return nsnull;
1553 : }
1554 :
1555 : PRUint32
1556 1964 : nsXULElement::GetAttrCount() const
1557 : {
1558 1964 : PRUint32 localCount = mAttrsAndChildren.AttrCount();
1559 1964 : PRUint32 protoCount = mPrototype ? mPrototype->mNumAttributes : 0;
1560 :
1561 1964 : if (localCount > protoCount) {
1562 : // More local than proto, remove dups from proto array
1563 1964 : PRUint32 count = localCount;
1564 :
1565 1964 : for (PRUint32 i = 0; i < protoCount; i++) {
1566 0 : const nsAttrName* name = &mPrototype->mAttributes[i].mName;
1567 0 : if (!mAttrsAndChildren.GetAttr(name->LocalName(), name->NamespaceID())) {
1568 0 : count++;
1569 : }
1570 : }
1571 :
1572 1964 : return count;
1573 : }
1574 :
1575 : // More proto than local, remove dups from local array
1576 0 : PRUint32 count = protoCount;
1577 :
1578 0 : for (PRUint32 i = 0; i < localCount; i++) {
1579 0 : const nsAttrName* name = mAttrsAndChildren.AttrNameAt(i);
1580 :
1581 0 : count++;
1582 0 : for (PRUint32 j = 0; j < protoCount; j++) {
1583 0 : if (mPrototype->mAttributes[j].mName.Equals(*name)) {
1584 0 : count--;
1585 0 : break;
1586 : }
1587 : }
1588 : }
1589 :
1590 0 : return count;
1591 : }
1592 :
1593 : void
1594 0 : nsXULElement::DestroyContent()
1595 : {
1596 0 : nsXULSlots* slots = static_cast<nsXULSlots*>(GetExistingDOMSlots());
1597 0 : if (slots) {
1598 0 : NS_IF_RELEASE(slots->mControllers);
1599 0 : if (slots->mFrameLoader) {
1600 0 : slots->mFrameLoader->Destroy();
1601 0 : slots->mFrameLoader = nsnull;
1602 : }
1603 : }
1604 :
1605 0 : nsStyledElement::DestroyContent();
1606 0 : }
1607 :
1608 : #ifdef DEBUG
1609 : void
1610 0 : nsXULElement::List(FILE* out, PRInt32 aIndent) const
1611 : {
1612 0 : nsCString prefix("XUL");
1613 0 : if (HasSlots()) {
1614 0 : prefix.Append('*');
1615 : }
1616 0 : prefix.Append(' ');
1617 :
1618 0 : nsStyledElement::List(out, aIndent, prefix);
1619 0 : }
1620 : #endif
1621 :
1622 : nsresult
1623 0 : nsXULElement::PreHandleEvent(nsEventChainPreVisitor& aVisitor)
1624 : {
1625 0 : aVisitor.mForceContentDispatch = true; //FIXME! Bug 329119
1626 0 : nsIAtom* tag = Tag();
1627 0 : if (IsRootOfNativeAnonymousSubtree() &&
1628 : (tag == nsGkAtoms::scrollbar || tag == nsGkAtoms::scrollcorner) &&
1629 : (aVisitor.mEvent->message == NS_MOUSE_CLICK ||
1630 : aVisitor.mEvent->message == NS_MOUSE_DOUBLECLICK ||
1631 : aVisitor.mEvent->message == NS_XUL_COMMAND ||
1632 : aVisitor.mEvent->message == NS_CONTEXTMENU ||
1633 : aVisitor.mEvent->message == NS_DRAGDROP_START ||
1634 : aVisitor.mEvent->message == NS_DRAGDROP_GESTURE)) {
1635 : // Don't propagate these events from native anonymous scrollbar.
1636 0 : aVisitor.mCanHandle = true;
1637 0 : aVisitor.mParentTarget = nsnull;
1638 0 : return NS_OK;
1639 : }
1640 0 : if (aVisitor.mEvent->message == NS_XUL_COMMAND &&
1641 : aVisitor.mEvent->eventStructType == NS_INPUT_EVENT &&
1642 0 : aVisitor.mEvent->originalTarget == static_cast<nsIContent*>(this) &&
1643 : tag != nsGkAtoms::command) {
1644 : // Check that we really have an xul command event. That will be handled
1645 : // in a special way.
1646 : nsCOMPtr<nsIDOMXULCommandEvent> xulEvent =
1647 0 : do_QueryInterface(aVisitor.mDOMEvent);
1648 : // See if we have a command elt. If so, we execute on the command
1649 : // instead of on our content element.
1650 0 : nsAutoString command;
1651 0 : if (xulEvent && GetAttr(kNameSpaceID_None, nsGkAtoms::command, command) &&
1652 0 : !command.IsEmpty()) {
1653 : // Stop building the event target chain for the original event.
1654 : // We don't want it to propagate to any DOM nodes.
1655 0 : aVisitor.mCanHandle = false;
1656 :
1657 : // XXX sXBL/XBL2 issue! Owner or current document?
1658 0 : nsCOMPtr<nsIDOMDocument> domDoc(do_QueryInterface(GetCurrentDoc()));
1659 0 : NS_ENSURE_STATE(domDoc);
1660 0 : nsCOMPtr<nsIDOMElement> commandElt;
1661 0 : domDoc->GetElementById(command, getter_AddRefs(commandElt));
1662 0 : nsCOMPtr<nsIContent> commandContent(do_QueryInterface(commandElt));
1663 0 : if (commandContent) {
1664 : // Create a new command event to dispatch to the element
1665 : // pointed to by the command attribute. The new event's
1666 : // sourceEvent will be the original command event that we're
1667 : // handling.
1668 : nsCOMPtr<nsIDOMNSEvent> nsevent =
1669 0 : do_QueryInterface(aVisitor.mDOMEvent);
1670 0 : while (nsevent) {
1671 0 : nsCOMPtr<nsIDOMEventTarget> oTarget;
1672 0 : nsevent->GetOriginalTarget(getter_AddRefs(oTarget));
1673 0 : NS_ENSURE_STATE(!SameCOMIdentity(oTarget, commandContent));
1674 0 : nsCOMPtr<nsIDOMEvent> tmp;
1675 : nsCOMPtr<nsIDOMXULCommandEvent> commandEvent =
1676 0 : do_QueryInterface(nsevent);
1677 0 : if (commandEvent) {
1678 0 : commandEvent->GetSourceEvent(getter_AddRefs(tmp));
1679 : }
1680 0 : nsevent = do_QueryInterface(tmp);
1681 : }
1682 :
1683 : nsInputEvent* orig =
1684 0 : static_cast<nsInputEvent*>(aVisitor.mEvent);
1685 : nsContentUtils::DispatchXULCommand(
1686 : commandContent,
1687 : NS_IS_TRUSTED_EVENT(aVisitor.mEvent),
1688 : aVisitor.mDOMEvent,
1689 : nsnull,
1690 : orig->isControl,
1691 : orig->isAlt,
1692 : orig->isShift,
1693 0 : orig->isMeta);
1694 : } else {
1695 0 : NS_WARNING("A XUL element is attached to a command that doesn't exist!\n");
1696 : }
1697 0 : return NS_OK;
1698 : }
1699 : }
1700 :
1701 0 : return nsStyledElement::PreHandleEvent(aVisitor);
1702 : }
1703 :
1704 : // XXX This _should_ be an implementation method, _not_ publicly exposed :-(
1705 : NS_IMETHODIMP
1706 0 : nsXULElement::GetResource(nsIRDFResource** aResource)
1707 : {
1708 0 : nsAutoString id;
1709 0 : GetAttr(kNameSpaceID_None, nsGkAtoms::ref, id);
1710 0 : if (id.IsEmpty()) {
1711 0 : GetAttr(kNameSpaceID_None, nsGkAtoms::id, id);
1712 : }
1713 :
1714 0 : if (!id.IsEmpty()) {
1715 0 : return nsXULContentUtils::RDFService()->
1716 0 : GetUnicodeResource(id, aResource);
1717 : }
1718 0 : *aResource = nsnull;
1719 :
1720 0 : return NS_OK;
1721 : }
1722 :
1723 :
1724 : NS_IMETHODIMP
1725 0 : nsXULElement::GetDatabase(nsIRDFCompositeDataSource** aDatabase)
1726 : {
1727 0 : nsCOMPtr<nsIXULTemplateBuilder> builder;
1728 0 : GetBuilder(getter_AddRefs(builder));
1729 :
1730 0 : if (builder)
1731 0 : builder->GetDatabase(aDatabase);
1732 : else
1733 0 : *aDatabase = nsnull;
1734 :
1735 0 : return NS_OK;
1736 : }
1737 :
1738 :
1739 : NS_IMETHODIMP
1740 0 : nsXULElement::GetBuilder(nsIXULTemplateBuilder** aBuilder)
1741 : {
1742 0 : *aBuilder = nsnull;
1743 :
1744 : // XXX sXBL/XBL2 issue! Owner or current document?
1745 0 : nsCOMPtr<nsIXULDocument> xuldoc = do_QueryInterface(GetCurrentDoc());
1746 0 : if (xuldoc)
1747 0 : xuldoc->GetTemplateBuilderFor(this, aBuilder);
1748 :
1749 0 : return NS_OK;
1750 : }
1751 :
1752 :
1753 : //----------------------------------------------------------------------
1754 : // Implementation methods
1755 :
1756 : // XXX DoGetID and DoGetClasses must be defined here because we have proto
1757 : // attributes.
1758 : nsIAtom*
1759 30 : nsXULElement::DoGetID() const
1760 : {
1761 30 : NS_ASSERTION(HasID(), "Unexpected call");
1762 : const nsAttrValue* attr =
1763 30 : FindLocalOrProtoAttr(kNameSpaceID_None, nsGkAtoms::id);
1764 :
1765 : // We need the nullcheck here because during unlink the prototype loses
1766 : // all of its attributes. We might want to change that.
1767 : // The nullcheck would also be needed if we make UnsetAttr use
1768 : // nsGenericElement::UnsetAttr as that calls out to various code between
1769 : // removing the attribute and calling ClearHasID().
1770 :
1771 30 : return attr ? attr->GetAtomValue() : nsnull;
1772 : }
1773 :
1774 : const nsAttrValue*
1775 0 : nsXULElement::DoGetClasses() const
1776 : {
1777 0 : NS_ASSERTION(HasFlag(NODE_MAY_HAVE_CLASS), "Unexpected call");
1778 0 : return FindLocalOrProtoAttr(kNameSpaceID_None, nsGkAtoms::_class);
1779 : }
1780 :
1781 : NS_IMETHODIMP
1782 0 : nsXULElement::WalkContentStyleRules(nsRuleWalker* aRuleWalker)
1783 : {
1784 0 : return NS_OK;
1785 : }
1786 :
1787 : css::StyleRule*
1788 0 : nsXULElement::GetInlineStyleRule()
1789 : {
1790 0 : if (!MayHaveStyle()) {
1791 0 : return nsnull;
1792 : }
1793 : // Fetch the cached style rule from the attributes.
1794 0 : const nsAttrValue* attrVal = FindLocalOrProtoAttr(kNameSpaceID_None, nsGkAtoms::style);
1795 :
1796 0 : if (attrVal && attrVal->Type() == nsAttrValue::eCSSStyleRule) {
1797 0 : return attrVal->GetCSSStyleRuleValue();
1798 : }
1799 :
1800 0 : return nsnull;
1801 : }
1802 :
1803 : nsChangeHint
1804 0 : nsXULElement::GetAttributeChangeHint(const nsIAtom* aAttribute,
1805 : PRInt32 aModType) const
1806 : {
1807 0 : nsChangeHint retval(NS_STYLE_HINT_NONE);
1808 :
1809 0 : if (aAttribute == nsGkAtoms::value &&
1810 : (aModType == nsIDOMMutationEvent::REMOVAL ||
1811 : aModType == nsIDOMMutationEvent::ADDITION)) {
1812 0 : nsIAtom *tag = Tag();
1813 0 : if (tag == nsGkAtoms::label || tag == nsGkAtoms::description)
1814 : // Label and description dynamically morph between a normal
1815 : // block and a cropping single-line XUL text frame. If the
1816 : // value attribute is being added or removed, then we need to
1817 : // return a hint of frame change. (See bugzilla bug 95475 for
1818 : // details.)
1819 0 : retval = NS_STYLE_HINT_FRAMECHANGE;
1820 : } else {
1821 : // if left or top changes we reflow. This will happen in xul
1822 : // containers that manage positioned children such as a stack.
1823 0 : if (nsGkAtoms::left == aAttribute || nsGkAtoms::top == aAttribute ||
1824 : nsGkAtoms::right == aAttribute || nsGkAtoms::bottom == aAttribute ||
1825 : nsGkAtoms::start == aAttribute || nsGkAtoms::end == aAttribute)
1826 0 : retval = NS_STYLE_HINT_REFLOW;
1827 : }
1828 :
1829 0 : return retval;
1830 : }
1831 :
1832 : NS_IMETHODIMP_(bool)
1833 66 : nsXULElement::IsAttributeMapped(const nsIAtom* aAttribute) const
1834 : {
1835 66 : return false;
1836 : }
1837 :
1838 : // Controllers Methods
1839 : NS_IMETHODIMP
1840 0 : nsXULElement::GetControllers(nsIControllers** aResult)
1841 : {
1842 0 : if (! Controllers()) {
1843 0 : nsDOMSlots* slots = DOMSlots();
1844 :
1845 : nsresult rv;
1846 : rv = NS_NewXULControllers(nsnull, NS_GET_IID(nsIControllers),
1847 0 : reinterpret_cast<void**>(&slots->mControllers));
1848 :
1849 0 : NS_ASSERTION(NS_SUCCEEDED(rv), "unable to create a controllers");
1850 0 : if (NS_FAILED(rv)) return rv;
1851 : }
1852 :
1853 0 : *aResult = Controllers();
1854 0 : NS_IF_ADDREF(*aResult);
1855 0 : return NS_OK;
1856 : }
1857 :
1858 : NS_IMETHODIMP
1859 0 : nsXULElement::GetBoxObject(nsIBoxObject** aResult)
1860 : {
1861 0 : *aResult = nsnull;
1862 :
1863 : // XXX sXBL/XBL2 issue! Owner or current document?
1864 0 : return OwnerDoc()->GetBoxObjectFor(this, aResult);
1865 : }
1866 :
1867 : // Methods for setting/getting attributes from nsIDOMXULElement
1868 : #define NS_IMPL_XUL_STRING_ATTR(_method, _atom) \
1869 : NS_IMETHODIMP \
1870 : nsXULElement::Get##_method(nsAString& aReturn) \
1871 : { \
1872 : GetAttr(kNameSpaceID_None, nsGkAtoms::_atom, aReturn); \
1873 : return NS_OK; \
1874 : } \
1875 : NS_IMETHODIMP \
1876 : nsXULElement::Set##_method(const nsAString& aValue) \
1877 : { \
1878 : return SetAttr(kNameSpaceID_None, nsGkAtoms::_atom, aValue, \
1879 : true); \
1880 : }
1881 :
1882 : #define NS_IMPL_XUL_BOOL_ATTR(_method, _atom) \
1883 : NS_IMETHODIMP \
1884 : nsXULElement::Get##_method(bool* aResult) \
1885 : { \
1886 : *aResult = BoolAttrIsTrue(nsGkAtoms::_atom); \
1887 : \
1888 : return NS_OK; \
1889 : } \
1890 : NS_IMETHODIMP \
1891 : nsXULElement::Set##_method(bool aValue) \
1892 : { \
1893 : if (aValue) \
1894 : SetAttr(kNameSpaceID_None, nsGkAtoms::_atom, \
1895 : NS_LITERAL_STRING("true"), true); \
1896 : else \
1897 : UnsetAttr(kNameSpaceID_None, nsGkAtoms::_atom, true); \
1898 : \
1899 : return NS_OK; \
1900 : }
1901 :
1902 :
1903 0 : NS_IMPL_XUL_STRING_ATTR(Id, id)
1904 0 : NS_IMPL_XUL_STRING_ATTR(ClassName, _class)
1905 0 : NS_IMPL_XUL_STRING_ATTR(Align, align)
1906 0 : NS_IMPL_XUL_STRING_ATTR(Dir, dir)
1907 0 : NS_IMPL_XUL_STRING_ATTR(Flex, flex)
1908 0 : NS_IMPL_XUL_STRING_ATTR(FlexGroup, flexgroup)
1909 0 : NS_IMPL_XUL_STRING_ATTR(Ordinal, ordinal)
1910 0 : NS_IMPL_XUL_STRING_ATTR(Orient, orient)
1911 0 : NS_IMPL_XUL_STRING_ATTR(Pack, pack)
1912 0 : NS_IMPL_XUL_BOOL_ATTR(Hidden, hidden)
1913 0 : NS_IMPL_XUL_BOOL_ATTR(Collapsed, collapsed)
1914 0 : NS_IMPL_XUL_BOOL_ATTR(AllowEvents, allowevents)
1915 0 : NS_IMPL_XUL_STRING_ATTR(Observes, observes)
1916 0 : NS_IMPL_XUL_STRING_ATTR(Menu, menu)
1917 0 : NS_IMPL_XUL_STRING_ATTR(ContextMenu, contextmenu)
1918 0 : NS_IMPL_XUL_STRING_ATTR(Tooltip, tooltip)
1919 0 : NS_IMPL_XUL_STRING_ATTR(Width, width)
1920 0 : NS_IMPL_XUL_STRING_ATTR(Height, height)
1921 0 : NS_IMPL_XUL_STRING_ATTR(MinWidth, minwidth)
1922 0 : NS_IMPL_XUL_STRING_ATTR(MinHeight, minheight)
1923 0 : NS_IMPL_XUL_STRING_ATTR(MaxWidth, maxwidth)
1924 0 : NS_IMPL_XUL_STRING_ATTR(MaxHeight, maxheight)
1925 0 : NS_IMPL_XUL_STRING_ATTR(Persist, persist)
1926 0 : NS_IMPL_XUL_STRING_ATTR(Left, left)
1927 0 : NS_IMPL_XUL_STRING_ATTR(Top, top)
1928 0 : NS_IMPL_XUL_STRING_ATTR(Datasources, datasources)
1929 0 : NS_IMPL_XUL_STRING_ATTR(Ref, ref)
1930 0 : NS_IMPL_XUL_STRING_ATTR(TooltipText, tooltiptext)
1931 0 : NS_IMPL_XUL_STRING_ATTR(StatusText, statustext)
1932 :
1933 : nsresult
1934 0 : nsXULElement::EnsureLocalStyle()
1935 : {
1936 : // Clone the prototype rule, if we don't have a local one.
1937 0 : if (mPrototype &&
1938 0 : !mAttrsAndChildren.GetAttr(nsGkAtoms::style, kNameSpaceID_None)) {
1939 :
1940 : nsXULPrototypeAttribute *protoattr =
1941 0 : FindPrototypeAttribute(kNameSpaceID_None, nsGkAtoms::style);
1942 0 : if (protoattr && protoattr->mValue.Type() == nsAttrValue::eCSSStyleRule) {
1943 : nsRefPtr<css::Rule> ruleClone =
1944 0 : protoattr->mValue.GetCSSStyleRuleValue()->Clone();
1945 :
1946 0 : nsString stringValue;
1947 0 : protoattr->mValue.ToString(stringValue);
1948 :
1949 0 : nsAttrValue value;
1950 0 : nsRefPtr<css::StyleRule> styleRule = do_QueryObject(ruleClone);
1951 0 : value.SetTo(styleRule, &stringValue);
1952 :
1953 : nsresult rv =
1954 0 : mAttrsAndChildren.SetAndTakeAttr(nsGkAtoms::style, value);
1955 0 : NS_ENSURE_SUCCESS(rv, rv);
1956 : }
1957 : }
1958 :
1959 0 : return NS_OK;
1960 : }
1961 :
1962 : nsresult
1963 144 : nsXULElement::LoadSrc()
1964 : {
1965 : // Allow frame loader only on objects for which a container box object
1966 : // can be obtained.
1967 144 : nsIAtom* tag = Tag();
1968 144 : if (tag != nsGkAtoms::browser &&
1969 : tag != nsGkAtoms::editor &&
1970 : tag != nsGkAtoms::iframe) {
1971 144 : return NS_OK;
1972 : }
1973 0 : if (!IsInDoc() ||
1974 0 : !OwnerDoc()->GetRootElement() ||
1975 0 : OwnerDoc()->GetRootElement()->
1976 0 : NodeInfo()->Equals(nsGkAtoms::overlay, kNameSpaceID_XUL)) {
1977 0 : return NS_OK;
1978 : }
1979 0 : nsXULSlots* slots = static_cast<nsXULSlots*>(GetSlots());
1980 0 : NS_ENSURE_TRUE(slots, NS_ERROR_OUT_OF_MEMORY);
1981 0 : if (!slots->mFrameLoader) {
1982 : // false as the last parameter so that xul:iframe/browser/editor
1983 : // session history handling works like dynamic html:iframes.
1984 : // Usually xul elements are used in chrome, which doesn't have
1985 : // session history at all.
1986 0 : slots->mFrameLoader = nsFrameLoader::Create(this, false);
1987 0 : NS_ENSURE_TRUE(slots->mFrameLoader, NS_OK);
1988 : }
1989 :
1990 0 : return slots->mFrameLoader->LoadFrame();
1991 : }
1992 :
1993 : nsresult
1994 0 : nsXULElement::GetFrameLoader(nsIFrameLoader **aFrameLoader)
1995 : {
1996 0 : *aFrameLoader = GetFrameLoader().get();
1997 0 : return NS_OK;
1998 : }
1999 :
2000 : already_AddRefed<nsFrameLoader>
2001 0 : nsXULElement::GetFrameLoader()
2002 : {
2003 0 : nsXULSlots* slots = static_cast<nsXULSlots*>(GetExistingSlots());
2004 0 : if (!slots)
2005 0 : return nsnull;
2006 :
2007 0 : nsFrameLoader* loader = slots->mFrameLoader;
2008 0 : NS_IF_ADDREF(loader);
2009 0 : return loader;
2010 : }
2011 :
2012 : nsresult
2013 0 : nsXULElement::SwapFrameLoaders(nsIFrameLoaderOwner* aOtherOwner)
2014 : {
2015 0 : nsCOMPtr<nsIContent> otherContent(do_QueryInterface(aOtherOwner));
2016 0 : NS_ENSURE_TRUE(otherContent, NS_ERROR_NOT_IMPLEMENTED);
2017 :
2018 0 : nsXULElement* otherEl = FromContent(otherContent);
2019 0 : NS_ENSURE_TRUE(otherEl, NS_ERROR_NOT_IMPLEMENTED);
2020 :
2021 0 : if (otherEl == this) {
2022 : // nothing to do
2023 0 : return NS_OK;
2024 : }
2025 :
2026 0 : nsXULSlots *ourSlots = static_cast<nsXULSlots*>(GetExistingDOMSlots());
2027 : nsXULSlots *otherSlots =
2028 0 : static_cast<nsXULSlots*>(otherEl->GetExistingDOMSlots());
2029 0 : if (!ourSlots || !ourSlots->mFrameLoader ||
2030 0 : !otherSlots || !otherSlots->mFrameLoader) {
2031 : // Can't handle swapping when there is nothing to swap... yet.
2032 0 : return NS_ERROR_NOT_IMPLEMENTED;
2033 : }
2034 :
2035 : return
2036 : ourSlots->mFrameLoader->SwapWithOtherLoader(otherSlots->mFrameLoader,
2037 : ourSlots->mFrameLoader,
2038 0 : otherSlots->mFrameLoader);
2039 : }
2040 :
2041 : NS_IMETHODIMP
2042 0 : nsXULElement::GetParentTree(nsIDOMXULMultiSelectControlElement** aTreeElement)
2043 : {
2044 0 : for (nsIContent* current = GetParent(); current;
2045 0 : current = current->GetParent()) {
2046 0 : if (current->NodeInfo()->Equals(nsGkAtoms::listbox,
2047 0 : kNameSpaceID_XUL)) {
2048 0 : CallQueryInterface(current, aTreeElement);
2049 : // XXX returning NS_OK because that's what the code used to do;
2050 : // is that the right thing, though?
2051 :
2052 0 : return NS_OK;
2053 : }
2054 : }
2055 :
2056 0 : return NS_OK;
2057 : }
2058 :
2059 : NS_IMETHODIMP
2060 0 : nsXULElement::Focus()
2061 : {
2062 0 : nsIFocusManager* fm = nsFocusManager::GetFocusManager();
2063 0 : nsCOMPtr<nsIDOMElement> elem = do_QueryObject(this);
2064 0 : return fm ? fm->SetFocus(this, 0) : NS_OK;
2065 : }
2066 :
2067 : NS_IMETHODIMP
2068 0 : nsXULElement::Blur()
2069 : {
2070 0 : if (!ShouldBlur(this))
2071 0 : return NS_OK;
2072 :
2073 0 : nsIDocument* doc = GetCurrentDoc();
2074 0 : if (!doc)
2075 0 : return NS_OK;
2076 :
2077 0 : nsIDOMWindow* win = doc->GetWindow();
2078 0 : nsIFocusManager* fm = nsFocusManager::GetFocusManager();
2079 0 : if (win && fm)
2080 0 : return fm->ClearFocus(win);
2081 0 : return NS_OK;
2082 : }
2083 :
2084 : NS_IMETHODIMP
2085 0 : nsXULElement::Click()
2086 : {
2087 0 : return ClickWithInputSource(nsIDOMMouseEvent::MOZ_SOURCE_UNKNOWN);
2088 : }
2089 :
2090 : nsresult
2091 0 : nsXULElement::ClickWithInputSource(PRUint16 aInputSource)
2092 : {
2093 0 : if (BoolAttrIsTrue(nsGkAtoms::disabled))
2094 0 : return NS_OK;
2095 :
2096 0 : nsCOMPtr<nsIDocument> doc = GetCurrentDoc(); // Strong just in case
2097 0 : if (doc) {
2098 0 : nsCOMPtr<nsIPresShell> shell = doc->GetShell();
2099 0 : if (shell) {
2100 : // strong ref to PresContext so events don't destroy it
2101 0 : nsRefPtr<nsPresContext> context = shell->GetPresContext();
2102 :
2103 0 : bool isCallerChrome = nsContentUtils::IsCallerChrome();
2104 :
2105 : nsMouseEvent eventDown(isCallerChrome, NS_MOUSE_BUTTON_DOWN,
2106 0 : nsnull, nsMouseEvent::eReal);
2107 : nsMouseEvent eventUp(isCallerChrome, NS_MOUSE_BUTTON_UP,
2108 0 : nsnull, nsMouseEvent::eReal);
2109 : nsMouseEvent eventClick(isCallerChrome, NS_MOUSE_CLICK, nsnull,
2110 0 : nsMouseEvent::eReal);
2111 : eventDown.inputSource = eventUp.inputSource = eventClick.inputSource
2112 0 : = aInputSource;
2113 :
2114 : // send mouse down
2115 0 : nsEventStatus status = nsEventStatus_eIgnore;
2116 : nsEventDispatcher::Dispatch(static_cast<nsIContent*>(this),
2117 0 : context, &eventDown, nsnull, &status);
2118 :
2119 : // send mouse up
2120 0 : status = nsEventStatus_eIgnore; // reset status
2121 : nsEventDispatcher::Dispatch(static_cast<nsIContent*>(this),
2122 0 : context, &eventUp, nsnull, &status);
2123 :
2124 : // send mouse click
2125 0 : status = nsEventStatus_eIgnore; // reset status
2126 : nsEventDispatcher::Dispatch(static_cast<nsIContent*>(this),
2127 0 : context, &eventClick, nsnull, &status);
2128 : }
2129 : }
2130 :
2131 : // oncommand is fired when an element is clicked...
2132 0 : return DoCommand();
2133 : }
2134 :
2135 : NS_IMETHODIMP
2136 0 : nsXULElement::DoCommand()
2137 : {
2138 0 : nsCOMPtr<nsIDocument> doc = GetCurrentDoc(); // strong just in case
2139 0 : if (doc) {
2140 0 : nsContentUtils::DispatchXULCommand(this, true);
2141 : }
2142 :
2143 0 : return NS_OK;
2144 : }
2145 :
2146 : nsIContent *
2147 756 : nsXULElement::GetBindingParent() const
2148 : {
2149 756 : return mBindingParent;
2150 : }
2151 :
2152 : bool
2153 750 : nsXULElement::IsNodeOfType(PRUint32 aFlags) const
2154 : {
2155 750 : return !(aFlags & ~eCONTENT);
2156 : }
2157 :
2158 : static void
2159 0 : PopupListenerPropertyDtor(void* aObject, nsIAtom* aPropertyName,
2160 : void* aPropertyValue, void* aData)
2161 : {
2162 : nsIDOMEventListener* listener =
2163 0 : static_cast<nsIDOMEventListener*>(aPropertyValue);
2164 0 : if (!listener) {
2165 0 : return;
2166 : }
2167 : nsEventListenerManager* manager = static_cast<nsINode*>(aObject)->
2168 0 : GetListenerManager(false);
2169 0 : if (manager) {
2170 : manager->RemoveEventListenerByType(listener,
2171 0 : NS_LITERAL_STRING("mousedown"),
2172 : NS_EVENT_FLAG_BUBBLE |
2173 0 : NS_EVENT_FLAG_SYSTEM_EVENT);
2174 : manager->RemoveEventListenerByType(listener,
2175 0 : NS_LITERAL_STRING("contextmenu"),
2176 : NS_EVENT_FLAG_BUBBLE |
2177 0 : NS_EVENT_FLAG_SYSTEM_EVENT);
2178 : }
2179 0 : NS_RELEASE(listener);
2180 : }
2181 :
2182 : nsresult
2183 0 : nsXULElement::AddPopupListener(nsIAtom* aName)
2184 : {
2185 : // Add a popup listener to the element
2186 : bool isContext = (aName == nsGkAtoms::context ||
2187 0 : aName == nsGkAtoms::contextmenu);
2188 : nsIAtom* listenerAtom = isContext ?
2189 : nsGkAtoms::contextmenulistener :
2190 0 : nsGkAtoms::popuplistener;
2191 :
2192 : nsCOMPtr<nsIDOMEventListener> popupListener =
2193 0 : static_cast<nsIDOMEventListener*>(GetProperty(listenerAtom));
2194 0 : if (popupListener) {
2195 : // Popup listener is already installed.
2196 0 : return NS_OK;
2197 : }
2198 :
2199 0 : popupListener = new nsXULPopupListener(this, isContext);
2200 :
2201 : // Add the popup as a listener on this element.
2202 0 : nsEventListenerManager* manager = GetListenerManager(true);
2203 0 : NS_ENSURE_TRUE(manager, NS_ERROR_FAILURE);
2204 : nsresult rv = SetProperty(listenerAtom, popupListener,
2205 0 : PopupListenerPropertyDtor, true);
2206 0 : NS_ENSURE_SUCCESS(rv, rv);
2207 : // Want the property to have a reference to the listener.
2208 0 : nsIDOMEventListener* listener = nsnull;
2209 0 : popupListener.swap(listener);
2210 :
2211 0 : if (isContext) {
2212 : manager->AddEventListenerByType(listener,
2213 0 : NS_LITERAL_STRING("contextmenu"),
2214 : NS_EVENT_FLAG_BUBBLE |
2215 0 : NS_EVENT_FLAG_SYSTEM_EVENT);
2216 : } else {
2217 : manager->AddEventListenerByType(listener,
2218 0 : NS_LITERAL_STRING("mousedown"),
2219 : NS_EVENT_FLAG_BUBBLE |
2220 0 : NS_EVENT_FLAG_SYSTEM_EVENT);
2221 : }
2222 0 : return NS_OK;
2223 : }
2224 :
2225 : nsEventStates
2226 328 : nsXULElement::IntrinsicState() const
2227 : {
2228 328 : nsEventStates state = nsStyledElement::IntrinsicState();
2229 :
2230 328 : if (IsReadWriteTextElement()) {
2231 0 : state |= NS_EVENT_STATE_MOZ_READWRITE;
2232 0 : state &= ~NS_EVENT_STATE_MOZ_READONLY;
2233 : }
2234 :
2235 : return state;
2236 : }
2237 :
2238 : //----------------------------------------------------------------------
2239 :
2240 : nsGenericElement::nsAttrInfo
2241 1253 : nsXULElement::GetAttrInfo(PRInt32 aNamespaceID, nsIAtom *aName) const
2242 : {
2243 :
2244 1253 : nsAttrInfo info(nsStyledElement::GetAttrInfo(aNamespaceID, aName));
2245 1253 : if (!info.mValue) {
2246 : nsXULPrototypeAttribute *protoattr =
2247 405 : FindPrototypeAttribute(aNamespaceID, aName);
2248 405 : if (protoattr) {
2249 0 : return nsAttrInfo(&protoattr->mName, &protoattr->mValue);
2250 : }
2251 : }
2252 :
2253 1253 : return info;
2254 : }
2255 :
2256 :
2257 : nsXULPrototypeAttribute *
2258 407 : nsXULElement::FindPrototypeAttribute(PRInt32 aNamespaceID,
2259 : nsIAtom* aLocalName) const
2260 : {
2261 407 : if (!mPrototype) {
2262 407 : return nsnull;
2263 : }
2264 :
2265 0 : PRUint32 i, count = mPrototype->mNumAttributes;
2266 0 : if (aNamespaceID == kNameSpaceID_None) {
2267 : // Common case so optimize for this
2268 0 : for (i = 0; i < count; ++i) {
2269 0 : nsXULPrototypeAttribute *protoattr = &mPrototype->mAttributes[i];
2270 0 : if (protoattr->mName.Equals(aLocalName)) {
2271 0 : return protoattr;
2272 : }
2273 : }
2274 : }
2275 : else {
2276 0 : for (i = 0; i < count; ++i) {
2277 0 : nsXULPrototypeAttribute *protoattr = &mPrototype->mAttributes[i];
2278 0 : if (protoattr->mName.Equals(aLocalName, aNamespaceID)) {
2279 0 : return protoattr;
2280 : }
2281 : }
2282 : }
2283 :
2284 0 : return nsnull;
2285 : }
2286 :
2287 0 : nsresult nsXULElement::MakeHeavyweight()
2288 : {
2289 0 : if (!mPrototype)
2290 0 : return NS_OK; // already heavyweight
2291 :
2292 0 : nsRefPtr<nsXULPrototypeElement> proto;
2293 0 : proto.swap(mPrototype);
2294 :
2295 0 : bool hadAttributes = mAttrsAndChildren.AttrCount() > 0;
2296 :
2297 : PRUint32 i;
2298 : nsresult rv;
2299 0 : for (i = 0; i < proto->mNumAttributes; ++i) {
2300 0 : nsXULPrototypeAttribute* protoattr = &proto->mAttributes[i];
2301 :
2302 : // We might have a local value for this attribute, in which case
2303 : // we don't want to copy the prototype's value.
2304 0 : if (hadAttributes &&
2305 : mAttrsAndChildren.GetAttr(protoattr->mName.LocalName(),
2306 0 : protoattr->mName.NamespaceID())) {
2307 0 : continue;
2308 : }
2309 :
2310 0 : nsAttrValue attrValue;
2311 :
2312 : // Style rules need to be cloned.
2313 0 : if (protoattr->mValue.Type() == nsAttrValue::eCSSStyleRule) {
2314 : nsRefPtr<css::Rule> ruleClone =
2315 0 : protoattr->mValue.GetCSSStyleRuleValue()->Clone();
2316 :
2317 0 : nsString stringValue;
2318 0 : protoattr->mValue.ToString(stringValue);
2319 :
2320 0 : nsRefPtr<css::StyleRule> styleRule = do_QueryObject(ruleClone);
2321 0 : attrValue.SetTo(styleRule, &stringValue);
2322 : }
2323 : else {
2324 0 : attrValue.SetTo(protoattr->mValue);
2325 : }
2326 :
2327 : // XXX we might wanna have a SetAndTakeAttr that takes an nsAttrName
2328 0 : if (protoattr->mName.IsAtom()) {
2329 0 : rv = mAttrsAndChildren.SetAndTakeAttr(protoattr->mName.Atom(), attrValue);
2330 : }
2331 : else {
2332 : rv = mAttrsAndChildren.SetAndTakeAttr(protoattr->mName.NodeInfo(),
2333 0 : attrValue);
2334 : }
2335 0 : NS_ENSURE_SUCCESS(rv, rv);
2336 : }
2337 0 : return NS_OK;
2338 : }
2339 :
2340 : nsresult
2341 0 : nsXULElement::HideWindowChrome(bool aShouldHide)
2342 : {
2343 0 : nsIDocument* doc = GetCurrentDoc();
2344 0 : if (!doc || doc->GetRootElement() != this)
2345 0 : return NS_ERROR_UNEXPECTED;
2346 :
2347 : // only top level chrome documents can hide the window chrome
2348 0 : if (!doc->IsRootDisplayDocument())
2349 0 : return NS_OK;
2350 :
2351 0 : nsIPresShell *shell = doc->GetShell();
2352 :
2353 0 : if (shell) {
2354 0 : nsIFrame* frame = GetPrimaryFrame();
2355 :
2356 0 : nsPresContext *presContext = shell->GetPresContext();
2357 :
2358 0 : if (frame && presContext && presContext->IsChrome()) {
2359 0 : nsIView* view = frame->GetClosestView();
2360 :
2361 0 : if (view) {
2362 0 : nsIWidget* w = view->GetWidget();
2363 0 : NS_ENSURE_STATE(w);
2364 0 : w->HideWindowChrome(aShouldHide);
2365 : }
2366 : }
2367 : }
2368 :
2369 0 : return NS_OK;
2370 : }
2371 :
2372 : nsIWidget*
2373 0 : nsXULElement::GetWindowWidget()
2374 : {
2375 0 : nsIDocument* doc = GetCurrentDoc();
2376 :
2377 : // only top level chrome documents can set the titlebar color
2378 0 : if (doc->IsRootDisplayDocument()) {
2379 0 : nsCOMPtr<nsISupports> container = doc->GetContainer();
2380 0 : nsCOMPtr<nsIBaseWindow> baseWindow = do_QueryInterface(container);
2381 0 : if (baseWindow) {
2382 0 : nsCOMPtr<nsIWidget> mainWidget;
2383 0 : baseWindow->GetMainWidget(getter_AddRefs(mainWidget));
2384 0 : return mainWidget;
2385 : }
2386 : }
2387 0 : return nsnull;
2388 : }
2389 :
2390 : void
2391 0 : nsXULElement::SetTitlebarColor(nscolor aColor, bool aActive)
2392 : {
2393 0 : nsIWidget* mainWidget = GetWindowWidget();
2394 0 : if (mainWidget) {
2395 0 : mainWidget->SetWindowTitlebarColor(aColor, aActive);
2396 : }
2397 0 : }
2398 :
2399 : class SetDrawInTitleBarEvent : public nsRunnable
2400 0 : {
2401 : public:
2402 0 : SetDrawInTitleBarEvent(nsIWidget* aWidget, bool aState)
2403 : : mWidget(aWidget)
2404 0 : , mState(aState)
2405 0 : {}
2406 :
2407 0 : NS_IMETHOD Run() {
2408 0 : NS_ASSERTION(mWidget, "You shouldn't call this runnable with a null widget!");
2409 :
2410 0 : mWidget->SetDrawsInTitlebar(mState);
2411 0 : return NS_OK;
2412 : }
2413 :
2414 : private:
2415 : nsCOMPtr<nsIWidget> mWidget;
2416 : bool mState;
2417 : };
2418 :
2419 : void
2420 0 : nsXULElement::SetDrawsInTitlebar(bool aState)
2421 : {
2422 0 : nsIWidget* mainWidget = GetWindowWidget();
2423 0 : if (mainWidget) {
2424 0 : nsContentUtils::AddScriptRunner(new SetDrawInTitleBarEvent(mainWidget, aState));
2425 : }
2426 0 : }
2427 :
2428 : class MarginSetter : public nsRunnable
2429 0 : {
2430 : public:
2431 0 : MarginSetter(nsIWidget* aWidget) :
2432 0 : mWidget(aWidget), mMargin(-1, -1, -1, -1)
2433 0 : {}
2434 0 : MarginSetter(nsIWidget *aWidget, const nsIntMargin& aMargin) :
2435 0 : mWidget(aWidget), mMargin(aMargin)
2436 0 : {}
2437 :
2438 0 : NS_IMETHOD Run()
2439 : {
2440 : // SetNonClientMargins can dispatch native events, hence doing
2441 : // it off a script runner.
2442 0 : mWidget->SetNonClientMargins(mMargin);
2443 0 : return NS_OK;
2444 : }
2445 :
2446 : private:
2447 : nsCOMPtr<nsIWidget> mWidget;
2448 : nsIntMargin mMargin;
2449 : };
2450 :
2451 : void
2452 0 : nsXULElement::SetChromeMargins(const nsAttrValue* aValue)
2453 : {
2454 0 : if (!aValue)
2455 0 : return;
2456 :
2457 0 : nsIWidget* mainWidget = GetWindowWidget();
2458 0 : if (!mainWidget)
2459 0 : return;
2460 :
2461 : // top, right, bottom, left - see nsAttrValue
2462 0 : nsIntMargin margins;
2463 0 : bool gotMargins = false;
2464 :
2465 0 : if (aValue->Type() == nsAttrValue::eIntMarginValue) {
2466 0 : gotMargins = aValue->GetIntMarginValue(margins);
2467 : } else {
2468 0 : nsAutoString tmp;
2469 0 : aValue->ToString(tmp);
2470 0 : gotMargins = nsContentUtils::ParseIntMarginValue(tmp, margins);
2471 : }
2472 0 : if (gotMargins) {
2473 0 : nsContentUtils::AddScriptRunner(new MarginSetter(mainWidget, margins));
2474 : }
2475 : }
2476 :
2477 : void
2478 0 : nsXULElement::ResetChromeMargins()
2479 : {
2480 0 : nsIWidget* mainWidget = GetWindowWidget();
2481 0 : if (!mainWidget)
2482 0 : return;
2483 : // See nsIWidget
2484 0 : nsContentUtils::AddScriptRunner(new MarginSetter(mainWidget));
2485 : }
2486 :
2487 : bool
2488 0 : nsXULElement::BoolAttrIsTrue(nsIAtom* aName)
2489 : {
2490 : const nsAttrValue* attr =
2491 0 : FindLocalOrProtoAttr(kNameSpaceID_None, aName);
2492 :
2493 0 : return attr && attr->Type() == nsAttrValue::eAtom &&
2494 0 : attr->GetAtomValue() == nsGkAtoms::_true;
2495 : }
2496 :
2497 : void
2498 0 : nsXULElement::RecompileScriptEventListeners()
2499 : {
2500 0 : PRInt32 i, count = mAttrsAndChildren.AttrCount();
2501 0 : bool haveLocalAttributes = (count > 0);
2502 0 : for (i = 0; i < count; ++i) {
2503 0 : const nsAttrName *name = mAttrsAndChildren.AttrNameAt(i);
2504 :
2505 : // Eventlistenener-attributes are always in the null namespace
2506 0 : if (!name->IsAtom()) {
2507 0 : continue;
2508 : }
2509 :
2510 0 : nsIAtom *attr = name->Atom();
2511 0 : if (!nsContentUtils::IsEventAttributeName(attr, EventNameType_XUL)) {
2512 0 : continue;
2513 : }
2514 :
2515 0 : nsAutoString value;
2516 0 : GetAttr(kNameSpaceID_None, attr, value);
2517 0 : AddScriptEventListener(attr, value, true);
2518 : }
2519 :
2520 0 : if (mPrototype) {
2521 : // If we have a prototype, the node we are binding to should
2522 : // have the same script-type - otherwise we will compile the
2523 : // event handlers incorrectly.
2524 0 : NS_ASSERTION(mPrototype->mScriptTypeID == GetScriptTypeID(),
2525 : "Prototype and node confused about default language?");
2526 :
2527 0 : count = mPrototype->mNumAttributes;
2528 0 : for (i = 0; i < count; ++i) {
2529 0 : const nsAttrName &name = mPrototype->mAttributes[i].mName;
2530 :
2531 : // Eventlistenener-attributes are always in the null namespace
2532 0 : if (!name.IsAtom()) {
2533 0 : continue;
2534 : }
2535 :
2536 0 : nsIAtom *attr = name.Atom();
2537 :
2538 : // Don't clobber a locally modified attribute.
2539 0 : if (haveLocalAttributes && mAttrsAndChildren.GetAttr(attr)) {
2540 0 : continue;
2541 : }
2542 :
2543 0 : if (!nsContentUtils::IsEventAttributeName(attr, EventNameType_XUL)) {
2544 0 : continue;
2545 : }
2546 :
2547 0 : nsAutoString value;
2548 0 : GetAttr(kNameSpaceID_None, attr, value);
2549 0 : AddScriptEventListener(attr, value, true);
2550 : }
2551 : }
2552 0 : }
2553 :
2554 1464 : NS_IMPL_CYCLE_COLLECTION_CLASS(nsXULPrototypeNode)
2555 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsXULPrototypeNode)
2556 0 : if (tmp->mType == nsXULPrototypeNode::eType_Element) {
2557 0 : static_cast<nsXULPrototypeElement*>(tmp)->Unlink();
2558 : }
2559 0 : else if (tmp->mType == nsXULPrototypeNode::eType_Script) {
2560 0 : static_cast<nsXULPrototypeScript*>(tmp)->UnlinkJSObjects();
2561 : }
2562 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
2563 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsXULPrototypeNode)
2564 0 : if (tmp->mType == nsXULPrototypeNode::eType_Element) {
2565 : nsXULPrototypeElement *elem =
2566 0 : static_cast<nsXULPrototypeElement*>(tmp);
2567 0 : NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mNodeInfo");
2568 0 : cb.NoteXPCOMChild(elem->mNodeInfo);
2569 : PRUint32 i;
2570 0 : for (i = 0; i < elem->mNumAttributes; ++i) {
2571 0 : const nsAttrName& name = elem->mAttributes[i].mName;
2572 0 : if (!name.IsAtom()) {
2573 0 : NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb,
2574 : "mAttributes[i].mName.NodeInfo()");
2575 0 : cb.NoteXPCOMChild(name.NodeInfo());
2576 : }
2577 : }
2578 0 : for (i = 0; i < elem->mChildren.Length(); ++i) {
2579 0 : NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mChildren[i]");
2580 0 : cb.NoteXPCOMChild(elem->mChildren[i]);
2581 : }
2582 : }
2583 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
2584 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
2585 0 : NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsXULPrototypeNode)
2586 0 : if (tmp->mType == nsXULPrototypeNode::eType_Element) {
2587 : nsXULPrototypeElement *elem =
2588 0 : static_cast<nsXULPrototypeElement*>(tmp);
2589 0 : if (elem->mHoldsScriptObject) {
2590 : PRUint32 i;
2591 0 : for (i = 0; i < elem->mNumAttributes; ++i) {
2592 0 : JSObject* handler = elem->mAttributes[i].mEventHandler;
2593 0 : NS_IMPL_CYCLE_COLLECTION_TRACE_CALLBACK(elem->mScriptTypeID,
2594 : handler,
2595 : "mAttributes[i].mEventHandler")
2596 : }
2597 : }
2598 : }
2599 0 : else if (tmp->mType == nsXULPrototypeNode::eType_Script) {
2600 : nsXULPrototypeScript *script =
2601 0 : static_cast<nsXULPrototypeScript*>(tmp);
2602 0 : NS_IMPL_CYCLE_COLLECTION_TRACE_CALLBACK(script->mScriptObject.mLangID,
2603 : script->mScriptObject.mObject,
2604 : "mScriptObject.mObject")
2605 : }
2606 0 : NS_IMPL_CYCLE_COLLECTION_TRACE_END
2607 :
2608 0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(nsXULPrototypeNode)
2609 0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(nsXULPrototypeNode)
2610 :
2611 0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsXULPrototypeNode)
2612 0 : NS_INTERFACE_MAP_ENTRY(nsISupports)
2613 0 : NS_INTERFACE_MAP_END
2614 :
2615 : //----------------------------------------------------------------------
2616 : //
2617 : // nsXULPrototypeAttribute
2618 : //
2619 :
2620 0 : nsXULPrototypeAttribute::~nsXULPrototypeAttribute()
2621 : {
2622 0 : MOZ_COUNT_DTOR(nsXULPrototypeAttribute);
2623 0 : }
2624 :
2625 :
2626 : //----------------------------------------------------------------------
2627 : //
2628 : // nsXULPrototypeElement
2629 : //
2630 :
2631 : nsresult
2632 0 : nsXULPrototypeElement::Serialize(nsIObjectOutputStream* aStream,
2633 : nsIScriptGlobalObject* aGlobal,
2634 : const nsCOMArray<nsINodeInfo> *aNodeInfos)
2635 : {
2636 : nsresult rv;
2637 :
2638 : // Write basic prototype data
2639 0 : rv = aStream->Write32(mType);
2640 :
2641 : // Write script language
2642 0 : rv |= aStream->Write32(mScriptTypeID);
2643 :
2644 : // Write Node Info
2645 0 : PRInt32 index = aNodeInfos->IndexOf(mNodeInfo);
2646 0 : NS_ASSERTION(index >= 0, "unknown nsINodeInfo index");
2647 0 : rv |= aStream->Write32(index);
2648 :
2649 : // Write Attributes
2650 0 : rv |= aStream->Write32(mNumAttributes);
2651 :
2652 0 : nsAutoString attributeValue;
2653 : PRUint32 i;
2654 0 : for (i = 0; i < mNumAttributes; ++i) {
2655 0 : nsCOMPtr<nsINodeInfo> ni;
2656 0 : if (mAttributes[i].mName.IsAtom()) {
2657 : ni = mNodeInfo->NodeInfoManager()->
2658 0 : GetNodeInfo(mAttributes[i].mName.Atom(), nsnull,
2659 : kNameSpaceID_None,
2660 0 : nsIDOMNode::ATTRIBUTE_NODE);
2661 0 : NS_ASSERTION(ni, "the nodeinfo should already exist");
2662 : }
2663 : else {
2664 0 : ni = mAttributes[i].mName.NodeInfo();
2665 : }
2666 :
2667 0 : index = aNodeInfos->IndexOf(ni);
2668 0 : NS_ASSERTION(index >= 0, "unknown nsINodeInfo index");
2669 0 : rv |= aStream->Write32(index);
2670 :
2671 0 : mAttributes[i].mValue.ToString(attributeValue);
2672 0 : rv |= aStream->WriteWStringZ(attributeValue.get());
2673 : }
2674 :
2675 : // Now write children
2676 0 : rv |= aStream->Write32(PRUint32(mChildren.Length()));
2677 0 : for (i = 0; i < mChildren.Length(); i++) {
2678 0 : nsXULPrototypeNode* child = mChildren[i].get();
2679 0 : switch (child->mType) {
2680 : case eType_Element:
2681 : case eType_Text:
2682 : case eType_PI:
2683 0 : rv |= child->Serialize(aStream, aGlobal, aNodeInfos);
2684 0 : break;
2685 : case eType_Script:
2686 0 : rv |= aStream->Write32(child->mType);
2687 0 : nsXULPrototypeScript* script = static_cast<nsXULPrototypeScript*>(child);
2688 :
2689 0 : rv |= aStream->Write32(script->mScriptObject.mLangID);
2690 :
2691 0 : rv |= aStream->Write8(script->mOutOfLine);
2692 0 : if (! script->mOutOfLine) {
2693 0 : rv |= script->Serialize(aStream, aGlobal, aNodeInfos);
2694 : } else {
2695 : rv |= aStream->WriteCompoundObject(script->mSrcURI,
2696 : NS_GET_IID(nsIURI),
2697 0 : true);
2698 :
2699 0 : if (script->mScriptObject.mObject) {
2700 : // This may return NS_OK without muxing script->mSrcURI's
2701 : // data into the cache file, in the case where that
2702 : // muxed document is already there (written by a prior
2703 : // session, or by an earlier cache episode during this
2704 : // session).
2705 0 : rv |= script->SerializeOutOfLine(aStream, aGlobal);
2706 : }
2707 : }
2708 0 : break;
2709 : }
2710 : }
2711 :
2712 0 : return rv;
2713 : }
2714 :
2715 : nsresult
2716 0 : nsXULPrototypeElement::Deserialize(nsIObjectInputStream* aStream,
2717 : nsIScriptGlobalObject* aGlobal,
2718 : nsIURI* aDocumentURI,
2719 : const nsCOMArray<nsINodeInfo> *aNodeInfos)
2720 : {
2721 0 : NS_PRECONDITION(aNodeInfos, "missing nodeinfo array");
2722 : nsresult rv;
2723 :
2724 : // Read script language
2725 0 : PRUint32 scriptId = 0;
2726 0 : rv = aStream->Read32(&scriptId);
2727 0 : mScriptTypeID = scriptId;
2728 :
2729 : // Read Node Info
2730 : PRUint32 number;
2731 0 : rv |= aStream->Read32(&number);
2732 0 : mNodeInfo = aNodeInfos->SafeObjectAt(number);
2733 0 : if (!mNodeInfo)
2734 0 : return NS_ERROR_UNEXPECTED;
2735 :
2736 : // Read Attributes
2737 0 : rv |= aStream->Read32(&number);
2738 0 : mNumAttributes = PRInt32(number);
2739 :
2740 : PRUint32 i;
2741 0 : if (mNumAttributes > 0) {
2742 0 : mAttributes = new nsXULPrototypeAttribute[mNumAttributes];
2743 0 : if (! mAttributes)
2744 0 : return NS_ERROR_OUT_OF_MEMORY;
2745 :
2746 0 : nsAutoString attributeValue;
2747 0 : for (i = 0; i < mNumAttributes; ++i) {
2748 0 : rv |= aStream->Read32(&number);
2749 0 : nsINodeInfo* ni = aNodeInfos->SafeObjectAt(number);
2750 0 : if (!ni)
2751 0 : return NS_ERROR_UNEXPECTED;
2752 :
2753 0 : mAttributes[i].mName.SetTo(ni);
2754 :
2755 0 : rv |= aStream->ReadString(attributeValue);
2756 0 : rv |= SetAttrAt(i, attributeValue, aDocumentURI);
2757 : }
2758 : }
2759 :
2760 0 : rv |= aStream->Read32(&number);
2761 0 : PRUint32 numChildren = PRInt32(number);
2762 :
2763 0 : if (numChildren > 0) {
2764 0 : if (!mChildren.SetCapacity(numChildren))
2765 0 : return NS_ERROR_OUT_OF_MEMORY;
2766 :
2767 0 : for (i = 0; i < numChildren; i++) {
2768 0 : rv |= aStream->Read32(&number);
2769 0 : Type childType = (Type)number;
2770 :
2771 0 : nsRefPtr<nsXULPrototypeNode> child;
2772 :
2773 0 : switch (childType) {
2774 : case eType_Element:
2775 0 : child = new nsXULPrototypeElement();
2776 0 : if (! child)
2777 0 : return NS_ERROR_OUT_OF_MEMORY;
2778 0 : child->mType = childType;
2779 :
2780 0 : rv |= child->Deserialize(aStream, aGlobal, aDocumentURI,
2781 0 : aNodeInfos);
2782 0 : break;
2783 : case eType_Text:
2784 0 : child = new nsXULPrototypeText();
2785 0 : if (! child)
2786 0 : return NS_ERROR_OUT_OF_MEMORY;
2787 0 : child->mType = childType;
2788 :
2789 0 : rv |= child->Deserialize(aStream, aGlobal, aDocumentURI,
2790 0 : aNodeInfos);
2791 0 : break;
2792 : case eType_PI:
2793 0 : child = new nsXULPrototypePI();
2794 0 : if (! child)
2795 0 : return NS_ERROR_OUT_OF_MEMORY;
2796 0 : child->mType = childType;
2797 :
2798 0 : rv |= child->Deserialize(aStream, aGlobal, aDocumentURI,
2799 0 : aNodeInfos);
2800 0 : break;
2801 : case eType_Script: {
2802 0 : PRUint32 langID = nsIProgrammingLanguage::UNKNOWN;
2803 0 : rv |= aStream->Read32(&langID);
2804 :
2805 : // language version/options obtained during deserialization.
2806 0 : nsXULPrototypeScript* script = new nsXULPrototypeScript(langID, 0, 0);
2807 0 : if (! script)
2808 0 : return NS_ERROR_OUT_OF_MEMORY;
2809 0 : child = script;
2810 0 : child->mType = childType;
2811 :
2812 0 : rv |= aStream->ReadBoolean(&script->mOutOfLine);
2813 0 : if (! script->mOutOfLine) {
2814 : rv |= script->Deserialize(aStream, aGlobal, aDocumentURI,
2815 0 : aNodeInfos);
2816 : } else {
2817 0 : rv |= aStream->ReadObject(true, getter_AddRefs(script->mSrcURI));
2818 :
2819 0 : rv |= script->DeserializeOutOfLine(aStream, aGlobal);
2820 : }
2821 : // If we failed to deserialize, consider deleting 'script'?
2822 0 : break;
2823 : }
2824 : default:
2825 0 : NS_NOTREACHED("Unexpected child type!");
2826 0 : rv = NS_ERROR_UNEXPECTED;
2827 : }
2828 :
2829 0 : mChildren.AppendElement(child);
2830 :
2831 : // Oh dear. Something failed during the deserialization.
2832 : // We don't know what. But likely consequences of failed
2833 : // deserializations included calls to |AbortCaching| which
2834 : // shuts down the cache and closes our streams.
2835 : // If that happens, next time through this loop, we die a messy
2836 : // death. So, let's just fail now, and propagate that failure
2837 : // upward so that the ChromeProtocolHandler knows it can't use
2838 : // a cached chrome channel for this.
2839 0 : if (NS_FAILED(rv))
2840 0 : return rv;
2841 : }
2842 : }
2843 :
2844 0 : return rv;
2845 : }
2846 :
2847 : nsresult
2848 0 : nsXULPrototypeElement::SetAttrAt(PRUint32 aPos, const nsAString& aValue,
2849 : nsIURI* aDocumentURI)
2850 : {
2851 0 : NS_PRECONDITION(aPos < mNumAttributes, "out-of-bounds");
2852 :
2853 : // WARNING!!
2854 : // This code is largely duplicated in nsXULElement::SetAttr.
2855 : // Any changes should be made to both functions.
2856 :
2857 0 : if (!mNodeInfo->NamespaceEquals(kNameSpaceID_XUL)) {
2858 0 : mAttributes[aPos].mValue.ParseStringOrAtom(aValue);
2859 :
2860 0 : return NS_OK;
2861 : }
2862 :
2863 0 : if (mAttributes[aPos].mName.Equals(nsGkAtoms::id) &&
2864 0 : !aValue.IsEmpty()) {
2865 0 : mHasIdAttribute = true;
2866 : // Store id as atom.
2867 : // id="" means that the element has no id. Not that it has
2868 : // emptystring as id.
2869 0 : mAttributes[aPos].mValue.ParseAtom(aValue);
2870 :
2871 0 : return NS_OK;
2872 : }
2873 0 : else if (mAttributes[aPos].mName.Equals(nsGkAtoms::_class)) {
2874 0 : mHasClassAttribute = true;
2875 : // Compute the element's class list
2876 0 : mAttributes[aPos].mValue.ParseAtomArray(aValue);
2877 :
2878 0 : return NS_OK;
2879 : }
2880 0 : else if (mAttributes[aPos].mName.Equals(nsGkAtoms::style)) {
2881 0 : mHasStyleAttribute = true;
2882 : // Parse the element's 'style' attribute
2883 0 : nsRefPtr<css::StyleRule> rule;
2884 :
2885 0 : nsCSSParser parser;
2886 :
2887 : // XXX Get correct Base URI (need GetBaseURI on *prototype* element)
2888 : parser.ParseStyleAttribute(aValue, aDocumentURI, aDocumentURI,
2889 : // This is basically duplicating what
2890 : // nsINode::NodePrincipal() does
2891 : mNodeInfo->NodeInfoManager()->
2892 : DocumentPrincipal(),
2893 0 : getter_AddRefs(rule));
2894 0 : if (rule) {
2895 0 : mAttributes[aPos].mValue.SetTo(rule, &aValue);
2896 :
2897 0 : return NS_OK;
2898 : }
2899 : // Don't abort if parsing failed, it could just be malformed css.
2900 : }
2901 :
2902 0 : mAttributes[aPos].mValue.ParseStringOrAtom(aValue);
2903 :
2904 0 : return NS_OK;
2905 : }
2906 :
2907 : void
2908 0 : nsXULPrototypeElement::Unlink()
2909 : {
2910 0 : if (mHoldsScriptObject) {
2911 : nsContentUtils::DropScriptObjects(mScriptTypeID, this,
2912 0 : &NS_CYCLE_COLLECTION_NAME(nsXULPrototypeNode));
2913 0 : mHoldsScriptObject = false;
2914 : }
2915 0 : mNumAttributes = 0;
2916 0 : delete[] mAttributes;
2917 0 : mAttributes = nsnull;
2918 0 : }
2919 :
2920 : //----------------------------------------------------------------------
2921 : //
2922 : // nsXULPrototypeScript
2923 : //
2924 :
2925 0 : nsXULPrototypeScript::nsXULPrototypeScript(PRUint32 aLangID, PRUint32 aLineNo, PRUint32 aVersion)
2926 : : nsXULPrototypeNode(eType_Script),
2927 : mLineNo(aLineNo),
2928 : mSrcLoading(false),
2929 : mOutOfLine(true),
2930 : mSrcLoadWaiters(nsnull),
2931 : mLangVersion(aVersion),
2932 0 : mScriptObject(aLangID)
2933 : {
2934 0 : NS_ASSERTION(aLangID != nsIProgrammingLanguage::UNKNOWN,
2935 : "The language ID must be known and constant");
2936 0 : }
2937 :
2938 :
2939 0 : nsXULPrototypeScript::~nsXULPrototypeScript()
2940 : {
2941 0 : UnlinkJSObjects();
2942 0 : }
2943 :
2944 : nsresult
2945 0 : nsXULPrototypeScript::Serialize(nsIObjectOutputStream* aStream,
2946 : nsIScriptGlobalObject* aGlobal,
2947 : const nsCOMArray<nsINodeInfo> *aNodeInfos)
2948 : {
2949 : nsIScriptContext *context = aGlobal->GetScriptContext(
2950 0 : mScriptObject.mLangID);
2951 0 : NS_ASSERTION(!mSrcLoading || mSrcLoadWaiters != nsnull ||
2952 : !mScriptObject.mObject,
2953 : "script source still loading when serializing?!");
2954 0 : if (!mScriptObject.mObject)
2955 0 : return NS_ERROR_FAILURE;
2956 :
2957 : // Write basic prototype data
2958 : nsresult rv;
2959 0 : rv = aStream->Write32(mLineNo);
2960 0 : if (NS_FAILED(rv)) return rv;
2961 0 : rv = aStream->Write32(mLangVersion);
2962 0 : if (NS_FAILED(rv)) return rv;
2963 : // And delegate the writing to the nsIScriptContext
2964 0 : rv = context->Serialize(aStream, mScriptObject.mObject);
2965 0 : if (NS_FAILED(rv)) return rv;
2966 :
2967 0 : return NS_OK;
2968 : }
2969 :
2970 : nsresult
2971 0 : nsXULPrototypeScript::SerializeOutOfLine(nsIObjectOutputStream* aStream,
2972 : nsIScriptGlobalObject* aGlobal)
2973 : {
2974 0 : nsresult rv = NS_ERROR_NOT_IMPLEMENTED;
2975 :
2976 0 : bool isChrome = false;
2977 0 : if (NS_FAILED(mSrcURI->SchemeIs("chrome", &isChrome)) || !isChrome)
2978 : // Don't cache scripts that don't come from chrome uris.
2979 0 : return rv;
2980 :
2981 0 : nsXULPrototypeCache* cache = nsXULPrototypeCache::GetInstance();
2982 0 : if (!cache)
2983 0 : return NS_ERROR_OUT_OF_MEMORY;
2984 :
2985 0 : NS_ASSERTION(cache->IsEnabled(),
2986 : "writing to the cache file, but the XUL cache is off?");
2987 : bool exists;
2988 0 : cache->HasData(mSrcURI, &exists);
2989 :
2990 :
2991 : /* return will be NS_OK from GetAsciiSpec.
2992 : * that makes no sense.
2993 : * nor does returning NS_OK from HasMuxedDocument.
2994 : * XXX return something meaningful.
2995 : */
2996 0 : if (exists)
2997 0 : return NS_OK;
2998 :
2999 0 : nsCOMPtr<nsIObjectOutputStream> oos;
3000 0 : rv = cache->GetOutputStream(mSrcURI, getter_AddRefs(oos));
3001 0 : NS_ENSURE_SUCCESS(rv, rv);
3002 :
3003 0 : rv |= Serialize(oos, aGlobal, nsnull);
3004 0 : rv |= cache->FinishOutputStream(mSrcURI);
3005 :
3006 0 : if (NS_FAILED(rv))
3007 0 : cache->AbortCaching();
3008 0 : return rv;
3009 : }
3010 :
3011 :
3012 : nsresult
3013 0 : nsXULPrototypeScript::Deserialize(nsIObjectInputStream* aStream,
3014 : nsIScriptGlobalObject* aGlobal,
3015 : nsIURI* aDocumentURI,
3016 : const nsCOMArray<nsINodeInfo> *aNodeInfos)
3017 : {
3018 : nsresult rv;
3019 :
3020 0 : NS_ASSERTION(!mSrcLoading || mSrcLoadWaiters != nsnull ||
3021 : !mScriptObject.mObject,
3022 : "prototype script not well-initialized when deserializing?!");
3023 :
3024 : // Read basic prototype data
3025 0 : aStream->Read32(&mLineNo);
3026 0 : aStream->Read32(&mLangVersion);
3027 :
3028 : nsIScriptContext *context = aGlobal->GetScriptContext(
3029 0 : mScriptObject.mLangID);
3030 0 : NS_ASSERTION(context != nsnull, "Have no context for deserialization");
3031 0 : NS_ENSURE_TRUE(context, NS_ERROR_UNEXPECTED);
3032 0 : nsScriptObjectHolder<JSScript> newScriptObject(context);
3033 0 : rv = context->Deserialize(aStream, newScriptObject);
3034 0 : if (NS_FAILED(rv)) {
3035 0 : NS_WARNING("Language deseralization failed");
3036 0 : return rv;
3037 : }
3038 0 : Set(newScriptObject);
3039 0 : return NS_OK;
3040 : }
3041 :
3042 :
3043 : nsresult
3044 0 : nsXULPrototypeScript::DeserializeOutOfLine(nsIObjectInputStream* aInput,
3045 : nsIScriptGlobalObject* aGlobal)
3046 : {
3047 : // Keep track of failure via rv, so we can
3048 : // AbortCaching if things look bad.
3049 0 : nsresult rv = NS_OK;
3050 0 : nsXULPrototypeCache* cache = nsXULPrototypeCache::GetInstance();
3051 :
3052 0 : nsCOMPtr<nsIObjectInputStream> objectInput = aInput;
3053 0 : if (cache) {
3054 0 : bool useXULCache = true;
3055 0 : if (mSrcURI) {
3056 : // NB: we must check the XUL script cache early, to avoid
3057 : // multiple deserialization attempts for a given script.
3058 : // Note that nsXULDocument::LoadScript
3059 : // checks the XUL script cache too, in order to handle the
3060 : // serialization case.
3061 : //
3062 : // We need do this only for <script src='strres.js'> and the
3063 : // like, i.e., out-of-line scripts that are included by several
3064 : // different XUL documents stored in the cache file.
3065 0 : useXULCache = cache->IsEnabled();
3066 :
3067 0 : if (useXULCache) {
3068 0 : PRUint32 newLangID = nsIProgrammingLanguage::UNKNOWN;
3069 : JSScript* newScriptObject =
3070 0 : cache->GetScript(mSrcURI, &newLangID);
3071 0 : if (newScriptObject) {
3072 : // Things may blow here if we simply change the script
3073 : // language - other code may already have pre-fetched the
3074 : // global for the language. (You can see this code by
3075 : // setting langID to UNKNOWN in the nsXULPrototypeScript
3076 : // ctor and not setting it until the scriptObject is set -
3077 : // code that pre-fetches these globals will then start
3078 : // asserting.)
3079 0 : if (mScriptObject.mLangID != newLangID) {
3080 0 : NS_ERROR("XUL cache gave different language?");
3081 0 : return NS_ERROR_UNEXPECTED;
3082 : }
3083 0 : Set(newScriptObject);
3084 : }
3085 : }
3086 : }
3087 :
3088 0 : if (! mScriptObject.mObject) {
3089 0 : if (mSrcURI) {
3090 0 : rv = cache->GetInputStream(mSrcURI, getter_AddRefs(objectInput));
3091 : }
3092 : // If !mSrcURI, we have an inline script. We shouldn't have
3093 : // to do anything else in that case, I think.
3094 :
3095 : // We do reflect errors into rv, but our caller may want to
3096 : // ignore our return value, because mScriptObject will be null
3097 : // after any error, and that suffices to cause the script to
3098 : // be reloaded (from the src= URI, if any) and recompiled.
3099 : // We're better off slow-loading than bailing out due to a
3100 : // error.
3101 0 : if (NS_SUCCEEDED(rv))
3102 0 : rv = Deserialize(objectInput, aGlobal, nsnull, nsnull);
3103 :
3104 0 : if (NS_SUCCEEDED(rv)) {
3105 0 : if (useXULCache && mSrcURI) {
3106 0 : bool isChrome = false;
3107 0 : mSrcURI->SchemeIs("chrome", &isChrome);
3108 0 : if (isChrome) {
3109 : cache->PutScript(mSrcURI,
3110 : mScriptObject.mLangID,
3111 0 : mScriptObject.mObject);
3112 : }
3113 : }
3114 0 : cache->FinishInputStream(mSrcURI);
3115 : } else {
3116 : // If mSrcURI is not in the cache,
3117 : // rv will be NS_ERROR_NOT_AVAILABLE and we'll try to
3118 : // update the cache file to hold a serialization of
3119 : // this script, once it has finished loading.
3120 0 : if (rv != NS_ERROR_NOT_AVAILABLE)
3121 0 : cache->AbortCaching();
3122 : }
3123 : }
3124 : }
3125 0 : return rv;
3126 : }
3127 :
3128 : nsresult
3129 0 : nsXULPrototypeScript::Compile(const PRUnichar* aText,
3130 : PRInt32 aTextLength,
3131 : nsIURI* aURI,
3132 : PRUint32 aLineNo,
3133 : nsIDocument* aDocument,
3134 : nsIScriptGlobalObjectOwner* aGlobalOwner)
3135 : {
3136 : // We'll compile the script using the prototype document's special
3137 : // script object as the parent. This ensures that we won't end up
3138 : // with an uncollectable reference.
3139 : //
3140 : // Compiling it using (for example) the first document's global
3141 : // object would cause JS to keep a reference via the __proto__ or
3142 : // parent pointer to the first document's global. If that happened,
3143 : // our script object would reference the first document, and the
3144 : // first document would indirectly reference the prototype document
3145 : // because it keeps the prototype cache alive. Circularity!
3146 : nsresult rv;
3147 :
3148 : // Use the prototype document's special context
3149 : nsIScriptContext *context;
3150 :
3151 : {
3152 0 : nsIScriptGlobalObject* global = aGlobalOwner->GetScriptGlobalObject();
3153 0 : NS_ASSERTION(global != nsnull, "prototype doc has no script global");
3154 0 : if (! global)
3155 0 : return NS_ERROR_UNEXPECTED;
3156 :
3157 0 : context = global->GetScriptContext(mScriptObject.mLangID);
3158 0 : NS_ASSERTION(context != nsnull, "no context for script global");
3159 0 : if (! context)
3160 0 : return NS_ERROR_UNEXPECTED;
3161 : }
3162 :
3163 0 : nsCAutoString urlspec;
3164 0 : nsContentUtils::GetWrapperSafeScriptFilename(aDocument, aURI, urlspec);
3165 :
3166 : // Ok, compile it to create a prototype script object!
3167 :
3168 0 : nsScriptObjectHolder<JSScript> newScriptObject(context);
3169 : rv = context->CompileScript(aText,
3170 : aTextLength,
3171 : // Use the enclosing document's principal
3172 : // XXX is this right? or should we use the
3173 : // protodoc's?
3174 : // If we start using the protodoc's, make sure
3175 : // the DowngradePrincipalIfNeeded stuff in
3176 : // nsXULDocument::OnStreamComplete still works!
3177 : aDocument->NodePrincipal(),
3178 : urlspec.get(),
3179 : aLineNo,
3180 : mLangVersion,
3181 0 : newScriptObject);
3182 0 : if (NS_FAILED(rv))
3183 0 : return rv;
3184 :
3185 0 : Set(newScriptObject);
3186 0 : return rv;
3187 : }
3188 :
3189 : void
3190 0 : nsXULPrototypeScript::UnlinkJSObjects()
3191 : {
3192 0 : if (mScriptObject.mObject) {
3193 : nsContentUtils::DropScriptObjects(mScriptObject.mLangID, this,
3194 0 : &NS_CYCLE_COLLECTION_NAME(nsXULPrototypeNode));
3195 0 : mScriptObject.mObject = nsnull;
3196 : }
3197 0 : }
3198 :
3199 : void
3200 0 : nsXULPrototypeScript::Set(JSScript* aObject)
3201 : {
3202 0 : NS_ASSERTION(!mScriptObject.mObject, "Leaking script object.");
3203 0 : if (!aObject) {
3204 0 : mScriptObject.mObject = nsnull;
3205 :
3206 0 : return;
3207 : }
3208 :
3209 : nsresult rv = nsContentUtils::HoldScriptObject(mScriptObject.mLangID,
3210 : this,
3211 : &NS_CYCLE_COLLECTION_NAME(nsXULPrototypeNode),
3212 0 : aObject, false);
3213 0 : if (NS_SUCCEEDED(rv)) {
3214 0 : mScriptObject.mObject = aObject;
3215 : }
3216 : }
3217 :
3218 : //----------------------------------------------------------------------
3219 : //
3220 : // nsXULPrototypeText
3221 : //
3222 :
3223 : nsresult
3224 0 : nsXULPrototypeText::Serialize(nsIObjectOutputStream* aStream,
3225 : nsIScriptGlobalObject* aGlobal,
3226 : const nsCOMArray<nsINodeInfo> *aNodeInfos)
3227 : {
3228 : nsresult rv;
3229 :
3230 : // Write basic prototype data
3231 0 : rv = aStream->Write32(mType);
3232 :
3233 0 : rv |= aStream->WriteWStringZ(mValue.get());
3234 :
3235 0 : return rv;
3236 : }
3237 :
3238 : nsresult
3239 0 : nsXULPrototypeText::Deserialize(nsIObjectInputStream* aStream,
3240 : nsIScriptGlobalObject* aGlobal,
3241 : nsIURI* aDocumentURI,
3242 : const nsCOMArray<nsINodeInfo> *aNodeInfos)
3243 : {
3244 : nsresult rv;
3245 :
3246 0 : rv = aStream->ReadString(mValue);
3247 :
3248 0 : return rv;
3249 : }
3250 :
3251 : //----------------------------------------------------------------------
3252 : //
3253 : // nsXULPrototypePI
3254 : //
3255 :
3256 : nsresult
3257 0 : nsXULPrototypePI::Serialize(nsIObjectOutputStream* aStream,
3258 : nsIScriptGlobalObject* aGlobal,
3259 : const nsCOMArray<nsINodeInfo> *aNodeInfos)
3260 : {
3261 : nsresult rv;
3262 :
3263 : // Write basic prototype data
3264 0 : rv = aStream->Write32(mType);
3265 :
3266 0 : rv |= aStream->WriteWStringZ(mTarget.get());
3267 0 : rv |= aStream->WriteWStringZ(mData.get());
3268 :
3269 0 : return rv;
3270 : }
3271 :
3272 : nsresult
3273 0 : nsXULPrototypePI::Deserialize(nsIObjectInputStream* aStream,
3274 : nsIScriptGlobalObject* aGlobal,
3275 : nsIURI* aDocumentURI,
3276 : const nsCOMArray<nsINodeInfo> *aNodeInfos)
3277 : {
3278 : nsresult rv;
3279 :
3280 0 : rv = aStream->ReadString(mTarget);
3281 0 : rv |= aStream->ReadString(mData);
3282 :
3283 0 : return rv;
3284 4392 : }
|