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