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