1/* 2 * Copyright 2007, The Android Open Source Project 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * * Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * * Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#define LOG_TAG "websettings" 27 28#include <config.h> 29#include <wtf/Platform.h> 30 31#include "ApplicationCacheStorage.h" 32#include "CString.h" 33#include "DatabaseTracker.h" 34#include "DocLoader.h" 35#include "Document.h" 36#include "EditorClientAndroid.h" 37#include "FileSystem.h" 38#include "Frame.h" 39#include "FrameLoader.h" 40#include "FrameView.h" 41#include "GeolocationPermissions.h" 42#include "GeolocationPositionCache.h" 43#include "Page.h" 44#include "PageCache.h" 45#include "RenderTable.h" 46#include "SQLiteFileSystem.h" 47#include "Settings.h" 48#include "WebCoreFrameBridge.h" 49#include "WebCoreJni.h" 50#if USE(V8) 51#include "WorkerContextExecutionProxy.h" 52#endif 53 54#include <JNIHelp.h> 55#include <utils/misc.h> 56 57namespace android { 58 59static const int permissionFlags660 = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP; 60 61struct FieldIds { 62 FieldIds(JNIEnv* env, jclass clazz) { 63 mLayoutAlgorithm = env->GetFieldID(clazz, "mLayoutAlgorithm", 64 "Landroid/webkit/WebSettings$LayoutAlgorithm;"); 65 mTextSize = env->GetFieldID(clazz, "mTextSize", 66 "Landroid/webkit/WebSettings$TextSize;"); 67 mStandardFontFamily = env->GetFieldID(clazz, "mStandardFontFamily", 68 "Ljava/lang/String;"); 69 mFixedFontFamily = env->GetFieldID(clazz, "mFixedFontFamily", 70 "Ljava/lang/String;"); 71 mSansSerifFontFamily = env->GetFieldID(clazz, "mSansSerifFontFamily", 72 "Ljava/lang/String;"); 73 mSerifFontFamily = env->GetFieldID(clazz, "mSerifFontFamily", 74 "Ljava/lang/String;"); 75 mCursiveFontFamily = env->GetFieldID(clazz, "mCursiveFontFamily", 76 "Ljava/lang/String;"); 77 mFantasyFontFamily = env->GetFieldID(clazz, "mFantasyFontFamily", 78 "Ljava/lang/String;"); 79 mDefaultTextEncoding = env->GetFieldID(clazz, "mDefaultTextEncoding", 80 "Ljava/lang/String;"); 81 mUserAgent = env->GetFieldID(clazz, "mUserAgent", 82 "Ljava/lang/String;"); 83 mMinimumFontSize = env->GetFieldID(clazz, "mMinimumFontSize", "I"); 84 mMinimumLogicalFontSize = env->GetFieldID(clazz, "mMinimumLogicalFontSize", "I"); 85 mDefaultFontSize = env->GetFieldID(clazz, "mDefaultFontSize", "I"); 86 mDefaultFixedFontSize = env->GetFieldID(clazz, "mDefaultFixedFontSize", "I"); 87 mLoadsImagesAutomatically = env->GetFieldID(clazz, "mLoadsImagesAutomatically", "Z"); 88#ifdef ANDROID_BLOCK_NETWORK_IMAGE 89 mBlockNetworkImage = env->GetFieldID(clazz, "mBlockNetworkImage", "Z"); 90#endif 91 mJavaScriptEnabled = env->GetFieldID(clazz, "mJavaScriptEnabled", "Z"); 92 mPluginState = env->GetFieldID(clazz, "mPluginState", 93 "Landroid/webkit/WebSettings$PluginState;"); 94#if ENABLE(DATABASE) 95 mDatabaseEnabled = env->GetFieldID(clazz, "mDatabaseEnabled", "Z"); 96#endif 97#if ENABLE(DOM_STORAGE) 98 mDomStorageEnabled = env->GetFieldID(clazz, "mDomStorageEnabled", "Z"); 99#endif 100#if ENABLE(DATABASE) || ENABLE(DOM_STORAGE) 101 // The databases saved to disk for both the SQL and DOM Storage APIs are stored 102 // in the same base directory. 103 mDatabasePath = env->GetFieldID(clazz, "mDatabasePath", "Ljava/lang/String;"); 104 mDatabasePathHasBeenSet = env->GetFieldID(clazz, "mDatabasePathHasBeenSet", "Z"); 105#endif 106#if ENABLE(OFFLINE_WEB_APPLICATIONS) 107 mAppCacheEnabled = env->GetFieldID(clazz, "mAppCacheEnabled", "Z"); 108 mAppCachePath = env->GetFieldID(clazz, "mAppCachePath", "Ljava/lang/String;"); 109 mAppCacheMaxSize = env->GetFieldID(clazz, "mAppCacheMaxSize", "J"); 110#endif 111#if ENABLE(WORKERS) 112 mWorkersEnabled = env->GetFieldID(clazz, "mWorkersEnabled", "Z"); 113#endif 114 mGeolocationEnabled = env->GetFieldID(clazz, "mGeolocationEnabled", "Z"); 115 mGeolocationDatabasePath = env->GetFieldID(clazz, "mGeolocationDatabasePath", "Ljava/lang/String;"); 116 mJavaScriptCanOpenWindowsAutomatically = env->GetFieldID(clazz, 117 "mJavaScriptCanOpenWindowsAutomatically", "Z"); 118 mUseWideViewport = env->GetFieldID(clazz, "mUseWideViewport", "Z"); 119 mSupportMultipleWindows = env->GetFieldID(clazz, "mSupportMultipleWindows", "Z"); 120 mShrinksStandaloneImagesToFit = env->GetFieldID(clazz, "mShrinksStandaloneImagesToFit", "Z"); 121 mUseDoubleTree = env->GetFieldID(clazz, "mUseDoubleTree", "Z"); 122 mPageCacheCapacity = env->GetFieldID(clazz, "mPageCacheCapacity", "I"); 123 124 LOG_ASSERT(mLayoutAlgorithm, "Could not find field mLayoutAlgorithm"); 125 LOG_ASSERT(mTextSize, "Could not find field mTextSize"); 126 LOG_ASSERT(mStandardFontFamily, "Could not find field mStandardFontFamily"); 127 LOG_ASSERT(mFixedFontFamily, "Could not find field mFixedFontFamily"); 128 LOG_ASSERT(mSansSerifFontFamily, "Could not find field mSansSerifFontFamily"); 129 LOG_ASSERT(mSerifFontFamily, "Could not find field mSerifFontFamily"); 130 LOG_ASSERT(mCursiveFontFamily, "Could not find field mCursiveFontFamily"); 131 LOG_ASSERT(mFantasyFontFamily, "Could not find field mFantasyFontFamily"); 132 LOG_ASSERT(mDefaultTextEncoding, "Could not find field mDefaultTextEncoding"); 133 LOG_ASSERT(mUserAgent, "Could not find field mUserAgent"); 134 LOG_ASSERT(mMinimumFontSize, "Could not find field mMinimumFontSize"); 135 LOG_ASSERT(mMinimumLogicalFontSize, "Could not find field mMinimumLogicalFontSize"); 136 LOG_ASSERT(mDefaultFontSize, "Could not find field mDefaultFontSize"); 137 LOG_ASSERT(mDefaultFixedFontSize, "Could not find field mDefaultFixedFontSize"); 138 LOG_ASSERT(mLoadsImagesAutomatically, "Could not find field mLoadsImagesAutomatically"); 139#ifdef ANDROID_BLOCK_NETWORK_IMAGE 140 LOG_ASSERT(mBlockNetworkImage, "Could not find field mBlockNetworkImage"); 141#endif 142 LOG_ASSERT(mJavaScriptEnabled, "Could not find field mJavaScriptEnabled"); 143 LOG_ASSERT(mPluginState, "Could not find field mPluginState"); 144#if ENABLE(OFFLINE_WEB_APPLICATIONS) 145 LOG_ASSERT(mAppCacheEnabled, "Could not find field mAppCacheEnabled"); 146 LOG_ASSERT(mAppCachePath, "Could not find field mAppCachePath"); 147 LOG_ASSERT(mAppCacheMaxSize, "Could not find field mAppCacheMaxSize"); 148#endif 149#if ENABLE(WORKERS) 150 LOG_ASSERT(mWorkersEnabled, "Could not find field mWorkersEnabled"); 151#endif 152 LOG_ASSERT(mJavaScriptCanOpenWindowsAutomatically, 153 "Could not find field mJavaScriptCanOpenWindowsAutomatically"); 154 LOG_ASSERT(mUseWideViewport, "Could not find field mUseWideViewport"); 155 LOG_ASSERT(mSupportMultipleWindows, "Could not find field mSupportMultipleWindows"); 156 LOG_ASSERT(mShrinksStandaloneImagesToFit, "Could not find field mShrinksStandaloneImagesToFit"); 157 LOG_ASSERT(mUseDoubleTree, "Could not find field mUseDoubleTree"); 158 LOG_ASSERT(mPageCacheCapacity, "Could not find field mPageCacheCapacity"); 159 160 jclass c = env->FindClass("java/lang/Enum"); 161 LOG_ASSERT(c, "Could not find Enum class!"); 162 mOrdinal = env->GetMethodID(c, "ordinal", "()I"); 163 LOG_ASSERT(mOrdinal, "Could not find method ordinal"); 164 c = env->FindClass("android/webkit/WebSettings$TextSize"); 165 LOG_ASSERT(c, "Could not find TextSize enum"); 166 mTextSizeValue = env->GetFieldID(c, "value", "I"); 167 } 168 169 // Field ids 170 jfieldID mLayoutAlgorithm; 171 jfieldID mTextSize; 172 jfieldID mStandardFontFamily; 173 jfieldID mFixedFontFamily; 174 jfieldID mSansSerifFontFamily; 175 jfieldID mSerifFontFamily; 176 jfieldID mCursiveFontFamily; 177 jfieldID mFantasyFontFamily; 178 jfieldID mDefaultTextEncoding; 179 jfieldID mUserAgent; 180 jfieldID mMinimumFontSize; 181 jfieldID mMinimumLogicalFontSize; 182 jfieldID mDefaultFontSize; 183 jfieldID mDefaultFixedFontSize; 184 jfieldID mLoadsImagesAutomatically; 185#ifdef ANDROID_BLOCK_NETWORK_IMAGE 186 jfieldID mBlockNetworkImage; 187#endif 188 jfieldID mJavaScriptEnabled; 189 jfieldID mPluginState; 190#if ENABLE(OFFLINE_WEB_APPLICATIONS) 191 jfieldID mAppCacheEnabled; 192 jfieldID mAppCachePath; 193 jfieldID mAppCacheMaxSize; 194#endif 195#if ENABLE(WORKERS) 196 jfieldID mWorkersEnabled; 197#endif 198 jfieldID mJavaScriptCanOpenWindowsAutomatically; 199 jfieldID mUseWideViewport; 200 jfieldID mSupportMultipleWindows; 201 jfieldID mShrinksStandaloneImagesToFit; 202 jfieldID mUseDoubleTree; 203 jfieldID mPageCacheCapacity; 204 // Ordinal() method and value field for enums 205 jmethodID mOrdinal; 206 jfieldID mTextSizeValue; 207 208#if ENABLE(DATABASE) 209 jfieldID mDatabaseEnabled; 210#endif 211#if ENABLE(DOM_STORAGE) 212 jfieldID mDomStorageEnabled; 213#endif 214 jfieldID mGeolocationEnabled; 215 jfieldID mGeolocationDatabasePath; 216#if ENABLE(DATABASE) || ENABLE(DOM_STORAGE) 217 jfieldID mDatabasePath; 218 jfieldID mDatabasePathHasBeenSet; 219#endif 220}; 221 222static struct FieldIds* gFieldIds; 223 224// Note: This is moved from the old FrameAndroid.cpp 225static void recursiveCleanupForFullLayout(WebCore::RenderObject* obj) 226{ 227 obj->setNeedsLayout(true, false); 228#ifdef ANDROID_LAYOUT 229 if (obj->isTable()) 230 (static_cast<WebCore::RenderTable *>(obj))->clearSingleColumn(); 231#endif 232 for (WebCore::RenderObject* n = obj->firstChild(); n; n = n->nextSibling()) 233 recursiveCleanupForFullLayout(n); 234} 235 236class WebSettings { 237public: 238 static void Sync(JNIEnv* env, jobject obj, jint frame) 239 { 240 WebCore::Frame* pFrame = (WebCore::Frame*)frame; 241 LOG_ASSERT(pFrame, "%s must take a valid frame pointer!", __FUNCTION__); 242 WebCore::Settings* s = pFrame->settings(); 243 if (!s) 244 return; 245 WebCore::DocLoader* docLoader = pFrame->document()->docLoader(); 246 247#ifdef ANDROID_LAYOUT 248 jobject layout = env->GetObjectField(obj, gFieldIds->mLayoutAlgorithm); 249 WebCore::Settings::LayoutAlgorithm l = (WebCore::Settings::LayoutAlgorithm) 250 env->CallIntMethod(layout, gFieldIds->mOrdinal); 251 if (s->layoutAlgorithm() != l) { 252 s->setLayoutAlgorithm(l); 253 if (pFrame->document()) { 254 pFrame->document()->updateStyleSelector(); 255 if (pFrame->document()->renderer()) { 256 recursiveCleanupForFullLayout(pFrame->document()->renderer()); 257 LOG_ASSERT(pFrame->view(), "No view for this frame when trying to relayout"); 258 pFrame->view()->layout(); 259 // FIXME: This call used to scroll the page to put the focus into view. 260 // It worked on the WebViewCore, but now scrolling is done outside of the 261 // WebViewCore, on the UI side, so there needs to be a new way to do this. 262 //pFrame->makeFocusVisible(); 263 } 264 } 265 } 266#endif 267 jobject textSize = env->GetObjectField(obj, gFieldIds->mTextSize); 268 float zoomFactor = env->GetIntField(textSize, gFieldIds->mTextSizeValue) / 100.0f; 269 if (pFrame->zoomFactor() != zoomFactor) 270 pFrame->setZoomFactor(zoomFactor, /*isTextOnly*/true); 271 272 jstring str = (jstring)env->GetObjectField(obj, gFieldIds->mStandardFontFamily); 273 s->setStandardFontFamily(to_string(env, str)); 274 275 str = (jstring)env->GetObjectField(obj, gFieldIds->mFixedFontFamily); 276 s->setFixedFontFamily(to_string(env, str)); 277 278 str = (jstring)env->GetObjectField(obj, gFieldIds->mSansSerifFontFamily); 279 s->setSansSerifFontFamily(to_string(env, str)); 280 281 str = (jstring)env->GetObjectField(obj, gFieldIds->mSerifFontFamily); 282 s->setSerifFontFamily(to_string(env, str)); 283 284 str = (jstring)env->GetObjectField(obj, gFieldIds->mCursiveFontFamily); 285 s->setCursiveFontFamily(to_string(env, str)); 286 287 str = (jstring)env->GetObjectField(obj, gFieldIds->mFantasyFontFamily); 288 s->setFantasyFontFamily(to_string(env, str)); 289 290 str = (jstring)env->GetObjectField(obj, gFieldIds->mDefaultTextEncoding); 291 s->setDefaultTextEncodingName(to_string(env, str)); 292 293 str = (jstring)env->GetObjectField(obj, gFieldIds->mUserAgent); 294 WebFrame::getWebFrame(pFrame)->setUserAgent(to_string(env, str)); 295 296 jint size = env->GetIntField(obj, gFieldIds->mMinimumFontSize); 297 s->setMinimumFontSize(size); 298 299 size = env->GetIntField(obj, gFieldIds->mMinimumLogicalFontSize); 300 s->setMinimumLogicalFontSize(size); 301 302 size = env->GetIntField(obj, gFieldIds->mDefaultFontSize); 303 s->setDefaultFontSize(size); 304 305 size = env->GetIntField(obj, gFieldIds->mDefaultFixedFontSize); 306 s->setDefaultFixedFontSize(size); 307 308 jboolean flag = env->GetBooleanField(obj, gFieldIds->mLoadsImagesAutomatically); 309 s->setLoadsImagesAutomatically(flag); 310 if (flag) 311 docLoader->setAutoLoadImages(true); 312 313#ifdef ANDROID_BLOCK_NETWORK_IMAGE 314 flag = env->GetBooleanField(obj, gFieldIds->mBlockNetworkImage); 315 s->setBlockNetworkImage(flag); 316 if(!flag) 317 docLoader->setBlockNetworkImage(false); 318#endif 319 320 flag = env->GetBooleanField(obj, gFieldIds->mJavaScriptEnabled); 321 s->setJavaScriptEnabled(flag); 322 323 // ON = 0 324 // ON_DEMAND = 1 325 // OFF = 2 326 jobject pluginState = env->GetObjectField(obj, gFieldIds->mPluginState); 327 int state = env->CallIntMethod(pluginState, gFieldIds->mOrdinal); 328 s->setPluginsEnabled(state < 2); 329#ifdef ANDROID_PLUGINS 330 s->setPluginsOnDemand(state == 1); 331#endif 332 333#if ENABLE(OFFLINE_WEB_APPLICATIONS) 334 flag = env->GetBooleanField(obj, gFieldIds->mAppCacheEnabled); 335 s->setOfflineWebApplicationCacheEnabled(flag); 336 str = (jstring)env->GetObjectField(obj, gFieldIds->mAppCachePath); 337 if (str) { 338 WebCore::String path = to_string(env, str); 339 if (path.length() && WebCore::cacheStorage().cacheDirectory().isNull()) { 340 WebCore::cacheStorage().setCacheDirectory(path); 341 // This database is created on the first load. If the file 342 // doesn't exist, we create it and set its permissions. The 343 // filename must match that in ApplicationCacheStorage.cpp. 344 String filename = pathByAppendingComponent(path, "ApplicationCache.db"); 345 int fd = open(filename.utf8().data(), O_CREAT | O_EXCL, permissionFlags660); 346 if (fd >= 0) 347 close(fd); 348 } 349 } 350 jlong maxsize = env->GetIntField(obj, gFieldIds->mAppCacheMaxSize); 351 WebCore::cacheStorage().setMaximumSize(maxsize); 352#endif 353 354 flag = env->GetBooleanField(obj, gFieldIds->mJavaScriptCanOpenWindowsAutomatically); 355 s->setJavaScriptCanOpenWindowsAutomatically(flag); 356 357#ifdef ANDROID_LAYOUT 358 flag = env->GetBooleanField(obj, gFieldIds->mUseWideViewport); 359 s->setUseWideViewport(flag); 360#endif 361 362#ifdef ANDROID_MULTIPLE_WINDOWS 363 flag = env->GetBooleanField(obj, gFieldIds->mSupportMultipleWindows); 364 s->setSupportMultipleWindows(flag); 365#endif 366 flag = env->GetBooleanField(obj, gFieldIds->mShrinksStandaloneImagesToFit); 367 s->setShrinksStandaloneImagesToFit(flag); 368#if ENABLE(DATABASE) 369 flag = env->GetBooleanField(obj, gFieldIds->mDatabaseEnabled); 370 s->setDatabasesEnabled(flag); 371 372 flag = env->GetBooleanField(obj, gFieldIds->mDatabasePathHasBeenSet); 373 if (flag) { 374 // If the user has set the database path, sync it to the DatabaseTracker. 375 str = (jstring)env->GetObjectField(obj, gFieldIds->mDatabasePath); 376 if (str) { 377 String path = to_string(env, str); 378 WebCore::DatabaseTracker::tracker().setDatabaseDirectoryPath(path); 379 // This database is created when the first HTML5 Database object is 380 // instantiated. If the file doesn't exist, we create it and set its 381 // permissions. The filename must match that in 382 // DatabaseTracker.cpp. 383 String filename = SQLiteFileSystem::appendDatabaseFileNameToPath(path, "Databases.db"); 384 int fd = open(filename.utf8().data(), O_CREAT | O_EXCL, permissionFlags660); 385 if (fd >= 0) 386 close(fd); 387 } 388 } 389#endif 390#if ENABLE(DOM_STORAGE) 391 flag = env->GetBooleanField(obj, gFieldIds->mDomStorageEnabled); 392 s->setLocalStorageEnabled(flag); 393 str = (jstring)env->GetObjectField(obj, gFieldIds->mDatabasePath); 394 if (str) { 395 WebCore::String localStorageDatabasePath = to_string(env,str); 396 if (localStorageDatabasePath.length()) { 397 localStorageDatabasePath = WebCore::pathByAppendingComponent( 398 localStorageDatabasePath, "localstorage"); 399 // We need 770 for folders 400 mkdir(localStorageDatabasePath.utf8().data(), 401 permissionFlags660 | S_IXUSR | S_IXGRP); 402 s->setLocalStorageDatabasePath(localStorageDatabasePath); 403 } 404 } 405#endif 406 407 flag = env->GetBooleanField(obj, gFieldIds->mGeolocationEnabled); 408 GeolocationPermissions::setAlwaysDeny(!flag); 409 str = (jstring)env->GetObjectField(obj, gFieldIds->mGeolocationDatabasePath); 410 if (str) { 411 WebCore::String path = to_string(env, str); 412 GeolocationPermissions::setDatabasePath(path); 413 WebCore::GeolocationPositionCache::setDatabasePath(path); 414 // This database is created when the first Geolocation object is 415 // instantiated. If the file doesn't exist, we create it and set its 416 // permissions. The filename must match that in 417 // GeolocationPositionCache.cpp. 418 WebCore::String filename = WebCore::SQLiteFileSystem::appendDatabaseFileNameToPath( 419 path, "CachedGeoposition.db"); 420 int fd = open(filename.utf8().data(), O_CREAT | O_EXCL, permissionFlags660); 421 if (fd >= 0) 422 close(fd); 423 } 424 425 size = env->GetIntField(obj, gFieldIds->mPageCacheCapacity); 426 if (size > 0) { 427 s->setUsesPageCache(true); 428 WebCore::pageCache()->setCapacity(size); 429 } else 430 s->setUsesPageCache(false); 431 } 432}; 433 434//------------------------------------------------------------- 435// JNI registration 436//------------------------------------------------------------- 437 438static JNINativeMethod gWebSettingsMethods[] = { 439 { "nativeSync", "(I)V", 440 (void*) WebSettings::Sync } 441}; 442 443int register_websettings(JNIEnv* env) 444{ 445 jclass clazz = env->FindClass("android/webkit/WebSettings"); 446 LOG_ASSERT(clazz, "Unable to find class WebSettings!"); 447 gFieldIds = new FieldIds(env, clazz); 448 return jniRegisterNativeMethods(env, "android/webkit/WebSettings", 449 gWebSettingsMethods, NELEM(gWebSettingsMethods)); 450} 451 452} 453