theme_manager.cc 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. // Copyright 2020 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "fuchsia_web/webengine/browser/theme_manager.h"
  5. #include "base/callback.h"
  6. #include "base/callback_helpers.h"
  7. #include "base/check.h"
  8. #include "base/fuchsia/fuchsia_logging.h"
  9. #include "third_party/blink/public/common/web_preferences/web_preferences.h"
  10. #include "third_party/blink/public/mojom/css/preferred_color_scheme.mojom.h"
  11. #include "third_party/blink/public/mojom/webpreferences/web_preferences.mojom.h"
  12. namespace {
  13. using blink::mojom::PreferredColorScheme;
  14. using fuchsia::settings::ThemeType;
  15. constexpr PreferredColorScheme kFallbackColorScheme =
  16. PreferredColorScheme::kLight;
  17. PreferredColorScheme ThemeTypeToBlinkScheme(ThemeType type) {
  18. switch (type) {
  19. case ThemeType::LIGHT:
  20. return PreferredColorScheme::kLight;
  21. case ThemeType::DARK:
  22. return PreferredColorScheme::kDark;
  23. default:
  24. NOTREACHED();
  25. return kFallbackColorScheme;
  26. }
  27. }
  28. } // namespace
  29. ThemeManager::ThemeManager(content::WebContents* web_contents,
  30. base::OnceClosure on_display_error)
  31. : web_contents_(web_contents),
  32. on_display_error_(std::move(on_display_error)) {
  33. DCHECK(web_contents_);
  34. // Per the FIDL API, the default theme is LIGHT.
  35. SetTheme(ThemeType::LIGHT);
  36. }
  37. ThemeManager::~ThemeManager() = default;
  38. void ThemeManager::SetTheme(ThemeType theme) {
  39. requested_theme_ = theme;
  40. if (theme == ThemeType::DEFAULT) {
  41. if (!EnsureDisplayService()) {
  42. OnDisplayServiceMissing();
  43. return;
  44. }
  45. }
  46. }
  47. bool ThemeManager::EnsureDisplayService() {
  48. if (observed_display_service_error_)
  49. return false;
  50. if (display_service_)
  51. return true;
  52. display_service_ = base::ComponentContextForProcess()
  53. ->svc()
  54. ->Connect<fuchsia::settings::Display>();
  55. display_service_.set_error_handler([this](zx_status_t status) {
  56. ZX_LOG_IF(ERROR, status != ZX_ERR_PEER_CLOSED, status)
  57. << "fuchsia.settings.Display disconnected.";
  58. observed_display_service_error_ = true;
  59. // If the channel to the Display service was dropped before we received a
  60. // response from WatchForDisplayChanges, then it's likely that the service
  61. // isn't available in the namespace at all, which should be reported as
  62. // an error on the Frame.
  63. // Otherwise, if a failure was detected for a Display that was previously
  64. // functioning, it should be treated as a transient issue and the last known
  65. // system theme should be used.
  66. if (requested_theme_ && (*requested_theme_ == ThemeType::DEFAULT) &&
  67. !did_receive_first_watch_result_) {
  68. OnDisplayServiceMissing();
  69. }
  70. });
  71. WatchForDisplayChanges();
  72. return true;
  73. }
  74. void ThemeManager::OnDisplayServiceMissing() {
  75. LOG(ERROR) << "DEFAULT theme requires access to the "
  76. "`fuchsia.settings.Display` service to work.";
  77. if (on_display_error_)
  78. std::move(on_display_error_).Run();
  79. }
  80. void ThemeManager::ApplyThemeToWebPreferences(
  81. blink::web_pref::WebPreferences* web_prefs) {
  82. DCHECK(requested_theme_);
  83. if (requested_theme_ == ThemeType::DEFAULT) {
  84. if (!system_theme_) {
  85. // Defer theme application until we receive a system theme.
  86. return;
  87. }
  88. web_prefs->preferred_color_scheme = ThemeTypeToBlinkScheme(*system_theme_);
  89. } else {
  90. DCHECK(requested_theme_ == ThemeType::LIGHT ||
  91. requested_theme_ == ThemeType::DARK);
  92. web_prefs->preferred_color_scheme =
  93. ThemeTypeToBlinkScheme(*requested_theme_);
  94. }
  95. }
  96. void ThemeManager::WatchForDisplayChanges() {
  97. DCHECK(display_service_);
  98. // Will reply immediately for the first call of Watch(). Subsequent calls to
  99. // Watch() will be replied to as changes occur.
  100. display_service_->Watch(
  101. fit::bind_member(this, &ThemeManager::OnWatchResultReceived));
  102. }
  103. void ThemeManager::OnWatchResultReceived(
  104. fuchsia::settings::DisplaySettings settings) {
  105. did_receive_first_watch_result_ = true;
  106. if (settings.has_theme() && settings.theme().has_theme_type() &&
  107. (settings.theme().theme_type() == ThemeType::DARK ||
  108. settings.theme().theme_type() == ThemeType::LIGHT)) {
  109. system_theme_ = settings.theme().theme_type();
  110. } else {
  111. system_theme_ = absl::nullopt;
  112. }
  113. web_contents_->OnWebPreferencesChanged();
  114. WatchForDisplayChanges();
  115. }