CSSLoader.cpp 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. /*
  2. * Copyright (c) 2021, the SerenityOS developers.
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <AK/Debug.h>
  7. #include <AK/URL.h>
  8. #include <LibWeb/CSS/Parser/Parser.h>
  9. #include <LibWeb/DOM/Document.h>
  10. #include <LibWeb/DOM/Element.h>
  11. #include <LibWeb/Loader/CSSLoader.h>
  12. #include <LibWeb/Loader/ResourceLoader.h>
  13. namespace Web {
  14. CSSLoader::CSSLoader(DOM::Element& owner_element)
  15. : m_owner_element(owner_element)
  16. {
  17. }
  18. void CSSLoader::load_from_text(const String& text)
  19. {
  20. m_style_sheet = parse_css(CSS::ParsingContext(m_owner_element.document()), text);
  21. if (!m_style_sheet) {
  22. m_style_sheet = CSS::CSSStyleSheet::create({});
  23. m_style_sheet->set_owner_node(&m_owner_element);
  24. }
  25. load_next_import_if_needed();
  26. }
  27. void CSSLoader::load_from_url(const URL& url)
  28. {
  29. m_style_sheet = CSS::CSSStyleSheet::create({});
  30. m_style_sheet->set_owner_node(&m_owner_element);
  31. auto request = LoadRequest::create_for_url_on_page(url, m_owner_element.document().page());
  32. set_resource(ResourceLoader::the().load_resource(Resource::Type::Generic, request));
  33. }
  34. void CSSLoader::resource_did_load()
  35. {
  36. VERIFY(resource());
  37. if (!resource()->has_encoded_data()) {
  38. dbgln_if(CSS_LOADER_DEBUG, "CSSLoader: Resource did load, no encoded data. URL: {}", resource()->url());
  39. } else {
  40. dbgln_if(CSS_LOADER_DEBUG, "CSSLoader: Resource did load, has encoded data. URL: {}", resource()->url());
  41. }
  42. auto sheet = parse_css(CSS::ParsingContext(m_owner_element.document()), resource()->encoded_data());
  43. if (!sheet) {
  44. dbgln_if(CSS_LOADER_DEBUG, "CSSLoader: Failed to parse stylesheet: {}", resource()->url());
  45. return;
  46. }
  47. bool was_imported = m_style_sheet->for_first_not_loaded_import_rule([&](auto& rule) {
  48. rule.set_style_sheet(sheet);
  49. });
  50. // Transfer the rules from the successfully parsed sheet into the sheet we've already inserted.
  51. if (!was_imported) {
  52. m_style_sheet->rules() = sheet->rules();
  53. }
  54. if (on_load)
  55. on_load();
  56. load_next_import_if_needed();
  57. }
  58. void CSSLoader::resource_did_fail()
  59. {
  60. dbgln_if(CSS_LOADER_DEBUG, "CSSLoader: Resource did fail. URL: {}", resource()->url());
  61. load_next_import_if_needed();
  62. }
  63. void CSSLoader::load_next_import_if_needed()
  64. {
  65. // Create load request for the first import which isn't loaded.
  66. // TODO: We need to somehow handle infinite cycles in imports.
  67. m_style_sheet->for_first_not_loaded_import_rule([&](auto& rule) {
  68. dbgln_if(CSS_LOADER_DEBUG, "CSSLoader: Loading @import {}", rule.url());
  69. LoadRequest request;
  70. request.set_url(rule.url());
  71. set_resource(ResourceLoader::the().load_resource(Resource::Type::Generic, request));
  72. });
  73. }
  74. }