CSSLoader.cpp 2.8 KB

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