blob: a5fd30cc983f2c49ca6f3f848e0ae2bd60c4b34f [file] [log] [blame]
// Copyright 2015 Google Inc. 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.
#ifndef COBALT_BROWSER_WEB_MODULE_H_
#define COBALT_BROWSER_WEB_MODULE_H_
#include <string>
#include <vector>
#include "base/callback.h"
#include "base/file_path.h"
#include "base/hash_tables.h"
#include "base/message_loop.h"
#include "base/synchronization/waitable_event.h"
#include "base/threading/thread.h"
#include "base/threading/thread_checker.h"
#include "cobalt/accessibility/tts_engine.h"
#include "cobalt/base/address_sanitizer.h"
#include "cobalt/base/console_commands.h"
#include "cobalt/base/source_location.h"
#include "cobalt/browser/lifecycle_observer.h"
#include "cobalt/browser/screen_shot_writer.h"
#include "cobalt/browser/splash_screen_cache.h"
#include "cobalt/css_parser/parser.h"
#if defined(ENABLE_DEBUG_CONSOLE)
#include "cobalt/debug/debug_server.h"
#include "cobalt/debug/render_overlay.h"
#endif // ENABLE_DEBUG_CONSOLE
#include "cobalt/dom/blob.h"
#include "cobalt/dom/csp_delegate.h"
#include "cobalt/dom/dom_settings.h"
#include "cobalt/dom/input_event_init.h"
#include "cobalt/dom/keyboard_event_init.h"
#include "cobalt/dom/local_storage_database.h"
#include "cobalt/dom/media_source.h"
#include "cobalt/dom/on_screen_keyboard_bridge.h"
#include "cobalt/dom/pointer_event_init.h"
#include "cobalt/dom/screenshot_manager.h"
#include "cobalt/dom/wheel_event_init.h"
#include "cobalt/dom/window.h"
#include "cobalt/dom_parser/parser.h"
#include "cobalt/layout/layout_manager.h"
#include "cobalt/loader/fetcher_factory.h"
#include "cobalt/math/size.h"
#include "cobalt/media/can_play_type_handler.h"
#include "cobalt/media/web_media_player_factory.h"
#include "cobalt/network/network_module.h"
#include "cobalt/render_tree/node.h"
#include "cobalt/render_tree/resource_provider.h"
#include "cobalt/script/global_environment.h"
#include "cobalt/script/javascript_engine.h"
#include "cobalt/script/script_runner.h"
#include "cobalt/webdriver/session_driver.h"
#include "googleurl/src/gurl.h"
namespace cobalt {
namespace browser {
// WebModule hosts all components of Cobalt that deal with or implement the
// WebAPI. This includes the ability to fetch resources given a URL, parse
// various web formats like HTML and CSS, host a DOM tree, manage a JavaScript
// engine, and lay out a web page. Ultimately, interaction with WebModule is
// done through calls to InjectEvent() such as when dealing with external input
// (e.g. keyboards and gamepads), and handling render tree output from WebModule
// when it calls the on_render_tree_produced_ callback (provided upon
// construction).
// At creation, the WebModule starts a dedicated thread, on which a private
// implementation object is construted that manages all internal components.
// All methods of the WebModule post tasks to the implementation object on that
// thread, so all internal functions are executed synchronously with respect to
// each other.
// This necessarily implies that details contained within WebModule, such as the
// DOM, are intentionally kept private, since these structures expect to be
// accessed from only one thread.
class WebModule : public LifecycleObserver {
public:
struct Options {
typedef base::Callback<scoped_refptr<script::Wrappable>(
const scoped_refptr<dom::Window>& window,
dom::MutationObserverTaskManager* mutation_observer_task_manager,
script::GlobalEnvironment* global_environment)>
CreateObjectFunction;
typedef base::hash_map<std::string, CreateObjectFunction>
InjectedWindowAttributes;
// All optional parameters defined in this structure should have their
// values initialized in the default constructor to useful defaults.
Options();
// The name of the WebModule. This is useful for debugging purposes as in
// the case where multiple WebModule objects exist, it can be used to
// differentiate which objects belong to which WebModule. It is used
// to name some CVals.
std::string name;
// The LayoutTrigger parameter dictates when a layout should be triggered.
// Tests will often set this up so that layouts are only performed when
// we specifically request them to be.
layout::LayoutManager::LayoutTrigger layout_trigger;
// Optional directory to add to the search path for web files (file://).
FilePath extra_web_file_dir;
// The navigation_callback functor will be called when JavaScript internal
// to the WebModule requests a page navigation, e.g. by modifying
// 'window.location.href'.
base::Callback<void(const GURL&)> navigation_callback;
// A list of callbacks to be called once the web page finishes loading.
std::vector<base::Closure> loaded_callbacks;
// injected_window_attributes contains a map of attributes to be injected
// into the WebModule's window object upon construction. This provides
// a mechanism to inject custom APIs into the WebModule object.
InjectedWindowAttributes injected_window_attributes;
// Options to customize DOMSettings.
dom::DOMSettings::Options dom_settings_options;
// Whether Cobalt is forbidden to render without receiving CSP headers.
csp::CSPHeaderPolicy require_csp;
// Image cache capacity in bytes.
int image_cache_capacity;
// Typeface cache capacity in bytes.
int remote_typeface_cache_capacity;
// Mesh cache capacity in bytes.
int mesh_cache_capacity;
// Whether map-to-mesh for rectangular videos is enabled.
bool enable_map_to_mesh_rectangular;
// Content Security Policy enforcement mode for this web module.
dom::CspEnforcementType csp_enforcement_mode;
// Token obtained from CSP to allow creation of insecure delegates.
int csp_insecure_allowed_token;
// Whether or not the web module's stat tracker should track event stats.
bool track_event_stats;
// If set to something other than 1.0f, when a video starts to play, the
// image cache will be flushed and temporarily multiplied by this value (
// must be less than or equal to 1.0f) until the video ends. This can
// help for platforms that are low on image memory while playing a video.
float image_cache_capacity_multiplier_when_playing_video;
// Specifies the priority of the web module's thread. This is the thread
// that is responsible for executing JavaScript, managing the DOM, and
// performing layouts. The default value is base::kThreadPriority_Normal.
base::ThreadPriority thread_priority;
// Specifies the priority that the web module's corresponding loader thread
// will be assigned. This is the thread responsible for performing resource
// decoding, such as image decoding. The default value is
// base::kThreadPriority_Low.
base::ThreadPriority loader_thread_priority;
// Specifies the priority tha the web module's animated image decoding
// thread will be assigned. This thread is responsible for decoding,
// blending and constructing individual frames from animated images. The
// default value is base::kThreadPriority_Low.
base::ThreadPriority animated_image_decode_thread_priority;
// To support 3D camera movements.
scoped_refptr<input::Camera3D> camera_3d;
script::JavaScriptEngine::Options javascript_engine_options;
// The video playback rate will be multiplied with the following value. Its
// default value is 1.0.
float video_playback_rate_multiplier;
// Allows image animations to be enabled/disabled. Its default value
// is true to enable them.
bool enable_image_animations;
// Whether or not to retain the remote typeface cache when the app enters
// the suspend state.
bool should_retain_remote_typeface_cache_on_suspend;
// The language and script to use with fonts. If left empty, then the
// language-script combination provided by base::GetSystemLanguageScript()
// is used.
std::string font_language_script_override;
// The splash screen cache object, owned by the BrowserModule.
SplashScreenCache* splash_screen_cache;
// The beforeunload event can give a web page a chance to shut
// itself down softly and ultimately call window.close(), however
// if it is not handled by the web application, we indicate this
// situation externally by calling this callback, so that if the
// beforeunload event was generated it can be known that there is
// no window.close() call pending.
base::Closure on_before_unload_fired_but_not_handled;
// Whether or not the WebModule is allowed to fetch from cache via
// h5vcc-cache://.
bool can_fetch_cache;
// The dom::OnScreenKeyboard forwards calls to this interface.
dom::OnScreenKeyboardBridge* on_screen_keyboard_bridge = NULL;
// This function takes in a render tree as input, and then calls the 2nd
// argument (which is another callback) when the screenshot is available.
// The callback's first parameter points to an unencoded image, where the
// format is R8G8B8A8 pixels (with no padding at the end of each row),
// and the second parameter is the dimensions of the image.
// Note that the callback could be called on a different thread, and is not
// guaranteed to be called on the caller thread.
// By using Callbacks here, it is easier to write tests, and use this
// functionality in Cobalt.
dom::ScreenshotManager::ProvideScreenshotFunctionCallback
provide_screenshot_function;
};
typedef layout::LayoutManager::LayoutResults LayoutResults;
typedef base::Callback<void(const LayoutResults&)>
OnRenderTreeProducedCallback;
typedef base::Callback<void(const GURL&, const std::string&)> OnErrorCallback;
typedef dom::Window::CloseCallback CloseCallback;
typedef base::Callback<void(const script::HeapStatistics&)>
JavaScriptHeapStatisticsCallback;
WebModule(const GURL& initial_url,
base::ApplicationState initial_application_state,
const OnRenderTreeProducedCallback& render_tree_produced_callback,
const OnErrorCallback& error_callback,
const CloseCallback& window_close_callback,
const base::Closure& window_minimize_callback,
media::CanPlayTypeHandler* can_play_type_handler,
media::WebMediaPlayerFactory* web_media_player_factory,
network::NetworkModule* network_module,
const math::Size& window_dimensions, float video_pixel_ratio,
render_tree::ResourceProvider* resource_provider,
float layout_refresh_rate, const Options& options);
~WebModule();
#if SB_HAS(ON_SCREEN_KEYBOARD)
// Injects an on screen keyboard input event into the web module. The value
// for type represents beforeinput or input.
void InjectOnScreenKeyboardInputEvent(base::Token type,
const dom::InputEventInit& event);
// Injects an on screen keyboard shown event into the web module.
void InjectOnScreenKeyboardShownEvent(int ticket);
// Injects an on screen keyboard hidden event into the web module.
void InjectOnScreenKeyboardHiddenEvent(int ticket);
// Injects an on screen keyboard focused event into the web module.
void InjectOnScreenKeyboardFocusedEvent(int ticket);
// Injects an on screen keyboard blurred event into the web module.
void InjectOnScreenKeyboardBlurredEvent(int ticket);
#endif // SB_HAS(ON_SCREEN_KEYBOARD)
// Injects a keyboard event into the web module. The value for type
// represents the event name, for example 'keydown' or 'keyup'.
void InjectKeyboardEvent(base::Token type,
const dom::KeyboardEventInit& event);
// Injects a pointer event into the web module. The value for type represents
// the event name, for example 'pointerdown', 'pointerup', or 'pointermove'.
void InjectPointerEvent(base::Token type, const dom::PointerEventInit& event);
// Injects a wheel event into the web module. The value for type represents
// the event name, for example 'wheel'.
void InjectWheelEvent(base::Token type, const dom::WheelEventInit& event);
// Injects a beforeunload event into the web module. If this event is not
// handled by the web application, |on_before_unload_fired_but_not_handled_|
// will be called.
void InjectBeforeUnloadEvent();
void InjectCaptionSettingsChangedEvent();
// Executes Javascript code in this web module. The calling thread will
// block until the JavaScript has executed and the output results are
// available.
std::string ExecuteJavascript(const std::string& script_utf8,
const base::SourceLocation& script_location,
bool* out_succeeded);
#if defined(ENABLE_WEBDRIVER)
// Creates a new webdriver::WindowDriver that interacts with the Window that
// is owned by this WebModule instance.
scoped_ptr<webdriver::WindowDriver> CreateWindowDriver(
const webdriver::protocol::WindowId& window_id);
#endif
#if defined(ENABLE_DEBUG_CONSOLE)
// Gets a reference to the debug server that interacts with this web module.
// The debug server is part of the debug server module owned by this web
// module, which is lazily created by this function if necessary.
debug::DebugServer* GetDebugServer();
#endif // ENABLE_DEBUG_CONSOLE
// Sets the size and pixel ratio of this web module, possibly causing relayout
// and re-render with the new parameters. Does nothing if the parameters are
// not different from the current parameters.
void SetSize(const math::Size& window_dimensions, float video_pixel_ratio);
void SetCamera3D(const scoped_refptr<input::Camera3D>& camera_3d);
void SetWebMediaPlayerFactory(
media::WebMediaPlayerFactory* web_media_player_factory);
void SetImageCacheCapacity(int64_t bytes);
void SetRemoteTypefaceCacheCapacity(int64_t bytes);
// LifecycleObserver implementation
void Prestart() override;
void Start(render_tree::ResourceProvider* resource_provider) override;
void Pause() override;
void Unpause() override;
void Suspend() override;
void Resume(render_tree::ResourceProvider* resource_provider) override;
// Attempt to reduce overall memory consumption. Called in response to a
// system indication that memory usage is nearing a critical level.
void ReduceMemory();
// Post a task that gets the current |script::HeapStatistics| for our
// |JavaScriptEngine| to the web module thread, and then passes that to
// |callback|. Note that |callback| will be called on the main web module
// thread. It is the responsibility of |callback| to get back to its
// intended thread should it want to.
void RequestJavaScriptHeapStatistics(
const JavaScriptHeapStatisticsCallback& callback);
private:
// Data required to construct a WebModule, initialized in the constructor and
// passed to |Initialize|.
struct ConstructionData {
ConstructionData(
const GURL& initial_url,
base::ApplicationState initial_application_state,
const OnRenderTreeProducedCallback& render_tree_produced_callback,
const OnErrorCallback& error_callback,
const CloseCallback& window_close_callback,
const base::Closure& window_minimize_callback,
media::CanPlayTypeHandler* can_play_type_handler,
media::WebMediaPlayerFactory* web_media_player_factory,
network::NetworkModule* network_module,
const math::Size& window_dimensions, float video_pixel_ratio,
render_tree::ResourceProvider* resource_provider,
int dom_max_element_depth, float layout_refresh_rate,
const Options& options)
: initial_url(initial_url),
initial_application_state(initial_application_state),
render_tree_produced_callback(render_tree_produced_callback),
error_callback(error_callback),
window_close_callback(window_close_callback),
window_minimize_callback(window_minimize_callback),
can_play_type_handler(can_play_type_handler),
web_media_player_factory(web_media_player_factory),
network_module(network_module),
window_dimensions(window_dimensions),
video_pixel_ratio(video_pixel_ratio),
resource_provider(resource_provider),
dom_max_element_depth(dom_max_element_depth),
layout_refresh_rate(layout_refresh_rate),
options(options) {}
GURL initial_url;
base::ApplicationState initial_application_state;
OnRenderTreeProducedCallback render_tree_produced_callback;
OnErrorCallback error_callback;
const CloseCallback& window_close_callback;
const base::Closure& window_minimize_callback;
media::CanPlayTypeHandler* can_play_type_handler;
media::WebMediaPlayerFactory* web_media_player_factory;
network::NetworkModule* network_module;
math::Size window_dimensions;
float video_pixel_ratio;
render_tree::ResourceProvider* resource_provider;
int dom_max_element_depth;
float layout_refresh_rate;
Options options;
};
// Forward declaration of the private implementation class.
class Impl;
// Destruction observer used to safely tear down this WebModule after the
// thread has been stopped.
class DestructionObserver : public MessageLoop::DestructionObserver {
public:
explicit DestructionObserver(WebModule* web_module);
void WillDestroyCurrentMessageLoop() override;
private:
WebModule* web_module_;
};
// Called by the constructor to create the private implementation object and
// perform any other initialization required on the dedicated thread.
void Initialize(const ConstructionData& data);
void ClearAllIntervalsAndTimeouts();
void CancelSynchronousLoads();
#if defined(ENABLE_PARTIAL_LAYOUT_CONTROL)
void OnPartialLayoutConsoleCommandReceived(const std::string& message);
#endif // defined(ENABLE_PARTIAL_LAYOUT_CONTROL)
// The message loop this object is running on.
MessageLoop* message_loop() const { return thread_.message_loop(); }
// Private implementation object.
scoped_ptr<Impl> impl_;
// The thread created and owned by this WebModule.
// All sub-objects of this object are created on this thread, and all public
// member functions are re-posted to this thread if necessary.
base::Thread thread_;
#if defined(ENABLE_PARTIAL_LAYOUT_CONTROL)
// Handles the 'partial_layout' command.
scoped_ptr<base::ConsoleCommandManager::CommandHandler>
partial_layout_command_handler_;
#endif // defined(ENABLE_PARTIAL_LAYOUT_CONTROL)
};
} // namespace browser
} // namespace cobalt
#endif // COBALT_BROWSER_WEB_MODULE_H_