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