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