1/* 2 * Copyright (C) 2005, 2006, 2007 Apple Inc. All rights reserved. 3 * (C) 2006 Graham Dennis (graham.dennis@gmail.com) 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of 15 * its contributors may be used to endorse or promote products derived 16 * from this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30#import "WebPreferencesPrivate.h" 31#import "WebPreferenceKeysPrivate.h" 32 33#import "WebKitLogging.h" 34#import "WebKitNSStringExtras.h" 35#import "WebKitSystemBits.h" 36#import "WebKitSystemInterface.h" 37#import "WebKitVersionChecks.h" 38#import "WebNSDictionaryExtras.h" 39#import "WebNSURLExtras.h" 40 41NSString *WebPreferencesChangedNotification = @"WebPreferencesChangedNotification"; 42NSString *WebPreferencesRemovedNotification = @"WebPreferencesRemovedNotification"; 43 44#define KEY(x) (_private->identifier ? [_private->identifier stringByAppendingString:(x)] : (x)) 45 46enum { WebPreferencesVersion = 1 }; 47 48static WebPreferences *_standardPreferences; 49static NSMutableDictionary *webPreferencesInstances; 50 51static bool contains(const char* const array[], int count, const char* item) 52{ 53 if (!item) 54 return false; 55 56 for (int i = 0; i < count; i++) 57 if (!strcasecmp(array[i], item)) 58 return true; 59 return false; 60} 61 62static WebCacheModel cacheModelForMainBundle(void) 63{ 64 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 65 66 // Apps that probably need the small setting 67 static const char* const documentViewerIDs[] = { 68 "Microsoft/com.microsoft.Messenger", 69 "com.adiumX.adiumX", 70 "com.alientechnology.Proteus", 71 "com.apple.Dashcode", 72 "com.apple.iChat", 73 "com.barebones.bbedit", 74 "com.barebones.textwrangler", 75 "com.barebones.yojimbo", 76 "com.equinux.iSale4", 77 "com.growl.growlframework", 78 "com.intrarts.PandoraMan", 79 "com.karelia.Sandvox", 80 "com.macromates.textmate", 81 "com.realmacsoftware.rapidweaverpro", 82 "com.red-sweater.marsedit", 83 "com.yahoo.messenger3", 84 "de.codingmonkeys.SubEthaEdit", 85 "fi.karppinen.Pyro", 86 "info.colloquy", 87 "kungfoo.tv.ecto", 88 }; 89 90 // Apps that probably need the medium setting 91 static const char* const documentBrowserIDs[] = { 92 "com.apple.Dictionary", 93 "com.apple.Xcode", 94 "com.apple.dashboard.client", 95 "com.apple.helpviewer", 96 "com.culturedcode.xyle", 97 "com.macrabbit.CSSEdit", 98 "com.panic.Coda", 99 "com.ranchero.NetNewsWire", 100 "com.thinkmac.NewsLife", 101 "org.xlife.NewsFire", 102 "uk.co.opencommunity.vienna2", 103 }; 104 105 // Apps that probably need the large setting 106 static const char* const primaryWebBrowserIDs[] = { 107 "com.app4mac.KidsBrowser" 108 "com.app4mac.wKiosk", 109 "com.freeverse.bumpercar", 110 "com.omnigroup.OmniWeb5", 111 "com.sunrisebrowser.Sunrise", 112 "net.hmdt-web.Shiira", 113 }; 114 115 WebCacheModel cacheModel; 116 117 const char* bundleID = [[[NSBundle mainBundle] bundleIdentifier] UTF8String]; 118 if (contains(documentViewerIDs, sizeof(documentViewerIDs) / sizeof(documentViewerIDs[0]), bundleID)) 119 cacheModel = WebCacheModelDocumentViewer; 120 else if (contains(documentBrowserIDs, sizeof(documentBrowserIDs) / sizeof(documentBrowserIDs[0]), bundleID)) 121 cacheModel = WebCacheModelDocumentBrowser; 122 else if (contains(primaryWebBrowserIDs, sizeof(primaryWebBrowserIDs) / sizeof(primaryWebBrowserIDs[0]), bundleID)) 123 cacheModel = WebCacheModelPrimaryWebBrowser; 124 else { 125 bool isLegacyApp = !WebKitLinkedOnOrAfter(WEBKIT_FIRST_VERSION_WITH_CACHE_MODEL_API); 126 if (isLegacyApp) 127 cacheModel = WebCacheModelDocumentBrowser; // To avoid regressions in apps that depended on old WebKit's large cache. 128 else 129 cacheModel = WebCacheModelDocumentViewer; // To save memory. 130 } 131 132 [pool drain]; 133 134 return cacheModel; 135} 136 137@interface WebPreferencesPrivate : NSObject 138{ 139@public 140 NSMutableDictionary *values; 141 NSString *identifier; 142 NSString *IBCreatorID; 143 BOOL autosaves; 144 BOOL automaticallyDetectsCacheModel; 145 unsigned numWebViews; 146} 147@end 148 149@implementation WebPreferencesPrivate 150- (void)dealloc 151{ 152 [values release]; 153 [identifier release]; 154 [IBCreatorID release]; 155 [super dealloc]; 156} 157@end 158 159@interface WebPreferences (WebInternal) 160+ (NSString *)_concatenateKeyWithIBCreatorID:(NSString *)key; 161+ (NSString *)_IBCreatorID; 162@end 163 164@interface WebPreferences (WebForwardDeclarations) 165// This pseudo-category is needed so these methods can be used from within other category implementations 166// without being in the public header file. 167- (BOOL)_boolValueForKey:(NSString *)key; 168- (void)_setBoolValue:(BOOL)value forKey:(NSString *)key; 169- (int)_integerValueForKey:(NSString *)key; 170- (void)_setIntegerValue:(int)value forKey:(NSString *)key; 171- (float)_floatValueForKey:(NSString *)key; 172- (void)_setFloatValue:(float)value forKey:(NSString *)key; 173- (void)_setUnsignedLongLongValue:(unsigned long long)value forKey:(NSString *)key; 174- (unsigned long long)_unsignedLongLongValueForKey:(NSString *)key; 175@end 176 177@implementation WebPreferences 178 179- init 180{ 181 // Create fake identifier 182 static int instanceCount = 1; 183 NSString *fakeIdentifier; 184 185 // At least ensure that identifier hasn't been already used. 186 fakeIdentifier = [NSString stringWithFormat:@"WebPreferences%d", instanceCount++]; 187 while ([[self class] _getInstanceForIdentifier:fakeIdentifier]){ 188 fakeIdentifier = [NSString stringWithFormat:@"WebPreferences%d", instanceCount++]; 189 } 190 191 return [self initWithIdentifier:fakeIdentifier]; 192} 193 194- (id)initWithIdentifier:(NSString *)anIdentifier 195{ 196 self = [super init]; 197 if (!self) 198 return nil; 199 200 _private = [[WebPreferencesPrivate alloc] init]; 201 _private->IBCreatorID = [[WebPreferences _IBCreatorID] retain]; 202 203 WebPreferences *instance = [[self class] _getInstanceForIdentifier:anIdentifier]; 204 if (instance){ 205 [self release]; 206 return [instance retain]; 207 } 208 209 _private->values = [[NSMutableDictionary alloc] init]; 210 _private->identifier = [anIdentifier copy]; 211 _private->automaticallyDetectsCacheModel = YES; 212 213 [[self class] _setInstance:self forIdentifier:_private->identifier]; 214 215 [self _postPreferencesChangesNotification]; 216 217 return self; 218} 219 220- (id)initWithCoder:(NSCoder *)decoder 221{ 222 self = [super init]; 223 if (!self) 224 return nil; 225 226 _private = [[WebPreferencesPrivate alloc] init]; 227 _private->IBCreatorID = [[WebPreferences _IBCreatorID] retain]; 228 _private->automaticallyDetectsCacheModel = YES; 229 230 @try { 231 id identifier = nil; 232 id values = nil; 233 if ([decoder allowsKeyedCoding]) { 234 identifier = [decoder decodeObjectForKey:@"Identifier"]; 235 values = [decoder decodeObjectForKey:@"Values"]; 236 } else { 237 int version; 238 [decoder decodeValueOfObjCType:@encode(int) at:&version]; 239 if (version == 1) { 240 identifier = [decoder decodeObject]; 241 values = [decoder decodeObject]; 242 } 243 } 244 245 if ([identifier isKindOfClass:[NSString class]]) 246 _private->identifier = [identifier copy]; 247 if ([values isKindOfClass:[NSDictionary class]]) 248 _private->values = [values mutableCopy]; // ensure dictionary is mutable 249 250 LOG(Encoding, "Identifier = %@, Values = %@\n", _private->identifier, _private->values); 251 } @catch(id) { 252 [self release]; 253 return nil; 254 } 255 256 // If we load a nib multiple times, or have instances in multiple 257 // nibs with the same name, the first guy up wins. 258 WebPreferences *instance = [[self class] _getInstanceForIdentifier:_private->identifier]; 259 if (instance) { 260 [self release]; 261 self = [instance retain]; 262 } else { 263 [[self class] _setInstance:self forIdentifier:_private->identifier]; 264 } 265 266 return self; 267} 268 269- (void)encodeWithCoder:(NSCoder *)encoder 270{ 271 if ([encoder allowsKeyedCoding]){ 272 [encoder encodeObject:_private->identifier forKey:@"Identifier"]; 273 [encoder encodeObject:_private->values forKey:@"Values"]; 274 LOG (Encoding, "Identifier = %@, Values = %@\n", _private->identifier, _private->values); 275 } 276 else { 277 int version = WebPreferencesVersion; 278 [encoder encodeValueOfObjCType:@encode(int) at:&version]; 279 [encoder encodeObject:_private->identifier]; 280 [encoder encodeObject:_private->values]; 281 } 282} 283 284+ (WebPreferences *)standardPreferences 285{ 286 if (_standardPreferences == nil) { 287 _standardPreferences = [[WebPreferences alloc] initWithIdentifier:nil]; 288 [_standardPreferences setAutosaves:YES]; 289 } 290 291 return _standardPreferences; 292} 293 294// if we ever have more than one WebPreferences object, this would move to init 295+ (void)initialize 296{ 297 NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys: 298 @"Times", WebKitStandardFontPreferenceKey, 299 @"Courier", WebKitFixedFontPreferenceKey, 300 @"Times", WebKitSerifFontPreferenceKey, 301 @"Helvetica", WebKitSansSerifFontPreferenceKey, 302 @"Apple Chancery", WebKitCursiveFontPreferenceKey, 303 @"Papyrus", WebKitFantasyFontPreferenceKey, 304 @"1", WebKitMinimumFontSizePreferenceKey, 305 @"9", WebKitMinimumLogicalFontSizePreferenceKey, 306 @"16", WebKitDefaultFontSizePreferenceKey, 307 @"13", WebKitDefaultFixedFontSizePreferenceKey, 308 @"ISO-8859-1", WebKitDefaultTextEncodingNamePreferenceKey, 309 [NSNumber numberWithBool:NO], WebKitUserStyleSheetEnabledPreferenceKey, 310 @"", WebKitUserStyleSheetLocationPreferenceKey, 311 [NSNumber numberWithBool:NO], WebKitShouldPrintBackgroundsPreferenceKey, 312 [NSNumber numberWithBool:NO], WebKitTextAreasAreResizablePreferenceKey, 313 [NSNumber numberWithBool:NO], WebKitShrinksStandaloneImagesToFitPreferenceKey, 314 [NSNumber numberWithBool:YES], WebKitJavaEnabledPreferenceKey, 315 [NSNumber numberWithBool:YES], WebKitJavaScriptEnabledPreferenceKey, 316 [NSNumber numberWithBool:YES], WebKitJavaScriptCanOpenWindowsAutomaticallyPreferenceKey, 317 [NSNumber numberWithBool:YES], WebKitPluginsEnabledPreferenceKey, 318 [NSNumber numberWithBool:YES], WebKitDatabasesEnabledPreferenceKey, 319 [NSNumber numberWithBool:YES], WebKitLocalStorageEnabledPreferenceKey, 320 [NSNumber numberWithBool:YES], WebKitAllowAnimatedImagesPreferenceKey, 321 [NSNumber numberWithBool:YES], WebKitAllowAnimatedImageLoopingPreferenceKey, 322 [NSNumber numberWithBool:YES], WebKitDisplayImagesKey, 323 @"1800", WebKitBackForwardCacheExpirationIntervalKey, 324 [NSNumber numberWithBool:NO], WebKitTabToLinksPreferenceKey, 325 [NSNumber numberWithBool:NO], WebKitPrivateBrowsingEnabledPreferenceKey, 326 [NSNumber numberWithBool:NO], WebKitRespectStandardStyleKeyEquivalentsPreferenceKey, 327 [NSNumber numberWithBool:NO], WebKitShowsURLsInToolTipsPreferenceKey, 328 @"1", WebKitPDFDisplayModePreferenceKey, 329 @"0", WebKitPDFScaleFactorPreferenceKey, 330 @"0", WebKitUseSiteSpecificSpoofingPreferenceKey, 331 [NSNumber numberWithInt:WebKitEditableLinkDefaultBehavior], WebKitEditableLinkBehaviorPreferenceKey, 332#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) 333 [NSNumber numberWithInt:WebTextDirectionSubmenuAutomaticallyIncluded], 334#else 335 [NSNumber numberWithInt:WebTextDirectionSubmenuNeverIncluded], 336#endif 337 WebKitTextDirectionSubmenuInclusionBehaviorPreferenceKey, 338 [NSNumber numberWithBool:NO], WebKitDOMPasteAllowedPreferenceKey, 339 [NSNumber numberWithBool:YES], WebKitUsesPageCachePreferenceKey, 340 [NSNumber numberWithInt:cacheModelForMainBundle()], WebKitCacheModelPreferenceKey, 341 [NSNumber numberWithBool:NO], WebKitDeveloperExtrasEnabledPreferenceKey, 342 [NSNumber numberWithBool:YES], WebKitAuthorAndUserStylesEnabledPreferenceKey, 343 [NSNumber numberWithBool:NO], WebKitApplicationChromeModeEnabledPreferenceKey, 344 [NSNumber numberWithBool:NO], WebKitWebArchiveDebugModeEnabledPreferenceKey, 345 [NSNumber numberWithBool:NO], WebKitOfflineWebApplicationCacheEnabledPreferenceKey, 346 [NSNumber numberWithBool:YES], WebKitZoomsTextOnlyPreferenceKey, 347#ifndef NDEBUG 348 // In Release and Production we skip a lot of object teardown during quit to speed up shutdown time. This breaks 349 // our RefCount Leak tracking, and so for Debug we will use the full document teardown. 350 [NSNumber numberWithBool:YES], WebKitEnableFullDocumentTeardownPreferenceKey, 351#endif 352 nil]; 353 354 // This value shouldn't ever change, which is assumed in the initialization of WebKitPDFDisplayModePreferenceKey above 355 ASSERT(kPDFDisplaySinglePageContinuous == 1); 356 [[NSUserDefaults standardUserDefaults] registerDefaults:dict]; 357} 358 359- (void)dealloc 360{ 361 [_private release]; 362 [super dealloc]; 363} 364 365- (NSString *)identifier 366{ 367 return _private->identifier; 368} 369 370- (id)_valueForKey:(NSString *)key 371{ 372 NSString *_key = KEY(key); 373 id o = [_private->values objectForKey:_key]; 374 if (o) 375 return o; 376 o = [[NSUserDefaults standardUserDefaults] objectForKey:_key]; 377 if (!o && key != _key) 378 o = [[NSUserDefaults standardUserDefaults] objectForKey:key]; 379 return o; 380} 381 382- (NSString *)_stringValueForKey:(NSString *)key 383{ 384 id s = [self _valueForKey:key]; 385 return [s isKindOfClass:[NSString class]] ? (NSString *)s : nil; 386} 387 388- (void)_setStringValue:(NSString *)value forKey:(NSString *)key 389{ 390 if ([[self _stringValueForKey:key] isEqualToString:value]) 391 return; 392 NSString *_key = KEY(key); 393 [_private->values setObject:value forKey:_key]; 394 if (_private->autosaves) 395 [[NSUserDefaults standardUserDefaults] setObject:value forKey:_key]; 396 [self _postPreferencesChangesNotification]; 397} 398 399- (int)_integerValueForKey:(NSString *)key 400{ 401 id o = [self _valueForKey:key]; 402 return [o respondsToSelector:@selector(intValue)] ? [o intValue] : 0; 403} 404 405- (void)_setIntegerValue:(int)value forKey:(NSString *)key 406{ 407 if ([self _integerValueForKey:key] == value) 408 return; 409 NSString *_key = KEY(key); 410 [_private->values _webkit_setInt:value forKey:_key]; 411 if (_private->autosaves) 412 [[NSUserDefaults standardUserDefaults] setInteger:value forKey:_key]; 413 [self _postPreferencesChangesNotification]; 414} 415 416- (float)_floatValueForKey:(NSString *)key 417{ 418 id o = [self _valueForKey:key]; 419 return [o respondsToSelector:@selector(floatValue)] ? [o floatValue] : 0.0f; 420} 421 422- (void)_setFloatValue:(float)value forKey:(NSString *)key 423{ 424 if ([self _floatValueForKey:key] == value) 425 return; 426 NSString *_key = KEY(key); 427 [_private->values _webkit_setFloat:value forKey:_key]; 428 if (_private->autosaves) 429 [[NSUserDefaults standardUserDefaults] setFloat:value forKey:_key]; 430 [self _postPreferencesChangesNotification]; 431} 432 433- (BOOL)_boolValueForKey:(NSString *)key 434{ 435 return [self _integerValueForKey:key] != 0; 436} 437 438- (void)_setBoolValue:(BOOL)value forKey:(NSString *)key 439{ 440 if ([self _boolValueForKey:key] == value) 441 return; 442 NSString *_key = KEY(key); 443 [_private->values _webkit_setBool:value forKey:_key]; 444 if (_private->autosaves) 445 [[NSUserDefaults standardUserDefaults] setBool:value forKey:_key]; 446 [self _postPreferencesChangesNotification]; 447} 448 449- (unsigned long long)_unsignedLongLongValueForKey:(NSString *)key 450{ 451 id o = [self _valueForKey:key]; 452 return [o respondsToSelector:@selector(unsignedLongLongValue)] ? [o unsignedLongLongValue] : 0; 453} 454 455- (void)_setUnsignedLongLongValue:(unsigned long long)value forKey:(NSString *)key 456{ 457 if ([self _unsignedLongLongValueForKey:key] == value) 458 return; 459 NSString *_key = KEY(key); 460 [_private->values _webkit_setUnsignedLongLong:value forKey:_key]; 461 if (_private->autosaves) 462 [[NSUserDefaults standardUserDefaults] setObject:[NSNumber numberWithUnsignedLongLong:value] forKey:_key]; 463 [self _postPreferencesChangesNotification]; 464} 465 466- (NSString *)standardFontFamily 467{ 468 return [self _stringValueForKey: WebKitStandardFontPreferenceKey]; 469} 470 471- (void)setStandardFontFamily:(NSString *)family 472{ 473 [self _setStringValue: family forKey: WebKitStandardFontPreferenceKey]; 474} 475 476- (NSString *)fixedFontFamily 477{ 478 return [self _stringValueForKey: WebKitFixedFontPreferenceKey]; 479} 480 481- (void)setFixedFontFamily:(NSString *)family 482{ 483 [self _setStringValue: family forKey: WebKitFixedFontPreferenceKey]; 484} 485 486- (NSString *)serifFontFamily 487{ 488 return [self _stringValueForKey: WebKitSerifFontPreferenceKey]; 489} 490 491- (void)setSerifFontFamily:(NSString *)family 492{ 493 [self _setStringValue: family forKey: WebKitSerifFontPreferenceKey]; 494} 495 496- (NSString *)sansSerifFontFamily 497{ 498 return [self _stringValueForKey: WebKitSansSerifFontPreferenceKey]; 499} 500 501- (void)setSansSerifFontFamily:(NSString *)family 502{ 503 [self _setStringValue: family forKey: WebKitSansSerifFontPreferenceKey]; 504} 505 506- (NSString *)cursiveFontFamily 507{ 508 return [self _stringValueForKey: WebKitCursiveFontPreferenceKey]; 509} 510 511- (void)setCursiveFontFamily:(NSString *)family 512{ 513 [self _setStringValue: family forKey: WebKitCursiveFontPreferenceKey]; 514} 515 516- (NSString *)fantasyFontFamily 517{ 518 return [self _stringValueForKey: WebKitFantasyFontPreferenceKey]; 519} 520 521- (void)setFantasyFontFamily:(NSString *)family 522{ 523 [self _setStringValue: family forKey: WebKitFantasyFontPreferenceKey]; 524} 525 526- (int)defaultFontSize 527{ 528 return [self _integerValueForKey: WebKitDefaultFontSizePreferenceKey]; 529} 530 531- (void)setDefaultFontSize:(int)size 532{ 533 [self _setIntegerValue: size forKey: WebKitDefaultFontSizePreferenceKey]; 534} 535 536- (int)defaultFixedFontSize 537{ 538 return [self _integerValueForKey: WebKitDefaultFixedFontSizePreferenceKey]; 539} 540 541- (void)setDefaultFixedFontSize:(int)size 542{ 543 [self _setIntegerValue: size forKey: WebKitDefaultFixedFontSizePreferenceKey]; 544} 545 546- (int)minimumFontSize 547{ 548 return [self _integerValueForKey: WebKitMinimumFontSizePreferenceKey]; 549} 550 551- (void)setMinimumFontSize:(int)size 552{ 553 [self _setIntegerValue: size forKey: WebKitMinimumFontSizePreferenceKey]; 554} 555 556- (int)minimumLogicalFontSize 557{ 558 return [self _integerValueForKey: WebKitMinimumLogicalFontSizePreferenceKey]; 559} 560 561- (void)setMinimumLogicalFontSize:(int)size 562{ 563 [self _setIntegerValue: size forKey: WebKitMinimumLogicalFontSizePreferenceKey]; 564} 565 566- (NSString *)defaultTextEncodingName 567{ 568 return [self _stringValueForKey: WebKitDefaultTextEncodingNamePreferenceKey]; 569} 570 571- (void)setDefaultTextEncodingName:(NSString *)encoding 572{ 573 [self _setStringValue: encoding forKey: WebKitDefaultTextEncodingNamePreferenceKey]; 574} 575 576- (BOOL)userStyleSheetEnabled 577{ 578 return [self _boolValueForKey: WebKitUserStyleSheetEnabledPreferenceKey]; 579} 580 581- (void)setUserStyleSheetEnabled:(BOOL)flag 582{ 583 [self _setBoolValue: flag forKey: WebKitUserStyleSheetEnabledPreferenceKey]; 584} 585 586- (NSURL *)userStyleSheetLocation 587{ 588 NSString *locationString = [self _stringValueForKey: WebKitUserStyleSheetLocationPreferenceKey]; 589 590 if ([locationString _webkit_looksLikeAbsoluteURL]) { 591 return [NSURL _web_URLWithDataAsString:locationString]; 592 } else { 593 locationString = [locationString stringByExpandingTildeInPath]; 594 return [NSURL fileURLWithPath:locationString]; 595 } 596} 597 598- (void)setUserStyleSheetLocation:(NSURL *)URL 599{ 600 NSString *locationString; 601 602 if ([URL isFileURL]) { 603 locationString = [[URL path] _web_stringByAbbreviatingWithTildeInPath]; 604 } else { 605 locationString = [URL _web_originalDataAsString]; 606 } 607 608 [self _setStringValue:locationString forKey: WebKitUserStyleSheetLocationPreferenceKey]; 609} 610 611- (BOOL)shouldPrintBackgrounds 612{ 613 return [self _boolValueForKey: WebKitShouldPrintBackgroundsPreferenceKey]; 614} 615 616- (void)setShouldPrintBackgrounds:(BOOL)flag 617{ 618 [self _setBoolValue: flag forKey: WebKitShouldPrintBackgroundsPreferenceKey]; 619} 620 621- (BOOL)isJavaEnabled 622{ 623 return [self _boolValueForKey: WebKitJavaEnabledPreferenceKey]; 624} 625 626- (void)setJavaEnabled:(BOOL)flag 627{ 628 [self _setBoolValue: flag forKey: WebKitJavaEnabledPreferenceKey]; 629} 630 631- (BOOL)isJavaScriptEnabled 632{ 633 return [self _boolValueForKey: WebKitJavaScriptEnabledPreferenceKey]; 634} 635 636- (void)setJavaScriptEnabled:(BOOL)flag 637{ 638 [self _setBoolValue: flag forKey: WebKitJavaScriptEnabledPreferenceKey]; 639} 640 641- (BOOL)javaScriptCanOpenWindowsAutomatically 642{ 643 return [self _boolValueForKey: WebKitJavaScriptCanOpenWindowsAutomaticallyPreferenceKey]; 644} 645 646- (void)setJavaScriptCanOpenWindowsAutomatically:(BOOL)flag 647{ 648 [self _setBoolValue: flag forKey: WebKitJavaScriptCanOpenWindowsAutomaticallyPreferenceKey]; 649} 650 651- (BOOL)arePlugInsEnabled 652{ 653 return [self _boolValueForKey: WebKitPluginsEnabledPreferenceKey]; 654} 655 656- (void)setPlugInsEnabled:(BOOL)flag 657{ 658 [self _setBoolValue: flag forKey: WebKitPluginsEnabledPreferenceKey]; 659} 660 661- (BOOL)allowsAnimatedImages 662{ 663 return [self _boolValueForKey: WebKitAllowAnimatedImagesPreferenceKey]; 664} 665 666- (void)setAllowsAnimatedImages:(BOOL)flag; 667{ 668 [self _setBoolValue: flag forKey: WebKitAllowAnimatedImagesPreferenceKey]; 669} 670 671- (BOOL)allowsAnimatedImageLooping 672{ 673 return [self _boolValueForKey: WebKitAllowAnimatedImageLoopingPreferenceKey]; 674} 675 676- (void)setAllowsAnimatedImageLooping: (BOOL)flag 677{ 678 [self _setBoolValue: flag forKey: WebKitAllowAnimatedImageLoopingPreferenceKey]; 679} 680 681- (void)setLoadsImagesAutomatically: (BOOL)flag 682{ 683 [self _setBoolValue: flag forKey: WebKitDisplayImagesKey]; 684} 685 686- (BOOL)loadsImagesAutomatically 687{ 688 return [self _boolValueForKey: WebKitDisplayImagesKey]; 689} 690 691- (void)setAutosaves:(BOOL)flag; 692{ 693 _private->autosaves = flag; 694} 695 696- (BOOL)autosaves 697{ 698 return _private->autosaves; 699} 700 701- (void)setTabsToLinks:(BOOL)flag 702{ 703 [self _setBoolValue: flag forKey: WebKitTabToLinksPreferenceKey]; 704} 705 706- (BOOL)tabsToLinks 707{ 708 return [self _boolValueForKey:WebKitTabToLinksPreferenceKey]; 709} 710 711- (void)setPrivateBrowsingEnabled:(BOOL)flag 712{ 713 [self _setBoolValue:flag forKey:WebKitPrivateBrowsingEnabledPreferenceKey]; 714} 715 716- (BOOL)privateBrowsingEnabled 717{ 718 return [self _boolValueForKey:WebKitPrivateBrowsingEnabledPreferenceKey]; 719} 720 721- (void)setUsesPageCache:(BOOL)usesPageCache 722{ 723 [self _setBoolValue:usesPageCache forKey:WebKitUsesPageCachePreferenceKey]; 724} 725 726- (BOOL)usesPageCache 727{ 728 return [self _boolValueForKey:WebKitUsesPageCachePreferenceKey]; 729} 730 731- (void)setCacheModel:(WebCacheModel)cacheModel 732{ 733 [self _setIntegerValue:cacheModel forKey:WebKitCacheModelPreferenceKey]; 734 [self setAutomaticallyDetectsCacheModel:NO]; 735} 736 737- (WebCacheModel)cacheModel 738{ 739 return [self _integerValueForKey:WebKitCacheModelPreferenceKey]; 740} 741 742@end 743 744@implementation WebPreferences (WebPrivate) 745 746- (BOOL)developerExtrasEnabled 747{ 748 NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; 749 if ([defaults boolForKey:@"DisableWebKitDeveloperExtras"]) 750 return NO; 751#ifdef NDEBUG 752 if ([defaults boolForKey:@"WebKitDeveloperExtras"] || [defaults boolForKey:@"IncludeDebugMenu"]) 753 return YES; 754 return [self _boolValueForKey:WebKitDeveloperExtrasEnabledPreferenceKey]; 755#else 756 return YES; // always enable in debug builds 757#endif 758} 759 760- (void)setDeveloperExtrasEnabled:(BOOL)flag 761{ 762 [self _setBoolValue:flag forKey:WebKitDeveloperExtrasEnabledPreferenceKey]; 763} 764 765- (BOOL)authorAndUserStylesEnabled 766{ 767 return [self _boolValueForKey:WebKitAuthorAndUserStylesEnabledPreferenceKey]; 768} 769 770- (void)setAuthorAndUserStylesEnabled:(BOOL)flag 771{ 772 [self _setBoolValue:flag forKey:WebKitAuthorAndUserStylesEnabledPreferenceKey]; 773} 774 775- (BOOL)applicationChromeModeEnabled 776{ 777 return [self _boolValueForKey:WebKitApplicationChromeModeEnabledPreferenceKey]; 778} 779 780- (void)setApplicationChromeModeEnabled:(BOOL)flag 781{ 782 [self _setBoolValue:flag forKey:WebKitApplicationChromeModeEnabledPreferenceKey]; 783} 784 785- (BOOL)webArchiveDebugModeEnabled 786{ 787 return [self _boolValueForKey:WebKitWebArchiveDebugModeEnabledPreferenceKey]; 788} 789 790- (void)setWebArchiveDebugModeEnabled:(BOOL)flag 791{ 792 [self _setBoolValue:flag forKey:WebKitWebArchiveDebugModeEnabledPreferenceKey]; 793} 794 795- (BOOL)offlineWebApplicationCacheEnabled 796{ 797 return [self _boolValueForKey:WebKitOfflineWebApplicationCacheEnabledPreferenceKey]; 798} 799 800- (void)setOfflineWebApplicationCacheEnabled:(BOOL)flag 801{ 802 [self _setBoolValue:flag forKey:WebKitOfflineWebApplicationCacheEnabledPreferenceKey]; 803} 804 805- (BOOL)zoomsTextOnly 806{ 807 return [self _boolValueForKey:WebKitZoomsTextOnlyPreferenceKey]; 808} 809 810- (void)setZoomsTextOnly:(BOOL)flag 811{ 812 [self _setBoolValue:flag forKey:WebKitZoomsTextOnlyPreferenceKey]; 813} 814 815- (BOOL)respectStandardStyleKeyEquivalents 816{ 817 return [self _boolValueForKey:WebKitRespectStandardStyleKeyEquivalentsPreferenceKey]; 818} 819 820- (void)setRespectStandardStyleKeyEquivalents:(BOOL)flag 821{ 822 [self _setBoolValue:flag forKey:WebKitRespectStandardStyleKeyEquivalentsPreferenceKey]; 823} 824 825- (BOOL)showsURLsInToolTips 826{ 827 return [self _boolValueForKey:WebKitShowsURLsInToolTipsPreferenceKey]; 828} 829 830- (void)setShowsURLsInToolTips:(BOOL)flag 831{ 832 [self _setBoolValue:flag forKey:WebKitShowsURLsInToolTipsPreferenceKey]; 833} 834 835- (BOOL)textAreasAreResizable 836{ 837 return [self _boolValueForKey: WebKitTextAreasAreResizablePreferenceKey]; 838} 839 840- (void)setTextAreasAreResizable:(BOOL)flag 841{ 842 [self _setBoolValue: flag forKey: WebKitTextAreasAreResizablePreferenceKey]; 843} 844 845- (BOOL)shrinksStandaloneImagesToFit 846{ 847 return [self _boolValueForKey:WebKitShrinksStandaloneImagesToFitPreferenceKey]; 848} 849 850- (void)setShrinksStandaloneImagesToFit:(BOOL)flag 851{ 852 [self _setBoolValue:flag forKey:WebKitShrinksStandaloneImagesToFitPreferenceKey]; 853} 854 855- (BOOL)automaticallyDetectsCacheModel 856{ 857 return _private->automaticallyDetectsCacheModel; 858} 859 860- (void)setAutomaticallyDetectsCacheModel:(BOOL)automaticallyDetectsCacheModel 861{ 862 _private->automaticallyDetectsCacheModel = automaticallyDetectsCacheModel; 863} 864 865- (NSTimeInterval)_backForwardCacheExpirationInterval 866{ 867 // FIXME: There's probably no good reason to read from the standard user defaults instead of self. 868 return (NSTimeInterval)[[NSUserDefaults standardUserDefaults] floatForKey:WebKitBackForwardCacheExpirationIntervalKey]; 869} 870 871- (float)PDFScaleFactor 872{ 873 return [self _floatValueForKey:WebKitPDFScaleFactorPreferenceKey]; 874} 875 876- (void)setPDFScaleFactor:(float)factor 877{ 878 [self _setFloatValue:factor forKey:WebKitPDFScaleFactorPreferenceKey]; 879} 880 881- (PDFDisplayMode)PDFDisplayMode; 882{ 883 PDFDisplayMode value = [self _integerValueForKey:WebKitPDFDisplayModePreferenceKey]; 884 if (value != kPDFDisplaySinglePage && value != kPDFDisplaySinglePageContinuous && value != kPDFDisplayTwoUp && value != kPDFDisplayTwoUpContinuous) { 885 // protect against new modes from future versions of OS X stored in defaults 886 value = kPDFDisplaySinglePageContinuous; 887 } 888 return value; 889} 890 891- (void)setPDFDisplayMode:(PDFDisplayMode)mode 892{ 893 [self _setIntegerValue:mode forKey:WebKitPDFDisplayModePreferenceKey]; 894} 895 896- (WebKitEditableLinkBehavior)editableLinkBehavior 897{ 898 WebKitEditableLinkBehavior value = static_cast<WebKitEditableLinkBehavior> ([self _integerValueForKey:WebKitEditableLinkBehaviorPreferenceKey]); 899 if (value != WebKitEditableLinkDefaultBehavior && 900 value != WebKitEditableLinkAlwaysLive && 901 value != WebKitEditableLinkNeverLive && 902 value != WebKitEditableLinkOnlyLiveWithShiftKey && 903 value != WebKitEditableLinkLiveWhenNotFocused) { 904 // ensure that a valid result is returned 905 value = WebKitEditableLinkDefaultBehavior; 906 } 907 908 return value; 909} 910 911- (void)setEditableLinkBehavior:(WebKitEditableLinkBehavior)behavior 912{ 913 [self _setIntegerValue:behavior forKey:WebKitEditableLinkBehaviorPreferenceKey]; 914} 915 916- (WebTextDirectionSubmenuInclusionBehavior)textDirectionSubmenuInclusionBehavior 917{ 918 WebTextDirectionSubmenuInclusionBehavior value = static_cast<WebTextDirectionSubmenuInclusionBehavior>([self _integerValueForKey:WebKitTextDirectionSubmenuInclusionBehaviorPreferenceKey]); 919 if (value != WebTextDirectionSubmenuNeverIncluded && 920 value != WebTextDirectionSubmenuAutomaticallyIncluded && 921 value != WebTextDirectionSubmenuAlwaysIncluded) { 922 // Ensure that a valid result is returned. 923 value = WebTextDirectionSubmenuNeverIncluded; 924 } 925 return value; 926} 927 928- (void)setTextDirectionSubmenuInclusionBehavior:(WebTextDirectionSubmenuInclusionBehavior)behavior 929{ 930 [self _setIntegerValue:behavior forKey:WebKitTextDirectionSubmenuInclusionBehaviorPreferenceKey]; 931} 932 933- (BOOL)_useSiteSpecificSpoofing 934{ 935 return [self _boolValueForKey:WebKitUseSiteSpecificSpoofingPreferenceKey]; 936} 937 938- (void)_setUseSiteSpecificSpoofing:(BOOL)newValue 939{ 940 [self _setBoolValue:newValue forKey:WebKitUseSiteSpecificSpoofingPreferenceKey]; 941} 942 943- (BOOL)databasesEnabled 944{ 945 return [self _boolValueForKey:WebKitDatabasesEnabledPreferenceKey]; 946} 947 948- (void)setDatabasesEnabled:(BOOL)databasesEnabled 949{ 950 [self _setBoolValue:databasesEnabled forKey:WebKitDatabasesEnabledPreferenceKey]; 951} 952 953- (BOOL)localStorageEnabled 954{ 955 return [self _boolValueForKey:WebKitLocalStorageEnabledPreferenceKey]; 956} 957 958- (void)setLocalStorageEnabled:(BOOL)localStorageEnabled 959{ 960 [self _setBoolValue:localStorageEnabled forKey:WebKitLocalStorageEnabledPreferenceKey]; 961} 962 963+ (WebPreferences *)_getInstanceForIdentifier:(NSString *)ident 964{ 965 LOG(Encoding, "requesting for %@\n", ident); 966 967 if (!ident) 968 return _standardPreferences; 969 970 WebPreferences *instance = [webPreferencesInstances objectForKey:[self _concatenateKeyWithIBCreatorID:ident]]; 971 972 return instance; 973} 974 975+ (void)_setInstance:(WebPreferences *)instance forIdentifier:(NSString *)ident 976{ 977 if (!webPreferencesInstances) 978 webPreferencesInstances = [[NSMutableDictionary alloc] init]; 979 if (ident) { 980 [webPreferencesInstances setObject:instance forKey:[self _concatenateKeyWithIBCreatorID:ident]]; 981 LOG(Encoding, "recording %p for %@\n", instance, [self _concatenateKeyWithIBCreatorID:ident]); 982 } 983} 984 985+ (void)_checkLastReferenceForIdentifier:(id)identifier 986{ 987 // FIXME: This won't work at all under garbage collection because retainCount returns a constant. 988 // We may need to change WebPreferences API so there's an explicit way to end the lifetime of one. 989 WebPreferences *instance = [webPreferencesInstances objectForKey:identifier]; 990 if ([instance retainCount] == 1) 991 [webPreferencesInstances removeObjectForKey:identifier]; 992} 993 994+ (void)_removeReferenceForIdentifier:(NSString *)ident 995{ 996 if (ident) 997 [self performSelector:@selector(_checkLastReferenceForIdentifier:) withObject:[self _concatenateKeyWithIBCreatorID:ident] afterDelay:0.1]; 998} 999 1000- (void)_postPreferencesChangesNotification 1001{ 1002 [[NSNotificationCenter defaultCenter] 1003 postNotificationName:WebPreferencesChangedNotification object:self 1004 userInfo:nil]; 1005} 1006 1007+ (CFStringEncoding)_systemCFStringEncoding 1008{ 1009 return WKGetWebDefaultCFStringEncoding(); 1010} 1011 1012+ (void)_setInitialDefaultTextEncodingToSystemEncoding 1013{ 1014 NSString *systemEncodingName = (NSString *)CFStringConvertEncodingToIANACharSetName([self _systemCFStringEncoding]); 1015 1016 // CFStringConvertEncodingToIANACharSetName() returns CP949 for kTextEncodingDOSKorean AKA "extended EUC-KR" AKA windows-939. 1017 // ICU uses this name for a different encoding, so we need to change the name to a value that actually gives us windows-939. 1018 // In addition, this value must match what is used in Safari, see <rdar://problem/5579292>. 1019 if ([systemEncodingName isEqualToString:@"CP949"]) 1020 systemEncodingName = @"ks_c_5601-1987"; 1021 [[NSUserDefaults standardUserDefaults] registerDefaults: 1022 [NSDictionary dictionaryWithObject:systemEncodingName forKey:WebKitDefaultTextEncodingNamePreferenceKey]]; 1023} 1024 1025static NSString *classIBCreatorID = nil; 1026 1027+ (void)_setIBCreatorID:(NSString *)string 1028{ 1029 NSString *old = classIBCreatorID; 1030 classIBCreatorID = [string copy]; 1031 [old release]; 1032} 1033 1034- (BOOL)isDOMPasteAllowed 1035{ 1036 return [self _boolValueForKey:WebKitDOMPasteAllowedPreferenceKey]; 1037} 1038 1039- (void)setDOMPasteAllowed:(BOOL)DOMPasteAllowed 1040{ 1041 [self _setBoolValue:DOMPasteAllowed forKey:WebKitDOMPasteAllowedPreferenceKey]; 1042} 1043 1044- (void)_setFTPDirectoryTemplatePath:(NSString *)path 1045{ 1046 [self _setStringValue:[path stringByStandardizingPath] forKey:WebKitFTPDirectoryTemplatePath]; 1047} 1048 1049- (NSString *)_localStorageDatabasePath 1050{ 1051 return [[self _stringValueForKey:WebKitLocalStorageDatabasePathPreferenceKey] stringByStandardizingPath]; 1052} 1053 1054- (void)_setLocalStorageDatabasePath:(NSString *)path 1055{ 1056 [self _setStringValue:[path stringByStandardizingPath] forKey:WebKitLocalStorageDatabasePathPreferenceKey]; 1057} 1058 1059- (NSString *)_ftpDirectoryTemplatePath 1060{ 1061 return [[self _stringValueForKey:WebKitFTPDirectoryTemplatePath] stringByStandardizingPath]; 1062} 1063 1064- (void)_setForceFTPDirectoryListings:(BOOL)force 1065{ 1066 [self _setBoolValue:force forKey:WebKitForceFTPDirectoryListings]; 1067} 1068 1069- (BOOL)_forceFTPDirectoryListings 1070{ 1071 return [self _boolValueForKey:WebKitForceFTPDirectoryListings]; 1072} 1073 1074- (void)didRemoveFromWebView 1075{ 1076 ASSERT(_private->numWebViews); 1077 if (--_private->numWebViews == 0) 1078 [[NSNotificationCenter defaultCenter] 1079 postNotificationName:WebPreferencesRemovedNotification 1080 object:self 1081 userInfo:nil]; 1082} 1083 1084- (void)willAddToWebView 1085{ 1086 ++_private->numWebViews; 1087} 1088 1089- (void)setFullDocumentTeardownEnabled:(BOOL)fullDocumentTeardownEnabled 1090{ 1091 [self _setBoolValue:fullDocumentTeardownEnabled forKey:WebKitEnableFullDocumentTeardownPreferenceKey]; 1092} 1093 1094- (BOOL)fullDocumentTeardownEnabled 1095{ 1096 return [self _boolValueForKey:WebKitEnableFullDocumentTeardownPreferenceKey]; 1097} 1098@end 1099 1100@implementation WebPreferences (WebInternal) 1101 1102+ (NSString *)_IBCreatorID 1103{ 1104 return classIBCreatorID; 1105} 1106 1107+ (NSString *)_concatenateKeyWithIBCreatorID:(NSString *)key 1108{ 1109 NSString *IBCreatorID = [WebPreferences _IBCreatorID]; 1110 if (!IBCreatorID) 1111 return key; 1112 return [IBCreatorID stringByAppendingString:key]; 1113} 1114 1115@end 1116