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 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/URL.h>
49#import <WebCore/PageCache.h>
50#import <WebCore/ThreadCheck.h>
51#import <WebCore/WebCoreObjCExtras.h>
52#import <runtime/InitializeThreading.h>
53#import <wtf/Assertions.h>
54#import <wtf/MainThread.h>
55#import <wtf/RunLoop.h>
56#import <wtf/StdLibExtras.h>
57#import <wtf/text/WTFString.h>
58
59#if PLATFORM(IOS)
60#import <WebCore/WebCoreThreadMessage.h>
61
62NSString *WebViewportInitialScaleKey = @"initial-scale";
63NSString *WebViewportMinimumScaleKey = @"minimum-scale";
64NSString *WebViewportMaximumScaleKey = @"maximum-scale";
65NSString *WebViewportUserScalableKey = @"user-scalable";
66NSString *WebViewportWidthKey        = @"width";
67NSString *WebViewportHeightKey       = @"height";
68NSString *WebViewportMinimalUIKey    = @"minimal-ui";
69
70static NSString *scaleKey = @"scale";
71static NSString *scaleIsInitialKey = @"scaleIsInitial";
72static NSString *scrollPointXKey = @"scrollPointX";
73static NSString *scrollPointYKey = @"scrollPointY";
74
75static NSString * const bookmarkIDKey = @"bookmarkID";
76static NSString * const sharedLinkUniqueIdentifierKey = @"sharedLinkUniqueIdentifier";
77#endif
78
79// Private keys used in the WebHistoryItem's dictionary representation.
80// see 3245793 for explanation of "lastVisitedDate"
81static NSString *lastVisitedTimeIntervalKey = @"lastVisitedDate";
82static NSString *titleKey = @"title";
83static NSString *childrenKey = @"children";
84static NSString *displayTitleKey = @"displayTitle";
85static NSString *lastVisitWasFailureKey = @"lastVisitWasFailure";
86static NSString *redirectURLsKey = @"redirectURLs";
87
88// Notification strings.
89NSString *WebHistoryItemChangedNotification = @"WebHistoryItemChangedNotification";
90
91using namespace WebCore;
92
93@implementation WebHistoryItemPrivate
94
95@end
96
97typedef HashMap<HistoryItem*, WebHistoryItem*> HistoryItemMap;
98
99static inline WebCoreHistoryItem* core(WebHistoryItemPrivate* itemPrivate)
100{
101    return itemPrivate->_historyItem.get();
102}
103
104static HistoryItemMap& historyItemWrappers()
105{
106    DEPRECATED_DEFINE_STATIC_LOCAL(HistoryItemMap, historyItemWrappers, ());
107    return historyItemWrappers;
108}
109
110void WKNotifyHistoryItemChanged(HistoryItem*)
111{
112#if !PLATFORM(IOS)
113    [[NSNotificationCenter defaultCenter]
114        postNotificationName:WebHistoryItemChangedNotification object:nil userInfo:nil];
115#else
116    WebThreadPostNotification(WebHistoryItemChangedNotification, nil, nil);
117#endif
118}
119
120@implementation WebHistoryItem
121
122+ (void)initialize
123{
124#if !PLATFORM(IOS)
125    JSC::initializeThreading();
126    WTF::initializeMainThreadToProcessMainThread();
127    RunLoop::initializeMainRunLoop();
128#endif
129    WebCoreObjCFinalizeOnMainThread(self);
130}
131
132- (instancetype)init
133{
134    return [self initWithWebCoreHistoryItem:HistoryItem::create()];
135}
136
137- (instancetype)initWithURLString:(NSString *)URLString title:(NSString *)title lastVisitedTimeInterval:(NSTimeInterval)time
138{
139    WebCoreThreadViolationCheckRoundOne();
140
141    WebHistoryItem *item = [self initWithWebCoreHistoryItem:HistoryItem::create(URLString, title)];
142    item->_private->_lastVisitedTime = time;
143
144    return item;
145}
146
147- (void)dealloc
148{
149    if (WebCoreObjCScheduleDeallocateOnMainThread([WebHistoryItem class], self))
150        return;
151
152    historyItemWrappers().remove(_private->_historyItem.get());
153    [_private release];
154
155    [super dealloc];
156}
157
158- (void)finalize
159{
160    WebCoreThreadViolationCheckRoundOne();
161
162    // FIXME: ~HistoryItem is what releases the history item's icon from the icon database
163    // It's probably not good to release icons from the database only when the object is garbage-collected.
164    // Need to change design so this happens at a predictable time.
165    historyItemWrappers().remove(_private->_historyItem.get());
166
167    [super finalize];
168}
169
170- (id)copyWithZone:(NSZone *)zone
171{
172    WebCoreThreadViolationCheckRoundOne();
173    WebHistoryItem *copy = [[[self class] alloc] initWithWebCoreHistoryItem:core(_private)->copy()];
174
175    copy->_private->_lastVisitedTime = _private->_lastVisitedTime;
176
177    historyItemWrappers().set(core(copy->_private), copy);
178
179    return copy;
180}
181
182// FIXME: Need to decide if this class ever returns URLs and decide on the name of this method
183- (NSString *)URLString
184{
185    ASSERT_MAIN_THREAD();
186    return nsStringNilIfEmpty(core(_private)->urlString());
187}
188
189// The first URL we loaded to get to where this history item points.  Includes both client
190// and server redirects.
191- (NSString *)originalURLString
192{
193    ASSERT_MAIN_THREAD();
194    return nsStringNilIfEmpty(core(_private)->originalURLString());
195}
196
197- (NSString *)title
198{
199    ASSERT_MAIN_THREAD();
200    return nsStringNilIfEmpty(core(_private)->title());
201}
202
203- (void)setAlternateTitle:(NSString *)alternateTitle
204{
205    core(_private)->setAlternateTitle(alternateTitle);
206}
207
208- (NSString *)alternateTitle
209{
210    return nsStringNilIfEmpty(core(_private)->alternateTitle());
211}
212
213#if !PLATFORM(IOS)
214- (NSImage *)icon
215{
216    return [[WebIconDatabase sharedIconDatabase] iconForURL:[self URLString] withSize:WebIconSmallSize];
217}
218#endif
219
220- (NSTimeInterval)lastVisitedTimeInterval
221{
222    ASSERT_MAIN_THREAD();
223    return _private->_lastVisitedTime;
224}
225
226- (NSUInteger)hash
227{
228    return [(NSString*)core(_private)->urlString() hash];
229}
230
231- (BOOL)isEqual:(id)anObject
232{
233    ASSERT_MAIN_THREAD();
234    if (![anObject isMemberOfClass:[WebHistoryItem class]]) {
235        return NO;
236    }
237
238    return core(_private)->urlString() == core(((WebHistoryItem*)anObject)->_private)->urlString();
239}
240
241- (NSString *)description
242{
243    ASSERT_MAIN_THREAD();
244    HistoryItem* coreItem = core(_private);
245    NSMutableString *result = [NSMutableString stringWithFormat:@"%@ %@", [super description], (NSString*)coreItem->urlString()];
246    if (!coreItem->target().isEmpty()) {
247        NSString *target = coreItem->target();
248        [result appendFormat:@" in \"%@\"", target];
249    }
250    if (coreItem->isTargetItem()) {
251        [result appendString:@" *target*"];
252    }
253    if (coreItem->formData()) {
254        [result appendString:@" *POST*"];
255    }
256
257    if (coreItem->children().size()) {
258        const HistoryItemVector& children = coreItem->children();
259        int currPos = [result length];
260        unsigned size = children.size();
261        for (unsigned i = 0; i < size; ++i) {
262            WebHistoryItem *child = kit(children[i].get());
263            [result appendString:@"\n"];
264            [result appendString:[child description]];
265        }
266        // shift all the contents over.  A bit slow, but hey, this is for debugging.
267        NSRange replRange = { static_cast<NSUInteger>(currPos), [result length] - currPos };
268        [result replaceOccurrencesOfString:@"\n" withString:@"\n    " options:0 range:replRange];
269    }
270
271    return result;
272}
273
274HistoryItem* core(WebHistoryItem *item)
275{
276    if (!item)
277        return 0;
278
279    ASSERT(historyItemWrappers().get(core(item->_private)) == item);
280
281    return core(item->_private);
282}
283
284WebHistoryItem *kit(HistoryItem* item)
285{
286    if (!item)
287        return nil;
288
289    WebHistoryItem *kitItem = historyItemWrappers().get(item);
290    if (kitItem)
291        return kitItem;
292
293    return [[[WebHistoryItem alloc] initWithWebCoreHistoryItem:item] autorelease];
294}
295
296+ (WebHistoryItem *)entryWithURL:(NSURL *)URL
297{
298    return [[[self alloc] initWithURL:URL title:nil] autorelease];
299}
300
301- (id)initWithURL:(NSURL *)URL target:(NSString *)target parent:(NSString *)parent title:(NSString *)title
302{
303    return [self initWithWebCoreHistoryItem:HistoryItem::create(URL, target, parent, title)];
304}
305
306- (id)initWithURLString:(NSString *)URLString title:(NSString *)title displayTitle:(NSString *)displayTitle lastVisitedTimeInterval:(NSTimeInterval)time
307{
308    WebHistoryItem *item = [self initWithWebCoreHistoryItem:HistoryItem::create(URLString, title, displayTitle)];
309
310    item->_private->_lastVisitedTime = time;
311
312    return item;
313}
314
315- (id)initWithWebCoreHistoryItem:(PassRefPtr<HistoryItem>)item
316{
317    WebCoreThreadViolationCheckRoundOne();
318    // Need to tell WebCore what function to call for the
319    // "History Item has Changed" notification - no harm in doing this
320    // everytime a WebHistoryItem is created
321    // Note: We also do this in [WebFrameView initWithFrame:] where we do
322    // other "init before WebKit is used" type things
323    WebCore::notifyHistoryItemChanged = WKNotifyHistoryItemChanged;
324
325    if (!(self = [super init]))
326        return nil;
327
328    _private = [[WebHistoryItemPrivate alloc] init];
329    _private->_historyItem = item;
330
331    ASSERT(!historyItemWrappers().get(core(_private)));
332    historyItemWrappers().set(core(_private), self);
333    return self;
334}
335
336- (void)setTitle:(NSString *)title
337{
338    core(_private)->setTitle(title);
339}
340
341- (void)setViewState:(id)statePList
342{
343    core(_private)->setViewState(statePList);
344}
345
346- (id)initFromDictionaryRepresentation:(NSDictionary *)dict
347{
348    ASSERT_MAIN_THREAD();
349    NSString *URLString = [dict _webkit_stringForKey:@""];
350    NSString *title = [dict _webkit_stringForKey:titleKey];
351
352    // Do an existence check to avoid calling doubleValue on a nil string. Leave
353    // time interval at 0 if there's no value in dict.
354    NSString *timeIntervalString = [dict _webkit_stringForKey:lastVisitedTimeIntervalKey];
355    NSTimeInterval lastVisited = timeIntervalString == nil ? 0 : [timeIntervalString doubleValue];
356
357    self = [self initWithURLString:URLString title:title displayTitle:[dict _webkit_stringForKey:displayTitleKey] lastVisitedTimeInterval:lastVisited];
358
359    // Check if we've read a broken URL from the file that has non-Latin1 chars.  If so, try to convert
360    // as if it was from user typing.
361    if (![URLString canBeConvertedToEncoding:NSISOLatin1StringEncoding]) {
362        NSURL *tempURL = [NSURL _web_URLWithUserTypedString:URLString];
363        ASSERT(tempURL);
364        NSString *newURLString = [tempURL _web_originalDataAsString];
365        core(_private)->setURLString(newURLString);
366        core(_private)->setOriginalURLString(newURLString);
367    }
368
369    if ([dict _webkit_boolForKey:lastVisitWasFailureKey])
370        core(_private)->setLastVisitWasFailure(true);
371
372    if (NSArray *redirectURLs = [dict _webkit_arrayForKey:redirectURLsKey]) {
373        NSUInteger size = [redirectURLs count];
374        auto redirectURLsVector = std::make_unique<Vector<String>>(size);
375        for (NSUInteger i = 0; i < size; ++i)
376            (*redirectURLsVector)[i] = String([redirectURLs _webkit_stringAtIndex:i]);
377        core(_private)->setRedirectURLs(WTF::move(redirectURLsVector));
378    }
379
380    NSArray *childDicts = [dict objectForKey:childrenKey];
381    if (childDicts) {
382        for (int i = [childDicts count] - 1; i >= 0; i--) {
383            WebHistoryItem *child = [[WebHistoryItem alloc] initFromDictionaryRepresentation:[childDicts objectAtIndex:i]];
384            core(_private)->addChildItem(core(child->_private));
385            [child release];
386        }
387    }
388
389#if PLATFORM(IOS)
390    NSNumber *scaleValue = [dict objectForKey:scaleKey];
391    NSNumber *scaleIsInitialValue = [dict objectForKey:scaleIsInitialKey];
392    if (scaleValue && scaleIsInitialValue)
393        core(_private)->setScale([scaleValue floatValue], [scaleIsInitialValue boolValue]);
394
395    if (id viewportArguments = [dict objectForKey:@"WebViewportArguments"])
396        [self _setViewportArguments:viewportArguments];
397
398    NSNumber *scrollPointXValue = [dict objectForKey:scrollPointXKey];
399    NSNumber *scrollPointYValue = [dict objectForKey:scrollPointYKey];
400    if (scrollPointXValue && scrollPointYValue)
401        core(_private)->setScrollPoint(IntPoint([scrollPointXValue intValue], [scrollPointYValue intValue]));
402
403    uint32_t bookmarkIDValue = [[dict objectForKey:bookmarkIDKey] unsignedIntValue];
404    if (bookmarkIDValue)
405        core(_private)->setBookmarkID(bookmarkIDValue);
406
407    NSString *sharedLinkUniqueIdentifierValue = [dict objectForKey:sharedLinkUniqueIdentifierKey];
408    if (sharedLinkUniqueIdentifierValue)
409        core(_private)->setSharedLinkUniqueIdentifier(sharedLinkUniqueIdentifierValue);
410#endif
411
412    return self;
413}
414
415- (NSPoint)scrollPoint
416{
417    ASSERT_MAIN_THREAD();
418    return core(_private)->scrollPoint();
419}
420
421- (void)_visitedWithTitle:(NSString *)title
422{
423    core(_private)->setTitle(title);
424    _private->_lastVisitedTime = [NSDate timeIntervalSinceReferenceDate];
425}
426
427@end
428
429@implementation WebHistoryItem (WebPrivate)
430
431- (id)initWithURL:(NSURL *)URL title:(NSString *)title
432{
433    return [self initWithURLString:[URL _web_originalDataAsString] title:title lastVisitedTimeInterval:0];
434}
435
436// FIXME: The only iOS difference here should be whether YES or NO is passed to dictionaryRepresentationIncludingChildren:
437#if PLATFORM(IOS)
438- (NSDictionary *)dictionaryRepresentation
439{
440    return [self dictionaryRepresentationIncludingChildren:YES];
441}
442
443- (NSDictionary *)dictionaryRepresentationIncludingChildren:(BOOL)includesChildren
444#else
445- (NSDictionary *)dictionaryRepresentation
446#endif
447{
448    ASSERT_MAIN_THREAD();
449    NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithCapacity:8];
450
451    HistoryItem* coreItem = core(_private);
452
453    if (!coreItem->urlString().isEmpty())
454        [dict setObject:(NSString*)coreItem->urlString() forKey:@""];
455    if (!coreItem->title().isEmpty())
456        [dict setObject:(NSString*)coreItem->title() forKey:titleKey];
457    if (!coreItem->alternateTitle().isEmpty())
458        [dict setObject:(NSString*)coreItem->alternateTitle() forKey:displayTitleKey];
459    if (_private->_lastVisitedTime) {
460        // Store as a string to maintain backward compatibility. (See 3245793)
461        [dict setObject:[NSString stringWithFormat:@"%.1lf", _private->_lastVisitedTime]
462                 forKey:lastVisitedTimeIntervalKey];
463    }
464    if (coreItem->lastVisitWasFailure())
465        [dict setObject:[NSNumber numberWithBool:YES] forKey:lastVisitWasFailureKey];
466    if (Vector<String>* redirectURLs = coreItem->redirectURLs()) {
467        size_t size = redirectURLs->size();
468        ASSERT(size);
469        NSMutableArray *result = [[NSMutableArray alloc] initWithCapacity:size];
470        for (size_t i = 0; i < size; ++i)
471            [result addObject:(NSString*)redirectURLs->at(i)];
472        [dict setObject:result forKey:redirectURLsKey];
473        [result release];
474    }
475
476#if PLATFORM(IOS)
477    if (includesChildren && coreItem->children().size()) {
478#else
479    if (coreItem->children().size()) {
480#endif
481        const HistoryItemVector& children = coreItem->children();
482        NSMutableArray *childDicts = [NSMutableArray arrayWithCapacity:children.size()];
483
484        for (int i = children.size() - 1; i >= 0; i--)
485            [childDicts addObject:[kit(children[i].get()) dictionaryRepresentation]];
486        [dict setObject: childDicts forKey:childrenKey];
487    }
488
489#if PLATFORM(IOS)
490    [dict setObject:[NSNumber numberWithFloat:core(_private)->scale()] forKey:scaleKey];
491    [dict setObject:[NSNumber numberWithBool:core(_private)->scaleIsInitial()] forKey:scaleIsInitialKey];
492
493    NSDictionary *viewportArguments = [self _viewportArguments];
494    if (viewportArguments)
495        [dict setObject:viewportArguments forKey:@"WebViewportArguments"];
496
497    IntPoint scrollPoint = core(_private)->scrollPoint();
498    [dict setObject:[NSNumber numberWithInt:scrollPoint.x()] forKey:scrollPointXKey];
499    [dict setObject:[NSNumber numberWithInt:scrollPoint.y()] forKey:scrollPointYKey];
500
501    uint32_t bookmarkID = core(_private)->bookmarkID();
502    if (bookmarkID)
503        [dict setObject:[NSNumber numberWithUnsignedInt:bookmarkID] forKey:bookmarkIDKey];
504
505    NSString *sharedLinkUniqueIdentifier = [self _sharedLinkUniqueIdentifier];
506    if (sharedLinkUniqueIdentifier)
507        [dict setObject:sharedLinkUniqueIdentifier forKey:sharedLinkUniqueIdentifierKey];
508#endif
509
510    return dict;
511}
512
513- (NSString *)target
514{
515    ASSERT_MAIN_THREAD();
516    return nsStringNilIfEmpty(core(_private)->target());
517}
518
519- (BOOL)isTargetItem
520{
521    return core(_private)->isTargetItem();
522}
523
524- (NSString *)RSSFeedReferrer
525{
526    return nsStringNilIfEmpty(core(_private)->referrer());
527}
528
529- (void)setRSSFeedReferrer:(NSString *)referrer
530{
531    core(_private)->setReferrer(referrer);
532}
533
534- (NSArray *)children
535{
536    ASSERT_MAIN_THREAD();
537    const HistoryItemVector& children = core(_private)->children();
538    if (!children.size())
539        return nil;
540
541    unsigned size = children.size();
542    NSMutableArray *result = [[[NSMutableArray alloc] initWithCapacity:size] autorelease];
543
544    for (unsigned i = 0; i < size; ++i)
545        [result addObject:kit(children[i].get())];
546
547    return result;
548}
549
550- (NSURL *)URL
551{
552    ASSERT_MAIN_THREAD();
553    const URL& url = core(_private)->url();
554    if (url.isEmpty())
555        return nil;
556    return url;
557}
558
559- (WebHistoryItem *)targetItem
560{
561    ASSERT_MAIN_THREAD();
562    return kit(core(_private)->targetItem());
563}
564
565#if !PLATFORM(IOS)
566+ (void)_releaseAllPendingPageCaches
567{
568}
569#endif
570
571- (id)_transientPropertyForKey:(NSString *)key
572{
573    return core(_private)->getTransientProperty(key);
574}
575
576- (void)_setTransientProperty:(id)property forKey:(NSString *)key
577{
578    core(_private)->setTransientProperty(key, property);
579}
580
581- (BOOL)lastVisitWasFailure
582{
583    return core(_private)->lastVisitWasFailure();
584}
585
586- (NSArray *)_redirectURLs
587{
588    Vector<String>* redirectURLs = core(_private)->redirectURLs();
589    if (!redirectURLs)
590        return nil;
591
592    size_t size = redirectURLs->size();
593    ASSERT(size);
594    NSMutableArray *result = [[NSMutableArray alloc] initWithCapacity:size];
595    for (size_t i = 0; i < size; ++i)
596        [result addObject:(NSString*)redirectURLs->at(i)];
597    return [result autorelease];
598}
599
600#if PLATFORM(IOS)
601- (void)_setScale:(float)scale isInitial:(BOOL)aFlag
602{
603    core(_private)->setScale(scale, aFlag);
604}
605
606- (float)_scale
607{
608    return core(_private)->scale();
609}
610
611- (BOOL)_scaleIsInitial
612{
613    return core(_private)->scaleIsInitial();
614}
615
616- (NSDictionary *)_viewportArguments
617{
618    const ViewportArguments& viewportArguments = core(_private)->viewportArguments();
619    NSMutableDictionary *argumentsDictionary = [NSMutableDictionary dictionary];
620    [argumentsDictionary setObject:[NSNumber numberWithFloat:viewportArguments.zoom] forKey:WebViewportInitialScaleKey];
621    [argumentsDictionary setObject:[NSNumber numberWithFloat:viewportArguments.minZoom] forKey:WebViewportMinimumScaleKey];
622    [argumentsDictionary setObject:[NSNumber numberWithFloat:viewportArguments.maxZoom] forKey:WebViewportMaximumScaleKey];
623    [argumentsDictionary setObject:[NSNumber numberWithFloat:viewportArguments.width] forKey:WebViewportWidthKey];
624    [argumentsDictionary setObject:[NSNumber numberWithFloat:viewportArguments.height] forKey:WebViewportHeightKey];
625    [argumentsDictionary setObject:[NSNumber numberWithFloat:viewportArguments.userZoom] forKey:WebViewportUserScalableKey];
626    [argumentsDictionary setObject:[NSNumber numberWithBool:viewportArguments.minimalUI] forKey:WebViewportMinimalUIKey];
627    return argumentsDictionary;
628}
629
630- (void)_setViewportArguments:(NSDictionary *)arguments
631{
632    ViewportArguments viewportArguments;
633    viewportArguments.zoom = [[arguments objectForKey:WebViewportInitialScaleKey] floatValue];
634    viewportArguments.minZoom = [[arguments objectForKey:WebViewportMinimumScaleKey] floatValue];
635    viewportArguments.maxZoom = [[arguments objectForKey:WebViewportMaximumScaleKey] floatValue];
636    viewportArguments.width = [[arguments objectForKey:WebViewportWidthKey] floatValue];
637    viewportArguments.height = [[arguments objectForKey:WebViewportHeightKey] floatValue];
638    viewportArguments.userZoom = [[arguments objectForKey:WebViewportUserScalableKey] floatValue];
639    viewportArguments.minimalUI = [[arguments objectForKey:WebViewportMinimalUIKey] boolValue];
640    core(_private)->setViewportArguments(viewportArguments);
641}
642
643- (CGPoint)_scrollPoint
644{
645    return core(_private)->scrollPoint();
646}
647
648- (void)_setScrollPoint:(CGPoint)scrollPoint
649{
650    core(_private)->setScrollPoint(IntPoint(scrollPoint));
651}
652
653- (uint32_t)_bookmarkID
654{
655    return core(_private)->bookmarkID();
656}
657
658- (void)_setBookmarkID:(uint32_t)bookmarkID
659{
660    core(_private)->setBookmarkID(bookmarkID);
661}
662
663- (NSString *)_sharedLinkUniqueIdentifier
664{
665    return nsStringNilIfEmpty(core(_private)->sharedLinkUniqueIdentifier());
666}
667
668- (void)_setSharedLinkUniqueIdentifier:(NSString *)identifier
669{
670    core(_private)->setSharedLinkUniqueIdentifier(identifier);
671}
672#endif // PLATFORM(IOS)
673
674- (BOOL)_isInPageCache
675{
676    return core(_private)->isInPageCache();
677}
678
679- (BOOL)_hasCachedPageExpired
680{
681    return core(_private)->hasCachedPageExpired();
682}
683
684@end
685