| // Copyright 2023 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #import "ios/web/content/js_messaging/content_web_frame.h" |
| |
| #import "base/json/json_writer.h" |
| #import "base/strings/string_util.h" |
| #import "base/strings/stringprintf.h" |
| #import "base/strings/utf_string_conversions.h" |
| #import "content/public/browser/render_frame_host.h" |
| #import "ios/web/content/web_state/content_web_state.h" |
| |
| namespace web { |
| |
| namespace { |
| |
| void WebToContentJavaScriptCallbackAdapter( |
| base::OnceCallback<void(const base::Value*)> web_callback, |
| base::Value value) { |
| std::move(web_callback).Run(&value); |
| } |
| |
| void WebWithErrorToContentJavaScriptCallbackAdapter( |
| ExecuteJavaScriptCallbackWithError web_callback, |
| base::Value value) { |
| std::move(web_callback).Run(&value, /*error=*/nil); |
| } |
| |
| std::u16string CreateFunctionCallWithParameters( |
| const std::string& name, |
| const base::Value::List& parameters) { |
| std::vector<std::string> parameter_strings(parameters.size()); |
| for (size_t i = 0; i < parameters.size(); ++i) { |
| parameter_strings[i] = base::WriteJson(parameters[i]).value_or(""); |
| } |
| std::string joined_paramters = base::JoinString(parameter_strings, ","); |
| return base::UTF8ToUTF16(base::StringPrintf("__gCrWeb.%s(%s)", name.c_str(), |
| joined_paramters.c_str())); |
| } |
| |
| } // namespace |
| |
| ContentWebFrame::ContentWebFrame(const std::string& web_frame_id, |
| content::RenderFrameHost* render_frame_host, |
| ContentWebState* content_web_state) |
| : web_frame_id_(web_frame_id), |
| content_web_state_(content_web_state), |
| render_frame_host_(render_frame_host) { |
| content_web_state->AddObserver(this); |
| render_frame_host_->AllowInjectingJavaScript(); |
| } |
| |
| ContentWebFrame::~ContentWebFrame() { |
| DetachFromWebState(); |
| } |
| |
| WebFrameInternal* ContentWebFrame::GetWebFrameInternal() { |
| return this; |
| } |
| |
| std::string ContentWebFrame::GetFrameId() const { |
| return web_frame_id_; |
| } |
| |
| bool ContentWebFrame::IsMainFrame() const { |
| return render_frame_host_->IsInPrimaryMainFrame(); |
| } |
| |
| url::Origin ContentWebFrame::GetSecurityOrigin() const { |
| return render_frame_host_->GetLastCommittedOrigin(); |
| } |
| |
| GURL ContentWebFrame::GetUrl() const { |
| return render_frame_host_->GetLastCommittedURL(); |
| } |
| |
| BrowserState* ContentWebFrame::GetBrowserState() { |
| return content_web_state_->GetBrowserState(); |
| ; |
| } |
| |
| base::WeakPtr<WebFrame> ContentWebFrame::AsWeakPtr() { |
| return weak_ptr_factory_.GetWeakPtr(); |
| } |
| |
| bool ContentWebFrame::CallJavaScriptFunction( |
| const std::string& name, |
| const base::Value::List& parameters) { |
| return ExecuteJavaScript(CreateFunctionCallWithParameters(name, parameters)); |
| } |
| |
| bool ContentWebFrame::CallJavaScriptFunction( |
| const std::string& name, |
| const base::Value::List& parameters, |
| base::OnceCallback<void(const base::Value*)> callback, |
| base::TimeDelta timeout) { |
| // TODO(crbug.com/40260088): Handle timeouts. |
| return ExecuteJavaScript(CreateFunctionCallWithParameters(name, parameters), |
| std::move(callback)); |
| } |
| |
| bool ContentWebFrame::CallJavaScriptFunctionInContentWorld( |
| const std::string& name, |
| const base::Value::List& parameters, |
| JavaScriptContentWorld* content_world) { |
| // TODO(crbug.com/40260088): Handle injecting into an isolated world. |
| return ExecuteJavaScript(CreateFunctionCallWithParameters(name, parameters)); |
| } |
| |
| bool ContentWebFrame::CallJavaScriptFunctionInContentWorld( |
| const std::string& name, |
| const base::Value::List& parameters, |
| JavaScriptContentWorld* content_world, |
| base::OnceCallback<void(const base::Value*)> callback, |
| base::TimeDelta timeout) { |
| // TODO(crbug.com/40260088): Handle timeouts and injecting into an isolated |
| // world. |
| return ExecuteJavaScript(CreateFunctionCallWithParameters(name, parameters), |
| std::move(callback)); |
| } |
| |
| bool ContentWebFrame::ExecuteJavaScriptInContentWorld( |
| const std::u16string& script, |
| JavaScriptContentWorld* content_world, |
| ExecuteJavaScriptCallbackWithError callback) { |
| render_frame_host_->ExecuteJavaScript( |
| script, base::BindOnce(&WebWithErrorToContentJavaScriptCallbackAdapter, |
| std::move(callback))); |
| return true; |
| } |
| |
| bool ContentWebFrame::ExecuteJavaScript(const std::u16string& script) { |
| render_frame_host_->ExecuteJavaScript( |
| script, content::RenderFrameHost::JavaScriptResultCallback()); |
| return true; |
| } |
| |
| bool ContentWebFrame::ExecuteJavaScript( |
| const std::u16string& script, |
| base::OnceCallback<void(const base::Value*)> callback) { |
| render_frame_host_->ExecuteJavaScript( |
| script, base::BindOnce(&WebToContentJavaScriptCallbackAdapter, |
| std::move(callback))); |
| return true; |
| } |
| |
| bool ContentWebFrame::ExecuteJavaScript( |
| const std::u16string& script, |
| ExecuteJavaScriptCallbackWithError callback) { |
| render_frame_host_->ExecuteJavaScript( |
| script, base::BindOnce(&WebWithErrorToContentJavaScriptCallbackAdapter, |
| std::move(callback))); |
| return true; |
| } |
| |
| void ContentWebFrame::DetachFromWebState() { |
| if (content_web_state_) { |
| content_web_state_->RemoveObserver(this); |
| content_web_state_ = nullptr; |
| } |
| } |
| |
| void ContentWebFrame::WebStateDestroyed(web::WebState* web_state) { |
| DetachFromWebState(); |
| } |
| |
| } // namespace web |