Browse Source

LibHTML: Add ResourceLoader to support protocol-agnostic URL loading

We now support loading both file:// and http:// URLs. Feel free to
visit http://www.serenityos.org/ and enjoy the fancy good times. :^)
Andreas Kling 5 years ago
parent
commit
3be6d1aff0

+ 1 - 0
Base/home/anon/www/welcome.html

@@ -23,6 +23,7 @@ h1 {
         <li><a href="images.html">images</a></li>
         <li><a href="images.html">images</a></li>
         <li><a href="selectors.html">selectors</a></li>
         <li><a href="selectors.html">selectors</a></li>
         <li><a href="link.html">link element</a></li>
         <li><a href="link.html">link element</a></li>
+        <li><a href="http://www.serenityos.org/">www.serenityos.org</a></li>
     </ul>
     </ul>
 </body>
 </body>
 </html>
 </html>

+ 11 - 6
Libraries/LibHTML/DOM/HTMLImageElement.cpp

@@ -1,7 +1,9 @@
+#include <LibDraw/PNGLoader.h>
 #include <LibHTML/CSS/StyleResolver.h>
 #include <LibHTML/CSS/StyleResolver.h>
 #include <LibHTML/DOM/Document.h>
 #include <LibHTML/DOM/Document.h>
 #include <LibHTML/DOM/HTMLImageElement.h>
 #include <LibHTML/DOM/HTMLImageElement.h>
 #include <LibHTML/Layout/LayoutImage.h>
 #include <LibHTML/Layout/LayoutImage.h>
+#include <LibHTML/ResourceLoader.h>
 
 
 HTMLImageElement::HTMLImageElement(Document& document, const String& tag_name)
 HTMLImageElement::HTMLImageElement(Document& document, const String& tag_name)
     : HTMLElement(document, tag_name)
     : HTMLElement(document, tag_name)
@@ -21,12 +23,15 @@ void HTMLImageElement::parse_attribute(const String& name, const String& value)
 void HTMLImageElement::load_image(const String& src)
 void HTMLImageElement::load_image(const String& src)
 {
 {
     URL src_url = document().complete_url(src);
     URL src_url = document().complete_url(src);
-    if (src_url.protocol() == "file") {
-        m_bitmap = GraphicsBitmap::load_from_file(src_url.path());
-    } else {
-        // FIXME: Implement! This whole thing should be at a different layer though..
-        ASSERT_NOT_REACHED();
-    }
+    ResourceLoader::the().load(src_url, [this](auto data) {
+        if (data.is_null()) {
+            dbg() << "HTMLImageElement: Failed to load " << this->src();
+            return;
+        }
+
+        m_bitmap = load_png_from_memory(data.data(), data.size());
+        document().invalidate_layout();
+    });
 }
 }
 
 
 int HTMLImageElement::preferred_width() const
 int HTMLImageElement::preferred_width() const

+ 12 - 12
Libraries/LibHTML/HtmlView.cpp

@@ -10,6 +10,7 @@
 #include <LibHTML/Layout/LayoutNode.h>
 #include <LibHTML/Layout/LayoutNode.h>
 #include <LibHTML/Parser/HTMLParser.h>
 #include <LibHTML/Parser/HTMLParser.h>
 #include <LibHTML/RenderingContext.h>
 #include <LibHTML/RenderingContext.h>
+#include <LibHTML/ResourceLoader.h>
 #include <stdio.h>
 #include <stdio.h>
 
 
 HtmlView::HtmlView(GWidget* parent)
 HtmlView::HtmlView(GWidget* parent)
@@ -174,19 +175,18 @@ void HtmlView::load(const URL& url)
     if (on_load_start)
     if (on_load_start)
         on_load_start(url);
         on_load_start(url);
 
 
-    auto f = CFile::construct();
-    f->set_filename(url.path());
-    if (!f->open(CIODevice::OpenMode::ReadOnly)) {
-        dbg() << "HtmlView::load: Error: " << f->error_string();
-        return;
-    }
+    ResourceLoader::the().load(url, [=](auto data) {
+        if (data.is_null()) {
+            dbg() << "Load failed!";
+            ASSERT_NOT_REACHED();
+        }
 
 
-    auto html = f->read_all();
-    auto document = parse_html(html, url);
-    document->normalize();
+        auto document = parse_html(data, url);
+        document->normalize();
 
 
-    set_document(document);
+        set_document(document);
 
 
-    if (on_title_change)
-        on_title_change(document->title());
+        if (on_title_change)
+            on_title_change(document->title());
+    });
 }
 }

+ 1 - 0
Libraries/LibHTML/Makefile.shared

@@ -37,6 +37,7 @@ LIBHTML_OBJS = \
     Layout/BoxModelMetrics.o \
     Layout/BoxModelMetrics.o \
     Layout/LineBox.o \
     Layout/LineBox.o \
     Layout/LineBoxFragment.o \
     Layout/LineBoxFragment.o \
+    ResourceLoader.o \
     HtmlView.o \
     HtmlView.o \
     Frame.o \
     Frame.o \
     Dump.o
     Dump.o

+ 50 - 0
Libraries/LibHTML/ResourceLoader.cpp

@@ -0,0 +1,50 @@
+#include <LibCore/CFile.h>
+#include <LibCore/CHttpJob.h>
+#include <LibCore/CHttpRequest.h>
+#include <LibCore/CNetworkResponse.h>
+#include <LibHTML/ResourceLoader.h>
+
+ResourceLoader& ResourceLoader::the()
+{
+    static ResourceLoader* s_the;
+    if (!s_the)
+        s_the = new ResourceLoader;
+    return *s_the;
+}
+
+void ResourceLoader::load(const URL& url, Function<void(const ByteBuffer&)> callback)
+{
+    if (url.protocol() == "file") {
+        auto f = CFile::construct();
+        f->set_filename(url.path());
+        if (!f->open(CIODevice::OpenMode::ReadOnly)) {
+            dbg() << "HtmlView::load: Error: " << f->error_string();
+            callback({});
+            return;
+        }
+
+        auto data = f->read_all();
+        callback(data);
+        return;
+    }
+
+    if (url.protocol() == "http") {
+        CHttpRequest request;
+        request.set_url(url);
+        request.set_method(CHttpRequest::Method::GET);
+        auto job = request.schedule();
+        job->on_finish = [job, callback = move(callback)](bool success) {
+            if (!success) {
+                dbg() << "HTTP job failed!";
+                ASSERT_NOT_REACHED();
+            }
+            auto* response = job->response();
+            ASSERT(response);
+            callback(response->payload());
+        };
+        return;
+    }
+
+    dbg() << "Unimplemented protocol: " << url.protocol();
+    ASSERT_NOT_REACHED();
+}

+ 14 - 0
Libraries/LibHTML/ResourceLoader.h

@@ -0,0 +1,14 @@
+#pragma once
+
+#include <AK/Function.h>
+#include <AK/URL.h>
+
+class ResourceLoader {
+public:
+    static ResourceLoader& the();
+
+    void load(const URL&, Function<void(const ByteBuffer&)>);
+
+private:
+    ResourceLoader() {}
+};