Changeset 79114 in webkit
- Timestamp:
- Feb 19, 2011 1:39:06 AM (13 years ago)
- Location:
- trunk
- Files:
-
- 13 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r79111 r79114 1 2011-02-19 James Simonsen <simonjam@chromium.org> 2 3 Reviewed by Adam Barth. 4 5 Make ScriptElement match the HTML5 spec 6 https://bugs.webkit.org/show_bug.cgi?id=54676 7 8 This implements the "prepare a script" section of the HTML5 spec in ScriptElement::prepareScript(). 9 http://www.whatwg.org/specs/web-apps/current-work/multipage/scripting-1.html#prepare-a-script 10 11 There are a couple of things missing from the spec that would be new functionality. These will be added later. 12 - Support for async=false 13 - Empty src attribute should dispatch an error. 14 15 There are a couple of slight behavioral changes to match the spec. 16 - An XHTML script that is loaded then copied will not fire load on the copy. 17 - If onbeforeload moves the script to a different document, then it will not try to execute again because wasAlreadyStarted is true. 18 19 The parsers were updated to use the new API, but not rewritten to look like the spec. That will be done separately. 20 21 * fast/dom/HTMLScriptElement/move-in-beforeload.html: Original author says test was only meant to check for crashes. Beforeload is not specified by HTML5. Test was modified to assume moved script wouldn't execute because wasAlreadyStarted is set. 22 * fast/dom/script-clone-rerun-src.xhtml: According to HTML5 spec, load should only fire after a script executes. Test was modified to match that. The old broken behavior was that load fired on the cloned element, even though it didn't execute. 23 1 24 2011-02-19 Andrew Wilson <atwilson@chromium.org> 2 25 -
trunk/LayoutTests/fast/dom/HTMLScriptElement/move-in-beforeload.html
r74752 r79114 9 9 <script> 10 10 if (window.layoutTestController) { 11 layoutTestController.waitUntilDone();12 11 layoutTestController.dumpAsText(); 13 12 } … … 19 18 var s = document.body.removeChild(document.getElementsByTagName("script")[2]); 20 19 document.getElementsByTagName("iframe")[0].contentDocument.body.appendChild(s); 20 testPassed(""); 21 21 }, false); 22 22 s.addEventListener("error", function() { 23 testFailed("error event should not fire.") 23 testFailed("error event should not fire."); 24 24 }, false); 25 25 s.addEventListener("load", function() { 26 testPassed(""); 27 if (window.layoutTestController) 28 layoutTestController.notifyDone(); 26 testFailed("script should not be loaded"); 29 27 }, false); 30 28 s.src = "external.js"; -
trunk/LayoutTests/fast/dom/script-clone-rerun-src.xhtml
r72638 r79114 12 12 layoutTestController.waitUntilDone(); 13 13 } 14 15 var firstLoad = true;16 17 function loaded() {18 if (firstLoad) {19 firstLoad = false;20 return;21 }22 23 result = 'PASS';24 if (i == 2)25 result = 'FAIL: script ran twice';26 else if (i > 2)27 result = 'FAIL: script ran ' + i + ' times';28 document.body.appendChild(document.createTextNode(result));29 30 layoutTestController.notifyDone();31 }32 33 14 </script> 34 15 </head> 35 16 <body> 36 17 <p>This test runs a script that clones and inserts its script element. The script should run exactly once and print PASS:</p> 37 <div><script src="resources/script-clone-rerun-src.js" onload="loaded()"></script></div>18 <div><script src="resources/script-clone-rerun-src.js"></script></div> 38 19 <script> 39 20 … … 41 22 var div = script.parentNode; 42 23 div.removeChild(script); 43 div.appendChild(script.cloneNode(true)); 24 var clone = script.cloneNode(true); 25 clone.addEventListener("load", function() { document.body.appendChild(document.createTextNode("FAIL: load event fired on clone")); }, false); 26 div.appendChild(clone); 27 28 setTimeout(function() { 29 result = 'FAIL: script never ran'; 30 if (i == 1) 31 result = 'PASS'; 32 else if (i > 1) 33 result = 'FAIL: script ran ' + i + ' times'; 34 document.body.appendChild(document.createTextNode(result)); 35 if (window.layoutTestController) 36 layoutTestController.notifyDone(); 37 }, 0); 44 38 45 39 </script> -
trunk/Source/WebCore/ChangeLog
r79112 r79114 1 2011-02-19 James Simonsen <simonjam@chromium.org> 2 3 Reviewed by Adam Barth. 4 5 Make ScriptElement match the HTML5 spec 6 https://bugs.webkit.org/show_bug.cgi?id=54676 7 8 This implements the "prepare a script" section of the HTML5 spec in ScriptElement::prepareScript(). 9 http://www.whatwg.org/specs/web-apps/current-work/multipage/scripting-1.html#prepare-a-script 10 11 There are a couple of things missing from the spec that would be new functionality. These will be added later. 12 - Support for async=false 13 - Empty src attribute should dispatch an error. 14 15 There are a couple of slight behavioral changes to match the spec. 16 - An XHTML script that is loaded then copied will not fire load on the copy. 17 - If onbeforeload moves the script to a different document, then it will not try to execute again because wasAlreadyStarted is true. 18 19 The parsers were updated to use the new API, but not rewritten to look like the spec. That will be done separately. 20 21 Test: All existing tests. 22 23 * dom/ScriptElement.cpp: Rewritten to match HTML5 spec. 24 (WebCore::ScriptElement::ScriptElement): 25 (WebCore::ScriptElement::insertedIntoDocument): Logic moved to prepareScript. 26 (WebCore::ScriptElement::childrenChanged): Logic moved to prepareScript. 27 (WebCore::ScriptElement::handleSourceAttribute): Logic moved to prepareScript. 28 (WebCore::isLegacySupportedJavaScriptLanguage): Added to support old script types in layout tests. 29 (WebCore::ScriptElement::isScriptTypeSupported): Derived from old shouldExecuteAsJavaScript(). 30 (WebCore::ScriptElement::prepareScript): START HERE. Main change. Should read exactly like HTML5's "prepare a script." Legacy type support needed for layout tests using XML parser. 31 (WebCore::ScriptElement::requestScript): Most logic moved to prepareScript. Check security settings here. 32 (WebCore::ScriptElement::executeScript): Combined evaluateScript() and executeScript() from old code. Logic moved to prepareScript. 33 (WebCore::ScriptElement::stopLoadRequest): Ignore parser executed scripts. 34 (WebCore::ScriptElement::execute): Renamed executeScript. 35 (WebCore::ScriptElement::notifyFinished): We should only listen for non-parser executed scripts. 36 (WebCore::ScriptElement::ignoresLoadRequest): New variable names. 37 (WebCore::ScriptElement::childrenAreCommentsOrEmptyText): Added for HTML5 compliance. 38 (WebCore::ScriptElement::scriptCharset): Use HTML5 variables. 39 * dom/ScriptElement.h: 40 (WebCore::ScriptElement::willBeParserExecuted): Added. 41 (WebCore::ScriptElement::readyToBeParserExecuted): Added. 42 (WebCore::ScriptElement::willExecuteWhenDocumentFinishedParsing): Added. 43 (WebCore::ScriptElement::cachedScript): prepareScript() is the only place that should load scripts. This accessor lets the parsers listen for when loads finish. 44 (WebCore::ScriptElement::isParserInserted): Added. 45 * dom/XMLDocumentParserLibxml2.cpp: 46 (WebCore::XMLDocumentParser::endElementNs): Should behave the same. Offloads much of its work to prepareScript(). 47 * dom/XMLDocumentParserQt.cpp: 48 (WebCore::XMLDocumentParser::parseEndElement): Identical to libxml2 changes. 49 * html/HTMLScriptElement.cpp: 50 (WebCore::HTMLScriptElement::insertedIntoDocument): No longer needs url. 51 (WebCore::HTMLScriptElement::hasSourceAttribute): Added. 52 * html/HTMLScriptElement.h: 53 * html/parser/HTMLScriptRunner.cpp: 54 (WebCore::HTMLScriptRunner::requestPendingScript): Requesting scripts offloaded to ScriptElement. 55 (WebCore::HTMLScriptRunner::runScript): Should behave the same. Offloads much of its work to prepareScript(). 56 * svg/SVGScriptElement.cpp: 57 (WebCore::SVGScriptElement::svgAttributeChanged): New ScriptElement function names. 58 (WebCore::SVGScriptElement::insertedIntoDocument): No longer needs url. 59 (WebCore::SVGScriptElement::finishParsingChildren): ScriptElement::finishParsingChildren is gone. 60 (WebCore::SVGScriptElement::hasSourceAttribute): Added. 61 (WebCore::SVGScriptElement::dispatchLoadEvent): New ScriptElement function names. 62 * svg/SVGScriptElement.h: 63 1 64 2011-02-19 Marc-Antoine Ruel <maruel@chromium.org> 2 65 -
trunk/Source/WebCore/dom/ScriptElement.cpp
r77750 r79114 52 52 namespace WebCore { 53 53 54 ScriptElement::ScriptElement(Element* element, bool wasInsertedByParser, bool wasAlreadyStarted)54 ScriptElement::ScriptElement(Element* element, bool parserInserted, bool alreadyStarted) 55 55 : m_element(element) 56 56 , m_cachedScript(0) 57 , m_ wasInsertedByParser(wasInsertedByParser)57 , m_parserInserted(parserInserted) 58 58 , m_isExternalScript(false) 59 , m_ wasAlreadyStarted(wasAlreadyStarted)59 , m_alreadyStarted(alreadyStarted) 60 60 , m_haveFiredLoad(false) 61 , m_willBeParserExecuted(false) 62 , m_readyToBeParserExecuted(false) 63 , m_willExecuteWhenDocumentFinishedParsing(false) 61 64 { 62 65 ASSERT(m_element); … … 68 71 } 69 72 70 void ScriptElement::insertedIntoDocument(const String& sourceUrl) 71 { 72 if (wasInsertedByParser() && !isAsynchronous()) 73 return; 74 75 // http://www.whatwg.org/specs/web-apps/current-work/#script 76 77 if (!sourceUrl.isEmpty()) { 78 requestScript(sourceUrl); 79 return; 80 } 81 82 // If there's an empty script node, we shouldn't evaluate the script 83 // because if a script is inserted afterwards (by setting text or innerText) 84 // it should be evaluated, and evaluateScript only evaluates a script once. 85 evaluateScript(ScriptSourceCode(scriptContent(), element()->document()->url())); // FIXME: Provide a real starting line number here. 73 void ScriptElement::insertedIntoDocument() 74 { 75 if (!m_parserInserted) 76 prepareScript(); // FIXME: Provide a real starting line number here. 86 77 } 87 78 … … 94 85 void ScriptElement::childrenChanged() 95 86 { 96 if (wasInsertedByParser()) 97 return; 98 99 // If a node is inserted as a child of the script element 100 // and the script element has been inserted in the document 101 // we evaluate the script. 102 if (m_element->inDocument() && m_element->firstChild()) 103 evaluateScript(ScriptSourceCode(scriptContent(), m_element->document()->url())); // FIXME: Provide a real starting line number here 104 } 105 106 void ScriptElement::finishParsingChildren(const String& sourceUrl) 107 { 108 // The parser just reached </script>. If we have no src and no text, 109 // allow dynamic loading later. 110 if (sourceUrl.isEmpty() && scriptContent().isEmpty()) 111 m_wasInsertedByParser = false; 87 if (!m_parserInserted && m_element->inDocument()) 88 prepareScript(); // FIXME: Provide a real starting line number here. 112 89 } 113 90 … … 117 94 return; 118 95 119 requestScript(sourceUrl);96 prepareScript(); // FIXME: Provide a real starting line number here. 120 97 } 121 98 122 99 // Helper function 123 static bool isSupportedJavaScriptLanguage(const String& language) 124 { 100 static bool isLegacySupportedJavaScriptLanguage(const String& language) 101 { 102 // Mozilla 1.8 accepts javascript1.0 - javascript1.7, but WinIE 7 accepts only javascript1.1 - javascript1.3. 103 // Mozilla 1.8 and WinIE 7 both accept javascript and livescript. 104 // WinIE 7 accepts ecmascript and jscript, but Mozilla 1.8 doesn't. 105 // Neither Mozilla 1.8 nor WinIE 7 accept leading or trailing whitespace. 106 // We want to accept all the values that either of these browsers accept, but not other values. 107 108 // FIXME: This function is not HTML5 compliant. These belong in the MIME registry as "text/javascript<version>" entries. 125 109 typedef HashSet<String, CaseFoldingHash> LanguageSet; 126 110 DEFINE_STATIC_LOCAL(LanguageSet, languages, ()); … … 138 122 languages.add("livescript"); 139 123 languages.add("ecmascript"); 140 languages.add("jscript"); 124 languages.add("jscript"); 141 125 } 142 126 … … 144 128 } 145 129 146 void ScriptElement::requestScript(const String& sourceUrl) 147 { 148 // FIXME: Eventually we'd like to evaluate scripts which are inserted into a 130 bool ScriptElement::isScriptTypeSupported(LegacyTypeSupport supportLegacyTypes) const 131 { 132 // FIXME: isLegacySupportedJavaScriptLanguage() is not valid HTML5. It is used here to maintain backwards compatibility with existing layout tests. The specific violations are: 133 // - Allowing type=javascript. type= should only support MIME types, such as text/javascript. 134 // - Allowing a different set of languages for language= and type=. language= supports Javascript 1.1 and 1.4-1.6, but type= does not. 135 136 String type = typeAttributeValue(); 137 String language = languageAttributeValue(); 138 if (type.isEmpty() && language.isEmpty()) 139 return true; // Assume text/javascript. 140 if (type.isEmpty()) { 141 type = "text/" + language.lower(); 142 if (MIMETypeRegistry::isSupportedJavaScriptMIMEType(type) || isLegacySupportedJavaScriptLanguage(language)) 143 return true; 144 } else if (MIMETypeRegistry::isSupportedJavaScriptMIMEType(type.stripWhiteSpace().lower()) || (supportLegacyTypes == AllowLegacyTypeInTypeAttribute && isLegacySupportedJavaScriptLanguage(type))) 145 return true; 146 return false; 147 } 148 149 // http://dev.w3.org/html5/spec/Overview.html#prepare-a-script 150 bool ScriptElement::prepareScript(const TextPosition1& scriptStartPosition, LegacyTypeSupport supportLegacyTypes) 151 { 152 if (m_alreadyStarted) 153 return false; 154 155 bool wasParserInserted; 156 if (m_parserInserted) { 157 wasParserInserted = true; 158 m_parserInserted = false; 159 } else 160 wasParserInserted = false; 161 162 // FIXME: HTML5 spec says we should set forceAsync. 163 164 // FIXME: HTML5 spec says we should check that all children are either comments or empty text nodes. 165 if (!hasSourceAttribute() && !m_element->firstChild()) 166 return false; 167 168 if (!m_element->inDocument()) 169 return false; 170 171 if (!isScriptTypeSupported(supportLegacyTypes)) 172 return false; 173 174 if (wasParserInserted) 175 m_parserInserted = true; 176 177 m_alreadyStarted = true; 178 179 // FIXME: If script is parser inserted, verify it's still in the original document. 180 181 // FIXME: Eventually we'd like to evaluate scripts which are inserted into a 149 182 // viewless document but this'll do for now. 150 183 // See http://bugs.webkit.org/show_bug.cgi?id=5727 151 184 if (!m_element->document()->frame()) 152 return; 185 return false; 186 187 if (!m_element->document()->frame()->script()->canExecuteScripts(AboutToExecuteScript)) 188 return false; 189 190 if (!isScriptForEventSupported()) 191 return false; 192 193 if (!charsetAttributeValue().isEmpty()) 194 m_characterEncoding = charsetAttributeValue(); 195 else 196 m_characterEncoding = m_element->document()->charset(); 197 198 if (hasSourceAttribute()) 199 if (!requestScript(sourceAttributeValue())) 200 return false; 201 202 if (hasSourceAttribute() && deferAttributeValue() && m_parserInserted && !asyncAttributeValue()) { 203 m_willExecuteWhenDocumentFinishedParsing = true; 204 m_willBeParserExecuted = true; 205 } else if (hasSourceAttribute() && m_parserInserted && !asyncAttributeValue()) 206 m_willBeParserExecuted = true; 207 else if (!hasSourceAttribute() && m_parserInserted && !m_element->document()->haveStylesheetsLoaded()) { 208 m_willBeParserExecuted = true; 209 m_readyToBeParserExecuted = true; 210 } else if (hasSourceAttribute()) 211 m_cachedScript->addClient(this); 212 else 213 executeScript(ScriptSourceCode(scriptContent(), m_element->document()->url(), scriptStartPosition)); 214 215 return true; 216 } 217 218 bool ScriptElement::requestScript(const String& sourceUrl) 219 { 220 if (!m_element->document()->contentSecurityPolicy()->canLoadExternalScriptFromSrc(sourceUrl)) 221 return false; 153 222 154 223 RefPtr<Document> originalDocument = m_element->document(); 155 224 if (!m_element->dispatchBeforeLoadEvent(sourceUrl)) 156 return ;225 return false; 157 226 if (!m_element->inDocument() || m_element->document() != originalDocument) 158 return ;227 return false; 159 228 160 229 ASSERT(!m_cachedScript); 230 // FIXME: If sourceUrl is empty, we should dispatchErrorEvent(). 161 231 m_cachedScript = m_element->document()->cachedResourceLoader()->requestScript(sourceUrl, scriptCharset()); 162 232 m_isExternalScript = true; 163 233 164 // m_wasInsertedByParser is never reset - always resied at the initial value set while parsing. 165 // m_wasAlreadyStarted is left untouched as well to avoid script reexecution, if a <script> element 166 // is removed and reappended to the document. 167 m_haveFiredLoad = false; 168 169 if (m_cachedScript) { 170 m_cachedScript->addClient(this); 171 return; 172 } 234 if (m_cachedScript) 235 return true; 173 236 174 237 dispatchErrorEvent(); 175 } 176 177 void ScriptElement::evaluateScript(const ScriptSourceCode& sourceCode) 178 { 179 if (wasAlreadyStarted() || sourceCode.isEmpty() || !shouldExecuteAsJavaScript()) 238 return false; 239 } 240 241 void ScriptElement::executeScript(const ScriptSourceCode& sourceCode) 242 { 243 ASSERT(m_alreadyStarted); 244 245 if (sourceCode.isEmpty()) 180 246 return; 181 247 … … 183 249 ASSERT(document); 184 250 if (Frame* frame = document->frame()) { 185 if (!frame->script()->canExecuteScripts(AboutToExecuteScript))186 return;187 188 m_wasAlreadyStarted = true;189 190 // http://www.whatwg.org/specs/web-apps/current-work/#script191 192 251 { 193 252 IgnoreDestructiveWriteCountIncrementer ignoreDesctructiveWriteCountIncrementer(m_isExternalScript ? document.get() : 0); … … 202 261 } 203 262 204 void ScriptElement::executeScript(const ScriptSourceCode& sourceCode)205 {206 if (wasAlreadyStarted() || sourceCode.isEmpty())207 return;208 RefPtr<Document> document = m_element->document();209 ASSERT(document);210 Frame* frame = document->frame();211 if (!frame)212 return;213 214 m_wasAlreadyStarted = true;215 216 frame->script()->executeScript(sourceCode);217 }218 219 263 void ScriptElement::stopLoadRequest() 220 264 { 221 265 if (m_cachedScript) { 222 m_cachedScript->removeClient(this); 266 if (!m_willBeParserExecuted) 267 m_cachedScript->removeClient(this); 223 268 m_cachedScript = 0; 224 269 } … … 227 272 void ScriptElement::execute(CachedScript* cachedScript) 228 273 { 274 ASSERT(!m_willBeParserExecuted); 229 275 ASSERT(cachedScript); 230 276 if (cachedScript->errorOccurred()) 231 277 dispatchErrorEvent(); 232 278 else { 233 e valuateScript(ScriptSourceCode(cachedScript));279 executeScript(ScriptSourceCode(cachedScript)); 234 280 dispatchLoadEvent(); 235 281 } … … 239 285 void ScriptElement::notifyFinished(CachedResource* o) 240 286 { 287 ASSERT(!m_willBeParserExecuted); 241 288 ASSERT_UNUSED(o, o == m_cachedScript); 242 289 m_element->document()->asyncScriptRunner()->executeScriptSoon(this, m_cachedScript); … … 246 293 bool ScriptElement::ignoresLoadRequest() const 247 294 { 248 return wasAlreadyStarted() || m_isExternalScript || wasInsertedByParser() || !m_element->inDocument(); 249 } 250 251 bool ScriptElement::shouldExecuteAsJavaScript() const 252 { 253 /* 254 Mozilla 1.8 accepts javascript1.0 - javascript1.7, but WinIE 7 accepts only javascript1.1 - javascript1.3. 255 Mozilla 1.8 and WinIE 7 both accept javascript and livescript. 256 WinIE 7 accepts ecmascript and jscript, but Mozilla 1.8 doesn't. 257 Neither Mozilla 1.8 nor WinIE 7 accept leading or trailing whitespace. 258 We want to accept all the values that either of these browsers accept, but not other values. 259 260 FIXME: Is this HTML5 compliant? 261 */ 262 String type = typeAttributeValue(); 263 if (!type.isEmpty()) { 264 if (!MIMETypeRegistry::isSupportedJavaScriptMIMEType(type.stripWhiteSpace().lower())) 265 return false; 266 } else { 267 String language = languageAttributeValue(); 268 if (!language.isEmpty() && !isSupportedJavaScriptLanguage(language)) 269 return false; 270 } 271 272 // No type or language is specified, so we assume the script to be JavaScript. 273 295 return m_alreadyStarted || m_isExternalScript || m_parserInserted || !m_element->inDocument(); 296 } 297 298 bool ScriptElement::isScriptForEventSupported() const 299 { 300 String eventAttribute = eventAttributeValue(); 274 301 String forAttribute = forAttributeValue(); 275 String eventAttribute = eventAttributeValue(); 276 if (!forAttribute.isEmpty() && !eventAttribute.isEmpty()) { 302 if (!eventAttribute.isEmpty() && !forAttribute.isEmpty()) { 277 303 forAttribute = forAttribute.stripWhiteSpace(); 278 304 if (!equalIgnoringCase(forAttribute, "window")) 279 305 return false; 280 306 281 307 eventAttribute = eventAttribute.stripWhiteSpace(); 282 308 if (!equalIgnoringCase(eventAttribute, "onload") && !equalIgnoringCase(eventAttribute, "onload()")) 283 309 return false; 284 310 } 285 286 311 return true; 287 }288 289 String ScriptElement::scriptCharset() const290 {291 // First we try to get encoding from charset attribute.292 String charset = charsetAttributeValue().stripWhiteSpace();293 294 // If charset has not been declared in script tag, fall back to frame encoding.295 if (charset.isEmpty())296 charset = m_element->document()->charset();297 298 return charset;299 312 } 300 313 … … 326 339 } 327 340 328 bool ScriptElement::isAsynchronous() const329 {330 // Only external scripts may be asynchronous.331 // See: http://dev.w3.org/html5/spec/Overview.html#attr-script-async332 return !sourceAttributeValue().isEmpty() && asyncAttributeValue();333 }334 335 bool ScriptElement::isDeferred() const336 {337 // Only external scripts may be deferred and async trumps defer to allow for backward compatibility.338 // See: http://dev.w3.org/html5/spec/Overview.html#attr-script-defer339 return !sourceAttributeValue().isEmpty() && !asyncAttributeValue() && deferAttributeValue();340 }341 342 341 ScriptElement* toScriptElement(Element* element) 343 342 { -
trunk/Source/WebCore/dom/ScriptElement.h
r76248 r79114 24 24 #include "CachedResourceClient.h" 25 25 #include "CachedResourceHandle.h" 26 #include <wtf/text/TextPosition.h> 26 27 27 28 namespace WebCore { … … 37 38 ScriptElement(Element*, bool createdByParser, bool isEvaluated); 38 39 virtual ~ScriptElement(); 39 40 40 41 Element* element() const { return m_element; } 41 42 42 // A charset for loading the script (may be overridden by HTTP headers or a BOM).43 String scriptCharset() const;43 enum LegacyTypeSupport { DisallowLegacyTypeInTypeAttribute, AllowLegacyTypeInTypeAttribute }; 44 bool prepareScript(const TextPosition1& scriptStartPosition = TextPosition1::minimumPosition(), LegacyTypeSupport = DisallowLegacyTypeInTypeAttribute); 44 45 46 String scriptCharset() const { return m_characterEncoding; } 45 47 String scriptContent() const; 46 bool shouldExecuteAsJavaScript() const;47 48 void executeScript(const ScriptSourceCode&); 48 49 void execute(CachedScript*); 49 50 50 51 // XML parser calls these 51 virtual String sourceAttributeValue() const = 0;52 52 virtual void dispatchLoadEvent() = 0; 53 53 virtual void dispatchErrorEvent() = 0; 54 bool isScriptTypeSupported(LegacyTypeSupport) const; 54 55 55 56 bool haveFiredLoadEvent() const { return m_haveFiredLoad; } 57 bool willBeParserExecuted() const { return m_willBeParserExecuted; } 58 bool readyToBeParserExecuted() const { return m_readyToBeParserExecuted; } 59 bool willExecuteWhenDocumentFinishedParsing() const { return m_willExecuteWhenDocumentFinishedParsing; } 60 CachedResourceHandle<CachedScript> cachedScript() { return m_cachedScript; } 56 61 57 62 protected: 58 63 void setHaveFiredLoadEvent(bool haveFiredLoad) { m_haveFiredLoad = haveFiredLoad; } 59 bool wasInsertedByParser() const { return m_wasInsertedByParser; }60 bool wasAlreadyStarted() const { return m_wasAlreadyStarted; }64 bool isParserInserted() const { return m_parserInserted; } 65 bool alreadyStarted() const { return m_alreadyStarted; } 61 66 62 67 // Helper functions used by our parent classes. 63 void insertedIntoDocument( const String& sourceUrl);68 void insertedIntoDocument(); 64 69 void removedFromDocument(); 65 70 void childrenChanged(); 66 void finishParsingChildren(const String& sourceUrl);67 71 void handleSourceAttribute(const String& sourceUrl); 68 72 69 73 private: 70 74 bool ignoresLoadRequest() const; 71 bool isAsynchronous() const; 72 bool isDeferred() const; 75 bool isScriptForEventSupported() const; 73 76 74 void requestScript(const String& sourceUrl); 75 void evaluateScript(const ScriptSourceCode&); 77 bool requestScript(const String& sourceUrl); 76 78 void stopLoadRequest(); 77 79 78 80 virtual void notifyFinished(CachedResource*); 79 81 82 virtual String sourceAttributeValue() const = 0; 80 83 virtual String charsetAttributeValue() const = 0; 81 84 virtual String typeAttributeValue() const = 0; … … 85 88 virtual bool asyncAttributeValue() const = 0; 86 89 virtual bool deferAttributeValue() const = 0; 90 virtual bool hasSourceAttribute() const = 0; 87 91 88 92 Element* m_element; 89 93 CachedResourceHandle<CachedScript> m_cachedScript; 90 bool m_wasInsertedByParser; 91 bool m_isExternalScript; 92 bool m_wasAlreadyStarted; 93 bool m_haveFiredLoad; 94 bool m_parserInserted : 1; 95 bool m_isExternalScript : 1; 96 bool m_alreadyStarted : 1; 97 bool m_haveFiredLoad : 1; 98 bool m_willBeParserExecuted : 1; // Same as "The parser will handle executing the script." 99 bool m_readyToBeParserExecuted : 1; 100 bool m_willExecuteWhenDocumentFinishedParsing : 1; 101 String m_characterEncoding; 102 String m_fallbackCharacterEncoding; 94 103 }; 95 104 -
trunk/Source/WebCore/dom/XMLDocumentParserLibxml2.cpp
r76248 r79114 881 881 m_requestingScript = true; 882 882 883 bool successfullyPrepared = scriptElement->prepareScript(m_scriptStartPosition, ScriptElement::AllowLegacyTypeInTypeAttribute); 884 if (!successfullyPrepared) { 883 885 #if ENABLE(XHTMLMP) 884 if (!scriptElement->shouldExecuteAsJavaScript()) 885 document()->setShouldProcessNoscriptElement(true); 886 else 887 #endif 888 { 889 // FIXME: Script execution should be shared should be shared between 886 if (!scriptElement->isScriptTypeSupported(ScriptElement::AllowLegacyTypeInTypeAttribute)) 887 document()->setShouldProcessNoscriptElement(true); 888 #endif 889 } else { 890 // FIXME: Script execution should be shared between 890 891 // the libxml2 and Qt XMLDocumentParser implementations. 891 892 … … 894 895 RefPtr<XMLDocumentParser> protect(this); 895 896 896 String scriptHref = scriptElement->sourceAttributeValue(); 897 if (!scriptHref.isEmpty()) { 898 // we have a src attribute 899 String scriptCharset = scriptElement->scriptCharset(); 900 if (element->dispatchBeforeLoadEvent(scriptHref) && 901 (m_pendingScript = document()->cachedResourceLoader()->requestScript(scriptHref, scriptCharset))) { 902 m_scriptElement = element; 903 m_pendingScript->addClient(this); 904 905 // m_pendingScript will be 0 if script was already loaded and ref() executed it 906 if (m_pendingScript) 907 pauseParsing(); 908 } else 909 m_scriptElement = 0; 897 if (scriptElement->readyToBeParserExecuted()) 898 scriptElement->executeScript(ScriptSourceCode(scriptElement->scriptContent(), document()->url(), m_scriptStartPosition)); 899 else if (scriptElement->willBeParserExecuted()) { 900 m_pendingScript = scriptElement->cachedScript(); 901 m_scriptElement = element; 902 m_pendingScript->addClient(this); 903 904 // m_pendingScript will be 0 if script was already loaded and addClient() executed it. 905 if (m_pendingScript) 906 pauseParsing(); 910 907 } else 911 scriptElement->executeScript(ScriptSourceCode(scriptElement->scriptContent(), document()->url(), m_scriptStartPosition));908 m_scriptElement = 0; 912 909 913 910 // JavaScript may have detached the parser -
trunk/Source/WebCore/dom/XMLDocumentParserQt.cpp
r75188 r79114 589 589 m_requestingScript = true; 590 590 591 #if ENABLE(XHTMLMP) 592 if (!scriptElement->shouldExecuteAsJavaScript()) 593 document()->setShouldProcessNoscriptElement(true); 594 else 595 #endif 596 { 597 String scriptHref = scriptElement->sourceAttributeValue(); 598 if (!scriptHref.isEmpty()) { 599 // we have a src attribute 600 String scriptCharset = scriptElement->scriptCharset(); 601 if (element->dispatchBeforeLoadEvent(scriptHref) && 602 (m_pendingScript = document()->cachedResourceLoader()->requestScript(scriptHref, scriptCharset))) { 603 m_scriptElement = element; 604 m_pendingScript->addClient(this); 605 606 // m_pendingScript will be 0 if script was already loaded and ref() executed it 607 if (m_pendingScript) 608 pauseParsing(); 609 } else 610 m_scriptElement = 0; 591 bool successfullyPrepared = scriptElement->prepareScript(m_scriptStartPosition, ScriptElement::AllowLegacyTypeInTypeAttribute); 592 if (!successfullyPrepared) { 593 #if ENABLE(XHTMLMP) 594 if (!scriptElement->isScriptTypeSupported(ScriptElement::AllowLegacyTypeInTypeAttribute)) 595 document()->setShouldProcessNoscriptElement(true); 596 #endif 597 } else { 598 if (scriptElement->readyToBeParserExecuted()) 599 scriptElement->executeScript(ScriptSourceCode(scriptElement->scriptContent(), document()->url(), m_scriptStartPosition)); 600 else if (scriptElement->willBeParserExecuted()) { 601 m_pendingScript = scriptElement->cachedScript(); 602 m_scriptElement = element; 603 m_pendingScript->addClient(this); 604 605 // m_pendingScript will be 0 if script was already loaded and addClient() executed it. 606 if (m_pendingScript) 607 pauseParsing(); 611 608 } else 612 scriptElement->executeScript(ScriptSourceCode(scriptElement->scriptContent(), document()->url(), m_scriptStartPosition));609 m_scriptElement = 0; 613 610 } 614 611 m_requestingScript = false; -
trunk/Source/WebCore/html/HTMLScriptElement.cpp
r73589 r79114 36 36 using namespace HTMLNames; 37 37 38 inline HTMLScriptElement::HTMLScriptElement(const QualifiedName& tagName, Document* document, bool wasInsertedByParser, bool wasAlreadyStarted)38 inline HTMLScriptElement::HTMLScriptElement(const QualifiedName& tagName, Document* document, bool wasInsertedByParser, bool alreadyStarted) 39 39 : HTMLElement(tagName, document) 40 , ScriptElement(this, wasInsertedByParser, wasAlreadyStarted)40 , ScriptElement(this, wasInsertedByParser, alreadyStarted) 41 41 { 42 42 ASSERT(hasTagName(scriptTag)); … … 75 75 } 76 76 77 void HTMLScriptElement::finishParsingChildren()78 {79 ScriptElement::finishParsingChildren(sourceAttributeValue());80 HTMLElement::finishParsingChildren();81 }82 83 77 void HTMLScriptElement::insertedIntoDocument() 84 78 { 85 79 HTMLElement::insertedIntoDocument(); 86 ScriptElement::insertedIntoDocument( sourceAttributeValue());80 ScriptElement::insertedIntoDocument(); 87 81 } 88 82 … … 161 155 } 162 156 157 bool HTMLScriptElement::hasSourceAttribute() const 158 { 159 return fastHasAttribute(srcAttr); 160 } 161 163 162 void HTMLScriptElement::dispatchLoadEvent() 164 163 { … … 176 175 PassRefPtr<Element> HTMLScriptElement::cloneElementWithoutAttributesAndChildren() const 177 176 { 178 return adoptRef(new HTMLScriptElement(tagQName(), document(), false, wasAlreadyStarted()));177 return adoptRef(new HTMLScriptElement(tagQName(), document(), false, alreadyStarted())); 179 178 } 180 179 -
trunk/Source/WebCore/html/HTMLScriptElement.h
r72995 r79114 40 40 41 41 private: 42 HTMLScriptElement(const QualifiedName&, Document*, bool wasInsertedByParser, bool wasAlreadyStarted);42 HTMLScriptElement(const QualifiedName&, Document*, bool wasInsertedByParser, bool alreadyStarted); 43 43 44 44 virtual void parseMappedAttribute(Attribute*); … … 48 48 49 49 virtual bool isURLAttribute(Attribute*) const; 50 virtual void finishParsingChildren();51 50 52 51 virtual void addSubresourceAttributeURLs(ListHashSet<KURL>&) const; … … 60 59 virtual bool asyncAttributeValue() const; 61 60 virtual bool deferAttributeValue() const; 61 virtual bool hasSourceAttribute() const; 62 62 63 63 virtual void dispatchLoadEvent(); -
trunk/Source/WebCore/html/parser/HTMLScriptRunner.cpp
r78058 r79114 263 263 { 264 264 ASSERT(!pendingScript.element()); 265 const AtomicString& srcValue = script->getAttribute(srcAttr);266 // Allow the host to disllow script loads (using the XSSAuditor, etc.)267 // FIXME: this check should be performed on the final URL in a redirect chain.268 if (!m_host->shouldLoadExternalScriptFromSrc(srcValue))269 return false;270 // FIXME: We need to resolve the url relative to the element.271 if (!script->dispatchBeforeLoadEvent(srcValue))272 return false;273 265 pendingScript.setElement(script); 274 266 // This should correctly return 0 for empty or invalid srcValues. 275 CachedScript* cachedScript = m_document->cachedResourceLoader()->requestScript(srcValue, toScriptElement(script)->scriptCharset());267 CachedScript* cachedScript = toScriptElement(script)->cachedScript().get(); 276 268 if (!cachedScript) { 277 269 notImplemented(); // Dispatch error event. … … 294 286 ScriptElement* scriptElement = toScriptElement(script); 295 287 ASSERT(scriptElement); 296 if (!scriptElement->shouldExecuteAsJavaScript()) 288 289 scriptElement->prepareScript(scriptStartPosition); 290 291 if (!scriptElement->willBeParserExecuted()) 297 292 return; 298 299 if (script->hasAttribute(srcAttr)) { 300 if (script->hasAttribute(asyncAttr)) // Async takes precendence over defer. 301 return; // Asynchronous scripts handle themselves. 302 303 if (script->hasAttribute(deferAttr)) 304 requestDeferredScript(script); 305 else 306 requestParsingBlockingScript(script); 307 } else if (!m_document->haveStylesheetsLoaded() && m_scriptNestingLevel == 1) { 308 // Block inline script execution on stylesheet load, unless we are in document.write(). 309 // The latter case can only happen if a script both triggers a stylesheet load 310 // and writes an inline script. Since write is blocking we have to execute the 311 // written script immediately, ignoring the pending sheets. 312 m_parsingBlockingScript.setElement(script); 313 m_parsingBlockingScript.setStartingPosition(scriptStartPosition); 314 } else { 315 ASSERT(isExecutingScript()); 316 ScriptSourceCode sourceCode(script->textContent(), documentURLForScriptExecution(m_document), scriptStartPosition); 317 scriptElement->executeScript(sourceCode); 318 } 319 } 320 } 321 322 } 293 294 if (scriptElement->willExecuteWhenDocumentFinishedParsing()) 295 requestDeferredScript(script); 296 else if (scriptElement->readyToBeParserExecuted()) { 297 if (m_scriptNestingLevel == 1) { 298 m_parsingBlockingScript.setElement(script); 299 m_parsingBlockingScript.setStartingPosition(scriptStartPosition); 300 } else { 301 ScriptSourceCode sourceCode(script->textContent(), documentURLForScriptExecution(m_document), scriptStartPosition); 302 scriptElement->executeScript(sourceCode); 303 } 304 } else 305 requestParsingBlockingScript(script); 306 } 307 } 308 309 } -
trunk/Source/WebCore/svg/SVGScriptElement.cpp
r78249 r79114 36 36 DEFINE_ANIMATED_BOOLEAN(SVGScriptElement, SVGNames::externalResourcesRequiredAttr, ExternalResourcesRequired, externalResourcesRequired) 37 37 38 inline SVGScriptElement::SVGScriptElement(const QualifiedName& tagName, Document* document, bool wasInsertedByParser, bool wasAlreadyStarted)38 inline SVGScriptElement::SVGScriptElement(const QualifiedName& tagName, Document* document, bool wasInsertedByParser, bool alreadyStarted) 39 39 : SVGElement(tagName, document) 40 , ScriptElement(this, wasInsertedByParser, wasAlreadyStarted)40 , ScriptElement(this, wasInsertedByParser, alreadyStarted) 41 41 { 42 42 } … … 73 73 // causes an immediate dispatch of the SVGLoad event. If the attribute value was 'false' before inserting the script element 74 74 // in the document, the SVGLoad event has already been dispatched. 75 if (!externalResourcesRequiredBaseValue() && !haveFiredLoadEvent() && ! wasInsertedByParser()) {75 if (!externalResourcesRequiredBaseValue() && !haveFiredLoadEvent() && !isParserInserted()) { 76 76 setHaveFiredLoadEvent(true); 77 77 ASSERT(haveLoadedRequiredResources()); … … 112 112 { 113 113 SVGElement::insertedIntoDocument(); 114 ScriptElement::insertedIntoDocument( sourceAttributeValue());115 116 if ( wasInsertedByParser())114 ScriptElement::insertedIntoDocument(); 115 116 if (isParserInserted()) 117 117 return; 118 118 … … 143 143 void SVGScriptElement::finishParsingChildren() 144 144 { 145 ScriptElement::finishParsingChildren(sourceAttributeValue());146 145 SVGElement::finishParsingChildren(); 147 146 … … 213 212 } 214 213 214 bool SVGScriptElement::hasSourceAttribute() const 215 { 216 return hasAttribute(XLinkNames::hrefAttr); 217 } 218 215 219 void SVGScriptElement::dispatchLoadEvent() 216 220 { 217 221 bool externalResourcesRequired = externalResourcesRequiredBaseValue(); 218 222 219 if ( wasInsertedByParser())223 if (isParserInserted()) 220 224 ASSERT(externalResourcesRequired != haveFiredLoadEvent()); 221 225 else if (haveFiredLoadEvent()) { … … 248 252 PassRefPtr<Element> SVGScriptElement::cloneElementWithoutAttributesAndChildren() const 249 253 { 250 return adoptRef(new SVGScriptElement(tagQName(), document(), false, wasAlreadyStarted()));254 return adoptRef(new SVGScriptElement(tagQName(), document(), false, alreadyStarted())); 251 255 } 252 256 -
trunk/Source/WebCore/svg/SVGScriptElement.h
r78249 r79114 43 43 44 44 private: 45 SVGScriptElement(const QualifiedName&, Document*, bool wasInsertedByParser, bool wasAlreadyStarted);45 SVGScriptElement(const QualifiedName&, Document*, bool wasInsertedByParser, bool alreadyStarted); 46 46 47 47 virtual void parseMappedAttribute(Attribute*); … … 69 69 virtual bool asyncAttributeValue() const; 70 70 virtual bool deferAttributeValue() const; 71 virtual bool hasSourceAttribute() const; 71 72 72 73 virtual void dispatchLoadEvent();
Note: See TracChangeset
for help on using the changeset viewer.