This source file includes following definitions.
- render_process_id_
- SendVisitedLinkTable
- AddLinks
- AddReset
- Update
- browser_context_
- NewTable
- Add
- Reset
- CommitVisitedLinks
- Observe
#include "components/visitedlink/browser/visitedlink_event_listener.h"
#include "base/memory/shared_memory.h"
#include "components/visitedlink/browser/visitedlink_delegate.h"
#include "components/visitedlink/common/visitedlink_messages.h"
#include "content/public/browser/notification_service.h"
#include "content/public/browser/notification_types.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_widget_host.h"
using base::Time;
using base::TimeDelta;
using content::RenderWidgetHost;
namespace {
const int kCommitIntervalMs = 100;
const unsigned kVisitedLinkBufferThreshold = 50;
}
namespace visitedlink {
class VisitedLinkUpdater {
public:
explicit VisitedLinkUpdater(int render_process_id)
: reset_needed_(false), render_process_id_(render_process_id) {
}
void SendVisitedLinkTable(base::SharedMemory* table_memory) {
content::RenderProcessHost* process =
content::RenderProcessHost::FromID(render_process_id_);
if (!process)
return;
base::SharedMemoryHandle handle_for_process;
table_memory->ShareToProcess(process->GetHandle(), &handle_for_process);
if (base::SharedMemory::IsHandleValid(handle_for_process))
process->Send(new ChromeViewMsg_VisitedLink_NewTable(
handle_for_process));
}
void AddLinks(const VisitedLinkCommon::Fingerprints& links) {
if (reset_needed_)
return;
if (pending_.size() + links.size() > kVisitedLinkBufferThreshold) {
AddReset();
return;
}
pending_.insert(pending_.end(), links.begin(), links.end());
}
void AddReset() {
reset_needed_ = true;
pending_.clear();
}
void Update() {
content::RenderProcessHost* process =
content::RenderProcessHost::FromID(render_process_id_);
if (!process)
return;
if (!process->VisibleWidgetCount())
return;
if (reset_needed_) {
process->Send(new ChromeViewMsg_VisitedLink_Reset());
reset_needed_ = false;
return;
}
if (pending_.empty())
return;
process->Send(new ChromeViewMsg_VisitedLink_Add(pending_));
pending_.clear();
}
private:
bool reset_needed_;
int render_process_id_;
VisitedLinkCommon::Fingerprints pending_;
};
VisitedLinkEventListener::VisitedLinkEventListener(
VisitedLinkMaster* master,
content::BrowserContext* browser_context)
: master_(master),
browser_context_(browser_context) {
registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CREATED,
content::NotificationService::AllBrowserContextsAndSources());
registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_TERMINATED,
content::NotificationService::AllBrowserContextsAndSources());
registrar_.Add(this, content::NOTIFICATION_RENDER_WIDGET_VISIBILITY_CHANGED,
content::NotificationService::AllBrowserContextsAndSources());
}
VisitedLinkEventListener::~VisitedLinkEventListener() {
if (!pending_visited_links_.empty())
pending_visited_links_.clear();
}
void VisitedLinkEventListener::NewTable(base::SharedMemory* table_memory) {
if (!table_memory)
return;
for (Updaters::iterator i = updaters_.begin(); i != updaters_.end(); ++i) {
content::RenderProcessHost* process =
content::RenderProcessHost::FromID(i->first);
if (!process)
continue;
i->second->SendVisitedLinkTable(table_memory);
}
}
void VisitedLinkEventListener::Add(VisitedLinkMaster::Fingerprint fingerprint) {
pending_visited_links_.push_back(fingerprint);
if (!coalesce_timer_.IsRunning()) {
coalesce_timer_.Start(FROM_HERE,
TimeDelta::FromMilliseconds(kCommitIntervalMs), this,
&VisitedLinkEventListener::CommitVisitedLinks);
}
}
void VisitedLinkEventListener::Reset() {
pending_visited_links_.clear();
coalesce_timer_.Stop();
for (Updaters::iterator i = updaters_.begin(); i != updaters_.end(); ++i) {
i->second->AddReset();
i->second->Update();
}
}
void VisitedLinkEventListener::CommitVisitedLinks() {
for (Updaters::iterator i = updaters_.begin(); i != updaters_.end(); ++i) {
i->second->AddLinks(pending_visited_links_);
i->second->Update();
}
pending_visited_links_.clear();
}
void VisitedLinkEventListener::Observe(
int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) {
switch (type) {
case content::NOTIFICATION_RENDERER_PROCESS_CREATED: {
content::RenderProcessHost* process =
content::Source<content::RenderProcessHost>(source).ptr();
if (browser_context_ != process->GetBrowserContext())
return;
if (!master_->shared_memory())
return;
updaters_[process->GetID()] =
make_linked_ptr(new VisitedLinkUpdater(process->GetID()));
updaters_[process->GetID()]->SendVisitedLinkTable(
master_->shared_memory());
break;
}
case content::NOTIFICATION_RENDERER_PROCESS_TERMINATED: {
content::RenderProcessHost* process =
content::Source<content::RenderProcessHost>(source).ptr();
if (updaters_.count(process->GetID())) {
updaters_.erase(process->GetID());
}
break;
}
case content::NOTIFICATION_RENDER_WIDGET_VISIBILITY_CHANGED: {
RenderWidgetHost* widget =
content::Source<RenderWidgetHost>(source).ptr();
int child_id = widget->GetProcess()->GetID();
if (updaters_.count(child_id))
updaters_[child_id]->Update();
break;
}
default:
NOTREACHED();
break;
}
}
}