| // 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/dom/window.h" |
| |
| #include <algorithm> |
| #include <memory> |
| |
| #include "base/bind.h" |
| #include "base/bind_helpers.h" |
| #include "base/trace_event/trace_event.h" |
| #include "cobalt/base/polymorphic_downcast.h" |
| #include "cobalt/base/tokens.h" |
| #include "cobalt/cssom/css_computed_style_declaration.h" |
| #include "cobalt/cssom/user_agent_style_sheet.h" |
| #include "cobalt/cssom/viewport_size.h" |
| #include "cobalt/dom/base64.h" |
| #include "cobalt/dom/camera_3d.h" |
| #include "cobalt/dom/console.h" |
| #include "cobalt/dom/device_orientation_event.h" |
| #include "cobalt/dom/document.h" |
| #include "cobalt/dom/dom_settings.h" |
| #include "cobalt/dom/element.h" |
| #include "cobalt/dom/error_event.h" |
| #include "cobalt/dom/error_event_init.h" |
| #include "cobalt/dom/event.h" |
| #include "cobalt/dom/history.h" |
| #include "cobalt/dom/html_element.h" |
| #include "cobalt/dom/html_element_context.h" |
| #include "cobalt/dom/input_event.h" |
| #include "cobalt/dom/keyboard_event.h" |
| #include "cobalt/dom/location.h" |
| #include "cobalt/dom/media_source.h" |
| #include "cobalt/dom/mouse_event.h" |
| #include "cobalt/dom/mutation_observer_task_manager.h" |
| #include "cobalt/dom/navigator.h" |
| #include "cobalt/dom/performance.h" |
| #include "cobalt/dom/pointer_event.h" |
| #include "cobalt/dom/screen.h" |
| #include "cobalt/dom/screenshot.h" |
| #include "cobalt/dom/screenshot_manager.h" |
| #include "cobalt/dom/storage.h" |
| #include "cobalt/dom/wheel_event.h" |
| #include "cobalt/dom/window_timers.h" |
| #include "cobalt/media_session/media_session_client.h" |
| #include "cobalt/script/environment_settings.h" |
| #include "cobalt/script/javascript_engine.h" |
| #include "cobalt/speech/speech_synthesis.h" |
| #include "starboard/file.h" |
| |
| using cobalt::cssom::ViewportSize; |
| using cobalt::media_session::MediaSession; |
| |
| namespace cobalt { |
| namespace dom { |
| |
| // This class fires the window's load event when the document is loaded. |
| class Window::RelayLoadEvent : public DocumentObserver { |
| public: |
| explicit RelayLoadEvent(Window* window) : window_(window) {} |
| |
| // From DocumentObserver. |
| void OnLoad() override { |
| window_->PostToDispatchEventName(FROM_HERE, base::Tokens::load()); |
| } |
| void OnMutation() override {} |
| void OnFocusChanged() override {} |
| |
| private: |
| Window* window_; |
| |
| DISALLOW_COPY_AND_ASSIGN(RelayLoadEvent); |
| }; |
| |
| namespace { |
| // Ensure that the timer resolution is at the lowest 20 microseconds in |
| // order to mitigate potential Spectre-related attacks. This is following |
| // Mozilla's lead as described here: |
| // https://www.mozilla.org/en-US/security/advisories/mfsa2018-01/ |
| const int64_t kPerformanceTimerMinResolutionInMicroseconds = 20; |
| } // namespace |
| |
| Window::Window( |
| script::EnvironmentSettings* settings, const ViewportSize& view_size, |
| base::ApplicationState initial_application_state, |
| cssom::CSSParser* css_parser, Parser* dom_parser, |
| loader::FetcherFactory* fetcher_factory, |
| loader::LoaderFactory* loader_factory, |
| render_tree::ResourceProvider** resource_provider, |
| loader::image::AnimatedImageTracker* animated_image_tracker, |
| loader::image::ImageCache* image_cache, |
| loader::image::ReducedCacheCapacityManager* |
| reduced_image_cache_capacity_manager, |
| loader::font::RemoteTypefaceCache* remote_typeface_cache, |
| loader::mesh::MeshCache* mesh_cache, |
| LocalStorageDatabase* local_storage_database, |
| media::CanPlayTypeHandler* can_play_type_handler, |
| media::WebMediaPlayerFactory* web_media_player_factory, |
| script::ExecutionState* execution_state, |
| script::ScriptRunner* script_runner, |
| script::ScriptValueFactory* script_value_factory, |
| MediaSource::Registry* media_source_registry, |
| DomStatTracker* dom_stat_tracker, const GURL& url, |
| const std::string& user_agent, const std::string& language, |
| const std::string& font_language_script, |
| const base::Callback<void(const GURL&)> navigation_callback, |
| const loader::Decoder::OnCompleteFunction& load_complete_callback, |
| network_bridge::CookieJar* cookie_jar, |
| const network_bridge::PostSender& post_sender, |
| csp::CSPHeaderPolicy require_csp, CspEnforcementType csp_enforcement_mode, |
| const base::Closure& csp_policy_changed_callback, |
| const base::Closure& ran_animation_frame_callbacks_callback, |
| const CloseCallback& window_close_callback, |
| const base::Closure& window_minimize_callback, |
| OnScreenKeyboardBridge* on_screen_keyboard_bridge, |
| const scoped_refptr<input::Camera3D>& camera_3d, |
| const OnStartDispatchEventCallback& on_start_dispatch_event_callback, |
| const OnStopDispatchEventCallback& on_stop_dispatch_event_callback, |
| const ScreenshotManager::ProvideScreenshotFunctionCallback& |
| screenshot_function_callback, |
| base::WaitableEvent* synchronous_loader_interrupt, |
| bool enable_inline_script_warnings, |
| const scoped_refptr<ui_navigation::NavItem>& ui_nav_root, |
| bool enable_map_to_mesh, int csp_insecure_allowed_token, |
| int dom_max_element_depth, float video_playback_rate_multiplier, |
| ClockType clock_type, const CacheCallback& splash_screen_cache_callback, |
| const scoped_refptr<captions::SystemCaptionSettings>& captions, |
| bool log_tts) |
| // 'window' object EventTargets require special handling for onerror events, |
| // see EventTarget constructor for more details. |
| : EventTarget(settings, kUnpackOnErrorEvents), |
| viewport_size_(view_size), |
| is_resize_event_pending_(false), |
| is_reporting_script_error_(false), |
| #if defined(ENABLE_TEST_RUNNER) |
| test_runner_(new TestRunner()), |
| #endif // ENABLE_TEST_RUNNER |
| html_element_context_(new HTMLElementContext( |
| settings, fetcher_factory, loader_factory, css_parser, dom_parser, |
| can_play_type_handler, web_media_player_factory, script_runner, |
| script_value_factory, media_source_registry, resource_provider, |
| animated_image_tracker, image_cache, |
| reduced_image_cache_capacity_manager, remote_typeface_cache, |
| mesh_cache, dom_stat_tracker, font_language_script, |
| initial_application_state, synchronous_loader_interrupt, |
| enable_inline_script_warnings, video_playback_rate_multiplier)), |
| performance_(new Performance(MakePerformanceClock(clock_type))), |
| ALLOW_THIS_IN_INITIALIZER_LIST(document_(new Document( |
| html_element_context_.get(), |
| Document::Options( |
| url, this, |
| base::Bind(&Window::FireHashChangeEvent, base::Unretained(this)), |
| performance_->timing()->GetNavigationStartClock(), |
| navigation_callback, ParseUserAgentStyleSheet(css_parser), |
| view_size, cookie_jar, post_sender, require_csp, |
| csp_enforcement_mode, csp_policy_changed_callback, |
| csp_insecure_allowed_token, dom_max_element_depth)))), |
| document_loader_(nullptr), |
| history_(new History()), |
| navigator_(new Navigator(settings, user_agent, language, |
| captions, script_value_factory)), |
| ALLOW_THIS_IN_INITIALIZER_LIST( |
| relay_on_load_event_(new RelayLoadEvent(this))), |
| console_(new Console(execution_state)), |
| ALLOW_THIS_IN_INITIALIZER_LIST( |
| window_timers_(new WindowTimers(this, debugger_hooks()))), |
| ALLOW_THIS_IN_INITIALIZER_LIST(animation_frame_request_callback_list_( |
| new AnimationFrameRequestCallbackList(this, debugger_hooks()))), |
| crypto_(new Crypto()), |
| speech_synthesis_( |
| new speech::SpeechSynthesis(settings, navigator_, log_tts)), |
| ALLOW_THIS_IN_INITIALIZER_LIST(local_storage_( |
| new Storage(this, Storage::kLocalStorage, local_storage_database))), |
| ALLOW_THIS_IN_INITIALIZER_LIST( |
| session_storage_(new Storage(this, Storage::kSessionStorage, NULL))), |
| screen_(new Screen(view_size)), |
| preflight_cache_(new loader::CORSPreflightCache()), |
| ran_animation_frame_callbacks_callback_( |
| ran_animation_frame_callbacks_callback), |
| window_close_callback_(window_close_callback), |
| window_minimize_callback_(window_minimize_callback), |
| // We only have an on_screen_keyboard_bridge when the platform supports |
| // it. Otherwise don't even expose it in the DOM. |
| on_screen_keyboard_(on_screen_keyboard_bridge |
| ? new OnScreenKeyboard(settings, |
| on_screen_keyboard_bridge, |
| script_value_factory) |
| : NULL), |
| splash_screen_cache_callback_(splash_screen_cache_callback), |
| on_start_dispatch_event_callback_(on_start_dispatch_event_callback), |
| on_stop_dispatch_event_callback_(on_stop_dispatch_event_callback), |
| screenshot_manager_(settings, screenshot_function_callback), |
| ui_nav_root_(ui_nav_root), |
| enable_map_to_mesh_(enable_map_to_mesh) { |
| #if !defined(ENABLE_TEST_RUNNER) |
| #endif |
| document_->AddObserver(relay_on_load_event_.get()); |
| html_element_context_->application_lifecycle_state()->AddObserver(this); |
| SetCamera3D(camera_3d); |
| |
| // Document load start is deferred from this constructor so that we can be |
| // guaranteed that this Window object is fully constructed before document |
| // loading begins. |
| base::MessageLoop::current()->task_runner()->PostTask( |
| FROM_HERE, |
| base::Bind(&Window::StartDocumentLoad, base::Unretained(this), |
| fetcher_factory, url, dom_parser, load_complete_callback)); |
| } |
| |
| void Window::StartDocumentLoad( |
| loader::FetcherFactory* fetcher_factory, const GURL& url, |
| Parser* dom_parser, |
| const loader::Decoder::OnCompleteFunction& load_complete_callback) { |
| document_loader_.reset(new loader::Loader( |
| base::Bind(&loader::FetcherFactory::CreateFetcher, |
| base::Unretained(fetcher_factory), url), |
| base::Bind(&Parser::ParseDocumentAsync, base::Unretained(dom_parser), |
| document_, base::SourceLocation(url.spec(), 1, 1)), |
| load_complete_callback)); |
| } |
| |
| scoped_refptr<base::BasicClock> Window::MakePerformanceClock( |
| ClockType clock_type) { |
| switch (clock_type) { |
| case kClockTypeTestRunner: { |
| #if defined(ENABLE_TEST_RUNNER) |
| return test_runner_->GetClock(); |
| #else |
| NOTREACHED(); |
| #endif |
| } break; |
| case kClockTypeSystemTime: { |
| return new base::SystemMonotonicClock(); |
| } break; |
| case kClockTypeResolutionLimitedSystemTime: { |
| return new base::MinimumResolutionClock( |
| new base::SystemMonotonicClock(), |
| base::TimeDelta::FromMicroseconds( |
| kPerformanceTimerMinResolutionInMicroseconds)); |
| } break; |
| } |
| NOTREACHED(); |
| return scoped_refptr<base::BasicClock>(); |
| } |
| |
| const scoped_refptr<Document>& Window::document() const { return document_; } |
| |
| const scoped_refptr<Location>& Window::location() const { |
| return document_->location(); |
| } |
| |
| const scoped_refptr<History>& Window::history() const { return history_; } |
| |
| // https://www.w3.org/TR/html50/browsers.html#dom-window-close |
| void Window::Close() { |
| LOG(INFO) << __func__; |
| if (!window_close_callback_.is_null()) { |
| window_close_callback_.Run( |
| performance_->timing()->GetNavigationStartClock()->Now()); |
| } |
| } |
| |
| void Window::Minimize() { |
| if (!window_minimize_callback_.is_null()) { |
| window_minimize_callback_.Run(); |
| } |
| } |
| |
| const scoped_refptr<Navigator>& Window::navigator() const { return navigator_; } |
| |
| script::Handle<ScreenshotManager::InterfacePromise> Window::Screenshot() { |
| scoped_refptr<render_tree::Node> render_tree_root = |
| document_->DoSynchronousLayoutAndGetRenderTree(); |
| |
| script::Handle<ScreenshotManager::InterfacePromise> promise = |
| html_element_context() |
| ->script_value_factory() |
| ->CreateInterfacePromise<dom::Screenshot>(); |
| |
| std::unique_ptr<ScreenshotManager::InterfacePromiseValue::Reference> |
| promise_reference(new ScreenshotManager::InterfacePromiseValue::Reference( |
| this, promise)); |
| |
| screenshot_manager_.Screenshot( |
| loader::image::EncodedStaticImage::ImageFormat::kPNG, render_tree_root, |
| std::move(promise_reference)); |
| |
| return promise; |
| } |
| |
| scoped_refptr<cssom::CSSStyleDeclaration> Window::GetComputedStyle( |
| const scoped_refptr<Element>& elt) { |
| scoped_refptr<HTMLElement> html_element = elt->AsHTMLElement(); |
| if (html_element) { |
| document_->UpdateComputedStyleOnElementAndAncestor(html_element.get()); |
| return html_element->css_computed_style_declaration(); |
| } |
| return NULL; |
| } |
| |
| scoped_refptr<cssom::CSSStyleDeclaration> Window::GetComputedStyle( |
| const scoped_refptr<Element>& elt, const std::string& pseudo_elt) { |
| // The getComputedStyle(elt, pseudoElt) method must run these steps: |
| // https://www.w3.org/TR/2013/WD-cssom-20131205/#dom-window-getcomputedstyle |
| |
| // 1. Let doc be the Document associated with the Window object on which the |
| // method was invoked. |
| DCHECK_EQ(document_, elt->node_document()) |
| << "getComputedStyle not supported for elements outside of the document"; |
| |
| scoped_refptr<HTMLElement> html_element = elt->AsHTMLElement(); |
| scoped_refptr<cssom::CSSComputedStyleDeclaration> obj; |
| if (html_element) { |
| document_->UpdateComputedStyleOnElementAndAncestor(html_element.get()); |
| |
| // 2. Let obj be elt. |
| obj = html_element->css_computed_style_declaration(); |
| |
| // 3. If pseudoElt is as an ASCII case-insensitive match for either |
| // ':before' or '::before' let obj be the ::before pseudo-element of elt. |
| if (base::LowerCaseEqualsASCII(pseudo_elt, ":before") || |
| base::LowerCaseEqualsASCII(pseudo_elt, "::before")) { |
| PseudoElement* pseudo_element = |
| html_element->pseudo_element(kBeforePseudoElementType); |
| obj = pseudo_element ? pseudo_element->css_computed_style_declaration() |
| : NULL; |
| } |
| |
| // 4. If pseudoElt is as an ASCII case-insensitive match for either ':after' |
| // or '::after' let obj be the ::after pseudo-element of elt. |
| if (base::LowerCaseEqualsASCII(pseudo_elt, ":after") || |
| base::LowerCaseEqualsASCII(pseudo_elt, "::after")) { |
| PseudoElement* pseudo_element = |
| html_element->pseudo_element(kAfterPseudoElementType); |
| obj = pseudo_element ? pseudo_element->css_computed_style_declaration() |
| : NULL; |
| } |
| } |
| // 5. Return a live CSS declaration block. |
| return obj; |
| } |
| |
| int32 Window::RequestAnimationFrame( |
| const AnimationFrameRequestCallbackList::FrameRequestCallbackArg& |
| callback) { |
| return animation_frame_request_callback_list_->RequestAnimationFrame( |
| callback); |
| } |
| |
| void Window::CancelAnimationFrame(int32 handle) { |
| animation_frame_request_callback_list_->CancelAnimationFrame(handle); |
| } |
| |
| scoped_refptr<MediaQueryList> Window::MatchMedia(const std::string& query) { |
| DCHECK(html_element_context_->css_parser()); |
| scoped_refptr<cssom::MediaList> media_list = |
| html_element_context_->css_parser()->ParseMediaList( |
| query, GetInlineSourceLocation()); |
| return base::WrapRefCounted(new MediaQueryList(media_list, screen_)); |
| } |
| |
| const scoped_refptr<Screen>& Window::screen() { return screen_; } |
| |
| scoped_refptr<Crypto> Window::crypto() const { return crypto_; } |
| |
| std::string Window::Btoa(const std::string& string_to_encode, |
| script::ExceptionState* exception_state) { |
| TRACE_EVENT0("cobalt::dom", "Window::Btoa()"); |
| LOG_ONCE(WARNING) |
| << "In older Cobalt(<19), btoa() can not take a string" |
| " containing NULL. Be careful that you don't need to stay " |
| "compatible with old versions of Cobalt if you use btoa."; |
| auto output = ForgivingBase64Encode(string_to_encode); |
| if (!output) { |
| DOMException::Raise(DOMException::kInvalidCharacterErr, exception_state); |
| return std::string(); |
| } |
| return *output; |
| } |
| |
| std::vector<uint8_t> Window::Atob(const std::string& encoded_string, |
| script::ExceptionState* exception_state) { |
| TRACE_EVENT0("cobalt::dom", "Window::Atob()"); |
| auto output = ForgivingBase64Decode(encoded_string); |
| if (!output) { |
| DOMException::Raise(DOMException::kInvalidCharacterErr, exception_state); |
| return {}; |
| } |
| return *output; |
| } |
| |
| int Window::SetTimeout(const WindowTimers::TimerCallbackArg& handler, |
| int timeout) { |
| DLOG_IF(WARNING, timeout < 0) |
| << "Window::SetTimeout received negative timeout: " << timeout; |
| timeout = std::max(timeout, 0); |
| |
| int return_value = 0; |
| if (window_timers_) { |
| return_value = window_timers_->SetTimeout(handler, timeout); |
| } else { |
| DLOG(WARNING) << "window_timers_ does not exist. Already destroyed?"; |
| } |
| |
| return return_value; |
| } |
| |
| void Window::ClearTimeout(int handle) { |
| if (window_timers_) { |
| window_timers_->ClearTimeout(handle); |
| } else { |
| DLOG(WARNING) << "window_timers_ does not exist. Already destroyed?"; |
| } |
| } |
| |
| int Window::SetInterval(const WindowTimers::TimerCallbackArg& handler, |
| int timeout) { |
| DLOG_IF(WARNING, timeout < 0) |
| << "Window::SetInterval received negative timeout: " << timeout; |
| timeout = std::max(timeout, 0); |
| |
| int return_value = 0; |
| if (window_timers_) { |
| return_value = window_timers_->SetInterval(handler, timeout); |
| } else { |
| DLOG(WARNING) << "window_timers_ does not exist. Already destroyed?"; |
| } |
| |
| return return_value; |
| } |
| |
| void Window::ClearInterval(int handle) { |
| if (window_timers_) { |
| window_timers_->ClearInterval(handle); |
| } else { |
| DLOG(WARNING) << "window_timers_ does not exist. Already destroyed?"; |
| } |
| } |
| |
| void Window::DestroyTimers() { window_timers_->DisableCallbacks(); } |
| |
| scoped_refptr<Storage> Window::local_storage() const { return local_storage_; } |
| |
| scoped_refptr<Storage> Window::session_storage() const { |
| return session_storage_; |
| } |
| |
| const scoped_refptr<Performance>& Window::performance() const { |
| return performance_; |
| } |
| |
| scoped_refptr<speech::SpeechSynthesis> Window::speech_synthesis() const { |
| return speech_synthesis_; |
| } |
| |
| const scoped_refptr<Console>& Window::console() const { return console_; } |
| |
| const scoped_refptr<Camera3D>& Window::camera_3d() const { return camera_3d_; } |
| |
| #if defined(ENABLE_TEST_RUNNER) |
| const scoped_refptr<TestRunner>& Window::test_runner() const { |
| return test_runner_; |
| } |
| #endif // ENABLE_TEST_RUNNER |
| |
| void Window::Gc(script::EnvironmentSettings* settings) { |
| if (settings) { |
| DOMSettings* dom_settings = |
| base::polymorphic_downcast<dom::DOMSettings*>(settings); |
| dom_settings->javascript_engine()->CollectGarbage(); |
| } |
| } |
| |
| HTMLElementContext* Window::html_element_context() const { |
| return html_element_context_.get(); |
| } |
| |
| void Window::RunAnimationFrameCallbacks() { |
| // Scope the StopWatch. It should not include any processing from |
| // |ran_animation_frame_callbacks_callback_|. |
| { |
| base::StopWatch stop_watch_run_animation_frame_callbacks( |
| DomStatTracker::kStopWatchTypeRunAnimationFrameCallbacks, |
| base::StopWatch::kAutoStartOn, |
| html_element_context()->dom_stat_tracker()); |
| |
| // First grab the current list of frame request callbacks and hold on to it |
| // here locally. |
| std::unique_ptr<AnimationFrameRequestCallbackList> frame_request_list = |
| std::move(animation_frame_request_callback_list_); |
| |
| // Then setup the Window's frame request callback list with a freshly |
| // created and empty one. |
| animation_frame_request_callback_list_.reset( |
| new AnimationFrameRequestCallbackList(this, debugger_hooks())); |
| |
| // Now, iterate through each of the callbacks and call them. |
| frame_request_list->RunCallbacks(*document_->timeline()->current_time()); |
| } |
| |
| // Run the callback if one exists. |
| if (!ran_animation_frame_callbacks_callback_.is_null()) { |
| ran_animation_frame_callbacks_callback_.Run(); |
| } |
| } |
| |
| bool Window::HasPendingAnimationFrameCallbacks() const { |
| return animation_frame_request_callback_list_->HasPendingCallbacks(); |
| } |
| |
| void Window::InjectEvent(const scoped_refptr<Event>& event) { |
| TRACE_EVENT1("cobalt::dom", "Window::InjectEvent()", "event", |
| event->type().c_str()); |
| |
| // Forward the event on to the correct object in DOM. |
| if (event->GetWrappableType() == base::GetTypeId<KeyboardEvent>()) { |
| // Event.target:focused element processing the key event or if no element |
| // focused, then the body element if available, otherwise the root element. |
| // https://www.w3.org/TR/2016/WD-uievents-20160804/#event-type-keydown |
| // https://www.w3.org/TR/2016/WD-uievents-20160804/#event-type-keypress |
| // https://www.w3.org/TR/2016/WD-uievents-20160804/#event-type-keyup |
| if (document_->active_element()) { |
| document_->active_element()->DispatchEvent(event); |
| } else { |
| document_->DispatchEvent(event); |
| } |
| } else if (event->GetWrappableType() == base::GetTypeId<InputEvent>()) { |
| // Dispatch any InputEvent directly to the OnScreenKeyboard element. |
| if (on_screen_keyboard_) { |
| on_screen_keyboard_->DispatchEvent(event); |
| } |
| } else { |
| SB_NOTREACHED(); |
| } |
| } |
| |
| void Window::SetApplicationState(base::ApplicationState state) { |
| html_element_context_->application_lifecycle_state()->SetApplicationState( |
| state); |
| } |
| |
| bool Window::ReportScriptError(const script::ErrorReport& error_report) { |
| // Runtime script errors: when the user agent is required to report an error |
| // for a particular script, it must run these steps, after which the error is |
| // either handled or not handled: |
| // https://www.w3.org/TR/html50/webappapis.html#runtime-script-errors |
| |
| // 1. If target is in error reporting mode, then abort these steps; the error |
| // is not handled. |
| if (is_reporting_script_error_) { |
| return false; |
| } |
| |
| // 2. Let target be in error reporting mode. |
| is_reporting_script_error_ = true; |
| |
| // 7. Let event be a new trusted ErrorEvent object that does not bubble but is |
| // cancelable, and which has the event name error. |
| // NOTE: Cobalt does not currently support trusted events. |
| ErrorEventInit error_event_init; |
| error_event_init.set_bubbles(false); |
| error_event_init.set_cancelable(true); |
| |
| if (error_report.is_muted) { |
| // 6. If script has muted errors, then set message to "Script error.", set |
| // location to the empty string, set line and col to 0, and set error |
| // object to null. |
| error_event_init.set_message("Script error."); |
| error_event_init.set_filename(""); |
| error_event_init.set_lineno(0); |
| error_event_init.set_colno(0); |
| error_event_init.set_error(NULL); |
| } else { |
| // 8. Initialize event's message attribute to message. |
| error_event_init.set_message(error_report.message); |
| // 9. Initialize event's filename attribute to location. |
| error_event_init.set_filename(error_report.filename); |
| // 10. Initialize event's lineno attribute to line. |
| error_event_init.set_lineno(error_report.line_number); |
| // 11. Initialize event's colno attribute to col. |
| error_event_init.set_colno(error_report.column_number); |
| // 12. Initialize event's error attribute to error object. |
| error_event_init.set_error(error_report.error ? error_report.error.get() |
| : NULL); |
| } |
| |
| scoped_refptr<ErrorEvent> error_event( |
| new ErrorEvent(base::Tokens::error(), error_event_init)); |
| |
| // 13. Dispatch event at target. |
| DispatchEvent(error_event); |
| |
| // 14. Let target no longer be in error reporting mode. |
| is_reporting_script_error_ = false; |
| |
| // 15. If event was canceled, then the error is handled. Otherwise, the error |
| // is not handled. |
| return error_event->default_prevented(); |
| } |
| |
| void Window::SetSynchronousLayoutCallback(const base::Closure& callback) { |
| document_->set_synchronous_layout_callback(callback); |
| } |
| |
| void Window::SetSynchronousLayoutAndProduceRenderTreeCallback( |
| const SynchronousLayoutAndProduceRenderTreeCallback& callback) { |
| document_->set_synchronous_layout_and_produce_render_tree_callback(callback); |
| } |
| |
| void Window::SetSize(ViewportSize size) { |
| if (size == viewport_size_) { |
| return; |
| } |
| |
| viewport_size_ = size; |
| screen_->SetSize(viewport_size_); |
| // This will cause layout invalidation. |
| document_->SetViewport(viewport_size_); |
| |
| if (html_element_context_->application_lifecycle_state() |
| ->GetVisibilityState() == kVisibilityStateVisible) { |
| DispatchEvent(new Event(base::Tokens::resize())); |
| } else { |
| is_resize_event_pending_ = true; |
| } |
| } |
| |
| void Window::SetCamera3D(const scoped_refptr<input::Camera3D>& camera_3d) { |
| camera_3d_ = new Camera3D(camera_3d); |
| camera_3d_->StartOrientationEvents(base::AsWeakPtr(this)); |
| } |
| |
| void Window::OnWindowFocusChanged(bool has_focus) { |
| DispatchEvent( |
| new Event(has_focus ? base::Tokens::focus() : base::Tokens::blur())); |
| } |
| |
| void Window::OnVisibilityStateChanged(VisibilityState visibility_state) { |
| if (is_resize_event_pending_ && visibility_state == kVisibilityStateVisible) { |
| is_resize_event_pending_ = false; |
| DispatchEvent(new Event(base::Tokens::resize())); |
| } |
| } |
| |
| void Window::OnFrozennessChanged(bool is_frozen) { |
| // Ignored by this class. |
| } |
| |
| void Window::OnDocumentRootElementUnableToProvideOffsetDimensions() { |
| DLOG(WARNING) << "Document root element unable to provide offset dimensions!"; |
| // If the root element was unable to provide its dimensions as a result of |
| // the app being in a visibility state that disables layout, then prepare a |
| // pending resize event, so that the resize will occur once layouts are again |
| // available. |
| if (html_element_context_->application_lifecycle_state() |
| ->GetVisibilityState() != kVisibilityStateVisible) { |
| is_resize_event_pending_ = true; |
| } |
| } |
| |
| void Window::OnStartDispatchEvent(const scoped_refptr<dom::Event>& event) { |
| if (!on_start_dispatch_event_callback_.is_null()) { |
| on_start_dispatch_event_callback_.Run(event); |
| } |
| } |
| |
| void Window::OnStopDispatchEvent(const scoped_refptr<dom::Event>& event) { |
| if (!on_stop_dispatch_event_callback_.is_null()) { |
| on_stop_dispatch_event_callback_.Run(event); |
| } |
| } |
| |
| void Window::ClearPointerStateForShutdown() { |
| document_->pointer_state()->ClearForShutdown(); |
| } |
| |
| void Window::TraceMembers(script::Tracer* tracer) { |
| EventTarget::TraceMembers(tracer); |
| |
| #if defined(ENABLE_TEST_RUNNER) |
| tracer->Trace(test_runner_); |
| #endif // ENABLE_TEST_RUNNER |
| tracer->Trace(performance_); |
| tracer->Trace(document_); |
| tracer->Trace(history_); |
| tracer->Trace(navigator_); |
| tracer->Trace(console_); |
| tracer->Trace(camera_3d_); |
| tracer->Trace(crypto_); |
| tracer->Trace(speech_synthesis_); |
| tracer->Trace(local_storage_); |
| tracer->Trace(session_storage_); |
| tracer->Trace(screen_); |
| tracer->Trace(on_screen_keyboard_); |
| } |
| |
| const scoped_refptr<media_session::MediaSession> |
| Window::media_session() const { |
| return navigator_->media_session(); |
| } |
| |
| void Window::CacheSplashScreen(const std::string& content, |
| const base::Optional<std::string>& topic) { |
| if (splash_screen_cache_callback_.is_null()) { |
| return; |
| } |
| DLOG(INFO) << "Caching splash screen for URL " << location()->url(); |
| splash_screen_cache_callback_.Run(content, topic); |
| } |
| |
| const scoped_refptr<OnScreenKeyboard>& Window::on_screen_keyboard() const { |
| return on_screen_keyboard_; |
| } |
| |
| void Window::ReleaseOnScreenKeyboard() { on_screen_keyboard_ = nullptr; } |
| |
| Window::~Window() { |
| if (ui_nav_root_) { |
| ui_nav_root_->SetEnabled(false); |
| } |
| html_element_context_->application_lifecycle_state()->RemoveObserver(this); |
| } |
| |
| void Window::FireHashChangeEvent() { |
| PostToDispatchEventName(FROM_HERE, base::Tokens::hashchange()); |
| } |
| |
| } // namespace dom |
| } // namespace cobalt |