Chromium Code Reviews| Index: ios/web/public/crw_navigation_item_storage.mm |
| diff --git a/ios/web/public/crw_navigation_item_storage.mm b/ios/web/public/crw_navigation_item_storage.mm |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..e3569dea2799a99ef60a88c0918e9a9e3ea3499c |
| --- /dev/null |
| +++ b/ios/web/public/crw_navigation_item_storage.mm |
| @@ -0,0 +1,237 @@ |
| +// Copyright 2017 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#import "ios/web/public/crw_navigation_item_storage.h" |
| + |
| +#import "base/strings/sys_string_conversions.h" |
|
Eugene But (OOO till 7-30)
2017/01/31 22:12:26
nit: s/import/include
kkhorimoto
2017/02/03 00:36:09
Done.
|
| +#import "ios/web/navigation/nscoder_util.h" |
| +#import "net/base/mac/url_conversions.h" |
| + |
| +#if !defined(__has_feature) || !__has_feature(objc_arc) |
| +#error "This file requires ARC support." |
| +#endif |
| + |
| +namespace web { |
| + |
| +// Keys used to serialize web::PageScrollState properties. |
| +NSString* const kNavigationItemStoragePageDisplayStateKey = @"state"; |
| +NSString* const kNavigationItemStorageScrollOffsetXKey = @"scrollX"; |
| +NSString* const kNavigationItemStorageScrollOffsetYKey = @"scrollY"; |
| +NSString* const kNavigationItemStorageMinimumZoomScaleKey = @"minZoom"; |
| +NSString* const kNavigationItemStorageMaximumZoomScaleKey = @"maxZoom"; |
| +NSString* const kNavigationItemStorageZoomScaleKey = @"zoom"; |
| + |
| +// Keys used to serialize navigation properties. |
| +NSString* const kNavigationItemStorageURLKey = @"virtualUrlString"; |
| +NSString* const kNavigationItemStorageURLDeperecatedKey = @"virtualUrl"; |
| +NSString* const kNavigationItemStorageReferrerURLKey = @"referrerUrlString"; |
| +NSString* const kNavigationItemStorageReferrerURLDeprecatedKey = @"referrer"; |
| +NSString* const kNavigationItemStorageReferrerPolicyKey = @"referrerPolicy"; |
| +NSString* const kNavigationItemStorageTimestampKey = @"timestamp"; |
| +NSString* const kNavigationItemStorageTitleKey = @"title"; |
| +NSString* const kNavigationItemStoragePOSTDataKey = @"POSTData"; |
| +NSString* const kNavigationItemStorageHTTPRequestHeadersKey = @"httpHeaders"; |
| +NSString* const kNavigationItemStorageSkipRepostFormConfirmationKey = |
| + @"skipResubmitDataConfirmation"; |
| +NSString* const kNavigationItemStorageUseDesktopUserAgentKey = |
| + @"useDesktopUserAgent"; |
| + |
| +} // namespace web |
| + |
| +namespace { |
| + |
| +// Converts a serialized NSDictionary to a web::PageDisplayState. |
| +web::PageDisplayState DisplayStateFromDictionary(NSDictionary* dictionary) { |
| + NSNumber* serializedValue = nil; |
| + web::PageScrollState scrollState; |
| + if ((serializedValue = |
| + dictionary[web::kNavigationItemStorageScrollOffsetXKey])) |
| + scrollState.set_offset_x([serializedValue doubleValue]); |
| + if ((serializedValue = |
| + dictionary[web::kNavigationItemStorageScrollOffsetYKey])) |
| + scrollState.set_offset_y([serializedValue doubleValue]); |
| + web::PageZoomState zoomState; |
| + if ((serializedValue = |
| + dictionary[web::kNavigationItemStorageMinimumZoomScaleKey])) |
| + zoomState.set_minimum_zoom_scale([serializedValue doubleValue]); |
| + if ((serializedValue = |
| + dictionary[web::kNavigationItemStorageMaximumZoomScaleKey])) |
| + zoomState.set_maximum_zoom_scale([serializedValue doubleValue]); |
| + if ((serializedValue = dictionary[web::kNavigationItemStorageZoomScaleKey])) |
| + zoomState.set_zoom_scale([serializedValue doubleValue]); |
| + return web::PageDisplayState(scrollState, zoomState); |
| +} |
| + |
| +// Serializes a web::PageDisplayState to an NSDictionary. |
| +NSDictionary* DictionaryFromDisplayState(web::PageDisplayState display_state) { |
| + return @{ |
| + web::kNavigationItemStorageScrollOffsetXKey : |
| + @(display_state.scroll_state().offset_x()), |
| + web::kNavigationItemStorageScrollOffsetYKey : |
| + @(display_state.scroll_state().offset_y()), |
| + web::kNavigationItemStorageMinimumZoomScaleKey : |
| + @(display_state.zoom_state().minimum_zoom_scale()), |
| + web::kNavigationItemStorageMaximumZoomScaleKey : |
| + @(display_state.zoom_state().maximum_zoom_scale()), |
| + web::kNavigationItemStorageZoomScaleKey : |
| + @(display_state.zoom_state().zoom_scale()) |
| + }; |
| +} |
| + |
| +} // namespace |
| + |
| +@implementation CRWNavigationItemStorage |
| + |
| +@synthesize virtualURL = _virtualURL; |
| +@synthesize referrer = _referrer; |
| +@synthesize timestamp = _timestamp; |
| +@synthesize title = _title; |
| +@synthesize displayState = _displayState; |
| +@synthesize shouldSkipRepostFormConfirmation = |
| + _shouldSkipRepostFormConfirmation; |
| +@synthesize overridingUserAgent = _overridingUserAgent; |
| +@synthesize POSTData = _POSTData; |
| +@synthesize HTTPRequestHeaders = _HTTPRequestHeaders; |
| + |
| +#pragma mark - NSObject |
| + |
| +- (NSUInteger)hash { |
| + NSUInteger hash = 0; |
| + hash ^= [net::NSURLWithGURL(_virtualURL) hash]; |
| + hash ^= [net::NSURLWithGURL(_referrer.url) hash]; |
| + hash ^= _referrer.policy; |
| + hash ^= _timestamp.ToTimeT(); |
| + hash ^= [base::SysUTF16ToNSString(_title) hash]; |
| + hash ^= [DictionaryFromDisplayState(_displayState) hash]; |
| + hash ^= _shouldSkipRepostFormConfirmation; |
| + // Bit shift |_overridingUserAgent| so to differentiate it from |
| + // |_shouldSkipRepostFormConfirmation| in the hash. |
| + hash ^= _overridingUserAgent << 1; |
| + hash ^= [_POSTData hash]; |
| + hash ^= [_HTTPRequestHeaders hash]; |
| + return hash; |
| +} |
| + |
| +- (BOOL)isEqual:(id)object { |
| + return [object class] == [self class] && [object hash] == [self hash]; |
|
Eugene But (OOO till 7-30)
2017/01/31 22:12:26
Equality of hashes does not mean objects equality,
kkhorimoto
2017/02/03 00:36:09
Fixed.
Eugene But (OOO till 7-30)
2017/02/03 01:52:34
So the other question was: "Is this method used ou
Eugene But (OOO till 7-30)
2017/02/03 01:57:16
The other reason for not using |hash| and |isEqual
kkhorimoto
2017/02/03 02:47:23
Done.
|
| +} |
| + |
| +- (NSString*)description { |
| + NSMutableString* description = |
| + [NSMutableString stringWithString:[super description]]; |
| + [description appendFormat:@"virtualURL : %s, ", _virtualURL.spec().c_str()]; |
| + [description appendFormat:@"referrer : %s, ", _referrer.url.spec().c_str()]; |
| + [description appendFormat:@"timestamp : %f, ", _timestamp.ToCFAbsoluteTime()]; |
| + [description appendFormat:@"title : %@, ", base::SysUTF16ToNSString(_title)]; |
| + [description appendFormat:@"displayState : %@", |
| + DictionaryFromDisplayState(_displayState)]; |
| + [description appendFormat:@"skipRepostConfirmation : %@, ", |
| + @(_shouldSkipRepostFormConfirmation)]; |
| + [description |
| + appendFormat:@"overridingUserAgent : %@, ", @(_overridingUserAgent)]; |
| + [description appendFormat:@"POSTData : %@, ", _POSTData]; |
| + [description appendFormat:@"HTTPRequestHeaders : %@", _HTTPRequestHeaders]; |
| + return description; |
| +} |
| + |
| +#pragma mark - NSCoding |
| + |
| +- (instancetype)initWithCoder:(NSCoder*)aDecoder { |
| + self = [super init]; |
| + if (self) { |
| + // Desktop chrome only persists virtualUrl_ and uses it to feed the url |
| + // when creating a NavigationEntry. |
| + if ([aDecoder containsValueForKey:web::kNavigationItemStorageURLKey]) { |
| + _virtualURL = GURL(web::nscoder_util::DecodeString( |
| + aDecoder, web::kNavigationItemStorageURLKey)); |
| + } else { |
| + // Backward compatibility. |
| + _virtualURL = net::GURLWithNSURL([aDecoder |
| + decodeObjectForKey:web::kNavigationItemStorageURLDeperecatedKey]); |
| + } |
| + |
| + if ([aDecoder |
| + containsValueForKey:web::kNavigationItemStorageReferrerURLKey]) { |
| + const std::string referrerString(web::nscoder_util::DecodeString( |
| + aDecoder, web::kNavigationItemStorageReferrerURLKey)); |
| + web::ReferrerPolicy referrerPolicy = |
| + static_cast<web::ReferrerPolicy>([aDecoder |
| + decodeIntForKey:web::kNavigationItemStorageReferrerPolicyKey]); |
| + _referrer = web::Referrer(GURL(referrerString), referrerPolicy); |
| + } else { |
| + // Backward compatibility. |
| + NSURL* referrerURL = |
| + [aDecoder decodeObjectForKey: |
| + web::kNavigationItemStorageReferrerURLDeprecatedKey]; |
| + _referrer = web::Referrer(net::GURLWithNSURL(referrerURL), |
| + web::ReferrerPolicyDefault); |
| + } |
| + |
| + if ([aDecoder |
| + containsValueForKey:web::kNavigationItemStorageTimestampKey]) { |
| + int64_t us = |
| + [aDecoder decodeInt64ForKey:web::kNavigationItemStorageTimestampKey]; |
| + _timestamp = base::Time::FromInternalValue(us); |
| + } |
| + |
| + NSString* title = |
| + [aDecoder decodeObjectForKey:web::kNavigationItemStorageTitleKey]; |
| + // Use a transition type of reload so that we don't incorrectly increase |
| + // the typed count. This is what desktop chrome does. |
| + _title = base::SysNSStringToUTF16(title); |
| + NSDictionary* serializedDisplayState = [aDecoder |
| + decodeObjectForKey:web::kNavigationItemStoragePageDisplayStateKey]; |
| + _displayState = DisplayStateFromDictionary(serializedDisplayState); |
| + _shouldSkipRepostFormConfirmation = |
| + [aDecoder decodeBoolForKey: |
| + web::kNavigationItemStorageSkipRepostFormConfirmationKey]; |
| + _overridingUserAgent = [aDecoder |
| + decodeBoolForKey:web::kNavigationItemStorageUseDesktopUserAgentKey]; |
| + _POSTData = |
| + [aDecoder decodeObjectForKey:web::kNavigationItemStoragePOSTDataKey]; |
| + _HTTPRequestHeaders = [aDecoder |
| + decodeObjectForKey:web::kNavigationItemStorageHTTPRequestHeadersKey]; |
| + } |
| + return self; |
| +} |
| + |
| +- (void)encodeWithCoder:(NSCoder*)aCoder { |
| + // Desktop Chrome doesn't persist |url_| or |originalUrl_|, only |
| + // |virtualUrl_|. |
| + web::nscoder_util::EncodeString(aCoder, web::kNavigationItemStorageURLKey, |
| + _virtualURL.spec()); |
| + web::nscoder_util::EncodeString( |
| + aCoder, web::kNavigationItemStorageReferrerURLKey, _referrer.url.spec()); |
| + [aCoder encodeInt:_referrer.policy |
| + forKey:web::kNavigationItemStorageReferrerPolicyKey]; |
| + [aCoder encodeInt64:_timestamp.ToInternalValue() |
| + forKey:web::kNavigationItemStorageTimestampKey]; |
| + |
| + [aCoder encodeObject:base::SysUTF16ToNSString(_title) |
| + forKey:web::kNavigationItemStorageTitleKey]; |
| + [aCoder encodeObject:DictionaryFromDisplayState(_displayState) |
| + forKey:web::kNavigationItemStoragePageDisplayStateKey]; |
| + [aCoder encodeBool:_shouldSkipRepostFormConfirmation |
| + forKey:web::kNavigationItemStorageSkipRepostFormConfirmationKey]; |
| + [aCoder encodeBool:_overridingUserAgent |
| + forKey:web::kNavigationItemStorageUseDesktopUserAgentKey]; |
| + [aCoder encodeObject:_POSTData forKey:web::kNavigationItemStoragePOSTDataKey]; |
| + [aCoder encodeObject:_HTTPRequestHeaders |
| + forKey:web::kNavigationItemStorageHTTPRequestHeadersKey]; |
| +} |
| + |
| +@end |
| + |
| +@implementation CRWNavigationItemStorage (Testing) |
| + |
| ++ (web::PageDisplayState)displayStateFromDictionary:(NSDictionary*)dictionary { |
| + return DisplayStateFromDictionary(dictionary); |
| +} |
| + |
| ++ (NSDictionary*)dictionaryFromDisplayState: |
| + (web::PageDisplayState)displayState { |
| + return DictionaryFromDisplayState(displayState); |
| +} |
| + |
| +@end |