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