Commit 13d04dd5 authored by mjs@apple.com's avatar mjs@apple.com

WebCore:

2009-02-05  Maciej Stachowiak  <mjs@apple.com> and Brady Eidson  <beidson@apple.com>

        Reviewed by Dan Bernstein and Geoff Garen.

        - WebCore code to track per-day and per-week visit counts in history

        The basic idea is as follows: we track daily visits for up to 13
        days, and weekly visits for up to 5 weeks past the end of the
        current daily visits. As soon as the number of daily counts goes
        over 13, we squish them down into weeks, and then prune the excess weeks.

        * history/HistoryItem.cpp:
        (WebCore::HistoryItem::HistoryItem): Remove bogus whitespace.
        (WebCore::timeToDay): Helper function: convert time to days from the epoch.
        (WebCore::HistoryItem::padDailyCountsForNewVisit): Insert 0 counts if
        a site is visited after a span of days.
        (WebCore::HistoryItem::collapseDailyVisitsToWeekly): Core day/week upgrade
        algorithm as described above.
        (WebCore::HistoryItem::recordVisitAtTime): Use above helpers to record all
        info about a visit to this history item.
        (WebCore::HistoryItem::setLastVisitedTime): Updated.
        (WebCore::HistoryItem::visited): Updated.
        (WebCore::HistoryItem::recordInitialVisit): New function to
        handle recording data about the very first visit, replacing the
        prior practice of explicitly setting visit count to 1.
        (WebCore::HistoryItem::adoptVisitCounts): Take ownership of
        daily and weekly visit count vectors.
        (WebCore::HistoryItem::mergeAutoCompleteHints): Added a comment
        noting that this function doesn't work properly now (though
        this shouldn't matter much in practice.)
        * history/HistoryItem.h:
        (WebCore::HistoryItem::dailyVisitCounts): Accessor for daily counts.
        (WebCore::HistoryItem::weeklyVisitCounts): Ditto for weekly counts.
        * WebCore.base.exp: Add new symbols and sort.

WebKit/win:

2009-02-05  Maciej Stachowiak  <mjs@apple.com> and Brady Eidson  <beidson@apple.com>

        Reviewed by Dan Bernstein and Geoff Garen..

        - WebKit code to track per-day and per-week visit counts in history

        For now this data is only exposed via SPI for performance reasons.

        * Interfaces/IWebHistoryItemPrivate.idl: Added new interface.
        * WebHistory.cpp:
        (WebHistory::visitedURL): Use new recordInitialVisit method.
        * WebHistoryItem.cpp:
        (WebHistoryItem::initFromDictionaryRepresentation): Add parsing support
        for new data.
        (WebHistoryItem::dictionaryRepresentation): Add saving support for
        new data.
        (WebHistoryItem::getDailyVisitCounts): SPI accessor.
        (WebHistoryItem::getWeeklyVisitCounts): SPI accessor.
        (WebHistoryItem::recordInitialVisit): Tell WebCore to record an initial visit.
        * WebHistoryItem.h:



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@40712 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 5a4dc3cf
2009-02-05 Maciej Stachowiak <mjs@apple.com> and Brady Eidson <beidson@apple.com>
Reviewed by Dan Bernstein and Geoff Garen.
- WebCore code to track per-day and per-week visit counts in history
The basic idea is as follows: we track daily visits for up to 13
days, and weekly visits for up to 5 weeks past the end of the
current daily visits. As soon as the number of daily counts goes
over 13, we squish them down into weeks, and then prune the excess weeks.
* history/HistoryItem.cpp:
(WebCore::HistoryItem::HistoryItem): Remove bogus whitespace.
(WebCore::timeToDay): Helper function: convert time to days from the epoch.
(WebCore::HistoryItem::padDailyCountsForNewVisit): Insert 0 counts if
a site is visited after a span of days.
(WebCore::HistoryItem::collapseDailyVisitsToWeekly): Core day/week upgrade
algorithm as described above.
(WebCore::HistoryItem::recordVisitAtTime): Use above helpers to record all
info about a visit to this history item.
(WebCore::HistoryItem::setLastVisitedTime): Updated.
(WebCore::HistoryItem::visited): Updated.
(WebCore::HistoryItem::recordInitialVisit): New function to
handle recording data about the very first visit, replacing the
prior practice of explicitly setting visit count to 1.
(WebCore::HistoryItem::adoptVisitCounts): Take ownership of
daily and weekly visit count vectors.
(WebCore::HistoryItem::mergeAutoCompleteHints): Added a comment
noting that this function doesn't work properly now (though
this shouldn't matter much in practice.)
* history/HistoryItem.h:
(WebCore::HistoryItem::dailyVisitCounts): Accessor for daily counts.
(WebCore::HistoryItem::weeklyVisitCounts): Ditto for weekly counts.
* WebCore.base.exp: Add new symbols and sort.
2009-02-05 Alexey Proskuryakov <ap@webkit.org>
Reviewed by Darin Adler.
......@@ -181,7 +181,9 @@ __ZN7WebCore11HistoryItem14addRedirectURLERKNS_6StringE
__ZN7WebCore11HistoryItem14setScrollPointERKNS_8IntPointE
__ZN7WebCore11HistoryItem15setIsTargetItemEb
__ZN7WebCore11HistoryItem15setRedirectURLsESt8auto_ptrIN3WTF6VectorINS_6StringELm0EEEE
__ZN7WebCore11HistoryItem16adoptVisitCountsERN3WTF6VectorIiLm0EEES4_
__ZN7WebCore11HistoryItem17setAlternateTitleERKNS_6StringE
__ZN7WebCore11HistoryItem18recordInitialVisitEv
__ZN7WebCore11HistoryItem18setLastVisitedTimeEd
__ZN7WebCore11HistoryItem20setOriginalURLStringERKNS_6StringE
__ZN7WebCore11HistoryItem20setTransientPropertyERKNS_6StringEP11objc_object
......@@ -453,7 +455,9 @@ __ZN7WebCore4Page12setGroupNameERKNS_6StringE
__ZN7WebCore4Page14setMediaVolumeEf
__ZN7WebCore4Page15addSchedulePairEN3WTF10PassRefPtrINS_12SchedulePairEEE
__ZN7WebCore4Page15backForwardListEv
__ZN7WebCore4Page15didMoveOnscreenEv
__ZN7WebCore4Page16setDefersLoadingEb
__ZN7WebCore4Page17willMoveOffscreenEv
__ZN7WebCore4Page18removeSchedulePairEN3WTF10PassRefPtrINS_12SchedulePairEEE
__ZN7WebCore4Page23clearUndoRedoOperationsEv
__ZN7WebCore4Page23pendingUnloadEventCountEv
......@@ -813,8 +817,6 @@ __ZNK7WebCore4Node18getSubresourceURLsERN3WTF11ListHashSetINS_4KURLENS_8KURLHash
__ZNK7WebCore4Node9nodeIndexEv
__ZNK7WebCore4Page10pluginDataEv
__ZNK7WebCore4Page34inLowQualityImageInterpolationModeEv
__ZN7WebCore4Page17willMoveOffscreenEv
__ZN7WebCore4Page15didMoveOnscreenEv
__ZNK7WebCore4Page9groupNameEv
__ZNK7WebCore5Frame11currentFormEv
__ZNK7WebCore5Frame11typingStyleEv
......
......@@ -74,7 +74,7 @@ HistoryItem::HistoryItem(const String& urlString, const String& title, const Str
, m_lastVisitWasFailure(false)
, m_isTargetItem(false)
, m_visitCount(0)
{
{
iconDatabase()->retainIconForPageURL(m_urlString);
}
......@@ -114,6 +114,8 @@ inline HistoryItem::HistoryItem(const HistoryItem& item)
, m_lastVisitWasFailure(item.m_lastVisitWasFailure)
, m_isTargetItem(item.m_isTargetItem)
, m_visitCount(item.m_visitCount)
, m_dailyVisitCounts(item.m_dailyVisitCounts)
, m_weeklyVisitCounts(item.m_weeklyVisitCounts)
, m_formContentType(item.m_formContentType)
{
ASSERT(!item.m_cachedPage);
......@@ -246,19 +248,67 @@ void HistoryItem::setParent(const String& parent)
m_parent = parent;
}
void HistoryItem::setLastVisitedTime(double time)
static inline int timeToDay(double time)
{
if (m_lastVisitedTime != time) {
m_lastVisitedTime = time;
m_visitCount++;
static const double secondsPerDay = 60 * 60 * 24;
return static_cast<int>(ceil(time / secondsPerDay));
}
void HistoryItem::padDailyCountsForNewVisit(double time)
{
if (m_dailyVisitCounts.isEmpty())
m_dailyVisitCounts.prepend(m_visitCount);
int daysElapsed = timeToDay(time) - timeToDay(m_lastVisitedTime);
if (daysElapsed < 0)
daysElapsed = 0;
Vector<int> padding;
padding.fill(0, daysElapsed);
m_dailyVisitCounts.prepend(padding);
}
static const size_t daysPerWeek = 7;
static const size_t maxDailyCounts = 2 * daysPerWeek - 1;
static const size_t maxWeeklyCounts = 5;
void HistoryItem::collapseDailyVisitsToWeekly()
{
while (m_dailyVisitCounts.size() > maxDailyCounts) {
int oldestWeekTotal = 0;
for (size_t i = 0; i < daysPerWeek; i++)
oldestWeekTotal += m_dailyVisitCounts[m_dailyVisitCounts.size() - daysPerWeek + i];
m_dailyVisitCounts.shrink(m_dailyVisitCounts.size() - daysPerWeek);
m_weeklyVisitCounts.prepend(oldestWeekTotal);
}
if (m_weeklyVisitCounts.size() > maxWeeklyCounts)
m_weeklyVisitCounts.shrink(maxWeeklyCounts);
}
void HistoryItem::visited(const String& title, double time)
void HistoryItem::recordVisitAtTime(double time)
{
m_title = title;
padDailyCountsForNewVisit(time);
m_lastVisitedTime = time;
m_visitCount++;
m_dailyVisitCounts[0]++;
collapseDailyVisitsToWeekly();
}
void HistoryItem::setLastVisitedTime(double time)
{
if (m_lastVisitedTime != time)
recordVisitAtTime(time);
}
void HistoryItem::visited(const String& title, double time)
{
m_title = title;
recordVisitAtTime(time);
}
int HistoryItem::visitCount() const
......@@ -266,11 +316,25 @@ int HistoryItem::visitCount() const
return m_visitCount;
}
void HistoryItem::recordInitialVisit()
{
ASSERT(!m_visitCount);
recordVisitAtTime(m_lastVisitedTime);
}
void HistoryItem::setVisitCount(int count)
{
m_visitCount = count;
}
void HistoryItem::adoptVisitCounts(Vector<int>& dailyCounts, Vector<int>& weeklyCounts)
{
m_dailyVisitCounts.clear();
m_dailyVisitCounts.swap(dailyCounts);
m_weeklyVisitCounts.clear();
m_weeklyVisitCounts.swap(weeklyCounts);
}
const IntPoint& HistoryItem::scrollPoint() const
{
return m_scrollPoint;
......@@ -395,6 +459,9 @@ bool HistoryItem::isCurrentDocument(Document* doc) const
void HistoryItem::mergeAutoCompleteHints(HistoryItem* otherItem)
{
// FIXME: this is broken - we should be merging the daily counts
// somehow. but this is to support API that's not really used in
// practice so leave it broken for now.
ASSERT(otherItem);
if (otherItem != this)
m_visitCount += otherItem->m_visitCount;
......
......@@ -122,6 +122,7 @@ public:
void setFormInfoFromRequest(const ResourceRequest&);
void recordInitialVisit();
void setVisitCount(int);
void setLastVisitWasFailure(bool wasFailure) { m_lastVisitWasFailure = wasFailure; }
......@@ -165,6 +166,10 @@ public:
int showTreeWithIndent(unsigned indentLevel) const;
#endif
void adoptVisitCounts(Vector<int>& dailyCounts, Vector<int>& weeklyCounts);
const Vector<int>& dailyVisitCounts() { return m_dailyVisitCounts; }
const Vector<int>& weeklyVisitCounts() { return m_weeklyVisitCounts; }
private:
HistoryItem();
HistoryItem(const String& urlString, const String& title, double lastVisited);
......@@ -173,6 +178,10 @@ private:
HistoryItem(const HistoryItem&);
void padDailyCountsForNewVisit(double time);
void collapseDailyVisitsToWeekly();
void recordVisitAtTime(double);
String m_urlString;
String m_originalURLString;
String m_referrer;
......@@ -192,6 +201,8 @@ private:
bool m_lastVisitWasFailure;
bool m_isTargetItem;
int m_visitCount;
Vector<int> m_dailyVisitCounts;
Vector<int> m_weeklyVisitCounts;
OwnPtr<Vector<String> > m_redirectURLs;
......
2009-02-05 Maciej Stachowiak <mjs@apple.com> and Brady Eidson <beidson@apple.com>
Reviewed by Dan Bernstein and Geoff Garen..
- WebKit code to track per-day and per-week visit counts in history
For now this data is only exposed via SPI for performance reasons.
* Interfaces/IWebHistoryItemPrivate.idl: Added new interface.
* WebHistory.cpp:
(WebHistory::visitedURL): Use new recordInitialVisit method.
* WebHistoryItem.cpp:
(WebHistoryItem::initFromDictionaryRepresentation): Add parsing support
for new data.
(WebHistoryItem::dictionaryRepresentation): Add saving support for
new data.
(WebHistoryItem::getDailyVisitCounts): SPI accessor.
(WebHistoryItem::getWeeklyVisitCounts): SPI accessor.
(WebHistoryItem::recordInitialVisit): Tell WebCore to record an initial visit.
* WebHistoryItem.h:
2009-02-05 Brent Fulgham <bfulgham@webkit.org>
Reviewed by Sam Weinig <sam@webkit.org>
......
......@@ -62,4 +62,8 @@ interface IWebHistoryItemPrivate : IUnknown
HRESULT redirectURLs([out, retval] IEnumVARIANT** result);
HRESULT visitedWithTitle([in] BSTR title);
HRESULT getDailyVisitCounts([out] int* number, [out, retval] int** counts);
HRESULT getWeeklyVisitCounts([out] int* number, [out, retval] int** counts);
HRESULT recordInitialVisit();
}
......@@ -705,7 +705,7 @@ void WebHistory::visitedURL(const KURL& url, const String& title, const String&
if (FAILED(entry->initWithURLString(BString(url.string()), BString(title), lastVisited)))
return;
item->setVisitCount(1);
item->recordInitialVisit();
CFDictionarySetValue(m_entriesByURL.get(), urlString.get(), entry);
}
......
......@@ -99,6 +99,8 @@ static CFStringRef visitCountKey = CFSTR("visitCount");
static CFStringRef lastVisitWasFailureKey = CFSTR("lastVisitWasFailure");
static CFStringRef lastVisitWasHTTPNonGetKey = CFSTR("lastVisitWasHTTPNonGet");
static CFStringRef redirectURLsKey = CFSTR("redirectURLs");
static CFStringRef dailyVisitCountKey = CFSTR("D"); // short key to save space
static CFStringRef weeklyVisitCountKey = CFSTR("W"); // short key to save space
HRESULT STDMETHODCALLTYPE WebHistoryItem::initFromDictionaryRepresentation(void* dictionary)
{
......@@ -142,6 +144,32 @@ HRESULT STDMETHODCALLTYPE WebHistoryItem::initFromDictionaryRepresentation(void*
(*redirectURLsVector)[i] = String(static_cast<CFStringRef>(CFArrayGetValueAtIndex(redirectURLsRef, i)));
}
CFArrayRef dailyCounts = static_cast<CFArrayRef>(CFDictionaryGetValue(dictionaryRef, dailyVisitCountKey));
if (dailyCounts || CFGetTypeID(dailyCounts) != CFArrayGetTypeID())
dailyCounts = 0;
CFArrayRef weeklyCounts = static_cast<CFArrayRef>(CFDictionaryGetValue(dictionaryRef, weeklyVisitCountKey));
if (weeklyCounts || CFGetTypeID(weeklyCounts) != CFArrayGetTypeID())
weeklyCounts = 0;
std::auto_ptr<Vector<int> > dailyVector, weeklyVector;
if (dailyCounts || weeklyCounts) {
CFIndex dailySize = dailyCounts ? CFArrayGetCount(dailyCounts) : 0;
CFIndex weeklySize = weeklyCounts ? CFArrayGetCount(weeklyCounts) : 0;
dailyVector.reset(new Vector<int>(dailySize));
weeklyVector.reset(new Vector<int>(weeklySize));
for (CFIndex i = 0; i < dailySize; ++i) {
CFNumberRef dailyCount = static_cast<CFNumberRef>(CFArrayGetValueAtIndex(dailyCounts, i));
if (CFGetTypeID(dailyCount) == CFNumberGetTypeID())
CFNumberGetValue(dailyCount, kCFNumberIntType, &(*dailyVector)[i]);
}
for (CFIndex i = 0; i < weeklySize; ++i) {
CFNumberRef weeklyCount = static_cast<CFNumberRef>(CFArrayGetValueAtIndex(weeklyCounts, i));
if (CFGetTypeID(weeklyCount) == CFNumberGetTypeID())
CFNumberGetValue(weeklyCount, kCFNumberIntType, &(*weeklyVector)[i]);
}
}
historyItemWrappers().remove(m_historyItem.get());
m_historyItem = HistoryItem::create(urlStringRef, titleRef, lastVisitedTime);
historyItemWrappers().set(m_historyItem.get(), this);
......@@ -156,6 +184,9 @@ HRESULT STDMETHODCALLTYPE WebHistoryItem::initFromDictionaryRepresentation(void*
if (redirectURLsVector.get())
m_historyItem->setRedirectURLs(redirectURLsVector);
if (dailyVector.get())
m_historyItem->adoptVisitCounts(*dailyVector, *weeklyVector);
return S_OK;
}
......@@ -169,8 +200,8 @@ HRESULT STDMETHODCALLTYPE WebHistoryItem::dictionaryRepresentation(void** dictio
return E_FAIL;
int keyCount = 0;
CFTypeRef keys[7];
CFTypeRef values[7];
CFTypeRef keys[9];
CFTypeRef values[9];
if (!m_historyItem->urlString().isEmpty()) {
keys[keyCount] = urlKey;
......@@ -215,6 +246,36 @@ HRESULT STDMETHODCALLTYPE WebHistoryItem::dictionaryRepresentation(void** dictio
values[keyCount++] = result;
}
const Vector<int>& dailyVisitCount(m_historyItem->dailyVisitCounts());
if (size_t size = dailyVisitCount.size()) {
Vector<CFNumberRef, 13> numbers;
for (size_t i = 0; i < size; ++i)
numbers[i] = CFNumberCreate(0, kCFNumberIntType, &dailyVisitCount[i]);
CFArrayRef result = CFArrayCreate(0, (const void**)numbers.data(), size, &kCFTypeArrayCallBacks);
for (size_t i = 0; i < size; ++i)
CFRelease(numbers[i]);
keys[keyCount] = dailyVisitCountKey;
values[keyCount++] = result;
}
const Vector<int>& weeklyVisitCount(m_historyItem->weeklyVisitCounts());
if (size_t size = weeklyVisitCount.size()) {
Vector<CFNumberRef, 13> numbers;
for (size_t i = 0; i < size; ++i)
numbers[i] = CFNumberCreate(0, kCFNumberIntType, &weeklyVisitCount[i]);
CFArrayRef result = CFArrayCreate(0, (const void**)numbers.data(), size, &kCFTypeArrayCallBacks);
for (size_t i = 0; i < size; ++i)
CFRelease(numbers[i]);
keys[keyCount] = weeklyVisitCountKey;
values[keyCount++] = result;
}
*dictionaryRef = CFDictionaryCreate(0, keys, values, keyCount, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
for (int i = 0; i < keyCount; ++i)
......@@ -425,6 +486,36 @@ HRESULT STDMETHODCALLTYPE WebHistoryItem::visitedWithTitle(BSTR title)
return S_OK;
}
HRESULT STDMETHODCALLTYPE WebHistoryItem::getDailyVisitCounts(int* number, int** counts)
{
if (!number || !counts) {
ASSERT_NOT_REACHED();
return E_POINTER;
}
*counts = const_cast<int*>(m_historyItem->dailyVisitCounts().data());
*number = m_historyItem->dailyVisitCounts().size();
return S_OK;
}
HRESULT STDMETHODCALLTYPE WebHistoryItem::getWeeklyVisitCounts(int* number, int** counts)
{
if (!number || !counts) {
ASSERT_NOT_REACHED();
return E_POINTER;
}
*counts = const_cast<int*>(m_historyItem->weeklyVisitCounts().data());
*number = m_historyItem->weeklyVisitCounts().size();
return S_OK;
}
HRESULT STDMETHODCALLTYPE WebHistoryItem::recordInitialVisit()
{
m_historyItem->recordInitialVisit();
return S_OK;
}
// IUnknown -------------------------------------------------------------------
HRESULT STDMETHODCALLTYPE WebHistoryItem::QueryInterface(REFIID riid, void** ppvObject)
......
......@@ -103,7 +103,9 @@ public:
virtual HRESULT STDMETHODCALLTYPE setLastVisitWasHTTPNonGet(BOOL HTTPNonGet);
virtual HRESULT STDMETHODCALLTYPE redirectURLs(IEnumVARIANT**);
virtual HRESULT STDMETHODCALLTYPE visitedWithTitle(BSTR title);
virtual HRESULT STDMETHODCALLTYPE getDailyVisitCounts(int* number, int** counts);
virtual HRESULT STDMETHODCALLTYPE getWeeklyVisitCounts(int* number, int** counts);
virtual HRESULT STDMETHODCALLTYPE recordInitialVisit();
// WebHistoryItem
WebCore::HistoryItem* historyItem() const;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment