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