18e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project/*
28e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * Copyright (C) 2006, 2007 Apple Inc.  All rights reserved.
38e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *
48e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * Redistribution and use in source and binary forms, with or without
58e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * modification, are permitted provided that the following conditions
68e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * are met:
78e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * 1. Redistributions of source code must retain the above copyright
88e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *    notice, this list of conditions and the following disclaimer.
98e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * 2. Redistributions in binary form must reproduce the above copyright
108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *    notice, this list of conditions and the following disclaimer in the
118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *    documentation and/or other materials provided with the distribution.
128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *
138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project */
258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "config.h"
278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "WebKitDLL.h"
288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "WebHistory.h"
298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "CFDictionaryPropertyBag.h"
310bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch#include "MemoryStream.h"
328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "WebKit.h"
338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "MarshallingHelpers.h"
348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "WebHistoryItem.h"
358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "WebKit.h"
368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "WebNotificationCenter.h"
378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "WebPreferences.h"
388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include <CoreFoundation/CoreFoundation.h>
390bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch#include <WebCore/HistoryItem.h>
400bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch#include <WebCore/HistoryPropertyList.h>
418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include <WebCore/KURL.h>
428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include <WebCore/PageGroup.h>
430bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch#include <WebCore/SharedBuffer.h>
440bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch#include <functional>
45563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark#include <wtf/StdLibExtras.h>
460bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch#include <wtf/Vector.h>
478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectusing namespace WebCore;
490bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochusing namespace std;
508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectCFStringRef DatesArrayKey = CFSTR("WebHistoryDates");
528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectCFStringRef FileVersionKey = CFSTR("WebHistoryFileVersion");
538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#define currentFileVersion 1
558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
560bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochclass WebHistoryWriter : public HistoryPropertyListWriter {
570bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochpublic:
580bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    WebHistoryWriter(const WebHistory::DateToEntriesMap&);
590bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
600bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochprivate:
610bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    virtual void writeHistoryItems(BinaryPropertyListObjectStream&);
620bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
630bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    const WebHistory::DateToEntriesMap& m_entriesByDate;
640bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Vector<WebHistory::DateKey> m_dateKeys;
650bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch};
660bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
670bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben MurdochWebHistoryWriter::WebHistoryWriter(const WebHistory::DateToEntriesMap& entriesByDate)
680bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    : m_entriesByDate(entriesByDate)
690bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch{
700bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    copyKeysToVector(m_entriesByDate, m_dateKeys);
710bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    sort(m_dateKeys.begin(), m_dateKeys.end());
720bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch}
730bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
740bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochvoid WebHistoryWriter::writeHistoryItems(BinaryPropertyListObjectStream& stream)
750bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch{
760bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    for (int dateIndex = m_dateKeys.size() - 1; dateIndex >= 0; --dateIndex) {
770bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        // get the entries for that date
780bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        CFArrayRef entries = m_entriesByDate.get(m_dateKeys[dateIndex]).get();
790bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        CFIndex entriesCount = CFArrayGetCount(entries);
800bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        for (CFIndex j = entriesCount - 1; j >= 0; --j) {
810bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            IWebHistoryItem* item = (IWebHistoryItem*) CFArrayGetValueAtIndex(entries, j);
820bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            COMPtr<WebHistoryItem> webItem(Query, item);
830bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            if (!webItem)
840bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                continue;
850bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
860bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            writeHistoryItem(stream, webItem->historyItem());
870bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        }
880bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    }
890bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch}
900bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic bool areEqualOrClose(double d1, double d2)
928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    double diff = d1-d2;
948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return (diff < .000001 && diff > -.000001);
958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
97643ca7872b450ea4efacab6188849e5aac2ba161Steve Blockstatic COMPtr<CFDictionaryPropertyBag> createUserInfoFromArray(BSTR notificationStr, CFArrayRef arrayItem)
988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    RetainPtr<CFMutableDictionaryRef> dictionary(AdoptCF,
1008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
1018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    RetainPtr<CFStringRef> key(AdoptCF, MarshallingHelpers::BSTRToCFStringRef(notificationStr));
1038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CFDictionaryAddValue(dictionary.get(), key.get(), arrayItem);
1048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
105643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    COMPtr<CFDictionaryPropertyBag> result = CFDictionaryPropertyBag::createInstance();
1068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    result->setDictionary(dictionary.get());
1078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return result;
1088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
110643ca7872b450ea4efacab6188849e5aac2ba161Steve Blockstatic COMPtr<CFDictionaryPropertyBag> createUserInfoFromHistoryItem(BSTR notificationStr, IWebHistoryItem* item)
1118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
1128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // reference counting of item added to the array is managed by the CFArray value callbacks
1138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    RetainPtr<CFArrayRef> itemList(AdoptCF, CFArrayCreate(0, (const void**) &item, 1, &MarshallingHelpers::kIUnknownArrayCallBacks));
114643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    COMPtr<CFDictionaryPropertyBag> info = createUserInfoFromArray(notificationStr, itemList.get());
1158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return info;
1168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// WebHistory -----------------------------------------------------------------
1198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectWebHistory::WebHistory()
1218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project: m_refCount(0)
1228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project, m_preferences(0)
1238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
1248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    gClassCount++;
1258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    gClassNameCount.add("WebHistory");
1268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_entriesByURL.adoptCF(CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &MarshallingHelpers::kIUnknownDictionaryValueCallBacks));
1288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_preferences = WebPreferences::sharedStandardPreferences();
1308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectWebHistory::~WebHistory()
1338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
1348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    gClassCount--;
1358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    gClassNameCount.remove("WebHistory");
1368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectWebHistory* WebHistory::createInstance()
1398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
1408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    WebHistory* instance = new WebHistory();
1418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    instance->AddRef();
1428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return instance;
1438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectHRESULT WebHistory::postNotification(NotificationType notifyType, IPropertyBag* userInfo /*=0*/)
1468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
1478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    IWebNotificationCenter* nc = WebNotificationCenter::defaultCenterInternal();
1488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    HRESULT hr = nc->postNotificationName(getNotificationString(notifyType), static_cast<IWebHistory*>(this), userInfo);
1498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (FAILED(hr))
1508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return hr;
1518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return S_OK;
1538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectBSTR WebHistory::getNotificationString(NotificationType notifyType)
1568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
1578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    static BSTR keys[6] = {0};
1588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!keys[0]) {
1598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        keys[0] = SysAllocString(WebHistoryItemsAddedNotification);
1608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        keys[1] = SysAllocString(WebHistoryItemsRemovedNotification);
1618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        keys[2] = SysAllocString(WebHistoryAllItemsRemovedNotification);
1628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        keys[3] = SysAllocString(WebHistoryLoadedNotification);
1638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        keys[4] = SysAllocString(WebHistoryItemsDiscardedWhileLoadingNotification);
1648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        keys[5] = SysAllocString(WebHistorySavedNotification);
1658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
1668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return keys[notifyType];
1678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// IUnknown -------------------------------------------------------------------
1708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectHRESULT STDMETHODCALLTYPE WebHistory::QueryInterface(REFIID riid, void** ppvObject)
1728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
1738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    *ppvObject = 0;
1748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (IsEqualGUID(riid, CLSID_WebHistory))
1758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        *ppvObject = this;
1768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    else if (IsEqualGUID(riid, IID_IUnknown))
1778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        *ppvObject = static_cast<IWebHistory*>(this);
1788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    else if (IsEqualGUID(riid, IID_IWebHistory))
1798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        *ppvObject = static_cast<IWebHistory*>(this);
180635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    else if (IsEqualGUID(riid, IID_IWebHistoryPrivate))
181635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        *ppvObject = static_cast<IWebHistoryPrivate*>(this);
1828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    else
1838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return E_NOINTERFACE;
1848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    AddRef();
1868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return S_OK;
1878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectULONG STDMETHODCALLTYPE WebHistory::AddRef(void)
1908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
1918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return ++m_refCount;
1928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectULONG STDMETHODCALLTYPE WebHistory::Release(void)
1958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
1968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    ULONG newRef = --m_refCount;
1978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!newRef)
1988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        delete(this);
1998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return newRef;
2018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
2028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// IWebHistory ----------------------------------------------------------------
2048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic inline COMPtr<WebHistory>& sharedHistoryStorage()
2068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
207563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    DEFINE_STATIC_LOCAL(COMPtr<WebHistory>, sharedHistory, ());
2088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return sharedHistory;
2098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
2108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectWebHistory* WebHistory::sharedHistory()
2128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
2138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return sharedHistoryStorage().get();
2148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
2158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectHRESULT STDMETHODCALLTYPE WebHistory::optionalSharedHistory(
2178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* [retval][out] */ IWebHistory** history)
2188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
2198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    *history = sharedHistory();
2208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (*history)
2218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        (*history)->AddRef();
2228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return S_OK;
2238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
2248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectHRESULT STDMETHODCALLTYPE WebHistory::setOptionalSharedHistory(
2268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* [in] */ IWebHistory* history)
2278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
2288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (sharedHistoryStorage() == history)
2298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return S_OK;
2308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    sharedHistoryStorage().query(history);
2318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    PageGroup::setShouldTrackVisitedLinks(sharedHistoryStorage());
2328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    PageGroup::removeAllVisitedLinks();
2338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return S_OK;
2348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
2358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectHRESULT STDMETHODCALLTYPE WebHistory::loadFromURL(
2378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* [in] */ BSTR url,
2388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* [out] */ IWebError** error,
2398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* [retval][out] */ BOOL* succeeded)
2408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
2418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    HRESULT hr = S_OK;
2428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    RetainPtr<CFMutableArrayRef> discardedItems(AdoptCF,
2438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        CFArrayCreateMutable(0, 0, &MarshallingHelpers::kIUnknownArrayCallBacks));
2448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    RetainPtr<CFURLRef> urlRef(AdoptCF, MarshallingHelpers::BSTRToCFURLRef(url));
2468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    hr = loadHistoryGutsFromURL(urlRef.get(), discardedItems.get(), error);
2488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (FAILED(hr))
2498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        goto exit;
2508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    hr = postNotification(kWebHistoryLoadedNotification);
2528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (FAILED(hr))
2538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        goto exit;
2548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (CFArrayGetCount(discardedItems.get()) > 0) {
256643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        COMPtr<CFDictionaryPropertyBag> userInfo = createUserInfoFromArray(getNotificationString(kWebHistoryItemsDiscardedWhileLoadingNotification), discardedItems.get());
257643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        hr = postNotification(kWebHistoryItemsDiscardedWhileLoadingNotification, userInfo.get());
2588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (FAILED(hr))
2598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            goto exit;
2608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
2618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectexit:
2638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (succeeded)
2648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        *succeeded = SUCCEEDED(hr);
2658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return hr;
2668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
2678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic CFDictionaryRef createHistoryListFromStream(CFReadStreamRef stream, CFPropertyListFormat format)
2698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
2708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return (CFDictionaryRef)CFPropertyListCreateFromStream(0, stream, 0, kCFPropertyListImmutable, &format, 0);
2718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
2728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectHRESULT WebHistory::loadHistoryGutsFromURL(CFURLRef url, CFMutableArrayRef discardedItems, IWebError** /*error*/) //FIXME
2748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
2758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CFPropertyListFormat format = kCFPropertyListBinaryFormat_v1_0 | kCFPropertyListXMLFormat_v1_0;
2768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    HRESULT hr = S_OK;
2778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int numberOfItemsLoaded = 0;
2788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    RetainPtr<CFReadStreamRef> stream(AdoptCF, CFReadStreamCreateWithFile(0, url));
2808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!stream)
2818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return E_FAIL;
2828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!CFReadStreamOpen(stream.get()))
2848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return E_FAIL;
2858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    RetainPtr<CFDictionaryRef> historyList(AdoptCF, createHistoryListFromStream(stream.get(), format));
2878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CFReadStreamClose(stream.get());
2888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!historyList)
2908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return E_FAIL;
2918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CFNumberRef fileVersionObject = (CFNumberRef)CFDictionaryGetValue(historyList.get(), FileVersionKey);
2938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int fileVersion;
2948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!CFNumberGetValue(fileVersionObject, kCFNumberIntType, &fileVersion))
2958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return E_FAIL;
2968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (fileVersion > currentFileVersion)
2988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return E_FAIL;
2998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CFArrayRef datesArray = (CFArrayRef)CFDictionaryGetValue(historyList.get(), DatesArrayKey);
3018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int itemCountLimit;
3038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    hr = historyItemLimit(&itemCountLimit);
3048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (FAILED(hr))
3058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return hr;
3068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CFAbsoluteTime limitDate;
3088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    hr = ageLimitDate(&limitDate);
3098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (FAILED(hr))
3108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return hr;
3118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    bool ageLimitPassed = false;
3138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    bool itemLimitPassed = false;
3148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CFIndex itemCount = CFArrayGetCount(datesArray);
3168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    for (CFIndex i = 0; i < itemCount; ++i) {
3178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        CFDictionaryRef itemAsDictionary = (CFDictionaryRef)CFArrayGetValueAtIndex(datesArray, i);
3188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        COMPtr<WebHistoryItem> item(AdoptCOM, WebHistoryItem::createInstance());
3198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        hr = item->initFromDictionaryRepresentation((void*)itemAsDictionary);
3208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (FAILED(hr))
3218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            return hr;
3228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // item without URL is useless; data on disk must have been bad; ignore
3248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        BOOL hasURL;
3258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        hr = item->hasURLString(&hasURL);
3268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (FAILED(hr))
3278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            return hr;
3288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (hasURL) {
3308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            // Test against date limit. Since the items are ordered newest to oldest, we can stop comparing
3318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            // once we've found the first item that's too old.
3328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            if (!ageLimitPassed) {
3338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                DATE lastVisitedTime;
3348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                hr = item->lastVisitedTimeInterval(&lastVisitedTime);
3358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                if (FAILED(hr))
3368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                    return hr;
3378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                if (timeToDate(MarshallingHelpers::DATEToCFAbsoluteTime(lastVisitedTime)) <= limitDate)
3388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                    ageLimitPassed = true;
3398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            }
3408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            if (ageLimitPassed || itemLimitPassed)
3418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                CFArrayAppendValue(discardedItems, item.get());
3428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            else {
343635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                bool added;
344635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                addItem(item.get(), true, &added); // ref is added inside addItem
345635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                if (added)
346635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                    ++numberOfItemsLoaded;
3478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                if (numberOfItemsLoaded == itemCountLimit)
3488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                    itemLimitPassed = true;
3498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            }
3508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
3518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
3528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return hr;
3538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
3548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectHRESULT STDMETHODCALLTYPE WebHistory::saveToURL(
3568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* [in] */ BSTR url,
3578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* [out] */ IWebError** error,
3588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* [retval][out] */ BOOL* succeeded)
3598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
3608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    HRESULT hr = S_OK;
3618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    RetainPtr<CFURLRef> urlRef(AdoptCF, MarshallingHelpers::BSTRToCFURLRef(url));
3628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    hr = saveHistoryGuts(urlRef.get(), error);
3648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (succeeded)
3668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        *succeeded = SUCCEEDED(hr);
3678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (SUCCEEDED(hr))
3688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        hr = postNotification(kWebHistorySavedNotification);
3698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return hr;
3718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
3728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectHRESULT WebHistory::saveHistoryGuts(CFURLRef url, IWebError** error)
3748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
3758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    HRESULT hr = S_OK;
3768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3770bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    // FIXME: Correctly report error when new API is ready.
3788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (error)
3798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        *error = 0;
3808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3810bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    RetainPtr<CFDataRef> data = this->data();
3820bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
3838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    RetainPtr<CFWriteStreamRef> stream(AdoptCF, CFWriteStreamCreateWithFile(kCFAllocatorDefault, url));
3848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!stream)
3858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return E_FAIL;
3868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!CFWriteStreamOpen(stream.get()))
3888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return E_FAIL;
3898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3900bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    const UInt8* dataPtr = CFDataGetBytePtr(data.get());
3910bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    CFIndex length = CFDataGetLength(data.get());
3928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3930bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    while (length) {
3940bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        CFIndex bytesWritten = CFWriteStreamWrite(stream.get(), dataPtr, length);
3950bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if (bytesWritten <= 0) {
3960bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            hr = E_FAIL;
3970bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            break;
3988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
3990bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        dataPtr += bytesWritten;
4000bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        length -= bytesWritten;
4018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
4028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4030bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    CFWriteStreamClose(stream.get());
4040bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
4058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return hr;
4068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
4078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectHRESULT STDMETHODCALLTYPE WebHistory::addItems(
4098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* [in] */ int itemCount,
4108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* [in] */ IWebHistoryItem** items)
4118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
4128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // There is no guarantee that the incoming entries are in any particular
4138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // order, but if this is called with a set of entries that were created by
4148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // iterating through the results of orderedLastVisitedDays and orderedItemsLastVisitedOnDay
4158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // then they will be ordered chronologically from newest to oldest. We can make adding them
4168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // faster (fewer compares) by inserting them from oldest to newest.
4178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    HRESULT hr;
4198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    for (int i = itemCount - 1; i >= 0; --i) {
420635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        hr = addItem(items[i], false, 0);
4218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (FAILED(hr))
4228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            return hr;
4238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
4248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return S_OK;
4268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
4278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectHRESULT STDMETHODCALLTYPE WebHistory::removeItems(
4298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* [in] */ int itemCount,
4308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* [in] */ IWebHistoryItem** items)
4318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
4328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    HRESULT hr;
4338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    for (int i = 0; i < itemCount; ++i) {
4348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        hr = removeItem(items[i]);
4358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (FAILED(hr))
4368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            return hr;
4378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
4388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return S_OK;
4408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
4418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectHRESULT STDMETHODCALLTYPE WebHistory::removeAllItems( void)
4438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
4440bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    m_entriesByDate.clear();
4450bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    m_orderedLastVisitedDays.clear();
446635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
447635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    CFIndex itemCount = CFDictionaryGetCount(m_entriesByURL.get());
448635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    Vector<IWebHistoryItem*> itemsVector(itemCount);
449635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    CFDictionaryGetKeysAndValues(m_entriesByURL.get(), 0, (const void**)itemsVector.data());
450635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    RetainPtr<CFArrayRef> allItems(AdoptCF, CFArrayCreate(kCFAllocatorDefault, (const void**)itemsVector.data(), itemCount, &MarshallingHelpers::kIUnknownArrayCallBacks));
451635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
4528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CFDictionaryRemoveAllValues(m_entriesByURL.get());
4538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    PageGroup::removeAllVisitedLinks();
4558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
456643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    COMPtr<CFDictionaryPropertyBag> userInfo = createUserInfoFromArray(getNotificationString(kWebHistoryAllItemsRemovedNotification), allItems.get());
457643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    return postNotification(kWebHistoryAllItemsRemovedNotification, userInfo.get());
4588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
4598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectHRESULT STDMETHODCALLTYPE WebHistory::orderedLastVisitedDays(
4618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* [out][in] */ int* count,
4628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* [in] */ DATE* calendarDates)
4638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
4640bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    int dateCount = m_entriesByDate.size();
4658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!calendarDates) {
4668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        *count = dateCount;
4678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return S_OK;
4688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
4698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (*count < dateCount) {
4718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        *count = dateCount;
4728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return E_FAIL;
4738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
4748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    *count = dateCount;
4760bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if (!m_orderedLastVisitedDays) {
4772fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        m_orderedLastVisitedDays = adoptArrayPtr(new DATE[dateCount]);
4780bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        DateToEntriesMap::const_iterator::Keys end = m_entriesByDate.end().keys();
4790bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        int i = 0;
4800bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        for (DateToEntriesMap::const_iterator::Keys it = m_entriesByDate.begin().keys(); it != end; ++it, ++i)
4810bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            m_orderedLastVisitedDays[i] = MarshallingHelpers::CFAbsoluteTimeToDATE(*it);
4820bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        // Use std::greater to sort the days in descending order (i.e., most-recent first).
4830bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        sort(m_orderedLastVisitedDays.get(), m_orderedLastVisitedDays.get() + dateCount, greater<DATE>());
4848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
4858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4860bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    memcpy(calendarDates, m_orderedLastVisitedDays.get(), dateCount * sizeof(DATE));
4878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return S_OK;
4888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
4898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectHRESULT STDMETHODCALLTYPE WebHistory::orderedItemsLastVisitedOnDay(
4918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* [out][in] */ int* count,
4928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* [in] */ IWebHistoryItem** items,
4938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* [in] */ DATE calendarDate)
4948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
4950bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    DateKey dateKey;
4960bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if (!findKey(&dateKey, MarshallingHelpers::DATEToCFAbsoluteTime(calendarDate))) {
4978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        *count = 0;
4988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return 0;
4998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
5008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
5010bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    CFArrayRef entries = m_entriesByDate.get(dateKey).get();
5028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!entries) {
5038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        *count = 0;
5048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return 0;
5058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
5068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
5078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int newCount = CFArrayGetCount(entries);
5088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
5098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!items) {
5108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        *count = newCount;
5118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return S_OK;
5128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
5138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
5148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (*count < newCount) {
5158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        *count = newCount;
5168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return E_FAIL;
5178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
5188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
5198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    *count = newCount;
5208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    for (int i = 0; i < newCount; i++) {
5218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        IWebHistoryItem* item = (IWebHistoryItem*)CFArrayGetValueAtIndex(entries, i);
5228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        item->AddRef();
5230bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        items[i] = item;
5248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
5258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
5268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return S_OK;
5278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
5288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
529635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source ProjectHRESULT STDMETHODCALLTYPE WebHistory::allItems(
530635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    /* [out][in] */ int* count,
531635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    /* [out][retval] */ IWebHistoryItem** items)
532635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{
533635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    int entriesByURLCount = CFDictionaryGetCount(m_entriesByURL.get());
534635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
535635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (!items) {
536635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        *count = entriesByURLCount;
537635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        return S_OK;
538635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    }
539635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
540635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (*count < entriesByURLCount) {
541635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        *count = entriesByURLCount;
542635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        return E_FAIL;
543635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    }
544635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
545635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    *count = entriesByURLCount;
546635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    CFDictionaryGetKeysAndValues(m_entriesByURL.get(), 0, (const void**)items);
547635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    for (int i = 0; i < entriesByURLCount; i++)
548635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        items[i]->AddRef();
549635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
550635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    return S_OK;
551635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project}
552635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
5530bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben MurdochHRESULT WebHistory::data(IStream** stream)
5540bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch{
5550bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if (!stream)
5560bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        return E_POINTER;
5570bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
5580bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    *stream = 0;
5590bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
5600bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    RetainPtr<CFDataRef> historyData = data();
5610bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if (!historyData)
5620bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        return S_OK;
5630bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
5640bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    COMPtr<MemoryStream> result = MemoryStream::createInstance(SharedBuffer::wrapCFData(historyData.get()));
5650bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    return result.copyRefTo(stream);
5660bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch}
5670bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
568cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve BlockHRESULT WebHistory::setVisitedLinkTrackingEnabled(BOOL visitedLinkTrackingEnabled)
569cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block{
570cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block    PageGroup::setShouldTrackVisitedLinks(visitedLinkTrackingEnabled);
571cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block    return S_OK;
572cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block}
573cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block
574cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve BlockHRESULT WebHistory::removeAllVisitedLinks()
575cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block{
576cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block    PageGroup::removeAllVisitedLinks();
577cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block    return S_OK;
578cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block}
579cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block
5808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectHRESULT STDMETHODCALLTYPE WebHistory::setHistoryItemLimit(
5818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* [in] */ int limit)
5828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
5838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!m_preferences)
5848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return E_FAIL;
5858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return m_preferences->setHistoryItemLimit(limit);
5868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
5878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
5888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectHRESULT STDMETHODCALLTYPE WebHistory::historyItemLimit(
5898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* [retval][out] */ int* limit)
5908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
5918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!m_preferences)
5928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return E_FAIL;
5938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return m_preferences->historyItemLimit(limit);
5948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
5958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
5968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectHRESULT STDMETHODCALLTYPE WebHistory::setHistoryAgeInDaysLimit(
5978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* [in] */ int limit)
5988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
5998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!m_preferences)
6008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return E_FAIL;
6018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return m_preferences->setHistoryAgeInDaysLimit(limit);
6028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
6038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
6048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectHRESULT STDMETHODCALLTYPE WebHistory::historyAgeInDaysLimit(
6058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* [retval][out] */ int* limit)
6068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
6078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!m_preferences)
6088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return E_FAIL;
6098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return m_preferences->historyAgeInDaysLimit(limit);
6108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
6118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
6128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectHRESULT WebHistory::removeItem(IWebHistoryItem* entry)
6138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
6148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    HRESULT hr = S_OK;
6158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    BSTR urlBStr = 0;
6168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
6178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    hr = entry->URLString(&urlBStr);
6188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (FAILED(hr))
6198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return hr;
6208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
6218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    RetainPtr<CFStringRef> urlString(AdoptCF, MarshallingHelpers::BSTRToCFStringRef(urlBStr));
6228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    SysFreeString(urlBStr);
6238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
6248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // If this exact object isn't stored, then make no change.
6258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // FIXME: Is this the right behavior if this entry isn't present, but another entry for the same URL is?
6268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // Maybe need to change the API to make something like removeEntryForURLString public instead.
6278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    IWebHistoryItem *matchingEntry = (IWebHistoryItem*)CFDictionaryGetValue(m_entriesByURL.get(), urlString.get());
6288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (matchingEntry != entry)
6298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return E_FAIL;
6308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
6318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    hr = removeItemForURLString(urlString.get());
6328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (FAILED(hr))
6338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return hr;
6348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
635643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    COMPtr<CFDictionaryPropertyBag> userInfo = createUserInfoFromHistoryItem(
6368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        getNotificationString(kWebHistoryItemsRemovedNotification), entry);
637643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    hr = postNotification(kWebHistoryItemsRemovedNotification, userInfo.get());
6388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
6398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return hr;
6408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
6418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
642635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source ProjectHRESULT WebHistory::addItem(IWebHistoryItem* entry, bool discardDuplicate, bool* added)
6438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
6448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    HRESULT hr = S_OK;
6458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
6468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!entry)
6478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return E_FAIL;
6488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
6498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    BSTR urlBStr = 0;
6508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    hr = entry->URLString(&urlBStr);
6518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (FAILED(hr))
6528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return hr;
6538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
6548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    RetainPtr<CFStringRef> urlString(AdoptCF, MarshallingHelpers::BSTRToCFStringRef(urlBStr));
6558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    SysFreeString(urlBStr);
6568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
6578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    COMPtr<IWebHistoryItem> oldEntry((IWebHistoryItem*) CFDictionaryGetValue(
6588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        m_entriesByURL.get(), urlString.get()));
6598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
6608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (oldEntry) {
661635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        if (discardDuplicate) {
662635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            if (added)
663635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                *added = false;
664635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            return S_OK;
665635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        }
666635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
6678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        removeItemForURLString(urlString.get());
6688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
6698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // If we already have an item with this URL, we need to merge info that drives the
6708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // URL autocomplete heuristics from that item into the new one.
6718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        IWebHistoryItemPrivate* entryPriv;
6728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        hr = entry->QueryInterface(IID_IWebHistoryItemPrivate, (void**)&entryPriv);
6738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (SUCCEEDED(hr)) {
6748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            entryPriv->mergeAutoCompleteHints(oldEntry.get());
6758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            entryPriv->Release();
6768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
6778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
6788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
6798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    hr = addItemToDateCaches(entry);
6808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (FAILED(hr))
6818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return hr;
6828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
6838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CFDictionarySetValue(m_entriesByURL.get(), urlString.get(), entry);
6848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
685643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    COMPtr<CFDictionaryPropertyBag> userInfo = createUserInfoFromHistoryItem(
6868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        getNotificationString(kWebHistoryItemsAddedNotification), entry);
687643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    hr = postNotification(kWebHistoryItemsAddedNotification, userInfo.get());
6888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
689635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (added)
690635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        *added = true;
691635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
6928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return hr;
6938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
6948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
6950bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochvoid WebHistory::visitedURL(const KURL& url, const String& title, const String& httpMethod, bool wasFailure, bool increaseVisitCount)
6968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
697635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    RetainPtr<CFStringRef> urlString(AdoptCF, url.string().createCFString());
6988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
699635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    IWebHistoryItem* entry = (IWebHistoryItem*) CFDictionaryGetValue(m_entriesByURL.get(), urlString.get());
700635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (entry) {
701635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        COMPtr<IWebHistoryItemPrivate> entryPrivate(Query, entry);
702635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        if (!entryPrivate)
703635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            return;
704635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
705635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // Remove the item from date caches before changing its last visited date.  Otherwise we might get duplicate entries
706635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // as seen in <rdar://problem/6570573>.
707635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        removeItemFromDateCaches(entry);
7080bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        entryPrivate->visitedWithTitle(BString(title), increaseVisitCount);
709635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    } else {
710635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        COMPtr<WebHistoryItem> item(AdoptCOM, WebHistoryItem::createInstance());
711635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        if (!item)
712635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            return;
713635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
714635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        entry = item.get();
715635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
716635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        SYSTEMTIME currentTime;
717635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        GetSystemTime(&currentTime);
718635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        DATE lastVisited;
719635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        if (!SystemTimeToVariantTime(&currentTime, &lastVisited))
720635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            return;
721635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
722635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        if (FAILED(entry->initWithURLString(BString(url.string()), BString(title), lastVisited)))
723635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            return;
724635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
725635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        item->recordInitialVisit();
726635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
727635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        CFDictionarySetValue(m_entriesByURL.get(), urlString.get(), entry);
728635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    }
729635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
730635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    addItemToDateCaches(entry);
731635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
732635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    COMPtr<IWebHistoryItemPrivate> entryPrivate(Query, entry);
733635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (!entryPrivate)
7348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
7358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
736635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    entryPrivate->setLastVisitWasFailure(wasFailure);
737635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (!httpMethod.isEmpty())
7380bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        entryPrivate->setLastVisitWasHTTPNonGet(!equalIgnoringCase(httpMethod, "GET") && url.protocolInHTTPFamily());
739635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
740563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    COMPtr<WebHistoryItem> item(Query, entry);
7410bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    item->historyItem()->setRedirectURLs(0);
742635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
743643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    COMPtr<CFDictionaryPropertyBag> userInfo = createUserInfoFromHistoryItem(
744635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        getNotificationString(kWebHistoryItemsAddedNotification), entry);
745643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    postNotification(kWebHistoryItemsAddedNotification, userInfo.get());
746635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project}
747635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
7488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectHRESULT WebHistory::itemForURLString(
7498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* [in] */ CFStringRef urlString,
750563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    /* [retval][out] */ IWebHistoryItem** item) const
7518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
7528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!item)
7538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return E_FAIL;
7548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    *item = 0;
7558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
7568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    IWebHistoryItem* foundItem = (IWebHistoryItem*) CFDictionaryGetValue(m_entriesByURL.get(), urlString);
7578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!foundItem)
7588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return E_FAIL;
7598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
7608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    foundItem->AddRef();
7618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    *item = foundItem;
7628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return S_OK;
7638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
7648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
7658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectHRESULT STDMETHODCALLTYPE WebHistory::itemForURL(
7668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* [in] */ BSTR url,
7678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* [retval][out] */ IWebHistoryItem** item)
7688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
7698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    RetainPtr<CFStringRef> urlString(AdoptCF, MarshallingHelpers::BSTRToCFStringRef(url));
7708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return itemForURLString(urlString.get(), item);
7718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
7728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
7738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectHRESULT WebHistory::removeItemForURLString(CFStringRef urlString)
7748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
7758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    IWebHistoryItem* entry = (IWebHistoryItem*) CFDictionaryGetValue(m_entriesByURL.get(), urlString);
7768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!entry)
7778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return E_FAIL;
7788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
7798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    HRESULT hr = removeItemFromDateCaches(entry);
7808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CFDictionaryRemoveValue(m_entriesByURL.get(), urlString);
7818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
7828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!CFDictionaryGetCount(m_entriesByURL.get()))
7838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        PageGroup::removeAllVisitedLinks();
7848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
7858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return hr;
7868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
7878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
788563af33bc48281d19dce701398dbb88cb54fd7ecCary ClarkCOMPtr<IWebHistoryItem> WebHistory::itemForURLString(const String& urlString) const
789563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark{
790563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    RetainPtr<CFStringRef> urlCFString(AdoptCF, urlString.createCFString());
791563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    if (!urlCFString)
792563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark        return 0;
793563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    COMPtr<IWebHistoryItem> item;
794563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    if (FAILED(itemForURLString(urlCFString.get(), &item)))
795563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark        return 0;
796563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    return item;
797563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark}
798563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
7998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectHRESULT WebHistory::addItemToDateCaches(IWebHistoryItem* entry)
8008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
8018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    HRESULT hr = S_OK;
8028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
8038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    DATE lastVisitedCOMTime;
8048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    entry->lastVisitedTimeInterval(&lastVisitedCOMTime);
8058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
8060bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    DateKey dateKey;
8070bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if (findKey(&dateKey, MarshallingHelpers::DATEToCFAbsoluteTime(lastVisitedCOMTime))) {
8088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // other entries already exist for this date
8090bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        hr = insertItem(entry, dateKey);
8108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    } else {
8110bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        ASSERT(!m_entriesByDate.contains(dateKey));
8128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // no other entries exist for this date
8138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        RetainPtr<CFMutableArrayRef> entryArray(AdoptCF,
8148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            CFArrayCreateMutable(0, 0, &MarshallingHelpers::kIUnknownArrayCallBacks));
8158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        CFArrayAppendValue(entryArray.get(), entry);
8160bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        m_entriesByDate.set(dateKey, entryArray);
8170bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        // Clear m_orderedLastVisitedDays so it will be regenerated when next requested.
8180bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        m_orderedLastVisitedDays.clear();
8198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
8208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
8218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return hr;
8228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
8238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
8248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectHRESULT WebHistory::removeItemFromDateCaches(IWebHistoryItem* entry)
8258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
8268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    HRESULT hr = S_OK;
8278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
8288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    DATE lastVisitedCOMTime;
8298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    entry->lastVisitedTimeInterval(&lastVisitedCOMTime);
8308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
8310bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    DateKey dateKey;
8320bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if (!findKey(&dateKey, MarshallingHelpers::DATEToCFAbsoluteTime(lastVisitedCOMTime)))
8338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return E_FAIL;
8348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
8350bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    DateToEntriesMap::iterator found = m_entriesByDate.find(dateKey);
8360bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    ASSERT(found != m_entriesByDate.end());
8370bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    CFMutableArrayRef entriesForDate = found->second.get();
8380bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
8398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CFIndex count = CFArrayGetCount(entriesForDate);
8408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    for (int i = count - 1; i >= 0; --i) {
8418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if ((IWebHistoryItem*)CFArrayGetValueAtIndex(entriesForDate, i) == entry)
8428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            CFArrayRemoveValueAtIndex(entriesForDate, i);
8438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
8448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
8458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // remove this date entirely if there are no other entries on it
8468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (CFArrayGetCount(entriesForDate) == 0) {
8470bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        m_entriesByDate.remove(found);
8480bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        // Clear m_orderedLastVisitedDays so it will be regenerated when next requested.
8490bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        m_orderedLastVisitedDays.clear();
8508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
8518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
8528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return hr;
8538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
8548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
855231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Blockstatic void getDayBoundaries(CFAbsoluteTime day, CFAbsoluteTime& beginningOfDay, CFAbsoluteTime& beginningOfNextDay)
8560bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch{
8570bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    RetainPtr<CFTimeZoneRef> timeZone(AdoptCF, CFTimeZoneCopyDefault());
8580bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    CFGregorianDate date = CFAbsoluteTimeGetGregorianDate(day, timeZone.get());
8590bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    date.hour = 0;
8600bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    date.minute = 0;
8610bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    date.second = 0;
862231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    beginningOfDay = CFGregorianDateGetAbsoluteTime(date, timeZone.get());
863231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    date.day += 1;
864231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    beginningOfNextDay = CFGregorianDateGetAbsoluteTime(date, timeZone.get());
865231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block}
8660bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
867231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Blockstatic inline CFAbsoluteTime beginningOfDay(CFAbsoluteTime date)
868231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{
869231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    static CFAbsoluteTime cachedBeginningOfDay = numeric_limits<CFAbsoluteTime>::quiet_NaN();
870231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    static CFAbsoluteTime cachedBeginningOfNextDay;
871231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    if (!(date >= cachedBeginningOfDay && date < cachedBeginningOfNextDay))
872231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        getDayBoundaries(date, cachedBeginningOfDay, cachedBeginningOfNextDay);
873231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    return cachedBeginningOfDay;
874231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block}
875231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
876231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Blockstatic inline WebHistory::DateKey dateKey(CFAbsoluteTime date)
877231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{
878231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    // Converting from double (CFAbsoluteTime) to int64_t (WebHistoryDateKey) is
879231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    // safe here because all sensible dates are in the range -2**48 .. 2**47 which
880231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    // safely fits in an int64_t.
881231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    return beginningOfDay(date);
8820bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch}
8830bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
8848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// Returns whether the day is already in the list of days,
8850bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch// and fills in *key with the found or proposed key.
8860bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochbool WebHistory::findKey(DateKey* key, CFAbsoluteTime forDay)
8870bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch{
8880bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    ASSERT_ARG(key, key);
8890bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
890231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    *key = dateKey(forDay);
8910bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    return m_entriesByDate.contains(*key);
8928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
8938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
8940bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben MurdochHRESULT WebHistory::insertItem(IWebHistoryItem* entry, DateKey dateKey)
8958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
8960bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    ASSERT_ARG(entry, entry);
8970bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    ASSERT_ARG(dateKey, m_entriesByDate.contains(dateKey));
8980bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
8998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    HRESULT hr = S_OK;
9008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
9018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!entry)
9028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return E_FAIL;
9038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
9048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    DATE entryTime;
9058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    entry->lastVisitedTimeInterval(&entryTime);
9060bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    CFMutableArrayRef entriesForDate = m_entriesByDate.get(dateKey).get();
9070bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    unsigned count = CFArrayGetCount(entriesForDate);
9080bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
9090bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    // The entries for each day are stored in a sorted array with the most recent entry first
9100bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    // Check for the common cases of the entry being newer than all existing entries or the first entry of the day
9110bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    bool isNewerThanAllEntries = false;
9120bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if (count) {
9130bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        IWebHistoryItem* item = const_cast<IWebHistoryItem*>(static_cast<const IWebHistoryItem*>(CFArrayGetValueAtIndex(entriesForDate, 0)));
9140bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        DATE itemTime;
9150bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        isNewerThanAllEntries = SUCCEEDED(item->lastVisitedTimeInterval(&itemTime)) && itemTime < entryTime;
9160bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    }
9170bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if (!count || isNewerThanAllEntries) {
9180bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        CFArrayInsertValueAtIndex(entriesForDate, 0, entry);
9190bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        return S_OK;
9200bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    }
9210bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
9220bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    // .. or older than all existing entries
9230bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    bool isOlderThanAllEntries = false;
9240bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if (count > 0) {
9250bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        IWebHistoryItem* item = const_cast<IWebHistoryItem*>(static_cast<const IWebHistoryItem*>(CFArrayGetValueAtIndex(entriesForDate, count - 1)));
9260bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        DATE itemTime;
9270bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        isOlderThanAllEntries = SUCCEEDED(item->lastVisitedTimeInterval(&itemTime)) && itemTime >= entryTime;
9280bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    }
9290bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if (isOlderThanAllEntries) {
9300bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        CFArrayInsertValueAtIndex(entriesForDate, count, entry);
9310bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        return S_OK;
9320bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    }
9330bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
9340bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    unsigned low = 0;
9350bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    unsigned high = count;
9360bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    while (low < high) {
9370bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        unsigned mid = low + (high - low) / 2;
9380bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        IWebHistoryItem* item = const_cast<IWebHistoryItem*>(static_cast<const IWebHistoryItem*>(CFArrayGetValueAtIndex(entriesForDate, mid)));
9390bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        DATE itemTime;
9400bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if (FAILED(item->lastVisitedTimeInterval(&itemTime)))
9410bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            return E_FAIL;
9420bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
9430bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if (itemTime >= entryTime)
9440bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            low = mid + 1;
9450bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        else
9460bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            high = mid;
9470bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    }
9480bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
9490bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    // low is now the index of the first entry that is older than entryDate
9500bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    CFArrayInsertValueAtIndex(entriesForDate, low, entry);
9518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return S_OK;
9528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
9538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
9548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectCFAbsoluteTime WebHistory::timeToDate(CFAbsoluteTime time)
9558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
9568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // can't just divide/round since the day boundaries depend on our current time zone
9578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    const double secondsPerDay = 60 * 60 * 24;
9588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CFTimeZoneRef timeZone = CFTimeZoneCopySystem();
9598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CFGregorianDate date = CFAbsoluteTimeGetGregorianDate(time, timeZone);
9608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    date.hour = date.minute = 0;
9618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    date.second = 0.0;
9628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CFAbsoluteTime timeInDays = CFGregorianDateGetAbsoluteTime(date, timeZone);
9638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (areEqualOrClose(time - timeInDays, secondsPerDay))
9648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        timeInDays += secondsPerDay;
9658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return timeInDays;
9668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
9678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
9688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// Return a date that marks the age limit for history entries saved to or
9698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// loaded from disk. Any entry older than this item should be rejected.
9708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectHRESULT WebHistory::ageLimitDate(CFAbsoluteTime* time)
9718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
9728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // get the current date as a CFAbsoluteTime
9738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CFAbsoluteTime currentDate = timeToDate(CFAbsoluteTimeGetCurrent());
9748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
9758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CFGregorianUnits ageLimit = {0};
9768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int historyLimitDays;
9778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    HRESULT hr = historyAgeInDaysLimit(&historyLimitDays);
9788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (FAILED(hr))
9798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return hr;
9808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    ageLimit.days = -historyLimitDays;
9818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    *time = CFAbsoluteTimeAddGregorianUnits(currentDate, CFTimeZoneCopySystem(), ageLimit);
9828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return S_OK;
9838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
9848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
9858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic void addVisitedLinkToPageGroup(const void* key, const void*, void* context)
9868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
9878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CFStringRef url = static_cast<CFStringRef>(key);
9888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    PageGroup* group = static_cast<PageGroup*>(context);
9898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
9908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CFIndex length = CFStringGetLength(url);
9918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    const UChar* characters = reinterpret_cast<const UChar*>(CFStringGetCharactersPtr(url));
9928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (characters)
9938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        group->addVisitedLink(characters, length);
9948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    else {
9958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        Vector<UChar, 512> buffer(length);
9968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        CFStringGetCharacters(url, CFRangeMake(0, length), reinterpret_cast<UniChar*>(buffer.data()));
9978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        group->addVisitedLink(buffer.data(), length);
9988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
9998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
10008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
10018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid WebHistory::addVisitedLinksToPageGroup(PageGroup& group)
10028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
10038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CFDictionaryApplyFunction(m_entriesByURL.get(), addVisitedLinkToPageGroup, &group);
10048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
10050bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
10060bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben MurdochRetainPtr<CFDataRef> WebHistory::data() const
10070bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch{
10080bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if (m_entriesByDate.isEmpty())
10090bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        return 0;
10100bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
10110bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    WebHistoryWriter writer(m_entriesByDate);
10120bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    writer.writePropertyList();
10130bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    return writer.releaseData();
10140bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch}
1015