Replace WTF::move with WTFMove
[WebKit-https.git] / Source / WebCore / history / HistoryItem.cpp
1 /*
2  * Copyright (C) 2005, 2006, 2008, 2011, 2014 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  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25
26 #include "config.h"
27 #include "HistoryItem.h"
28
29 #include "CachedPage.h"
30 #include "Document.h"
31 #include "IconDatabase.h"
32 #include "KeyedCoding.h"
33 #include "PageCache.h"
34 #include "ResourceRequest.h"
35 #include "SerializedScriptValue.h"
36 #include "SharedBuffer.h"
37 #include <stdio.h>
38 #include <wtf/CurrentTime.h>
39 #include <wtf/DateMath.h>
40 #include <wtf/text/CString.h>
41
42 namespace WebCore {
43
44 static long long generateSequenceNumber()
45 {
46     // Initialize to the current time to reduce the likelihood of generating
47     // identifiers that overlap with those from past/future browser sessions.
48     static long long next = static_cast<long long>(currentTime() * 1000000.0);
49     return ++next;
50 }
51
52 static void defaultNotifyHistoryItemChanged(HistoryItem*)
53 {
54 }
55
56 WEBCORE_EXPORT void (*notifyHistoryItemChanged)(HistoryItem*) = defaultNotifyHistoryItemChanged;
57
58 HistoryItem::HistoryItem()
59     : m_pageScaleFactor(0)
60     , m_lastVisitWasFailure(false)
61     , m_isTargetItem(false)
62     , m_itemSequenceNumber(generateSequenceNumber())
63     , m_documentSequenceNumber(generateSequenceNumber())
64     , m_pruningReason(PruningReason::None)
65 #if PLATFORM(IOS)
66     , m_scale(0)
67     , m_scaleIsInitial(false)
68     , m_bookmarkID(0)
69 #endif
70 {
71 }
72
73 HistoryItem::HistoryItem(const String& urlString, const String& title)
74     : m_urlString(urlString)
75     , m_originalURLString(urlString)
76     , m_title(title)
77     , m_pageScaleFactor(0)
78     , m_lastVisitWasFailure(false)
79     , m_isTargetItem(false)
80     , m_itemSequenceNumber(generateSequenceNumber())
81     , m_documentSequenceNumber(generateSequenceNumber())
82     , m_pruningReason(PruningReason::None)
83 #if PLATFORM(IOS)
84     , m_scale(0)
85     , m_scaleIsInitial(false)
86     , m_bookmarkID(0)
87 #endif
88 {    
89     iconDatabase().retainIconForPageURL(m_urlString);
90 }
91
92 HistoryItem::HistoryItem(const String& urlString, const String& title, const String& alternateTitle)
93     : m_urlString(urlString)
94     , m_originalURLString(urlString)
95     , m_title(title)
96     , m_displayTitle(alternateTitle)
97     , m_pageScaleFactor(0)
98     , m_lastVisitWasFailure(false)
99     , m_isTargetItem(false)
100     , m_itemSequenceNumber(generateSequenceNumber())
101     , m_documentSequenceNumber(generateSequenceNumber())
102     , m_pruningReason(PruningReason::None)
103 #if PLATFORM(IOS)
104     , m_scale(0)
105     , m_scaleIsInitial(false)
106     , m_bookmarkID(0)
107 #endif
108 {
109     iconDatabase().retainIconForPageURL(m_urlString);
110 }
111
112 HistoryItem::~HistoryItem()
113 {
114     ASSERT(!m_cachedPage);
115     iconDatabase().releaseIconForPageURL(m_urlString);
116 }
117
118 inline HistoryItem::HistoryItem(const HistoryItem& item)
119     : RefCounted<HistoryItem>()
120     , m_urlString(item.m_urlString)
121     , m_originalURLString(item.m_originalURLString)
122     , m_referrer(item.m_referrer)
123     , m_target(item.m_target)
124     , m_title(item.m_title)
125     , m_displayTitle(item.m_displayTitle)
126     , m_scrollPosition(item.m_scrollPosition)
127     , m_pageScaleFactor(item.m_pageScaleFactor)
128     , m_lastVisitWasFailure(item.m_lastVisitWasFailure)
129     , m_isTargetItem(item.m_isTargetItem)
130     , m_itemSequenceNumber(item.m_itemSequenceNumber)
131     , m_documentSequenceNumber(item.m_documentSequenceNumber)
132     , m_formContentType(item.m_formContentType)
133     , m_pruningReason(PruningReason::None)
134 #if PLATFORM(IOS)
135     , m_scale(item.m_scale)
136     , m_scaleIsInitial(item.m_scaleIsInitial)
137     , m_bookmarkID(item.m_bookmarkID)
138     , m_sharedLinkUniqueIdentifier(item.m_sharedLinkUniqueIdentifier)
139 #endif
140 {
141     if (item.m_formData)
142         m_formData = item.m_formData->copy();
143         
144     unsigned size = item.m_children.size();
145     m_children.reserveInitialCapacity(size);
146     for (unsigned i = 0; i < size; ++i)
147         m_children.uncheckedAppend(item.m_children[i]->copy());
148
149     if (item.m_redirectURLs)
150         m_redirectURLs = std::make_unique<Vector<String>>(*item.m_redirectURLs);
151 }
152
153 Ref<HistoryItem> HistoryItem::copy() const
154 {
155     return adoptRef(*new HistoryItem(*this));
156 }
157
158 void HistoryItem::reset()
159 {
160     iconDatabase().releaseIconForPageURL(m_urlString);
161
162     m_urlString = String();
163     m_originalURLString = String();
164     m_referrer = String();
165     m_target = String();
166     m_title = String();
167     m_displayTitle = String();
168
169     m_lastVisitWasFailure = false;
170     m_isTargetItem = false;
171
172     m_redirectURLs = nullptr;
173
174     m_itemSequenceNumber = generateSequenceNumber();
175
176     m_stateObject = nullptr;
177     m_documentSequenceNumber = generateSequenceNumber();
178
179     m_formData = nullptr;
180     m_formContentType = String();
181
182     clearChildren();
183 }
184
185 const String& HistoryItem::urlString() const
186 {
187     return m_urlString;
188 }
189
190 // The first URL we loaded to get to where this history item points.  Includes both client
191 // and server redirects.
192 const String& HistoryItem::originalURLString() const
193 {
194     return m_originalURLString;
195 }
196
197 const String& HistoryItem::title() const
198 {
199     return m_title;
200 }
201
202 const String& HistoryItem::alternateTitle() const
203 {
204     return m_displayTitle;
205 }
206
207 bool HistoryItem::hasCachedPageExpired() const
208 {
209     return m_cachedPage ? m_cachedPage->hasExpired() : false;
210 }
211
212 URL HistoryItem::url() const
213 {
214     return URL(ParsedURLString, m_urlString);
215 }
216
217 URL HistoryItem::originalURL() const
218 {
219     return URL(ParsedURLString, m_originalURLString);
220 }
221
222 const String& HistoryItem::referrer() const
223 {
224     return m_referrer;
225 }
226
227 const String& HistoryItem::target() const
228 {
229     return m_target;
230 }
231
232 void HistoryItem::setAlternateTitle(const String& alternateTitle)
233 {
234     m_displayTitle = alternateTitle;
235     notifyHistoryItemChanged(this);
236 }
237
238 void HistoryItem::setURLString(const String& urlString)
239 {
240     if (m_urlString != urlString) {
241         iconDatabase().releaseIconForPageURL(m_urlString);
242         m_urlString = urlString;
243         iconDatabase().retainIconForPageURL(m_urlString);
244     }
245     
246     notifyHistoryItemChanged(this);
247 }
248
249 void HistoryItem::setURL(const URL& url)
250 {
251     PageCache::singleton().remove(*this);
252     setURLString(url.string());
253     clearDocumentState();
254 }
255
256 void HistoryItem::setOriginalURLString(const String& urlString)
257 {
258     m_originalURLString = urlString;
259     notifyHistoryItemChanged(this);
260 }
261
262 void HistoryItem::setReferrer(const String& referrer)
263 {
264     m_referrer = referrer;
265     notifyHistoryItemChanged(this);
266 }
267
268 void HistoryItem::setTitle(const String& title)
269 {
270     m_title = title;
271     notifyHistoryItemChanged(this);
272 }
273
274 void HistoryItem::setTarget(const String& target)
275 {
276     m_target = target;
277     notifyHistoryItemChanged(this);
278 }
279
280 const IntPoint& HistoryItem::scrollPosition() const
281 {
282     return m_scrollPosition;
283 }
284
285 void HistoryItem::setScrollPosition(const IntPoint& position)
286 {
287     m_scrollPosition = position;
288 }
289
290 void HistoryItem::clearScrollPosition()
291 {
292     m_scrollPosition = IntPoint();
293 }
294
295 float HistoryItem::pageScaleFactor() const
296 {
297     return m_pageScaleFactor;
298 }
299
300 void HistoryItem::setPageScaleFactor(float scaleFactor)
301 {
302     m_pageScaleFactor = scaleFactor;
303 }
304
305 void HistoryItem::setDocumentState(const Vector<String>& state)
306 {
307     m_documentState = state;
308 }
309
310 const Vector<String>& HistoryItem::documentState() const
311 {
312     return m_documentState;
313 }
314
315 void HistoryItem::clearDocumentState()
316 {
317     m_documentState.clear();
318 }
319
320 void HistoryItem::setShouldOpenExternalURLsPolicy(ShouldOpenExternalURLsPolicy policy)
321 {
322     m_shouldOpenExternalURLsPolicy = policy;
323 }
324
325 ShouldOpenExternalURLsPolicy HistoryItem::shouldOpenExternalURLsPolicy() const
326 {
327     return m_shouldOpenExternalURLsPolicy;
328 }
329
330 bool HistoryItem::isTargetItem() const
331 {
332     return m_isTargetItem;
333 }
334
335 void HistoryItem::setIsTargetItem(bool flag)
336 {
337     m_isTargetItem = flag;
338 }
339
340 void HistoryItem::setStateObject(RefPtr<SerializedScriptValue>&& object)
341 {
342     m_stateObject = WTFMove(object);
343 }
344
345 void HistoryItem::addChildItem(Ref<HistoryItem>&& child)
346 {
347     ASSERT(!childItemWithTarget(child->target()));
348     m_children.append(WTFMove(child));
349 }
350
351 void HistoryItem::setChildItem(Ref<HistoryItem>&& child)
352 {
353     ASSERT(!child->isTargetItem());
354     unsigned size = m_children.size();
355     for (unsigned i = 0; i < size; ++i)  {
356         if (m_children[i]->target() == child->target()) {
357             child->setIsTargetItem(m_children[i]->isTargetItem());
358             m_children[i] = WTFMove(child);
359             return;
360         }
361     }
362     m_children.append(WTFMove(child));
363 }
364
365 HistoryItem* HistoryItem::childItemWithTarget(const String& target)
366 {
367     unsigned size = m_children.size();
368     for (unsigned i = 0; i < size; ++i) {
369         if (m_children[i]->target() == target)
370             return m_children[i].ptr();
371     }
372     return nullptr;
373 }
374
375 HistoryItem* HistoryItem::childItemWithDocumentSequenceNumber(long long number)
376 {
377     unsigned size = m_children.size();
378     for (unsigned i = 0; i < size; ++i) {
379         if (m_children[i]->documentSequenceNumber() == number)
380             return m_children[i].ptr();
381     }
382     return nullptr;
383 }
384
385 const HistoryItemVector& HistoryItem::children() const
386 {
387     return m_children;
388 }
389
390 bool HistoryItem::hasChildren() const
391 {
392     return !m_children.isEmpty();
393 }
394
395 void HistoryItem::clearChildren()
396 {
397     m_children.clear();
398 }
399
400 bool HistoryItem::isAncestorOf(const HistoryItem& item) const
401 {
402     for (size_t i = 0; i < m_children.size(); ++i) {
403         auto& child = m_children[i].get();
404         if (&child == &item)
405             return true;
406         if (child.isAncestorOf(item))
407             return true;
408     }
409     return false;
410 }
411
412 // We do same-document navigation if going to a different item and if either of the following is true:
413 // - The other item corresponds to the same document (for history entries created via pushState or fragment changes).
414 // - The other item corresponds to the same set of documents, including frames (for history entries created via regular navigation)
415 bool HistoryItem::shouldDoSameDocumentNavigationTo(HistoryItem& otherItem) const
416 {
417     if (this == &otherItem)
418         return false;
419
420     if (stateObject() || otherItem.stateObject())
421         return documentSequenceNumber() == otherItem.documentSequenceNumber();
422     
423     if ((url().hasFragmentIdentifier() || otherItem.url().hasFragmentIdentifier()) && equalIgnoringFragmentIdentifier(url(), otherItem.url()))
424         return documentSequenceNumber() == otherItem.documentSequenceNumber();
425     
426     return hasSameDocumentTree(otherItem);
427 }
428
429 // Does a recursive check that this item and its descendants have the same
430 // document sequence numbers as the other item.
431 bool HistoryItem::hasSameDocumentTree(HistoryItem& otherItem) const
432 {
433     if (documentSequenceNumber() != otherItem.documentSequenceNumber())
434         return false;
435         
436     if (children().size() != otherItem.children().size())
437         return false;
438
439     for (size_t i = 0; i < children().size(); i++) {
440         auto& child = children()[i].get();
441         auto* otherChild = otherItem.childItemWithDocumentSequenceNumber(child.documentSequenceNumber());
442         if (!otherChild || !child.hasSameDocumentTree(*otherChild))
443             return false;
444     }
445
446     return true;
447 }
448
449 // Does a non-recursive check that this item and its immediate children have the
450 // same frames as the other item.
451 bool HistoryItem::hasSameFrames(HistoryItem& otherItem) const
452 {
453     if (target() != otherItem.target())
454         return false;
455         
456     if (children().size() != otherItem.children().size())
457         return false;
458
459     for (size_t i = 0; i < children().size(); i++) {
460         if (!otherItem.childItemWithTarget(children()[i]->target()))
461             return false;
462     }
463
464     return true;
465 }
466
467 String HistoryItem::formContentType() const
468 {
469     return m_formContentType;
470 }
471
472 void HistoryItem::setFormInfoFromRequest(const ResourceRequest& request)
473 {
474     m_referrer = request.httpReferrer();
475     
476     if (equalIgnoringCase(request.httpMethod(), "POST")) {
477         // FIXME: Eventually we have to make this smart enough to handle the case where
478         // we have a stream for the body to handle the "data interspersed with files" feature.
479         m_formData = request.httpBody();
480         m_formContentType = request.httpContentType();
481     } else {
482         m_formData = nullptr;
483         m_formContentType = String();
484     }
485 }
486
487 void HistoryItem::setFormData(RefPtr<FormData>&& formData)
488 {
489     m_formData = WTFMove(formData);
490 }
491
492 void HistoryItem::setFormContentType(const String& formContentType)
493 {
494     m_formContentType = formContentType;
495 }
496
497 FormData* HistoryItem::formData()
498 {
499     return m_formData.get();
500 }
501
502 bool HistoryItem::isCurrentDocument(Document& document) const
503 {
504     // FIXME: We should find a better way to check if this is the current document.
505     return equalIgnoringFragmentIdentifier(url(), document.url());
506 }
507
508 void HistoryItem::addRedirectURL(const String& url)
509 {
510     if (!m_redirectURLs)
511         m_redirectURLs = std::make_unique<Vector<String>>();
512
513     // Our API allows us to store all the URLs in the redirect chain, but for
514     // now we only have a use for the final URL.
515     (*m_redirectURLs).resize(1);
516     (*m_redirectURLs)[0] = url;
517 }
518
519 Vector<String>* HistoryItem::redirectURLs() const
520 {
521     return m_redirectURLs.get();
522 }
523
524 void HistoryItem::setRedirectURLs(std::unique_ptr<Vector<String>> redirectURLs)
525 {
526     m_redirectURLs = WTFMove(redirectURLs);
527 }
528
529 void HistoryItem::notifyChanged()
530 {
531     notifyHistoryItemChanged(this);
532 }
533
534 #ifndef NDEBUG
535
536 int HistoryItem::showTree() const
537 {
538     return showTreeWithIndent(0);
539 }
540
541 int HistoryItem::showTreeWithIndent(unsigned indentLevel) const
542 {
543     Vector<char> prefix;
544     for (unsigned i = 0; i < indentLevel; ++i)
545         prefix.append("  ", 2);
546     prefix.append("\0", 1);
547
548     fprintf(stderr, "%s+-%s (%p)\n", prefix.data(), m_urlString.utf8().data(), this);
549     
550     int totalSubItems = 0;
551     for (unsigned i = 0; i < m_children.size(); ++i)
552         totalSubItems += m_children[i]->showTreeWithIndent(indentLevel + 1);
553     return totalSubItems + 1;
554 }
555
556 #endif
557                 
558 } // namespace WebCore
559
560 #ifndef NDEBUG
561
562 int showTree(const WebCore::HistoryItem* item)
563 {
564     return item->showTree();
565 }
566
567 #endif