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