2009-03-26 Jungshik Shin <jshin@chromium.org>
[WebKit-https.git] / WebKit / mac / WebView / WebPreferences.mm
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
41 NSString *WebPreferencesChangedNotification = @"WebPreferencesChangedNotification";
42 NSString *WebPreferencesRemovedNotification = @"WebPreferencesRemovedNotification";
43
44 #define KEY(x) (_private->identifier ? [_private->identifier stringByAppendingString:(x)] : (x))
45
46 enum { WebPreferencesVersion = 1 };
47
48 static WebPreferences *_standardPreferences;
49 static NSMutableDictionary *webPreferencesInstances;
50
51 static 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
62 static 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],   WebKitUsesEncodingDetectorPreferenceKey,
310         [NSNumber numberWithBool:NO],   WebKitUserStyleSheetEnabledPreferenceKey,
311         @"",                            WebKitUserStyleSheetLocationPreferenceKey,
312         [NSNumber numberWithBool:NO],   WebKitShouldPrintBackgroundsPreferenceKey,
313         [NSNumber numberWithBool:NO],   WebKitTextAreasAreResizablePreferenceKey,
314         [NSNumber numberWithBool:NO],   WebKitShrinksStandaloneImagesToFitPreferenceKey,
315         [NSNumber numberWithBool:YES],  WebKitJavaEnabledPreferenceKey,
316         [NSNumber numberWithBool:YES],  WebKitJavaScriptEnabledPreferenceKey,
317         [NSNumber numberWithBool:YES],  WebKitWebSecurityEnabledPreferenceKey,
318         [NSNumber numberWithBool:YES],  WebKitAllowUniversalAccessFromFileURLsPreferenceKey,
319         [NSNumber numberWithBool:YES],  WebKitJavaScriptCanOpenWindowsAutomaticallyPreferenceKey,
320         [NSNumber numberWithBool:YES],  WebKitPluginsEnabledPreferenceKey,
321         [NSNumber numberWithBool:YES],  WebKitDatabasesEnabledPreferenceKey,
322         [NSNumber numberWithBool:YES],  WebKitLocalStorageEnabledPreferenceKey,
323         [NSNumber numberWithBool:YES],  WebKitAllowAnimatedImagesPreferenceKey,
324         [NSNumber numberWithBool:YES],  WebKitAllowAnimatedImageLoopingPreferenceKey,
325         [NSNumber numberWithBool:YES],  WebKitDisplayImagesKey,
326         @"1800",                        WebKitBackForwardCacheExpirationIntervalKey,
327         [NSNumber numberWithBool:NO],   WebKitTabToLinksPreferenceKey,
328         [NSNumber numberWithBool:NO],   WebKitPrivateBrowsingEnabledPreferenceKey,
329         [NSNumber numberWithBool:NO],   WebKitRespectStandardStyleKeyEquivalentsPreferenceKey,
330         [NSNumber numberWithBool:NO],   WebKitShowsURLsInToolTipsPreferenceKey,
331         @"1",                           WebKitPDFDisplayModePreferenceKey,
332         @"0",                           WebKitPDFScaleFactorPreferenceKey,
333         @"0",                           WebKitUseSiteSpecificSpoofingPreferenceKey,
334         [NSNumber numberWithInt:WebKitEditableLinkDefaultBehavior], WebKitEditableLinkBehaviorPreferenceKey,
335 #if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
336         [NSNumber numberWithInt:WebTextDirectionSubmenuAutomaticallyIncluded],
337 #else
338         [NSNumber numberWithInt:WebTextDirectionSubmenuNeverIncluded],
339 #endif
340                                         WebKitTextDirectionSubmenuInclusionBehaviorPreferenceKey,
341         [NSNumber numberWithBool:NO],   WebKitDOMPasteAllowedPreferenceKey,
342         [NSNumber numberWithBool:YES],  WebKitUsesPageCachePreferenceKey,
343         [NSNumber numberWithInt:cacheModelForMainBundle()], WebKitCacheModelPreferenceKey,
344         [NSNumber numberWithBool:NO],   WebKitDeveloperExtrasEnabledPreferenceKey,
345         [NSNumber numberWithBool:YES],  WebKitAuthorAndUserStylesEnabledPreferenceKey,
346         [NSNumber numberWithBool:NO],   WebKitApplicationChromeModeEnabledPreferenceKey,
347         [NSNumber numberWithBool:NO],   WebKitWebArchiveDebugModeEnabledPreferenceKey,
348         [NSNumber numberWithBool:NO],   WebKitOfflineWebApplicationCacheEnabledPreferenceKey,
349         [NSNumber numberWithBool:YES],  WebKitZoomsTextOnlyPreferenceKey,
350 #ifndef NDEBUG
351         // In Release and Production we skip a lot of object teardown during quit to speed up shutdown time.  This breaks
352         // our RefCount Leak tracking, and so for Debug we will use the full document teardown.
353         [NSNumber numberWithBool:YES],  WebKitEnableFullDocumentTeardownPreferenceKey,
354 #endif
355         nil];
356
357     // This value shouldn't ever change, which is assumed in the initialization of WebKitPDFDisplayModePreferenceKey above
358     ASSERT(kPDFDisplaySinglePageContinuous == 1);
359     [[NSUserDefaults standardUserDefaults] registerDefaults:dict];
360 }
361
362 - (void)dealloc
363 {
364     [_private release];
365     [super dealloc];
366 }
367
368 - (NSString *)identifier
369 {
370     return _private->identifier;
371 }
372
373 - (id)_valueForKey:(NSString *)key
374 {
375     NSString *_key = KEY(key);
376     id o = [_private->values objectForKey:_key];
377     if (o)
378         return o;
379     o = [[NSUserDefaults standardUserDefaults] objectForKey:_key];
380     if (!o && key != _key)
381         o = [[NSUserDefaults standardUserDefaults] objectForKey:key];
382     return o;
383 }
384
385 - (NSString *)_stringValueForKey:(NSString *)key
386 {
387     id s = [self _valueForKey:key];
388     return [s isKindOfClass:[NSString class]] ? (NSString *)s : nil;
389 }
390
391 - (void)_setStringValue:(NSString *)value forKey:(NSString *)key
392 {
393     if ([[self _stringValueForKey:key] isEqualToString:value])
394         return;
395     NSString *_key = KEY(key);
396     [_private->values setObject:value forKey:_key];
397     if (_private->autosaves)
398         [[NSUserDefaults standardUserDefaults] setObject:value forKey:_key];
399     [self _postPreferencesChangesNotification];
400 }
401
402 - (int)_integerValueForKey:(NSString *)key
403 {
404     id o = [self _valueForKey:key];
405     return [o respondsToSelector:@selector(intValue)] ? [o intValue] : 0;
406 }
407
408 - (void)_setIntegerValue:(int)value forKey:(NSString *)key
409 {
410     if ([self _integerValueForKey:key] == value)
411         return;
412     NSString *_key = KEY(key);
413     [_private->values _webkit_setInt:value forKey:_key];
414     if (_private->autosaves)
415         [[NSUserDefaults standardUserDefaults] setInteger:value forKey:_key];
416     [self _postPreferencesChangesNotification];
417 }
418
419 - (float)_floatValueForKey:(NSString *)key
420 {
421     id o = [self _valueForKey:key];
422     return [o respondsToSelector:@selector(floatValue)] ? [o floatValue] : 0.0f;
423 }
424
425 - (void)_setFloatValue:(float)value forKey:(NSString *)key
426 {
427     if ([self _floatValueForKey:key] == value)
428         return;
429     NSString *_key = KEY(key);
430     [_private->values _webkit_setFloat:value forKey:_key];
431     if (_private->autosaves)
432         [[NSUserDefaults standardUserDefaults] setFloat:value forKey:_key];
433     [self _postPreferencesChangesNotification];
434 }
435
436 - (BOOL)_boolValueForKey:(NSString *)key
437 {
438     return [self _integerValueForKey:key] != 0;
439 }
440
441 - (void)_setBoolValue:(BOOL)value forKey:(NSString *)key
442 {
443     if ([self _boolValueForKey:key] == value)
444         return;
445     NSString *_key = KEY(key);
446     [_private->values _webkit_setBool:value forKey:_key];
447     if (_private->autosaves)
448         [[NSUserDefaults standardUserDefaults] setBool:value forKey:_key];
449     [self _postPreferencesChangesNotification];
450 }
451
452 - (unsigned long long)_unsignedLongLongValueForKey:(NSString *)key
453 {
454     id o = [self _valueForKey:key];
455     return [o respondsToSelector:@selector(unsignedLongLongValue)] ? [o unsignedLongLongValue] : 0;
456 }
457
458 - (void)_setUnsignedLongLongValue:(unsigned long long)value forKey:(NSString *)key
459 {
460     if ([self _unsignedLongLongValueForKey:key] == value)
461         return;
462     NSString *_key = KEY(key);
463     [_private->values _webkit_setUnsignedLongLong:value forKey:_key];
464     if (_private->autosaves)
465         [[NSUserDefaults standardUserDefaults] setObject:[NSNumber numberWithUnsignedLongLong:value] forKey:_key];
466     [self _postPreferencesChangesNotification];
467 }
468
469 - (NSString *)standardFontFamily
470 {
471     return [self _stringValueForKey: WebKitStandardFontPreferenceKey];
472 }
473
474 - (void)setStandardFontFamily:(NSString *)family
475 {
476     [self _setStringValue: family forKey: WebKitStandardFontPreferenceKey];
477 }
478
479 - (NSString *)fixedFontFamily
480 {
481     return [self _stringValueForKey: WebKitFixedFontPreferenceKey];
482 }
483
484 - (void)setFixedFontFamily:(NSString *)family
485 {
486     [self _setStringValue: family forKey: WebKitFixedFontPreferenceKey];
487 }
488
489 - (NSString *)serifFontFamily
490 {
491     return [self _stringValueForKey: WebKitSerifFontPreferenceKey];
492 }
493
494 - (void)setSerifFontFamily:(NSString *)family 
495 {
496     [self _setStringValue: family forKey: WebKitSerifFontPreferenceKey];
497 }
498
499 - (NSString *)sansSerifFontFamily
500 {
501     return [self _stringValueForKey: WebKitSansSerifFontPreferenceKey];
502 }
503
504 - (void)setSansSerifFontFamily:(NSString *)family
505 {
506     [self _setStringValue: family forKey: WebKitSansSerifFontPreferenceKey];
507 }
508
509 - (NSString *)cursiveFontFamily
510 {
511     return [self _stringValueForKey: WebKitCursiveFontPreferenceKey];
512 }
513
514 - (void)setCursiveFontFamily:(NSString *)family
515 {
516     [self _setStringValue: family forKey: WebKitCursiveFontPreferenceKey];
517 }
518
519 - (NSString *)fantasyFontFamily
520 {
521     return [self _stringValueForKey: WebKitFantasyFontPreferenceKey];
522 }
523
524 - (void)setFantasyFontFamily:(NSString *)family
525 {
526     [self _setStringValue: family forKey: WebKitFantasyFontPreferenceKey];
527 }
528
529 - (int)defaultFontSize
530 {
531     return [self _integerValueForKey: WebKitDefaultFontSizePreferenceKey];
532 }
533
534 - (void)setDefaultFontSize:(int)size
535 {
536     [self _setIntegerValue: size forKey: WebKitDefaultFontSizePreferenceKey];
537 }
538
539 - (int)defaultFixedFontSize
540 {
541     return [self _integerValueForKey: WebKitDefaultFixedFontSizePreferenceKey];
542 }
543
544 - (void)setDefaultFixedFontSize:(int)size
545 {
546     [self _setIntegerValue: size forKey: WebKitDefaultFixedFontSizePreferenceKey];
547 }
548
549 - (int)minimumFontSize
550 {
551     return [self _integerValueForKey: WebKitMinimumFontSizePreferenceKey];
552 }
553
554 - (void)setMinimumFontSize:(int)size
555 {
556     [self _setIntegerValue: size forKey: WebKitMinimumFontSizePreferenceKey];
557 }
558
559 - (int)minimumLogicalFontSize
560 {
561   return [self _integerValueForKey: WebKitMinimumLogicalFontSizePreferenceKey];
562 }
563
564 - (void)setMinimumLogicalFontSize:(int)size
565 {
566   [self _setIntegerValue: size forKey: WebKitMinimumLogicalFontSizePreferenceKey];
567 }
568
569 - (NSString *)defaultTextEncodingName
570 {
571     return [self _stringValueForKey: WebKitDefaultTextEncodingNamePreferenceKey];
572 }
573
574 - (void)setDefaultTextEncodingName:(NSString *)encoding
575 {
576     [self _setStringValue: encoding forKey: WebKitDefaultTextEncodingNamePreferenceKey];
577 }
578
579 - (BOOL)userStyleSheetEnabled
580 {
581     return [self _boolValueForKey: WebKitUserStyleSheetEnabledPreferenceKey];
582 }
583
584 - (void)setUserStyleSheetEnabled:(BOOL)flag
585 {
586     [self _setBoolValue: flag forKey: WebKitUserStyleSheetEnabledPreferenceKey];
587 }
588
589 - (NSURL *)userStyleSheetLocation
590 {
591     NSString *locationString = [self _stringValueForKey: WebKitUserStyleSheetLocationPreferenceKey];
592     
593     if ([locationString _webkit_looksLikeAbsoluteURL]) {
594         return [NSURL _web_URLWithDataAsString:locationString];
595     } else {
596         locationString = [locationString stringByExpandingTildeInPath];
597         return [NSURL fileURLWithPath:locationString];
598     }
599 }
600
601 - (void)setUserStyleSheetLocation:(NSURL *)URL
602 {
603     NSString *locationString;
604     
605     if ([URL isFileURL]) {
606         locationString = [[URL path] _web_stringByAbbreviatingWithTildeInPath];
607     } else {
608         locationString = [URL _web_originalDataAsString];
609     }
610     
611     [self _setStringValue:locationString forKey: WebKitUserStyleSheetLocationPreferenceKey];
612 }
613
614 - (BOOL)shouldPrintBackgrounds
615 {
616     return [self _boolValueForKey: WebKitShouldPrintBackgroundsPreferenceKey];
617 }
618
619 - (void)setShouldPrintBackgrounds:(BOOL)flag
620 {
621     [self _setBoolValue: flag forKey: WebKitShouldPrintBackgroundsPreferenceKey];
622 }
623
624 - (BOOL)isJavaEnabled
625 {
626     return [self _boolValueForKey: WebKitJavaEnabledPreferenceKey];
627 }
628
629 - (void)setJavaEnabled:(BOOL)flag
630 {
631     [self _setBoolValue: flag forKey: WebKitJavaEnabledPreferenceKey];
632 }
633
634 - (BOOL)isJavaScriptEnabled
635 {
636     return [self _boolValueForKey: WebKitJavaScriptEnabledPreferenceKey];
637 }
638
639 - (void)setJavaScriptEnabled:(BOOL)flag
640 {
641     [self _setBoolValue: flag forKey: WebKitJavaScriptEnabledPreferenceKey];
642 }
643
644 - (BOOL)javaScriptCanOpenWindowsAutomatically
645 {
646     return [self _boolValueForKey: WebKitJavaScriptCanOpenWindowsAutomaticallyPreferenceKey];
647 }
648
649 - (void)setJavaScriptCanOpenWindowsAutomatically:(BOOL)flag
650 {
651     [self _setBoolValue: flag forKey: WebKitJavaScriptCanOpenWindowsAutomaticallyPreferenceKey];
652 }
653
654 - (BOOL)arePlugInsEnabled
655 {
656     return [self _boolValueForKey: WebKitPluginsEnabledPreferenceKey];
657 }
658
659 - (void)setPlugInsEnabled:(BOOL)flag
660 {
661     [self _setBoolValue: flag forKey: WebKitPluginsEnabledPreferenceKey];
662 }
663
664 - (BOOL)allowsAnimatedImages
665 {
666     return [self _boolValueForKey: WebKitAllowAnimatedImagesPreferenceKey];
667 }
668
669 - (void)setAllowsAnimatedImages:(BOOL)flag
670 {
671     [self _setBoolValue: flag forKey: WebKitAllowAnimatedImagesPreferenceKey];
672 }
673
674 - (BOOL)allowsAnimatedImageLooping
675 {
676     return [self _boolValueForKey: WebKitAllowAnimatedImageLoopingPreferenceKey];
677 }
678
679 - (void)setAllowsAnimatedImageLooping: (BOOL)flag
680 {
681     [self _setBoolValue: flag forKey: WebKitAllowAnimatedImageLoopingPreferenceKey];
682 }
683
684 - (void)setLoadsImagesAutomatically: (BOOL)flag
685 {
686     [self _setBoolValue: flag forKey: WebKitDisplayImagesKey];
687 }
688
689 - (BOOL)loadsImagesAutomatically
690 {
691     return [self _boolValueForKey: WebKitDisplayImagesKey];
692 }
693
694 - (void)setAutosaves:(BOOL)flag
695 {
696     _private->autosaves = flag;
697 }
698
699 - (BOOL)autosaves
700 {
701     return _private->autosaves;
702 }
703
704 - (void)setTabsToLinks:(BOOL)flag
705 {
706     [self _setBoolValue: flag forKey: WebKitTabToLinksPreferenceKey];
707 }
708
709 - (BOOL)tabsToLinks
710 {
711     return [self _boolValueForKey:WebKitTabToLinksPreferenceKey];
712 }
713
714 - (void)setPrivateBrowsingEnabled:(BOOL)flag
715 {
716     [self _setBoolValue:flag forKey:WebKitPrivateBrowsingEnabledPreferenceKey];
717 }
718
719 - (BOOL)privateBrowsingEnabled
720 {
721     return [self _boolValueForKey:WebKitPrivateBrowsingEnabledPreferenceKey];
722 }
723
724 - (void)setUsesPageCache:(BOOL)usesPageCache
725 {
726     [self _setBoolValue:usesPageCache forKey:WebKitUsesPageCachePreferenceKey];
727 }
728
729 - (BOOL)usesPageCache
730 {
731     return [self _boolValueForKey:WebKitUsesPageCachePreferenceKey];
732 }
733
734 - (void)setCacheModel:(WebCacheModel)cacheModel
735 {
736     [self _setIntegerValue:cacheModel forKey:WebKitCacheModelPreferenceKey];
737     [self setAutomaticallyDetectsCacheModel:NO];
738 }
739
740 - (WebCacheModel)cacheModel
741 {
742     return [self _integerValueForKey:WebKitCacheModelPreferenceKey];
743 }
744
745 @end
746
747 @implementation WebPreferences (WebPrivate)
748
749 - (BOOL)developerExtrasEnabled
750 {
751     NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
752     if ([defaults boolForKey:@"DisableWebKitDeveloperExtras"])
753         return NO;
754 #ifdef NDEBUG
755     if ([defaults boolForKey:@"WebKitDeveloperExtras"] || [defaults boolForKey:@"IncludeDebugMenu"])
756         return YES;
757     return [self _boolValueForKey:WebKitDeveloperExtrasEnabledPreferenceKey];
758 #else
759     return YES; // always enable in debug builds
760 #endif
761 }
762
763 - (void)setDeveloperExtrasEnabled:(BOOL)flag
764 {
765     [self _setBoolValue:flag forKey:WebKitDeveloperExtrasEnabledPreferenceKey];
766 }
767
768 - (BOOL)authorAndUserStylesEnabled
769 {
770     return [self _boolValueForKey:WebKitAuthorAndUserStylesEnabledPreferenceKey];
771 }
772
773 - (void)setAuthorAndUserStylesEnabled:(BOOL)flag
774 {
775     [self _setBoolValue:flag forKey:WebKitAuthorAndUserStylesEnabledPreferenceKey];
776 }
777
778 - (BOOL)applicationChromeModeEnabled
779 {
780     return [self _boolValueForKey:WebKitApplicationChromeModeEnabledPreferenceKey];
781 }
782
783 - (void)setApplicationChromeModeEnabled:(BOOL)flag
784 {
785     [self _setBoolValue:flag forKey:WebKitApplicationChromeModeEnabledPreferenceKey];
786 }
787
788 - (BOOL)webArchiveDebugModeEnabled
789 {
790     return [self _boolValueForKey:WebKitWebArchiveDebugModeEnabledPreferenceKey];
791 }
792
793 - (void)setWebArchiveDebugModeEnabled:(BOOL)flag
794 {
795     [self _setBoolValue:flag forKey:WebKitWebArchiveDebugModeEnabledPreferenceKey];
796 }
797
798 - (BOOL)offlineWebApplicationCacheEnabled
799 {
800     return [self _boolValueForKey:WebKitOfflineWebApplicationCacheEnabledPreferenceKey];
801 }
802
803 - (void)setOfflineWebApplicationCacheEnabled:(BOOL)flag
804 {
805     [self _setBoolValue:flag forKey:WebKitOfflineWebApplicationCacheEnabledPreferenceKey];
806 }
807
808 - (BOOL)zoomsTextOnly
809 {
810     return [self _boolValueForKey:WebKitZoomsTextOnlyPreferenceKey];
811 }
812
813 - (void)setZoomsTextOnly:(BOOL)flag
814 {
815     [self _setBoolValue:flag forKey:WebKitZoomsTextOnlyPreferenceKey];
816 }
817
818 - (BOOL)respectStandardStyleKeyEquivalents
819 {
820     return [self _boolValueForKey:WebKitRespectStandardStyleKeyEquivalentsPreferenceKey];
821 }
822
823 - (void)setRespectStandardStyleKeyEquivalents:(BOOL)flag
824 {
825     [self _setBoolValue:flag forKey:WebKitRespectStandardStyleKeyEquivalentsPreferenceKey];
826 }
827
828 - (BOOL)showsURLsInToolTips
829 {
830     return [self _boolValueForKey:WebKitShowsURLsInToolTipsPreferenceKey];
831 }
832
833 - (void)setShowsURLsInToolTips:(BOOL)flag
834 {
835     [self _setBoolValue:flag forKey:WebKitShowsURLsInToolTipsPreferenceKey];
836 }
837
838 - (BOOL)textAreasAreResizable
839 {
840     return [self _boolValueForKey: WebKitTextAreasAreResizablePreferenceKey];
841 }
842
843 - (void)setTextAreasAreResizable:(BOOL)flag
844 {
845     [self _setBoolValue: flag forKey: WebKitTextAreasAreResizablePreferenceKey];
846 }
847
848 - (BOOL)shrinksStandaloneImagesToFit
849 {
850     return [self _boolValueForKey:WebKitShrinksStandaloneImagesToFitPreferenceKey];
851 }
852
853 - (void)setShrinksStandaloneImagesToFit:(BOOL)flag
854 {
855     [self _setBoolValue:flag forKey:WebKitShrinksStandaloneImagesToFitPreferenceKey];
856 }
857
858 - (BOOL)automaticallyDetectsCacheModel
859 {
860     return _private->automaticallyDetectsCacheModel;
861 }
862
863 - (void)setAutomaticallyDetectsCacheModel:(BOOL)automaticallyDetectsCacheModel
864 {
865     _private->automaticallyDetectsCacheModel = automaticallyDetectsCacheModel;
866 }
867
868 - (BOOL)usesEncodingDetector
869 {
870     return [self _boolValueForKey: WebKitUsesEncodingDetectorPreferenceKey];
871 }
872
873 - (void)setUsesEncodingDetector:(BOOL)flag
874 {
875     [self _setBoolValue: flag forKey: WebKitUsesEncodingDetectorPreferenceKey];
876 }
877
878 - (BOOL)isWebSecurityEnabled
879 {
880     return [self _boolValueForKey: WebKitWebSecurityEnabledPreferenceKey];
881 }
882
883 - (void)setWebSecurityEnabled:(BOOL)flag
884 {
885     [self _setBoolValue: flag forKey: WebKitWebSecurityEnabledPreferenceKey];
886 }
887
888 - (BOOL)allowUniversalAccessFromFileURLs
889 {
890     return [self _boolValueForKey: WebKitAllowUniversalAccessFromFileURLsPreferenceKey];
891 }
892
893 - (void)setAllowUniversalAccessFromFileURLs:(BOOL)flag
894 {
895     [self _setBoolValue: flag forKey: WebKitAllowUniversalAccessFromFileURLsPreferenceKey];
896 }
897
898 - (NSTimeInterval)_backForwardCacheExpirationInterval
899 {
900     // FIXME: There's probably no good reason to read from the standard user defaults instead of self.
901     return (NSTimeInterval)[[NSUserDefaults standardUserDefaults] floatForKey:WebKitBackForwardCacheExpirationIntervalKey];
902 }
903
904 - (float)PDFScaleFactor
905 {
906     return [self _floatValueForKey:WebKitPDFScaleFactorPreferenceKey];
907 }
908
909 - (void)setPDFScaleFactor:(float)factor
910 {
911     [self _setFloatValue:factor forKey:WebKitPDFScaleFactorPreferenceKey];
912 }
913
914 - (PDFDisplayMode)PDFDisplayMode
915 {
916     PDFDisplayMode value = [self _integerValueForKey:WebKitPDFDisplayModePreferenceKey];
917     if (value != kPDFDisplaySinglePage && value != kPDFDisplaySinglePageContinuous && value != kPDFDisplayTwoUp && value != kPDFDisplayTwoUpContinuous) {
918         // protect against new modes from future versions of OS X stored in defaults
919         value = kPDFDisplaySinglePageContinuous;
920     }
921     return value;
922 }
923
924 - (void)setPDFDisplayMode:(PDFDisplayMode)mode
925 {
926     [self _setIntegerValue:mode forKey:WebKitPDFDisplayModePreferenceKey];
927 }
928
929 - (WebKitEditableLinkBehavior)editableLinkBehavior
930 {
931     WebKitEditableLinkBehavior value = static_cast<WebKitEditableLinkBehavior> ([self _integerValueForKey:WebKitEditableLinkBehaviorPreferenceKey]);
932     if (value != WebKitEditableLinkDefaultBehavior &&
933         value != WebKitEditableLinkAlwaysLive &&
934         value != WebKitEditableLinkNeverLive &&
935         value != WebKitEditableLinkOnlyLiveWithShiftKey &&
936         value != WebKitEditableLinkLiveWhenNotFocused) {
937         // ensure that a valid result is returned
938         value = WebKitEditableLinkDefaultBehavior;
939     }
940     
941     return value;
942 }
943
944 - (void)setEditableLinkBehavior:(WebKitEditableLinkBehavior)behavior
945 {
946     [self _setIntegerValue:behavior forKey:WebKitEditableLinkBehaviorPreferenceKey];
947 }
948
949 - (WebTextDirectionSubmenuInclusionBehavior)textDirectionSubmenuInclusionBehavior
950 {
951     WebTextDirectionSubmenuInclusionBehavior value = static_cast<WebTextDirectionSubmenuInclusionBehavior>([self _integerValueForKey:WebKitTextDirectionSubmenuInclusionBehaviorPreferenceKey]);
952     if (value != WebTextDirectionSubmenuNeverIncluded &&
953         value != WebTextDirectionSubmenuAutomaticallyIncluded &&
954         value != WebTextDirectionSubmenuAlwaysIncluded) {
955         // Ensure that a valid result is returned.
956         value = WebTextDirectionSubmenuNeverIncluded;
957     }
958     return value;
959 }
960
961 - (void)setTextDirectionSubmenuInclusionBehavior:(WebTextDirectionSubmenuInclusionBehavior)behavior
962 {
963     [self _setIntegerValue:behavior forKey:WebKitTextDirectionSubmenuInclusionBehaviorPreferenceKey];
964 }
965
966 - (BOOL)_useSiteSpecificSpoofing
967 {
968     return [self _boolValueForKey:WebKitUseSiteSpecificSpoofingPreferenceKey];
969 }
970
971 - (void)_setUseSiteSpecificSpoofing:(BOOL)newValue
972 {
973     [self _setBoolValue:newValue forKey:WebKitUseSiteSpecificSpoofingPreferenceKey];
974 }
975
976 - (BOOL)databasesEnabled
977 {
978     return [self _boolValueForKey:WebKitDatabasesEnabledPreferenceKey];
979 }
980
981 - (void)setDatabasesEnabled:(BOOL)databasesEnabled
982 {
983     [self _setBoolValue:databasesEnabled forKey:WebKitDatabasesEnabledPreferenceKey];
984 }
985
986 - (BOOL)localStorageEnabled
987 {
988     return [self _boolValueForKey:WebKitLocalStorageEnabledPreferenceKey];
989 }
990
991 - (void)setLocalStorageEnabled:(BOOL)localStorageEnabled
992 {
993     [self _setBoolValue:localStorageEnabled forKey:WebKitLocalStorageEnabledPreferenceKey];
994 }
995
996 + (WebPreferences *)_getInstanceForIdentifier:(NSString *)ident
997 {
998     LOG(Encoding, "requesting for %@\n", ident);
999
1000     if (!ident)
1001         return _standardPreferences;
1002     
1003     WebPreferences *instance = [webPreferencesInstances objectForKey:[self _concatenateKeyWithIBCreatorID:ident]];
1004
1005     return instance;
1006 }
1007
1008 + (void)_setInstance:(WebPreferences *)instance forIdentifier:(NSString *)ident
1009 {
1010     if (!webPreferencesInstances)
1011         webPreferencesInstances = [[NSMutableDictionary alloc] init];
1012     if (ident) {
1013         [webPreferencesInstances setObject:instance forKey:[self _concatenateKeyWithIBCreatorID:ident]];
1014         LOG(Encoding, "recording %p for %@\n", instance, [self _concatenateKeyWithIBCreatorID:ident]);
1015     }
1016 }
1017
1018 + (void)_checkLastReferenceForIdentifier:(id)identifier
1019 {
1020     // FIXME: This won't work at all under garbage collection because retainCount returns a constant.
1021     // We may need to change WebPreferences API so there's an explicit way to end the lifetime of one.
1022     WebPreferences *instance = [webPreferencesInstances objectForKey:identifier];
1023     if ([instance retainCount] == 1)
1024         [webPreferencesInstances removeObjectForKey:identifier];
1025 }
1026
1027 + (void)_removeReferenceForIdentifier:(NSString *)ident
1028 {
1029     if (ident)
1030         [self performSelector:@selector(_checkLastReferenceForIdentifier:) withObject:[self _concatenateKeyWithIBCreatorID:ident] afterDelay:0.1];
1031 }
1032
1033 - (void)_postPreferencesChangesNotification
1034 {
1035     [[NSNotificationCenter defaultCenter]
1036         postNotificationName:WebPreferencesChangedNotification object:self
1037                     userInfo:nil];
1038 }
1039
1040 + (CFStringEncoding)_systemCFStringEncoding
1041 {
1042     return WKGetWebDefaultCFStringEncoding();
1043 }
1044
1045 + (void)_setInitialDefaultTextEncodingToSystemEncoding
1046 {
1047     NSString *systemEncodingName = (NSString *)CFStringConvertEncodingToIANACharSetName([self _systemCFStringEncoding]);
1048
1049     // CFStringConvertEncodingToIANACharSetName() returns CP949 for kTextEncodingDOSKorean AKA "extended EUC-KR" AKA windows-939.
1050     // ICU uses this name for a different encoding, so we need to change the name to a value that actually gives us windows-939.
1051     // In addition, this value must match what is used in Safari, see <rdar://problem/5579292>.
1052     if ([systemEncodingName isEqualToString:@"CP949"])
1053         systemEncodingName = @"ks_c_5601-1987";
1054     [[NSUserDefaults standardUserDefaults] registerDefaults:
1055         [NSDictionary dictionaryWithObject:systemEncodingName forKey:WebKitDefaultTextEncodingNamePreferenceKey]];
1056 }
1057
1058 static NSString *classIBCreatorID = nil;
1059
1060 + (void)_setIBCreatorID:(NSString *)string
1061 {
1062     NSString *old = classIBCreatorID;
1063     classIBCreatorID = [string copy];
1064     [old release];
1065 }
1066
1067 - (BOOL)isDOMPasteAllowed
1068 {
1069     return [self _boolValueForKey:WebKitDOMPasteAllowedPreferenceKey];
1070 }
1071
1072 - (void)setDOMPasteAllowed:(BOOL)DOMPasteAllowed
1073 {
1074     [self _setBoolValue:DOMPasteAllowed forKey:WebKitDOMPasteAllowedPreferenceKey];
1075 }
1076
1077 - (void)_setFTPDirectoryTemplatePath:(NSString *)path
1078 {
1079     [self _setStringValue:[path stringByStandardizingPath] forKey:WebKitFTPDirectoryTemplatePath];
1080 }
1081
1082 - (NSString *)_localStorageDatabasePath
1083 {
1084     return [[self _stringValueForKey:WebKitLocalStorageDatabasePathPreferenceKey] stringByStandardizingPath];
1085 }
1086
1087 - (void)_setLocalStorageDatabasePath:(NSString *)path
1088 {
1089     [self _setStringValue:[path stringByStandardizingPath] forKey:WebKitLocalStorageDatabasePathPreferenceKey];
1090 }
1091
1092 - (NSString *)_ftpDirectoryTemplatePath
1093 {
1094     return [[self _stringValueForKey:WebKitFTPDirectoryTemplatePath] stringByStandardizingPath];
1095 }
1096
1097 - (void)_setForceFTPDirectoryListings:(BOOL)force
1098 {
1099     [self _setBoolValue:force forKey:WebKitForceFTPDirectoryListings];
1100 }
1101
1102 - (BOOL)_forceFTPDirectoryListings
1103 {
1104     return [self _boolValueForKey:WebKitForceFTPDirectoryListings];
1105 }
1106
1107 - (void)didRemoveFromWebView
1108 {
1109     ASSERT(_private->numWebViews);
1110     if (--_private->numWebViews == 0)
1111         [[NSNotificationCenter defaultCenter]
1112             postNotificationName:WebPreferencesRemovedNotification
1113                           object:self
1114                         userInfo:nil];
1115 }
1116
1117 - (void)willAddToWebView
1118 {
1119     ++_private->numWebViews;
1120 }
1121
1122 - (void)setFullDocumentTeardownEnabled:(BOOL)fullDocumentTeardownEnabled
1123 {
1124     [self _setBoolValue:fullDocumentTeardownEnabled forKey:WebKitEnableFullDocumentTeardownPreferenceKey];
1125 }
1126
1127 - (BOOL)fullDocumentTeardownEnabled
1128 {
1129     return [self _boolValueForKey:WebKitEnableFullDocumentTeardownPreferenceKey];
1130 }
1131 @end
1132
1133 @implementation WebPreferences (WebInternal)
1134
1135 + (NSString *)_IBCreatorID
1136 {
1137     return classIBCreatorID;
1138 }
1139
1140 + (NSString *)_concatenateKeyWithIBCreatorID:(NSString *)key
1141 {
1142     NSString *IBCreatorID = [WebPreferences _IBCreatorID];
1143     if (!IBCreatorID)
1144         return key;
1145     return [IBCreatorID stringByAppendingString:key];
1146 }
1147
1148 @end