blob: e34da1002ea550aa628ed8994d94fffaf1a1a144 [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "android_webview/browser/renderer_host/aw_render_view_host_ext.h"
#include "android_webview/browser/aw_browser_context.h"
#include "android_webview/browser/aw_contents_client_bridge.h"
#include "base/android/scoped_java_ref.h"
#include "base/bind.h"
#include "base/callback.h"
#include "base/command_line.h"
#include "base/logging.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/navigation_handle.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/web_contents.h"
#include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
namespace android_webview {
namespace {
void ShouldOverrideUrlLoadingOnUI(
content::WebContents* web_contents,
const std::u16string& url,
bool has_user_gesture,
bool is_redirect,
bool is_main_frame,
mojom::FrameHost::ShouldOverrideUrlLoadingCallback callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
bool ignore_navigation = false;
AwContentsClientBridge* client =
AwContentsClientBridge::FromWebContents(web_contents);
if (client) {
if (!client->ShouldOverrideUrlLoading(url, has_user_gesture, is_redirect,
is_main_frame, &ignore_navigation)) {
// If the shouldOverrideUrlLoading call caused a java exception we should
// always return immediately here!
return;
}
} else {
LOG(WARNING) << "Failed to find the associated render view host for url: "
<< url;
}
std::move(callback).Run(ignore_navigation);
}
} // namespace
AwRenderViewHostExt::AwRenderViewHostExt(AwRenderViewHostExtClient* client,
content::WebContents* contents)
: content::WebContentsObserver(contents),
client_(client),
has_new_hit_test_data_(false),
frame_host_receivers_(contents,
this,
content::WebContentsFrameReceiverSetPassKey()) {
DCHECK(client_);
}
AwRenderViewHostExt::~AwRenderViewHostExt() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
}
void AwRenderViewHostExt::DocumentHasImages(DocumentHasImagesResult result) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!web_contents()->GetRenderViewHost()) {
std::move(result).Run(false);
return;
}
if (local_main_frame_remote_) {
local_main_frame_remote_->DocumentHasImage(std::move(result));
} else {
// Still have to respond to the API call WebView#docuemntHasImages.
// Otherwise the listener of the response may be starved.
std::move(result).Run(false);
}
}
bool AwRenderViewHostExt::HasNewHitTestData() const {
return has_new_hit_test_data_;
}
void AwRenderViewHostExt::MarkHitTestDataRead() {
has_new_hit_test_data_ = false;
}
void AwRenderViewHostExt::RequestNewHitTestDataAt(
const gfx::PointF& touch_center,
const gfx::SizeF& touch_area) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// We only need to get blink::WebView on the renderer side to invoke the
// blink hit test Mojo method, so sending this message via LocalMainFrame
// interface is enough.
if (local_main_frame_remote_)
local_main_frame_remote_->HitTest(touch_center, touch_area);
}
const mojom::HitTestData& AwRenderViewHostExt::GetLastHitTestData() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return *last_hit_test_data_;
}
void AwRenderViewHostExt::SetTextZoomFactor(float factor) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (local_main_frame_remote_)
local_main_frame_remote_->SetTextZoomFactor(factor);
}
void AwRenderViewHostExt::ResetScrollAndScaleState() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (local_main_frame_remote_)
local_main_frame_remote_->ResetScrollAndScaleState();
}
void AwRenderViewHostExt::SetInitialPageScale(double page_scale_factor) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (local_main_frame_remote_)
local_main_frame_remote_->SetInitialPageScale(page_scale_factor);
}
void AwRenderViewHostExt::SetWillSuppressErrorPage(bool suppress) {
will_suppress_error_page_ = suppress;
}
void AwRenderViewHostExt::SmoothScroll(int target_x,
int target_y,
base::TimeDelta duration) {
if (local_main_frame_remote_)
local_main_frame_remote_->SmoothScroll(target_x, target_y, duration);
}
void AwRenderViewHostExt::ResetLocalMainFrameRemote(
content::RenderFrameHost* frame_host) {
local_main_frame_remote_.reset();
frame_host->GetRemoteAssociatedInterfaces()->GetInterface(
local_main_frame_remote_.BindNewEndpointAndPassReceiver());
}
void AwRenderViewHostExt::RenderFrameCreated(
content::RenderFrameHost* frame_host) {
// Only handle the active main frame, neither speculative ones nor subframes.
if (frame_host != web_contents()->GetMainFrame())
return;
ResetLocalMainFrameRemote(frame_host);
}
void AwRenderViewHostExt::RenderFrameHostChanged(
content::RenderFrameHost* old_host,
content::RenderFrameHost* new_host) {
// Since we skipped speculative main frames in RenderFrameCreated, we must
// watch for them being swapped in by watching for RenderFrameHostChanged().
if (new_host != web_contents()->GetMainFrame())
return;
ResetLocalMainFrameRemote(new_host);
}
void AwRenderViewHostExt::DidStartNavigation(
content::NavigationHandle* navigation_handle) {
if (will_suppress_error_page_)
navigation_handle->SetSilentlyIgnoreErrors();
}
void AwRenderViewHostExt::DidFinishNavigation(
content::NavigationHandle* navigation_handle) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!navigation_handle->HasCommitted() ||
(!navigation_handle->IsInMainFrame() &&
!navigation_handle->HasSubframeNavigationEntryCommitted()))
return;
AwBrowserContext::FromWebContents(web_contents())
->AddVisitedURLs(navigation_handle->GetRedirectChain());
}
void AwRenderViewHostExt::OnPageScaleFactorChanged(float page_scale_factor) {
client_->OnWebLayoutPageScaleFactorChanged(page_scale_factor);
}
void AwRenderViewHostExt::UpdateHitTestData(
mojom::HitTestDataPtr hit_test_data) {
content::RenderFrameHost* main_frame_host =
frame_host_receivers_.GetCurrentTargetFrame();
while (main_frame_host->GetParent())
main_frame_host = main_frame_host->GetParent();
// Make sense from any frame of the current frame tree, because a focused
// node could be in either the mainframe or a subframe.
if (main_frame_host != web_contents()->GetMainFrame())
return;
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
last_hit_test_data_ = std::move(hit_test_data);
has_new_hit_test_data_ = true;
}
void AwRenderViewHostExt::ContentsSizeChanged(const gfx::Size& contents_size) {
content::RenderFrameHost* render_frame_host =
frame_host_receivers_.GetCurrentTargetFrame();
// Only makes sense coming from the main frame of the current frame tree.
if (render_frame_host != web_contents()->GetMainFrame())
return;
client_->OnWebLayoutContentsSizeChanged(contents_size);
}
void AwRenderViewHostExt::ShouldOverrideUrlLoading(
const std::u16string& url,
bool has_user_gesture,
bool is_redirect,
bool is_main_frame,
ShouldOverrideUrlLoadingCallback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
content::GetUIThreadTaskRunner({})->PostTask(
FROM_HERE, base::BindOnce(&ShouldOverrideUrlLoadingOnUI, web_contents(),
url, has_user_gesture, is_redirect,
is_main_frame, std::move(callback)));
}
} // namespace android_webview