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