📄 webhistory.cpp
字号:
/* * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */#include "config.h"#include "WebKitDLL.h"#include "WebHistory.h"#include "CFDictionaryPropertyBag.h"#include "WebKit.h"#include "MarshallingHelpers.h"#include "WebHistoryItem.h"#include "WebKit.h"#include "WebNotificationCenter.h"#include "WebPreferences.h"#include <CoreFoundation/CoreFoundation.h>#pragma warning( push, 0 )#include <wtf/Vector.h>#include <WebCore/KURL.h>#include <WebCore/PageGroup.h>#include <WebCore/HistoryItem.h>#pragma warning( pop )#include <wtf/StdLibExtras.h>using namespace WebCore;CFStringRef DatesArrayKey = CFSTR("WebHistoryDates");CFStringRef FileVersionKey = CFSTR("WebHistoryFileVersion");#define currentFileVersion 1static bool areEqualOrClose(double d1, double d2){ double diff = d1-d2; return (diff < .000001 && diff > -.000001);}static CFDictionaryPropertyBag* createUserInfoFromArray(BSTR notificationStr, CFArrayRef arrayItem){ RetainPtr<CFMutableDictionaryRef> dictionary(AdoptCF, CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)); RetainPtr<CFStringRef> key(AdoptCF, MarshallingHelpers::BSTRToCFStringRef(notificationStr)); CFDictionaryAddValue(dictionary.get(), key.get(), arrayItem); CFDictionaryPropertyBag* result = CFDictionaryPropertyBag::createInstance(); result->setDictionary(dictionary.get()); return result;}static CFDictionaryPropertyBag* createUserInfoFromHistoryItem(BSTR notificationStr, IWebHistoryItem* item){ // reference counting of item added to the array is managed by the CFArray value callbacks RetainPtr<CFArrayRef> itemList(AdoptCF, CFArrayCreate(0, (const void**) &item, 1, &MarshallingHelpers::kIUnknownArrayCallBacks)); CFDictionaryPropertyBag* info = createUserInfoFromArray(notificationStr, itemList.get()); return info;}static void releaseUserInfo(CFDictionaryPropertyBag* userInfo){ // free the dictionary userInfo->setDictionary(0); int result = userInfo->Release(); (void)result; ASSERT(result == 0); // make sure no one else holds a reference to the userInfo.}// WebHistory -----------------------------------------------------------------WebHistory::WebHistory(): m_refCount(0), m_preferences(0){ gClassCount++; gClassNameCount.add("WebHistory"); m_entriesByURL.adoptCF(CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &MarshallingHelpers::kIUnknownDictionaryValueCallBacks)); m_datesWithEntries.adoptCF(CFArrayCreateMutable(0, 0, &kCFTypeArrayCallBacks)); m_entriesByDate.adoptCF(CFArrayCreateMutable(0, 0, &kCFTypeArrayCallBacks)); m_preferences = WebPreferences::sharedStandardPreferences();}WebHistory::~WebHistory(){ gClassCount--; gClassNameCount.remove("WebHistory");}WebHistory* WebHistory::createInstance(){ WebHistory* instance = new WebHistory(); instance->AddRef(); return instance;}HRESULT WebHistory::postNotification(NotificationType notifyType, IPropertyBag* userInfo /*=0*/){ IWebNotificationCenter* nc = WebNotificationCenter::defaultCenterInternal(); HRESULT hr = nc->postNotificationName(getNotificationString(notifyType), static_cast<IWebHistory*>(this), userInfo); if (FAILED(hr)) return hr; return S_OK;}BSTR WebHistory::getNotificationString(NotificationType notifyType){ static BSTR keys[6] = {0}; if (!keys[0]) { keys[0] = SysAllocString(WebHistoryItemsAddedNotification); keys[1] = SysAllocString(WebHistoryItemsRemovedNotification); keys[2] = SysAllocString(WebHistoryAllItemsRemovedNotification); keys[3] = SysAllocString(WebHistoryLoadedNotification); keys[4] = SysAllocString(WebHistoryItemsDiscardedWhileLoadingNotification); keys[5] = SysAllocString(WebHistorySavedNotification); } return keys[notifyType];}// IUnknown -------------------------------------------------------------------HRESULT STDMETHODCALLTYPE WebHistory::QueryInterface(REFIID riid, void** ppvObject){ *ppvObject = 0; if (IsEqualGUID(riid, CLSID_WebHistory)) *ppvObject = this; else if (IsEqualGUID(riid, IID_IUnknown)) *ppvObject = static_cast<IWebHistory*>(this); else if (IsEqualGUID(riid, IID_IWebHistory)) *ppvObject = static_cast<IWebHistory*>(this); else if (IsEqualGUID(riid, IID_IWebHistoryPrivate)) *ppvObject = static_cast<IWebHistoryPrivate*>(this); else return E_NOINTERFACE; AddRef(); return S_OK;}ULONG STDMETHODCALLTYPE WebHistory::AddRef(void){ return ++m_refCount;}ULONG STDMETHODCALLTYPE WebHistory::Release(void){ ULONG newRef = --m_refCount; if (!newRef) delete(this); return newRef;}// IWebHistory ----------------------------------------------------------------static inline COMPtr<WebHistory>& sharedHistoryStorage(){ DEFINE_STATIC_LOCAL(COMPtr<WebHistory>, sharedHistory, ()); return sharedHistory;}WebHistory* WebHistory::sharedHistory(){ return sharedHistoryStorage().get();}HRESULT STDMETHODCALLTYPE WebHistory::optionalSharedHistory( /* [retval][out] */ IWebHistory** history){ *history = sharedHistory(); if (*history) (*history)->AddRef(); return S_OK;}HRESULT STDMETHODCALLTYPE WebHistory::setOptionalSharedHistory( /* [in] */ IWebHistory* history){ if (sharedHistoryStorage() == history) return S_OK; sharedHistoryStorage().query(history); PageGroup::setShouldTrackVisitedLinks(sharedHistoryStorage()); PageGroup::removeAllVisitedLinks(); return S_OK;}HRESULT STDMETHODCALLTYPE WebHistory::loadFromURL( /* [in] */ BSTR url, /* [out] */ IWebError** error, /* [retval][out] */ BOOL* succeeded){ HRESULT hr = S_OK; RetainPtr<CFMutableArrayRef> discardedItems(AdoptCF, CFArrayCreateMutable(0, 0, &MarshallingHelpers::kIUnknownArrayCallBacks)); RetainPtr<CFURLRef> urlRef(AdoptCF, MarshallingHelpers::BSTRToCFURLRef(url)); hr = loadHistoryGutsFromURL(urlRef.get(), discardedItems.get(), error); if (FAILED(hr)) goto exit; hr = postNotification(kWebHistoryLoadedNotification); if (FAILED(hr)) goto exit; if (CFArrayGetCount(discardedItems.get()) > 0) { CFDictionaryPropertyBag* userInfo = createUserInfoFromArray(getNotificationString(kWebHistoryItemsDiscardedWhileLoadingNotification), discardedItems.get()); hr = postNotification(kWebHistoryItemsDiscardedWhileLoadingNotification, userInfo); releaseUserInfo(userInfo); if (FAILED(hr)) goto exit; }exit: if (succeeded) *succeeded = SUCCEEDED(hr); return hr;}static CFDictionaryRef createHistoryListFromStream(CFReadStreamRef stream, CFPropertyListFormat format){ return (CFDictionaryRef)CFPropertyListCreateFromStream(0, stream, 0, kCFPropertyListImmutable, &format, 0);}HRESULT WebHistory::loadHistoryGutsFromURL(CFURLRef url, CFMutableArrayRef discardedItems, IWebError** /*error*/) //FIXME{ CFPropertyListFormat format = kCFPropertyListBinaryFormat_v1_0 | kCFPropertyListXMLFormat_v1_0; HRESULT hr = S_OK; int numberOfItemsLoaded = 0; RetainPtr<CFReadStreamRef> stream(AdoptCF, CFReadStreamCreateWithFile(0, url)); if (!stream) return E_FAIL; if (!CFReadStreamOpen(stream.get())) return E_FAIL; RetainPtr<CFDictionaryRef> historyList(AdoptCF, createHistoryListFromStream(stream.get(), format)); CFReadStreamClose(stream.get()); if (!historyList) return E_FAIL; CFNumberRef fileVersionObject = (CFNumberRef)CFDictionaryGetValue(historyList.get(), FileVersionKey); int fileVersion; if (!CFNumberGetValue(fileVersionObject, kCFNumberIntType, &fileVersion)) return E_FAIL; if (fileVersion > currentFileVersion) return E_FAIL; CFArrayRef datesArray = (CFArrayRef)CFDictionaryGetValue(historyList.get(), DatesArrayKey); int itemCountLimit; hr = historyItemLimit(&itemCountLimit); if (FAILED(hr)) return hr; CFAbsoluteTime limitDate; hr = ageLimitDate(&limitDate); if (FAILED(hr)) return hr; bool ageLimitPassed = false; bool itemLimitPassed = false; CFIndex itemCount = CFArrayGetCount(datesArray); for (CFIndex i = 0; i < itemCount; ++i) { CFDictionaryRef itemAsDictionary = (CFDictionaryRef)CFArrayGetValueAtIndex(datesArray, i); COMPtr<WebHistoryItem> item(AdoptCOM, WebHistoryItem::createInstance()); hr = item->initFromDictionaryRepresentation((void*)itemAsDictionary); if (FAILED(hr)) return hr; // item without URL is useless; data on disk must have been bad; ignore BOOL hasURL; hr = item->hasURLString(&hasURL); if (FAILED(hr)) return hr; if (hasURL) { // Test against date limit. Since the items are ordered newest to oldest, we can stop comparing // once we've found the first item that's too old. if (!ageLimitPassed) { DATE lastVisitedTime; hr = item->lastVisitedTimeInterval(&lastVisitedTime); if (FAILED(hr)) return hr; if (timeToDate(MarshallingHelpers::DATEToCFAbsoluteTime(lastVisitedTime)) <= limitDate) ageLimitPassed = true; } if (ageLimitPassed || itemLimitPassed) CFArrayAppendValue(discardedItems, item.get());
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -