|
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
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 #ifndef nsIScriptElement_h___ |
|
7 #define nsIScriptElement_h___ |
|
8 |
|
9 #include "nsISupports.h" |
|
10 #include "nsIURI.h" |
|
11 #include "nsCOMPtr.h" |
|
12 #include "nsIScriptLoaderObserver.h" |
|
13 #include "nsWeakPtr.h" |
|
14 #include "nsIParser.h" |
|
15 #include "nsContentCreatorFunctions.h" |
|
16 #include "nsIDOMHTMLScriptElement.h" |
|
17 #include "mozilla/CORSMode.h" |
|
18 |
|
19 #define NS_ISCRIPTELEMENT_IID \ |
|
20 { 0x491628bc, 0xce7c, 0x4db4, \ |
|
21 { 0x93, 0x3f, 0xce, 0x1b, 0x75, 0xee, 0x75, 0xce } } |
|
22 |
|
23 /** |
|
24 * Internal interface implemented by script elements |
|
25 */ |
|
26 class nsIScriptElement : public nsIScriptLoaderObserver { |
|
27 public: |
|
28 NS_DECLARE_STATIC_IID_ACCESSOR(NS_ISCRIPTELEMENT_IID) |
|
29 |
|
30 nsIScriptElement(mozilla::dom::FromParser aFromParser) |
|
31 : mLineNumber(0), |
|
32 mAlreadyStarted(false), |
|
33 mMalformed(false), |
|
34 mDoneAddingChildren(aFromParser == mozilla::dom::NOT_FROM_PARSER || |
|
35 aFromParser == mozilla::dom::FROM_PARSER_FRAGMENT), |
|
36 mForceAsync(aFromParser == mozilla::dom::NOT_FROM_PARSER || |
|
37 aFromParser == mozilla::dom::FROM_PARSER_FRAGMENT), |
|
38 mFrozen(false), |
|
39 mDefer(false), |
|
40 mAsync(false), |
|
41 mExternal(false), |
|
42 mParserCreated(aFromParser == mozilla::dom::FROM_PARSER_FRAGMENT ? |
|
43 mozilla::dom::NOT_FROM_PARSER : aFromParser), |
|
44 // Fragment parser-created scripts (if executable) |
|
45 // behave like script-created scripts. |
|
46 mCreatorParser(nullptr) |
|
47 { |
|
48 } |
|
49 |
|
50 /** |
|
51 * Content type identifying the scripting language. Can be empty, in |
|
52 * which case javascript will be assumed. |
|
53 */ |
|
54 virtual void GetScriptType(nsAString& type) = 0; |
|
55 |
|
56 /** |
|
57 * Location of script source text. Can return null, in which case |
|
58 * this is assumed to be an inline script element. |
|
59 */ |
|
60 nsIURI* GetScriptURI() |
|
61 { |
|
62 NS_PRECONDITION(mFrozen, "Not ready for this call yet!"); |
|
63 return mUri; |
|
64 } |
|
65 |
|
66 /** |
|
67 * Script source text for inline script elements. |
|
68 */ |
|
69 virtual void GetScriptText(nsAString& text) = 0; |
|
70 |
|
71 virtual void GetScriptCharset(nsAString& charset) = 0; |
|
72 |
|
73 /** |
|
74 * Freezes the return values of GetScriptDeferred(), GetScriptAsync() and |
|
75 * GetScriptURI() so that subsequent modifications to the attributes don't |
|
76 * change execution behavior. |
|
77 */ |
|
78 virtual void FreezeUriAsyncDefer() = 0; |
|
79 |
|
80 /** |
|
81 * Is the script deferred. Currently only supported by HTML scripts. |
|
82 */ |
|
83 bool GetScriptDeferred() |
|
84 { |
|
85 NS_PRECONDITION(mFrozen, "Not ready for this call yet!"); |
|
86 return mDefer; |
|
87 } |
|
88 |
|
89 /** |
|
90 * Is the script async. Currently only supported by HTML scripts. |
|
91 */ |
|
92 bool GetScriptAsync() |
|
93 { |
|
94 NS_PRECONDITION(mFrozen, "Not ready for this call yet!"); |
|
95 return mAsync; |
|
96 } |
|
97 |
|
98 /** |
|
99 * Is the script an external script? |
|
100 */ |
|
101 bool GetScriptExternal() |
|
102 { |
|
103 NS_PRECONDITION(mFrozen, "Not ready for this call yet!"); |
|
104 return mExternal; |
|
105 } |
|
106 |
|
107 /** |
|
108 * Returns how the element was created. |
|
109 */ |
|
110 mozilla::dom::FromParser GetParserCreated() |
|
111 { |
|
112 return mParserCreated; |
|
113 } |
|
114 |
|
115 void SetScriptLineNumber(uint32_t aLineNumber) |
|
116 { |
|
117 mLineNumber = aLineNumber; |
|
118 } |
|
119 uint32_t GetScriptLineNumber() |
|
120 { |
|
121 return mLineNumber; |
|
122 } |
|
123 |
|
124 void SetIsMalformed() |
|
125 { |
|
126 mMalformed = true; |
|
127 } |
|
128 bool IsMalformed() |
|
129 { |
|
130 return mMalformed; |
|
131 } |
|
132 |
|
133 void PreventExecution() |
|
134 { |
|
135 mAlreadyStarted = true; |
|
136 } |
|
137 |
|
138 void LoseParserInsertedness() |
|
139 { |
|
140 mFrozen = false; |
|
141 mUri = nullptr; |
|
142 mCreatorParser = nullptr; |
|
143 mParserCreated = mozilla::dom::NOT_FROM_PARSER; |
|
144 bool async = false; |
|
145 nsCOMPtr<nsIDOMHTMLScriptElement> htmlScript = do_QueryInterface(this); |
|
146 if (htmlScript) { |
|
147 htmlScript->GetAsync(&async); |
|
148 } |
|
149 mForceAsync = !async; |
|
150 } |
|
151 |
|
152 void SetCreatorParser(nsIParser* aParser) |
|
153 { |
|
154 mCreatorParser = do_GetWeakReference(aParser); |
|
155 } |
|
156 |
|
157 /** |
|
158 * Unblocks the creator parser |
|
159 */ |
|
160 void UnblockParser() |
|
161 { |
|
162 nsCOMPtr<nsIParser> parser = do_QueryReferent(mCreatorParser); |
|
163 if (parser) { |
|
164 parser->UnblockParser(); |
|
165 } |
|
166 } |
|
167 |
|
168 /** |
|
169 * Attempts to resume parsing asynchronously |
|
170 */ |
|
171 void ContinueParserAsync() |
|
172 { |
|
173 nsCOMPtr<nsIParser> parser = do_QueryReferent(mCreatorParser); |
|
174 if (parser) { |
|
175 parser->ContinueInterruptedParsingAsync(); |
|
176 } |
|
177 } |
|
178 |
|
179 /** |
|
180 * Informs the creator parser that the evaluation of this script is starting |
|
181 */ |
|
182 void BeginEvaluating() |
|
183 { |
|
184 nsCOMPtr<nsIParser> parser = do_QueryReferent(mCreatorParser); |
|
185 if (parser) { |
|
186 parser->BeginEvaluatingParserInsertedScript(); |
|
187 } |
|
188 } |
|
189 |
|
190 /** |
|
191 * Informs the creator parser that the evaluation of this script is ending |
|
192 */ |
|
193 void EndEvaluating() |
|
194 { |
|
195 nsCOMPtr<nsIParser> parser = do_QueryReferent(mCreatorParser); |
|
196 if (parser) { |
|
197 parser->EndEvaluatingParserInsertedScript(); |
|
198 } |
|
199 } |
|
200 |
|
201 /** |
|
202 * Retrieves a pointer to the creator parser if this has one or null if not |
|
203 */ |
|
204 already_AddRefed<nsIParser> GetCreatorParser() |
|
205 { |
|
206 nsCOMPtr<nsIParser> parser = do_QueryReferent(mCreatorParser); |
|
207 return parser.forget(); |
|
208 } |
|
209 |
|
210 /** |
|
211 * This method is called when the parser finishes creating the script |
|
212 * element's children, if any are present. |
|
213 * |
|
214 * @return whether the parser will be blocked while this script is being |
|
215 * loaded |
|
216 */ |
|
217 bool AttemptToExecute() |
|
218 { |
|
219 mDoneAddingChildren = true; |
|
220 bool block = MaybeProcessScript(); |
|
221 if (!mAlreadyStarted) { |
|
222 // Need to lose parser-insertedness here to allow another script to cause |
|
223 // execution later. |
|
224 LoseParserInsertedness(); |
|
225 } |
|
226 return block; |
|
227 } |
|
228 |
|
229 /** |
|
230 * Get the CORS mode of the script element |
|
231 */ |
|
232 virtual mozilla::CORSMode GetCORSMode() const |
|
233 { |
|
234 /* Default to no CORS */ |
|
235 return mozilla::CORS_NONE; |
|
236 } |
|
237 |
|
238 /** |
|
239 * Fire an error event |
|
240 */ |
|
241 virtual nsresult FireErrorEvent() = 0; |
|
242 |
|
243 protected: |
|
244 /** |
|
245 * Processes the script if it's in the document-tree and links to or |
|
246 * contains a script. Once it has been evaluated there is no way to make it |
|
247 * reevaluate the script, you'll have to create a new element. This also means |
|
248 * that when adding a src attribute to an element that already contains an |
|
249 * inline script, the script referenced by the src attribute will not be |
|
250 * loaded. |
|
251 * |
|
252 * In order to be able to use multiple childNodes, or to use the |
|
253 * fallback mechanism of using both inline script and linked script you have |
|
254 * to add all attributes and childNodes before adding the element to the |
|
255 * document-tree. |
|
256 * |
|
257 * @return whether the parser will be blocked while this script is being |
|
258 * loaded |
|
259 */ |
|
260 virtual bool MaybeProcessScript() = 0; |
|
261 |
|
262 /** |
|
263 * The start line number of the script. |
|
264 */ |
|
265 uint32_t mLineNumber; |
|
266 |
|
267 /** |
|
268 * The "already started" flag per HTML5. |
|
269 */ |
|
270 bool mAlreadyStarted; |
|
271 |
|
272 /** |
|
273 * The script didn't have an end tag. |
|
274 */ |
|
275 bool mMalformed; |
|
276 |
|
277 /** |
|
278 * False if parser-inserted but the parser hasn't triggered running yet. |
|
279 */ |
|
280 bool mDoneAddingChildren; |
|
281 |
|
282 /** |
|
283 * If true, the .async property returns true instead of reflecting the |
|
284 * content attribute. |
|
285 */ |
|
286 bool mForceAsync; |
|
287 |
|
288 /** |
|
289 * Whether src, defer and async are frozen. |
|
290 */ |
|
291 bool mFrozen; |
|
292 |
|
293 /** |
|
294 * The effective deferredness. |
|
295 */ |
|
296 bool mDefer; |
|
297 |
|
298 /** |
|
299 * The effective asyncness. |
|
300 */ |
|
301 bool mAsync; |
|
302 |
|
303 /** |
|
304 * The effective externalness. A script can be external with mUri being null |
|
305 * if the src attribute contained an invalid URL string. |
|
306 */ |
|
307 bool mExternal; |
|
308 |
|
309 /** |
|
310 * Whether this element was parser-created. |
|
311 */ |
|
312 mozilla::dom::FromParser mParserCreated; |
|
313 |
|
314 /** |
|
315 * The effective src (or null if no src). |
|
316 */ |
|
317 nsCOMPtr<nsIURI> mUri; |
|
318 |
|
319 /** |
|
320 * The creator parser of a non-defer, non-async parser-inserted script. |
|
321 */ |
|
322 nsWeakPtr mCreatorParser; |
|
323 }; |
|
324 |
|
325 NS_DEFINE_STATIC_IID_ACCESSOR(nsIScriptElement, NS_ISCRIPTELEMENT_IID) |
|
326 |
|
327 #endif // nsIScriptElement_h___ |