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