Reviewed by Hyatt.
[WebKit.git] / WebKit / WebView.subproj / WebPreferences.m
1 /*
2  * Copyright (C) 2005 Apple Computer, Inc.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1.  Redistributions of source code must retain the above copyright
9  *     notice, this list of conditions and the following disclaimer. 
10  * 2.  Redistributions in binary form must reproduce the above copyright
11  *     notice, this list of conditions and the following disclaimer in the
12  *     documentation and/or other materials provided with the distribution. 
13  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14  *     its contributors may be used to endorse or promote products derived
15  *     from this software without specific prior written permission. 
16  *
17  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 #import <WebKit/WebPreferencesPrivate.h>
30 #import <WebKit/WebPreferenceKeysPrivate.h>
31
32 #import <WebKit/WebKitLogging.h>
33 #import <WebKit/WebKitNSStringExtras.h>
34 #import <WebKit/WebNSDictionaryExtras.h>
35 #import <WebKit/WebNSURLExtras.h>
36
37 #import <WebCore/WebCoreSettings.h>
38
39 #import <Carbon/Carbon.h>                           // For TEC
40 #import <CoreFoundation/CFStringDefaultEncoding.h>  // For __CFStringGetUserDefaultEncoding
41
42 NSString *WebPreferencesChangedNotification = @"WebPreferencesChangedNotification";
43
44 #define KEY(x) (_private->identifier ? [_private->identifier stringByAppendingString:(x)] : (x))
45
46 enum { WebPreferencesVersion = 1 };
47
48 @interface WebPreferencesPrivate : NSObject
49 {
50 @public
51     NSMutableDictionary *values;
52     NSString *identifier;
53     NSString *IBCreatorID;
54     BOOL autosaves;
55 }
56 @end
57
58 @implementation WebPreferencesPrivate
59 - (void)dealloc
60 {
61     [values release];
62     [identifier release];
63     [IBCreatorID release];
64     [super dealloc];
65 }
66 @end
67
68 @interface WebPreferences (WebInternal)
69 + (NSString *)_concatenateKeyWithIBCreatorID:(NSString *)key;
70 + (NSString *)_IBCreatorID;
71 @end
72
73 @interface WebPreferences (WebForwardDeclarations)
74 // This pseudo-category is needed so these methods can be used from within other category implementations
75 // without being in the public header file.
76 - (BOOL)_boolValueForKey:(NSString *)key;
77 - (void)_setBoolValue:(BOOL)value forKey:(NSString *)key;
78 @end
79
80 @implementation WebPreferences
81
82 - init
83 {
84     // Create fake identifier
85     static int instanceCount = 1;
86     NSString *fakeIdentifier;
87     
88     // At least ensure that identifier hasn't been already used.  
89     fakeIdentifier = [NSString stringWithFormat:@"WebPreferences%d", instanceCount++];
90     while ([[self class] _getInstanceForIdentifier:fakeIdentifier]){
91         fakeIdentifier = [NSString stringWithFormat:@"WebPreferences%d", instanceCount++];
92     }
93     
94     return [self initWithIdentifier:fakeIdentifier];
95 }
96
97 static WebPreferences *_standardPreferences = nil;
98
99 - (id)initWithIdentifier:(NSString *)anIdentifier
100 {
101     [super init];
102
103     _private = [[WebPreferencesPrivate alloc] init];
104     _private->IBCreatorID = [[WebPreferences _IBCreatorID] retain];
105
106     WebPreferences *instance = [[self class] _getInstanceForIdentifier:anIdentifier];
107     if (instance){
108         [self release];
109         return [instance retain];
110     }
111
112     _private->values = [[NSMutableDictionary alloc] init];
113     _private->identifier = [anIdentifier copy];
114     
115     [[self class] _setInstance:self forIdentifier:_private->identifier];
116
117     [[NSNotificationCenter defaultCenter]
118        postNotificationName:WebPreferencesChangedNotification object:self userInfo:nil];
119
120     return self;
121 }
122
123 - (id)initWithCoder:(NSCoder *)decoder
124 {
125     volatile id result = nil;
126
127 NS_DURING
128
129     int version;
130
131     _private = [[WebPreferencesPrivate alloc] init];
132     _private->IBCreatorID = [[WebPreferences _IBCreatorID] retain];
133     
134     if ([decoder allowsKeyedCoding]){
135         _private->identifier = [[decoder decodeObjectForKey:@"Identifier"] retain];
136         _private->values = [[decoder decodeObjectForKey:@"Values"] retain];
137         LOG (Encoding, "Identifier = %@, Values = %@\n", _private->identifier, _private->values);
138     }
139     else {
140         [decoder decodeValueOfObjCType:@encode(int) at:&version];
141         if (version == 1){
142             _private->identifier = [[decoder decodeObject] retain];
143             _private->values = [[decoder decodeObject] retain];
144         }
145     }
146     
147     // If we load a nib multiple times, or have instances in multiple
148     // nibs with the same name, the first guy up wins.
149     WebPreferences *instance = [[self class] _getInstanceForIdentifier:_private->identifier];
150     if (instance){
151         [self release];
152         result = [instance retain];
153     }
154     else {
155         [[self class] _setInstance:self forIdentifier:_private->identifier];
156         result = self;
157     }
158     
159 NS_HANDLER
160
161     result = nil;
162     [self release];
163     
164 NS_ENDHANDLER
165
166     return result;
167 }
168
169 - (void)encodeWithCoder:(NSCoder *)encoder
170 {
171     if ([encoder allowsKeyedCoding]){
172         [encoder encodeObject:_private->identifier forKey:@"Identifier"];
173         [encoder encodeObject:_private->values forKey:@"Values"];
174         LOG (Encoding, "Identifier = %@, Values = %@\n", _private->identifier, _private->values);
175     }
176     else {
177         int version = WebPreferencesVersion;
178         [encoder encodeValueOfObjCType:@encode(int) at:&version];
179         [encoder encodeObject:_private->identifier];
180         [encoder encodeObject:_private->values];
181     }
182 }
183
184 + (WebPreferences *)standardPreferences
185 {
186     if (_standardPreferences == nil) {
187         _standardPreferences = [[WebPreferences alloc] initWithIdentifier:nil];
188         [_standardPreferences setAutosaves:YES];
189         [_standardPreferences _postPreferencesChangesNotification];
190     }
191
192     return _standardPreferences;
193 }
194
195 // if we ever have more than one WebPreferences object, this would move to init
196 + (void)initialize
197 {
198     NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:
199         @"0x0",                         WebKitLogLevelPreferenceKey,
200         @"Times",                       WebKitStandardFontPreferenceKey,
201         @"Courier",                     WebKitFixedFontPreferenceKey,
202         @"Times",                       WebKitSerifFontPreferenceKey,
203         @"Helvetica",                   WebKitSansSerifFontPreferenceKey,
204         @"Apple Chancery",              WebKitCursiveFontPreferenceKey,
205         @"Papyrus",                     WebKitFantasyFontPreferenceKey,
206         @"1",                           WebKitMinimumFontSizePreferenceKey,
207         @"9",                           WebKitMinimumLogicalFontSizePreferenceKey, 
208         @"16",                          WebKitDefaultFontSizePreferenceKey,
209         @"13",                          WebKitDefaultFixedFontSizePreferenceKey,
210         @"ISO-8859-1",                  WebKitDefaultTextEncodingNamePreferenceKey,
211         @"4",                           WebKitPageCacheSizePreferenceKey,
212         @"8388608",                     WebKitObjectCacheSizePreferenceKey,
213         [NSNumber numberWithBool:NO],   WebKitUserStyleSheetEnabledPreferenceKey,
214         @"",                            WebKitUserStyleSheetLocationPreferenceKey,
215         [NSNumber numberWithBool:NO],   WebKitShouldPrintBackgroundsPreferenceKey,
216         [NSNumber numberWithBool:NO],   WebKitTextAreasAreResizablePreferenceKey,
217         [NSNumber numberWithBool:YES],  WebKitJavaEnabledPreferenceKey,
218         [NSNumber numberWithBool:YES],  WebKitJavaScriptEnabledPreferenceKey,
219         [NSNumber numberWithBool:YES],  WebKitJavaScriptCanOpenWindowsAutomaticallyPreferenceKey,
220         [NSNumber numberWithBool:YES],  WebKitPluginsEnabledPreferenceKey,
221         [NSNumber numberWithBool:YES],  WebKitAllowAnimatedImagesPreferenceKey,
222         [NSNumber numberWithBool:YES],  WebKitAllowAnimatedImageLoopingPreferenceKey,
223         [NSNumber numberWithBool:YES],  WebKitDisplayImagesKey,
224         @"1800",                        WebKitBackForwardCacheExpirationIntervalKey,
225         [NSNumber numberWithBool:NO],   WebKitTabToLinksPreferenceKey,
226         [NSNumber numberWithBool:NO],   WebKitPrivateBrowsingEnabledPreferenceKey,
227         [NSNumber numberWithBool:NO],   WebKitRespectStandardStyleKeyEquivalentsPreferenceKey,
228         [NSNumber numberWithBool:NO],   WebKitShowsURLsInToolTipsPreferenceKey,
229         nil];
230
231     [[NSUserDefaults standardUserDefaults] registerDefaults:dict];
232 }
233
234 - (void)dealloc
235 {
236     [_private release];
237     [super dealloc];
238 }
239
240 - (NSString *)identifier
241 {
242     return _private->identifier;
243 }
244
245 - (id)_valueForKey:(NSString *)key
246 {
247     NSString *_key = KEY(key);
248     id o = [_private->values objectForKey:_key];
249     if (o)
250         return o;
251     o = [[NSUserDefaults standardUserDefaults] objectForKey:_key];
252     if (!o && key != _key)
253         o = [[NSUserDefaults standardUserDefaults] objectForKey:key];
254     return o;
255 }
256
257 - (NSString *)_stringValueForKey:(NSString *)key
258 {
259     id s = [self _valueForKey:key];
260     return [s isKindOfClass:[NSString class]] ? (NSString *)s : nil;
261 }
262
263 - (void)_setStringValue:(NSString *)value forKey:(NSString *)key
264 {
265     if ([[self _stringValueForKey:key] isEqualToString:value])
266         return;
267     NSString *_key = KEY(key);
268     [_private->values setObject:value forKey:_key];
269     if (_private->autosaves)
270         [[NSUserDefaults standardUserDefaults] setObject:value forKey:_key];
271     [self _postPreferencesChangesNotification];
272 }
273
274 - (int)_integerValueForKey:(NSString *)key
275 {
276     id o = [self _valueForKey:key];
277     // 
278     return [o respondsToSelector:@selector(intValue)] ? [o intValue] : 0;
279 }
280
281 - (void)_setIntegerValue:(int)value forKey:(NSString *)key
282 {
283     if ([self _integerValueForKey:key] == value)
284         return;
285     NSString *_key = KEY(key);
286     [_private->values _webkit_setInt:value forKey:_key];
287     if (_private->autosaves)
288         [[NSUserDefaults standardUserDefaults] setInteger:value forKey:_key];
289     [self _postPreferencesChangesNotification];
290 }
291
292 - (BOOL)_boolValueForKey:(NSString *)key
293 {
294     return [self _integerValueForKey:key] != 0;
295 }
296
297 - (void)_setBoolValue:(BOOL)value forKey:(NSString *)key
298 {
299     if ([self _boolValueForKey:key] == value)
300         return;
301     NSString *_key = KEY(key);
302     [_private->values _webkit_setBool:value forKey:_key];
303     if (_private->autosaves)
304         [[NSUserDefaults standardUserDefaults] setBool:value forKey:_key];
305     [self _postPreferencesChangesNotification];
306 }
307
308 - (NSString *)standardFontFamily
309 {
310     return [self _stringValueForKey: WebKitStandardFontPreferenceKey];
311 }
312
313 - (void)setStandardFontFamily:(NSString *)family
314 {
315     [self _setStringValue: family forKey: WebKitStandardFontPreferenceKey];
316 }
317
318 - (NSString *)fixedFontFamily
319 {
320     return [self _stringValueForKey: WebKitFixedFontPreferenceKey];
321 }
322
323 - (void)setFixedFontFamily:(NSString *)family
324 {
325     [self _setStringValue: family forKey: WebKitFixedFontPreferenceKey];
326 }
327
328 - (NSString *)serifFontFamily
329 {
330     return [self _stringValueForKey: WebKitSerifFontPreferenceKey];
331 }
332
333 - (void)setSerifFontFamily:(NSString *)family 
334 {
335     [self _setStringValue: family forKey: WebKitSerifFontPreferenceKey];
336 }
337
338 - (NSString *)sansSerifFontFamily
339 {
340     return [self _stringValueForKey: WebKitSansSerifFontPreferenceKey];
341 }
342
343 - (void)setSansSerifFontFamily:(NSString *)family
344 {
345     [self _setStringValue: family forKey: WebKitSansSerifFontPreferenceKey];
346 }
347
348 - (NSString *)cursiveFontFamily
349 {
350     return [self _stringValueForKey: WebKitCursiveFontPreferenceKey];
351 }
352
353 - (void)setCursiveFontFamily:(NSString *)family
354 {
355     [self _setStringValue: family forKey: WebKitCursiveFontPreferenceKey];
356 }
357
358 - (NSString *)fantasyFontFamily
359 {
360     return [self _stringValueForKey: WebKitFantasyFontPreferenceKey];
361 }
362
363 - (void)setFantasyFontFamily:(NSString *)family
364 {
365     [self _setStringValue: family forKey: WebKitFantasyFontPreferenceKey];
366 }
367
368 - (int)defaultFontSize
369 {
370     return [self _integerValueForKey: WebKitDefaultFontSizePreferenceKey];
371 }
372
373 - (void)setDefaultFontSize:(int)size
374 {
375     [self _setIntegerValue: size forKey: WebKitDefaultFontSizePreferenceKey];
376 }
377
378 - (int)defaultFixedFontSize
379 {
380     return [self _integerValueForKey: WebKitDefaultFixedFontSizePreferenceKey];
381 }
382
383 - (void)setDefaultFixedFontSize:(int)size
384 {
385     [self _setIntegerValue: size forKey: WebKitDefaultFixedFontSizePreferenceKey];
386 }
387
388 - (int)minimumFontSize
389 {
390     return [self _integerValueForKey: WebKitMinimumFontSizePreferenceKey];
391 }
392
393 - (void)setMinimumFontSize:(int)size
394 {
395     [self _setIntegerValue: size forKey: WebKitMinimumFontSizePreferenceKey];
396 }
397
398 - (int)minimumLogicalFontSize
399 {
400   return [self _integerValueForKey: WebKitMinimumLogicalFontSizePreferenceKey];
401 }
402
403 - (void)setMinimumLogicalFontSize:(int)size
404 {
405   [self _setIntegerValue: size forKey: WebKitMinimumLogicalFontSizePreferenceKey];
406 }
407
408 - (NSString *)defaultTextEncodingName
409 {
410     return [self _stringValueForKey: WebKitDefaultTextEncodingNamePreferenceKey];
411 }
412
413 - (void)setDefaultTextEncodingName:(NSString *)encoding
414 {
415     [self _setStringValue: encoding forKey: WebKitDefaultTextEncodingNamePreferenceKey];
416 }
417
418 - (BOOL)userStyleSheetEnabled
419 {
420     return [self _boolValueForKey: WebKitUserStyleSheetEnabledPreferenceKey];
421 }
422
423 - (void)setUserStyleSheetEnabled:(BOOL)flag
424 {
425     [self _setBoolValue: flag forKey: WebKitUserStyleSheetEnabledPreferenceKey];
426 }
427
428 - (NSURL *)userStyleSheetLocation
429 {
430     NSString *locationString = [self _stringValueForKey: WebKitUserStyleSheetLocationPreferenceKey];
431     
432     if ([locationString _webkit_looksLikeAbsoluteURL]) {
433         return [NSURL _web_URLWithDataAsString:locationString];
434     } else {
435         locationString = [locationString stringByExpandingTildeInPath];
436         return [NSURL fileURLWithPath:locationString];
437     }
438 }
439
440 - (void)setUserStyleSheetLocation:(NSURL *)URL
441 {
442     NSString *locationString;
443     
444     if ([URL isFileURL]) {
445         locationString = [[URL path] _web_stringByAbbreviatingWithTildeInPath];
446     } else {
447         locationString = [URL _web_originalDataAsString];
448     }
449     
450     [self _setStringValue:locationString forKey: WebKitUserStyleSheetLocationPreferenceKey];
451 }
452
453 - (BOOL)shouldPrintBackgrounds
454 {
455     return [self _boolValueForKey: WebKitShouldPrintBackgroundsPreferenceKey];
456 }
457
458 - (void)setShouldPrintBackgrounds:(BOOL)flag
459 {
460     [self _setBoolValue: flag forKey: WebKitShouldPrintBackgroundsPreferenceKey];
461 }
462
463 - (BOOL)isJavaEnabled
464 {
465     return [self _boolValueForKey: WebKitJavaEnabledPreferenceKey];
466 }
467
468 - (void)setJavaEnabled:(BOOL)flag
469 {
470     [self _setBoolValue: flag forKey: WebKitJavaEnabledPreferenceKey];
471 }
472
473 - (BOOL)isJavaScriptEnabled
474 {
475     return [self _boolValueForKey: WebKitJavaScriptEnabledPreferenceKey];
476 }
477
478 - (void)setJavaScriptEnabled:(BOOL)flag
479 {
480     [self _setBoolValue: flag forKey: WebKitJavaScriptEnabledPreferenceKey];
481 }
482
483 - (BOOL)javaScriptCanOpenWindowsAutomatically
484 {
485     return [self _boolValueForKey: WebKitJavaScriptCanOpenWindowsAutomaticallyPreferenceKey];
486 }
487
488 - (void)setJavaScriptCanOpenWindowsAutomatically:(BOOL)flag
489 {
490     [self _setBoolValue: flag forKey: WebKitJavaScriptCanOpenWindowsAutomaticallyPreferenceKey];
491 }
492
493 - (BOOL)arePlugInsEnabled
494 {
495     return [self _boolValueForKey: WebKitPluginsEnabledPreferenceKey];
496 }
497
498 - (void)setPlugInsEnabled:(BOOL)flag
499 {
500     [self _setBoolValue: flag forKey: WebKitPluginsEnabledPreferenceKey];
501 }
502
503 - (BOOL)allowsAnimatedImages
504 {
505     return [self _boolValueForKey: WebKitAllowAnimatedImagesPreferenceKey];
506 }
507
508 - (void)setAllowsAnimatedImages:(BOOL)flag;
509 {
510     [self _setBoolValue: flag forKey: WebKitAllowAnimatedImagesPreferenceKey];
511 }
512
513 - (BOOL)allowsAnimatedImageLooping
514 {
515     return [self _boolValueForKey: WebKitAllowAnimatedImageLoopingPreferenceKey];
516 }
517
518 - (void)setAllowsAnimatedImageLooping: (BOOL)flag
519 {
520     [self _setBoolValue: flag forKey: WebKitAllowAnimatedImageLoopingPreferenceKey];
521 }
522
523 - (void)setLoadsImagesAutomatically: (BOOL)flag
524 {
525     [self _setBoolValue: flag forKey: WebKitDisplayImagesKey];
526 }
527
528 - (BOOL)loadsImagesAutomatically
529 {
530     return [self _boolValueForKey: WebKitDisplayImagesKey];
531 }
532
533 - (void)setAutosaves:(BOOL)flag;
534 {
535     _private->autosaves = flag;
536 }
537
538 - (BOOL)autosaves
539 {
540     return _private->autosaves;
541 }
542
543 - (void)setTabsToLinks:(BOOL)flag
544 {
545     [self _setBoolValue: flag forKey: WebKitTabToLinksPreferenceKey];
546 }
547
548 - (BOOL)tabsToLinks
549 {
550     return [self _boolValueForKey:WebKitTabToLinksPreferenceKey];
551 }
552
553 - (void)setPrivateBrowsingEnabled:(BOOL)flag
554 {
555     [self _setBoolValue:flag forKey:WebKitPrivateBrowsingEnabledPreferenceKey];
556 }
557
558 - (BOOL)privateBrowsingEnabled
559 {
560     return [self _boolValueForKey:WebKitPrivateBrowsingEnabledPreferenceKey];
561 }
562
563 @end
564
565 @implementation WebPreferences (WebPrivate)
566
567 - (BOOL)respectStandardStyleKeyEquivalents
568 {
569     return [self _boolValueForKey:WebKitRespectStandardStyleKeyEquivalentsPreferenceKey];
570 }
571
572 - (void)setRespectStandardStyleKeyEquivalents:(BOOL)flag
573 {
574     [self _setBoolValue:flag forKey:WebKitRespectStandardStyleKeyEquivalentsPreferenceKey];
575 }
576
577 - (BOOL)showsURLsInToolTips
578 {
579     return [self _boolValueForKey:WebKitShowsURLsInToolTipsPreferenceKey];
580 }
581
582 - (void)setShowsURLsInToolTips:(BOOL)flag
583 {
584     [self _setBoolValue:flag forKey:WebKitShowsURLsInToolTipsPreferenceKey];
585 }
586
587 - (BOOL)textAreasAreResizable
588 {
589     return [self _boolValueForKey: WebKitTextAreasAreResizablePreferenceKey];
590 }
591
592 - (void)setTextAreasAreResizable:(BOOL)flag
593 {
594     [self _setBoolValue: flag forKey: WebKitTextAreasAreResizablePreferenceKey];
595 }
596
597 - (int)_pageCacheSize
598 {
599     return [[NSUserDefaults standardUserDefaults] integerForKey:WebKitPageCacheSizePreferenceKey];
600 }
601
602 - (int)_objectCacheSize
603 {
604     return [[NSUserDefaults standardUserDefaults] integerForKey:WebKitObjectCacheSizePreferenceKey];
605 }
606
607 - (NSTimeInterval)_backForwardCacheExpirationInterval
608 {
609     return (NSTimeInterval)[[NSUserDefaults standardUserDefaults] floatForKey:WebKitBackForwardCacheExpirationIntervalKey];
610 }
611
612 static NSMutableDictionary *webPreferencesInstances = nil;
613
614 + (WebPreferences *)_getInstanceForIdentifier:(NSString *)ident
615 {
616         LOG (Encoding, "requesting for %@\n", ident);
617
618     if (!ident){
619         if(_standardPreferences)
620             return _standardPreferences;
621         return nil;
622     }    
623     
624     WebPreferences *instance = [webPreferencesInstances objectForKey:[self _concatenateKeyWithIBCreatorID:ident]];
625
626     return instance;
627 }
628
629 + (void)_setInstance:(WebPreferences *)instance forIdentifier:(NSString *)ident
630 {
631     if (!webPreferencesInstances)
632         webPreferencesInstances = [[NSMutableDictionary alloc] init];
633     if (ident) {
634         [webPreferencesInstances setObject:instance forKey:[self _concatenateKeyWithIBCreatorID:ident]];
635         LOG (Encoding, "recording %p for %@\n", instance, [self _concatenateKeyWithIBCreatorID:ident]);
636     }
637 }
638
639 + (void)_removeReferenceForIdentifier:(NSString *)ident
640 {
641     if (ident != nil) {
642         [webPreferencesInstances performSelector:@selector(_web_checkLastReferenceForIdentifier:) withObject: [self _concatenateKeyWithIBCreatorID:ident] afterDelay:.1];
643     }
644 }
645
646 - (void)_postPreferencesChangesNotification
647 {
648     [[NSNotificationCenter defaultCenter]
649         postNotificationName:WebPreferencesChangedNotification object:self
650                     userInfo:nil];
651 }
652
653 + (CFStringEncoding)_systemCFStringEncoding
654 {
655 #if OMIT_TIGER_FEATURES
656     CFStringEncoding encoding = CFStringGetSystemEncoding();
657
658     // Map from system encodings to the appropriate default web encoding.
659     // Web pages that are not labeled will be decoded assuming this encoding,
660     // so it's important that this be the most likely encoding to encounter
661     // on a web page. MacArabic, MacHebrew, and MacRoman are not common on
662     // the web, so instead we map to the most common similar encoding actually used.
663     switch (encoding) {
664         case kCFStringEncodingMacArabic:
665             encoding = kCFStringEncodingDOSArabic;
666             break;
667         case kCFStringEncodingMacHebrew:
668             encoding = kCFStringEncodingDOSHebrew;
669             break;
670         case kCFStringEncodingMacRoman:
671             encoding = kCFStringEncodingISOLatin1;
672             break;
673     }
674
675     // We must not use any encoding that has no IANA character set name.
676     if (CFStringConvertEncodingToIANACharSetName(encoding) == NULL)
677         return kCFStringEncodingISOLatin1;
678 #else
679     UInt32 script = 0;
680     UInt32 region = 0;
681     TextEncoding encoding;
682     OSErr err;
683     ItemCount dontcare;
684
685     // We can't use the Script Manager as it will not return things that use
686     // a script that is not supported on Mac OS X.
687     __CFStringGetUserDefaultEncoding(&script, &region);
688     err = TECGetWebTextEncodings(region, &encoding, 1, &dontcare);
689     if (err != noErr)
690         encoding = kCFStringEncodingISOLatin1;
691 #endif
692
693     return encoding;
694 }
695
696 + (void)_setInitialDefaultTextEncodingToSystemEncoding
697 {
698     [[NSUserDefaults standardUserDefaults] registerDefaults:
699         [NSDictionary dictionaryWithObject:(NSString *)CFStringConvertEncodingToIANACharSetName([self _systemCFStringEncoding])
700                                     forKey:WebKitDefaultTextEncodingNamePreferenceKey]];
701 }
702
703 static NSString *classIBCreatorID = nil;
704
705 + (void)_setIBCreatorID:(NSString *)string
706 {
707     NSString *old = classIBCreatorID;
708     classIBCreatorID = [string copy];
709     [old release];
710 }
711
712 @end
713
714 @implementation WebPreferences (WebInternal)
715
716 + (NSString *)_IBCreatorID
717 {
718     return classIBCreatorID;
719 }
720
721 + (NSString *)_concatenateKeyWithIBCreatorID:(NSString *)key
722 {
723     NSString *IBCreatorID = [WebPreferences _IBCreatorID];
724     if (!IBCreatorID)
725         return key;
726     return [IBCreatorID stringByAppendingString:key];
727 }
728
729 @end
730
731 @implementation NSMutableDictionary (WebInternal)
732
733 - (void)_web_checkLastReferenceForIdentifier:(NSString *)identifier
734 {
735     WebPreferences *instance = [webPreferencesInstances objectForKey:identifier];
736     if ([instance retainCount] == 1)
737         [webPreferencesInstances removeObjectForKey:identifier];
738 }
739
740 @end