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