Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /* This Source Code Form is subject to the terms of the Mozilla Public
3 : * License, v. 2.0. If a copy of the MPL was not distributed with this
4 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 : *
6 : * This Original Code has been modified by IBM Corporation.
7 : * Modifications made by IBM described herein are
8 : * Copyright (c) International Business Machines
9 : * Corporation, 2000
10 : *
11 : * Modifications to Mozilla code or documentation
12 : * identified per MPL Section 3.3
13 : *
14 : * Date Modified by Description of modification
15 : * 03/27/2000 IBM Corp. Added PR_CALLBACK for Optlink
16 : * use in OS2
17 : */
18 :
19 : #include "nsCOMPtr.h"
20 : #include "nsDOMCID.h"
21 : #include "nsError.h"
22 : #include "nsDOMString.h"
23 : #include "nsIDOMEvent.h"
24 : #include "nsIAtom.h"
25 : #include "nsIBaseWindow.h"
26 : #include "nsIDOMAttr.h"
27 : #include "nsIDOMDocument.h"
28 : #include "nsIDOMElement.h"
29 : #include "nsIDOMEventListener.h"
30 : #include "nsIDOMNodeList.h"
31 : #include "nsIDOMXULCommandDispatcher.h"
32 : #include "nsIDOMXULElement.h"
33 : #include "nsIDOMXULSelectCntrlItemEl.h"
34 : #include "nsIDocument.h"
35 : #include "nsLayoutStylesheetCache.h"
36 : #include "mozilla/AsyncEventDispatcher.h"
37 : #include "mozilla/ClearOnShutdown.h"
38 : #include "mozilla/EventListenerManager.h"
39 : #include "mozilla/EventStateManager.h"
40 : #include "mozilla/EventStates.h"
41 : #include "mozilla/DeclarationBlockInlines.h"
42 : #include "nsFocusManager.h"
43 : #include "nsHTMLStyleSheet.h"
44 : #include "nsNameSpaceManager.h"
45 : #include "nsIObjectInputStream.h"
46 : #include "nsIObjectOutputStream.h"
47 : #include "nsIPresShell.h"
48 : #include "nsIPrincipal.h"
49 : #include "nsIRDFCompositeDataSource.h"
50 : #include "nsIRDFNode.h"
51 : #include "nsIRDFService.h"
52 : #include "nsIScriptContext.h"
53 : #include "nsIScriptError.h"
54 : #include "nsIScriptSecurityManager.h"
55 : #include "nsIServiceManager.h"
56 : #include "mozilla/css/StyleRule.h"
57 : #include "nsIURL.h"
58 : #include "nsViewManager.h"
59 : #include "nsIWidget.h"
60 : #include "nsIXULDocument.h"
61 : #include "nsIXULTemplateBuilder.h"
62 : #include "nsLayoutCID.h"
63 : #include "nsContentCID.h"
64 : #include "mozilla/dom/Event.h"
65 : #include "nsRDFCID.h"
66 : #include "nsStyleConsts.h"
67 : #include "nsXPIDLString.h"
68 : #include "nsXULControllers.h"
69 : #include "nsIBoxObject.h"
70 : #include "nsPIBoxObject.h"
71 : #include "XULDocument.h"
72 : #include "nsXULPopupListener.h"
73 : #include "nsRuleWalker.h"
74 : #include "nsIDOMCSSStyleDeclaration.h"
75 : #include "nsCSSParser.h"
76 : #include "ListBoxObject.h"
77 : #include "nsContentUtils.h"
78 : #include "nsContentList.h"
79 : #include "mozilla/InternalMutationEvent.h"
80 : #include "mozilla/MouseEvents.h"
81 : #include "nsIDOMMutationEvent.h"
82 : #include "nsPIDOMWindow.h"
83 : #include "nsJSPrincipals.h"
84 : #include "nsDOMAttributeMap.h"
85 : #include "nsGkAtoms.h"
86 : #include "nsXULContentUtils.h"
87 : #include "nsNodeUtils.h"
88 : #include "nsFrameLoader.h"
89 : #include "mozilla/Logging.h"
90 : #include "rdf.h"
91 : #include "nsIControllers.h"
92 : #include "nsAttrValueOrString.h"
93 : #include "nsAttrValueInlines.h"
94 : #include "mozilla/Attributes.h"
95 : #include "nsIController.h"
96 : #include "nsQueryObject.h"
97 : #include <algorithm>
98 : #include "nsIDOMChromeWindow.h"
99 :
100 : // The XUL doc interface
101 : #include "nsIDOMXULDocument.h"
102 :
103 : #include "nsReadableUtils.h"
104 : #include "nsIFrame.h"
105 : #include "nsNodeInfoManager.h"
106 : #include "nsXBLBinding.h"
107 : #include "mozilla/EventDispatcher.h"
108 : #include "mozAutoDocUpdate.h"
109 : #include "nsIDOMXULCommandEvent.h"
110 : #include "nsCCUncollectableMarker.h"
111 : #include "nsICSSDeclaration.h"
112 :
113 : #include "mozilla/dom/XULElementBinding.h"
114 : #include "mozilla/dom/BoxObject.h"
115 : #include "mozilla/dom/HTMLIFrameElement.h"
116 :
117 : using namespace mozilla;
118 : using namespace mozilla::dom;
119 :
120 : #ifdef XUL_PROTOTYPE_ATTRIBUTE_METERING
121 : uint32_t nsXULPrototypeAttribute::gNumElements;
122 : uint32_t nsXULPrototypeAttribute::gNumAttributes;
123 : uint32_t nsXULPrototypeAttribute::gNumCacheTests;
124 : uint32_t nsXULPrototypeAttribute::gNumCacheHits;
125 : uint32_t nsXULPrototypeAttribute::gNumCacheSets;
126 : uint32_t nsXULPrototypeAttribute::gNumCacheFills;
127 : #endif
128 :
129 : #define NS_DISPATCH_XUL_COMMAND (1 << 0)
130 :
131 : class nsXULElementTearoff final : public nsIFrameLoaderOwner
132 : {
133 142 : ~nsXULElementTearoff() {}
134 :
135 : public:
136 : NS_DECL_CYCLE_COLLECTING_ISUPPORTS
137 1423 : NS_DECL_CYCLE_COLLECTION_CLASS(nsXULElementTearoff)
138 :
139 143 : explicit nsXULElementTearoff(nsXULElement* aElement)
140 143 : : mElement(aElement)
141 : {
142 143 : }
143 :
144 92 : NS_FORWARD_NSIFRAMELOADEROWNER(static_cast<nsXULElement*>(mElement.get())->)
145 : private:
146 : nsCOMPtr<nsIDOMXULElement> mElement;
147 : };
148 :
149 0 : NS_IMPL_CYCLE_COLLECTION(nsXULElementTearoff, mElement)
150 :
151 143 : NS_IMPL_CYCLE_COLLECTING_ADDREF(nsXULElementTearoff)
152 427 : NS_IMPL_CYCLE_COLLECTING_RELEASE(nsXULElementTearoff)
153 :
154 711 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsXULElementTearoff)
155 0 : NS_INTERFACE_MAP_ENTRY(nsIFrameLoaderOwner)
156 0 : NS_INTERFACE_MAP_END_AGGREGATED(mElement)
157 :
158 : //----------------------------------------------------------------------
159 : // nsXULElement
160 : //
161 :
162 2273 : nsXULElement::nsXULElement(already_AddRefed<mozilla::dom::NodeInfo> aNodeInfo)
163 : : nsStyledElement(aNodeInfo),
164 2273 : mBindingParent(nullptr)
165 : {
166 : XUL_PROTOTYPE_ATTRIBUTE_METER(gNumElements);
167 :
168 : // We may be READWRITE by default; check.
169 2273 : if (IsReadWriteTextElement()) {
170 5 : AddStatesSilently(NS_EVENT_STATE_MOZ_READWRITE);
171 5 : RemoveStatesSilently(NS_EVENT_STATE_MOZ_READONLY);
172 : }
173 2273 : }
174 :
175 62 : nsXULElement::~nsXULElement()
176 : {
177 93 : }
178 :
179 706 : nsXULElement::nsXULSlots::nsXULSlots()
180 706 : : nsXULElement::nsDOMSlots()
181 : {
182 706 : }
183 :
184 0 : nsXULElement::nsXULSlots::~nsXULSlots()
185 : {
186 0 : NS_IF_RELEASE(mControllers); // Forces release
187 0 : nsCOMPtr<nsIFrameLoader> frameLoader = do_QueryInterface(mFrameLoaderOrOpener);
188 0 : if (frameLoader) {
189 0 : static_cast<nsFrameLoader*>(frameLoader.get())->Destroy();
190 : }
191 0 : }
192 :
193 : void
194 287 : nsXULElement::nsXULSlots::Traverse(nsCycleCollectionTraversalCallback &cb)
195 : {
196 287 : NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mFrameLoaderOrOpener");
197 287 : cb.NoteXPCOMChild(mFrameLoaderOrOpener);
198 287 : }
199 :
200 : nsINode::nsSlots*
201 706 : nsXULElement::CreateSlots()
202 : {
203 706 : return new nsXULSlots();
204 : }
205 :
206 : void
207 1 : nsXULElement::MaybeUpdatePrivateLifetime()
208 : {
209 2 : if (AttrValueIs(kNameSpaceID_None, nsGkAtoms::windowtype,
210 2 : NS_LITERAL_STRING("navigator:browser"),
211 1 : eCaseMatters)) {
212 1 : return;
213 : }
214 :
215 0 : nsPIDOMWindowOuter* win = OwnerDoc()->GetWindow();
216 0 : nsCOMPtr<nsIDocShell> docShell = win ? win->GetDocShell() : nullptr;
217 0 : if (docShell) {
218 0 : docShell->SetAffectPrivateSessionLifetime(false);
219 : }
220 : }
221 :
222 : /* static */
223 : already_AddRefed<nsXULElement>
224 1667 : nsXULElement::Create(nsXULPrototypeElement* aPrototype, mozilla::dom::NodeInfo *aNodeInfo,
225 : bool aIsScriptable, bool aIsRoot)
226 : {
227 3334 : RefPtr<mozilla::dom::NodeInfo> ni = aNodeInfo;
228 5001 : RefPtr<nsXULElement> element = new nsXULElement(ni.forget());
229 1667 : if (element) {
230 1667 : if (aPrototype->mHasIdAttribute) {
231 979 : element->SetHasID();
232 : }
233 1667 : if (aPrototype->mHasClassAttribute) {
234 605 : element->SetMayHaveClass();
235 : }
236 1667 : if (aPrototype->mHasStyleAttribute) {
237 7 : element->SetMayHaveStyle();
238 : }
239 :
240 1667 : element->MakeHeavyweight(aPrototype);
241 1667 : if (aIsScriptable) {
242 : // Check each attribute on the prototype to see if we need to do
243 : // any additional processing and hookup that would otherwise be
244 : // done 'automagically' by SetAttr().
245 5162 : for (uint32_t i = 0; i < aPrototype->mNumAttributes; ++i) {
246 3894 : element->AddListenerFor(aPrototype->mAttributes[i].mName,
247 3894 : true);
248 : }
249 : }
250 :
251 1667 : if (aIsRoot && aPrototype->mNodeInfo->Equals(nsGkAtoms::window)) {
252 26 : for (uint32_t i = 0; i < aPrototype->mNumAttributes; ++i) {
253 25 : if (aPrototype->mAttributes[i].mName.Equals(nsGkAtoms::windowtype)) {
254 1 : element->MaybeUpdatePrivateLifetime();
255 : }
256 : }
257 : }
258 : }
259 :
260 3334 : return element.forget();
261 : }
262 :
263 : nsresult
264 1667 : nsXULElement::Create(nsXULPrototypeElement* aPrototype,
265 : nsIDocument* aDocument,
266 : bool aIsScriptable,
267 : bool aIsRoot,
268 : Element** aResult)
269 : {
270 : // Create an nsXULElement from a prototype
271 1667 : NS_PRECONDITION(aPrototype != nullptr, "null ptr");
272 1667 : if (! aPrototype)
273 0 : return NS_ERROR_NULL_POINTER;
274 :
275 1667 : NS_PRECONDITION(aResult != nullptr, "null ptr");
276 1667 : if (! aResult)
277 0 : return NS_ERROR_NULL_POINTER;
278 :
279 3334 : RefPtr<mozilla::dom::NodeInfo> nodeInfo;
280 1667 : if (aDocument) {
281 1667 : mozilla::dom::NodeInfo* ni = aPrototype->mNodeInfo;
282 : nodeInfo = aDocument->NodeInfoManager()->
283 3334 : GetNodeInfo(ni->NameAtom(), ni->GetPrefixAtom(), ni->NamespaceID(),
284 1667 : nsIDOMNode::ELEMENT_NODE);
285 : } else {
286 0 : nodeInfo = aPrototype->mNodeInfo;
287 : }
288 :
289 3334 : RefPtr<nsXULElement> element = Create(aPrototype, nodeInfo,
290 3334 : aIsScriptable, aIsRoot);
291 1667 : element.forget(aResult);
292 :
293 1667 : return NS_OK;
294 : }
295 :
296 : nsresult
297 58 : NS_NewXULElement(Element** aResult, already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo)
298 : {
299 116 : RefPtr<mozilla::dom::NodeInfo> ni = aNodeInfo;
300 :
301 58 : NS_PRECONDITION(ni, "need nodeinfo for non-proto Create");
302 :
303 58 : nsIDocument* doc = ni->GetDocument();
304 58 : if (doc && !doc->AllowXULXBL()) {
305 0 : return NS_ERROR_NOT_AVAILABLE;
306 : }
307 :
308 116 : NS_ADDREF(*aResult = new nsXULElement(ni.forget()));
309 :
310 58 : return NS_OK;
311 : }
312 :
313 : void
314 6 : NS_TrustedNewXULElement(nsIContent** aResult,
315 : already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo)
316 : {
317 12 : RefPtr<mozilla::dom::NodeInfo> ni = aNodeInfo;
318 6 : NS_PRECONDITION(ni, "need nodeinfo for non-proto Create");
319 :
320 : // Create an nsXULElement with the specified namespace and tag.
321 12 : NS_ADDREF(*aResult = new nsXULElement(ni.forget()));
322 6 : }
323 :
324 : //----------------------------------------------------------------------
325 : // nsISupports interface
326 :
327 : NS_IMPL_CYCLE_COLLECTION_CLASS(nsXULElement)
328 :
329 424 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsXULElement,
330 : nsStyledElement)
331 : {
332 424 : nsXULSlots* slots = static_cast<nsXULSlots*>(tmp->GetExistingSlots());
333 424 : if (slots) {
334 287 : slots->Traverse(cb);
335 : }
336 : }
337 424 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
338 :
339 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsXULElement,
340 : nsStyledElement)
341 : // Why aren't we unlinking the prototype?
342 0 : tmp->ClearHasID();
343 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
344 :
345 30103 : NS_IMPL_ADDREF_INHERITED(nsXULElement, nsStyledElement)
346 23794 : NS_IMPL_RELEASE_INHERITED(nsXULElement, nsStyledElement)
347 :
348 20383 : NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(nsXULElement)
349 15653 : NS_INTERFACE_TABLE_INHERITED(nsXULElement, nsIDOMNode, nsIDOMElement,
350 : nsIDOMXULElement)
351 15653 : NS_ELEMENT_INTERFACE_TABLE_TO_MAP_SEGUE
352 447 : NS_INTERFACE_MAP_ENTRY_TEAROFF(nsIFrameLoaderOwner,
353 : new nsXULElementTearoff(this))
354 161 : NS_INTERFACE_MAP_END_INHERITING(nsStyledElement)
355 :
356 : //----------------------------------------------------------------------
357 : // nsIDOMNode interface
358 :
359 : nsresult
360 542 : nsXULElement::Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
361 : bool aPreallocateChildren) const
362 : {
363 542 : *aResult = nullptr;
364 :
365 1084 : RefPtr<mozilla::dom::NodeInfo> ni = aNodeInfo;
366 1626 : RefPtr<nsXULElement> element = new nsXULElement(ni.forget());
367 :
368 542 : nsresult rv = element->mAttrsAndChildren.EnsureCapacityToClone(mAttrsAndChildren,
369 542 : aPreallocateChildren);
370 542 : NS_ENSURE_SUCCESS(rv, rv);
371 :
372 : // XXX TODO: set up RDF generic builder n' stuff if there is a
373 : // 'datasources' attribute? This is really kind of tricky,
374 : // because then we'd need to -selectively- copy children that
375 : // -weren't- generated from RDF. Ugh. Forget it.
376 :
377 : // Note that we're _not_ copying mControllers.
378 :
379 542 : uint32_t count = mAttrsAndChildren.AttrCount();
380 542 : rv = NS_OK;
381 2085 : for (uint32_t i = 0; i < count; ++i) {
382 1543 : const nsAttrName* originalName = mAttrsAndChildren.AttrNameAt(i);
383 1543 : const nsAttrValue* originalValue = mAttrsAndChildren.AttrAt(i);
384 3086 : nsAttrValue attrValue;
385 :
386 : // Style rules need to be cloned.
387 1543 : if (originalValue->Type() == nsAttrValue::eCSSDeclaration) {
388 3 : DeclarationBlock* decl = originalValue->GetCSSDeclarationValue();
389 6 : RefPtr<DeclarationBlock> declClone = decl->Clone();
390 :
391 6 : nsString stringValue;
392 3 : originalValue->ToString(stringValue);
393 :
394 3 : attrValue.SetTo(declClone.forget(), &stringValue);
395 : } else {
396 1540 : attrValue.SetTo(*originalValue);
397 : }
398 :
399 : bool oldValueSet;
400 1543 : if (originalName->IsAtom()) {
401 1187 : rv = element->mAttrsAndChildren.SetAndSwapAttr(originalName->Atom(),
402 : attrValue,
403 1187 : &oldValueSet);
404 : } else {
405 356 : rv = element->mAttrsAndChildren.SetAndSwapAttr(originalName->NodeInfo(),
406 : attrValue,
407 356 : &oldValueSet);
408 : }
409 1543 : NS_ENSURE_SUCCESS(rv, rv);
410 1543 : element->AddListenerFor(*originalName, true);
411 1549 : if (originalName->Equals(nsGkAtoms::id) &&
412 6 : !originalValue->IsEmptyString()) {
413 6 : element->SetHasID();
414 : }
415 1543 : if (originalName->Equals(nsGkAtoms::_class)) {
416 439 : element->SetMayHaveClass();
417 : }
418 1543 : if (originalName->Equals(nsGkAtoms::style)) {
419 3 : element->SetMayHaveStyle();
420 : }
421 : }
422 :
423 542 : element.forget(aResult);
424 542 : return rv;
425 : }
426 :
427 : //----------------------------------------------------------------------
428 :
429 : already_AddRefed<nsINodeList>
430 2 : nsXULElement::GetElementsByAttribute(const nsAString& aAttribute,
431 : const nsAString& aValue)
432 : {
433 4 : nsCOMPtr<nsIAtom> attrAtom(NS_Atomize(aAttribute));
434 2 : void* attrValue = new nsString(aValue);
435 : RefPtr<nsContentList> list =
436 : new nsContentList(this,
437 : XULDocument::MatchAttribute,
438 : nsContentUtils::DestroyMatchString,
439 : attrValue,
440 : true,
441 : attrAtom,
442 6 : kNameSpaceID_Unknown);
443 4 : return list.forget();
444 : }
445 :
446 : already_AddRefed<nsINodeList>
447 0 : nsXULElement::GetElementsByAttributeNS(const nsAString& aNamespaceURI,
448 : const nsAString& aAttribute,
449 : const nsAString& aValue,
450 : ErrorResult& rv)
451 : {
452 0 : nsCOMPtr<nsIAtom> attrAtom(NS_Atomize(aAttribute));
453 :
454 0 : int32_t nameSpaceId = kNameSpaceID_Wildcard;
455 0 : if (!aNamespaceURI.EqualsLiteral("*")) {
456 0 : rv =
457 : nsContentUtils::NameSpaceManager()->RegisterNameSpace(aNamespaceURI,
458 0 : nameSpaceId);
459 0 : if (rv.Failed()) {
460 0 : return nullptr;
461 : }
462 : }
463 :
464 0 : void* attrValue = new nsString(aValue);
465 : RefPtr<nsContentList> list =
466 : new nsContentList(this,
467 : XULDocument::MatchAttribute,
468 : nsContentUtils::DestroyMatchString,
469 : attrValue,
470 : true,
471 : attrAtom,
472 0 : nameSpaceId);
473 :
474 0 : return list.forget();
475 : }
476 :
477 : EventListenerManager*
478 553 : nsXULElement::GetEventListenerManagerForAttr(nsIAtom* aAttrName, bool* aDefer)
479 : {
480 : // XXXbz sXBL/XBL2 issue: should we instead use GetComposedDoc()
481 : // here, override BindToTree for those classes and munge event
482 : // listeners there?
483 553 : nsIDocument* doc = OwnerDoc();
484 :
485 : nsPIDOMWindowInner *window;
486 553 : Element *root = doc->GetRootElement();
487 553 : if ((!root || root == this) && !mNodeInfo->Equals(nsGkAtoms::overlay) &&
488 : (window = doc->GetInnerWindow())) {
489 :
490 6 : nsCOMPtr<EventTarget> piTarget = do_QueryInterface(window);
491 :
492 3 : *aDefer = false;
493 3 : return piTarget->GetOrCreateListenerManager();
494 : }
495 :
496 550 : return nsStyledElement::GetEventListenerManagerForAttr(aAttrName, aDefer);
497 : }
498 :
499 : // returns true if the element is not a list
500 0 : static bool IsNonList(mozilla::dom::NodeInfo* aNodeInfo)
501 : {
502 0 : return !aNodeInfo->Equals(nsGkAtoms::tree) &&
503 0 : !aNodeInfo->Equals(nsGkAtoms::listbox) &&
504 0 : !aNodeInfo->Equals(nsGkAtoms::richlistbox);
505 : }
506 :
507 : bool
508 3 : nsXULElement::IsFocusableInternal(int32_t *aTabIndex, bool aWithMouse)
509 : {
510 : /*
511 : * Returns true if an element may be focused, and false otherwise. The inout
512 : * argument aTabIndex will be set to the tab order index to be used; -1 for
513 : * elements that should not be part of the tab order and a greater value to
514 : * indicate its tab order.
515 : *
516 : * Confusingly, the supplied value for the aTabIndex argument may indicate
517 : * whether the element may be focused as a result of the -moz-user-focus
518 : * property, where -1 means no and 0 means yes.
519 : *
520 : * For controls, the element cannot be focused and is not part of the tab
521 : * order if it is disabled.
522 : *
523 : * Controls (those that implement nsIDOMXULControlElement):
524 : * *aTabIndex = -1 no tabindex Not focusable or tabbable
525 : * *aTabIndex = -1 tabindex="-1" Not focusable or tabbable
526 : * *aTabIndex = -1 tabindex=">=0" Focusable and tabbable
527 : * *aTabIndex >= 0 no tabindex Focusable and tabbable
528 : * *aTabIndex >= 0 tabindex="-1" Focusable but not tabbable
529 : * *aTabIndex >= 0 tabindex=">=0" Focusable and tabbable
530 : * Non-controls:
531 : * *aTabIndex = -1 Not focusable or tabbable
532 : * *aTabIndex >= 0 Focusable and tabbable
533 : *
534 : * If aTabIndex is null, then the tabindex is not computed, and
535 : * true is returned for non-disabled controls and false otherwise.
536 : */
537 :
538 : // elements are not focusable by default
539 3 : bool shouldFocus = false;
540 :
541 : #ifdef XP_MACOSX
542 : // on Mac, mouse interactions only focus the element if it's a list,
543 : // or if it's a remote target, since the remote target must handle
544 : // the focus.
545 : if (aWithMouse &&
546 : IsNonList(mNodeInfo) &&
547 : !EventStateManager::IsRemoteTarget(this))
548 : {
549 : return false;
550 : }
551 : #endif
552 :
553 6 : nsCOMPtr<nsIDOMXULControlElement> xulControl = do_QueryObject(this);
554 3 : if (xulControl) {
555 : // a disabled element cannot be focused and is not part of the tab order
556 : bool disabled;
557 0 : xulControl->GetDisabled(&disabled);
558 0 : if (disabled) {
559 0 : if (aTabIndex)
560 0 : *aTabIndex = -1;
561 0 : return false;
562 : }
563 0 : shouldFocus = true;
564 : }
565 :
566 3 : if (aTabIndex) {
567 3 : if (xulControl) {
568 0 : if (HasAttr(kNameSpaceID_None, nsGkAtoms::tabindex)) {
569 : // if either the aTabIndex argument or a specified tabindex is non-negative,
570 : // the element becomes focusable.
571 0 : int32_t tabIndex = 0;
572 0 : xulControl->GetTabIndex(&tabIndex);
573 0 : shouldFocus = *aTabIndex >= 0 || tabIndex >= 0;
574 0 : *aTabIndex = tabIndex;
575 : } else {
576 : // otherwise, if there is no tabindex attribute, just use the value of
577 : // *aTabIndex to indicate focusability. Reset any supplied tabindex to 0.
578 0 : shouldFocus = *aTabIndex >= 0;
579 0 : if (shouldFocus)
580 0 : *aTabIndex = 0;
581 : }
582 :
583 0 : if (shouldFocus && sTabFocusModelAppliesToXUL &&
584 0 : !(sTabFocusModel & eTabFocus_formElementsMask)) {
585 : // By default, the tab focus model doesn't apply to xul element on any system but OS X.
586 : // on OS X we're following it for UI elements (XUL) as sTabFocusModel is based on
587 : // "Full Keyboard Access" system setting (see mac/nsILookAndFeel).
588 : // both textboxes and list elements (i.e. trees and list) should always be focusable
589 : // (textboxes are handled as html:input)
590 : // For compatibility, we only do this for controls, otherwise elements like <browser>
591 : // cannot take this focus.
592 0 : if (IsNonList(mNodeInfo))
593 0 : *aTabIndex = -1;
594 : }
595 : } else {
596 3 : shouldFocus = *aTabIndex >= 0;
597 : }
598 : }
599 :
600 3 : return shouldFocus;
601 : }
602 :
603 : bool
604 0 : nsXULElement::PerformAccesskey(bool aKeyCausesActivation,
605 : bool aIsTrustedEvent)
606 : {
607 0 : nsCOMPtr<nsIContent> content(this);
608 :
609 0 : if (IsXULElement(nsGkAtoms::label)) {
610 0 : nsCOMPtr<nsIDOMElement> element;
611 :
612 0 : nsAutoString control;
613 0 : GetAttr(kNameSpaceID_None, nsGkAtoms::control, control);
614 0 : if (!control.IsEmpty()) {
615 : //XXXsmaug Should we use ShadowRoot::GetElementById in case
616 : // content is in Shadow DOM?
617 : nsCOMPtr<nsIDOMDocument> domDocument =
618 0 : do_QueryInterface(content->GetUncomposedDoc());
619 0 : if (domDocument)
620 0 : domDocument->GetElementById(control, getter_AddRefs(element));
621 : }
622 : // here we'll either change |content| to the element referenced by
623 : // |element|, or clear it.
624 0 : content = do_QueryInterface(element);
625 :
626 0 : if (!content) {
627 0 : return false;
628 : }
629 : }
630 :
631 0 : nsIFrame* frame = content->GetPrimaryFrame();
632 0 : if (!frame || !frame->IsVisibleConsideringAncestors()) {
633 0 : return false;
634 : }
635 :
636 0 : bool focused = false;
637 0 : nsXULElement* elm = FromContent(content);
638 0 : if (elm) {
639 : // Define behavior for each type of XUL element.
640 0 : if (!content->IsXULElement(nsGkAtoms::toolbarbutton)) {
641 0 : nsIFocusManager* fm = nsFocusManager::GetFocusManager();
642 0 : if (fm) {
643 0 : nsCOMPtr<nsIDOMElement> elementToFocus;
644 : // for radio buttons, focus the radiogroup instead
645 0 : if (content->IsXULElement(nsGkAtoms::radio)) {
646 0 : nsCOMPtr<nsIDOMXULSelectControlItemElement> controlItem(do_QueryInterface(content));
647 0 : if (controlItem) {
648 : bool disabled;
649 0 : controlItem->GetDisabled(&disabled);
650 0 : if (!disabled) {
651 0 : nsCOMPtr<nsIDOMXULSelectControlElement> selectControl;
652 0 : controlItem->GetControl(getter_AddRefs(selectControl));
653 0 : elementToFocus = do_QueryInterface(selectControl);
654 : }
655 : }
656 : } else {
657 0 : elementToFocus = do_QueryInterface(content);
658 : }
659 0 : if (elementToFocus) {
660 0 : fm->SetFocus(elementToFocus, nsIFocusManager::FLAG_BYKEY);
661 :
662 : // Return true if the element became focused.
663 0 : nsPIDOMWindowOuter* window = OwnerDoc()->GetWindow();
664 0 : focused = (window && window->GetFocusedNode());
665 : }
666 : }
667 : }
668 0 : if (aKeyCausesActivation &&
669 0 : !content->IsAnyOfXULElements(nsGkAtoms::textbox, nsGkAtoms::menulist)) {
670 0 : elm->ClickWithInputSource(nsIDOMMouseEvent::MOZ_SOURCE_KEYBOARD, aIsTrustedEvent);
671 : }
672 : } else {
673 0 : return content->PerformAccesskey(aKeyCausesActivation, aIsTrustedEvent);
674 : }
675 :
676 0 : return focused;
677 : }
678 :
679 : //----------------------------------------------------------------------
680 :
681 : void
682 5437 : nsXULElement::AddListenerFor(const nsAttrName& aName,
683 : bool aCompileEventHandlers)
684 : {
685 : // If appropriate, add a popup listener and/or compile the event
686 : // handler. Called when we change the element's document, create a
687 : // new element, change an attribute's value, etc.
688 : // Eventlistenener-attributes are always in the null namespace
689 5437 : if (aName.IsAtom()) {
690 5076 : nsIAtom *attr = aName.Atom();
691 5076 : MaybeAddPopupListener(attr);
692 10152 : if (aCompileEventHandlers &&
693 5076 : nsContentUtils::IsEventAttributeName(attr, EventNameType_XUL)) {
694 956 : nsAutoString value;
695 478 : GetAttr(kNameSpaceID_None, attr, value);
696 478 : SetEventHandler(attr, value, true);
697 : }
698 : }
699 5437 : }
700 :
701 : void
702 6049 : nsXULElement::MaybeAddPopupListener(nsIAtom* aLocalName)
703 : {
704 : // If appropriate, add a popup listener. Called when we change the
705 : // element's document, create a new element, change an attribute's
706 : // value, etc.
707 12098 : if (aLocalName == nsGkAtoms::menu ||
708 12097 : aLocalName == nsGkAtoms::contextmenu ||
709 : // XXXdwh popup and context are deprecated
710 12096 : aLocalName == nsGkAtoms::popup ||
711 6048 : aLocalName == nsGkAtoms::context) {
712 25 : AddPopupListener(aLocalName);
713 : }
714 6049 : }
715 :
716 : //----------------------------------------------------------------------
717 : //
718 : // nsIContent interface
719 : //
720 : void
721 3702 : nsXULElement::UpdateEditableState(bool aNotify)
722 : {
723 : // Don't call through to Element here because the things
724 : // it does don't work for cases when we're an editable control.
725 3702 : nsIContent *parent = GetParent();
726 :
727 3702 : SetEditableFlag(parent && parent->HasFlag(NODE_IS_EDITABLE));
728 3702 : UpdateState(aNotify);
729 3702 : }
730 :
731 : /**
732 : * Returns true if the user-agent style sheet rules for this XUL element are
733 : * in minimal-xul.css instead of xul.css.
734 : */
735 30 : static inline bool XULElementsRulesInMinimalXULSheet(nsIAtom* aTag)
736 : {
737 : return // scrollbar parts:
738 56 : aTag == nsGkAtoms::scrollbar ||
739 36 : aTag == nsGkAtoms::scrollbarbutton ||
740 18 : aTag == nsGkAtoms::scrollcorner ||
741 12 : aTag == nsGkAtoms::slider ||
742 4 : aTag == nsGkAtoms::thumb ||
743 0 : aTag == nsGkAtoms::scale ||
744 : // other
745 0 : aTag == nsGkAtoms::resizer ||
746 30 : aTag == nsGkAtoms::label ||
747 30 : aTag == nsGkAtoms::videocontrols;
748 : }
749 :
750 : #ifdef DEBUG
751 : /**
752 : * Returns true if aElement is a XUL element created by the video controls
753 : * binding. HTML <video> and <audio> bindings pull in this binding. This
754 : * binding creates lots of different types of XUL elements.
755 : */
756 : static inline bool
757 0 : IsInVideoControls(nsXULElement* aElement)
758 : {
759 0 : nsIContent* ancestor = aElement->GetParent();
760 0 : while (ancestor) {
761 0 : if (ancestor->NodeInfo()->Equals(nsGkAtoms::videocontrols, kNameSpaceID_XUL)) {
762 0 : return true;
763 : }
764 0 : ancestor = ancestor->GetParent();
765 : }
766 0 : return false;
767 : }
768 :
769 : /**
770 : * Returns true if aElement is an element created by the <binding
771 : * id="feedreaderUI"> binding or one of the bindings bound to such an element.
772 : * element in one of the binding for such an element. Only
773 : * subscribe.xhtml#feedSubscribeLine pulls in the feedreaderUI binding. This
774 : * binding creates lots of different types of XUL elements.
775 : */
776 : bool
777 0 : IsInFeedSubscribeLine(nsXULElement* aElement)
778 : {
779 0 : nsIContent* bindingParent = aElement->GetBindingParent();
780 0 : if (bindingParent) {
781 0 : while (bindingParent->GetBindingParent()) {
782 0 : bindingParent = bindingParent->GetBindingParent();
783 : }
784 0 : nsIAtom* idAtom = bindingParent->GetID();
785 0 : if (idAtom && idAtom->Equals(NS_LITERAL_STRING("feedSubscribeLine"))) {
786 0 : return true;
787 : }
788 : }
789 0 : return false;
790 : }
791 : #endif
792 :
793 0 : class XULInContentErrorReporter : public Runnable
794 : {
795 : public:
796 0 : explicit XULInContentErrorReporter(nsIDocument* aDocument)
797 0 : : mozilla::Runnable("XULInContentErrorReporter")
798 0 : , mDocument(aDocument)
799 : {
800 0 : }
801 :
802 0 : NS_IMETHOD Run() override
803 : {
804 0 : mDocument->WarnOnceAbout(nsIDocument::eImportXULIntoContent, false);
805 0 : return NS_OK;
806 : }
807 :
808 : private:
809 : nsCOMPtr<nsIDocument> mDocument;
810 : };
811 :
812 : nsresult
813 3702 : nsXULElement::BindToTree(nsIDocument* aDocument,
814 : nsIContent* aParent,
815 : nsIContent* aBindingParent,
816 : bool aCompileEventHandlers)
817 : {
818 6850 : if (!aBindingParent &&
819 1699 : aDocument &&
820 2999 : !aDocument->IsLoadedAsInteractiveData() &&
821 5002 : !aDocument->AllowXULXBL() &&
822 0 : !aDocument->HasWarnedAbout(nsIDocument::eImportXULIntoContent)) {
823 0 : nsContentUtils::AddScriptRunner(new XULInContentErrorReporter(aDocument));
824 : }
825 :
826 3702 : nsresult rv = nsStyledElement::BindToTree(aDocument, aParent,
827 : aBindingParent,
828 3702 : aCompileEventHandlers);
829 3702 : NS_ENSURE_SUCCESS(rv, rv);
830 :
831 3702 : nsIDocument* doc = GetComposedDoc();
832 5953 : if (doc &&
833 3732 : !doc->LoadsFullXULStyleSheetUpFront() &&
834 30 : !doc->IsUnstyledDocument()) {
835 :
836 : // To save CPU cycles and memory, non-XUL documents only load the user
837 : // agent style sheet rules for a minimal set of XUL elements such as
838 : // 'scrollbar' that may be created implicitly for their content (those
839 : // rules being in minimal-xul.css). This is where we make sure that all
840 : // the other XUL UA style sheet rules (xul.css) have been loaded if the
841 : // minimal set is not sufficient.
842 : //
843 : // We do this during binding, not element construction, because elements
844 : // can be moved from the document that creates them to another document.
845 :
846 30 : if (!XULElementsRulesInMinimalXULSheet(NodeInfo()->NameAtom())) {
847 0 : auto cache = nsLayoutStylesheetCache::For(doc->GetStyleBackendType());
848 0 : doc->EnsureOnDemandBuiltInUASheet(cache->XULSheet());
849 : // To keep memory usage down it is important that we try and avoid
850 : // pulling xul.css into non-XUL documents. That should be very rare, and
851 : // for HTML we currently should only pull it in if the document contains
852 : // an <audio> or <video> element. This assertion is here to make sure
853 : // that we don't fail to notice if a change to bindings causes us to
854 : // start pulling in xul.css much more frequently. If this assertion
855 : // fails then we need to figure out why, and how we can continue to avoid
856 : // pulling in xul.css.
857 : // Note that add-ons may introduce bindings that cause this assertion to
858 : // fire.
859 0 : NS_ASSERTION(IsInVideoControls(this) ||
860 : IsInFeedSubscribeLine(this) ||
861 : IsXULElement(nsGkAtoms::datetimebox),
862 : "Unexpected XUL element in non-XUL doc");
863 : }
864 : }
865 :
866 3702 : if (aDocument) {
867 2251 : NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(),
868 : "Missing a script blocker!");
869 : // We're in a document now. Kick off the frame load.
870 2251 : LoadSrc();
871 : }
872 :
873 3702 : return rv;
874 : }
875 :
876 : void
877 716 : nsXULElement::UnbindFromTree(bool aDeep, bool aNullParent)
878 : {
879 : // mControllers can own objects that are implemented
880 : // in JavaScript (such as some implementations of
881 : // nsIControllers. These objects prevent their global
882 : // object's script object from being garbage collected,
883 : // which means JS continues to hold an owning reference
884 : // to the nsGlobalWindow, which owns the document,
885 : // which owns this content. That's a cycle, so we break
886 : // it here. (It might be better to break this by releasing
887 : // mDocument in nsGlobalWindow::SetDocShell, but I'm not
888 : // sure whether that would fix all possible cycles through
889 : // mControllers.)
890 716 : nsXULSlots* slots = static_cast<nsXULSlots*>(GetExistingDOMSlots());
891 716 : if (slots) {
892 20 : NS_IF_RELEASE(slots->mControllers);
893 40 : RefPtr<nsFrameLoader> frameLoader = GetFrameLoader();
894 20 : if (frameLoader) {
895 1 : frameLoader->Destroy();
896 : }
897 20 : slots->mFrameLoaderOrOpener = nullptr;
898 : }
899 :
900 716 : nsStyledElement::UnbindFromTree(aDeep, aNullParent);
901 716 : }
902 :
903 : void
904 68 : nsXULElement::RemoveChildAt(uint32_t aIndex, bool aNotify)
905 : {
906 136 : nsCOMPtr<nsIContent> oldKid = mAttrsAndChildren.GetSafeChildAt(aIndex);
907 68 : if (!oldKid) {
908 0 : return;
909 : }
910 :
911 : // On the removal of a <treeitem>, <treechildren>, or <treecell> element,
912 : // the possibility exists that some of the items in the removed subtree
913 : // are selected (and therefore need to be deselected). We need to account for this.
914 136 : nsCOMPtr<nsIDOMXULMultiSelectControlElement> controlElement;
915 136 : nsCOMPtr<nsIListBoxObject> listBox;
916 68 : bool fireSelectionHandler = false;
917 :
918 : // -1 = do nothing, -2 = null out current item
919 : // anything else = index to re-set as current
920 68 : int32_t newCurrentIndex = -1;
921 :
922 68 : if (oldKid->NodeInfo()->Equals(nsGkAtoms::listitem, kNameSpaceID_XUL)) {
923 : // This is the nasty case. We have (potentially) a slew of selected items
924 : // and cells going away.
925 : // First, retrieve the tree.
926 : // Check first whether this element IS the tree
927 0 : controlElement = do_QueryObject(this);
928 :
929 : // If it's not, look at our parent
930 0 : if (!controlElement)
931 0 : GetParentTree(getter_AddRefs(controlElement));
932 0 : nsCOMPtr<nsIContent> controlContent(do_QueryInterface(controlElement));
933 0 : RefPtr<nsXULElement> xulElement = FromContentOrNull(controlContent);
934 :
935 0 : nsCOMPtr<nsIDOMElement> oldKidElem = do_QueryInterface(oldKid);
936 0 : if (xulElement && oldKidElem) {
937 : // Iterate over all of the items and find out if they are contained inside
938 : // the removed subtree.
939 : int32_t length;
940 0 : controlElement->GetSelectedCount(&length);
941 0 : for (int32_t i = 0; i < length; i++) {
942 0 : nsCOMPtr<nsIDOMXULSelectControlItemElement> node;
943 0 : controlElement->MultiGetSelectedItem(i, getter_AddRefs(node));
944 : // we need to QI here to do an XPCOM-correct pointercompare
945 0 : nsCOMPtr<nsIDOMElement> selElem = do_QueryInterface(node);
946 0 : if (selElem == oldKidElem &&
947 0 : NS_SUCCEEDED(controlElement->RemoveItemFromSelection(node))) {
948 0 : length--;
949 0 : i--;
950 0 : fireSelectionHandler = true;
951 : }
952 : }
953 :
954 0 : nsCOMPtr<nsIDOMXULSelectControlItemElement> curItem;
955 0 : controlElement->GetCurrentItem(getter_AddRefs(curItem));
956 0 : nsCOMPtr<nsIContent> curNode = do_QueryInterface(curItem);
957 0 : if (curNode && nsContentUtils::ContentIsDescendantOf(curNode, oldKid)) {
958 : // Current item going away
959 0 : IgnoredErrorResult ignored;
960 0 : nsCOMPtr<nsIBoxObject> box = xulElement->GetBoxObject(ignored);
961 0 : listBox = do_QueryInterface(box);
962 0 : if (listBox && oldKidElem) {
963 0 : listBox->GetIndexOfItem(oldKidElem, &newCurrentIndex);
964 : }
965 :
966 : // If any of this fails, we'll just set the current item to null
967 0 : if (newCurrentIndex == -1)
968 0 : newCurrentIndex = -2;
969 : }
970 : }
971 : }
972 :
973 68 : nsStyledElement::RemoveChildAt(aIndex, aNotify);
974 :
975 68 : if (newCurrentIndex == -2) {
976 0 : controlElement->SetCurrentItem(nullptr);
977 68 : } else if (newCurrentIndex > -1) {
978 : // Make sure the index is still valid
979 : int32_t treeRows;
980 0 : listBox->GetRowCount(&treeRows);
981 0 : if (treeRows > 0) {
982 0 : newCurrentIndex = std::min((treeRows - 1), newCurrentIndex);
983 0 : nsCOMPtr<nsIDOMElement> newCurrentItem;
984 0 : listBox->GetItemAtIndex(newCurrentIndex, getter_AddRefs(newCurrentItem));
985 0 : nsCOMPtr<nsIDOMXULSelectControlItemElement> xulCurItem = do_QueryInterface(newCurrentItem);
986 0 : if (xulCurItem)
987 0 : controlElement->SetCurrentItem(xulCurItem);
988 : } else {
989 0 : controlElement->SetCurrentItem(nullptr);
990 : }
991 : }
992 :
993 : nsIDocument* doc;
994 68 : if (fireSelectionHandler && (doc = GetComposedDoc())) {
995 0 : nsContentUtils::DispatchTrustedEvent(doc,
996 : static_cast<nsIContent*>(this),
997 0 : NS_LITERAL_STRING("select"),
998 : false,
999 0 : true);
1000 : }
1001 : }
1002 :
1003 : void
1004 15 : nsXULElement::UnregisterAccessKey(const nsAString& aOldValue)
1005 : {
1006 : // If someone changes the accesskey, unregister the old one
1007 : //
1008 15 : nsIDocument* doc = GetComposedDoc();
1009 15 : if (doc && !aOldValue.IsEmpty()) {
1010 15 : nsIPresShell *shell = doc->GetShell();
1011 :
1012 15 : if (shell) {
1013 15 : nsIContent *content = this;
1014 :
1015 : // find out what type of content node this is
1016 15 : if (mNodeInfo->Equals(nsGkAtoms::label)) {
1017 : // For anonymous labels the unregistering must
1018 : // occur on the binding parent control.
1019 : // XXXldb: And what if the binding parent is null?
1020 3 : content = GetBindingParent();
1021 : }
1022 :
1023 15 : if (content) {
1024 : shell->GetPresContext()->EventStateManager()->
1025 15 : UnregisterAccessKey(content, aOldValue.First());
1026 : }
1027 : }
1028 : }
1029 15 : }
1030 :
1031 : nsresult
1032 1035 : nsXULElement::BeforeSetAttr(int32_t aNamespaceID, nsIAtom* aName,
1033 : const nsAttrValueOrString* aValue, bool aNotify)
1034 : {
1035 1096 : if (aNamespaceID == kNameSpaceID_None && aName == nsGkAtoms::accesskey &&
1036 61 : IsInUncomposedDoc()) {
1037 84 : nsAutoString oldValue;
1038 42 : if (GetAttr(aNamespaceID, aName, oldValue)) {
1039 15 : UnregisterAccessKey(oldValue);
1040 : }
1041 1964 : } else if (aNamespaceID == kNameSpaceID_None &&
1042 1964 : (aName == nsGkAtoms::command || aName == nsGkAtoms::observes) &&
1043 9 : IsInUncomposedDoc()) {
1044 : // XXX sXBL/XBL2 issue! Owner or current document?
1045 18 : nsAutoString oldValue;
1046 9 : GetAttr(kNameSpaceID_None, nsGkAtoms::observes, oldValue);
1047 9 : if (oldValue.IsEmpty()) {
1048 9 : GetAttr(kNameSpaceID_None, nsGkAtoms::command, oldValue);
1049 : }
1050 :
1051 9 : if (!oldValue.IsEmpty()) {
1052 9 : RemoveBroadcaster(oldValue);
1053 : }
1054 1946 : } else if (aNamespaceID == kNameSpaceID_None &&
1055 922 : aValue &&
1056 1911 : mNodeInfo->Equals(nsGkAtoms::window) &&
1057 5 : aName == nsGkAtoms::chromemargin) {
1058 0 : nsAttrValue attrValue;
1059 : // Make sure the margin format is valid first
1060 0 : if (!attrValue.ParseIntMarginValue(aValue->String())) {
1061 0 : return NS_ERROR_INVALID_ARG;
1062 : }
1063 1946 : } else if (aNamespaceID == kNameSpaceID_None &&
1064 962 : aName == nsGkAtoms::usercontextid) {
1065 0 : nsAutoString oldValue;
1066 0 : bool hasAttribute = GetAttr(kNameSpaceID_None, nsGkAtoms::usercontextid, oldValue);
1067 0 : if (hasAttribute && (!aValue || !aValue->String().Equals(oldValue))) {
1068 0 : MOZ_ASSERT(false, "Changing usercontextid is not allowed.");
1069 : return NS_ERROR_INVALID_ARG;
1070 : }
1071 : }
1072 :
1073 1035 : return nsStyledElement::BeforeSetAttr(aNamespaceID, aName,
1074 1035 : aValue, aNotify);
1075 : }
1076 :
1077 : nsresult
1078 1035 : nsXULElement::AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
1079 : const nsAttrValue* aValue,
1080 : const nsAttrValue* aOldValue, bool aNotify)
1081 : {
1082 1035 : if (aNamespaceID == kNameSpaceID_None) {
1083 1013 : if (aValue) {
1084 : // Add popup and event listeners. We can't call AddListenerFor since
1085 : // the attribute isn't set yet.
1086 973 : MaybeAddPopupListener(aName);
1087 973 : if (nsContentUtils::IsEventAttributeName(aName, EventNameType_XUL)) {
1088 75 : if (aValue->Type() == nsAttrValue::eString) {
1089 60 : SetEventHandler(aName, aValue->GetStringValue(), true);
1090 : } else {
1091 30 : nsAutoString body;
1092 15 : aValue->ToString(body);
1093 15 : SetEventHandler(aName, body, true);
1094 : }
1095 : }
1096 :
1097 973 : nsIDocument* document = GetUncomposedDoc();
1098 :
1099 : // Hide chrome if needed
1100 973 : if (mNodeInfo->Equals(nsGkAtoms::window)) {
1101 5 : if (aName == nsGkAtoms::hidechrome) {
1102 0 : HideWindowChrome(
1103 0 : aValue->Equals(NS_LITERAL_STRING("true"), eCaseMatters));
1104 5 : } else if (aName == nsGkAtoms::chromemargin) {
1105 0 : SetChromeMargins(aValue);
1106 10 : } else if (aName == nsGkAtoms::windowtype &&
1107 5 : document && document->GetRootElement() == this) {
1108 0 : MaybeUpdatePrivateLifetime();
1109 : }
1110 : }
1111 : // title, (in)activetitlebarcolor and drawintitlebar are settable on
1112 : // any root node (windows, dialogs, etc)
1113 973 : if (document && document->GetRootElement() == this) {
1114 5 : if (aName == nsGkAtoms::title) {
1115 0 : document->NotifyPossibleTitleChange(false);
1116 10 : } else if ((aName == nsGkAtoms::activetitlebarcolor ||
1117 5 : aName == nsGkAtoms::inactivetitlebarcolor)) {
1118 0 : nscolor color = NS_RGBA(0, 0, 0, 0);
1119 0 : if (aValue->Type() == nsAttrValue::eColor) {
1120 0 : aValue->GetColorValue(color);
1121 : } else {
1122 0 : nsAutoString tmp;
1123 0 : nsAttrValue attrValue;
1124 0 : aValue->ToString(tmp);
1125 0 : attrValue.ParseColor(tmp);
1126 0 : attrValue.GetColorValue(color);
1127 : }
1128 0 : SetTitlebarColor(color, aName == nsGkAtoms::activetitlebarcolor);
1129 5 : } else if (aName == nsGkAtoms::drawintitlebar) {
1130 0 : SetDrawsInTitlebar(
1131 0 : aValue->Equals(NS_LITERAL_STRING("true"), eCaseMatters));
1132 5 : } else if (aName == nsGkAtoms::drawtitle) {
1133 0 : SetDrawsTitle(
1134 0 : aValue->Equals(NS_LITERAL_STRING("true"), eCaseMatters));
1135 5 : } else if (aName == nsGkAtoms::localedir) {
1136 : // if the localedir changed on the root element, reset the document direction
1137 0 : nsCOMPtr<nsIXULDocument> xuldoc = do_QueryInterface(document);
1138 0 : if (xuldoc) {
1139 0 : xuldoc->ResetDocumentDirection();
1140 : }
1141 10 : } else if (aName == nsGkAtoms::lwtheme ||
1142 5 : aName == nsGkAtoms::lwthemetextcolor) {
1143 : // if the lwtheme changed, make sure to reset the document lwtheme cache
1144 0 : nsCOMPtr<nsIXULDocument> xuldoc = do_QueryInterface(document);
1145 0 : if (xuldoc) {
1146 0 : xuldoc->ResetDocumentLWTheme();
1147 0 : UpdateBrightTitlebarForeground(document);
1148 0 : }
1149 5 : } else if (aName == nsGkAtoms::brighttitlebarforeground) {
1150 0 : UpdateBrightTitlebarForeground(document);
1151 : }
1152 : }
1153 :
1154 973 : if (aName == nsGkAtoms::src && document) {
1155 1 : LoadSrc();
1156 : }
1157 : } else {
1158 40 : if (mNodeInfo->Equals(nsGkAtoms::window)) {
1159 0 : if (aName == nsGkAtoms::hidechrome) {
1160 0 : HideWindowChrome(false);
1161 0 : } else if (aName == nsGkAtoms::chromemargin) {
1162 0 : ResetChromeMargins();
1163 : }
1164 : }
1165 :
1166 40 : nsIDocument* doc = GetUncomposedDoc();
1167 40 : if (doc && doc->GetRootElement() == this) {
1168 0 : if ((aName == nsGkAtoms::activetitlebarcolor ||
1169 0 : aName == nsGkAtoms::inactivetitlebarcolor)) {
1170 : // Use 0, 0, 0, 0 as the "none" color.
1171 0 : SetTitlebarColor(NS_RGBA(0, 0, 0, 0), aName == nsGkAtoms::activetitlebarcolor);
1172 0 : } else if (aName == nsGkAtoms::localedir) {
1173 : // if the localedir changed on the root element, reset the document direction
1174 0 : nsCOMPtr<nsIXULDocument> xuldoc = do_QueryInterface(doc);
1175 0 : if (xuldoc) {
1176 0 : xuldoc->ResetDocumentDirection();
1177 : }
1178 0 : } else if ((aName == nsGkAtoms::lwtheme ||
1179 0 : aName == nsGkAtoms::lwthemetextcolor)) {
1180 : // if the lwtheme changed, make sure to restyle appropriately
1181 0 : nsCOMPtr<nsIXULDocument> xuldoc = do_QueryInterface(doc);
1182 0 : if (xuldoc) {
1183 0 : xuldoc->ResetDocumentLWTheme();
1184 0 : UpdateBrightTitlebarForeground(doc);
1185 0 : }
1186 0 : } else if (aName == nsGkAtoms::brighttitlebarforeground) {
1187 0 : UpdateBrightTitlebarForeground(doc);
1188 0 : } else if (aName == nsGkAtoms::drawintitlebar) {
1189 0 : SetDrawsInTitlebar(false);
1190 0 : } else if (aName == nsGkAtoms::drawtitle) {
1191 0 : SetDrawsTitle(false);
1192 : }
1193 : }
1194 : }
1195 :
1196 : // XXX need to check if they're changing an event handler: if
1197 : // so, then we need to unhook the old one. Or something.
1198 : }
1199 :
1200 1035 : return nsStyledElement::AfterSetAttr(aNamespaceID, aName,
1201 1035 : aValue, aOldValue, aNotify);
1202 : }
1203 :
1204 : bool
1205 969 : nsXULElement::ParseAttribute(int32_t aNamespaceID,
1206 : nsIAtom* aAttribute,
1207 : const nsAString& aValue,
1208 : nsAttrValue& aResult)
1209 : {
1210 : // Parse into a nsAttrValue
1211 969 : if (!nsStyledElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
1212 : aResult)) {
1213 : // Fall back to parsing as atom for short values
1214 918 : aResult.ParseStringOrAtom(aValue);
1215 : }
1216 :
1217 969 : return true;
1218 : }
1219 :
1220 : void
1221 9 : nsXULElement::RemoveBroadcaster(const nsAString & broadcasterId)
1222 : {
1223 18 : nsCOMPtr<nsIDOMXULDocument> xuldoc = do_QueryInterface(OwnerDoc());
1224 9 : if (xuldoc) {
1225 18 : nsCOMPtr<nsIDOMElement> broadcaster;
1226 18 : nsCOMPtr<nsIDOMDocument> domDoc (do_QueryInterface(xuldoc));
1227 9 : domDoc->GetElementById(broadcasterId, getter_AddRefs(broadcaster));
1228 9 : if (broadcaster) {
1229 18 : xuldoc->RemoveBroadcastListenerFor(broadcaster, this,
1230 18 : NS_LITERAL_STRING("*"));
1231 : }
1232 : }
1233 9 : }
1234 :
1235 : void
1236 0 : nsXULElement::DestroyContent()
1237 : {
1238 0 : nsXULSlots* slots = static_cast<nsXULSlots*>(GetExistingDOMSlots());
1239 0 : if (slots) {
1240 0 : NS_IF_RELEASE(slots->mControllers);
1241 0 : RefPtr<nsFrameLoader> frameLoader = GetFrameLoader();
1242 0 : if (frameLoader) {
1243 0 : frameLoader->Destroy();
1244 : }
1245 0 : slots->mFrameLoaderOrOpener = nullptr;
1246 : }
1247 :
1248 0 : nsStyledElement::DestroyContent();
1249 0 : }
1250 :
1251 : #ifdef DEBUG
1252 : void
1253 0 : nsXULElement::List(FILE* out, int32_t aIndent) const
1254 : {
1255 0 : nsCString prefix("XUL");
1256 0 : if (HasSlots()) {
1257 0 : prefix.Append('*');
1258 : }
1259 0 : prefix.Append(' ');
1260 :
1261 0 : nsStyledElement::List(out, aIndent, prefix);
1262 0 : }
1263 : #endif
1264 :
1265 : bool
1266 1302 : nsXULElement::IsEventStoppedFromAnonymousScrollbar(EventMessage aMessage)
1267 : {
1268 1302 : return (IsRootOfNativeAnonymousSubtree() &&
1269 1302 : IsAnyOfXULElements(nsGkAtoms::scrollbar, nsGkAtoms::scrollcorner) &&
1270 0 : (aMessage == eMouseClick || aMessage == eMouseDoubleClick ||
1271 0 : aMessage == eXULCommand || aMessage == eContextMenu ||
1272 1302 : aMessage == eDragStart || aMessage == eMouseAuxClick));
1273 : }
1274 :
1275 : nsresult
1276 0 : nsXULElement::DispatchXULCommand(const EventChainVisitor& aVisitor,
1277 : nsAutoString& aCommand)
1278 : {
1279 : // XXX sXBL/XBL2 issue! Owner or current document?
1280 0 : nsCOMPtr<nsIDOMDocument> domDoc(do_QueryInterface(GetUncomposedDoc()));
1281 0 : NS_ENSURE_STATE(domDoc);
1282 0 : nsCOMPtr<nsIDOMElement> commandElt;
1283 0 : domDoc->GetElementById(aCommand, getter_AddRefs(commandElt));
1284 0 : nsCOMPtr<nsIContent> commandContent(do_QueryInterface(commandElt));
1285 0 : if (commandContent) {
1286 : // Create a new command event to dispatch to the element
1287 : // pointed to by the command attribute. The new event's
1288 : // sourceEvent will be the original command event that we're
1289 : // handling.
1290 0 : nsCOMPtr<nsIDOMEvent> domEvent = aVisitor.mDOMEvent;
1291 0 : while (domEvent) {
1292 0 : Event* event = domEvent->InternalDOMEvent();
1293 0 : NS_ENSURE_STATE(!SameCOMIdentity(event->GetOriginalTarget(),
1294 : commandContent));
1295 : nsCOMPtr<nsIDOMXULCommandEvent> commandEvent =
1296 0 : do_QueryInterface(domEvent);
1297 0 : if (commandEvent) {
1298 0 : commandEvent->GetSourceEvent(getter_AddRefs(domEvent));
1299 : } else {
1300 0 : domEvent = nullptr;
1301 : }
1302 : }
1303 0 : WidgetInputEvent* orig = aVisitor.mEvent->AsInputEvent();
1304 0 : nsContentUtils::DispatchXULCommand(
1305 : commandContent,
1306 0 : orig->IsTrusted(),
1307 0 : aVisitor.mDOMEvent,
1308 : nullptr,
1309 0 : orig->IsControl(),
1310 0 : orig->IsAlt(),
1311 0 : orig->IsShift(),
1312 0 : orig->IsMeta());
1313 : } else {
1314 0 : NS_WARNING("A XUL element is attached to a command that doesn't exist!\n");
1315 : }
1316 0 : return NS_OK;
1317 : }
1318 :
1319 : nsresult
1320 1302 : nsXULElement::GetEventTargetParent(EventChainPreVisitor& aVisitor)
1321 : {
1322 1302 : aVisitor.mForceContentDispatch = true; //FIXME! Bug 329119
1323 1302 : if (IsEventStoppedFromAnonymousScrollbar(aVisitor.mEvent->mMessage)) {
1324 : // Don't propagate these events from native anonymous scrollbar.
1325 0 : aVisitor.mCanHandle = true;
1326 0 : aVisitor.mParentTarget = nullptr;
1327 0 : return NS_OK;
1328 : }
1329 2604 : if (aVisitor.mEvent->mMessage == eXULCommand &&
1330 0 : aVisitor.mEvent->mClass == eInputEventClass &&
1331 1302 : aVisitor.mEvent->mOriginalTarget == static_cast<nsIContent*>(this) &&
1332 0 : !IsXULElement(nsGkAtoms::command)) {
1333 : // Check that we really have an xul command event. That will be handled
1334 : // in a special way.
1335 : nsCOMPtr<nsIDOMXULCommandEvent> xulEvent =
1336 0 : do_QueryInterface(aVisitor.mDOMEvent);
1337 : // See if we have a command elt. If so, we execute on the command
1338 : // instead of on our content element.
1339 0 : nsAutoString command;
1340 0 : if (xulEvent &&
1341 0 : GetAttr(kNameSpaceID_None, nsGkAtoms::command, command) &&
1342 0 : !command.IsEmpty()) {
1343 : // Stop building the event target chain for the original event.
1344 : // We don't want it to propagate to any DOM nodes.
1345 0 : aVisitor.mCanHandle = false;
1346 0 : aVisitor.mAutomaticChromeDispatch = false;
1347 : // Dispatch XUL command in PreHandleEvent to prevent it breaks event
1348 : // target chain creation
1349 0 : aVisitor.mWantsPreHandleEvent = true;
1350 0 : aVisitor.mItemFlags |= NS_DISPATCH_XUL_COMMAND;
1351 0 : return NS_OK;
1352 : }
1353 : }
1354 :
1355 1302 : return nsStyledElement::GetEventTargetParent(aVisitor);
1356 : }
1357 :
1358 : nsresult
1359 0 : nsXULElement::PreHandleEvent(EventChainVisitor& aVisitor)
1360 : {
1361 0 : if (aVisitor.mItemFlags & NS_DISPATCH_XUL_COMMAND) {
1362 0 : nsAutoString command;
1363 0 : GetAttr(kNameSpaceID_None, nsGkAtoms::command, command);
1364 0 : MOZ_ASSERT(!command.IsEmpty());
1365 0 : return DispatchXULCommand(aVisitor, command);
1366 : }
1367 0 : return nsStyledElement::PreHandleEvent(aVisitor);
1368 : }
1369 :
1370 : // XXX This _should_ be an implementation method, _not_ publicly exposed :-(
1371 : already_AddRefed<nsIRDFResource>
1372 0 : nsXULElement::GetResource(ErrorResult& rv)
1373 : {
1374 0 : nsAutoString id;
1375 0 : GetAttr(kNameSpaceID_None, nsGkAtoms::ref, id);
1376 0 : if (id.IsEmpty()) {
1377 0 : GetAttr(kNameSpaceID_None, nsGkAtoms::id, id);
1378 : }
1379 :
1380 0 : if (id.IsEmpty()) {
1381 0 : return nullptr;
1382 : }
1383 :
1384 0 : nsCOMPtr<nsIRDFResource> resource;
1385 0 : rv = nsXULContentUtils::RDFService()->
1386 0 : GetUnicodeResource(id, getter_AddRefs(resource));
1387 0 : return resource.forget();
1388 : }
1389 :
1390 : already_AddRefed<nsIRDFCompositeDataSource>
1391 1888 : nsXULElement::GetDatabase()
1392 : {
1393 3776 : nsCOMPtr<nsIXULTemplateBuilder> builder = GetBuilder();
1394 1888 : if (!builder) {
1395 1888 : return nullptr;
1396 : }
1397 :
1398 0 : nsCOMPtr<nsIRDFCompositeDataSource> database;
1399 0 : builder->GetDatabase(getter_AddRefs(database));
1400 0 : return database.forget();
1401 : }
1402 :
1403 :
1404 : already_AddRefed<nsIXULTemplateBuilder>
1405 1888 : nsXULElement::GetBuilder()
1406 : {
1407 : // XXX sXBL/XBL2 issue! Owner or current document?
1408 3776 : nsCOMPtr<nsIXULDocument> xuldoc = do_QueryInterface(GetUncomposedDoc());
1409 1888 : if (!xuldoc) {
1410 0 : return nullptr;
1411 : }
1412 :
1413 3776 : nsCOMPtr<nsIXULTemplateBuilder> builder;
1414 1888 : xuldoc->GetTemplateBuilderFor(this, getter_AddRefs(builder));
1415 1888 : return builder.forget();
1416 : }
1417 :
1418 : //----------------------------------------------------------------------
1419 : // Implementation methods
1420 :
1421 : NS_IMETHODIMP
1422 2091 : nsXULElement::WalkContentStyleRules(nsRuleWalker* aRuleWalker)
1423 : {
1424 2091 : return NS_OK;
1425 : }
1426 :
1427 : nsChangeHint
1428 321 : nsXULElement::GetAttributeChangeHint(const nsIAtom* aAttribute,
1429 : int32_t aModType) const
1430 : {
1431 321 : nsChangeHint retval(nsChangeHint(0));
1432 :
1433 321 : if (aAttribute == nsGkAtoms::value &&
1434 14 : (aModType == nsIDOMMutationEvent::REMOVAL ||
1435 : aModType == nsIDOMMutationEvent::ADDITION)) {
1436 12 : if (IsAnyOfXULElements(nsGkAtoms::label, nsGkAtoms::description))
1437 : // Label and description dynamically morph between a normal
1438 : // block and a cropping single-line XUL text frame. If the
1439 : // value attribute is being added or removed, then we need to
1440 : // return a hint of frame change. (See bugzilla bug 95475 for
1441 : // details.)
1442 5 : retval = nsChangeHint_ReconstructFrame;
1443 : } else {
1444 : // if left or top changes we reflow. This will happen in xul
1445 : // containers that manage positioned children such as a stack.
1446 630 : if (nsGkAtoms::left == aAttribute || nsGkAtoms::top == aAttribute ||
1447 945 : nsGkAtoms::right == aAttribute || nsGkAtoms::bottom == aAttribute ||
1448 630 : nsGkAtoms::start == aAttribute || nsGkAtoms::end == aAttribute)
1449 0 : retval = NS_STYLE_HINT_REFLOW;
1450 : }
1451 :
1452 321 : return retval;
1453 : }
1454 :
1455 : NS_IMETHODIMP_(bool)
1456 1303 : nsXULElement::IsAttributeMapped(const nsIAtom* aAttribute) const
1457 : {
1458 1303 : return false;
1459 : }
1460 :
1461 : nsIControllers*
1462 12 : nsXULElement::GetControllers(ErrorResult& rv)
1463 : {
1464 12 : if (! Controllers()) {
1465 1 : nsDOMSlots* slots = DOMSlots();
1466 :
1467 1 : rv = NS_NewXULControllers(nullptr, NS_GET_IID(nsIControllers),
1468 2 : reinterpret_cast<void**>(&slots->mControllers));
1469 :
1470 1 : NS_ASSERTION(!rv.Failed(), "unable to create a controllers");
1471 1 : if (rv.Failed()) {
1472 0 : return nullptr;
1473 : }
1474 : }
1475 :
1476 12 : return Controllers();
1477 : }
1478 :
1479 : already_AddRefed<BoxObject>
1480 12 : nsXULElement::GetBoxObject(ErrorResult& rv)
1481 : {
1482 : // XXX sXBL/XBL2 issue! Owner or current document?
1483 12 : return OwnerDoc()->GetBoxObjectFor(this, rv);
1484 : }
1485 :
1486 : nsresult
1487 2252 : nsXULElement::LoadSrc()
1488 : {
1489 : // Allow frame loader only on objects for which a container box object
1490 : // can be obtained.
1491 2252 : if (!IsAnyOfXULElements(nsGkAtoms::browser, nsGkAtoms::editor,
1492 : nsGkAtoms::iframe)) {
1493 2248 : return NS_OK;
1494 : }
1495 12 : if (!IsInUncomposedDoc() ||
1496 8 : !OwnerDoc()->GetRootElement() ||
1497 4 : OwnerDoc()->GetRootElement()->
1498 8 : NodeInfo()->Equals(nsGkAtoms::overlay, kNameSpaceID_XUL)) {
1499 0 : return NS_OK;
1500 : }
1501 8 : RefPtr<nsFrameLoader> frameLoader = GetFrameLoader();
1502 4 : if (!frameLoader) {
1503 : // Check if we have an opener we need to be setting
1504 4 : nsXULSlots* slots = static_cast<nsXULSlots*>(Slots());
1505 8 : nsCOMPtr<nsPIDOMWindowOuter> opener = do_QueryInterface(slots->mFrameLoaderOrOpener);
1506 4 : if (!opener) {
1507 : // If we are a primary xul-browser, we want to take the opener property!
1508 8 : nsCOMPtr<nsIDOMChromeWindow> chromeWindow = do_QueryInterface(OwnerDoc()->GetWindow());
1509 8 : if (AttrValueIs(kNameSpaceID_None, nsGkAtoms::primary,
1510 7 : nsGkAtoms::_true, eIgnoreCase) &&
1511 3 : chromeWindow) {
1512 4 : nsCOMPtr<mozIDOMWindowProxy> wp;
1513 2 : chromeWindow->TakeOpenerForInitialContentBrowser(getter_AddRefs(wp));
1514 2 : opener = nsPIDOMWindowOuter::From(wp);
1515 : }
1516 : }
1517 :
1518 : // false as the last parameter so that xul:iframe/browser/editor
1519 : // session history handling works like dynamic html:iframes.
1520 : // Usually xul elements are used in chrome, which doesn't have
1521 : // session history at all.
1522 4 : frameLoader = nsFrameLoader::Create(this, opener, false);
1523 4 : slots->mFrameLoaderOrOpener = static_cast<nsIFrameLoader*>(frameLoader);
1524 4 : NS_ENSURE_TRUE(frameLoader, NS_OK);
1525 :
1526 : (new AsyncEventDispatcher(this,
1527 8 : NS_LITERAL_STRING("XULFrameLoaderCreated"),
1528 8 : /* aBubbles */ true))->RunDOMEventWhenSafe();
1529 :
1530 8 : if (AttrValueIs(kNameSpaceID_None, nsGkAtoms::prerendered,
1531 8 : NS_LITERAL_STRING("true"), eIgnoreCase)) {
1532 0 : nsresult rv = frameLoader->SetIsPrerendered();
1533 0 : NS_ENSURE_SUCCESS(rv,rv);
1534 : }
1535 : }
1536 :
1537 4 : return frameLoader->LoadFrame();
1538 : }
1539 :
1540 : nsresult
1541 0 : nsXULElement::GetFrameLoaderXPCOM(nsIFrameLoader **aFrameLoader)
1542 : {
1543 0 : *aFrameLoader = GetFrameLoader().take();
1544 0 : return NS_OK;
1545 : }
1546 :
1547 : already_AddRefed<nsFrameLoader>
1548 214 : nsXULElement::GetFrameLoader()
1549 : {
1550 214 : nsXULSlots* slots = static_cast<nsXULSlots*>(GetExistingSlots());
1551 214 : if (!slots)
1552 3 : return nullptr;
1553 :
1554 422 : nsCOMPtr<nsIFrameLoader> loader = do_QueryInterface(slots->mFrameLoaderOrOpener);
1555 211 : return already_AddRefed<nsFrameLoader>(static_cast<nsFrameLoader*>(loader.forget().take()));
1556 : }
1557 :
1558 : void
1559 0 : nsXULElement::PresetOpenerWindow(mozIDOMWindowProxy* aWindow, ErrorResult& aRv)
1560 : {
1561 0 : nsXULSlots* slots = static_cast<nsXULSlots*>(Slots());
1562 0 : MOZ_ASSERT(!slots->mFrameLoaderOrOpener, "A frameLoader or opener is present when calling PresetOpenerWindow");
1563 :
1564 0 : slots->mFrameLoaderOrOpener = aWindow;
1565 0 : }
1566 :
1567 : nsresult
1568 0 : nsXULElement::SetIsPrerendered()
1569 : {
1570 0 : return SetAttr(kNameSpaceID_None, nsGkAtoms::prerendered, nullptr,
1571 0 : NS_LITERAL_STRING("true"), true);
1572 : }
1573 :
1574 : void
1575 0 : nsXULElement::InternalSetFrameLoader(nsIFrameLoader* aNewFrameLoader)
1576 : {
1577 0 : nsXULSlots* slots = static_cast<nsXULSlots*>(GetExistingDOMSlots());
1578 0 : MOZ_ASSERT(slots);
1579 :
1580 0 : slots->mFrameLoaderOrOpener = aNewFrameLoader;
1581 0 : }
1582 :
1583 : void
1584 0 : nsXULElement::SwapFrameLoaders(HTMLIFrameElement& aOtherLoaderOwner,
1585 : ErrorResult& rv)
1586 : {
1587 0 : if (!GetExistingDOMSlots()) {
1588 0 : rv.Throw(NS_ERROR_NOT_IMPLEMENTED);
1589 0 : return;
1590 : }
1591 :
1592 0 : nsCOMPtr<nsIFrameLoaderOwner> flo = do_QueryInterface(static_cast<nsIDOMXULElement*>(this));
1593 0 : aOtherLoaderOwner.SwapFrameLoaders(flo, rv);
1594 : }
1595 :
1596 : void
1597 0 : nsXULElement::SwapFrameLoaders(nsXULElement& aOtherLoaderOwner,
1598 : ErrorResult& rv)
1599 : {
1600 0 : if (&aOtherLoaderOwner == this) {
1601 : // nothing to do
1602 0 : return;
1603 : }
1604 :
1605 0 : if (!GetExistingDOMSlots()) {
1606 0 : rv.Throw(NS_ERROR_NOT_IMPLEMENTED);
1607 0 : return;
1608 : }
1609 :
1610 0 : nsCOMPtr<nsIFrameLoaderOwner> flo = do_QueryInterface(static_cast<nsIDOMXULElement*>(this));
1611 0 : aOtherLoaderOwner.SwapFrameLoaders(flo, rv);
1612 : }
1613 :
1614 : void
1615 0 : nsXULElement::SwapFrameLoaders(nsIFrameLoaderOwner* aOtherLoaderOwner,
1616 : mozilla::ErrorResult& rv)
1617 : {
1618 0 : if (!GetExistingDOMSlots()) {
1619 0 : rv.Throw(NS_ERROR_NOT_IMPLEMENTED);
1620 0 : return;
1621 : }
1622 :
1623 0 : RefPtr<nsFrameLoader> loader = GetFrameLoader();
1624 0 : RefPtr<nsFrameLoader> otherLoader = aOtherLoaderOwner->GetFrameLoader();
1625 0 : if (!loader || !otherLoader) {
1626 0 : rv.Throw(NS_ERROR_NOT_IMPLEMENTED);
1627 0 : return;
1628 : }
1629 :
1630 0 : nsCOMPtr<nsIFrameLoaderOwner> flo = do_QueryInterface(static_cast<nsIDOMXULElement*>(this));
1631 0 : rv = loader->SwapWithOtherLoader(otherLoader, flo, aOtherLoaderOwner);
1632 : }
1633 :
1634 : NS_IMETHODIMP
1635 0 : nsXULElement::GetParentTree(nsIDOMXULMultiSelectControlElement** aTreeElement)
1636 : {
1637 0 : for (nsIContent* current = GetParent(); current;
1638 0 : current = current->GetParent()) {
1639 0 : if (current->NodeInfo()->Equals(nsGkAtoms::listbox,
1640 : kNameSpaceID_XUL)) {
1641 0 : CallQueryInterface(current, aTreeElement);
1642 : // XXX returning NS_OK because that's what the code used to do;
1643 : // is that the right thing, though?
1644 :
1645 0 : return NS_OK;
1646 : }
1647 : }
1648 :
1649 0 : return NS_OK;
1650 : }
1651 :
1652 : void
1653 0 : nsXULElement::Click(CallerType aCallerType)
1654 : {
1655 0 : ClickWithInputSource(nsIDOMMouseEvent::MOZ_SOURCE_UNKNOWN,
1656 0 : aCallerType == CallerType::System);
1657 0 : }
1658 :
1659 : void
1660 0 : nsXULElement::ClickWithInputSource(uint16_t aInputSource, bool aIsTrustedEvent)
1661 : {
1662 0 : if (BoolAttrIsTrue(nsGkAtoms::disabled))
1663 0 : return;
1664 :
1665 0 : nsCOMPtr<nsIDocument> doc = GetComposedDoc(); // Strong just in case
1666 0 : if (doc) {
1667 0 : nsCOMPtr<nsIPresShell> shell = doc->GetShell();
1668 0 : if (shell) {
1669 : // strong ref to PresContext so events don't destroy it
1670 0 : RefPtr<nsPresContext> context = shell->GetPresContext();
1671 :
1672 : WidgetMouseEvent eventDown(aIsTrustedEvent, eMouseDown,
1673 0 : nullptr, WidgetMouseEvent::eReal);
1674 : WidgetMouseEvent eventUp(aIsTrustedEvent, eMouseUp,
1675 0 : nullptr, WidgetMouseEvent::eReal);
1676 : WidgetMouseEvent eventClick(aIsTrustedEvent, eMouseClick, nullptr,
1677 0 : WidgetMouseEvent::eReal);
1678 0 : eventDown.inputSource = eventUp.inputSource = eventClick.inputSource
1679 0 : = aInputSource;
1680 :
1681 : // send mouse down
1682 0 : nsEventStatus status = nsEventStatus_eIgnore;
1683 0 : EventDispatcher::Dispatch(static_cast<nsIContent*>(this),
1684 0 : context, &eventDown, nullptr, &status);
1685 :
1686 : // send mouse up
1687 0 : status = nsEventStatus_eIgnore; // reset status
1688 0 : EventDispatcher::Dispatch(static_cast<nsIContent*>(this),
1689 0 : context, &eventUp, nullptr, &status);
1690 :
1691 : // send mouse click
1692 0 : status = nsEventStatus_eIgnore; // reset status
1693 0 : EventDispatcher::Dispatch(static_cast<nsIContent*>(this),
1694 0 : context, &eventClick, nullptr, &status);
1695 :
1696 : // If the click has been prevented, lets skip the command call
1697 : // this is how a physical click works
1698 0 : if (status == nsEventStatus_eConsumeNoDefault) {
1699 0 : return;
1700 : }
1701 : }
1702 : }
1703 :
1704 : // oncommand is fired when an element is clicked...
1705 0 : DoCommand();
1706 : }
1707 :
1708 : void
1709 0 : nsXULElement::DoCommand()
1710 : {
1711 0 : nsCOMPtr<nsIDocument> doc = GetComposedDoc(); // strong just in case
1712 0 : if (doc) {
1713 0 : nsContentUtils::DispatchXULCommand(this, true);
1714 : }
1715 0 : }
1716 :
1717 : nsIContent *
1718 223709 : nsXULElement::GetBindingParent() const
1719 : {
1720 223709 : return mBindingParent;
1721 : }
1722 :
1723 : bool
1724 150780 : nsXULElement::IsNodeOfType(uint32_t aFlags) const
1725 : {
1726 150780 : return !(aFlags & ~eCONTENT);
1727 : }
1728 :
1729 : nsresult
1730 25 : nsXULElement::AddPopupListener(nsIAtom* aName)
1731 : {
1732 : // Add a popup listener to the element
1733 26 : bool isContext = (aName == nsGkAtoms::context ||
1734 26 : aName == nsGkAtoms::contextmenu);
1735 25 : uint32_t listenerFlag = isContext ?
1736 : XUL_ELEMENT_HAS_CONTENTMENU_LISTENER :
1737 25 : XUL_ELEMENT_HAS_POPUP_LISTENER;
1738 :
1739 25 : if (HasFlag(listenerFlag)) {
1740 0 : return NS_OK;
1741 : }
1742 :
1743 : nsCOMPtr<nsIDOMEventListener> listener =
1744 50 : new nsXULPopupListener(this, isContext);
1745 :
1746 : // Add the popup as a listener on this element.
1747 25 : EventListenerManager* manager = GetOrCreateListenerManager();
1748 25 : SetFlags(listenerFlag);
1749 :
1750 25 : if (isContext) {
1751 25 : manager->AddEventListenerByType(listener,
1752 50 : NS_LITERAL_STRING("contextmenu"),
1753 100 : TrustedEventsAtSystemGroupBubble());
1754 : } else {
1755 0 : manager->AddEventListenerByType(listener,
1756 0 : NS_LITERAL_STRING("mousedown"),
1757 0 : TrustedEventsAtSystemGroupBubble());
1758 : }
1759 25 : return NS_OK;
1760 : }
1761 :
1762 : EventStates
1763 4746 : nsXULElement::IntrinsicState() const
1764 : {
1765 4746 : EventStates state = nsStyledElement::IntrinsicState();
1766 :
1767 4746 : if (IsReadWriteTextElement()) {
1768 13 : state |= NS_EVENT_STATE_MOZ_READWRITE;
1769 13 : state &= ~NS_EVENT_STATE_MOZ_READONLY;
1770 : }
1771 :
1772 4746 : return state;
1773 : }
1774 :
1775 : //----------------------------------------------------------------------
1776 :
1777 : nsresult
1778 1667 : nsXULElement::MakeHeavyweight(nsXULPrototypeElement* aPrototype)
1779 : {
1780 1667 : if (!aPrototype) {
1781 0 : return NS_OK;
1782 : }
1783 :
1784 : uint32_t i;
1785 : nsresult rv;
1786 6689 : for (i = 0; i < aPrototype->mNumAttributes; ++i) {
1787 5022 : nsXULPrototypeAttribute* protoattr = &aPrototype->mAttributes[i];
1788 10044 : nsAttrValue attrValue;
1789 :
1790 : // Style rules need to be cloned.
1791 5022 : if (protoattr->mValue.Type() == nsAttrValue::eCSSDeclaration) {
1792 7 : DeclarationBlock* decl = protoattr->mValue.GetCSSDeclarationValue();
1793 14 : RefPtr<DeclarationBlock> declClone = decl->Clone();
1794 :
1795 14 : nsString stringValue;
1796 7 : protoattr->mValue.ToString(stringValue);
1797 :
1798 7 : attrValue.SetTo(declClone.forget(), &stringValue);
1799 : } else {
1800 5015 : attrValue.SetTo(protoattr->mValue);
1801 : }
1802 :
1803 : bool oldValueSet;
1804 : // XXX we might wanna have a SetAndTakeAttr that takes an nsAttrName
1805 5022 : if (protoattr->mName.IsAtom()) {
1806 4807 : rv = mAttrsAndChildren.SetAndSwapAttr(protoattr->mName.Atom(),
1807 4807 : attrValue, &oldValueSet);
1808 : } else {
1809 215 : rv = mAttrsAndChildren.SetAndSwapAttr(protoattr->mName.NodeInfo(),
1810 215 : attrValue, &oldValueSet);
1811 : }
1812 5022 : NS_ENSURE_SUCCESS(rv, rv);
1813 : }
1814 1667 : return NS_OK;
1815 : }
1816 :
1817 : nsresult
1818 0 : nsXULElement::HideWindowChrome(bool aShouldHide)
1819 : {
1820 0 : nsIDocument* doc = GetUncomposedDoc();
1821 0 : if (!doc || doc->GetRootElement() != this)
1822 0 : return NS_ERROR_UNEXPECTED;
1823 :
1824 : // only top level chrome documents can hide the window chrome
1825 0 : if (!doc->IsRootDisplayDocument())
1826 0 : return NS_OK;
1827 :
1828 0 : nsIPresShell *shell = doc->GetShell();
1829 :
1830 0 : if (shell) {
1831 0 : nsIFrame* frame = GetPrimaryFrame();
1832 :
1833 0 : nsPresContext *presContext = shell->GetPresContext();
1834 :
1835 0 : if (frame && presContext && presContext->IsChrome()) {
1836 0 : nsView* view = frame->GetClosestView();
1837 :
1838 0 : if (view) {
1839 0 : nsIWidget* w = view->GetWidget();
1840 0 : NS_ENSURE_STATE(w);
1841 0 : w->HideWindowChrome(aShouldHide);
1842 : }
1843 : }
1844 : }
1845 :
1846 0 : return NS_OK;
1847 : }
1848 :
1849 : nsIWidget*
1850 0 : nsXULElement::GetWindowWidget()
1851 : {
1852 0 : nsIDocument* doc = GetComposedDoc();
1853 :
1854 : // only top level chrome documents can set the titlebar color
1855 0 : if (doc && doc->IsRootDisplayDocument()) {
1856 0 : nsCOMPtr<nsISupports> container = doc->GetContainer();
1857 0 : nsCOMPtr<nsIBaseWindow> baseWindow = do_QueryInterface(container);
1858 0 : if (baseWindow) {
1859 0 : nsCOMPtr<nsIWidget> mainWidget;
1860 0 : baseWindow->GetMainWidget(getter_AddRefs(mainWidget));
1861 0 : return mainWidget;
1862 : }
1863 : }
1864 0 : return nullptr;
1865 : }
1866 :
1867 : void
1868 0 : nsXULElement::SetTitlebarColor(nscolor aColor, bool aActive)
1869 : {
1870 0 : nsIWidget* mainWidget = GetWindowWidget();
1871 0 : if (mainWidget) {
1872 0 : mainWidget->SetWindowTitlebarColor(aColor, aActive);
1873 : }
1874 0 : }
1875 :
1876 0 : class SetDrawInTitleBarEvent : public Runnable
1877 : {
1878 : public:
1879 0 : SetDrawInTitleBarEvent(nsIWidget* aWidget, bool aState)
1880 0 : : mozilla::Runnable("SetDrawInTitleBarEvent")
1881 : , mWidget(aWidget)
1882 0 : , mState(aState)
1883 0 : {}
1884 :
1885 0 : NS_IMETHOD Run() override {
1886 0 : NS_ASSERTION(mWidget, "You shouldn't call this runnable with a null widget!");
1887 :
1888 0 : mWidget->SetDrawsInTitlebar(mState);
1889 0 : return NS_OK;
1890 : }
1891 :
1892 : private:
1893 : nsCOMPtr<nsIWidget> mWidget;
1894 : bool mState;
1895 : };
1896 :
1897 : void
1898 0 : nsXULElement::SetDrawsInTitlebar(bool aState)
1899 : {
1900 0 : nsIWidget* mainWidget = GetWindowWidget();
1901 0 : if (mainWidget) {
1902 0 : nsContentUtils::AddScriptRunner(new SetDrawInTitleBarEvent(mainWidget, aState));
1903 : }
1904 0 : }
1905 :
1906 : void
1907 0 : nsXULElement::SetDrawsTitle(bool aState)
1908 : {
1909 0 : nsIWidget* mainWidget = GetWindowWidget();
1910 0 : if (mainWidget) {
1911 : // We can do this synchronously because SetDrawsTitle doesn't have any
1912 : // synchronous effects apart from a harmless invalidation.
1913 0 : mainWidget->SetDrawsTitle(aState);
1914 : }
1915 0 : }
1916 :
1917 : void
1918 0 : nsXULElement::UpdateBrightTitlebarForeground(nsIDocument* aDoc)
1919 : {
1920 0 : nsIWidget* mainWidget = GetWindowWidget();
1921 0 : if (mainWidget) {
1922 : // We can do this synchronously because SetBrightTitlebarForeground doesn't have any
1923 : // synchronous effects apart from a harmless invalidation.
1924 0 : mainWidget->SetUseBrightTitlebarForeground(
1925 0 : aDoc->GetDocumentLWTheme() == nsIDocument::Doc_Theme_Bright ||
1926 0 : aDoc->GetRootElement()->AttrValueIs(kNameSpaceID_None,
1927 : nsGkAtoms::brighttitlebarforeground,
1928 0 : NS_LITERAL_STRING("true"),
1929 0 : eCaseMatters));
1930 : }
1931 0 : }
1932 :
1933 0 : class MarginSetter : public Runnable
1934 : {
1935 : public:
1936 0 : explicit MarginSetter(nsIWidget* aWidget)
1937 0 : : mozilla::Runnable("MarginSetter")
1938 : , mWidget(aWidget)
1939 0 : , mMargin(-1, -1, -1, -1)
1940 : {
1941 0 : }
1942 0 : MarginSetter(nsIWidget* aWidget, const LayoutDeviceIntMargin& aMargin)
1943 0 : : mozilla::Runnable("MarginSetter")
1944 : , mWidget(aWidget)
1945 0 : , mMargin(aMargin)
1946 : {
1947 0 : }
1948 :
1949 0 : NS_IMETHOD Run() override
1950 : {
1951 : // SetNonClientMargins can dispatch native events, hence doing
1952 : // it off a script runner.
1953 0 : mWidget->SetNonClientMargins(mMargin);
1954 0 : return NS_OK;
1955 : }
1956 :
1957 : private:
1958 : nsCOMPtr<nsIWidget> mWidget;
1959 : LayoutDeviceIntMargin mMargin;
1960 : };
1961 :
1962 : void
1963 0 : nsXULElement::SetChromeMargins(const nsAttrValue* aValue)
1964 : {
1965 0 : if (!aValue)
1966 0 : return;
1967 :
1968 0 : nsIWidget* mainWidget = GetWindowWidget();
1969 0 : if (!mainWidget)
1970 0 : return;
1971 :
1972 : // top, right, bottom, left - see nsAttrValue
1973 0 : nsIntMargin margins;
1974 0 : bool gotMargins = false;
1975 :
1976 0 : if (aValue->Type() == nsAttrValue::eIntMarginValue) {
1977 0 : gotMargins = aValue->GetIntMarginValue(margins);
1978 : } else {
1979 0 : nsAutoString tmp;
1980 0 : aValue->ToString(tmp);
1981 0 : gotMargins = nsContentUtils::ParseIntMarginValue(tmp, margins);
1982 : }
1983 0 : if (gotMargins) {
1984 0 : nsContentUtils::AddScriptRunner(
1985 : new MarginSetter(
1986 0 : mainWidget, LayoutDeviceIntMargin::FromUnknownMargin(margins)));
1987 : }
1988 : }
1989 :
1990 : void
1991 0 : nsXULElement::ResetChromeMargins()
1992 : {
1993 0 : nsIWidget* mainWidget = GetWindowWidget();
1994 0 : if (!mainWidget)
1995 0 : return;
1996 : // See nsIWidget
1997 0 : nsContentUtils::AddScriptRunner(new MarginSetter(mainWidget));
1998 : }
1999 :
2000 : bool
2001 7 : nsXULElement::BoolAttrIsTrue(nsIAtom* aName) const
2002 : {
2003 : const nsAttrValue* attr =
2004 7 : GetAttrInfo(kNameSpaceID_None, aName).mValue;
2005 :
2006 12 : return attr && attr->Type() == nsAttrValue::eAtom &&
2007 12 : attr->GetAtomValue() == nsGkAtoms::_true;
2008 : }
2009 :
2010 : void
2011 0 : nsXULElement::RecompileScriptEventListeners()
2012 : {
2013 0 : int32_t i, count = mAttrsAndChildren.AttrCount();
2014 0 : for (i = 0; i < count; ++i) {
2015 0 : const nsAttrName *name = mAttrsAndChildren.AttrNameAt(i);
2016 :
2017 : // Eventlistenener-attributes are always in the null namespace
2018 0 : if (!name->IsAtom()) {
2019 0 : continue;
2020 : }
2021 :
2022 0 : nsIAtom *attr = name->Atom();
2023 0 : if (!nsContentUtils::IsEventAttributeName(attr, EventNameType_XUL)) {
2024 0 : continue;
2025 : }
2026 :
2027 0 : nsAutoString value;
2028 0 : GetAttr(kNameSpaceID_None, attr, value);
2029 0 : SetEventHandler(attr, value, true);
2030 : }
2031 0 : }
2032 :
2033 : bool
2034 0 : nsXULElement::IsEventAttributeNameInternal(nsIAtom *aName)
2035 : {
2036 0 : return nsContentUtils::IsEventAttributeName(aName, EventNameType_XUL);
2037 : }
2038 :
2039 : JSObject*
2040 384 : nsXULElement::WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto)
2041 : {
2042 384 : return dom::XULElementBinding::Wrap(aCx, this, aGivenProto);
2043 : }
2044 :
2045 : NS_IMPL_CYCLE_COLLECTION_CLASS(nsXULPrototypeNode)
2046 :
2047 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsXULPrototypeNode)
2048 0 : if (tmp->mType == nsXULPrototypeNode::eType_Element) {
2049 0 : static_cast<nsXULPrototypeElement*>(tmp)->Unlink();
2050 0 : } else if (tmp->mType == nsXULPrototypeNode::eType_Script) {
2051 0 : static_cast<nsXULPrototypeScript*>(tmp)->UnlinkJSObjects();
2052 : }
2053 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
2054 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsXULPrototypeNode)
2055 0 : if (tmp->mType == nsXULPrototypeNode::eType_Element) {
2056 : nsXULPrototypeElement *elem =
2057 0 : static_cast<nsXULPrototypeElement*>(tmp);
2058 0 : NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mNodeInfo");
2059 0 : cb.NoteNativeChild(elem->mNodeInfo,
2060 0 : NS_CYCLE_COLLECTION_PARTICIPANT(NodeInfo));
2061 : uint32_t i;
2062 0 : for (i = 0; i < elem->mNumAttributes; ++i) {
2063 0 : const nsAttrName& name = elem->mAttributes[i].mName;
2064 0 : if (!name.IsAtom()) {
2065 : NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb,
2066 0 : "mAttributes[i].mName.NodeInfo()");
2067 0 : cb.NoteNativeChild(name.NodeInfo(),
2068 0 : NS_CYCLE_COLLECTION_PARTICIPANT(NodeInfo));
2069 : }
2070 : }
2071 0 : ImplCycleCollectionTraverse(cb, elem->mChildren, "mChildren");
2072 : }
2073 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
2074 432 : NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsXULPrototypeNode)
2075 432 : if (tmp->mType == nsXULPrototypeNode::eType_Script) {
2076 : nsXULPrototypeScript *script =
2077 39 : static_cast<nsXULPrototypeScript*>(tmp);
2078 39 : script->Trace(aCallbacks, aClosure);
2079 : }
2080 432 : NS_IMPL_CYCLE_COLLECTION_TRACE_END
2081 :
2082 0 : NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(nsXULPrototypeNode, AddRef)
2083 0 : NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(nsXULPrototypeNode, Release)
2084 :
2085 : //----------------------------------------------------------------------
2086 : //
2087 : // nsXULPrototypeAttribute
2088 : //
2089 :
2090 2220 : nsXULPrototypeAttribute::~nsXULPrototypeAttribute()
2091 : {
2092 1110 : MOZ_COUNT_DTOR(nsXULPrototypeAttribute);
2093 1110 : }
2094 :
2095 :
2096 : //----------------------------------------------------------------------
2097 : //
2098 : // nsXULPrototypeElement
2099 : //
2100 :
2101 : nsresult
2102 0 : nsXULPrototypeElement::Serialize(nsIObjectOutputStream* aStream,
2103 : nsXULPrototypeDocument* aProtoDoc,
2104 : const nsTArray<RefPtr<mozilla::dom::NodeInfo>> *aNodeInfos)
2105 : {
2106 : nsresult rv;
2107 :
2108 : // Write basic prototype data
2109 0 : rv = aStream->Write32(mType);
2110 :
2111 : // Write Node Info
2112 0 : int32_t index = aNodeInfos->IndexOf(mNodeInfo);
2113 0 : NS_ASSERTION(index >= 0, "unknown mozilla::dom::NodeInfo index");
2114 0 : nsresult tmp = aStream->Write32(index);
2115 0 : if (NS_FAILED(tmp)) {
2116 0 : rv = tmp;
2117 : }
2118 :
2119 : // Write Attributes
2120 0 : tmp = aStream->Write32(mNumAttributes);
2121 0 : if (NS_FAILED(tmp)) {
2122 0 : rv = tmp;
2123 : }
2124 :
2125 0 : nsAutoString attributeValue;
2126 : uint32_t i;
2127 0 : for (i = 0; i < mNumAttributes; ++i) {
2128 0 : RefPtr<mozilla::dom::NodeInfo> ni;
2129 0 : if (mAttributes[i].mName.IsAtom()) {
2130 : ni = mNodeInfo->NodeInfoManager()->
2131 0 : GetNodeInfo(mAttributes[i].mName.Atom(), nullptr,
2132 : kNameSpaceID_None,
2133 0 : nsIDOMNode::ATTRIBUTE_NODE);
2134 0 : NS_ASSERTION(ni, "the nodeinfo should already exist");
2135 : } else {
2136 0 : ni = mAttributes[i].mName.NodeInfo();
2137 : }
2138 :
2139 0 : index = aNodeInfos->IndexOf(ni);
2140 0 : NS_ASSERTION(index >= 0, "unknown mozilla::dom::NodeInfo index");
2141 0 : tmp = aStream->Write32(index);
2142 0 : if (NS_FAILED(tmp)) {
2143 0 : rv = tmp;
2144 : }
2145 :
2146 0 : mAttributes[i].mValue.ToString(attributeValue);
2147 0 : tmp = aStream->WriteWStringZ(attributeValue.get());
2148 0 : if (NS_FAILED(tmp)) {
2149 0 : rv = tmp;
2150 : }
2151 : }
2152 :
2153 : // Now write children
2154 0 : tmp = aStream->Write32(uint32_t(mChildren.Length()));
2155 0 : if (NS_FAILED(tmp)) {
2156 0 : rv = tmp;
2157 : }
2158 0 : for (i = 0; i < mChildren.Length(); i++) {
2159 0 : nsXULPrototypeNode* child = mChildren[i].get();
2160 0 : switch (child->mType) {
2161 : case eType_Element:
2162 : case eType_Text:
2163 : case eType_PI:
2164 0 : tmp = child->Serialize(aStream, aProtoDoc, aNodeInfos);
2165 0 : if (NS_FAILED(tmp)) {
2166 0 : rv = tmp;
2167 : }
2168 0 : break;
2169 : case eType_Script:
2170 0 : tmp = aStream->Write32(child->mType);
2171 0 : if (NS_FAILED(tmp)) {
2172 0 : rv = tmp;
2173 : }
2174 0 : nsXULPrototypeScript* script = static_cast<nsXULPrototypeScript*>(child);
2175 :
2176 0 : tmp = aStream->Write8(script->mOutOfLine);
2177 0 : if (NS_FAILED(tmp)) {
2178 0 : rv = tmp;
2179 : }
2180 0 : if (! script->mOutOfLine) {
2181 0 : tmp = script->Serialize(aStream, aProtoDoc, aNodeInfos);
2182 0 : if (NS_FAILED(tmp)) {
2183 0 : rv = tmp;
2184 : }
2185 : } else {
2186 : tmp = aStream->WriteCompoundObject(script->mSrcURI,
2187 : NS_GET_IID(nsIURI),
2188 0 : true);
2189 0 : if (NS_FAILED(tmp)) {
2190 0 : rv = tmp;
2191 : }
2192 :
2193 0 : if (script->HasScriptObject()) {
2194 : // This may return NS_OK without muxing script->mSrcURI's
2195 : // data into the cache file, in the case where that
2196 : // muxed document is already there (written by a prior
2197 : // session, or by an earlier cache episode during this
2198 : // session).
2199 0 : tmp = script->SerializeOutOfLine(aStream, aProtoDoc);
2200 0 : if (NS_FAILED(tmp)) {
2201 0 : rv = tmp;
2202 : }
2203 : }
2204 : }
2205 0 : break;
2206 : }
2207 : }
2208 :
2209 0 : return rv;
2210 : }
2211 :
2212 : nsresult
2213 1297 : nsXULPrototypeElement::Deserialize(nsIObjectInputStream* aStream,
2214 : nsXULPrototypeDocument* aProtoDoc,
2215 : nsIURI* aDocumentURI,
2216 : const nsTArray<RefPtr<mozilla::dom::NodeInfo>> *aNodeInfos)
2217 : {
2218 1297 : NS_PRECONDITION(aNodeInfos, "missing nodeinfo array");
2219 :
2220 : // Read Node Info
2221 1297 : uint32_t number = 0;
2222 1297 : nsresult rv = aStream->Read32(&number);
2223 1297 : if (NS_WARN_IF(NS_FAILED(rv))) return rv;
2224 1297 : mNodeInfo = aNodeInfos->SafeElementAt(number, nullptr);
2225 1297 : if (!mNodeInfo) {
2226 0 : return NS_ERROR_UNEXPECTED;
2227 : }
2228 :
2229 : // Read Attributes
2230 1297 : rv = aStream->Read32(&number);
2231 1297 : if (NS_WARN_IF(NS_FAILED(rv))) return rv;
2232 1297 : mNumAttributes = int32_t(number);
2233 :
2234 1297 : if (mNumAttributes > 0) {
2235 2460 : mAttributes = new (fallible) nsXULPrototypeAttribute[mNumAttributes];
2236 1230 : if (!mAttributes) {
2237 0 : return NS_ERROR_OUT_OF_MEMORY;
2238 : }
2239 :
2240 2460 : nsAutoString attributeValue;
2241 5168 : for (uint32_t i = 0; i < mNumAttributes; ++i) {
2242 3938 : rv = aStream->Read32(&number);
2243 3938 : if (NS_WARN_IF(NS_FAILED(rv))) return rv;
2244 3938 : mozilla::dom::NodeInfo* ni = aNodeInfos->SafeElementAt(number, nullptr);
2245 3938 : if (!ni) {
2246 0 : return NS_ERROR_UNEXPECTED;
2247 : }
2248 :
2249 3938 : mAttributes[i].mName.SetTo(ni);
2250 :
2251 3938 : rv = aStream->ReadString(attributeValue);
2252 3938 : if (NS_WARN_IF(NS_FAILED(rv))) return rv;
2253 3938 : rv = SetAttrAt(i, attributeValue, aDocumentURI);
2254 3938 : if (NS_WARN_IF(NS_FAILED(rv))) return rv;
2255 : }
2256 : }
2257 :
2258 1297 : rv = aStream->Read32(&number);
2259 1297 : if (NS_WARN_IF(NS_FAILED(rv))) return rv;
2260 1297 : uint32_t numChildren = int32_t(number);
2261 :
2262 1297 : if (numChildren > 0) {
2263 371 : if (!mChildren.SetCapacity(numChildren, fallible)) {
2264 0 : return NS_ERROR_OUT_OF_MEMORY;
2265 : }
2266 :
2267 1787 : for (uint32_t i = 0; i < numChildren; i++) {
2268 1416 : rv = aStream->Read32(&number);
2269 1416 : if (NS_WARN_IF(NS_FAILED(rv))) return rv;
2270 1416 : Type childType = (Type)number;
2271 :
2272 2832 : RefPtr<nsXULPrototypeNode> child;
2273 :
2274 1416 : switch (childType) {
2275 : case eType_Element:
2276 1291 : child = new nsXULPrototypeElement();
2277 1291 : rv = child->Deserialize(aStream, aProtoDoc, aDocumentURI,
2278 1291 : aNodeInfos);
2279 1291 : if (NS_WARN_IF(NS_FAILED(rv))) return rv;
2280 1291 : break;
2281 : case eType_Text:
2282 86 : child = new nsXULPrototypeText();
2283 86 : rv = child->Deserialize(aStream, aProtoDoc, aDocumentURI,
2284 86 : aNodeInfos);
2285 86 : if (NS_WARN_IF(NS_FAILED(rv))) return rv;
2286 86 : break;
2287 : case eType_PI:
2288 0 : child = new nsXULPrototypePI();
2289 0 : rv = child->Deserialize(aStream, aProtoDoc, aDocumentURI,
2290 0 : aNodeInfos);
2291 0 : if (NS_WARN_IF(NS_FAILED(rv))) return rv;
2292 0 : break;
2293 : case eType_Script: {
2294 : // language version/options obtained during deserialization.
2295 39 : RefPtr<nsXULPrototypeScript> script = new nsXULPrototypeScript(0, 0);
2296 :
2297 39 : rv = aStream->ReadBoolean(&script->mOutOfLine);
2298 39 : if (NS_WARN_IF(NS_FAILED(rv))) return rv;
2299 39 : if (!script->mOutOfLine) {
2300 1 : rv = script->Deserialize(aStream, aProtoDoc, aDocumentURI,
2301 1 : aNodeInfos);
2302 1 : if (NS_WARN_IF(NS_FAILED(rv))) return rv;
2303 : } else {
2304 76 : nsCOMPtr<nsISupports> supports;
2305 38 : rv = aStream->ReadObject(true, getter_AddRefs(supports));
2306 38 : if (NS_WARN_IF(NS_FAILED(rv))) return rv;
2307 38 : script->mSrcURI = do_QueryInterface(supports);
2308 :
2309 38 : rv = script->DeserializeOutOfLine(aStream, aProtoDoc);
2310 38 : if (NS_WARN_IF(NS_FAILED(rv))) return rv;
2311 : }
2312 :
2313 39 : child = script.forget();
2314 39 : break;
2315 : }
2316 : default:
2317 0 : MOZ_ASSERT(false, "Unexpected child type!");
2318 : return NS_ERROR_UNEXPECTED;
2319 : }
2320 :
2321 1416 : MOZ_ASSERT(child, "Don't append null to mChildren");
2322 1416 : MOZ_ASSERT(child->mType == childType);
2323 1416 : mChildren.AppendElement(child);
2324 :
2325 : // Oh dear. Something failed during the deserialization.
2326 : // We don't know what. But likely consequences of failed
2327 : // deserializations included calls to |AbortCaching| which
2328 : // shuts down the cache and closes our streams.
2329 : // If that happens, next time through this loop, we die a messy
2330 : // death. So, let's just fail now, and propagate that failure
2331 : // upward so that the ChromeProtocolHandler knows it can't use
2332 : // a cached chrome channel for this.
2333 1416 : if (NS_WARN_IF(NS_FAILED(rv)))
2334 0 : return rv;
2335 : }
2336 : }
2337 :
2338 1297 : return rv;
2339 : }
2340 :
2341 : nsresult
2342 5066 : nsXULPrototypeElement::SetAttrAt(uint32_t aPos, const nsAString& aValue,
2343 : nsIURI* aDocumentURI)
2344 : {
2345 5066 : NS_PRECONDITION(aPos < mNumAttributes, "out-of-bounds");
2346 :
2347 : // WARNING!!
2348 : // This code is largely duplicated in nsXULElement::SetAttr.
2349 : // Any changes should be made to both functions.
2350 :
2351 5066 : if (!mNodeInfo->NamespaceEquals(kNameSpaceID_XUL)) {
2352 32 : mAttributes[aPos].mValue.ParseStringOrAtom(aValue);
2353 :
2354 32 : return NS_OK;
2355 : }
2356 :
2357 6018 : if (mAttributes[aPos].mName.Equals(nsGkAtoms::id) &&
2358 984 : !aValue.IsEmpty()) {
2359 984 : mHasIdAttribute = true;
2360 : // Store id as atom.
2361 : // id="" means that the element has no id. Not that it has
2362 : // emptystring as id.
2363 984 : mAttributes[aPos].mValue.ParseAtom(aValue);
2364 :
2365 984 : return NS_OK;
2366 4050 : } else if (mAttributes[aPos].mName.Equals(nsGkAtoms::_class)) {
2367 605 : mHasClassAttribute = true;
2368 : // Compute the element's class list
2369 605 : mAttributes[aPos].mValue.ParseAtomArray(aValue);
2370 :
2371 605 : return NS_OK;
2372 3445 : } else if (mAttributes[aPos].mName.Equals(nsGkAtoms::style)) {
2373 7 : mHasStyleAttribute = true;
2374 : // Parse the element's 'style' attribute
2375 :
2376 7 : nsCSSParser parser;
2377 :
2378 : // XXX Get correct Base URI (need GetBaseURI on *prototype* element)
2379 : // TODO: If we implement Content Security Policy for chrome documents
2380 : // as has been discussed, the CSP should be checked here to see if
2381 : // inline styles are allowed to be applied.
2382 : RefPtr<css::Declaration> declaration =
2383 14 : parser.ParseStyleAttribute(aValue, aDocumentURI, aDocumentURI,
2384 : // This is basically duplicating what
2385 : // nsINode::NodePrincipal() does
2386 : mNodeInfo->NodeInfoManager()->
2387 7 : DocumentPrincipal());
2388 7 : if (declaration) {
2389 7 : mAttributes[aPos].mValue.SetTo(declaration.forget(), &aValue);
2390 :
2391 7 : return NS_OK;
2392 : }
2393 : // Don't abort if parsing failed, it could just be malformed css.
2394 : }
2395 :
2396 3438 : mAttributes[aPos].mValue.ParseStringOrAtom(aValue);
2397 :
2398 3438 : return NS_OK;
2399 : }
2400 :
2401 : void
2402 393 : nsXULPrototypeElement::Unlink()
2403 : {
2404 393 : mNumAttributes = 0;
2405 393 : delete[] mAttributes;
2406 393 : mAttributes = nullptr;
2407 393 : mChildren.Clear();
2408 393 : }
2409 :
2410 : void
2411 1297 : nsXULPrototypeElement::TraceAllScripts(JSTracer* aTrc)
2412 : {
2413 2713 : for (uint32_t i = 0; i < mChildren.Length(); ++i) {
2414 1416 : nsXULPrototypeNode* child = mChildren[i];
2415 1416 : if (child->mType == nsXULPrototypeNode::eType_Element) {
2416 1291 : static_cast<nsXULPrototypeElement*>(child)->TraceAllScripts(aTrc);
2417 125 : } else if (child->mType == nsXULPrototypeNode::eType_Script) {
2418 39 : static_cast<nsXULPrototypeScript*>(child)->TraceScriptObject(aTrc);
2419 : }
2420 : }
2421 1297 : }
2422 :
2423 : //----------------------------------------------------------------------
2424 : //
2425 : // nsXULPrototypeScript
2426 : //
2427 :
2428 39 : nsXULPrototypeScript::nsXULPrototypeScript(uint32_t aLineNo, uint32_t aVersion)
2429 : : nsXULPrototypeNode(eType_Script),
2430 : mLineNo(aLineNo),
2431 : mSrcLoading(false),
2432 : mOutOfLine(true),
2433 : mSrcLoadWaiters(nullptr),
2434 : mLangVersion(aVersion),
2435 39 : mScriptObject(nullptr)
2436 : {
2437 39 : }
2438 :
2439 :
2440 0 : nsXULPrototypeScript::~nsXULPrototypeScript()
2441 : {
2442 0 : UnlinkJSObjects();
2443 0 : }
2444 :
2445 : nsresult
2446 0 : nsXULPrototypeScript::Serialize(nsIObjectOutputStream* aStream,
2447 : nsXULPrototypeDocument* aProtoDoc,
2448 : const nsTArray<RefPtr<mozilla::dom::NodeInfo>> *aNodeInfos)
2449 : {
2450 0 : NS_ENSURE_TRUE(aProtoDoc, NS_ERROR_UNEXPECTED);
2451 :
2452 0 : AutoJSAPI jsapi;
2453 0 : if (!jsapi.Init(xpc::CompilationScope())) {
2454 0 : return NS_ERROR_UNEXPECTED;
2455 : }
2456 :
2457 0 : NS_ASSERTION(!mSrcLoading || mSrcLoadWaiters != nullptr ||
2458 : !mScriptObject,
2459 : "script source still loading when serializing?!");
2460 0 : if (!mScriptObject)
2461 0 : return NS_ERROR_FAILURE;
2462 :
2463 : // Write basic prototype data
2464 : nsresult rv;
2465 0 : rv = aStream->Write32(mLineNo);
2466 0 : if (NS_FAILED(rv)) return rv;
2467 0 : rv = aStream->Write32(mLangVersion);
2468 0 : if (NS_FAILED(rv)) return rv;
2469 :
2470 0 : JSContext* cx = jsapi.cx();
2471 0 : JS::Rooted<JSScript*> script(cx, mScriptObject);
2472 0 : MOZ_ASSERT(xpc::CompilationScope() == JS::CurrentGlobalOrNull(cx));
2473 0 : return nsContentUtils::XPConnect()->WriteScript(aStream, cx, script);
2474 : }
2475 :
2476 : nsresult
2477 0 : nsXULPrototypeScript::SerializeOutOfLine(nsIObjectOutputStream* aStream,
2478 : nsXULPrototypeDocument* aProtoDoc)
2479 : {
2480 0 : nsresult rv = NS_ERROR_NOT_IMPLEMENTED;
2481 :
2482 0 : bool isChrome = false;
2483 0 : if (NS_FAILED(mSrcURI->SchemeIs("chrome", &isChrome)) || !isChrome)
2484 : // Don't cache scripts that don't come from chrome uris.
2485 0 : return rv;
2486 :
2487 0 : nsXULPrototypeCache* cache = nsXULPrototypeCache::GetInstance();
2488 0 : if (!cache)
2489 0 : return NS_ERROR_OUT_OF_MEMORY;
2490 :
2491 0 : NS_ASSERTION(cache->IsEnabled(),
2492 : "writing to the cache file, but the XUL cache is off?");
2493 : bool exists;
2494 0 : cache->HasData(mSrcURI, &exists);
2495 :
2496 : /* return will be NS_OK from GetAsciiSpec.
2497 : * that makes no sense.
2498 : * nor does returning NS_OK from HasMuxedDocument.
2499 : * XXX return something meaningful.
2500 : */
2501 0 : if (exists)
2502 0 : return NS_OK;
2503 :
2504 0 : nsCOMPtr<nsIObjectOutputStream> oos;
2505 0 : rv = cache->GetOutputStream(mSrcURI, getter_AddRefs(oos));
2506 0 : NS_ENSURE_SUCCESS(rv, rv);
2507 :
2508 0 : nsresult tmp = Serialize(oos, aProtoDoc, nullptr);
2509 0 : if (NS_FAILED(tmp)) {
2510 0 : rv = tmp;
2511 : }
2512 0 : tmp = cache->FinishOutputStream(mSrcURI);
2513 0 : if (NS_FAILED(tmp)) {
2514 0 : rv = tmp;
2515 : }
2516 :
2517 0 : if (NS_FAILED(rv))
2518 0 : cache->AbortCaching();
2519 0 : return rv;
2520 : }
2521 :
2522 :
2523 : nsresult
2524 38 : nsXULPrototypeScript::Deserialize(nsIObjectInputStream* aStream,
2525 : nsXULPrototypeDocument* aProtoDoc,
2526 : nsIURI* aDocumentURI,
2527 : const nsTArray<RefPtr<mozilla::dom::NodeInfo>> *aNodeInfos)
2528 : {
2529 : nsresult rv;
2530 38 : NS_ASSERTION(!mSrcLoading || mSrcLoadWaiters != nullptr ||
2531 : !mScriptObject,
2532 : "prototype script not well-initialized when deserializing?!");
2533 :
2534 : // Read basic prototype data
2535 38 : rv = aStream->Read32(&mLineNo);
2536 38 : if (NS_FAILED(rv)) return rv;
2537 38 : rv = aStream->Read32(&mLangVersion);
2538 38 : if (NS_FAILED(rv)) return rv;
2539 :
2540 76 : AutoJSAPI jsapi;
2541 38 : if (!jsapi.Init(xpc::CompilationScope())) {
2542 0 : return NS_ERROR_UNEXPECTED;
2543 : }
2544 38 : JSContext* cx = jsapi.cx();
2545 :
2546 76 : JS::Rooted<JSScript*> newScriptObject(cx);
2547 76 : rv = nsContentUtils::XPConnect()->ReadScript(aStream, cx,
2548 76 : newScriptObject.address());
2549 38 : NS_ENSURE_SUCCESS(rv, rv);
2550 38 : Set(newScriptObject);
2551 38 : return NS_OK;
2552 : }
2553 :
2554 :
2555 : nsresult
2556 38 : nsXULPrototypeScript::DeserializeOutOfLine(nsIObjectInputStream* aInput,
2557 : nsXULPrototypeDocument* aProtoDoc)
2558 : {
2559 : // Keep track of failure via rv, so we can
2560 : // AbortCaching if things look bad.
2561 38 : nsresult rv = NS_OK;
2562 38 : nsXULPrototypeCache* cache = nsXULPrototypeCache::GetInstance();
2563 :
2564 76 : nsCOMPtr<nsIObjectInputStream> objectInput = aInput;
2565 38 : if (cache) {
2566 38 : bool useXULCache = true;
2567 38 : if (mSrcURI) {
2568 : // NB: we must check the XUL script cache early, to avoid
2569 : // multiple deserialization attempts for a given script.
2570 : // Note that XULDocument::LoadScript
2571 : // checks the XUL script cache too, in order to handle the
2572 : // serialization case.
2573 : //
2574 : // We need do this only for <script src='strres.js'> and the
2575 : // like, i.e., out-of-line scripts that are included by several
2576 : // different XUL documents stored in the cache file.
2577 38 : useXULCache = cache->IsEnabled();
2578 :
2579 38 : if (useXULCache) {
2580 : JSScript* newScriptObject =
2581 38 : cache->GetScript(mSrcURI);
2582 38 : if (newScriptObject)
2583 1 : Set(newScriptObject);
2584 : }
2585 : }
2586 :
2587 38 : if (!mScriptObject) {
2588 37 : if (mSrcURI) {
2589 37 : rv = cache->GetInputStream(mSrcURI, getter_AddRefs(objectInput));
2590 : }
2591 : // If !mSrcURI, we have an inline script. We shouldn't have
2592 : // to do anything else in that case, I think.
2593 :
2594 : // We do reflect errors into rv, but our caller may want to
2595 : // ignore our return value, because mScriptObject will be null
2596 : // after any error, and that suffices to cause the script to
2597 : // be reloaded (from the src= URI, if any) and recompiled.
2598 : // We're better off slow-loading than bailing out due to a
2599 : // error.
2600 37 : if (NS_SUCCEEDED(rv))
2601 37 : rv = Deserialize(objectInput, aProtoDoc, nullptr, nullptr);
2602 :
2603 37 : if (NS_SUCCEEDED(rv)) {
2604 37 : if (useXULCache && mSrcURI) {
2605 37 : bool isChrome = false;
2606 37 : mSrcURI->SchemeIs("chrome", &isChrome);
2607 37 : if (isChrome) {
2608 74 : JS::Rooted<JSScript*> script(RootingCx(), GetScriptObject());
2609 37 : cache->PutScript(mSrcURI, script);
2610 : }
2611 : }
2612 37 : cache->FinishInputStream(mSrcURI);
2613 : } else {
2614 : // If mSrcURI is not in the cache,
2615 : // rv will be NS_ERROR_NOT_AVAILABLE and we'll try to
2616 : // update the cache file to hold a serialization of
2617 : // this script, once it has finished loading.
2618 0 : if (rv != NS_ERROR_NOT_AVAILABLE)
2619 0 : cache->AbortCaching();
2620 : }
2621 : }
2622 : }
2623 76 : return rv;
2624 : }
2625 :
2626 0 : class NotifyOffThreadScriptCompletedRunnable : public Runnable
2627 : {
2628 : // An array of all outstanding script receivers. All reference counting of
2629 : // these objects happens on the main thread. When we return to the main
2630 : // thread from script compilation we make sure our receiver is still in
2631 : // this array (still alive) before proceeding. This array is cleared during
2632 : // shutdown, potentially before all outstanding script compilations have
2633 : // finished. We do not need to worry about pointer replay here, because
2634 : // a) we should not be starting script compilation after clearing this
2635 : // array and b) in all other cases the receiver will still be alive.
2636 : static StaticAutoPtr<nsTArray<nsCOMPtr<nsIOffThreadScriptReceiver>>> sReceivers;
2637 : static bool sSetupClearOnShutdown;
2638 :
2639 : nsIOffThreadScriptReceiver* mReceiver;
2640 : void *mToken;
2641 :
2642 : public:
2643 0 : NotifyOffThreadScriptCompletedRunnable(nsIOffThreadScriptReceiver* aReceiver,
2644 : void* aToken)
2645 0 : : mozilla::Runnable("NotifyOffThreadScriptCompletedRunnable")
2646 : , mReceiver(aReceiver)
2647 0 : , mToken(aToken)
2648 : {
2649 0 : }
2650 :
2651 0 : static void NoteReceiver(nsIOffThreadScriptReceiver* aReceiver)
2652 : {
2653 0 : if (!sSetupClearOnShutdown) {
2654 0 : ClearOnShutdown(&sReceivers);
2655 0 : sSetupClearOnShutdown = true;
2656 0 : sReceivers = new nsTArray<nsCOMPtr<nsIOffThreadScriptReceiver>>();
2657 : }
2658 :
2659 : // If we ever crash here, it's because we tried to lazy compile script
2660 : // too late in shutdown.
2661 0 : sReceivers->AppendElement(aReceiver);
2662 0 : }
2663 :
2664 : NS_DECL_NSIRUNNABLE
2665 : };
2666 :
2667 3 : StaticAutoPtr<nsTArray<nsCOMPtr<nsIOffThreadScriptReceiver>>> NotifyOffThreadScriptCompletedRunnable::sReceivers;
2668 : bool NotifyOffThreadScriptCompletedRunnable::sSetupClearOnShutdown = false;
2669 :
2670 : NS_IMETHODIMP
2671 0 : NotifyOffThreadScriptCompletedRunnable::Run()
2672 : {
2673 0 : MOZ_ASSERT(NS_IsMainThread());
2674 :
2675 0 : JS::Rooted<JSScript*> script(RootingCx());
2676 : {
2677 0 : AutoJSAPI jsapi;
2678 0 : if (!jsapi.Init(xpc::CompilationScope())) {
2679 : // Now what? I guess we just leak... this should probably never
2680 : // happen.
2681 0 : return NS_ERROR_UNEXPECTED;
2682 : }
2683 0 : JSContext* cx = jsapi.cx();
2684 0 : script = JS::FinishOffThreadScript(cx, mToken);
2685 : }
2686 :
2687 0 : if (!sReceivers) {
2688 : // We've already shut down.
2689 0 : return NS_OK;
2690 : }
2691 :
2692 0 : auto index = sReceivers->IndexOf(mReceiver);
2693 0 : MOZ_RELEASE_ASSERT(index != sReceivers->NoIndex);
2694 0 : nsCOMPtr<nsIOffThreadScriptReceiver> receiver = (*sReceivers)[index].forget();
2695 0 : sReceivers->RemoveElementAt(index);
2696 :
2697 0 : return receiver->OnScriptCompileComplete(script, script ? NS_OK : NS_ERROR_FAILURE);
2698 : }
2699 :
2700 : static void
2701 0 : OffThreadScriptReceiverCallback(void *aToken, void *aCallbackData)
2702 : {
2703 : // Be careful not to adjust the refcount on the receiver, as this callback
2704 : // may be invoked off the main thread.
2705 0 : nsIOffThreadScriptReceiver* aReceiver = static_cast<nsIOffThreadScriptReceiver*>(aCallbackData);
2706 : RefPtr<NotifyOffThreadScriptCompletedRunnable> notify =
2707 0 : new NotifyOffThreadScriptCompletedRunnable(aReceiver, aToken);
2708 0 : NS_DispatchToMainThread(notify);
2709 0 : }
2710 :
2711 : nsresult
2712 0 : nsXULPrototypeScript::Compile(JS::SourceBufferHolder& aSrcBuf,
2713 : nsIURI* aURI, uint32_t aLineNo,
2714 : nsIDocument* aDocument,
2715 : nsIOffThreadScriptReceiver *aOffThreadReceiver /* = nullptr */)
2716 : {
2717 : // We'll compile the script in the compilation scope.
2718 0 : AutoJSAPI jsapi;
2719 0 : if (!jsapi.Init(xpc::CompilationScope())) {
2720 0 : return NS_ERROR_UNEXPECTED;
2721 : }
2722 0 : JSContext* cx = jsapi.cx();
2723 :
2724 : nsresult rv;
2725 0 : nsAutoCString urlspec;
2726 0 : nsContentUtils::GetWrapperSafeScriptFilename(aDocument, aURI, urlspec, &rv);
2727 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
2728 0 : return rv;
2729 : }
2730 :
2731 : // Ok, compile it to create a prototype script object!
2732 0 : NS_ENSURE_TRUE(JSVersion(mLangVersion) != JSVERSION_UNKNOWN, NS_OK);
2733 0 : JS::CompileOptions options(cx);
2734 0 : options.setIntroductionType("scriptElement")
2735 0 : .setFileAndLine(urlspec.get(), aLineNo)
2736 0 : .setVersion(JSVersion(mLangVersion));
2737 : // If the script was inline, tell the JS parser to save source for
2738 : // Function.prototype.toSource(). If it's out of line, we retrieve the
2739 : // source from the files on demand.
2740 0 : options.setSourceIsLazy(mOutOfLine);
2741 0 : JS::Rooted<JSObject*> scope(cx, JS::CurrentGlobalOrNull(cx));
2742 0 : if (scope) {
2743 0 : JS::ExposeObjectToActiveJS(scope);
2744 : }
2745 :
2746 0 : if (aOffThreadReceiver && JS::CanCompileOffThread(cx, options, aSrcBuf.length())) {
2747 0 : if (!JS::CompileOffThread(cx, options,
2748 : aSrcBuf.get(), aSrcBuf.length(),
2749 : OffThreadScriptReceiverCallback,
2750 : static_cast<void*>(aOffThreadReceiver))) {
2751 0 : return NS_ERROR_OUT_OF_MEMORY;
2752 : }
2753 0 : NotifyOffThreadScriptCompletedRunnable::NoteReceiver(aOffThreadReceiver);
2754 : } else {
2755 0 : JS::Rooted<JSScript*> script(cx);
2756 0 : if (!JS::Compile(cx, options, aSrcBuf, &script))
2757 0 : return NS_ERROR_OUT_OF_MEMORY;
2758 0 : Set(script);
2759 : }
2760 0 : return NS_OK;
2761 : }
2762 :
2763 : nsresult
2764 0 : nsXULPrototypeScript::Compile(const char16_t* aText,
2765 : int32_t aTextLength,
2766 : nsIURI* aURI,
2767 : uint32_t aLineNo,
2768 : nsIDocument* aDocument,
2769 : nsIOffThreadScriptReceiver *aOffThreadReceiver /* = nullptr */)
2770 : {
2771 : JS::SourceBufferHolder srcBuf(aText, aTextLength,
2772 0 : JS::SourceBufferHolder::NoOwnership);
2773 0 : return Compile(srcBuf, aURI, aLineNo, aDocument, aOffThreadReceiver);
2774 : }
2775 :
2776 : void
2777 0 : nsXULPrototypeScript::UnlinkJSObjects()
2778 : {
2779 0 : if (mScriptObject) {
2780 0 : mScriptObject = nullptr;
2781 0 : mozilla::DropJSObjects(this);
2782 : }
2783 0 : }
2784 :
2785 : void
2786 39 : nsXULPrototypeScript::Set(JSScript* aObject)
2787 : {
2788 39 : MOZ_ASSERT(!mScriptObject, "Leaking script object.");
2789 39 : if (!aObject) {
2790 0 : mScriptObject = nullptr;
2791 0 : return;
2792 : }
2793 :
2794 39 : mScriptObject = aObject;
2795 39 : mozilla::HoldJSObjects(this);
2796 : }
2797 :
2798 : //----------------------------------------------------------------------
2799 : //
2800 : // nsXULPrototypeText
2801 : //
2802 :
2803 : nsresult
2804 0 : nsXULPrototypeText::Serialize(nsIObjectOutputStream* aStream,
2805 : nsXULPrototypeDocument* aProtoDoc,
2806 : const nsTArray<RefPtr<mozilla::dom::NodeInfo>> *aNodeInfos)
2807 : {
2808 : nsresult rv;
2809 :
2810 : // Write basic prototype data
2811 0 : rv = aStream->Write32(mType);
2812 :
2813 0 : nsresult tmp = aStream->WriteWStringZ(mValue.get());
2814 0 : if (NS_FAILED(tmp)) {
2815 0 : rv = tmp;
2816 : }
2817 :
2818 0 : return rv;
2819 : }
2820 :
2821 : nsresult
2822 86 : nsXULPrototypeText::Deserialize(nsIObjectInputStream* aStream,
2823 : nsXULPrototypeDocument* aProtoDoc,
2824 : nsIURI* aDocumentURI,
2825 : const nsTArray<RefPtr<mozilla::dom::NodeInfo>> *aNodeInfos)
2826 : {
2827 86 : nsresult rv = aStream->ReadString(mValue);
2828 86 : if (NS_WARN_IF(NS_FAILED(rv))) {
2829 0 : return rv;
2830 : }
2831 86 : return NS_OK;
2832 : }
2833 :
2834 : //----------------------------------------------------------------------
2835 : //
2836 : // nsXULPrototypePI
2837 : //
2838 :
2839 : nsresult
2840 0 : nsXULPrototypePI::Serialize(nsIObjectOutputStream* aStream,
2841 : nsXULPrototypeDocument* aProtoDoc,
2842 : const nsTArray<RefPtr<mozilla::dom::NodeInfo>> *aNodeInfos)
2843 : {
2844 : nsresult rv;
2845 :
2846 : // Write basic prototype data
2847 0 : rv = aStream->Write32(mType);
2848 :
2849 0 : nsresult tmp = aStream->WriteWStringZ(mTarget.get());
2850 0 : if (NS_FAILED(tmp)) {
2851 0 : rv = tmp;
2852 : }
2853 0 : tmp = aStream->WriteWStringZ(mData.get());
2854 0 : if (NS_FAILED(tmp)) {
2855 0 : rv = tmp;
2856 : }
2857 :
2858 0 : return rv;
2859 : }
2860 :
2861 : nsresult
2862 9 : nsXULPrototypePI::Deserialize(nsIObjectInputStream* aStream,
2863 : nsXULPrototypeDocument* aProtoDoc,
2864 : nsIURI* aDocumentURI,
2865 : const nsTArray<RefPtr<mozilla::dom::NodeInfo>> *aNodeInfos)
2866 : {
2867 : nsresult rv;
2868 :
2869 9 : rv = aStream->ReadString(mTarget);
2870 9 : if (NS_FAILED(rv)) return rv;
2871 9 : rv = aStream->ReadString(mData);
2872 9 : if (NS_FAILED(rv)) return rv;
2873 :
2874 9 : return rv;
2875 : }
|