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