Serenity Operating System
at master 114 lines 3.7 kB view raw
1/* 2 * Copyright (c) 2021, the SerenityOS developers. 3 * Copyright (c) 2021, Sam Atkins <atkinssj@serenityos.org> 4 * Copyright (c) 2022, Andreas Kling <kling@serenityos.org> 5 * 6 * SPDX-License-Identifier: BSD-2-Clause 7 */ 8 9#include <AK/Debug.h> 10#include <AK/URL.h> 11#include <LibWeb/Bindings/CSSImportRulePrototype.h> 12#include <LibWeb/Bindings/Intrinsics.h> 13#include <LibWeb/CSS/CSSImportRule.h> 14#include <LibWeb/CSS/Parser/Parser.h> 15#include <LibWeb/DOM/Document.h> 16#include <LibWeb/HTML/Window.h> 17#include <LibWeb/Loader/ResourceLoader.h> 18 19namespace Web::CSS { 20 21WebIDL::ExceptionOr<JS::NonnullGCPtr<CSSImportRule>> CSSImportRule::create(AK::URL url, DOM::Document& document) 22{ 23 auto& realm = document.realm(); 24 return MUST_OR_THROW_OOM(realm.heap().allocate<CSSImportRule>(realm, move(url), document)); 25} 26 27CSSImportRule::CSSImportRule(AK::URL url, DOM::Document& document) 28 : CSSRule(document.realm()) 29 , m_url(move(url)) 30 , m_document(document) 31{ 32 dbgln_if(CSS_LOADER_DEBUG, "CSSImportRule: Loading import URL: {}", m_url); 33 auto request = LoadRequest::create_for_url_on_page(m_url, document.page()); 34 35 // NOTE: Mark this rule as delaying the document load event *before* calling set_resource() 36 // as it may trigger a synchronous resource_did_load() callback. 37 m_document_load_event_delayer.emplace(document); 38 39 set_resource(ResourceLoader::the().load_resource(Resource::Type::Generic, request)); 40} 41 42JS::ThrowCompletionOr<void> CSSImportRule::initialize(JS::Realm& realm) 43{ 44 MUST_OR_THROW_OOM(Base::initialize(realm)); 45 set_prototype(&Bindings::ensure_web_prototype<Bindings::CSSImportRulePrototype>(realm, "CSSImportRule")); 46 47 return {}; 48} 49 50void CSSImportRule::visit_edges(Cell::Visitor& visitor) 51{ 52 Base::visit_edges(visitor); 53 visitor.visit(m_document); 54 visitor.visit(m_style_sheet); 55} 56 57// https://www.w3.org/TR/cssom/#serialize-a-css-rule 58DeprecatedString CSSImportRule::serialized() const 59{ 60 StringBuilder builder; 61 // The result of concatenating the following: 62 63 // 1. The string "@import" followed by a single SPACE (U+0020). 64 builder.append("@import "sv); 65 66 // 2. The result of performing serialize a URL on the rule’s location. 67 // FIXME: Look into the correctness of this serialization 68 builder.append("url("sv); 69 builder.append(m_url.to_deprecated_string()); 70 builder.append(')'); 71 72 // FIXME: 3. If the rule’s associated media list is not empty, a single SPACE (U+0020) followed by the result of performing serialize a media query list on the media list. 73 74 // 4. The string ";", i.e., SEMICOLON (U+003B). 75 builder.append(';'); 76 77 return builder.to_deprecated_string(); 78} 79 80void CSSImportRule::resource_did_fail() 81{ 82 dbgln_if(CSS_LOADER_DEBUG, "CSSImportRule: Resource did fail. URL: {}", resource()->url()); 83 84 m_document_load_event_delayer.clear(); 85} 86 87void CSSImportRule::resource_did_load() 88{ 89 VERIFY(resource()); 90 91 if (!m_document) 92 return; 93 94 m_document_load_event_delayer.clear(); 95 96 if (!resource()->has_encoded_data()) { 97 dbgln_if(CSS_LOADER_DEBUG, "CSSImportRule: Resource did load, no encoded data. URL: {}", resource()->url()); 98 } else { 99 dbgln_if(CSS_LOADER_DEBUG, "CSSImportRule: Resource did load, has encoded data. URL: {}", resource()->url()); 100 } 101 102 auto* sheet = parse_css_stylesheet(CSS::Parser::ParsingContext(*m_document, resource()->url()), resource()->encoded_data()); 103 if (!sheet) { 104 dbgln_if(CSS_LOADER_DEBUG, "CSSImportRule: Failed to parse stylesheet: {}", resource()->url()); 105 return; 106 } 107 108 m_style_sheet = sheet; 109 110 m_document->style_computer().invalidate_rule_cache(); 111 m_document->invalidate_style(); 112} 113 114}