Home | History | Annotate | Download | only in native
      1 // Copyright (c) 2013 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_settings.h"
      6 
      7 #include "android_webview/browser/renderer_host/aw_render_view_host_ext.h"
      8 #include "android_webview/native/aw_contents.h"
      9 #include "base/android/jni_android.h"
     10 #include "base/android/jni_string.h"
     11 #include "base/command_line.h"
     12 #include "base/supports_user_data.h"
     13 #include "content/public/browser/navigation_controller.h"
     14 #include "content/public/browser/navigation_entry.h"
     15 #include "content/public/browser/render_view_host.h"
     16 #include "content/public/browser/web_contents.h"
     17 #include "content/public/common/content_client.h"
     18 #include "content/public/common/content_switches.h"
     19 #include "jni/AwSettings_jni.h"
     20 #include "webkit/common/user_agent/user_agent.h"
     21 #include "webkit/common/webpreferences.h"
     22 
     23 using base::android::ConvertJavaStringToUTF16;
     24 using base::android::ConvertUTF8ToJavaString;
     25 using base::android::ScopedJavaLocalRef;
     26 
     27 namespace android_webview {
     28 
     29 const void* kAwSettingsUserDataKey = &kAwSettingsUserDataKey;
     30 
     31 class AwSettingsUserData : public base::SupportsUserData::Data {
     32  public:
     33   AwSettingsUserData(AwSettings* ptr) : settings_(ptr) {}
     34 
     35   static AwSettings* GetSettings(content::WebContents* web_contents) {
     36     if (!web_contents)
     37       return NULL;
     38     AwSettingsUserData* data = reinterpret_cast<AwSettingsUserData*>(
     39         web_contents->GetUserData(kAwSettingsUserDataKey));
     40     return data ? data->settings_ : NULL;
     41   }
     42 
     43  private:
     44   AwSettings* settings_;
     45 };
     46 
     47 AwSettings::AwSettings(JNIEnv* env, jobject obj, jlong web_contents)
     48     : WebContentsObserver(
     49           reinterpret_cast<content::WebContents*>(web_contents)),
     50       accelerated_2d_canvas_disabled_by_switch_(
     51           CommandLine::ForCurrentProcess()->HasSwitch(
     52               switches::kDisableAccelerated2dCanvas)),
     53       aw_settings_(env, obj) {
     54   reinterpret_cast<content::WebContents*>(web_contents)->
     55       SetUserData(kAwSettingsUserDataKey, new AwSettingsUserData(this));
     56 }
     57 
     58 AwSettings::~AwSettings() {
     59   if (web_contents()) {
     60     web_contents()->SetUserData(kAwSettingsUserDataKey, NULL);
     61   }
     62 
     63   JNIEnv* env = base::android::AttachCurrentThread();
     64   ScopedJavaLocalRef<jobject> scoped_obj = aw_settings_.get(env);
     65   jobject obj = scoped_obj.obj();
     66   if (!obj) return;
     67   Java_AwSettings_nativeAwSettingsGone(env, obj,
     68                                        reinterpret_cast<intptr_t>(this));
     69 }
     70 
     71 void AwSettings::Destroy(JNIEnv* env, jobject obj) {
     72   delete this;
     73 }
     74 
     75 AwSettings* AwSettings::FromWebContents(content::WebContents* web_contents) {
     76   return AwSettingsUserData::GetSettings(web_contents);
     77 }
     78 
     79 AwRenderViewHostExt* AwSettings::GetAwRenderViewHostExt() {
     80   if (!web_contents()) return NULL;
     81   AwContents* contents = AwContents::FromWebContents(web_contents());
     82   if (!contents) return NULL;
     83   return contents->render_view_host_ext();
     84 }
     85 
     86 void AwSettings::ResetScrollAndScaleState(JNIEnv* env, jobject obj) {
     87   AwRenderViewHostExt* rvhe = GetAwRenderViewHostExt();
     88   if (!rvhe) return;
     89   rvhe->ResetScrollAndScaleState();
     90 }
     91 
     92 void AwSettings::UpdateEverything() {
     93   JNIEnv* env = base::android::AttachCurrentThread();
     94   CHECK(env);
     95   ScopedJavaLocalRef<jobject> scoped_obj = aw_settings_.get(env);
     96   jobject obj = scoped_obj.obj();
     97   if (!obj) return;
     98   // Grab the lock and call UpdateEverythingLocked.
     99   Java_AwSettings_updateEverything(env, obj);
    100 }
    101 
    102 void AwSettings::UpdateEverythingLocked(JNIEnv* env, jobject obj) {
    103   UpdateInitialPageScaleLocked(env, obj);
    104   UpdateWebkitPreferencesLocked(env, obj);
    105   UpdateUserAgentLocked(env, obj);
    106   ResetScrollAndScaleState(env, obj);
    107   UpdateFormDataPreferencesLocked(env, obj);
    108 }
    109 
    110 void AwSettings::UpdateUserAgentLocked(JNIEnv* env, jobject obj) {
    111   if (!web_contents()) return;
    112 
    113   ScopedJavaLocalRef<jstring> str =
    114       Java_AwSettings_getUserAgentLocked(env, obj);
    115   bool ua_overidden = str.obj() != NULL;
    116 
    117   if (ua_overidden) {
    118     std::string override = base::android::ConvertJavaStringToUTF8(str);
    119     web_contents()->SetUserAgentOverride(override);
    120   }
    121 
    122   const content::NavigationController& controller =
    123       web_contents()->GetController();
    124   for (int i = 0; i < controller.GetEntryCount(); ++i)
    125     controller.GetEntryAtIndex(i)->SetIsOverridingUserAgent(ua_overidden);
    126 }
    127 
    128 void AwSettings::UpdateWebkitPreferencesLocked(JNIEnv* env, jobject obj) {
    129   if (!web_contents()) return;
    130   AwRenderViewHostExt* render_view_host_ext = GetAwRenderViewHostExt();
    131   if (!render_view_host_ext) return;
    132 
    133   content::RenderViewHost* render_view_host =
    134       web_contents()->GetRenderViewHost();
    135   if (!render_view_host) return;
    136   render_view_host->UpdateWebkitPreferences(
    137       render_view_host->GetWebkitPreferences());
    138 }
    139 
    140 void AwSettings::UpdateInitialPageScaleLocked(JNIEnv* env, jobject obj) {
    141   AwRenderViewHostExt* rvhe = GetAwRenderViewHostExt();
    142   if (!rvhe) return;
    143 
    144   float initial_page_scale_percent =
    145       Java_AwSettings_getInitialPageScalePercentLocked(env, obj);
    146   if (initial_page_scale_percent == 0) {
    147     rvhe->SetInitialPageScale(-1);
    148   } else {
    149     float dip_scale = static_cast<float>(
    150         Java_AwSettings_getDIPScaleLocked(env, obj));
    151     rvhe->SetInitialPageScale(initial_page_scale_percent / dip_scale / 100.0f);
    152   }
    153 }
    154 
    155 void AwSettings::UpdateFormDataPreferencesLocked(JNIEnv* env, jobject obj) {
    156   if (!web_contents()) return;
    157   AwContents* contents = AwContents::FromWebContents(web_contents());
    158   if (!contents) return;
    159 
    160   contents->SetSaveFormData(Java_AwSettings_getSaveFormDataLocked(env, obj));
    161 }
    162 
    163 void AwSettings::RenderViewCreated(content::RenderViewHost* render_view_host) {
    164   // A single WebContents can normally have 0 to many RenderViewHost instances
    165   // associated with it.
    166   // This is important since there is only one RenderViewHostExt instance per
    167   // WebContents (and not one RVHExt per RVH, as you might expect) and updating
    168   // settings via RVHExt only ever updates the 'current' RVH.
    169   // In android_webview we don't swap out the RVH on cross-site navigations, so
    170   // we shouldn't have to deal with the multiple RVH per WebContents case. That
    171   // in turn means that the newly created RVH is always the 'current' RVH
    172   // (since we only ever go from 0 to 1 RVH instances) and hence the DCHECK.
    173   DCHECK(web_contents()->GetRenderViewHost() == render_view_host);
    174 
    175   UpdateEverything();
    176 }
    177 
    178 void AwSettings::WebContentsDestroyed(content::WebContents* web_contents) {
    179   delete this;
    180 }
    181 
    182 // static
    183 void AwSettings::PopulateFixedPreferences(WebPreferences* web_prefs) {
    184   web_prefs->shrinks_standalone_images_to_fit = false;
    185   web_prefs->should_clear_document_background = false;
    186 }
    187 
    188 void AwSettings::PopulateWebPreferences(WebPreferences* web_prefs) {
    189   JNIEnv* env = base::android::AttachCurrentThread();
    190   CHECK(env);
    191   ScopedJavaLocalRef<jobject> scoped_obj = aw_settings_.get(env);
    192   jobject obj = scoped_obj.obj();
    193   if (!obj) return;
    194   // Grab the lock and call PopulateWebPreferencesLocked.
    195   Java_AwSettings_populateWebPreferences(
    196       env, obj, reinterpret_cast<jlong>(web_prefs));
    197 }
    198 
    199 void AwSettings::PopulateWebPreferencesLocked(
    200     JNIEnv* env, jobject obj, jlong web_prefs_ptr) {
    201   AwRenderViewHostExt* render_view_host_ext = GetAwRenderViewHostExt();
    202   if (!render_view_host_ext) return;
    203 
    204   WebPreferences* web_prefs = reinterpret_cast<WebPreferences*>(web_prefs_ptr);
    205   PopulateFixedPreferences(web_prefs);
    206 
    207   web_prefs->text_autosizing_enabled =
    208       Java_AwSettings_getTextAutosizingEnabledLocked(env, obj);
    209 
    210   int text_size_percent = Java_AwSettings_getTextSizePercentLocked(env, obj);
    211   if (web_prefs->text_autosizing_enabled) {
    212     web_prefs->font_scale_factor = text_size_percent / 100.0f;
    213     web_prefs->force_enable_zoom = text_size_percent >= 130;
    214     // Use the default zoom factor value when Text Autosizer is turned on.
    215     render_view_host_ext->SetTextZoomFactor(1);
    216   } else {
    217     web_prefs->force_enable_zoom = false;
    218     render_view_host_ext->SetTextZoomFactor(text_size_percent / 100.0f);
    219   }
    220 
    221   web_prefs->standard_font_family_map[webkit_glue::kCommonScript] =
    222       ConvertJavaStringToUTF16(
    223           Java_AwSettings_getStandardFontFamilyLocked(env, obj));
    224 
    225   web_prefs->fixed_font_family_map[webkit_glue::kCommonScript] =
    226       ConvertJavaStringToUTF16(
    227           Java_AwSettings_getFixedFontFamilyLocked(env, obj));
    228 
    229   web_prefs->sans_serif_font_family_map[webkit_glue::kCommonScript] =
    230       ConvertJavaStringToUTF16(
    231           Java_AwSettings_getSansSerifFontFamilyLocked(env, obj));
    232 
    233   web_prefs->serif_font_family_map[webkit_glue::kCommonScript] =
    234       ConvertJavaStringToUTF16(
    235           Java_AwSettings_getSerifFontFamilyLocked(env, obj));
    236 
    237   web_prefs->cursive_font_family_map[webkit_glue::kCommonScript] =
    238       ConvertJavaStringToUTF16(
    239           Java_AwSettings_getCursiveFontFamilyLocked(env, obj));
    240 
    241   web_prefs->fantasy_font_family_map[webkit_glue::kCommonScript] =
    242       ConvertJavaStringToUTF16(
    243           Java_AwSettings_getFantasyFontFamilyLocked(env, obj));
    244 
    245   web_prefs->default_encoding = ConvertJavaStringToUTF8(
    246       Java_AwSettings_getDefaultTextEncodingLocked(env, obj));
    247 
    248   web_prefs->minimum_font_size =
    249       Java_AwSettings_getMinimumFontSizeLocked(env, obj);
    250 
    251   web_prefs->minimum_logical_font_size =
    252       Java_AwSettings_getMinimumLogicalFontSizeLocked(env, obj);
    253 
    254   web_prefs->default_font_size =
    255       Java_AwSettings_getDefaultFontSizeLocked(env, obj);
    256 
    257   web_prefs->default_fixed_font_size =
    258       Java_AwSettings_getDefaultFixedFontSizeLocked(env, obj);
    259 
    260   // Blink's LoadsImagesAutomatically and ImagesEnabled must be
    261   // set cris-cross to Android's. See
    262   // https://code.google.com/p/chromium/issues/detail?id=224317#c26
    263   web_prefs->loads_images_automatically =
    264       Java_AwSettings_getImagesEnabledLocked(env, obj);
    265   web_prefs->images_enabled =
    266       Java_AwSettings_getLoadsImagesAutomaticallyLocked(env, obj);
    267 
    268   web_prefs->javascript_enabled =
    269       Java_AwSettings_getJavaScriptEnabledLocked(env, obj);
    270 
    271   web_prefs->allow_universal_access_from_file_urls =
    272       Java_AwSettings_getAllowUniversalAccessFromFileURLsLocked(env, obj);
    273 
    274   web_prefs->allow_file_access_from_file_urls =
    275       Java_AwSettings_getAllowFileAccessFromFileURLsLocked(env, obj);
    276 
    277   web_prefs->javascript_can_open_windows_automatically =
    278       Java_AwSettings_getJavaScriptCanOpenWindowsAutomaticallyLocked(env, obj);
    279 
    280   web_prefs->supports_multiple_windows =
    281       Java_AwSettings_getSupportMultipleWindowsLocked(env, obj);
    282 
    283   web_prefs->plugins_enabled =
    284       !Java_AwSettings_getPluginsDisabledLocked(env, obj);
    285 
    286   web_prefs->application_cache_enabled =
    287       Java_AwSettings_getAppCacheEnabledLocked(env, obj);
    288 
    289   web_prefs->local_storage_enabled =
    290       Java_AwSettings_getDomStorageEnabledLocked(env, obj);
    291 
    292   web_prefs->databases_enabled =
    293       Java_AwSettings_getDatabaseEnabledLocked(env, obj);
    294 
    295   web_prefs->wide_viewport_quirk = true;
    296   web_prefs->use_wide_viewport =
    297       Java_AwSettings_getUseWideViewportLocked(env, obj);
    298 
    299   web_prefs->double_tap_to_zoom_enabled =
    300       Java_AwSettings_supportsDoubleTapZoomLocked(env, obj);
    301 
    302   web_prefs->initialize_at_minimum_page_scale =
    303       Java_AwSettings_getLoadWithOverviewModeLocked(env, obj);
    304 
    305   web_prefs->user_gesture_required_for_media_playback =
    306       Java_AwSettings_getMediaPlaybackRequiresUserGestureLocked(env, obj);
    307 
    308   // Temporary setting, for K release only
    309   // This is a fork from upstream chromium, and should go away once
    310   // https://code.google.com/p/chromium/issues/detail?id=297216
    311   // is implemented
    312   web_prefs->allow_running_insecure_content = true;
    313 
    314   ScopedJavaLocalRef<jstring> url =
    315       Java_AwSettings_getDefaultVideoPosterURLLocked(env, obj);
    316   web_prefs->default_video_poster_url = url.obj() ?
    317       GURL(ConvertJavaStringToUTF8(url)) : GURL();
    318 
    319   bool support_quirks = Java_AwSettings_getSupportLegacyQuirksLocked(env, obj);
    320   // Please see the corresponding Blink settings for bug references.
    321   web_prefs->support_deprecated_target_density_dpi = support_quirks;
    322   web_prefs->use_legacy_background_size_shorthand_behavior = support_quirks;
    323   web_prefs->viewport_meta_layout_size_quirk = support_quirks;
    324   web_prefs->viewport_meta_merge_content_quirk = support_quirks;
    325   web_prefs->viewport_meta_non_user_scalable_quirk = support_quirks;
    326   web_prefs->viewport_meta_zero_values_quirk = support_quirks;
    327   web_prefs->clobber_user_agent_initial_scale_quirk = support_quirks;
    328   web_prefs->ignore_main_frame_overflow_hidden_quirk = support_quirks;
    329   web_prefs->report_screen_size_in_physical_pixels_quirk = support_quirks;
    330 
    331   web_prefs->password_echo_enabled =
    332       Java_AwSettings_getPasswordEchoEnabledLocked(env, obj);
    333   web_prefs->spatial_navigation_enabled =
    334       Java_AwSettings_getSpatialNavigationLocked(env, obj);
    335 
    336   web_prefs->accelerated_2d_canvas_enabled = true;
    337   if (accelerated_2d_canvas_disabled_by_switch_ ||
    338       !Java_AwSettings_getEnableSupportedHardwareAcceleratedFeaturesLocked(
    339           env, obj)) {
    340     // Any canvas smaller than this will fallback to software. Abusing this
    341     // slightly to turn canvas off without changing
    342     // accelerated_2d_canvas_enabled, which also affects compositing mode.
    343     // Using 100M instead of max int to avoid overflows.
    344     web_prefs->minimum_accelerated_2d_canvas_size = 100 * 1000 * 1000;
    345   }
    346 }
    347 
    348 static jlong Init(JNIEnv* env,
    349                   jobject obj,
    350                   jlong web_contents) {
    351   AwSettings* settings = new AwSettings(env, obj, web_contents);
    352   return reinterpret_cast<intptr_t>(settings);
    353 }
    354 
    355 static jstring GetDefaultUserAgent(JNIEnv* env, jclass clazz) {
    356   return base::android::ConvertUTF8ToJavaString(
    357       env, content::GetUserAgent(GURL())).Release();
    358 }
    359 
    360 bool RegisterAwSettings(JNIEnv* env) {
    361   return RegisterNativesImpl(env) >= 0;
    362 }
    363 
    364 }  // namespace android_webview
    365