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 "nsScriptElement.h"
8 #include "mozilla/BasicEvents.h"
9 #include "mozilla/EventDispatcher.h"
10 #include "mozilla/dom/Element.h"
11 #include "nsContentUtils.h"
12 #include "nsPresContext.h"
13 #include "nsScriptLoader.h"
14 #include "nsIParser.h"
15 #include "nsGkAtoms.h"
16 #include "nsContentSink.h"
17 
18 using namespace mozilla;
19 using namespace mozilla::dom;
20 
21 NS_IMETHODIMP
ScriptAvailable(nsresult aResult,nsIScriptElement * aElement,bool aIsInline,nsIURI * aURI,int32_t aLineNo)22 nsScriptElement::ScriptAvailable(nsresult aResult,
23                                  nsIScriptElement *aElement,
24                                  bool aIsInline,
25                                  nsIURI *aURI,
26                                  int32_t aLineNo)
27 {
28   if (!aIsInline && NS_FAILED(aResult)) {
29     nsCOMPtr<nsIParser> parser = do_QueryReferent(mCreatorParser);
30     if (parser) {
31       parser->PushDefinedInsertionPoint();
32     }
33     nsresult rv = FireErrorEvent();
34     if (parser) {
35       parser->PopDefinedInsertionPoint();
36     }
37     return rv;
38   }
39   return NS_OK;
40 }
41 
42 /* virtual */ nsresult
FireErrorEvent()43 nsScriptElement::FireErrorEvent()
44 {
45   nsCOMPtr<nsIContent> cont =
46     do_QueryInterface((nsIScriptElement*) this);
47 
48   return nsContentUtils::DispatchTrustedEvent(cont->OwnerDoc(),
49                                               cont,
50                                               NS_LITERAL_STRING("error"),
51                                               false /* bubbles */,
52                                               false /* cancelable */);
53 }
54 
55 NS_IMETHODIMP
ScriptEvaluated(nsresult aResult,nsIScriptElement * aElement,bool aIsInline)56 nsScriptElement::ScriptEvaluated(nsresult aResult,
57                                  nsIScriptElement *aElement,
58                                  bool aIsInline)
59 {
60   nsresult rv = NS_OK;
61   if (!aIsInline) {
62     nsCOMPtr<nsIContent> cont =
63       do_QueryInterface((nsIScriptElement*) this);
64 
65     RefPtr<nsPresContext> presContext =
66       nsContentUtils::GetContextForContent(cont);
67 
68     nsEventStatus status = nsEventStatus_eIgnore;
69     EventMessage message = NS_SUCCEEDED(aResult) ? eLoad : eLoadError;
70     WidgetEvent event(true, message);
71     // Load event doesn't bubble.
72     event.mFlags.mBubbles = (message != eLoad);
73 
74     EventDispatcher::Dispatch(cont, presContext, &event, nullptr, &status);
75   }
76 
77   return rv;
78 }
79 
80 void
CharacterDataChanged(nsIDocument * aDocument,nsIContent * aContent,CharacterDataChangeInfo * aInfo)81 nsScriptElement::CharacterDataChanged(nsIDocument *aDocument,
82                                       nsIContent* aContent,
83                                       CharacterDataChangeInfo* aInfo)
84 {
85   MaybeProcessScript();
86 }
87 
88 void
AttributeChanged(nsIDocument * aDocument,Element * aElement,int32_t aNameSpaceID,nsIAtom * aAttribute,int32_t aModType,const nsAttrValue * aOldValue)89 nsScriptElement::AttributeChanged(nsIDocument* aDocument,
90                                   Element* aElement,
91                                   int32_t aNameSpaceID,
92                                   nsIAtom* aAttribute,
93                                   int32_t aModType,
94                                   const nsAttrValue* aOldValue)
95 {
96   MaybeProcessScript();
97 }
98 
99 void
ContentAppended(nsIDocument * aDocument,nsIContent * aContainer,nsIContent * aFirstNewContent,int32_t aNewIndexInContainer)100 nsScriptElement::ContentAppended(nsIDocument* aDocument,
101                                  nsIContent* aContainer,
102                                  nsIContent* aFirstNewContent,
103                                  int32_t aNewIndexInContainer)
104 {
105   MaybeProcessScript();
106 }
107 
108 void
ContentInserted(nsIDocument * aDocument,nsIContent * aContainer,nsIContent * aChild,int32_t aIndexInContainer)109 nsScriptElement::ContentInserted(nsIDocument *aDocument,
110                                  nsIContent* aContainer,
111                                  nsIContent* aChild,
112                                  int32_t aIndexInContainer)
113 {
114   MaybeProcessScript();
115 }
116 
117 bool
MaybeProcessScript()118 nsScriptElement::MaybeProcessScript()
119 {
120   nsCOMPtr<nsIContent> cont =
121     do_QueryInterface((nsIScriptElement*) this);
122 
123   NS_ASSERTION(cont->DebugGetSlots()->mMutationObservers.Contains(this),
124                "You forgot to add self as observer");
125 
126   if (mAlreadyStarted || !mDoneAddingChildren ||
127       !cont->GetComposedDoc() || mMalformed || !HasScriptContent()) {
128     return false;
129   }
130 
131   FreezeUriAsyncDefer();
132 
133   mAlreadyStarted = true;
134 
135   nsIDocument* ownerDoc = cont->OwnerDoc();
136   nsCOMPtr<nsIParser> parser = ((nsIScriptElement*) this)->GetCreatorParser();
137   if (parser) {
138     nsCOMPtr<nsIContentSink> sink = parser->GetContentSink();
139     if (sink) {
140       nsCOMPtr<nsIDocument> parserDoc = do_QueryInterface(sink->GetTarget());
141       if (ownerDoc != parserDoc) {
142         // Willful violation of HTML5 as of 2010-12-01
143         return false;
144       }
145     }
146   }
147 
148   RefPtr<nsScriptLoader> loader = ownerDoc->ScriptLoader();
149   return loader->ProcessScriptElement(this);
150 }
151