| // Copyright 2015 The Cobalt Authors. All Rights Reserved. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #include "cobalt/browser/splash_screen.h" |
| |
| #include <string> |
| |
| #include "base/bind.h" |
| #include "base/callback.h" |
| #include "base/cancelable_callback.h" |
| #include "base/threading/platform_thread.h" |
| #include "base/time/time.h" |
| #include "cobalt/browser/splash_screen_cache.h" |
| #include "cobalt/dom/window.h" |
| #include "cobalt/loader/cache_fetcher.h" |
| |
| namespace cobalt { |
| namespace browser { |
| namespace { |
| |
| const int kSplashShutdownSeconds = 2; |
| |
| typedef base::Callback<void(base::TimeDelta)> Callback; |
| void PostCallbackToMessageLoop(const Callback& callback, |
| base::MessageLoop* message_loop, |
| base::TimeDelta time) { |
| DCHECK(message_loop); |
| message_loop->task_runner()->PostTask(FROM_HERE, base::Bind(callback, time)); |
| } |
| |
| // TODO: consolidate definitions of BindToLoop / BindToCurrentLoop |
| // from here and media in base. |
| Callback BindToLoop(const Callback& callback, base::MessageLoop* message_loop) { |
| return base::Bind(&PostCallbackToMessageLoop, callback, message_loop); |
| } |
| |
| void OnError(const GURL& /* url */, const std::string& error) { |
| LOG(ERROR) << error; |
| } |
| |
| } // namespace |
| |
| SplashScreen::SplashScreen( |
| base::ApplicationState initial_application_state, |
| const WebModule::OnRenderTreeProducedCallback& |
| render_tree_produced_callback, |
| network::NetworkModule* network_module, |
| const cssom::ViewportSize& window_dimensions, |
| render_tree::ResourceProvider* resource_provider, float layout_refresh_rate, |
| const base::Optional<GURL>& fallback_splash_screen_url, |
| const GURL& initial_main_web_module_url, |
| SplashScreenCache* splash_screen_cache, |
| const base::Callback<void(base::TimeDelta)>& |
| on_splash_screen_shutdown_complete) |
| : render_tree_produced_callback_(render_tree_produced_callback), |
| self_message_loop_(base::MessageLoop::current()), |
| on_splash_screen_shutdown_complete_(on_splash_screen_shutdown_complete), |
| shutdown_signaled_(false) { |
| WebModule::Options web_module_options; |
| web_module_options.name = "SplashScreenWebModule"; |
| |
| // We want the splash screen to load and appear as quickly as possible, so |
| // we set it and its image decoding thread to be high priority. |
| web_module_options.thread_priority = base::ThreadPriority::HIGHEST; |
| web_module_options.loader_thread_priority = base::ThreadPriority::HIGHEST; |
| web_module_options.animated_image_decode_thread_priority = |
| base::ThreadPriority::HIGHEST; |
| |
| base::Optional<GURL> url_to_pass = fallback_splash_screen_url; |
| // Use the cached URL rather than the passed in URL if it exists. |
| base::Optional<std::string> key = |
| SplashScreenCache::GetKeyForStartUrl(initial_main_web_module_url); |
| DCHECK(fallback_splash_screen_url || |
| (key && splash_screen_cache && |
| splash_screen_cache->IsSplashScreenCached(*key))); |
| if (key && splash_screen_cache && |
| splash_screen_cache->IsSplashScreenCached(*key)) { |
| url_to_pass = GURL(loader::kCacheScheme + ("://" + *key)); |
| web_module_options.can_fetch_cache = true; |
| web_module_options.splash_screen_cache = splash_screen_cache; |
| } |
| |
| base::Callback<void(base::TimeDelta)> on_window_close( |
| BindToLoop(on_splash_screen_shutdown_complete, self_message_loop_)); |
| |
| web_module_options.on_before_unload_fired_but_not_handled = |
| base::Bind(on_window_close, base::TimeDelta()); |
| |
| // Since the splash screen is intended to possibly fade in to the main web |
| // module contents, make sure blending is enabled for its background. |
| web_module_options.clear_window_with_background_color = false; |
| |
| DCHECK(url_to_pass); |
| web_module_.reset(new WebModule( |
| *url_to_pass, initial_application_state, render_tree_produced_callback_, |
| base::Bind(&OnError), on_window_close, |
| base::Closure(), // window_minimize_callback |
| NULL /* can_play_type_handler */, NULL /* web_media_player_factory */, |
| network_module, window_dimensions, 1.f /*video_pixel_ratio*/, |
| resource_provider, layout_refresh_rate, web_module_options)); |
| } |
| |
| SplashScreen::~SplashScreen() { |
| DCHECK_EQ(base::MessageLoop::current(), self_message_loop_); |
| // Destroy the web module first to prevent our callbacks from being called |
| // (from another thread) while member objects are being destroyed. |
| web_module_.reset(); |
| // Cancel any pending run of the splash screen shutdown callback. |
| on_splash_screen_shutdown_complete_.Cancel(); |
| } |
| |
| void SplashScreen::Shutdown() { |
| DCHECK_EQ(base::MessageLoop::current(), self_message_loop_); |
| DCHECK(web_module_); |
| DCHECK(!ShutdownSignaled()) << "Shutdown() should be called at most once."; |
| |
| if (!on_splash_screen_shutdown_complete_.callback().is_null()) { |
| base::MessageLoop::current()->task_runner()->PostDelayedTask( |
| FROM_HERE, |
| base::Bind(on_splash_screen_shutdown_complete_.callback(), |
| base::TimeDelta()), |
| base::TimeDelta::FromSeconds(kSplashShutdownSeconds)); |
| } |
| web_module_->InjectBeforeUnloadEvent(); |
| |
| shutdown_signaled_ = true; |
| } |
| |
| } // namespace browser |
| } // namespace cobalt |