| Index: chrome/browser/sync/glue/session_model_associator.cc
|
| diff --git a/chrome/browser/sync/glue/session_model_associator.cc b/chrome/browser/sync/glue/session_model_associator.cc
|
| index ced8e3f94ee1e96eaf8669d7f7fa8bf5810d1952..298f3bf05d42761776ca4d8c6878a51ab401646e 100644
|
| --- a/chrome/browser/sync/glue/session_model_associator.cc
|
| +++ b/chrome/browser/sync/glue/session_model_associator.cc
|
| @@ -36,6 +36,7 @@
|
| #include "sync/protocol/session_specifics.pb.h"
|
| #include "sync/syncable/syncable.h"
|
| #include "sync/util/get_session_name.h"
|
| +#include "sync/util/time.h"
|
| #if defined(OS_LINUX)
|
| #include "base/linux_util.h"
|
| #elif defined(OS_WIN)
|
| @@ -224,7 +225,6 @@ bool SessionModelAssociator::AssociateWindows(bool reload_tabs,
|
| // Store the order of tabs.
|
| bool found_tabs = false;
|
| for (int j = 0; j < (*i)->GetTabCount(); ++j) {
|
| - const SessionTab* tab;
|
| SessionID::id_type tab_id = (*i)->GetTabIdAt(j);
|
|
|
| if (reload_tabs) {
|
| @@ -244,6 +244,7 @@ bool SessionModelAssociator::AssociateWindows(bool reload_tabs,
|
| // change processor calling AssociateTab for all modified tabs.
|
| // Therefore, we can key whether this window has valid tabs based on
|
| // the tab's presence in the tracker.
|
| + const SyncedSessionTab* tab;
|
| if (synced_session_tracker_.LookupSessionTab(local_tag, tab_id, &tab)) {
|
| found_tabs = true;
|
| window_s.add_tab(tab_id);
|
| @@ -368,61 +369,31 @@ bool SessionModelAssociator::WriteTabContentsToSyncModel(TabLink* tab_link,
|
| int64 sync_id = tab_link->sync_id();
|
| GURL old_tab_url = tab_link->url();
|
|
|
| + // Load the last stored version of this tab so we can compare changes. If this
|
| + // is a new tab, session_tab will be a blank/newly created SessionTab object.
|
| + SyncedSessionTab* session_tab =
|
| + synced_session_tracker_.GetTab(GetCurrentMachineTag(),
|
| + tab.GetSessionId());
|
| +
|
| // We build a clean session specifics directly from the tab data.
|
| sync_pb::SessionSpecifics session_s;
|
| session_s.set_session_tag(GetCurrentMachineTag());
|
| sync_pb::SessionTab* tab_s = session_s.mutable_tab();
|
| - SessionID::id_type tab_id = tab.GetSessionId();
|
| - tab_s->set_tab_id(tab_id);
|
| - tab_s->set_window_id(tab.GetWindowId());
|
| - const int current_index = tab.GetCurrentEntryIndex();
|
| - const int min_index = std::max(0,
|
| - current_index - kMaxSyncNavigationCount);
|
| - const int max_index = std::min(current_index + kMaxSyncNavigationCount,
|
| - tab.GetEntryCount());
|
| - const int pending_index = tab.GetPendingEntryIndex();
|
| - tab_s->set_pinned(window.IsTabPinned(&tab));
|
| - if (tab.HasExtensionAppId()) {
|
| - tab_s->set_extension_app_id(tab.GetExtensionAppId());
|
| - }
|
| - tab_s->mutable_navigation()->Clear();
|
| - for (int i = min_index; i < max_index; ++i) {
|
| - const NavigationEntry* entry = (i == pending_index) ?
|
| - tab.GetPendingEntry() : tab.GetEntryAtIndex(i);
|
| - DCHECK(entry);
|
| - if (entry->GetVirtualURL().is_valid()) {
|
| - if (i == current_index && entry->GetVirtualURL().is_valid()) {
|
| - tab_link->set_url(entry->GetVirtualURL());
|
| - DVLOG(1) << "Associating tab " << tab_id << " with sync id " << sync_id
|
| - << ", url " << entry->GetVirtualURL().spec()
|
| - << " and title " << entry->GetTitle();
|
| - }
|
| - TabNavigation tab_nav;
|
| - tab_nav.SetFromNavigationEntry(*entry);
|
| - sync_pb::TabNavigation* nav_s = tab_s->add_navigation();
|
| - PopulateSessionSpecificsNavigation(&tab_nav, nav_s);
|
| - }
|
| - }
|
| - tab_s->set_current_navigation_index(current_index);
|
|
|
| - // Convert to a local representation and store in synced session tracker for
|
| - // bookkeeping purposes.
|
| - SessionTab* session_tab =
|
| - synced_session_tracker_.GetTab(GetCurrentMachineTag(),
|
| - tab_s->tab_id());
|
| - synced_session_tracker_.GetSession(GetCurrentMachineTag())->modified_time =
|
| - base::Time::Now();
|
| - PopulateSessionTabFromSpecifics(*tab_s,
|
| - base::Time::Now(),
|
| - session_tab);
|
| + GURL new_url;
|
| + AssociateTabContents(window, tab, session_tab, tab_s, &new_url);
|
|
|
| - // If the url changed, kick off the favicon load for the new url.
|
| - bool url_changed = false;
|
| - if (tab_link->url().is_valid() && tab_link->url() != old_tab_url) {
|
| - url_changed = true;
|
| + // Trigger the favicon load if needed. We do this before opening the write
|
| + // transaction to avoid jank.
|
| + tab_link->set_url(new_url);
|
| + if (new_url != old_tab_url) {
|
| LoadFaviconForTab(tab_link);
|
| }
|
|
|
| + // Update our last modified time.
|
| + synced_session_tracker_.GetSession(GetCurrentMachineTag())->modified_time =
|
| + base::Time::Now();
|
| +
|
| sync_api::WriteTransaction trans(FROM_HERE, sync_service_->GetUserShare());
|
| sync_api::WriteNode tab_node(&trans);
|
| if (!tab_node.InitByIdLookup(sync_id)) {
|
| @@ -435,12 +406,16 @@ bool SessionModelAssociator::WriteTabContentsToSyncModel(TabLink* tab_link,
|
| return false;
|
| }
|
|
|
| - // Preserve the existing favicon only if the url didn't change.
|
| - if (!url_changed) {
|
| - tab_s->set_favicon(tab_node.GetSessionSpecifics().tab().favicon());
|
| - tab_s->set_favicon_source(
|
| - tab_node.GetSessionSpecifics().tab().favicon_source());
|
| - } // else store the empty favicon data back in.
|
| + if (new_url == old_tab_url) {
|
| + // Load the old specifics and copy over the favicon data if needed.
|
| + // TODO(zea): store local favicons in the |synced_favicons_| map and use
|
| + // that instead of reading from sync. This will be necessary to switch to
|
| + // the new api.
|
| + const sync_pb::SessionSpecifics old_specifics =
|
| + tab_node.GetSessionSpecifics();
|
| + tab_s->set_favicon(old_specifics.tab().favicon());
|
| + tab_s->set_favicon_source(old_specifics.tab().favicon_source());
|
| + }
|
|
|
| // Write into the actual sync model.
|
| tab_node.SetSessionSpecifics(session_s);
|
| @@ -448,6 +423,96 @@ bool SessionModelAssociator::WriteTabContentsToSyncModel(TabLink* tab_link,
|
| return true;
|
| }
|
|
|
| +// Builds |sync_tab| by combining data from |prev_tab| and |new_tab|. Updates
|
| +// |prev_tab| to reflect the newest version.
|
| +// Timestamps are chosen from either |prev_tab| or base::Time::Now() based on
|
| +// the following rules:
|
| +// 1. If a navigation exists in both |new_tab| and |prev_tab|, as determined
|
| +// by the unique id, and the navigation didn't just become the current
|
| +// navigation, we preserve the old timestamp.
|
| +// 2. If the navigation exists in both but just become the current navigation
|
| +// (e.g. the user went back in history to this navigation), we update the
|
| +// timestamp to Now().
|
| +// 3. All new navigations not present in |prev_tab| have their timestamps set to
|
| +// Now().
|
| +void SessionModelAssociator::AssociateTabContents(
|
| + const SyncedWindowDelegate& window,
|
| + const SyncedTabDelegate& new_tab,
|
| + SyncedSessionTab* prev_tab,
|
| + sync_pb::SessionTab* sync_tab,
|
| + GURL* new_url) {
|
| + DCHECK(prev_tab);
|
| + DCHECK(sync_tab);
|
| + DCHECK(new_url);
|
| + SessionID::id_type tab_id = new_tab.GetSessionId();
|
| + sync_tab->set_tab_id(tab_id);
|
| + sync_tab->set_window_id(new_tab.GetWindowId());
|
| + const int current_index = new_tab.GetCurrentEntryIndex();
|
| + sync_tab->set_current_navigation_index(current_index);
|
| + const int min_index = std::max(0,
|
| + current_index - kMaxSyncNavigationCount);
|
| + const int max_index = std::min(current_index + kMaxSyncNavigationCount,
|
| + new_tab.GetEntryCount());
|
| + const int pending_index = new_tab.GetPendingEntryIndex();
|
| + sync_tab->set_pinned(window.IsTabPinned(&new_tab));
|
| + if (new_tab.HasExtensionAppId()) {
|
| + sync_tab->set_extension_app_id(new_tab.GetExtensionAppId());
|
| + }
|
| +
|
| + sync_tab->mutable_navigation()->Clear();
|
| + std::vector<SyncedTabNavigation>::const_iterator prev_nav_iter;
|
| + for (int i = min_index; i < max_index; ++i) {
|
| + const NavigationEntry* entry = (i == pending_index) ?
|
| + new_tab.GetPendingEntry() : new_tab.GetEntryAtIndex(i);
|
| + DCHECK(entry);
|
| + if (i == min_index) {
|
| + // Find the location of the first navigation within the previous list of
|
| + // navigations. We only need to do this once, as all subsequent
|
| + // navigations are either contiguous or completely new.
|
| + for (prev_nav_iter = prev_tab->synced_tab_navigations.begin();
|
| + prev_nav_iter != prev_tab->synced_tab_navigations.end();
|
| + ++prev_nav_iter) {
|
| + if (prev_nav_iter->unique_id() == entry->GetUniqueID())
|
| + break;
|
| + }
|
| + }
|
| + if (entry->GetVirtualURL().is_valid()) {
|
| + if (i == current_index) {
|
| + *new_url = GURL(entry->GetVirtualURL().spec());
|
| + DVLOG(1) << "Associating local tab " << new_tab.GetSessionId()
|
| + << " with url " << new_url->spec() << " and title "
|
| + << entry->GetTitle();
|
| +
|
| + }
|
| + sync_pb::TabNavigation* sync_nav = sync_tab->add_navigation();
|
| + PopulateSessionSpecificsNavigation(*entry, sync_nav);
|
| +
|
| + // If this navigation is an old one, reuse the old timestamp. Otherwise we
|
| + // leave the timestamp as the current time.
|
| + if (prev_nav_iter != prev_tab->synced_tab_navigations.end() &&
|
| + prev_nav_iter->unique_id() == entry->GetUniqueID()) {
|
| + // Check that we haven't gone back/foward in the nav stack to this page
|
| + // (if so, we want to refresh the timestamp).
|
| + if (!(current_index != prev_tab->current_navigation_index &&
|
| + current_index == i)) {
|
| + sync_nav->set_timestamp(TimeToProtoTime(prev_nav_iter->timestamp()));
|
| + DVLOG(2) << "Nav to " << sync_nav->virtual_url() << " already known, "
|
| + << "reusing old timestamp " << sync_nav->timestamp();
|
| + }
|
| + // Even if the user went back in their history, they may have skipped
|
| + // over navigations, so the subsequent navigation entries may need their
|
| + // old timestamps preserved.
|
| + ++prev_nav_iter;
|
| + }
|
| + }
|
| + }
|
| +
|
| + // Now update our local version with the newest data.
|
| + PopulateSessionTabFromSpecifics(*sync_tab,
|
| + base::Time::Now(),
|
| + prev_tab);
|
| +}
|
| +
|
| void SessionModelAssociator::LoadFaviconForTab(TabLink* tab_link) {
|
| const CommandLine& command_line = *CommandLine::ForCurrentProcess();
|
| if (!command_line.HasSwitch(switches::kSyncTabFavicons))
|
| @@ -557,14 +622,13 @@ void SessionModelAssociator::FaviconsUpdated(
|
| // TODO(zea): perhaps sync state (scroll position, form entries, etc.) as well?
|
| // See http://crbug.com/67068.
|
| void SessionModelAssociator::PopulateSessionSpecificsNavigation(
|
| - const TabNavigation* navigation,
|
| + const NavigationEntry& navigation,
|
| sync_pb::TabNavigation* tab_navigation) {
|
| - tab_navigation->set_index(navigation->index());
|
| - tab_navigation->set_virtual_url(navigation->virtual_url().spec());
|
| + tab_navigation->set_virtual_url(navigation.GetVirtualURL().spec());
|
| // FIXME(zea): Support referrer policy?
|
| - tab_navigation->set_referrer(navigation->referrer().url.spec());
|
| - tab_navigation->set_title(UTF16ToUTF8(navigation->title()));
|
| - switch (navigation->transition()) {
|
| + tab_navigation->set_referrer(navigation.GetReferrer().url.spec());
|
| + tab_navigation->set_title(UTF16ToUTF8(navigation.GetTitle()));
|
| + switch (navigation.GetTransitionType()) {
|
| case content::PAGE_TRANSITION_LINK:
|
| tab_navigation->set_page_transition(
|
| sync_pb::TabNavigation_PageTransition_LINK);
|
| @@ -629,6 +693,8 @@ void SessionModelAssociator::PopulateSessionSpecificsNavigation(
|
| tab_navigation->set_page_transition(
|
| sync_pb::TabNavigation_PageTransition_TYPED);
|
| }
|
| + tab_navigation->set_unique_id(navigation.GetUniqueID());
|
| + tab_navigation->set_timestamp(TimeToProtoTime(base::Time::Now()));
|
| }
|
|
|
| void SessionModelAssociator::Associate(const SyncedTabDelegate* tab,
|
| @@ -714,6 +780,9 @@ SyncError SessionModelAssociator::DisassociateModels() {
|
| current_machine_tag_ = "";
|
| current_session_name_ = "";
|
| load_consumer_.CancelAllRequests();
|
| + synced_favicons_.clear();
|
| + synced_favicon_pages_.clear();
|
| + synced_favicon_usage_.clear();
|
|
|
| // There is no local model stored with which to disassociate, just notify
|
| // foreign session handlers.
|
| @@ -755,6 +824,19 @@ void SessionModelAssociator::OnSessionNameInitialized(
|
| current_session_name_ = name;
|
| }
|
|
|
| +bool SessionModelAssociator::GetSyncedFaviconForPageURL(
|
| + const std::string& url,
|
| + std::string* png_favicon) const {
|
| + std::map<std::string, std::string>::const_iterator iter =
|
| + synced_favicon_pages_.find(url);
|
| + if (iter == synced_favicon_pages_.end())
|
| + return false;
|
| + const std::string& favicon = *(synced_favicons_.find(iter->second)->second);
|
| + png_favicon->assign(favicon);
|
| + DCHECK_GT(favicon.size(), 0U);
|
| + return true;
|
| +}
|
| +
|
| void SessionModelAssociator::InitializeCurrentSessionName() {
|
| DCHECK(CalledOnValidThread());
|
| if (setup_for_test_) {
|
| @@ -873,10 +955,35 @@ void SessionModelAssociator::AssociateForeignSpecifics(
|
| } else if (specifics.has_tab()) {
|
| const sync_pb::SessionTab& tab_s = specifics.tab();
|
| SessionID::id_type tab_id = tab_s.tab_id();
|
| - SessionTab* tab =
|
| + SyncedSessionTab* tab =
|
| synced_session_tracker_.GetTab(foreign_session_tag, tab_id);
|
| +
|
| + // Figure out what the previous url for this tab was (may be empty string
|
| + // if this is a new tab).
|
| + std::string previous_url;
|
| + if (tab->navigations.size() > 0) {
|
| + int selected_index = tab->current_navigation_index;
|
| + selected_index = std::max(
|
| + 0,
|
| + std::min(selected_index,
|
| + static_cast<int>(tab->navigations.size() - 1)));
|
| + if (tab->navigations[selected_index].virtual_url().is_valid())
|
| + previous_url = tab->navigations[selected_index].virtual_url().spec();
|
| + }
|
| +
|
| + // Update SessionTab based on protobuf.
|
| PopulateSessionTabFromSpecifics(tab_s, modification_time, tab);
|
| +
|
| + // Also increments synced_favicon_usage_ and updates synced_favicon_pages_.
|
| LoadForeignTabFavicon(tab_s);
|
| +
|
| + // Now check to see if the favicon associated with the previous url is no
|
| + // longer in use. This will have no effect if the current url matches the
|
| + // previous url (LoadForeignTabFavicon increments, this decrements, no net
|
| + // change in usage), or if the previous_url was not set (new tab).
|
| + DecrementAndCleanFaviconForURL(previous_url);
|
| +
|
| + // Update the last modified time.
|
| if (foreign_session->modified_time < modification_time)
|
| foreign_session->modified_time = modification_time;
|
| } else {
|
| @@ -885,6 +992,39 @@ void SessionModelAssociator::AssociateForeignSpecifics(
|
| }
|
| }
|
|
|
| +void SessionModelAssociator::DecrementAndCleanFaviconForURL(
|
| + std::string page_url) {
|
| + if (page_url.empty())
|
| + return;
|
| + std::map<std::string, std::string>::const_iterator iter =
|
| + synced_favicon_pages_.find(page_url);
|
| + if (iter != synced_favicon_pages_.end()) {
|
| + const std::string& favicon_url = iter->second;
|
| + synced_favicon_usage_[favicon_url]--;
|
| + if (synced_favicon_usage_[favicon_url] <= 0) {
|
| + // No more tabs using this favicon. Erase it.
|
| + synced_favicons_.erase(favicon_url);
|
| + // Erase the page mappings to the favicon url. We iterate through all
|
| + // page urls in case multiple pages share the same favicon.
|
| + std::map<std::string, std::string>::iterator page_iter;
|
| + for (page_iter = synced_favicon_pages_.begin();
|
| + page_iter != synced_favicon_pages_.end();) {
|
| + std::map<std::string, std::string>::iterator to_delete = page_iter;
|
| + ++page_iter;
|
| + if (to_delete->second == favicon_url) {
|
| + synced_favicon_pages_.erase(to_delete);
|
| + }
|
| + }
|
| + // Lastly, erase the counts related to the favicon url.
|
| + synced_favicon_usage_.erase(favicon_url);
|
| + }
|
| + }
|
| +}
|
| +
|
| +size_t SessionModelAssociator::NumFaviconsForTesting() const {
|
| + return synced_favicons_.size();
|
| +}
|
| +
|
| bool SessionModelAssociator::DisassociateForeignSession(
|
| const std::string& foreign_session_tag) {
|
| DCHECK(CalledOnValidThread());
|
| @@ -969,7 +1109,7 @@ void SessionModelAssociator::PopulateSessionWindowFromSpecifics(
|
| void SessionModelAssociator::PopulateSessionTabFromSpecifics(
|
| const sync_pb::SessionTab& specifics,
|
| const base::Time& mtime,
|
| - SessionTab* tab) {
|
| + SyncedSessionTab* tab) {
|
| DCHECK_EQ(tab->tab_id.id(), specifics.tab_id());
|
| if (specifics.has_tab_id())
|
| tab->tab_id.set_id(specifics.tab_id());
|
| @@ -984,24 +1124,27 @@ void SessionModelAssociator::PopulateSessionTabFromSpecifics(
|
| if (specifics.has_extension_app_id())
|
| tab->extension_app_id = specifics.extension_app_id();
|
| tab->timestamp = mtime;
|
| - tab->navigations.clear(); // In case we are reusing a previous SessionTab.
|
| - for (int i = 0; i < specifics.navigation_size(); i++) {
|
| - AppendSessionTabNavigation(specifics.navigation(i), &tab->navigations);
|
| + // Cleared in case we reuse a pre-existing SyncedSessionTab object.
|
| + tab->navigations.clear();
|
| + tab->synced_tab_navigations.clear();
|
| + for (int i = 0; i < specifics.navigation_size(); ++i) {
|
| + AppendSessionTabNavigation(specifics.navigation(i),
|
| + tab);
|
| }
|
| }
|
|
|
| // Static
|
| void SessionModelAssociator::AppendSessionTabNavigation(
|
| const sync_pb::TabNavigation& specifics,
|
| - std::vector<TabNavigation>* navigations) {
|
| + SyncedSessionTab* tab) {
|
| int index = 0;
|
| GURL virtual_url;
|
| GURL referrer;
|
| string16 title;
|
| std::string state;
|
| content::PageTransition transition(content::PAGE_TRANSITION_LINK);
|
| - if (specifics.has_index())
|
| - index = specifics.index();
|
| + base::Time timestamp;
|
| + int unique_id = 0;
|
| if (specifics.has_virtual_url()) {
|
| GURL gurl(specifics.virtual_url());
|
| virtual_url = gurl;
|
| @@ -1071,50 +1214,54 @@ void SessionModelAssociator::AppendSessionTabNavigation(
|
| }
|
| }
|
| }
|
| - TabNavigation tab_navigation(
|
| + if (specifics.has_timestamp()) {
|
| + timestamp = ProtoTimeToTime(specifics.timestamp());
|
| + }
|
| + if (specifics.has_unique_id()) {
|
| + unique_id = specifics.unique_id();
|
| + }
|
| + SyncedTabNavigation tab_navigation(
|
| index, virtual_url,
|
| content::Referrer(referrer, WebKit::WebReferrerPolicyDefault), title,
|
| - state, transition);
|
| - navigations->insert(navigations->end(), tab_navigation);
|
| + state, transition, unique_id, timestamp);
|
| + // We insert it twice, once for our SyncedTabNavigations, once for the normal
|
| + // TabNavigation (used by the session restore UI).
|
| + tab->synced_tab_navigations.insert(tab->synced_tab_navigations.end(),
|
| + tab_navigation);
|
| + tab->navigations.insert(tab->navigations.end(),
|
| + tab_navigation);
|
| }
|
|
|
| void SessionModelAssociator::LoadForeignTabFavicon(
|
| const sync_pb::SessionTab& tab) {
|
| if (!tab.has_favicon() || tab.favicon().empty())
|
| return;
|
| - if (tab.favicon_type() != sync_pb::SessionTab::TYPE_WEB_FAVICON) {
|
| + if (!tab.has_favicon_type() ||
|
| + tab.favicon_type() != sync_pb::SessionTab::TYPE_WEB_FAVICON) {
|
| DVLOG(1) << "Ignoring non-web favicon.";
|
| return;
|
| }
|
| - int current_navigation_index = tab.current_navigation_index();
|
| - if (current_navigation_index < 0 ||
|
| - current_navigation_index >= tab.navigation_size()) {
|
| + if (tab.navigation_size() == 0)
|
| return;
|
| - }
|
| - GURL navigation_url(tab.navigation(current_navigation_index).virtual_url());
|
| + int selected_index = tab.current_navigation_index();
|
| + selected_index = std::max(
|
| + 0,
|
| + std::min(selected_index,
|
| + static_cast<int>(tab.navigation_size() - 1)));
|
| + GURL navigation_url(tab.navigation(selected_index).virtual_url());
|
| if (!navigation_url.is_valid())
|
| return;
|
| GURL favicon_source(tab.favicon_source());
|
| if (!favicon_source.is_valid())
|
| return;
|
|
|
| - HistoryService* history =
|
| - profile_->GetHistoryService(Profile::EXPLICIT_ACCESS);
|
| - FaviconService* favicon_service =
|
| - profile_->GetFaviconService(Profile::EXPLICIT_ACCESS);
|
| - if (!history || !favicon_service)
|
| - return;
|
| - std::vector<unsigned char> icon_bytes;
|
| const std::string& favicon = tab.favicon();
|
| - icon_bytes.assign(reinterpret_cast<const unsigned char*>(favicon.data()),
|
| - reinterpret_cast<const unsigned char*>(favicon.data() +
|
| - favicon.length()));
|
| DVLOG(1) << "Storing synced favicon for url " << navigation_url.spec()
|
| - << " with size " << icon_bytes.size() << " bytes.";
|
| - favicon_service->SetFavicon(navigation_url,
|
| - favicon_source,
|
| - icon_bytes,
|
| - history::FAVICON);
|
| + << " with size " << favicon.size() << " bytes.";
|
| + synced_favicons_[favicon_source.spec()] =
|
| + make_linked_ptr<std::string>(new std::string(favicon));
|
| + synced_favicon_usage_[favicon_source.spec()]++;
|
| + synced_favicon_pages_[navigation_url.spec()] = favicon_source.spec();
|
| }
|
|
|
| bool SessionModelAssociator::UpdateSyncModelDataFromClient(SyncError* error) {
|
| @@ -1218,7 +1365,13 @@ bool SessionModelAssociator::GetForeignTab(
|
| const SessionID::id_type tab_id,
|
| const SessionTab** tab) {
|
| DCHECK(CalledOnValidThread());
|
| - return synced_session_tracker_.LookupSessionTab(tag, tab_id, tab);
|
| + const SyncedSessionTab* synced_tab;
|
| + bool success = synced_session_tracker_.LookupSessionTab(tag,
|
| + tab_id,
|
| + &synced_tab);
|
| + if (success)
|
| + *tab = synced_tab;
|
| + return success;
|
| }
|
|
|
| void SessionModelAssociator::DeleteStaleSessions() {
|
|
|