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