aw_contents.cc revision 8e502b6b4304d7e73f45e488c4824ea91782ff16
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 "android_webview/native/aw_contents.h"
6
7#include "android_webview/browser/aw_browser_context.h"
8#include "android_webview/browser/aw_browser_main_parts.h"
9#include "android_webview/browser/gpu_memory_buffer_factory_impl.h"
10#include "android_webview/browser/in_process_view_renderer.h"
11#include "android_webview/browser/net_disk_cache_remover.h"
12#include "android_webview/browser/renderer_host/aw_resource_dispatcher_host_delegate.h"
13#include "android_webview/common/aw_hit_test_data.h"
14#include "android_webview/native/aw_autofill_manager_delegate.h"
15#include "android_webview/native/aw_browser_dependency_factory.h"
16#include "android_webview/native/aw_contents_client_bridge.h"
17#include "android_webview/native/aw_contents_io_thread_client_impl.h"
18// START: Printing fork b/10190508
19#include "android_webview/native/aw_pdf_exporter.h"
20// END: Printing fork b/10190508
21#include "android_webview/native/aw_picture.h"
22#include "android_webview/native/aw_web_contents_delegate.h"
23#include "android_webview/native/java_browser_view_renderer_helper.h"
24#include "android_webview/native/state_serializer.h"
25#include "android_webview/public/browser/draw_gl.h"
26#include "base/android/jni_android.h"
27#include "base/android/jni_array.h"
28#include "base/android/jni_string.h"
29#include "base/android/scoped_java_ref.h"
30#include "base/atomicops.h"
31#include "base/bind.h"
32#include "base/callback.h"
33#include "base/message_loop/message_loop.h"
34#include "base/pickle.h"
35#include "base/strings/string16.h"
36#include "base/supports_user_data.h"
37#include "components/autofill/content/browser/autofill_driver_impl.h"
38#include "components/autofill/core/browser/autofill_manager.h"
39#include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
40#include "components/navigation_interception/intercept_navigation_delegate.h"
41#include "content/public/browser/android/content_view_core.h"
42#include "content/public/browser/browser_thread.h"
43#include "content/public/browser/cert_store.h"
44#include "content/public/browser/favicon_status.h"
45#include "content/public/browser/navigation_entry.h"
46#include "content/public/browser/render_process_host.h"
47#include "content/public/browser/render_view_host.h"
48#include "content/public/browser/web_contents.h"
49#include "content/public/common/renderer_preferences.h"
50#include "content/public/common/ssl_status.h"
51#include "jni/AwContents_jni.h"
52#include "net/cert/x509_certificate.h"
53#include "third_party/skia/include/core/SkPicture.h"
54#include "ui/base/l10n/l10n_util_android.h"
55#include "ui/gfx/android/java_bitmap.h"
56#include "ui/gfx/image/image.h"
57
58struct AwDrawSWFunctionTable;
59struct AwDrawGLFunctionTable;
60
61using autofill::AutofillDriverImpl;
62using autofill::AutofillManager;
63using base::android::AttachCurrentThread;
64using base::android::ConvertJavaStringToUTF16;
65using base::android::ConvertJavaStringToUTF8;
66using base::android::ConvertUTF16ToJavaString;
67using base::android::ConvertUTF8ToJavaString;
68using base::android::JavaRef;
69using base::android::ScopedJavaGlobalRef;
70using base::android::ScopedJavaLocalRef;
71using navigation_interception::InterceptNavigationDelegate;
72using content::BrowserThread;
73using content::ContentViewCore;
74using content::WebContents;
75
76extern "C" {
77static AwDrawGLFunction DrawGLFunction;
78static void DrawGLFunction(int view_context,
79                           AwDrawGLInfo* draw_info,
80                           void* spare) {
81  // |view_context| is the value that was returned from the java
82  // AwContents.onPrepareDrawGL; this cast must match the code there.
83  reinterpret_cast<android_webview::BrowserViewRenderer*>(view_context)->DrawGL(
84      draw_info);
85}
86}
87
88namespace android_webview {
89
90namespace {
91
92JavaBrowserViewRendererHelper* java_renderer_helper() {
93  return JavaBrowserViewRendererHelper::GetInstance();
94}
95
96const void* kAwContentsUserDataKey = &kAwContentsUserDataKey;
97
98class AwContentsUserData : public base::SupportsUserData::Data {
99 public:
100  AwContentsUserData(AwContents* ptr) : contents_(ptr) {}
101
102  static AwContents* GetContents(WebContents* web_contents) {
103    if (!web_contents)
104      return NULL;
105    AwContentsUserData* data = reinterpret_cast<AwContentsUserData*>(
106        web_contents->GetUserData(kAwContentsUserDataKey));
107    return data ? data->contents_ : NULL;
108  }
109
110 private:
111  AwContents* contents_;
112};
113
114base::subtle::Atomic32 g_instance_count = 0;
115
116}  // namespace
117
118// static
119AwContents* AwContents::FromWebContents(WebContents* web_contents) {
120  return AwContentsUserData::GetContents(web_contents);
121}
122
123// static
124AwContents* AwContents::FromID(int render_process_id, int render_view_id) {
125  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
126  const content::RenderViewHost* rvh =
127      content::RenderViewHost::FromID(render_process_id, render_view_id);
128  if (!rvh) return NULL;
129  content::WebContents* web_contents =
130      content::WebContents::FromRenderViewHost(rvh);
131  if (!web_contents) return NULL;
132  return FromWebContents(web_contents);
133}
134
135AwContents::AwContents(scoped_ptr<WebContents> web_contents)
136    : web_contents_(web_contents.Pass()),
137      browser_view_renderer_(
138          new InProcessViewRenderer(this, java_renderer_helper(),
139                                    web_contents_.get())) {
140  base::subtle::NoBarrier_AtomicIncrement(&g_instance_count, 1);
141  icon_helper_.reset(new IconHelper(web_contents_.get()));
142  icon_helper_->SetListener(this);
143  web_contents_->SetUserData(kAwContentsUserDataKey,
144                             new AwContentsUserData(this));
145  render_view_host_ext_.reset(
146      new AwRenderViewHostExt(this, web_contents_.get()));
147
148  AwAutofillManagerDelegate* autofill_manager_delegate =
149      AwAutofillManagerDelegate::FromWebContents(web_contents_.get());
150  if (autofill_manager_delegate)
151    InitAutofillIfNecessary(autofill_manager_delegate->GetSaveFormData());
152
153  web_contents_->GetMutableRendererPrefs()->tap_multiple_targets_strategy =
154      content::TAP_MULTIPLE_TARGETS_STRATEGY_NONE;
155}
156
157void AwContents::SetJavaPeers(JNIEnv* env,
158                              jobject obj,
159                              jobject aw_contents,
160                              jobject web_contents_delegate,
161                              jobject contents_client_bridge,
162                              jobject io_thread_client,
163                              jobject intercept_navigation_delegate) {
164  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
165  // The |aw_content| param is technically spurious as it duplicates |obj| but
166  // is passed over anyway to make the binding more explicit.
167  java_ref_ = JavaObjectWeakGlobalRef(env, aw_contents);
168
169  web_contents_delegate_.reset(
170      new AwWebContentsDelegate(env, web_contents_delegate));
171  web_contents_->SetDelegate(web_contents_delegate_.get());
172
173  contents_client_bridge_.reset(
174      new AwContentsClientBridge(env, contents_client_bridge));
175  AwContentsClientBridgeBase::Associate(web_contents_.get(),
176                                        contents_client_bridge_.get());
177
178  AwContentsIoThreadClientImpl::Associate(
179      web_contents_.get(), ScopedJavaLocalRef<jobject>(env, io_thread_client));
180  int child_id = web_contents_->GetRenderProcessHost()->GetID();
181  int route_id = web_contents_->GetRoutingID();
182  AwResourceDispatcherHostDelegate::OnIoThreadClientReady(child_id, route_id);
183
184  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
185  InterceptNavigationDelegate::Associate(
186      web_contents_.get(),
187      make_scoped_ptr(new InterceptNavigationDelegate(
188          env, intercept_navigation_delegate)));
189}
190
191void AwContents::SetSaveFormData(bool enabled) {
192  InitAutofillIfNecessary(enabled);
193  // We need to check for the existence, since autofill_manager_delegate
194  // may not be created when the setting is false.
195  if (AutofillDriverImpl::FromWebContents(web_contents_.get())) {
196    AwAutofillManagerDelegate::FromWebContents(web_contents_.get())->
197        SetSaveFormData(enabled);
198  }
199}
200
201void AwContents::InitAutofillIfNecessary(bool enabled) {
202  // Do not initialize if the feature is not enabled.
203  if (!enabled)
204    return;
205  // Check if the autofill driver already exists.
206  content::WebContents* web_contents = web_contents_.get();
207  if (AutofillDriverImpl::FromWebContents(web_contents))
208    return;
209
210  AwBrowserContext::FromWebContents(web_contents)->
211      CreateUserPrefServiceIfNecessary();
212  AwAutofillManagerDelegate::CreateForWebContents(web_contents);
213  AutofillDriverImpl::CreateForWebContentsAndDelegate(
214      web_contents,
215      AwAutofillManagerDelegate::FromWebContents(web_contents),
216      l10n_util::GetDefaultLocale(),
217      AutofillManager::DISABLE_AUTOFILL_DOWNLOAD_MANAGER);
218}
219
220void AwContents::SetAwAutofillManagerDelegate(jobject delegate) {
221  JNIEnv* env = AttachCurrentThread();
222  ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
223  if (obj.is_null())
224    return;
225  Java_AwContents_setAwAutofillManagerDelegate(env, obj.obj(), delegate);
226}
227
228AwContents::~AwContents() {
229  DCHECK(AwContents::FromWebContents(web_contents_.get()) == this);
230  web_contents_->RemoveUserData(kAwContentsUserDataKey);
231  if (find_helper_.get())
232    find_helper_->SetListener(NULL);
233  if (icon_helper_.get())
234    icon_helper_->SetListener(NULL);
235  base::subtle::NoBarrier_AtomicIncrement(&g_instance_count, -1);
236}
237
238jint AwContents::GetWebContents(JNIEnv* env, jobject obj) {
239  DCHECK(web_contents_);
240  return reinterpret_cast<jint>(web_contents_.get());
241}
242
243void AwContents::Destroy(JNIEnv* env, jobject obj) {
244  delete this;
245}
246
247static jint Init(JNIEnv* env, jclass, jobject browser_context) {
248  // TODO(joth): Use |browser_context| to get the native BrowserContext, rather
249  // than hard-code the default instance lookup here.
250  scoped_ptr<WebContents> web_contents(content::WebContents::Create(
251      content::WebContents::CreateParams(AwBrowserContext::GetDefault())));
252  // Return an 'uninitialized' instance; most work is deferred until the
253  // subsequent SetJavaPeers() call.
254  return reinterpret_cast<jint>(new AwContents(web_contents.Pass()));
255}
256
257static void SetAwDrawSWFunctionTable(JNIEnv* env, jclass, jint function_table) {
258  BrowserViewRenderer::SetAwDrawSWFunctionTable(
259      reinterpret_cast<AwDrawSWFunctionTable*>(function_table));
260}
261
262static void SetAwDrawGLFunctionTable(JNIEnv* env, jclass, jint function_table) {
263  GpuMemoryBufferFactoryImpl::SetAwDrawGLFunctionTable(
264      reinterpret_cast<AwDrawGLFunctionTable*>(function_table));
265}
266
267static jint GetAwDrawGLFunction(JNIEnv* env, jclass) {
268  return reinterpret_cast<jint>(&DrawGLFunction);
269}
270
271// static
272jint GetNativeInstanceCount(JNIEnv* env, jclass) {
273  return base::subtle::NoBarrier_Load(&g_instance_count);
274}
275
276jint AwContents::GetAwDrawGLViewContext(JNIEnv* env, jobject obj) {
277  return reinterpret_cast<jint>(browser_view_renderer_.get());
278}
279
280namespace {
281void DocumentHasImagesCallback(const ScopedJavaGlobalRef<jobject>& message,
282                               bool has_images) {
283  Java_AwContents_onDocumentHasImagesResponse(AttachCurrentThread(),
284                                              has_images,
285                                              message.obj());
286}
287}  // namespace
288
289void AwContents::DocumentHasImages(JNIEnv* env, jobject obj, jobject message) {
290  ScopedJavaGlobalRef<jobject> j_message;
291  j_message.Reset(env, message);
292  render_view_host_ext_->DocumentHasImages(
293      base::Bind(&DocumentHasImagesCallback, j_message));
294}
295
296namespace {
297void GenerateMHTMLCallback(ScopedJavaGlobalRef<jobject>* callback,
298                           const base::FilePath& path, int64 size) {
299  JNIEnv* env = AttachCurrentThread();
300  // Android files are UTF8, so the path conversion below is safe.
301  Java_AwContents_generateMHTMLCallback(
302      env,
303      ConvertUTF8ToJavaString(env, path.AsUTF8Unsafe()).obj(),
304      size, callback->obj());
305}
306}  // namespace
307
308void AwContents::GenerateMHTML(JNIEnv* env, jobject obj,
309                               jstring jpath, jobject callback) {
310  ScopedJavaGlobalRef<jobject>* j_callback = new ScopedJavaGlobalRef<jobject>();
311  j_callback->Reset(env, callback);
312  web_contents_->GenerateMHTML(
313      base::FilePath(ConvertJavaStringToUTF8(env, jpath)),
314      base::Bind(&GenerateMHTMLCallback, base::Owned(j_callback)));
315}
316
317// START: Printing fork b/10190508
318void AwContents::CreatePdfExporter(JNIEnv* env,
319                                   jobject obj,
320                                   jobject pdfExporter) {
321
322  pdf_exporter_.reset(
323      new AwPdfExporter(env,
324                        pdfExporter,
325                        browser_view_renderer_.get(),
326                        web_contents_.get()));
327}
328// END: Printing fork b/10190508
329
330void AwContents::PerformLongClick() {
331  JNIEnv* env = AttachCurrentThread();
332  ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
333  if (obj.is_null())
334    return;
335
336  Java_AwContents_performLongClick(env, obj.obj());
337}
338
339bool AwContents::OnReceivedHttpAuthRequest(const JavaRef<jobject>& handler,
340                                           const std::string& host,
341                                           const std::string& realm) {
342  JNIEnv* env = AttachCurrentThread();
343  ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
344  if (obj.is_null())
345    return false;
346
347  ScopedJavaLocalRef<jstring> jhost = ConvertUTF8ToJavaString(env, host);
348  ScopedJavaLocalRef<jstring> jrealm = ConvertUTF8ToJavaString(env, realm);
349  Java_AwContents_onReceivedHttpAuthRequest(env, obj.obj(), handler.obj(),
350      jhost.obj(), jrealm.obj());
351  return true;
352}
353
354void AwContents::AddVisitedLinks(JNIEnv* env,
355                                   jobject obj,
356                                   jobjectArray jvisited_links) {
357  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
358  std::vector<string16> visited_link_strings;
359  base::android::AppendJavaStringArrayToStringVector(
360      env, jvisited_links, &visited_link_strings);
361
362  std::vector<GURL> visited_link_gurls;
363  for (std::vector<string16>::const_iterator itr = visited_link_strings.begin();
364       itr != visited_link_strings.end();
365       ++itr) {
366    visited_link_gurls.push_back(GURL(*itr));
367  }
368
369  AwBrowserContext::FromWebContents(web_contents_.get())
370      ->AddVisitedURLs(visited_link_gurls);
371}
372
373bool RegisterAwContents(JNIEnv* env) {
374  return RegisterNativesImpl(env) >= 0;
375}
376
377namespace {
378
379void ShowGeolocationPromptHelperTask(const JavaObjectWeakGlobalRef& java_ref,
380                                     const GURL& origin) {
381  JNIEnv* env = AttachCurrentThread();
382  ScopedJavaLocalRef<jobject> j_ref = java_ref.get(env);
383  if (j_ref.obj()) {
384    ScopedJavaLocalRef<jstring> j_origin(
385        ConvertUTF8ToJavaString(env, origin.spec()));
386    Java_AwContents_onGeolocationPermissionsShowPrompt(env,
387                                                       j_ref.obj(),
388                                                       j_origin.obj());
389  }
390}
391
392void ShowGeolocationPromptHelper(const JavaObjectWeakGlobalRef& java_ref,
393                                 const GURL& origin) {
394  JNIEnv* env = AttachCurrentThread();
395  if (java_ref.get(env).obj()) {
396    content::BrowserThread::PostTask(
397        content::BrowserThread::UI,
398        FROM_HERE,
399        base::Bind(&ShowGeolocationPromptHelperTask,
400                   java_ref,
401                   origin));
402  }
403}
404
405} // anonymous namespace
406
407void AwContents::ShowGeolocationPrompt(const GURL& requesting_frame,
408                                       base::Callback<void(bool)> callback) {
409  GURL origin = requesting_frame.GetOrigin();
410  bool show_prompt = pending_geolocation_prompts_.empty();
411  pending_geolocation_prompts_.push_back(OriginCallback(origin, callback));
412  if (show_prompt) {
413    ShowGeolocationPromptHelper(java_ref_, origin);
414  }
415}
416
417// Invoked from Java
418void AwContents::InvokeGeolocationCallback(JNIEnv* env,
419                                           jobject obj,
420                                           jboolean value,
421                                           jstring origin) {
422  GURL callback_origin(base::android::ConvertJavaStringToUTF16(env, origin));
423  if (callback_origin.GetOrigin() ==
424      pending_geolocation_prompts_.front().first) {
425    pending_geolocation_prompts_.front().second.Run(value);
426    pending_geolocation_prompts_.pop_front();
427    if (!pending_geolocation_prompts_.empty()) {
428      ShowGeolocationPromptHelper(java_ref_,
429                                  pending_geolocation_prompts_.front().first);
430    }
431  }
432}
433
434void AwContents::HideGeolocationPrompt(const GURL& origin) {
435  bool removed_current_outstanding_callback = false;
436  std::list<OriginCallback>::iterator it = pending_geolocation_prompts_.begin();
437  while (it != pending_geolocation_prompts_.end()) {
438    if ((*it).first == origin.GetOrigin()) {
439      if (it == pending_geolocation_prompts_.begin()) {
440        removed_current_outstanding_callback = true;
441      }
442      it = pending_geolocation_prompts_.erase(it);
443    } else {
444      ++it;
445    }
446  }
447
448  if (removed_current_outstanding_callback) {
449    JNIEnv* env = AttachCurrentThread();
450    ScopedJavaLocalRef<jobject> j_ref = java_ref_.get(env);
451    if (j_ref.obj()) {
452      Java_AwContents_onGeolocationPermissionsHidePrompt(env, j_ref.obj());
453    }
454    if (!pending_geolocation_prompts_.empty()) {
455      ShowGeolocationPromptHelper(java_ref_,
456                            pending_geolocation_prompts_.front().first);
457    }
458  }
459}
460
461void AwContents::FindAllAsync(JNIEnv* env, jobject obj, jstring search_string) {
462  GetFindHelper()->FindAllAsync(ConvertJavaStringToUTF16(env, search_string));
463}
464
465void AwContents::FindNext(JNIEnv* env, jobject obj, jboolean forward) {
466  GetFindHelper()->FindNext(forward);
467}
468
469void AwContents::ClearMatches(JNIEnv* env, jobject obj) {
470  GetFindHelper()->ClearMatches();
471}
472
473void AwContents::ClearCache(
474    JNIEnv* env,
475    jobject obj,
476    jboolean include_disk_files) {
477  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
478  render_view_host_ext_->ClearCache();
479
480  if (include_disk_files) {
481    RemoveHttpDiskCache(web_contents_->GetBrowserContext(),
482                        web_contents_->GetRoutingID());
483  }
484}
485
486FindHelper* AwContents::GetFindHelper() {
487  if (!find_helper_.get()) {
488    find_helper_.reset(new FindHelper(web_contents_.get()));
489    find_helper_->SetListener(this);
490  }
491  return find_helper_.get();
492}
493
494void AwContents::OnFindResultReceived(int active_ordinal,
495                                      int match_count,
496                                      bool finished) {
497  JNIEnv* env = AttachCurrentThread();
498  ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
499  if (obj.is_null())
500    return;
501
502  Java_AwContents_onFindResultReceived(
503      env, obj.obj(), active_ordinal, match_count, finished);
504}
505
506void AwContents::OnReceivedIcon(const GURL& icon_url, const SkBitmap& bitmap) {
507  JNIEnv* env = AttachCurrentThread();
508  ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
509  if (obj.is_null())
510    return;
511
512  content::NavigationEntry* entry =
513      web_contents_->GetController().GetActiveEntry();
514
515  if (entry) {
516    entry->GetFavicon().valid = true;
517    entry->GetFavicon().url = icon_url;
518    entry->GetFavicon().image = gfx::Image::CreateFrom1xBitmap(bitmap);
519  }
520
521  Java_AwContents_onReceivedIcon(
522      env, obj.obj(), gfx::ConvertToJavaBitmap(&bitmap).obj());
523}
524
525void AwContents::OnReceivedTouchIconUrl(const std::string& url,
526                                        bool precomposed) {
527  JNIEnv* env = AttachCurrentThread();
528  ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
529  if (obj.is_null())
530    return;
531
532  Java_AwContents_onReceivedTouchIconUrl(
533      env, obj.obj(), ConvertUTF8ToJavaString(env, url).obj(), precomposed);
534}
535
536bool AwContents::RequestDrawGL(jobject canvas) {
537  JNIEnv* env = AttachCurrentThread();
538  ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
539  if (obj.is_null())
540    return false;
541  return Java_AwContents_requestDrawGL(env, obj.obj(), canvas);
542}
543
544void AwContents::PostInvalidate() {
545  JNIEnv* env = AttachCurrentThread();
546  ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
547  if (!obj.is_null())
548    Java_AwContents_postInvalidateOnAnimation(env, obj.obj());
549}
550
551void AwContents::UpdateGlobalVisibleRect() {
552  JNIEnv* env = AttachCurrentThread();
553  ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
554  if (!obj.is_null())
555    Java_AwContents_updateGlobalVisibleRect(env, obj.obj());
556}
557
558void AwContents::OnNewPicture() {
559  JNIEnv* env = AttachCurrentThread();
560  ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
561  if (!obj.is_null())
562    Java_AwContents_onNewPicture(env, obj.obj());
563}
564
565base::android::ScopedJavaLocalRef<jbyteArray>
566    AwContents::GetCertificate(JNIEnv* env,
567                               jobject obj) {
568  content::NavigationEntry* entry =
569      web_contents_->GetController().GetActiveEntry();
570  if (!entry)
571    return ScopedJavaLocalRef<jbyteArray>();
572  // Get the certificate
573  int cert_id = entry->GetSSL().cert_id;
574  scoped_refptr<net::X509Certificate> cert;
575  bool ok = content::CertStore::GetInstance()->RetrieveCert(cert_id, &cert);
576  if (!ok)
577    return ScopedJavaLocalRef<jbyteArray>();
578
579  // Convert the certificate and return it
580  std::string der_string;
581  net::X509Certificate::GetDEREncoded(cert->os_cert_handle(), &der_string);
582  return base::android::ToJavaByteArray(env,
583      reinterpret_cast<const uint8*>(der_string.data()), der_string.length());
584}
585
586void AwContents::RequestNewHitTestDataAt(JNIEnv* env, jobject obj,
587                                         jint x, jint y) {
588  render_view_host_ext_->RequestNewHitTestDataAt(x, y);
589}
590
591void AwContents::UpdateLastHitTestData(JNIEnv* env, jobject obj) {
592  if (!render_view_host_ext_->HasNewHitTestData()) return;
593
594  const AwHitTestData& data = render_view_host_ext_->GetLastHitTestData();
595  render_view_host_ext_->MarkHitTestDataRead();
596
597  // Make sure to null the Java object if data is empty/invalid.
598  ScopedJavaLocalRef<jstring> extra_data_for_type;
599  if (data.extra_data_for_type.length())
600    extra_data_for_type = ConvertUTF8ToJavaString(
601        env, data.extra_data_for_type);
602
603  ScopedJavaLocalRef<jstring> href;
604  if (data.href.length())
605    href = ConvertUTF16ToJavaString(env, data.href);
606
607  ScopedJavaLocalRef<jstring> anchor_text;
608  if (data.anchor_text.length())
609    anchor_text = ConvertUTF16ToJavaString(env, data.anchor_text);
610
611  ScopedJavaLocalRef<jstring> img_src;
612  if (data.img_src.is_valid())
613    img_src = ConvertUTF8ToJavaString(env, data.img_src.spec());
614
615  Java_AwContents_updateHitTestData(env,
616                                    obj,
617                                    data.type,
618                                    extra_data_for_type.obj(),
619                                    href.obj(),
620                                    anchor_text.obj(),
621                                    img_src.obj());
622}
623
624void AwContents::OnSizeChanged(JNIEnv* env, jobject obj,
625                               int w, int h, int ow, int oh) {
626  browser_view_renderer_->OnSizeChanged(w, h);
627}
628
629void AwContents::SetViewVisibility(JNIEnv* env, jobject obj, bool visible) {
630  browser_view_renderer_->SetViewVisibility(visible);
631}
632
633void AwContents::SetWindowVisibility(JNIEnv* env, jobject obj, bool visible) {
634  browser_view_renderer_->SetWindowVisibility(visible);
635}
636
637void AwContents::SetIsPaused(JNIEnv* env, jobject obj, bool paused) {
638  browser_view_renderer_->SetIsPaused(paused);
639}
640
641void AwContents::OnAttachedToWindow(JNIEnv* env, jobject obj, int w, int h) {
642  browser_view_renderer_->OnAttachedToWindow(w, h);
643}
644
645void AwContents::OnDetachedFromWindow(JNIEnv* env, jobject obj) {
646  browser_view_renderer_->OnDetachedFromWindow();
647}
648
649base::android::ScopedJavaLocalRef<jbyteArray>
650AwContents::GetOpaqueState(JNIEnv* env, jobject obj) {
651  // Required optimization in WebViewClassic to not save any state if
652  // there has been no navigations.
653  if (!web_contents_->GetController().GetEntryCount())
654    return ScopedJavaLocalRef<jbyteArray>();
655
656  Pickle pickle;
657  if (!WriteToPickle(*web_contents_, &pickle)) {
658    return ScopedJavaLocalRef<jbyteArray>();
659  } else {
660    return base::android::ToJavaByteArray(env,
661       reinterpret_cast<const uint8*>(pickle.data()), pickle.size());
662  }
663}
664
665jboolean AwContents::RestoreFromOpaqueState(
666    JNIEnv* env, jobject obj, jbyteArray state) {
667  // TODO(boliu): This copy can be optimized out if this is a performance
668  // problem.
669  std::vector<uint8> state_vector;
670  base::android::JavaByteArrayToByteVector(env, state, &state_vector);
671
672  Pickle pickle(reinterpret_cast<const char*>(state_vector.begin()),
673                state_vector.size());
674  PickleIterator iterator(pickle);
675
676  return RestoreFromPickle(&iterator, web_contents_.get());
677}
678
679bool AwContents::OnDraw(JNIEnv* env,
680                        jobject obj,
681                        jobject canvas,
682                        jboolean is_hardware_accelerated,
683                        jint scroll_x,
684                        jint scroll_y,
685                        jint clip_left,
686                        jint clip_top,
687                        jint clip_right,
688                        jint clip_bottom) {
689  return browser_view_renderer_->OnDraw(
690      canvas,
691      is_hardware_accelerated,
692      gfx::Vector2d(scroll_x, scroll_y),
693      gfx::Rect(
694          clip_left, clip_top, clip_right - clip_left, clip_bottom - clip_top));
695}
696
697void AwContents::SetGlobalVisibleRect(JNIEnv* env,
698                                      jobject obj,
699                                      jint visible_left,
700                                      jint visible_top,
701                                      jint visible_right,
702                                      jint visible_bottom) {
703  browser_view_renderer_->SetGlobalVisibleRect(
704      gfx::Rect(visible_left,
705                visible_top,
706                visible_right - visible_left,
707                visible_bottom - visible_top));
708}
709
710void AwContents::SetPendingWebContentsForPopup(
711    scoped_ptr<content::WebContents> pending) {
712  if (pending_contents_.get()) {
713    // TODO(benm): Support holding multiple pop up window requests.
714    LOG(WARNING) << "Blocking popup window creation as an outstanding "
715                 << "popup window is still pending.";
716    base::MessageLoop::current()->DeleteSoon(FROM_HERE, pending.release());
717    return;
718  }
719  pending_contents_.reset(new AwContents(pending.Pass()));
720}
721
722void AwContents::FocusFirstNode(JNIEnv* env, jobject obj) {
723  web_contents_->FocusThroughTabTraversal(false);
724}
725
726void AwContents::SetBackgroundColor(JNIEnv* env, jobject obj, jint color) {
727  render_view_host_ext_->SetBackgroundColor(color);
728}
729
730jint AwContents::ReleasePopupAwContents(JNIEnv* env, jobject obj) {
731  return reinterpret_cast<jint>(pending_contents_.release());
732}
733
734gfx::Point AwContents::GetLocationOnScreen() {
735  JNIEnv* env = AttachCurrentThread();
736  ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
737  if (obj.is_null())
738    return gfx::Point();
739  std::vector<int> location;
740  base::android::JavaIntArrayToIntVector(
741      env,
742      Java_AwContents_getLocationOnScreen(env, obj.obj()).obj(),
743      &location);
744  return gfx::Point(location[0], location[1]);
745}
746
747void AwContents::ScrollContainerViewTo(gfx::Vector2d new_value) {
748  JNIEnv* env = AttachCurrentThread();
749  ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
750  if (obj.is_null())
751    return;
752  Java_AwContents_scrollContainerViewTo(
753      env, obj.obj(), new_value.x(), new_value.y());
754}
755
756
757void AwContents::DidOverscroll(gfx::Vector2d overscroll_delta) {
758  JNIEnv* env = AttachCurrentThread();
759  ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
760  if (obj.is_null())
761    return;
762  Java_AwContents_didOverscroll(
763      env, obj.obj(), overscroll_delta.x(), overscroll_delta.y());
764}
765
766void AwContents::SetDipScale(JNIEnv* env, jobject obj, jfloat dipScale) {
767  browser_view_renderer_->SetDipScale(dipScale);
768}
769
770void AwContents::SetDisplayedPageScaleFactor(JNIEnv* env,
771                                             jobject obj,
772                                             jfloat pageScaleFactor) {
773  browser_view_renderer_->SetPageScaleFactor(pageScaleFactor);
774}
775
776void AwContents::ScrollTo(JNIEnv* env, jobject obj, jint xPix, jint yPix) {
777  browser_view_renderer_->ScrollTo(gfx::Vector2d(xPix, yPix));
778}
779
780void AwContents::OnWebLayoutPageScaleFactorChanged(float page_scale_factor) {
781  JNIEnv* env = AttachCurrentThread();
782  ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
783  if (obj.is_null())
784    return;
785  Java_AwContents_onWebLayoutPageScaleFactorChanged(env, obj.obj(),
786                                                         page_scale_factor);
787}
788
789jint AwContents::CapturePicture(JNIEnv* env,
790                                jobject obj,
791                                int width,
792                                int height) {
793  return reinterpret_cast<jint>(new AwPicture(
794      browser_view_renderer_->CapturePicture(width, height)));
795}
796
797void AwContents::EnableOnNewPicture(JNIEnv* env,
798                                    jobject obj,
799                                    jboolean enabled) {
800  browser_view_renderer_->EnableOnNewPicture(enabled);
801}
802
803void AwContents::SetJsOnlineProperty(JNIEnv* env,
804                                     jobject obj,
805                                     jboolean network_up) {
806  render_view_host_ext_->SetJsOnlineProperty(network_up);
807}
808
809}  // namespace android_webview
810