blob: f5351012ea931b73760056be353a3d64a50fad76 [file] [log] [blame]
// Copyright 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 "content/browser/android/content_view_core_impl.h"
#include <stddef.h>
#include "base/android/jni_android.h"
#include "base/android/jni_array.h"
#include "base/android/jni_string.h"
#include "base/android/scoped_java_ref.h"
#include "base/command_line.h"
#include "base/logging.h"
#include "base/macros.h"
#include "base/metrics/histogram.h"
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
#include "cc/layers/layer.h"
#include "cc/layers/solid_color_layer.h"
#include "cc/output/begin_frame_args.h"
#include "cc/output/viewport_selection_bound.h"
#include "content/browser/accessibility/browser_accessibility_state_impl.h"
#include "content/browser/android/gesture_event_type.h"
#include "content/browser/android/interstitial_page_delegate_android.h"
#include "content/browser/android/java/gin_java_bridge_dispatcher_host.h"
#include "content/browser/android/load_url_params.h"
#include "content/browser/frame_host/interstitial_page_impl.h"
#include "content/browser/geolocation/geolocation_service_context.h"
#include "content/browser/media/media_web_contents_observer.h"
#include "content/browser/renderer_host/compositor_impl_android.h"
#include "content/browser/renderer_host/input/web_input_event_builders_android.h"
#include "content/browser/renderer_host/input/web_input_event_util.h"
#include "content/browser/renderer_host/render_view_host_impl.h"
#include "content/browser/renderer_host/render_widget_host_impl.h"
#include "content/browser/renderer_host/render_widget_host_view_android.h"
#include "content/browser/web_contents/web_contents_view_android.h"
#include "content/common/frame_messages.h"
#include "content/common/input/web_input_event_traits.h"
#include "content/common/input_messages.h"
#include "content/common/view_messages.h"
#include "content/public/browser/android/compositor.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/favicon_status.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/screen_orientation_dispatcher_host.h"
#include "content/public/browser/ssl_host_state_delegate.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/content_client.h"
#include "content/public/common/content_switches.h"
#include "content/public/common/menu_item.h"
#include "content/public/common/user_agent.h"
#include "jni/ContentViewCore_jni.h"
#include "third_party/WebKit/public/web/WebInputEvent.h"
#include "ui/android/view_android.h"
#include "ui/android/window_android.h"
#include "ui/events/android/motion_event_android.h"
#include "ui/events/blink/blink_event_util.h"
#include "ui/gfx/android/java_bitmap.h"
#include "ui/gfx/geometry/point_conversions.h"
#include "ui/gfx/geometry/size_conversions.h"
#include "ui/gfx/geometry/size_f.h"
using base::android::AttachCurrentThread;
using base::android::ConvertJavaStringToUTF16;
using base::android::ConvertJavaStringToUTF8;
using base::android::ConvertUTF16ToJavaString;
using base::android::ConvertUTF8ToJavaString;
using base::android::ScopedJavaLocalRef;
using blink::WebGestureEvent;
using blink::WebInputEvent;
namespace content {
namespace {
// Describes the type and enabled state of a select popup item.
//
// A Java counterpart will be generated for this enum.
// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.content.browser.input
enum PopupItemType {
// Popup item is of type group
POPUP_ITEM_TYPE_GROUP,
// Popup item is disabled
POPUP_ITEM_TYPE_DISABLED,
// Popup item is enabled
POPUP_ITEM_TYPE_ENABLED,
};
const void* const kContentViewUserDataKey = &kContentViewUserDataKey;
int GetRenderProcessIdFromRenderViewHost(RenderViewHost* host) {
DCHECK(host);
RenderProcessHost* render_process = host->GetProcess();
DCHECK(render_process);
if (render_process->HasConnection())
return render_process->GetHandle();
return 0;
}
ScopedJavaLocalRef<jobject> CreateJavaRect(
JNIEnv* env,
const gfx::Rect& rect) {
return ScopedJavaLocalRef<jobject>(
Java_ContentViewCore_createRect(env,
static_cast<int>(rect.x()),
static_cast<int>(rect.y()),
static_cast<int>(rect.right()),
static_cast<int>(rect.bottom())));
}
int ToGestureEventType(WebInputEvent::Type type) {
switch (type) {
case WebInputEvent::GestureScrollBegin:
return GESTURE_EVENT_TYPE_SCROLL_START;
case WebInputEvent::GestureScrollEnd:
return GESTURE_EVENT_TYPE_SCROLL_END;
case WebInputEvent::GestureScrollUpdate:
return GESTURE_EVENT_TYPE_SCROLL_BY;
case WebInputEvent::GestureFlingStart:
return GESTURE_EVENT_TYPE_FLING_START;
case WebInputEvent::GestureFlingCancel:
return GESTURE_EVENT_TYPE_FLING_CANCEL;
case WebInputEvent::GestureShowPress:
return GESTURE_EVENT_TYPE_SHOW_PRESS;
case WebInputEvent::GestureTap:
return GESTURE_EVENT_TYPE_SINGLE_TAP_CONFIRMED;
case WebInputEvent::GestureTapUnconfirmed:
return GESTURE_EVENT_TYPE_SINGLE_TAP_UNCONFIRMED;
case WebInputEvent::GestureTapDown:
return GESTURE_EVENT_TYPE_TAP_DOWN;
case WebInputEvent::GestureTapCancel:
return GESTURE_EVENT_TYPE_TAP_CANCEL;
case WebInputEvent::GestureDoubleTap:
return GESTURE_EVENT_TYPE_DOUBLE_TAP;
case WebInputEvent::GestureLongPress:
return GESTURE_EVENT_TYPE_LONG_PRESS;
case WebInputEvent::GestureLongTap:
return GESTURE_EVENT_TYPE_LONG_TAP;
case WebInputEvent::GesturePinchBegin:
return GESTURE_EVENT_TYPE_PINCH_BEGIN;
case WebInputEvent::GesturePinchEnd:
return GESTURE_EVENT_TYPE_PINCH_END;
case WebInputEvent::GesturePinchUpdate:
return GESTURE_EVENT_TYPE_PINCH_BY;
case WebInputEvent::GestureTwoFingerTap:
default:
NOTREACHED() << "Invalid source gesture type: "
<< WebInputEventTraits::GetName(type);
return -1;
}
}
} // namespace
// Enables a callback when the underlying WebContents is destroyed, to enable
// nulling the back-pointer.
class ContentViewCoreImpl::ContentViewUserData
: public base::SupportsUserData::Data {
public:
explicit ContentViewUserData(ContentViewCoreImpl* content_view_core)
: content_view_core_(content_view_core) {
}
~ContentViewUserData() override {
// TODO(joth): When chrome has finished removing the TabContents class (see
// crbug.com/107201) consider inverting relationship, so ContentViewCore
// would own WebContents. That effectively implies making the WebContents
// destructor private on Android.
delete content_view_core_;
}
ContentViewCoreImpl* get() const { return content_view_core_; }
private:
// Not using scoped_ptr as ContentViewCoreImpl destructor is private.
ContentViewCoreImpl* content_view_core_;
DISALLOW_IMPLICIT_CONSTRUCTORS(ContentViewUserData);
};
// static
ContentViewCoreImpl* ContentViewCoreImpl::FromWebContents(
content::WebContents* web_contents) {
ContentViewCoreImpl::ContentViewUserData* data =
static_cast<ContentViewCoreImpl::ContentViewUserData*>(
web_contents->GetUserData(kContentViewUserDataKey));
return data ? data->get() : NULL;
}
// static
ContentViewCore* ContentViewCore::FromWebContents(
content::WebContents* web_contents) {
return ContentViewCoreImpl::FromWebContents(web_contents);
}
// static
ContentViewCore* ContentViewCore::GetNativeContentViewCore(JNIEnv* env,
jobject obj) {
return reinterpret_cast<ContentViewCore*>(
Java_ContentViewCore_getNativeContentViewCore(env, obj));
}
ContentViewCoreImpl::ContentViewCoreImpl(
JNIEnv* env,
jobject obj,
WebContents* web_contents,
jobject view_android_delegate,
ui::WindowAndroid* window_android,
jobject java_bridge_retained_object_set)
: WebContentsObserver(web_contents),
java_ref_(env, obj),
web_contents_(static_cast<WebContentsImpl*>(web_contents)),
root_layer_(cc::SolidColorLayer::Create()),
page_scale_(1),
dpi_scale_(ui::GetScaleFactorForNativeView(this)),
window_android_(window_android),
device_orientation_(0),
accessibility_enabled_(false) {
CHECK(web_contents) <<
"A ContentViewCoreImpl should be created with a valid WebContents.";
DCHECK(window_android_);
DCHECK(view_android_delegate);
view_android_delegate_.Reset(AttachCurrentThread(), view_android_delegate);
root_layer_->SetBackgroundColor(GetBackgroundColor(env, obj));
gfx::Size physical_size(
Java_ContentViewCore_getPhysicalBackingWidthPix(env, obj),
Java_ContentViewCore_getPhysicalBackingHeightPix(env, obj));
root_layer_->SetBounds(physical_size);
root_layer_->SetIsDrawable(true);
// Currently, the only use case we have for overriding a user agent involves
// spoofing a desktop Linux user agent for "Request desktop site".
// Automatically set it for all WebContents so that it is available when a
// NavigationEntry requires the user agent to be overridden.
const char kLinuxInfoStr[] = "X11; Linux x86_64";
std::string product = content::GetContentClient()->GetProduct();
std::string spoofed_ua =
BuildUserAgentFromOSAndProduct(kLinuxInfoStr, product);
web_contents->SetUserAgentOverride(spoofed_ua);
java_bridge_dispatcher_host_ =
new GinJavaBridgeDispatcherHost(web_contents,
java_bridge_retained_object_set);
InitWebContents();
}
void ContentViewCoreImpl::AddObserver(
ContentViewCoreImplObserver* observer) {
observer_list_.AddObserver(observer);
}
void ContentViewCoreImpl::RemoveObserver(
ContentViewCoreImplObserver* observer) {
observer_list_.RemoveObserver(observer);
}
ContentViewCoreImpl::~ContentViewCoreImpl() {
root_layer_->RemoveFromParent();
FOR_EACH_OBSERVER(ContentViewCoreImplObserver,
observer_list_,
OnContentViewCoreDestroyed());
observer_list_.Clear();
JNIEnv* env = base::android::AttachCurrentThread();
ScopedJavaLocalRef<jobject> j_obj = java_ref_.get(env);
java_ref_.reset();
if (!j_obj.is_null()) {
Java_ContentViewCore_onNativeContentViewCoreDestroyed(
env, j_obj.obj(), reinterpret_cast<intptr_t>(this));
}
}
void ContentViewCoreImpl::UpdateWindowAndroid(
JNIEnv* env,
const base::android::JavaParamRef<jobject>& obj,
jlong window_android) {
if (window_android) {
DCHECK(!window_android_);
window_android_ = reinterpret_cast<ui::WindowAndroid*>(window_android);
FOR_EACH_OBSERVER(ContentViewCoreImplObserver,
observer_list_,
OnAttachedToWindow());
} else {
FOR_EACH_OBSERVER(ContentViewCoreImplObserver,
observer_list_,
OnDetachedFromWindow());
window_android_ = NULL;
}
}
base::android::ScopedJavaLocalRef<jobject>
ContentViewCoreImpl::GetWebContentsAndroid(JNIEnv* env,
const JavaParamRef<jobject>& obj) {
return web_contents_->GetJavaWebContents();
}
base::android::ScopedJavaLocalRef<jobject>
ContentViewCoreImpl::GetJavaWindowAndroid(JNIEnv* env,
const JavaParamRef<jobject>& obj) {
if (!window_android_)
return ScopedJavaLocalRef<jobject>();
return window_android_->GetJavaObject();
}
void ContentViewCoreImpl::OnJavaContentViewCoreDestroyed(
JNIEnv* env,
const JavaParamRef<jobject>& obj) {
DCHECK(env->IsSameObject(java_ref_.get(env).obj(), obj));
java_ref_.reset();
// Java peer has gone, ContentViewCore is not functional and waits to
// be destroyed with WebContents.
// We need to reset WebContentsViewAndroid's reference, otherwise, there
// could have call in when swapping the WebContents,
// see http://crbug.com/383939 .
DCHECK(web_contents_);
static_cast<WebContentsViewAndroid*>(
static_cast<WebContentsImpl*>(web_contents_)->GetView())->
SetContentViewCore(NULL);
}
void ContentViewCoreImpl::InitWebContents() {
DCHECK(web_contents_);
static_cast<WebContentsViewAndroid*>(
static_cast<WebContentsImpl*>(web_contents_)->GetView())->
SetContentViewCore(this);
DCHECK(!web_contents_->GetUserData(kContentViewUserDataKey));
web_contents_->SetUserData(kContentViewUserDataKey,
new ContentViewUserData(this));
}
void ContentViewCoreImpl::RenderViewReady() {
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
if (!obj.is_null())
Java_ContentViewCore_onRenderProcessChange(env, obj.obj());
if (device_orientation_ != 0)
SendOrientationChangeEventInternal();
}
void ContentViewCoreImpl::RenderViewHostChanged(RenderViewHost* old_host,
RenderViewHost* new_host) {
int old_pid = 0;
if (old_host) {
old_pid = GetRenderProcessIdFromRenderViewHost(old_host);
RenderWidgetHostViewAndroid* view =
static_cast<RenderWidgetHostViewAndroid*>(
old_host->GetWidget()->GetView());
if (view)
view->SetContentViewCore(NULL);
view = static_cast<RenderWidgetHostViewAndroid*>(
new_host->GetWidget()->GetView());
if (view)
view->SetContentViewCore(this);
}
int new_pid = GetRenderProcessIdFromRenderViewHost(
web_contents_->GetRenderViewHost());
if (new_pid != old_pid) {
// Notify the Java side that the renderer process changed.
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
if (!obj.is_null()) {
Java_ContentViewCore_onRenderProcessChange(env, obj.obj());
}
}
SetFocusInternal(HasFocus());
SetAccessibilityEnabledInternal(accessibility_enabled_);
}
RenderWidgetHostViewAndroid*
ContentViewCoreImpl::GetRenderWidgetHostViewAndroid() const {
RenderWidgetHostView* rwhv = NULL;
if (web_contents_) {
rwhv = web_contents_->GetRenderWidgetHostView();
if (web_contents_->ShowingInterstitialPage()) {
rwhv = web_contents_->GetInterstitialPage()
->GetMainFrame()
->GetRenderViewHost()
->GetWidget()
->GetView();
}
}
return static_cast<RenderWidgetHostViewAndroid*>(rwhv);
}
ScopedJavaLocalRef<jobject> ContentViewCoreImpl::GetJavaObject() {
JNIEnv* env = AttachCurrentThread();
return java_ref_.get(env);
}
jint ContentViewCoreImpl::GetBackgroundColor(JNIEnv* env, jobject obj) {
RenderWidgetHostViewAndroid* rwhva = GetRenderWidgetHostViewAndroid();
if (!rwhva)
return SK_ColorWHITE;
return rwhva->GetCachedBackgroundColor();
}
void ContentViewCoreImpl::PauseOrResumeGeolocation(bool should_pause) {
if (should_pause)
web_contents_->GetGeolocationServiceContext()->PauseUpdates();
else
web_contents_->GetGeolocationServiceContext()->ResumeUpdates();
}
// All positions and sizes are in CSS pixels.
// Note that viewport_width/height is a best effort based.
// ContentViewCore has the actual information about the physical viewport size.
void ContentViewCoreImpl::UpdateFrameInfo(
const gfx::Vector2dF& scroll_offset,
float page_scale_factor,
const gfx::Vector2dF& page_scale_factor_limits,
const gfx::SizeF& content_size,
const gfx::SizeF& viewport_size,
const gfx::Vector2dF& controls_offset,
const gfx::Vector2dF& content_offset,
bool is_mobile_optimized_hint,
const cc::ViewportSelectionBound& selection_start) {
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
if (obj.is_null() || !window_android_)
return;
window_android_->set_content_offset(
gfx::ScaleVector2d(content_offset, dpi_scale_));
page_scale_ = page_scale_factor;
// The CursorAnchorInfo API in Android only supports zero width selection
// bounds.
const jboolean has_insertion_marker =
selection_start.type == cc::SELECTION_BOUND_CENTER;
const jboolean is_insertion_marker_visible = selection_start.visible;
const jfloat insertion_marker_horizontal =
has_insertion_marker ? selection_start.edge_top.x() : 0.0f;
const jfloat insertion_marker_top =
has_insertion_marker ? selection_start.edge_top.y() : 0.0f;
const jfloat insertion_marker_bottom =
has_insertion_marker ? selection_start.edge_bottom.y() : 0.0f;
Java_ContentViewCore_updateFrameInfo(
env, obj.obj(),
scroll_offset.x(),
scroll_offset.y(),
page_scale_factor,
page_scale_factor_limits.x(),
page_scale_factor_limits.y(),
content_size.width(),
content_size.height(),
viewport_size.width(),
viewport_size.height(),
controls_offset.y(),
content_offset.y(),
is_mobile_optimized_hint,
has_insertion_marker,
is_insertion_marker_visible,
insertion_marker_horizontal,
insertion_marker_top,
insertion_marker_bottom);
}
void ContentViewCoreImpl::SetTitle(const base::string16& title) {
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
if (obj.is_null())
return;
ScopedJavaLocalRef<jstring> jtitle =
ConvertUTF8ToJavaString(env, base::UTF16ToUTF8(title));
Java_ContentViewCore_setTitle(env, obj.obj(), jtitle.obj());
}
void ContentViewCoreImpl::OnBackgroundColorChanged(SkColor color) {
root_layer_->SetBackgroundColor(color);
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
if (obj.is_null())
return;
Java_ContentViewCore_onBackgroundColorChanged(env, obj.obj(), color);
}
void ContentViewCoreImpl::ShowSelectPopupMenu(
RenderFrameHost* frame,
const gfx::Rect& bounds,
const std::vector<MenuItem>& items,
int selected_item,
bool multiple,
bool right_aligned) {
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jobject> j_obj = java_ref_.get(env);
if (j_obj.is_null())
return;
ScopedJavaLocalRef<jobject> bounds_rect(CreateJavaRect(env, bounds));
// For multi-select list popups we find the list of previous selections by
// iterating through the items. But for single selection popups we take the
// given |selected_item| as is.
ScopedJavaLocalRef<jintArray> selected_array;
if (multiple) {
scoped_ptr<jint[]> native_selected_array(new jint[items.size()]);
size_t selected_count = 0;
for (size_t i = 0; i < items.size(); ++i) {
if (items[i].checked)
native_selected_array[selected_count++] = i;
}
selected_array = ScopedJavaLocalRef<jintArray>(
env, env->NewIntArray(selected_count));
env->SetIntArrayRegion(selected_array.obj(), 0, selected_count,
native_selected_array.get());
} else {
selected_array = ScopedJavaLocalRef<jintArray>(env, env->NewIntArray(1));
jint value = selected_item;
env->SetIntArrayRegion(selected_array.obj(), 0, 1, &value);
}
ScopedJavaLocalRef<jintArray> enabled_array(env,
env->NewIntArray(items.size()));
std::vector<base::string16> labels;
labels.reserve(items.size());
for (size_t i = 0; i < items.size(); ++i) {
labels.push_back(items[i].label);
jint enabled =
(items[i].type == MenuItem::GROUP ? POPUP_ITEM_TYPE_GROUP :
(items[i].enabled ? POPUP_ITEM_TYPE_ENABLED :
POPUP_ITEM_TYPE_DISABLED));
env->SetIntArrayRegion(enabled_array.obj(), i, 1, &enabled);
}
ScopedJavaLocalRef<jobjectArray> items_array(
base::android::ToJavaArrayOfStrings(env, labels));
Java_ContentViewCore_showSelectPopup(
env, j_obj.obj(), reinterpret_cast<intptr_t>(frame), bounds_rect.obj(),
items_array.obj(), enabled_array.obj(), multiple, selected_array.obj(),
right_aligned);
}
void ContentViewCoreImpl::HideSelectPopupMenu() {
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jobject> j_obj = java_ref_.get(env);
if (!j_obj.is_null())
Java_ContentViewCore_hideSelectPopup(env, j_obj.obj());
}
void ContentViewCoreImpl::OnGestureEventAck(const blink::WebGestureEvent& event,
InputEventAckState ack_result) {
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jobject> j_obj = java_ref_.get(env);
if (j_obj.is_null())
return;
switch (event.type) {
case WebInputEvent::GestureFlingStart:
if (ack_result == INPUT_EVENT_ACK_STATE_CONSUMED) {
// The view expects the fling velocity in pixels/s.
Java_ContentViewCore_onFlingStartEventConsumed(env, j_obj.obj(),
event.data.flingStart.velocityX * dpi_scale(),
event.data.flingStart.velocityY * dpi_scale());
} else {
// If a scroll ends with a fling, a SCROLL_END event is never sent.
// However, if that fling went unconsumed, we still need to let the
// listeners know that scrolling has ended.
Java_ContentViewCore_onScrollEndEventAck(env, j_obj.obj());
}
break;
case WebInputEvent::GestureFlingCancel:
Java_ContentViewCore_onFlingCancelEventAck(env, j_obj.obj());
break;
case WebInputEvent::GestureScrollBegin:
Java_ContentViewCore_onScrollBeginEventAck(env, j_obj.obj());
break;
case WebInputEvent::GestureScrollUpdate:
if (ack_result == INPUT_EVENT_ACK_STATE_CONSUMED)
Java_ContentViewCore_onScrollUpdateGestureConsumed(env, j_obj.obj());
break;
case WebInputEvent::GestureScrollEnd:
Java_ContentViewCore_onScrollEndEventAck(env, j_obj.obj());
break;
case WebInputEvent::GesturePinchBegin:
Java_ContentViewCore_onPinchBeginEventAck(env, j_obj.obj());
break;
case WebInputEvent::GesturePinchEnd:
Java_ContentViewCore_onPinchEndEventAck(env, j_obj.obj());
break;
case WebInputEvent::GestureTap:
Java_ContentViewCore_onSingleTapEventAck(
env,
j_obj.obj(),
ack_result == INPUT_EVENT_ACK_STATE_CONSUMED,
event.x * dpi_scale(),
event.y * dpi_scale());
break;
default:
break;
}
}
bool ContentViewCoreImpl::FilterInputEvent(const blink::WebInputEvent& event) {
if (event.type != WebInputEvent::GestureTap &&
event.type != WebInputEvent::GestureDoubleTap &&
event.type != WebInputEvent::GestureLongTap &&
event.type != WebInputEvent::GestureLongPress)
return false;
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jobject> j_obj = java_ref_.get(env);
if (j_obj.is_null())
return false;
const blink::WebGestureEvent& gesture =
static_cast<const blink::WebGestureEvent&>(event);
int gesture_type = ToGestureEventType(event.type);
return Java_ContentViewCore_filterTapOrPressEvent(env,
j_obj.obj(),
gesture_type,
gesture.x * dpi_scale(),
gesture.y * dpi_scale());
}
bool ContentViewCoreImpl::HasFocus() {
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
if (obj.is_null())
return false;
return Java_ContentViewCore_hasFocus(env, obj.obj());
}
void ContentViewCoreImpl::RequestDisallowInterceptTouchEvent() {
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
if (!obj.is_null())
Java_ContentViewCore_requestDisallowInterceptTouchEvent(env, obj.obj());
}
void ContentViewCoreImpl::OnSelectionChanged(const std::string& text) {
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
if (obj.is_null())
return;
ScopedJavaLocalRef<jstring> jtext = ConvertUTF8ToJavaString(env, text);
Java_ContentViewCore_onSelectionChanged(env, obj.obj(), jtext.obj());
}
void ContentViewCoreImpl::OnSelectionEvent(ui::SelectionEventType event,
const gfx::PointF& selection_anchor,
const gfx::RectF& selection_rect) {
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jobject> j_obj = java_ref_.get(env);
if (j_obj.is_null())
return;
gfx::PointF selection_anchor_pix =
gfx::ScalePoint(selection_anchor, dpi_scale());
gfx::RectF selection_rect_pix = gfx::ScaleRect(selection_rect, dpi_scale());
Java_ContentViewCore_onSelectionEvent(
env, j_obj.obj(), event, selection_anchor_pix.x(),
selection_anchor_pix.y(), selection_rect_pix.x(), selection_rect_pix.y(),
selection_rect_pix.right(), selection_rect_pix.bottom());
}
bool ContentViewCoreImpl::ShowPastePopup(int x_dip, int y_dip) {
RenderWidgetHostViewAndroid* view = GetRenderWidgetHostViewAndroid();
if (!view)
return false;
view->OnShowingPastePopup(gfx::PointF(x_dip, y_dip));
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
if (obj.is_null())
return false;
return Java_ContentViewCore_showPastePopupWithFeedback(
env, obj.obj(), static_cast<jint>(x_dip * dpi_scale()),
static_cast<jint>(y_dip * dpi_scale()));
}
void ContentViewCoreImpl::GetScaledContentBitmap(
float scale,
SkColorType preferred_color_type,
const gfx::Rect& src_subrect,
const ReadbackRequestCallback& result_callback) {
RenderWidgetHostViewAndroid* view = GetRenderWidgetHostViewAndroid();
if (!view || preferred_color_type == kUnknown_SkColorType) {
result_callback.Run(SkBitmap(), READBACK_FAILED);
return;
}
view->GetScaledContentBitmap(scale, preferred_color_type, src_subrect,
result_callback);
}
void ContentViewCoreImpl::StartContentIntent(const GURL& content_url,
bool is_main_frame) {
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jobject> j_obj = java_ref_.get(env);
if (j_obj.is_null())
return;
ScopedJavaLocalRef<jstring> jcontent_url =
ConvertUTF8ToJavaString(env, content_url.spec());
Java_ContentViewCore_startContentIntent(env,
j_obj.obj(),
jcontent_url.obj(),
is_main_frame);
}
void ContentViewCoreImpl::ShowDisambiguationPopup(
const gfx::Rect& rect_pixels,
const SkBitmap& zoomed_bitmap) {
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
if (obj.is_null())
return;
ScopedJavaLocalRef<jobject> rect_object(CreateJavaRect(env, rect_pixels));
ScopedJavaLocalRef<jobject> java_bitmap =
gfx::ConvertToJavaBitmap(&zoomed_bitmap);
DCHECK(!java_bitmap.is_null());
Java_ContentViewCore_showDisambiguationPopup(env,
obj.obj(),
rect_object.obj(),
java_bitmap.obj());
}
ScopedJavaLocalRef<jobject>
ContentViewCoreImpl::CreateMotionEventSynthesizer() {
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
if (obj.is_null())
return ScopedJavaLocalRef<jobject>();
return Java_ContentViewCore_createMotionEventSynthesizer(env, obj.obj());
}
bool ContentViewCoreImpl::ShouldBlockMediaRequest(const GURL& url) {
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
if (obj.is_null())
return true;
ScopedJavaLocalRef<jstring> j_url = ConvertUTF8ToJavaString(env, url.spec());
return Java_ContentViewCore_shouldBlockMediaRequest(env, obj.obj(),
j_url.obj());
}
void ContentViewCoreImpl::DidStopFlinging() {
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
if (!obj.is_null())
Java_ContentViewCore_onNativeFlingStopped(env, obj.obj());
}
ScopedJavaLocalRef<jobject> ContentViewCoreImpl::GetContext() const {
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
if (obj.is_null())
return ScopedJavaLocalRef<jobject>();
return Java_ContentViewCore_getContext(env, obj.obj());
}
gfx::Size ContentViewCoreImpl::GetViewSizeWithOSKHidden() const {
gfx::Size size_pix;
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jobject> j_obj = java_ref_.get(env);
if (j_obj.is_null())
return size_pix = gfx::Size();
size_pix = gfx::Size(
Java_ContentViewCore_getViewportWidthPix(env, j_obj.obj()),
Java_ContentViewCore_getViewportHeightWithOSKHiddenPix(env, j_obj.obj()));
gfx::Size size_dip = gfx::ScaleToCeiledSize(size_pix, 1.0f / dpi_scale());
if (DoTopControlsShrinkBlinkSize())
size_dip.Enlarge(0, -GetTopControlsHeightDip());
return size_dip;
}
gfx::Size ContentViewCoreImpl::GetViewSize() const {
gfx::Size size = GetViewportSizeDip();
if (DoTopControlsShrinkBlinkSize())
size.Enlarge(0, -GetTopControlsHeightDip());
return size;
}
gfx::Size ContentViewCoreImpl::GetPhysicalBackingSize() const {
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jobject> j_obj = java_ref_.get(env);
if (j_obj.is_null())
return gfx::Size();
return gfx::Size(
Java_ContentViewCore_getPhysicalBackingWidthPix(env, j_obj.obj()),
Java_ContentViewCore_getPhysicalBackingHeightPix(env, j_obj.obj()));
}
gfx::Size ContentViewCoreImpl::GetViewportSizePix() const {
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jobject> j_obj = java_ref_.get(env);
if (j_obj.is_null())
return gfx::Size();
return gfx::Size(
Java_ContentViewCore_getViewportWidthPix(env, j_obj.obj()),
Java_ContentViewCore_getViewportHeightPix(env, j_obj.obj()));
}
int ContentViewCoreImpl::GetTopControlsHeightPix() const {
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jobject> j_obj = java_ref_.get(env);
if (j_obj.is_null())
return 0;
return Java_ContentViewCore_getTopControlsHeightPix(env, j_obj.obj());
}
gfx::Size ContentViewCoreImpl::GetViewportSizeDip() const {
return gfx::ScaleToCeiledSize(GetViewportSizePix(), 1.0f / dpi_scale());
}
bool ContentViewCoreImpl::DoTopControlsShrinkBlinkSize() const {
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jobject> j_obj = java_ref_.get(env);
if (j_obj.is_null())
return false;
return Java_ContentViewCore_doTopControlsShrinkBlinkSize(env, j_obj.obj());
}
float ContentViewCoreImpl::GetTopControlsHeightDip() const {
return GetTopControlsHeightPix() / dpi_scale();
}
void ContentViewCoreImpl::AttachLayer(scoped_refptr<cc::Layer> layer) {
root_layer_->InsertChild(layer, 0);
root_layer_->SetIsDrawable(false);
}
void ContentViewCoreImpl::RemoveLayer(scoped_refptr<cc::Layer> layer) {
layer->RemoveFromParent();
if (!root_layer_->children().size())
root_layer_->SetIsDrawable(true);
}
void ContentViewCoreImpl::MoveRangeSelectionExtent(const gfx::PointF& extent) {
if (!web_contents_)
return;
web_contents_->MoveRangeSelectionExtent(gfx::ToRoundedPoint(extent));
}
void ContentViewCoreImpl::SelectBetweenCoordinates(const gfx::PointF& base,
const gfx::PointF& extent) {
if (!web_contents_)
return;
gfx::Point base_point = gfx::ToRoundedPoint(base);
gfx::Point extent_point = gfx::ToRoundedPoint(extent);
if (base_point == extent_point)
return;
web_contents_->SelectRange(base_point, extent_point);
}
ScopedJavaLocalRef<jobject> ContentViewCoreImpl::GetViewAndroidDelegate()
const {
return base::android::ScopedJavaLocalRef<jobject>(view_android_delegate_);
}
ui::WindowAndroid* ContentViewCoreImpl::GetWindowAndroid() const {
return window_android_;
}
const scoped_refptr<cc::Layer>& ContentViewCoreImpl::GetLayer() const {
return root_layer_;
}
// ----------------------------------------------------------------------------
// Methods called from Java via JNI
// ----------------------------------------------------------------------------
void ContentViewCoreImpl::SelectPopupMenuItems(
JNIEnv* env,
const JavaParamRef<jobject>& obj,
jlong selectPopupSourceFrame,
const JavaParamRef<jintArray>& indices) {
RenderFrameHostImpl* rfhi =
reinterpret_cast<RenderFrameHostImpl*>(selectPopupSourceFrame);
DCHECK(rfhi);
if (indices == NULL) {
rfhi->DidCancelPopupMenu();
return;
}
int selected_count = env->GetArrayLength(indices);
std::vector<int> selected_indices;
jint* indices_ptr = env->GetIntArrayElements(indices, NULL);
for (int i = 0; i < selected_count; ++i)
selected_indices.push_back(indices_ptr[i]);
env->ReleaseIntArrayElements(indices, indices_ptr, JNI_ABORT);
rfhi->DidSelectPopupMenuItems(selected_indices);
}
WebContents* ContentViewCoreImpl::GetWebContents() const {
return web_contents_;
}
void ContentViewCoreImpl::SetFocus(JNIEnv* env,
const JavaParamRef<jobject>& obj,
jboolean focused) {
SetFocusInternal(focused);
}
void ContentViewCoreImpl::SetFocusInternal(bool focused) {
if (!GetRenderWidgetHostViewAndroid())
return;
if (focused)
GetRenderWidgetHostViewAndroid()->Focus();
else
GetRenderWidgetHostViewAndroid()->Blur();
}
void ContentViewCoreImpl::SendOrientationChangeEvent(
JNIEnv* env,
const JavaParamRef<jobject>& obj,
jint orientation) {
if (device_orientation_ != orientation) {
device_orientation_ = orientation;
SendOrientationChangeEventInternal();
}
}
jboolean ContentViewCoreImpl::OnTouchEvent(
JNIEnv* env,
const JavaParamRef<jobject>& obj,
const JavaParamRef<jobject>& motion_event,
jlong time_ms,
jint android_action,
jint pointer_count,
jint history_size,
jint action_index,
jfloat pos_x_0,
jfloat pos_y_0,
jfloat pos_x_1,
jfloat pos_y_1,
jint pointer_id_0,
jint pointer_id_1,
jfloat touch_major_0,
jfloat touch_major_1,
jfloat touch_minor_0,
jfloat touch_minor_1,
jfloat orientation_0,
jfloat orientation_1,
jfloat tilt_0,
jfloat tilt_1,
jfloat raw_pos_x,
jfloat raw_pos_y,
jint android_tool_type_0,
jint android_tool_type_1,
jint android_button_state,
jint android_meta_state,
jboolean is_touch_handle_event) {
RenderWidgetHostViewAndroid* rwhv = GetRenderWidgetHostViewAndroid();
// Avoid synthesizing a touch event if it cannot be forwarded.
if (!rwhv)
return false;
ui::MotionEventAndroid::Pointer pointer0(pointer_id_0,
pos_x_0,
pos_y_0,
touch_major_0,
touch_minor_0,
orientation_0,
tilt_0,
android_tool_type_0);
ui::MotionEventAndroid::Pointer pointer1(pointer_id_1,
pos_x_1,
pos_y_1,
touch_major_1,
touch_minor_1,
orientation_1,
tilt_1,
android_tool_type_1);
ui::MotionEventAndroid event(1.f / dpi_scale(),
env,
motion_event,
time_ms,
android_action,
pointer_count,
history_size,
action_index,
android_button_state,
android_meta_state,
raw_pos_x - pos_x_0,
raw_pos_y - pos_y_0,
pointer0,
pointer1);
return is_touch_handle_event ? rwhv->OnTouchHandleEvent(event)
: rwhv->OnTouchEvent(event);
}
float ContentViewCoreImpl::GetDpiScale() const {
return dpi_scale_;
}
jboolean ContentViewCoreImpl::SendMouseMoveEvent(
JNIEnv* env,
const JavaParamRef<jobject>& obj,
jlong time_ms,
jfloat x,
jfloat y,
jint tool_type) {
RenderWidgetHostViewAndroid* rwhv = GetRenderWidgetHostViewAndroid();
if (!rwhv)
return false;
blink::WebMouseEvent event = WebMouseEventBuilder::Build(
WebInputEvent::MouseMove,
blink::WebMouseEvent::ButtonNone,
time_ms / 1000.0, x / dpi_scale(), y / dpi_scale(), 0, 1,
ui::ToWebPointerType(static_cast<ui::MotionEvent::ToolType>(tool_type)));
rwhv->SendMouseEvent(event);
return true;
}
jboolean ContentViewCoreImpl::SendMouseWheelEvent(
JNIEnv* env,
const JavaParamRef<jobject>& obj,
jlong time_ms,
jfloat x,
jfloat y,
jfloat ticks_x,
jfloat ticks_y,
jfloat pixels_per_tick) {
RenderWidgetHostViewAndroid* rwhv = GetRenderWidgetHostViewAndroid();
if (!rwhv)
return false;
if (!ticks_x && !ticks_y)
return false;
blink::WebMouseWheelEvent event = WebMouseWheelEventBuilder::Build(
ticks_x, ticks_y, pixels_per_tick / dpi_scale(), time_ms / 1000.0,
x / dpi_scale(), y / dpi_scale());
rwhv->SendMouseWheelEvent(event);
return true;
}
WebGestureEvent ContentViewCoreImpl::MakeGestureEvent(WebInputEvent::Type type,
int64_t time_ms,
float x,
float y) const {
return WebGestureEventBuilder::Build(
type, time_ms / 1000.0, x / dpi_scale(), y / dpi_scale());
}
void ContentViewCoreImpl::SendGestureEvent(
const blink::WebGestureEvent& event) {
RenderWidgetHostViewAndroid* rwhv = GetRenderWidgetHostViewAndroid();
if (rwhv)
rwhv->SendGestureEvent(event);
}
void ContentViewCoreImpl::ScrollBegin(JNIEnv* env,
const JavaParamRef<jobject>& obj,
jlong time_ms,
jfloat x,
jfloat y,
jfloat hintx,
jfloat hinty,
jboolean target_viewport) {
WebGestureEvent event = MakeGestureEvent(
WebInputEvent::GestureScrollBegin, time_ms, x, y);
event.data.scrollBegin.deltaXHint = hintx / dpi_scale();
event.data.scrollBegin.deltaYHint = hinty / dpi_scale();
event.data.scrollBegin.targetViewport = target_viewport;
SendGestureEvent(event);
}
void ContentViewCoreImpl::ScrollEnd(JNIEnv* env,
const JavaParamRef<jobject>& obj,
jlong time_ms) {
WebGestureEvent event = MakeGestureEvent(
WebInputEvent::GestureScrollEnd, time_ms, 0, 0);
SendGestureEvent(event);
}
void ContentViewCoreImpl::ScrollBy(JNIEnv* env,
const JavaParamRef<jobject>& obj,
jlong time_ms,
jfloat x,
jfloat y,
jfloat dx,
jfloat dy) {
WebGestureEvent event = MakeGestureEvent(
WebInputEvent::GestureScrollUpdate, time_ms, x, y);
event.data.scrollUpdate.deltaX = -dx / dpi_scale();
event.data.scrollUpdate.deltaY = -dy / dpi_scale();
SendGestureEvent(event);
}
void ContentViewCoreImpl::FlingStart(JNIEnv* env,
const JavaParamRef<jobject>& obj,
jlong time_ms,
jfloat x,
jfloat y,
jfloat vx,
jfloat vy,
jboolean target_viewport) {
WebGestureEvent event = MakeGestureEvent(
WebInputEvent::GestureFlingStart, time_ms, x, y);
event.data.flingStart.velocityX = vx / dpi_scale();
event.data.flingStart.velocityY = vy / dpi_scale();
event.data.flingStart.targetViewport = target_viewport;
SendGestureEvent(event);
}
void ContentViewCoreImpl::FlingCancel(JNIEnv* env,
const JavaParamRef<jobject>& obj,
jlong time_ms) {
WebGestureEvent event = MakeGestureEvent(
WebInputEvent::GestureFlingCancel, time_ms, 0, 0);
event.data.flingCancel.preventBoosting = true;
SendGestureEvent(event);
}
void ContentViewCoreImpl::SingleTap(JNIEnv* env,
const JavaParamRef<jobject>& obj,
jlong time_ms,
jfloat x,
jfloat y) {
// Tap gestures should always be preceded by a TapDown, ensuring consistency
// with the touch-based gesture detection pipeline.
WebGestureEvent tap_down_event = MakeGestureEvent(
WebInputEvent::GestureTapDown, time_ms, x, y);
tap_down_event.data.tap.tapCount = 1;
SendGestureEvent(tap_down_event);
WebGestureEvent tap_event = MakeGestureEvent(
WebInputEvent::GestureTap, time_ms, x, y);
tap_event.data.tap.tapCount = 1;
SendGestureEvent(tap_event);
}
void ContentViewCoreImpl::DoubleTap(JNIEnv* env,
const JavaParamRef<jobject>& obj,
jlong time_ms,
jfloat x,
jfloat y) {
WebGestureEvent event = MakeGestureEvent(
WebInputEvent::GestureDoubleTap, time_ms, x, y);
// Set the tap count to 1 even for DoubleTap, in order to be consistent with
// double tap behavior on a mobile viewport. See crbug.com/234986 for context.
event.data.tap.tapCount = 1;
SendGestureEvent(event);
}
void ContentViewCoreImpl::LongPress(JNIEnv* env,
const JavaParamRef<jobject>& obj,
jlong time_ms,
jfloat x,
jfloat y) {
WebGestureEvent event = MakeGestureEvent(
WebInputEvent::GestureLongPress, time_ms, x, y);
SendGestureEvent(event);
}
void ContentViewCoreImpl::PinchBegin(JNIEnv* env,
const JavaParamRef<jobject>& obj,
jlong time_ms,
jfloat x,
jfloat y) {
WebGestureEvent event = MakeGestureEvent(
WebInputEvent::GesturePinchBegin, time_ms, x, y);
SendGestureEvent(event);
}
void ContentViewCoreImpl::PinchEnd(JNIEnv* env,
const JavaParamRef<jobject>& obj,
jlong time_ms) {
WebGestureEvent event = MakeGestureEvent(
WebInputEvent::GesturePinchEnd, time_ms, 0, 0);
SendGestureEvent(event);
}
void ContentViewCoreImpl::PinchBy(JNIEnv* env,
const JavaParamRef<jobject>& obj,
jlong time_ms,
jfloat anchor_x,
jfloat anchor_y,
jfloat delta) {
WebGestureEvent event = MakeGestureEvent(
WebInputEvent::GesturePinchUpdate, time_ms, anchor_x, anchor_y);
event.data.pinchUpdate.scale = delta;
SendGestureEvent(event);
}
void ContentViewCoreImpl::SelectBetweenCoordinates(
JNIEnv* env,
const JavaParamRef<jobject>& obj,
jfloat x1,
jfloat y1,
jfloat x2,
jfloat y2) {
SelectBetweenCoordinates(gfx::PointF(x1 / dpi_scale(), y1 / dpi_scale()),
gfx::PointF(x2 / dpi_scale(), y2 / dpi_scale()));
}
void ContentViewCoreImpl::DismissTextHandles(JNIEnv* env,
const JavaParamRef<jobject>& obj) {
RenderWidgetHostViewAndroid* rwhv = GetRenderWidgetHostViewAndroid();
if (rwhv)
rwhv->DismissTextHandles();
}
void ContentViewCoreImpl::SetTextHandlesTemporarilyHidden(
JNIEnv* env,
const JavaParamRef<jobject>& obj,
jboolean hidden) {
RenderWidgetHostViewAndroid* rwhv = GetRenderWidgetHostViewAndroid();
if (rwhv)
rwhv->SetTextHandlesTemporarilyHidden(hidden);
}
void ContentViewCoreImpl::ResetGestureDetection(
JNIEnv* env,
const JavaParamRef<jobject>& obj) {
RenderWidgetHostViewAndroid* rwhv = GetRenderWidgetHostViewAndroid();
if (rwhv)
rwhv->ResetGestureDetection();
}
void ContentViewCoreImpl::SetDoubleTapSupportEnabled(
JNIEnv* env,
const JavaParamRef<jobject>& obj,
jboolean enabled) {
RenderWidgetHostViewAndroid* rwhv = GetRenderWidgetHostViewAndroid();
if (rwhv)
rwhv->SetDoubleTapSupportEnabled(enabled);
}
void ContentViewCoreImpl::SetMultiTouchZoomSupportEnabled(
JNIEnv* env,
const JavaParamRef<jobject>& obj,
jboolean enabled) {
RenderWidgetHostViewAndroid* rwhv = GetRenderWidgetHostViewAndroid();
if (rwhv)
rwhv->SetMultiTouchZoomSupportEnabled(enabled);
}
void ContentViewCoreImpl::SetAllowJavascriptInterfacesInspection(
JNIEnv* env,
const JavaParamRef<jobject>& obj,
jboolean allow) {
java_bridge_dispatcher_host_->SetAllowObjectContentsInspection(allow);
}
void ContentViewCoreImpl::AddJavascriptInterface(
JNIEnv* env,
const JavaParamRef<jobject>& /* obj */,
const JavaParamRef<jobject>& object,
const JavaParamRef<jstring>& name,
const JavaParamRef<jclass>& safe_annotation_clazz) {
java_bridge_dispatcher_host_->AddNamedObject(
ConvertJavaStringToUTF8(env, name), object, safe_annotation_clazz);
}
void ContentViewCoreImpl::RemoveJavascriptInterface(
JNIEnv* env,
const JavaParamRef<jobject>& /* obj */,
const JavaParamRef<jstring>& name) {
java_bridge_dispatcher_host_->RemoveNamedObject(
ConvertJavaStringToUTF8(env, name));
}
void ContentViewCoreImpl::WasResized(JNIEnv* env,
const JavaParamRef<jobject>& obj) {
RenderWidgetHostViewAndroid* view = GetRenderWidgetHostViewAndroid();
gfx::Size physical_size(
Java_ContentViewCore_getPhysicalBackingWidthPix(env, obj),
Java_ContentViewCore_getPhysicalBackingHeightPix(env, obj));
root_layer_->SetBounds(physical_size);
if (view) {
web_contents_->SendScreenRects();
view->WasResized();
}
}
long ContentViewCoreImpl::GetNativeImeAdapter(
JNIEnv* env,
const JavaParamRef<jobject>& obj) {
RenderWidgetHostViewAndroid* rwhva = GetRenderWidgetHostViewAndroid();
if (!rwhva)
return 0;
return rwhva->GetNativeImeAdapter();
}
void ContentViewCoreImpl::ForceUpdateImeAdapter(long native_ime_adapter) {
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
if (obj.is_null())
return;
Java_ContentViewCore_forceUpdateImeAdapter(env, obj.obj(),
native_ime_adapter);
}
void ContentViewCoreImpl::UpdateImeAdapter(long native_ime_adapter,
int text_input_type,
int text_input_flags,
const std::string& text,
int selection_start,
int selection_end,
int composition_start,
int composition_end,
bool show_ime_if_needed,
bool is_non_ime_change) {
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
if (obj.is_null())
return;
ScopedJavaLocalRef<jstring> jstring_text = ConvertUTF8ToJavaString(env, text);
Java_ContentViewCore_updateImeAdapter(env,
obj.obj(),
native_ime_adapter,
text_input_type,
text_input_flags,
jstring_text.obj(),
selection_start,
selection_end,
composition_start,
composition_end,
show_ime_if_needed,
is_non_ime_change);
}
void ContentViewCoreImpl::SetAccessibilityEnabled(
JNIEnv* env,
const JavaParamRef<jobject>& obj,
bool enabled) {
SetAccessibilityEnabledInternal(enabled);
}
void ContentViewCoreImpl::SetTextTrackSettings(
JNIEnv* env,
const JavaParamRef<jobject>& obj,
jboolean textTracksEnabled,
const JavaParamRef<jstring>& textTrackBackgroundColor,
const JavaParamRef<jstring>& textTrackFontFamily,
const JavaParamRef<jstring>& textTrackFontStyle,
const JavaParamRef<jstring>& textTrackFontVariant,
const JavaParamRef<jstring>& textTrackTextColor,
const JavaParamRef<jstring>& textTrackTextShadow,
const JavaParamRef<jstring>& textTrackTextSize) {
FrameMsg_TextTrackSettings_Params params;
params.text_tracks_enabled = textTracksEnabled;
params.text_track_background_color = ConvertJavaStringToUTF8(
env, textTrackBackgroundColor);
params.text_track_font_family = ConvertJavaStringToUTF8(
env, textTrackFontFamily);
params.text_track_font_style = ConvertJavaStringToUTF8(
env, textTrackFontStyle);
params.text_track_font_variant = ConvertJavaStringToUTF8(
env, textTrackFontVariant);
params.text_track_text_color = ConvertJavaStringToUTF8(
env, textTrackTextColor);
params.text_track_text_shadow = ConvertJavaStringToUTF8(
env, textTrackTextShadow);
params.text_track_text_size = ConvertJavaStringToUTF8(
env, textTrackTextSize);
web_contents_->GetMainFrame()->SetTextTrackSettings(params);
}
bool ContentViewCoreImpl::IsFullscreenRequiredForOrientationLock() const {
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
if (obj.is_null())
return true;
return Java_ContentViewCore_isFullscreenRequiredForOrientationLock(env,
obj.obj());
}
void ContentViewCoreImpl::SetAccessibilityEnabledInternal(bool enabled) {
accessibility_enabled_ = enabled;
BrowserAccessibilityStateImpl* accessibility_state =
BrowserAccessibilityStateImpl::GetInstance();
if (enabled) {
// This enables accessibility globally unless it was explicitly disallowed
// by a command-line flag.
accessibility_state->OnScreenReaderDetected();
// If it was actually enabled globally, enable it for this RenderWidget now.
if (accessibility_state->IsAccessibleBrowser() && web_contents_)
web_contents_->AddAccessibilityMode(AccessibilityModeComplete);
} else {
accessibility_state->ResetAccessibilityMode();
if (web_contents_) {
web_contents_->SetAccessibilityMode(
accessibility_state->accessibility_mode());
}
}
}
void ContentViewCoreImpl::SendOrientationChangeEventInternal() {
RenderWidgetHostViewAndroid* rwhv = GetRenderWidgetHostViewAndroid();
if (rwhv)
rwhv->UpdateScreenInfo(this);
static_cast<WebContentsImpl*>(web_contents())->
screen_orientation_dispatcher_host()->OnOrientationChange();
}
void ContentViewCoreImpl::ExtractSmartClipData(JNIEnv* env,
const JavaParamRef<jobject>& obj,
jint x,
jint y,
jint width,
jint height) {
gfx::Rect rect(
static_cast<int>(x / dpi_scale()),
static_cast<int>(y / dpi_scale()),
static_cast<int>((width > 0 && width < dpi_scale()) ?
1 : (int)(width / dpi_scale())),
static_cast<int>((height > 0 && height < dpi_scale()) ?
1 : (int)(height / dpi_scale())));
GetWebContents()->Send(new ViewMsg_ExtractSmartClipData(
GetWebContents()->GetRoutingID(), rect));
}
jint ContentViewCoreImpl::GetCurrentRenderProcessId(
JNIEnv* env,
const JavaParamRef<jobject>& obj) {
return GetRenderProcessIdFromRenderViewHost(
web_contents_->GetRenderViewHost());
}
void ContentViewCoreImpl::SetBackgroundOpaque(JNIEnv* env,
const JavaParamRef<jobject>& jobj,
jboolean opaque) {
if (GetRenderWidgetHostViewAndroid()) {
if (opaque)
GetRenderWidgetHostViewAndroid()->SetBackgroundColorToDefault();
else
GetRenderWidgetHostViewAndroid()->SetBackgroundColor(SK_ColorTRANSPARENT);
}
}
void ContentViewCoreImpl::RequestTextSurroundingSelection(
int max_length,
const base::Callback<
void(const base::string16& content, int start_offset, int end_offset)>&
callback) {
DCHECK(!callback.is_null());
RenderFrameHost* focused_frame = web_contents_->GetFocusedFrame();
if (!focused_frame)
return;
if (GetRenderWidgetHostViewAndroid()) {
GetRenderWidgetHostViewAndroid()->SetTextSurroundingSelectionCallback(
callback);
focused_frame->Send(new FrameMsg_TextSurroundingSelectionRequest(
focused_frame->GetRoutingID(), max_length));
}
}
void ContentViewCoreImpl::OnShowUnhandledTapUIIfNeeded(int x_dip, int y_dip) {
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
if (obj.is_null())
return;
Java_ContentViewCore_onShowUnhandledTapUIIfNeeded(
env, obj.obj(), static_cast<jint>(x_dip * dpi_scale()),
static_cast<jint>(y_dip * dpi_scale()));
}
float ContentViewCoreImpl::GetScaleFactor() const {
return page_scale_ * dpi_scale_;
}
void ContentViewCoreImpl::OnSmartClipDataExtracted(
const base::string16& text,
const base::string16& html,
const gfx::Rect& clip_rect) {
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
if (obj.is_null())
return;
ScopedJavaLocalRef<jstring> jtext = ConvertUTF16ToJavaString(env, text);
ScopedJavaLocalRef<jstring> jhtml = ConvertUTF16ToJavaString(env, html);
ScopedJavaLocalRef<jobject> clip_rect_object(CreateJavaRect(env, clip_rect));
Java_ContentViewCore_onSmartClipDataExtracted(
env, obj.obj(), jtext.obj(), jhtml.obj(), clip_rect_object.obj());
}
void ContentViewCoreImpl::WebContentsDestroyed() {
WebContentsViewAndroid* wcva = static_cast<WebContentsViewAndroid*>(
static_cast<WebContentsImpl*>(web_contents())->GetView());
DCHECK(wcva);
wcva->SetContentViewCore(NULL);
}
bool ContentViewCoreImpl::PullStart() {
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
if (!obj.is_null())
return Java_ContentViewCore_onOverscrollRefreshStart(env, obj.obj());
return false;
}
void ContentViewCoreImpl::PullUpdate(float delta) {
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
if (!obj.is_null())
Java_ContentViewCore_onOverscrollRefreshUpdate(env, obj.obj(), delta);
}
void ContentViewCoreImpl::PullRelease(bool allow_refresh) {
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
if (!obj.is_null()) {
Java_ContentViewCore_onOverscrollRefreshRelease(env, obj.obj(),
allow_refresh);
}
}
void ContentViewCoreImpl::PullReset() {
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
if (!obj.is_null())
Java_ContentViewCore_onOverscrollRefreshReset(env, obj.obj());
}
// This is called for each ContentView.
jlong Init(JNIEnv* env,
const JavaParamRef<jobject>& obj,
const JavaParamRef<jobject>& web_contents,
const JavaParamRef<jobject>& view_android_delegate,
jlong window_android,
const JavaParamRef<jobject>& retained_objects_set) {
ContentViewCoreImpl* view = new ContentViewCoreImpl(
env, obj, WebContents::FromJavaWebContents(web_contents),
view_android_delegate,
reinterpret_cast<ui::WindowAndroid*>(window_android),
retained_objects_set);
return reinterpret_cast<intptr_t>(view);
}
static ScopedJavaLocalRef<jobject> FromWebContentsAndroid(
JNIEnv* env,
const JavaParamRef<jclass>& clazz,
const JavaParamRef<jobject>& jweb_contents) {
WebContents* web_contents = WebContents::FromJavaWebContents(jweb_contents);
if (!web_contents)
return ScopedJavaLocalRef<jobject>();
ContentViewCore* view = ContentViewCore::FromWebContents(web_contents);
if (!view)
return ScopedJavaLocalRef<jobject>();
return view->GetJavaObject();
}
bool RegisterContentViewCore(JNIEnv* env) {
return RegisterNativesImpl(env);
}
} // namespace content