Browse Source

LibWeb: Bring up basic external script execution in the new parser

This only works in some narrow cases, but should be enough for our own
welcome.html at least. :^)
Andreas Kling 5 years ago
parent
commit
4c9c6b3a7b

+ 5 - 0
Libraries/LibWeb/DOM/Document.cpp

@@ -424,4 +424,9 @@ void Document::set_pending_parsing_blocking_script(Badge<HTMLScriptElement>, HTM
     m_pending_parsing_blocking_script = script;
     m_pending_parsing_blocking_script = script;
 }
 }
 
 
+NonnullRefPtr<HTMLScriptElement> Document::take_pending_parsing_blocking_script(Badge<HTMLDocumentParser>)
+{
+    return m_pending_parsing_blocking_script.release_nonnull();
+}
+
 }
 }

+ 2 - 0
Libraries/LibWeb/DOM/Document.h

@@ -130,6 +130,8 @@ public:
     NonnullRefPtr<Text> create_text_node(const String& data);
     NonnullRefPtr<Text> create_text_node(const String& data);
 
 
     void set_pending_parsing_blocking_script(Badge<HTMLScriptElement>, HTMLScriptElement*);
     void set_pending_parsing_blocking_script(Badge<HTMLScriptElement>, HTMLScriptElement*);
+    HTMLScriptElement* pending_parsing_blocking_script() { return m_pending_parsing_blocking_script; }
+    NonnullRefPtr<HTMLScriptElement> take_pending_parsing_blocking_script(Badge<HTMLDocumentParser>);
 
 
 private:
 private:
     virtual RefPtr<LayoutNode> create_layout_node(const StyleProperties* parent_style) const override;
     virtual RefPtr<LayoutNode> create_layout_node(const StyleProperties* parent_style) const override;

+ 4 - 1
Libraries/LibWeb/DOM/HTMLScriptElement.cpp

@@ -189,7 +189,8 @@ void HTMLScriptElement::prepare_script(Badge<HTMLDocumentParser>)
 
 
         // FIXME: Check classic vs. module script type
         // FIXME: Check classic vs. module script type
 
 
-        ResourceLoader::the().load(url, [this, url](auto& data, auto&) {
+        // FIXME: This load should be made asynchronous and the parser should spin an event loop etc.
+        ResourceLoader::the().load_sync(url, [this, url](auto& data, auto&) {
             if (data.is_null()) {
             if (data.is_null()) {
                 dbg() << "HTMLScriptElement: Failed to load " << url;
                 dbg() << "HTMLScriptElement: Failed to load " << url;
                 return;
                 return;
@@ -212,6 +213,7 @@ void HTMLScriptElement::prepare_script(Badge<HTMLDocumentParser>)
     }
     }
 
 
     else if (has_attribute("src") && m_parser_inserted && !has_attribute("async")) {
     else if (has_attribute("src") && m_parser_inserted && !has_attribute("async")) {
+
         document().set_pending_parsing_blocking_script({}, this);
         document().set_pending_parsing_blocking_script({}, this);
         when_the_script_is_ready([this] {
         when_the_script_is_ready([this] {
             m_ready_to_be_parser_executed = true;
             m_ready_to_be_parser_executed = true;
@@ -234,6 +236,7 @@ void HTMLScriptElement::prepare_script(Badge<HTMLDocumentParser>)
 
 
 void HTMLScriptElement::script_became_ready()
 void HTMLScriptElement::script_became_ready()
 {
 {
+    m_script_ready = true;
     if (!m_script_ready_callback)
     if (!m_script_ready_callback)
         return;
         return;
     m_script_ready_callback();
     m_script_ready_callback();

+ 2 - 1
Libraries/LibWeb/DOM/HTMLScriptElement.h

@@ -40,15 +40,16 @@ public:
     virtual void children_changed() override;
     virtual void children_changed() override;
 
 
     bool is_non_blocking() const { return m_non_blocking; }
     bool is_non_blocking() const { return m_non_blocking; }
+    bool is_ready_to_be_parser_executed() const { return m_ready_to_be_parser_executed; }
 
 
     void set_parser_document(Badge<HTMLDocumentParser>, Document&);
     void set_parser_document(Badge<HTMLDocumentParser>, Document&);
     void set_non_blocking(Badge<HTMLDocumentParser>, bool);
     void set_non_blocking(Badge<HTMLDocumentParser>, bool);
     void prepare_script(Badge<HTMLDocumentParser>);
     void prepare_script(Badge<HTMLDocumentParser>);
+    void execute_script();
 
 
 private:
 private:
     void script_became_ready();
     void script_became_ready();
     void when_the_script_is_ready(Function<void()>);
     void when_the_script_is_ready(Function<void()>);
-    void execute_script();
 
 
     WeakPtr<Document> m_parser_document;
     WeakPtr<Document> m_parser_document;
     WeakPtr<Document> m_preparation_time_document;
     WeakPtr<Document> m_preparation_time_document;

+ 40 - 0
Libraries/LibWeb/Parser/HTMLDocumentParser.cpp

@@ -704,8 +704,48 @@ void HTMLDocumentParser::handle_text(HTMLToken& token)
         if (script_nesting_level() == 0)
         if (script_nesting_level() == 0)
             m_parser_pause_flag = false;
             m_parser_pause_flag = false;
         // FIXME: Handle tokenizer insertion point stuff here too.
         // FIXME: Handle tokenizer insertion point stuff here too.
+
+        while (document().pending_parsing_blocking_script()) {
+            if (script_nesting_level() != 0) {
+                m_parser_pause_flag = true;
+                // FIXME: Abort the processing of any nested invocations of the tokenizer,
+                //        yielding control back to the caller. (Tokenization will resume when
+                //        the caller returns to the "outer" tree construction stage.)
+                TODO();
+            } else {
+                auto the_script = document().take_pending_parsing_blocking_script({});
+                m_tokenizer.set_blocked(true);
+
+                // FIXME: If the parser's Document has a style sheet that is blocking scripts
+                //        or the script's "ready to be parser-executed" flag is not set:
+                //        spin the event loop until the parser's Document has no style sheet
+                //        that is blocking scripts and the script's "ready to be parser-executed"
+                //        flag is set.
+
+                ASSERT(the_script->is_ready_to_be_parser_executed());
+
+                if (m_aborted)
+                    return;
+
+                m_tokenizer.set_blocked(false);
+
+                // FIXME: Handle tokenizer insertion point stuff here too.
+
+                ASSERT(script_nesting_level() == 0);
+                increment_script_nesting_level();
+
+                the_script->execute_script();
+
+                decrement_script_nesting_level();
+                ASSERT(script_nesting_level() == 0);
+                m_parser_pause_flag = false;
+
+                // FIXME: Handle tokenizer insertion point stuff here too.
+            }
+        }
         return;
         return;
     }
     }
+
     if (token.is_end_tag()) {
     if (token.is_end_tag()) {
         m_stack_of_open_elements.pop();
         m_stack_of_open_elements.pop();
         m_insertion_mode = m_original_insertion_mode;
         m_insertion_mode = m_original_insertion_mode;

+ 1 - 1
Libraries/LibWeb/Parser/HTMLDocumentParser.h

@@ -121,7 +121,7 @@ private:
     bool m_parsing_fragment { false };
     bool m_parsing_fragment { false };
     bool m_scripting_enabled { true };
     bool m_scripting_enabled { true };
     bool m_invoked_via_document_write { false };
     bool m_invoked_via_document_write { false };
-
+    bool m_aborted { false };
     bool m_parser_pause_flag { false };
     bool m_parser_pause_flag { false };
     size_t m_script_nesting_level { 0 };
     size_t m_script_nesting_level { 0 };
 
 

+ 6 - 0
Libraries/LibWeb/Parser/HTMLTokenizer.h

@@ -130,6 +130,9 @@ public:
 
 
     void switch_to(Badge<HTMLDocumentParser>, State new_state);
     void switch_to(Badge<HTMLDocumentParser>, State new_state);
 
 
+    void set_blocked(bool b) { m_blocked = b; }
+    bool is_blocked() const { return m_blocked; }
+
 private:
 private:
     Optional<u32> next_codepoint();
     Optional<u32> next_codepoint();
     Optional<u32> peek_codepoint(size_t offset) const;
     Optional<u32> peek_codepoint(size_t offset) const;
@@ -172,5 +175,8 @@ private:
     Queue<HTMLToken> m_queued_tokens;
     Queue<HTMLToken> m_queued_tokens;
 
 
     u32 m_character_reference_code { 0 };
     u32 m_character_reference_code { 0 };
+
+    bool m_blocked { false };
 };
 };
+
 }
 }