Add ICU message format support
[chromium-blink-merge.git] / ios / web / navigation / crw_session_entry.mm
blob81a95af96a3b439cc61280608b880cb2d13eaf3a
1 // Copyright 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #import "ios/web/navigation/crw_session_entry.h"
7 #include "base/mac/objc_property_releaser.h"
8 #include "base/mac/scoped_nsobject.h"
9 #include "base/memory/scoped_ptr.h"
10 #include "base/strings/sys_string_conversions.h"
11 #include "ios/web/navigation/navigation_item_impl.h"
12 #include "ios/web/navigation/nscoder_util.h"
13 #include "ios/web/public/navigation_item.h"
14 #include "ios/web/public/web_state/page_display_state.h"
15 #import "net/base/mac/url_conversions.h"
17 namespace web {
18 // Keys used to serialize web::PageScrollState properties.
19 NSString* const kSessionEntryPageScrollStateKey = @"state";
20 NSString* const kSessionEntryScrollOffsetXKey = @"scrollX";
21 NSString* const kSessionEntryScrollOffsetYKey = @"scrollY";
22 NSString* const kSessionEntryMinimumZoomScaleKey = @"minZoom";
23 NSString* const kSessionEntryMaximumZoomScaleKey = @"maxZoom";
24 NSString* const kSessionEntryZoomScaleKey = @"zoom";
26 // Keys used to serialize navigation properties.
27 NSString* const kSessionEntryURLKey = @"virtualUrlString";
28 NSString* const kSessionEntryURLDeperecatedKey = @"virtualUrl";
29 NSString* const kSessionEntryReferrerURLKey = @"referrerUrlString";
30 NSString* const kSessionEntryReferrerURLDeprecatedKey = @"referrer";
31 NSString* const kSessionEntryReferrerPolicyKey = @"referrerPolicy";
32 NSString* const kSessionEntryTimestampKey = @"timestamp";
33 NSString* const kSessionEntryTitleKey = @"title";
34 NSString* const kSessionEntryPOSTDataKey = @"POSTData";
35 NSString* const kSessionEntryHTTPRequestHeadersKey = @"httpHeaders";
36 NSString* const kSessionEntrySkipResubmitConfirmationKey =
37     @"skipResubmitDataConfirmation";
38 NSString* const kSessionEntryUseDesktopUserAgentKey = @"useDesktopUserAgent";
41 @interface CRWSessionEntry () {
42   // The original URL of the page.  In cases where a redirect occurred, |url_|
43   // will contain the final post-redirect URL, and |originalUrl_| will contain
44   // the pre-redirect URL.  This field is not persisted to disk.
45   GURL _originalUrl;
47   // The NavigationItemImpl corresponding to this CRWSessionEntry.
48   // TODO(stuartmorgan): Move ownership to NavigationManagerImpl.
49   scoped_ptr<web::NavigationItemImpl> _navigationItem;
51   base::mac::ObjCPropertyReleaser _propertyReleaser_CRWSessionEntry;
53 // Redefine originalUrl to be read-write.
54 @property(nonatomic, readwrite) const GURL& originalUrl;
56 // Converts a serialized NSDictionary to a web::PageDisplayState.
57 + (web::PageDisplayState)pageDisplayStateFromDictionary:
58         (NSDictionary*)dictionary;
59 // Serializes a web::PageDisplayState to an NSDictionary.
60 + (NSDictionary*)dictionaryFromPageDisplayState:
61         (const web::PageDisplayState&)displayState;
62 // Returns a readable description of |displayState|.
63 + (NSString*)descriptionForPageDisplayState:
64         (const web::PageDisplayState&)displayState;
65 @end
67 @implementation CRWSessionEntry
69 @synthesize originalUrl = _originalUrl;
71 - (instancetype)initWithNavigationItem:(scoped_ptr<web::NavigationItem>)item {
72   self = [super init];
73   if (self) {
74     _propertyReleaser_CRWSessionEntry.Init(self, [CRWSessionEntry class]);
75     _navigationItem.reset(
76         static_cast<web::NavigationItemImpl*>(item.release()));
77     self.originalUrl = _navigationItem->GetURL();
78   }
79   return self;
82 - (instancetype)initWithCoder:(NSCoder*)aDecoder {
83   self = [super init];
84   if (self) {
85     _propertyReleaser_CRWSessionEntry.Init(self, [CRWSessionEntry class]);
86     _navigationItem.reset(new web::NavigationItemImpl());
88     // Desktop chrome only persists virtualUrl_ and uses it to feed the url
89     // when creating a NavigationEntry.
90     GURL url;
91     if ([aDecoder containsValueForKey:web::kSessionEntryURLKey]) {
92       url = GURL(
93           web::nscoder_util::DecodeString(aDecoder, web::kSessionEntryURLKey));
94     } else {
95       // Backward compatibility.
96       url = net::GURLWithNSURL(
97           [aDecoder decodeObjectForKey:web::kSessionEntryURLDeperecatedKey]);
98     }
99     _navigationItem->SetURL(url);
100     self.originalUrl = url;
102     if ([aDecoder containsValueForKey:web::kSessionEntryReferrerURLKey]) {
103       const std::string referrerString(web::nscoder_util::DecodeString(
104           aDecoder, web::kSessionEntryReferrerURLKey));
105       web::ReferrerPolicy referrerPolicy = static_cast<web::ReferrerPolicy>(
106           [aDecoder decodeIntForKey:web::kSessionEntryReferrerPolicyKey]);
107       _navigationItem->SetReferrer(
108           web::Referrer(GURL(referrerString), referrerPolicy));
109     } else {
110       // Backward compatibility.
111       NSURL* referrer = [aDecoder
112           decodeObjectForKey:web::kSessionEntryReferrerURLDeprecatedKey];
113       _navigationItem->SetReferrer(web::Referrer(
114           net::GURLWithNSURL(referrer), web::ReferrerPolicyDefault));
115     }
117     if ([aDecoder containsValueForKey:web::kSessionEntryTimestampKey]) {
118       int64 us = [aDecoder decodeInt64ForKey:web::kSessionEntryTimestampKey];
119       _navigationItem->SetTimestamp(base::Time::FromInternalValue(us));
120     }
122     NSString* title = [aDecoder decodeObjectForKey:web::kSessionEntryTitleKey];
123     // Use a transition type of reload so that we don't incorrectly increase
124     // the typed count.  This is what desktop chrome does.
125     _navigationItem->SetTitle(base::SysNSStringToUTF16(title));
126     _navigationItem->SetTransitionType(ui::PAGE_TRANSITION_RELOAD);
127     _navigationItem->SetPageDisplayState([[self class]
128         pageDisplayStateFromDictionary:
129             [aDecoder
130                 decodeObjectForKey:web::kSessionEntryPageScrollStateKey]]);
131     _navigationItem->SetShouldSkipResubmitDataConfirmation([aDecoder
132         decodeBoolForKey:web::kSessionEntrySkipResubmitConfirmationKey]);
133     _navigationItem->SetIsOverridingUserAgent(
134         [aDecoder decodeBoolForKey:web::kSessionEntryUseDesktopUserAgentKey]);
135     _navigationItem->SetPostData(
136         [aDecoder decodeObjectForKey:web::kSessionEntryPOSTDataKey]);
137     _navigationItem->AddHttpRequestHeaders(
138         [aDecoder decodeObjectForKey:web::kSessionEntryHTTPRequestHeadersKey]);
139   }
140   return self;
143 - (void)encodeWithCoder:(NSCoder*)aCoder {
144   // Desktop Chrome doesn't persist |url_| or |originalUrl_|, only
145   // |virtualUrl_|.
146   web::nscoder_util::EncodeString(aCoder, web::kSessionEntryURLKey,
147                                   _navigationItem->GetVirtualURL().spec());
148   web::nscoder_util::EncodeString(aCoder, web::kSessionEntryReferrerURLKey,
149                                   _navigationItem->GetReferrer().url.spec());
150   [aCoder encodeInt:_navigationItem->GetReferrer().policy
151              forKey:web::kSessionEntryReferrerPolicyKey];
152   [aCoder encodeInt64:_navigationItem->GetTimestamp().ToInternalValue()
153                forKey:web::kSessionEntryTimestampKey];
155   [aCoder encodeObject:base::SysUTF16ToNSString(_navigationItem->GetTitle())
156                 forKey:web::kSessionEntryTitleKey];
157   [aCoder encodeObject:[[self class] dictionaryFromPageDisplayState:
158                                          _navigationItem->GetPageDisplayState()]
159                 forKey:web::kSessionEntryPageScrollStateKey];
160   [aCoder encodeBool:_navigationItem->ShouldSkipResubmitDataConfirmation()
161               forKey:web::kSessionEntrySkipResubmitConfirmationKey];
162   [aCoder encodeBool:_navigationItem->IsOverridingUserAgent()
163               forKey:web::kSessionEntryUseDesktopUserAgentKey];
164   [aCoder encodeObject:_navigationItem->GetPostData()
165                 forKey:web::kSessionEntryPOSTDataKey];
166   [aCoder encodeObject:_navigationItem->GetHttpRequestHeaders()
167                 forKey:web::kSessionEntryHTTPRequestHeadersKey];
170 // TODO(ios): Shall we overwrite EqualTo:?
172 - (instancetype)copyWithZone:(NSZone*)zone {
173   CRWSessionEntry* copy = [[[self class] alloc] init];
174   copy->_propertyReleaser_CRWSessionEntry.Init(copy, [CRWSessionEntry class]);
175   copy->_navigationItem.reset(
176       new web::NavigationItemImpl(*_navigationItem.get()));
177   copy->_originalUrl = _originalUrl;
178   return copy;
181 - (NSString*)description {
182   return [NSString
183       stringWithFormat:
184           @"url:%@ originalurl:%@ title:%@ transition:%d displayState:%@ "
185           @"desktopUA:%d",
186           base::SysUTF8ToNSString(_navigationItem->GetURL().spec()),
187           base::SysUTF8ToNSString(self.originalUrl.spec()),
188           base::SysUTF16ToNSString(_navigationItem->GetTitle()),
189           _navigationItem->GetTransitionType(),
190           [[self class] descriptionForPageDisplayState:
191                             _navigationItem->GetPageDisplayState()],
192           _navigationItem->IsOverridingUserAgent()];
195 - (web::NavigationItem*)navigationItem {
196   return _navigationItem.get();
199 - (web::NavigationItemImpl*)navigationItemImpl {
200   return _navigationItem.get();
203 #pragma mark - Serialization helpers
205 + (web::PageDisplayState)pageDisplayStateFromDictionary:
206     (NSDictionary*)dictionary {
207   NSNumber* serializedValue = nil;
208   web::PageScrollState scrollState;
209   if ((serializedValue = dictionary[web::kSessionEntryScrollOffsetXKey]))
210     scrollState.set_offset_x([serializedValue doubleValue]);
211   if ((serializedValue = dictionary[web::kSessionEntryScrollOffsetYKey]))
212     scrollState.set_offset_y([serializedValue doubleValue]);
213   web::PageZoomState zoomState;
214   if ((serializedValue = dictionary[web::kSessionEntryMinimumZoomScaleKey]))
215     zoomState.set_minimum_zoom_scale([serializedValue doubleValue]);
216   if ((serializedValue = dictionary[web::kSessionEntryMaximumZoomScaleKey]))
217     zoomState.set_maximum_zoom_scale([serializedValue doubleValue]);
218   if ((serializedValue = dictionary[web::kSessionEntryZoomScaleKey]))
219     zoomState.set_zoom_scale([serializedValue doubleValue]);
220   return web::PageDisplayState(scrollState, zoomState);
223 + (NSDictionary*)dictionaryFromPageDisplayState:
224     (const web::PageDisplayState&)displayState {
225   return @{
226     web::kSessionEntryScrollOffsetXKey :
227         @(displayState.scroll_state().offset_x()),
228     web::kSessionEntryScrollOffsetYKey :
229         @(displayState.scroll_state().offset_y()),
230     web::kSessionEntryMinimumZoomScaleKey :
231         @(displayState.zoom_state().minimum_zoom_scale()),
232     web::kSessionEntryMaximumZoomScaleKey :
233         @(displayState.zoom_state().maximum_zoom_scale()),
234     web::kSessionEntryZoomScaleKey :
235         @(displayState.zoom_state().zoom_scale())
236   };
239 + (NSString*)descriptionForPageDisplayState:
240         (const web::PageDisplayState&)displayState {
241   NSString* const kPageScrollStateDescriptionFormat =
242       @"{ scrollOffset:(%0.2f, %0.2f), zoomScaleRange:(%0.2f, %0.2f), "
243       @"zoomScale:%0.2f }";
244   return
245       [NSString stringWithFormat:kPageScrollStateDescriptionFormat,
246                                  displayState.scroll_state().offset_x(),
247                                  displayState.scroll_state().offset_y(),
248                                  displayState.zoom_state().minimum_zoom_scale(),
249                                  displayState.zoom_state().maximum_zoom_scale(),
250                                  displayState.zoom_state().zoom_scale()];
253 @end