// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "chrome/browser/history/visit_tracker.h" #include "base/stl_util-inl.h" namespace history { // When the list gets longer than 'MaxItems', CleanupTransitionList will resize // the list down to 'ResizeTo' size. This is so we only do few block moves of // the data rather than constantly shuffle stuff around in the vector. static const size_t kMaxItemsInTransitionList = 96; static const size_t kResizeBigTransitionListTo = 64; COMPILE_ASSERT(kResizeBigTransitionListTo < kMaxItemsInTransitionList, max_items_must_be_larger_than_resize_to); VisitTracker::VisitTracker() { } VisitTracker::~VisitTracker() { STLDeleteContainerPairSecondPointers(hosts_.begin(), hosts_.end()); } // This function is potentially slow because it may do up to two brute-force // searches of the transitions list. This transitions list is kept to a // relatively small number by CleanupTransitionList so it shouldn't be a big // deal. However, if this ends up being noticable for performance, we may want // to optimize lookup. VisitID VisitTracker::GetLastVisit(const void* host, int32 page_id, const GURL& referrer) { if (referrer.is_empty() || !host) return 0; HostList::iterator i = hosts_.find(host); if (i == hosts_.end()) return 0; // We don't have any entries for this host. TransitionList& transitions = *i->second; // Recall that a page ID is associated with a single session history entry. // In the case of automatically loaded iframes, many visits/URLs can have the // same page ID. // // We search backwards, starting at the current page ID, for the referring // URL. This won't always be correct. For example, if a render process has // the same page open in two different tabs, or even in two different frames, // we can get confused about which was which. We can have the renderer // report more precise referrer information in the future, but this is a // hard problem and doesn't affect much in terms of real-world issues. // // We assume that the page IDs are increasing over time, so larger IDs than // the current input ID happened in the future (this will occur if the user // goes back). We can ignore future transitions because if you navigate, go // back, and navigate some more, we'd like to have one node with two out // edges in our visit graph. for (int i = static_cast<int>(transitions.size()) - 1; i >= 0; i--) { if (transitions[i].page_id <= page_id && transitions[i].url == referrer) { // Found it. return transitions[i].visit_id; } } // We can't find the referrer. return 0; } void VisitTracker::AddVisit(const void* host, int32 page_id, const GURL& url, VisitID visit_id) { TransitionList* transitions = hosts_[host]; if (!transitions) { transitions = new TransitionList; hosts_[host] = transitions; } Transition t; t.url = url; t.page_id = page_id; t.visit_id = visit_id; transitions->push_back(t); CleanupTransitionList(transitions); } void VisitTracker::NotifyRenderProcessHostDestruction(const void* host) { HostList::iterator i = hosts_.find(host); if (i == hosts_.end()) return; // We don't have any entries for this host. delete i->second; hosts_.erase(i); } void VisitTracker::CleanupTransitionList(TransitionList* transitions) { if (transitions->size() <= kMaxItemsInTransitionList) return; // Nothing to do. transitions->erase(transitions->begin(), transitions->begin() + kResizeBigTransitionListTo); } } // namespace history