From 3cc0c477db072cb5a30d53fc0df1f7ff63a3fe2a Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Sat, 13 Jun 2020 22:24:49 +0200 Subject: [PATCH] LibWeb: Add basic element support This patch implements a simple element with fallback content. If the URL from the data attribute fails to load (including 404), we render the DOM tree inside the as fallback content. This works by generating a different layout tree for the depending on the state and success of the data load. Since we cannot currently do incremental layout tree updates, we have to force a complete layout tree rebuild when the resource load finishes/fails. --- Libraries/LibWeb/CMakeLists.txt | 2 + Libraries/LibWeb/DOM/Element.h | 3 +- Libraries/LibWeb/DOM/ElementFactory.cpp | 3 + Libraries/LibWeb/DOM/HTMLObjectElement.cpp | 78 ++++++++++++++++++++++ Libraries/LibWeb/DOM/HTMLObjectElement.h | 61 +++++++++++++++++ 5 files changed, 146 insertions(+), 1 deletion(-) create mode 100644 Libraries/LibWeb/DOM/HTMLObjectElement.cpp create mode 100644 Libraries/LibWeb/DOM/HTMLObjectElement.h diff --git a/Libraries/LibWeb/CMakeLists.txt b/Libraries/LibWeb/CMakeLists.txt index 71ebc082d6..138f737767 100644 --- a/Libraries/LibWeb/CMakeLists.txt +++ b/Libraries/LibWeb/CMakeLists.txt @@ -52,6 +52,7 @@ set(SOURCES DOM/HTMLIFrameElement.cpp DOM/HTMLImageElement.cpp DOM/HTMLInputElement.cpp + DOM/HTMLObjectElement.cpp DOM/HTMLLinkElement.cpp DOM/HTMLScriptElement.cpp DOM/HTMLStyleElement.cpp @@ -95,6 +96,7 @@ set(SOURCES Layout/LineBoxFragment.cpp LayoutTreeModel.cpp Loader/FrameLoader.cpp + Loader/ImageLoader.cpp Loader/ImageResource.cpp Loader/Resource.cpp Loader/ResourceLoader.cpp diff --git a/Libraries/LibWeb/DOM/Element.h b/Libraries/LibWeb/DOM/Element.h index cca9f83c6a..be1f22fbb9 100644 --- a/Libraries/LibWeb/DOM/Element.h +++ b/Libraries/LibWeb/DOM/Element.h @@ -79,9 +79,10 @@ public: String inner_html() const; void set_inner_html(StringView); -private: +protected: RefPtr create_layout_node(const StyleProperties* parent_style) const override; +private: Attribute* find_attribute(const FlyString& name); const Attribute* find_attribute(const FlyString& name) const; diff --git a/Libraries/LibWeb/DOM/ElementFactory.cpp b/Libraries/LibWeb/DOM/ElementFactory.cpp index c8ba8bdb60..213a228d2c 100644 --- a/Libraries/LibWeb/DOM/ElementFactory.cpp +++ b/Libraries/LibWeb/DOM/ElementFactory.cpp @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -94,6 +95,8 @@ NonnullRefPtr create_element(Document& document, const FlyString& tag_n return adopt(*new HTMLScriptElement(document, lowercase_tag_name)); if (lowercase_tag_name == HTML::TagNames::canvas) return adopt(*new HTMLCanvasElement(document, lowercase_tag_name)); + if (lowercase_tag_name == HTML::TagNames::object) + return adopt(*new HTMLObjectElement(document, lowercase_tag_name)); return adopt(*new Element(document, lowercase_tag_name)); } diff --git a/Libraries/LibWeb/DOM/HTMLObjectElement.cpp b/Libraries/LibWeb/DOM/HTMLObjectElement.cpp new file mode 100644 index 0000000000..f76177bb16 --- /dev/null +++ b/Libraries/LibWeb/DOM/HTMLObjectElement.cpp @@ -0,0 +1,78 @@ +/* + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Web { + +HTMLObjectElement::HTMLObjectElement(Document& document, const FlyString& tag_name) + : HTMLElement(document, tag_name) +{ + m_image_loader.on_load = [this] { + m_should_show_fallback_content = false; + this->document().force_layout(); + }; + + m_image_loader.on_fail = [this] { + m_should_show_fallback_content = true; + this->document().force_layout(); + }; +} + +HTMLObjectElement::~HTMLObjectElement() +{ +} + +void HTMLObjectElement::parse_attribute(const FlyString& name, const String& value) +{ + HTMLElement::parse_attribute(name, value); + + if (name == HTML::AttributeNames::data) + m_image_loader.load(document().complete_url(value)); +} + +RefPtr HTMLObjectElement::create_layout_node(const StyleProperties* parent_style) const +{ + if (m_should_show_fallback_content) + return HTMLElement::create_layout_node(parent_style); + + auto style = document().style_resolver().resolve_style(*this, parent_style); + auto display = style->string_or_fallback(CSS::PropertyID::Display, "inline"); + if (display == "none") + return nullptr; + if (m_image_loader.image_decoder()) + return adopt(*new LayoutImage(*this, move(style), m_image_loader)); + return nullptr; +} + +} diff --git a/Libraries/LibWeb/DOM/HTMLObjectElement.h b/Libraries/LibWeb/DOM/HTMLObjectElement.h new file mode 100644 index 0000000000..2e59f36d3b --- /dev/null +++ b/Libraries/LibWeb/DOM/HTMLObjectElement.h @@ -0,0 +1,61 @@ +/* + * 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 +#include +#include + +namespace Web { + +class LayoutDocument; + +class HTMLObjectElement final : public HTMLElement { +public: + HTMLObjectElement(Document&, const FlyString& tag_name); + virtual ~HTMLObjectElement() override; + + virtual void parse_attribute(const FlyString& name, const String& value) override; + + String data() const { return attribute(HTML::AttributeNames::data); } + String type() const { return attribute(HTML::AttributeNames::type); } + +private: + virtual RefPtr create_layout_node(const StyleProperties* parent_style) const override; + + ImageLoader m_image_loader; + bool m_should_show_fallback_content { false }; +}; + +template<> +inline bool is(const Node& node) +{ + return is(node) && to(node).tag_name() == HTML::TagNames::object; +} + +}