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