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