📄 webhistory.cpp
字号:
{ HRESULT hr = S_OK; if (!entry) return E_FAIL; BSTR urlBStr = 0; hr = entry->URLString(&urlBStr); if (FAILED(hr)) return hr; RetainPtr<CFStringRef> urlString(AdoptCF, MarshallingHelpers::BSTRToCFStringRef(urlBStr)); SysFreeString(urlBStr); COMPtr<IWebHistoryItem> oldEntry((IWebHistoryItem*) CFDictionaryGetValue( m_entriesByURL.get(), urlString.get())); if (oldEntry) { if (discardDuplicate) { if (added) *added = false; return S_OK; } removeItemForURLString(urlString.get()); // If we already have an item with this URL, we need to merge info that drives the // URL autocomplete heuristics from that item into the new one. IWebHistoryItemPrivate* entryPriv; hr = entry->QueryInterface(IID_IWebHistoryItemPrivate, (void**)&entryPriv); if (SUCCEEDED(hr)) { entryPriv->mergeAutoCompleteHints(oldEntry.get()); entryPriv->Release(); } } hr = addItemToDateCaches(entry); if (FAILED(hr)) return hr; CFDictionarySetValue(m_entriesByURL.get(), urlString.get(), entry); CFDictionaryPropertyBag* userInfo = createUserInfoFromHistoryItem( getNotificationString(kWebHistoryItemsAddedNotification), entry); hr = postNotification(kWebHistoryItemsAddedNotification, userInfo); releaseUserInfo(userInfo); if (added) *added = true; return hr;}void WebHistory::visitedURL(const KURL& url, const String& title, const String& httpMethod, bool wasFailure){ RetainPtr<CFStringRef> urlString(AdoptCF, url.string().createCFString()); IWebHistoryItem* entry = (IWebHistoryItem*) CFDictionaryGetValue(m_entriesByURL.get(), urlString.get()); if (entry) { COMPtr<IWebHistoryItemPrivate> entryPrivate(Query, entry); if (!entryPrivate) return; // Remove the item from date caches before changing its last visited date. Otherwise we might get duplicate entries // as seen in <rdar://problem/6570573>. removeItemFromDateCaches(entry); entryPrivate->visitedWithTitle(BString(title)); } else { COMPtr<WebHistoryItem> item(AdoptCOM, WebHistoryItem::createInstance()); if (!item) return; entry = item.get(); SYSTEMTIME currentTime; GetSystemTime(¤tTime); DATE lastVisited; if (!SystemTimeToVariantTime(¤tTime, &lastVisited)) return; if (FAILED(entry->initWithURLString(BString(url.string()), BString(title), lastVisited))) return; item->recordInitialVisit(); CFDictionarySetValue(m_entriesByURL.get(), urlString.get(), entry); } addItemToDateCaches(entry); COMPtr<IWebHistoryItemPrivate> entryPrivate(Query, entry); if (!entryPrivate) return; entryPrivate->setLastVisitWasFailure(wasFailure); if (!httpMethod.isEmpty()) entryPrivate->setLastVisitWasHTTPNonGet(!equalIgnoringCase(httpMethod, "GET") && (url.protocolIs("http") || url.protocolIs("https"))); COMPtr<WebHistoryItem> item(Query, entry); item->historyItem()->setRedirectURLs(std::auto_ptr<Vector<String> >()); CFDictionaryPropertyBag* userInfo = createUserInfoFromHistoryItem( getNotificationString(kWebHistoryItemsAddedNotification), entry); postNotification(kWebHistoryItemsAddedNotification, userInfo); releaseUserInfo(userInfo);}HRESULT WebHistory::itemForURLString( /* [in] */ CFStringRef urlString, /* [retval][out] */ IWebHistoryItem** item) const{ if (!item) return E_FAIL; *item = 0; IWebHistoryItem* foundItem = (IWebHistoryItem*) CFDictionaryGetValue(m_entriesByURL.get(), urlString); if (!foundItem) return E_FAIL; foundItem->AddRef(); *item = foundItem; return S_OK;}HRESULT STDMETHODCALLTYPE WebHistory::itemForURL( /* [in] */ BSTR url, /* [retval][out] */ IWebHistoryItem** item){ RetainPtr<CFStringRef> urlString(AdoptCF, MarshallingHelpers::BSTRToCFStringRef(url)); return itemForURLString(urlString.get(), item);}HRESULT WebHistory::removeItemForURLString(CFStringRef urlString){ IWebHistoryItem* entry = (IWebHistoryItem*) CFDictionaryGetValue(m_entriesByURL.get(), urlString); if (!entry) return E_FAIL; HRESULT hr = removeItemFromDateCaches(entry); CFDictionaryRemoveValue(m_entriesByURL.get(), urlString); if (!CFDictionaryGetCount(m_entriesByURL.get())) PageGroup::removeAllVisitedLinks(); return hr;}COMPtr<IWebHistoryItem> WebHistory::itemForURLString(const String& urlString) const{ RetainPtr<CFStringRef> urlCFString(AdoptCF, urlString.createCFString()); if (!urlCFString) return 0; COMPtr<IWebHistoryItem> item; if (FAILED(itemForURLString(urlCFString.get(), &item))) return 0; return item;}HRESULT WebHistory::addItemToDateCaches(IWebHistoryItem* entry){ HRESULT hr = S_OK; DATE lastVisitedCOMTime; entry->lastVisitedTimeInterval(&lastVisitedCOMTime); CFAbsoluteTime lastVisitedDate = timeToDate(MarshallingHelpers::DATEToCFAbsoluteTime(lastVisitedCOMTime)); int dateIndex; if (findIndex(&dateIndex, lastVisitedDate)) { // other entries already exist for this date hr = insertItem(entry, dateIndex); } else { // no other entries exist for this date RetainPtr<CFNumberRef> lastVisitedDateRef(AdoptCF, CFNumberCreate(0, kCFNumberDoubleType, &lastVisitedDate)); CFArrayInsertValueAtIndex(m_datesWithEntries.get(), dateIndex, lastVisitedDateRef.get()); RetainPtr<CFMutableArrayRef> entryArray(AdoptCF, CFArrayCreateMutable(0, 0, &MarshallingHelpers::kIUnknownArrayCallBacks)); CFArrayAppendValue(entryArray.get(), entry); CFArrayInsertValueAtIndex(m_entriesByDate.get(), dateIndex, entryArray.get()); } return hr;}HRESULT WebHistory::removeItemFromDateCaches(IWebHistoryItem* entry){ HRESULT hr = S_OK; DATE lastVisitedCOMTime; entry->lastVisitedTimeInterval(&lastVisitedCOMTime); CFAbsoluteTime lastVisitedDate = timeToDate(MarshallingHelpers::DATEToCFAbsoluteTime(lastVisitedCOMTime)); int dateIndex; if (!findIndex(&dateIndex, lastVisitedDate)) return E_FAIL; CFMutableArrayRef entriesForDate = (CFMutableArrayRef) CFArrayGetValueAtIndex(m_entriesByDate.get(), dateIndex); CFIndex count = CFArrayGetCount(entriesForDate); for (int i = count - 1; i >= 0; --i) { if ((IWebHistoryItem*)CFArrayGetValueAtIndex(entriesForDate, i) == entry) CFArrayRemoveValueAtIndex(entriesForDate, i); } // remove this date entirely if there are no other entries on it if (CFArrayGetCount(entriesForDate) == 0) { CFArrayRemoveValueAtIndex(m_entriesByDate.get(), dateIndex); CFArrayRemoveValueAtIndex(m_datesWithEntries.get(), dateIndex); } return hr;}// Returns whether the day is already in the list of days,// and fills in *index with the found or proposed index.bool WebHistory::findIndex(int* index, CFAbsoluteTime forDay){ CFAbsoluteTime forDayInDays = timeToDate(forDay); //FIXME: just does linear search through days; inefficient if many days int count = CFArrayGetCount(m_datesWithEntries.get()); for (*index = 0; *index < count; ++*index) { CFNumberRef entryTimeNumberRef = (CFNumberRef) CFArrayGetValueAtIndex(m_datesWithEntries.get(), *index); CFAbsoluteTime entryTime; CFNumberGetValue(entryTimeNumberRef, kCFNumberDoubleType, &entryTime); CFAbsoluteTime entryInDays = timeToDate(entryTime); if (areEqualOrClose(forDayInDays, entryInDays)) return true; else if (forDayInDays > entryInDays) return false; } return false;}HRESULT WebHistory::insertItem(IWebHistoryItem* entry, int dateIndex){ HRESULT hr = S_OK; if (!entry) return E_FAIL; if (dateIndex < 0 || dateIndex >= CFArrayGetCount(m_entriesByDate.get())) return E_FAIL; //FIXME: just does linear search through entries; inefficient if many entries for this date DATE entryTime; entry->lastVisitedTimeInterval(&entryTime); CFMutableArrayRef entriesForDate = (CFMutableArrayRef) CFArrayGetValueAtIndex(m_entriesByDate.get(), dateIndex); int count = CFArrayGetCount(entriesForDate); // optimized for inserting oldest to youngest int index; for (index = 0; index < count; ++index) { IWebHistoryItem* indEntry = (IWebHistoryItem*) CFArrayGetValueAtIndex(entriesForDate, index); DATE indTime; hr = indEntry->lastVisitedTimeInterval(&indTime); if (FAILED(hr)) return hr; if (entryTime < indTime) break; } CFArrayInsertValueAtIndex(entriesForDate, index, entry); return S_OK;}CFAbsoluteTime WebHistory::timeToDate(CFAbsoluteTime time){ // can't just divide/round since the day boundaries depend on our current time zone const double secondsPerDay = 60 * 60 * 24; CFTimeZoneRef timeZone = CFTimeZoneCopySystem(); CFGregorianDate date = CFAbsoluteTimeGetGregorianDate(time, timeZone); date.hour = date.minute = 0; date.second = 0.0; CFAbsoluteTime timeInDays = CFGregorianDateGetAbsoluteTime(date, timeZone); if (areEqualOrClose(time - timeInDays, secondsPerDay)) timeInDays += secondsPerDay; return timeInDays;}// Return a date that marks the age limit for history entries saved to or// loaded from disk. Any entry older than this item should be rejected.HRESULT WebHistory::ageLimitDate(CFAbsoluteTime* time){ // get the current date as a CFAbsoluteTime CFAbsoluteTime currentDate = timeToDate(CFAbsoluteTimeGetCurrent()); CFGregorianUnits ageLimit = {0}; int historyLimitDays; HRESULT hr = historyAgeInDaysLimit(&historyLimitDays); if (FAILED(hr)) return hr; ageLimit.days = -historyLimitDays; *time = CFAbsoluteTimeAddGregorianUnits(currentDate, CFTimeZoneCopySystem(), ageLimit); return S_OK;}static void addVisitedLinkToPageGroup(const void* key, const void*, void* context){ CFStringRef url = static_cast<CFStringRef>(key); PageGroup* group = static_cast<PageGroup*>(context); CFIndex length = CFStringGetLength(url); const UChar* characters = reinterpret_cast<const UChar*>(CFStringGetCharactersPtr(url)); if (characters) group->addVisitedLink(characters, length); else { Vector<UChar, 512> buffer(length); CFStringGetCharacters(url, CFRangeMake(0, length), reinterpret_cast<UniChar*>(buffer.data())); group->addVisitedLink(buffer.data(), length); }}void WebHistory::addVisitedLinksToPageGroup(PageGroup& group){ CFDictionaryApplyFunction(m_entriesByURL.get(), addVisitedLinkToPageGroup, &group);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -