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. :^)
This commit is contained in:
Andreas Kling 2019-10-08 19:37:15 +02:00
parent 3fdc595e0c
commit 3be6d1aff0
6 changed files with 89 additions and 18 deletions

View file

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

View file

@ -1,7 +1,9 @@
#include <LibDraw/PNGLoader.h>
#include <LibHTML/CSS/StyleResolver.h>
#include <LibHTML/DOM/Document.h>
#include <LibHTML/DOM/HTMLImageElement.h>
#include <LibHTML/Layout/LayoutImage.h>
#include <LibHTML/ResourceLoader.h>
HTMLImageElement::HTMLImageElement(Document& document, const String& 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)
{
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

View file

@ -10,6 +10,7 @@
#include <LibHTML/Layout/LayoutNode.h>
#include <LibHTML/Parser/HTMLParser.h>
#include <LibHTML/RenderingContext.h>
#include <LibHTML/ResourceLoader.h>
#include <stdio.h>
HtmlView::HtmlView(GWidget* parent)
@ -174,19 +175,18 @@ void HtmlView::load(const URL& url)
if (on_load_start)
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());
});
}

View file

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

View file

@ -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();
}

View file

@ -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() {}
};