1 // Copyright 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "content/browser/android/content_view_core_impl.h" 6 7 #include "base/android/jni_android.h" 8 #include "base/android/jni_array.h" 9 #include "base/android/jni_string.h" 10 #include "base/android/scoped_java_ref.h" 11 #include "base/command_line.h" 12 #include "base/json/json_writer.h" 13 #include "base/logging.h" 14 #include "base/metrics/histogram.h" 15 #include "base/strings/utf_string_conversions.h" 16 #include "base/values.h" 17 #include "cc/layers/layer.h" 18 #include "cc/layers/solid_color_layer.h" 19 #include "cc/output/begin_frame_args.h" 20 #include "content/browser/android/gesture_event_type.h" 21 #include "content/browser/android/interstitial_page_delegate_android.h" 22 #include "content/browser/android/java/gin_java_bridge_dispatcher_host.h" 23 #include "content/browser/android/load_url_params.h" 24 #include "content/browser/frame_host/interstitial_page_impl.h" 25 #include "content/browser/frame_host/navigation_controller_impl.h" 26 #include "content/browser/frame_host/navigation_entry_impl.h" 27 #include "content/browser/geolocation/geolocation_dispatcher_host.h" 28 #include "content/browser/media/media_web_contents_observer.h" 29 #include "content/browser/renderer_host/compositor_impl_android.h" 30 #include "content/browser/renderer_host/input/motion_event_android.h" 31 #include "content/browser/renderer_host/input/web_input_event_builders_android.h" 32 #include "content/browser/renderer_host/input/web_input_event_util.h" 33 #include "content/browser/renderer_host/render_view_host_impl.h" 34 #include "content/browser/renderer_host/render_widget_host_impl.h" 35 #include "content/browser/renderer_host/render_widget_host_view_android.h" 36 #include "content/browser/screen_orientation/screen_orientation_dispatcher_host.h" 37 #include "content/browser/ssl/ssl_host_state.h" 38 #include "content/browser/web_contents/web_contents_view_android.h" 39 #include "content/common/frame_messages.h" 40 #include "content/common/input/web_input_event_traits.h" 41 #include "content/common/input_messages.h" 42 #include "content/common/view_messages.h" 43 #include "content/public/browser/browser_accessibility_state.h" 44 #include "content/public/browser/browser_context.h" 45 #include "content/public/browser/favicon_status.h" 46 #include "content/public/browser/render_frame_host.h" 47 #include "content/public/browser/web_contents.h" 48 #include "content/public/common/content_client.h" 49 #include "content/public/common/content_switches.h" 50 #include "content/public/common/menu_item.h" 51 #include "content/public/common/page_transition_types.h" 52 #include "content/public/common/user_agent.h" 53 #include "jni/ContentViewCore_jni.h" 54 #include "third_party/WebKit/public/web/WebInputEvent.h" 55 #include "ui/base/android/view_android.h" 56 #include "ui/base/android/window_android.h" 57 #include "ui/gfx/android/java_bitmap.h" 58 #include "ui/gfx/screen.h" 59 #include "ui/gfx/size_conversions.h" 60 #include "ui/gfx/size_f.h" 61 62 using base::android::AttachCurrentThread; 63 using base::android::ConvertJavaStringToUTF16; 64 using base::android::ConvertJavaStringToUTF8; 65 using base::android::ConvertUTF16ToJavaString; 66 using base::android::ConvertUTF8ToJavaString; 67 using base::android::ScopedJavaGlobalRef; 68 using base::android::ScopedJavaLocalRef; 69 using blink::WebGestureEvent; 70 using blink::WebInputEvent; 71 72 // Describes the type and enabled state of a select popup item. 73 namespace { 74 75 enum { 76 #define DEFINE_POPUP_ITEM_TYPE(name, value) POPUP_ITEM_TYPE_##name = value, 77 #include "content/browser/android/popup_item_type_list.h" 78 #undef DEFINE_POPUP_ITEM_TYPE 79 }; 80 81 } //namespace 82 83 namespace content { 84 85 namespace { 86 87 const void* kContentViewUserDataKey = &kContentViewUserDataKey; 88 89 int GetRenderProcessIdFromRenderViewHost(RenderViewHost* host) { 90 DCHECK(host); 91 RenderProcessHost* render_process = host->GetProcess(); 92 DCHECK(render_process); 93 if (render_process->HasConnection()) 94 return render_process->GetHandle(); 95 else 96 return 0; 97 } 98 99 ScopedJavaLocalRef<jobject> CreateJavaRect( 100 JNIEnv* env, 101 const gfx::Rect& rect) { 102 return ScopedJavaLocalRef<jobject>( 103 Java_ContentViewCore_createRect(env, 104 static_cast<int>(rect.x()), 105 static_cast<int>(rect.y()), 106 static_cast<int>(rect.right()), 107 static_cast<int>(rect.bottom()))); 108 } 109 110 int ToGestureEventType(WebInputEvent::Type type) { 111 switch (type) { 112 case WebInputEvent::GestureScrollBegin: 113 return SCROLL_START; 114 case WebInputEvent::GestureScrollEnd: 115 return SCROLL_END; 116 case WebInputEvent::GestureScrollUpdate: 117 return SCROLL_BY; 118 case WebInputEvent::GestureFlingStart: 119 return FLING_START; 120 case WebInputEvent::GestureFlingCancel: 121 return FLING_CANCEL; 122 case WebInputEvent::GestureShowPress: 123 return SHOW_PRESS; 124 case WebInputEvent::GestureTap: 125 return SINGLE_TAP_CONFIRMED; 126 case WebInputEvent::GestureTapUnconfirmed: 127 return SINGLE_TAP_UNCONFIRMED; 128 case WebInputEvent::GestureTapDown: 129 return TAP_DOWN; 130 case WebInputEvent::GestureTapCancel: 131 return TAP_CANCEL; 132 case WebInputEvent::GestureDoubleTap: 133 return DOUBLE_TAP; 134 case WebInputEvent::GestureLongPress: 135 return LONG_PRESS; 136 case WebInputEvent::GestureLongTap: 137 return LONG_TAP; 138 case WebInputEvent::GesturePinchBegin: 139 return PINCH_BEGIN; 140 case WebInputEvent::GesturePinchEnd: 141 return PINCH_END; 142 case WebInputEvent::GesturePinchUpdate: 143 return PINCH_BY; 144 case WebInputEvent::GestureTwoFingerTap: 145 case WebInputEvent::GestureScrollUpdateWithoutPropagation: 146 default: 147 NOTREACHED() << "Invalid source gesture type: " 148 << WebInputEventTraits::GetName(type); 149 return -1; 150 }; 151 } 152 153 float GetPrimaryDisplayDeviceScaleFactor() { 154 const gfx::Display& display = 155 gfx::Screen::GetNativeScreen()->GetPrimaryDisplay(); 156 return display.device_scale_factor(); 157 } 158 159 } // namespace 160 161 // Enables a callback when the underlying WebContents is destroyed, to enable 162 // nulling the back-pointer. 163 class ContentViewCoreImpl::ContentViewUserData 164 : public base::SupportsUserData::Data { 165 public: 166 explicit ContentViewUserData(ContentViewCoreImpl* content_view_core) 167 : content_view_core_(content_view_core) { 168 } 169 170 virtual ~ContentViewUserData() { 171 // TODO(joth): When chrome has finished removing the TabContents class (see 172 // crbug.com/107201) consider inverting relationship, so ContentViewCore 173 // would own WebContents. That effectively implies making the WebContents 174 // destructor private on Android. 175 delete content_view_core_; 176 } 177 178 ContentViewCoreImpl* get() const { return content_view_core_; } 179 180 private: 181 // Not using scoped_ptr as ContentViewCoreImpl destructor is private. 182 ContentViewCoreImpl* content_view_core_; 183 184 DISALLOW_IMPLICIT_CONSTRUCTORS(ContentViewUserData); 185 }; 186 187 // static 188 ContentViewCoreImpl* ContentViewCoreImpl::FromWebContents( 189 content::WebContents* web_contents) { 190 ContentViewCoreImpl::ContentViewUserData* data = 191 reinterpret_cast<ContentViewCoreImpl::ContentViewUserData*>( 192 web_contents->GetUserData(kContentViewUserDataKey)); 193 return data ? data->get() : NULL; 194 } 195 196 // static 197 ContentViewCore* ContentViewCore::FromWebContents( 198 content::WebContents* web_contents) { 199 return ContentViewCoreImpl::FromWebContents(web_contents); 200 } 201 202 // static 203 ContentViewCore* ContentViewCore::GetNativeContentViewCore(JNIEnv* env, 204 jobject obj) { 205 return reinterpret_cast<ContentViewCore*>( 206 Java_ContentViewCore_getNativeContentViewCore(env, obj)); 207 } 208 209 ContentViewCoreImpl::ContentViewCoreImpl( 210 JNIEnv* env, 211 jobject obj, 212 WebContents* web_contents, 213 ui::ViewAndroid* view_android, 214 ui::WindowAndroid* window_android, 215 jobject java_bridge_retained_object_set) 216 : WebContentsObserver(web_contents), 217 java_ref_(env, obj), 218 web_contents_(static_cast<WebContentsImpl*>(web_contents)), 219 root_layer_(cc::SolidColorLayer::Create()), 220 dpi_scale_(GetPrimaryDisplayDeviceScaleFactor()), 221 view_android_(view_android), 222 window_android_(window_android), 223 device_orientation_(0), 224 accessibility_enabled_(false) { 225 CHECK(web_contents) << 226 "A ContentViewCoreImpl should be created with a valid WebContents."; 227 228 root_layer_->SetBackgroundColor(GetBackgroundColor(env, obj)); 229 gfx::Size physical_size( 230 Java_ContentViewCore_getPhysicalBackingWidthPix(env, obj), 231 Java_ContentViewCore_getPhysicalBackingHeightPix(env, obj)); 232 root_layer_->SetBounds(physical_size); 233 root_layer_->SetIsDrawable(true); 234 235 // Currently, the only use case we have for overriding a user agent involves 236 // spoofing a desktop Linux user agent for "Request desktop site". 237 // Automatically set it for all WebContents so that it is available when a 238 // NavigationEntry requires the user agent to be overridden. 239 const char kLinuxInfoStr[] = "X11; Linux x86_64"; 240 std::string product = content::GetContentClient()->GetProduct(); 241 std::string spoofed_ua = 242 BuildUserAgentFromOSAndProduct(kLinuxInfoStr, product); 243 web_contents->SetUserAgentOverride(spoofed_ua); 244 245 java_bridge_dispatcher_host_.reset( 246 new GinJavaBridgeDispatcherHost(web_contents, 247 java_bridge_retained_object_set)); 248 249 InitWebContents(); 250 } 251 252 ContentViewCoreImpl::~ContentViewCoreImpl() { 253 JNIEnv* env = base::android::AttachCurrentThread(); 254 ScopedJavaLocalRef<jobject> j_obj = java_ref_.get(env); 255 java_ref_.reset(); 256 if (!j_obj.is_null()) { 257 Java_ContentViewCore_onNativeContentViewCoreDestroyed( 258 env, j_obj.obj(), reinterpret_cast<intptr_t>(this)); 259 } 260 } 261 262 base::android::ScopedJavaLocalRef<jobject> 263 ContentViewCoreImpl::GetWebContentsAndroid(JNIEnv* env, jobject obj) { 264 return web_contents_->GetJavaWebContents(); 265 } 266 267 void ContentViewCoreImpl::OnJavaContentViewCoreDestroyed(JNIEnv* env, 268 jobject obj) { 269 DCHECK(env->IsSameObject(java_ref_.get(env).obj(), obj)); 270 java_ref_.reset(); 271 } 272 273 void ContentViewCoreImpl::InitWebContents() { 274 DCHECK(web_contents_); 275 static_cast<WebContentsViewAndroid*>( 276 static_cast<WebContentsImpl*>(web_contents_)->GetView())-> 277 SetContentViewCore(this); 278 DCHECK(!web_contents_->GetUserData(kContentViewUserDataKey)); 279 web_contents_->SetUserData(kContentViewUserDataKey, 280 new ContentViewUserData(this)); 281 } 282 283 void ContentViewCoreImpl::RenderViewReady() { 284 JNIEnv* env = AttachCurrentThread(); 285 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env); 286 if (!obj.is_null()) 287 Java_ContentViewCore_onRenderProcessChange(env, obj.obj()); 288 289 if (device_orientation_ != 0) 290 SendOrientationChangeEventInternal(); 291 } 292 293 void ContentViewCoreImpl::RenderViewHostChanged(RenderViewHost* old_host, 294 RenderViewHost* new_host) { 295 int old_pid = 0; 296 if (old_host) { 297 old_pid = GetRenderProcessIdFromRenderViewHost(old_host); 298 299 RenderWidgetHostViewAndroid* view = 300 static_cast<RenderWidgetHostViewAndroid*>(old_host->GetView()); 301 if (view) 302 view->SetContentViewCore(NULL); 303 304 view = static_cast<RenderWidgetHostViewAndroid*>(new_host->GetView()); 305 if (view) 306 view->SetContentViewCore(this); 307 } 308 int new_pid = GetRenderProcessIdFromRenderViewHost( 309 web_contents_->GetRenderViewHost()); 310 if (new_pid != old_pid) { 311 // Notify the Java side that the renderer process changed. 312 JNIEnv* env = AttachCurrentThread(); 313 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env); 314 if (!obj.is_null()) { 315 Java_ContentViewCore_onRenderProcessChange(env, obj.obj()); 316 } 317 } 318 319 SetFocusInternal(HasFocus()); 320 SetAccessibilityEnabledInternal(accessibility_enabled_); 321 } 322 323 RenderWidgetHostViewAndroid* 324 ContentViewCoreImpl::GetRenderWidgetHostViewAndroid() { 325 RenderWidgetHostView* rwhv = NULL; 326 if (web_contents_) { 327 rwhv = web_contents_->GetRenderWidgetHostView(); 328 if (web_contents_->ShowingInterstitialPage()) { 329 rwhv = static_cast<InterstitialPageImpl*>( 330 web_contents_->GetInterstitialPage())-> 331 GetRenderViewHost()->GetView(); 332 } 333 } 334 return static_cast<RenderWidgetHostViewAndroid*>(rwhv); 335 } 336 337 ScopedJavaLocalRef<jobject> ContentViewCoreImpl::GetJavaObject() { 338 JNIEnv* env = AttachCurrentThread(); 339 return java_ref_.get(env); 340 } 341 342 jint ContentViewCoreImpl::GetBackgroundColor(JNIEnv* env, jobject obj) { 343 RenderWidgetHostViewAndroid* rwhva = GetRenderWidgetHostViewAndroid(); 344 if (!rwhva) 345 return SK_ColorWHITE; 346 return rwhva->GetCachedBackgroundColor(); 347 } 348 349 void ContentViewCoreImpl::OnHide(JNIEnv* env, jobject obj) { 350 Hide(); 351 } 352 353 void ContentViewCoreImpl::OnShow(JNIEnv* env, jobject obj) { 354 Show(); 355 } 356 357 void ContentViewCoreImpl::Show() { 358 GetWebContents()->WasShown(); 359 } 360 361 void ContentViewCoreImpl::Hide() { 362 GetWebContents()->WasHidden(); 363 PauseVideo(); 364 } 365 366 void ContentViewCoreImpl::PauseVideo() { 367 RenderViewHostImpl* rvhi = static_cast<RenderViewHostImpl*>( 368 web_contents_->GetRenderViewHost()); 369 if (rvhi) 370 rvhi->media_web_contents_observer()->PauseVideo(); 371 } 372 373 void ContentViewCoreImpl::PauseOrResumeGeolocation(bool should_pause) { 374 web_contents_->geolocation_dispatcher_host()->PauseOrResume(should_pause); 375 } 376 377 void ContentViewCoreImpl::PauseOrResumeVideoCaptureStream(bool should_pause) { 378 RenderViewHostImpl* rvhi = static_cast<RenderViewHostImpl*>( 379 web_contents_->GetRenderViewHost()); 380 if (!rvhi) 381 return; 382 if (should_pause) 383 rvhi->Send(new ViewMsg_PauseVideoCaptureStream(rvhi->GetRoutingID())); 384 else 385 rvhi->Send(new ViewMsg_ResumeVideoCaptureStream(rvhi->GetRoutingID())); 386 } 387 388 // All positions and sizes are in CSS pixels. 389 // Note that viewport_width/height is a best effort based. 390 // ContentViewCore has the actual information about the physical viewport size. 391 void ContentViewCoreImpl::UpdateFrameInfo( 392 const gfx::Vector2dF& scroll_offset, 393 float page_scale_factor, 394 const gfx::Vector2dF& page_scale_factor_limits, 395 const gfx::SizeF& content_size, 396 const gfx::SizeF& viewport_size, 397 const gfx::Vector2dF& controls_offset, 398 const gfx::Vector2dF& content_offset, 399 float overdraw_bottom_height) { 400 JNIEnv* env = AttachCurrentThread(); 401 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env); 402 if (obj.is_null()) 403 return; 404 405 if (window_android_) { 406 window_android_->set_content_offset( 407 gfx::ScaleVector2d(content_offset, dpi_scale_)); 408 } 409 410 Java_ContentViewCore_updateFrameInfo( 411 env, obj.obj(), 412 scroll_offset.x(), 413 scroll_offset.y(), 414 page_scale_factor, 415 page_scale_factor_limits.x(), 416 page_scale_factor_limits.y(), 417 content_size.width(), 418 content_size.height(), 419 viewport_size.width(), 420 viewport_size.height(), 421 controls_offset.y(), 422 content_offset.y(), 423 overdraw_bottom_height); 424 } 425 426 void ContentViewCoreImpl::SetTitle(const base::string16& title) { 427 JNIEnv* env = AttachCurrentThread(); 428 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env); 429 if (obj.is_null()) 430 return; 431 ScopedJavaLocalRef<jstring> jtitle = 432 ConvertUTF8ToJavaString(env, base::UTF16ToUTF8(title)); 433 Java_ContentViewCore_setTitle(env, obj.obj(), jtitle.obj()); 434 } 435 436 void ContentViewCoreImpl::OnBackgroundColorChanged(SkColor color) { 437 root_layer_->SetBackgroundColor(color); 438 439 JNIEnv* env = AttachCurrentThread(); 440 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env); 441 if (obj.is_null()) 442 return; 443 Java_ContentViewCore_onBackgroundColorChanged(env, obj.obj(), color); 444 } 445 446 void ContentViewCoreImpl::ShowSelectPopupMenu(const gfx::Rect& bounds, 447 const std::vector<MenuItem>& items, int selected_item, bool multiple) { 448 JNIEnv* env = AttachCurrentThread(); 449 ScopedJavaLocalRef<jobject> j_obj = java_ref_.get(env); 450 if (j_obj.is_null()) 451 return; 452 453 ScopedJavaLocalRef<jobject> bounds_rect(CreateJavaRect(env, bounds)); 454 455 // For multi-select list popups we find the list of previous selections by 456 // iterating through the items. But for single selection popups we take the 457 // given |selected_item| as is. 458 ScopedJavaLocalRef<jintArray> selected_array; 459 if (multiple) { 460 scoped_ptr<jint[]> native_selected_array(new jint[items.size()]); 461 size_t selected_count = 0; 462 for (size_t i = 0; i < items.size(); ++i) { 463 if (items[i].checked) 464 native_selected_array[selected_count++] = i; 465 } 466 467 selected_array = ScopedJavaLocalRef<jintArray>( 468 env, env->NewIntArray(selected_count)); 469 env->SetIntArrayRegion(selected_array.obj(), 0, selected_count, 470 native_selected_array.get()); 471 } else { 472 selected_array = ScopedJavaLocalRef<jintArray>(env, env->NewIntArray(1)); 473 jint value = selected_item; 474 env->SetIntArrayRegion(selected_array.obj(), 0, 1, &value); 475 } 476 477 ScopedJavaLocalRef<jintArray> enabled_array(env, 478 env->NewIntArray(items.size())); 479 std::vector<base::string16> labels; 480 labels.reserve(items.size()); 481 for (size_t i = 0; i < items.size(); ++i) { 482 labels.push_back(items[i].label); 483 jint enabled = 484 (items[i].type == MenuItem::GROUP ? POPUP_ITEM_TYPE_GROUP : 485 (items[i].enabled ? POPUP_ITEM_TYPE_ENABLED : 486 POPUP_ITEM_TYPE_DISABLED)); 487 env->SetIntArrayRegion(enabled_array.obj(), i, 1, &enabled); 488 } 489 ScopedJavaLocalRef<jobjectArray> items_array( 490 base::android::ToJavaArrayOfStrings(env, labels)); 491 Java_ContentViewCore_showSelectPopup(env, j_obj.obj(), 492 bounds_rect.obj(), 493 items_array.obj(), 494 enabled_array.obj(), 495 multiple, 496 selected_array.obj()); 497 } 498 499 void ContentViewCoreImpl::HideSelectPopupMenu() { 500 JNIEnv* env = AttachCurrentThread(); 501 ScopedJavaLocalRef<jobject> j_obj = java_ref_.get(env); 502 if (!j_obj.is_null()) 503 Java_ContentViewCore_hideSelectPopup(env, j_obj.obj()); 504 } 505 506 void ContentViewCoreImpl::OnGestureEventAck(const blink::WebGestureEvent& event, 507 InputEventAckState ack_result) { 508 JNIEnv* env = AttachCurrentThread(); 509 ScopedJavaLocalRef<jobject> j_obj = java_ref_.get(env); 510 if (j_obj.is_null()) 511 return; 512 513 switch (event.type) { 514 case WebInputEvent::GestureFlingStart: 515 if (ack_result == INPUT_EVENT_ACK_STATE_CONSUMED) { 516 // The view expects the fling velocity in pixels/s. 517 Java_ContentViewCore_onFlingStartEventConsumed(env, j_obj.obj(), 518 event.data.flingStart.velocityX * dpi_scale(), 519 event.data.flingStart.velocityY * dpi_scale()); 520 } else { 521 // If a scroll ends with a fling, a SCROLL_END event is never sent. 522 // However, if that fling went unconsumed, we still need to let the 523 // listeners know that scrolling has ended. 524 Java_ContentViewCore_onScrollEndEventAck(env, j_obj.obj()); 525 } 526 527 if (ack_result == INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS) { 528 // The view expects the fling velocity in pixels/s. 529 Java_ContentViewCore_onFlingStartEventHadNoConsumer(env, j_obj.obj(), 530 event.data.flingStart.velocityX * dpi_scale(), 531 event.data.flingStart.velocityY * dpi_scale()); 532 } 533 break; 534 case WebInputEvent::GestureFlingCancel: 535 Java_ContentViewCore_onFlingCancelEventAck(env, j_obj.obj()); 536 break; 537 case WebInputEvent::GestureScrollBegin: 538 Java_ContentViewCore_onScrollBeginEventAck(env, j_obj.obj()); 539 break; 540 case WebInputEvent::GestureScrollUpdate: 541 if (ack_result == INPUT_EVENT_ACK_STATE_CONSUMED) 542 Java_ContentViewCore_onScrollUpdateGestureConsumed(env, j_obj.obj()); 543 break; 544 case WebInputEvent::GestureScrollEnd: 545 Java_ContentViewCore_onScrollEndEventAck(env, j_obj.obj()); 546 break; 547 case WebInputEvent::GesturePinchBegin: 548 Java_ContentViewCore_onPinchBeginEventAck(env, j_obj.obj()); 549 break; 550 case WebInputEvent::GesturePinchEnd: 551 Java_ContentViewCore_onPinchEndEventAck(env, j_obj.obj()); 552 break; 553 case WebInputEvent::GestureTap: 554 Java_ContentViewCore_onSingleTapEventAck( 555 env, 556 j_obj.obj(), 557 ack_result == INPUT_EVENT_ACK_STATE_CONSUMED, 558 event.x * dpi_scale(), 559 event.y * dpi_scale()); 560 break; 561 case WebInputEvent::GestureDoubleTap: 562 Java_ContentViewCore_onDoubleTapEventAck(env, j_obj.obj()); 563 break; 564 default: 565 break; 566 } 567 } 568 569 bool ContentViewCoreImpl::FilterInputEvent(const blink::WebInputEvent& event) { 570 if (event.type != WebInputEvent::GestureTap && 571 event.type != WebInputEvent::GestureDoubleTap && 572 event.type != WebInputEvent::GestureLongTap && 573 event.type != WebInputEvent::GestureLongPress) 574 return false; 575 576 JNIEnv* env = AttachCurrentThread(); 577 ScopedJavaLocalRef<jobject> j_obj = java_ref_.get(env); 578 if (j_obj.is_null()) 579 return false; 580 581 const blink::WebGestureEvent& gesture = 582 static_cast<const blink::WebGestureEvent&>(event); 583 int gesture_type = ToGestureEventType(event.type); 584 return Java_ContentViewCore_filterTapOrPressEvent(env, 585 j_obj.obj(), 586 gesture_type, 587 gesture.x * dpi_scale(), 588 gesture.y * dpi_scale()); 589 590 // TODO(jdduke): Also report double-tap UMA, crbug/347568. 591 } 592 593 bool ContentViewCoreImpl::HasFocus() { 594 JNIEnv* env = AttachCurrentThread(); 595 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env); 596 if (obj.is_null()) 597 return false; 598 return Java_ContentViewCore_hasFocus(env, obj.obj()); 599 } 600 601 void ContentViewCoreImpl::OnSelectionChanged(const std::string& text) { 602 JNIEnv* env = AttachCurrentThread(); 603 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env); 604 if (obj.is_null()) 605 return; 606 ScopedJavaLocalRef<jstring> jtext = ConvertUTF8ToJavaString(env, text); 607 Java_ContentViewCore_onSelectionChanged(env, obj.obj(), jtext.obj()); 608 } 609 610 void ContentViewCoreImpl::OnSelectionBoundsChanged( 611 const ViewHostMsg_SelectionBounds_Params& params) { 612 JNIEnv* env = AttachCurrentThread(); 613 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env); 614 if (obj.is_null()) 615 return; 616 ScopedJavaLocalRef<jobject> anchor_rect_dip( 617 CreateJavaRect(env, params.anchor_rect)); 618 ScopedJavaLocalRef<jobject> focus_rect_dip( 619 CreateJavaRect(env, params.focus_rect)); 620 Java_ContentViewCore_onSelectionBoundsChanged(env, obj.obj(), 621 anchor_rect_dip.obj(), 622 params.anchor_dir, 623 focus_rect_dip.obj(), 624 params.focus_dir, 625 params.is_anchor_first); 626 } 627 628 void ContentViewCoreImpl::ShowPastePopup(int x_dip, int y_dip) { 629 JNIEnv* env = AttachCurrentThread(); 630 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env); 631 if (obj.is_null()) 632 return; 633 Java_ContentViewCore_showPastePopup(env, obj.obj(), 634 static_cast<jint>(x_dip), 635 static_cast<jint>(y_dip)); 636 } 637 638 void ContentViewCoreImpl::GetScaledContentBitmap( 639 float scale, 640 jobject jbitmap_config, 641 gfx::Rect src_subrect, 642 const base::Callback<void(bool, const SkBitmap&)>& result_callback) { 643 RenderWidgetHostViewAndroid* view = GetRenderWidgetHostViewAndroid(); 644 if (!view) { 645 result_callback.Run(false, SkBitmap()); 646 return; 647 } 648 SkBitmap::Config skbitmap_format = gfx::ConvertToSkiaConfig(jbitmap_config); 649 view->GetScaledContentBitmap(scale, skbitmap_format, src_subrect, 650 result_callback); 651 } 652 653 void ContentViewCoreImpl::StartContentIntent(const GURL& content_url) { 654 JNIEnv* env = AttachCurrentThread(); 655 ScopedJavaLocalRef<jobject> j_obj = java_ref_.get(env); 656 if (j_obj.is_null()) 657 return; 658 ScopedJavaLocalRef<jstring> jcontent_url = 659 ConvertUTF8ToJavaString(env, content_url.spec()); 660 Java_ContentViewCore_startContentIntent(env, 661 j_obj.obj(), 662 jcontent_url.obj()); 663 } 664 665 void ContentViewCoreImpl::ShowDisambiguationPopup( 666 const gfx::Rect& target_rect, 667 const SkBitmap& zoomed_bitmap) { 668 JNIEnv* env = AttachCurrentThread(); 669 670 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env); 671 if (obj.is_null()) 672 return; 673 674 ScopedJavaLocalRef<jobject> rect_object(CreateJavaRect(env, target_rect)); 675 676 ScopedJavaLocalRef<jobject> java_bitmap = 677 gfx::ConvertToJavaBitmap(&zoomed_bitmap); 678 DCHECK(!java_bitmap.is_null()); 679 680 Java_ContentViewCore_showDisambiguationPopup(env, 681 obj.obj(), 682 rect_object.obj(), 683 java_bitmap.obj()); 684 } 685 686 ScopedJavaLocalRef<jobject> ContentViewCoreImpl::CreateTouchEventSynthesizer() { 687 JNIEnv* env = AttachCurrentThread(); 688 689 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env); 690 if (obj.is_null()) 691 return ScopedJavaLocalRef<jobject>(); 692 return Java_ContentViewCore_createTouchEventSynthesizer(env, obj.obj()); 693 } 694 695 ScopedJavaLocalRef<jobject> ContentViewCoreImpl::GetContentVideoViewClient() { 696 JNIEnv* env = AttachCurrentThread(); 697 698 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env); 699 if (obj.is_null()) 700 return ScopedJavaLocalRef<jobject>(); 701 702 return Java_ContentViewCore_getContentVideoViewClient(env, obj.obj()); 703 } 704 705 ScopedJavaLocalRef<jobject> ContentViewCoreImpl::GetContext() { 706 JNIEnv* env = AttachCurrentThread(); 707 708 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env); 709 if (obj.is_null()) 710 return ScopedJavaLocalRef<jobject>(); 711 712 return Java_ContentViewCore_getContext(env, obj.obj()); 713 } 714 715 bool ContentViewCoreImpl::ShouldBlockMediaRequest(const GURL& url) { 716 JNIEnv* env = AttachCurrentThread(); 717 718 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env); 719 if (obj.is_null()) 720 return true; 721 ScopedJavaLocalRef<jstring> j_url = ConvertUTF8ToJavaString(env, url.spec()); 722 return Java_ContentViewCore_shouldBlockMediaRequest(env, obj.obj(), 723 j_url.obj()); 724 } 725 726 void ContentViewCoreImpl::DidStopFlinging() { 727 JNIEnv* env = AttachCurrentThread(); 728 729 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env); 730 if (!obj.is_null()) 731 Java_ContentViewCore_onNativeFlingStopped(env, obj.obj()); 732 } 733 734 gfx::Size ContentViewCoreImpl::GetViewSize() const { 735 gfx::Size size = GetViewportSizeDip(); 736 gfx::Size offset = GetViewportSizeOffsetDip(); 737 size.Enlarge(-offset.width(), -offset.height()); 738 return size; 739 } 740 741 gfx::Size ContentViewCoreImpl::GetPhysicalBackingSize() const { 742 JNIEnv* env = AttachCurrentThread(); 743 ScopedJavaLocalRef<jobject> j_obj = java_ref_.get(env); 744 if (j_obj.is_null()) 745 return gfx::Size(); 746 return gfx::Size( 747 Java_ContentViewCore_getPhysicalBackingWidthPix(env, j_obj.obj()), 748 Java_ContentViewCore_getPhysicalBackingHeightPix(env, j_obj.obj())); 749 } 750 751 gfx::Size ContentViewCoreImpl::GetViewportSizePix() const { 752 JNIEnv* env = AttachCurrentThread(); 753 ScopedJavaLocalRef<jobject> j_obj = java_ref_.get(env); 754 if (j_obj.is_null()) 755 return gfx::Size(); 756 return gfx::Size( 757 Java_ContentViewCore_getViewportWidthPix(env, j_obj.obj()), 758 Java_ContentViewCore_getViewportHeightPix(env, j_obj.obj())); 759 } 760 761 gfx::Size ContentViewCoreImpl::GetViewportSizeOffsetPix() const { 762 JNIEnv* env = AttachCurrentThread(); 763 ScopedJavaLocalRef<jobject> j_obj = java_ref_.get(env); 764 if (j_obj.is_null()) 765 return gfx::Size(); 766 return gfx::Size( 767 Java_ContentViewCore_getViewportSizeOffsetWidthPix(env, j_obj.obj()), 768 Java_ContentViewCore_getViewportSizeOffsetHeightPix(env, j_obj.obj())); 769 } 770 771 gfx::Size ContentViewCoreImpl::GetViewportSizeDip() const { 772 return gfx::ToCeiledSize( 773 gfx::ScaleSize(GetViewportSizePix(), 1.0f / dpi_scale())); 774 } 775 776 gfx::Size ContentViewCoreImpl::GetViewportSizeOffsetDip() const { 777 return gfx::ToCeiledSize( 778 gfx::ScaleSize(GetViewportSizeOffsetPix(), 1.0f / dpi_scale())); 779 } 780 781 float ContentViewCoreImpl::GetOverdrawBottomHeightDip() const { 782 JNIEnv* env = AttachCurrentThread(); 783 ScopedJavaLocalRef<jobject> j_obj = java_ref_.get(env); 784 if (j_obj.is_null()) 785 return 0.f; 786 return Java_ContentViewCore_getOverdrawBottomHeightPix(env, j_obj.obj()) 787 / dpi_scale(); 788 } 789 790 void ContentViewCoreImpl::AttachLayer(scoped_refptr<cc::Layer> layer) { 791 root_layer_->AddChild(layer); 792 root_layer_->SetIsDrawable(false); 793 } 794 795 void ContentViewCoreImpl::RemoveLayer(scoped_refptr<cc::Layer> layer) { 796 layer->RemoveFromParent(); 797 798 if (!root_layer_->children().size()) 799 root_layer_->SetIsDrawable(true); 800 } 801 802 void ContentViewCoreImpl::LoadUrl( 803 NavigationController::LoadURLParams& params) { 804 GetWebContents()->GetController().LoadURLWithParams(params); 805 } 806 807 ui::ViewAndroid* ContentViewCoreImpl::GetViewAndroid() const { 808 // view_android_ should never be null for Chrome. 809 DCHECK(view_android_); 810 return view_android_; 811 } 812 813 ui::WindowAndroid* ContentViewCoreImpl::GetWindowAndroid() const { 814 // This should never be NULL for Chrome, but will be NULL for WebView. 815 DCHECK(window_android_); 816 return window_android_; 817 } 818 819 scoped_refptr<cc::Layer> ContentViewCoreImpl::GetLayer() const { 820 return root_layer_.get(); 821 } 822 823 // ---------------------------------------------------------------------------- 824 // Methods called from Java via JNI 825 // ---------------------------------------------------------------------------- 826 827 void ContentViewCoreImpl::SelectPopupMenuItems(JNIEnv* env, jobject obj, 828 jintArray indices) { 829 RenderViewHostImpl* rvhi = static_cast<RenderViewHostImpl*>( 830 web_contents_->GetRenderViewHost()); 831 DCHECK(rvhi); 832 if (indices == NULL) { 833 rvhi->DidCancelPopupMenu(); 834 return; 835 } 836 837 int selected_count = env->GetArrayLength(indices); 838 std::vector<int> selected_indices; 839 jint* indices_ptr = env->GetIntArrayElements(indices, NULL); 840 for (int i = 0; i < selected_count; ++i) 841 selected_indices.push_back(indices_ptr[i]); 842 env->ReleaseIntArrayElements(indices, indices_ptr, JNI_ABORT); 843 rvhi->DidSelectPopupMenuItems(selected_indices); 844 } 845 846 void ContentViewCoreImpl::LoadUrl( 847 JNIEnv* env, jobject obj, 848 jstring url, 849 jint load_url_type, 850 jint transition_type, 851 jstring j_referrer_url, 852 jint referrer_policy, 853 jint ua_override_option, 854 jstring extra_headers, 855 jbyteArray post_data, 856 jstring base_url_for_data_url, 857 jstring virtual_url_for_data_url, 858 jboolean can_load_local_resources, 859 jboolean is_renderer_initiated) { 860 DCHECK(url); 861 NavigationController::LoadURLParams params( 862 GURL(ConvertJavaStringToUTF8(env, url))); 863 864 params.load_type = static_cast<NavigationController::LoadURLType>( 865 load_url_type); 866 params.transition_type = PageTransitionFromInt(transition_type); 867 params.override_user_agent = 868 static_cast<NavigationController::UserAgentOverrideOption>( 869 ua_override_option); 870 871 if (extra_headers) 872 params.extra_headers = ConvertJavaStringToUTF8(env, extra_headers); 873 874 if (post_data) { 875 std::vector<uint8> http_body_vector; 876 base::android::JavaByteArrayToByteVector(env, post_data, &http_body_vector); 877 params.browser_initiated_post_data = 878 base::RefCountedBytes::TakeVector(&http_body_vector); 879 } 880 881 if (base_url_for_data_url) { 882 params.base_url_for_data_url = 883 GURL(ConvertJavaStringToUTF8(env, base_url_for_data_url)); 884 } 885 886 if (virtual_url_for_data_url) { 887 params.virtual_url_for_data_url = 888 GURL(ConvertJavaStringToUTF8(env, virtual_url_for_data_url)); 889 } 890 891 params.can_load_local_resources = can_load_local_resources; 892 if (j_referrer_url) { 893 params.referrer = content::Referrer( 894 GURL(ConvertJavaStringToUTF8(env, j_referrer_url)), 895 static_cast<blink::WebReferrerPolicy>(referrer_policy)); 896 } 897 898 params.is_renderer_initiated = is_renderer_initiated; 899 900 LoadUrl(params); 901 } 902 903 ScopedJavaLocalRef<jstring> ContentViewCoreImpl::GetURL( 904 JNIEnv* env, jobject) const { 905 return ConvertUTF8ToJavaString(env, GetWebContents()->GetURL().spec()); 906 } 907 908 jboolean ContentViewCoreImpl::IsIncognito(JNIEnv* env, jobject obj) { 909 return GetWebContents()->GetBrowserContext()->IsOffTheRecord(); 910 } 911 912 WebContents* ContentViewCoreImpl::GetWebContents() const { 913 return web_contents_; 914 } 915 916 void ContentViewCoreImpl::SetFocus(JNIEnv* env, jobject obj, jboolean focused) { 917 SetFocusInternal(focused); 918 } 919 920 void ContentViewCoreImpl::SetFocusInternal(bool focused) { 921 if (!GetRenderWidgetHostViewAndroid()) 922 return; 923 924 if (focused) 925 GetRenderWidgetHostViewAndroid()->Focus(); 926 else 927 GetRenderWidgetHostViewAndroid()->Blur(); 928 } 929 930 void ContentViewCoreImpl::SendOrientationChangeEvent(JNIEnv* env, 931 jobject obj, 932 jint orientation) { 933 if (device_orientation_ != orientation) { 934 device_orientation_ = orientation; 935 SendOrientationChangeEventInternal(); 936 } 937 } 938 939 jboolean ContentViewCoreImpl::OnTouchEvent(JNIEnv* env, 940 jobject obj, 941 jobject motion_event, 942 jlong time_ms, 943 jint android_action, 944 jint pointer_count, 945 jint history_size, 946 jint action_index, 947 jfloat pos_x_0, 948 jfloat pos_y_0, 949 jfloat pos_x_1, 950 jfloat pos_y_1, 951 jint pointer_id_0, 952 jint pointer_id_1, 953 jfloat touch_major_0, 954 jfloat touch_major_1, 955 jfloat raw_pos_x, 956 jfloat raw_pos_y, 957 jint android_tool_type_0, 958 jint android_tool_type_1, 959 jint android_button_state) { 960 RenderWidgetHostViewAndroid* rwhv = GetRenderWidgetHostViewAndroid(); 961 // Avoid synthesizing a touch event if it cannot be forwarded. 962 if (!rwhv) 963 return false; 964 965 MotionEventAndroid event(1.f / dpi_scale(), 966 env, 967 motion_event, 968 time_ms, 969 android_action, 970 pointer_count, 971 history_size, 972 action_index, 973 pos_x_0, 974 pos_y_0, 975 pos_x_1, 976 pos_y_1, 977 pointer_id_0, 978 pointer_id_1, 979 touch_major_0, 980 touch_major_1, 981 raw_pos_x, 982 raw_pos_y, 983 android_tool_type_0, 984 android_tool_type_1, 985 android_button_state); 986 987 return rwhv->OnTouchEvent(event); 988 } 989 990 float ContentViewCoreImpl::GetDpiScale() const { 991 return dpi_scale_; 992 } 993 994 jboolean ContentViewCoreImpl::SendMouseMoveEvent(JNIEnv* env, 995 jobject obj, 996 jlong time_ms, 997 jfloat x, 998 jfloat y) { 999 RenderWidgetHostViewAndroid* rwhv = GetRenderWidgetHostViewAndroid(); 1000 if (!rwhv) 1001 return false; 1002 1003 blink::WebMouseEvent event = WebMouseEventBuilder::Build( 1004 WebInputEvent::MouseMove, 1005 blink::WebMouseEvent::ButtonNone, 1006 time_ms / 1000.0, x / dpi_scale(), y / dpi_scale(), 0, 1); 1007 1008 rwhv->SendMouseEvent(event); 1009 return true; 1010 } 1011 1012 jboolean ContentViewCoreImpl::SendMouseWheelEvent(JNIEnv* env, 1013 jobject obj, 1014 jlong time_ms, 1015 jfloat x, 1016 jfloat y, 1017 jfloat vertical_axis) { 1018 RenderWidgetHostViewAndroid* rwhv = GetRenderWidgetHostViewAndroid(); 1019 if (!rwhv) 1020 return false; 1021 1022 WebMouseWheelEventBuilder::Direction direction; 1023 if (vertical_axis > 0) { 1024 direction = WebMouseWheelEventBuilder::DIRECTION_UP; 1025 } else if (vertical_axis < 0) { 1026 direction = WebMouseWheelEventBuilder::DIRECTION_DOWN; 1027 } else { 1028 return false; 1029 } 1030 blink::WebMouseWheelEvent event = WebMouseWheelEventBuilder::Build( 1031 direction, time_ms / 1000.0, x / dpi_scale(), y / dpi_scale()); 1032 1033 rwhv->SendMouseWheelEvent(event); 1034 return true; 1035 } 1036 1037 WebGestureEvent ContentViewCoreImpl::MakeGestureEvent( 1038 WebInputEvent::Type type, int64 time_ms, float x, float y) const { 1039 return WebGestureEventBuilder::Build( 1040 type, time_ms / 1000.0, x / dpi_scale(), y / dpi_scale()); 1041 } 1042 1043 void ContentViewCoreImpl::SendGestureEvent( 1044 const blink::WebGestureEvent& event) { 1045 RenderWidgetHostViewAndroid* rwhv = GetRenderWidgetHostViewAndroid(); 1046 if (rwhv) 1047 rwhv->SendGestureEvent(event); 1048 } 1049 1050 void ContentViewCoreImpl::ScrollBegin(JNIEnv* env, 1051 jobject obj, 1052 jlong time_ms, 1053 jfloat x, 1054 jfloat y, 1055 jfloat hintx, 1056 jfloat hinty) { 1057 WebGestureEvent event = MakeGestureEvent( 1058 WebInputEvent::GestureScrollBegin, time_ms, x, y); 1059 event.data.scrollBegin.deltaXHint = hintx / dpi_scale(); 1060 event.data.scrollBegin.deltaYHint = hinty / dpi_scale(); 1061 1062 SendGestureEvent(event); 1063 } 1064 1065 void ContentViewCoreImpl::ScrollEnd(JNIEnv* env, jobject obj, jlong time_ms) { 1066 WebGestureEvent event = MakeGestureEvent( 1067 WebInputEvent::GestureScrollEnd, time_ms, 0, 0); 1068 SendGestureEvent(event); 1069 } 1070 1071 void ContentViewCoreImpl::ScrollBy(JNIEnv* env, jobject obj, jlong time_ms, 1072 jfloat x, jfloat y, jfloat dx, jfloat dy) { 1073 WebGestureEvent event = MakeGestureEvent( 1074 WebInputEvent::GestureScrollUpdate, time_ms, x, y); 1075 event.data.scrollUpdate.deltaX = -dx / dpi_scale(); 1076 event.data.scrollUpdate.deltaY = -dy / dpi_scale(); 1077 1078 SendGestureEvent(event); 1079 } 1080 1081 void ContentViewCoreImpl::FlingStart(JNIEnv* env, jobject obj, jlong time_ms, 1082 jfloat x, jfloat y, jfloat vx, jfloat vy) { 1083 WebGestureEvent event = MakeGestureEvent( 1084 WebInputEvent::GestureFlingStart, time_ms, x, y); 1085 event.data.flingStart.velocityX = vx / dpi_scale(); 1086 event.data.flingStart.velocityY = vy / dpi_scale(); 1087 1088 SendGestureEvent(event); 1089 } 1090 1091 void ContentViewCoreImpl::FlingCancel(JNIEnv* env, jobject obj, jlong time_ms) { 1092 WebGestureEvent event = MakeGestureEvent( 1093 WebInputEvent::GestureFlingCancel, time_ms, 0, 0); 1094 SendGestureEvent(event); 1095 } 1096 1097 void ContentViewCoreImpl::SingleTap(JNIEnv* env, jobject obj, jlong time_ms, 1098 jfloat x, jfloat y) { 1099 WebGestureEvent event = MakeGestureEvent( 1100 WebInputEvent::GestureTap, time_ms, x, y); 1101 event.data.tap.tapCount = 1; 1102 1103 SendGestureEvent(event); 1104 } 1105 1106 void ContentViewCoreImpl::DoubleTap(JNIEnv* env, jobject obj, jlong time_ms, 1107 jfloat x, jfloat y) { 1108 WebGestureEvent event = MakeGestureEvent( 1109 WebInputEvent::GestureDoubleTap, time_ms, x, y); 1110 // Set the tap count to 1 even for DoubleTap, in order to be consistent with 1111 // double tap behavior on a mobile viewport. See crbug.com/234986 for context. 1112 event.data.tap.tapCount = 1; 1113 1114 SendGestureEvent(event); 1115 } 1116 1117 void ContentViewCoreImpl::LongPress(JNIEnv* env, jobject obj, jlong time_ms, 1118 jfloat x, jfloat y) { 1119 WebGestureEvent event = MakeGestureEvent( 1120 WebInputEvent::GestureLongPress, time_ms, x, y); 1121 1122 SendGestureEvent(event); 1123 } 1124 1125 void ContentViewCoreImpl::PinchBegin(JNIEnv* env, jobject obj, jlong time_ms, 1126 jfloat x, jfloat y) { 1127 WebGestureEvent event = MakeGestureEvent( 1128 WebInputEvent::GesturePinchBegin, time_ms, x, y); 1129 SendGestureEvent(event); 1130 } 1131 1132 void ContentViewCoreImpl::PinchEnd(JNIEnv* env, jobject obj, jlong time_ms) { 1133 WebGestureEvent event = MakeGestureEvent( 1134 WebInputEvent::GesturePinchEnd, time_ms, 0, 0); 1135 SendGestureEvent(event); 1136 } 1137 1138 void ContentViewCoreImpl::PinchBy(JNIEnv* env, jobject obj, jlong time_ms, 1139 jfloat anchor_x, jfloat anchor_y, 1140 jfloat delta) { 1141 WebGestureEvent event = MakeGestureEvent( 1142 WebInputEvent::GesturePinchUpdate, time_ms, anchor_x, anchor_y); 1143 event.data.pinchUpdate.scale = delta; 1144 1145 SendGestureEvent(event); 1146 } 1147 1148 void ContentViewCoreImpl::SelectBetweenCoordinates(JNIEnv* env, jobject obj, 1149 jfloat x1, jfloat y1, 1150 jfloat x2, jfloat y2) { 1151 if (!web_contents_) 1152 return; 1153 1154 web_contents_->SelectRange( 1155 gfx::Point(x1 / dpi_scale(), y1 / dpi_scale()), 1156 gfx::Point(x2 / dpi_scale(), y2 / dpi_scale())); 1157 } 1158 1159 void ContentViewCoreImpl::MoveCaret(JNIEnv* env, jobject obj, 1160 jfloat x, jfloat y) { 1161 if (GetRenderWidgetHostViewAndroid()) { 1162 GetRenderWidgetHostViewAndroid()->MoveCaret( 1163 gfx::Point(x / dpi_scale(), y / dpi_scale())); 1164 } 1165 } 1166 1167 void ContentViewCoreImpl::ResetGestureDetection(JNIEnv* env, jobject obj) { 1168 RenderWidgetHostViewAndroid* rwhv = GetRenderWidgetHostViewAndroid(); 1169 if (rwhv) 1170 rwhv->ResetGestureDetection(); 1171 } 1172 1173 void ContentViewCoreImpl::SetDoubleTapSupportEnabled(JNIEnv* env, 1174 jobject obj, 1175 jboolean enabled) { 1176 RenderWidgetHostViewAndroid* rwhv = GetRenderWidgetHostViewAndroid(); 1177 if (rwhv) 1178 rwhv->SetDoubleTapSupportEnabled(enabled); 1179 } 1180 1181 void ContentViewCoreImpl::SetMultiTouchZoomSupportEnabled(JNIEnv* env, 1182 jobject obj, 1183 jboolean enabled) { 1184 RenderWidgetHostViewAndroid* rwhv = GetRenderWidgetHostViewAndroid(); 1185 if (rwhv) 1186 rwhv->SetMultiTouchZoomSupportEnabled(enabled); 1187 } 1188 1189 void ContentViewCoreImpl::LoadIfNecessary(JNIEnv* env, jobject obj) { 1190 web_contents_->GetController().LoadIfNecessary(); 1191 } 1192 1193 void ContentViewCoreImpl::RequestRestoreLoad(JNIEnv* env, jobject obj) { 1194 web_contents_->GetController().SetNeedsReload(); 1195 } 1196 1197 void ContentViewCoreImpl::Reload(JNIEnv* env, 1198 jobject obj, 1199 jboolean check_for_repost) { 1200 if (web_contents_->GetController().NeedsReload()) 1201 web_contents_->GetController().LoadIfNecessary(); 1202 else 1203 web_contents_->GetController().Reload(check_for_repost); 1204 } 1205 1206 void ContentViewCoreImpl::ReloadIgnoringCache(JNIEnv* env, 1207 jobject obj, 1208 jboolean check_for_repost) { 1209 web_contents_->GetController().ReloadIgnoringCache(check_for_repost); 1210 } 1211 1212 void ContentViewCoreImpl::CancelPendingReload(JNIEnv* env, jobject obj) { 1213 web_contents_->GetController().CancelPendingReload(); 1214 } 1215 1216 void ContentViewCoreImpl::ContinuePendingReload(JNIEnv* env, jobject obj) { 1217 web_contents_->GetController().ContinuePendingReload(); 1218 } 1219 1220 void ContentViewCoreImpl::ClearHistory(JNIEnv* env, jobject obj) { 1221 // TODO(creis): Do callers of this need to know if it fails? 1222 if (web_contents_->GetController().CanPruneAllButLastCommitted()) 1223 web_contents_->GetController().PruneAllButLastCommitted(); 1224 } 1225 1226 void ContentViewCoreImpl::AddStyleSheetByURL( 1227 JNIEnv* env, jobject obj, jstring url) { 1228 if (!web_contents_) 1229 return; 1230 1231 web_contents_->GetMainFrame()->Send(new FrameMsg_AddStyleSheetByURL( 1232 web_contents_->GetMainFrame()->GetRoutingID(), 1233 ConvertJavaStringToUTF8(env, url))); 1234 } 1235 1236 void ContentViewCoreImpl::SetAllowJavascriptInterfacesInspection( 1237 JNIEnv* env, 1238 jobject obj, 1239 jboolean allow) { 1240 java_bridge_dispatcher_host_->SetAllowObjectContentsInspection(allow); 1241 } 1242 1243 void ContentViewCoreImpl::AddJavascriptInterface( 1244 JNIEnv* env, 1245 jobject /* obj */, 1246 jobject object, 1247 jstring name, 1248 jclass safe_annotation_clazz) { 1249 ScopedJavaLocalRef<jobject> scoped_object(env, object); 1250 ScopedJavaLocalRef<jclass> scoped_clazz(env, safe_annotation_clazz); 1251 java_bridge_dispatcher_host_->AddNamedObject( 1252 ConvertJavaStringToUTF8(env, name), scoped_object, scoped_clazz); 1253 } 1254 1255 void ContentViewCoreImpl::RemoveJavascriptInterface(JNIEnv* env, 1256 jobject /* obj */, 1257 jstring name) { 1258 java_bridge_dispatcher_host_->RemoveNamedObject( 1259 ConvertJavaStringToUTF8(env, name)); 1260 } 1261 1262 void ContentViewCoreImpl::WasResized(JNIEnv* env, jobject obj) { 1263 RenderWidgetHostViewAndroid* view = GetRenderWidgetHostViewAndroid(); 1264 gfx::Size physical_size( 1265 Java_ContentViewCore_getPhysicalBackingWidthPix(env, obj), 1266 Java_ContentViewCore_getPhysicalBackingHeightPix(env, obj)); 1267 root_layer_->SetBounds(physical_size); 1268 1269 if (view) { 1270 RenderWidgetHostImpl* host = RenderWidgetHostImpl::From( 1271 view->GetRenderWidgetHost()); 1272 host->SendScreenRects(); 1273 view->WasResized(); 1274 } 1275 } 1276 1277 void ContentViewCoreImpl::ShowInterstitialPage( 1278 JNIEnv* env, jobject obj, jstring jurl, jlong delegate_ptr) { 1279 GURL url(base::android::ConvertJavaStringToUTF8(env, jurl)); 1280 InterstitialPageDelegateAndroid* delegate = 1281 reinterpret_cast<InterstitialPageDelegateAndroid*>(delegate_ptr); 1282 InterstitialPage* interstitial = InterstitialPage::Create( 1283 web_contents_, false, url, delegate); 1284 delegate->set_interstitial_page(interstitial); 1285 interstitial->Show(); 1286 } 1287 1288 jboolean ContentViewCoreImpl::IsShowingInterstitialPage(JNIEnv* env, 1289 jobject obj) { 1290 return web_contents_->ShowingInterstitialPage(); 1291 } 1292 1293 jboolean ContentViewCoreImpl::IsRenderWidgetHostViewReady(JNIEnv* env, 1294 jobject obj) { 1295 RenderWidgetHostViewAndroid* view = GetRenderWidgetHostViewAndroid(); 1296 return view && view->HasValidFrame(); 1297 } 1298 1299 void ContentViewCoreImpl::ExitFullscreen(JNIEnv* env, jobject obj) { 1300 RenderViewHost* host = web_contents_->GetRenderViewHost(); 1301 if (!host) 1302 return; 1303 host->ExitFullscreen(); 1304 } 1305 1306 void ContentViewCoreImpl::UpdateTopControlsState(JNIEnv* env, 1307 jobject obj, 1308 bool enable_hiding, 1309 bool enable_showing, 1310 bool animate) { 1311 RenderViewHost* host = web_contents_->GetRenderViewHost(); 1312 if (!host) 1313 return; 1314 host->Send(new ViewMsg_UpdateTopControlsState(host->GetRoutingID(), 1315 enable_hiding, 1316 enable_showing, 1317 animate)); 1318 } 1319 1320 void ContentViewCoreImpl::ShowImeIfNeeded(JNIEnv* env, jobject obj) { 1321 RenderViewHost* host = web_contents_->GetRenderViewHost(); 1322 host->Send(new ViewMsg_ShowImeIfNeeded(host->GetRoutingID())); 1323 } 1324 1325 void ContentViewCoreImpl::ScrollFocusedEditableNodeIntoView(JNIEnv* env, 1326 jobject obj) { 1327 RenderViewHost* host = web_contents_->GetRenderViewHost(); 1328 host->Send(new InputMsg_ScrollFocusedEditableNodeIntoRect( 1329 host->GetRoutingID(), gfx::Rect())); 1330 } 1331 1332 void ContentViewCoreImpl::SelectWordAroundCaret(JNIEnv* env, jobject obj) { 1333 RenderViewHost* host = web_contents_->GetRenderViewHost(); 1334 if (!host) 1335 return; 1336 host->SelectWordAroundCaret(); 1337 } 1338 1339 namespace { 1340 1341 static void AddNavigationEntryToHistory(JNIEnv* env, jobject obj, 1342 jobject history, 1343 NavigationEntry* entry, 1344 int index) { 1345 // Get the details of the current entry 1346 ScopedJavaLocalRef<jstring> j_url( 1347 ConvertUTF8ToJavaString(env, entry->GetURL().spec())); 1348 ScopedJavaLocalRef<jstring> j_virtual_url( 1349 ConvertUTF8ToJavaString(env, entry->GetVirtualURL().spec())); 1350 ScopedJavaLocalRef<jstring> j_original_url( 1351 ConvertUTF8ToJavaString(env, entry->GetOriginalRequestURL().spec())); 1352 ScopedJavaLocalRef<jstring> j_title( 1353 ConvertUTF16ToJavaString(env, entry->GetTitle())); 1354 ScopedJavaLocalRef<jobject> j_bitmap; 1355 const FaviconStatus& status = entry->GetFavicon(); 1356 if (status.valid && status.image.ToSkBitmap()->getSize() > 0) 1357 j_bitmap = gfx::ConvertToJavaBitmap(status.image.ToSkBitmap()); 1358 1359 // Add the item to the list 1360 Java_ContentViewCore_addToNavigationHistory( 1361 env, obj, history, index, j_url.obj(), j_virtual_url.obj(), 1362 j_original_url.obj(), j_title.obj(), j_bitmap.obj()); 1363 } 1364 1365 } // namespace 1366 1367 int ContentViewCoreImpl::GetNavigationHistory(JNIEnv* env, 1368 jobject obj, 1369 jobject history) { 1370 // Iterate through navigation entries to populate the list 1371 const NavigationController& controller = web_contents_->GetController(); 1372 int count = controller.GetEntryCount(); 1373 for (int i = 0; i < count; ++i) { 1374 AddNavigationEntryToHistory( 1375 env, obj, history, controller.GetEntryAtIndex(i), i); 1376 } 1377 1378 return controller.GetCurrentEntryIndex(); 1379 } 1380 1381 void ContentViewCoreImpl::GetDirectedNavigationHistory(JNIEnv* env, 1382 jobject obj, 1383 jobject history, 1384 jboolean is_forward, 1385 jint max_entries) { 1386 // Iterate through navigation entries to populate the list 1387 const NavigationController& controller = web_contents_->GetController(); 1388 int count = controller.GetEntryCount(); 1389 int num_added = 0; 1390 int increment_value = is_forward ? 1 : -1; 1391 for (int i = controller.GetCurrentEntryIndex() + increment_value; 1392 i >= 0 && i < count; 1393 i += increment_value) { 1394 if (num_added >= max_entries) 1395 break; 1396 1397 AddNavigationEntryToHistory( 1398 env, obj, history, controller.GetEntryAtIndex(i), i); 1399 num_added++; 1400 } 1401 } 1402 1403 ScopedJavaLocalRef<jstring> 1404 ContentViewCoreImpl::GetOriginalUrlForActiveNavigationEntry(JNIEnv* env, 1405 jobject obj) { 1406 NavigationEntry* entry = web_contents_->GetController().GetVisibleEntry(); 1407 if (entry == NULL) 1408 return ScopedJavaLocalRef<jstring>(env, NULL); 1409 return ConvertUTF8ToJavaString(env, entry->GetOriginalRequestURL().spec()); 1410 } 1411 1412 long ContentViewCoreImpl::GetNativeImeAdapter(JNIEnv* env, jobject obj) { 1413 RenderWidgetHostViewAndroid* rwhva = GetRenderWidgetHostViewAndroid(); 1414 if (!rwhva) 1415 return 0; 1416 return rwhva->GetNativeImeAdapter(); 1417 } 1418 1419 namespace { 1420 void JavaScriptResultCallback(const ScopedJavaGlobalRef<jobject>& callback, 1421 const base::Value* result) { 1422 JNIEnv* env = base::android::AttachCurrentThread(); 1423 std::string json; 1424 base::JSONWriter::Write(result, &json); 1425 ScopedJavaLocalRef<jstring> j_json = ConvertUTF8ToJavaString(env, json); 1426 Java_ContentViewCore_onEvaluateJavaScriptResult(env, 1427 j_json.obj(), 1428 callback.obj()); 1429 } 1430 } // namespace 1431 1432 void ContentViewCoreImpl::EvaluateJavaScript(JNIEnv* env, 1433 jobject obj, 1434 jstring script, 1435 jobject callback, 1436 jboolean start_renderer) { 1437 RenderViewHost* rvh = web_contents_->GetRenderViewHost(); 1438 DCHECK(rvh); 1439 1440 if (start_renderer && !rvh->IsRenderViewLive()) { 1441 if (!web_contents_->CreateRenderViewForInitialEmptyDocument()) { 1442 LOG(ERROR) << "Failed to create RenderView in EvaluateJavaScript"; 1443 return; 1444 } 1445 } 1446 1447 if (!callback) { 1448 // No callback requested. 1449 web_contents_->GetMainFrame()->ExecuteJavaScript( 1450 ConvertJavaStringToUTF16(env, script)); 1451 return; 1452 } 1453 1454 // Secure the Java callback in a scoped object and give ownership of it to the 1455 // base::Callback. 1456 ScopedJavaGlobalRef<jobject> j_callback; 1457 j_callback.Reset(env, callback); 1458 content::RenderFrameHost::JavaScriptResultCallback c_callback = 1459 base::Bind(&JavaScriptResultCallback, j_callback); 1460 1461 web_contents_->GetMainFrame()->ExecuteJavaScript( 1462 ConvertJavaStringToUTF16(env, script), 1463 c_callback); 1464 } 1465 1466 bool ContentViewCoreImpl::GetUseDesktopUserAgent( 1467 JNIEnv* env, jobject obj) { 1468 NavigationEntry* entry = web_contents_->GetController().GetVisibleEntry(); 1469 return entry && entry->GetIsOverridingUserAgent(); 1470 } 1471 1472 void ContentViewCoreImpl::UpdateImeAdapter(long native_ime_adapter, 1473 int text_input_type, 1474 const std::string& text, 1475 int selection_start, 1476 int selection_end, 1477 int composition_start, 1478 int composition_end, 1479 bool show_ime_if_needed, 1480 bool is_non_ime_change) { 1481 JNIEnv* env = AttachCurrentThread(); 1482 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env); 1483 if (obj.is_null()) 1484 return; 1485 1486 ScopedJavaLocalRef<jstring> jstring_text = ConvertUTF8ToJavaString(env, text); 1487 Java_ContentViewCore_updateImeAdapter(env, obj.obj(), 1488 native_ime_adapter, text_input_type, 1489 jstring_text.obj(), 1490 selection_start, selection_end, 1491 composition_start, composition_end, 1492 show_ime_if_needed, is_non_ime_change); 1493 } 1494 1495 void ContentViewCoreImpl::ClearSslPreferences(JNIEnv* env, jobject obj) { 1496 SSLHostState* state = SSLHostState::GetFor( 1497 web_contents_->GetController().GetBrowserContext()); 1498 state->Clear(); 1499 } 1500 1501 void ContentViewCoreImpl::SetUseDesktopUserAgent( 1502 JNIEnv* env, 1503 jobject obj, 1504 jboolean enabled, 1505 jboolean reload_on_state_change) { 1506 if (GetUseDesktopUserAgent(env, obj) == enabled) 1507 return; 1508 1509 // Make sure the navigation entry actually exists. 1510 NavigationEntry* entry = web_contents_->GetController().GetVisibleEntry(); 1511 if (!entry) 1512 return; 1513 1514 // Set the flag in the NavigationEntry. 1515 entry->SetIsOverridingUserAgent(enabled); 1516 1517 // Send the override to the renderer. 1518 if (reload_on_state_change) { 1519 // Reloading the page will send the override down as part of the 1520 // navigation IPC message. 1521 NavigationControllerImpl& controller = 1522 static_cast<NavigationControllerImpl&>(web_contents_->GetController()); 1523 controller.ReloadOriginalRequestURL(false); 1524 } 1525 } 1526 1527 void ContentViewCoreImpl::SetAccessibilityEnabled(JNIEnv* env, jobject obj, 1528 bool enabled) { 1529 SetAccessibilityEnabledInternal(enabled); 1530 } 1531 1532 void ContentViewCoreImpl::ShowSelectionHandlesAutomatically() const { 1533 JNIEnv* env = AttachCurrentThread(); 1534 ScopedJavaLocalRef<jobject> obj(java_ref_.get(env)); 1535 if (obj.is_null()) 1536 return; 1537 Java_ContentViewCore_showSelectionHandlesAutomatically(env, obj.obj()); 1538 } 1539 1540 void ContentViewCoreImpl::SetAccessibilityEnabledInternal(bool enabled) { 1541 accessibility_enabled_ = enabled; 1542 RenderWidgetHostViewAndroid* host_view = GetRenderWidgetHostViewAndroid(); 1543 if (!host_view) 1544 return; 1545 RenderWidgetHostImpl* host_impl = RenderWidgetHostImpl::From( 1546 host_view->GetRenderWidgetHost()); 1547 BrowserAccessibilityState* accessibility_state = 1548 BrowserAccessibilityState::GetInstance(); 1549 if (enabled) { 1550 // This enables accessibility globally unless it was explicitly disallowed 1551 // by a command-line flag. 1552 accessibility_state->OnScreenReaderDetected(); 1553 // If it was actually enabled globally, enable it for this RenderWidget now. 1554 if (accessibility_state->IsAccessibleBrowser() && host_impl) 1555 host_impl->AddAccessibilityMode(AccessibilityModeComplete); 1556 } else { 1557 accessibility_state->ResetAccessibilityMode(); 1558 if (host_impl) 1559 host_impl->ResetAccessibilityMode(); 1560 } 1561 } 1562 1563 void ContentViewCoreImpl::SendOrientationChangeEventInternal() { 1564 RenderWidgetHostViewAndroid* rwhv = GetRenderWidgetHostViewAndroid(); 1565 if (rwhv) 1566 rwhv->UpdateScreenInfo(GetViewAndroid()); 1567 } 1568 1569 void ContentViewCoreImpl::ExtractSmartClipData(JNIEnv* env, 1570 jobject obj, 1571 jint x, 1572 jint y, 1573 jint width, 1574 jint height) { 1575 gfx::Rect rect( 1576 static_cast<int>(x / dpi_scale()), 1577 static_cast<int>(y / dpi_scale()), 1578 static_cast<int>((width > 0 && width < dpi_scale()) ? 1579 1 : (int)(width / dpi_scale())), 1580 static_cast<int>((height > 0 && height < dpi_scale()) ? 1581 1 : (int)(height / dpi_scale()))); 1582 GetWebContents()->Send(new ViewMsg_ExtractSmartClipData( 1583 GetWebContents()->GetRoutingID(), rect)); 1584 } 1585 1586 jint ContentViewCoreImpl::GetCurrentRenderProcessId(JNIEnv* env, jobject obj) { 1587 return GetRenderProcessIdFromRenderViewHost( 1588 web_contents_->GetRenderViewHost()); 1589 } 1590 1591 void ContentViewCoreImpl::SetBackgroundOpaque(JNIEnv* env, jobject jobj, 1592 jboolean opaque) { 1593 if (GetRenderWidgetHostViewAndroid()) 1594 GetRenderWidgetHostViewAndroid()->SetBackgroundOpaque(opaque); 1595 } 1596 1597 void ContentViewCoreImpl::RequestTextSurroundingSelection( 1598 int max_length, 1599 const base::Callback< 1600 void(const base::string16& content, int start_offset, int end_offset)>& 1601 callback) { 1602 DCHECK(!callback.is_null()); 1603 RenderFrameHost* focused_frame = web_contents_->GetFocusedFrame(); 1604 if (!focused_frame) 1605 return; 1606 if (GetRenderWidgetHostViewAndroid()) { 1607 GetRenderWidgetHostViewAndroid()->SetTextSurroundingSelectionCallback( 1608 callback); 1609 focused_frame->Send(new FrameMsg_TextSurroundingSelectionRequest( 1610 focused_frame->GetRoutingID(), max_length)); 1611 } 1612 } 1613 1614 void ContentViewCoreImpl::OnSmartClipDataExtracted( 1615 const base::string16& text, 1616 const base::string16& html, 1617 const gfx::Rect& clip_rect) { 1618 JNIEnv* env = AttachCurrentThread(); 1619 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env); 1620 if (obj.is_null()) 1621 return; 1622 ScopedJavaLocalRef<jstring> jtext = ConvertUTF16ToJavaString(env, text); 1623 ScopedJavaLocalRef<jstring> jhtml = ConvertUTF16ToJavaString(env, html); 1624 ScopedJavaLocalRef<jobject> clip_rect_object(CreateJavaRect(env, clip_rect)); 1625 Java_ContentViewCore_onSmartClipDataExtracted( 1626 env, obj.obj(), jtext.obj(), jhtml.obj(), clip_rect_object.obj()); 1627 } 1628 1629 void ContentViewCoreImpl::WebContentsDestroyed() { 1630 WebContentsViewAndroid* wcva = static_cast<WebContentsViewAndroid*>( 1631 static_cast<WebContentsImpl*>(web_contents())->GetView()); 1632 DCHECK(wcva); 1633 wcva->SetContentViewCore(NULL); 1634 } 1635 1636 // This is called for each ContentView. 1637 jlong Init(JNIEnv* env, 1638 jobject obj, 1639 jlong native_web_contents, 1640 jlong view_android, 1641 jlong window_android, 1642 jobject retained_objects_set) { 1643 ContentViewCoreImpl* view = new ContentViewCoreImpl( 1644 env, obj, 1645 reinterpret_cast<WebContents*>(native_web_contents), 1646 reinterpret_cast<ui::ViewAndroid*>(view_android), 1647 reinterpret_cast<ui::WindowAndroid*>(window_android), 1648 retained_objects_set); 1649 return reinterpret_cast<intptr_t>(view); 1650 } 1651 1652 bool RegisterContentViewCore(JNIEnv* env) { 1653 return RegisterNativesImpl(env); 1654 } 1655 1656 } // namespace content 1657