diff options
-rw-r--r-- | chrome/app/generated_resources.grd | 9 | ||||
-rw-r--r-- | chrome/browser/cookies_tree_model.cc | 117 | ||||
-rw-r--r-- | chrome/browser/cookies_tree_model.h | 101 | ||||
-rw-r--r-- | chrome/browser/gtk/options/cookies_view.cc | 130 | ||||
-rw-r--r-- | chrome/browser/gtk/options/cookies_view.h | 23 | ||||
-rw-r--r-- | chrome/browser/in_process_webkit/dom_storage_context.cc | 48 | ||||
-rw-r--r-- | chrome/browser/in_process_webkit/dom_storage_context.h | 12 | ||||
-rw-r--r-- | chrome/browser/views/options/cookies_view.cc | 163 | ||||
-rw-r--r-- | chrome/browser/views/options/cookies_view.h | 57 | ||||
-rwxr-xr-x | chrome/chrome_browser.gypi | 2 | ||||
-rwxr-xr-x | chrome/chrome_tests.gypi | 1 |
11 files changed, 597 insertions, 66 deletions
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index 2b8bdb5..2fc89f2 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd @@ -4879,6 +4879,15 @@ Keep your key file in a safe place. You will need it to create new versions of y <message name="IDS_COOKIES_DOMAIN_COLUMN_HEADER" desc="The label of the Domain header in the Cookies table"> Site </message> + <message name="IDS_COOKIES_LOCAL_STORAGE_ORIGIN_LABEL" desc="The Local Storage Origin label"> + Origin: + </message> + <message name="IDS_COOKIES_LOCAL_STORAGE_SIZE_ON_DISK_LABEL" desc="The Local Storage Size on disk label"> + Size on disk: + </message> + <message name="IDS_COOKIES_LOCAL_STORAGE_LAST_MODIFIED_LABEL" desc="The Local Storage Last modified label"> + Last modified: + </message> <message name="IDS_COOKIES_NAME_COLUMN_HEADER" desc="The label of the Cookie Name header in the Cookies table"> Cookie Name </message> diff --git a/chrome/browser/cookies_tree_model.cc b/chrome/browser/cookies_tree_model.cc index 71932e8..7944028 100644 --- a/chrome/browser/cookies_tree_model.cc +++ b/chrome/browser/cookies_tree_model.cc @@ -14,6 +14,7 @@ #include "app/tree_node_model.h" #include "base/linked_ptr.h" #include "base/string_util.h" +#include "chrome/browser/in_process_webkit/webkit_context.h" #include "chrome/browser/net/chrome_url_request_context.h" #include "chrome/browser/profile.h" #include "grit/app_resources.h" @@ -114,6 +115,22 @@ class OriginNodeComparator { } // namespace /////////////////////////////////////////////////////////////////////////////// +// CookieTreeLocalStorageNode, public: + +CookieTreeLocalStorageNode::CookieTreeLocalStorageNode( + BrowsingDataLocalStorageHelper::LocalStorageInfo* local_storage_info) + : CookieTreeNode(UTF8ToWide( + !local_storage_info->origin.empty() ? + local_storage_info->origin : + local_storage_info->database_identifier)), + local_storage_info_(local_storage_info) { +} + +void CookieTreeLocalStorageNode::DeleteStoredObjects() { + GetModel()->DeleteLocalStorage(local_storage_info_->file_path); +} + +/////////////////////////////////////////////////////////////////////////////// // CookieTreeRootNode, public: CookieTreeOriginNode* CookieTreeRootNode::GetOrCreateOriginNode( const std::wstring& origin) { @@ -155,6 +172,17 @@ CookieTreeCookiesNode* CookieTreeOriginNode::GetOrCreateCookiesNode() { return retval; } +CookieTreeLocalStoragesNode* + CookieTreeOriginNode::GetOrCreateLocalStoragesNode() { + if (local_storages_child_) + return local_storages_child_; + // need to make a LocalStorages node, add it to the tree, and return it + CookieTreeLocalStoragesNode* retval = new CookieTreeLocalStoragesNode; + GetModel()->Add(this, cookies_child_ ? 1 : 0, retval); + local_storages_child_ = retval; + return retval; +} + /////////////////////////////////////////////////////////////////////////////// // CookieTreeCookiesNode, public: @@ -173,14 +201,47 @@ void CookieTreeCookiesNode::AddCookieNode( } /////////////////////////////////////////////////////////////////////////////// +// CookieTreeLocalStoragesNode, public: + +CookieTreeLocalStoragesNode::CookieTreeLocalStoragesNode() + : CookieTreeNode(l10n_util::GetString(IDS_COOKIES_LOCAL_STORAGE)) { +} + +void CookieTreeLocalStoragesNode::AddLocalStorageNode( + CookieTreeLocalStorageNode* new_child) { + std::vector<CookieTreeNode*>::iterator local_storage_iterator = + lower_bound(children().begin(), + children().end(), + new_child, + CookieTreeLocalStorageNode::CookieNodeComparator()); + GetModel()->Add(this, + (local_storage_iterator - children().begin()), + new_child); +} + +/////////////////////////////////////////////////////////////////////////////// // CookieTreeCookieNode, private bool CookieTreeCookieNode::CookieNodeComparator::operator() ( const CookieTreeNode* lhs, const CookieTreeNode* rhs) { - return (static_cast<const CookieTreeCookieNode*>(lhs)-> - cookie_->second.Name() < - static_cast<const CookieTreeCookieNode*>(rhs)-> - cookie_->second.Name()); + const CookieTreeCookieNode* left = + static_cast<const CookieTreeCookieNode*>(lhs); + const CookieTreeCookieNode* right = + static_cast<const CookieTreeCookieNode*>(rhs); + return (left->cookie_->second.Name() < right->cookie_->second.Name()); +} + +/////////////////////////////////////////////////////////////////////////////// +// CookieTreeLocalStorageNode, private + +bool CookieTreeLocalStorageNode::CookieNodeComparator::operator() ( + const CookieTreeNode* lhs, const CookieTreeNode* rhs) { + const CookieTreeLocalStorageNode* left = + static_cast<const CookieTreeLocalStorageNode*>(lhs); + const CookieTreeLocalStorageNode* right = + static_cast<const CookieTreeLocalStorageNode*>(rhs); + return (left->local_storage_info_->origin < + right->local_storage_info_->origin); } /////////////////////////////////////////////////////////////////////////////// @@ -191,6 +252,13 @@ CookiesTreeModel::CookiesTreeModel(Profile* profile) new CookieTreeRootNode(this))), profile_(profile) { LoadCookies(); + local_storage_model_ = new BrowsingDataLocalStorageHelper(profile_); + local_storage_model_->StartFetching(NewCallback( + this, &CookiesTreeModel::OnStorageModelInfoLoaded)); +} + +CookiesTreeModel::~CookiesTreeModel() { + local_storage_model_->CancelNotification(); } /////////////////////////////////////////////////////////////////////////////// @@ -218,6 +286,8 @@ int CookiesTreeModel::GetIconIndex(TreeModelNode* node) { case CookieTreeNode::DetailedInfo::TYPE_COOKIE: return COOKIE; break; + case CookieTreeNode::DetailedInfo::TYPE_LOCAL_STORAGE: + // TODO(bulach): add an icon for local storage. default: return -1; } @@ -283,11 +353,50 @@ void CookiesTreeModel::DeleteCookieNode(CookieTreeNode* cookie_node) { delete Remove(parent_node, cookie_node_index); } +void CookiesTreeModel::DeleteLocalStorage(const FilePath& file_path) { + local_storage_model_->DeleteLocalStorageFile(file_path); +} + +void CookiesTreeModel::DeleteAllLocalStorage() { + local_storage_model_->DeleteAllLocalStorageFiles(); +} + void CookiesTreeModel::UpdateSearchResults(const std::wstring& filter) { CookieTreeNode* root = GetRoot(); int num_children = root->GetChildCount(); for (int i = num_children - 1; i >= 0; --i) delete Remove(root, i); LoadCookiesWithFilter(filter); + PopulateLocalStorageInfoWithFilter(filter); + NotifyObserverTreeNodeChanged(root); +} + +void CookiesTreeModel::OnStorageModelInfoLoaded( + const LocalStorageInfoList& local_storage_info) { + local_storage_info_list_ = local_storage_info; + PopulateLocalStorageInfoWithFilter(L""); +} + +void CookiesTreeModel::PopulateLocalStorageInfoWithFilter( + const std::wstring& filter) { + CookieTreeRootNode* root = static_cast<CookieTreeRootNode*>(GetRoot()); + for (LocalStorageInfoList::iterator local_storage_info = + local_storage_info_list_.begin(); + local_storage_info != local_storage_info_list_.end(); + ++local_storage_info) { + std::string origin = + !local_storage_info->host.empty() ? + local_storage_info->host : + local_storage_info->database_identifier; + if (!filter.size() || + (UTF8ToWide(origin).find(filter) != std::wstring::npos)) { + CookieTreeOriginNode* origin_node = root->GetOrCreateOriginNode( + UTF8ToWide(local_storage_info->host)); + CookieTreeLocalStoragesNode* local_storages_node = + origin_node->GetOrCreateLocalStoragesNode(); + local_storages_node->AddLocalStorageNode( + new CookieTreeLocalStorageNode(&(*local_storage_info))); + } + } NotifyObserverTreeNodeChanged(root); } diff --git a/chrome/browser/cookies_tree_model.h b/chrome/browser/cookies_tree_model.h index 11b7f8a..45c7585 100644 --- a/chrome/browser/cookies_tree_model.h +++ b/chrome/browser/cookies_tree_model.h @@ -10,9 +10,12 @@ #include "app/tree_node_model.h" #include "base/scoped_ptr.h" +#include "chrome/browser/browsing_data_local_storage_helper.h" #include "net/base/cookie_monster.h" class CookiesTreeModel; +class CookieTreeLocalStorageNode; +class CookieTreeLocalStoragesNode; class CookieTreeCookieNode; class CookieTreeCookiesNode; class CookieTreeOriginNode; @@ -33,18 +36,27 @@ class CookieTreeNode : public TreeNode<CookieTreeNode> { TYPE_ROOT, // This is used for CookieTreeRootNode nodes. TYPE_ORIGIN, // This is used for CookieTreeOriginNode nodes. TYPE_COOKIES, // This is used for CookieTreeCookiesNode nodes. - TYPE_COOKIE // This is used for CookieTreeCookieNode nodes. + TYPE_COOKIE, // This is used for CookieTreeCookieNode nodes. + TYPE_LOCAL_STORAGES, // This is used for CookieTreeLocalStoragesNode. + TYPE_LOCAL_STORAGE, // This is used for CookieTreeLocalStorageNode. }; DetailedInfo(const std::wstring& origin, NodeType node_type, - const net::CookieMonster::CookieListPair* cookie) + const net::CookieMonster::CookieListPair* cookie, + const BrowsingDataLocalStorageHelper::LocalStorageInfo* + local_storage_info) : origin(origin), node_type(node_type), - cookie(cookie) {} + cookie(cookie), + local_storage_info(local_storage_info) { + if (node_type == TYPE_LOCAL_STORAGE) + DCHECK(local_storage_info); + } std::wstring origin; NodeType node_type; const net::CookieMonster::CookieListPair* cookie; + const BrowsingDataLocalStorageHelper::LocalStorageInfo* local_storage_info; }; CookieTreeNode() {} @@ -79,7 +91,7 @@ class CookieTreeRootNode : public CookieTreeNode { // CookieTreeNode methods: virtual CookiesTreeModel* GetModel() const { return model_; } virtual DetailedInfo GetDetailedInfo() const { - return DetailedInfo(std::wstring(), DetailedInfo::TYPE_ROOT, NULL); + return DetailedInfo(std::wstring(), DetailedInfo::TYPE_ROOT, NULL, NULL); } private: @@ -92,16 +104,19 @@ class CookieTreeRootNode : public CookieTreeNode { class CookieTreeOriginNode : public CookieTreeNode { public: explicit CookieTreeOriginNode(const std::wstring& origin) - : CookieTreeNode(origin), cookies_child_(NULL) {} + : CookieTreeNode(origin), cookies_child_(NULL), + local_storages_child_(NULL) {} virtual ~CookieTreeOriginNode() {} // CookieTreeNode methods: virtual DetailedInfo GetDetailedInfo() const { - return DetailedInfo(GetTitle(), DetailedInfo::TYPE_ORIGIN, NULL); + return DetailedInfo(GetTitle(), DetailedInfo::TYPE_ORIGIN, NULL, NULL); } // CookieTreeOriginNode methods: CookieTreeCookiesNode* GetOrCreateCookiesNode(); + CookieTreeLocalStoragesNode* GetOrCreateLocalStoragesNode(); + private: // A pointer to the COOKIES node. Eventually we will also have database, @@ -111,6 +126,7 @@ class CookieTreeOriginNode : public CookieTreeNode { // DATABASES etc node seems less preferable than storing an extra pointer per // origin. CookieTreeCookiesNode* cookies_child_; + CookieTreeLocalStoragesNode* local_storages_child_; DISALLOW_COPY_AND_ASSIGN(CookieTreeOriginNode); }; @@ -124,7 +140,7 @@ class CookieTreeCookiesNode : public CookieTreeNode { // CookieTreeNode methods: virtual DetailedInfo GetDetailedInfo() const { return DetailedInfo(GetParent()->GetTitle(), DetailedInfo::TYPE_COOKIES, - NULL); + NULL, NULL); } // CookieTreeCookiesNode methods: @@ -147,7 +163,7 @@ class CookieTreeCookieNode : public CookieTreeNode { virtual void DeleteStoredObjects(); virtual DetailedInfo GetDetailedInfo() const { return DetailedInfo(GetParent()->GetParent()->GetTitle(), - DetailedInfo::TYPE_COOKIE, cookie_); + DetailedInfo::TYPE_COOKIE, cookie_, NULL); } private: @@ -165,11 +181,64 @@ class CookieTreeCookieNode : public CookieTreeNode { DISALLOW_COPY_AND_ASSIGN(CookieTreeCookieNode); }; +// CookieTreeLocalStoragesNode ------------------------------------------------- +class CookieTreeLocalStoragesNode : public CookieTreeNode { + public: + CookieTreeLocalStoragesNode(); + virtual ~CookieTreeLocalStoragesNode() {} + + // CookieTreeNode methods: + virtual DetailedInfo GetDetailedInfo() const { + return DetailedInfo(GetParent()->GetTitle(), + DetailedInfo::TYPE_LOCAL_STORAGES, + NULL, + NULL); + } + + // CookieTreeStoragesNode methods: + void AddLocalStorageNode(CookieTreeLocalStorageNode* child); + + private: + DISALLOW_COPY_AND_ASSIGN(CookieTreeLocalStoragesNode); +}; + +class CookieTreeLocalStorageNode : public CookieTreeNode { + public: + friend class CookieTreeLocalStoragesNode; + + // Does not take ownership of local_storage_info, and local_storage_info + // should remain valid at least as long as the CookieTreeStorageNode is valid. + explicit CookieTreeLocalStorageNode( + BrowsingDataLocalStorageHelper::LocalStorageInfo* local_storage_info); + virtual ~CookieTreeLocalStorageNode() {} + + // CookieTreeStorageNode methods: + virtual void DeleteStoredObjects(); + virtual DetailedInfo GetDetailedInfo() const { + return DetailedInfo(GetParent()->GetParent()->GetTitle(), + DetailedInfo::TYPE_LOCAL_STORAGE, NULL, + local_storage_info_); + } + + private: + // Comparator functor, takes CookieTreeNode so that we can use it in + // lower_bound using children()'s iterators, which are CookieTreeNode*. + class CookieNodeComparator { + public: + bool operator() (const CookieTreeNode* lhs, const CookieTreeNode* rhs); + }; + + // local_storage_info_ is not owned by the node, and is expected to remain + // valid as long as the CookieTreeLocalStorageNode is valid. + BrowsingDataLocalStorageHelper::LocalStorageInfo* local_storage_info_; + + DISALLOW_COPY_AND_ASSIGN(CookieTreeLocalStorageNode); +}; class CookiesTreeModel : public TreeNodeModel<CookieTreeNode> { public: explicit CookiesTreeModel(Profile* profile); - virtual ~CookiesTreeModel() {} + virtual ~CookiesTreeModel(); // TreeModel methods: // Returns the set of icons for the nodes in the tree. You only need override @@ -185,6 +254,8 @@ class CookiesTreeModel : public TreeNodeModel<CookieTreeNode> { void DeleteCookie(const net::CookieMonster::CookieListPair& cookie); void DeleteAllCookies(); void DeleteCookieNode(CookieTreeNode* cookie_node); + void DeleteLocalStorage(const FilePath& file_path); + void DeleteAllLocalStorage(); // Filter the origins to only display matched results. void UpdateSearchResults(const std::wstring& filter); @@ -192,18 +263,28 @@ class CookiesTreeModel : public TreeNodeModel<CookieTreeNode> { private: enum CookieIconIndex { ORIGIN = 0, - COOKIE = 1 + COOKIE = 1, + LOCAL_STORAGE = 2, }; typedef net::CookieMonster::CookieList CookieList; typedef std::vector<net::CookieMonster::CookieListPair*> CookiePtrList; + typedef std::vector<BrowsingDataLocalStorageHelper::LocalStorageInfo> + LocalStorageInfoList; void LoadCookies(); void LoadCookiesWithFilter(const std::wstring& filter); + void OnStorageModelInfoLoaded(const LocalStorageInfoList& local_storage_info); + + void PopulateLocalStorageInfoWithFilter(const std::wstring& filter); + // The profile from which this model sources cookies. Profile* profile_; CookieList all_cookies_; + scoped_refptr<BrowsingDataLocalStorageHelper> local_storage_model_; + LocalStorageInfoList local_storage_info_list_; + DISALLOW_COPY_AND_ASSIGN(CookiesTreeModel); }; diff --git a/chrome/browser/gtk/options/cookies_view.cc b/chrome/browser/gtk/options/cookies_view.cc index fb9c8c6..d63a59d 100644 --- a/chrome/browser/gtk/options/cookies_view.cc +++ b/chrome/browser/gtk/options/cookies_view.cc @@ -35,8 +35,8 @@ enum { // The currently open cookie manager, if any. CookiesView* instance_ = NULL; -void InitCookieDetailStyle(GtkWidget* entry, GtkStyle* label_style, - GtkStyle* dialog_style) { +void InitBrowserDetailStyle(GtkWidget* entry, GtkStyle* label_style, + GtkStyle* dialog_style) { gtk_widget_modify_fg(entry, GTK_STATE_NORMAL, &label_style->fg[GTK_STATE_NORMAL]); gtk_widget_modify_fg(entry, GTK_STATE_INSENSITIVE, @@ -193,31 +193,54 @@ void CookiesView::Init() { G_CALLBACK(OnSelectionChanged), this); // Cookie details. - GtkWidget* details_frame = gtk_frame_new(NULL); - gtk_frame_set_shadow_type(GTK_FRAME(details_frame), GTK_SHADOW_ETCHED_IN); - gtk_box_pack_start(GTK_BOX(cookie_list_vbox), details_frame, + GtkWidget* cookie_details_frame = gtk_frame_new(NULL); + gtk_frame_set_shadow_type(GTK_FRAME(cookie_details_frame), + GTK_SHADOW_ETCHED_IN); + gtk_box_pack_start(GTK_BOX(cookie_list_vbox), cookie_details_frame, FALSE, FALSE, 0); cookie_details_table_ = gtk_table_new(7, 2, FALSE); - gtk_container_add(GTK_CONTAINER(details_frame), cookie_details_table_); + gtk_container_add(GTK_CONTAINER(cookie_details_frame), cookie_details_table_); gtk_table_set_col_spacing(GTK_TABLE(cookie_details_table_), 0, gtk_util::kLabelSpacing); int row = 0; - InitCookieDetailRow(row++, IDS_COOKIES_COOKIE_NAME_LABEL, - &cookie_name_entry_); - InitCookieDetailRow(row++, IDS_COOKIES_COOKIE_CONTENT_LABEL, - &cookie_content_entry_); - InitCookieDetailRow(row++, IDS_COOKIES_COOKIE_DOMAIN_LABEL, - &cookie_domain_entry_); - InitCookieDetailRow(row++, IDS_COOKIES_COOKIE_PATH_LABEL, - &cookie_path_entry_); - InitCookieDetailRow(row++, IDS_COOKIES_COOKIE_SENDFOR_LABEL, - &cookie_send_for_entry_); - InitCookieDetailRow(row++, IDS_COOKIES_COOKIE_CREATED_LABEL, - &cookie_created_entry_); - InitCookieDetailRow(row++, IDS_COOKIES_COOKIE_EXPIRES_LABEL, - &cookie_expires_entry_); + InitDetailRow(row++, IDS_COOKIES_COOKIE_NAME_LABEL, + cookie_details_table_, &cookie_name_entry_); + InitDetailRow(row++, IDS_COOKIES_COOKIE_CONTENT_LABEL, + cookie_details_table_, &cookie_content_entry_); + InitDetailRow(row++, IDS_COOKIES_COOKIE_DOMAIN_LABEL, + cookie_details_table_, &cookie_domain_entry_); + InitDetailRow(row++, IDS_COOKIES_COOKIE_PATH_LABEL, + cookie_details_table_, &cookie_path_entry_); + InitDetailRow(row++, IDS_COOKIES_COOKIE_SENDFOR_LABEL, + cookie_details_table_, &cookie_send_for_entry_); + InitDetailRow(row++, IDS_COOKIES_COOKIE_CREATED_LABEL, + cookie_details_table_, &cookie_created_entry_); + InitDetailRow(row++, IDS_COOKIES_COOKIE_EXPIRES_LABEL, + cookie_details_table_, &cookie_expires_entry_); + + // Local storage details. + GtkWidget* local_storage_details_frame = gtk_frame_new(NULL); + gtk_frame_set_shadow_type(GTK_FRAME(local_storage_details_frame), + GTK_SHADOW_ETCHED_IN); + gtk_box_pack_start(GTK_BOX(cookie_list_vbox), local_storage_details_frame, + FALSE, FALSE, 0); + local_storage_details_table_ = gtk_table_new(3, 2, FALSE); + gtk_container_add(GTK_CONTAINER(local_storage_details_frame), + local_storage_details_table_); + gtk_table_set_col_spacing(GTK_TABLE(local_storage_details_table_), 0, + gtk_util::kLabelSpacing); + + row = 0; + InitDetailRow(row++, IDS_COOKIES_LOCAL_STORAGE_ORIGIN_LABEL, + local_storage_details_table_, &local_storage_origin_entry_); + InitDetailRow(row++, IDS_COOKIES_LOCAL_STORAGE_SIZE_ON_DISK_LABEL, + local_storage_details_table_, &local_storage_size_entry_); + InitDetailRow(row++, IDS_COOKIES_LOCAL_STORAGE_LAST_MODIFIED_LABEL, + local_storage_details_table_, + &local_storage_last_modified_entry_); + UpdateVisibleDetailedInfo(cookie_details_table_); // Populate the view. cookies_tree_adapter_->Init(); SetInitialTreeState(); @@ -231,30 +254,38 @@ void CookiesView::InitStylesAndShow() { GtkStyle* label_style = gtk_widget_get_style(description_label_); GtkStyle* dialog_style = gtk_widget_get_style(dialog_); - InitCookieDetailStyle(cookie_name_entry_, label_style, dialog_style); - InitCookieDetailStyle(cookie_content_entry_, label_style, dialog_style); - InitCookieDetailStyle(cookie_domain_entry_, label_style, dialog_style); - InitCookieDetailStyle(cookie_path_entry_, label_style, dialog_style); - InitCookieDetailStyle(cookie_send_for_entry_, label_style, dialog_style); - InitCookieDetailStyle(cookie_created_entry_, label_style, dialog_style); - InitCookieDetailStyle(cookie_expires_entry_, label_style, dialog_style); + // Cookie details. + InitBrowserDetailStyle(cookie_name_entry_, label_style, dialog_style); + InitBrowserDetailStyle(cookie_content_entry_, label_style, dialog_style); + InitBrowserDetailStyle(cookie_domain_entry_, label_style, dialog_style); + InitBrowserDetailStyle(cookie_path_entry_, label_style, dialog_style); + InitBrowserDetailStyle(cookie_send_for_entry_, label_style, dialog_style); + InitBrowserDetailStyle(cookie_created_entry_, label_style, dialog_style); + InitBrowserDetailStyle(cookie_expires_entry_, label_style, dialog_style); + + // Local storage details. + InitBrowserDetailStyle(local_storage_origin_entry_, label_style, + dialog_style); + InitBrowserDetailStyle(local_storage_size_entry_, label_style, dialog_style); + InitBrowserDetailStyle(local_storage_last_modified_entry_, label_style, + dialog_style); gtk_widget_show_all(dialog_); } -void CookiesView::InitCookieDetailRow(int row, int label_id, - GtkWidget** entry) { +void CookiesView::InitDetailRow(int row, int label_id, + GtkWidget* details_table, GtkWidget** entry) { GtkWidget* name_label = gtk_label_new( l10n_util::GetStringUTF8(label_id).c_str()); gtk_misc_set_alignment(GTK_MISC(name_label), 1, 0.5); - gtk_table_attach(GTK_TABLE(cookie_details_table_), name_label, + gtk_table_attach(GTK_TABLE(details_table), name_label, 0, 1, row, row + 1, GTK_FILL, GTK_FILL, 0, 0); *entry = gtk_entry_new(); gtk_entry_set_editable(GTK_ENTRY(*entry), FALSE); gtk_entry_set_has_frame(GTK_ENTRY(*entry), FALSE); - gtk_table_attach_defaults(GTK_TABLE(cookie_details_table_), *entry, + gtk_table_attach_defaults(GTK_TABLE(details_table), *entry, 1, 2, row, row + 1); } @@ -279,9 +310,15 @@ void CookiesView::EnableControls() { static_cast<CookieTreeNode*>( cookies_tree_adapter_->GetNode(&iter))->GetDetailedInfo(); if (detailed_info.node_type == CookieTreeNode::DetailedInfo::TYPE_COOKIE) { + UpdateVisibleDetailedInfo(cookie_details_table_); PopulateCookieDetails(detailed_info.cookie->first, detailed_info.cookie->second); + } else if (detailed_info.node_type == + CookieTreeNode::DetailedInfo::TYPE_LOCAL_STORAGE) { + UpdateVisibleDetailedInfo(local_storage_details_table_); + PopulateLocalStorageDetails(*detailed_info.local_storage_info); } else { + UpdateVisibleDetailedInfo(cookie_details_table_); ClearCookieDetails(); } } else { @@ -299,6 +336,12 @@ void CookiesView::SetCookieDetailsSensitivity(gboolean enabled) { gtk_widget_set_sensitive(cookie_expires_entry_, enabled); } +void CookiesView::SetLocalStorageDetailsSensitivity(gboolean enabled) { + gtk_widget_set_sensitive(local_storage_origin_entry_, enabled); + gtk_widget_set_sensitive(local_storage_size_entry_, enabled); + gtk_widget_set_sensitive(local_storage_last_modified_entry_, enabled); +} + void CookiesView::PopulateCookieDetails( const std::string& domain, const net::CookieMonster::CanonicalCookie& cookie) { @@ -326,6 +369,22 @@ void CookiesView::PopulateCookieDetails( SetCookieDetailsSensitivity(TRUE); } +void CookiesView::PopulateLocalStorageDetails( + const BrowsingDataLocalStorageHelper::LocalStorageInfo& + local_storage_info) { + gtk_entry_set_text(GTK_ENTRY(local_storage_origin_entry_), + local_storage_info.origin.c_str()); + gtk_entry_set_text(GTK_ENTRY(local_storage_size_entry_), + WideToUTF8(FormatBytes( + local_storage_info.size, + GetByteDisplayUnits(local_storage_info.size), + true)).c_str()); + gtk_entry_set_text(GTK_ENTRY(local_storage_last_modified_entry_), + WideToUTF8(base::TimeFormatFriendlyDateAndTime( + local_storage_info.last_modified)).c_str()); + SetLocalStorageDetailsSensitivity(TRUE); +} + void CookiesView::ClearCookieDetails() { std::string no_cookie = l10n_util::GetStringUTF8(IDS_COOKIES_COOKIE_NONESELECTED); @@ -437,6 +496,15 @@ void CookiesView::UpdateFilterResults() { } } +void CookiesView::UpdateVisibleDetailedInfo(GtkWidget* table) { + // Toggle the parent (the table frame) visibility. + gtk_widget_show(gtk_widget_get_parent(table)); + GtkWidget* other = local_storage_details_table_; + if (table == local_storage_details_table_) + other = cookie_details_table_; + gtk_widget_hide(gtk_widget_get_parent(other)); +} + // static void CookiesView::OnFilterEntryActivated(GtkEntry* entry, CookiesView* window) { window->filter_update_factory_.RevokeAll(); diff --git a/chrome/browser/gtk/options/cookies_view.h b/chrome/browser/gtk/options/cookies_view.h index 260e3db..8dff1a1 100644 --- a/chrome/browser/gtk/options/cookies_view.h +++ b/chrome/browser/gtk/options/cookies_view.h @@ -12,6 +12,7 @@ #include "base/basictypes.h" #include "base/scoped_ptr.h" #include "base/task.h" +#include "chrome/browser/browsing_data_local_storage_helper.h" #include "chrome/common/gtk_tree.h" #include "net/base/cookie_monster.h" #include "testing/gtest/include/gtest/gtest_prod.h" @@ -46,8 +47,9 @@ class CookiesView : public gtk_tree::TreeAdapter::Delegate { // Initialize the widget styles and display the dialog. void InitStylesAndShow(); - // Helper for initializing cookie details table. - void InitCookieDetailRow(int row, int label_id, GtkWidget** display_label); + // Helper for initializing cookie / local storage details table. + void InitDetailRow(int row, int label_id, + GtkWidget* details_table, GtkWidget** display_label); // Set the initial selection and tree expanded state. void SetInitialTreeState(); @@ -58,10 +60,18 @@ class CookiesView : public gtk_tree::TreeAdapter::Delegate { // Set sensitivity of cookie details. void SetCookieDetailsSensitivity(gboolean enabled); + // Set sensitivity of local storage details. + void SetLocalStorageDetailsSensitivity(gboolean enabled); + // Show the details of the currently selected cookie. void PopulateCookieDetails(const std::string& domain, const net::CookieMonster::CanonicalCookie& cookie); + // Show the details of the currently selected local storage. + void PopulateLocalStorageDetails( + const BrowsingDataLocalStorageHelper::LocalStorageInfo& + local_storage_info); + // Reset the cookie details display. void ClearCookieDetails(); @@ -90,6 +100,9 @@ class CookiesView : public gtk_tree::TreeAdapter::Delegate { // Filter the list against the text in |filter_entry_|. void UpdateFilterResults(); + // Sets which of the detailed info table is visible. + void UpdateVisibleDetailedInfo(GtkWidget* table); + // Callbacks for user actions filtering the list. static void OnFilterEntryActivated(GtkEntry* entry, CookiesView* window); static void OnFilterEntryChanged(GtkEditable* editable, CookiesView* window); @@ -120,6 +133,12 @@ class CookiesView : public gtk_tree::TreeAdapter::Delegate { GtkWidget* cookie_created_entry_; GtkWidget* cookie_expires_entry_; + // The local storage details widgets. + GtkWidget* local_storage_details_table_; + GtkWidget* local_storage_origin_entry_; + GtkWidget* local_storage_size_entry_; + GtkWidget* local_storage_last_modified_entry_; + // The profile. Profile* profile_; diff --git a/chrome/browser/in_process_webkit/dom_storage_context.cc b/chrome/browser/in_process_webkit/dom_storage_context.cc index 3997c5f..c19b6cf 100644 --- a/chrome/browser/in_process_webkit/dom_storage_context.cc +++ b/chrome/browser/in_process_webkit/dom_storage_context.cc @@ -11,13 +11,22 @@ #include "chrome/browser/in_process_webkit/dom_storage_namespace.h" #include "chrome/browser/in_process_webkit/webkit_context.h" #include "chrome/common/dom_storage_common.h" +#include "webkit/glue/glue_util.h" -static const char* kLocalStorageDirectory = "Local Storage"; +const FilePath::CharType DOMStorageContext::kLocalStorageDirectory[] = + FILE_PATH_LITERAL("Local Storage"); + +const FilePath::CharType DOMStorageContext::kLocalStorageExtension[] = + FILE_PATH_LITERAL(".localstorage"); + +static const FilePath::CharType kLocalStorageOldPath[] = + FILE_PATH_LITERAL("localStorage"); // TODO(jorlow): Remove after Chrome 4 ships. static void MigrateLocalStorageDirectory(const FilePath& data_path) { - FilePath new_path = data_path.AppendASCII(kLocalStorageDirectory); - FilePath old_path = data_path.AppendASCII("localStorage"); + FilePath new_path = data_path.Append( + DOMStorageContext::kLocalStorageDirectory); + FilePath old_path = data_path.Append(kLocalStorageOldPath); if (!file_util::DirectoryExists(new_path) && file_util::DirectoryExists(old_path)) { file_util::Move(old_path, new_path); @@ -148,7 +157,7 @@ void DOMStorageContext::DeleteDataModifiedSince(const base::Time& cutoff) { PurgeMemory(); file_util::FileEnumerator file_enumerator( - webkit_context_->data_path().AppendASCII(kLocalStorageDirectory), false, + webkit_context_->data_path().Append(kLocalStorageDirectory), false, file_util::FileEnumerator::FILES); for (FilePath path = file_enumerator.Next(); !path.value().empty(); path = file_enumerator.Next()) { @@ -159,12 +168,41 @@ void DOMStorageContext::DeleteDataModifiedSince(const base::Time& cutoff) { } } +void DOMStorageContext::DeleteLocalStorageFile(const FilePath& file_path) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::WEBKIT)); + + // Make sure that we don't delete a database that's currently being accessed + // by unloading all of the databases temporarily. + // TODO(bulach): both this method and DeleteDataModifiedSince could purge + // only the memory used by the specific file instead of all memory at once. + // See http://code.google.com/p/chromium/issues/detail?id=32000 + PurgeMemory(); + file_util::Delete(file_path, false); +} + +void DOMStorageContext::DeleteAllLocalStorageFiles() { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::WEBKIT)); + + // Make sure that we don't delete a database that's currently being accessed + // by unloading all of the databases temporarily. + PurgeMemory(); + + file_util::FileEnumerator file_enumerator( + webkit_context_->data_path().Append(kLocalStorageDirectory), false, + file_util::FileEnumerator::FILES); + for (FilePath file_path = file_enumerator.Next(); !file_path.empty(); + file_path = file_enumerator.Next()) { + if (file_path.Extension() == kLocalStorageExtension) + file_util::Delete(file_path, false); + } +} + DOMStorageNamespace* DOMStorageContext::CreateLocalStorage() { FilePath data_path = webkit_context_->data_path(); FilePath dir_path; if (!data_path.empty()) { MigrateLocalStorageDirectory(data_path); - dir_path = data_path.AppendASCII(kLocalStorageDirectory); + dir_path = data_path.Append(kLocalStorageDirectory); } DOMStorageNamespace* new_namespace = DOMStorageNamespace::CreateLocalStorageNamespace(this, dir_path); diff --git a/chrome/browser/in_process_webkit/dom_storage_context.h b/chrome/browser/in_process_webkit/dom_storage_context.h index fb68f4c9..4981c07 100644 --- a/chrome/browser/in_process_webkit/dom_storage_context.h +++ b/chrome/browser/in_process_webkit/dom_storage_context.h @@ -66,6 +66,18 @@ class DOMStorageContext { // date that's supplied. void DeleteDataModifiedSince(const base::Time& cutoff); + // Deletes a single local storage file. + void DeleteLocalStorageFile(const FilePath& file_path); + + // Deletes all local storage files. + void DeleteAllLocalStorageFiles(); + + // The local storage directory. + static const FilePath::CharType kLocalStorageDirectory[]; + + // The local storage file extension. + static const FilePath::CharType kLocalStorageExtension[]; + private: // Get the local storage instance. The object is owned by this class. DOMStorageNamespace* CreateLocalStorage(); diff --git a/chrome/browser/views/options/cookies_view.cc b/chrome/browser/views/options/cookies_view.cc index 7e5f0b4..68dd2df 100644 --- a/chrome/browser/views/options/cookies_view.cc +++ b/chrome/browser/views/options/cookies_view.cc @@ -31,7 +31,6 @@ static const int kCookieInfoViewBorderSize = 1; static const int kCookieInfoViewInsetSize = 3; static const int kSearchFilterDelayMs = 500; - /////////////////////////////////////////////////////////////////////////////// // CookiesTreeView // Overridden to handle Delete key presses @@ -49,20 +48,19 @@ class CookiesTreeView : public views::TreeView { }; CookiesTreeView::CookiesTreeView(CookiesTreeModel* cookies_model) { - SetModel(cookies_model); - SetRootShown(false); - SetEditable(false); + SetModel(cookies_model); + SetRootShown(false); + SetEditable(false); } void CookiesTreeView::RemoveSelectedItems() { TreeModelNode* selected_node = GetSelectedNode(); if (selected_node) { static_cast<CookiesTreeModel*>(model())->DeleteCookieNode( - static_cast<CookieTreeCookieNode*>(GetSelectedNode())); + static_cast<CookieTreeNode*>(GetSelectedNode())); } } - /////////////////////////////////////////////////////////////////////////////// // CookieInfoView, public: @@ -253,6 +251,123 @@ void CookieInfoView::Init() { } /////////////////////////////////////////////////////////////////////////////// +// LocalStorageInfoView, public: + +LocalStorageInfoView::LocalStorageInfoView() + : origin_label_(NULL), + origin_value_field_(NULL), + size_label_(NULL), + size_value_field_(NULL), + last_modified_label_(NULL), + last_modified_value_field_(NULL) { +} + +LocalStorageInfoView::~LocalStorageInfoView() { +} + +void LocalStorageInfoView::SetLocalStorageInfo( + const BrowsingDataLocalStorageHelper::LocalStorageInfo& + local_storage_info) { + origin_value_field_->SetText(UTF8ToWide(local_storage_info.origin)); + size_value_field_->SetText( + FormatBytes(local_storage_info.size, + GetByteDisplayUnits(local_storage_info.size), + true)); + last_modified_value_field_->SetText( + base::TimeFormatFriendlyDateAndTime(local_storage_info.last_modified)); + EnableLocalStorageDisplay(true); +} + +void LocalStorageInfoView::EnableLocalStorageDisplay(bool enabled) { + origin_value_field_->SetEnabled(enabled); + size_value_field_->SetEnabled(enabled); + last_modified_value_field_->SetEnabled(enabled); +} + +void LocalStorageInfoView::ClearLocalStorageDisplay() { + std::wstring no_cookie_string = + l10n_util::GetString(IDS_COOKIES_COOKIE_NONESELECTED); + origin_value_field_->SetText(no_cookie_string); + size_value_field_->SetText(no_cookie_string); + last_modified_value_field_->SetText(no_cookie_string); + EnableLocalStorageDisplay(false); +} + +/////////////////////////////////////////////////////////////////////////////// +// LocalStorageInfoView, views::View overrides: + +void LocalStorageInfoView::ViewHierarchyChanged(bool is_add, + views::View* parent, + views::View* child) { + if (is_add && child == this) + Init(); +} + +/////////////////////////////////////////////////////////////////////////////// +// LocalStorageInfoView, private: + +void LocalStorageInfoView::Init() { + SkColor border_color = color_utils::GetSysSkColor(COLOR_3DSHADOW); + views::Border* border = views::Border::CreateSolidBorder( + kCookieInfoViewBorderSize, border_color); + set_border(border); + + origin_label_ = new views::Label( + l10n_util::GetString(IDS_COOKIES_LOCAL_STORAGE_ORIGIN_LABEL)); + origin_value_field_ = new views::Textfield; + size_label_ = new views::Label( + l10n_util::GetString(IDS_COOKIES_LOCAL_STORAGE_SIZE_ON_DISK_LABEL)); + size_value_field_ = new views::Textfield; + last_modified_label_ = new views::Label( + l10n_util::GetString(IDS_COOKIES_LOCAL_STORAGE_LAST_MODIFIED_LABEL)); + last_modified_value_field_ = new views::Textfield; + + using views::GridLayout; + using views::ColumnSet; + + GridLayout* layout = new GridLayout(this); + layout->SetInsets(kCookieInfoViewInsetSize, + kCookieInfoViewInsetSize, + kCookieInfoViewInsetSize, + kCookieInfoViewInsetSize); + SetLayoutManager(layout); + + int three_column_layout_id = 0; + ColumnSet* column_set = layout->AddColumnSet(three_column_layout_id); + column_set->AddColumn(GridLayout::TRAILING, GridLayout::CENTER, 0, + GridLayout::USE_PREF, 0, 0); + column_set->AddPaddingColumn(0, kRelatedControlHorizontalSpacing); + column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 1, + GridLayout::USE_PREF, 0, 0); + + layout->StartRow(0, three_column_layout_id); + layout->AddView(origin_label_); + layout->AddView(origin_value_field_); + layout->AddPaddingRow(0, kRelatedControlSmallVerticalSpacing); + layout->StartRow(0, three_column_layout_id); + layout->AddView(size_label_); + layout->AddView(size_value_field_); + layout->AddPaddingRow(0, kRelatedControlSmallVerticalSpacing); + layout->StartRow(0, three_column_layout_id); + layout->AddView(last_modified_label_); + layout->AddView(last_modified_value_field_); + + // Color these borderless text areas the same as the containing dialog. + SkColor text_area_background = color_utils::GetSysSkColor(COLOR_3DFACE); + // Now that the Textfields are in the view hierarchy, we can initialize them. + origin_value_field_->SetReadOnly(true); + origin_value_field_->RemoveBorder(); + origin_value_field_->SetBackgroundColor(text_area_background); + size_value_field_->SetReadOnly(true); + size_value_field_->RemoveBorder(); + size_value_field_->SetBackgroundColor(text_area_background); + last_modified_value_field_->SetReadOnly(true); + last_modified_value_field_->RemoveBorder(); + last_modified_value_field_->SetBackgroundColor(text_area_background); +} + + +/////////////////////////////////////////////////////////////////////////////// // CookiesView, public: // static @@ -371,10 +486,17 @@ void CookiesView::OnTreeViewSelectionChanged(views::TreeView* tree_view) { static_cast<CookieTreeNode*>(tree_view->GetSelectedNode())-> GetDetailedInfo(); if (detailed_info.node_type == CookieTreeNode::DetailedInfo::TYPE_COOKIE) { - info_view_->SetCookie(detailed_info.cookie->first, - detailed_info.cookie->second); + UpdateVisibleDetailedInfo(cookie_info_view_); + cookie_info_view_->SetCookie(detailed_info.cookie->first, + detailed_info.cookie->second); + } else if (detailed_info.node_type == + CookieTreeNode::DetailedInfo::TYPE_LOCAL_STORAGE) { + UpdateVisibleDetailedInfo(local_storage_info_view_); + local_storage_info_view_->SetLocalStorageInfo( + *detailed_info.local_storage_info); } else { - info_view_->ClearCookieDisplay(); + UpdateVisibleDetailedInfo(cookie_info_view_); + cookie_info_view_->ClearCookieDisplay(); } } @@ -393,7 +515,8 @@ CookiesView::CookiesView(Profile* profile) clear_search_button_(NULL), description_label_(NULL), cookies_tree_(NULL), - info_view_(NULL), + cookie_info_view_(NULL), + local_storage_info_view_(NULL), remove_button_(NULL), remove_all_button_(NULL), profile_(profile), @@ -421,7 +544,8 @@ void CookiesView::Init() { l10n_util::GetString(IDS_COOKIES_INFO_LABEL)); description_label_->SetHorizontalAlignment(views::Label::ALIGN_LEFT); cookies_tree_model_.reset(new CookiesTreeModel(profile_)); - info_view_ = new CookieInfoView; + cookie_info_view_ = new CookieInfoView; + local_storage_info_view_ = new LocalStorageInfoView; cookies_tree_ = new CookiesTreeView(cookies_tree_model_.get()); remove_button_ = new views::NativeButton( this, l10n_util::GetString(IDS_COOKIES_REMOVE_LABEL)); @@ -469,7 +593,10 @@ void CookiesView::Init() { layout->AddPaddingRow(0, kRelatedControlVerticalSpacing); layout->StartRow(0, single_column_layout_id); - layout->AddView(info_view_); + layout->AddView(cookie_info_view_, 1, 2); + + layout->StartRow(0, single_column_layout_id); + layout->AddView(local_storage_info_view_); // Add the Remove/Remove All buttons to the ClientView View* parent = GetParent(); @@ -477,6 +604,8 @@ void CookiesView::Init() { parent->AddChildView(remove_all_button_); if (!cookies_tree_model_.get()->GetRoot()->GetChildCount()) UpdateForEmptyState(); + else + UpdateVisibleDetailedInfo(cookie_info_view_); } void CookiesView::ResetSearchQuery() { @@ -486,7 +615,15 @@ void CookiesView::ResetSearchQuery() { } void CookiesView::UpdateForEmptyState() { - info_view_->ClearCookieDisplay(); + cookie_info_view_->ClearCookieDisplay(); remove_button_->SetEnabled(false); remove_all_button_->SetEnabled(false); + UpdateVisibleDetailedInfo(cookie_info_view_); +} + +void CookiesView::UpdateVisibleDetailedInfo(views::View* view) { + view->SetVisible(true); + views::View* other = local_storage_info_view_; + if (view == local_storage_info_view_) other = cookie_info_view_; + other->SetVisible(false); } diff --git a/chrome/browser/views/options/cookies_view.h b/chrome/browser/views/options/cookies_view.h index d7c1b23..91d6cf4a 100644 --- a/chrome/browser/views/options/cookies_view.h +++ b/chrome/browser/views/options/cookies_view.h @@ -8,6 +8,7 @@ #include <string> #include "base/task.h" +#include "chrome/browser/browsing_data_local_storage_helper.h" #include "net/base/cookie_monster.h" #include "views/controls/button/button.h" #include "views/controls/tree/tree_view.h" @@ -24,9 +25,11 @@ class NativeButton; } // namespace views +class BrowsingDataLocalStorageHelper; class CookieInfoView; class CookiesTreeModel; class CookiesTreeView; +class LocalStorageInfoView; class Profile; class Timer; @@ -96,13 +99,23 @@ class CookiesView : public views::View, // Update the UI when there are no cookies. void UpdateForEmptyState(); + // Update the UI when a cookie is selected. + void UpdateForCookieState(); + + // Update the UI when a local storage is selected. + void UpdateForLocalStorageState(); + + // Updates view to be visible inside detailed_info_view_; + void UpdateVisibleDetailedInfo(views::View* view); + // Assorted dialog controls views::Label* search_label_; views::Textfield* search_field_; views::NativeButton* clear_search_button_; views::Label* description_label_; CookiesTreeView* cookies_tree_; - CookieInfoView* info_view_; + CookieInfoView* cookie_info_view_; + LocalStorageInfoView* local_storage_info_view_; views::NativeButton* remove_button_; views::NativeButton* remove_all_button_; @@ -172,4 +185,46 @@ class CookieInfoView : public views::View { DISALLOW_COPY_AND_ASSIGN(CookieInfoView); }; +/////////////////////////////////////////////////////////////////////////////// +// LocalStorageInfoView +// +// Responsible for displaying a tabular grid of Local Storage information. +class LocalStorageInfoView : public views::View { + public: + LocalStorageInfoView(); + virtual ~LocalStorageInfoView(); + + // Update the display from the specified Local Storage info. + void SetLocalStorageInfo( + const BrowsingDataLocalStorageHelper::LocalStorageInfo& + local_storage_info); + + // Clears the cookie display to indicate that no or multiple local storages + // are selected. + void ClearLocalStorageDisplay(); + + // Enables or disables the local storate property text fields. + void EnableLocalStorageDisplay(bool enabled); + + protected: + // views::View overrides: + virtual void ViewHierarchyChanged( + bool is_add, views::View* parent, views::View* child); + + private: + // Set up the view layout + void Init(); + + // Individual property labels + views::Label* origin_label_; + views::Textfield* origin_value_field_; + views::Label* size_label_; + views::Textfield* size_value_field_; + views::Label* last_modified_label_; + views::Textfield* last_modified_value_field_; + + DISALLOW_COPY_AND_ASSIGN(LocalStorageInfoView); +}; + + #endif // CHROME_BROWSER_VIEWS_OPTIONS_COOKIES_VIEW_H_ diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index 551b232..2c75384 100755 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -222,6 +222,8 @@ 'browser/browser_url_handler.cc', 'browser/browser_url_handler.h', 'browser/browser_window.h', + 'browser/browsing_data_local_storage_helper.cc', + 'browser/browsing_data_local_storage_helper.h', 'browser/browsing_data_remover.cc', 'browser/browsing_data_remover.h', 'browser/browsing_instance.cc', diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi index 2d68d00..8363d97 100755 --- a/chrome/chrome_tests.gypi +++ b/chrome/chrome_tests.gypi @@ -1084,6 +1084,7 @@ 'browser/autocomplete/autocomplete_browsertest.cc', 'browser/browser_browsertest.cc', 'browser/browser_init_browsertest.cc', + 'browser/browsing_data_local_storage_helper_unittest.cc', 'browser/crash_recovery_browsertest.cc', 'browser/download/save_page_browsertest.cc', 'browser/extensions/autoupdate_interceptor.cc', |