aw_contents.cc revision 5db5c4ec98571177cc4dec6df1ad33269f632543
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, pdfExporter, browser_view_renderer_.get()));
324}
325// END: Printing fork b/10190508
326
327void AwContents::PerformLongClick() {
328  JNIEnv* env = AttachCurrentThread();
329  ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
330  if (obj.is_null())
331    return;
332
333  Java_AwContents_performLongClick(env, obj.obj());
334}
335
336bool AwContents::OnReceivedHttpAuthRequest(const JavaRef<jobject>& handler,
337                                           const std::string& host,
338                                           const std::string& realm) {
339  JNIEnv* env = AttachCurrentThread();
340  ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
341  if (obj.is_null())
342    return false;
343
344  ScopedJavaLocalRef<jstring> jhost = ConvertUTF8ToJavaString(env, host);
345  ScopedJavaLocalRef<jstring> jrealm = ConvertUTF8ToJavaString(env, realm);
346  Java_AwContents_onReceivedHttpAuthRequest(env, obj.obj(), handler.obj(),
347      jhost.obj(), jrealm.obj());
348  return true;
349}
350
351void AwContents::AddVisitedLinks(JNIEnv* env,
352                                   jobject obj,
353                                   jobjectArray jvisited_links) {
354  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
355  std::vector<string16> visited_link_strings;
356  base::android::AppendJavaStringArrayToStringVector(
357      env, jvisited_links, &visited_link_strings);
358
359  std::vector<GURL> visited_link_gurls;
360  for (std::vector<string16>::const_iterator itr = visited_link_strings.begin();
361       itr != visited_link_strings.end();
362       ++itr) {
363    visited_link_gurls.push_back(GURL(*itr));
364  }
365
366  AwBrowserContext::FromWebContents(web_contents_.get())
367      ->AddVisitedURLs(visited_link_gurls);
368}
369
370bool RegisterAwContents(JNIEnv* env) {
371  return RegisterNativesImpl(env) >= 0;
372}
373
374namespace {
375
376void ShowGeolocationPromptHelperTask(const JavaObjectWeakGlobalRef& java_ref,
377                                     const GURL& origin) {
378  JNIEnv* env = AttachCurrentThread();
379  ScopedJavaLocalRef<jobject> j_ref = java_ref.get(env);
380  if (j_ref.obj()) {
381    ScopedJavaLocalRef<jstring> j_origin(
382        ConvertUTF8ToJavaString(env, origin.spec()));
383    Java_AwContents_onGeolocationPermissionsShowPrompt(env,
384                                                       j_ref.obj(),
385                                                       j_origin.obj());
386  }
387}
388
389void ShowGeolocationPromptHelper(const JavaObjectWeakGlobalRef& java_ref,
390                                 const GURL& origin) {
391  JNIEnv* env = AttachCurrentThread();
392  if (java_ref.get(env).obj()) {
393    content::BrowserThread::PostTask(
394        content::BrowserThread::UI,
395        FROM_HERE,
396        base::Bind(&ShowGeolocationPromptHelperTask,
397                   java_ref,
398                   origin));
399  }
400}
401
402} // anonymous namespace
403
404void AwContents::ShowGeolocationPrompt(const GURL& requesting_frame,
405                                       base::Callback<void(bool)> callback) {
406  GURL origin = requesting_frame.GetOrigin();
407  bool show_prompt = pending_geolocation_prompts_.empty();
408  pending_geolocation_prompts_.push_back(OriginCallback(origin, callback));
409  if (show_prompt) {
410    ShowGeolocationPromptHelper(java_ref_, origin);
411  }
412}
413
414// Invoked from Java
415void AwContents::InvokeGeolocationCallback(JNIEnv* env,
416                                           jobject obj,
417                                           jboolean value,
418                                           jstring origin) {
419  GURL callback_origin(base::android::ConvertJavaStringToUTF16(env, origin));
420  if (callback_origin.GetOrigin() ==
421      pending_geolocation_prompts_.front().first) {
422    pending_geolocation_prompts_.front().second.Run(value);
423    pending_geolocation_prompts_.pop_front();
424    if (!pending_geolocation_prompts_.empty()) {
425      ShowGeolocationPromptHelper(java_ref_,
426                                  pending_geolocation_prompts_.front().first);
427    }
428  }
429}
430
431void AwContents::HideGeolocationPrompt(const GURL& origin) {
432  bool removed_current_outstanding_callback = false;
433  std::list<OriginCallback>::iterator it = pending_geolocation_prompts_.begin();
434  while (it != pending_geolocation_prompts_.end()) {
435    if ((*it).first == origin.GetOrigin()) {
436      if (it == pending_geolocation_prompts_.begin()) {
437        removed_current_outstanding_callback = true;
438      }
439      it = pending_geolocation_prompts_.erase(it);
440    } else {
441      ++it;
442    }
443  }
444
445  if (removed_current_outstanding_callback) {
446    JNIEnv* env = AttachCurrentThread();
447    ScopedJavaLocalRef<jobject> j_ref = java_ref_.get(env);
448    if (j_ref.obj()) {
449      Java_AwContents_onGeolocationPermissionsHidePrompt(env, j_ref.obj());
450    }
451    if (!pending_geolocation_prompts_.empty()) {
452      ShowGeolocationPromptHelper(java_ref_,
453                            pending_geolocation_prompts_.front().first);
454    }
455  }
456}
457
458void AwContents::FindAllAsync(JNIEnv* env, jobject obj, jstring search_string) {
459  GetFindHelper()->FindAllAsync(ConvertJavaStringToUTF16(env, search_string));
460}
461
462void AwContents::FindNext(JNIEnv* env, jobject obj, jboolean forward) {
463  GetFindHelper()->FindNext(forward);
464}
465
466void AwContents::ClearMatches(JNIEnv* env, jobject obj) {
467  GetFindHelper()->ClearMatches();
468}
469
470void AwContents::ClearCache(
471    JNIEnv* env,
472    jobject obj,
473    jboolean include_disk_files) {
474  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
475  render_view_host_ext_->ClearCache();
476
477  if (include_disk_files) {
478    RemoveHttpDiskCache(web_contents_->GetBrowserContext(),
479                        web_contents_->GetRoutingID());
480  }
481}
482
483FindHelper* AwContents::GetFindHelper() {
484  if (!find_helper_.get()) {
485    find_helper_.reset(new FindHelper(web_contents_.get()));
486    find_helper_->SetListener(this);
487  }
488  return find_helper_.get();
489}
490
491void AwContents::OnFindResultReceived(int active_ordinal,
492                                      int match_count,
493                                      bool finished) {
494  JNIEnv* env = AttachCurrentThread();
495  ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
496  if (obj.is_null())
497    return;
498
499  Java_AwContents_onFindResultReceived(
500      env, obj.obj(), active_ordinal, match_count, finished);
501}
502
503void AwContents::OnReceivedIcon(const GURL& icon_url, const SkBitmap& bitmap) {
504  JNIEnv* env = AttachCurrentThread();
505  ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
506  if (obj.is_null())
507    return;
508
509  content::NavigationEntry* entry =
510      web_contents_->GetController().GetActiveEntry();
511
512  if (entry) {
513    entry->GetFavicon().valid = true;
514    entry->GetFavicon().url = icon_url;
515    entry->GetFavicon().image = gfx::Image::CreateFrom1xBitmap(bitmap);
516  }
517
518  Java_AwContents_onReceivedIcon(
519      env, obj.obj(), gfx::ConvertToJavaBitmap(&bitmap).obj());
520}
521
522void AwContents::OnReceivedTouchIconUrl(const std::string& url,
523                                        bool precomposed) {
524  JNIEnv* env = AttachCurrentThread();
525  ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
526  if (obj.is_null())
527    return;
528
529  Java_AwContents_onReceivedTouchIconUrl(
530      env, obj.obj(), ConvertUTF8ToJavaString(env, url).obj(), precomposed);
531}
532
533bool AwContents::RequestDrawGL(jobject canvas) {
534  JNIEnv* env = AttachCurrentThread();
535  ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
536  if (obj.is_null())
537    return false;
538  return Java_AwContents_requestDrawGL(env, obj.obj(), canvas);
539}
540
541void AwContents::PostInvalidate() {
542  JNIEnv* env = AttachCurrentThread();
543  ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
544  if (!obj.is_null())
545    Java_AwContents_postInvalidateOnAnimation(env, obj.obj());
546}
547
548void AwContents::UpdateGlobalVisibleRect() {
549  JNIEnv* env = AttachCurrentThread();
550  ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
551  if (!obj.is_null())
552    Java_AwContents_updateGlobalVisibleRect(env, obj.obj());
553}
554
555void AwContents::OnNewPicture() {
556  JNIEnv* env = AttachCurrentThread();
557  ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
558  if (!obj.is_null())
559    Java_AwContents_onNewPicture(env, obj.obj());
560}
561
562base::android::ScopedJavaLocalRef<jbyteArray>
563    AwContents::GetCertificate(JNIEnv* env,
564                               jobject obj) {
565  content::NavigationEntry* entry =
566      web_contents_->GetController().GetActiveEntry();
567  if (!entry)
568    return ScopedJavaLocalRef<jbyteArray>();
569  // Get the certificate
570  int cert_id = entry->GetSSL().cert_id;
571  scoped_refptr<net::X509Certificate> cert;
572  bool ok = content::CertStore::GetInstance()->RetrieveCert(cert_id, &cert);
573  if (!ok)
574    return ScopedJavaLocalRef<jbyteArray>();
575
576  // Convert the certificate and return it
577  std::string der_string;
578  net::X509Certificate::GetDEREncoded(cert->os_cert_handle(), &der_string);
579  return base::android::ToJavaByteArray(env,
580      reinterpret_cast<const uint8*>(der_string.data()), der_string.length());
581}
582
583void AwContents::RequestNewHitTestDataAt(JNIEnv* env, jobject obj,
584                                         jint x, jint y) {
585  render_view_host_ext_->RequestNewHitTestDataAt(x, y);
586}
587
588void AwContents::UpdateLastHitTestData(JNIEnv* env, jobject obj) {
589  if (!render_view_host_ext_->HasNewHitTestData()) return;
590
591  const AwHitTestData& data = render_view_host_ext_->GetLastHitTestData();
592  render_view_host_ext_->MarkHitTestDataRead();
593
594  // Make sure to null the Java object if data is empty/invalid.
595  ScopedJavaLocalRef<jstring> extra_data_for_type;
596  if (data.extra_data_for_type.length())
597    extra_data_for_type = ConvertUTF8ToJavaString(
598        env, data.extra_data_for_type);
599
600  ScopedJavaLocalRef<jstring> href;
601  if (data.href.length())
602    href = ConvertUTF16ToJavaString(env, data.href);
603
604  ScopedJavaLocalRef<jstring> anchor_text;
605  if (data.anchor_text.length())
606    anchor_text = ConvertUTF16ToJavaString(env, data.anchor_text);
607
608  ScopedJavaLocalRef<jstring> img_src;
609  if (data.img_src.is_valid())
610    img_src = ConvertUTF8ToJavaString(env, data.img_src.spec());
611
612  Java_AwContents_updateHitTestData(env,
613                                    obj,
614                                    data.type,
615                                    extra_data_for_type.obj(),
616                                    href.obj(),
617                                    anchor_text.obj(),
618                                    img_src.obj());
619}
620
621void AwContents::OnSizeChanged(JNIEnv* env, jobject obj,
622                               int w, int h, int ow, int oh) {
623  browser_view_renderer_->OnSizeChanged(w, h);
624}
625
626void AwContents::SetViewVisibility(JNIEnv* env, jobject obj, bool visible) {
627  browser_view_renderer_->SetViewVisibility(visible);
628}
629
630void AwContents::SetWindowVisibility(JNIEnv* env, jobject obj, bool visible) {
631  browser_view_renderer_->SetWindowVisibility(visible);
632}
633
634void AwContents::SetIsPaused(JNIEnv* env, jobject obj, bool paused) {
635  browser_view_renderer_->SetIsPaused(paused);
636}
637
638void AwContents::OnAttachedToWindow(JNIEnv* env, jobject obj, int w, int h) {
639  browser_view_renderer_->OnAttachedToWindow(w, h);
640}
641
642void AwContents::OnDetachedFromWindow(JNIEnv* env, jobject obj) {
643  browser_view_renderer_->OnDetachedFromWindow();
644}
645
646base::android::ScopedJavaLocalRef<jbyteArray>
647AwContents::GetOpaqueState(JNIEnv* env, jobject obj) {
648  // Required optimization in WebViewClassic to not save any state if
649  // there has been no navigations.
650  if (!web_contents_->GetController().GetEntryCount())
651    return ScopedJavaLocalRef<jbyteArray>();
652
653  Pickle pickle;
654  if (!WriteToPickle(*web_contents_, &pickle)) {
655    return ScopedJavaLocalRef<jbyteArray>();
656  } else {
657    return base::android::ToJavaByteArray(env,
658       reinterpret_cast<const uint8*>(pickle.data()), pickle.size());
659  }
660}
661
662jboolean AwContents::RestoreFromOpaqueState(
663    JNIEnv* env, jobject obj, jbyteArray state) {
664  // TODO(boliu): This copy can be optimized out if this is a performance
665  // problem.
666  std::vector<uint8> state_vector;
667  base::android::JavaByteArrayToByteVector(env, state, &state_vector);
668
669  Pickle pickle(reinterpret_cast<const char*>(state_vector.begin()),
670                state_vector.size());
671  PickleIterator iterator(pickle);
672
673  return RestoreFromPickle(&iterator, web_contents_.get());
674}
675
676bool AwContents::OnDraw(JNIEnv* env,
677                        jobject obj,
678                        jobject canvas,
679                        jboolean is_hardware_accelerated,
680                        jint scroll_x,
681                        jint scroll_y,
682                        jint clip_left,
683                        jint clip_top,
684                        jint clip_right,
685                        jint clip_bottom) {
686  return browser_view_renderer_->OnDraw(
687      canvas,
688      is_hardware_accelerated,
689      gfx::Vector2d(scroll_x, scroll_y),
690      gfx::Rect(
691          clip_left, clip_top, clip_right - clip_left, clip_bottom - clip_top));
692}
693
694void AwContents::SetGlobalVisibleRect(JNIEnv* env,
695                                      jobject obj,
696                                      jint visible_left,
697                                      jint visible_top,
698                                      jint visible_right,
699                                      jint visible_bottom) {
700  browser_view_renderer_->SetGlobalVisibleRect(
701      gfx::Rect(visible_left,
702                visible_top,
703                visible_right - visible_left,
704                visible_bottom - visible_top));
705}
706
707void AwContents::SetPendingWebContentsForPopup(
708    scoped_ptr<content::WebContents> pending) {
709  if (pending_contents_.get()) {
710    // TODO(benm): Support holding multiple pop up window requests.
711    LOG(WARNING) << "Blocking popup window creation as an outstanding "
712                 << "popup window is still pending.";
713    base::MessageLoop::current()->DeleteSoon(FROM_HERE, pending.release());
714    return;
715  }
716  pending_contents_.reset(new AwContents(pending.Pass()));
717}
718
719void AwContents::FocusFirstNode(JNIEnv* env, jobject obj) {
720  web_contents_->FocusThroughTabTraversal(false);
721}
722
723void AwContents::SetBackgroundColor(JNIEnv* env, jobject obj, jint color) {
724  render_view_host_ext_->SetBackgroundColor(color);
725}
726
727jint AwContents::ReleasePopupAwContents(JNIEnv* env, jobject obj) {
728  return reinterpret_cast<jint>(pending_contents_.release());
729}
730
731gfx::Point AwContents::GetLocationOnScreen() {
732  JNIEnv* env = AttachCurrentThread();
733  ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
734  if (obj.is_null())
735    return gfx::Point();
736  std::vector<int> location;
737  base::android::JavaIntArrayToIntVector(
738      env,
739      Java_AwContents_getLocationOnScreen(env, obj.obj()).obj(),
740      &location);
741  return gfx::Point(location[0], location[1]);
742}
743
744void AwContents::ScrollContainerViewTo(gfx::Vector2d new_value) {
745  JNIEnv* env = AttachCurrentThread();
746  ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
747  if (obj.is_null())
748    return;
749  Java_AwContents_scrollContainerViewTo(
750      env, obj.obj(), new_value.x(), new_value.y());
751}
752
753
754void AwContents::DidOverscroll(gfx::Vector2d overscroll_delta) {
755  JNIEnv* env = AttachCurrentThread();
756  ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
757  if (obj.is_null())
758    return;
759  Java_AwContents_didOverscroll(
760      env, obj.obj(), overscroll_delta.x(), overscroll_delta.y());
761}
762
763void AwContents::SetDipScale(JNIEnv* env, jobject obj, jfloat dipScale) {
764  browser_view_renderer_->SetDipScale(dipScale);
765}
766
767void AwContents::SetDisplayedPageScaleFactor(JNIEnv* env,
768                                             jobject obj,
769                                             jfloat pageScaleFactor) {
770  browser_view_renderer_->SetPageScaleFactor(pageScaleFactor);
771}
772
773void AwContents::ScrollTo(JNIEnv* env, jobject obj, jint xPix, jint yPix) {
774  browser_view_renderer_->ScrollTo(gfx::Vector2d(xPix, yPix));
775}
776
777void AwContents::OnWebLayoutPageScaleFactorChanged(float page_scale_factor) {
778  JNIEnv* env = AttachCurrentThread();
779  ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
780  if (obj.is_null())
781    return;
782  Java_AwContents_onWebLayoutPageScaleFactorChanged(env, obj.obj(),
783                                                         page_scale_factor);
784}
785
786jint AwContents::CapturePicture(JNIEnv* env,
787                                jobject obj,
788                                int width,
789                                int height) {
790  return reinterpret_cast<jint>(new AwPicture(
791      browser_view_renderer_->CapturePicture(width, height)));
792}
793
794void AwContents::EnableOnNewPicture(JNIEnv* env,
795                                    jobject obj,
796                                    jboolean enabled) {
797  browser_view_renderer_->EnableOnNewPicture(enabled);
798}
799
800void AwContents::SetJsOnlineProperty(JNIEnv* env,
801                                     jobject obj,
802                                     jboolean network_up) {
803  render_view_host_ext_->SetJsOnlineProperty(network_up);
804}
805
806}  // namespace android_webview
807