1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #include "ScriptElement.h"
8 #include "ScriptLoader.h"
9 #include "mozilla/BasicEvents.h"
10 #include "mozilla/EventDispatcher.h"
11 #include "mozilla/dom/Document.h"
12 #include "mozilla/dom/Element.h"
13 #include "nsContentUtils.h"
14 #include "nsPresContext.h"
15 #include "nsIParser.h"
16 #include "nsGkAtoms.h"
17 #include "nsContentSink.h"
18 
19 using namespace mozilla;
20 using namespace mozilla::dom;
21 
22 NS_IMETHODIMP
ScriptAvailable(nsresult aResult,nsIScriptElement * aElement,bool aIsInlineClassicScript,nsIURI * aURI,int32_t aLineNo)23 ScriptElement::ScriptAvailable(nsresult aResult, nsIScriptElement* aElement,
24                                bool aIsInlineClassicScript, nsIURI* aURI,
25                                int32_t aLineNo) {
26   if (!aIsInlineClassicScript && NS_FAILED(aResult)) {
27     nsCOMPtr<nsIParser> parser = do_QueryReferent(mCreatorParser);
28     if (parser) {
29       parser->IncrementScriptNestingLevel();
30     }
31     nsresult rv = FireErrorEvent();
32     if (parser) {
33       parser->DecrementScriptNestingLevel();
34     }
35     return rv;
36   }
37   return NS_OK;
38 }
39 
40 /* virtual */
FireErrorEvent()41 nsresult ScriptElement::FireErrorEvent() {
42   nsCOMPtr<nsIContent> cont = do_QueryInterface((nsIScriptElement*)this);
43 
44   return nsContentUtils::DispatchTrustedEvent(
45       cont->OwnerDoc(), cont, u"error"_ns, CanBubble::eNo, Cancelable::eNo);
46 }
47 
48 NS_IMETHODIMP
ScriptEvaluated(nsresult aResult,nsIScriptElement * aElement,bool aIsInline)49 ScriptElement::ScriptEvaluated(nsresult aResult, nsIScriptElement* aElement,
50                                bool aIsInline) {
51   nsresult rv = NS_OK;
52   if (!aIsInline) {
53     nsCOMPtr<nsIContent> cont = do_QueryInterface((nsIScriptElement*)this);
54 
55     RefPtr<nsPresContext> presContext =
56         nsContentUtils::GetContextForContent(cont);
57 
58     nsEventStatus status = nsEventStatus_eIgnore;
59     EventMessage message = NS_SUCCEEDED(aResult) ? eLoad : eLoadError;
60     WidgetEvent event(true, message);
61     // Load event doesn't bubble.
62     event.mFlags.mBubbles = (message != eLoad);
63 
64     EventDispatcher::Dispatch(cont, presContext, &event, nullptr, &status);
65   }
66 
67   return rv;
68 }
69 
CharacterDataChanged(nsIContent * aContent,const CharacterDataChangeInfo &)70 void ScriptElement::CharacterDataChanged(nsIContent* aContent,
71                                          const CharacterDataChangeInfo&) {
72   MaybeProcessScript();
73 }
74 
AttributeChanged(Element * aElement,int32_t aNameSpaceID,nsAtom * aAttribute,int32_t aModType,const nsAttrValue * aOldValue)75 void ScriptElement::AttributeChanged(Element* aElement, int32_t aNameSpaceID,
76                                      nsAtom* aAttribute, int32_t aModType,
77                                      const nsAttrValue* aOldValue) {
78   MaybeProcessScript();
79 }
80 
ContentAppended(nsIContent * aFirstNewContent)81 void ScriptElement::ContentAppended(nsIContent* aFirstNewContent) {
82   MaybeProcessScript();
83 }
84 
ContentInserted(nsIContent * aChild)85 void ScriptElement::ContentInserted(nsIContent* aChild) {
86   MaybeProcessScript();
87 }
88 
MaybeProcessScript()89 bool ScriptElement::MaybeProcessScript() {
90   nsCOMPtr<nsIContent> cont = do_QueryInterface((nsIScriptElement*)this);
91 
92   NS_ASSERTION(cont->DebugGetSlots()->mMutationObservers.Contains(this),
93                "You forgot to add self as observer");
94 
95   if (mAlreadyStarted || !mDoneAddingChildren || !cont->GetComposedDoc() ||
96       mMalformed || !HasScriptContent()) {
97     return false;
98   }
99 
100   Document* ownerDoc = cont->OwnerDoc();
101   FreezeExecutionAttrs(ownerDoc);
102 
103   mAlreadyStarted = true;
104 
105   nsCOMPtr<nsIParser> parser = ((nsIScriptElement*)this)->GetCreatorParser();
106   if (parser) {
107     nsCOMPtr<nsIContentSink> sink = parser->GetContentSink();
108     if (sink) {
109       nsCOMPtr<Document> parserDoc = do_QueryInterface(sink->GetTarget());
110       if (ownerDoc != parserDoc) {
111         // Willful violation of HTML5 as of 2010-12-01
112         return false;
113       }
114     }
115   }
116 
117   RefPtr<ScriptLoader> loader = ownerDoc->ScriptLoader();
118   return loader->ProcessScriptElement(this);
119 }
120