Switch remaining users of Document::inPageCache() to pageCacheState()
[WebKit-https.git] / Source / WebCore / history / HistoryItem.cpp
index c59dbab..c82f159 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2005, 2006, 2008, 2011 Apple Inc. All rights reserved.
+ * Copyright (C) 2005, 2006, 2008, 2011, 2014 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
  *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 #include "CachedPage.h"
 #include "Document.h"
 #include "IconDatabase.h"
+#include "KeyedCoding.h"
 #include "PageCache.h"
 #include "ResourceRequest.h"
 #include "SerializedScriptValue.h"
 #include "SharedBuffer.h"
 #include <stdio.h>
 #include <wtf/CurrentTime.h>
-#include <wtf/Decoder.h>
-#include <wtf/Encoder.h>
-#include <wtf/MathExtras.h>
+#include <wtf/DateMath.h>
 #include <wtf/text/CString.h>
 
 namespace WebCore {
 
-const uint32_t backForwardTreeEncodingVersion = 2;
-
 static long long generateSequenceNumber()
 {
     // Initialize to the current time to reduce the likelihood of generating
@@ -56,79 +53,47 @@ static void defaultNotifyHistoryItemChanged(HistoryItem*)
 {
 }
 
-void (*notifyHistoryItemChanged)(HistoryItem*) = defaultNotifyHistoryItemChanged;
+WEBCORE_EXPORT void (*notifyHistoryItemChanged)(HistoryItem*) = defaultNotifyHistoryItemChanged;
 
 HistoryItem::HistoryItem()
-    : m_lastVisitedTime(0)
-    , m_lastVisitWasHTTPNonGet(false)
-    , m_pageScaleFactor(0)
+    : m_pageScaleFactor(0)
     , m_lastVisitWasFailure(false)
     , m_isTargetItem(false)
-    , m_visitCount(0)
     , m_itemSequenceNumber(generateSequenceNumber())
     , m_documentSequenceNumber(generateSequenceNumber())
-    , m_next(0)
-    , m_prev(0)
+    , m_pruningReason(PruningReason::None)
 {
 }
 
-HistoryItem::HistoryItem(const String& urlString, const String& title, double time)
+HistoryItem::HistoryItem(const String& urlString, const String& title)
     : m_urlString(urlString)
     , m_originalURLString(urlString)
     , m_title(title)
-    , m_lastVisitedTime(time)
-    , m_lastVisitWasHTTPNonGet(false)
     , m_pageScaleFactor(0)
     , m_lastVisitWasFailure(false)
     , m_isTargetItem(false)
-    , m_visitCount(0)
     , m_itemSequenceNumber(generateSequenceNumber())
     , m_documentSequenceNumber(generateSequenceNumber())
-    , m_next(0)
-    , m_prev(0)
-{    
+    , m_pruningReason(PruningReason::None)
+{
     iconDatabase().retainIconForPageURL(m_urlString);
 }
 
-HistoryItem::HistoryItem(const String& urlString, const String& title, const String& alternateTitle, double time)
+HistoryItem::HistoryItem(const String& urlString, const String& title, const String& alternateTitle)
     : m_urlString(urlString)
     , m_originalURLString(urlString)
     , m_title(title)
     , m_displayTitle(alternateTitle)
-    , m_lastVisitedTime(time)
-    , m_lastVisitWasHTTPNonGet(false)
     , m_pageScaleFactor(0)
     , m_lastVisitWasFailure(false)
     , m_isTargetItem(false)
-    , m_visitCount(0)
     , m_itemSequenceNumber(generateSequenceNumber())
     , m_documentSequenceNumber(generateSequenceNumber())
-    , m_next(0)
-    , m_prev(0)
+    , m_pruningReason(PruningReason::None)
 {
     iconDatabase().retainIconForPageURL(m_urlString);
 }
 
-HistoryItem::HistoryItem(const KURL& url, const String& target, const String& parent, const String& title)
-    : m_urlString(url.string())
-    , m_originalURLString(url.string())
-    , m_target(target)
-    , m_parent(parent)
-    , m_title(title)
-    , m_lastVisitedTime(0)
-    , m_lastVisitWasHTTPNonGet(false)
-    , m_pageScaleFactor(0)
-    , m_lastVisitWasFailure(false)
-    , m_isTargetItem(false)
-    , m_visitCount(0)
-    , m_itemSequenceNumber(generateSequenceNumber())
-    , m_documentSequenceNumber(generateSequenceNumber())
-    , m_next(0)
-    , m_prev(0)
-{    
-    iconDatabase().retainIconForPageURL(m_urlString);
-}
-
 HistoryItem::~HistoryItem()
 {
     ASSERT(!m_cachedPage);
@@ -141,21 +106,23 @@ inline HistoryItem::HistoryItem(const HistoryItem& item)
     , m_originalURLString(item.m_originalURLString)
     , m_referrer(item.m_referrer)
     , m_target(item.m_target)
-    , m_parent(item.m_parent)
     , m_title(item.m_title)
     , m_displayTitle(item.m_displayTitle)
-    , m_lastVisitedTime(item.m_lastVisitedTime)
-    , m_lastVisitWasHTTPNonGet(item.m_lastVisitWasHTTPNonGet)
-    , m_scrollPoint(item.m_scrollPoint)
+    , m_scrollPosition(item.m_scrollPosition)
     , m_pageScaleFactor(item.m_pageScaleFactor)
     , m_lastVisitWasFailure(item.m_lastVisitWasFailure)
     , m_isTargetItem(item.m_isTargetItem)
-    , m_visitCount(item.m_visitCount)
-    , m_dailyVisitCounts(item.m_dailyVisitCounts)
-    , m_weeklyVisitCounts(item.m_weeklyVisitCounts)
     , m_itemSequenceNumber(item.m_itemSequenceNumber)
     , m_documentSequenceNumber(item.m_documentSequenceNumber)
     , m_formContentType(item.m_formContentType)
+    , m_pruningReason(PruningReason::None)
+#if PLATFORM(IOS)
+    , m_obscuredInset(item.m_obscuredInset)
+    , m_scale(item.m_scale)
+    , m_scaleIsInitial(item.m_scaleIsInitial)
+    , m_bookmarkID(item.m_bookmarkID)
+    , m_sharedLinkUniqueIdentifier(item.m_sharedLinkUniqueIdentifier)
+#endif
 {
     if (item.m_formData)
         m_formData = item.m_formData->copy();
@@ -166,12 +133,12 @@ inline HistoryItem::HistoryItem(const HistoryItem& item)
         m_children.uncheckedAppend(item.m_children[i]->copy());
 
     if (item.m_redirectURLs)
-        m_redirectURLs = adoptPtr(new Vector<String>(*item.m_redirectURLs));
+        m_redirectURLs = std::make_unique<Vector<String>>(*item.m_redirectURLs);
 }
 
-PassRefPtr<HistoryItem> HistoryItem::copy() const
+Ref<HistoryItem> HistoryItem::copy() const
 {
-    return adoptRef(new HistoryItem(*this));
+    return adoptRef(*new HistoryItem(*this));
 }
 
 void HistoryItem::reset()
@@ -182,27 +149,20 @@ void HistoryItem::reset()
     m_originalURLString = String();
     m_referrer = String();
     m_target = String();
-    m_parent = String();
     m_title = String();
     m_displayTitle = String();
 
-    m_lastVisitedTime = 0;
-    m_lastVisitWasHTTPNonGet = false;
-
     m_lastVisitWasFailure = false;
     m_isTargetItem = false;
-    m_visitCount = 0;
-    m_dailyVisitCounts.clear();
-    m_weeklyVisitCounts.clear();
 
-    m_redirectURLs.clear();
+    m_redirectURLs = nullptr;
 
     m_itemSequenceNumber = generateSequenceNumber();
 
-    m_stateObject = 0;
+    m_stateObject = nullptr;
     m_documentSequenceNumber = generateSequenceNumber();
 
-    m_formData = 0;
+    m_formData = nullptr;
     m_formContentType = String();
 
     clearChildren();
@@ -230,19 +190,19 @@ const String& HistoryItem::alternateTitle() const
     return m_displayTitle;
 }
 
-double HistoryItem::lastVisitedTime() const
+bool HistoryItem::hasCachedPageExpired() const
 {
-    return m_lastVisitedTime;
+    return m_cachedPage ? m_cachedPage->hasExpired() : false;
 }
 
-KURL HistoryItem::url() const
+URL HistoryItem::url() const
 {
-    return KURL(ParsedURLString, m_urlString);
+    return URL(ParsedURLString, m_urlString);
 }
 
-KURL HistoryItem::originalURL() const
+URL HistoryItem::originalURL() const
 {
-    return KURL(ParsedURLString, m_originalURLString);
+    return URL(ParsedURLString, m_originalURLString);
 }
 
 const String& HistoryItem::referrer() const
@@ -255,11 +215,6 @@ const String& HistoryItem::target() const
     return m_target;
 }
 
-const String& HistoryItem::parent() const
-{
-    return m_parent;
-}
-
 void HistoryItem::setAlternateTitle(const String& alternateTitle)
 {
     m_displayTitle = alternateTitle;
@@ -277,9 +232,9 @@ void HistoryItem::setURLString(const String& urlString)
     notifyHistoryItemChanged(this);
 }
 
-void HistoryItem::setURL(const KURL& url)
+void HistoryItem::setURL(const URL& url)
 {
-    pageCache()->remove(this);
+    PageCache::singleton().remove(*this);
     setURLString(url.string());
     clearDocumentState();
 }
@@ -308,114 +263,19 @@ void HistoryItem::setTarget(const String& target)
     notifyHistoryItemChanged(this);
 }
 
-void HistoryItem::setParent(const String& parent)
+const IntPoint& HistoryItem::scrollPosition() const
 {
-    m_parent = parent;
+    return m_scrollPosition;
 }
 
-static inline int timeToDay(double time)
+void HistoryItem::setScrollPosition(const IntPoint& position)
 {
-    static const double secondsPerDay = 60 * 60 * 24;
-    return static_cast<int>(ceil(time / secondsPerDay));
+    m_scrollPosition = position;
 }
 
-void HistoryItem::padDailyCountsForNewVisit(double time)
+void HistoryItem::clearScrollPosition()
 {
-    if (m_dailyVisitCounts.isEmpty())
-        m_dailyVisitCounts.prepend(m_visitCount);
-
-    int daysElapsed = timeToDay(time) - timeToDay(m_lastVisitedTime);
-
-    if (daysElapsed < 0)
-      daysElapsed = 0;
-
-    Vector<int> padding;
-    padding.fill(0, daysElapsed);
-    m_dailyVisitCounts.prepend(padding);
-}
-
-static const size_t daysPerWeek = 7;
-static const size_t maxDailyCounts = 2 * daysPerWeek - 1;
-static const size_t maxWeeklyCounts = 5;
-
-void HistoryItem::collapseDailyVisitsToWeekly()
-{
-    while (m_dailyVisitCounts.size() > maxDailyCounts) {
-        int oldestWeekTotal = 0;
-        for (size_t i = 0; i < daysPerWeek; i++)
-            oldestWeekTotal += m_dailyVisitCounts[m_dailyVisitCounts.size() - daysPerWeek + i];
-        m_dailyVisitCounts.shrink(m_dailyVisitCounts.size() - daysPerWeek);
-        m_weeklyVisitCounts.prepend(oldestWeekTotal);
-    }
-
-    if (m_weeklyVisitCounts.size() > maxWeeklyCounts)
-        m_weeklyVisitCounts.shrink(maxWeeklyCounts);
-}
-
-void HistoryItem::recordVisitAtTime(double time, VisitCountBehavior visitCountBehavior)
-{
-    padDailyCountsForNewVisit(time);
-
-    m_lastVisitedTime = time;
-
-    if (visitCountBehavior == IncreaseVisitCount) {
-        ++m_visitCount;
-        ++m_dailyVisitCounts[0];
-    }
-
-    collapseDailyVisitsToWeekly();
-}
-
-void HistoryItem::setLastVisitedTime(double time)
-{
-    if (m_lastVisitedTime != time)
-        recordVisitAtTime(time);
-}
-
-void HistoryItem::visited(const String& title, double time, VisitCountBehavior visitCountBehavior)
-{
-    m_title = title;
-    recordVisitAtTime(time, visitCountBehavior);
-}
-
-int HistoryItem::visitCount() const
-{
-    return m_visitCount;
-}
-
-void HistoryItem::recordInitialVisit()
-{
-    ASSERT(!m_visitCount);
-    recordVisitAtTime(m_lastVisitedTime);
-}
-
-void HistoryItem::setVisitCount(int count)
-{
-    m_visitCount = count;
-}
-
-void HistoryItem::adoptVisitCounts(Vector<int>& dailyCounts, Vector<int>& weeklyCounts)
-{
-    m_dailyVisitCounts.clear();
-    m_dailyVisitCounts.swap(dailyCounts);
-    m_weeklyVisitCounts.clear();
-    m_weeklyVisitCounts.swap(weeklyCounts);
-}
-
-const IntPoint& HistoryItem::scrollPoint() const
-{
-    return m_scrollPoint;
-}
-
-void HistoryItem::setScrollPoint(const IntPoint& point)
-{
-    m_scrollPoint = point;
-}
-
-void HistoryItem::clearScrollPoint()
-{
-    m_scrollPoint.setX(0);
-    m_scrollPoint.setY(0);
+    m_scrollPosition = IntPoint();
 }
 
 float HistoryItem::pageScaleFactor() const
@@ -443,6 +303,16 @@ void HistoryItem::clearDocumentState()
     m_documentState.clear();
 }
 
+void HistoryItem::setShouldOpenExternalURLsPolicy(ShouldOpenExternalURLsPolicy policy)
+{
+    m_shouldOpenExternalURLsPolicy = policy;
+}
+
+ShouldOpenExternalURLsPolicy HistoryItem::shouldOpenExternalURLsPolicy() const
+{
+    return m_shouldOpenExternalURLsPolicy;
+}
+
 bool HistoryItem::isTargetItem() const
 {
     return m_isTargetItem;
@@ -453,68 +323,49 @@ void HistoryItem::setIsTargetItem(bool flag)
     m_isTargetItem = flag;
 }
 
-void HistoryItem::setStateObject(PassRefPtr<SerializedScriptValue> object)
+void HistoryItem::setStateObject(RefPtr<SerializedScriptValue>&& object)
 {
-    m_stateObject = object;
+    m_stateObject = WTFMove(object);
 }
 
-void HistoryItem::addChildItem(PassRefPtr<HistoryItem> child)
+void HistoryItem::addChildItem(Ref<HistoryItem>&& child)
 {
     ASSERT(!childItemWithTarget(child->target()));
-    m_children.append(child);
+    m_children.append(WTFMove(child));
 }
 
-void HistoryItem::setChildItem(PassRefPtr<HistoryItem> child)
+void HistoryItem::setChildItem(Ref<HistoryItem>&& child)
 {
     ASSERT(!child->isTargetItem());
     unsigned size = m_children.size();
     for (unsigned i = 0; i < size; ++i)  {
         if (m_children[i]->target() == child->target()) {
             child->setIsTargetItem(m_children[i]->isTargetItem());
-            m_children[i] = child;
+            m_children[i] = WTFMove(child);
             return;
         }
     }
-    m_children.append(child);
+    m_children.append(WTFMove(child));
 }
 
-HistoryItem* HistoryItem::childItemWithTarget(const String& target) const
+HistoryItem* HistoryItem::childItemWithTarget(const String& target)
 {
     unsigned size = m_children.size();
     for (unsigned i = 0; i < size; ++i) {
         if (m_children[i]->target() == target)
-            return m_children[i].get();
+            return m_children[i].ptr();
     }
-    return 0;
+    return nullptr;
 }
 
-HistoryItem* HistoryItem::childItemWithDocumentSequenceNumber(long long number) const
+HistoryItem* HistoryItem::childItemWithDocumentSequenceNumber(long long number)
 {
     unsigned size = m_children.size();
     for (unsigned i = 0; i < size; ++i) {
         if (m_children[i]->documentSequenceNumber() == number)
-            return m_children[i].get();
-    }
-    return 0;
-}
-
-// <rdar://problem/4895849> HistoryItem::findTargetItem() should be replaced with a non-recursive method.
-HistoryItem* HistoryItem::findTargetItem()
-{
-    if (m_isTargetItem)
-        return this;
-    unsigned size = m_children.size();
-    for (unsigned i = 0; i < size; ++i) {
-        if (HistoryItem* match = m_children[i]->targetItem())
-            return match;
+            return m_children[i].ptr();
     }
-    return 0;
-}
-
-HistoryItem* HistoryItem::targetItem()
-{
-    HistoryItem* foundItem = findTargetItem();
-    return foundItem ? foundItem : this;
+    return nullptr;
 }
 
 const HistoryItemVector& HistoryItem::children() const
@@ -532,37 +383,49 @@ void HistoryItem::clearChildren()
     m_children.clear();
 }
 
+bool HistoryItem::isAncestorOf(const HistoryItem& item) const
+{
+    for (size_t i = 0; i < m_children.size(); ++i) {
+        auto& child = m_children[i].get();
+        if (&child == &item)
+            return true;
+        if (child.isAncestorOf(item))
+            return true;
+    }
+    return false;
+}
+
 // We do same-document navigation if going to a different item and if either of the following is true:
 // - The other item corresponds to the same document (for history entries created via pushState or fragment changes).
 // - The other item corresponds to the same set of documents, including frames (for history entries created via regular navigation)
-bool HistoryItem::shouldDoSameDocumentNavigationTo(HistoryItem* otherItem) const
+bool HistoryItem::shouldDoSameDocumentNavigationTo(HistoryItem& otherItem) const
 {
-    if (this == otherItem)
+    if (this == &otherItem)
         return false;
 
-    if (stateObject() || otherItem->stateObject())
-        return documentSequenceNumber() == otherItem->documentSequenceNumber();
+    if (stateObject() || otherItem.stateObject())
+        return documentSequenceNumber() == otherItem.documentSequenceNumber();
     
-    if ((url().hasFragmentIdentifier() || otherItem->url().hasFragmentIdentifier()) && equalIgnoringFragmentIdentifier(url(), otherItem->url()))
-        return documentSequenceNumber() == otherItem->documentSequenceNumber();        
+    if ((url().hasFragmentIdentifier() || otherItem.url().hasFragmentIdentifier()) && equalIgnoringFragmentIdentifier(url(), otherItem.url()))
+        return documentSequenceNumber() == otherItem.documentSequenceNumber();
     
     return hasSameDocumentTree(otherItem);
 }
 
 // Does a recursive check that this item and its descendants have the same
 // document sequence numbers as the other item.
-bool HistoryItem::hasSameDocumentTree(HistoryItem* otherItem) const
+bool HistoryItem::hasSameDocumentTree(HistoryItem& otherItem) const
 {
-    if (documentSequenceNumber() != otherItem->documentSequenceNumber())
+    if (documentSequenceNumber() != otherItem.documentSequenceNumber())
         return false;
         
-    if (children().size() != otherItem->children().size())
+    if (children().size() != otherItem.children().size())
         return false;
 
     for (size_t i = 0; i < children().size(); i++) {
-        HistoryItem* child = children()[i].get();
-        HistoryItem* otherChild = otherItem->childItemWithDocumentSequenceNumber(child->documentSequenceNumber());
-        if (!otherChild || !child->hasSameDocumentTree(otherChild))
+        auto& child = children()[i].get();
+        auto* otherChild = otherItem.childItemWithDocumentSequenceNumber(child.documentSequenceNumber());
+        if (!otherChild || !child.hasSameDocumentTree(*otherChild))
             return false;
     }
 
@@ -571,16 +434,16 @@ bool HistoryItem::hasSameDocumentTree(HistoryItem* otherItem) const
 
 // Does a non-recursive check that this item and its immediate children have the
 // same frames as the other item.
-bool HistoryItem::hasSameFrames(HistoryItem* otherItem) const
+bool HistoryItem::hasSameFrames(HistoryItem& otherItem) const
 {
-    if (target() != otherItem->target())
+    if (target() != otherItem.target())
         return false;
         
-    if (children().size() != otherItem->children().size())
+    if (children().size() != otherItem.children().size())
         return false;
 
     for (size_t i = 0; i < children().size(); i++) {
-        if (!otherItem->childItemWithTarget(children()[i]->target()))
+        if (!otherItem.childItemWithTarget(children()[i]->target()))
             return false;
     }
 
@@ -596,20 +459,20 @@ void HistoryItem::setFormInfoFromRequest(const ResourceRequest& request)
 {
     m_referrer = request.httpReferrer();
     
-    if (equalIgnoringCase(request.httpMethod(), "POST")) {
+    if (equalLettersIgnoringASCIICase(request.httpMethod(), "post")) {
         // FIXME: Eventually we have to make this smart enough to handle the case where
         // we have a stream for the body to handle the "data interspersed with files" feature.
         m_formData = request.httpBody();
         m_formContentType = request.httpContentType();
     } else {
-        m_formData = 0;
+        m_formData = nullptr;
         m_formContentType = String();
     }
 }
 
-void HistoryItem::setFormData(PassRefPtr<FormData> formData)
+void HistoryItem::setFormData(RefPtr<FormData>&& formData)
 {
-    m_formData = formData;
+    m_formData = WTFMove(formData);
 }
 
 void HistoryItem::setFormContentType(const String& formContentType)
@@ -622,26 +485,16 @@ FormData* HistoryItem::formData()
     return m_formData.get();
 }
 
-bool HistoryItem::isCurrentDocument(Document* doc) const
+bool HistoryItem::isCurrentDocument(Document& document) const
 {
     // FIXME: We should find a better way to check if this is the current document.
-    return equalIgnoringFragmentIdentifier(url(), doc->url());
-}
-
-void HistoryItem::mergeAutoCompleteHints(HistoryItem* otherItem)
-{
-    // FIXME: this is broken - we should be merging the daily counts
-    // somehow.  but this is to support API that's not really used in
-    // practice so leave it broken for now.
-    ASSERT(otherItem);
-    if (otherItem != this)
-        m_visitCount += otherItem->m_visitCount;
+    return equalIgnoringFragmentIdentifier(url(), document.url());
 }
 
 void HistoryItem::addRedirectURL(const String& url)
 {
     if (!m_redirectURLs)
-        m_redirectURLs = adoptPtr(new Vector<String>);
+        m_redirectURLs = std::make_unique<Vector<String>>();
 
     // Our API allows us to store all the URLs in the redirect chain, but for
     // now we only have a use for the final URL.
@@ -654,202 +507,14 @@ Vector<String>* HistoryItem::redirectURLs() const
     return m_redirectURLs.get();
 }
 
-void HistoryItem::setRedirectURLs(PassOwnPtr<Vector<String> > redirectURLs)
+void HistoryItem::setRedirectURLs(std::unique_ptr<Vector<String>> redirectURLs)
 {
-    m_redirectURLs = redirectURLs;
-}
-
-void HistoryItem::encodeBackForwardTree(Encoder& encoder) const
-{
-    encoder.encodeUInt32(backForwardTreeEncodingVersion);
-
-    encodeBackForwardTreeNode(encoder);
+    m_redirectURLs = WTFMove(redirectURLs);
 }
 
-void HistoryItem::encodeBackForwardTreeNode(Encoder& encoder) const
+void HistoryItem::notifyChanged()
 {
-    size_t size = m_children.size();
-    encoder.encodeUInt64(size);
-    for (size_t i = 0; i < size; ++i) {
-        const HistoryItem& child = *m_children[i];
-
-        encoder.encodeString(child.m_originalURLString);
-
-        encoder.encodeString(child.m_urlString);
-
-        child.encodeBackForwardTreeNode(encoder);
-    }
-
-    encoder.encodeInt64(m_documentSequenceNumber);
-
-    size = m_documentState.size();
-    encoder.encodeUInt64(size);
-    for (size_t i = 0; i < size; ++i)
-        encoder.encodeString(m_documentState[i]);
-
-    encoder.encodeString(m_formContentType);
-
-    encoder.encodeBool(m_formData);
-    if (m_formData)
-        m_formData->encodeForBackForward(encoder);
-
-    encoder.encodeInt64(m_itemSequenceNumber);
-
-    encoder.encodeString(m_referrer);
-
-    encoder.encodeInt32(m_scrollPoint.x());
-    encoder.encodeInt32(m_scrollPoint.y());
-    
-    encoder.encodeFloat(m_pageScaleFactor);
-
-    encoder.encodeBool(m_stateObject);
-    if (m_stateObject) {
-#if !USE(V8)
-        encoder.encodeBytes(m_stateObject->data().data(), m_stateObject->data().size());
-#else
-        encoder.encodeString(m_stateObject->toWireString());
-#endif
-    }
-
-    encoder.encodeString(m_target);
-}
-
-struct DecodeRecursionStackElement {
-    RefPtr<HistoryItem> node;
-    size_t i;
-    uint64_t size;
-
-    DecodeRecursionStackElement(PassRefPtr<HistoryItem> node, size_t i, uint64_t size)
-        : node(node)
-        , i(i)
-        , size(size)
-    {
-    }
-};
-
-PassRefPtr<HistoryItem> HistoryItem::decodeBackForwardTree(const String& topURLString, const String& topTitle, const String& topOriginalURLString, Decoder& decoder)
-{
-    // Since the data stream is not trusted, the decode has to be non-recursive.
-    // We don't want bad data to cause a stack overflow.
-
-    uint32_t version;
-    if (!decoder.decodeUInt32(version))
-        return 0;
-    if (version != backForwardTreeEncodingVersion)
-        return 0;
-
-    String urlString = topURLString;
-    String title = topTitle;
-    String originalURLString = topOriginalURLString;
-
-    Vector<DecodeRecursionStackElement, 16> recursionStack;
-
-recurse:
-    RefPtr<HistoryItem> node = create(urlString, title, 0);
-
-    node->setOriginalURLString(originalURLString);
-
-    title = String();
-
-    uint64_t size;
-    if (!decoder.decodeUInt64(size))
-        return 0;
-    size_t i;
-    RefPtr<HistoryItem> child;
-    for (i = 0; i < size; ++i) {
-        if (!decoder.decodeString(originalURLString))
-            return 0;
-
-        if (!decoder.decodeString(urlString))
-            return 0;
-
-        recursionStack.append(DecodeRecursionStackElement(node.release(), i, size));
-        goto recurse;
-
-resume:
-        node->m_children.append(child.release());
-    }
-
-    if (!decoder.decodeInt64(node->m_documentSequenceNumber))
-        return 0;
-
-    if (!decoder.decodeUInt64(size))
-        return 0;
-    for (i = 0; i < size; ++i) {
-        String state;
-        if (!decoder.decodeString(state))
-            return 0;
-        node->m_documentState.append(state);
-    }
-
-    if (!decoder.decodeString(node->m_formContentType))
-        return 0;
-
-    bool hasFormData;
-    if (!decoder.decodeBool(hasFormData))
-        return 0;
-    if (hasFormData) {
-        node->m_formData = FormData::decodeForBackForward(decoder);
-        if (!node->m_formData)
-            return 0;
-    }
-
-    if (!decoder.decodeInt64(node->m_itemSequenceNumber))
-        return 0;
-
-    if (!decoder.decodeString(node->m_referrer))
-        return 0;
-
-    int32_t x;
-    if (!decoder.decodeInt32(x))
-        return 0;
-    int32_t y;
-    if (!decoder.decodeInt32(y))
-        return 0;
-    node->m_scrollPoint = IntPoint(x, y);
-    
-    if (!decoder.decodeFloat(node->m_pageScaleFactor))
-        return 0;
-
-    bool hasStateObject;
-    if (!decoder.decodeBool(hasStateObject))
-        return 0;
-    if (hasStateObject) {
-#if !USE(V8)
-        Vector<uint8_t> bytes;
-        if (!decoder.decodeBytes(bytes))
-            return 0;
-        node->m_stateObject = SerializedScriptValue::adopt(bytes);
-#else
-        String string;
-        if (!decoder.decodeString(string))
-            return 0;
-        node->m_stateObject = SerializedScriptValue::createFromWire(string);
-#endif
-    }
-
-    if (!decoder.decodeString(node->m_target))
-        return 0;
-
-    // Simulate recursion with our own stack.
-    if (!recursionStack.isEmpty()) {
-        DecodeRecursionStackElement& element = recursionStack.last();
-        child = node.release();
-        node = element.node.release();
-        i = element.i;
-        size = element.size;
-        recursionStack.removeLast();
-        goto resume;
-    }
-
-    return node.release();
-}
-
-void HistoryItem::markForFullStyleRecalc()
-{
-    // Children are guaranteed not to have CachedPages.
-    if (m_cachedPage)
-        m_cachedPage->markForFullStyleRecalc();
+    notifyHistoryItemChanged(this);
 }
 
 #ifndef NDEBUG