diff --git a/Libraries/LibWeb/DOM/HTMLImageElement.cpp b/Libraries/LibWeb/DOM/HTMLImageElement.cpp
index c0d9b250ee..3efea5977e 100644
--- a/Libraries/LibWeb/DOM/HTMLImageElement.cpp
+++ b/Libraries/LibWeb/DOM/HTMLImageElement.cpp
@@ -54,8 +54,9 @@ void HTMLImageElement::parse_attribute(const FlyString& name, const String& valu
void HTMLImageElement::load_image(const String& src)
{
- URL src_url = document().complete_url(src);
- auto resource = ResourceLoader::the().load_resource(src_url);
+ LoadRequest request;
+ request.set_url(document().complete_url(src));
+ auto resource = ResourceLoader::the().load_resource(request);
set_resource(resource);
}
diff --git a/Libraries/LibWeb/Forward.h b/Libraries/LibWeb/Forward.h
index 2b81759bbb..ac10ad7245 100644
--- a/Libraries/LibWeb/Forward.h
+++ b/Libraries/LibWeb/Forward.h
@@ -48,6 +48,7 @@ class PageView;
class ImageData;
class LayoutDocument;
class LayoutNode;
+class LoadRequest;
class MouseEvent;
class Node;
class Origin;
diff --git a/Libraries/LibWeb/Loader/LoadRequest.h b/Libraries/LibWeb/Loader/LoadRequest.h
new file mode 100644
index 0000000000..03652601ce
--- /dev/null
+++ b/Libraries/LibWeb/Loader/LoadRequest.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2020, Andreas Kling
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include
+#include
+
+namespace Web {
+
+class LoadRequest {
+public:
+ LoadRequest()
+ {
+ }
+
+ bool is_valid() const { return m_url.is_valid(); }
+
+ const URL& url() const { return m_url; }
+ void set_url(const URL& url) { m_url = url; }
+
+ unsigned hash() const { return m_url.to_string().hash(); }
+
+ bool operator==(const LoadRequest& other) const
+ {
+ return m_url == other.m_url;
+ }
+
+private:
+ URL m_url;
+};
+
+}
+
+namespace AK {
+
+template<>
+struct Traits : public GenericTraits {
+ static unsigned hash(const Web::LoadRequest& request) { return request.hash(); }
+};
+
+}
diff --git a/Libraries/LibWeb/Loader/Resource.cpp b/Libraries/LibWeb/Loader/Resource.cpp
index 17e6a3c38d..e261220b82 100644
--- a/Libraries/LibWeb/Loader/Resource.cpp
+++ b/Libraries/LibWeb/Loader/Resource.cpp
@@ -29,13 +29,13 @@
namespace Web {
-NonnullRefPtr Resource::create(Badge, const URL& url)
+NonnullRefPtr Resource::create(Badge, const LoadRequest& request)
{
- return adopt(*new Resource(url));
+ return adopt(*new Resource(request));
}
-Resource::Resource(const URL& url)
- : m_url(url)
+Resource::Resource(const LoadRequest& request)
+ : m_request(request)
{
}
diff --git a/Libraries/LibWeb/Loader/Resource.h b/Libraries/LibWeb/Loader/Resource.h
index 80a55da64a..9af4ecb406 100644
--- a/Libraries/LibWeb/Loader/Resource.h
+++ b/Libraries/LibWeb/Loader/Resource.h
@@ -33,6 +33,7 @@
#include
#include
#include
+#include
namespace Web {
@@ -43,7 +44,7 @@ class Resource : public RefCounted {
AK_MAKE_NONMOVABLE(Resource);
public:
- static NonnullRefPtr create(Badge, const URL&);
+ static NonnullRefPtr create(Badge, const LoadRequest&);
~Resource();
bool is_loaded() const { return m_loaded; }
@@ -53,7 +54,7 @@ public:
bool has_encoded_data() const { return !m_encoded_data.is_null(); }
- const URL& url() const { return m_url; }
+ const URL& url() const { return m_request.url(); }
const ByteBuffer& encoded_data() const { return m_encoded_data; }
void register_client(Badge, ResourceClient&);
@@ -75,9 +76,9 @@ public:
void did_fail(Badge, const String& error);
private:
- explicit Resource(const URL&);
+ explicit Resource(const LoadRequest&);
- URL m_url;
+ LoadRequest m_request;
ByteBuffer m_encoded_data;
bool m_loaded { false };
bool m_failed { false };
diff --git a/Libraries/LibWeb/Loader/ResourceLoader.cpp b/Libraries/LibWeb/Loader/ResourceLoader.cpp
index 2d39dcf67f..4a5591fbc6 100644
--- a/Libraries/LibWeb/Loader/ResourceLoader.cpp
+++ b/Libraries/LibWeb/Loader/ResourceLoader.cpp
@@ -31,6 +31,7 @@
#include
#include
#include
+#include
#include
#include
@@ -69,15 +70,25 @@ void ResourceLoader::load_sync(const URL& url, Function ResourceLoader::load_resource(const URL& url)
+static HashMap> s_resource_cache;
+
+RefPtr ResourceLoader::load_resource(const LoadRequest& request)
{
- if (!url.is_valid())
+ if (!request.is_valid())
return nullptr;
- auto resource = Resource::create({}, url);
+ auto it = s_resource_cache.find(request);
+ if (it != s_resource_cache.end()) {
+ dbg() << "Reusing cached resource for: " << request.url();
+ return it->value;
+ }
+
+ auto resource = Resource::create({}, request);
+
+ s_resource_cache.set(request, resource);
load(
- url,
+ request.url(),
[=](auto& data, auto& headers) {
const_cast(*resource).did_load({}, data, headers);
},
diff --git a/Libraries/LibWeb/Loader/ResourceLoader.h b/Libraries/LibWeb/Loader/ResourceLoader.h
index d9a696a774..34968790c3 100644
--- a/Libraries/LibWeb/Loader/ResourceLoader.h
+++ b/Libraries/LibWeb/Loader/ResourceLoader.h
@@ -42,7 +42,7 @@ class ResourceLoader : public Core::Object {
public:
static ResourceLoader& the();
- RefPtr load_resource(const URL&);
+ RefPtr load_resource(const LoadRequest&);
void load(const URL&, Function& response_headers)> success_callback, Function error_callback = nullptr);
void load_sync(const URL&, Function& response_headers)> success_callback, Function error_callback = nullptr);