~ubuntu-branches/ubuntu/raring/qtwebkit-source/raring-proposed

« back to all changes in this revision

Viewing changes to Source/WebKit/mac/History/WebHistoryItem.mm

  • Committer: Package Import Robot
  • Author(s): Jonathan Riddell
  • Date: 2013-02-18 14:24:18 UTC
  • Revision ID: package-import@ubuntu.com-20130218142418-eon0jmjg3nj438uy
Tags: upstream-2.3
ImportĀ upstreamĀ versionĀ 2.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2005, 2007, 2008 Apple 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 "WebHistoryItemInternal.h"
 
30
#import "WebHistoryItemPrivate.h"
 
31
 
 
32
#import "WebFrameInternal.h"
 
33
#import "WebFrameView.h"
 
34
#import "WebHTMLViewInternal.h"
 
35
#import "WebIconDatabase.h"
 
36
#import "WebKitLogging.h"
 
37
#import "WebKitNSStringExtras.h"
 
38
#import "WebNSArrayExtras.h"
 
39
#import "WebNSDictionaryExtras.h"
 
40
#import "WebNSObjectExtras.h"
 
41
#import "WebNSURLExtras.h"
 
42
#import "WebNSURLRequestExtras.h"
 
43
#import "WebNSViewExtras.h"
 
44
#import "WebPluginController.h"
 
45
#import "WebTypesInternal.h"
 
46
#import <WebCore/HistoryItem.h>
 
47
#import <WebCore/Image.h>
 
48
#import <WebCore/KURL.h>
 
49
#import <WebCore/PageCache.h>
 
50
#import <WebCore/RunLoop.h>
 
51
#import <WebCore/ThreadCheck.h>
 
52
#import <WebCore/WebCoreObjCExtras.h>
 
53
#import <runtime/InitializeThreading.h>
 
54
#import <wtf/Assertions.h>
 
55
#import <wtf/MainThread.h>
 
56
#import <wtf/StdLibExtras.h>
 
57
#import <wtf/text/WTFString.h>
 
58
 
 
59
// Private keys used in the WebHistoryItem's dictionary representation.
 
60
// see 3245793 for explanation of "lastVisitedDate"
 
61
static NSString *lastVisitedTimeIntervalKey = @"lastVisitedDate";
 
62
static NSString *visitCountKey = @"visitCount";
 
63
static NSString *titleKey = @"title";
 
64
static NSString *childrenKey = @"children";
 
65
static NSString *displayTitleKey = @"displayTitle";
 
66
static NSString *lastVisitWasFailureKey = @"lastVisitWasFailure";
 
67
static NSString *lastVisitWasHTTPNonGetKey = @"lastVisitWasHTTPNonGet";
 
68
static NSString *redirectURLsKey = @"redirectURLs";
 
69
static NSString *dailyVisitCountKey = @"D"; // short key to save space
 
70
static NSString *weeklyVisitCountKey = @"W"; // short key to save space
 
71
 
 
72
// Notification strings.
 
73
NSString *WebHistoryItemChangedNotification = @"WebHistoryItemChangedNotification";
 
74
 
 
75
using namespace WebCore;
 
76
using namespace std;
 
77
 
 
78
typedef HashMap<HistoryItem*, WebHistoryItem*> HistoryItemMap;
 
79
 
 
80
static inline WebHistoryItemPrivate* kitPrivate(WebCoreHistoryItem* list) { return (WebHistoryItemPrivate*)list; }
 
81
static inline WebCoreHistoryItem* core(WebHistoryItemPrivate* list) { return (WebCoreHistoryItem*)list; }
 
82
 
 
83
static HistoryItemMap& historyItemWrappers()
 
84
{
 
85
    DEFINE_STATIC_LOCAL(HistoryItemMap, historyItemWrappers, ());
 
86
    return historyItemWrappers;
 
87
}
 
88
 
 
89
void WKNotifyHistoryItemChanged(HistoryItem*)
 
90
{
 
91
    [[NSNotificationCenter defaultCenter]
 
92
        postNotificationName:WebHistoryItemChangedNotification object:nil userInfo:nil];
 
93
}
 
94
 
 
95
@implementation WebHistoryItem
 
96
 
 
97
+ (void)initialize
 
98
{
 
99
    JSC::initializeThreading();
 
100
    WTF::initializeMainThreadToProcessMainThread();
 
101
    WebCore::RunLoop::initializeMainRunLoop();
 
102
    WebCoreObjCFinalizeOnMainThread(self);
 
103
}
 
104
 
 
105
- (id)init
 
106
{
 
107
    return [self initWithWebCoreHistoryItem:HistoryItem::create()];
 
108
}
 
109
 
 
110
- (id)initWithURLString:(NSString *)URLString title:(NSString *)title lastVisitedTimeInterval:(NSTimeInterval)time
 
111
{
 
112
    WebCoreThreadViolationCheckRoundOne();
 
113
    return [self initWithWebCoreHistoryItem:HistoryItem::create(URLString, title, time)];
 
114
}
 
115
 
 
116
- (void)dealloc
 
117
{
 
118
    if (WebCoreObjCScheduleDeallocateOnMainThread([WebHistoryItem class], self))
 
119
        return;
 
120
 
 
121
    if (_private) {
 
122
        HistoryItem* coreItem = core(_private);
 
123
        coreItem->deref();
 
124
        historyItemWrappers().remove(coreItem);
 
125
    }
 
126
    [super dealloc];
 
127
}
 
128
 
 
129
- (void)finalize
 
130
{
 
131
    WebCoreThreadViolationCheckRoundOne();
 
132
    // FIXME: ~HistoryItem is what releases the history item's icon from the icon database
 
133
    // It's probably not good to release icons from the database only when the object is garbage-collected. 
 
134
    // Need to change design so this happens at a predictable time.
 
135
    if (_private) {
 
136
        HistoryItem* coreItem = core(_private);
 
137
        coreItem->deref();
 
138
        historyItemWrappers().remove(coreItem);
 
139
    }
 
140
    [super finalize];
 
141
}
 
142
 
 
143
- (id)copyWithZone:(NSZone *)zone
 
144
{
 
145
    WebCoreThreadViolationCheckRoundOne();
 
146
    WebHistoryItem *copy = [[[self class] alloc] initWithWebCoreHistoryItem:core(_private)->copy()];
 
147
    historyItemWrappers().set(core(copy->_private), copy);
 
148
 
 
149
    return copy;
 
150
}
 
151
 
 
152
// FIXME: Need to decide if this class ever returns URLs and decide on the name of this method
 
153
- (NSString *)URLString
 
154
{
 
155
    ASSERT_MAIN_THREAD();
 
156
    return nsStringNilIfEmpty(core(_private)->urlString());
 
157
}
 
158
 
 
159
// The first URL we loaded to get to where this history item points.  Includes both client
 
160
// and server redirects.
 
161
- (NSString *)originalURLString
 
162
{
 
163
    ASSERT_MAIN_THREAD();
 
164
    return nsStringNilIfEmpty(core(_private)->originalURLString());
 
165
}
 
166
 
 
167
- (NSString *)title
 
168
{
 
169
    ASSERT_MAIN_THREAD();
 
170
    return nsStringNilIfEmpty(core(_private)->title());
 
171
}
 
172
 
 
173
- (void)setAlternateTitle:(NSString *)alternateTitle
 
174
{
 
175
    core(_private)->setAlternateTitle(alternateTitle);
 
176
}
 
177
 
 
178
- (NSString *)alternateTitle
 
179
{
 
180
    return nsStringNilIfEmpty(core(_private)->alternateTitle());
 
181
}
 
182
 
 
183
- (NSImage *)icon
 
184
{
 
185
    return [[WebIconDatabase sharedIconDatabase] iconForURL:[self URLString] withSize:WebIconSmallSize];
 
186
}
 
187
 
 
188
- (NSTimeInterval)lastVisitedTimeInterval
 
189
{
 
190
    ASSERT_MAIN_THREAD();
 
191
    return core(_private)->lastVisitedTime();
 
192
}
 
193
 
 
194
- (NSUInteger)hash
 
195
{
 
196
    return [(NSString*)core(_private)->urlString() hash];
 
197
}
 
198
 
 
199
- (BOOL)isEqual:(id)anObject
 
200
{
 
201
    ASSERT_MAIN_THREAD();
 
202
    if (![anObject isMemberOfClass:[WebHistoryItem class]]) {
 
203
        return NO;
 
204
    }
 
205
    
 
206
    return core(_private)->urlString() == core(((WebHistoryItem*)anObject)->_private)->urlString();
 
207
}
 
208
 
 
209
- (NSString *)description
 
210
{
 
211
    ASSERT_MAIN_THREAD();
 
212
    HistoryItem* coreItem = core(_private);
 
213
    NSMutableString *result = [NSMutableString stringWithFormat:@"%@ %@", [super description], (NSString*)coreItem->urlString()];
 
214
    if (!coreItem->target().isEmpty()) {
 
215
        NSString *target = coreItem->target();
 
216
        [result appendFormat:@" in \"%@\"", target];
 
217
    }
 
218
    if (coreItem->isTargetItem()) {
 
219
        [result appendString:@" *target*"];
 
220
    }
 
221
    if (coreItem->formData()) {
 
222
        [result appendString:@" *POST*"];
 
223
    }
 
224
    
 
225
    if (coreItem->children().size()) {
 
226
        const HistoryItemVector& children = coreItem->children();
 
227
        int currPos = [result length];
 
228
        unsigned size = children.size();        
 
229
        for (unsigned i = 0; i < size; ++i) {
 
230
            WebHistoryItem *child = kit(children[i].get());
 
231
            [result appendString:@"\n"];
 
232
            [result appendString:[child description]];
 
233
        }
 
234
        // shift all the contents over.  A bit slow, but hey, this is for debugging.
 
235
        NSRange replRange = { static_cast<NSUInteger>(currPos), [result length] - currPos };
 
236
        [result replaceOccurrencesOfString:@"\n" withString:@"\n    " options:0 range:replRange];
 
237
    }
 
238
    
 
239
    return result;
 
240
}
 
241
 
 
242
@end
 
243
 
 
244
@interface WebWindowWatcher : NSObject
 
245
@end
 
246
 
 
247
 
 
248
@implementation WebHistoryItem (WebInternal)
 
249
 
 
250
HistoryItem* core(WebHistoryItem *item)
 
251
{
 
252
    if (!item)
 
253
        return 0;
 
254
    
 
255
    ASSERT(historyItemWrappers().get(core(item->_private)) == item);
 
256
 
 
257
    return core(item->_private);
 
258
}
 
259
 
 
260
WebHistoryItem *kit(HistoryItem* item)
 
261
{
 
262
    if (!item)
 
263
        return nil;
 
264
        
 
265
    WebHistoryItem *kitItem = historyItemWrappers().get(item);
 
266
    if (kitItem)
 
267
        return kitItem;
 
268
    
 
269
    return [[[WebHistoryItem alloc] initWithWebCoreHistoryItem:item] autorelease];
 
270
}
 
271
 
 
272
+ (WebHistoryItem *)entryWithURL:(NSURL *)URL
 
273
{
 
274
    return [[[self alloc] initWithURL:URL title:nil] autorelease];
 
275
}
 
276
 
 
277
static WebWindowWatcher *_windowWatcher = nil;
 
278
 
 
279
+ (void)initWindowWatcherIfNecessary
 
280
{
 
281
    if (_windowWatcher)
 
282
        return;
 
283
    _windowWatcher = [[WebWindowWatcher alloc] init];
 
284
    [[NSNotificationCenter defaultCenter] addObserver:_windowWatcher selector:@selector(windowWillClose:)
 
285
        name:NSWindowWillCloseNotification object:nil];
 
286
}
 
287
 
 
288
- (id)initWithURL:(NSURL *)URL target:(NSString *)target parent:(NSString *)parent title:(NSString *)title
 
289
{
 
290
    return [self initWithWebCoreHistoryItem:HistoryItem::create(URL, target, parent, title)];
 
291
}
 
292
 
 
293
- (id)initWithURLString:(NSString *)URLString title:(NSString *)title displayTitle:(NSString *)displayTitle lastVisitedTimeInterval:(NSTimeInterval)time
 
294
{
 
295
    return [self initWithWebCoreHistoryItem:HistoryItem::create(URLString, title, displayTitle, time)];
 
296
}
 
297
 
 
298
- (id)initWithWebCoreHistoryItem:(PassRefPtr<HistoryItem>)item
 
299
{   
 
300
    WebCoreThreadViolationCheckRoundOne();
 
301
    // Need to tell WebCore what function to call for the 
 
302
    // "History Item has Changed" notification - no harm in doing this
 
303
    // everytime a WebHistoryItem is created
 
304
    // Note: We also do this in [WebFrameView initWithFrame:] where we do
 
305
    // other "init before WebKit is used" type things
 
306
    WebCore::notifyHistoryItemChanged = WKNotifyHistoryItemChanged;
 
307
    
 
308
    self = [super init];
 
309
    
 
310
    _private = kitPrivate(item.leakRef());
 
311
    ASSERT(!historyItemWrappers().get(core(_private)));
 
312
    historyItemWrappers().set(core(_private), self);
 
313
    return self;
 
314
}
 
315
 
 
316
- (void)setTitle:(NSString *)title
 
317
{
 
318
    core(_private)->setTitle(title);
 
319
}
 
320
 
 
321
- (void)setVisitCount:(int)count
 
322
{
 
323
    core(_private)->setVisitCount(count);
 
324
}
 
325
 
 
326
- (void)setViewState:(id)statePList
 
327
{
 
328
    core(_private)->setViewState(statePList);
 
329
}
 
330
 
 
331
- (void)_mergeAutoCompleteHints:(WebHistoryItem *)otherItem
 
332
{
 
333
    ASSERT_ARG(otherItem, otherItem);
 
334
    core(_private)->mergeAutoCompleteHints(core(otherItem->_private));
 
335
}
 
336
 
 
337
- (id)initFromDictionaryRepresentation:(NSDictionary *)dict
 
338
{
 
339
    ASSERT_MAIN_THREAD();
 
340
    NSString *URLString = [dict _webkit_stringForKey:@""];
 
341
    NSString *title = [dict _webkit_stringForKey:titleKey];
 
342
 
 
343
    // Do an existence check to avoid calling doubleValue on a nil string. Leave
 
344
    // time interval at 0 if there's no value in dict.
 
345
    NSString *timeIntervalString = [dict _webkit_stringForKey:lastVisitedTimeIntervalKey];
 
346
    NSTimeInterval lastVisited = timeIntervalString == nil ? 0 : [timeIntervalString doubleValue];
 
347
 
 
348
    self = [self initWithURLString:URLString title:title displayTitle:[dict _webkit_stringForKey:displayTitleKey] lastVisitedTimeInterval:lastVisited];
 
349
    
 
350
    // Check if we've read a broken URL from the file that has non-Latin1 chars.  If so, try to convert
 
351
    // as if it was from user typing.
 
352
    if (![URLString canBeConvertedToEncoding:NSISOLatin1StringEncoding]) {
 
353
        NSURL *tempURL = [NSURL _web_URLWithUserTypedString:URLString];
 
354
        ASSERT(tempURL);
 
355
        NSString *newURLString = [tempURL _web_originalDataAsString];
 
356
        core(_private)->setURLString(newURLString);
 
357
        core(_private)->setOriginalURLString(newURLString);
 
358
    } 
 
359
 
 
360
    int visitCount = [dict _webkit_intForKey:visitCountKey];
 
361
    
 
362
    // Can't trust data on disk, and we've had at least one report of this (<rdar://6572300>).
 
363
    if (visitCount < 0) {
 
364
        LOG_ERROR("visit count for history item \"%@\" is negative (%d), will be reset to 1", URLString, visitCount);
 
365
        visitCount = 1;
 
366
    }
 
367
    core(_private)->setVisitCount(visitCount);
 
368
 
 
369
    if ([dict _webkit_boolForKey:lastVisitWasFailureKey])
 
370
        core(_private)->setLastVisitWasFailure(true);
 
371
    
 
372
    BOOL lastVisitWasHTTPNonGet = [dict _webkit_boolForKey:lastVisitWasHTTPNonGetKey];
 
373
    NSString *tempURLString = [URLString lowercaseString];
 
374
    if (lastVisitWasHTTPNonGet && ([tempURLString hasPrefix:@"http:"] || [tempURLString hasPrefix:@"https:"]))
 
375
        core(_private)->setLastVisitWasHTTPNonGet(lastVisitWasHTTPNonGet);
 
376
 
 
377
    if (NSArray *redirectURLs = [dict _webkit_arrayForKey:redirectURLsKey]) {
 
378
        NSUInteger size = [redirectURLs count];
 
379
        OwnPtr<Vector<String> > redirectURLsVector = adoptPtr(new Vector<String>(size));
 
380
        for (NSUInteger i = 0; i < size; ++i)
 
381
            (*redirectURLsVector)[i] = String([redirectURLs _webkit_stringAtIndex:i]);
 
382
        core(_private)->setRedirectURLs(redirectURLsVector.release());
 
383
    }
 
384
 
 
385
    NSArray *dailyCounts = [dict _webkit_arrayForKey:dailyVisitCountKey];
 
386
    NSArray *weeklyCounts = [dict _webkit_arrayForKey:weeklyVisitCountKey];
 
387
    if (dailyCounts || weeklyCounts) {
 
388
        Vector<int> coreDailyCounts([dailyCounts count]);
 
389
        Vector<int> coreWeeklyCounts([weeklyCounts count]);
 
390
 
 
391
        // Daily and weekly counts < 0 are errors in the data read from disk, so reset to 0.
 
392
        for (size_t i = 0; i < coreDailyCounts.size(); ++i)
 
393
            coreDailyCounts[i] = max([[dailyCounts _webkit_numberAtIndex:i] intValue], 0);
 
394
        for (size_t i = 0; i < coreWeeklyCounts.size(); ++i)
 
395
            coreWeeklyCounts[i] = max([[weeklyCounts _webkit_numberAtIndex:i] intValue], 0);
 
396
    
 
397
        core(_private)->adoptVisitCounts(coreDailyCounts, coreWeeklyCounts);
 
398
    }
 
399
 
 
400
    NSArray *childDicts = [dict objectForKey:childrenKey];
 
401
    if (childDicts) {
 
402
        for (int i = [childDicts count] - 1; i >= 0; i--) {
 
403
            WebHistoryItem *child = [[WebHistoryItem alloc] initFromDictionaryRepresentation:[childDicts objectAtIndex:i]];
 
404
            core(_private)->addChildItem(core(child->_private));
 
405
            [child release];
 
406
        }
 
407
    }
 
408
 
 
409
    return self;
 
410
}
 
411
 
 
412
- (NSPoint)scrollPoint
 
413
{
 
414
    ASSERT_MAIN_THREAD();
 
415
    return core(_private)->scrollPoint();
 
416
}
 
417
 
 
418
- (void)_visitedWithTitle:(NSString *)title increaseVisitCount:(BOOL)increaseVisitCount
 
419
{
 
420
    core(_private)->visited(title, [NSDate timeIntervalSinceReferenceDate], increaseVisitCount ? IncreaseVisitCount : DoNotIncreaseVisitCount);
 
421
}
 
422
 
 
423
- (void)_recordInitialVisit
 
424
{
 
425
    core(_private)->recordInitialVisit();
 
426
}
 
427
 
 
428
@end
 
429
 
 
430
@implementation WebHistoryItem (WebPrivate)
 
431
 
 
432
- (id)initWithURL:(NSURL *)URL title:(NSString *)title
 
433
{
 
434
    return [self initWithURLString:[URL _web_originalDataAsString] title:title lastVisitedTimeInterval:0];
 
435
}
 
436
 
 
437
- (NSDictionary *)dictionaryRepresentation
 
438
{
 
439
    ASSERT_MAIN_THREAD();
 
440
    NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithCapacity:8];
 
441
 
 
442
    HistoryItem* coreItem = core(_private);
 
443
    
 
444
    if (!coreItem->urlString().isEmpty())
 
445
        [dict setObject:(NSString*)coreItem->urlString() forKey:@""];
 
446
    if (!coreItem->title().isEmpty())
 
447
        [dict setObject:(NSString*)coreItem->title() forKey:titleKey];
 
448
    if (!coreItem->alternateTitle().isEmpty())
 
449
        [dict setObject:(NSString*)coreItem->alternateTitle() forKey:displayTitleKey];
 
450
    if (coreItem->lastVisitedTime() != 0.0) {
 
451
        // Store as a string to maintain backward compatibility. (See 3245793)
 
452
        [dict setObject:[NSString stringWithFormat:@"%.1lf", coreItem->lastVisitedTime()]
 
453
                 forKey:lastVisitedTimeIntervalKey];
 
454
    }
 
455
    if (coreItem->visitCount())
 
456
        [dict setObject:[NSNumber numberWithInt:coreItem->visitCount()] forKey:visitCountKey];
 
457
    if (coreItem->lastVisitWasFailure())
 
458
        [dict setObject:[NSNumber numberWithBool:YES] forKey:lastVisitWasFailureKey];
 
459
    if (coreItem->lastVisitWasHTTPNonGet()) {
 
460
        ASSERT(coreItem->urlString().startsWith("http:", false) || coreItem->urlString().startsWith("https:", false));
 
461
        [dict setObject:[NSNumber numberWithBool:YES] forKey:lastVisitWasHTTPNonGetKey];
 
462
    }
 
463
    if (Vector<String>* redirectURLs = coreItem->redirectURLs()) {
 
464
        size_t size = redirectURLs->size();
 
465
        ASSERT(size);
 
466
        NSMutableArray *result = [[NSMutableArray alloc] initWithCapacity:size];
 
467
        for (size_t i = 0; i < size; ++i)
 
468
            [result addObject:(NSString*)redirectURLs->at(i)];
 
469
        [dict setObject:result forKey:redirectURLsKey];
 
470
        [result release];
 
471
    }
 
472
    
 
473
    const Vector<int>& dailyVisitCounts = coreItem->dailyVisitCounts();
 
474
    if (dailyVisitCounts.size()) {
 
475
        NSMutableArray *array = [[NSMutableArray alloc] initWithCapacity:13];
 
476
        for (size_t i = 0; i < dailyVisitCounts.size(); ++i)
 
477
            [array addObject:[NSNumber numberWithInt:dailyVisitCounts[i]]];
 
478
        [dict setObject:array forKey:dailyVisitCountKey];
 
479
        [array release];
 
480
    }
 
481
    
 
482
    const Vector<int>& weeklyVisitCounts = coreItem->weeklyVisitCounts();
 
483
    if (weeklyVisitCounts.size()) {
 
484
        NSMutableArray *array = [[NSMutableArray alloc] initWithCapacity:5];
 
485
        for (size_t i = 0; i < weeklyVisitCounts.size(); ++i)
 
486
            [array addObject:[NSNumber numberWithInt:weeklyVisitCounts[i]]];
 
487
        [dict setObject:array forKey:weeklyVisitCountKey];
 
488
        [array release];
 
489
    }    
 
490
    
 
491
    if (coreItem->children().size()) {
 
492
        const HistoryItemVector& children = coreItem->children();
 
493
        NSMutableArray *childDicts = [NSMutableArray arrayWithCapacity:children.size()];
 
494
        
 
495
        for (int i = children.size() - 1; i >= 0; i--)
 
496
            [childDicts addObject:[kit(children[i].get()) dictionaryRepresentation]];
 
497
        [dict setObject: childDicts forKey:childrenKey];
 
498
    }
 
499
 
 
500
    return dict;
 
501
}
 
502
 
 
503
- (NSString *)target
 
504
{
 
505
    ASSERT_MAIN_THREAD();
 
506
    return nsStringNilIfEmpty(core(_private)->target());
 
507
}
 
508
 
 
509
- (BOOL)isTargetItem
 
510
{
 
511
    return core(_private)->isTargetItem();
 
512
}
 
513
 
 
514
- (int)visitCount
 
515
{
 
516
    ASSERT_MAIN_THREAD();
 
517
    return core(_private)->visitCount();
 
518
}
 
519
 
 
520
- (NSString *)RSSFeedReferrer
 
521
{
 
522
    return nsStringNilIfEmpty(core(_private)->referrer());
 
523
}
 
524
 
 
525
- (void)setRSSFeedReferrer:(NSString *)referrer
 
526
{
 
527
    core(_private)->setReferrer(referrer);
 
528
}
 
529
 
 
530
- (NSArray *)children
 
531
{
 
532
    ASSERT_MAIN_THREAD();
 
533
    const HistoryItemVector& children = core(_private)->children();
 
534
    if (!children.size())
 
535
        return nil;
 
536
 
 
537
    unsigned size = children.size();
 
538
    NSMutableArray *result = [[[NSMutableArray alloc] initWithCapacity:size] autorelease];
 
539
    
 
540
    for (unsigned i = 0; i < size; ++i)
 
541
        [result addObject:kit(children[i].get())];
 
542
    
 
543
    return result;
 
544
}
 
545
 
 
546
- (void)setAlwaysAttemptToUsePageCache:(BOOL)flag
 
547
{
 
548
    // Safari 2.0 uses this for SnapBack, so we stub it out to avoid a crash.
 
549
}
 
550
 
 
551
- (NSURL *)URL
 
552
{
 
553
    ASSERT_MAIN_THREAD();
 
554
    const KURL& url = core(_private)->url();
 
555
    if (url.isEmpty())
 
556
        return nil;
 
557
    return url;
 
558
}
 
559
 
 
560
// This should not be called directly for WebHistoryItems that are already included
 
561
// in WebHistory. Use -[WebHistory setLastVisitedTimeInterval:forItem:] instead.
 
562
- (void)_setLastVisitedTimeInterval:(NSTimeInterval)time
 
563
{
 
564
    core(_private)->setLastVisitedTime(time);
 
565
}
 
566
 
 
567
// FIXME: <rdar://problem/4880065> - Push Global History into WebCore
 
568
// Once that task is complete, this accessor can go away
 
569
- (NSCalendarDate *)_lastVisitedDate
 
570
{
 
571
    ASSERT_MAIN_THREAD();
 
572
    return [[[NSCalendarDate alloc] initWithTimeIntervalSinceReferenceDate:core(_private)->lastVisitedTime()] autorelease];
 
573
}
 
574
 
 
575
- (WebHistoryItem *)targetItem
 
576
{    
 
577
    ASSERT_MAIN_THREAD();
 
578
    return kit(core(_private)->targetItem());
 
579
}
 
580
 
 
581
+ (void)_releaseAllPendingPageCaches
 
582
{
 
583
    pageCache()->releaseAutoreleasedPagesNow();
 
584
}
 
585
 
 
586
- (id)_transientPropertyForKey:(NSString *)key
 
587
{
 
588
    return core(_private)->getTransientProperty(key);
 
589
}
 
590
 
 
591
- (void)_setTransientProperty:(id)property forKey:(NSString *)key
 
592
{
 
593
    core(_private)->setTransientProperty(key, property);
 
594
}
 
595
 
 
596
- (BOOL)lastVisitWasFailure
 
597
{
 
598
    return core(_private)->lastVisitWasFailure();
 
599
}
 
600
 
 
601
- (void)_setLastVisitWasFailure:(BOOL)failure
 
602
{
 
603
    core(_private)->setLastVisitWasFailure(failure);
 
604
}
 
605
 
 
606
- (BOOL)_lastVisitWasHTTPNonGet
 
607
{
 
608
    return core(_private)->lastVisitWasHTTPNonGet();
 
609
}
 
610
 
 
611
- (NSArray *)_redirectURLs
 
612
{
 
613
    Vector<String>* redirectURLs = core(_private)->redirectURLs();
 
614
    if (!redirectURLs)
 
615
        return nil;
 
616
 
 
617
    size_t size = redirectURLs->size();
 
618
    ASSERT(size);
 
619
    NSMutableArray *result = [[NSMutableArray alloc] initWithCapacity:size];
 
620
    for (size_t i = 0; i < size; ++i)
 
621
        [result addObject:(NSString*)redirectURLs->at(i)];
 
622
    return [result autorelease];
 
623
}
 
624
 
 
625
- (size_t)_getDailyVisitCounts:(const int**)counts
 
626
{
 
627
    HistoryItem* coreItem = core(_private);
 
628
    *counts = coreItem->dailyVisitCounts().data();
 
629
    return coreItem->dailyVisitCounts().size();
 
630
}
 
631
 
 
632
- (size_t)_getWeeklyVisitCounts:(const int**)counts
 
633
{
 
634
    HistoryItem* coreItem = core(_private);
 
635
    *counts = coreItem->weeklyVisitCounts().data();
 
636
    return coreItem->weeklyVisitCounts().size();
 
637
}
 
638
 
 
639
@end
 
640
 
 
641
 
 
642
// FIXME: <rdar://problem/4886761>.
 
643
// This is a bizarre policy. We flush the page caches ANY time ANY window is closed?
 
644
 
 
645
@implementation WebWindowWatcher
 
646
 
 
647
- (void)windowWillClose:(NSNotification *)notification
 
648
{
 
649
    if (!pthread_main_np()) {
 
650
        [self performSelectorOnMainThread:_cmd withObject:notification waitUntilDone:NO];
 
651
        return;
 
652
    }
 
653
 
 
654
    pageCache()->releaseAutoreleasedPagesNow();
 
655
}
 
656
 
 
657
@end