/* * Copyright (c) 2018-2021, Andreas Kling * Copyright (c) 2021, the SerenityOS developers. * Copyright (c) 2021, Sam Atkins * * SPDX-License-Identifier: BSD-2-Clause */ #include #include #include #include #include #include #include namespace Web::HTML { HTMLLinkElement::HTMLLinkElement(DOM::Document& document, DOM::QualifiedName qualified_name) : HTMLElement(document, move(qualified_name)) { } HTMLLinkElement::~HTMLLinkElement() = default; void HTMLLinkElement::inserted() { HTMLElement::inserted(); if (m_relationship & Relationship::Stylesheet && !(m_relationship & Relationship::Alternate)) { auto url = document().parse_url(href()); dbgln_if(CSS_LOADER_DEBUG, "HTMLLinkElement: Loading import URL: {}", url); auto request = LoadRequest::create_for_url_on_page(url, document().page()); // NOTE: Mark this element as delaying the document load event *before* calling set_resource() // as it may trigger a synchronous resource_did_load() callback. m_document_load_event_delayer.emplace(document()); set_resource(ResourceLoader::the().load_resource(Resource::Type::Generic, request)); // NOTE: If we ended up not loading a resource for whatever reason, don't delay the load event. if (!resource()) m_document_load_event_delayer.clear(); } if (m_relationship & Relationship::Preload) { // FIXME: Respect the "as" attribute. LoadRequest request; request.set_url(document().parse_url(attribute(HTML::AttributeNames::href))); m_preload_resource = ResourceLoader::the().load_resource(Resource::Type::Generic, request); } else if (m_relationship & Relationship::DNSPrefetch) { ResourceLoader::the().prefetch_dns(document().parse_url(attribute(HTML::AttributeNames::href))); } else if (m_relationship & Relationship::Preconnect) { ResourceLoader::the().preconnect(document().parse_url(attribute(HTML::AttributeNames::href))); } } void HTMLLinkElement::parse_attribute(const FlyString& name, const String& value) { if (name == HTML::AttributeNames::rel) { m_relationship = 0; auto parts = value.split_view(' '); for (auto& part : parts) { if (part == "stylesheet"sv) m_relationship |= Relationship::Stylesheet; else if (part == "alternate"sv) m_relationship |= Relationship::Alternate; else if (part == "preload"sv) m_relationship |= Relationship::Preload; else if (part == "dns-prefetch"sv) m_relationship |= Relationship::DNSPrefetch; else if (part == "preconnect"sv) m_relationship |= Relationship::Preconnect; } } } void HTMLLinkElement::resource_did_fail() { dbgln_if(CSS_LOADER_DEBUG, "HTMLLinkElement: Resource did fail. URL: {}", resource()->url()); m_document_load_event_delayer.clear(); } void HTMLLinkElement::resource_did_load() { VERIFY(resource()); m_document_load_event_delayer.clear(); if (!resource()->has_encoded_data()) { dbgln_if(CSS_LOADER_DEBUG, "HTMLLinkElement: Resource did load, no encoded data. URL: {}", resource()->url()); } else { dbgln_if(CSS_LOADER_DEBUG, "HTMLLinkElement: Resource did load, has encoded data. URL: {}", resource()->url()); if (resource()->mime_type() != "text/css"sv) { dbgln_if(CSS_LOADER_DEBUG, "HTMLLinkElement: Resource did load, but MIME type was {} instead of text/css. URL: {}", resource()->mime_type(), resource()->url()); return; } } auto sheet = parse_css_stylesheet(CSS::ParsingContext(document(), resource()->url()), resource()->encoded_data()); if (!sheet) { dbgln_if(CSS_LOADER_DEBUG, "HTMLLinkElement: Failed to parse stylesheet: {}", resource()->url()); return; } sheet->set_owner_node(this); document().style_sheets().add_sheet(sheet.release_nonnull()); } }