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::HasTouchEventHandlers(bool need_touch_events) { 491 JNIEnv* env = AttachCurrentThread(); 492 ScopedJavaLocalRef<jobject> j_obj = java_ref_.get(env); 493 if (j_obj.is_null()) 494 return; 495 Java_ContentViewCore_hasTouchEventHandlers(env, 496 j_obj.obj(), 497 need_touch_events); 498 } 499 500 bool ContentViewCoreImpl::HasFocus() { 501 JNIEnv* env = AttachCurrentThread(); 502 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env); 503 if (obj.is_null()) 504 return false; 505 return Java_ContentViewCore_hasFocus(env, obj.obj()); 506 } 507 508 void ContentViewCoreImpl::OnSelectionChanged(const std::string& text) { 509 JNIEnv* env = AttachCurrentThread(); 510 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env); 511 if (obj.is_null()) 512 return; 513 ScopedJavaLocalRef<jstring> jtext = ConvertUTF8ToJavaString(env, text); 514 Java_ContentViewCore_onSelectionChanged(env, obj.obj(), jtext.obj()); 515 } 516 517 void ContentViewCoreImpl::OnSelectionBoundsChanged( 518 const ViewHostMsg_SelectionBounds_Params& params) { 519 JNIEnv* env = AttachCurrentThread(); 520 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env); 521 if (obj.is_null()) 522 return; 523 ScopedJavaLocalRef<jobject> anchor_rect_dip( 524 CreateJavaRect(env, params.anchor_rect)); 525 ScopedJavaLocalRef<jobject> focus_rect_dip( 526 CreateJavaRect(env, params.focus_rect)); 527 Java_ContentViewCore_onSelectionBoundsChanged(env, obj.obj(), 528 anchor_rect_dip.obj(), 529 params.anchor_dir, 530 focus_rect_dip.obj(), 531 params.focus_dir, 532 params.is_anchor_first); 533 } 534 535 void ContentViewCoreImpl::ShowPastePopup(int x_dip, int y_dip) { 536 JNIEnv* env = AttachCurrentThread(); 537 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env); 538 if (obj.is_null()) 539 return; 540 Java_ContentViewCore_showPastePopup(env, obj.obj(), 541 static_cast<jint>(x_dip), 542 static_cast<jint>(y_dip)); 543 } 544 545 unsigned int ContentViewCoreImpl::GetScaledContentTexture( 546 float scale, 547 gfx::Size* out_size) { 548 RenderWidgetHostViewAndroid* view = GetRenderWidgetHostViewAndroid(); 549 if (!view) 550 return 0; 551 552 return view->GetScaledContentTexture(scale, out_size); 553 } 554 555 void ContentViewCoreImpl::StartContentIntent(const GURL& content_url) { 556 JNIEnv* env = AttachCurrentThread(); 557 ScopedJavaLocalRef<jobject> j_obj = java_ref_.get(env); 558 if (j_obj.is_null()) 559 return; 560 ScopedJavaLocalRef<jstring> jcontent_url = 561 ConvertUTF8ToJavaString(env, content_url.spec()); 562 Java_ContentViewCore_startContentIntent(env, 563 j_obj.obj(), 564 jcontent_url.obj()); 565 } 566 567 void ContentViewCoreImpl::ShowDisambiguationPopup( 568 const gfx::Rect& target_rect, 569 const SkBitmap& zoomed_bitmap) { 570 JNIEnv* env = AttachCurrentThread(); 571 572 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env); 573 if (obj.is_null()) 574 return; 575 576 ScopedJavaLocalRef<jobject> rect_object(CreateJavaRect(env, target_rect)); 577 578 ScopedJavaLocalRef<jobject> java_bitmap = 579 gfx::ConvertToJavaBitmap(&zoomed_bitmap); 580 DCHECK(!java_bitmap.is_null()); 581 582 Java_ContentViewCore_showDisambiguationPopup(env, 583 obj.obj(), 584 rect_object.obj(), 585 java_bitmap.obj()); 586 } 587 588 ScopedJavaLocalRef<jobject> ContentViewCoreImpl::CreateSmoothScroller( 589 bool scroll_down, int mouse_event_x, int mouse_event_y) { 590 JNIEnv* env = AttachCurrentThread(); 591 592 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env); 593 if (obj.is_null()) 594 return ScopedJavaLocalRef<jobject>(); 595 return Java_ContentViewCore_createSmoothScroller( 596 env, obj.obj(), scroll_down, mouse_event_x, mouse_event_y); 597 } 598 599 void ContentViewCoreImpl::NotifyExternalSurface( 600 int player_id, bool is_request, const gfx::RectF& rect) { 601 JNIEnv* env = AttachCurrentThread(); 602 603 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env); 604 if (obj.is_null()) 605 return; 606 607 Java_ContentViewCore_notifyExternalSurface( 608 env, 609 obj.obj(), 610 static_cast<jint>(player_id), 611 static_cast<jboolean>(is_request), 612 static_cast<jfloat>(rect.x()), 613 static_cast<jfloat>(rect.y()), 614 static_cast<jfloat>(rect.width()), 615 static_cast<jfloat>(rect.height())); 616 } 617 618 ScopedJavaLocalRef<jobject> ContentViewCoreImpl::GetContentVideoViewClient() { 619 JNIEnv* env = AttachCurrentThread(); 620 621 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env); 622 if (obj.is_null()) 623 return ScopedJavaLocalRef<jobject>(); 624 625 return Java_ContentViewCore_getContentVideoViewClient(env, obj.obj()); 626 } 627 628 ScopedJavaLocalRef<jobject> ContentViewCoreImpl::GetContext() { 629 JNIEnv* env = AttachCurrentThread(); 630 631 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env); 632 if (obj.is_null()) 633 return ScopedJavaLocalRef<jobject>(); 634 635 return Java_ContentViewCore_getContext(env, obj.obj()); 636 } 637 638 gfx::Size ContentViewCoreImpl::GetPhysicalBackingSize() const { 639 JNIEnv* env = AttachCurrentThread(); 640 ScopedJavaLocalRef<jobject> j_obj = java_ref_.get(env); 641 if (j_obj.is_null()) 642 return gfx::Size(); 643 return gfx::Size( 644 Java_ContentViewCore_getPhysicalBackingWidthPix(env, j_obj.obj()), 645 Java_ContentViewCore_getPhysicalBackingHeightPix(env, j_obj.obj())); 646 } 647 648 gfx::Size ContentViewCoreImpl::GetViewportSizePix() const { 649 JNIEnv* env = AttachCurrentThread(); 650 ScopedJavaLocalRef<jobject> j_obj = java_ref_.get(env); 651 if (j_obj.is_null()) 652 return gfx::Size(); 653 return gfx::Size( 654 Java_ContentViewCore_getViewportWidthPix(env, j_obj.obj()), 655 Java_ContentViewCore_getViewportHeightPix(env, j_obj.obj())); 656 } 657 658 gfx::Size ContentViewCoreImpl::GetViewportSizeOffsetPix() const { 659 JNIEnv* env = AttachCurrentThread(); 660 ScopedJavaLocalRef<jobject> j_obj = java_ref_.get(env); 661 if (j_obj.is_null()) 662 return gfx::Size(); 663 return gfx::Size( 664 Java_ContentViewCore_getViewportSizeOffsetWidthPix(env, j_obj.obj()), 665 Java_ContentViewCore_getViewportSizeOffsetHeightPix(env, j_obj.obj())); 666 } 667 668 gfx::Size ContentViewCoreImpl::GetViewportSizeDip() const { 669 return gfx::ToCeiledSize( 670 gfx::ScaleSize(GetViewportSizePix(), 1.0f / GetDpiScale())); 671 } 672 673 gfx::Size ContentViewCoreImpl::GetViewportSizeOffsetDip() const { 674 return gfx::ToCeiledSize( 675 gfx::ScaleSize(GetViewportSizeOffsetPix(), 1.0f / GetDpiScale())); 676 } 677 678 float ContentViewCoreImpl::GetOverdrawBottomHeightDip() const { 679 JNIEnv* env = AttachCurrentThread(); 680 ScopedJavaLocalRef<jobject> j_obj = java_ref_.get(env); 681 if (j_obj.is_null()) 682 return 0.f; 683 return Java_ContentViewCore_getOverdrawBottomHeightPix(env, j_obj.obj()) 684 / GetDpiScale(); 685 } 686 687 void ContentViewCoreImpl::AttachLayer(scoped_refptr<cc::Layer> layer) { 688 root_layer_->AddChild(layer); 689 } 690 691 void ContentViewCoreImpl::RemoveLayer(scoped_refptr<cc::Layer> layer) { 692 layer->RemoveFromParent(); 693 } 694 695 void ContentViewCoreImpl::LoadUrl( 696 NavigationController::LoadURLParams& params) { 697 GetWebContents()->GetController().LoadURLWithParams(params); 698 UpdateTabCrashedFlag(); 699 } 700 701 void ContentViewCoreImpl::SetNeedsBeginFrame(bool enabled) { 702 JNIEnv* env = AttachCurrentThread(); 703 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env); 704 if (obj.is_null()) 705 return; 706 Java_ContentViewCore_setVSyncNotificationEnabled( 707 env, obj.obj(), static_cast<jboolean>(enabled)); 708 } 709 710 void ContentViewCoreImpl::SetNeedsAnimate() { 711 JNIEnv* env = AttachCurrentThread(); 712 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env); 713 if (obj.is_null()) 714 return; 715 Java_ContentViewCore_setNeedsAnimate(env, obj.obj()); 716 } 717 718 ui::ViewAndroid* ContentViewCoreImpl::GetViewAndroid() const { 719 // view_android_ should never be null for Chrome. 720 DCHECK(view_android_); 721 return view_android_; 722 } 723 724 ui::WindowAndroid* ContentViewCoreImpl::GetWindowAndroid() const { 725 // This should never be NULL for Chrome, but will be NULL for WebView. 726 DCHECK(window_android_); 727 return window_android_; 728 } 729 730 scoped_refptr<cc::Layer> ContentViewCoreImpl::GetLayer() const { 731 return root_layer_.get(); 732 } 733 734 // ---------------------------------------------------------------------------- 735 // Methods called from Java via JNI 736 // ---------------------------------------------------------------------------- 737 738 void ContentViewCoreImpl::SelectPopupMenuItems(JNIEnv* env, jobject obj, 739 jintArray indices) { 740 RenderViewHostImpl* rvhi = static_cast<RenderViewHostImpl*>( 741 web_contents_->GetRenderViewHost()); 742 DCHECK(rvhi); 743 if (indices == NULL) { 744 rvhi->DidCancelPopupMenu(); 745 return; 746 } 747 748 int selected_count = env->GetArrayLength(indices); 749 std::vector<int> selected_indices; 750 jint* indices_ptr = env->GetIntArrayElements(indices, NULL); 751 for (int i = 0; i < selected_count; ++i) 752 selected_indices.push_back(indices_ptr[i]); 753 env->ReleaseIntArrayElements(indices, indices_ptr, JNI_ABORT); 754 rvhi->DidSelectPopupMenuItems(selected_indices); 755 } 756 757 void ContentViewCoreImpl::LoadUrl( 758 JNIEnv* env, jobject obj, 759 jstring url, 760 jint load_url_type, 761 jint transition_type, 762 jint ua_override_option, 763 jstring extra_headers, 764 jbyteArray post_data, 765 jstring base_url_for_data_url, 766 jstring virtual_url_for_data_url, 767 jboolean can_load_local_resources) { 768 DCHECK(url); 769 NavigationController::LoadURLParams params( 770 GURL(ConvertJavaStringToUTF8(env, url))); 771 772 params.load_type = static_cast<NavigationController::LoadURLType>( 773 load_url_type); 774 params.transition_type = PageTransitionFromInt(transition_type); 775 params.override_user_agent = 776 static_cast<NavigationController::UserAgentOverrideOption>( 777 ua_override_option); 778 779 if (extra_headers) 780 params.extra_headers = ConvertJavaStringToUTF8(env, extra_headers); 781 782 if (post_data) { 783 std::vector<uint8> http_body_vector; 784 base::android::JavaByteArrayToByteVector(env, post_data, &http_body_vector); 785 params.browser_initiated_post_data = 786 base::RefCountedBytes::TakeVector(&http_body_vector); 787 } 788 789 if (base_url_for_data_url) { 790 params.base_url_for_data_url = 791 GURL(ConvertJavaStringToUTF8(env, base_url_for_data_url)); 792 } 793 794 if (virtual_url_for_data_url) { 795 params.virtual_url_for_data_url = 796 GURL(ConvertJavaStringToUTF8(env, virtual_url_for_data_url)); 797 } 798 799 params.can_load_local_resources = can_load_local_resources; 800 801 LoadUrl(params); 802 } 803 804 jint ContentViewCoreImpl::GetCurrentRenderProcessId(JNIEnv* env, jobject obj) { 805 return GetRenderProcessIdFromRenderViewHost( 806 web_contents_->GetRenderViewHost()); 807 } 808 809 ScopedJavaLocalRef<jstring> ContentViewCoreImpl::GetURL( 810 JNIEnv* env, jobject) const { 811 // The current users of the Java API expect to use the active entry 812 // rather than the visible entry, which is exposed by WebContents::GetURL. 813 content::NavigationEntry* entry = 814 web_contents_->GetController().GetActiveEntry(); 815 GURL url = entry ? entry->GetVirtualURL() : GURL::EmptyGURL(); 816 return ConvertUTF8ToJavaString(env, url.spec()); 817 } 818 819 ScopedJavaLocalRef<jstring> ContentViewCoreImpl::GetTitle( 820 JNIEnv* env, jobject obj) const { 821 return ConvertUTF16ToJavaString(env, GetWebContents()->GetTitle()); 822 } 823 824 jboolean ContentViewCoreImpl::IsIncognito(JNIEnv* env, jobject obj) { 825 return GetWebContents()->GetBrowserContext()->IsOffTheRecord(); 826 } 827 828 WebContents* ContentViewCoreImpl::GetWebContents() const { 829 return web_contents_; 830 } 831 832 void ContentViewCoreImpl::SetFocus(JNIEnv* env, jobject obj, jboolean focused) { 833 SetFocusInternal(focused); 834 } 835 836 void ContentViewCoreImpl::SetFocusInternal(bool focused) { 837 if (!GetRenderWidgetHostViewAndroid()) 838 return; 839 840 if (focused) 841 GetRenderWidgetHostViewAndroid()->Focus(); 842 else 843 GetRenderWidgetHostViewAndroid()->Blur(); 844 } 845 846 void ContentViewCoreImpl::SendOrientationChangeEvent(JNIEnv* env, 847 jobject obj, 848 jint orientation) { 849 RenderWidgetHostViewAndroid* rwhv = GetRenderWidgetHostViewAndroid(); 850 if (rwhv) 851 rwhv->UpdateScreenInfo(rwhv->GetNativeView()); 852 853 RenderViewHostImpl* rvhi = static_cast<RenderViewHostImpl*>( 854 web_contents_->GetRenderViewHost()); 855 rvhi->SendOrientationChangeEvent(orientation); 856 } 857 858 jboolean ContentViewCoreImpl::SendTouchEvent(JNIEnv* env, 859 jobject obj, 860 jlong time_ms, 861 jint type, 862 jobjectArray pts) { 863 RenderWidgetHostViewAndroid* rwhv = GetRenderWidgetHostViewAndroid(); 864 if (rwhv) { 865 using WebKit::WebTouchEvent; 866 WebKit::WebTouchEvent event; 867 TouchPoint::BuildWebTouchEvent(env, type, time_ms, GetDpiScale(), pts, 868 event); 869 rwhv->SendTouchEvent(event); 870 return true; 871 } 872 return false; 873 } 874 875 float ContentViewCoreImpl::GetTouchPaddingDip() { 876 return 48.0f / GetDpiScale(); 877 } 878 879 float ContentViewCoreImpl::GetDpiScale() const { 880 return dpi_scale_; 881 } 882 883 void ContentViewCoreImpl::RequestContentClipping( 884 const gfx::Rect& clipping, 885 const gfx::Size& content_size) { 886 RenderWidgetHostViewAndroid* rwhv = GetRenderWidgetHostViewAndroid(); 887 if (rwhv) 888 rwhv->RequestContentClipping(clipping, content_size); 889 } 890 891 jboolean ContentViewCoreImpl::SendMouseMoveEvent(JNIEnv* env, 892 jobject obj, 893 jlong time_ms, 894 jfloat x, 895 jfloat y) { 896 RenderWidgetHostViewAndroid* rwhv = GetRenderWidgetHostViewAndroid(); 897 if (!rwhv) 898 return false; 899 900 WebKit::WebMouseEvent event = WebMouseEventBuilder::Build( 901 WebInputEvent::MouseMove, 902 WebKit::WebMouseEvent::ButtonNone, 903 time_ms / 1000.0, x / GetDpiScale(), y / GetDpiScale(), 0, 1); 904 905 rwhv->SendMouseEvent(event); 906 return true; 907 } 908 909 jboolean ContentViewCoreImpl::SendMouseWheelEvent(JNIEnv* env, 910 jobject obj, 911 jlong time_ms, 912 jfloat x, 913 jfloat y, 914 jfloat vertical_axis) { 915 RenderWidgetHostViewAndroid* rwhv = GetRenderWidgetHostViewAndroid(); 916 if (!rwhv) 917 return false; 918 919 WebMouseWheelEventBuilder::Direction direction; 920 if (vertical_axis > 0) { 921 direction = WebMouseWheelEventBuilder::DIRECTION_UP; 922 } else if (vertical_axis < 0) { 923 direction = WebMouseWheelEventBuilder::DIRECTION_DOWN; 924 } else { 925 return false; 926 } 927 WebKit::WebMouseWheelEvent event = WebMouseWheelEventBuilder::Build( 928 direction, time_ms / 1000.0, x / GetDpiScale(), y / GetDpiScale()); 929 930 rwhv->SendMouseWheelEvent(event); 931 return true; 932 } 933 934 WebGestureEvent ContentViewCoreImpl::MakeGestureEvent( 935 WebInputEvent::Type type, long time_ms, float x, float y) const { 936 return WebGestureEventBuilder::Build( 937 type, time_ms / 1000.0, x / GetDpiScale(), y / GetDpiScale()); 938 } 939 940 void ContentViewCoreImpl::SendGestureEvent( 941 const WebKit::WebGestureEvent& event) { 942 RenderWidgetHostViewAndroid* rwhv = GetRenderWidgetHostViewAndroid(); 943 if (rwhv) 944 rwhv->SendGestureEvent(event); 945 } 946 947 void ContentViewCoreImpl::UpdateTabCrashedFlag() { 948 // Since RenderWidgetHostView is associated with the lifetime of the renderer 949 // process, we use it to test whether there is a renderer process. 950 tab_crashed_ = !(web_contents_->GetRenderWidgetHostView()); 951 } 952 953 void ContentViewCoreImpl::ScrollBegin(JNIEnv* env, jobject obj, jlong time_ms, 954 jfloat x, jfloat y) { 955 WebGestureEvent event = MakeGestureEvent( 956 WebInputEvent::GestureScrollBegin, time_ms, x, y); 957 SendGestureEvent(event); 958 } 959 960 void ContentViewCoreImpl::ScrollEnd(JNIEnv* env, jobject obj, jlong time_ms) { 961 WebGestureEvent event = MakeGestureEvent( 962 WebInputEvent::GestureScrollEnd, time_ms, 0, 0); 963 SendGestureEvent(event); 964 } 965 966 void ContentViewCoreImpl::ScrollBy(JNIEnv* env, jobject obj, jlong time_ms, 967 jfloat x, jfloat y, jfloat dx, jfloat dy, 968 jboolean last_input_event_for_vsync) { 969 WebGestureEvent event = MakeGestureEvent( 970 WebInputEvent::GestureScrollUpdate, time_ms, x, y); 971 event.data.scrollUpdate.deltaX = -dx / GetDpiScale(); 972 event.data.scrollUpdate.deltaY = -dy / GetDpiScale(); 973 974 SendGestureEvent(event); 975 976 // TODO(brianderson): Clean up last_input_event_for_vsync. crbug.com/247043 977 if (last_input_event_for_vsync) { 978 SendBeginFrame(base::TimeTicks() + 979 base::TimeDelta::FromMilliseconds(time_ms)); 980 } 981 } 982 983 void ContentViewCoreImpl::FlingStart(JNIEnv* env, jobject obj, jlong time_ms, 984 jfloat x, jfloat y, jfloat vx, jfloat vy) { 985 WebGestureEvent event = MakeGestureEvent( 986 WebInputEvent::GestureFlingStart, time_ms, x, y); 987 988 // Velocity should not be scaled by DIP since that interacts poorly with the 989 // deceleration constants. The DIP scaling is done on the renderer. 990 event.data.flingStart.velocityX = vx; 991 event.data.flingStart.velocityY = vy; 992 993 SendGestureEvent(event); 994 } 995 996 void ContentViewCoreImpl::FlingCancel(JNIEnv* env, jobject obj, jlong time_ms) { 997 WebGestureEvent event = MakeGestureEvent( 998 WebInputEvent::GestureFlingCancel, time_ms, 0, 0); 999 SendGestureEvent(event); 1000 } 1001 1002 void ContentViewCoreImpl::SingleTap(JNIEnv* env, jobject obj, jlong time_ms, 1003 jfloat x, jfloat y, 1004 jboolean disambiguation_popup_tap) { 1005 WebGestureEvent event = MakeGestureEvent( 1006 WebInputEvent::GestureTap, time_ms, x, y); 1007 1008 event.data.tap.tapCount = 1; 1009 if (!disambiguation_popup_tap) { 1010 const float touch_padding_dip = GetTouchPaddingDip(); 1011 event.data.tap.width = touch_padding_dip; 1012 event.data.tap.height = touch_padding_dip; 1013 } 1014 1015 SendGestureEvent(event); 1016 } 1017 1018 void ContentViewCoreImpl::SingleTapUnconfirmed(JNIEnv* env, jobject obj, 1019 jlong time_ms, 1020 jfloat x, jfloat y) { 1021 WebGestureEvent event = MakeGestureEvent( 1022 WebInputEvent::GestureTapUnconfirmed, time_ms, x, y); 1023 1024 event.data.tap.tapCount = 1; 1025 1026 const float touch_padding_dip = GetTouchPaddingDip(); 1027 event.data.tap.width = touch_padding_dip; 1028 event.data.tap.height = touch_padding_dip; 1029 1030 SendGestureEvent(event); 1031 } 1032 1033 void ContentViewCoreImpl::ShowPressState(JNIEnv* env, jobject obj, 1034 jlong time_ms, 1035 jfloat x, jfloat y) { 1036 WebGestureEvent event = MakeGestureEvent( 1037 WebInputEvent::GestureTapDown, time_ms, x, y); 1038 SendGestureEvent(event); 1039 } 1040 1041 void ContentViewCoreImpl::ShowPressCancel(JNIEnv* env, 1042 jobject obj, 1043 jlong time_ms, 1044 jfloat x, 1045 jfloat y) { 1046 WebGestureEvent event = MakeGestureEvent( 1047 WebInputEvent::GestureTapCancel, time_ms, x, y); 1048 SendGestureEvent(event); 1049 } 1050 1051 void ContentViewCoreImpl::DoubleTap(JNIEnv* env, jobject obj, jlong time_ms, 1052 jfloat x, jfloat y) { 1053 WebGestureEvent event = MakeGestureEvent( 1054 WebInputEvent::GestureDoubleTap, time_ms, x, y); 1055 SendGestureEvent(event); 1056 } 1057 1058 void ContentViewCoreImpl::LongPress(JNIEnv* env, jobject obj, jlong time_ms, 1059 jfloat x, jfloat y, 1060 jboolean disambiguation_popup_tap) { 1061 WebGestureEvent event = MakeGestureEvent( 1062 WebInputEvent::GestureLongPress, time_ms, x, y); 1063 1064 if (!disambiguation_popup_tap) { 1065 const float touch_padding_dip = GetTouchPaddingDip(); 1066 event.data.longPress.width = touch_padding_dip; 1067 event.data.longPress.height = touch_padding_dip; 1068 } 1069 1070 SendGestureEvent(event); 1071 } 1072 1073 void ContentViewCoreImpl::LongTap(JNIEnv* env, jobject obj, jlong time_ms, 1074 jfloat x, jfloat y, 1075 jboolean disambiguation_popup_tap) { 1076 WebGestureEvent event = MakeGestureEvent( 1077 WebInputEvent::GestureLongTap, time_ms, x, y); 1078 1079 if (!disambiguation_popup_tap) { 1080 const float touch_padding_dip = GetTouchPaddingDip(); 1081 event.data.longPress.width = touch_padding_dip; 1082 event.data.longPress.height = touch_padding_dip; 1083 } 1084 1085 SendGestureEvent(event); 1086 } 1087 1088 void ContentViewCoreImpl::PinchBegin(JNIEnv* env, jobject obj, jlong time_ms, 1089 jfloat x, jfloat y) { 1090 WebGestureEvent event = MakeGestureEvent( 1091 WebInputEvent::GesturePinchBegin, time_ms, x, y); 1092 SendGestureEvent(event); 1093 } 1094 1095 void ContentViewCoreImpl::PinchEnd(JNIEnv* env, jobject obj, jlong time_ms) { 1096 WebGestureEvent event = MakeGestureEvent( 1097 WebInputEvent::GesturePinchEnd, time_ms, 0, 0); 1098 SendGestureEvent(event); 1099 } 1100 1101 void ContentViewCoreImpl::PinchBy(JNIEnv* env, jobject obj, jlong time_ms, 1102 jfloat anchor_x, jfloat anchor_y, 1103 jfloat delta, 1104 jboolean last_input_event_for_vsync) { 1105 WebGestureEvent event = MakeGestureEvent( 1106 WebInputEvent::GesturePinchUpdate, time_ms, anchor_x, anchor_y); 1107 event.data.pinchUpdate.scale = delta; 1108 1109 SendGestureEvent(event); 1110 1111 // TODO(brianderson): Clean up last_input_event_for_vsync. crbug.com/247043 1112 if (last_input_event_for_vsync) { 1113 SendBeginFrame(base::TimeTicks() + 1114 base::TimeDelta::FromMilliseconds(time_ms)); 1115 } 1116 } 1117 1118 void ContentViewCoreImpl::SelectBetweenCoordinates(JNIEnv* env, jobject obj, 1119 jfloat x1, jfloat y1, 1120 jfloat x2, jfloat y2) { 1121 if (GetRenderWidgetHostViewAndroid()) { 1122 GetRenderWidgetHostViewAndroid()->SelectRange( 1123 gfx::Point(x1 / GetDpiScale(), y1 / GetDpiScale()), 1124 gfx::Point(x2 / GetDpiScale(), y2 / GetDpiScale())); 1125 } 1126 } 1127 1128 void ContentViewCoreImpl::MoveCaret(JNIEnv* env, jobject obj, 1129 jfloat x, jfloat y) { 1130 if (GetRenderWidgetHostViewAndroid()) { 1131 GetRenderWidgetHostViewAndroid()->MoveCaret( 1132 gfx::Point(x / GetDpiScale(), y / GetDpiScale())); 1133 } 1134 } 1135 1136 jboolean ContentViewCoreImpl::CanGoBack(JNIEnv* env, jobject obj) { 1137 return web_contents_->GetController().CanGoBack(); 1138 } 1139 1140 jboolean ContentViewCoreImpl::CanGoForward(JNIEnv* env, jobject obj) { 1141 return web_contents_->GetController().CanGoForward(); 1142 } 1143 1144 jboolean ContentViewCoreImpl::CanGoToOffset(JNIEnv* env, jobject obj, 1145 jint offset) { 1146 return web_contents_->GetController().CanGoToOffset(offset); 1147 } 1148 1149 void ContentViewCoreImpl::GoBack(JNIEnv* env, jobject obj) { 1150 web_contents_->GetController().GoBack(); 1151 UpdateTabCrashedFlag(); 1152 } 1153 1154 void ContentViewCoreImpl::GoForward(JNIEnv* env, jobject obj) { 1155 web_contents_->GetController().GoForward(); 1156 UpdateTabCrashedFlag(); 1157 } 1158 1159 void ContentViewCoreImpl::GoToOffset(JNIEnv* env, jobject obj, jint offset) { 1160 web_contents_->GetController().GoToOffset(offset); 1161 UpdateTabCrashedFlag(); 1162 } 1163 1164 void ContentViewCoreImpl::GoToNavigationIndex(JNIEnv* env, 1165 jobject obj, 1166 jint index) { 1167 web_contents_->GetController().GoToIndex(index); 1168 UpdateTabCrashedFlag(); 1169 } 1170 1171 void ContentViewCoreImpl::StopLoading(JNIEnv* env, jobject obj) { 1172 web_contents_->Stop(); 1173 } 1174 1175 void ContentViewCoreImpl::Reload(JNIEnv* env, jobject obj) { 1176 // Set check_for_repost parameter to false as we have no repost confirmation 1177 // dialog ("confirm form resubmission" screen will still appear, however). 1178 if (web_contents_->GetController().NeedsReload()) 1179 web_contents_->GetController().LoadIfNecessary(); 1180 else 1181 web_contents_->GetController().Reload(true); 1182 UpdateTabCrashedFlag(); 1183 } 1184 1185 void ContentViewCoreImpl::CancelPendingReload(JNIEnv* env, jobject obj) { 1186 web_contents_->GetController().CancelPendingReload(); 1187 } 1188 1189 void ContentViewCoreImpl::ContinuePendingReload(JNIEnv* env, jobject obj) { 1190 web_contents_->GetController().ContinuePendingReload(); 1191 } 1192 1193 void ContentViewCoreImpl::ClearHistory(JNIEnv* env, jobject obj) { 1194 // TODO(creis): Do callers of this need to know if it fails? 1195 if (web_contents_->GetController().CanPruneAllButVisible()) 1196 web_contents_->GetController().PruneAllButVisible(); 1197 } 1198 1199 void ContentViewCoreImpl::AddJavascriptInterface( 1200 JNIEnv* env, 1201 jobject /* obj */, 1202 jobject object, 1203 jstring name, 1204 jclass safe_annotation_clazz, 1205 jobject retained_object_set) { 1206 ScopedJavaLocalRef<jobject> scoped_object(env, object); 1207 ScopedJavaLocalRef<jclass> scoped_clazz(env, safe_annotation_clazz); 1208 JavaObjectWeakGlobalRef weak_retained_object_set(env, retained_object_set); 1209 1210 // JavaBoundObject creates the NPObject with a ref count of 1, and 1211 // JavaBridgeDispatcherHostManager takes its own ref. 1212 JavaBridgeDispatcherHostManager* java_bridge = 1213 web_contents_->java_bridge_dispatcher_host_manager(); 1214 java_bridge->SetRetainedObjectSet(weak_retained_object_set); 1215 NPObject* bound_object = JavaBoundObject::Create(scoped_object, scoped_clazz, 1216 java_bridge->AsWeakPtr()); 1217 java_bridge->AddNamedObject(ConvertJavaStringToUTF16(env, name), 1218 bound_object); 1219 WebKit::WebBindings::releaseObject(bound_object); 1220 } 1221 1222 void ContentViewCoreImpl::RemoveJavascriptInterface(JNIEnv* env, 1223 jobject /* obj */, 1224 jstring name) { 1225 web_contents_->java_bridge_dispatcher_host_manager()->RemoveNamedObject( 1226 ConvertJavaStringToUTF16(env, name)); 1227 } 1228 1229 void ContentViewCoreImpl::UpdateVSyncParameters(JNIEnv* env, jobject /* obj */, 1230 jlong timebase_micros, 1231 jlong interval_micros) { 1232 RenderWidgetHostViewAndroid* view = GetRenderWidgetHostViewAndroid(); 1233 if (!view) 1234 return; 1235 1236 RenderWidgetHostImpl* host = RenderWidgetHostImpl::From( 1237 view->GetRenderWidgetHost()); 1238 1239 host->UpdateVSyncParameters( 1240 base::TimeTicks::FromInternalValue(timebase_micros), 1241 base::TimeDelta::FromMicroseconds(interval_micros)); 1242 1243 vsync_interval_ = 1244 base::TimeDelta::FromMicroseconds(interval_micros); 1245 expected_browser_composite_time_ = 1246 vsync_interval_ * kDefaultBrowserCompositeVSyncFraction; 1247 } 1248 1249 void ContentViewCoreImpl::OnVSync(JNIEnv* env, jobject /* obj */, 1250 jlong frame_time_micros) { 1251 base::TimeTicks frame_time = 1252 base::TimeTicks::FromInternalValue(frame_time_micros); 1253 SendBeginFrame(frame_time); 1254 } 1255 1256 void ContentViewCoreImpl::SendBeginFrame(base::TimeTicks frame_time) { 1257 RenderWidgetHostViewAndroid* view = GetRenderWidgetHostViewAndroid(); 1258 if (!view) 1259 return; 1260 1261 base::TimeTicks display_time = frame_time + vsync_interval_; 1262 base::TimeTicks deadline = display_time - expected_browser_composite_time_; 1263 1264 view->SendBeginFrame( 1265 cc::BeginFrameArgs::Create(frame_time, deadline, vsync_interval_)); 1266 } 1267 1268 jboolean ContentViewCoreImpl::OnAnimate(JNIEnv* env, jobject /* obj */, 1269 jlong frame_time_micros) { 1270 RenderWidgetHostViewAndroid* view = GetRenderWidgetHostViewAndroid(); 1271 if (!view) 1272 return false; 1273 1274 return view->Animate(base::TimeTicks::FromInternalValue(frame_time_micros)); 1275 } 1276 1277 jboolean ContentViewCoreImpl::PopulateBitmapFromCompositor(JNIEnv* env, 1278 jobject obj, 1279 jobject jbitmap) { 1280 RenderWidgetHostViewAndroid* view = GetRenderWidgetHostViewAndroid(); 1281 if (!view) 1282 return false; 1283 1284 return view->PopulateBitmapWithContents(jbitmap); 1285 } 1286 1287 void ContentViewCoreImpl::WasResized(JNIEnv* env, jobject obj) { 1288 RenderWidgetHostViewAndroid* view = GetRenderWidgetHostViewAndroid(); 1289 if (view) 1290 view->WasResized(); 1291 } 1292 1293 void ContentViewCoreImpl::ShowInterstitialPage( 1294 JNIEnv* env, jobject obj, jstring jurl, jint delegate_ptr) { 1295 GURL url(base::android::ConvertJavaStringToUTF8(env, jurl)); 1296 InterstitialPageDelegateAndroid* delegate = 1297 reinterpret_cast<InterstitialPageDelegateAndroid*>(delegate_ptr); 1298 InterstitialPage* interstitial = InterstitialPage::Create( 1299 web_contents_, false, url, delegate); 1300 delegate->set_interstitial_page(interstitial); 1301 interstitial->Show(); 1302 } 1303 1304 jboolean ContentViewCoreImpl::IsShowingInterstitialPage(JNIEnv* env, 1305 jobject obj) { 1306 return web_contents_->ShowingInterstitialPage(); 1307 } 1308 1309 void ContentViewCoreImpl::AttachExternalVideoSurface(JNIEnv* env, 1310 jobject obj, 1311 jint player_id, 1312 jobject jsurface) { 1313 #if defined(GOOGLE_TV) 1314 RenderViewHostImpl* rvhi = static_cast<RenderViewHostImpl*>( 1315 web_contents_->GetRenderViewHost()); 1316 BrowserMediaPlayerManager* browser_media_player_manager = 1317 rvhi ? static_cast<BrowserMediaPlayerManager*>( 1318 rvhi->media_player_manager()) 1319 : NULL; 1320 if (browser_media_player_manager) { 1321 browser_media_player_manager->AttachExternalVideoSurface( 1322 static_cast<int>(player_id), jsurface); 1323 } 1324 #endif 1325 } 1326 1327 void ContentViewCoreImpl::DetachExternalVideoSurface(JNIEnv* env, 1328 jobject obj, 1329 jint player_id) { 1330 #if defined(GOOGLE_TV) 1331 RenderViewHostImpl* rvhi = static_cast<RenderViewHostImpl*>( 1332 web_contents_->GetRenderViewHost()); 1333 BrowserMediaPlayerManager* browser_media_player_manager = 1334 rvhi ? static_cast<BrowserMediaPlayerManager*>( 1335 rvhi->media_player_manager()) 1336 : NULL; 1337 if (browser_media_player_manager) { 1338 browser_media_player_manager->DetachExternalVideoSurface( 1339 static_cast<int>(player_id)); 1340 } 1341 #endif 1342 } 1343 1344 jboolean ContentViewCoreImpl::IsRenderWidgetHostViewReady(JNIEnv* env, 1345 jobject obj) { 1346 RenderWidgetHostViewAndroid* view = GetRenderWidgetHostViewAndroid(); 1347 return view && view->HasValidFrame(); 1348 } 1349 1350 void ContentViewCoreImpl::ExitFullscreen(JNIEnv* env, jobject obj) { 1351 RenderViewHost* host = web_contents_->GetRenderViewHost(); 1352 host->ExitFullscreen(); 1353 } 1354 1355 void ContentViewCoreImpl::UpdateTopControlsState(JNIEnv* env, 1356 jobject obj, 1357 bool enable_hiding, 1358 bool enable_showing, 1359 bool animate) { 1360 RenderViewHost* host = web_contents_->GetRenderViewHost(); 1361 host->Send(new ViewMsg_UpdateTopControlsState(host->GetRoutingID(), 1362 enable_hiding, 1363 enable_showing, 1364 animate)); 1365 } 1366 1367 void ContentViewCoreImpl::ShowImeIfNeeded(JNIEnv* env, jobject obj) { 1368 RenderViewHost* host = web_contents_->GetRenderViewHost(); 1369 host->Send(new ViewMsg_ShowImeIfNeeded(host->GetRoutingID())); 1370 } 1371 1372 void ContentViewCoreImpl::ScrollFocusedEditableNodeIntoView(JNIEnv* env, 1373 jobject obj) { 1374 RenderViewHost* host = web_contents_->GetRenderViewHost(); 1375 host->Send(new InputMsg_ScrollFocusedEditableNodeIntoRect( 1376 host->GetRoutingID(), gfx::Rect())); 1377 } 1378 1379 namespace { 1380 1381 static void AddNavigationEntryToHistory(JNIEnv* env, jobject obj, 1382 jobject history, 1383 NavigationEntry* entry, 1384 int index) { 1385 // Get the details of the current entry 1386 ScopedJavaLocalRef<jstring> j_url( 1387 ConvertUTF8ToJavaString(env, entry->GetURL().spec())); 1388 ScopedJavaLocalRef<jstring> j_virtual_url( 1389 ConvertUTF8ToJavaString(env, entry->GetVirtualURL().spec())); 1390 ScopedJavaLocalRef<jstring> j_original_url( 1391 ConvertUTF8ToJavaString(env, entry->GetOriginalRequestURL().spec())); 1392 ScopedJavaLocalRef<jstring> j_title( 1393 ConvertUTF16ToJavaString(env, entry->GetTitle())); 1394 ScopedJavaLocalRef<jobject> j_bitmap; 1395 const FaviconStatus& status = entry->GetFavicon(); 1396 if (status.valid && status.image.ToSkBitmap()->getSize() > 0) 1397 j_bitmap = gfx::ConvertToJavaBitmap(status.image.ToSkBitmap()); 1398 1399 // Add the item to the list 1400 Java_ContentViewCore_addToNavigationHistory( 1401 env, obj, history, index, j_url.obj(), j_virtual_url.obj(), 1402 j_original_url.obj(), j_title.obj(), j_bitmap.obj()); 1403 } 1404 1405 } // namespace 1406 1407 int ContentViewCoreImpl::GetNavigationHistory(JNIEnv* env, 1408 jobject obj, 1409 jobject history) { 1410 // Iterate through navigation entries to populate the list 1411 const NavigationController& controller = web_contents_->GetController(); 1412 int count = controller.GetEntryCount(); 1413 for (int i = 0; i < count; ++i) { 1414 AddNavigationEntryToHistory( 1415 env, obj, history, controller.GetEntryAtIndex(i), i); 1416 } 1417 1418 return controller.GetCurrentEntryIndex(); 1419 } 1420 1421 void ContentViewCoreImpl::GetDirectedNavigationHistory(JNIEnv* env, 1422 jobject obj, 1423 jobject history, 1424 jboolean is_forward, 1425 jint max_entries) { 1426 // Iterate through navigation entries to populate the list 1427 const NavigationController& controller = web_contents_->GetController(); 1428 int count = controller.GetEntryCount(); 1429 int num_added = 0; 1430 int increment_value = is_forward ? 1 : -1; 1431 for (int i = controller.GetCurrentEntryIndex() + increment_value; 1432 i >= 0 && i < count; 1433 i += increment_value) { 1434 if (num_added >= max_entries) 1435 break; 1436 1437 AddNavigationEntryToHistory( 1438 env, obj, history, controller.GetEntryAtIndex(i), i); 1439 num_added++; 1440 } 1441 } 1442 1443 ScopedJavaLocalRef<jstring> 1444 ContentViewCoreImpl::GetOriginalUrlForActiveNavigationEntry(JNIEnv* env, 1445 jobject obj) { 1446 NavigationEntry* entry = web_contents_->GetController().GetActiveEntry(); 1447 if (entry == NULL) 1448 return ScopedJavaLocalRef<jstring>(env, NULL); 1449 return ConvertUTF8ToJavaString(env, entry->GetOriginalRequestURL().spec()); 1450 } 1451 1452 int ContentViewCoreImpl::GetNativeImeAdapter(JNIEnv* env, jobject obj) { 1453 RenderWidgetHostViewAndroid* rwhva = GetRenderWidgetHostViewAndroid(); 1454 if (!rwhva) 1455 return 0; 1456 return rwhva->GetNativeImeAdapter(); 1457 } 1458 1459 jboolean ContentViewCoreImpl::NeedsReload(JNIEnv* env, jobject obj) { 1460 return web_contents_->GetController().NeedsReload(); 1461 } 1462 1463 void ContentViewCoreImpl::UndoScrollFocusedEditableNodeIntoView( 1464 JNIEnv* env, 1465 jobject obj) { 1466 RenderViewHost* host = web_contents_->GetRenderViewHost(); 1467 host->Send( 1468 new ViewMsg_UndoScrollFocusedEditableNodeIntoView(host->GetRoutingID())); 1469 } 1470 1471 namespace { 1472 void JavaScriptResultCallback(const ScopedJavaGlobalRef<jobject>& callback, 1473 const base::Value* result) { 1474 JNIEnv* env = base::android::AttachCurrentThread(); 1475 std::string json; 1476 base::JSONWriter::Write(result, &json); 1477 ScopedJavaLocalRef<jstring> j_json = ConvertUTF8ToJavaString(env, json); 1478 Java_ContentViewCore_onEvaluateJavaScriptResult(env, 1479 j_json.obj(), 1480 callback.obj()); 1481 } 1482 } // namespace 1483 1484 void ContentViewCoreImpl::EvaluateJavaScript(JNIEnv* env, 1485 jobject obj, 1486 jstring script, 1487 jobject callback, 1488 jboolean start_renderer) { 1489 RenderViewHost* rvh = web_contents_->GetRenderViewHost(); 1490 DCHECK(rvh); 1491 1492 if (start_renderer && !rvh->IsRenderViewLive()) { 1493 if (!web_contents_->CreateRenderViewForInitialEmptyDocument()) { 1494 LOG(ERROR) << "Failed to create RenderView in EvaluateJavaScript"; 1495 return; 1496 } 1497 } 1498 1499 if (!callback) { 1500 // No callback requested. 1501 rvh->ExecuteJavascriptInWebFrame(string16(), // frame_xpath 1502 ConvertJavaStringToUTF16(env, script)); 1503 return; 1504 } 1505 1506 // Secure the Java callback in a scoped object and give ownership of it to the 1507 // base::Callback. 1508 ScopedJavaGlobalRef<jobject> j_callback; 1509 j_callback.Reset(env, callback); 1510 content::RenderViewHost::JavascriptResultCallback c_callback = 1511 base::Bind(&JavaScriptResultCallback, j_callback); 1512 1513 rvh->ExecuteJavascriptInWebFrameCallbackResult( 1514 string16(), // frame_xpath 1515 ConvertJavaStringToUTF16(env, script), 1516 c_callback); 1517 } 1518 1519 bool ContentViewCoreImpl::GetUseDesktopUserAgent( 1520 JNIEnv* env, jobject obj) { 1521 NavigationEntry* entry = web_contents_->GetController().GetActiveEntry(); 1522 return entry && entry->GetIsOverridingUserAgent(); 1523 } 1524 1525 void ContentViewCoreImpl::UpdateImeAdapter(int native_ime_adapter, 1526 int text_input_type, 1527 const std::string& text, 1528 int selection_start, 1529 int selection_end, 1530 int composition_start, 1531 int composition_end, 1532 bool show_ime_if_needed) { 1533 JNIEnv* env = AttachCurrentThread(); 1534 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env); 1535 if (obj.is_null()) 1536 return; 1537 1538 ScopedJavaLocalRef<jstring> jstring_text = ConvertUTF8ToJavaString(env, text); 1539 Java_ContentViewCore_updateImeAdapter(env, obj.obj(), 1540 native_ime_adapter, text_input_type, 1541 jstring_text.obj(), 1542 selection_start, selection_end, 1543 composition_start, composition_end, 1544 show_ime_if_needed); 1545 } 1546 1547 void ContentViewCoreImpl::ProcessImeBatchStateAck(bool is_begin) { 1548 JNIEnv* env = AttachCurrentThread(); 1549 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env); 1550 if (obj.is_null()) 1551 return; 1552 Java_ContentViewCore_processImeBatchStateAck(env, obj.obj(), is_begin); 1553 } 1554 1555 void ContentViewCoreImpl::ClearSslPreferences(JNIEnv* env, jobject obj) { 1556 SSLHostState* state = SSLHostState::GetFor( 1557 web_contents_->GetController().GetBrowserContext()); 1558 state->Clear(); 1559 } 1560 1561 void ContentViewCoreImpl::SetUseDesktopUserAgent( 1562 JNIEnv* env, 1563 jobject obj, 1564 jboolean enabled, 1565 jboolean reload_on_state_change) { 1566 if (GetUseDesktopUserAgent(env, obj) == enabled) 1567 return; 1568 1569 // Make sure the navigation entry actually exists. 1570 NavigationEntry* entry = web_contents_->GetController().GetActiveEntry(); 1571 if (!entry) 1572 return; 1573 1574 // Set the flag in the NavigationEntry. 1575 entry->SetIsOverridingUserAgent(enabled); 1576 1577 // Send the override to the renderer. 1578 if (reload_on_state_change) { 1579 // Reloading the page will send the override down as part of the 1580 // navigation IPC message. 1581 NavigationControllerImpl& controller = 1582 static_cast<NavigationControllerImpl&>(web_contents_->GetController()); 1583 controller.ReloadOriginalRequestURL(false); 1584 } 1585 } 1586 1587 void ContentViewCoreImpl::SetAccessibilityEnabled(JNIEnv* env, jobject obj, 1588 bool enabled) { 1589 RenderWidgetHostViewAndroid* host_view = GetRenderWidgetHostViewAndroid(); 1590 if (!host_view) 1591 return; 1592 RenderWidgetHostImpl* host_impl = RenderWidgetHostImpl::From( 1593 host_view->GetRenderWidgetHost()); 1594 BrowserAccessibilityState* accessibility_state = 1595 BrowserAccessibilityState::GetInstance(); 1596 if (enabled) { 1597 // This enables accessibility globally unless it was explicitly disallowed 1598 // by a command-line flag. 1599 accessibility_state->OnScreenReaderDetected(); 1600 // If it was actually enabled globally, enable it for this RenderWidget now. 1601 if (accessibility_state->IsAccessibleBrowser() && host_impl) 1602 host_impl->SetAccessibilityMode(AccessibilityModeComplete); 1603 } else { 1604 accessibility_state->DisableAccessibility(); 1605 if (host_impl) 1606 host_impl->SetAccessibilityMode(AccessibilityModeOff); 1607 } 1608 } 1609 1610 // This is called for each ContentView. 1611 jint Init(JNIEnv* env, jobject obj, 1612 jboolean hardware_accelerated, 1613 jint native_web_contents, 1614 jint view_android, 1615 jint window_android) { 1616 ContentViewCoreImpl* view = new ContentViewCoreImpl( 1617 env, obj, hardware_accelerated, 1618 reinterpret_cast<WebContents*>(native_web_contents), 1619 reinterpret_cast<ui::ViewAndroid*>(view_android), 1620 reinterpret_cast<ui::WindowAndroid*>(window_android)); 1621 return reinterpret_cast<jint>(view); 1622 } 1623 1624 bool RegisterContentViewCore(JNIEnv* env) { 1625 return RegisterNativesImpl(env); 1626 } 1627 1628 } // namespace content 1629