Android Chromoting: Remove exit-fullscreen button.
[chromium-blink-merge.git] / ios / web / navigation / crw_session_entry.mm
blobc786499e7b20397173dfca0dfe64c3183f870c5c
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_scroll_state.h"
15 #import "net/base/mac/url_conversions.h"
17 namespace {
18 // Keys used to serialize web::PageScrollState properties.
19 NSString* const kScrollOffsetXKey = @"scrollX";
20 NSString* const kScrollOffsetYKey = @"scrollY";
21 NSString* const kMinimumZoomScaleKey = @"minZoom";
22 NSString* const kMaximumZoomScaleKey = @"maxZoom";
23 NSString* const kZoomScaleKey = @"zoom";
26 @interface CRWSessionEntry () {
27   // The index in the CRWSessionController.
28   //
29   // This is used when determining the selected CRWSessionEntry and only useful
30   // to the SessionServiceIOS.
31   NSInteger _index;
33   // The original URL of the page.  In cases where a redirect occurred, |url_|
34   // will contain the final post-redirect URL, and |originalUrl_| will contain
35   // the pre-redirect URL.  This field is not persisted to disk.
36   GURL _originalUrl;
38   // Headers passed along with the request. For POST requests, these are
39   // persisted, to be able to resubmit them. Some specialized non-POST requests
40   // may also pass custom headers.
41   base::scoped_nsobject<NSMutableDictionary> _httpHeaders;
43   // Data submitted with a POST request, persisted for resubmits.
44   NSData* _POSTData;
46   // Serialized representation of the state object that was used in conjunction
47   // with a JavaScript window.history.pushState() or
48   // window.history.replaceState() call that created or modified this
49   // CRWSessionEntry. Intended to be used for JavaScript history operations and
50   // will be nil in most cases.
51   NSString* _serializedStateObject;
53   // Whether or not this entry was created by calling history.pushState().
54   BOOL _createdFromPushState;
56   // If |YES| use a desktop user agent in HTTP requests and UIWebView.
57   BOOL _useDesktopUserAgent;
59   // If |YES| the page was last fetched through the data reduction proxy.
60   BOOL _usedDataReductionProxy;
62   // Whether or not to bypass showing the resubmit data confirmation when
63   // loading a POST request. Set to YES for browser-generated POST requests such
64   // as search-by-image requests.
65   BOOL _skipResubmitDataConfirmation;
67   // The NavigationItemImpl corresponding to this CRWSessionEntry.
68   // TODO(stuartmorgan): Move ownership to NavigationManagerImpl.
69   scoped_ptr<web::NavigationItemImpl> _navigationItem;
71   base::mac::ObjCPropertyReleaser _propertyReleaser_CRWSessionEntry;
73 // Redefine originalUrl to be read-write.
74 @property(nonatomic, readwrite) const GURL& originalUrl;
76 // Converts a serialized NSDictionary to a web::PageScrollState.
77 + (web::PageScrollState)scrollStateFromDictionary:(NSDictionary*)dictionary;
78 // Serializes a web::PageScrollState to an NSDictionary.
79 + (NSDictionary*)dictionaryFromScrollState:
80     (const web::PageScrollState&)scrollState;
81 // Returns a readable description of |scrollState|.
82 + (NSString*)scrollStateDescription:(const web::PageScrollState&)scrollState;
83 @end
85 @implementation CRWSessionEntry
87 @synthesize POSTData = _POSTData;
88 @synthesize originalUrl = _originalUrl;
89 @synthesize useDesktopUserAgent = _useDesktopUserAgent;
90 @synthesize usedDataReductionProxy = _usedDataReductionProxy;
91 @synthesize index = _index;
92 @synthesize serializedStateObject = _serializedStateObject;
93 @synthesize createdFromPushState = _createdFromPushState;
94 @synthesize skipResubmitDataConfirmation = _skipResubmitDataConfirmation;
96 // Creates a new session entry. These may be nil.
97 - (instancetype)initWithUrl:(const GURL&)url
98                    referrer:(const web::Referrer&)referrer
99                  transition:(ui::PageTransition)transition
100         useDesktopUserAgent:(BOOL)useDesktopUserAgent
101           rendererInitiated:(BOOL)rendererInitiated {
102   self = [super init];
103   if (self) {
104     _propertyReleaser_CRWSessionEntry.Init(self, [CRWSessionEntry class]);
105     _navigationItem.reset(new web::NavigationItemImpl());
107     _navigationItem->SetURL(url);
108     _navigationItem->SetReferrer(referrer);
109     _navigationItem->SetTransitionType(transition);
110     _navigationItem->set_is_renderer_initiated(rendererInitiated);
112     self.originalUrl = url;
113     self.useDesktopUserAgent = useDesktopUserAgent;
114   }
115   return self;
118 - (instancetype)initWithNavigationItem:(scoped_ptr<web::NavigationItem>)item
119                                  index:(int)index {
120   self = [super init];
121   if (self) {
122     _propertyReleaser_CRWSessionEntry.Init(self, [CRWSessionEntry class]);
123     _navigationItem.reset(
124         static_cast<web::NavigationItemImpl*>(item.release()));
126     self.index = index;
127     self.originalUrl = _navigationItem->GetURL();
128     self.useDesktopUserAgent = NO;
129   }
130   return self;
133 - (instancetype)initWithCoder:(NSCoder*)aDecoder {
134   self = [super init];
135   if (self) {
136     _propertyReleaser_CRWSessionEntry.Init(self, [CRWSessionEntry class]);
137     _navigationItem.reset(new web::NavigationItemImpl());
139     // Desktop chrome only persists virtualUrl_ and uses it to feed the url
140     // when creating a NavigationEntry.
141     GURL url;
142     if ([aDecoder containsValueForKey:@"virtualUrlString"]) {
143       url = GURL(
144           web::nscoder_util::DecodeString(aDecoder, @"virtualUrlString"));
145     } else {
146       // Backward compatibility.
147       url = net::GURLWithNSURL([aDecoder decodeObjectForKey:@"virtualUrl"]);
148     }
149     _navigationItem->SetURL(url);
150     self.originalUrl = url;
152     if ([aDecoder containsValueForKey:@"referrerUrlString"]) {
153       const std::string referrerString(web::nscoder_util::DecodeString(
154           aDecoder, @"referrerUrlString"));
155       web::ReferrerPolicy referrerPolicy =
156           static_cast<web::ReferrerPolicy>(
157               [aDecoder decodeIntForKey:@"referrerPolicy"]);
158       _navigationItem->SetReferrer(
159           web::Referrer(GURL(referrerString), referrerPolicy));
160     } else {
161       // Backward compatibility.
162       NSURL* referrer = [aDecoder decodeObjectForKey:@"referrer"];
163       _navigationItem->SetReferrer(web::Referrer(
164           net::GURLWithNSURL(referrer), web::ReferrerPolicyDefault));
165     }
167     if ([aDecoder containsValueForKey:@"timestamp"]) {
168       int64 us = [aDecoder decodeInt64ForKey:@"timestamp"];
169       _navigationItem->SetTimestamp(base::Time::FromInternalValue(us));
170     }
172     NSString* title = [aDecoder decodeObjectForKey:@"title"];
173     // Use a transition type of reload so that we don't incorrectly increase
174     // the typed count.  This is what desktop chrome does.
175     _navigationItem->SetPageID(-1);
176     _navigationItem->SetTitle(base::SysNSStringToUTF16(title));
177     _navigationItem->SetTransitionType(ui::PAGE_TRANSITION_RELOAD);
178     _navigationItem->SetPageScrollState([[self class]
179         scrollStateFromDictionary:[aDecoder decodeObjectForKey:@"state"]]);
180     self.index = [aDecoder decodeIntForKey:@"index"];
181     self.useDesktopUserAgent =
182         [aDecoder decodeBoolForKey:@"useDesktopUserAgent"];
183     self.usedDataReductionProxy =
184         [aDecoder decodeBoolForKey:@"usedDataReductionProxy"];
185     [self addHTTPHeaders:[aDecoder decodeObjectForKey:@"httpHeaders"]];
186     self.POSTData = [aDecoder decodeObjectForKey:@"POSTData"];
187     self.skipResubmitDataConfirmation =
188         [aDecoder decodeBoolForKey:@"skipResubmitDataConfirmation"];
189   }
190   return self;
193 - (void)encodeWithCoder:(NSCoder*)aCoder {
194   // Desktop Chrome doesn't persist |url_| or |originalUrl_|, only
195   // |virtualUrl_|.
196   [aCoder encodeInt:self.index forKey:@"index"];
197   web::nscoder_util::EncodeString(aCoder, @"virtualUrlString",
198                                   _navigationItem->GetVirtualURL().spec());
199   web::nscoder_util::EncodeString(aCoder, @"referrerUrlString",
200                                   _navigationItem->GetReferrer().url.spec());
201   [aCoder encodeInt:_navigationItem->GetReferrer().policy
202              forKey:@"referrerPolicy"];
203   [aCoder encodeInt64:_navigationItem->GetTimestamp().ToInternalValue()
204                forKey:@"timestamp"];
206   [aCoder encodeObject:base::SysUTF16ToNSString(_navigationItem->GetTitle())
207                 forKey:@"title"];
208   [aCoder encodeObject:[[self class] dictionaryFromScrollState:
209                                          _navigationItem->GetPageScrollState()]
210                 forKey:@"state"];
211   [aCoder encodeBool:self.useDesktopUserAgent forKey:@"useDesktopUserAgent"];
212   [aCoder encodeBool:self.usedDataReductionProxy
213               forKey:@"usedDataReductionProxy"];
214   [aCoder encodeObject:self.httpHeaders forKey:@"httpHeaders"];
215   [aCoder encodeObject:self.POSTData forKey:@"POSTData"];
216   [aCoder encodeBool:self.skipResubmitDataConfirmation
217               forKey:@"skipResubmitDataConfirmation"];
220 // TODO(ios): Shall we overwrite EqualTo:?
222 - (instancetype)copyWithZone:(NSZone*)zone {
223   CRWSessionEntry* copy = [[[self class] alloc] init];
224   copy->_propertyReleaser_CRWSessionEntry.Init(copy, [CRWSessionEntry class]);
225   copy->_navigationItem.reset(
226       new web::NavigationItemImpl(*_navigationItem.get()));
227   copy->_index = _index;
228   copy->_originalUrl = _originalUrl;
229   copy->_useDesktopUserAgent = _useDesktopUserAgent;
230   copy->_usedDataReductionProxy = _usedDataReductionProxy;
231   copy->_POSTData = [_POSTData copy];
232   copy->_httpHeaders.reset([_httpHeaders mutableCopy]);
233   copy->_skipResubmitDataConfirmation = _skipResubmitDataConfirmation;
234   return copy;
237 - (NSString*)description {
238   return [NSString
239       stringWithFormat:
240           @"url:%@ originalurl:%@ title:%@ transition:%d scrollState:%@ "
241           @"desktopUA:%d " @"proxy:%d",
242           base::SysUTF8ToNSString(_navigationItem->GetURL().spec()),
243           base::SysUTF8ToNSString(self.originalUrl.spec()),
244           base::SysUTF16ToNSString(_navigationItem->GetTitle()),
245           _navigationItem->GetTransitionType(),
246           [[self class]
247               scrollStateDescription:_navigationItem->GetPageScrollState()],
248           _useDesktopUserAgent, _usedDataReductionProxy];
251 - (web::NavigationItem*)navigationItem {
252   return _navigationItem.get();
255 - (NSDictionary*)httpHeaders {
256   return _httpHeaders ? [NSDictionary dictionaryWithDictionary:_httpHeaders]
257                       : nil;
260 - (void)addHTTPHeaders:(NSDictionary*)moreHTTPHeaders {
261   if (_httpHeaders)
262     [_httpHeaders addEntriesFromDictionary:moreHTTPHeaders];
263   else
264     _httpHeaders.reset([moreHTTPHeaders mutableCopy]);
267 - (void)removeHTTPHeaderForKey:(NSString*)key {
268   [_httpHeaders removeObjectForKey:key];
269   if (![_httpHeaders count])
270     _httpHeaders.reset();
273 - (void)resetHTTPHeaders {
274   _httpHeaders.reset();
277 #pragma mark - Serialization helpers
279 + (web::PageScrollState)scrollStateFromDictionary:(NSDictionary*)dictionary {
280   web::PageScrollState scrollState;
281   NSNumber* serializedValue = nil;
282   if ((serializedValue = dictionary[kScrollOffsetXKey]))
283     scrollState.set_scroll_offset_x([serializedValue doubleValue]);
284   if ((serializedValue = dictionary[kScrollOffsetYKey]))
285     scrollState.set_scroll_offset_y([serializedValue doubleValue]);
286   if ((serializedValue = dictionary[kMinimumZoomScaleKey]))
287     scrollState.set_minimum_zoom_scale([serializedValue doubleValue]);
288   if ((serializedValue = dictionary[kMaximumZoomScaleKey]))
289     scrollState.set_maximum_zoom_scale([serializedValue doubleValue]);
290   if ((serializedValue = dictionary[kZoomScaleKey]))
291     scrollState.set_zoom_scale([serializedValue doubleValue]);
292   return scrollState;
295 + (NSDictionary*)dictionaryFromScrollState:
296     (const web::PageScrollState&)scrollState {
297   return @{
298     kScrollOffsetXKey : @(scrollState.scroll_offset_x()),
299     kScrollOffsetYKey : @(scrollState.scroll_offset_y()),
300     kMinimumZoomScaleKey : @(scrollState.minimum_zoom_scale()),
301     kMaximumZoomScaleKey : @(scrollState.maximum_zoom_scale()),
302     kZoomScaleKey : @(scrollState.zoom_scale())
303   };
306 + (NSString*)scrollStateDescription:(const web::PageScrollState&)scrollState {
307   NSString* const kPageScrollStateDescriptionFormat =
308       @"{ scrollOffset:(%0.2f, %0.2f), zoomScaleRange:(%0.2f, %0.2f), "
309       @"zoomScale:%0.2f }";
310   return [NSString stringWithFormat:kPageScrollStateDescriptionFormat,
311                                     scrollState.scroll_offset_x(),
312                                     scrollState.scroll_offset_y(),
313                                     scrollState.minimum_zoom_scale(),
314                                     scrollState.maximum_zoom_scale(),
315                                     scrollState.zoom_scale()];
318 @end