diff --git a/cobalt/BUILD.gn b/cobalt/BUILD.gn index f80c773450d8..f7f22b9ae134 100644 --- a/cobalt/BUILD.gn +++ b/cobalt/BUILD.gn @@ -49,10 +49,12 @@ if (!is_android) { defines = [] deps = [ + ":embed_polyfilled_javascript", "//cobalt/renderer:renderer", "//cobalt/services/crash_annotator", "//cobalt/services/crash_annotator/public/mojom", "//cobalt/user_agent", + "//components/js_injection/browser:browser", "//content/public/app", "//content/shell:content_shell_app", "//content/shell:content_shell_lib", @@ -84,6 +86,23 @@ action("cobalt_build_info") { ] } +config("embed_polyfilled_javascript_config") { + include_dirs = [ root_gen_dir ] +} + +# TODO(b/390710539): migrate to GRIT +action("embed_polyfilled_javascript") { + script = "//cobalt/build/generate_data_header.py" + outputs = [ "$target_gen_dir/embedded_resources/embedded_js.h" ] + public_configs = [ ":embed_polyfilled_javascript_config" ] + + args = [ + "CobaltJavaScriptPolyfill", + rebase_path(outputs[0], root_build_dir), + rebase_path("embedded_resources", root_build_dir), + ] +} + if (is_android) { test("cobalt_unittests") { testonly = true diff --git a/cobalt/android/BUILD.gn b/cobalt/android/BUILD.gn index ab62facee1d2..ac08d7c88e89 100644 --- a/cobalt/android/BUILD.gn +++ b/cobalt/android/BUILD.gn @@ -241,6 +241,7 @@ shared_library("libcobalt_content_shell_content_view") { testonly = true deps = [ ":content_shell_jni_headers", + "//cobalt:embed_polyfilled_javascript", "//cobalt/renderer:renderer", "//cobalt/services/crash_annotator", "//cobalt/services/crash_annotator/public/mojom", @@ -248,6 +249,7 @@ shared_library("libcobalt_content_shell_content_view") { # TODO: what can be removed in the dependencies? "//components/crash/content/browser", + "//components/js_injection/browser:browser", "//content/shell:content_shell_app", "//content/shell:content_shell_lib", "//content/shell:pak", diff --git a/cobalt/android/apk/app/src/kabuki_polyfill/amati_device_inspector.js b/cobalt/android/apk/app/src/kabuki_polyfill/amati_device_inspector.js deleted file mode 100644 index 55c97fb478d3..000000000000 --- a/cobalt/android/apk/app/src/kabuki_polyfill/amati_device_inspector.js +++ /dev/null @@ -1,6 +0,0 @@ -/** - * @license - * Copyright The Cobalt Authors. - * SPDX-License-Identifier: Apache-2.0 - */ -Android_AmatiDeviceInspector.printIsAmatiDevice(); diff --git a/cobalt/android/apk/app/src/kabuki_polyfill/chrobalt_preload.js b/cobalt/android/apk/app/src/kabuki_polyfill/chrobalt_preload.js deleted file mode 100644 index 6d529d14d28a..000000000000 --- a/cobalt/android/apk/app/src/kabuki_polyfill/chrobalt_preload.js +++ /dev/null @@ -1,7 +0,0 @@ -import { initializeH5vccPlatformService } from './h5vcc_platform_service.js'; -import { initializeHTMLMediaElement } from './html_media_element_extension.js'; - -export function chrobaltPreload() { - initializeH5vccPlatformService(); - initializeHTMLMediaElement(); -} diff --git a/cobalt/android/apk/app/src/kabuki_polyfill/html_media_element_extension.js b/cobalt/android/apk/app/src/kabuki_polyfill/html_media_element_extension.js deleted file mode 100644 index 2a1aef3dfe46..000000000000 --- a/cobalt/android/apk/app/src/kabuki_polyfill/html_media_element_extension.js +++ /dev/null @@ -1,11 +0,0 @@ -/** - * @license - * Copyright The Cobalt Authors. - * SPDX-License-Identifier: Apache-2.0 - */ - -export function initializeHTMLMediaElement() { - if (typeof HTMLMediaElementExtension !== 'undefined') { - HTMLMediaElement.prototype.canPlayType = HTMLMediaElementExtension.canPlayType; - } -} diff --git a/cobalt/base/generated_resources_types.h b/cobalt/base/generated_resources_types.h index 9b807e5fc650..a3708bd3540d 100644 --- a/cobalt/base/generated_resources_types.h +++ b/cobalt/base/generated_resources_types.h @@ -17,16 +17,16 @@ #include -#include "base/containers/hash_tables.h" +#include struct FileContents { FileContents() {} - FileContents(const unsigned char *data, int size) : data(data), size(size) {} + FileContents(const unsigned char* data, int size) : data(data), size(size) {} - const unsigned char *data; + const unsigned char* data; int size; }; -typedef base::hash_map GeneratedResourceMap; +typedef std::map GeneratedResourceMap; #endif // COBALT_BASE_GENERATED_RESOURCES_TYPES_H_ diff --git a/cobalt/cobalt_content_browser_client.h b/cobalt/cobalt_content_browser_client.h index 12d3ba624302..2fcfcc6d7c4a 100644 --- a/cobalt/cobalt_content_browser_client.h +++ b/cobalt/cobalt_content_browser_client.h @@ -42,7 +42,7 @@ class CobaltContentBrowserClient : public content::ShellContentBrowserClient { blink::UserAgentMetadata GetUserAgentMetadata() override; void OverrideWebkitPrefs(content::WebContents* web_contents, blink::web_pref::WebPreferences* prefs) override; - void OnWebContentsCreated(content::WebContents* web_contents); + void OnWebContentsCreated(content::WebContents* web_contents) override; void RegisterBrowserInterfaceBindersForFrame( content::RenderFrameHost* render_frame_host, mojo::BinderMapWithContext* binder_map) diff --git a/cobalt/cobalt_web_contents_observer.cc b/cobalt/cobalt_web_contents_observer.cc index e7b18bf0fab6..ca24f044d39e 100644 --- a/cobalt/cobalt_web_contents_observer.cc +++ b/cobalt/cobalt_web_contents_observer.cc @@ -13,9 +13,45 @@ // limitations under the License. #include "cobalt/cobalt_web_contents_observer.h" +#include "base/strings/utf_string_conversions.h" +#include "cobalt/embedded_resources/embedded_js.h" namespace cobalt { +CobaltWebContentsObserver::CobaltWebContentsObserver( + content::WebContents* web_contents) + : content::WebContentsObserver(web_contents) { + // Create browser-side mojo service component + js_communication_host_ = + std::make_unique(web_contents); + + RegisterInjectedJavaScript(); +} + +void CobaltWebContentsObserver::RegisterInjectedJavaScript() { + // Get the embedded header resource + GeneratedResourceMap resource_map; + CobaltJavaScriptPolyfill::GenerateMap(resource_map); + + for (const auto& [file_name, file_contents] : resource_map) { + LOG(INFO) << "JS injection for filename: " << file_name; + std::string js(reinterpret_cast(file_contents.data), + file_contents.size); + + // Inject a script at document start for all origins + const std::u16string script(base::UTF8ToUTF16(js)); + const std::vector allowed_origins({"*"}); + auto result = js_communication_host_->AddDocumentStartJavaScript( + script, allowed_origins); + + if (result.error_message.has_value()) { + // error_message contains a value + LOG(WARNING) << "Failed to register JS injection for:" << file_name + << ", error message: " << result.error_message.value(); + } + } +} + // Placeholder for a WebContentsObserver override void CobaltWebContentsObserver::PrimaryMainDocumentElementAvailable() { LOG(INFO) << "Cobalt::PrimaryMainDocumentElementAvailable"; diff --git a/cobalt/cobalt_web_contents_observer.h b/cobalt/cobalt_web_contents_observer.h index 82f34a4d627c..d9d9cd08f3ea 100644 --- a/cobalt/cobalt_web_contents_observer.h +++ b/cobalt/cobalt_web_contents_observer.h @@ -18,14 +18,20 @@ #include "content/public/browser/web_contents_observer.h" #include "content/shell/browser/shell_content_browser_client.h" +#include "components/js_injection/browser/js_communication_host.h" + namespace cobalt { class CobaltWebContentsObserver : public content::WebContentsObserver { public: - explicit CobaltWebContentsObserver(content::WebContents* web_contents) - : content::WebContentsObserver(web_contents) {} + explicit CobaltWebContentsObserver(content::WebContents* web_contents); void PrimaryMainDocumentElementAvailable() override; + + private: + void RegisterInjectedJavaScript(); + + std::unique_ptr js_communication_host_; }; } // namespace cobalt diff --git a/cobalt/android/apk/app/src/kabuki_polyfill/h5vcc_platform_service.js b/cobalt/embedded_resources/h5vcc_platform_service_on_java_bridge.js similarity index 97% rename from cobalt/android/apk/app/src/kabuki_polyfill/h5vcc_platform_service.js rename to cobalt/embedded_resources/h5vcc_platform_service_on_java_bridge.js index b8ba198a423e..f8f7697ff637 100644 --- a/cobalt/android/apk/app/src/kabuki_polyfill/h5vcc_platform_service.js +++ b/cobalt/embedded_resources/h5vcc_platform_service_on_java_bridge.js @@ -39,7 +39,7 @@ class PlatformServiceClient { } } -export function initializeH5vccPlatformService() { +function initializeH5vccPlatformService() { if (typeof Android_H5vccPlatformService === 'undefined') { return; } @@ -72,3 +72,5 @@ export function initializeH5vccPlatformService() { }, } } + +initializeH5vccPlatformService(); diff --git a/cobalt/embedded_resources/html_media_element_extension_on_java_bridge.js b/cobalt/embedded_resources/html_media_element_extension_on_java_bridge.js new file mode 100644 index 000000000000..200360e0ac3a --- /dev/null +++ b/cobalt/embedded_resources/html_media_element_extension_on_java_bridge.js @@ -0,0 +1,8 @@ +/** + * @license + * Copyright The Cobalt Authors. + * SPDX-License-Identifier: Apache-2.0 + */ +if (typeof HTMLMediaElementExtension !== 'undefined') { + HTMLMediaElement.prototype.canPlayType = HTMLMediaElementExtension.canPlayType; +} diff --git a/cobalt/renderer/BUILD.gn b/cobalt/renderer/BUILD.gn index 4e32e33d7c65..76e29c6174e5 100644 --- a/cobalt/renderer/BUILD.gn +++ b/cobalt/renderer/BUILD.gn @@ -21,6 +21,7 @@ source_set("renderer") { deps = [ "//cobalt/media/audio:webaudio", "//components/cdm/renderer", + "//components/js_injection/renderer:renderer", "//components/network_hints/renderer", "//components/web_cache/renderer", "//content/public/common", diff --git a/cobalt/renderer/cobalt_content_renderer_client.cc b/cobalt/renderer/cobalt_content_renderer_client.cc index 13485a2b9513..8a2a27a37bf6 100644 --- a/cobalt/renderer/cobalt_content_renderer_client.cc +++ b/cobalt/renderer/cobalt_content_renderer_client.cc @@ -105,7 +105,9 @@ void CobaltContentRendererClient::ExposeInterfacesToBrowser( } void CobaltContentRendererClient::RenderFrameCreated( - content::RenderFrame* render_frame) {} + content::RenderFrame* render_frame) { + new js_injection::JsCommunication(render_frame); +} void CobaltContentRendererClient::PrepareErrorPage( content::RenderFrame* render_frame, @@ -285,6 +287,13 @@ bool CobaltContentRendererClient::IsSupportedVideoType( } #endif // BUILDFLAG(USE_STARBOARD_MEDIA) +void CobaltContentRendererClient::RunScriptsAtDocumentStart( + content::RenderFrame* render_frame) { + js_injection::JsCommunication* communication = + js_injection::JsCommunication::Get(render_frame); + communication->RunScriptsAtDocumentStart(); +} + std::unique_ptr CobaltContentRendererClient::CreatePrescientNetworking( content::RenderFrame* render_frame) { diff --git a/cobalt/renderer/cobalt_content_renderer_client.h b/cobalt/renderer/cobalt_content_renderer_client.h index eb319c8294d2..d9e39bdd3ec0 100644 --- a/cobalt/renderer/cobalt_content_renderer_client.h +++ b/cobalt/renderer/cobalt_content_renderer_client.h @@ -10,6 +10,7 @@ #include "build/build_config.h" #include "cobalt/media/audio/cobalt_audio_device_factory.h" +#include "components/js_injection/renderer/js_communication.h" #include "content/public/common/alternative_error_page_override_info.mojom-forward.h" #include "content/public/renderer/content_renderer_client.h" #include "media/mojo/buildflags.h" @@ -65,6 +66,9 @@ class CobaltContentRendererClient : public content::ContentRendererClient { bool IsSupportedVideoType(const media::VideoType& type) override; #endif // BUILDFLAG(USE_STARBOARD_MEDIA) + // JS Injection hook + void RunScriptsAtDocumentStart(content::RenderFrame* render_frame) override; + std::unique_ptr CreatePrescientNetworking( content::RenderFrame* render_frame) override;