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