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